// swap USD standard conventions- TODO: replace by a template when available private static Swap swapUsd(LocalDate start, LocalDate end, PayReceive payReceive, NotionalSchedule notional, double fixedRate) { SwapLeg fixedLeg = CurveGammaCalculatorTest.fixedLeg(start, end, Frequency.P6M, payReceive, notional, fixedRate, StubConvention.SHORT_INITIAL); SwapLeg iborLeg = CurveGammaCalculatorTest.iborLeg(start, end, USD_LIBOR_3M, (payReceive == PAY) ? RECEIVE : PAY, notional, StubConvention.SHORT_INITIAL); return(Swap.of(fixedLeg, iborLeg)); }
//------------------------------------------------------------------------- public Trade parseTrade(FpmlDocument document, XmlElement tradeEl) { // supported elements: // 'exchangedCurrency1/paymentAmount' // 'exchangedCurrency2/paymentAmount' // 'valueDate' // 'currency1ValueDate' // 'currency2ValueDate' // 'nonDeliverableSettlement?' // ignored elements: // 'dealtCurrency?' // 'exchangeRate' XmlElement fxEl = tradeEl.getChild("fxSingleLeg"); // amounts TradeInfoBuilder tradeInfoBuilder = document.parseTradeInfo(tradeEl); XmlElement curr1El = fxEl.getChild("exchangedCurrency1"); XmlElement curr2El = fxEl.getChild("exchangedCurrency2"); // pay/receive and counterparty 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"); } // amount CurrencyAmount curr1Amount = document.parseCurrencyAmount(curr1El.getChild("paymentAmount")); CurrencyAmount curr2Amount = document.parseCurrencyAmount(curr2El.getChild("paymentAmount")); if (curr1PayReceive == PayReceive.PAY) { curr1Amount = curr1Amount.negative(); curr2Amount = curr2Amount.positive(); } else { curr1Amount = curr1Amount.positive(); curr2Amount = curr2Amount.negative(); } // payment date LocalDate currency1Date = document.parseDate(fxEl.findChild("currency1ValueDate").orElseGet(() => fxEl.getChild("valueDate"))); LocalDate currency2Date = document.parseDate(fxEl.findChild("currency2ValueDate").orElseGet(() => fxEl.getChild("valueDate"))); // FxSingle or NDF Optional <XmlElement> ndfEl = fxEl.findChild("nonDeliverableSettlement"); if (!ndfEl.Present) { return(FxSingleTrade.builder().info(tradeInfoBuilder.build()).product(FxSingle.of(Payment.of(curr1Amount, currency1Date), Payment.of(curr2Amount, currency2Date))).build()); } if (!currency1Date.Equals(currency2Date)) { throw new FpmlParseException("FxNdf only supports a single payment date"); } return(parseNdf(document, fxEl, ndfEl.get(), curr1Amount, curr2Amount, currency1Date, tradeInfoBuilder)); }
private AdjustablePayment parsePremium(XmlElement swaptionEl, FpmlDocument document, TradeInfoBuilder tradeInfoBuilder) { XmlElement premiumEl = swaptionEl.getChild("premium"); PayReceive payReceive = document.parsePayerReceiver(premiumEl, tradeInfoBuilder); XmlElement paymentAmountEl = premiumEl.getChild("paymentAmount"); CurrencyAmount ccyAmount = document.parseCurrencyAmount(paymentAmountEl); ccyAmount = payReceive.Pay ? ccyAmount.negated() : ccyAmount; AdjustableDate paymentDate = premiumEl.findChild("paymentDate").map(el => document.parseAdjustableDate(el)).get(); return(AdjustablePayment.of(ccyAmount, paymentDate)); }
private FxSingle parseLeg(XmlElement legEl, FpmlDocument document, TradeInfoBuilder tradeInfoBuilder) { // supported elements: // 'exchangedCurrency1/paymentAmount' // 'exchangedCurrency2/paymentAmount' // 'valueDate' // ignored elements: // 'dealtCurrency?' // 'exchangeRate' // rejected elements: // 'nonDeliverableSettlement?' // 'currency1ValueDate' // 'currency2ValueDate' document.validateNotPresent(legEl, "currency1ValueDate"); document.validateNotPresent(legEl, "currency2ValueDate"); document.validateNotPresent(legEl, "nonDeliverableSettlement"); XmlElement curr1El = legEl.getChild("exchangedCurrency1"); XmlElement curr2El = legEl.getChild("exchangedCurrency2"); // pay/receive and counterparty 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"); } // amount CurrencyAmount curr1Amount = document.parseCurrencyAmount(curr1El.getChild("paymentAmount")); CurrencyAmount curr2Amount = document.parseCurrencyAmount(curr2El.getChild("paymentAmount")); if (curr1PayReceive == PayReceive.PAY) { curr1Amount = curr1Amount.negative(); curr2Amount = curr2Amount.positive(); } else { curr1Amount = curr1Amount.positive(); curr2Amount = curr2Amount.negative(); } // payment date LocalDate valueDate = document.parseDate(legEl.getChild("valueDate")); // result return(FxSingle.of(curr1Amount, curr2Amount, valueDate)); }
//------------------------------------------------------------------------- public Trade parseTrade(FpmlDocument document, XmlElement tradeEl) { // supported elements: // 'payerPartyReference' // 'receiverPartyReference' // 'startDate' // 'maturityDate' // 'principal' // 'fixedRate' // 'dayCountFraction' // ignored elements: // 'payerAccountReference?' // 'receiverAccountReference?' // 'interest?' // rejected elements: // 'features?' // 'payment*' TradeInfoBuilder tradeInfoBuilder = document.parseTradeInfo(tradeEl); XmlElement termEl = tradeEl.getChild("termDeposit"); document.validateNotPresent(termEl, "features"); document.validateNotPresent(termEl, "payment"); TermDeposit.Builder termBuilder = TermDeposit.builder(); // pay/receive and counterparty PayReceive payReceive = document.parsePayerReceiver(termEl, tradeInfoBuilder); termBuilder.buySell(BuySell.ofBuy(payReceive.Pay)); // start date termBuilder.startDate(document.parseDate(termEl.getChild("startDate"))); // maturity date termBuilder.endDate(document.parseDate(termEl.getChild("maturityDate"))); // principal CurrencyAmount principal = document.parseCurrencyAmount(termEl.getChild("principal")); termBuilder.currency(principal.Currency); termBuilder.notional(principal.Amount); // fixed rate termBuilder.rate(document.parseDecimal(termEl.getChild("fixedRate"))); // day count termBuilder.dayCount(document.parseDayCountFraction(termEl.getChild("dayCountFraction"))); return(TermDepositTrade.builder().info(tradeInfoBuilder.build()).product(termBuilder.build()).build()); }
// 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> /// Creates an Ibor cap/floor leg. /// <para> /// The Ibor index should be {@code EUR_EURIBOR_3M} or {@code EUR_EURIBOR_6M} to match the availability of the curve /// data in <seealso cref="IborCapletFloorletDataSet"/>. /// /// </para> /// </summary> /// <param name="index"> the index </param> /// <param name="startDate"> the start date </param> /// <param name="endDate"> the end date </param> /// <param name="strikeSchedule"> the strike </param> /// <param name="notionalSchedule"> the notional </param> /// <param name="putCall"> cap or floor </param> /// <param name="payRec"> pay or receive </param> /// <returns> the instance </returns> public static IborCapFloorLeg createCapFloorLegUnresolved(IborIndex index, LocalDate startDate, LocalDate endDate, ValueSchedule strikeSchedule, ValueSchedule notionalSchedule, PutCall putCall, PayReceive payRec) { Frequency frequency = Frequency.of(index.Tenor.Period); PeriodicSchedule paySchedule = PeriodicSchedule.of(startDate, endDate, frequency, BUSINESS_ADJ, StubConvention.NONE, RollConventions.NONE); IborRateCalculation rateCalculation = IborRateCalculation.of(index); if (putCall.Call) { return(IborCapFloorLeg.builder().calculation(rateCalculation).capSchedule(strikeSchedule).notional(notionalSchedule).paymentSchedule(paySchedule).payReceive(payRec).build()); } return(IborCapFloorLeg.builder().calculation(rateCalculation).floorSchedule(strikeSchedule).notional(notionalSchedule).paymentSchedule(paySchedule).payReceive(payRec).build()); }
//------------------------------------------------------------------------- /// <summary> /// Creates an Ibor cap/floor leg. /// <para> /// The Ibor index should be {@code EUR_EURIBOR_3M} or {@code EUR_EURIBOR_6M} to match the availability of the curve /// data in <seealso cref="IborCapletFloorletDataSet"/>. /// /// </para> /// </summary> /// <param name="index"> the index </param> /// <param name="startDate"> the start date </param> /// <param name="endDate"> the end date </param> /// <param name="strikeSchedule"> the strike </param> /// <param name="notionalSchedule"> the notional </param> /// <param name="putCall"> cap or floor </param> /// <param name="payRec"> pay or receive </param> /// <returns> the instance </returns> public static ResolvedIborCapFloorLeg createCapFloorLeg(IborIndex index, LocalDate startDate, LocalDate endDate, ValueSchedule strikeSchedule, ValueSchedule notionalSchedule, PutCall putCall, PayReceive payRec) { IborCapFloorLeg leg = createCapFloorLegUnresolved(index, startDate, endDate, strikeSchedule, notionalSchedule, putCall, payRec); return(leg.resolve(REF_DATA)); }
/// <summary> /// Create a pay leg. /// <para> /// The pay leg created is periodic fixed rate payments without compounding. /// The Ibor index is used to specify the payment frequency. /// /// </para> /// </summary> /// <param name="index"> the Ibor index </param> /// <param name="startDate"> the start date </param> /// <param name="endDate"> the end date </param> /// <param name="fixedRate"> the fixed rate </param> /// <param name="notional"> the notional </param> /// <param name="payRec"> pay or receive </param> /// <returns> the instance </returns> public static SwapLeg createFixedPayLegUnresolved(IborIndex index, LocalDate startDate, LocalDate endDate, double fixedRate, double notional, PayReceive payRec) { Frequency frequency = Frequency.of(index.Tenor.Period); PeriodicSchedule accSchedule = PeriodicSchedule.of(startDate, endDate, frequency, BUSINESS_ADJ, StubConvention.NONE, RollConventions.NONE); return(RateCalculationSwapLeg.builder().payReceive(payRec).accrualSchedule(accSchedule).calculation(FixedRateCalculation.of(fixedRate, ACT_360)).paymentSchedule(PaymentSchedule.builder().paymentFrequency(frequency).paymentDateOffset(DaysAdjustment.NONE).build()).notionalSchedule(NotionalSchedule.of(CurrencyAmount.of(EUR, notional))).build()); }
//------------------------------------------------------------------------- /// <summary> /// Create a pay leg. /// <para> /// The pay leg created is periodic fixed rate payments without compounding. /// The Ibor index is used to specify the payment frequency. /// /// </para> /// </summary> /// <param name="index"> the Ibor index </param> /// <param name="startDate"> the start date </param> /// <param name="endDate"> the end date </param> /// <param name="fixedRate"> the fixed rate </param> /// <param name="notional"> the notional </param> /// <param name="payRec"> pay or receive </param> /// <returns> the instance </returns> public static ResolvedSwapLeg createFixedPayLeg(IborIndex index, LocalDate startDate, LocalDate endDate, double fixedRate, double notional, PayReceive payRec) { SwapLeg leg = createFixedPayLegUnresolved(index, startDate, endDate, fixedRate, notional, payRec); return(leg.resolve(REF_DATA)); }
// fixed rate leg private static SwapLeg iborLeg(LocalDate start, LocalDate end, IborIndex index, PayReceive payReceive, NotionalSchedule notional, StubConvention stubConvention) { Frequency freq = Frequency.of(index.Tenor.Period); return(RateCalculationSwapLeg.builder().payReceive(payReceive).accrualSchedule(PeriodicSchedule.builder().startDate(start).endDate(end).frequency(freq).businessDayAdjustment(BDA_MF).stubConvention(stubConvention).build()).paymentSchedule(PaymentSchedule.builder().paymentFrequency(freq).paymentDateOffset(DaysAdjustment.NONE).build()).notionalSchedule(notional).calculation(IborRateCalculation.builder().index(index).fixingDateOffset(DaysAdjustment.ofBusinessDays(-2, index.FixingCalendar, BDA_P)).build()).build()); }
// fixed rate leg private static SwapLeg fixedLeg(LocalDate start, LocalDate end, Frequency frequency, PayReceive payReceive, NotionalSchedule notional, double fixedRate, StubConvention stubConvention) { return(RateCalculationSwapLeg.builder().payReceive(payReceive).accrualSchedule(PeriodicSchedule.builder().startDate(start).endDate(end).frequency(frequency).businessDayAdjustment(BDA_MF).stubConvention(stubConvention).build()).paymentSchedule(PaymentSchedule.builder().paymentFrequency(frequency).paymentDateOffset(DaysAdjustment.NONE).build()).notionalSchedule(notional).calculation(FixedRateCalculation.builder().dayCount(THIRTY_U_360).rate(ValueSchedule.of(fixedRate)).build()).build()); }
// parses the CDS internal Trade parseCds(FpmlDocument document, XmlElement tradeEl, TradeInfoBuilder tradeInfoBuilder) { XmlElement cdsEl = tradeEl.getChild("creditDefaultSwap"); XmlElement generalTermsEl = cdsEl.getChild("generalTerms"); XmlElement feeLegEl = cdsEl.getChild("feeLeg"); document.validateNotPresent(generalTermsEl, "basketReferenceInformation"); document.validateNotPresent(feeLegEl, "singlePayment"); BuySell buySell = document.parseBuyerSeller(generalTermsEl, tradeInfoBuilder); // effective and termination date are optional in FpML but mandatory for Strata 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().startDate(effectiveDate.Unadjusted).startDateBusinessDayAdjustment(effectiveDate.Adjustment).endDate(terminationDate.Unadjusted).endDateBusinessDayAdjustment(terminationDate.Adjustment).businessDayAdjustment(bda); // an upfront fee Optional <XmlElement> initialPaymentOptEl = feeLegEl.findChild("initialPayment"); AdjustablePayment upfrontFee = null; if (initialPaymentOptEl.Present) { 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.Unadjusted); AdjustableDate adjDate = AdjustableDate.of(date, bda); upfrontFee = payRec.Pay ? AdjustablePayment.ofPay(amount, adjDate) : AdjustablePayment.ofReceive(amount, adjDate); } // we require a periodicPayment and fixedAmountCalculation XmlElement periodicPaymentEl = feeLegEl.getChild("periodicPayment"); scheduleBuilder.frequency(periodicPaymentEl.findChild("paymentFrequency").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").ifPresent(el => scheduleBuilder.lastRegularEndDate(document.parseDate(el))); scheduleBuilder.rollConvention(periodicPaymentEl.findChild("rollConvention").map(el => document.convertRollConvention(el.Content)).orElse(null)); XmlElement fixedAmountCalcEl = periodicPaymentEl.getChild("fixedAmountCalculation"); double fixedRate = document.parseDecimal(fixedAmountCalcEl.getChild("fixedRate")); DayCount dayCount = fixedAmountCalcEl.findChild("dayCountFraction").map(el => document.parseDayCountFraction(el)).orElse(DayCounts.ACT_360); // handle a single protectionTerms element XmlElement protectionTermEl = cdsEl.getChild("protectionTerms"); CurrencyAmount notional = document.parseCurrencyAmount(protectionTermEl.getChild("calculationAmount")); // single name CDS Optional <XmlElement> singleOptEl = generalTermsEl.findChild("referenceInformation"); if (singleOptEl.Present) { // we require a single entityId XmlElement referenceEntityEl = singleOptEl.get().getChild("referenceEntity"); XmlElement entityIdEl = referenceEntityEl.getChild("entityId"); string scheme = entityIdEl.findAttribute("entityIdScheme").orElse("http://www.fpml.org/coding-scheme/external/entity-id-RED-1-0"); string value = entityIdEl.Content; StandardId entityId = StandardId.of(scheme, value); Cds cds = Cds.builder().buySell(buySell).legalEntityId(entityId).currency(notional.Currency).notional(notional.Amount).paymentSchedule(scheduleBuilder.build()).fixedRate(fixedRate).dayCount(dayCount).build(); return(CdsTrade.builder().info(tradeInfoBuilder.build()).product(cds).upfrontFee(upfrontFee).build()); } // CDS index Optional <XmlElement> indexOptEl = generalTermsEl.findChild("indexReferenceInformation"); if (indexOptEl.Present) { string indexName = indexOptEl.get().getChild("indexName").Content; CdsIndex cdsIndex = CdsIndex.builder().buySell(buySell).cdsIndexId(StandardId.of("CDX-Name", indexName)).currency(notional.Currency).notional(notional.Amount).paymentSchedule(scheduleBuilder.build()).fixedRate(fixedRate).dayCount(dayCount).build(); return(CdsIndexTrade.builder().info(tradeInfoBuilder.build()).product(cdsIndex).upfrontFee(upfrontFee).build()); } // unknown type throw new FpmlParseException("FpML CDS must be single name or index"); }