20#include <ql/math/matrixutilities/pseudosqrt.hpp>
21#include <ql/pricingengines/blackformula.hpp>
22#include <ql/processes/ornsteinuhlenbeckprocess.hpp>
29using std::adjacent_difference;
41 const Handle<YieldTermStructure>& discountCurve,
const QuantLib::Handle<QuantLib::BlackVolTermStructure>& volLong,
42 const QuantLib::Handle<QuantLib::BlackVolTermStructure>& volShort,
43 const QuantLib::Handle<QuantExt::CorrelationTermStructure>& rho, Real beta)
44 : discountCurve_(discountCurve), volTSLongAsset_(volLong), volTSShortAsset_(volShort), rho_(rho), beta_(beta) {
45 QL_REQUIRE(
beta_ >= 0.0,
"beta >= 0 required, found " <<
beta_);
53 auto& mp =
results_.additionalResults;
54 QL_REQUIRE(
arguments_.exercise->type() == QuantLib::Exercise::European,
"Only European Spread Option supported");
57 Date today = Settings::instance().evaluationDate();
59 Date exerciseDate =
arguments_.exercise->lastDate();
62 if (paymentDate == Date())
65 QL_REQUIRE(paymentDate >= exerciseDate,
"Payment date needs to be on or after exercise date");
78 double F1 = parameterFlow1.atm;
79 double F2 = parameterFlow2.atm;
80 double sigma1 = parameterFlow1.sigma;
81 double sigma2 = parameterFlow2.sigma;
82 double obsTime1 = parameterFlow1.tn;
83 double obsTime2 = parameterFlow2.tn;
84 double accruals1 = parameterFlow1.accruals;
85 double accruals2 = parameterFlow2.accruals;
92 double w1 =
arguments_.longAssetFlow->gearing();
93 double w2 =
arguments_.shortAssetFlow->gearing();
95 double effectiveStrike =
arguments_.effectiveStrike - w1 * accruals1 + w2 * accruals2;
96 Real correlation = QuantLib::Null<Real>();
98 if (exerciseDate <= today && paymentDate <= today) {
100 }
else if (exerciseDate <= today && paymentDate > today) {
103 double omega =
arguments_.type == Option::Call ? 1 : -1;
105 results_.value = df *
arguments_.quantity * omega * std::max(w1 * F1 - w2 * F2 - effectiveStrike, 0.0);
107 }
else if (effectiveStrike + F2 * w2 < 0) {
110 results_.value = df *
arguments_.quantity * std::max(w1 * F1 - w2 * F2 - effectiveStrike, 0.0);
116 sigma1 = sigma1 * std::min(1.0, std::sqrt(obsTime1 / tte));
117 sigma2 = sigma2 * std::min(1.0, std::sqrt(obsTime2 / tte));
120 Y = (F2 * w2 + effectiveStrike);
122 sigmaY = sigma2 * F2 * w2 / Y;
124 sigma = std::sqrt(std::pow(sigma1, 2.0) + std::pow(sigmaY, 2.0) - 2 * sigma1 * sigmaY * correlation);
126 stdDev = sigma *
sqrt(tte);
133 mp[
"accruals1"] = accruals1;
134 mp[
"sigma1"] = sigma1;
135 mp[
"obsTime1"] = obsTime1;
137 mp[
"accruals2"] = accruals2;
138 mp[
"sigma2"] = sigma2;
139 mp[
"obsTime2"] = obsTime2;
144 mp[
"stdDev"] = stdDev;
147 mp[
"sigma_Y"] = sigmaY;
150 mp[
"exerciseDate"] = exerciseDate;
151 mp[
"paymentDate"] = paymentDate;
154 mp[
"rho"] = correlation;
155 mp[
"index1_pricingDates"] = parameterFlow1.pricingDates;
156 mp[
"index1_index"] = parameterFlow1.indexNames;
157 mp[
"index1_index_expiry"] = parameterFlow1.expiries;
158 mp[
"index1_fixing"] = parameterFlow1.fixings;
159 mp[
"index2_pricingDates"] = parameterFlow2.pricingDates;
160 mp[
"index2_index"] = parameterFlow2.indexNames;
161 mp[
"index2_index_expiry"] = parameterFlow2.expiries;
162 mp[
"index2_fixing"] = parameterFlow2.fixings;
167 const ext::shared_ptr<BlackVolTermStructure>& vol,
168 const ext::shared_ptr<FxIndex>& fxIndex)
const {
170 if (
auto cf = ext::dynamic_pointer_cast<CommodityIndexedCashFlow>(flow)) {
172 res.
tn = vol->timeFromReference(cf->pricingDate());
175 fxSpot = fxIndex->fixing(cf->pricingDate());
177 double atmUnderlyingCurrency = cf->index()->fixing(cf->pricingDate());
178 res.
atm = atmUnderlyingCurrency * fxSpot;
179 res.
sigma = res.
tn > 0 && !QuantLib::close_enough(res.
tn, 0.0)
180 ? vol->blackVol(res.
tn, atmUnderlyingCurrency,
true)
182 res.
indexNames.push_back(cf->index()->name());
183 res.
expiries.push_back(cf->index()->expiryDate());
184 res.
fixings.push_back(atmUnderlyingCurrency);
186 }
else if (
auto avgCf = ext::dynamic_pointer_cast<CommodityIndexedAverageCashFlow>(flow)) {
190 std::placeholders::_2, vol));
191 res.
tn = parameter.tn;
192 res.
atm = parameter.forward;
194 res.
sigma = parameter.sigma;
196 res.
expiries = parameter.indexExpiries;
197 res.
fixings = parameter.fixings;
200 QL_FAIL(
"SpreadOptionEngine supports only CommodityIndexedCashFlow or CommodityIndexedAverageCashFlow");
206 const Date& ed_1,
const Date& ed_2,
const ext::shared_ptr<BlackVolTermStructure>& vol)
const {
207 if (
beta_ == 0.0 || ed_1 == ed_2) {
210 Time t_1 = vol->timeFromReference(ed_1);
211 Time t_2 = vol->timeFromReference(ed_2);
212 return exp(-
beta_ * fabs(t_2 - t_1));
217 if (
arguments_.longAssetFlow->index()->underlyingName() !=
arguments_.shortAssetFlow->index()->underlyingName()) {
const Instrument::results * results_
const QuantLib::Handle< QuantExt::CorrelationTermStructure > rho_
QuantLib::Handle< QuantLib::BlackVolTermStructure > volTSShortAsset_
void calculate() const override
QuantLib::Handle< QuantLib::YieldTermStructure > discountCurve_
QuantLib::Handle< QuantLib::BlackVolTermStructure > volTSLongAsset_
CommoditySpreadOptionAnalyticalEngine(const QuantLib::Handle< QuantLib::YieldTermStructure > &discountCurve, const QuantLib::Handle< QuantLib::BlackVolTermStructure > &volTSLongAsset, const QuantLib::Handle< QuantLib::BlackVolTermStructure > &volTSShortAsset, const QuantLib::Handle< QuantExt::CorrelationTermStructure > &rho, Real beta=0.0)
double intraAssetCorrelation(const QuantLib::Date &e1, const QuantLib::Date &e2, const ext::shared_ptr< BlackVolTermStructure > &vol) const
Return the correlation between two future expiry dates ed_1 and ed_2.
PricingParameter derivePricingParameterFromFlow(const ext::shared_ptr< CommodityCashFlow > &flow, const ext::shared_ptr< BlackVolTermStructure > &vol, const ext::shared_ptr< FxIndex > &fxIndex) const
commodity average price option engine
Cash flow dependent on the average commodity spot price or future's settlement price over a period....
Cash flow dependent on a single commodity spot price or future's settlement price.
commodity spread option engine
base class for multi path generators
MomentMatchingResults matchFirstTwoMomentsTurnbullWakeman(const ext::shared_ptr< CommodityIndexedAverageCashFlow > &flow, const ext::shared_ptr< QuantLib::BlackVolTermStructure > &vol, const std::function< double(const QuantLib::Date &expiry1, const QuantLib::Date &expiry2)> &rho, QuantLib::Real strike)
RandomVariable sqrt(RandomVariable x)
CompiledFormula exp(CompiledFormula x)
std::vector< QuantLib::Date > pricingDates
std::vector< std::string > indexNames
std::vector< Real > fixings
std::vector< QuantLib::Date > expiries
Swap::arguments * arguments_