Beispiel #1
0
        public Cashflow[] GetCashflows(IMarketCondition market, bool netted = true)
        {
            //var payTerm = Frequency.GetTerm();
            //var accDates = new List<Date> {StartDate};
            //accDates.AddRange(new Schedule(FirstPaymentDate, MaturityDate, payTerm, Stub.ShortEnd).ToArray())
            //var Accruals = new Schedule(_implicitAccStartDate, MaturityDate, payTerm, Stub.ShortEnd).ToArray();
            var len    = Accruals.Length;
            var tArray = new double[len - 1];

            for (var i = 0; i < len - 1; ++i)
            {
                tArray[i] = DayCount.CalcDayCountFraction(Accruals[i], Accruals[i + 1]);
            }
            double[] begPrincipal;
            double[] interest;
            double[] principalPay;
            double[] prepayment;
            double[] defaultPrincipal;
            if (!IsFloatingRate)
            {
                MortgageCalculator.GetPaymentDetails(tArray, Notional, Coupon, Frequency, AmortizationType, out begPrincipal, out interest, out principalPay, out prepayment, out defaultPrincipal, _numPastPayment);
                var beg = Accruals[0];
                var end = Accruals[1];
                if (StartDate != beg)
                {
                    //first interest should be adjusted
                    interest[0] = interest[0] * (end - StartDate) / (end - beg);
                }
            }
            else
            {
                double[] begPrincipal1;
                double[] interest1;
                double[] principalPay1;
                double[] prepayment1;
                double[] defaultPrincipal1;
                MortgageCalculator.GetPaymentDetails(tArray, Notional, Coupon, Frequency, AmortizationType, out begPrincipal1, out interest1, out principalPay1, out prepayment1, out defaultPrincipal1, _numPastPayment);

                var ratePairs = market.HistoricalIndexRates.Value[IndexType].Select(x => Tuple.Create(x.Key, x.Value)).OrderBy(x => x.Item1).ToArray();
                int index;
                for (index = ratePairs.Length - 1; index > 0; --index)
                {
                    if (ratePairs[index].Item1 <= ResetDate)
                    {
                        break;
                    }
                }
                var newRate = ratePairs[index].Item2 * FloatingRateMultiplier;

                double[] begPrincipal2;
                double[] interest2;
                double[] principalPay2;
                double[] prepayment2;
                double[] defaultPrincipal2;
                var      n = Accruals.FirstIndexOf(x => x > ResetDate);
                var      p = n < 2 ? Notional : begPrincipal1[n - 2];
                MortgageCalculator.GetPaymentDetails(tArray.Skip(n - 1).ToArray(), p, newRate, Frequency, AmortizationType, out begPrincipal2, out interest2, out principalPay2, out prepayment2, out defaultPrincipal2, _numPastPayment);

                //accDate[n-1] accDate[n]
                var start = Accruals[n - 1];
                var end   = Accruals[n];

                var newInterst = p * (DayCount.CalcDayCountFraction(start, ResetDate) * Coupon + DayCount.CalcDayCountFraction(ResetDate, end) * newRate);
                interest1[n - 1]         = newInterst;
                principalPay1[n - 1]     = principalPay2[0];
                prepayment1[n - 1]       = prepayment2[0];
                defaultPrincipal1[n - 1] = defaultPrincipal2[0];
                begPrincipal1[n - 1]     = p - principalPay1[n - 1] - prepayment1[n - 1] - defaultPrincipal1[n - 1];

                double[] begPrincipal3;
                double[] interest3;
                double[] principalPay3;
                double[] prepayment3;
                double[] defaultPrincipal3;
                MortgageCalculator.GetPaymentDetails(tArray.Skip(n).ToArray(), begPrincipal1[n - 1], newRate, Frequency, AmortizationType, out begPrincipal3, out interest3, out principalPay3, out prepayment3, out defaultPrincipal3, _numPastPayment);

                var beg = Accruals[0];
                end = Accruals[1];
                if (StartDate != beg)
                {
                    //first interest should be adjusted
                    interest1[0] = interest1[0] * (end - StartDate) / (end - beg);
                }

                var tempList = begPrincipal1.Take(n).ToList();
                tempList.AddRange(begPrincipal3);
                begPrincipal = tempList.ToArray();

                tempList = interest1.Take(n).ToList();
                tempList.AddRange(interest3);
                interest = tempList.ToArray();

                tempList = principalPay1.Take(n).ToList();
                tempList.AddRange(principalPay3);
                principalPay = tempList.ToArray();

                tempList = prepayment1.Take(n).ToList();
                tempList.AddRange(prepayment3);
                prepayment = tempList.ToArray();

                tempList = defaultPrincipal1.Take(n).ToList();
                tempList.AddRange(defaultPrincipal3);
                defaultPrincipal = tempList.ToArray();
            }

            var cashflows = new List <Cashflow>();

            for (var i = 0; i < begPrincipal.Length; ++i)
            {
                var df = market.GetDf(Accruals[i + 1]);
                cashflows.Add(new Cashflow(Accruals[i], Accruals[i + 1], Accruals[i + 1], principalPay[i], Currency, CashflowType.Principal, true, df, null));
                cashflows.Add(new Cashflow(Accruals[i], Accruals[i + 1], Accruals[i + 1], interest[i], Currency, CashflowType.Coupon, true, df, null));
                cashflows.Add(new Cashflow(Accruals[i], Accruals[i + 1], Accruals[i + 1], -interest[i] * TaxRate, Currency, CashflowType.Tax, true, df, null));
                cashflows.Add(new Cashflow(Accruals[i], Accruals[i + 1], Accruals[i + 1], prepayment[i], Currency, CashflowType.Prepayment, true, df, null));
                cashflows.Add(new Cashflow(Accruals[i], Accruals[i + 1], Accruals[i + 1], defaultPrincipal[i], Currency, CashflowType.PrincipalLossOnDefault, true, df, null));
            }
            return(cashflows.ToArray());
        }
Beispiel #2
0
        private Cashflow[] GetBondCashflows(IMarketCondition market, bool netted = true, bool calcAi = false)
        {
            var accruals             = Accruals.ToArray();
            var schedulePaymentDates = calcAi ? Accruals.Skip(1).ToArray() : PaymentSchedule.ToArray();

            if (schedulePaymentDates.Length == 0)
            {
                throw  new PricingLibraryException("Number of payments is 0");
            }

            List <CfCalculationDetail[]> cfCalcDetails;

            var cashflows  = new List <Cashflow>();
            var prevCfDate = accruals[0];

            var coupons = Coupon.GetCoupon(
                Accruals,
                market.FixingCurve.HasValue ? market.FixingCurve.Value : null,
                market.HistoricalIndexRates.HasValue ? market.HistoricalIndexRates.Value : null,
                out cfCalcDetails,
                IssueRate,
                _compensationRate);
            var refStartDates = new List <Date>();
            var refEndDates   = new List <Date>();

            for (var i = 0; i < coupons.Length; ++i)
            {
                var refStartDate = accruals[i];
                var refEndDate   = accruals[i + 1];
                if (i == 0 && !_isRegualDate[i])
                {
                    if (PaymentFreq != Frequency.None)
                    {
                        if (Stub == Stub.LongStart || Stub == Stub.ShortStart)
                        {
                            refStartDate = PaymentFreq.GetTerm().Prev(refEndDate);
                        }
                        else
                        {
                            refEndDate = PaymentFreq.GetTerm().Next(refStartDate);
                        }
                    }
                }
                refStartDates.Add(refStartDate);
                refEndDates.Add(refEndDate);
            }

            IAmortization amortization;

            if (AmortizationType == AmortizationType.EqualPrincipal || AmortizationType == AmortizationType.EqualPrincipalAndInterest)
            {
                //for these two types, amortization is calculated in cash flow calculation
                var      tArr = coupons.Select((x, i) => AccrualDayCount.CalcDayCountFraction(accruals[i], accruals[i + 1], refStartDates[i], refEndDates[i])).ToArray();
                double[] begPrincipal;
                double[] interest;
                double[] principalPay;
                double[] prepayment;
                double[] defaultPrincipal;
                _mortgageCalculator.GetPaymentDetails(tArr, Notional, coupons, PaymentFreq, AmortizationType, out begPrincipal, out interest, out principalPay, out prepayment, out defaultPrincipal, 0);
                amortization = new Amortization(ToAmortizationSchedule(schedulePaymentDates, principalPay.Select((x, i) => Tuple.Create(i + 1, x)).ToDictionary(x => x.Item1, x => x.Item2)), false);
            }
            else
            {
                amortization = Amoritzation.Adjust(new Schedule(schedulePaymentDates), Calendar, calcAi ? AccrualBizDayRule : PaymentBizDayRule, PaymentFreq);
                amortization = amortization.ResetAmortization(market.ValuationDate);
            }

            for (var i = 0; i < coupons.Length; ++i)
            {
                var amortizationRedemption = 0.0;
                var remainPrincipal        = 100.0;
                var couponPay = 0.0;
                var prevDate  = prevCfDate;
                if (amortization.AmortizationSchedule != null && amortization.AmortizationSchedule.Any(x => x.Key > prevCfDate && x.Key < schedulePaymentDates[i]))
                {
                    var intermediatePrePayDate = amortization.AmortizationSchedule.Where(x => x.Key > prevCfDate && x.Key < schedulePaymentDates[i]).Select(x => x.Key).OrderBy(x => x).ToArray();
                    CfCalculationDetail[] tmpCfCalculationDetails;
                    foreach (var date in intermediatePrePayDate)
                    {
                        amortizationRedemption = amortization.GetRemainingPrincipal(prevDate);
                        remainPrincipal        = Notional * amortizationRedemption;
                        var periodCoupon = Coupon.GetCoupon(prevDate, date, market.FixingCurve.Value, market.HistoricalIndexRates, out tmpCfCalculationDetails, _compensationRate[i]);
                        couponPay = remainPrincipal * periodCoupon * AccrualDayCount.CalcDayCountFraction(prevDate, date, refStartDates[i], refEndDates[i]);
                        cashflows.Add(new Cashflow(prevDate, date, date, couponPay, Currency, CashflowType.Coupon, tmpCfCalculationDetails.Aggregate(true, (current, v) => current & v.IsFixed), market.GetDf(date), cfCalcDetails[i], refStartDates[i], refEndDates[i], remainPrincipal, periodCoupon));
                        prevDate = date;
                    }
                    coupons[i]       = Coupon.GetCoupon(prevDate, accruals[i + 1], market.FixingCurve.Value, market.HistoricalIndexRates, out tmpCfCalculationDetails, _compensationRate[i]);
                    cfCalcDetails[i] = tmpCfCalculationDetails;
                }

                amortizationRedemption = amortization.GetRemainingPrincipal(prevDate);
                remainPrincipal        = Notional * amortizationRedemption;
                couponPay = remainPrincipal * coupons[i] * AccrualDayCount.CalcDayCountFraction(prevDate, accruals[i + 1], refStartDates[i], refEndDates[i]);

                if (i == coupons.Length - 1)
                {
                    amortizationRedemption = amortization.GetRemainingPrincipal(prevCfDate);
                    remainPrincipal        = Notional * amortizationRedemption;

                    //final settlement might be adjusted, coupon [MaturityDate, settlementDate) is added
                    if (SettlmentGap != null)
                    {
                        var settlementDate = SettlmentGap.Get(Calendar, UnderlyingMaturityDate);
                        if (settlementDate > accruals[i + 1])
                        {
                            var tmpCoupon        = double.IsNaN(_settlementCoupon) ? coupons[i] : _settlementCoupon;
                            var additionalCoupon = remainPrincipal * tmpCoupon * AccrualDayCount.CalcDayCountFraction(UnderlyingMaturityDate, settlementDate, refStartDates[i], refEndDates[i]);
                            couponPay += additionalCoupon;
                        }
                    }

                    couponPay = Redemption.GetRedemptionPayment(couponPay, remainPrincipal) - remainPrincipal;
                }

                cashflows.Add(new Cashflow(prevDate, accruals[i + 1], schedulePaymentDates[i], couponPay, Currency, CashflowType.Coupon, cfCalcDetails[i] == null ? true : cfCalcDetails[i].Aggregate(true, (current, v) => current & v.IsFixed), market.GetDf(schedulePaymentDates[i]), cfCalcDetails[i], refStartDates[i], refEndDates[i], remainPrincipal, coupons[i]));
                prevCfDate = accruals[i + 1];
            }

            cashflows.AddRange(amortization.AmortizationSchedule.Keys.Select(key => new Cashflow(key, key, key, amortization.AmortizationSchedule[key] * Notional, Currency, CashflowType.Principal, true, market.GetDf(key), null)));

            if (netted)
            {
                return(cashflows
                       .GroupBy(cf => cf.PaymentDate)
                       .Select(item => new Cashflow(item.Min(x => x.AccrualStartDate), item.Max(x => x.AccrualEndDate), item.Key, item.Sum(entry => entry.PaymentAmount), Currency, CashflowType.Coupon, item.Aggregate(true, (current, v) => current && v.IsFixed), market.GetDf(item.Key), item.Min(x => x.CalculationDetails), item.Min(x => x.RefStartDate), item.Max(x => x.RefEndDate), item.Max(entry => entry.StartPrincipal), item.Sum(entry => entry.CouponRate)))
                       .OrderBy(cf => cf.PaymentDate)
                       .ToArray());
            }
            else
            {
                return(cashflows.ToArray());
            }
        }