public override IPricingResult Calculate(AbsWithRepurchase trade, IMarketCondition market, PricingRequest request) { var result = new PricingResult(market.ValuationDate, request); if (result.IsRequested(PricingRequest.Cashflow)) { var underlyingLoanCfs = trade.GetCashflows(market, false).ToArray(); var surplus = 0.0; var repurchasedLoanCfs = new List <Cashflow[]> { underlyingLoanCfs }; var underlyingLoanPayDates = repurchasedLoanCfs.SelectMany(x => x.Select(cf => cf.PaymentDate)).Distinct().ToArray(); var payOutCashflows = trade.Tranches.SelectMany(x => x.GetCashflows(market, false)).ToArray(); //assumption: repurchased loans have same features as the original loan excepth the startDate and mautirytDate for (var i = 0; i < underlyingLoanPayDates.Length - 1; ++i) { //repurchase prior to the final cash flow var tCfs = repurchasedLoanCfs.SelectMany(x => x).Where(x => x.PaymentDate == underlyingLoanPayDates[i] && (x.CashflowType == CashflowType.Principal || x.CashflowType == CashflowType.Coupon || x.CashflowType == CashflowType.Tax)).ToArray(); surplus += tCfs.Sum(x => x.PaymentAmount); var payOutAmount = payOutCashflows.Where(x => x.PaymentDate >= underlyingLoanPayDates[i] && x.PaymentDate < underlyingLoanPayDates[i + 1]).Sum(x => x.PaymentAmount); surplus -= payOutAmount; var endDate = trade.PayOutDates.Where(x => x > underlyingLoanPayDates[i]); if (endDate.Any()) { repurchasedLoanCfs.Add(RepurchasedLoanCashflow(underlyingLoanPayDates[i + 1], surplus * trade.RepurchaseRatio, trade.Loan, market, underlyingLoanPayDates[i], endDate.First())); } surplus *= (1.0 - trade.RepurchaseRatio); } var payOutCf = payOutCashflows.Select( x => new Cashflow(x.AccrualEndDate, x.AccrualEndDate, x.PaymentDate, -x.PaymentAmount, x.PaymentCurrency, x.CashflowType, x.IsFixed, market.GetDf(x.PaymentDate), x.CalculationDetails, x.RefStartDate, x.RefEndDate, x.StartPrincipal, x.CouponRate)); result.Cashflows = repurchasedLoanCfs.SelectMany(x => x).Union(payOutCf).ToArray(); } return(result); }
private Cashflow[] GetCashflows(CallableBond callableBond, IMarketCondition market) { var exerciseDates = callableBond.EmbededOptions.SelectMany(x => x.ExerciseDates).ToArray(); if (_adjustCouponDates) { return(callableBond.GetCashflows(market) .Select(cf => new Cashflow( cf.AccrualStartDate, cf.AccrualEndDate, AdjustToGrid(new[] { cf.PaymentDate }, exerciseDates)[0], cf.PaymentAmount, cf.PaymentCurrency, cf.CashflowType, cf.IsFixed, market.GetDf(AdjustToGrid(new[] { cf.PaymentDate }, exerciseDates)[0]), cf.CalculationDetails) ).ToArray()); } return(callableBond.GetCashflows(market)); }
public Cashflow[] GetCashflows(IMarketCondition market, bool netted = true) { //TODO return(new[] { new Cashflow(StartDate, UnderlyingMaturityDate, UnderlyingMaturityDate, -NotionalInFgnCcy * NearStrikeFxRate, DomCcy, CashflowType.Gross, true, market.GetDf(UnderlyingMaturityDate), null), new Cashflow(StartDate, UnderlyingMaturityDate, UnderlyingMaturityDate, NotionalInFgnCcy, FgnCcy, CashflowType.Gross, true, market.GetDf(UnderlyingMaturityDate), null), }); }
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 Cashflow[] GetCashflows(IMarketCondition market, bool netted = true) { var coupon = Notional * DepositRate * DayCount.CalcDayCountFraction(StartDate, UnderlyingMaturityDate); if (netted) { return(new[] { new Cashflow(StartDate, UnderlyingMaturityDate, UnderlyingMaturityDate, coupon + Notional, Currency, CashflowType.Principal, true, market.GetDf(UnderlyingMaturityDate), null) }); } else { return(new[] { new Cashflow(StartDate, UnderlyingMaturityDate, UnderlyingMaturityDate, coupon, Currency, CashflowType.Coupon, true, market.GetDf(UnderlyingMaturityDate), null), new Cashflow(StartDate, UnderlyingMaturityDate, UnderlyingMaturityDate, Notional, Currency, CashflowType.Principal, true, market.GetDf(UnderlyingMaturityDate), null) }); } }
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()); } }
public Cashflow[] GetCashflows(IMarketCondition market, bool netted = true) { return(PremiumLeg.GetCashflows(market, netted) .Select(x => new Cashflow(x.AccrualStartDate, x.AccrualEndDate, x.PaymentDate, x.PaymentAmount * SwapDirection.Sign(), x.PaymentCurrency, x.CashflowType, x.IsFixed, market.GetDf(x.PaymentDate), x.CalculationDetails)) .ToArray()); }
private Cashflow[] RepurchasedLoanCashflow( Date repurchasedLoanFirstPaymentDate, double repurchasedLoanAmount, Loan loan, IMarketCondition market, Date startDate, Date endDate ) { var newLoan = new Loan(startDate, endDate, repurchasedLoanFirstPaymentDate, repurchasedLoanAmount, loan.NumOfPayment, loan.DayCount, loan.Frequency, loan.Coupon, loan.ResetDate, loan.IsFloatingRate, loan.IndexType, loan.FloatingRateMultiplier, loan.AmortizationType, loan.Currency, loan.MortgageCalculator, loan.TaxRate); var cfs = new[] { new Cashflow(startDate, startDate, startDate, -repurchasedLoanAmount, CurrencyCode.CNY, CashflowType.Repurchase, true, market.GetDf(startDate), null) } .Union(newLoan.GetCashflows(market, false)).ToList(); return(cfs.ToArray()); }