//------------------------------------------------------------------------- /// <summary> /// Parses the year-month and variant. /// </summary> /// <param name="row"> the CSV row to parse </param> /// <param name="type"> the ETD type </param> /// <returns> the expiry year-month and variant </returns> /// <exception cref="IllegalArgumentException"> if the row cannot be parsed </exception> public static Pair <YearMonth, EtdVariant> parseEtdVariant(CsvRow row, EtdType type) { YearMonth yearMonth = LoaderUtils.parseYearMonth(row.getValue(EXPIRY_FIELD)); int week = row.findValue(EXPIRY_WEEK_FIELD).map(s => LoaderUtils.parseInteger(s)).orElse(0); int day = row.findValue(EXPIRY_DAY_FIELD).map(s => LoaderUtils.parseInteger(s)).orElse(0); Optional <EtdSettlementType> settleType = row.findValue(SETTLEMENT_TYPE_FIELD).map(s => parseEtdSettlementType(s)); Optional <EtdOptionType> optionType = row.findValue(EXERCISE_STYLE_FIELD).map(s => parseEtdOptionType(s)); // check valid combinations if (!settleType.Present) { if (day == 0) { if (week == 0) { return(Pair.of(yearMonth, EtdVariant.ofMonthly())); } else { return(Pair.of(yearMonth, EtdVariant.ofWeekly(week))); } } else { if (week == 0) { return(Pair.of(yearMonth, EtdVariant.ofDaily(day))); } else { throw new System.ArgumentException("ETD date columns conflict, cannot set both expiry day and expiry week"); } } } else { if (day == 0) { throw new System.ArgumentException("ETD date columns conflict, must set expiry day for Flex " + type); } if (week != 0) { throw new System.ArgumentException("ETD date columns conflict, cannot set expiry week for Flex " + type); } if (type == EtdType.FUTURE) { return(Pair.of(yearMonth, EtdVariant.ofFlexFuture(day, settleType.get()))); } else { if (!optionType.Present) { throw new System.ArgumentException("ETD option type not found for Flex Option"); } return(Pair.of(yearMonth, EtdVariant.ofFlexOption(day, settleType.get(), optionType.get()))); } } }
// parses the trade private static FxSingleTrade parseRow(CsvRow row, TradeInfo info) { if (row.findValue(CONVENTION_FIELD).Present || row.findValue(BUY_SELL_FIELD).Present) { return(parseConvention(row, info)); } else { return(parseFull(row, info)); } }
// parses the additional GenericSecurityPosition information internal static Position parseNonEtdPosition(CsvRow row, PositionInfo info, PositionCsvInfoResolver resolver) { SecurityPosition @base = parseSecurityPosition(row, info, resolver); double? tickSizeOpt = row.findValue(TICK_SIZE).map(str => LoaderUtils.parseDouble(str)); Optional <Currency> currencyOpt = row.findValue(CURRENCY).map(str => Currency.of(str)); double? tickValueOpt = row.findValue(TICK_VALUE).map(str => LoaderUtils.parseDouble(str)); double contractSize = row.findValue(CONTRACT_SIZE).map(str => LoaderUtils.parseDouble(str)).orElse(1d); if (tickSizeOpt.HasValue && currencyOpt.Present && tickValueOpt.HasValue) { SecurityPriceInfo priceInfo = SecurityPriceInfo.of(tickSizeOpt.Value, CurrencyAmount.of(currencyOpt.get(), tickValueOpt.Value), contractSize); GenericSecurity sec = GenericSecurity.of(SecurityInfo.of(@base.SecurityId, priceInfo)); return(GenericSecurityPosition.ofLongShort(@base.Info, sec, @base.LongQuantity, @base.ShortQuantity)); } return(@base); }
// parses a trade from the CSV row internal static SecurityQuantityTrade parseTrade(CsvRow row, TradeInfo info, TradeCsvInfoResolver resolver) { SecurityTrade trade = parseSecurityTrade(row, info, resolver); SecurityTrade @base = resolver.completeTrade(row, trade); double?tickSizeOpt = row.findValue(TICK_SIZE).map(str => LoaderUtils.parseDouble(str)); Optional <Currency> currencyOpt = row.findValue(CURRENCY).map(str => Currency.of(str)); double?tickValueOpt = row.findValue(TICK_VALUE).map(str => LoaderUtils.parseDouble(str)); double contractSize = row.findValue(CONTRACT_SIZE).map(str => LoaderUtils.parseDouble(str)).orElse(1d); if (tickSizeOpt.HasValue && currencyOpt.Present && tickValueOpt.HasValue) { SecurityPriceInfo priceInfo = SecurityPriceInfo.of(tickSizeOpt.Value, CurrencyAmount.of(currencyOpt.get(), tickValueOpt.Value), contractSize); GenericSecurity sec = GenericSecurity.of(SecurityInfo.of(@base.SecurityId, priceInfo)); return(GenericSecurityTrade.of(@base.Info, sec, @base.Quantity, @base.Price)); } return(@base); }
// parses the payment date adjustment, which consists of two linked optional fields internal static Optional <BusinessDayAdjustment> parsePaymentDateAdjustment(CsvRow row) { Optional <BusinessDayAdjustment> paymentAdj = null; Optional <string> paymentDateCnv = row.findValue(PAYMENT_DATE_CNV_FIELD); // Optional field with Business day adjustment if (paymentDateCnv.Present) { BusinessDayConvention bdCnv = LoaderUtils.parseBusinessDayConvention(paymentDateCnv.get()); if (!bdCnv.Equals(BusinessDayConventions.NO_ADJUST)) { Optional <string> paymentDateCalOpt = row.findValue(PAYMENT_DATE_CAL_FIELD); if (paymentDateCalOpt.Present) { paymentAdj = BusinessDayAdjustment.of(LoaderUtils.parseBusinessDayConvention(paymentDateCnv.get()), HolidayCalendarId.of(paymentDateCalOpt.get())); } } } return(paymentAdj); }
// parses a SecurityTrade from the CSV row private static SecurityTrade parseSecurityTrade(CsvRow row, TradeInfo info, TradeCsvInfoResolver resolver) { string securityIdScheme = row.findValue(SECURITY_ID_SCHEME_FIELD).orElse(DEFAULT_SECURITY_SCHEME); string securityIdValue = row.getValue(SECURITY_ID_FIELD); SecurityId securityId = SecurityId.of(securityIdScheme, securityIdValue); double price = LoaderUtils.parseDouble(row.getValue(PRICE_FIELD)); double quantity = parseTradeQuantity(row); return(SecurityTrade.of(info, securityId, quantity, price)); }
// parses the base SecurityPosition internal static SecurityPosition parseSecurityPosition(CsvRow row, PositionInfo info, PositionCsvInfoResolver resolver) { string securityIdScheme = row.findValue(SECURITY_ID_SCHEME_FIELD).orElse(DEFAULT_SECURITY_SCHEME); string securityIdValue = row.getValue(SECURITY_ID_FIELD); SecurityId securityId = SecurityId.of(securityIdScheme, securityIdValue); DoublesPair quantity = CsvLoaderUtils.parseQuantity(row); SecurityPosition position = SecurityPosition.ofLongShort(info, securityId, quantity.First, quantity.Second); return(resolver.completePosition(row, position)); }
//------------------------------------------------------------------------- // parses a position from the CSV row internal static Position parsePosition(CsvRow row, PositionInfo info, PositionCsvInfoResolver resolver) { if (row.findValue(EXPIRY_FIELD).Present) { // etd if (row.findValue(PUT_CALL_FIELD).Present || row.findValue(EXERCISE_PRICE_FIELD).Present) { return(resolver.parseEtdOptionPosition(row, info)); } else { return(resolver.parseEtdFuturePosition(row, info)); } } else { return(parseNonEtdPosition(row, info, resolver)); } }
// parses the trade quantity, considering the optional buy/sell field private static double parseTradeQuantity(CsvRow row) { double quantity = LoaderUtils.parseDouble(row.getValue(QUANTITY_FIELD)); Optional <BuySell> buySellOpt = row.findValue(BUY_SELL_FIELD).map(str => LoaderUtils.parseBuySell(str)); if (buySellOpt.Present) { quantity = buySellOpt.get().normalize(quantity); } return(quantity); }
// parses a SecurityPosition from the CSV row, converting ETD information internal static SecurityPosition parsePositionLightweight(CsvRow row, PositionInfo info, PositionCsvInfoResolver resolver) { if (row.findValue(EXPIRY_FIELD).Present) { // etd if (row.findValue(PUT_CALL_FIELD).Present || row.findValue(EXERCISE_PRICE_FIELD).Present) { return(resolver.parseEtdOptionSecurityPosition(row, info)); } else { return(resolver.parseEtdFutureSecurityPosition(row, info)); } } else { // simple return(parseSecurityPosition(row, info, resolver)); } }
// parse an FxSingle internal static FxSingle parseFxSingle(CsvRow row, string prefix) { PayReceive direction1 = LoaderUtils.parsePayReceive(row.getValue(prefix + LEG_1_DIRECTION_FIELD)); Currency currency1 = Currency.of(row.getValue(prefix + LEG_1_CURRENCY_FIELD)); double notional1 = LoaderUtils.parseDouble(row.getValue(prefix + LEG_1_NOTIONAL_FIELD)); LocalDate paymentDate1 = row.findValue(prefix + LEG_1_PAYMENT_DATE_FIELD).map(str => LoaderUtils.parseDate(str)).orElseGet(() => LoaderUtils.parseDate(row.getValue(prefix + PAYMENT_DATE_FIELD))); PayReceive direction2 = LoaderUtils.parsePayReceive(row.getValue(prefix + LEG_2_DIRECTION_FIELD)); Currency currency2 = Currency.of(row.getValue(prefix + LEG_2_CURRENCY_FIELD)); double notional2 = LoaderUtils.parseDouble(row.getValue(prefix + LEG_2_NOTIONAL_FIELD)); LocalDate paymentDate2 = row.findValue(prefix + LEG_2_PAYMENT_DATE_FIELD).map(str => LoaderUtils.parseDate(str)).orElseGet(() => LoaderUtils.parseDate(row.getValue(prefix + PAYMENT_DATE_FIELD))); Optional <BusinessDayAdjustment> paymentAdj = parsePaymentDateAdjustment(row); if (direction1.Equals(direction2)) { throw new System.ArgumentException(Messages.format("FxSingle legs must not have the same direction: {}, {}", direction1.ToString(), direction2.ToString())); } Payment payment1 = Payment.of(currency1, direction1.normalize(notional1), paymentDate1); Payment payment2 = Payment.of(currency2, direction2.normalize(notional2), paymentDate2); return(paymentAdj.map(adj => FxSingle.of(payment1, payment2, adj)).orElseGet(() => FxSingle.of(payment1, payment2))); }
//------------------------------------------------------------------------- /// <summary> /// Parses the quantity. /// </summary> /// <param name="row"> the CSV row to parse </param> /// <returns> the quantity, long first, short second </returns> /// <exception cref="IllegalArgumentException"> if the row cannot be parsed </exception> public static DoublesPair parseQuantity(CsvRow row) { double?quantityOpt = row.findValue(QUANTITY_FIELD).map(s => LoaderUtils.parseDouble(s)); if (quantityOpt.HasValue) { double quantity = quantityOpt.Value; return(DoublesPair.of(quantity >= 0 ? quantity : 0, quantity >= 0 ? 0 : -quantity)); } double?longQuantityOpt = row.findValue(LONG_QUANTITY_FIELD).map(s => LoaderUtils.parseDouble(s)); double?shortQuantityOpt = row.findValue(SHORT_QUANTITY_FIELD).map(s => LoaderUtils.parseDouble(s)); if (!longQuantityOpt.HasValue && !shortQuantityOpt.HasValue) { throw new System.ArgumentException(Messages.format("Security must contain a quantity column, either '{}' or '{}' and '{}'", QUANTITY_FIELD, LONG_QUANTITY_FIELD, SHORT_QUANTITY_FIELD)); } double longQuantity = ArgChecker.notNegative(longQuantityOpt.GetValueOrDefault(0d), LONG_QUANTITY_FIELD); double shortQuantity = ArgChecker.notNegative(shortQuantityOpt.GetValueOrDefault(0d), SHORT_QUANTITY_FIELD); return(DoublesPair.of(longQuantity, shortQuantity)); }
// parse the row to a trade private static TermDepositTrade parseRow(CsvRow row, TradeInfo info, TradeCsvInfoResolver resolver) { BuySell buySell = LoaderUtils.parseBuySell(row.getValue(BUY_SELL_FIELD)); double notional = LoaderUtils.parseDouble(row.getValue(NOTIONAL_FIELD)); double fixedRate = LoaderUtils.parseDoublePercent(row.getValue(FIXED_RATE_FIELD)); Optional <TermDepositConvention> conventionOpt = row.findValue(CONVENTION_FIELD).map(s => TermDepositConvention.of(s)); Optional <Period> tenorOpt = row.findValue(TENOR_FIELD).map(s => LoaderUtils.parseTenor(s).Period); Optional <LocalDate> startDateOpt = row.findValue(START_DATE_FIELD).map(s => LoaderUtils.parseDate(s)); Optional <LocalDate> endDateOpt = row.findValue(END_DATE_FIELD).map(s => LoaderUtils.parseDate(s)); Optional <Currency> currencyOpt = row.findValue(CURRENCY_FIELD).map(s => Currency.parse(s)); Optional <DayCount> dayCountOpt = row.findValue(DAY_COUNT_FIELD).map(s => LoaderUtils.parseDayCount(s)); BusinessDayConvention dateCnv = row.findValue(DATE_ADJ_CNV_FIELD).map(s => LoaderUtils.parseBusinessDayConvention(s)).orElse(BusinessDayConventions.MODIFIED_FOLLOWING); Optional <HolidayCalendarId> dateCalOpt = row.findValue(DATE_ADJ_CAL_FIELD).map(s => HolidayCalendarId.of(s)); // use convention if available if (conventionOpt.Present) { if (currencyOpt.Present || dayCountOpt.Present) { throw new System.ArgumentException("TermDeposit trade had invalid combination of fields. When '" + CONVENTION_FIELD + "' is present these fields must not be present: " + ImmutableList.of(CURRENCY_FIELD, DAY_COUNT_FIELD)); } TermDepositConvention convention = conventionOpt.get(); // explicit dates take precedence over relative ones if (startDateOpt.Present && endDateOpt.Present) { if (tenorOpt.Present) { throw new System.ArgumentException("TermDeposit 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(TENOR_FIELD)); } LocalDate startDate = startDateOpt.get(); LocalDate endDate = endDateOpt.get(); TermDepositTrade trade = convention.toTrade(info, startDate, endDate, buySell, notional, fixedRate); return(adjustTrade(trade, dateCnv, dateCalOpt)); } // relative dates if (tenorOpt.Present && info.TradeDate.Present) { if (startDateOpt.Present || endDateOpt.Present) { throw new System.ArgumentException("TermDeposit trade had invalid combination of fields. When these fields are found " + ImmutableList.of(CONVENTION_FIELD, TENOR_FIELD, TRADE_DATE_FIELD) + " then these fields must not be present " + ImmutableList.of(START_DATE_FIELD, END_DATE_FIELD)); } LocalDate tradeDate = info.TradeDate.get(); Period periodToStart = tenorOpt.get(); TermDepositTrade trade = convention.createTrade(tradeDate, periodToStart, buySell, notional, fixedRate, resolver.ReferenceData); trade = trade.toBuilder().info(info).build(); return(adjustTrade(trade, dateCnv, dateCalOpt)); } } else if (startDateOpt.Present && endDateOpt.Present && currencyOpt.Present && dayCountOpt.Present) { LocalDate startDate = startDateOpt.get(); LocalDate endDate = endDateOpt.get(); Currency currency = currencyOpt.get(); DayCount dayCount = dayCountOpt.get(); TermDeposit.Builder builder = TermDeposit.builder().buySell(buySell).currency(currency).notional(notional).startDate(startDate).endDate(endDate).dayCount(dayCount).rate(fixedRate); TermDepositTrade trade = TermDepositTrade.of(info, builder.build()); return(adjustTrade(trade, dateCnv, dateCalOpt)); } // no match throw new System.ArgumentException("TermDeposit 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, TENOR_FIELD) + " or " + ImmutableList.of(CONVENTION_FIELD, START_DATE_FIELD, END_DATE_FIELD) + " or " + ImmutableList.of(START_DATE_FIELD, END_DATE_FIELD, CURRENCY_FIELD, DAY_COUNT_FIELD)); }
// parse the row to a trade private static FraTrade parseRow(CsvRow row, TradeInfo info, TradeCsvInfoResolver resolver) { BuySell buySell = LoaderUtils.parseBuySell(row.getValue(BUY_SELL_FIELD)); double notional = LoaderUtils.parseDouble(row.getValue(NOTIONAL_FIELD)); double fixedRate = LoaderUtils.parseDoublePercent(row.getValue(FIXED_RATE_FIELD)); Optional <FraConvention> conventionOpt = row.findValue(CONVENTION_FIELD).map(s => FraConvention.of(s)); Optional <Period> periodToStartOpt = row.findValue(PERIOD_TO_START_FIELD).map(s => LoaderUtils.parsePeriod(s)); Optional <LocalDate> startDateOpt = row.findValue(START_DATE_FIELD).map(s => LoaderUtils.parseDate(s)); Optional <LocalDate> endDateOpt = row.findValue(END_DATE_FIELD).map(s => LoaderUtils.parseDate(s)); Optional <IborIndex> indexOpt = row.findValue(INDEX_FIELD).map(s => IborIndex.of(s)); Optional <IborIndex> interpolatedOpt = row.findValue(INTERPOLATED_INDEX_FIELD).map(s => IborIndex.of(s)); Optional <DayCount> dayCountOpt = row.findValue(DAY_COUNT_FIELD).map(s => LoaderUtils.parseDayCount(s)); BusinessDayConvention dateCnv = row.findValue(DATE_ADJ_CNV_FIELD).map(s => LoaderUtils.parseBusinessDayConvention(s)).orElse(BusinessDayConventions.MODIFIED_FOLLOWING); Optional <HolidayCalendarId> dateCalOpt = row.findValue(DATE_ADJ_CAL_FIELD).map(s => HolidayCalendarId.of(s)); // not parsing paymentDate, fixingDateOffset, discounting // use convention if available if (conventionOpt.Present) { if (indexOpt.Present || interpolatedOpt.Present || dayCountOpt.Present) { throw new System.ArgumentException("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.Present && endDateOpt.Present) { if (periodToStartOpt.Present) { throw new System.ArgumentException("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, dateCnv, dateCalOpt)); } // relative dates if (periodToStartOpt.Present && info.TradeDate.Present) { if (startDateOpt.Present || endDateOpt.Present) { throw new System.ArgumentException("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.TradeDate.get(); Period periodToStart = periodToStartOpt.get(); FraTrade trade = convention.createTrade(tradeDate, periodToStart, buySell, notional, fixedRate, resolver.ReferenceData); trade = trade.toBuilder().info(info).build(); return(adjustTrade(trade, dateCnv, dateCalOpt)); } } else if (startDateOpt.Present && endDateOpt.Present && indexOpt.Present) { 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()), dateCnv, dateCalOpt)); } // no match throw new System.ArgumentException("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)); }