예제 #1
0
파일: SwapLeg.cs 프로젝트: stepinto163/Qdp
        public Cashflow[] GetCashflows(IMarketCondition market, bool netted = true)
        {
            var accDates     = Accruals.ToArray();
            var cashflowType = (Coupon is FixedCoupon) ? CashflowType.FixedLegInterest : CashflowType.FloatingLegInterest;
            var cashflows    = new List <Cashflow>();

            for (var i = 0; i < accDates.Length - 1; ++i)
            {
                CfCalculationDetail[] temp;
                var paymentRate = Coupon.GetCoupon(accDates[i], accDates[i + 1], market.FixingCurve.Value, market.HistoricalIndexRates, out temp) * DayCount.CalcDayCountFraction(accDates[i], accDates[i + 1]);
                cashflows.Add(
                    new Cashflow(
                        accDates[i],
                        accDates[i + 1],
                        accDates[i + 1],
                        Notional * paymentRate,
                        Currency,
                        cashflowType,
                        temp.Aggregate(true, (current, x) => current && x.IsFixed),
                        market.DiscountCurve.Value.GetDf(accDates[i + 1]),
                        temp
                        )
                    );
            }

            if (NotionalExchange)
            {
                if (cashflows.Count >= 1)
                {
                    var last = cashflows[cashflows.Count - 1];
                    if (netted)
                    {
                        cashflows[cashflows.Count - 1] = new Cashflow(last.AccrualStartDate, last.AccrualEndDate, last.PaymentDate, last.PaymentAmount + Notional, Currency, CashflowType.Principal, last.IsFixed, market.DiscountCurve.Value.GetDf(last.PaymentDate), last.CalculationDetails);
                    }
                    else
                    {
                        cashflows.Add(new Cashflow(last.AccrualStartDate, last.AccrualEndDate, last.PaymentDate, Notional, Currency, CashflowType.Principal, true, market.DiscountCurve.Value.GetDf(last.PaymentDate), null));
                    }
                }
            }

            if (TerminationDate != null && !double.IsNaN(TerminationAmount))
            {
                return(cashflows.Where(x => x.PaymentDate < TerminationDate).ToArray()
                       .Union(new[] { new Cashflow(TerminationDate, TerminationDate, TerminationDate, TerminationAmount, Currency, CashflowType.TerminationFee, true, market.DiscountCurve.Value.GetDf(TerminationDate), null) })
                       .ToArray());
            }
            else
            {
                return(cashflows.ToArray());
            }
        }
예제 #2
0
파일: SwapLeg.cs 프로젝트: stepinto163/Qdp
        public double GetAccruedInterest(Date calcDate, IMarketCondition market, bool isEod = true)
        {
            var accs = Accruals.ToArray();

            if (market.ValuationDate < accs[0] || market.ValuationDate > accs.Last())
            {
                return(0.0);
            }

            var cashflow = GetCashflows(market, false).ToArray();

            if (!cashflow.Any())
            {
                return(0.0);
            }

            var nextCashflow = cashflow.FirstIndexOf(x => x.PaymentDate >= calcDate);
            var startDate    = nextCashflow == 0 ? accs[0] : cashflow[nextCashflow - 1].PaymentDate;
            var amount       = cashflow[nextCashflow].PaymentAmount;
            var endDate      = cashflow[nextCashflow].PaymentDate;

            //return (calcDate - startDate + (isEod ? 1 : 0)) / (endDate - startDate) * amount;
            return((calcDate - startDate) / (endDate - startDate) * amount);
        }
예제 #3
0
파일: Bond.cs 프로젝트: stepinto163/Qdp
        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());
            }
        }
예제 #4
0
파일: Bond.cs 프로젝트: stepinto163/Qdp
        public Bond(
            string id,
            Date startDate,
            Date maturityDate,
            double notional,
            CurrencyCode currency,
            ICoupon coupon,
            ICalendar calendar,
            Frequency paymentFreq,
            Stub stub,
            IDayCount accrualDayCount,
            IDayCount paymentDayCount,
            BusinessDayConvention accrualBizDayRule,
            BusinessDayConvention paymentBizDayRule,
            DayGap settlementGap,
            TradingMarket bondTradingMarket,
            bool stickToEom               = false,
            IRedemption redemption        = null,
            Date firstPaymentDate         = null,
            bool isZeroCouponBond         = false,
            double issuePrice             = double.NaN,
            double issueRate              = double.NaN,
            AmortizationType amortionType = AmortizationType.None,
            Dictionary <Date, double> amortizationInDates     = null,
            Dictionary <int, double> amortizationInIndex      = null,
            bool renormalizeAfterAmoritzation                 = false,
            Dictionary <int, double> stepWiseCompensationRate = null,
            Dictionary <string, double> optionToCall          = null,
            Dictionary <string, double> optionToPut           = null,
            Dictionary <string, double> optionToAssPut        = null,
            double settlementCoupon = double.NaN,
            bool roundCleanPrice    = false
            )
        {
            Id        = id;
            StartDate = startDate;
            UnderlyingMaturityDate = maturityDate;
            Notional                 = notional;
            Currency                 = currency;
            Coupon                   = coupon;
            Calendar                 = calendar;
            PaymentFreq              = paymentFreq;
            Stub                     = stub;
            AccrualDayCount          = accrualDayCount;
            PaymentDayCount          = paymentDayCount;
            AccrualBizDayRule        = accrualBizDayRule;
            PaymentBizDayRule        = paymentBizDayRule;
            SettlmentGap             = settlementGap;
            _settlementCoupon        = settlementCoupon;
            BondTradeingMarket       = bondTradingMarket;
            FirstPaymentDate         = firstPaymentDate;
            IsZeroCouponBond         = isZeroCouponBond;
            IssuePrice               = issuePrice;
            IssueRate                = issueRate;
            StickToEom               = stickToEom;
            StepWiseCompensationRate = stepWiseCompensationRate;
            RoundCleanPrice          = roundCleanPrice;

            OptionToCall   = optionToCall;
            OptionToPut    = optionToPut;
            OptionToAssPut = optionToAssPut;

            Tenor = string.Format("{0},{1}", (int)(UnderlyingMaturityDate - StartDate), "D");

            IrregularPayment = false;
            if (Coupon is CustomizedCoupon)
            {
            }
            else
            {
                List <Date> tmpDate;
                if (FirstPaymentDate == null)
                {
                    var schedule = new Schedule(StartDate, UnderlyingMaturityDate, PaymentFreq.GetTerm(), Stub, Calendar,
                                                AccrualBizDayRule);
                    tmpDate       = schedule.ToList();
                    _isRegualDate = schedule.IsRegular;
                }
                else
                {
                    var schedule    = new Schedule(FirstPaymentDate, UnderlyingMaturityDate, PaymentFreq.GetTerm(), Stub, Calendar, AccrualBizDayRule);
                    var regAccruals = schedule.ToList();
                    tmpDate = new List <Date> {
                        StartDate
                    };
                    tmpDate.AddRange(regAccruals);
                    IrregularPayment = false;
                    _isRegualDate    = new List <bool> {
                        IrregularPayment
                    };
                    _isRegualDate.AddRange(schedule.IsRegular);
                }

                if (tmpDate.Count > 2)
                {
                    if (PaymentBizDayRule.Adjust(calendar, tmpDate[tmpDate.Count - 2]).Equals(tmpDate.Last()))
                    {
                        tmpDate.RemoveAt(tmpDate.Count - 2);
                        _isRegualDate.RemoveAt(_isRegualDate.Count - 2);
                    }
                }

                Accruals = new Schedule(tmpDate);

                if (FirstPaymentDate == null)
                {
                    PaymentSchedule =
                        new Schedule(
                            new Schedule(StartDate, UnderlyingMaturityDate, PaymentFreq.GetTerm(), Stub, Calendar, PaymentBizDayRule).Skip(1));
                }
                else
                {
                    PaymentSchedule =
                        new Schedule(
                            new Schedule(FirstPaymentDate, UnderlyingMaturityDate, PaymentFreq.GetTerm(), Stub, Calendar, PaymentBizDayRule));
                }
            }

            if (Accruals.Count() != PaymentSchedule.Count() + 1)
            {
                throw new PricingLibraryException("Bond's number of accrual periods do not match number of payments");
            }

            AmortizationType             = amortionType;
            AmortizationInDates          = amortizationInDates;
            AmortizationInIndex          = amortizationInIndex;
            RenormalizeAfterAmoritzation = renormalizeAfterAmoritzation;
            IAmortization amortization;

            if (AmortizationInDates != null)
            {
                amortization = new Amortization(amortizationInDates, RenormalizeAfterAmoritzation);
            }
            else if (AmortizationInIndex != null)
            {
                amortization = new Amortization(ToAmortizationSchedule(PaymentSchedule.ToArray(), AmortizationInIndex), RenormalizeAfterAmoritzation);
            }
            else
            {
                //EqualPrincipal or EqualPrincipalAndInterest will be calculated later
                amortization = new Amortization();
            }
            Amoritzation        = amortization;
            _mortgageCalculator = new MortgageCalculator(new Psa(0.0), new Sda(0.0));

            Redemption = redemption ?? new Redemption(1.0, RedemptionType.None);
            //Redemption = redemption ?? new Redemption(1.0, PriceQuoteType.Clean);

            if (PaymentFreq == Frequency.None)
            {
                IrregularPayment = true;
            }
            else
            {
                for (var i = 0; i < Accruals.Count() - 1; ++i)
                {
                    if (PaymentFreq.GetTerm().Next(Accruals.ToArray()[i]) != Accruals.ToArray()[i + 1])
                    {
                        IrregularPayment = false;
                        break;
                    }
                }
            }

            _compensationRate = Accruals.Skip(1).Select(x => 0.0).ToArray();

            if (stepWiseCompensationRate != null)
            {
                var compensationCoupons = new List <double>();
                var arr = StepWiseCompensationRate.OrderBy(x => x.Key).Select(x => Tuple.Create(x.Key, x.Value)).ToArray();
                for (var i = 0; i < Accruals.Count() - 1; ++i)
                {
                    compensationCoupons.Add(i > 0 ? compensationCoupons[i - 1] : 0.0);
                    var updateCoupon       = arr.FirstOrDefault(x => x.Item1 == (i + 1));
                    var compensationCoupon = updateCoupon != null ? updateCoupon.Item2 : 0.0;
                    compensationCoupons[i] += compensationCoupon;
                }
                _compensationRate = compensationCoupons.ToArray();
            }
        }