void BlackCapFloorEngine::calculate() const { Real value = 0.0; Real vega = 0.0; Size optionlets = arguments_.startDates.size(); std::vector<Real> values(optionlets, 0.0); std::vector<Real> vegas(optionlets, 0.0); std::vector<Real> stdDevs(optionlets, 0.0); CapFloor::Type type = arguments_.type; Date today = vol_->referenceDate(); Date settlement = discountCurve_->referenceDate(); for (Size i=0; i<optionlets; ++i) { Date paymentDate = arguments_.endDates[i]; // handling of settlementDate, npvDate and includeSettlementFlows // should be implemented. // For the time being just discard expired caplets if (paymentDate > settlement) { DiscountFactor d = arguments_.nominals[i] * arguments_.gearings[i] * discountCurve_->discount(paymentDate) * arguments_.accrualTimes[i]; Rate forward = arguments_.forwards[i]; Date fixingDate = arguments_.fixingDates[i]; Time sqrtTime = 0.0; if (fixingDate > today) sqrtTime = std::sqrt(vol_->timeFromReference(fixingDate)); if (type == CapFloor::Cap || type == CapFloor::Collar) { Rate strike = arguments_.capRates[i]; if (sqrtTime>0.0) { stdDevs[i] = std::sqrt(vol_->blackVariance(fixingDate, strike)); vegas[i] = blackFormulaStdDevDerivative(strike, forward, stdDevs[i], d, displacement_) * sqrtTime; } // include caplets with past fixing date values[i] = blackFormula(Option::Call, strike, forward, stdDevs[i], d, displacement_); } if (type == CapFloor::Floor || type == CapFloor::Collar) { Rate strike = arguments_.floorRates[i]; Real floorletVega = 0.0; if (sqrtTime>0.0) { stdDevs[i] = std::sqrt(vol_->blackVariance(fixingDate, strike)); floorletVega = blackFormulaStdDevDerivative(strike, forward, stdDevs[i], d, displacement_) * sqrtTime; } Real floorlet = blackFormula(Option::Put, strike, forward, stdDevs[i], d, displacement_); if (type == CapFloor::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 != CapFloor::Collar) results_.additionalResults["optionletsStdDev"] = stdDevs; }
void YoYInflationCapFloorEngine::calculate() const { // copy black version then adapt to others Real value = 0.0; Size optionlets = arguments_.startDates.size(); std::vector<Real> values(optionlets, 0.0); std::vector<Real> stdDevs(optionlets, 0.0); std::vector<Real> forwards(optionlets, 0.0); YoYInflationCapFloor::Type type = arguments_.type; Handle<YoYInflationTermStructure> yoyTS = index()->yoyInflationTermStructure(); Handle<YieldTermStructure> nominalTS = !nominalTermStructure_.empty() ? nominalTermStructure_ : yoyTS->nominalTermStructure(); Date settlement = nominalTS->referenceDate(); for (Size i=0; i<optionlets; ++i) { Date paymentDate = arguments_.payDates[i]; if (paymentDate > settlement) { // discard expired caplets DiscountFactor d = arguments_.nominals[i] * arguments_.gearings[i] * nominalTS->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->yoyRate(arguments_.fixingDates[i],Period(0,Days)); Rate forward = forwards[i]; Date fixingDate = arguments_.fixingDates[i]; Time sqrtTime = 0.0; if (fixingDate > volatility_->baseDate()){ sqrtTime = std::sqrt( volatility_->timeFromBase(fixingDate)); } if (type == YoYInflationCapFloor::Cap || type == YoYInflationCapFloor::Collar) { Rate strike = arguments_.capRates[i]; if (sqrtTime>0.0) { stdDevs[i] = std::sqrt( volatility_->totalVariance(fixingDate, strike, Period(0,Days))); } // sttDev=0 for already-fixed dates so everything on forward values[i] = optionletImpl(Option::Call, strike, forward, stdDevs[i], d); } if (type == YoYInflationCapFloor::Floor || type == YoYInflationCapFloor::Collar) { Rate strike = arguments_.floorRates[i]; if (sqrtTime>0.0) { stdDevs[i] = std::sqrt( volatility_->totalVariance(fixingDate, strike, Period(0,Days))); } Real floorlet = optionletImpl(Option::Put, strike, forward, stdDevs[i], d); if (type == YoYInflationCapFloor::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 != YoYInflationCapFloor::Collar) results_.additionalResults["optionletsStdDev"] = stdDevs; }