/src/quantlib/ql/pricingengines/americanpayoffathit.cpp
Line | Count | Source |
1 | | /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | |
3 | | /* |
4 | | Copyright (C) 2004 Ferdinando Ametrano |
5 | | |
6 | | This file is part of QuantLib, a free-software/open-source library |
7 | | for financial quantitative analysts and developers - http://quantlib.org/ |
8 | | |
9 | | QuantLib is free software: you can redistribute it and/or modify it |
10 | | under the terms of the QuantLib license. You should have received a |
11 | | copy of the license along with this program; if not, please email |
12 | | <quantlib-dev@lists.sf.net>. The license is also available online at |
13 | | <https://www.quantlib.org/license.shtml>. |
14 | | |
15 | | This program is distributed in the hope that it will be useful, but WITHOUT |
16 | | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
17 | | FOR A PARTICULAR PURPOSE. See the license for more details. |
18 | | */ |
19 | | |
20 | | #include <ql/pricingengines/americanpayoffathit.hpp> |
21 | | #include <ql/math/distributions/normaldistribution.hpp> |
22 | | |
23 | | namespace QuantLib { |
24 | | |
25 | | AmericanPayoffAtHit::AmericanPayoffAtHit( |
26 | | Real spot, DiscountFactor discount, DiscountFactor dividendDiscount, |
27 | | Real variance, const ext::shared_ptr<StrikedTypePayoff>& payoff) |
28 | 0 | : spot_(spot), discount_(discount), dividendDiscount_(dividendDiscount), |
29 | 0 | variance_(variance) { |
30 | |
|
31 | 0 | QL_REQUIRE(spot_>0.0, |
32 | 0 | "positive spot value required"); |
33 | | |
34 | 0 | QL_REQUIRE(discount_>0.0, |
35 | 0 | "positive discount required"); |
36 | | |
37 | 0 | QL_REQUIRE(dividendDiscount_>0.0, |
38 | 0 | "positive dividend discount required"); |
39 | | |
40 | 0 | QL_REQUIRE(variance_>=0.0, |
41 | 0 | "negative variance not allowed"); |
42 | | |
43 | 0 | stdDev_ = std::sqrt(variance_); |
44 | |
|
45 | 0 | Option::Type type = payoff->optionType(); |
46 | 0 | strike_ = payoff->strike(); |
47 | | |
48 | |
|
49 | 0 | log_H_S_ = std::log(strike_/spot_); |
50 | |
|
51 | 0 | Real n_d1, n_d2; |
52 | 0 | if (variance_>=QL_EPSILON) { |
53 | 0 | if (discount_==0.0 && dividendDiscount_==0.0) { |
54 | 0 | mu_ = - 0.5; |
55 | 0 | lambda_ = 0.5; |
56 | 0 | } else if (discount_==0.0) { |
57 | 0 | QL_FAIL("null discount not handled yet"); |
58 | 0 | } else { |
59 | 0 | mu_ = std::log(dividendDiscount_/discount_)/variance_ - 0.5; |
60 | 0 | lambda_ = std::sqrt(mu_*mu_-2.0*std::log(discount_)/variance_); |
61 | 0 | } |
62 | 0 | D1_ = log_H_S_/stdDev_ + lambda_*stdDev_; |
63 | 0 | D2_ = D1_ - 2.0*lambda_*stdDev_; |
64 | 0 | CumulativeNormalDistribution f; |
65 | 0 | cum_d1_ = f(D1_); |
66 | 0 | cum_d2_ = f(D2_); |
67 | 0 | n_d1 = f.derivative(D1_); |
68 | 0 | n_d2 = f.derivative(D2_); |
69 | 0 | } else { |
70 | | // not tested yet |
71 | 0 | mu_ = std::log(dividendDiscount_/discount_)/variance_ - 0.5; |
72 | 0 | lambda_ = std::sqrt(mu_*mu_-2.0*std::log(discount_)/variance_); |
73 | 0 | if (log_H_S_>0) { |
74 | 0 | cum_d1_= 1.0; |
75 | 0 | cum_d2_= 1.0; |
76 | 0 | } else { |
77 | 0 | cum_d1_= 0.0; |
78 | 0 | cum_d2_= 0.0; |
79 | 0 | } |
80 | 0 | n_d1 = 0.0; |
81 | 0 | n_d2 = 0.0; |
82 | 0 | } |
83 | | |
84 | | |
85 | 0 | switch (type) { |
86 | | // up-and-in cash-(at-hit)-or-nothing option |
87 | | // a.k.a. american call with cash-or-nothing payoff |
88 | 0 | case Option::Call: |
89 | 0 | if (strike_>spot_) { |
90 | 0 | alpha_ = 1.0-cum_d1_;// N(-d1) |
91 | 0 | DalphaDd1_ = - n_d1;// -n( d1) |
92 | 0 | beta_ = 1.0-cum_d2_;// N(-d2) |
93 | 0 | DbetaDd2_ = - n_d2;// -n( d2) |
94 | 0 | } else { |
95 | 0 | alpha_ = 0.5; |
96 | 0 | DalphaDd1_ = 0.0; |
97 | 0 | beta_ = 0.5; |
98 | 0 | DbetaDd2_ = 0.0; |
99 | 0 | } |
100 | 0 | break; |
101 | | // down-and-in cash-(at-hit)-or-nothing option |
102 | | // a.k.a. american put with cash-or-nothing payoff |
103 | 0 | case Option::Put: |
104 | 0 | if (strike_<spot_) { |
105 | 0 | alpha_ = cum_d1_;// N(d1) |
106 | 0 | DalphaDd1_ = n_d1;// n(d1) |
107 | 0 | beta_ = cum_d2_;// N(d2) |
108 | 0 | DbetaDd2_ = n_d2;// n(d2) |
109 | 0 | } else { |
110 | 0 | alpha_ = 0.5; |
111 | 0 | DalphaDd1_ = 0.0; |
112 | 0 | beta_ = 0.5; |
113 | 0 | DbetaDd2_ = 0.0; |
114 | 0 | } |
115 | 0 | break; |
116 | 0 | default: |
117 | 0 | QL_FAIL("invalid option type"); |
118 | 0 | } |
119 | | |
120 | | |
121 | 0 | muPlusLambda_ = mu_ + lambda_; |
122 | 0 | muMinusLambda_ = mu_ - lambda_; |
123 | 0 | inTheMoney_ = (type==Option::Call && strike_<spot_) || |
124 | 0 | (type==Option::Put && strike_>spot_); |
125 | |
|
126 | 0 | if (inTheMoney_) { |
127 | 0 | forward_ = 1.0; |
128 | 0 | X_ = 1.0; |
129 | 0 | DXDstrike_ = 0.0; |
130 | 0 | } else { |
131 | 0 | forward_ = std::pow(strike_/spot_, muPlusLambda_); |
132 | 0 | X_ = std::pow(strike_/spot_, muMinusLambda_); |
133 | | // DXDstrike_ = ......; |
134 | 0 | } |
135 | | |
136 | | |
137 | | // Binary Cash-Or-Nothing payoff? |
138 | 0 | ext::shared_ptr<CashOrNothingPayoff> coo = |
139 | 0 | ext::dynamic_pointer_cast<CashOrNothingPayoff>(payoff); |
140 | 0 | if (coo != nullptr) { |
141 | 0 | K_ = coo->cashPayoff(); |
142 | 0 | DKDstrike_ = 0.0; |
143 | 0 | } |
144 | | |
145 | | // Binary Asset-Or-Nothing payoff? |
146 | 0 | ext::shared_ptr<AssetOrNothingPayoff> aoo = |
147 | 0 | ext::dynamic_pointer_cast<AssetOrNothingPayoff>(payoff); |
148 | 0 | if (aoo != nullptr) { |
149 | 0 | if (inTheMoney_) { |
150 | 0 | K_ = spot_; |
151 | 0 | DKDstrike_ = 0.0; |
152 | 0 | } else { |
153 | 0 | K_ = aoo->strike(); |
154 | 0 | DKDstrike_ = 1.0; |
155 | 0 | } |
156 | 0 | } |
157 | 0 | } |
158 | | |
159 | | |
160 | 0 | Real AmericanPayoffAtHit::delta() const { |
161 | 0 | Real tempDelta = - spot_ * stdDev_; |
162 | 0 | Real DalphaDs = DalphaDd1_/tempDelta; |
163 | 0 | Real DbetaDs = DbetaDd2_/tempDelta; |
164 | |
|
165 | 0 | Real DforwardDs, DXDs; |
166 | 0 | if (inTheMoney_) { |
167 | 0 | DforwardDs = 0.0; |
168 | 0 | DXDs = 0.0; |
169 | 0 | } else { |
170 | 0 | DforwardDs = -muPlusLambda_ * forward_ / spot_; |
171 | 0 | DXDs = -muMinusLambda_ * X_ / spot_; |
172 | 0 | } |
173 | |
|
174 | 0 | return K_ * ( |
175 | 0 | DalphaDs * forward_ + alpha_ * DforwardDs |
176 | 0 | + DbetaDs * X_ + beta_ * DXDs |
177 | 0 | ); |
178 | 0 | } |
179 | | |
180 | | |
181 | 0 | Real AmericanPayoffAtHit::gamma() const { |
182 | 0 | Real tempDelta = - spot_ * stdDev_; |
183 | 0 | Real DalphaDs = DalphaDd1_/tempDelta; |
184 | 0 | Real DbetaDs = DbetaDd2_/tempDelta; |
185 | 0 | Real D2alphaDs2 = -DalphaDs/spot_*(1-D1_/stdDev_); |
186 | 0 | Real D2betaDs2 = -DbetaDs /spot_*(1-D2_/stdDev_); |
187 | |
|
188 | 0 | Real DforwardDs, DXDs, D2forwardDs2, D2XDs2; |
189 | 0 | if (inTheMoney_) { |
190 | 0 | DforwardDs = 0.0; |
191 | 0 | DXDs = 0.0; |
192 | 0 | D2forwardDs2 = 0.0; |
193 | 0 | D2XDs2 = 0.0; |
194 | 0 | } else { |
195 | 0 | DforwardDs = -muPlusLambda_ * forward_ / spot_; |
196 | 0 | DXDs = -muMinusLambda_ * X_ / spot_; |
197 | 0 | D2forwardDs2 = muPlusLambda_ * forward_ / (spot_*spot_)*(1+muPlusLambda_); |
198 | 0 | D2XDs2 = muMinusLambda_ * X_ / (spot_*spot_)*(1+muMinusLambda_); |
199 | 0 | } |
200 | |
|
201 | 0 | return K_ * ( |
202 | 0 | D2alphaDs2 * forward_ + DalphaDs * DforwardDs |
203 | 0 | + DalphaDs * DforwardDs + alpha_ * D2forwardDs2 |
204 | 0 | + D2betaDs2 * X_ + DbetaDs * DXDs |
205 | 0 | + DbetaDs * DXDs + beta_ * D2XDs2 |
206 | 0 | ); |
207 | |
|
208 | 0 | } |
209 | | |
210 | | |
211 | 0 | Real AmericanPayoffAtHit::rho(Time maturity) const { |
212 | 0 | QL_REQUIRE(maturity>=0.0, |
213 | 0 | "negative maturity not allowed"); |
214 | | |
215 | | // actually D.Dr / T |
216 | 0 | Real DalphaDr = -DalphaDd1_/(lambda_*stdDev_) * (1.0 + mu_); |
217 | 0 | Real DbetaDr = DbetaDd2_ /(lambda_*stdDev_) * (1.0 + mu_); |
218 | 0 | Real DforwardDr, DXDr; |
219 | 0 | if (inTheMoney_) { |
220 | 0 | DforwardDr = 0.0; |
221 | 0 | DXDr = 0.0; |
222 | 0 | } else { |
223 | 0 | DforwardDr = forward_ * (1.0+(1.0+mu_)/lambda_) * log_H_S_ / variance_; |
224 | 0 | DXDr = X_ * (1.0-(1.0+mu_)/lambda_) * log_H_S_ / variance_; |
225 | 0 | } |
226 | |
|
227 | 0 | return maturity * K_ * ( |
228 | 0 | DalphaDr * forward_ |
229 | 0 | + alpha_ * DforwardDr |
230 | 0 | + DbetaDr * X_ |
231 | 0 | + beta_ * DXDr |
232 | 0 | ); |
233 | 0 | } |
234 | | |
235 | | } |
236 | | |