Exemple #1
0
 /**
  * Bootstrapper the credit curve from a single CDS, by making it have zero clean price.
  * Obviously the resulting credit (hazard) curve will be flat.
  *
  * @param tradeDate The 'current' date
  * @param stepinDate Date when party assumes ownership. This is normally today + 1 (T+1). Aka assignment date or effective date.
  * @param valueDate The valuation date. The date that values are PVed to. Is is normally today + 3 business days.  Aka cash-settle date.
  * @param startDate The protection start date. If protectStart = true, then protections starts at the beginning of the day, otherwise it
  * is at the end.
  * @param endDate The maturity (or end of protection) of  the CDS
  * @param fractionalParSpread - the (fractional) coupon that makes the CDS worth par (i.e. zero clean price)
  * @param payAccOnDefault Is the accrued premium paid in the event of a default
  * @param tenor The nominal step between premium payments (e.g. 3 months, 6 months).
  * @param stubType the stub convention
  * @param protectStart Does protection start at the beginning of the day
  * @param yieldCurve Curve from which payments are discounted
  * @param recoveryRate the recovery rate
  * @return The credit curve
  */
 public PiecewiseconstantHazardRate calibrateCreditCurve(
     DateTime tradeDate,
     DateTime stepinDate,
     DateTime valueDate,
     DateTime startDate,
     DateTime endDate,
     double fractionalParSpread,
     Boolean payAccOnDefault,
     int tenor,
     StubConvention stubType,
     Boolean protectStart,
     YieldTermStructure yieldCurve,
     double recoveryRate)
 {
     return(calibrateCreditCurve(
                tradeDate, stepinDate, valueDate, startDate, new DateTime[] { endDate },
                new double[] { fractionalParSpread }, payAccOnDefault, tenor, stubType, protectStart,
                yieldCurve, recoveryRate));
 }
Exemple #2
0
        /**
         * Bootstrapper the credit curve, by making each market CDS in turn have zero clean price.
         *
         * @param tradeDate The 'current' date
         * @param stepinDate Date when party assumes ownership. This is normally today + 1 (T+1). Aka assignment date or effective date.
         * @param valueDate The valuation date. The date that values are PVed to. Is is normally today + 3 business days.  Aka cash-settle date.
         * @param startDate The protection start date. If protectStart = true, then protections starts at the beginning of the day, otherwise it
         * is at the end.
         * @param endDates The maturities (or end of protection) of each of the CDSs - must be ascending
         * @param fractionalParSpreads - the (fractional) coupon that makes each CDS worth par (i.e. zero clean price)
         * @param payAccOnDefault Is the accrued premium paid in the event of a default
         * @param tenor The nominal step between premium payments (e.g. 3 months, 6 months).
         * @param stubType the stub convention
         * @param protectStart Does protection start at the beginning of the day
         * @param yieldCurve Curve from which payments are discounted
         * @param recoveryRate the recovery rate
         * @return The credit curve
         */
        public PiecewiseconstantHazardRate calibrateCreditCurve(
            DateTime tradeDate,
            DateTime stepinDate,
            DateTime valueDate,
            DateTime startDate,
            DateTime[] endDates,
            double[] fractionalParSpreads,
            Boolean payAccOnDefault,
            int tenor,
            StubConvention stubType,
            Boolean protectStart,
            YieldTermStructure yieldCurve,
            double recoveryRate)
        {
            int n = endDates.Length;

            CDS[] cds = new CDS[n];
            for (int i = 0; i < n; i++)
            {
                cds[i] = new CDS(0.01, 100000, endDates[i], CdsAnalyticFactory.getNextIMMDate(stepinDate), tradeDate,
                                 CdsAnalyticFactory.getPrevIMMDate(stepinDate), "Quarterly", recoveryRate, 3, 3);
            }
            return(calibrateCreditCurve(cds, fractionalParSpreads, yieldCurve));
        }
        //-------------------------------------------------------------------------
        // accrual schedule
        private static PeriodicSchedule parseAccrualSchedule(CsvRow row, string leg)
        {
            PeriodicSchedule.Builder builder = PeriodicSchedule.builder();
            // basics
            builder.startDate(LoaderUtils.parseDate(getValueWithFallback(row, leg, START_DATE_FIELD)));
            builder.endDate(LoaderUtils.parseDate(getValueWithFallback(row, leg, END_DATE_FIELD)));
            builder.frequency(Frequency.parse(getValue(row, leg, FREQUENCY_FIELD)));
            // adjustments
            BusinessDayAdjustment            dateAdj      = parseBusinessDayAdjustment(row, leg, DATE_ADJ_CNV_FIELD, DATE_ADJ_CAL_FIELD).orElse(BusinessDayAdjustment.NONE);
            Optional <BusinessDayAdjustment> startDateAdj = parseBusinessDayAdjustment(row, leg, START_DATE_CNV_FIELD, START_DATE_CAL_FIELD);
            Optional <BusinessDayAdjustment> endDateAdj   = parseBusinessDayAdjustment(row, leg, END_DATE_CNV_FIELD, END_DATE_CAL_FIELD);

            builder.businessDayAdjustment(dateAdj);
            if (startDateAdj.Present && !startDateAdj.get().Equals(dateAdj))
            {
                builder.startDateBusinessDayAdjustment(startDateAdj.get());
            }
            if (endDateAdj.Present && !endDateAdj.get().Equals(dateAdj))
            {
                builder.endDateBusinessDayAdjustment(endDateAdj.get());
            }
            // optionals
            builder.stubConvention(findValueWithFallback(row, leg, STUB_CONVENTION_FIELD).map(s => StubConvention.of(s)).orElse(StubConvention.SMART_INITIAL));
            findValue(row, leg, ROLL_CONVENTION_FIELD).map(s => LoaderUtils.parseRollConvention(s)).ifPresent(v => builder.rollConvention(v));
            findValue(row, leg, FIRST_REGULAR_START_DATE_FIELD).map(s => LoaderUtils.parseDate(s)).ifPresent(v => builder.firstRegularStartDate(v));
            findValue(row, leg, LAST_REGULAR_END_DATE_FIELD).map(s => LoaderUtils.parseDate(s)).ifPresent(v => builder.lastRegularEndDate(v));
            parseAdjustableDate(row, leg, OVERRIDE_START_DATE_FIELD, OVERRIDE_START_DATE_CNV_FIELD, OVERRIDE_START_DATE_CAL_FIELD).ifPresent(d => builder.overrideStartDate(d));
            return(builder.build());
        }
        //-------------------------------------------------------------------------
        public override void start(Stage primaryStage)
        {
            LocalDate today = LocalDate.now(ZoneId.systemDefault());

            // setup GUI elements
            Label      startLbl = new Label("Start date:");
            DatePicker startInp = new DatePicker(today);

            startLbl.LabelFor        = startInp;
            startInp.ShowWeekNumbers = false;

            Label      endLbl = new Label("End date:");
            DatePicker endInp = new DatePicker(today.plusYears(1));

            endLbl.LabelFor        = endInp;
            endInp.ShowWeekNumbers = false;

            Label freqLbl = new Label("Frequency:");
            ChoiceBox <Frequency> freqInp = new ChoiceBox <Frequency>(FXCollections.observableArrayList(Frequency.P1M, Frequency.P2M, Frequency.P3M, Frequency.P4M, Frequency.P6M, Frequency.P12M));

            freqLbl.LabelFor = freqInp;
            freqInp.Value    = Frequency.P3M;

            Label stubLbl = new Label("Stub:");
            ObservableList <StubConvention> stubOptions = FXCollections.observableArrayList(StubConvention.values());

            stubOptions.add(0, null);
            ChoiceBox <StubConvention> stubInp = new ChoiceBox <StubConvention>(stubOptions);

            stubLbl.LabelFor = stubInp;
            stubInp.Value    = StubConvention.SMART_INITIAL;

            Label rollLbl = new Label("Roll:");
            ChoiceBox <RollConvention> rollInp = new ChoiceBox <RollConvention>(FXCollections.observableArrayList(null, RollConventions.NONE, RollConventions.EOM, RollConventions.IMM, RollConventions.IMMAUD, RollConventions.IMMNZD, RollConventions.SFE));

            rollLbl.LabelFor = rollInp;
            rollInp.Value    = RollConventions.NONE;

            Label bdcLbl = new Label("Adjust:");
            ChoiceBox <BusinessDayConvention> bdcInp = new ChoiceBox <BusinessDayConvention>(FXCollections.observableArrayList(BusinessDayConventions.NO_ADJUST, BusinessDayConventions.FOLLOWING, BusinessDayConventions.MODIFIED_FOLLOWING, BusinessDayConventions.PRECEDING, BusinessDayConventions.MODIFIED_PRECEDING, BusinessDayConventions.MODIFIED_FOLLOWING_BI_MONTHLY, BusinessDayConventions.NEAREST));

            bdcLbl.LabelFor = bdcInp;
            bdcInp.Value    = BusinessDayConventions.MODIFIED_FOLLOWING;

            Label holidayLbl = new Label("Holidays:");
            ChoiceBox <HolidayCalendarId> holidayInp = new ChoiceBox <HolidayCalendarId>(FXCollections.observableArrayList(HolidayCalendarIds.CHZU, HolidayCalendarIds.GBLO, HolidayCalendarIds.EUTA, HolidayCalendarIds.FRPA, HolidayCalendarIds.JPTO, HolidayCalendarIds.NYFD, HolidayCalendarIds.NYSE, HolidayCalendarIds.USNY, HolidayCalendarIds.USGS, HolidayCalendarIds.NO_HOLIDAYS, HolidayCalendarIds.SAT_SUN));

            holidayLbl.LabelFor = holidayInp;
            holidayInp.Value    = HolidayCalendarIds.GBLO;

            TableView <SchedulePeriod> resultGrid = new TableView <SchedulePeriod>();
            TableColumn <SchedulePeriod, LocalDate> unadjustedCol = new TableColumn <SchedulePeriod, LocalDate>("Unadjusted dates");
            TableColumn <SchedulePeriod, LocalDate> adjustedCol   = new TableColumn <SchedulePeriod, LocalDate>("Adjusted dates");

            TableColumn <SchedulePeriod, LocalDate> resultUnadjStartCol = new TableColumn <SchedulePeriod, LocalDate>("Start");

            resultUnadjStartCol.CellValueFactory = new TableCallback <>(SchedulePeriod.meta().unadjustedStartDate());
            TableColumn <SchedulePeriod, LocalDate> resultUnadjEndCol = new TableColumn <SchedulePeriod, LocalDate>("End");

            resultUnadjEndCol.CellValueFactory = new TableCallback <>(SchedulePeriod.meta().unadjustedEndDate());
            TableColumn <SchedulePeriod, Period> resultUnadjLenCol = new TableColumn <SchedulePeriod, Period>("Length");

            resultUnadjLenCol.CellValueFactory = ReadOnlyCallback.of(sch => Period.between(sch.UnadjustedStartDate, sch.UnadjustedEndDate));

            TableColumn <SchedulePeriod, LocalDate> resultStartCol = new TableColumn <SchedulePeriod, LocalDate>("Start");

            resultStartCol.CellValueFactory = new TableCallback <>(SchedulePeriod.meta().startDate());
            TableColumn <SchedulePeriod, LocalDate> resultEndCol = new TableColumn <SchedulePeriod, LocalDate>("End");

            resultEndCol.CellValueFactory = new TableCallback <>(SchedulePeriod.meta().endDate());
            TableColumn <SchedulePeriod, Period> resultLenCol = new TableColumn <SchedulePeriod, Period>("Length");

            resultLenCol.CellValueFactory = ReadOnlyCallback.of(sch => sch.length());

            unadjustedCol.Columns.add(resultUnadjStartCol);
            unadjustedCol.Columns.add(resultUnadjEndCol);
            unadjustedCol.Columns.add(resultUnadjLenCol);
            adjustedCol.Columns.add(resultStartCol);
            adjustedCol.Columns.add(resultEndCol);
            adjustedCol.Columns.add(resultLenCol);
            resultGrid.Columns.add(unadjustedCol);
            resultGrid.Columns.add(adjustedCol);
            resultGrid.Placeholder = new Label("Schedule not yet generated");

            unadjustedCol.prefWidthProperty().bind(resultGrid.widthProperty().divide(2));
            adjustedCol.prefWidthProperty().bind(resultGrid.widthProperty().divide(2));
            resultUnadjStartCol.prefWidthProperty().bind(unadjustedCol.widthProperty().divide(3));
            resultUnadjEndCol.prefWidthProperty().bind(unadjustedCol.widthProperty().divide(3));
            resultUnadjLenCol.prefWidthProperty().bind(unadjustedCol.widthProperty().divide(3));
            resultStartCol.prefWidthProperty().bind(adjustedCol.widthProperty().divide(3));
            resultEndCol.prefWidthProperty().bind(adjustedCol.widthProperty().divide(3));
            resultLenCol.prefWidthProperty().bind(adjustedCol.widthProperty().divide(3));

            // setup generation button
            // this uses the GUI thread which is not the best idea
            Button btn = new Button();

            btn.Text     = "Generate";
            btn.OnAction = @event =>
            {
                LocalDate             start  = startInp.Value;
                LocalDate             end    = endInp.Value;
                Frequency             freq   = freqInp.Value;
                StubConvention        stub   = stubInp.Value;
                RollConvention        roll   = rollInp.Value;
                HolidayCalendarId     holCal = holidayInp.Value;
                BusinessDayConvention bdc    = bdcInp.Value;
                BusinessDayAdjustment bda    = BusinessDayAdjustment.of(bdc, holCal);
                PeriodicSchedule      defn   = PeriodicSchedule.builder().startDate(start).endDate(end).frequency(freq).businessDayAdjustment(bda).stubConvention(stub).rollConvention(roll).build();
                try
                {
                    Schedule schedule = defn.createSchedule(REF_DATA);
                    Console.WriteLine(schedule);
                    resultGrid.Items = FXCollections.observableArrayList(schedule.Periods);
                }
                catch (ScheduleException ex)
                {
                    resultGrid.Items       = FXCollections.emptyObservableList();
                    resultGrid.Placeholder = new Label(ex.Message);
                    Console.WriteLine(ex.Message);
                }
            };

            // layout the components
            GridPane gp = new GridPane();

            gp.Hgap    = 10;
            gp.Vgap    = 10;
            gp.Padding = new Insets(0, 10, 0, 10);
            gp.add(startLbl, 1, 1);
            gp.add(startInp, 2, 1);
            gp.add(endLbl, 1, 2);
            gp.add(endInp, 2, 2);
            gp.add(freqLbl, 1, 3);
            gp.add(freqInp, 2, 3);
            gp.add(bdcLbl, 3, 1);
            gp.add(bdcInp, 4, 1);
            gp.add(holidayLbl, 3, 2);
            gp.add(holidayInp, 4, 2);
            gp.add(stubLbl, 3, 3);
            gp.add(stubInp, 4, 3);
            gp.add(rollLbl, 3, 4);
            gp.add(rollInp, 4, 4);
            gp.add(btn, 3, 5, 2, 1);
            gp.add(resultGrid, 1, 7, 4, 1);

            BorderPane bp    = new BorderPane(gp);
            Scene      scene = new Scene(bp, 600, 600);

            // launch
            primaryStage.Title = "Periodic schedule generator";
            primaryStage.Scene = scene;
            primaryStage.show();
        }
        /// <summary>
        /// This mimics JpmcdsDateListMakeRegular. Produces a set of ascending dates by following the rules:<para>
        /// If the stub is at the front end, we role backwards from the endDate at an integer multiple of the specified step size (e.g. 3M),
        /// adding these date until we pass the startDate(this date is not added). If the stub type is short, the startDate is added (as the first date), hence the first period
        /// will be less than (or equal to) the remaining periods. If the stub type is long, the startDate is also added, but the date immediately
        /// </para>
        /// after that is removed, so the first period is longer than the remaining.<para>
        /// If the stub is at the back end, we role forward from the startDate at an integer multiple of the specified step size (e.g. 3M),
        /// adding these date until we pass the endDate(this date is not added). If the stub type is short, the endDate is added (as the last date), hence the last period
        /// will be less than (or equal to) the other periods. If the stub type is long, the endDate is also added, but the date immediately
        /// before that is removed, so the last period is longer than the others.
        ///
        /// </para>
        /// </summary>
        /// <param name="startDate"> The start date - this will be the first entry in the list </param>
        /// <param name="endDate"> The end date - this will be the last entry in the list </param>
        /// <param name="step"> the step period (e.g. 3M - will produce dates every 3 months, with adjustments at the beginning or end based on stub type) </param>
        /// <param name="stubType"> the stub convention </param>
        /// <returns> an array of DateTime </returns>
        public static DateTime[] getUnadjustedDates(DateTime startDate, DateTime endDate, int step, StubConvention stubType)
        {
            if (DateTime.Compare(startDate, endDate) == 0)
            { // this can only happen if protectionStart == true
                DateTime[] tempDates = new DateTime[2];
                tempDates[0] = startDate;
                tempDates[1] = endDate;
                return(tempDates);
            }
            OMLib.Conventions.DayCount.ActualActual dc = new OMLib.Conventions.DayCount.ActualActual(OMLib.Conventions.DayCount.ActualActual.Convention.ISDA);

            double days    = (double)365.0 * (step / 12.0);
            int    nApprox = 3 + (int)(dc.DayCount(startDate, endDate) / days);

            IList <DateTime> dates = new List <DateTime>(nApprox);

            // stub at front end, so start at endDate and work backwards
            if (stubType == StubConvention.SHORT_FINAL || stubType == StubConvention.LONG_FINAL || stubType == StubConvention.NONE)
            {
                int      intervals = 0;
                DateTime tDate     = endDate;
                while (DateTime.Compare(tDate, startDate) > 0)
                {
                    dates.Add(tDate);
                    int tStep = step * (++intervals); // this mimics ISDA c code, rather than true market convention
                    tDate = endDate.AddMonths(tStep);
                }

                int n = dates.Count;
                if (tDate.Equals(startDate) || n == 1 || stubType == StubConvention.SHORT_INITIAL)
                {
                    dates.Add(startDate);
                }
                else
                {
                    // long front stub - remove the last date entry in the list and replace it with startDate
                    dates.RemoveAt(n - 1);
                    dates.Add(startDate);
                }

                int        m   = dates.Count;
                DateTime[] res = new DateTime[m];
                // want to output in ascending chronological order, so need to reverse the list
                int j = m - 1;
                for (int i = 0; i < m; i++, j--)
                {
                    res[j] = dates[i];
                }
                return(res);

                // stub at back end, so start at startDate and work forward
            }
            else
            {
                int      intervals = 0;
                DateTime tDate     = startDate;
                while (DateTime.Compare(tDate, endDate) < 0)
                {
                    dates.Add(tDate);
                    int tStep = step * (++intervals); // this mimics ISDA c code, rather than true market convention
                    tDate = startDate.AddMonths(tStep);
                }

                int n = dates.Count;
                if (tDate.Equals(endDate) || n == 1 || stubType == StubConvention.SHORT_FINAL)
                {
                    dates.Add(endDate);
                }
                else
                {
                    // long back stub - remove the last date entry in the list and replace it with endDate
                    dates.RemoveAt(n - 1);
                    dates.Add(endDate);
                }
                DateTime[] res = new DateTime[dates.Count];
                res = dates.ToArray();
                return(res);
            }
        }
 /// <summary>
 /// Mimics JpmcdsCdsFeeLegMake </summary>
 /// <param name="startDate"> The protection start date </param>
 /// <param name="endDate"> The protection end date </param>
 /// <param name="step"> The period or frequency at which payments are made (e.g. every three months) </param>
 /// <param name="stubType"> The stub convention </param>
 /// <param name="businessdayAdjustmentConvention"> options are 'following' or 'proceeding' </param>
 /// <param name="calandar"> A holiday calendar </param>
 /// <param name="protectionStart"> If true, protection starts are the beginning rather than end of day (protection still ends at end of day). </param>
 public IsdaPremiumLegSchedule(DateTime startDate, DateTime endDate, int step,
                               StubConvention stubType, QLNet.BusinessDayConvention businessdayAdjustmentConvention, QLNet.Calendar calandar, bool protectionStart) : this(getUnadjustedDates(startDate, endDate, step, stubType), businessdayAdjustmentConvention, calandar, protectionStart)
 {
 }
Exemple #7
0
 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.of(fixedRate, THIRTY_U_360)).build());
 }
Exemple #8
0
        /**
         * Set up a strip of increasing maturity CDSs that have some coupons in common.  The trade date, step-in date and valuation date and
         * accrual start date are all common, as is the payment frequency. The maturities are expressed as integer multiples of the
         * payment interval from a reference date (the next IMM date after the trade date for standard CDSs) - this guarantees that premiums
         * will be the same across several CDSs.
         * @param tradeDate The trade date
         * @param stepinDate (aka Protection Effective sate or assignment date). Date when party assumes ownership. This is usually T+1. This is when protection
         * (and risk) starts in terms of the model. Note, this is sometimes just called the Effective Date, however this can cause
         * confusion with the legal effective date which is T-60 or T-90.
         * @param cashSettlementDate The cash settlement date. The date that values are PVed to. Is is normally today + 3 business days.
         * @param accStartDate  Accrual Start Date. This is when the CDS nominally starts in terms of premium payments.  i.e. the number
         * of days in the first period (and thus the amount of the first premium payment) is counted from this date.
         * @param maturityReferanceDate A reference date that maturities are measured from. For standard CDSSs, this is the next IMM  date after
         * the trade date, so the actually maturities will be some fixed periods after this.
         * @param maturityIndexes The maturities are fixed integer multiples of the payment interval, so for 6M, 1Y and 2Y tenors with a 3M
         * payment interval, would require 2, 4, and 8 as the indices
         * @param payAccOnDefault Is the accrued premium paid in the event of a default
         * @param paymentInterval The nominal step between premium payments (e.g. 3 months, 6 months).
         * @param stubType the stub convention
         * @param protectStart If protectStart = true, then protections starts at the beginning of the day, otherwise it is at the end.
         * @param recoveryRate The recovery rate
         * @param businessdayAdjustmentConvention How are adjustments for non-business days made
         * @param calendar HolidayCalendar defining what is a non-business day
         * @param accrualDayCount Day count used for accrual
         * @param curveDayCount Day count used on curve (NOTE ISDA uses ACT/365 and it is not recommended to change this)
         */
        public MultiCdsAnalytic(
            DateTime tradeDate,
            DateTime stepinDate,
            DateTime cashSettlementDate,
            DateTime accStartDate,
            DateTime maturityReferanceDate,
            int[] maturityIndexes,
            Boolean payAccOnDefault,
            int paymentInterval,
            StubConvention stubType,
            Boolean protectStart,
            double recoveryRate,
            QLNet.BusinessDayConvention businessdayAdjustmentConvention,
            QLNet.Calendar calendar,
            Enums.DayCount accrualDayCount,
            Enums.DayCount curveDayCount)
        {
            OMLib.Conventions.DayCount.Thirty360 swapDCC        = new OMLib.Conventions.DayCount.Thirty360();
            OMLib.Conventions.DayCount.Actual360 moneyMarketDCC = new OMLib.Conventions.DayCount.Actual360();
            OMLib.Conventions.DayCount.Actual365 curveDCC       = new OMLib.Conventions.DayCount.Actual365();

            _nMaturities     = maturityIndexes.Length;
            _payAccOnDefault = payAccOnDefault;


            _accStart = DateTime.Compare(accStartDate, tradeDate) < 0 ?
                        -curveDCC.YearFraction(accStartDate, tradeDate) :
                        curveDCC.YearFraction(tradeDate, accStartDate);
            DateTime temp = DateTime.Compare(stepinDate, accStartDate) > 0 ? stepinDate : accStartDate;
            DateTime effectiveStartDate = protectStart ? temp.AddDays(-1) : temp;

            _cashSettlementTime       = curveDCC.YearFraction(tradeDate, cashSettlementDate);
            _effectiveProtectionStart = curveDCC.YearFraction(tradeDate, effectiveStartDate);
            _lgd = 1 - recoveryRate;

            DateTime[] maturities = new DateTime[_nMaturities];
            _protectionEnd = new double[_nMaturities];
            int period = paymentInterval;

            for (int i = 0; i < _nMaturities; i++)
            {
                int tStep = period * maturityIndexes[i];
                maturities[i]     = maturityReferanceDate.AddMonths(tStep);
                _protectionEnd[i] = curveDCC.YearFraction(tradeDate, maturities[i]);
            }

            IsdaPremiumLegSchedule fullPaymentSchedule = new IsdaPremiumLegSchedule(accStartDate, maturities[_nMaturities - 1], period,
                                                                                    stubType, businessdayAdjustmentConvention, calendar, protectStart);
            //remove already expired coupons
            IsdaPremiumLegSchedule paymentSchedule = fullPaymentSchedule.truncateSchedule(stepinDate);
            int couponOffset = fullPaymentSchedule.getNumPayments() - paymentSchedule.getNumPayments();

            _totalPayments   = paymentSchedule.getNumPayments();
            _standardCoupons = new CdsCoupon[_totalPayments - 1];
            for (int i = 0; i < (_totalPayments - 1); i++)
            {     //The last coupon is actually a terminal coupon, so not included here
                _standardCoupons[i] = new CdsCoupon(
                    tradeDate, paymentSchedule.getAccPaymentDateTriplet(i), protectStart, accrualDayCount, curveDayCount);
            }

            //find the terminal coupons
            _terminalCoupons    = new CdsCoupon[_nMaturities];
            _matIndexToPayments = new int[_nMaturities];
            _accruedDays        = new int[_nMaturities];
            _accrued            = new double[_nMaturities];
            long secondJulianDate = stepinDate.Ticks;

            for (int i = 0; i < _nMaturities; i++)
            {
                int index = fullPaymentSchedule.getNominalPaymentDateIndex(maturities[i]);

                //maturity is unadjusted, but if protectionStart=true (i.e. standard CDS) there is effectively an extra day of accrued interest
                DateTime accEnd = protectStart ? maturities[i].AddDays(1) : maturities[i];
                _terminalCoupons[i] = new CdsCoupon(
                    tradeDate, fullPaymentSchedule.getAccStartDate(index), accEnd,
                    fullPaymentSchedule.getPaymentDate(index), protectStart);
                _matIndexToPayments[i] = index - couponOffset;
                //This will only matter for the edge case when the trade date is 1 day before maturity
                DateTime tDate2 = _matIndexToPayments[i] < 0 ?
                                  fullPaymentSchedule.getAccStartDate(couponOffset - 1) : paymentSchedule.getAccStartDate(0);
                long firstJulianDate = tDate2.Ticks;
                _accruedDays[i] = secondJulianDate > firstJulianDate ? (int)(secondJulianDate - firstJulianDate) : 0;
                _accrued[i]     = DateTime.Compare(tDate2, stepinDate) < 0 ? swapDCC.YearFraction(tDate2, stepinDate) : 0.0;
            }
        }
        // ibor 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());
        }
        // parse a trade based on a convention
        internal static SwapTrade parseWithConvention(CsvRow row, TradeInfo info, TradeCsvInfoResolver resolver, string conventionStr)
        {
            BuySell                      buySell              = LoaderUtils.parseBuySell(row.getValue(BUY_SELL_FIELD));
            double                       notional             = LoaderUtils.parseDouble(row.getValue(NOTIONAL_FIELD));
            double                       fixedRate            = LoaderUtils.parseDoublePercent(row.getValue(FIXED_RATE_FIELD));
            Optional <Period>            periodToStartOpt     = row.findValue(PERIOD_TO_START_FIELD).map(s => LoaderUtils.parsePeriod(s));
            Optional <Tenor>             tenorOpt             = row.findValue(TENOR_FIELD).map(s => LoaderUtils.parseTenor(s));
            Optional <LocalDate>         startDateOpt         = row.findValue(START_DATE_FIELD).map(s => LoaderUtils.parseDate(s));
            Optional <LocalDate>         endDateOpt           = row.findValue(END_DATE_FIELD).map(s => LoaderUtils.parseDate(s));
            Optional <RollConvention>    rollCnvOpt           = row.findValue(ROLL_CONVENTION_FIELD).map(s => LoaderUtils.parseRollConvention(s));
            Optional <StubConvention>    stubCnvOpt           = row.findValue(STUB_CONVENTION_FIELD).map(s => StubConvention.of(s));
            Optional <LocalDate>         firstRegStartDateOpt = row.findValue(FIRST_REGULAR_START_DATE_FIELD).map(s => LoaderUtils.parseDate(s));
            Optional <LocalDate>         lastRegEndDateOpt    = row.findValue(LAST_REGULAR_END_DATE_FIELD).map(s => LoaderUtils.parseDate(s));
            BusinessDayConvention        dateCnv              = row.findValue(DATE_ADJ_CNV_FIELD).map(s => LoaderUtils.parseBusinessDayConvention(s)).orElse(BusinessDayConventions.MODIFIED_FOLLOWING);
            Optional <HolidayCalendarId> dateCalOpt           = row.findValue(DATE_ADJ_CAL_FIELD).map(s => HolidayCalendarId.of(s));
            double?                      fxRateOpt            = row.findValue(FX_RATE_FIELD).map(str => LoaderUtils.parseDouble(str));

            // explicit dates take precedence over relative ones
            if (startDateOpt.Present && endDateOpt.Present)
            {
                if (periodToStartOpt.Present || tenorOpt.Present)
                {
                    throw new System.ArgumentException("Swap trade had invalid combination of fields. When these fields are found " + ImmutableList.of(CONVENTION_FIELD, START_DATE_FIELD, END_DATE_FIELD) + " then these fields must not be present " + ImmutableList.of(PERIOD_TO_START_FIELD, TENOR_FIELD));
                }
                LocalDate startDate = startDateOpt.get();
                LocalDate endDate   = endDateOpt.get();
                SwapTrade trade     = createSwap(info, conventionStr, startDate, endDate, buySell, notional, fixedRate, fxRateOpt);
                return(adjustTrade(trade, rollCnvOpt, stubCnvOpt, firstRegStartDateOpt, lastRegEndDateOpt, dateCnv, dateCalOpt));
            }

            // start date + tenor
            if (startDateOpt.Present && tenorOpt.Present)
            {
                if (periodToStartOpt.Present || endDateOpt.Present)
                {
                    throw new System.ArgumentException("Swap trade had invalid combination of fields. When these fields are found " + ImmutableList.of(CONVENTION_FIELD, START_DATE_FIELD, TENOR_FIELD) + " then these fields must not be present " + ImmutableList.of(PERIOD_TO_START_FIELD, END_DATE_FIELD));
                }
                LocalDate startDate = startDateOpt.get();
                Tenor     tenor     = tenorOpt.get();
                LocalDate endDate   = startDate.plus(tenor);
                SwapTrade trade     = createSwap(info, conventionStr, startDate, endDate, buySell, notional, fixedRate, fxRateOpt);
                return(adjustTrade(trade, rollCnvOpt, stubCnvOpt, firstRegStartDateOpt, lastRegEndDateOpt, dateCnv, dateCalOpt));
            }

            // relative dates
            if (periodToStartOpt.Present && tenorOpt.Present && info.TradeDate.Present)
            {
                if (startDateOpt.Present || endDateOpt.Present)
                {
                    throw new System.ArgumentException("Swap trade had invalid combination of fields. When these fields are found " + ImmutableList.of(CONVENTION_FIELD, PERIOD_TO_START_FIELD, TENOR_FIELD, TRADE_DATE_FIELD) + " then these fields must not be present " + ImmutableList.of(START_DATE_FIELD, END_DATE_FIELD));
                }
                LocalDate tradeDate     = info.TradeDate.get();
                Period    periodToStart = periodToStartOpt.get();
                Tenor     tenor         = tenorOpt.get();
                if (fxRateOpt.HasValue)
                {
                    XCcyIborIborSwapConvention convention = XCcyIborIborSwapConvention.of(conventionStr);
                    double    notionalFlat = notional * fxRateOpt.Value;
                    SwapTrade trade        = convention.createTrade(tradeDate, periodToStart, tenor, buySell, notional, notionalFlat, fixedRate, resolver.ReferenceData);
                    trade = trade.toBuilder().info(info).build();
                    return(adjustTrade(trade, rollCnvOpt, stubCnvOpt, firstRegStartDateOpt, lastRegEndDateOpt, dateCnv, dateCalOpt));
                }
                else
                {
                    SingleCurrencySwapConvention convention = SingleCurrencySwapConvention.of(conventionStr);
                    SwapTrade trade = convention.createTrade(tradeDate, periodToStart, tenor, buySell, notional, fixedRate, resolver.ReferenceData);
                    trade = trade.toBuilder().info(info).build();
                    return(adjustTrade(trade, rollCnvOpt, stubCnvOpt, firstRegStartDateOpt, lastRegEndDateOpt, dateCnv, dateCalOpt));
                }
            }

            // no match
            throw new System.ArgumentException("Swap trade had invalid combination of fields. These fields are mandatory:" + ImmutableList.of(BUY_SELL_FIELD, NOTIONAL_FIELD, FIXED_RATE_FIELD) + " and one of these combinations is mandatory: " + ImmutableList.of(CONVENTION_FIELD, TRADE_DATE_FIELD, PERIOD_TO_START_FIELD, TENOR_FIELD) + " or " + ImmutableList.of(CONVENTION_FIELD, START_DATE_FIELD, TENOR_FIELD) + " or " + ImmutableList.of(CONVENTION_FIELD, START_DATE_FIELD, END_DATE_FIELD));
        }