Beispiel #1
0
        public PremiumLegElement(double protectionStart, CdsCoupon coupon, YieldTermStructure yieldCurve, int creditCurveKnot, double[] knots, AccrualOnDefaultFormulae formula) : base(coupon, yieldCurve, creditCurveKnot)
        {
            _coupon = coupon;

            _creditCurveKnot = creditCurveKnot;
            _formula         = formula;
            if (formula == AccrualOnDefaultFormulae.ORIGINAL_ISDA)
            {
                _omega = 1.0 / 730;
            }
            else
            {
                _omega = 0.0;
            }

            _knots = DoublesScheduleGenerator.truncateSetInclusive(Math.Max(_coupon.getEffStart(), protectionStart), _coupon.getEffEnd(), knots);
            _n     = _knots.Length;
            _rt    = new double[_n];
            _p     = new double[_n];
            for (int i = 0; i < _n; i++)
            {
                _rt[i] = yieldCurve.getRT_(_knots[i]);
                _p[i]  = Math.Exp(-_rt[i]);
            }
        }
        private double calculateSinglePeriodAccrualOnDefault(
            CdsCoupon coupon,
            double effectiveStart,
            double[] integrationPoints,
            YieldTermStructure yieldCurve,
            PiecewiseconstantHazardRate creditCurve)
        {
            double start = Math.Max(coupon.getEffStart(), effectiveStart);

            if (start >= coupon.getEffEnd())
            {
                return(0.0); //this coupon has already expired
            }

            double[] knots = DoublesScheduleGenerator.truncateSetInclusive(start, coupon.getEffEnd(), integrationPoints);

            double t   = knots[0];
            double ht0 = creditCurve.getRT_(t);
            double rt0 = yieldCurve.getRT_(t);
            double b0  = Math.Exp(-rt0 - ht0); // this is the risky discount factor

            double t0     = t - coupon.getEffStart() + _omega;
            double pv     = 0.0;
            int    nItems = knots.Length;

            for (int j = 1; j < nItems; ++j)
            {
                t = knots[j];
                double ht1 = creditCurve.getRT_(t);
                double rt1 = yieldCurve.getRT_(t);
                double b1  = Math.Exp(-rt1 - ht1);

                double dt = knots[j] - knots[j - 1];

                double dht  = ht1 - ht0;
                double drt  = rt1 - rt0;
                double dhrt = dht + drt;

                double tPV;
                double t1 = t - coupon.getEffStart() + _omega;
                if (Math.Abs(dhrt) < 1e-5)
                {
                    tPV = dht * b0 * (t0 * Maths.Epsilon.epsilon(-dhrt) + dt * Maths.Epsilon.epsilonP(-dhrt));
                }
                else
                {
                    tPV = dht / dhrt * (t0 * b0 - t1 * b1 + dt / dhrt * (b0 - b1));
                }
                t0  = t1;
                pv += tPV;
                ht0 = ht1;
                rt0 = rt1;
                b0  = b1;
            }
            return(coupon.getYFRatio() * pv);
        }
Beispiel #3
0
        public CDS(double Coupon, double notional, DateTime maturity, DateTime firstpaymentday, DateTime tradedate,
                   DateTime formerpaymentday, string frequency, double recovery, int settlement, int Cashsettlement)
        {
            //  Product Setup
            OMLib.Conventions.DayCount.Actual360 AccuralDCC = new OMLib.Conventions.DayCount.Actual360();
            OMLib.Conventions.DayCount.Actual365 curveDCC   = new OMLib.Conventions.DayCount.Actual365();
            Calendar calendar = new UnitedStates();

            formerpaymentday = calendar.adjust(formerpaymentday, BusinessDayConvention.Following);
            int accrued = AccuralDCC.DayCount(formerpaymentday, calendar.adjust(tradedate, BusinessDayConvention.Following)) + 1;

            this.accruedday       = accrued;
            this.marketvalue      = new double();
            this.accruedamt       = notional * Coupon * accrued / 360;
            this.Notional         = notional;
            this._payAccOnDefault = true;
            OMLib.Conventions.BusinessDayConvention convention = new OMLib.Conventions.BusinessDayConvention(Enums.BusinessDayConvention.ModifiedFollowing, tradedate);
            this.tradedate = calendar.adjust(tradedate, BusinessDayConvention.ModifiedFollowing); /*convention.AdjustedDate;*/

            this.Recovery         = recovery;
            convention            = new OMLib.Conventions.BusinessDayConvention(Enums.BusinessDayConvention.ModifiedFollowing, firstpaymentday);
            this.firstpaymentdate = CdsAnalyticFactory.getNextIMMDate(tradedate);   /*convention.AdjustedDate;*/

            convention             = new OMLib.Conventions.BusinessDayConvention(Enums.BusinessDayConvention.ModifiedFollowing, formerpaymentday);
            this.formerpaymentdate = CdsAnalyticFactory.getPrevIMMDate(tradedate);//calendar.adjust(formerpaymentday,BusinessDayConvention.ModifiedFollowing); /*convention.AdjustedDate;*/
            this.Maturity          = maturity;
            this.PremiumRate       = Coupon;
            this.Frequency         = frequency;
            this.Cashsettlement    = Cashsettlement;
            DateTime valueDate = calendar.adjust(tradedate.AddDays(Cashsettlement));

            convention            = new OMLib.Conventions.BusinessDayConvention(Enums.BusinessDayConvention.ModifiedFollowing, tradedate.AddDays(3));
            this.evalDate         = calendar.adjust(tradedate.AddDays(settlement), BusinessDayConvention.ModifiedFollowing); /*convention.AdjustedDate;*/
            this.Payment_Schedule = PremiumDates(this.Maturity, CdsAnalyticFactory.getNextIMMDate(tradedate), this.Frequency);
            QLNet.Calendar.OrthodoxImpl cal             = new Calendar.OrthodoxImpl();
            IsdaPremiumLegSchedule      paymentSchedule = new IsdaPremiumLegSchedule(formerpaymentdate, maturity, payment_interval, StubConvention.SHORT_INITIAL, QLNet.BusinessDayConvention.ModifiedFollowing, cal, true);

            _coupons = CdsCoupon.makeCoupons(tradedate, paymentSchedule, true, ACT_360, ACT_365);
            OMLib.Conventions.DayCount.Actual365 CurveDCC = new OMLib.Conventions.DayCount.Actual365();

            DateTime effectiveStartDate = tradedate;

            _accStart = DateTime.Compare(formerpaymentdate, tradedate) < 0 ?-CurveDCC.YearFraction(formerpaymentdate, tradedate) :
                        CurveDCC.YearFraction(tradedate, formerpaymentdate);
            _cashSettlementTime       = CurveDCC.YearFraction(tradedate, valueDate);
            _effectiveProtectionStart = DateTime.Compare(effectiveStartDate, tradedate) < 0 ?
                                        -CurveDCC.YearFraction(effectiveStartDate, tradedate) :
                                        CurveDCC.YearFraction(tradedate, effectiveStartDate);
            _protectionEnd = CurveDCC.YearFraction(tradedate, maturity);


            DateTime accStart = paymentSchedule.getAccStartDate(0);
        }
        public double pvPremiumLegCreditSensitivity(
            CDS cds,
            YieldTermStructure yieldCurve,
            PiecewiseconstantHazardRate creditCurve,
            int creditCurveNode)
        {
            if (cds.getProtectionEnd() <= 0.0)
            { //short cut already expired CDSs
                return(0.0);
            }

            int    n       = cds.getNumPayments();
            double pvSense = 0.0;

            for (int i = 0; i < n; i++)
            {
                CdsCoupon c             = cds.getCoupon(i);
                double    paymentTime   = c.getPaymentTime();
                double    creditObsTime = c.getEffEnd();
                double    dqdh          = creditCurve.getSingleNodeDiscountFactorSensitivity(creditObsTime, creditCurveNode);
                if (dqdh == 0)
                {
                    continue;
                }
                double p = Math.Exp(-yieldCurve.getRT_(paymentTime));
                pvSense += c.getYearFrac() * p * dqdh;
            }

            if (cds.isPayAccOnDefault())
            {
                double   start = cds.getNumPayments() == 1 ? cds.getEffectiveProtectionStart() : cds.getAccStart();
                double[] integrationSchedule = DoublesScheduleGenerator.getIntegrationsPoints(start, cds.getProtectionEnd(), yieldCurve, creditCurve);

                double accPVSense = 0.0;
                for (int i = 0; i < n; i++)
                {
                    accPVSense += calculateSinglePeriodAccrualOnDefaultCreditSensitivity(
                        cds.getCoupon(i),
                        cds.getEffectiveProtectionStart(), integrationSchedule, yieldCurve, creditCurve, creditCurveNode);
                }
                pvSense += accPVSense;
            }

            double df = Math.Exp(-yieldCurve.getRT_(cds.getCashSettleTime()));

            pvSense /= df;
            return(pvSense);
        }
Beispiel #5
0
 public CouponOnlyElement(CdsCoupon coupon, YieldTermStructure yieldCurve, int creditCurveKnot)
 {
     _riskLessValue   = coupon.getYearFrac() * Math.Exp(-yieldCurve.getRT_(coupon.getPaymentTime()));
     _effEnd          = coupon.getEffEnd();
     _creditCurveKnot = creditCurveKnot;
 }
        public CreditCurveCalibrator(MultiCdsAnalytic multiCDS, YieldTermStructure yieldCurve, AccrualOnDefaultFormulae formula)
        {
            _nCDS        = multiCDS.getNumMaturities();
            _t           = new double[_nCDS];
            _lgd         = new double[_nCDS];
            _unitAccured = new double[_nCDS];
            for (int i = 0; i < _nCDS; i++)
            {
                _t[i]           = multiCDS.getProtectionEnd(i);
                _lgd[i]         = multiCDS.getLGD();
                _unitAccured[i] = multiCDS.getAccruedPremiumPerUnitSpread(i);
            }
            _valuationDF = Math.Exp(-yieldCurve.getRT_(multiCDS.getCashSettleTime()));

            //This is the global set of knots - it will be truncated down for the various leg elements
            //TODO this will not match ISDA C for forward starting (i.e. accStart > tradeDate) CDS, and will give different answers
            //if the Markit 'fix' is used in that case
            double[] knots = DoublesScheduleGenerator.getIntegrationsPoints(
                multiCDS.getEffectiveProtectionStart(), _t[_nCDS - 1], yieldCurve.t.ToArray(), _t.ToArray());

            //The protection leg
            _protElems = new ProtectionLegElement[_nCDS];
            for (int i = 0; i < _nCDS; i++)
            {
                _protElems[i] = new ProtectionLegElement(
                    i == 0 ? multiCDS.getEffectiveProtectionStart() : _t[i - 1], _t[i], yieldCurve, i, knots);
            }

            _cds2CouponsMap      = new int[_nCDS][];
            _cdsCouponsUpdateMap = new int[_nCDS][];
            _knot2CouponsMap     = new int[_nCDS][];

            List <CdsCoupon> allCoupons = new List <CdsCoupon>(_nCDS + multiCDS.getTotalPayments() - 1);

            allCoupons.AddRange(multiCDS.getStandardCoupons().ToList());
            allCoupons.Add(multiCDS.getTerminalCoupon(_nCDS - 1));
            int[] temp = new int[multiCDS.getTotalPayments()];
            for (int i = 0; i < multiCDS.getTotalPayments(); i++)
            {
                temp[i] = i;
            }
            _cds2CouponsMap[_nCDS - 1] = temp;

            //complete the list of unique coupons and fill out the cds2CouponsMap
            for (int i = 0; i < _nCDS - 1; i++)
            {
                CdsCoupon c         = multiCDS.getTerminalCoupon(i);
                int       nPayments = Math.Max(0, multiCDS.getPaymentIndexForMaturity(i)) + 1;
                _cds2CouponsMap[i] = new int[nPayments];
                for (int jj = 0; jj < nPayments - 1; jj++)
                {
                    _cds2CouponsMap[i][jj] = jj;
                }
                //because of business-day adjustment, a terminal coupon can be identical to a standard coupon,
                //in which case it is not added again
                int index = allCoupons.IndexOf(c);
                if (index == -1)
                {
                    index = allCoupons.Count;
                    allCoupons.Add(c);
                }
                _cds2CouponsMap[i][nPayments - 1] = index;
            }

            //loop over the coupons to populate the couponUpdateMap
            _nCoupons = allCoupons.Count;
            int[] sizes = new int[_nCDS];
            int[] map   = new int[_nCoupons];
            for (int i = 0; i < _nCoupons; i++)
            {
                CdsCoupon c     = allCoupons[i];
                int       index = Array.BinarySearch(_t, c.getEffEnd());
                if (index < 0)
                {
                    index = -(index + 1);
                }
                sizes[index]++;
                map[i] = index;
            }

            //make the protection leg elements

            if (multiCDS.isPayAccOnDefault())
            {
                _premElems = new PremiumLegElement[_nCoupons];
                for (int i = 0; i < _nCoupons; i++)
                {
                    _premElems[i] = new PremiumLegElement(multiCDS.getEffectiveProtectionStart(), allCoupons[i], yieldCurve, map[i],
                                                          knots, formula);
                }
            }
            else
            {
                _premElems = new CouponOnlyElement[_nCoupons];
                for (int i = 0; i < _nCoupons; i++)
                {
                    _premElems[i] = new CouponOnlyElement(allCoupons[i], yieldCurve, map[i]);
                }
            }

            //sort a map from coupon to curve node, to a map from curve node to coupons
            for (int i = 0; i < _nCDS; i++)
            {
                _knot2CouponsMap[i] = new int[sizes[i]];
            }
            int[] indexes = new int[_nCDS];
            for (int i = 0; i < _nCoupons; i++)
            {
                int index = map[i];
                _knot2CouponsMap[index][indexes[index]++] = i;
            }

            //the cdsCouponsUpdateMap is the intersection of the cds2CouponsMap and knot2CouponsMap
            for (int i = 0; i < _nCDS; i++)
            {
                _cdsCouponsUpdateMap[i] = intersection(_knot2CouponsMap[i], _cds2CouponsMap[i]);
            }
        }
        public CreditCurveCalibrator(CDS[] cds, YieldTermStructure yieldCurve, AccrualOnDefaultFormulae formula)
        {
            _nCDS = cds.Length;
            Boolean payAccOnDefault = cds[0].isPayAccOnDefault();
            double  accStart        = cds[0].getAccStart();
            double  effectProtStart = cds[0].getEffectiveProtectionStart();
            double  cashSettleTime  = cds[0].getCashSettleTime();

            _t    = new double[_nCDS];
            _t[0] = cds[0].getProtectionEnd();
            //Check all the CDSs match
            for (int i = 1; i < _nCDS; i++)
            {
                _t[i] = cds[i].getProtectionEnd();
            }

            _valuationDF = Math.Exp(-yieldCurve.getRT_(cashSettleTime));
            _lgd         = new double[_nCDS];
            _unitAccured = new double[_nCDS];
            for (int i = 0; i < _nCDS; i++)
            {
                _lgd[i]         = cds[i].getLGD();
                _unitAccured[i] = cds[i].getAccruedYearFraction();
            }

            //This is the global set of knots - it will be truncated down for the various leg elements
            //TODO this will not match ISDA C for forward starting (i.e. accStart > tradeDate) CDS, and will give different answers
            //if the Markit 'fix' is used in that case

            double[] knots = DoublesScheduleGenerator.
                             getIntegrationsPoints(effectProtStart, _t[_nCDS - 1], yieldCurve.t.ToArray(), _t);

            //The protection leg
            _protElems = new ProtectionLegElement[_nCDS];
            for (int i = 0; i < _nCDS; i++)
            {
                _protElems[i] = new ProtectionLegElement(i == 0 ? effectProtStart : _t[i - 1], _t[i], yieldCurve, i, knots);
            }

            _cds2CouponsMap      = new int[_nCDS][];
            _cdsCouponsUpdateMap = new int[_nCDS][];
            _knot2CouponsMap     = new int[_nCDS][];

            int nPaymentsFinalCDS       = cds[_nCDS - 1].getNumPayments();
            List <CdsCoupon> allCoupons = new List <CdsCoupon>(_nCDS + nPaymentsFinalCDS - 1);

            allCoupons.AddRange(cds[_nCDS - 1].getCoupons());
            int[] temp = new int[nPaymentsFinalCDS];
            for (int i = 0; i < nPaymentsFinalCDS; i++)
            {
                temp[i] = i;
            }
            _cds2CouponsMap[_nCDS - 1] = temp;

            //complete the list of unique coupons and fill out the cds2CouponsMap
            for (int i = 0; i < _nCDS - 1; i++)
            {
                CdsCoupon[] c         = cds[i].getCoupons();
                int         nPayments = c.Length;
                _cds2CouponsMap[i] = new int[nPayments];
                for (int k = 0; k < nPayments; k++)
                {
                    int index = -1;
                    for (int j = 0; j < allCoupons.Count; j++)
                    {
                        if (allCoupons[j].Equals(c[k]))
                        {
                            index = j;
                            break;
                        }
                    }
                    if (index == -1)
                    {
                        index = allCoupons.Count;
                        allCoupons.Add(c[k]);
                    }
                    _cds2CouponsMap[i][k] = index;
                }
            }

            //loop over the coupons to populate the couponUpdateMap
            _nCoupons = allCoupons.Count;
            int[] sizes = new int[_nCDS];
            int[] map   = new int[_nCoupons];
            for (int i = 0; i < _nCoupons; i++)
            {
                CdsCoupon c     = allCoupons[i];
                int       index = Array.BinarySearch(_t, c.getEffEnd());
                if (index < 0)
                {
                    index = -(index + 1);
                }
                sizes[index]++;
                map[i] = index;
            }

            //make the protection leg elements

            if (payAccOnDefault)
            {
                _premElems = new PremiumLegElement[_nCoupons];
                for (int i = 0; i < _nCoupons; i++)
                {
                    _premElems[i] = new PremiumLegElement(effectProtStart, allCoupons[i], yieldCurve, map[i], knots, formula);
                }
            }
            else
            {
                _premElems = new CouponOnlyElement[_nCoupons];
                for (int i = 0; i < _nCoupons; i++)
                {
                    _premElems[i] = new CouponOnlyElement(allCoupons[i], yieldCurve, map[i]);
                }
            }

            //sort a map from coupon to curve node, to a map from curve node to coupons
            for (int i = 0; i < _nCDS; i++)
            {
                _knot2CouponsMap[i] = new int[sizes[i]];
            }
            int[] indexes = new int[_nCDS];
            for (int i = 0; i < _nCoupons; i++)
            {
                int index = map[i];
                _knot2CouponsMap[index][indexes[index]++] = i;
            }

            //the cdsCouponsUpdateMap is the intersection of the cds2CouponsMap and knot2CouponsMap
            for (int i = 0; i < _nCDS; i++)
            {
                _cdsCouponsUpdateMap[i] = intersection(_knot2CouponsMap[i], _cds2CouponsMap[i]);
            }
        }
Beispiel #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;
            }
        }
        private double calculateSinglePeriodAccrualOnDefaultCreditSensitivity(
            CdsCoupon coupon,
            double effStart,
            double[] integrationPoints,
            YieldTermStructure yieldCurve,
            PiecewiseconstantHazardRate creditCurve,
            int creditCurveNode)
        {
            double start = Math.Max(coupon.getEffStart(), effStart);

            if (start >= coupon.getEffEnd())
            {
                return(0.0);
            }
            double[] knots = DoublesScheduleGenerator.truncateSetInclusive(start, coupon.getEffEnd(), integrationPoints);

            double t     = knots[0];
            double ht0   = creditCurve.getRT_(t);
            double rt0   = yieldCurve.getRT_(t);
            double p0    = Math.Exp(-rt0);
            double q0    = Math.Exp(-ht0);
            double b0    = p0 * q0; // this is the risky discount factor
            double dqdr0 = creditCurve.getSingleNodeDiscountFactorSensitivity(t, creditCurveNode);

            double t0      = t - coupon.getEffStart() + _omega;
            double pvSense = 0.0;
            int    nItems  = knots.Length;

            for (int j = 1; j < nItems; ++j)
            {
                t = knots[j];
                double ht1   = creditCurve.getRT_(t);
                double rt1   = yieldCurve.getRT_(t);
                double p1    = Math.Exp(-rt1);
                double q1    = Math.Exp(-ht1);
                double b1    = p1 * q1;
                double dqdr1 = creditCurve.getSingleNodeDiscountFactorSensitivity(t, creditCurveNode);

                double dt = knots[j] - knots[j - 1];

                double dht  = ht1 - ht0;
                double drt  = rt1 - rt0;
                double dhrt = dht + drt + 1e-50; // to keep consistent with ISDA c code

                double tPvSense;
                // TODO once the maths is written up in a white paper, check these formula again,
                // since tests again finite difference could miss some subtle error

                if (_formula == AccrualOnDefaultFormulae.MARKIT_FIX)
                {
                    if (Math.Abs(dhrt) < 1e-5)
                    {
                        double eP     = Maths.Epsilon.epsilonP(-dhrt);
                        double ePP    = Maths.Epsilon.epsilonPP(-dhrt);
                        double dPVdq0 = p0 * dt * ((1 + dht) * eP - dht * ePP);
                        double dPVdq1 = b0 * dt / q1 * (-eP + dht * ePP);
                        tPvSense = dPVdq0 * dqdr0 + dPVdq1 * dqdr1;
                    }
                    else
                    {
                        double w1     = (b0 - b1) / dhrt;
                        double w2     = w1 - b1;
                        double w3     = dht / dhrt;
                        double w4     = dt / dhrt;
                        double w5     = (1 - w3) * w2;
                        double dPVdq0 = w4 / q0 * (w5 + w3 * (b0 - w1));
                        double dPVdq1 = w4 / q1 * (w5 + w3 * (b1 * (1 + dhrt) - w1));
                        tPvSense = dPVdq0 * dqdr0 - dPVdq1 * dqdr1;
                    }
                }
                else
                {
                    double t1 = t - coupon.getEffStart() + _omega;
                    if (Math.Abs(dhrt) < 1e-5)
                    {
                        double e      = Maths.Epsilon.epsilon(-dhrt);
                        double eP     = Maths.Epsilon.epsilonP(-dhrt);
                        double ePP    = Maths.Epsilon.epsilonPP(-dhrt);
                        double w1     = t0 * e + dt * eP;
                        double w2     = t0 * eP + dt * ePP;
                        double dPVdq0 = p0 * ((1 + dht) * w1 - dht * w2);
                        double dPVdq1 = b0 / q1 * (-w1 + dht * w2);
                        tPvSense = dPVdq0 * dqdr0 + dPVdq1 * dqdr1;
                    }
                    else
                    {
                        double w1     = dt / dhrt;
                        double w2     = dht / dhrt;
                        double w3     = (t0 + w1) * b0 - (t1 + w1) * b1;
                        double w4     = (1 - w2) / dhrt;
                        double w5     = w1 / dhrt * (b0 - b1);
                        double dPVdq0 = w4 * w3 / q0 + w2 * ((t0 + w1) * p0 - w5 / q0);
                        double dPVdq1 = w4 * w3 / q1 + w2 * ((t1 + w1) * p1 - w5 / q1);
                        tPvSense = dPVdq0 * dqdr0 - dPVdq1 * dqdr1;
                    }
                    t0 = t1;
                }

                pvSense += tPvSense;
                ht0      = ht1;
                rt0      = rt1;
                p0       = p1;
                q0       = q1;
                b0       = b1;
                dqdr0    = dqdr1;
            }
            return(coupon.getYFRatio() * pvSense);
        }