com.opengamma.strata.loader.csv.SwaptionTradeCsvPlugin Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of strata-loader Show documentation
Show all versions of strata-loader Show documentation
Loaders from standard and Strata-specific data formats
/*
* Copyright (C) 2019 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.loader.csv;
import static com.opengamma.strata.collect.Guavate.toImmutableList;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.EXERCISE_DATES_CAL_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.EXERCISE_DATES_CNV_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.EXERCISE_DATES_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.EXPIRY_DATE_CAL_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.EXPIRY_DATE_CNV_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.EXPIRY_DATE_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.EXPIRY_TIME_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.EXPIRY_ZONE_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.LONG_SHORT_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.PAYOFF_SETTLEMENT_DATE_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.PAYOFF_SETTLEMENT_TYPE_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.PREMIUM_AMOUNT_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.PREMIUM_CURRENCY_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.PREMIUM_DATE_CAL_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.PREMIUM_DATE_CNV_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.PREMIUM_DATE_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.PREMIUM_DIRECTION_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.TRADE_TYPE_FIELD;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.opengamma.strata.basics.currency.AdjustablePayment;
import com.opengamma.strata.basics.date.AdjustableDate;
import com.opengamma.strata.basics.date.AdjustableDates;
import com.opengamma.strata.basics.date.BusinessDayAdjustment;
import com.opengamma.strata.basics.date.BusinessDayConvention;
import com.opengamma.strata.basics.date.DaysAdjustment;
import com.opengamma.strata.basics.date.HolidayCalendarId;
import com.opengamma.strata.collect.io.CsvOutput.CsvRowOutputWithHeaders;
import com.opengamma.strata.collect.io.CsvRow;
import com.opengamma.strata.loader.LoaderUtils;
import com.opengamma.strata.loader.csv.FullSwapTradeCsvPlugin.VariableElements;
import com.opengamma.strata.product.Trade;
import com.opengamma.strata.product.TradeInfo;
import com.opengamma.strata.product.common.LongShort;
import com.opengamma.strata.product.swap.Swap;
import com.opengamma.strata.product.swap.SwapTrade;
import com.opengamma.strata.product.swaption.CashSwaptionSettlement;
import com.opengamma.strata.product.swaption.CashSwaptionSettlementMethod;
import com.opengamma.strata.product.swaption.PhysicalSwaptionSettlement;
import com.opengamma.strata.product.swaption.Swaption;
import com.opengamma.strata.product.swaption.SwaptionExercise;
import com.opengamma.strata.product.swaption.SwaptionSettlement;
import com.opengamma.strata.product.swaption.SwaptionTrade;
/**
* Handles the CSV file format for Swaption trades.
*/
final class SwaptionTradeCsvPlugin implements TradeCsvParserPlugin, TradeCsvWriterPlugin {
/**
* The singleton instance of the plugin.
*/
public static final SwaptionTradeCsvPlugin INSTANCE = new SwaptionTradeCsvPlugin();
private static final String PHYSICAL = "PHYSICAL";
//-------------------------------------------------------------------------
@Override
public Set tradeTypeNames() {
return ImmutableSet.of("SWAPTION");
}
@Override
public boolean isAdditionalRow(CsvRow baseRow, CsvRow additionalRow) {
return additionalRow.getField(TRADE_TYPE_FIELD).toUpperCase(Locale.ENGLISH).equals("VARIABLE");
}
@Override
public Optional parseTrade(
Class> requiredJavaType,
CsvRow baseRow,
List additionalRows,
TradeInfo info,
TradeCsvInfoResolver resolver) {
if (requiredJavaType.isAssignableFrom(SwaptionTrade.class)) {
return Optional.of(resolver.parseSwaptionTrade(baseRow, additionalRows, info));
}
return Optional.empty();
}
@Override
public String getName() {
return SwaptionTrade.class.getSimpleName();
}
@Override
public Set> supportedTradeTypes() {
return ImmutableSet.of(SwaptionTrade.class);
}
//-------------------------------------------------------------------------
/**
* Parses from the CSV row.
*
* @param row the CSV row
* @param info the trade info
* @param resolver the resolver used to parse additional information
* @return the parsed trade
*/
static SwaptionTrade parse(CsvRow row, List variableRows, TradeInfo info, TradeCsvInfoResolver resolver) {
SwapTrade swapTrade = SwapTradeCsvPlugin.parseSwap(row, variableRows, info, resolver.getReferenceData());
SwaptionTrade trade = parseRow(row, info, swapTrade.getProduct());
return resolver.completeTrade(row, trade);
}
//-------------------------------------------------------------------------
// parse the row to a trade
private static SwaptionTrade parseRow(CsvRow row, TradeInfo info, Swap underlying) {
LongShort longShort = LoaderUtils.parseLongShort(row.getValue(LONG_SHORT_FIELD));
SwaptionSettlement settlement = parseSettlement(row);
AdjustableDate expiryDate = CsvLoaderUtils.parseAdjustableDate(
row, EXPIRY_DATE_FIELD, EXPIRY_DATE_CNV_FIELD, EXPIRY_DATE_CAL_FIELD);
LocalTime expiryTime = row.getValue(EXPIRY_TIME_FIELD, LoaderUtils::parseTime);
ZoneId expiryZone = row.getValue(EXPIRY_ZONE_FIELD, LoaderUtils::parseZoneId);
AdjustablePayment premium = CsvLoaderUtils.tryParsePremiumFromDefaultFields(row)
.orElse(AdjustablePayment.of(underlying.getLegs().get(0).getCurrency(), 0d, expiryDate));
Swaption.Builder swaption = Swaption.builder()
.longShort(longShort)
.swaptionSettlement(settlement)
.expiryDate(expiryDate)
.expiryTime(expiryTime)
.expiryZone(expiryZone)
.underlying(underlying);
parseSwaptionExercise(row).ifPresent(swaption::exerciseInfo);
return SwaptionTrade.builder()
.info(info)
.product(swaption.build())
.premium(premium)
.build();
}
// parses the settlement cash/physical
private static SwaptionSettlement parseSettlement(CsvRow row) {
String settlementType = row.getValue(PAYOFF_SETTLEMENT_TYPE_FIELD);
if (settlementType.equalsIgnoreCase(PHYSICAL)) {
return PhysicalSwaptionSettlement.DEFAULT;
}
CashSwaptionSettlementMethod method = CashSwaptionSettlementMethod.of(settlementType);
LocalDate date = row.getValue(PAYOFF_SETTLEMENT_DATE_FIELD, LoaderUtils::parseDate);
return CashSwaptionSettlement.of(date, method);
}
//-------------------------------------------------------------------------
@Override
public Set headers(List trades) {
LinkedHashSet headers = new LinkedHashSet<>(
FullSwapTradeCsvPlugin.INSTANCE.headers(trades.stream()
.map(trade -> SwapTrade.of(TradeInfo.empty(), trade.getProduct().getUnderlying()))
.collect(toImmutableList())));
headers.add(LONG_SHORT_FIELD);
headers.add(PAYOFF_SETTLEMENT_TYPE_FIELD);
headers.add(PAYOFF_SETTLEMENT_DATE_FIELD);
headers.add(EXPIRY_DATE_FIELD);
if (trades.stream()
.anyMatch(trade -> !trade.getProduct().getExpiryDate().getAdjustment().equals(BusinessDayAdjustment.NONE))) {
headers.add(EXPIRY_DATE_CNV_FIELD);
headers.add(EXPIRY_DATE_CAL_FIELD);
}
headers.add(EXPIRY_TIME_FIELD);
headers.add(EXPIRY_ZONE_FIELD);
headers.add(PREMIUM_DATE_FIELD);
headers.add(PREMIUM_DATE_CNV_FIELD);
headers.add(PREMIUM_DATE_CAL_FIELD);
headers.add(PREMIUM_DIRECTION_FIELD);
headers.add(PREMIUM_CURRENCY_FIELD);
headers.add(PREMIUM_AMOUNT_FIELD);
if (trades.stream().anyMatch(trade -> trade.getProduct().getExerciseInfo().isPresent())) {
headers.add(EXERCISE_DATES_FIELD);
headers.add(EXERCISE_DATES_CAL_FIELD);
headers.add(EXERCISE_DATES_CNV_FIELD);
}
return headers;
}
@Override
public void writeCsv(CsvRowOutputWithHeaders csv, SwaptionTrade trade) {
Swaption product = trade.getProduct();
csv.writeCell(TRADE_TYPE_FIELD, "Swaption");
VariableElements variableElements = FullSwapTradeCsvPlugin.INSTANCE.writeProduct(csv, product.getUnderlying());
csv.writeCell(LONG_SHORT_FIELD, product.getLongShort());
writeSettlement(csv, product);
csv.writeCell(EXPIRY_DATE_FIELD, product.getExpiryDate().getUnadjusted());
if (!product.getExpiryDate().getAdjustment().equals(BusinessDayAdjustment.NONE)) {
csv.writeCell(EXPIRY_DATE_CNV_FIELD, product.getExpiryDate().getAdjustment().getConvention());
csv.writeCell(EXPIRY_DATE_CAL_FIELD, product.getExpiryDate().getAdjustment().getCalendar());
}
csv.writeCell(EXPIRY_TIME_FIELD, product.getExpiryTime());
csv.writeCell(EXPIRY_ZONE_FIELD, product.getExpiryZone().getId());
CsvWriterUtils.writePremiumFields(csv, trade.getPremium());
trade.getProduct().getExerciseInfo()
.ifPresent(exercise -> writeSwaptionExercise(csv, exercise, product.getExpiryDate()));
csv.writeNewLine();
variableElements.writeLines(csv);
}
private void writeSwaptionExercise(
CsvRowOutputWithHeaders csv,
SwaptionExercise exercise,
AdjustableDate expiryDate) {
Function extractUnadjustedDate = date -> date.getUnadjusted().toString();
List dates = exercise.getDateDefinition().toAdjustableDateList();
if (exercise.isEuropean() && !dates.contains(expiryDate) || exercise.isBermudan()) {
csv.writeCell(EXERCISE_DATES_FIELD, pipeJoined(dates, extractUnadjustedDate));
csv.writeCell(EXERCISE_DATES_CAL_FIELD, exercise.getDateDefinition().getAdjustment().getCalendar());
csv.writeCell(EXERCISE_DATES_CNV_FIELD, exercise.getDateDefinition().getAdjustment().getConvention());
} else if (exercise.isAmerican()) {
//To implement if/when we support American swaptions. A frequency might have to be added.
}
}
private String pipeJoined(List dates, Function mapper) {
return dates.stream().map(mapper).collect(Collectors.joining("|"));
}
private static Optional parseSwaptionExercise(CsvRow row) {
Optional exerciseDatesString = row.findValue(CsvLoaderColumns.EXERCISE_DATES_FIELD);
if (!exerciseDatesString.isPresent()) {
return Optional.empty();
}
Function> pipeSplitter = s -> Stream.of(s.split("\\|")).collect(Collectors.toList());
List dates = exerciseDatesString
.map(pipeSplitter)
.orElse(ImmutableList.of())
.stream()
.map(LoaderUtils::parseDate)
.collect(Collectors.toList());
BusinessDayConvention convention = row.getValue(EXERCISE_DATES_CNV_FIELD, LoaderUtils::parseBusinessDayConvention);
HolidayCalendarId calendar = row.getValue(EXERCISE_DATES_CAL_FIELD, HolidayCalendarId::of);
BusinessDayAdjustment bdAdjustment = BusinessDayAdjustment.of(convention, calendar);
SwaptionExercise exercise;
if (dates.size() == 1) {
exercise = SwaptionExercise.ofEuropean(AdjustableDate.of(dates.get(0), bdAdjustment), DaysAdjustment.NONE);
} else {
exercise = SwaptionExercise.ofBermudan(AdjustableDates.of(bdAdjustment, dates), DaysAdjustment.NONE);
}
return Optional.of(exercise);
}
private void writeSettlement(CsvRowOutputWithHeaders csv, Swaption product) {
if (product.getSwaptionSettlement() instanceof CashSwaptionSettlement) {
CashSwaptionSettlement cashSettle = (CashSwaptionSettlement) product.getSwaptionSettlement();
csv.writeCell(PAYOFF_SETTLEMENT_TYPE_FIELD, cashSettle.getMethod().toString());
csv.writeCell(PAYOFF_SETTLEMENT_DATE_FIELD, cashSettle.getSettlementDate());
} else {
// default to physical (FpML does this)
csv.writeCell(PAYOFF_SETTLEMENT_TYPE_FIELD, PHYSICAL);
}
}
//-------------------------------------------------------------------------
// Restricted constructor.
private SwaptionTradeCsvPlugin() {
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy