public static double zSpread(Bond bond, double cleanPrice, YieldTermStructure discount, DayCounter dayCounter, Compounding compounding, Frequency frequency, Date settlementDate = null, double accuracy = 1.0e-10, int maxIterations = 100, double guess = 0.0) { if (settlementDate == null) { settlementDate = bond.settlementDate(); } Utils.QL_REQUIRE(BondFunctions.isTradable(bond, settlementDate), () => "non tradable at " + settlementDate + " (maturity being " + bond.maturityDate() + ")", QLNetExceptionEnum.NotTradableException); double dirtyPrice = cleanPrice + bond.accruedAmount(settlementDate); dirtyPrice /= 100.0 / bond.notional(settlementDate); return(CashFlows.zSpread(bond.cashflows(), discount, dirtyPrice, dayCounter, compounding, frequency, false, settlementDate, settlementDate, accuracy, maxIterations, guess)); }
protected override void performCalculations() { Utils.QL_REQUIRE(!bondHelpers_.empty(), () => "no bondHelpers given"); maxDate_ = Date.minDate(); Date refDate = referenceDate(); // double check bond quotes still valid and/or instruments not expired for (int i = 0; i < bondHelpers_.Count; ++i) { Bond bond = bondHelpers_[i].bond(); Utils.QL_REQUIRE(bondHelpers_[i].quote().link.isValid(), () => (i + 1) + " bond (maturity: " + bond.maturityDate() + ") has an invalid price quote"); Date bondSettlement = bond.settlementDate(); Utils.QL_REQUIRE(bondSettlement >= refDate, () => (i + 1) + " bond settlemente date (" + bondSettlement + ") before curve reference date (" + refDate + ")"); Utils.QL_REQUIRE(BondFunctions.isTradable(bond, bondSettlement), () => (i + 1) + " bond non tradable at " + bondSettlement + " settlement date (maturity" + " being " + bond.maturityDate() + ")", QLNetExceptionEnum.NotTradableException); maxDate_ = Date.Max(maxDate_, bondHelpers_[i].pillarDate()); bondHelpers_[i].setTermStructure(this); } fittingMethod_.init(); fittingMethod_.calculate(); }
public static double nextCouponRate(Bond bond, Date settlementDate = null) { if (settlementDate == null) { settlementDate = bond.settlementDate(); } return(CashFlows.nextCouponRate(bond.cashflows(), false, settlementDate)); }
public static bool isTradable(Bond bond, Date settlementDate = null) { if (settlementDate == null) { settlementDate = bond.settlementDate(); } return(bond.notional(settlementDate).IsNotEqual(0.0)); }
public static CashFlow previousCashFlow(Bond bond, Date refDate = null) { if (refDate == null) { refDate = bond.settlementDate(); } return(CashFlows.previousCashFlow(bond.cashflows(), false, refDate)); }
public static Date nextCashFlowDate(Bond bond, Date refDate = null) { if (refDate == null) { refDate = bond.settlementDate(); } return(CashFlows.nextCashFlowDate(bond.cashflows(), false, refDate)); }
//! rerun every time instruments/referenceDate changes internal virtual void init() { // yield conventions DayCounter yieldDC = curve_.dayCounter(); Compounding yieldComp = Compounding.Compounded; Frequency yieldFreq = Frequency.Annual; int n = curve_.bondHelpers_.Count; costFunction_ = new FittingCost(this); costFunction_.firstCashFlow_ = new InitializedList <int>(n); for (int i = 0; i < curve_.bondHelpers_.Count; ++i) { Bond bond = curve_.bondHelpers_[i].bond(); List <CashFlow> cf = bond.cashflows(); Date bondSettlement = bond.settlementDate(); for (int k = 0; k < cf.Count; ++k) { if (!cf[k].hasOccurred(bondSettlement, false)) { costFunction_.firstCashFlow_[i] = k; break; } } } if (calculateWeights_) { //if (weights_.empty()) weights_ = new Vector(n); double squaredSum = 0.0; for (int i = 0; i < curve_.bondHelpers_.Count; ++i) { Bond bond = curve_.bondHelpers_[i].bond(); double cleanPrice = curve_.bondHelpers_[i].quote().link.value(); Date bondSettlement = bond.settlementDate(); double ytm = BondFunctions.yield(bond, cleanPrice, yieldDC, yieldComp, yieldFreq, bondSettlement); double dur = BondFunctions.duration(bond, ytm, yieldDC, yieldComp, yieldFreq, Duration.Type.Modified, bondSettlement); weights_[i] = 1.0 / dur; squaredSum += weights_[i] * weights_[i]; } weights_ /= Math.Sqrt(squaredSum); } Utils.QL_REQUIRE(weights_.size() == n, () => "Given weights do not cover all boostrapping helpers"); }
public static Date referencePeriodEnd(Bond bond, Date settlementDate = null) { if (settlementDate == null) { settlementDate = bond.settlementDate(); } Utils.QL_REQUIRE(BondFunctions.isTradable(bond, settlementDate), () => "non tradable at " + settlementDate + " (maturity being " + bond.maturityDate() + ")"); return(CashFlows.referencePeriodEnd(bond.cashflows(), false, settlementDate)); }
public static int accrualDays(Bond bond, Date settlementDate = null) { if (settlementDate == null) { settlementDate = bond.settlementDate(); } Utils.QL_REQUIRE(BondFunctions.isTradable(bond, settlementDate), "non tradable at " + settlementDate + " (maturity being " + bond.maturityDate() + ")"); return(CashFlows.accrualDays(bond.cashflows(), false, settlementDate)); }
public static double convexity(Bond bond, InterestRate yield, Date settlementDate = null) { if (settlementDate == null) { settlementDate = bond.settlementDate(); } Utils.QL_REQUIRE(BondFunctions.isTradable(bond, settlementDate), () => "non tradable at " + settlementDate + " (maturity being " + bond.maturityDate() + ")"); return(CashFlows.convexity(bond.cashflows(), yield, false, settlementDate)); }
public static double accruedAmount(Bond bond, Date settlementDate = null) { if (settlementDate == null) { settlementDate = bond.settlementDate(); } Utils.QL_REQUIRE(BondFunctions.isTradable(bond, settlementDate), () => "non tradable at " + settlementDate + " (maturity being " + bond.maturityDate() + ")"); return(CashFlows.accruedAmount(bond.cashflows(), false, settlementDate) * 100.0 / bond.notional(settlementDate)); }
public static double bps(Bond bond, YieldTermStructure discountCurve, Date settlementDate = null) { if (settlementDate == null) { settlementDate = bond.settlementDate(); } Utils.QL_REQUIRE(BondFunctions.isTradable(bond, settlementDate), () => "non tradable at " + settlementDate + " (maturity being " + bond.maturityDate() + ")"); return(CashFlows.bps(bond.cashflows(), discountCurve, false, settlementDate) * 100.0 / bond.notional(settlementDate)); }
public static double accruedDays(Bond bond, Date settlementDate = null) { if (settlementDate == null) { settlementDate = bond.settlementDate(); } Utils.QL_REQUIRE(BondFunctions.isTradable(bond, settlementDate), () => "non tradable at " + settlementDate + " (maturity being " + bond.maturityDate() + ")", QLNetExceptionEnum.NotTradableException); return(CashFlows.accruedDays(bond.cashflows(), false, settlementDate)); }
public static double duration(Bond bond, InterestRate yield, Duration.Type type = Duration.Type.Modified, Date settlementDate = null) { if (settlementDate == null) { settlementDate = bond.settlementDate(); } Utils.QL_REQUIRE(BondFunctions.isTradable(bond, settlementDate), "non tradable at " + settlementDate + " (maturity being " + bond.maturityDate() + ")"); return(CashFlows.duration(bond.cashflows(), yield, type, false, settlementDate)); }
public static double yieldValueBasisPoint(Bond bond, InterestRate yield, Date settlementDate = null) { if (settlementDate == null) { settlementDate = bond.settlementDate(); } Utils.QL_REQUIRE(BondFunctions.isTradable(bond, settlementDate), () => "non tradable at " + settlementDate + " (maturity being " + bond.maturityDate() + ")", QLNetExceptionEnum.NotTradableException); return(CashFlows.yieldValueBasisPoint(bond.cashflows(), yield, false, settlementDate)); }
public static double dirtyPrice(Bond bond, InterestRate yield, Date settlementDate = null) { if (settlementDate == null) { settlementDate = bond.settlementDate(); } Utils.QL_REQUIRE(BondFunctions.isTradable(bond, settlementDate), () => "non tradable at " + settlementDate + " (maturity being " + bond.maturityDate() + ")"); double dirtyPrice = CashFlows.npv(bond.cashflows(), yield, false, settlementDate) * 100.0 / bond.notional(settlementDate); return(dirtyPrice); }
public static double cleanPrice(Bond bond, YieldTermStructure discount, double zSpread, DayCounter dayCounter, Compounding compounding, Frequency frequency, Date settlementDate = null) { if (settlementDate == null) { settlementDate = bond.settlementDate(); } Utils.QL_REQUIRE(BondFunctions.isTradable(bond, settlementDate), () => "non tradable at " + settlementDate + " (maturity being " + bond.maturityDate() + ")"); double dirtyPrice = CashFlows.npv(bond.cashflows(), discount, zSpread, dayCounter, compounding, frequency, false, settlementDate) * 100.0 / bond.notional(settlementDate); return(dirtyPrice - bond.accruedAmount(settlementDate)); }
public static double atmRate(Bond bond, YieldTermStructure discountCurve, Date settlementDate = null, double?cleanPrice = null) { if (settlementDate == null) { settlementDate = bond.settlementDate(); } Utils.QL_REQUIRE(BondFunctions.isTradable(bond, settlementDate), () => "non tradable at " + settlementDate + " (maturity being " + bond.maturityDate() + ")"); double?dirtyPrice = cleanPrice == null ? null : cleanPrice + bond.accruedAmount(settlementDate); double currentNotional = bond.notional(settlementDate); double?npv = dirtyPrice / 100.0 * currentNotional; return(CashFlows.atmRate(bond.cashflows(), discountCurve, false, settlementDate, settlementDate, npv)); }
public static double cleanPrice(Bond bond, YieldTermStructure discountCurve, Date settlementDate = null) { if (settlementDate == null) { settlementDate = bond.settlementDate(); } Utils.QL_REQUIRE(BondFunctions.isTradable(bond, settlementDate), () => "non tradable at " + settlementDate + " settlementDate date (maturity being " + bond.maturityDate() + ")"); double dirtyPrice = CashFlows.npv(bond.cashflows(), discountCurve, false, settlementDate) * 100.0 / bond.notional(settlementDate); return(dirtyPrice - bond.accruedAmount(settlementDate)); }
public override Vector values(Vector x) { Date refDate = fittingMethod_.curve_.referenceDate(); DayCounter dc = fittingMethod_.curve_.dayCounter(); int n = fittingMethod_.curve_.bondHelpers_.Count; Vector values = new Vector(n); for (int i = 0; i < n; ++i) { BondHelper helper = fittingMethod_.curve_.bondHelpers_[i]; Bond bond = helper.bond(); Date bondSettlement = bond.settlementDate(); // CleanPrice_i = sum( cf_k * d(t_k) ) - accruedAmount double modelPrice = 0.0; List <CashFlow> cf = bond.cashflows(); for (int k = firstCashFlow_[i]; k < cf.Count; ++k) { double tenor = dc.yearFraction(refDate, cf[k].date()); modelPrice += cf[k].amount() * fittingMethod_.discountFunction(x, tenor); } if (helper.useCleanPrice()) { modelPrice -= bond.accruedAmount(bondSettlement); } // adjust price (NPV) for forward settlement if (bondSettlement != refDate) { double tenor = dc.yearFraction(refDate, bondSettlement); modelPrice /= fittingMethod_.discountFunction(x, tenor); } double marketPrice = helper.quote().link.value(); double error = modelPrice - marketPrice; double weightedError = fittingMethod_.weights_[i] * error; values[i] = weightedError * weightedError; } return(values); }
public AssetSwap(bool parAssetSwap, Bond bond, double bondCleanPrice, double nonParRepayment, double gearing, IborIndex iborIndex, double spread = 0.0, DayCounter floatingDayCount = null, Date dealMaturity = null, bool payBondCoupon = false) : base(2) { bond_ = bond; bondCleanPrice_ = bondCleanPrice; nonParRepayment_ = nonParRepayment; spread_ = spread; parSwap_ = parAssetSwap; Schedule tempSch = new Schedule(bond_.settlementDate(), bond_.maturityDate(), iborIndex.tenor(), iborIndex.fixingCalendar(), iborIndex.businessDayConvention(), iborIndex.businessDayConvention(), DateGeneration.Rule.Backward, false); // endOfMonth if (dealMaturity == null) { dealMaturity = bond_.maturityDate(); } Utils.QL_REQUIRE(dealMaturity <= tempSch.dates().Last(), () => "deal maturity " + dealMaturity + " cannot be later than (adjusted) bond maturity " + tempSch.dates().Last()); Utils.QL_REQUIRE(dealMaturity > tempSch.dates()[0], () => "deal maturity " + dealMaturity + " must be later than swap start date " + tempSch.dates()[0]); // the following might become an input parameter BusinessDayConvention paymentAdjustment = BusinessDayConvention.Following; Date finalDate = tempSch.calendar().adjust(dealMaturity, paymentAdjustment); Schedule schedule = tempSch.until(finalDate); // bondCleanPrice must be the (forward) clean price // at the floating schedule start date upfrontDate_ = schedule.startDate(); double dirtyPrice = bondCleanPrice_ + bond_.accruedAmount(upfrontDate_); double notional = bond_.notional(upfrontDate_); /* In the market asset swap, the bond is purchased in return for * payment of the full price. The notional of the floating leg is * then scaled by the full price. */ if (!parSwap_) { notional *= dirtyPrice / 100.0; } if (floatingDayCount == null) { legs_[1] = new IborLeg(schedule, iborIndex) .withSpreads(spread) .withGearings(gearing) .withNotionals(notional) .withPaymentAdjustment(paymentAdjustment); } else { legs_[1] = new IborLeg(schedule, iborIndex) .withSpreads(spread) .withGearings(gearing) .withPaymentDayCounter(floatingDayCount) .withNotionals(notional) .withPaymentAdjustment(paymentAdjustment); } foreach (CashFlow c in legs_[1]) { c.registerWith(update); } List <CashFlow> bondLeg = bond_.cashflows(); // skip bond redemption int i; for (i = 0; i < bondLeg.Count && bondLeg[i].date() <= dealMaturity; ++i) { // whatever might be the choice for the discounting engine // bond flows on upfrontDate_ must be discarded bool upfrontDateBondFlows = false; if (!bondLeg[i].hasOccurred(upfrontDate_, upfrontDateBondFlows)) { legs_[0].Add(bondLeg[i]); } } // if the first skipped cashflow is not the redemption // and it is a coupon then add the accrued coupon if (i < bondLeg.Count - 1) { Coupon c = bondLeg[i] as Coupon; if (c != null) { CashFlow accruedCoupon = new SimpleCashFlow(c.accruedAmount(dealMaturity), finalDate); legs_[0].Add(accruedCoupon); } } // add the nonParRepayment_ CashFlow nonParRepaymentFlow = new SimpleCashFlow(nonParRepayment_, finalDate); legs_[0].Add(nonParRepaymentFlow); Utils.QL_REQUIRE(!legs_[0].empty(), () => "empty bond leg to start with"); // special flows if (parSwap_) { // upfront on the floating leg double upfront = (dirtyPrice - 100.0) / 100.0 * notional; CashFlow upfrontCashFlow = new SimpleCashFlow(upfront, upfrontDate_); legs_[1].Insert(0, upfrontCashFlow); // backpayment on the floating leg // (accounts for non-par redemption, if any) double backPayment = notional; CashFlow backPaymentCashFlow = new SimpleCashFlow(backPayment, finalDate); legs_[1].Add(backPaymentCashFlow); } else { // final notional exchange CashFlow finalCashFlow = new SimpleCashFlow(notional, finalDate); legs_[1].Add(finalCashFlow); } Utils.QL_REQUIRE(!legs_[0].empty(), () => "empty bond leg"); foreach (CashFlow c in legs_[0]) { c.registerWith(update); } if (payBondCoupon) { payer_[0] = -1.0; payer_[1] = +1.0; } else { payer_[0] = +1.0; payer_[1] = -1.0; } }
public AssetSwap(bool payBondCoupon, Bond bond, double bondCleanPrice, IborIndex iborIndex, double spread, Schedule floatSchedule = null, DayCounter floatingDayCount = null, bool parAssetSwap = true) : base(2) { bond_ = bond; bondCleanPrice_ = bondCleanPrice; nonParRepayment_ = 100; spread_ = spread; parSwap_ = parAssetSwap; Schedule schedule = floatSchedule; if (floatSchedule == null) { schedule = new Schedule(bond_.settlementDate(), bond_.maturityDate(), iborIndex.tenor(), iborIndex.fixingCalendar(), iborIndex.businessDayConvention(), iborIndex.businessDayConvention(), DateGeneration.Rule.Backward, false); // endOfMonth } // the following might become an input parameter BusinessDayConvention paymentAdjustment = BusinessDayConvention.Following; Date finalDate = schedule.calendar().adjust(schedule.endDate(), paymentAdjustment); Date adjBondMaturityDate = schedule.calendar().adjust(bond_.maturityDate(), paymentAdjustment); Utils.QL_REQUIRE(finalDate == adjBondMaturityDate, () => "adjusted schedule end date (" + finalDate + ") must be equal to adjusted bond maturity date (" + adjBondMaturityDate + ")"); // bondCleanPrice must be the (forward) clean price // at the floating schedule start date upfrontDate_ = schedule.startDate(); double dirtyPrice = bondCleanPrice_ + bond_.accruedAmount(upfrontDate_); double notional = bond_.notional(upfrontDate_); /* In the market asset swap, the bond is purchased in return for * payment of the full price. The notional of the floating leg is * then scaled by the full price. */ if (!parSwap_) { notional *= dirtyPrice / 100.0; } if (floatingDayCount == null) { legs_[1] = new IborLeg(schedule, iborIndex) .withSpreads(spread) .withNotionals(notional) .withPaymentAdjustment(paymentAdjustment); } else { legs_[1] = new IborLeg(schedule, iborIndex) .withSpreads(spread) .withPaymentDayCounter(floatingDayCount) .withNotionals(notional) .withPaymentAdjustment(paymentAdjustment); } foreach (CashFlow c in legs_[1]) { c.registerWith(update); } List <CashFlow> bondLeg = bond_.cashflows(); foreach (CashFlow c in bondLeg) { // whatever might be the choice for the discounting engine // bond flows on upfrontDate_ must be discarded bool upfrontDateBondFlows = false; if (!(c.hasOccurred(upfrontDate_, upfrontDateBondFlows))) { legs_[0].Add(c); } } Utils.QL_REQUIRE(!legs_[0].empty(), () => "empty bond leg to start with"); // special flows if (parSwap_) { // upfront on the floating leg double upfront = (dirtyPrice - 100.0) / 100.0 * notional; CashFlow upfrontCashFlow = new SimpleCashFlow(upfront, upfrontDate_); legs_[1].Insert(0, upfrontCashFlow); // backpayment on the floating leg // (accounts for non-par redemption, if any) double backPayment = notional; CashFlow backPaymentCashFlow = new SimpleCashFlow(backPayment, finalDate); legs_[1].Add(backPaymentCashFlow); } else { // final notional exchange CashFlow finalCashFlow = new SimpleCashFlow(notional, finalDate); legs_[1].Add(finalCashFlow); } Utils.QL_REQUIRE(!legs_[0].empty(), () => "empty bond leg"); foreach (CashFlow c in legs_[0]) { c.registerWith(update); } if (payBondCoupon) { payer_[0] = -1.0; payer_[1] = +1.0; } else { payer_[0] = +1.0; payer_[1] = -1.0; } }