//! NPV and BPS of the cash flows. // The NPV and BPS of the cash flows calculated together for performance reason public static void npvbps(Leg leg, YieldTermStructure discountCurve, bool includeSettlementDateFlows, Date settlementDate, Date npvDate, out double npv, out double bps) { npv = bps = 0.0; if (leg.empty()) { bps = 0.0; return; } for (int i = 0; i < leg.Count; ++i) { CashFlow cf = leg[i]; if (!cf.hasOccurred(settlementDate, includeSettlementDateFlows) && !cf.tradingExCoupon(settlementDate)) { Coupon cp = leg[i] as Coupon; double df = discountCurve.discount(cf.date()); npv += cf.amount() * df; if (cp != null) { bps += cp.nominal() * cp.accrualPeriod() * df; } } } double d = discountCurve.discount(npvDate); npv /= d; bps = Const.BASIS_POINT * bps / d; }
//! NPV of a single cash flows public static double npv(CashFlow cashflow, YieldTermStructure discountCurve, Date settlementDate = null, Date npvDate = null, int exDividendDays = 0) { double NPV = 0.0; if (cashflow == null) { return(0.0); } if (settlementDate == null) { settlementDate = discountCurve.referenceDate(); } if (!cashflow.hasOccurred(settlementDate + exDividendDays)) { NPV = cashflow.amount() * discountCurve.discount(cashflow.date()); } if (npvDate == null) { return(NPV); } else { return(NPV / discountCurve.discount(npvDate)); } }
// At-the-money rate of the cash flows. // The result is the fixed rate for which a fixed rate cash flow vector, equivalent to the input vector, has the required NPV according to the given term structure. If the required NPV is // not given, the input cash flow vector's NPV is used instead. public static double atmRate(Leg leg, YieldTermStructure discountCurve, bool includeSettlementDateFlows, Date settlementDate = null, Date npvDate = null, double?targetNpv = null) { if (settlementDate == null) { settlementDate = Settings.evaluationDate(); } if (npvDate == null) { npvDate = settlementDate; } double npv = 0.0; BPSCalculator calc = new BPSCalculator(discountCurve); for (int i = 0; i < leg.Count; ++i) { CashFlow cf = leg[i]; if (!cf.hasOccurred(settlementDate, includeSettlementDateFlows) && !cf.tradingExCoupon(settlementDate)) { npv += cf.amount() * discountCurve.discount(cf.date()); cf.accept(calc); } } if (targetNpv == null) { targetNpv = npv - calc.nonSensNPV(); } else { targetNpv *= discountCurve.discount(npvDate); targetNpv -= calc.nonSensNPV(); } if (targetNpv.IsEqual(0.0)) { return(0.0); } double bps = calc.bps(); Utils.QL_REQUIRE(bps.IsNotEqual(0.0), () => "null bps: impossible atm rate"); return(targetNpv.Value / bps); }
public void visit(CashFlow cf) { nonSensNPV_ += cf.amount() * discountCurve_.discount(cf.date()); }
// other public override void setupArguments(IPricingEngineArguments args) { base.setupArguments(args); Arguments arguments = args as Arguments; Utils.QL_REQUIRE(arguments != null, () => "argument type does not match"); arguments.type = type_; arguments.nominal1 = nominal1_; arguments.nominal2 = nominal2_; arguments.index1 = index1_; arguments.index2 = index2_; List <CashFlow> leg1Coupons = leg1(); List <CashFlow> leg2Coupons = leg2(); arguments.leg1ResetDates = arguments.leg1PayDates = arguments.leg1FixingDates = new InitializedList <Date>(leg1Coupons.Count); arguments.leg2ResetDates = arguments.leg2PayDates = arguments.leg2FixingDates = new InitializedList <Date>(leg2Coupons.Count); arguments.leg1Spreads = arguments.leg1AccrualTimes = arguments.leg1Gearings = new InitializedList <double>(leg1Coupons.Count); arguments.leg2Spreads = arguments.leg2AccrualTimes = arguments.leg2Gearings = new InitializedList <double>(leg2Coupons.Count); arguments.leg1Coupons = new InitializedList <double?>(leg1Coupons.Count, null); arguments.leg2Coupons = new InitializedList <double?>(leg2Coupons.Count, null); arguments.leg1IsRedemptionFlow = new InitializedList <bool>(leg1Coupons.Count, false); arguments.leg2IsRedemptionFlow = new InitializedList <bool>(leg2Coupons.Count, false); arguments.leg1CappedRates = arguments.leg1FlooredRates = new InitializedList <double?>(leg1Coupons.Count, null); arguments.leg2CappedRates = arguments.leg2FlooredRates = new InitializedList <double?>(leg2Coupons.Count, null); for (int i = 0; i < leg1Coupons.Count; ++i) { FloatingRateCoupon coupon = leg1Coupons[i] as FloatingRateCoupon; if (coupon != null) { arguments.leg1AccrualTimes[i] = coupon.accrualPeriod(); arguments.leg1PayDates[i] = coupon.date(); arguments.leg1ResetDates[i] = coupon.accrualStartDate(); arguments.leg1FixingDates[i] = coupon.fixingDate(); arguments.leg1Spreads[i] = coupon.spread(); arguments.leg1Gearings[i] = coupon.gearing(); try { arguments.leg1Coupons[i] = coupon.amount(); } catch (Exception) { arguments.leg1Coupons[i] = null; } CappedFlooredCoupon cfcoupon = leg1Coupons[i] as CappedFlooredCoupon; if (cfcoupon != null) { arguments.leg1CappedRates[i] = cfcoupon.cap(); arguments.leg1FlooredRates[i] = cfcoupon.floor(); } } else { CashFlow cashflow = leg1Coupons[i] as CashFlow; int j = arguments.leg1PayDates.FindIndex(x => x == cashflow.date()); Utils.QL_REQUIRE(j != -1, () => "nominal redemption on " + cashflow.date() + "has no corresponding coupon"); int jIdx = j; // Size jIdx = j - arguments->leg1PayDates.begin(); arguments.leg1IsRedemptionFlow[i] = true; arguments.leg1Coupons[i] = cashflow.amount(); arguments.leg1ResetDates[i] = arguments.leg1ResetDates[jIdx]; arguments.leg1FixingDates[i] = arguments.leg1FixingDates[jIdx]; arguments.leg1AccrualTimes[i] = 0.0; arguments.leg1Spreads[i] = 0.0; arguments.leg1Gearings[i] = 1.0; arguments.leg1PayDates[i] = cashflow.date(); } } for (int i = 0; i < leg2Coupons.Count; ++i) { FloatingRateCoupon coupon = leg2Coupons[i] as FloatingRateCoupon; if (coupon != null) { arguments.leg2AccrualTimes[i] = coupon.accrualPeriod(); arguments.leg2PayDates[i] = coupon.date(); arguments.leg2ResetDates[i] = coupon.accrualStartDate(); arguments.leg2FixingDates[i] = coupon.fixingDate(); arguments.leg2Spreads[i] = coupon.spread(); arguments.leg2Gearings[i] = coupon.gearing(); try { arguments.leg2Coupons[i] = coupon.amount(); } catch (Exception) { arguments.leg2Coupons[i] = null; } CappedFlooredCoupon cfcoupon = leg2Coupons[i] as CappedFlooredCoupon; if (cfcoupon != null) { arguments.leg2CappedRates[i] = cfcoupon.cap(); arguments.leg2FlooredRates[i] = cfcoupon.floor(); } } else { CashFlow cashflow = leg2Coupons[i] as CashFlow; int j = arguments.leg2PayDates.FindIndex(x => x == cashflow.date()); Utils.QL_REQUIRE(j != -1, () => "nominal redemption on " + cashflow.date() + "has no corresponding coupon"); int jIdx = j; // j - arguments->leg2PayDates.begin(); arguments.leg2IsRedemptionFlow[i] = true; arguments.leg2Coupons[i] = cashflow.amount(); arguments.leg2ResetDates[i] = arguments.leg2ResetDates[jIdx]; arguments.leg2FixingDates[i] = arguments.leg2FixingDates[jIdx]; arguments.leg2AccrualTimes[i] = 0.0; arguments.leg2Spreads[i] = 0.0; arguments.leg2Gearings[i] = 1.0; arguments.leg2PayDates[i] = cashflow.date(); } } }
public static double dirtyPriceFromYield(double faceAmount, List <CashFlow> cashflows, double yield, DayCounter dayCounter, Compounding compounding, Frequency frequency, Date settlement) { if (frequency == Frequency.NoFrequency || frequency == Frequency.Once) { frequency = Frequency.Annual; } InterestRate y = new InterestRate(yield, dayCounter, compounding, frequency); double price = 0.0; double discount = 1.0; Date lastDate = null; for (int i = 0; i < cashflows.Count - 1; ++i) { if (cashflows[i].hasOccurred(settlement)) { continue; } Date couponDate = cashflows[i].Date; double amount = cashflows[i].amount(); if (lastDate == null) { // first not-expired coupon if (i > 0) { lastDate = cashflows[i - 1].Date; } else { if (cashflows[i].GetType().IsSubclassOf(typeof(Coupon))) { lastDate = ((Coupon)cashflows[i]).accrualStartDate(); } else { lastDate = couponDate - new Period(1, TimeUnit.Years); } } discount *= y.discountFactor(settlement, couponDate, lastDate, couponDate); } else { discount *= y.discountFactor(lastDate, couponDate); } lastDate = couponDate; price += amount * discount; } CashFlow redemption = cashflows.Last(); if (!redemption.hasOccurred(settlement)) { Date redemptionDate = redemption.Date; double amount = redemption.amount(); if (lastDate == null) { // no coupons lastDate = redemptionDate - new Period(1, TimeUnit.Years); discount *= y.discountFactor(settlement, redemptionDate, lastDate, redemptionDate); } else { discount *= y.discountFactor(lastDate, redemptionDate); } price += amount * discount; } return(price / faceAmount * 100.0); }
protected double cashFlowRiskyValue(CashFlow cf, NotionalPath notionalPath) { return(cf.amount() * notionalPath.notionalRate(cf.date())); //TODO: fix for more complicated cashflows }