Exemplo n.º 1
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));
            }
        }
Exemplo n.º 2
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());
        }
Exemplo n.º 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));
        }
Exemplo n.º 4
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());
        }
Exemplo n.º 5
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());
        }
Exemplo n.º 6
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");
        }
Exemplo n.º 7
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);
        }
Exemplo n.º 8
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");
            }
        }
        //-------------------------------------------------------------------------
        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());
        }