91 {
92
93 vector<vector<Real> > allStrikes =
callSurface_->strikes();
95
96
97 for (Size i = 0; i <
expiries().size(); i++) {
99
100 vector<Real>
strikes = allStrikes[i];
101 QL_REQUIRE(
strikes.size() > 0,
"No strikes for expiry " << expiry);
102
103
106 continue;
107 }
108
109
110
111
113 for (Size k = 0; k <
strikes.size(); k++) {
115 if (k == 0)
117 else
119 break;
120 }
121 }
122
123
126
127 Size maxIter = 100;
128 Size j = 0;
129 bool isForward = false;
130 while (!isForward && j < maxIter) {
131
132 if (
type_ == Exercise::American) {
133
134
135
136 vector<Real> amerStrikes(2);
137 auto it_lower = std::lower_bound(
strikes.begin(),
strikes.end(), forward);
139 it_lower = std::prev(it_lower);
140 amerStrikes[1] = *it_lower;
141 amerStrikes[0] = (it_lower ==
strikes.begin()) ? *it_lower : *std::prev(it_lower);
142
143
144
145
146
150 Time t = dc.yearFraction(asof, expiry);
151
152
154
155
156 QuantLib::ext::shared_ptr<SimpleQuote> volQuote = QuantLib::ext::make_shared<SimpleQuote>(0.1);
157 Handle<BlackVolTermStructure> volTs(
158 QuantLib::ext::make_shared<BlackConstantVol>(asof, cal, Handle<Quote>(volQuote), dc));
159 Handle<YieldTermStructure> divTs(QuantLib::ext::make_shared<FlatForward>(asof, q, dc));
160
161
162 QuantLib::ext::shared_ptr<GeneralizedBlackScholesProcess> gbsp =
164 QuantLib::ext::shared_ptr<PricingEngine> engine =
165 QuantLib::ext::make_shared<QuantExt::BaroneAdesiWhaleyApproximationEngine>(gbsp);
166
167 vector<vector<Volatility> > vols(2, vector<Volatility>(amerStrikes.size()));
168 vector<Option::Type> types;
169 types.push_back(Option::Call);
170 types.push_back(Option::Put);
171
172 for (Size l = 0; l < types.size(); l++) {
173 for (Size k = 0; k < amerStrikes.size(); k++) {
174
175 QuantLib::ext::shared_ptr<StrikedTypePayoff> payoff(new PlainVanillaPayoff(types[l], amerStrikes[k]));
176 QuantLib::ext::shared_ptr<Exercise> exercise = QuantLib::ext::make_shared<AmericanExercise>(expiry);
177 VanillaOption option(payoff, exercise);
178 option.setPricingEngine(engine);
179
180
181 Real targetPrice = types[l] == Option::Call ?
callSurface_->price(expiry, amerStrikes[k])
183
184
185 try {
186 PriceError f(option, *volQuote, targetPrice);
187 Brent solver;
188 solver.setMaxEvaluations(100);
189 solver.setLowerBound(0.0001);
190 vols[l][k] = solver.solve(f, 0.0001, 0.2, 0.01);
191 } catch (...) {
192 vols[l][k] = 0.0;
193 }
194 }
195 }
196
197 vector<Real> newStrikes;
198 vector<Date> dates;
199 vector<Real> callPremiums, putPremiums;
200
201 for (Size k = 0; k < amerStrikes.size(); k++) {
202 if (vols[0][k] != 0.0 && vols[1][k] != 0.0) {
203
204 Real call = blackFormula(Option::Call, amerStrikes[k], forward, vols[0][k] *
sqrt(t),
206 Real put = blackFormula(Option::Put, amerStrikes[k], forward, vols[1][k] *
sqrt(t),
208
209 if (call != 0.0 && put != 0.0) {
210 newStrikes.push_back(amerStrikes[k]);
211 dates.push_back(expiry);
212 callPremiums.push_back(call);
213 putPremiums.push_back(put);
214 }
215 }
216 }
217
218
219 if (newStrikes.size() > 0) {
220
221 callSurface = QuantLib::ext::make_shared<OptionPriceSurface>(asof, dates, newStrikes, callPremiums, dc);
222 putSurface = QuantLib::ext::make_shared<OptionPriceSurface>(asof, dates, newStrikes, putPremiums, dc);
223 }
224 }
225
226 Real newForward = 0.0;
227
228 if (forward <=
strikes.front()) {
230
231 isForward = newForward <=
strikes.front();
232 }
else if (forward >=
strikes.back()) {
234
235 isForward = newForward >=
strikes.back();
236 } else {
238
239
240 isForward = fabs((newForward - forward) / forward) < 0.001;
241 }
242 forward = newForward;
243 j++;
244 }
246 }
247}
QuantLib::Real forwardFromPutCallParity(QuantLib::Date d, QuantLib::Real call, const OptionPriceSurface &callSurface, const OptionPriceSurface &putSurface) const
const std::vector< QuantLib::Date > expiries() const
return the expiries
RandomVariable sqrt(RandomVariable x)
CompiledFormula log(CompiledFormula x)