binomial.cpp

Go to the documentation of this file.
00001 
00002 
00003 
00004 #include "americanfudge.h"
00005 #include "american_option_approximation.h"
00006 #include "binomial.h"
00007 #include "Bisection.h"
00008 
00013 //  description:  This function calculates the values of the American Put and the American Call. It calls several virtual function. The function are virtual, so that child classes can implement different versions of the algorithm. The final value of the American call is stored as C, and the final value of the American put is stored as P.
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   //cout << .5*(exp(_u) + exp(_v)) << " " << exp( _alpha * _dt) << endl;
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       //_S_grid[ k] = S( i, j);
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   //CHECK(Sigma<=0, __LINE__, Funcname);
00255   //CHECK(is_NA( Sigma), __LINE__, Funcname);
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 }

Generated on Fri Jan 7 12:36:18 2011 for public_options by  doxygen 1.5.1