Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
Classes | Functions
QuantExt::CommodityAveragePriceOptionMomementMatching Namespace Reference

Classes

struct  MomentMatchingResults
 

Functions

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)
 

Function Documentation

◆ matchFirstTwoMomentsTurnbullWakeman()

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 
)

Definition at line 44 of file commodityapoengine.cpp.

48 {
49 Date today = Settings::instance().evaluationDate();
51
52 res.tn = 0.0;
53 res.accruals = 0.0;
54 double EA = 0;
55 std::vector<Date> futureExpiries;
56 std::map<Date, Real> futureVols;
57 std::vector<double> spotVariances;
58 size_t n = flow->indices().size();
59 double atmUnderlyingCcy = 0;
60
61 for (const auto& [pricingDate, index] : flow->indices()) {
62 Date fixingDate = index->fixingCalendar().adjust(pricingDate, Preceding);
63 Real fxRate = (flow->fxIndex()) ? flow->fxIndex()->fixing(fixingDate) : 1.0;
64 res.indexNames.push_back(index->name());
65 res.pricingDates.push_back(fixingDate);
66 res.indexExpiries.push_back(index->expiryDate());
67 res.fixings.push_back(index->fixing(fixingDate) * fxRate);
68 if (pricingDate <= today) {
69 res.accruals += res.fixings.back();
70 } else {
71 atmUnderlyingCcy = index->fixing(fixingDate);
72 res.forwards.push_back(res.fixings.back());
73 res.times.push_back(vol->timeFromReference(pricingDate));
74 // use ATM vol if no strike is given
75 double K = strike == Null<Real>() ? atmUnderlyingCcy : strike;
76 if (flow->useFuturePrice()) {
77 Date expiry = index->expiryDate();
78 futureExpiries.push_back(expiry);
79 if (futureVols.count(expiry) == 0) {
80 futureVols[expiry] = vol->blackVol(expiry, K);
81 }
82 } else {
83 spotVariances.push_back(
84 vol->blackVariance(res.times.back(), K));
85 res.spotVols.push_back(std::sqrt(spotVariances.back() / res.times.back()));
86 }
87 EA += res.forwards.back();
88 }
89 }
90 res.accruals /= static_cast<double>(n);
91 EA /= static_cast<double>(n);
92
93 res.forward = EA;
94
95 double EA2 = 0.0;
96
97 if (flow->useFuturePrice()) {
98 // References future prices
99 for (Size i = 0; i < res.forwards.size(); ++i) {
100 Date e_i = futureExpiries[i];
101 Volatility v_i = futureVols.at(e_i);
102 res.futureVols.push_back(v_i);
103 EA2 += res.forwards[i] * res.forwards[i] * exp(v_i * v_i * res.times[i]);
104 for (Size j = 0; j < i; ++j) {
105 Date e_j = futureExpiries[j];
106 Volatility v_j = futureVols.at(e_j);
107 EA2 += 2 * res.forwards[i] * res.forwards[j] * exp(rho(e_i, e_j) * v_i * v_j * res.times[j]);
108 }
109 }
110 } else {
111 // References spot prices
112 for (Size i = 0; i < res.forwards.size(); ++i) {
113 EA2 += res.forwards[i] * res.forwards[i] * exp(spotVariances[i]);
114 for (Size j = 0; j < i; ++j) {
115 EA2 += 2 * res.forwards[i] * res.forwards[j] * exp(spotVariances[j]);
116 }
117 }
118 }
119 EA2 /= std::pow(static_cast<double>(n), 2.0);
120 res.EA2 = EA2;
121
122 QL_REQUIRE(!std::isinf(EA2),
123 "moment matching fails (EA2 = inf) - this is possibly due to too high input volatilities.");
124
125 // Calculate value
126 if (!res.times.empty()) {
127 res.tn = res.times.back();
128 double s = EA2 / (EA * EA);
129 // if future vol = 0 for all dates, then EA2 = EA*EA, but
130 // due to numerical precision EA2 can be actually less than EA*EA
131 if (s < 1.0 || QuantLib::close_enough(s, 1)) {
132 res.sigma = 0.0;
133 } else {
134 res.sigma = std::sqrt(std::log(s) / res.tn);
135 }
136 } else {
137 res.tn = 0;
138 res.sigma = 0;
139 }
140 return res;
141}
CompiledFormula exp(CompiledFormula x)
+ Here is the caller graph for this function: