/** * Parses the FpML document extracting the trades. * <p> * This parses the specified FpML root element, using the map of references. * The FpML specification uses references to link one part of the XML to another. * For example, if one part of the XML has {@code <foo id="fooId">}, the references * map will contain an entry mapping "fooId" to the parsed element {@code <foo>}. * * @param fpmlRootEl the source of the FpML XML document * @param references the map of id/href to referenced element * @return the parsed trades * @throws RuntimeException if a parse error occurred */ public List<Trade> parseTrades( XmlElement fpmlRootEl, Map<String, XmlElement> references) { FpmlDocument document = new FpmlDocument(fpmlRootEl, references, ourPartySelector, tradeInfoParser, refData); List<XmlElement> tradeEls = document.getFpmlRoot().getChildren("trade"); ImmutableList.Builder<Trade> builder = ImmutableList.builder(); for (XmlElement tradeEl : tradeEls) { builder.add(parseTrade(document, tradeEl)); } return builder.build(); }
/** * Converts an FpML 'AdjustableDate' or 'AdjustableDate2' to an {@code AdjustableDate}. * * @param baseEl the FpML adjustable date element * @return the adjustable date * @throws RuntimeException if unable to parse */ public AdjustableDate parseAdjustableDate(XmlElement baseEl) { // FpML content: ('unadjustedDate', 'dateAdjustments', 'adjustedDate?') Optional<XmlElement> unadjOptEl = baseEl.findChild("unadjustedDate"); if (unadjOptEl.isPresent()) { LocalDate unadjustedDate = parseDate(unadjOptEl.get()); Optional<XmlElement> adjustmentOptEl = baseEl.findChild("dateAdjustments"); Optional<XmlElement> adjustmentRefOptEl = baseEl.findChild("dateAdjustmentsReference"); if (!adjustmentOptEl.isPresent() && !adjustmentRefOptEl.isPresent()) { return AdjustableDate.of(unadjustedDate); } XmlElement adjustmentEl = adjustmentRefOptEl.isPresent() ? lookupReference(adjustmentRefOptEl.get()) : adjustmentOptEl.get(); BusinessDayAdjustment adjustment = parseBusinessDayAdjustments(adjustmentEl); return AdjustableDate.of(unadjustedDate, adjustment); } LocalDate adjustedDate = parseDate(baseEl.getChild("adjustedDate")); return AdjustableDate.of(adjustedDate); }
@Override public Trade parseTrade(FpmlDocument document, XmlElement tradeEl) { document.parseTradeInfo(tradeEl); // expected to throw an exception throw new UnsupportedOperationException(); }
/** * Converts an FpML 'DayCountFraction' to a {@code DayCount}. * * @param baseEl the FpML day count element to parse * @return the day count * @throws RuntimeException if unable to parse */ public DayCount parseDayCountFraction(XmlElement baseEl) { validateScheme( baseEl, "dayCountFractionScheme", "http://www.fpml.org/coding-scheme/day-count-fraction", // standard form "http://www.fpml.org/spec/2004/day-count-fraction"); // seen in the wild return convertDayCount(baseEl.getContent()); }
private void checkStubForOvernightIndex(XmlElement baseEl, FpmlDocument document, OvernightIndex index) { document.validateNotPresent(baseEl, "stubAmount"); document.validateNotPresent(baseEl, "stubRate"); List<XmlElement> indicesEls = baseEl.getChildren("floatingRate"); if (indicesEls.size() == 1) { XmlElement indexEl = indicesEls.get(0); document.validateNotPresent(indexEl, "floatingRateMultiplierSchedule"); document.validateNotPresent(indexEl, "spreadSchedule"); document.validateNotPresent(indexEl, "rateTreatment"); document.validateNotPresent(indexEl, "capRateSchedule"); document.validateNotPresent(indexEl, "floorRateSchedule"); Index parsed = document.parseIndex(indexEl); if (parsed.equals(index)) { return; } throw new FpmlParseException("OvernightIndex swap cannot have a different index in the stub: " + baseEl); } throw new FpmlParseException("Unknown stub structure: " + baseEl); }
private IborRateStubCalculation parseStubCalculation(XmlElement baseEl, FpmlDocument document) { Optional<XmlElement> rateOptEl = baseEl.findChild("stubRate"); if (rateOptEl.isPresent()) { return IborRateStubCalculation.ofFixedRate(document.parseDecimal(rateOptEl.get())); return IborRateStubCalculation.ofKnownAmount(document.parseCurrencyAmount(amountOptEl.get())); document.validateNotPresent(indexEl, "floatingRateMultiplierSchedule"); document.validateNotPresent(indexEl, "spreadSchedule"); document.validateNotPresent(indexEl, "rateTreatment"); document.validateNotPresent(indexEl, "capRateSchedule"); document.validateNotPresent(indexEl, "floorRateSchedule"); return IborRateStubCalculation.ofIborRate((IborIndex) document.parseIndex(indexEl)); } else if (indicesEls.size() == 2) { XmlElement index1El = indicesEls.get(0); document.validateNotPresent(index1El, "floatingRateMultiplierSchedule"); document.validateNotPresent(index1El, "spreadSchedule"); document.validateNotPresent(index1El, "rateTreatment"); document.validateNotPresent(index1El, "capRateSchedule"); document.validateNotPresent(index1El, "floorRateSchedule"); XmlElement index2El = indicesEls.get(1); document.validateNotPresent(index2El, "floatingRateMultiplierSchedule"); document.validateNotPresent(index2El, "spreadSchedule"); document.validateNotPresent(index2El, "rateTreatment"); document.validateNotPresent(index2El, "capRateSchedule"); document.validateNotPresent(index2El, "floorRateSchedule"); return IborRateStubCalculation.ofIborInterpolatedRate( (IborIndex) document.parseIndex(index1El), (IborIndex) document.parseIndex(index2El));
XmlElement generalTermsEl = cdsEl.getChild("generalTerms"); XmlElement feeLegEl = cdsEl.getChild("feeLeg"); document.validateNotPresent(generalTermsEl, "basketReferenceInformation"); document.validateNotPresent(feeLegEl, "singlePayment"); BuySell buySell = document.parseBuyerSeller(generalTermsEl, tradeInfoBuilder); AdjustableDate effectiveDate = document.parseAdjustableDate(generalTermsEl.getChild("effectiveDate")); AdjustableDate terminationDate = document.parseAdjustableDate(generalTermsEl.getChild("scheduledTerminationDate")); BusinessDayAdjustment bda = generalTermsEl.findChild("dateAdjustments") .map(el -> document.parseBusinessDayAdjustments(el)) .orElse(BusinessDayAdjustment.NONE); PeriodicSchedule.Builder scheduleBuilder = PeriodicSchedule.builder() if (initialPaymentOptEl.isPresent()) { XmlElement initialPaymentEl = initialPaymentOptEl.get(); PayReceive payRec = document.parsePayerReceiver(initialPaymentEl, tradeInfoBuilder); CurrencyAmount amount = document.parseCurrencyAmount(initialPaymentEl.getChild("paymentAmount")); LocalDate date = initialPaymentEl.findChild("adjustablePaymentDate") .map(el -> document.parseDate(el)) .orElse(effectiveDate.getUnadjusted()); AdjustableDate adjDate = AdjustableDate.of(date, bda); .map(el -> document.parseFrequency(el)) .orElse(Frequency.P3M)); periodicPaymentEl.findChild("firstPaymentDate") .ifPresent(el -> scheduleBuilder.firstRegularStartDate(document.parseDate(el))); periodicPaymentEl.findChild("firstPeriodStartDate") .ifPresent(el -> scheduleBuilder.overrideStartDate(AdjustableDate.of(document.parseDate(el)))); periodicPaymentEl.findChild("lastRegularPaymentDate")
public void document() { XmlElement tradeDateEl = XmlElement.ofContent("tradeDate", "2000-06-30"); XmlElement tradeHeaderEl = XmlElement.ofChildren("tradeHeader", ImmutableList.of(tradeDateEl)); XmlElement tradeEl = XmlElement.ofChildren("trade", ImmutableMap.of("href", "foo"), ImmutableList.of(tradeHeaderEl)); XmlElement rootEl = XmlElement.ofChildren("dataDocument", ImmutableList.of(tradeEl)); FpmlDocument test = new FpmlDocument(rootEl, ImmutableMap.of(), FpmlPartySelector.any(), FpmlTradeInfoParserPlugin.standard(), REF_DATA); assertEquals(test.getFpmlRoot(), rootEl); assertEquals(test.getParties(), ImmutableListMultimap.of()); assertEquals(test.getReferences(), ImmutableMap.of()); assertEquals(test.getOurPartyHrefIds(), ImmutableList.of()); assertThrows(() -> test.lookupReference(tradeEl), FpmlParseException.class, ".*reference not found.*"); assertThrows(() -> test.validateNotPresent(tradeEl, "tradeHeader"), FpmlParseException.class, ".*tradeHeader.*"); }
TradeInfoBuilder tradeInfoBuilder = document.parseTradeInfo(tradeEl); XmlElement fraEl = tradeEl.getChild("fra"); Fra.Builder fraBuilder = Fra.builder(); fraBuilder.buySell(document.parseBuyerSeller(fraEl, tradeInfoBuilder)); fraBuilder.startDate(document.parseDate(fraEl.getChild("adjustedEffectiveDate"))); fraBuilder.endDate(document.parseDate(fraEl.getChild("adjustedTerminationDate"))); fraBuilder.paymentDate(document.parseAdjustableDate(fraEl.getChild("paymentDate"))); fraBuilder.fixingDateOffset(document.parseRelativeDateOffsetDays(fraEl.getChild("fixingDateOffset"))); fraBuilder.dayCount(document.parseDayCountFraction(fraEl.getChild("dayCountFraction"))); CurrencyAmount notional = document.parseCurrencyAmount(fraEl.getChild("notional")); fraBuilder.currency(notional.getCurrency()); fraBuilder.notional(notional.getAmount()); fraBuilder.fixedRate(document.parseDecimal(fraEl.getChild("fixedRate"))); List<Index> indexes = document.parseIndexes(fraEl); switch (indexes.size()) { case 1:
TradeInfoBuilder tradeInfoBuilder = document.parseTradeInfo(tradeEl); XmlElement termEl = tradeEl.getChild("termDeposit"); document.validateNotPresent(termEl, "features"); document.validateNotPresent(termEl, "payment"); TermDeposit.Builder termBuilder = TermDeposit.builder(); PayReceive payReceive = document.parsePayerReceiver(termEl, tradeInfoBuilder); termBuilder.buySell(BuySell.ofBuy(payReceive.isPay())); termBuilder.startDate(document.parseDate(termEl.getChild("startDate"))); termBuilder.endDate(document.parseDate(termEl.getChild("maturityDate"))); CurrencyAmount principal = document.parseCurrencyAmount(termEl.getChild("principal")); termBuilder.currency(principal.getCurrency()); termBuilder.notional(principal.getAmount()); termBuilder.rate(document.parseDecimal(termEl.getChild("fixedRate"))); termBuilder.dayCount(document.parseDayCountFraction(termEl.getChild("dayCountFraction")));
document.validateNotPresent(floatingEl, "rateTreatment"); document.validateNotPresent(floatingEl, "capRateSchedule"); document.validateNotPresent(floatingEl, "floorRateSchedule"); Index index = document.parseIndex(floatingEl); if (index instanceof IborIndex) { IborRateCalculation.Builder iborRateBuilder = IborRateCalculation.builder(); iborRateBuilder.dayCount(document.parseDayCountFraction(calcEl.getChild("dayCountFraction"))); iborRateBuilder.index((IborIndex) document.parseIndex(floatingEl)); document.validateNotPresent(el, "type"); iborRateBuilder.spread(parseSchedule(el, document)); }); iborRateBuilder.firstRegularRate(document.parseDecimal(el)); }); document.validateNotPresent(resetDatesEl, "initialFixingDate"); document.validateNotPresent(resetDatesEl, "rateCutOffDaysOffset"); resetDatesEl.findChild("resetRelativeTo").ifPresent(el -> { iborRateBuilder.fixingRelativeTo(parseResetRelativeTo(el)); }); iborRateBuilder.fixingDateOffset(document.parseRelativeDateOffsetDays(resetDatesEl.getChild("fixingDates"))); Frequency resetFreq = document.parseFrequency(resetDatesEl.getChild("resetFrequency")); if (!accrualSchedule.getFrequency().equals(resetFreq)) { ResetSchedule.Builder resetScheduleBuilder = ResetSchedule.builder();
XmlElement relativeToEl = lookupReference(baseEl.getChild("dateRelativeTo")); LocalDate baseDate; if (relativeToEl.hasContent()) { baseDate = parseDate(relativeToEl); } else if (relativeToEl.getName().contains("relative")) { baseDate = parseAdjustedRelativeDateOffset(relativeToEl).getUnadjusted(); } else { throw new FpmlParseException( "Unable to resolve 'dateRelativeTo' to a date: " + baseEl.getChild("dateRelativeTo").getAttribute(HREF)); Period period = parsePeriod(baseEl); Optional<XmlElement> dayTypeEl = baseEl.findChild("dayType"); boolean calendarDays = period.isZero() || (dayTypeEl.isPresent() && dayTypeEl.get().getContent().equals("Calendar")); BusinessDayAdjustment bda1 = parseBusinessDayAdjustments(baseEl); BusinessDayAdjustment bda2 = baseEl.findChild("relativeDateAdjustments") .map(el -> parseBusinessDayAdjustments(el)) .orElse(bda1);
document.validateNotPresent(legEl, "currency1ValueDate"); document.validateNotPresent(legEl, "currency2ValueDate"); document.validateNotPresent(legEl, "nonDeliverableSettlement"); XmlElement curr1El = legEl.getChild("exchangedCurrency1"); XmlElement curr2El = legEl.getChild("exchangedCurrency2"); PayReceive curr1PayReceive = document.parsePayerReceiver(curr1El, tradeInfoBuilder); PayReceive curr2PayReceive = document.parsePayerReceiver(curr2El, tradeInfoBuilder); if (curr1PayReceive == curr2PayReceive) { throw new FpmlParseException("FX single leg currencies must not have same Pay/Receive direction"); CurrencyAmount curr1Amount = document.parseCurrencyAmount(curr1El.getChild("paymentAmount")); CurrencyAmount curr2Amount = document.parseCurrencyAmount(curr2El.getChild("paymentAmount")); if (curr1PayReceive == PayReceive.PAY) { curr1Amount = curr1Amount.negative(); LocalDate valueDate = document.parseDate(legEl.getChild("valueDate"));
document.validateNotPresent(inflationEl, "spreadSchedule"); document.validateNotPresent(inflationEl, "rateTreatment"); document.validateNotPresent(inflationEl, "capRateSchedule"); document.validateNotPresent(inflationEl, "floorRateSchedule"); document.validateNotPresent(legEl, "stubCalculationPeriodAmount"); // TODO: parse fixed stub rate InflationRateCalculation.Builder builder = InflationRateCalculation.builder(); builder.index(document.parsePriceIndex(inflationEl)); builder.lag(document.parsePeriod(inflationEl.getChild("inflationLag"))); builder.firstIndexValue(document.parseDecimal(el)); });
document.validateNotPresent(legEl, "resetDates"); FixedRateCalculation.Builder fixedRateBuilder = FixedRateCalculation.builder(); calcEl.findChild("futureValueNotional").ifPresent(fvnEl -> { FutureValueNotional notional = FutureValueNotional.builder() .value(document.parseDecimal(fvnEl.getChild("amount"))) .dayCountDays(fvnEl.findChild("calculationPeriodNumberOfDays") .map(str -> (int) document.parseDecimal(str)) .orElse(null)) .valueDate(fvnEl.findChild("valueDate").map(str -> document.parseDate(str)).orElse(null)) .build(); fixedRateBuilder.futureValueNotional(notional); }); fixedRateBuilder.rate(parseSchedule(fixedEl, document)); fixedRateBuilder.dayCount(document.parseDayCountFraction(calcEl.getChild("dayCountFraction")));
@Override public Trade parseTrade(FpmlDocument document, XmlElement tradeEl) { // supported elements: // 'payment/payerPartyReference' // 'payment/receiverPartyReference' // 'payment/paymentAmount' // 'payment/paymentDate?' // ignored elements: // 'payment/payerAccountReference?' // 'payment/receiverAccountReference?' // 'payment/paymentType?' // 'payment/settlementInformation?' // 'payment/discountFactor?' // 'payment/presentValueAmount?' TradeInfoBuilder tradeInfoBuilder = document.parseTradeInfo(tradeEl); XmlElement bulletEl = tradeEl.getChild("bulletPayment"); XmlElement paymentEl = bulletEl.getChild("payment"); BulletPayment.Builder bulletBuilder = BulletPayment.builder(); // pay/receive and counterparty bulletBuilder.payReceive(document.parsePayerReceiver(paymentEl, tradeInfoBuilder)); // payment date bulletBuilder.date(document.parseAdjustableDate(paymentEl.getChild("paymentDate"))); // amount bulletBuilder.value(document.parseCurrencyAmount(paymentEl.getChild("paymentAmount"))); return BulletPaymentTrade.builder() .info(tradeInfoBuilder.build()) .product(bulletBuilder.build()) .build(); }
TradeInfoBuilder tradeInfoBuilder = document.parseTradeInfo(tradeEl); XmlElement curr1El = fxEl.getChild("exchangedCurrency1"); XmlElement curr2El = fxEl.getChild("exchangedCurrency2"); PayReceive curr1PayReceive = document.parsePayerReceiver(curr1El, tradeInfoBuilder); PayReceive curr2PayReceive = document.parsePayerReceiver(curr2El, tradeInfoBuilder); if (curr1PayReceive == curr2PayReceive) { throw new FpmlParseException("FX single leg currencies must not have same Pay/Receive direction"); CurrencyAmount curr1Amount = document.parseCurrencyAmount(curr1El.getChild("paymentAmount")); CurrencyAmount curr2Amount = document.parseCurrencyAmount(curr2El.getChild("paymentAmount")); if (curr1PayReceive == PayReceive.PAY) { curr1Amount = curr1Amount.negative(); LocalDate currency1Date = document.parseDate( fxEl.findChild("currency1ValueDate").orElseGet(() -> fxEl.getChild("valueDate"))); LocalDate currency2Date = document.parseDate( fxEl.findChild("currency2ValueDate").orElseGet(() -> fxEl.getChild("valueDate")));
public void documentFrequency() { XmlElement tradeDateEl = XmlElement.ofContent("tradeDate", "2000-06-30"); XmlElement tradeHeaderEl = XmlElement.ofChildren("tradeHeader", ImmutableList.of(tradeDateEl)); XmlElement tradeEl = XmlElement.ofChildren("trade", ImmutableMap.of("href", "foo"), ImmutableList.of(tradeHeaderEl)); XmlElement rootEl = XmlElement.ofChildren("dataDocument", ImmutableList.of(tradeEl)); FpmlDocument test = new FpmlDocument(rootEl, ImmutableMap.of(), FpmlPartySelector.any(), FpmlTradeInfoParserPlugin.standard(), REF_DATA); assertEquals(test.convertFrequency("1", "M"), Frequency.P1M); assertEquals(test.convertFrequency("12", "M"), Frequency.P12M); assertEquals(test.convertFrequency("1", "Y"), Frequency.P12M); assertEquals(test.convertFrequency("13", "Y"), Frequency.of(Period.ofYears(13))); }
public void documentTenor() { XmlElement tradeDateEl = XmlElement.ofContent("tradeDate", "2000-06-30"); XmlElement tradeHeaderEl = XmlElement.ofChildren("tradeHeader", ImmutableList.of(tradeDateEl)); XmlElement tradeEl = XmlElement.ofChildren("trade", ImmutableMap.of("href", "foo"), ImmutableList.of(tradeHeaderEl)); XmlElement rootEl = XmlElement.ofChildren("dataDocument", ImmutableList.of(tradeEl)); FpmlDocument test = new FpmlDocument(rootEl, ImmutableMap.of(), FpmlPartySelector.any(), FpmlTradeInfoParserPlugin.standard(), REF_DATA); assertEquals(test.convertIndexTenor("1", "M"), Tenor.TENOR_1M); assertEquals(test.convertIndexTenor("12", "M"), Tenor.TENOR_12M); assertEquals(test.convertIndexTenor("1", "Y"), Tenor.TENOR_12M); assertEquals(test.convertIndexTenor("13", "Y"), Tenor.of(Period.ofYears(13))); }
if (knownAmountOptEl.isPresent()) { XmlElement knownAmountEl = knownAmountOptEl.get(); document.validateNotPresent(legEl, "stubCalculationPeriodAmount"); document.validateNotPresent(legEl, "resetDates"); PayReceive payReceive = document.parsePayerReceiver(legEl, tradeInfoBuilder); ValueSchedule amountSchedule = parseSchedule(knownAmountEl, document); .paymentSchedule(paymentSchedule) .amount(amountSchedule) .currency(document.parseCurrency(knownAmountEl.getChild("currency"))) .build()); } else { document.validateNotPresent(calcEl, "fxLinkedNotionalSchedule"); PayReceive payReceive = document.parsePayerReceiver(legEl, tradeInfoBuilder); NotionalSchedule notionalSchedule = parseSwapNotionalSchedule(legEl, calcEl, document); RateCalculation calculation = parseSwapCalculation(legEl, calcEl, accrualSchedule, document);