boolean missingDayCount = false; String legPrefix = "Leg 1 "; Optional<String> payReceiveOpt = Optional.of(getValue(row, legPrefix, DIRECTION_FIELD)); int i = 1; while (payReceiveOpt.isPresent()) { FloatingRateIndex index = parseIndex(row, legPrefix); indices.add(index); if (index != null) { if (index == null && !findValue(row, legPrefix, DAY_COUNT_FIELD).isPresent()) { missingDayCount = true; payReceiveOpt = findValue(row, legPrefix, DIRECTION_FIELD); List<SwapLeg> legs = parseLegs(row, indices, defaultFixedLegDayCount); Swap swap = Swap.of(legs); return SwapTrade.of(info, swap);
private static String getValueWithFallback(CsvRow row, String leg, String field) { return findValueWithFallback(row, leg, field) .orElseThrow(() -> new IllegalArgumentException("Swap leg must define field: '" + leg + field + "' or '" + field + "'")); }
private static RateCalculation parseRateCalculation( CsvRow row, String leg, FloatingRateIndex index, DayCount defaultFixedLegDayCount, BusinessDayAdjustment bda, Currency currency) { if (index instanceof IborIndex) { return parseIborRateCalculation(row, leg, (IborIndex) index, bda, currency); } else if (index instanceof OvernightIndex) { Optional<FloatingRateName> frnOpt = FloatingRateName.extendedEnum().find(getValue(row, leg, INDEX_FIELD)); if (frnOpt.isPresent()) { FloatingRateName frn = frnOpt.get(); if (frn.getType() == FloatingRateType.OVERNIGHT_AVERAGED) { return parseOvernightRateCalculation(row, leg, (OvernightIndex) index, OvernightAccrualMethod.AVERAGED); } } return parseOvernightRateCalculation(row, leg, (OvernightIndex) index, OvernightAccrualMethod.COMPOUNDED); } else if (index instanceof PriceIndex) { return parseInflationRateCalculation(row, leg, (PriceIndex) index, currency); } else { return parseFixedRateCalculation(row, leg, currency, defaultFixedLegDayCount); } }
private static RateCalculation parseInflationRateCalculation(CsvRow row, String leg, PriceIndex priceIndex, Currency currency) { InflationRateCalculation.Builder builder = InflationRateCalculation.builder(); // basics builder.index(priceIndex); builder.lag(parseInflationLag(findValue(row, leg, INFLATION_LAG_FIELD), currency)); builder.indexCalculationMethod(parseInflationMethod(findValue(row, leg, INFLATION_METHOD_FIELD), currency)); // optionals findValue(row, leg, INFLATION_FIRST_INDEX_VALUE_FIELD) .map(s -> LoaderUtils.parseDouble(s)) .ifPresent(v -> builder.firstIndexValue(v)); findValue(row, leg, GEARING_FIELD) .map(s -> LoaderUtils.parseDouble(s)) .ifPresent(v -> builder.gearing(ValueSchedule.of(v))); return builder.build(); }
builder.startDate(LoaderUtils.parseDate(getValueWithFallback(row, leg, START_DATE_FIELD))); builder.endDate(LoaderUtils.parseDate(getValueWithFallback(row, leg, END_DATE_FIELD))); builder.frequency(Frequency.parse(getValue(row, leg, FREQUENCY_FIELD))); BusinessDayAdjustment dateAdj = parseBusinessDayAdjustment(row, leg, DATE_ADJ_CNV_FIELD, DATE_ADJ_CAL_FIELD) .orElse(BusinessDayAdjustment.NONE); Optional<BusinessDayAdjustment> startDateAdj = parseBusinessDayAdjustment(row, leg, START_DATE_CNV_FIELD, START_DATE_CAL_FIELD); Optional<BusinessDayAdjustment> endDateAdj = parseBusinessDayAdjustment(row, leg, END_DATE_CNV_FIELD, END_DATE_CAL_FIELD); builder.businessDayAdjustment(dateAdj); if (startDateAdj.isPresent() && !startDateAdj.get().equals(dateAdj)) { builder.stubConvention(findValueWithFallback(row, leg, STUB_CONVENTION_FIELD) .map(s -> StubConvention.of(s)) .orElse(StubConvention.SMART_INITIAL)); findValue(row, leg, ROLL_CONVENTION_FIELD) .map(s -> LoaderUtils.parseRollConvention(s)) .ifPresent(v -> builder.rollConvention(v)); findValue(row, leg, FIRST_REGULAR_START_DATE_FIELD) .map(s -> LoaderUtils.parseDate(s)) .ifPresent(v -> builder.firstRegularStartDate(v)); findValue(row, leg, LAST_REGULAR_END_DATE_FIELD) .map(s -> LoaderUtils.parseDate(s)) .ifPresent(v -> builder.lastRegularEndDate(v)); parseAdjustableDate( row, leg, OVERRIDE_START_DATE_FIELD, OVERRIDE_START_DATE_CNV_FIELD, OVERRIDE_START_DATE_CAL_FIELD) .ifPresent(d -> builder.overrideStartDate(d));
private static RateCalculationSwapLeg parseLeg( CsvRow row, String leg, FloatingRateIndex index, DayCount defaultFixedLegDayCount) { PayReceive payReceive = LoaderUtils.parsePayReceive(getValue(row, leg, DIRECTION_FIELD)); PeriodicSchedule accrualSch = parseAccrualSchedule(row, leg); PaymentSchedule paymentSch = parsePaymentSchedule(row, leg, accrualSch.getFrequency()); NotionalSchedule notionalSch = parseNotionalSchedule(row, leg); RateCalculation calc = parseRateCalculation( row, leg, index, defaultFixedLegDayCount, accrualSch.getBusinessDayAdjustment(), notionalSch.getCurrency()); return RateCalculationSwapLeg.builder() .payReceive(payReceive) .accrualSchedule(accrualSch) .paymentSchedule(paymentSch) .notionalSchedule(notionalSch) .calculation(calc) .build(); }
Optional<Frequency> resetFrequencyOpt = findValue(row, leg, RESET_FREQUENCY_FIELD).map(v -> Frequency.parse(v)); IborRateResetMethod resetMethod = findValue(row, leg, RESET_METHOD_FIELD) .map(v -> IborRateResetMethod.of(v)) .orElse(IborRateResetMethod.WEIGHTED); BusinessDayAdjustment resetDateAdj = parseBusinessDayAdjustment(row, leg, RESET_DATE_CNV_FIELD, RESET_DATE_CAL_FIELD).orElse(bda); resetFrequencyOpt.ifPresent(freq -> builder.resetPeriods(ResetSchedule.builder() .resetFrequency(freq) findValue(row, leg, DAY_COUNT_FIELD) .map(s -> LoaderUtils.parseDayCount(s)) .ifPresent(v -> builder.dayCount(v)); findValue(row, leg, FIXING_RELATIVE_TO_FIELD) .map(s -> FixingRelativeTo.of(s)) .ifPresent(v -> builder.fixingRelativeTo(v)); Optional<DaysAdjustment> fixingAdjOpt = parseDaysAdjustment( row, leg, FIXING_OFFSET_ADJ_CAL_FIELD); fixingAdjOpt.ifPresent(v -> builder.fixingDateOffset(v)); findValue(row, leg, NEGATIVE_RATE_METHOD_FIELD).map(s -> NegativeRateMethod.of(s)) .ifPresent(v -> builder.negativeRateMethod(v)); findValue(row, leg, FIRST_RATE_FIELD) .map(s -> LoaderUtils.parseDoublePercent(s)) .ifPresent(v -> builder.firstRate(v)); findValue(row, leg, GEARING_FIELD) .map(s -> LoaderUtils.parseDouble(s)) .ifPresent(v -> builder.gearing(ValueSchedule.of(v)));
private static NotionalSchedule parseNotionalSchedule(CsvRow row, String leg) { NotionalSchedule.Builder builder = NotionalSchedule.builder(); Currency currency = Currency.of(getValueWithFallback(row, leg, CURRENCY_FIELD)); builder.currency(currency); builder.amount(ValueSchedule.of(LoaderUtils.parseDouble(getValueWithFallback(row, leg, NOTIONAL_FIELD)))); Optional<FxIndex> fxIndexOpt = findValue(row, leg, FX_RESET_INDEX_FIELD).map(s -> FxIndex.of(s)); Optional<Currency> notionalCurrencyOpt = findValue(row, leg, NOTIONAL_CURRENCY_FIELD).map(s -> Currency.of(s)); Optional<FxResetFixingRelativeTo> fxFixingRelativeToOpt = findValue(row, leg, FX_RESET_RELATIVE_TO_FIELD) .map(s -> FxResetFixingRelativeTo.of(s)); Optional<DaysAdjustment> fxResetAdjOpt = parseDaysAdjustment( row, leg, findValue(row, leg, NOTIONAL_INITIAL_EXCHANGE_FIELD) .map(s -> LoaderUtils.parseBoolean(s)) .ifPresent(v -> builder.initialExchange(v)); findValue(row, leg, NOTIONAL_INTERMEDIATE_EXCHANGE_FIELD) .map(s -> LoaderUtils.parseBoolean(s)) .ifPresent(v -> builder.intermediateExchange(v)); findValue(row, leg, NOTIONAL_FINAL_EXCHANGE_FIELD) .map(s -> LoaderUtils.parseBoolean(s)) .ifPresent(v -> builder.finalExchange(v));
private static FloatingRateIndex parseIndex(CsvRow row, String leg) { Optional<String> fixedRateOpt = findValue(row, leg, FIXED_RATE_FIELD); Optional<String> indexOpt = findValue(row, leg, INDEX_FIELD); if (fixedRateOpt.isPresent()) { if (indexOpt.isPresent()) { throw new IllegalArgumentException( "Swap leg must not define both '" + leg + FIXED_RATE_FIELD + "' and '" + leg + INDEX_FIELD + "'"); } return null; } if (!indexOpt.isPresent()) { throw new IllegalArgumentException( "Swap leg must define either '" + leg + FIXED_RATE_FIELD + "' or '" + leg + INDEX_FIELD + "'"); } // use FloatingRateName to identify Ibor vs other String indexStr = indexOpt.get(); FloatingRateName frn = FloatingRateName.parse(indexStr); if (frn.getType() == FloatingRateType.IBOR) { // re-parse Ibor using tenor, which ensures tenor picked up from indexStr if present Frequency freq = Frequency.parse(getValue(row, leg, FREQUENCY_FIELD)); Tenor iborTenor = freq.isTerm() ? frn.getDefaultTenor() : Tenor.of(freq.getPeriod()); return FloatingRateIndex.parse(indexStr, iborTenor); } return frn.toFloatingRateIndex(); }
private static Optional<DaysAdjustment> parseDaysAdjustment( CsvRow row, String leg, String daysField, String daysCalField, String cnvField, String calField) { Optional<Integer> daysOpt = findValue(row, leg, daysField) .map(s -> Integer.valueOf(s)); HolidayCalendarId cal = findValue(row, leg, daysCalField) .map(s -> HolidayCalendarId.of(s)) .orElse(HolidayCalendarIds.NO_HOLIDAYS); BusinessDayAdjustment bda = parseBusinessDayAdjustment(row, leg, cnvField, calField) .orElse(BusinessDayAdjustment.NONE); if (!daysOpt.isPresent()) { return Optional.empty(); } return Optional.of(DaysAdjustment.builder() .days(daysOpt.get()) .calendar(cal) .adjustment(bda) .build()); }
private static PaymentSchedule parsePaymentSchedule(CsvRow row, String leg, Frequency accrualFrequency) { PaymentSchedule.Builder builder = PaymentSchedule.builder(); // basics builder.paymentFrequency(findValue(row, leg, PAYMENT_FREQUENCY_FIELD) .map(s -> Frequency.parse(s)) .orElse(accrualFrequency)); Optional<DaysAdjustment> offsetOpt = parseDaysAdjustment( row, leg, PAYMENT_OFFSET_DAYS_FIELD, PAYMENT_OFFSET_CAL_FIELD, PAYMENT_OFFSET_ADJ_CNV_FIELD, PAYMENT_OFFSET_ADJ_CAL_FIELD); builder.paymentDateOffset(offsetOpt.orElse(DaysAdjustment.NONE)); // optionals findValue(row, leg, PAYMENT_RELATIVE_TO_FIELD) .map(s -> PaymentRelativeTo.of(s)) .ifPresent(v -> builder.paymentRelativeTo(v)); findValue(row, leg, COMPOUNDING_METHOD_FIELD) .map(s -> CompoundingMethod.of(s)) .ifPresent(v -> builder.compoundingMethod(v)); findValue(row, leg, PAYMENT_FIRST_REGULAR_START_DATE_FIELD) .map(s -> LoaderUtils.parseDate(s)) .ifPresent(v -> builder.firstRegularStartDate(v)); findValue(row, leg, PAYMENT_LAST_REGULAR_END_DATE_FIELD) .map(s -> LoaderUtils.parseDate(s)) .ifPresent(v -> builder.lastRegularEndDate(v)); return builder.build(); }
private static String getValue(CsvRow row, String leg, String field) { return findValue(row, leg, field) .orElseThrow(() -> new IllegalArgumentException("Swap leg must define field: '" + leg + field + "'")); }
private static SwapTrade parseRow(CsvRow row, TradeInfo info, TradeCsvInfoResolver resolver) { Optional<String> conventionOpt = row.findValue(CONVENTION_FIELD); if (conventionOpt.isPresent()) { return parseWithConvention(row, info, resolver, conventionOpt.get()); } else { Optional<String> payReceive = row.findValue("Leg 1 " + DIRECTION_FIELD); if (payReceive.isPresent()) { return FullSwapTradeCsvLoader.parse(row, info); } throw new IllegalArgumentException( "Swap trade had invalid combination of fields. Must include either '" + CONVENTION_FIELD + "' or '" + "Leg 1 " + DIRECTION_FIELD + "'"); } }
double fixedRate = LoaderUtils.parseDoublePercent(getValue(row, leg, FIXED_RATE_FIELD)); DayCount dayCount = findValue(row, leg, DAY_COUNT_FIELD) .map(s -> LoaderUtils.parseDayCount(s)).orElse(defaultFixedLegDayCount); if (dayCount == null) { builder.rate(ValueSchedule.of(fixedRate)); Optional<Double> initialStubRateOpt = findValue(row, leg, INITIAL_STUB_RATE_FIELD) .map(s -> LoaderUtils.parseDoublePercent(s)); Optional<Double> initialStubAmountOpt = findValue(row, leg, INITIAL_STUB_AMOUNT_FIELD) .map(s -> LoaderUtils.parseDouble(s)); if (initialStubRateOpt.isPresent() && initialStubAmountOpt.isPresent()) { FixedRateStubCalculation.ofKnownAmount(CurrencyAmount.of(currency, v)))); Optional<Double> finalStubRateOpt = findValue(row, leg, FINAL_STUB_RATE_FIELD) .map(s -> LoaderUtils.parseDoublePercent(s)); Optional<Double> finalStubAmountOpt = findValue(row, leg, FINAL_STUB_AMOUNT_FIELD) .map(s -> LoaderUtils.parseDouble(s)); if (finalStubRateOpt.isPresent() && finalStubAmountOpt.isPresent()) {
private static Optional<BusinessDayAdjustment> parseBusinessDayAdjustment( CsvRow row, String leg, String cnvField, String calField) { BusinessDayConvention dateCnv = findValue(row, leg, cnvField) .map(s -> LoaderUtils.parseBusinessDayConvention(s)) .orElse(BusinessDayConventions.MODIFIED_FOLLOWING); return findValue(row, leg, calField) .map(s -> HolidayCalendarId.of(s)) .map(cal -> BusinessDayAdjustment.of(dateCnv, cal)); }
private static Optional<AdjustableDate> parseAdjustableDate( CsvRow row, String leg, String dateField, String cnvField, String calField) { Optional<LocalDate> dateOpt = findValue(row, leg, dateField).map(s -> LoaderUtils.parseDate(s)); if (!dateOpt.isPresent()) { return Optional.empty(); } BusinessDayConvention dateCnv = findValue(row, leg, cnvField) .map(s -> LoaderUtils.parseBusinessDayConvention(s)) .orElse(BusinessDayConventions.MODIFIED_FOLLOWING); HolidayCalendarId cal = findValue(row, leg, calField) .map(s -> HolidayCalendarId.of(s)) .orElse(HolidayCalendarIds.NO_HOLIDAYS); return Optional.of(AdjustableDate.of(dateOpt.get(), BusinessDayAdjustment.of(dateCnv, cal))); }
String interpolatedField) { Optional<Double> stubRateOpt = findValue(row, leg, rateField).map(s -> LoaderUtils.parseDoublePercent(s)); Optional<Double> stubAmountOpt = findValue(row, leg, amountField).map(s -> LoaderUtils.parseDouble(s)); Optional<IborIndex> stubIndexOpt = findValue(row, leg, indexField).map(s -> IborIndex.of(s)); Optional<IborIndex> stubIndex2Opt = findValue(row, leg, interpolatedField).map(s -> IborIndex.of(s)); if (stubRateOpt.isPresent() && !stubAmountOpt.isPresent() && !stubIndexOpt.isPresent() && !stubIndex2Opt.isPresent()) { return Optional.of(IborRateStubCalculation.ofFixedRate(stubRateOpt.get()));
private static RateCalculation parseOvernightRateCalculation( CsvRow row, String leg, OvernightIndex overnightIndex, OvernightAccrualMethod accrualMethod) { OvernightRateCalculation.Builder builder = OvernightRateCalculation.builder(); // basics builder.index(overnightIndex); builder.accrualMethod(findValue(row, leg, ACCRUAL_METHOD_FIELD) .map(s -> OvernightAccrualMethod.of(s)) .orElse(accrualMethod)); // optionals findValue(row, leg, DAY_COUNT_FIELD) .map(s -> LoaderUtils.parseDayCount(s)) .ifPresent(v -> builder.dayCount(v)); findValue(row, leg, RATE_CUT_OFF_DAYS_FIELD) .map(s -> Integer.valueOf(s)) .ifPresent(v -> builder.rateCutOffDays(v)); findValue(row, leg, NEGATIVE_RATE_METHOD_FIELD).map(s -> NegativeRateMethod.of(s)) .ifPresent(v -> builder.negativeRateMethod(v)); findValue(row, leg, GEARING_FIELD) .map(s -> LoaderUtils.parseDouble(s)) .ifPresent(v -> builder.gearing(ValueSchedule.of(v))); findValue(row, leg, SPREAD_FIELD) .map(s -> LoaderUtils.parseDoublePercent(s)) .ifPresent(v -> builder.spread(ValueSchedule.of(v))); return builder.build(); }