// LazyObject interface protected override void performCalculations() { // update dates Date referenceDate = termVolSurface_.referenceDate(); DayCounter dc = termVolSurface_.dayCounter(); BlackCapFloorEngine dummy = new BlackCapFloorEngine( // discounting does not matter here iborIndex_.forwardingTermStructure(), 0.20, dc); for (int i = 0; i < nOptionletTenors_; ++i) { CapFloor temp = new MakeCapFloor(CapFloorType.Cap, capFloorLengths_[i], iborIndex_, 0.04, // dummy strike new Period(0, TimeUnit.Days)) .withPricingEngine(dummy); FloatingRateCoupon lFRC = temp.lastFloatingRateCoupon(); optionletDates_[i] = lFRC.fixingDate(); optionletPaymentDates_[i] = lFRC.date(); optionletAccrualPeriods_[i] = lFRC.accrualPeriod(); optionletTimes_[i] = dc.yearFraction(referenceDate, optionletDates_[i]); atmOptionletRate_[i] = lFRC.indexFixing(); } if (floatingSwitchStrike_ && capFlooMatrixNotInitialized_) { double averageAtmOptionletRate = 0.0; for (int i = 0; i < nOptionletTenors_; ++i) { averageAtmOptionletRate += atmOptionletRate_[i]; } switchStrike_ = averageAtmOptionletRate / nOptionletTenors_; } Handle <YieldTermStructure> discountCurve = discount_.empty() ? iborIndex_.forwardingTermStructure() : discount_; List <double> strikes = new List <double>(termVolSurface_.strikes()); // initialize CapFloorMatrix if (capFlooMatrixNotInitialized_) { for (int i = 0; i < nOptionletTenors_; ++i) { capFloors_[i] = new List <CapFloor>(nStrikes_); } // construction might go here for (int j = 0; j < nStrikes_; ++j) { // using out-of-the-money options CapFloorType capFloorType = strikes[j] < switchStrike_ ? CapFloorType.Floor : CapFloorType.Cap; for (int i = 0; i < nOptionletTenors_; ++i) { if (volatilityType_ == VolatilityType.ShiftedLognormal) { BlackCapFloorEngine engine = new BlackCapFloorEngine(discountCurve, new Handle <Quote>(volQuotes_[i][j]), dc, displacement_); capFloors_[i].Add(new MakeCapFloor(capFloorType, capFloorLengths_[i], iborIndex_, strikes[j], new Period(0, TimeUnit.Days)).withPricingEngine(engine)); } else if (volatilityType_ == VolatilityType.Normal) { BachelierCapFloorEngine engine = new BachelierCapFloorEngine(discountCurve, new Handle <Quote>(volQuotes_[i][j]), dc); capFloors_[i].Add(new MakeCapFloor(capFloorType, capFloorLengths_[i], iborIndex_, strikes[j], new Period(0, TimeUnit.Days)).withPricingEngine(engine)); } else { Utils.QL_FAIL("unknown volatility type: " + volatilityType_); } } } capFlooMatrixNotInitialized_ = false; } for (int j = 0; j < nStrikes_; ++j) { Option.Type optionletType = strikes[j] < switchStrike_ ? Option.Type.Put : Option.Type.Call; double previousCapFloorPrice = 0.0; for (int i = 0; i < nOptionletTenors_; ++i) { capFloorVols_[i, j] = termVolSurface_.volatility(capFloorLengths_[i], strikes[j], true); volQuotes_[i][j].setValue(capFloorVols_[i, j]); capFloorPrices_[i, j] = capFloors_[i][j].NPV(); optionletPrices_[i, j] = capFloorPrices_[i, j] - previousCapFloorPrice; previousCapFloorPrice = capFloorPrices_[i, j]; double d = discountCurve.link.discount(optionletPaymentDates_[i]); double optionletAnnuity = optionletAccrualPeriods_[i] * d; try { if (volatilityType_ == VolatilityType.ShiftedLognormal) { optionletStDevs_[i, j] = Utils.blackFormulaImpliedStdDev(optionletType, strikes[j], atmOptionletRate_[i], optionletPrices_[i, j], optionletAnnuity, displacement_, optionletStDevs_[i, j], accuracy_, maxIter_); } else if (volatilityType_ == VolatilityType.Normal) { optionletStDevs_[i, j] = Math.Sqrt(optionletTimes_[i]) * Utils.bachelierBlackFormulaImpliedVol( optionletType, strikes[j], atmOptionletRate_[i], optionletTimes_[i], optionletPrices_[i, j], optionletAnnuity); } else { Utils.QL_FAIL("Unknown volatility type: " + volatilityType_); } } catch (Exception e) { if (dontThrow_) { optionletStDevs_[i, j] = 0.0; } else { Utils.QL_FAIL("could not bootstrap optionlet:" + "\n type: " + optionletType + "\n strike: " + (strikes[j]) + "\n atm: " + (atmOptionletRate_[i]) + "\n price: " + optionletPrices_[i, j] + "\n annuity: " + optionletAnnuity + "\n expiry: " + optionletDates_[i] + "\n error: " + e.Message); } } optionletVolatilities_[i][j] = optionletStDevs_[i, j] / Math.Sqrt(optionletTimes_[i]); } } }
public YoYInflationCapFloor makeYoYCapFloor(CapFloorType type, List<CashFlow> leg, double strike, double volatility, int which) { YoYInflationCapFloor result = null; switch (type) { case CapFloorType.Cap: result = new YoYInflationCap(leg, new List<double>(){strike}); break; case CapFloorType.Floor: result = new YoYInflationFloor( leg, new List<double>() { strike } ); break; default: Utils.QL_FAIL("unknown YoYInflation cap/floor type"); break; } result.setPricingEngine(makeEngine(volatility, which)); return result; }
public override void calculate() { if (model_ == null) { throw new ArgumentException("null model"); } Date referenceDate = new Date(); DayCounter dayCounter = new DayCounter(); try{ TermStructureConsistentModel tsmodel = (TermStructureConsistentModel)model_.link; ///if (tsmodel != null) referenceDate = tsmodel.termStructure().link.referenceDate(); dayCounter = tsmodel.termStructure().link.dayCounter(); } //else catch { referenceDate = termStructure_.link.referenceDate(); dayCounter = termStructure_.link.dayCounter(); } double value = 0.0; CapFloorType type = arguments_.type; int nPeriods = arguments_.endDates.Count; for (int i = 0; i < nPeriods; i++) { double fixingTime = dayCounter.yearFraction(referenceDate, arguments_.fixingDates[i]); double paymentTime = dayCounter.yearFraction(referenceDate, arguments_.endDates[i]); #if QL_TODAYS_PAYMENTS if (paymentTime >= 0.0) { #else if (paymentTime > 0.0) { #endif double tenor = arguments_.accrualTimes[i]; double fixing = (double)arguments_.forwards[i]; if (fixingTime <= 0.0) { if (type == CapFloorType.Cap || type == CapFloorType.Collar) { double discount = model_.link.discount(paymentTime); double strike = (double)arguments_.capRates[i]; value += discount * arguments_.nominals[i] * tenor * arguments_.gearings[i] * Math.Max(0.0, fixing - strike); } if (type == CapFloorType.Floor || type == CapFloorType.Collar) { double discount = model_.link.discount(paymentTime); double strike = (double)arguments_.floorRates[i]; double mult = (type == CapFloorType.Floor) ? 1.0 : -1.0; value += discount * arguments_.nominals[i] * tenor * mult * arguments_.gearings[i] * Math.Max(0.0, strike - fixing); } } else { double maturity = dayCounter.yearFraction(referenceDate, arguments_.startDates[i]); if (type == CapFloorType.Cap || type == CapFloorType.Collar) { double temp = 1.0 + (double)arguments_.capRates[i] * tenor; value += arguments_.nominals[i] * arguments_.gearings[i] * temp * model_.link.discountBondOption(Option.Type.Put, 1.0 / temp, maturity, paymentTime); } if (type == CapFloorType.Floor || type == CapFloorType.Collar) { double temp = 1.0 + (double)arguments_.floorRates[i] * tenor; double mult = (type == CapFloorType.Floor) ? 1.0 : -1.0; value += arguments_.nominals[i] * arguments_.gearings[i] * temp *mult * model_.link.discountBondOption(Option.Type.Call, 1.0 / temp, maturity, paymentTime); } } } } results_.value = value; } }
public override void calculate() { // copy black version then adapt to others double value = 0.0; int optionlets = arguments_.startDates.Count; InitializedList <double> values = new InitializedList <double>(optionlets, 0.0); InitializedList <double> stdDevs = new InitializedList <double>(optionlets, 0.0); InitializedList <double> forwards = new InitializedList <double> (optionlets, 0.0); CapFloorType type = arguments_.type; Handle <YoYInflationTermStructure> yoyTS = index().yoyInflationTermStructure(); Handle <YieldTermStructure> nominalTS = yoyTS.link.nominalTermStructure(); Date settlement = nominalTS.link.referenceDate(); for (int i = 0; i < optionlets; ++i) { Date paymentDate = arguments_.payDates[i]; if (paymentDate > settlement) { // discard expired caplets double d = arguments_.nominals[i] * arguments_.gearings[i] * nominalTS.link.discount(paymentDate) * arguments_.accrualTimes[i]; // We explicitly have the index and assume that // the fixing is natural, i.e. no convexity adjustment. // If that was required then we would also need // nominal vols in the pricing engine, i.e. a different engine. // This also means that we do not need the coupon to have // a pricing engine to return the swaplet rate and then // the adjusted fixing in the instrument. forwards[i] = yoyTS.link.yoyRate(arguments_.fixingDates[i], new Period(0, TimeUnit.Days)); double forward = forwards[i]; Date fixingDate = arguments_.fixingDates[i]; double sqrtTime = 0.0; if (fixingDate > volatility_.link.baseDate()) { sqrtTime = Math.Sqrt(volatility_.link.timeFromBase(fixingDate)); } if (type == CapFloorType.Cap || type == CapFloorType.Collar) { double strike = arguments_.capRates[i].Value; if (sqrtTime > 0.0) { stdDevs[i] = Math.Sqrt(volatility_.link.totalVariance(fixingDate, strike, new Period(0, TimeUnit.Days))); } // sttDev=0 for already-fixed dates so everything on forward values[i] = optionletImpl(Option.Type.Call, strike, forward, stdDevs[i], d); } if (type == CapFloorType.Floor || type == CapFloorType.Collar) { double strike = arguments_.floorRates[i].Value; if (sqrtTime > 0.0) { stdDevs[i] = Math.Sqrt(volatility_.link.totalVariance(fixingDate, strike, new Period(0, TimeUnit.Days))); } double floorlet = optionletImpl(Option.Type.Put, strike, forward, stdDevs[i], d); if (type == CapFloorType.Floor) { values[i] = floorlet; } else { // a collar is long a cap and short a floor values[i] -= floorlet; } } value += values[i]; } } results_.value = value; results_.additionalResults["optionletsPrice"] = values; results_.additionalResults["optionletsAtmForward"] = forwards; if (type != CapFloorType.Collar) { results_.additionalResults["optionletsStdDev"] = stdDevs; } }
public CapFloor makeCapFloor(CapFloorType type, List<CashFlow> leg, double strike, double volatility) { CapFloor result; switch (type) { case CapFloorType.Cap: result = (CapFloor)new Cap(leg, new List<double>() { strike }); break; case CapFloorType.Floor: result = (CapFloor)new Floor(leg, new List<double>() { strike }); break; default: throw new ArgumentException("unknown cap/floor type"); } result.setPricingEngine(makeEngine(volatility)); return result; }
string typeToString(CapFloorType type) { switch (type) { case CapFloorType.Cap: return "cap"; case CapFloorType.Floor: return "floor"; case CapFloorType.Collar: return "collar"; default: throw new ArgumentException("unknown cap/floor type"); } }
public override void calculate() { double value = 0.0; double vega = 0.0; int optionlets = arguments_.startDates.Count; List <double> values = new InitializedList <double>(optionlets, 0.0); List <double> vegas = new InitializedList <double>(optionlets, 0.0); List <double> stdDevs = new InitializedList <double>(optionlets, 0.0); CapFloorType type = arguments_.type; Date today = vol_.link.referenceDate(); Date settlement = discountCurve_.link.referenceDate(); for (int i = 0; i < optionlets; ++i) { Date paymentDate = arguments_.endDates[i]; // handling of settlementDate, npvDate and includeSettlementFlows // should be implemented. // For the double being just discard expired caplets if (paymentDate > settlement) { double d = arguments_.nominals[i] * arguments_.gearings[i] * discountCurve_.link.discount(paymentDate) * arguments_.accrualTimes[i]; double forward = arguments_.forwards[i].Value; Date fixingDate = arguments_.fixingDates[i]; double sqrtTime = 0.0; if (fixingDate > today) { sqrtTime = Math.Sqrt(vol_.link.timeFromReference(fixingDate)); } if (type == CapFloorType.Cap || type == CapFloorType.Collar) { double strike = arguments_.capRates[i].Value; if (sqrtTime > 0.0) { stdDevs[i] = Math.Sqrt(vol_.link.blackVariance(fixingDate, strike)); vegas[i] = Utils.bachelierBlackFormulaStdDevDerivative(strike, forward, stdDevs[i], d) * sqrtTime; } // include caplets with past fixing date values[i] = Utils.bachelierBlackFormula(Option.Type.Call, strike, forward, stdDevs[i], d); } if (type == CapFloorType.Floor || type == CapFloorType.Collar) { double strike = arguments_.floorRates[i].Value; double floorletVega = 0.0; if (sqrtTime > 0.0) { stdDevs[i] = Math.Sqrt(vol_.link.blackVariance(fixingDate, strike)); floorletVega = Utils.bachelierBlackFormulaStdDevDerivative(strike, forward, stdDevs[i], d) * sqrtTime; } double floorlet = Utils.bachelierBlackFormula(Option.Type.Put, strike, forward, stdDevs[i], d); if (type == CapFloorType.Floor) { values[i] = floorlet; vegas[i] = floorletVega; } else { // a collar is long a cap and short a floor values[i] -= floorlet; vegas[i] -= floorletVega; } } value += values[i]; vega += vegas[i]; } } results_.value = value; results_.additionalResults["vega"] = vega; results_.additionalResults["optionletsPrice"] = values; results_.additionalResults["optionletsVega"] = vegas; results_.additionalResults["optionletsAtmForward"] = arguments_.forwards; if (type != CapFloorType.Collar) { results_.additionalResults["optionletsStdDev"] = stdDevs; } }