00001
00002
00003
00004 #include "americanfudge.h"
00005 #include "american_option_approximation.h"
00006 #include "binomial.h"
00007 #include "Bisection.h"
00008
00013
00014 void binomial_option::init_calc_derived_attributes() const {
00015 _dt = _tau / _NumberIterations;
00016 _u = _alpha * _dt + log( 1 + sqrt( exp( _sigma * _sigma * _dt) - 1));
00017 _v = _alpha * _dt + log( 1 - sqrt( exp( _sigma * _sigma * _dt) - 1));
00018 _Scap = _u - _v;
00019 _Ccap = _v;
00020
00021
00022
00023 allocate_price_vectors();
00024
00025 solve_call_put();
00026 }
00027
00034 double binomial_option::S( int i, int j) const {
00035 return _S * exp( i * _Ccap + j * _Scap);
00036 }
00037
00044 void binomial_option::allocate_price_vectors() const {
00045 unsigned int sz = (_NumberIterations+1) * (_NumberIterations+1);
00046 if (_call_grid.size() != sz) {
00047 std::vector<double> foo( sz); foo.swap( _call_grid);
00048 }
00049 if (_put_grid.size() != sz) {
00050 std::vector<double> foo( sz); foo.swap( _put_grid);
00051 }
00052 if (_S_grid.size() != sz) {
00053 std::vector<double> foo( sz); foo.swap( _S_grid);
00054 }
00055 }
00056
00063 int binomial_option::get_grid_offset( int i, int j) const {
00064 return (i*(_NumberIterations+1)+j);
00065 }
00066
00087 int binomial_option::get_min_j( int i) const {
00088 return 0;
00089 }
00090
00111 int binomial_option::get_max_j( int i) const {
00112 return i;
00113 }
00114
00120 void binomial_option::solve_call_put() const {
00121 int i, j, k;
00122 int l, m;
00123 double intrinsic_value, tau, exp_alpha_r_tau, exp_r_tau;
00124
00125 _exp_r_t = exp( -_r * _dt);
00126
00127 i = _NumberIterations;
00128 for (j=get_min_j(i); j<=get_max_j(i); j++) {
00129 k = get_grid_offset( i, j);
00130 _S_grid[ k] = S( i, j);
00131 _call_grid[ k] = (_S_grid[k] > _K)? (_S_grid[k] - _K):0;
00132 _put_grid[ k] = (_S_grid[k] > _K)? 0:(_K - _S_grid[k]);
00133 }
00134
00135 int jmin, jmax;
00136 std::vector<double>::iterator ps, pslead, ps_end;
00137 double ds;
00138
00139 for (--i; i>=0; --i) {
00140 jmin = get_min_j(i);
00141 jmax = get_max_j(i);
00142
00143 ps = _S_grid.begin() + get_grid_offset( i, jmin);
00144 pslead = ps + 1;
00145 ps_end = _S_grid.begin() + get_grid_offset( i, jmax);
00146
00147 *ps = S(i, jmin);
00148 ds = exp( _Scap);
00149
00150 while (ps != ps_end) {
00151 *pslead ++ = ds * *ps ++;
00152 }
00153 }
00154
00155 for (i = _NumberIterations-1; i>=0; --i) {
00156 tau = (_NumberIterations - i) * _dt;
00157 exp_alpha_r_tau = exp( (_alpha - _r)*tau);
00158 exp_r_tau = exp( - _r * tau);
00159
00160 for (j=get_min_j(i); j<=get_max_j(i); j++) {
00161 k = get_grid_offset( i, j);
00162 l = get_grid_offset( i+1, j);
00163 m = get_grid_offset( i+1, j+1);
00164
00165
00166
00167 if (_calc_call) {
00168 _call_grid[ k] = .5*(_call_grid[ l]+_call_grid[ m]) * _exp_r_t;
00169 intrinsic_value = call_intrinsic_value( _S_grid[k], exp_alpha_r_tau, exp_r_tau);
00170 if (_call_grid[ k] < intrinsic_value) {
00171 _call_grid[ k] = intrinsic_value;
00172 }
00173 }
00174
00175 if (_calc_put) {
00176 _put_grid[ k] = .5*(_put_grid[ l]+_put_grid[ m]) * _exp_r_t;
00177 intrinsic_value = put_intrinsic_value( _S_grid[k], exp_alpha_r_tau, exp_r_tau);
00178 if (_put_grid[ k] < intrinsic_value) {
00179 _put_grid[ k] = intrinsic_value;
00180 }
00181 }
00182 }
00183 }
00184
00185 k = get_grid_offset( 0, 0);
00186 _C = _call_grid[k];
00187 _P = _put_grid[k];
00188 }
00189
00190 double binomial_option::C_sigma( double sigma) {
00191 _calc_call = true;
00192 _calc_put = false;
00193 if (sigma != _sigma) put_sigma( sigma);
00194 _calc_put = true;
00195 return _C;
00196 }
00197
00198 double binomial_option::P_sigma( double sigma) {
00199 _calc_call = false;
00200 _calc_put = true;
00201 if (sigma != _sigma) put_sigma( sigma);
00202 _calc_call = true;
00203 return _P;
00204 }
00205
00206 double binomial_option::call_intrinsic_value() const {
00207 double tmp = _S - _K;
00208 tmp = (tmp>0)? tmp : 0;
00209
00210 double tmp2 = _S*exp((_alpha - _r)*_tau) - _K * exp( -_r * _tau);
00211 return (tmp2 > tmp) ? tmp2 : tmp;
00212 }
00213
00214
00215 double binomial_option::put_intrinsic_value() const {
00216 double tmp = _K - _S;
00217 tmp = (tmp>0)? tmp : 0;
00218
00219 double tmp2 = _K * exp( -_r * _tau) - _S*exp((_alpha - _r)*_tau);
00220 return (tmp2 > tmp) ? tmp2 : tmp;
00221 }
00222
00223 #ifdef CHECK
00224 #undef CHECK
00225 #endif
00226 #ifdef linux
00227 #define CHECK(y,z,a) if (y) { _error_msg = __STRING(y)" at line "\
00228 __STRING(z)" in " a "::check_attributes"; \
00229 return (_erno = z);}
00230 #else
00231 #define CHECK(y,z,a) if (y) {_error_msg = #y" at line "\
00232 #z" in " #a"::check_attributes"; \
00233 return (_erno = z);}
00234 #endif
00235
00236 int binomial_option::strictly_check_attributes(
00237 double S,
00238 double K,
00239 double Tau,
00240 double Alpha,
00241 double R,
00242 double Sigma,
00243 int NumberIterations)
00244 {
00245 #define Funcname "binomial_option::check_attributes"
00246
00247 _error_msg = "";
00248 _erno = 0;
00249
00250 CHECK(S <= 0, __LINE__, Funcname);
00251 CHECK(K <= 0, __LINE__, Funcname);
00252 CHECK(Tau <= 0, __LINE__, Funcname);
00253 CHECK(R < 0, __LINE__, Funcname);
00254
00255
00256 CHECK(NumberIterations<=0, __LINE__, Funcname);
00257
00258 return 0;
00259 }
00260
00261 double binomial_option::call_implied_sigma( double call_price, bool show_iterations)
00262 {
00263 int erno;
00264
00265 erno = strictly_check_attributes(
00266 _S,
00267 _K,
00268 _tau,
00269 _alpha,
00270 _r,
00271 _sigma,
00272 _NumberIterations);
00273
00274 if (erno) {
00275 if (_sigma == 0) {
00276 _C = call_intrinsic_value();
00277 return NA;
00278 }
00279
00280 _C_implied_sigma = NA;
00281 throw std::domain_error( _error_msg);
00282 }
00283
00284 if (call_price < call_intrinsic_value()) {
00285 _C_implied_sigma = NA;
00286 throw std::domain_error( "call_price < call_intrinsic_value in binomial_option::call_implied_volatility");
00287 }
00288
00289 double sigma0, sigma1, price_sigma0, price_sigma1;
00290
00291 american_option_fudge aof( _S, _K, _tau, _alpha, _r, _sigma);
00292 american_option_approximation aop( _S, _K, _tau, _alpha, _r, _sigma);
00293
00294 sigma0 = aof.call_implied_sigma( call_price);
00295
00296 sigma1 = aop.call_implied_sigma( call_price);
00297
00298 if (sigma1 == sigma0) sigma1 *= 1.1;
00299
00300 option_pair *op = dynamic_cast< option_pair * > ( this);
00301
00302 stradle_value(
00303 sigma0,
00304 sigma1,
00305 price_sigma0,
00306 price_sigma1,
00307 call_price,
00308 *op,
00309 &option_pair::C_sigma,
00310 true,
00311 true,
00312 1,
00313 1e-5,
00314 1e5);
00315
00316 Bisection_Secant< option_pair, double >
00317 solution(
00318 sigma0,
00319 sigma1,
00320 price_sigma0,
00321 price_sigma1,
00322 call_price,
00323 .0001,
00324 .0001,
00325 100,
00326 *op,
00327 &option_pair::C_sigma);
00328
00329 solution.do_iteration( show_iterations);
00330
00331 if (!solution.get_converged()) {
00332 _C_implied_sigma = NA;
00333 throw std::domain_error( "sigma did not converge in option_pair::call_implied_sigma");
00334 }
00335
00336 return solution.get_x_mid();
00337 }
00338
00339 double binomial_option::put_implied_sigma( double put_price, bool show_iterations)
00340 {
00341 int erno;
00342
00343 erno = strictly_check_attributes(
00344 _S,
00345 _K,
00346 _tau,
00347 _alpha,
00348 _r,
00349 _sigma,
00350 _NumberIterations);
00351
00352 if (erno) {
00353 if (_sigma == 0) {
00354 _P = put_intrinsic_value();
00355 return NA;
00356 }
00357
00358 _P_implied_sigma = NA;
00359 throw std::domain_error( _error_msg);
00360 }
00361
00362 if (put_price < put_intrinsic_value()) {
00363 _P_implied_sigma = NA;
00364 throw std::domain_error( "put_price < put_intrinsic_value in binomial_option::put_implied_volatility");
00365 }
00366
00367 double sigma0, sigma1, price_sigma0, price_sigma1;
00368
00369 american_option_fudge aof( _S, _K, _tau, _alpha, _r, _sigma);
00370 american_option_approximation aop( _S, _K, _tau, _alpha, _r, _sigma);
00371
00372 sigma0 = aof.put_implied_sigma( put_price);
00373
00374 sigma1 = aop.put_implied_sigma( put_price);
00375
00376 if (sigma1 == sigma0) sigma1 *= 1.1;
00377
00378 option_pair *op = dynamic_cast< option_pair * > ( this);
00379
00380 stradle_value(
00381 sigma0,
00382 sigma1,
00383 price_sigma0,
00384 price_sigma1,
00385 put_price,
00386 *op,
00387 &option_pair::P_sigma,
00388 true,
00389 true,
00390 1,
00391 1e-5,
00392 1e5);
00393
00394 Bisection_Secant< option_pair, double >
00395 solution(
00396 sigma0,
00397 sigma1,
00398 price_sigma0,
00399 price_sigma1,
00400 put_price,
00401 .0001,
00402 .0001,
00403 100,
00404 *op,
00405 &option_pair::P_sigma);
00406
00407 solution.do_iteration( show_iterations);
00408
00409 if (!solution.get_converged()) {
00410 _P_implied_sigma = NA;
00411 throw std::domain_error( "sigma did not converge in option_pair::put_implied_sigma");
00412 }
00413
00414 return solution.get_x_mid();
00415 }