예제 #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 SwapLeg(Date startDate,
                       Date maturityDate,
                       double notional,
                       bool notionalExchange,
                       CurrencyCode currency,
                       ICoupon coupon,
                       ICalendar calendar,
                       Frequency paymentFreq,
                       Stub paymentStub,
                       IDayCount dayCount,
                       BusinessDayConvention paymentBda,
                       DayGap settlementGap   = null,
                       Date firstPaymenetDate = null,
                       Date terminationDate   = null,
                       double terminateAmount = double.NaN
                       )
        {
            StartDate = startDate;
            UnderlyingMaturityDate = maturityDate;
            Notional          = notional;
            NotionalExchange  = notionalExchange;
            Currency          = currency;
            Coupon            = coupon;
            Calendar          = calendar;
            PaymentFreq       = paymentFreq;
            PaymentStub       = paymentStub;
            DayCount          = dayCount;
            PaymentBda        = paymentBda;
            SettlmentGap      = settlementGap ?? new DayGap("+0BD");
            FirstPaymentDate  = firstPaymenetDate;
            TerminationDate   = terminationDate;
            TerminationAmount = terminateAmount;

            if (FirstPaymentDate != null)
            {
                var temp = new Schedule(FirstPaymentDate, UnderlyingMaturityDate, PaymentFreq.GetTerm(), PaymentStub, Calendar, PaymentBda);
                Accruals = new Schedule(new[] { StartDate }.Union(temp));
            }
            else
            {
                Accruals = new Schedule(StartDate, UnderlyingMaturityDate, PaymentFreq.GetTerm(), PaymentStub, Calendar, PaymentBda);
            }

            if (TerminationDate != null)
            {
                Accruals = new Schedule(Accruals.Where(x => x < TerminationDate));
            }

            PaymentSchedule = new Schedule(Accruals.Skip(1));
        }
예제 #3
0
파일: SwapLeg.cs 프로젝트: stepinto163/Qdp
        public Tuple <Date, double>[] GetPaymentRates(IMarketCondition market)
        {
            List <CfCalculationDetail[]> temp;
            var coupons  = Coupon.GetCoupon(Accruals, market.FixingCurve.Value, market.HistoricalIndexRates, out temp);
            var accDates = Accruals.ToList();
            var ret      = new List <Tuple <Date, double> > ();

            for (var i = 1; i < accDates.Count; ++i)
            {
                ret.Add(
                    Tuple.Create(accDates[i], coupons[i - 1] * DayCount.CalcDayCountFraction(accDates[i - 1], accDates[i]))
                    );
            }
            return(ret.ToArray());
        }
예제 #4
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);
        }
예제 #5
0
파일: Loan.cs 프로젝트: stepinto163/Qdp
        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());
        }
 public bool IsValidAccrual(string accrualId)
 {
     return(Accruals.ContainsKey(accrualId));
 }
예제 #7
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());
            }
        }
예제 #8
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();
            }
        }