Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
Classes | Public Member Functions | Protected Attributes | Private Member Functions | List of all members
CommoditySpreadOptionAnalyticalEngine Class Reference

#include <qle/pricingengines/commodityspreadoptionengine.hpp>

+ Inheritance diagram for CommoditySpreadOptionAnalyticalEngine:
+ Collaboration diagram for CommoditySpreadOptionAnalyticalEngine:

Classes

struct  PricingParameter
 

Public Member Functions

 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)
 
void calculate () const override
 

Protected Attributes

QuantLib::Handle< QuantLib::YieldTermStructure > discountCurve_
 
QuantLib::Handle< QuantLib::BlackVolTermStructure > volTSLongAsset_
 
QuantLib::Handle< QuantLib::BlackVolTermStructure > volTSShortAsset_
 
const QuantLib::Handle< QuantExt::CorrelationTermStructurerho_
 
QuantLib::Real beta_
 

Private Member Functions

PricingParameter derivePricingParameterFromFlow (const ext::shared_ptr< CommodityCashFlow > &flow, const ext::shared_ptr< BlackVolTermStructure > &vol, const ext::shared_ptr< FxIndex > &fxIndex) const
 
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. More...
 
double rho () const
 

Detailed Description

Commodity Spread Option Engine Uses the Kirk Approximation described in Iain J. Clark - Commodity Option Pricing - Section 2.9 Rho is the correlation between two commodities and for asian future spreads the intra-asset correlation between two future contracts are parametrized as \(\rho(s, t) = \exp(-\beta * \abs(s - t))\) where \(s\) and \(t\) are times to futures expiry.

Definition at line 42 of file commodityspreadoptionengine.hpp.

Constructor & Destructor Documentation

◆ CommoditySpreadOptionAnalyticalEngine()

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 
)

Definition at line 40 of file commodityspreadoptionengine.cpp.

44 : discountCurve_(discountCurve), volTSLongAsset_(volLong), volTSShortAsset_(volShort), rho_(rho), beta_(beta) {
45 QL_REQUIRE(beta_ >= 0.0, "beta >= 0 required, found " << beta_);
46 registerWith(discountCurve_);
47 registerWith(volTSLongAsset_);
48 registerWith(volTSShortAsset_);
49}
const QuantLib::Handle< QuantExt::CorrelationTermStructure > rho_
QuantLib::Handle< QuantLib::BlackVolTermStructure > volTSShortAsset_
QuantLib::Handle< QuantLib::YieldTermStructure > discountCurve_
QuantLib::Handle< QuantLib::BlackVolTermStructure > volTSLongAsset_

Member Function Documentation

◆ calculate()

void calculate ( ) const
override

Definition at line 51 of file commodityspreadoptionengine.cpp.

51 {
52 // Populate some additional results that don't change
53 auto& mp = results_.additionalResults;
54 QL_REQUIRE(arguments_.exercise->type() == QuantLib::Exercise::European, "Only European Spread Option supported");
55 QL_REQUIRE(arguments_.longAssetFlow && arguments_.shortAssetFlow, "flows can not be null");
56
57 Date today = Settings::instance().evaluationDate();
58
59 Date exerciseDate = arguments_.exercise->lastDate();
60
61 Date paymentDate = arguments_.paymentDate;
62 if (paymentDate == Date())
63 paymentDate = std::max(arguments_.longAssetFlow->date(), arguments_.shortAssetFlow->date());
64
65 QL_REQUIRE(paymentDate >= exerciseDate, "Payment date needs to be on or after exercise date");
66
67 double df = discountCurve_->discount(paymentDate);
68
69 Time ttp = discountCurve_->timeFromReference(paymentDate);
70 Time tte = discountCurve_->timeFromReference(exerciseDate);
71
72 auto parameterFlow1 =
74
75 auto parameterFlow2 =
76 derivePricingParameterFromFlow(arguments_.shortAssetFlow, *volTSShortAsset_, arguments_.shortAssetFxIndex);
77
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;
86
87 double sigma = 0;
88 double stdDev = 0;
89 double Y = 0;
90 double Z = 0;
91 double sigmaY = 0;
92 double w1 = arguments_.longAssetFlow->gearing();
93 double w2 = arguments_.shortAssetFlow->gearing();
94 // Adjust strike for past fixings
95 double effectiveStrike = arguments_.effectiveStrike - w1 * accruals1 + w2 * accruals2;
96 Real correlation = QuantLib::Null<Real>();
97
98 if (exerciseDate <= today && paymentDate <= today) {
99 results_.value = 0;
100 } else if (exerciseDate <= today && paymentDate > today) {
101 // if observation time is before expiry, continue the process with zero vol and zero drift from pricing date to
102 // expiry
103 double omega = arguments_.type == Option::Call ? 1 : -1;
104
105 results_.value = df * arguments_.quantity * omega * std::max(w1 * F1 - w2 * F2 - effectiveStrike, 0.0);
106
107 } else if (effectiveStrike + F2 * w2 < 0) {
108 // Effective strike can be become negative if accrueds large enough
109 if (arguments_.type == Option::Call) {
110 results_.value = df * arguments_.quantity * std::max(w1 * F1 - w2 * F2 - effectiveStrike, 0.0);
111 } else {
112 results_.value = 0.0;
113 }
114
115 } else {
116 sigma1 = sigma1 * std::min(1.0, std::sqrt(obsTime1 / tte));
117 sigma2 = sigma2 * std::min(1.0, std::sqrt(obsTime2 / tte));
118 correlation = rho();
119 // KirkFormula
120 Y = (F2 * w2 + effectiveStrike);
121 Z = w1 * F1 / Y;
122 sigmaY = sigma2 * F2 * w2 / Y;
123
124 sigma = std::sqrt(std::pow(sigma1, 2.0) + std::pow(sigmaY, 2.0) - 2 * sigma1 * sigmaY * correlation);
125
126 stdDev = sigma * sqrt(tte);
127
128 results_.value = arguments_.quantity * Y * blackFormula(arguments_.type, 1, Z, stdDev, df);
129 }
130
131 // Calendar spread adjustment if observation period is before the exercise date
132 mp["F1"] = F1;
133 mp["accruals1"] = accruals1;
134 mp["sigma1"] = sigma1;
135 mp["obsTime1"] = obsTime1;
136 mp["F2"] = F2;
137 mp["accruals2"] = accruals2;
138 mp["sigma2"] = sigma2;
139 mp["obsTime2"] = obsTime2;
140 mp["tte"] = tte;
141 mp["ttp"] = ttp;
142 mp["df"] = df;
143 mp["sigma"] = sigma;
144 mp["stdDev"] = stdDev;
145 mp["Y"] = Y;
146 mp["Z"] = Z;
147 mp["sigma_Y"] = sigmaY;
148 mp["quantity"] = arguments_.quantity;
149 mp["npv"] = results_.value;
150 mp["exerciseDate"] = exerciseDate;
151 mp["paymentDate"] = paymentDate;
152 mp["w1"] = w1;
153 mp["w2"] = w2;
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;
163}
const Instrument::results * results_
Definition: cdsoption.cpp:81
PricingParameter derivePricingParameterFromFlow(const ext::shared_ptr< CommodityCashFlow > &flow, const ext::shared_ptr< BlackVolTermStructure > &vol, const ext::shared_ptr< FxIndex > &fxIndex) const
RandomVariable sqrt(RandomVariable x)
Swap::arguments * arguments_
+ Here is the call graph for this function:

◆ derivePricingParameterFromFlow()

CommoditySpreadOptionAnalyticalEngine::PricingParameter derivePricingParameterFromFlow ( const ext::shared_ptr< CommodityCashFlow > &  flow,
const ext::shared_ptr< BlackVolTermStructure > &  vol,
const ext::shared_ptr< FxIndex > &  fxIndex 
) const
private

Definition at line 166 of file commodityspreadoptionengine.cpp.

168 {
169 PricingParameter res;
170 if (auto cf = ext::dynamic_pointer_cast<CommodityIndexedCashFlow>(flow)) {
171 res.accruals = 0.0;
172 res.tn = vol->timeFromReference(cf->pricingDate());
173 double fxSpot = 1.0;
174 if (fxIndex) {
175 fxSpot = fxIndex->fixing(cf->pricingDate());
176 }
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)
181 : 0.0;
182 res.indexNames.push_back(cf->index()->name());
183 res.expiries.push_back(cf->index()->expiryDate());
184 res.fixings.push_back(atmUnderlyingCurrency);
185 res.pricingDates.push_back(cf->pricingDate());
186 } else if (auto avgCf = ext::dynamic_pointer_cast<CommodityIndexedAverageCashFlow>(flow)) {
188 avgCf, vol,
189 std::bind(&CommoditySpreadOptionAnalyticalEngine::intraAssetCorrelation, this, std::placeholders::_1,
190 std::placeholders::_2, vol));
191 res.tn = parameter.tn;
192 res.atm = parameter.forward;
193 res.accruals = parameter.accruals;
194 res.sigma = parameter.sigma;
195 res.indexNames = parameter.indexNames;
196 res.expiries = parameter.indexExpiries;
197 res.fixings = parameter.fixings;
198 res.pricingDates = parameter.pricingDates;
199 } else {
200 QL_FAIL("SpreadOptionEngine supports only CommodityIndexedCashFlow or CommodityIndexedAverageCashFlow");
201 }
202 return res;
203}
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.
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)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ intraAssetCorrelation()

Real intraAssetCorrelation ( const QuantLib::Date &  e1,
const QuantLib::Date &  e2,
const ext::shared_ptr< BlackVolTermStructure > &  vol 
) const
private

Return the correlation between two future expiry dates ed_1 and ed_2.

Definition at line 205 of file commodityspreadoptionengine.cpp.

206 {
207 if (beta_ == 0.0 || ed_1 == ed_2) {
208 return 1.0;
209 } else {
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));
213 }
214}
CompiledFormula exp(CompiledFormula x)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ rho()

Real rho ( ) const
private

Definition at line 216 of file commodityspreadoptionengine.cpp.

216 {
217 if (arguments_.longAssetFlow->index()->underlyingName() != arguments_.shortAssetFlow->index()->underlyingName()) {
218 return rho_->correlation(arguments_.exercise->lastDate());
219 } else {
220 return intraAssetCorrelation(arguments_.shortAssetLastPricingDate, arguments_.longAssetLastPricingDate,
222 }
223}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Member Data Documentation

◆ discountCurve_

QuantLib::Handle<QuantLib::YieldTermStructure> discountCurve_
protected

Definition at line 74 of file commodityspreadoptionengine.hpp.

◆ volTSLongAsset_

QuantLib::Handle<QuantLib::BlackVolTermStructure> volTSLongAsset_
protected

Definition at line 75 of file commodityspreadoptionengine.hpp.

◆ volTSShortAsset_

QuantLib::Handle<QuantLib::BlackVolTermStructure> volTSShortAsset_
protected

Definition at line 76 of file commodityspreadoptionengine.hpp.

◆ rho_

const QuantLib::Handle<QuantExt::CorrelationTermStructure> rho_
protected

Definition at line 77 of file commodityspreadoptionengine.hpp.

◆ beta_

QuantLib::Real beta_
protected

Definition at line 78 of file commodityspreadoptionengine.hpp.