public AmortizingFloatingRateBond(int settlementDays, List <double> notionals, Schedule schedule, IborIndex index, DayCounter accrualDayCounter, BusinessDayConvention paymentConvention = BusinessDayConvention.Following, int fixingDays = 0, List <double> gearings = null, List <double> spreads = null, List <double?> caps = null, List <double?> floors = null, bool inArrears = false, Date issueDate = null) : base(settlementDays, schedule.calendar(), issueDate) { if (gearings == null) { gearings = new List <double>() { 1, 1.0 } } ; if (spreads == null) { spreads = new List <double>() { 1, 0.0 } } ; if (caps == null) { caps = new List <double?>(); } if (floors == null) { floors = new List <double?>(); } maturityDate_ = schedule.endDate(); cashflows_ = new IborLeg(schedule, index) .withCaps(caps) .withFloors(floors) .inArrears(inArrears) .withSpreads(spreads) .withGearings(gearings) .withFixingDays(fixingDays) .withPaymentDayCounter(accrualDayCounter) .withPaymentAdjustment(paymentConvention) .withNotionals(notionals).value(); addRedemptionsToCashflows(); Utils.QL_REQUIRE(!cashflows().empty(), () => "bond with no cashflows!"); index.registerWith(update); } } }
public FloatingLoan(Type type, double nominal, Schedule floatingSchedule, double floatingSpread, DayCounter floatingDayCount, Schedule principalSchedule, BusinessDayConvention?paymentConvention, IborIndex index) : base(2) { type_ = type; nominal_ = nominal; floatingSchedule_ = floatingSchedule; floatingSpread_ = floatingSpread; floatingDayCount_ = floatingDayCount; principalSchedule_ = principalSchedule; iborIndex_ = index; if (paymentConvention.HasValue) { paymentConvention_ = paymentConvention.Value; } else { paymentConvention_ = floatingSchedule_.businessDayConvention(); } List <CashFlow> principalLeg = new PricipalLeg(principalSchedule, floatingDayCount) .withNotionals(nominal) .withPaymentAdjustment(paymentConvention_) .withSign(type == Type.Loan ? -1 : 1); // temporary for (int i = 0; i < principalLeg.Count - 1; i++) { Principal p = (Principal)principalLeg[i]; notionals_.Add(p.nominal()); } List <CashFlow> floatingLeg = new IborLeg(floatingSchedule, iborIndex_) .withPaymentDayCounter(floatingDayCount_) .withSpreads(floatingSpread_) .withPaymentAdjustment(paymentConvention_) .withNotionals(notionals_); legs_[0] = floatingLeg; legs_[1] = principalLeg; if (type_ == Type.Loan) { payer_[0] = -1; payer_[1] = +1; } else { payer_[0] = +1; payer_[1] = -1; } }
public BasisSwap(Type type, double nominal, Schedule float1Schedule, IborIndex iborIndex1, double spread1, DayCounter float1DayCount, Schedule float2Schedule, IborIndex iborIndex2, double spread2, DayCounter float2DayCount, BusinessDayConvention?paymentConvention) : base(2) { type_ = type; nominal_ = nominal; floating1Schedule_ = float1Schedule; spread1_ = spread1; floating1DayCount_ = float1DayCount; iborIndex1_ = iborIndex1; floating2Schedule_ = float2Schedule; spread2_ = spread2; floating2DayCount_ = float2DayCount; iborIndex2_ = iborIndex2; if (paymentConvention.HasValue) { paymentConvention_ = paymentConvention.Value; } else { paymentConvention_ = floating1Schedule_.businessDayConvention(); } List <CashFlow> floating1Leg = new IborLeg(float1Schedule, iborIndex1) .withPaymentDayCounter(float1DayCount) .withSpreads(spread1) .withNotionals(nominal) .withPaymentAdjustment(paymentConvention_); List <CashFlow> floating2Leg = new IborLeg(float2Schedule, iborIndex2) .withPaymentDayCounter(float2DayCount) .withSpreads(spread2) .withNotionals(nominal) .withPaymentAdjustment(paymentConvention_); foreach (var cf in floating1Leg) { cf.registerWith(update); } foreach (var cf in floating2Leg) { cf.registerWith(update); } legs_[0] = floating1Leg; legs_[1] = floating2Leg; if (type_ == Type.Payer) { payer_[0] = -1; payer_[1] = +1; longNo_ = 1; longSpread_ = spread2; shortNo_ = 0; shortSpread_ = spread1; } else { payer_[0] = +1; payer_[1] = -1; longNo_ = 0; longSpread_ = spread1; shortNo_ = 1; shortSpread_ = spread2; } }
public LiborForwardModelProcess(int size, IborIndex index) : this(size, index, new EulerDiscretization()) { }
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; } }
public CPISwap(Type type, double nominal, bool subtractInflationNominal, // float+spread leg double spread, DayCounter floatDayCount, Schedule floatSchedule, BusinessDayConvention floatPaymentRoll, int fixingDays, IborIndex floatIndex, // fixed x inflation leg double fixedRate, double baseCPI, DayCounter fixedDayCount, Schedule fixedSchedule, BusinessDayConvention fixedPaymentRoll, Period observationLag, ZeroInflationIndex fixedIndex, InterpolationType observationInterpolation = InterpolationType.AsIndex, double?inflationNominal = null) : base(2) { type_ = type; nominal_ = nominal; subtractInflationNominal_ = subtractInflationNominal; spread_ = spread; floatDayCount_ = floatDayCount; floatSchedule_ = floatSchedule; floatPaymentRoll_ = floatPaymentRoll; fixingDays_ = fixingDays; floatIndex_ = floatIndex; fixedRate_ = fixedRate; baseCPI_ = baseCPI; fixedDayCount_ = fixedDayCount; fixedSchedule_ = fixedSchedule; fixedPaymentRoll_ = fixedPaymentRoll; fixedIndex_ = fixedIndex; observationLag_ = observationLag; observationInterpolation_ = observationInterpolation; Utils.QL_REQUIRE(floatSchedule_.Count > 0, () => "empty float schedule"); Utils.QL_REQUIRE(fixedSchedule_.Count > 0, () => "empty fixed schedule"); // todo if roll!=unadjusted then need calendars ... inflationNominal_ = inflationNominal ?? nominal_; List <CashFlow> floatingLeg; if (floatSchedule_.Count > 1) { floatingLeg = new IborLeg(floatSchedule_, floatIndex_) .withFixingDays(fixingDays_) .withPaymentDayCounter(floatDayCount_) .withSpreads(spread_) .withNotionals(nominal_) .withPaymentAdjustment(floatPaymentRoll_); } else { floatingLeg = new List <CashFlow>(); } if (floatSchedule_.Count == 1 || !subtractInflationNominal_ || (subtractInflationNominal && Math.Abs(nominal_ - inflationNominal_) > 0.00001) ) { Date payNotional; if (floatSchedule_.Count == 1) { // no coupons payNotional = floatSchedule_[0]; payNotional = floatSchedule_.calendar().adjust(payNotional, floatPaymentRoll_); } else { // use the pay date of the last coupon payNotional = floatingLeg.Last().date(); } double floatAmount = subtractInflationNominal_ ? nominal_ - inflationNominal_ : nominal_; CashFlow nf = new SimpleCashFlow(floatAmount, payNotional); floatingLeg.Add(nf); } // a CPIleg know about zero legs and inclusion of base inflation notional List <CashFlow> cpiLeg = new CPILeg(fixedSchedule_, fixedIndex_, baseCPI_, observationLag_) .withFixedRates(fixedRate_) .withPaymentDayCounter(fixedDayCount_) .withObservationInterpolation(observationInterpolation_) .withSubtractInflationNominal(subtractInflationNominal_) .withNotionals(inflationNominal_) .withPaymentAdjustment(fixedPaymentRoll_); foreach (CashFlow cashFlow in cpiLeg) { cashFlow.registerWith(update); } if (floatingLeg.Count > 0) { foreach (CashFlow cashFlow in floatingLeg) { cashFlow.registerWith(update); } } legs_[0] = cpiLeg; legs_[1] = floatingLeg; if (type_ == Type.Payer) { payer_[0] = 1.0; payer_[1] = -1.0; } else { payer_[0] = -1.0; payer_[1] = 1.0; } }
// calculating swaption volatility matrix using // Rebonatos approx. formula. Be aware that this // matrix is valid only for regular fixings and // assumes that the fix and floating leg have the // same frequency public SwaptionVolatilityMatrix getSwaptionVolatilityMatrix() { if (swaptionVola != null) { return(swaptionVola); } IborIndex index = process_.index(); Date today = process_.fixingDates()[0]; int size = process_.size() / 2; Matrix volatilities = new Matrix(size, size); List <Date> exercises = new InitializedList <Date>(size); for (int i = 0; i < size; ++i) { exercises[i] = process_.fixingDates()[i + 1]; } List <Period> lengths = new InitializedList <Period>(size); for (int i = 0; i < size; ++i) { lengths[i] = (i + 1) * index.tenor(); } Vector f = process_.initialValues(); for (int k = 0; k < size; ++k) { int alpha = k; double t_alpha = process_.fixingTimes()[alpha + 1]; Matrix var = new Matrix(size, size); for (int i = alpha + 1; i <= k + size; ++i) { for (int j = i; j <= k + size; ++j) { var[i - alpha - 1, j - alpha - 1] = var[j - alpha - 1, i - alpha - 1] = covarProxy_.integratedCovariance(i, j, t_alpha, null); } } for (int l = 1; l <= size; ++l) { int beta = l + k; Vector w = w_0(alpha, beta); double sum = 0.0; for (int i = alpha + 1; i <= beta; ++i) { for (int j = alpha + 1; j <= beta; ++j) { sum += w[i] * w[j] * f[i] * f[j] * var[i - alpha - 1, j - alpha - 1]; } } volatilities[k, l - 1] = Math.Sqrt(sum / t_alpha) / S_0(alpha, beta); } } return(swaptionVola = new SwaptionVolatilityMatrix(today, exercises, lengths, volatilities, index.dayCounter())); }
public FloatingCatBond(int settlementDays, double faceAmount, Date startDate, Date maturityDate, Frequency couponFrequency, Calendar calendar, IborIndex iborIndex, DayCounter accrualDayCounter, NotionalRisk notionalRisk, BusinessDayConvention accrualConvention = BusinessDayConvention.Following, BusinessDayConvention paymentConvention = BusinessDayConvention.Following, int fixingDays = 0, List <double> gearings = null, List <double> spreads = null, List <double?> caps = null, List <double?> floors = null, bool inArrears = false, double redemption = 100.0, Date issueDate = null, Date stubDate = null, DateGeneration.Rule rule = DateGeneration.Rule.Backward, bool endOfMonth = false) : base(settlementDays, calendar, issueDate, notionalRisk) { maturityDate_ = maturityDate; Date firstDate = null, nextToLastDate = null; switch (rule) { case DateGeneration.Rule.Backward: firstDate = new Date(); nextToLastDate = stubDate; break; case DateGeneration.Rule.Forward: firstDate = stubDate; nextToLastDate = new Date(); break; case DateGeneration.Rule.Zero: case DateGeneration.Rule.ThirdWednesday: case DateGeneration.Rule.Twentieth: case DateGeneration.Rule.TwentiethIMM: Utils.QL_FAIL("stub date (" + stubDate + ") not allowed with " + rule + " DateGeneration.Rule"); break; default: Utils.QL_FAIL("unknown DateGeneration::Rule (" + rule + ")"); break; } Schedule schedule = new Schedule(startDate, maturityDate_, new Period(couponFrequency), calendar_, accrualConvention, accrualConvention, rule, endOfMonth, firstDate, nextToLastDate); cashflows_ = new IborLeg(schedule, iborIndex) .withFixingDays(fixingDays) .withGearings(gearings) .withSpreads(spreads) .withCaps(caps) .withFloors(floors) .inArrears(inArrears) .withPaymentDayCounter(accrualDayCounter) .withPaymentAdjustment(paymentConvention) .withNotionals(faceAmount); addRedemptionsToCashflows(new InitializedList <double>(1, redemption)); Utils.QL_REQUIRE(!cashflows().empty(), () => "bond with no cashflows!"); Utils.QL_REQUIRE(redemptions_.Count == 1, () => "multiple redemptions created"); iborIndex.registerWith(update); }
public BMASwap(Type type, double nominal, // Libor leg Schedule liborSchedule, double liborFraction, double liborSpread, IborIndex liborIndex, DayCounter liborDayCount, // BMA leg Schedule bmaSchedule, BMAIndex bmaIndex, DayCounter bmaDayCount) : base(2) { type_ = type; nominal_ = nominal; liborFraction_ = liborFraction; liborSpread_ = liborSpread; BusinessDayConvention convention = liborSchedule.businessDayConvention(); legs_[0] = new IborLeg(liborSchedule, liborIndex) .withPaymentDayCounter(liborDayCount) .withFixingDays(liborIndex.fixingDays()) .withGearings(liborFraction) .withSpreads(liborSpread) .withNotionals(nominal) .withPaymentAdjustment(convention); legs_[1] = new AverageBMALeg(bmaSchedule, bmaIndex) .withPaymentDayCounter(bmaDayCount) .withNotionals(nominal) .withPaymentAdjustment(bmaSchedule.businessDayConvention()); for (int j = 0; j < 2; ++j) { for (int i = 0; i < legs_[j].Count; i++) { legs_[j][i].registerWith(update); } } switch (type_) { case Type.Payer: payer_[0] = +1.0; payer_[1] = -1.0; break; case Type.Receiver: payer_[0] = -1.0; payer_[1] = +1.0; break; default: Utils.QL_FAIL("Unknown BMA-swap type"); break; } }
private void init(BusinessDayConvention?paymentConvention1, BusinessDayConvention?paymentConvention2) { Utils.QL_REQUIRE(nominal1_.Count == schedule1_.Count - 1, () => "nominal1 size (" + nominal1_.Count + ") does not match schedule1 size (" + schedule1_.size() + ")"); Utils.QL_REQUIRE(nominal2_.Count == schedule2_.Count - 1, () => "nominal2 size (" + nominal2_.Count + ") does not match schedule2 size (" + nominal2_.Count + ")"); Utils.QL_REQUIRE(gearing1_.Count == 0 || gearing1_.Count == nominal1_.Count, () => "nominal1 size (" + nominal1_.Count + ") does not match gearing1 size (" + gearing1_.Count + ")"); Utils.QL_REQUIRE(gearing2_.Count == 0 || gearing2_.Count == nominal2_.Count, () => "nominal2 size (" + nominal2_.Count + ") does not match gearing2 size (" + gearing2_.Count + ")"); Utils.QL_REQUIRE(cappedRate1_.Count == 0 || cappedRate1_.Count == nominal1_.Count, () => "nominal1 size (" + nominal1_.Count + ") does not match cappedRate1 size (" + cappedRate1_.Count + ")"); Utils.QL_REQUIRE(cappedRate2_.Count == 0 || cappedRate2_.Count == nominal2_.Count, () => "nominal2 size (" + nominal2_.Count + ") does not match cappedRate2 size (" + cappedRate2_.Count + ")"); Utils.QL_REQUIRE(flooredRate1_.Count == 0 || flooredRate1_.Count == nominal1_.Count, () => "nominal1 size (" + nominal1_.Count + ") does not match flooredRate1 size (" + flooredRate1_.Count + ")"); Utils.QL_REQUIRE(flooredRate2_.Count == 0 || flooredRate2_.Count == nominal2_.Count, () => "nominal2 size (" + nominal2_.Count + ") does not match flooredRate2 size (" + flooredRate2_.Count + ")"); if (paymentConvention1 != null) { paymentConvention1_ = paymentConvention1.Value; } else { paymentConvention1_ = schedule1_.businessDayConvention(); } if (paymentConvention2 != null) { paymentConvention2_ = paymentConvention2.Value; } else { paymentConvention2_ = schedule2_.businessDayConvention(); } if (gearing1_.Count == 0) { gearing1_ = new InitializedList <double>(nominal1_.Count, 1.0); } if (gearing2_.Count == 0) { gearing2_ = new InitializedList <double>(nominal2_.Count, 1.0); } if (spread1_.Count == 0) { spread1_ = new InitializedList <double>(nominal1_.Count, 0.0); } if (spread2_.Count == 0) { spread2_ = new InitializedList <double>(nominal2_.Count, 0.0); } if (cappedRate1_.Count == 0) { cappedRate1_ = new InitializedList <double?>(nominal1_.Count, null); } if (cappedRate2_.Count == 0) { cappedRate2_ = new InitializedList <double?>(nominal2_.Count, null); } if (flooredRate1_.Count == 0) { flooredRate1_ = new InitializedList <double?>(nominal1_.Count, null); } if (flooredRate2_.Count == 0) { flooredRate2_ = new InitializedList <double?>(nominal2_.Count, null); } bool isNull = cappedRate1_[0] == null; for (int i = 0; i < cappedRate1_.Count; i++) { if (isNull) { Utils.QL_REQUIRE(cappedRate1_[i] == null, () => "cappedRate1 must be null for all or none entry (" + (i + 1) + "th is " + cappedRate1_[i] + ")"); } else { Utils.QL_REQUIRE(cappedRate1_[i] != null, () => "cappedRate 1 must be null for all or none entry (" + "1st is " + cappedRate1_[0] + ")"); } } isNull = cappedRate2_[0] == null; for (int i = 0; i < cappedRate2_.Count; i++) { if (isNull) { Utils.QL_REQUIRE(cappedRate2_[i] == null, () => "cappedRate2 must be null for all or none entry (" + (i + 1) + "th is " + cappedRate2_[i] + ")"); } else { Utils.QL_REQUIRE(cappedRate2_[i] != null, () => "cappedRate2 must be null for all or none entry (" + "1st is " + cappedRate2_[0] + ")"); } } isNull = flooredRate1_[0] == null; for (int i = 0; i < flooredRate1_.Count; i++) { if (isNull) { Utils.QL_REQUIRE(flooredRate1_[i] == null, () => "flooredRate1 must be null for all or none entry (" + (i + 1) + "th is " + flooredRate1_[i] + ")"); } else { Utils.QL_REQUIRE(flooredRate1_[i] != null, () => "flooredRate 1 must be null for all or none entry (" + "1st is " + flooredRate1_[0] + ")"); } } isNull = flooredRate2_[0] == null; for (int i = 0; i < flooredRate2_.Count; i++) { if (isNull) { Utils.QL_REQUIRE(flooredRate2_[i] == null, () => "flooredRate2 must be null for all or none entry (" + (i + 1) + "th is " + flooredRate2_[i] + ")"); } else { Utils.QL_REQUIRE(flooredRate2_[i] != null, () => "flooredRate2 must be null for all or none entry (" + "1st is " + flooredRate2_[0] + ")"); } } // if the gearing is zero then the ibor / cms leg will be set up with // fixed coupons which makes trouble here in this context. We therefore // use a dirty trick and enforce the gearing to be non zero. for (int i = 0; i < gearing1_.Count; i++) { if (Utils.close(gearing1_[i], 0.0)) { gearing1_[i] = Const.QL_EPSILON; } } for (int i = 0; i < gearing2_.Count; i++) { if (Utils.close(gearing2_[i], 0.0)) { gearing2_[i] = Const.QL_EPSILON; } } IborIndex ibor1 = index1_ as IborIndex; IborIndex ibor2 = index2_ as IborIndex; SwapIndex cms1 = index1_ as SwapIndex; SwapIndex cms2 = index2_ as SwapIndex; SwapSpreadIndex cmsspread1 = index1_ as SwapSpreadIndex; SwapSpreadIndex cmsspread2 = index2_ as SwapSpreadIndex; Utils.QL_REQUIRE(ibor1 != null || cms1 != null || cmsspread1 != null, () => "index1 must be ibor or cms or cms spread"); Utils.QL_REQUIRE(ibor2 != null || cms2 != null || cmsspread2 != null, () => "index2 must be ibor or cms"); if (ibor1 != null) { IborLeg leg = new IborLeg(schedule1_, ibor1); leg = (IborLeg)leg.withPaymentDayCounter(dayCount1_) .withSpreads(spread1_) .withGearings(gearing1_) .withPaymentAdjustment(paymentConvention1_) .withNotionals(nominal1_); if (cappedRate1_[0] != null) { leg = (IborLeg)leg.withCaps(cappedRate1_); } if (flooredRate1_[0] != null) { leg = (IborLeg)leg.withFloors(flooredRate1_); } legs_[0] = leg; } if (ibor2 != null) { IborLeg leg = new IborLeg(schedule2_, ibor2); leg = (IborLeg)leg.withPaymentDayCounter(dayCount2_) .withSpreads(spread2_) .withGearings(gearing2_) .withPaymentAdjustment(paymentConvention2_) .withNotionals(nominal2_); if (cappedRate2_[0] != null) { leg = (IborLeg)leg.withCaps(cappedRate2_); } if (flooredRate2_[0] != null) { leg = (IborLeg)leg.withFloors(flooredRate2_); } legs_[1] = leg; } if (cms1 != null) { CmsLeg leg = new CmsLeg(schedule1_, cms1); leg = (CmsLeg)leg.withPaymentDayCounter(dayCount1_) .withSpreads(spread1_) .withGearings(gearing1_) .withNotionals(nominal1_) .withPaymentAdjustment(paymentConvention1_); if (cappedRate1_[0] != null) { leg = (CmsLeg)leg.withCaps(cappedRate1_); } if (flooredRate1_[0] != null) { leg = (CmsLeg)leg.withFloors(flooredRate1_); } legs_[0] = leg; } if (cms2 != null) { CmsLeg leg = new CmsLeg(schedule2_, cms2); leg = (CmsLeg)leg.withPaymentDayCounter(dayCount2_) .withSpreads(spread2_) .withGearings(gearing2_) .withNotionals(nominal2_) .withPaymentAdjustment(paymentConvention2_); if (cappedRate2_[0] != null) { leg = (CmsLeg)leg.withCaps(cappedRate2_); } if (flooredRate2_[0] != null) { leg = (CmsLeg)leg.withFloors(flooredRate2_); } legs_[1] = leg; } if (cmsspread1 != null) { CmsSpreadLeg leg = new CmsSpreadLeg(schedule1_, cmsspread1); leg = (CmsSpreadLeg)leg.withPaymentDayCounter(dayCount1_) .withSpreads(spread1_) .withGearings(gearing1_) .withNotionals(nominal1_) .withPaymentAdjustment(paymentConvention1_); if (cappedRate1_[0] != null) { leg = (CmsSpreadLeg)leg.withCaps(cappedRate1_); } if (flooredRate1_[0] != null) { leg = (CmsSpreadLeg)leg.withFloors(flooredRate1_); } legs_[0] = leg; } if (cmsspread2 != null) { CmsSpreadLeg leg = new CmsSpreadLeg(schedule2_, cmsspread2); leg = (CmsSpreadLeg)leg.withPaymentDayCounter(dayCount2_) .withSpreads(spread2_) .withGearings(gearing2_) .withNotionals(nominal2_) .withPaymentAdjustment(paymentConvention2_); if (cappedRate2_[0] != null) { leg = (CmsSpreadLeg)leg.withCaps(cappedRate2_); } if (flooredRate2_[0] != null) { leg = (CmsSpreadLeg)leg.withFloors(flooredRate2_); } legs_[1] = leg; } if (intermediateCapitalExchange_) { for (int i = 0; i < legs_[0].Count - 1; i++) { double cap = nominal1_[i] - nominal1_[i + 1]; if (!Utils.close(cap, 0.0)) { legs_[0].Insert(i + 1, new Redemption(cap, legs_[0][i].date())); nominal1_.Insert(i + 1, nominal1_[i]); i++; } } for (int i = 0; i < legs_[1].Count - 1; i++) { double cap = nominal2_[i] - nominal2_[i + 1]; if (!Utils.close(cap, 0.0)) { legs_[1].Insert(i + 1, new Redemption(cap, legs_[1][i].date())); nominal2_.Insert(i + 1, nominal2_[i]); i++; } } } if (finalCapitalExchange_) { legs_[0].Add(new Redemption(nominal1_.Last(), legs_[0].Last().date())); nominal1_.Add(nominal1_.Last()); legs_[1].Add(new Redemption(nominal2_.Last(), legs_[1].Last().date())); nominal2_.Add(nominal2_.Last()); } foreach (var c in legs_[0]) { c.registerWith(update); } foreach (var c in legs_[1]) { c.registerWith(update); } switch (type_) { case VanillaSwap.Type.Payer: payer_[0] = -1.0; payer_[1] = +1.0; break; case VanillaSwap.Type.Receiver: payer_[0] = +1.0; payer_[1] = -1.0; break; default: Utils.QL_FAIL("Unknown float float - swap type"); break; } }
public FloatingRateBond(int settlementDays, double faceAmount, Schedule schedule, IborIndex index, DayCounter paymentDayCounter, BusinessDayConvention paymentConvention, int fixingDays, List <double> gearings, List <double> spreads, List <double?> caps, List <double?> floors, bool inArrears, double redemption, Date issueDate) : base(settlementDays, schedule.calendar(), issueDate) { maturityDate_ = schedule.endDate(); cashflows_ = new IborLeg(schedule, index) .withPaymentDayCounter(paymentDayCounter) .withFixingDays(fixingDays) .withGearings(gearings) .withSpreads(spreads) .withCaps(caps) .withFloors(floors) .inArrears(inArrears) .withNotionals(faceAmount) .withPaymentAdjustment(paymentConvention); addRedemptionsToCashflows(new List <double>() { redemption }); Utils.QL_REQUIRE(cashflows().Count != 0, () => "bond with no cashflows!"); Utils.QL_REQUIRE(redemptions_.Count == 1, () => "multiple redemptions created"); index.registerWith(update); }
public FloatingRateBond(int settlementDays, double faceAmount, Schedule schedule, IborIndex index, DayCounter paymentDayCounter, BusinessDayConvention paymentConvention, int fixingDays, List <double> gearings, List <double> spreads) : this(settlementDays, faceAmount, schedule, index, paymentDayCounter, BusinessDayConvention.Following, fixingDays, gearings, spreads, new List <double?>(), new List <double?>(), false, 100, null) { }
public FloatingRateBond(int settlementDays, double faceAmount, Schedule schedule, IborIndex index, DayCounter paymentDayCounter) : this(settlementDays, faceAmount, schedule, index, paymentDayCounter, BusinessDayConvention.Following, 0, new List <double>() { 1 }, new List <double>() { 0 }, new List <double?>(), new List <double?>(), false, 100, null) { }
public override void calculate() { /* both DTS, YTS ref dates and pricing date consistency * checks? settlement... */ Utils.QL_REQUIRE(!discountCurve_.empty(), () => "no discount term structure set"); Utils.QL_REQUIRE(!defaultTS_.empty(), () => "no ctpty default term structure set"); Utils.QL_REQUIRE(!swaptionletEngine_.empty(), () => "no swap option engine set"); Date priceDate = defaultTS_.link.referenceDate(); double cumOptVal = 0.0, cumPutVal = 0.0; // Vanilla swap so 0 leg is floater int index = 0; Date nextFD = arguments_.fixedPayDates[index]; Date swapletStart = priceDate; while (nextFD < priceDate) { index++; nextFD = arguments_.fixedPayDates[index]; } // Compute fair spread for strike value: // copy args into the non risky engine Swap.Arguments noCVAArgs = baseSwapEngine_.link.getArguments() as Swap.Arguments; noCVAArgs.legs = this.arguments_.legs; noCVAArgs.payer = this.arguments_.payer; baseSwapEngine_.link.calculate(); double baseSwapRate = ((FixedRateCoupon)arguments_.legs[0][0]).rate(); Swap.Results vSResults = baseSwapEngine_.link.getResults() as Swap.Results; double?baseSwapFairRate = -baseSwapRate * vSResults.legNPV[1] / vSResults.legNPV[0]; double?baseSwapNPV = vSResults.value; VanillaSwap.Type reversedType = arguments_.type == VanillaSwap.Type.Payer ? VanillaSwap.Type.Receiver : VanillaSwap.Type.Payer; // Swaplet options summatory: while (nextFD != arguments_.fixedPayDates.Last()) { // iFD coupon not fixed, create swaptionlet: IborIndex swapIndex = ((FloatingRateCoupon)arguments_.legs[1][0]).index() as IborIndex; // Alternatively one could cap this period to, say, 1M Period baseSwapsTenor = new Period(arguments_.fixedPayDates.Last().serialNumber() - swapletStart.serialNumber(), TimeUnit.Days); VanillaSwap swaplet = new MakeVanillaSwap(baseSwapsTenor, swapIndex, baseSwapFairRate) .withType(arguments_.type) .withNominal(arguments_.nominal) .withEffectiveDate(swapletStart) .withTerminationDate(arguments_.fixedPayDates.Last()).value(); VanillaSwap revSwaplet = new MakeVanillaSwap(baseSwapsTenor, swapIndex, baseSwapFairRate) .withType(reversedType) .withNominal(arguments_.nominal) .withEffectiveDate(swapletStart) .withTerminationDate(arguments_.fixedPayDates.Last()).value(); Swaption swaptionlet = new Swaption(swaplet, new EuropeanExercise(swapletStart)); Swaption putSwaplet = new Swaption(revSwaplet, new EuropeanExercise(swapletStart)); swaptionlet.setPricingEngine(swaptionletEngine_.currentLink()); putSwaplet.setPricingEngine(swaptionletEngine_.currentLink()); // atm underlying swap means that the value of put = value // call so this double pricing is not needed cumOptVal += swaptionlet.NPV() * defaultTS_.link.defaultProbability( swapletStart, nextFD); cumPutVal += putSwaplet.NPV() * invstDTS_.link.defaultProbability(swapletStart, nextFD); swapletStart = nextFD; index++; nextFD = arguments_.fixedPayDates[index]; } results_.value = baseSwapNPV - (1.0 - ctptyRecoveryRate_) * cumOptVal + (1.0 - invstRecoveryRate_) * cumPutVal; results_.fairRate = -baseSwapRate * (vSResults.legNPV[1] - (1.0 - ctptyRecoveryRate_) * cumOptVal + (1.0 - invstRecoveryRate_) * cumPutVal) / vSResults.legNPV[0]; }