com.opengamma.strata.loader.csv.FraTradeCsvPlugin 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) 2017 - 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.loader.csv.CsvLoaderColumns.BUY_SELL_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.CONVENTION_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.CURRENCY_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.DATE_ADJ_CAL_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.DATE_ADJ_CNV_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.DAY_COUNT_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.END_DATE_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.FIXED_RATE_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.FRA_DISCOUNTING_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.INDEX_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.INTERPOLATED_INDEX_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.NOTIONAL_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.PAYMENT_DATE_CAL_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.PAYMENT_DATE_CNV_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.PAYMENT_DATE_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.PERIOD_TO_START_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.START_DATE_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.TRADE_DATE_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderColumns.TRADE_TYPE_FIELD;
import static com.opengamma.strata.loader.csv.CsvLoaderUtils.formattedPercentage;
import java.time.LocalDate;
import java.time.Period;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.opengamma.strata.basics.currency.Currency;
import com.opengamma.strata.basics.date.BusinessDayAdjustment;
import com.opengamma.strata.basics.date.BusinessDayConvention;
import com.opengamma.strata.basics.date.BusinessDayConventions;
import com.opengamma.strata.basics.date.DayCount;
import com.opengamma.strata.basics.date.HolidayCalendarId;
import com.opengamma.strata.basics.index.IborIndex;
import com.opengamma.strata.collect.io.CsvOutput.CsvRowOutputWithHeaders;
import com.opengamma.strata.collect.io.CsvRow;
import com.opengamma.strata.collect.result.ParseFailureException;
import com.opengamma.strata.loader.LoaderUtils;
import com.opengamma.strata.product.Trade;
import com.opengamma.strata.product.TradeInfo;
import com.opengamma.strata.product.common.BuySell;
import com.opengamma.strata.product.fra.Fra;
import com.opengamma.strata.product.fra.FraDiscountingMethod;
import com.opengamma.strata.product.fra.FraTrade;
import com.opengamma.strata.product.fra.type.FraConvention;
/**
* Handles the CSV file format for FRA trades.
*/
final class FraTradeCsvPlugin implements TradeCsvParserPlugin, TradeCsvWriterPlugin {
/**
* The singleton instance of the plugin.
*/
public static final FraTradeCsvPlugin INSTANCE = new FraTradeCsvPlugin();
//-------------------------------------------------------------------------
@Override
public Set tradeTypeNames() {
return ImmutableSet.of("FRA");
}
@Override
public Optional parseTrade(
Class> requiredJavaType,
CsvRow baseRow,
List additionalRows,
TradeInfo info,
TradeCsvInfoResolver resolver) {
if (requiredJavaType.isAssignableFrom(FraTrade.class)) {
return Optional.of(resolver.parseFraTrade(baseRow, info));
}
return Optional.empty();
}
@Override
public String getName() {
return FraTrade.class.getSimpleName();
}
@Override
public Set> supportedTradeTypes() {
return ImmutableSet.of(FraTrade.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 FraTrade parse(CsvRow row, TradeInfo info, TradeCsvInfoResolver resolver) {
FraTrade trade = parseRow(row, info, resolver);
return resolver.completeTrade(row, trade);
}
// parse the row to a trade
private static FraTrade parseRow(CsvRow row, TradeInfo info, TradeCsvInfoResolver resolver) {
BuySell buySell = row.getValue(BUY_SELL_FIELD, LoaderUtils::parseBuySell);
Optional currencyOpt = row.findValue(CURRENCY_FIELD, Currency::of);
double notional = row.getValue(NOTIONAL_FIELD, LoaderUtils::parseDouble);
double fixedRate = row.getValue(FIXED_RATE_FIELD, LoaderUtils::parseDoublePercent);
Optional conventionOpt = row.findValue(CONVENTION_FIELD, FraConvention::of);
Optional periodToStartOpt = row.findValue(PERIOD_TO_START_FIELD, LoaderUtils::parsePeriod);
Optional startDateOpt = row.findValue(START_DATE_FIELD, LoaderUtils::parseDate);
Optional endDateOpt = row.findValue(END_DATE_FIELD, LoaderUtils::parseDate);
Optional indexOpt = row.findValue(INDEX_FIELD, IborIndex::of);
Optional interpolatedOpt = row.findValue(INTERPOLATED_INDEX_FIELD, IborIndex::of);
Optional dayCountOpt = row.findValue(DAY_COUNT_FIELD, LoaderUtils::parseDayCount);
Optional discMethodOpt = row.findValue(FRA_DISCOUNTING_FIELD, FraDiscountingMethod::of);
BusinessDayConvention dateCnv = row.findValue(DATE_ADJ_CNV_FIELD, LoaderUtils::parseBusinessDayConvention)
.orElse(BusinessDayConventions.MODIFIED_FOLLOWING);
Optional dateCalOpt = row.findValue(DATE_ADJ_CAL_FIELD, HolidayCalendarId::of);
// not parsing paymentDate, fixingDateOffset, discounting
// use convention if available
if (conventionOpt.isPresent()) {
if (indexOpt.isPresent() || interpolatedOpt.isPresent() || dayCountOpt.isPresent()) {
throw new ParseFailureException(
"Fra trade had invalid combination of fields. When '" + CONVENTION_FIELD +
"' is present these fields must not be present: " +
ImmutableList.of(INDEX_FIELD, INTERPOLATED_INDEX_FIELD, DAY_COUNT_FIELD));
}
FraConvention convention = conventionOpt.get();
// explicit dates take precedence over relative ones
if (startDateOpt.isPresent() && endDateOpt.isPresent()) {
if (periodToStartOpt.isPresent()) {
throw new ParseFailureException(
"Fra trade had invalid combination of fields. When these fields are found " +
ImmutableList.of(CONVENTION_FIELD, START_DATE_FIELD, END_DATE_FIELD) +
" then these fields must not be present " +
ImmutableList.of(PERIOD_TO_START_FIELD));
}
LocalDate startDate = startDateOpt.get();
LocalDate endDate = endDateOpt.get();
// NOTE: payment date assumed to be the start date
FraTrade trade = convention.toTrade(info, startDate, endDate, startDate, buySell, notional, fixedRate);
return adjustTrade(trade, currencyOpt, discMethodOpt, dateCnv, dateCalOpt);
}
// relative dates
if (periodToStartOpt.isPresent() && info.getTradeDate().isPresent()) {
if (startDateOpt.isPresent() || endDateOpt.isPresent()) {
throw new ParseFailureException(
"Fra trade had invalid combination of fields. When these fields are found " +
ImmutableList.of(CONVENTION_FIELD, PERIOD_TO_START_FIELD, TRADE_DATE_FIELD) +
" then these fields must not be present " +
ImmutableList.of(START_DATE_FIELD, END_DATE_FIELD));
}
LocalDate tradeDate = info.getTradeDate().get();
Period periodToStart = periodToStartOpt.get();
FraTrade trade =
convention.createTrade(tradeDate, periodToStart, buySell, notional, fixedRate, resolver.getReferenceData());
trade = trade.toBuilder().info(info).build();
return adjustTrade(trade, currencyOpt, discMethodOpt, dateCnv, dateCalOpt);
}
} else if (startDateOpt.isPresent() && endDateOpt.isPresent() && indexOpt.isPresent()) {
LocalDate startDate = startDateOpt.get();
LocalDate endDate = endDateOpt.get();
IborIndex index = indexOpt.get();
Fra.Builder builder = Fra.builder()
.buySell(buySell)
.notional(notional)
.startDate(startDate)
.endDate(endDate)
.fixedRate(fixedRate)
.index(index);
interpolatedOpt.ifPresent(interpolated -> builder.indexInterpolated(interpolated));
dayCountOpt.ifPresent(dayCount -> builder.dayCount(dayCount));
return adjustTrade(FraTrade.of(info, builder.build()), currencyOpt, discMethodOpt, dateCnv, dateCalOpt);
}
// no match
throw new ParseFailureException(
"Fra trade had invalid combination of fields. These fields are mandatory:" +
ImmutableList.of(BUY_SELL_FIELD, NOTIONAL_FIELD, FIXED_RATE_FIELD) +
" and one of these combinations is mandatory: " +
ImmutableList.of(CONVENTION_FIELD, TRADE_DATE_FIELD, PERIOD_TO_START_FIELD) +
" or " +
ImmutableList.of(CONVENTION_FIELD, START_DATE_FIELD, END_DATE_FIELD) +
" or " +
ImmutableList.of(START_DATE_FIELD, END_DATE_FIELD, INDEX_FIELD));
}
// adjust trade based on additional fields specified
private static FraTrade adjustTrade(
FraTrade trade,
Optional currencyOpt,
Optional discMethodOpt,
BusinessDayConvention dateCnv,
Optional dateCalOpt) {
if (!currencyOpt.isPresent() && !discMethodOpt.isPresent() && !dateCalOpt.isPresent()) {
return trade;
}
Fra.Builder builder = trade.getProduct().toBuilder();
currencyOpt.ifPresent(currency -> builder.currency(currency));
discMethodOpt.ifPresent(discMethod -> builder.discounting(discMethod));
dateCalOpt.ifPresent(cal -> builder.businessDayAdjustment(BusinessDayAdjustment.of(dateCnv, cal)));
return trade.toBuilder()
.product(builder.build())
.build();
}
//-------------------------------------------------------------------------
@Override
public Set headers(List trades) {
LinkedHashSet headers = new LinkedHashSet<>();
headers.add(BUY_SELL_FIELD);
headers.add(START_DATE_FIELD);
headers.add(END_DATE_FIELD);
if (trades.stream()
.anyMatch(trade -> !trade.getProduct().getCurrency().equals(trade.getProduct().getIndex().getCurrency()))) {
headers.add(CURRENCY_FIELD);
}
headers.add(NOTIONAL_FIELD);
headers.add(FIXED_RATE_FIELD);
headers.add(INDEX_FIELD);
if (trades.stream().anyMatch(trade -> !trade.getProduct().getIndexInterpolated().isPresent())) {
headers.add(INTERPOLATED_INDEX_FIELD);
}
if (trades.stream()
.anyMatch(trade -> !trade.getProduct().getDayCount().equals(trade.getProduct().getIndex().getDayCount()))) {
headers.add(DAY_COUNT_FIELD);
}
if (trades.stream()
.anyMatch(trade -> !trade.getProduct().getDiscounting().equals(FraDiscountingMethod.ISDA))) {
headers.add(FRA_DISCOUNTING_FIELD);
}
headers.add(DATE_ADJ_CNV_FIELD);
headers.add(DATE_ADJ_CAL_FIELD);
headers.add(PAYMENT_DATE_FIELD);
headers.add(PAYMENT_DATE_CNV_FIELD);
headers.add(PAYMENT_DATE_CAL_FIELD);
return headers;
}
@Override
public void writeCsv(CsvRowOutputWithHeaders csv, FraTrade trade) {
Fra product = trade.getProduct();
csv.writeCell(TRADE_TYPE_FIELD, "Fra");
csv.writeCell(START_DATE_FIELD, product.getStartDate());
csv.writeCell(END_DATE_FIELD, product.getEndDate());
csv.writeCell(BUY_SELL_FIELD, product.getBuySell());
if (!product.getCurrency().equals(product.getIndex().getCurrency())) {
csv.writeCell(CURRENCY_FIELD, product.getCurrency());
}
csv.writeCell(NOTIONAL_FIELD, product.getNotional());
csv.writeCell(FIXED_RATE_FIELD, formattedPercentage(product.getFixedRate()));
csv.writeCell(INDEX_FIELD, product.getIndex());
product.getIndexInterpolated().ifPresent(index -> csv.writeCell(INTERPOLATED_INDEX_FIELD, index));
if (!product.getDayCount().equals(product.getIndex().getDayCount())) {
csv.writeCell(DAY_COUNT_FIELD, product.getDayCount());
}
if (csv.headers().contains(FRA_DISCOUNTING_FIELD)) {
csv.writeCell(FRA_DISCOUNTING_FIELD, product.getDiscounting());
}
product.getBusinessDayAdjustment().ifPresent(bda -> {
csv.writeCell(DATE_ADJ_CNV_FIELD, bda.getConvention());
csv.writeCell(DATE_ADJ_CAL_FIELD, bda.getCalendar());
});
csv.writeCell(PAYMENT_DATE_FIELD, product.getPaymentDate().getUnadjusted());
csv.writeCell(PAYMENT_DATE_CAL_FIELD, product.getPaymentDate().getAdjustment().getCalendar());
csv.writeCell(PAYMENT_DATE_CNV_FIELD, product.getPaymentDate().getAdjustment().getConvention());
csv.writeNewLine();
}
//-------------------------------------------------------------------------
// Restricted constructor.
private FraTradeCsvPlugin() {
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy