Beispiel #1
0
        //-------------------------------------------------------------------------
        public Trade parseTrade(FpmlDocument document, XmlElement tradeEl)
        {
            // supported elements:
            //  'swapStream+'
            //  'swapStream/buyerPartyReference'
            //  'swapStream/sellerPartyReference'
            //  'swapStream/calculationPeriodDates'
            //  'swapStream/paymentDates'
            //  'swapStream/resetDates?'
            //  'swapStream/calculationPeriodAmount'
            //  'swapStream/stubCalculationPeriodAmount?'
            //  'swapStream/principalExchanges?'
            //  'swapStream/calculationPeriodAmount/knownAmountSchedule'
            // ignored elements:
            //  'Product.model?'
            //  'swapStream/cashflows?'
            //  'swapStream/settlementProvision?'
            //  'swapStream/formula?'
            //  'earlyTerminationProvision?'
            //  'cancelableProvision?'
            //  'extendibleProvision?'
            //  'additionalPayment*'
            //  'additionalTerms?'
            // rejected elements:
            //  'swapStream/calculationPeriodAmount/calculation/fxLinkedNotionalSchedule'
            //  'swapStream/calculationPeriodAmount/calculation/futureValueNotional'
            TradeInfoBuilder tradeInfoBuilder = document.parseTradeInfo(tradeEl);
            Swap             swap             = parseSwap(document, tradeEl, tradeInfoBuilder);

            return(SwapTrade.builder().info(tradeInfoBuilder.build()).product(swap).build());
        }
Beispiel #2
0
        //-------------------------------------------------------------------------
        // Converts an FpML 'StubPeriodTypeEnum' to a {@code StubConvention}.
        private StubConvention parseStubConvention(XmlElement baseEl, FpmlDocument document)
        {
            string str = baseEl.Content;

            if (str.Equals("ShortInitial"))
            {
                return(StubConvention.SHORT_INITIAL);
            }
            else if (str.Equals("ShortFinal"))
            {
                return(StubConvention.SHORT_FINAL);
            }
            else if (str.Equals("LongInitial"))
            {
                return(StubConvention.LONG_INITIAL);
            }
            else if (str.Equals("LongFinal"))
            {
                return(StubConvention.LONG_FINAL);
            }
            else
            {
                throw new FpmlParseException(Messages.format("Unknown 'stubPeriodType' value '{}', expected 'ShortInitial', 'ShortFinal', 'LongInitial' or 'LongFinal'", str));
            }
        }
Beispiel #3
0
        // Converts an FpML 'Schedule' to a {@code ValueSchedule}.
        private ValueSchedule parseSchedule(XmlElement scheduleEl, FpmlDocument document)
        {
            // FpML content: ('initialValue', 'step*')
            // FpML 'step' content: ('stepDate', 'stepValue')
            double initialValue = document.parseDecimal(scheduleEl.getChild("initialValue"));

            return(parseSchedule(scheduleEl, initialValue, null, document));
        }
Beispiel #4
0
        // Converts an FpML 'StubValue' to a {@code IborRateStubCalculation}.
        private IborRateStubCalculation parseStubCalculation(XmlElement baseEl, FpmlDocument document)
        {
            Optional <XmlElement> rateOptEl = baseEl.findChild("stubRate");

            if (rateOptEl.Present)
            {
                return(IborRateStubCalculation.ofFixedRate(document.parseDecimal(rateOptEl.get())));
            }
            Optional <XmlElement> amountOptEl = baseEl.findChild("stubAmount");

            if (amountOptEl.Present)
            {
                return(IborRateStubCalculation.ofKnownAmount(document.parseCurrencyAmount(amountOptEl.get())));
            }
            IList <XmlElement> indicesEls = baseEl.getChildren("floatingRate");

            if (indicesEls.Count == 1)
            {
                XmlElement indexEl = indicesEls[0];
                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.Count == 2)
            {
                XmlElement index1El = indicesEls[0];
                document.validateNotPresent(index1El, "floatingRateMultiplierSchedule");
                document.validateNotPresent(index1El, "spreadSchedule");
                document.validateNotPresent(index1El, "rateTreatment");
                document.validateNotPresent(index1El, "capRateSchedule");
                document.validateNotPresent(index1El, "floorRateSchedule");
                XmlElement index2El = indicesEls[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)));
            }
            throw new FpmlParseException("Unknown stub structure: " + baseEl);
        }
Beispiel #5
0
        // parses the swap
        internal Swap parseSwap(FpmlDocument document, XmlElement tradeEl, TradeInfoBuilder tradeInfoBuilder)
        {
            XmlElement swapEl = tradeEl.getChild("swap");
            ImmutableList <XmlElement> legEls = swapEl.getChildren("swapStream");

            ImmutableList.Builder <SwapLeg> legsBuilder = ImmutableList.builder();
            foreach (XmlElement legEl in legEls)
            {
                // calculation
                XmlElement       calcPeriodAmountEl = legEl.getChild("calculationPeriodAmount");
                XmlElement       calcEl             = calcPeriodAmountEl.findChild("calculation").orElse(XmlElement.ofChildren("calculation", ImmutableList.of()));
                PeriodicSchedule accrualSchedule    = parseSwapAccrualSchedule(legEl, document);
                PaymentSchedule  paymentSchedule    = parseSwapPaymentSchedule(legEl, calcEl, document);
                // known amount or rate calculation
                Optional <XmlElement> knownAmountOptEl = calcPeriodAmountEl.findChild("knownAmountSchedule");
                if (knownAmountOptEl.Present)
                {
                    XmlElement knownAmountEl = knownAmountOptEl.get();
                    document.validateNotPresent(legEl, "stubCalculationPeriodAmount");
                    document.validateNotPresent(legEl, "resetDates");
                    // pay/receive and counterparty
                    PayReceive    payReceive     = document.parsePayerReceiver(legEl, tradeInfoBuilder);
                    ValueSchedule amountSchedule = parseSchedule(knownAmountEl, document);
                    // build
                    legsBuilder.add(KnownAmountSwapLeg.builder().payReceive(payReceive).accrualSchedule(accrualSchedule).paymentSchedule(paymentSchedule).amount(amountSchedule).currency(document.parseCurrency(knownAmountEl.getChild("currency"))).build());
                }
                else
                {
                    document.validateNotPresent(calcEl, "fxLinkedNotionalSchedule");
                    document.validateNotPresent(calcEl, "futureValueNotional");
                    // pay/receive and counterparty
                    PayReceive       payReceive       = document.parsePayerReceiver(legEl, tradeInfoBuilder);
                    NotionalSchedule notionalSchedule = parseSwapNotionalSchedule(legEl, calcEl, document);
                    RateCalculation  calculation      = parseSwapCalculation(legEl, calcEl, accrualSchedule, document);
                    // build
                    legsBuilder.add(RateCalculationSwapLeg.builder().payReceive(payReceive).accrualSchedule(accrualSchedule).paymentSchedule(paymentSchedule).notionalSchedule(notionalSchedule).calculation(calculation).build());
                }
            }
            return(Swap.of(legsBuilder.build()));
        }
Beispiel #6
0
        // checks that the index on a stub matches the main index (this is handling bad FpML)
        private void checkStubForOvernightIndex(XmlElement baseEl, FpmlDocument document, OvernightIndex index)
        {
            document.validateNotPresent(baseEl, "stubAmount");
            document.validateNotPresent(baseEl, "stubRate");
            IList <XmlElement> indicesEls = baseEl.getChildren("floatingRate");

            if (indicesEls.Count == 1)
            {
                XmlElement indexEl = indicesEls[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);
        }
Beispiel #7
0
        // Converts an FpML 'Schedule' to a {@code ValueSchedule}.
        private ValueSchedule parseSchedule(XmlElement scheduleEl, double initialValue, ValueStepSequence seq, FpmlDocument document)
        {
            IList <XmlElement> stepEls = scheduleEl.getChildren("step");

            ImmutableList.Builder <ValueStep> stepBuilder = ImmutableList.builder();
            foreach (XmlElement stepEl in stepEls)
            {
                LocalDate stepDate  = document.parseDate(stepEl.getChild("stepDate"));
                double    stepValue = document.parseDecimal(stepEl.getChild("stepValue"));
                stepBuilder.add(ValueStep.of(stepDate, ValueAdjustment.ofReplace(stepValue)));
            }
            return(ValueSchedule.builder().initialValue(initialValue).steps(stepBuilder.build()).stepSequence(seq).build());
        }
Beispiel #8
0
        //-------------------------------------------------------------------------
        // Converts an FpML 'StubValue' to a {@code FixedRateStubCalculation}.
        private FixedRateStubCalculation parseStubCalculationForFixed(XmlElement baseEl, FpmlDocument document)
        {
            Optional <XmlElement> rateOptEl = baseEl.findChild("stubRate");

            if (rateOptEl.Present)
            {
                return(FixedRateStubCalculation.ofFixedRate(document.parseDecimal(rateOptEl.get())));
            }
            Optional <XmlElement> amountOptEl = baseEl.findChild("stubAmount");

            if (amountOptEl.Present)
            {
                return(FixedRateStubCalculation.ofKnownAmount(document.parseCurrencyAmount(amountOptEl.get())));
            }
            throw new FpmlParseException("Invalid stub, fixed rate leg cannot have a floating rate stub");
        }
Beispiel #9
0
        // Converts an FpML 'FloatingRateCalculation' to a {@code RateCalculation}.
        private RateCalculation parseFloat(XmlElement legEl, XmlElement calcEl, XmlElement floatingEl, PeriodicSchedule accrualSchedule, FpmlDocument document)
        {
            // supported elements:
            //  'calculationPeriodAmount/calculation/floatingRateCalculation'
            //  'calculationPeriodAmount/calculation/floatingRateCalculation/floatingRateIndex'
            //  'calculationPeriodAmount/calculation/floatingRateCalculation/indexTenor?'
            //  'calculationPeriodAmount/calculation/floatingRateCalculation/floatingRateMultiplierSchedule?'
            //  'calculationPeriodAmount/calculation/floatingRateCalculation/spreadSchedule*'
            //  'calculationPeriodAmount/calculation/floatingRateCalculation/initialRate?' (Ibor only)
            //  'calculationPeriodAmount/calculation/floatingRateCalculation/averagingMethod?'
            //  'calculationPeriodAmount/calculation/floatingRateCalculation/negativeInterestRateTreatment?'
            //  'calculationPeriodAmount/calculation/dayCountFraction'
            //  'resetDates/resetRelativeTo'
            //  'resetDates/fixingDates'
            //  'resetDates/rateCutOffDaysOffset' (OIS only)
            //  'resetDates/resetFrequency'
            //  'resetDates/resetDatesAdjustments'
            //  'stubCalculationPeriodAmount/initalStub' (Ibor only, Overnight must match index)
            //  'stubCalculationPeriodAmount/finalStub' (Ibor only, Overnight must match index)
            // ignored elements:
            //  'calculationPeriodAmount/calculation/floatingRateCalculation/finalRateRounding?'
            //  'calculationPeriodAmount/calculation/discounting?'
            //  'resetDates/calculationPeriodDatesReference'
            // rejected elements:
            //  'calculationPeriodAmount/calculation/floatingRateCalculation/spreadSchedule/type?'
            //  'calculationPeriodAmount/calculation/floatingRateCalculation/rateTreatment?'
            //  'calculationPeriodAmount/calculation/floatingRateCalculation/capRateSchedule?'
            //  'calculationPeriodAmount/calculation/floatingRateCalculation/floorRateSchedule?'
            //  'resetDates/initialFixingDate'
            document.validateNotPresent(floatingEl, "rateTreatment");
            document.validateNotPresent(floatingEl, "capRateSchedule");
            document.validateNotPresent(floatingEl, "floorRateSchedule");
            Index index = document.parseIndex(floatingEl);

            if (index is IborIndex)
            {
                IborRateCalculation.Builder iborRateBuilder = IborRateCalculation.builder();
                // day count
                iborRateBuilder.dayCount(document.parseDayCountFraction(calcEl.getChild("dayCountFraction")));
                // index
                iborRateBuilder.index((IborIndex)document.parseIndex(floatingEl));
                // gearing
                floatingEl.findChild("floatingRateMultiplierSchedule").ifPresent(el =>
                {
                    iborRateBuilder.gearing(parseSchedule(el, document));
                });
                // spread
                if (floatingEl.getChildren("spreadSchedule").size() > 1)
                {
                    throw new FpmlParseException("Only one 'spreadSchedule' is supported");
                }
                floatingEl.findChild("spreadSchedule").ifPresent(el =>
                {
                    document.validateNotPresent(el, "type");
                    iborRateBuilder.spread(parseSchedule(el, document));
                });
                // initial fixed rate
                floatingEl.findChild("initialRate").ifPresent(el =>
                {
                    iborRateBuilder.firstRegularRate(document.parseDecimal(el));
                });
                // negative rates
                floatingEl.findChild("negativeInterestRateTreatment").ifPresent(el =>
                {
                    iborRateBuilder.negativeRateMethod(parseNegativeInterestRateTreatment(el));
                });
                // resets
                legEl.findChild("resetDates").ifPresent(resetDatesEl =>
                {
                    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.Frequency.Equals(resetFreq))
                    {
                        ResetSchedule.Builder resetScheduleBuilder = ResetSchedule.builder();
                        resetScheduleBuilder.resetFrequency(resetFreq);
                        floatingEl.findChild("averagingMethod").ifPresent(el =>
                        {
                            resetScheduleBuilder.resetMethod(parseAveragingMethod(el));
                        });
                        resetScheduleBuilder.businessDayAdjustment(document.parseBusinessDayAdjustments(resetDatesEl.getChild("resetDatesAdjustments")));
                        iborRateBuilder.resetPeriods(resetScheduleBuilder.build());
                    }
                });

                // stubs
                legEl.findChild("stubCalculationPeriodAmount").ifPresent(stubsEl =>
                {
                    stubsEl.findChild("initialStub").ifPresent(el =>
                    {
                        iborRateBuilder.initialStub(parseStubCalculation(el, document));
                    });
                    stubsEl.findChild("finalStub").ifPresent(el =>
                    {
                        iborRateBuilder.finalStub(parseStubCalculation(el, document));
                    });
                });
                return(iborRateBuilder.build());
            }
            else if (index is OvernightIndex)
            {
                OvernightRateCalculation.Builder overnightRateBuilder = OvernightRateCalculation.builder();
                document.validateNotPresent(floatingEl, "initialRate");   // TODO: should support this in the model
                // stubs
                legEl.findChild("stubCalculationPeriodAmount").ifPresent(stubsEl =>
                {
                    stubsEl.findChild("initialStub").ifPresent(el =>
                    {
                        checkStubForOvernightIndex(el, document, (OvernightIndex)index);
                    });
                    stubsEl.findChild("finalStub").ifPresent(el =>
                    {
                        checkStubForOvernightIndex(el, document, (OvernightIndex)index);
                    });
                });
                // day count
                overnightRateBuilder.dayCount(document.parseDayCountFraction(calcEl.getChild("dayCountFraction")));
                // index
                overnightRateBuilder.index((OvernightIndex)document.parseIndex(floatingEl));
                // accrual method
                FloatingRateName idx = FloatingRateName.of(floatingEl.getChild("floatingRateIndex").Content);
                if (idx.Type == FloatingRateType.OVERNIGHT_COMPOUNDED)
                {
                    overnightRateBuilder.accrualMethod(OvernightAccrualMethod.COMPOUNDED);
                }
                // gearing
                floatingEl.findChild("floatingRateMultiplierSchedule").ifPresent(el =>
                {
                    overnightRateBuilder.gearing(parseSchedule(el, document));
                });
                // spread
                if (floatingEl.getChildren("spreadSchedule").size() > 1)
                {
                    throw new FpmlParseException("Only one 'spreadSchedule' is supported");
                }
                floatingEl.findChild("spreadSchedule").ifPresent(el =>
                {
                    document.validateNotPresent(el, "type");
                    overnightRateBuilder.spread(parseSchedule(el, document));
                });
                // negative rates
                floatingEl.findChild("negativeInterestRateTreatment").ifPresent(el =>
                {
                    overnightRateBuilder.negativeRateMethod(parseNegativeInterestRateTreatment(el));
                });
                // rate cut off
                legEl.findChild("resetDates").ifPresent(resetDatesEl =>
                {
                    document.validateNotPresent(resetDatesEl, "initialFixingDate");
                    resetDatesEl.findChild("rateCutOffDaysOffset").ifPresent(el =>
                    {
                        Period cutOff = document.parsePeriod(el);
                        if (cutOff.toTotalMonths() != 0)
                        {
                            throw new FpmlParseException("Invalid 'rateCutOffDaysOffset' value, expected days-based period: " + cutOff);
                        }
                        overnightRateBuilder.rateCutOffDays(-cutOff.Days);
                    });
                });
                return(overnightRateBuilder.build());
            }
            else
            {
                throw new FpmlParseException("Invalid 'floatingRateIndex' type, not Ibor or Overnight");
            }
        }
Beispiel #10
0
 // Converts an FpML 'fixedRateSchedule' to a {@code RateCalculation}.
 private RateCalculation parseFixed(XmlElement legEl, XmlElement calcEl, XmlElement fixedEl, FpmlDocument document)
 {
     // supported elements:
     //  'calculationPeriodAmount/calculation/fixedRateSchedule'
     //  'calculationPeriodAmount/calculation/dayCountFraction'
     //  'stubCalculationPeriodAmount'
     // rejected elements:
     //  'resetDates'
     //  'stubCalculationPeriodAmount/initialStub/floatingRate'
     //  'stubCalculationPeriodAmount/finalStub/floatingRate'
     document.validateNotPresent(legEl, "resetDates");
     FixedRateCalculation.Builder fixedRateBuilder = FixedRateCalculation.builder();
     fixedRateBuilder.rate(parseSchedule(fixedEl, document));
     fixedRateBuilder.dayCount(document.parseDayCountFraction(calcEl.getChild("dayCountFraction")));
     // stub
     legEl.findChild("stubCalculationPeriodAmount").ifPresent(stubsEl =>
     {
         stubsEl.findChild("initialStub").ifPresent(el =>
         {
             fixedRateBuilder.initialStub(parseStubCalculationForFixed(el, document));
         });
         stubsEl.findChild("finalStub").ifPresent(el =>
         {
             fixedRateBuilder.finalStub(parseStubCalculationForFixed(el, document));
         });
     });
     return(fixedRateBuilder.build());
 }
Beispiel #11
0
        // parse swap rate calculation
        private RateCalculation parseSwapCalculation(XmlElement legEl, XmlElement calcEl, PeriodicSchedule accrualSchedule, FpmlDocument document)
        {
            // supported elements:
            //  'calculationPeriodAmount/calculation/fixedRateSchedule'
            //  'calculationPeriodAmount/calculation/floatingRateCalculation'
            //  'calculationPeriodAmount/calculation/inflationRateCalculation'
            Optional <XmlElement> fixedOptEl     = calcEl.findChild("fixedRateSchedule");
            Optional <XmlElement> floatingOptEl  = calcEl.findChild("floatingRateCalculation");
            Optional <XmlElement> inflationOptEl = calcEl.findChild("inflationRateCalculation");

            if (fixedOptEl.Present)
            {
                return(parseFixed(legEl, calcEl, fixedOptEl.get(), document));
            }
            else if (floatingOptEl.Present)
            {
                return(parseFloat(legEl, calcEl, floatingOptEl.get(), accrualSchedule, document));
            }
            else if (inflationOptEl.Present)
            {
                return(parseInflation(legEl, calcEl, inflationOptEl.get(), accrualSchedule, document));
            }
            else
            {
                throw new FpmlParseException("Invalid 'calculation' type, not fixedRateSchedule, floatingRateCalculation or inflationRateCalculation");
            }
        }
Beispiel #12
0
        // parses the notional schedule
        private NotionalSchedule parseSwapNotionalSchedule(XmlElement legEl, XmlElement calcEl, FpmlDocument document)
        {
            // supported elements:
            //  'principalExchanges/initialExchange'
            //  'principalExchanges/finalExchange'
            //  'principalExchanges/intermediateExchange'
            //  'calculationPeriodAmount/calculation/notionalSchedule/notionalStepSchedule'
            //  'calculationPeriodAmount/calculation/notionalSchedule/notionalStepParameters'
            NotionalSchedule.Builder notionalScheduleBuilder = NotionalSchedule.builder();
            // exchanges
            legEl.findChild("principalExchanges").ifPresent(el =>
            {
                notionalScheduleBuilder.initialExchange(bool.Parse(el.getChild("initialExchange").Content));
                notionalScheduleBuilder.intermediateExchange(bool.Parse(el.getChild("intermediateExchange").Content));
                notionalScheduleBuilder.finalExchange(bool.Parse(el.getChild("finalExchange").Content));
            });
            // notional schedule
            XmlElement            notionalEl         = calcEl.getChild("notionalSchedule");
            XmlElement            stepScheduleEl     = notionalEl.getChild("notionalStepSchedule");
            Optional <XmlElement> paramScheduleElOpt = notionalEl.findChild("notionalStepParameters");
            double            initialValue           = document.parseDecimal(stepScheduleEl.getChild("initialValue"));
            ValueStepSequence seq = paramScheduleElOpt.map(el => parseAmountSchedule(el, initialValue, document)).orElse(null);

            notionalScheduleBuilder.amount(parseSchedule(stepScheduleEl, initialValue, seq, document));
            notionalScheduleBuilder.currency(document.parseCurrency(stepScheduleEl.getChild("currency")));
            return(notionalScheduleBuilder.build());
        }
Beispiel #13
0
        // parses the payment schedule
        private PaymentSchedule parseSwapPaymentSchedule(XmlElement legEl, XmlElement calcEl, FpmlDocument document)
        {
            // supported elements:
            //  'paymentDates/paymentFrequency'
            //  'paymentDates/payRelativeTo'
            //  'paymentDates/paymentDaysOffset?'
            //  'paymentDates/paymentDatesAdjustments'
            //  'calculationPeriodAmount/calculation/compoundingMethod'
            //  'paymentDates/firstPaymentDate?'
            //  'paymentDates/lastRegularPaymentDate?'
            // ignored elements:
            //  'paymentDates/calculationPeriodDatesReference'
            //  'paymentDates/resetDatesReference'
            //  'paymentDates/valuationDatesReference'
            PaymentSchedule.Builder paymentScheduleBuilder = PaymentSchedule.builder();
            // payment dates
            XmlElement paymentDatesEl = legEl.getChild("paymentDates");

            // frequency
            paymentScheduleBuilder.paymentFrequency(document.parseFrequency(paymentDatesEl.getChild("paymentFrequency")));
            //default for IRS is pay relative to period end; Strata model will apply the defaulting but the values is needed
            //here for first and last payment date checks
            PaymentRelativeTo payRelativeTo = paymentDatesEl.findChild("payRelativeTo").map(el => parsePayRelativeTo(el)).orElse(PaymentRelativeTo.PERIOD_END);

            paymentScheduleBuilder.paymentRelativeTo(payRelativeTo);
            // dates
            if (payRelativeTo == PaymentRelativeTo.PERIOD_END)
            {
                // ignore data if not PeriodEnd and hope schedule is worked out correctly by other means
                // this provides compatibility for old code that ignored these FpML fields
                paymentDatesEl.findChild("firstPaymentDate").map(el => document.parseDate(el)).ifPresent(date => paymentScheduleBuilder.firstRegularStartDate(date));
                paymentDatesEl.findChild("lastRegularPaymentDate").map(el => document.parseDate(el)).ifPresent(date => paymentScheduleBuilder.lastRegularEndDate(date));
            }
            // offset
            Optional <XmlElement> paymentOffsetEl = paymentDatesEl.findChild("paymentDaysOffset");
            BusinessDayAdjustment payAdjustment   = document.parseBusinessDayAdjustments(paymentDatesEl.getChild("paymentDatesAdjustments"));

            if (paymentOffsetEl.Present)
            {
                Period period = document.parsePeriod(paymentOffsetEl.get());
                if (period.toTotalMonths() != 0)
                {
                    throw new FpmlParseException("Invalid 'paymentDatesAdjustments' value, expected days-based period: " + period);
                }
                Optional <XmlElement> dayTypeEl = paymentOffsetEl.get().findChild("dayType");
                bool fixingCalendarDays         = period.Zero || (dayTypeEl.Present && dayTypeEl.get().Content.Equals("Calendar"));
                if (fixingCalendarDays)
                {
                    paymentScheduleBuilder.paymentDateOffset(DaysAdjustment.ofCalendarDays(period.Days, payAdjustment));
                }
                else
                {
                    paymentScheduleBuilder.paymentDateOffset(DaysAdjustment.ofBusinessDays(period.Days, payAdjustment.Calendar));
                }
            }
            else
            {
                paymentScheduleBuilder.paymentDateOffset(DaysAdjustment.ofCalendarDays(0, payAdjustment));
            }
            // compounding
            calcEl.findChild("compoundingMethod").ifPresent(compoundingEl =>
            {
                paymentScheduleBuilder.compoundingMethod(CompoundingMethod.of(compoundingEl.Content));
            });
            return(paymentScheduleBuilder.build());
        }
Beispiel #14
0
        // parses the accrual schedule
        private PeriodicSchedule parseSwapAccrualSchedule(XmlElement legEl, FpmlDocument document)
        {
            // supported elements:
            //  'calculationPeriodDates/effectiveDate'
            //  'calculationPeriodDates/relativeEffectiveDate'
            //  'calculationPeriodDates/terminationDate'
            //  'calculationPeriodDates/relativeTerminationDate'
            //  'calculationPeriodDates/calculationPeriodDates'
            //  'calculationPeriodDates/calculationPeriodDatesAdjustments'
            //  'calculationPeriodDates/firstPeriodStartDate?'
            //  'calculationPeriodDates/firstRegularPeriodStartDate?'
            //  'calculationPeriodDates/lastRegularPeriodEndDate?'
            //  'calculationPeriodDates/stubPeriodType?'
            //  'calculationPeriodDates/calculationPeriodFrequency'
            // ignored elements:
            //  'calculationPeriodDates/firstCompoundingPeriodEndDate?'
            PeriodicSchedule.Builder accrualScheduleBuilder = PeriodicSchedule.builder();
            // calculation dates
            XmlElement calcPeriodDatesEl = legEl.getChild("calculationPeriodDates");
            // business day adjustments
            BusinessDayAdjustment bda = document.parseBusinessDayAdjustments(calcPeriodDatesEl.getChild("calculationPeriodDatesAdjustments"));

            accrualScheduleBuilder.businessDayAdjustment(bda);
            // start date
            AdjustableDate startDate = calcPeriodDatesEl.findChild("effectiveDate").map(el => document.parseAdjustableDate(el)).orElseGet(() => document.parseAdjustedRelativeDateOffset(calcPeriodDatesEl.getChild("relativeEffectiveDate")));

            accrualScheduleBuilder.startDate(startDate.Unadjusted);
            if (!bda.Equals(startDate.Adjustment))
            {
                accrualScheduleBuilder.startDateBusinessDayAdjustment(startDate.Adjustment);
            }
            // end date
            AdjustableDate endDate = calcPeriodDatesEl.findChild("terminationDate").map(el => document.parseAdjustableDate(el)).orElseGet(() => document.parseAdjustedRelativeDateOffset(calcPeriodDatesEl.getChild("relativeTerminationDate")));

            accrualScheduleBuilder.endDate(endDate.Unadjusted);
            if (!bda.Equals(endDate.Adjustment))
            {
                accrualScheduleBuilder.endDateBusinessDayAdjustment(endDate.Adjustment);
            }
            // first period start date
            calcPeriodDatesEl.findChild("firstPeriodStartDate").ifPresent(el =>
            {
                accrualScheduleBuilder.overrideStartDate(document.parseAdjustableDate(el));
            });
            // first regular date
            calcPeriodDatesEl.findChild("firstRegularPeriodStartDate").ifPresent(el =>
            {
                accrualScheduleBuilder.firstRegularStartDate(document.parseDate(el));
            });
            // last regular date
            calcPeriodDatesEl.findChild("lastRegularPeriodEndDate").ifPresent(el =>
            {
                accrualScheduleBuilder.lastRegularEndDate(document.parseDate(el));
            });
            // stub type
            calcPeriodDatesEl.findChild("stubPeriodType").ifPresent(el =>
            {
                accrualScheduleBuilder.stubConvention(parseStubConvention(el, document));
            });
            // frequency
            XmlElement freqEl      = calcPeriodDatesEl.getChild("calculationPeriodFrequency");
            Frequency  accrualFreq = document.parseFrequency(freqEl);

            accrualScheduleBuilder.frequency(accrualFreq);
            // roll convention
            accrualScheduleBuilder.rollConvention(document.convertRollConvention(freqEl.getChild("rollConvention").Content));
            return(accrualScheduleBuilder.build());
        }
Beispiel #15
0
        // Converts an FpML 'NonNegativeAmountSchedule' to a {@code ValueStepSequence}.
        private ValueStepSequence parseAmountSchedule(XmlElement scheduleEl, double initialValue, FpmlDocument document)
        {
            Frequency             freq        = document.parseFrequency(scheduleEl.getChild("stepFrequency"));
            LocalDate             start       = document.parseDate(scheduleEl.getChild("firstNotionalStepDate"));
            LocalDate             end         = document.parseDate(scheduleEl.getChild("lastNotionalStepDate"));
            Optional <XmlElement> amountElOpt = scheduleEl.findChild("notionalStepAmount");

            if (amountElOpt.Present)
            {
                double amount = document.parseDecimal(amountElOpt.get());
                return(ValueStepSequence.of(start, end, freq, ValueAdjustment.ofDeltaAmount(amount)));
            }
            double rate       = document.parseDecimal(scheduleEl.getChild("notionalStepRate"));
            string relativeTo = scheduleEl.findChild("stepRelativeTo").map(el => el.Content).orElse("Previous");

            if (relativeTo.Equals("Previous"))
            {
                return(ValueStepSequence.of(start, end, freq, ValueAdjustment.ofDeltaMultiplier(rate)));
            }
            else if (relativeTo.Equals("Initial"))
            {
                // data model does not support 'relative to initial' but can calculate amount here
                double amount = initialValue * rate;
                return(ValueStepSequence.of(start, end, freq, ValueAdjustment.ofDeltaAmount(amount)));
            }
            else
            {
                throw new FpmlParseException(Messages.format("Unknown 'stepRelativeTo' value '{}', expected 'Initial' or 'Previous'", relativeTo));
            }
        }
Beispiel #16
0
        // Converts an FpML 'InflationRateCalculation' to a {@code RateCalculation}.
        private RateCalculation parseInflation(XmlElement legEl, XmlElement calcEl, XmlElement inflationEl, PeriodicSchedule accrualSchedule, FpmlDocument document)
        {
            // supported elements:
            //  'calculationPeriodAmount/calculation/inflationRateCalculation'
            //  'calculationPeriodAmount/calculation/inflationRateCalculation/floatingRateIndex'
            //  'calculationPeriodAmount/calculation/inflationRateCalculation/indexTenor?'
            //  'calculationPeriodAmount/calculation/inflationRateCalculation/floatingRateMultiplierSchedule?'
            //  'calculationPeriodAmount/calculation/inflationRateCalculation/inflationLag'
            //  'calculationPeriodAmount/calculation/inflationRateCalculation/interpolationMethod'
            //  'calculationPeriodAmount/calculation/inflationRateCalculation/initialIndexLevel?'
            //  'calculationPeriodAmount/calculation/dayCountFraction'
            // ignored elements:
            // 'calculationPeriodAmount/calculation/inflationRateCalculation/indexSource'
            // 'calculationPeriodAmount/calculation/inflationRateCalculation/mainPublication'
            // 'calculationPeriodAmount/calculation/inflationRateCalculation/fallbackBondApplicable'
            //  'calculationPeriodAmount/calculation/floatingRateCalculation/initialRate?'
            //  'calculationPeriodAmount/calculation/floatingRateCalculation/finalRateRounding?'
            //  'calculationPeriodAmount/calculation/floatingRateCalculation/averagingMethod?'
            //  'calculationPeriodAmount/calculation/floatingRateCalculation/negativeInterestRateTreatment?'
            //  'resetDates'
            // rejected elements:
            //  'calculationPeriodAmount/calculation/floatingRateCalculation/spreadSchedule*'
            //  'calculationPeriodAmount/calculation/floatingRateCalculation/rateTreatment?'
            //  'calculationPeriodAmount/calculation/floatingRateCalculation/capRateSchedule?'
            //  'calculationPeriodAmount/calculation/floatingRateCalculation/floorRateSchedule?'
            //  'stubCalculationPeriodAmount'
            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();
            // index
            builder.index(document.parsePriceIndex(inflationEl));
            // lag
            builder.lag(document.parsePeriod(inflationEl.getChild("inflationLag")));
            // interpolation
            string interpStr = inflationEl.getChild("interpolationMethod").Content;

            builder.indexCalculationMethod(interpStr.ToLower(Locale.ENGLISH).Contains("linear") ? PriceIndexCalculationMethod.INTERPOLATED : PriceIndexCalculationMethod.MONTHLY);
            // initial index
            inflationEl.findChild("initialIndexLevel").ifPresent(el =>
            {
                builder.firstIndexValue(document.parseDecimal(el));
            });
            // gearing
            inflationEl.findChild("floatingRateMultiplierSchedule").ifPresent(el =>
            {
                builder.gearing(parseSchedule(el, document));
            });
            return(builder.build());
        }
        //-------------------------------------------------------------------------
        public Trade parseTrade(FpmlDocument document, XmlElement tradeEl)
        {
            // supported elements:
            //  'buyerPartyReference'
            //  'sellerPartyReference'
            //  'adjustedTerminationDate'
            //  'paymentDate'
            //  'fixingDateOffset'
            //  'dayCountFraction'
            //  'notional'
            //  'fixedRate'
            //  'floatingRateIndex'
            //  'indexTenor+'
            //  'fraDiscounting'
            // ignored elements:
            //  'Product.model?'
            //  'buyerAccountReference?'
            //  'sellerAccountReference?'
            //  'calculationPeriodNumberOfDays'
            //  'additionalPayment*'
            TradeInfoBuilder tradeInfoBuilder = document.parseTradeInfo(tradeEl);
            XmlElement       fraEl            = tradeEl.getChild("fra");

            Fra.Builder fraBuilder = Fra.builder();
            // buy/sell and counterparty
            fraBuilder.buySell(document.parseBuyerSeller(fraEl, tradeInfoBuilder));
            // start date
            fraBuilder.startDate(document.parseDate(fraEl.getChild("adjustedEffectiveDate")));
            // end date
            fraBuilder.endDate(document.parseDate(fraEl.getChild("adjustedTerminationDate")));
            // payment date
            fraBuilder.paymentDate(document.parseAdjustableDate(fraEl.getChild("paymentDate")));
            // fixing offset
            fraBuilder.fixingDateOffset(document.parseRelativeDateOffsetDays(fraEl.getChild("fixingDateOffset")));
            // dateRelativeTo required to refer to adjustedEffectiveDate, so ignored here
            // day count
            fraBuilder.dayCount(document.parseDayCountFraction(fraEl.getChild("dayCountFraction")));
            // notional
            CurrencyAmount notional = document.parseCurrencyAmount(fraEl.getChild("notional"));

            fraBuilder.currency(notional.Currency);
            fraBuilder.notional(notional.Amount);
            // fixed rate
            fraBuilder.fixedRate(document.parseDecimal(fraEl.getChild("fixedRate")));
            // index
            IList <Index> indexes = document.parseIndexes(fraEl);

            switch (indexes.Count)
            {
            case 1:
                fraBuilder.index((IborIndex)indexes[0]);
                break;

            case 2:
                fraBuilder.index((IborIndex)indexes[0]);
                fraBuilder.indexInterpolated((IborIndex)indexes[1]);
                break;

            default:
                throw new FpmlParseException("Expected one or two indexes, but found " + indexes.Count);
            }
            // discounting
            fraBuilder.discounting(FraDiscountingMethod.of(fraEl.getChild("fraDiscounting").Content));

            return(FraTrade.builder().info(tradeInfoBuilder.build()).product(fraBuilder.build()).build());
        }