File Coverage

blib/lib/Math/Business/BlackScholes.pm
Criterion Covered Total %
statement 146 151 96.6
branch 87 104 83.6
condition 12 15 80.0
subroutine 16 16 100.0
pod 0 6 0.0
total 261 292 89.3


line stmt bran cond sub pod time code
1             # Copyright (c) 2002-2008 Anders Johnson. All rights reserved. This program is
2             # free software; you can redistribute it and/or modify it under the same terms
3             # as Perl itself. The author categorically disclaims any liability for this
4             # software.
5              
6             =head1 NAME
7              
8             Math::Business::BlackScholes - Black-Scholes option price model functions
9              
10             =head1 SYNOPSIS
11              
12             use Math::Business::BlackScholes
13             qw/call_price call_put_prices implied_volatility_call/;
14              
15             my $volatility=implied_volatility_call(
16             $current_market_price, $option_price_in, $strike_price_in,
17             $remaining_term_in, $interest_rate, $fractional_yield
18             );
19              
20             my $call=call_price(
21             $current_market_price, $volatility, $strike_price,
22             $remaining_term, $interest_rate, $fractional_yield
23             );
24              
25             $volatility=Math::Business::BlackScholes::historical_volatility(
26             \@closing_prices, 251
27             );
28              
29             my $put=Math::Business::BlackScholes::put_price(
30             $current_market_price, $volatility, $strike_price,
31             $remaining_term, $interest_rate
32             ); # $fractional_yield defaults to 0.0
33              
34             my ($c, $p)=call_put_prices(
35             $current_market_price, $volatility, $strike_price,
36             $remaining_term, $interest_rate, $fractional_yield
37             );
38              
39             my $call_discrete_div=call_price(
40             $current_market_price, $volatility, $strike_price,
41             $remaining_term, $interest_rate,
42             { 0.3 => 0.35, 0.55 => 0.35 }
43             );
44              
45             =head1 DESCRIPTION
46              
47             Estimates the fair market price of a European stock option
48             according to the Black-Scholes model.
49              
50             call_price() returns the price of a call option.
51             put_price() returns the value of a put option.
52             call_put_prices() returns a 2-element array whose first element is the price
53             of a call option, and whose second element is the price of the put option
54             with the same parameters; it is expected to be computationally more efficient
55             than calling call_price() and put_price() sequentially with the same arguments.
56             Each of these routines accepts the same set of parameters:
57              
58             C<$current_market_price> is the price for which the underlying security is
59             currently trading.
60             C<$volatility> is the standard deviation of the probability distribution of
61             the natural logarithm of the stock price one year in the future.
62             C<$strike_price> is the strike price of the option.
63             C<$remaining_term> is the time remaining until the option expires, in years.
64             C<$interest_rate> is the risk-free interest rate (per year) as a fraction.
65             C<$fractional_yield> is the fraction of the stock price that the stock
66             yields in dividends per year; it is assumed to be zero if unspecified.
67              
68             =head2 Discrete Dividends
69              
70             If C<$fractional_yield> is specified as a number, then the actual timing of
71             the ex-dividend dates relative to the current time and the option expiration
72             time can affect the option price by as much as the value of a single dividend.
73              
74             C<$fractional_yield> may instead be specified as a hashref, each key of which
75             is the remaining amount of time before the dividend is paid, in years,
76             and each value of which is the dividend amount.
77             This produces more accurate results when the dividends that will be assigned
78             during the term of the option are reliably predictable.
79             The ex-dividend date of each dividend so represented is assumed to occur
80             within the I term of the option, even if the dividend is paid
81             after the term expires.
82              
83             =head2 Determining Parameter Values
84              
85             C<$volatility> and C<$fractional_yield> are traditionally estimated based on
86             historical data.
87             C<$interest_rate> is traditionally equal to the current T-bill rate.
88             The model assumes that these parameters are stable over the term of the
89             option.
90              
91             C<$volatility> (a.k.a. I) is sometimes expressed as a percentage,
92             which is misleading because it's not a ratio.
93             If you have it as a percentage, then you'll need to divide it by 100 before
94             passing it to this module.
95             Ditto for C<$interest_rate> and C<$fractional_yield>.
96              
97             Two ways to estimate C<$volatility> are provided.
98             historical_volatility() takes an arrayref of at least 10 (preferably 100 or
99             more) consecutive daily closing prices of the underlying security, in either
100             chronological or reverse chronological order.
101             It then multiplies the variance of the log of day-to-day returns by the number
102             of trading days per year specified by the second argument (or 250 by default).
103             The square-root of this yearly variance is returned.
104              
105             implied_volatility_call() computes the implied volatility based on the known
106             trading price of a "reference" call option on the same underlying security with
107             a different strike price and/or term, using the Newton-Raphson method, or the
108             bisection method if it fails to converge otherwise.
109             It's invoked like call_price(), except that the second argument is taken as
110             the price of the call option, and the volatility is returned.
111             You can override the default option price tolerance of 1e-4 by passing an
112             additional argument beyond C<$fractional_yield>.
113             If called in an array context, the second element of the return value is an
114             estimate of the error magnitude, and the third element is the number of
115             iterations required to obtain the result.
116             The error magnitude may be quite large unless you use a
117             reference option whose price exceeds its intrinsic value by an amount larger
118             than or comparable to the absolute difference of the market price and the
119             strike price, and it is undefined if the price of the reference option is
120             less than what would be calculated with zero volatility.
121             If the price of the reference option is greater than what would be calculated
122             with infinite volatility, then both the result and the error estimate are
123             undefined.
124             An exception is thrown if it fails to converge within
125             C<$Math::Business::BlackScholes::max_iter> (100 by default) iterations.
126             An analogous implied_volatility_put() is also available.
127              
128             =head2 American Options
129              
130             Whereas a European stock option may be exercised only when it expires,
131             an American option may be exercised any time prior to its expiration.
132             The price of an American option can be approximated as the maximum price
133             of similar European options over all possible remaining terms not greater
134             than the remaining term of the American option.
135             This maximum usually occurs at the end of the remaining term, or just before
136             or just after the final ex-dividend date within the remaining term.
137              
138             =head2 Negative Market Value
139              
140             An underlying security with a negative market value is assumed to be a short.
141             Buying a short is equivalent to selling the security, so a call option on
142             a short is equivalent to a put option.
143             This is somewhat confusing, and arguably a warning ought to be generated if
144             it gets invoked.
145              
146             =head1 DIAGNOSTICS
147              
148             Attempting to evaluate an option with a negative term will result in a croak(),
149             because that's meaningless.
150             Passing suspicious arguments (I a negative interest rate) will result
151             in descriptive warning messages.
152             To disable such messages, try this:
153              
154             {
155             local($SIG{__WARN__})=sub{};
156             $value=call_price( ... );
157             }
158              
159             =head1 CAVEATS
160              
161             =over 2
162              
163             =item *
164              
165             This module requires C.
166              
167             =item *
168              
169             The fractional computational error of call_price() and put_price() is
170             usually negligible.
171             However, while the computational error of second result of call_put_prices()
172             is typically small in comparison to the current market price, it might be
173             significant in comparison to the result itself.
174             That's probably unimportant for most purposes.
175              
176             =item *
177              
178             historical_volatility() tends to produce misleading results because the
179             behavior of the underlying security is most likely not truly log-normal.
180             In particular, the price varies predictably after a dividend is distributed,
181             and the daily variance is expected to be greater after financial announcements
182             are made.
183             Also, a large number of data points are required to obtain statistically
184             meaningful results, but having a large number of data points implies that the
185             results are outdated.
186              
187             =item *
188              
189             The author categorically disclaims any liability for this module.
190              
191             =back
192              
193             =head1 BUGS
194              
195             =over 2
196              
197             =item *
198              
199             The length of the namespace component "BlackScholes" is said to cause
200             unspecified portability problems for DOS and other 8.3 filesystems,
201             but the consensus of the Perl community was that it is more important
202             to have a descriptive name.
203              
204             =item *
205              
206             You can't passed a blessed reference with the C<0+> (numeric conversion)
207             operator overloaded (see L) as a numerical C<$fractional_yield>.
208             Instead, convert it into a numeric scalar before calling these functions.
209              
210             =back
211              
212             =head1 SEE ALSO
213              
214             L
215              
216             =head1 AUTHOR
217              
218             Anders Johnson >
219              
220             =head1 ACKNOWLEDGMENTS
221              
222             Thanks to Richard Solberg for helping to debug the implied volatility
223             functions.
224              
225             =cut
226              
227             package Math::Business::BlackScholes;
228              
229 3     3   40983 use strict;
  3         7  
  3         171  
230              
231             BEGIN {
232 3     3   16 use Exporter;
  3         5  
  3         131  
233 3     3   17 use vars qw/$VERSION @ISA @EXPORT_OK/;
  3         25  
  3         468  
234 3     3   8 $VERSION = 1.01;
235 3         58 @ISA = qw/Exporter/;
236 3         77 @EXPORT_OK = (
237             qw/call_price put_price call_put_prices/,
238             qw/historical_volatility/,
239             qw/implied_volatility_call implied_volatility_put/
240             );
241             }
242              
243 3     3   3126 use Math::CDF qw/pnorm/;
  3         22804  
  3         1111  
244 3     3   38 use Carp;
  3         8  
  3         7056  
245              
246             # Don't call this directly -- it might change without notice
247             sub _precompute1 {
248             my (
249 299     299   619 $st, $lsx, $put, $adj_market, $sigma, $strike, $term,
250             $interest, $adj_yield
251             )=@_;
252              
253 299         563 my $seyt=$adj_market * exp(-$adj_yield * $term);
254 299         444 my $xert=$strike * exp(-$interest * $term);
255 299         278 my $d1;
256             my $nd1;
257 0         0 my $nd2;
258 299 100 100     2127 if($sigma==0.0 || $term==0.0 || $adj_market==0.0 || $strike<=0.0) {
      66        
      66        
259 61 100       105 if($seyt > $xert) {
260 38 100       89 ($nd1, $nd2) = $put ? (0.0, 0.0) : (1.0, 1.0);
261             }
262             else {
263 23 100       59 ($nd1, $nd2) = $put ? (-1.0, -1.0) : (0.0, 0.0);
264             }
265             }
266             else {
267 238         274 my $ssrt=$sigma * $st;
268 238         440 $d1=(
269             $lsx + ($interest - $adj_yield + 0.5*$sigma*$sigma)*$term
270             ) / $ssrt;
271 238         245 my $d2=$d1 - $ssrt;
272 238 100       1352 ($nd1, $nd2) = $put ?
273             (-pnorm(-$d1), -pnorm(-$d2)) : (pnorm($d1), pnorm($d2));
274             }
275 299         1321 return ($seyt*$nd1 - $xert*$nd2, $seyt, $xert, $d1);
276             }
277              
278             # Don't call this directly -- it might change without notice
279             sub _precompute {
280 141 50   141   279 @_<6 && carp("Too few arguments");
281 141         237 my ($put, $market, $sigma, $strike, $term, $interest, $yield)=@_;
282              
283 141 50       277 $market>=0.0 || croak("Negative market price");
284 141 100       277 if($sigma<0.0) {
285 5         945 carp("Negative volatility (using absolute value instead)");
286 5         23 $sigma=-$sigma;
287             }
288 141 100       981 $strike>=0.0 || carp("Negative strike price");
289 141 50       283 $term>=0.0 || croak("Negative remaining term");
290 141 100       1095 $interest>=0.0 || carp("Negative interest rate");
291 141         189 my ($adj_market, $adj_yield) = ($market, $yield);
292 141 100       342 if(ref $yield) {
    100          
293 15         14 my $warned;
294 15         37 for my $when (keys %$yield) {
295 23 100       60 unless($when>=0) {
296 7 50       17 unless($warned++) {
297 7         1127 carp("Negative dividend time");
298             }
299             }
300 23         339 $adj_market -= $yield->{$when}*exp(-$interest * $when);
301             }
302 15         25 $adj_yield=0.0;
303             }
304             elsif(!defined $yield) {
305 19         24 $adj_yield=0.0;
306             }
307 141 100       1242 $adj_yield>=0.0 || carp("Negative yield");
308 141 100       1003 @_>7 && carp("Ignoring additional arguments");
309              
310 141         229 my $st=sqrt($term);
311 141         168 my $sx=$adj_market / $strike;
312 141 100       366 my $lsx=log($sx) if $sx>0;
313             return (
314 141         276 _precompute1(
315             $st, $lsx, $put, $adj_market, $sigma, $strike, $term,
316             $interest, $adj_yield
317             ), $st, $lsx, $adj_market, $adj_yield
318             );
319             }
320              
321             sub call_price {
322 44 100   44 0 6531 if($_[0]<0.0) {
323 2         8 return put_price(-$_[0], $_[1], -$_[2], @_[3..$#_]);
324             }
325 42         114 my ($price) = _precompute(0, @_);
326 42         107 return $price;
327             }
328              
329             sub put_price {
330 43 100   43 0 1057 if($_[0]<0.0) {
331 2         9 return call_price(-$_[0], $_[1], -$_[2], @_[3..$#_]);
332             }
333 41         77 my ($price) = _precompute(1, @_);
334 41         103 return $price;
335             }
336              
337             sub call_put_prices {
338 22 100   22 0 90 if($_[0]<0.0) {
339 1         8 my ($put, $call)=call_put_prices(
340             -$_[0], $_[1], -$_[2], @_[3..$#_]
341             );
342 1         3 return ($call, $put);
343             }
344 21         37 my ($call, $seyt, $xert) = _precompute(0, @_);
345 21         62 return ($call, $call - $seyt + $xert);
346             }
347              
348             sub historical_volatility {
349 3     3 0 139 my ($close, $days)=@_;
350 3 100       12 $days=250 unless defined $days;
351 3         13 my @close=@$close; # Don't clobber the argument
352 3 50       9 if(@close<10) {
353 0         0 croak "Not enough data points"
354             }
355 3         7 my ($tot, $sqtot, $n)=(0.0, 0.0, 0);
356 3         12 my $last=log(shift(@close));
357 3         18 while(@close) {
358 49         79 my $next=log(shift(@close));
359 49         57 my $ret=$next-$last;
360 49         50 $tot+=$ret;
361 49         59 $sqtot+=$ret*$ret;
362 49         46 $n++;
363 49         101 $last=$next;
364             }
365 3         20 return sqrt($days * ($sqtot - $tot*$tot/$n)/($n-1));
366             }
367              
368             sub implied_volatility_call {
369 20 100   20 0 752 if($_[0]<0.0) {
370 1         4 return implied_volatility_put(
371             -$_[0], $_[1], -$_[2], @_[3..$#_]
372             );
373             }
374 19         57 return _implied_volatility(0, @_);
375             }
376              
377             sub implied_volatility_put {
378 19 100   19 0 768 if($_[0]<0.0) {
379 1         3 return implied_volatility_call(
380             -$_[0], $_[1], -$_[2], @_[3..$#_]
381             );
382             }
383 18         53 return _implied_volatility(1, @_);
384             }
385              
386 3     3   40 use vars qw/$max_iter/;
  3         8  
  3         3851  
387             $max_iter=100;
388             my $pipi; # becomes 1/sqrt(2*PI) when needed
389             # Don't call this directly -- it might change without notice
390             sub _implied_volatility {
391 37     37   49 my $put=shift;
392 37         62 my ($market, $option_price, $strike, $term, $interest, $yield, $tol)=@_;
393 37 100       77 $yield=0 unless defined $yield;
394 37 50       92 if(@_>7) {
395 0         0 carp("Ignoring additional arguments");
396 0         0 pop(@_) while @_>7;
397             }
398 37 100       69 pop(@_) if defined $tol;
399 37 100       91 $tol=1e-4 unless defined $tol;
400 37         41 $tol=abs($tol);
401 37 50       79 $market>0.0 ||
402             croak("Positive market price required to determine volatility");
403 37 50       65 $strike>0.0 ||
404             croak("Positive strike price required to determine volatility");
405 37 50       78 $term>0.0 || croak("Positive term required to determine volatility");
406 37 50       116 $option_price>0.0 || croak("Option price must be positive");
407 37         40 my $sigma_low=0.0;
408 37         106 my ($price_low, $seyt, $xert, $d1, $st, $lsx, $adj_market, $adj_yield) =
409             _precompute(
410             $put, $market, 0.0, @_[2..$#_]
411             );
412 37         124 my @precomp_args = @_[2..$#_];
413 37         48 $precomp_args[3] = $adj_yield;
414 37 0       70 return wantarray ? (0.0, undef, 0) : 0.0 if $price_low > $option_price;
    50          
415 37 100       129 return wantarray ? (undef, undef, 0) : undef
    100          
    100          
416             if $option_price > ($put ? $xert : $seyt);
417 35         80 my $sigma_high=($option_price)/(0.398*$market*$st);
418 35         34 my $price_high;
419 35         45 my $n=0;
420 35         70 while($n<$max_iter) {
421 66         122 ($price_high, $seyt, $xert, $d1) = _precompute1(
422             $st, $lsx, $put, $adj_market, $sigma_high, @precomp_args
423             );
424 66 100       186 last if $price_high > $option_price-$tol;
425 31         36 ($sigma_low, $price_low) = ($sigma_high, $price_high);
426 31         34 $sigma_high += $sigma_high;
427 31         63 $n++;
428             }
429 35 100       72 $pipi=1/sqrt(4*atan2(1,0)) unless defined $pipi;
430 35         43 my ($sigma, $price)=($sigma_high, $price_high);
431 35         42 while(1) {
432 111         133 my $diff=$option_price - $price;
433 111         150 my $done=abs($diff) < $tol;
434 111 100 100     369 return $sigma if $done && !wantarray;
435 94 100       149 if($diff>0.0) {
436 38         52 ($sigma_low, $price_low)=($sigma, $price);
437             }
438             else {
439 56         73 ($sigma_high, $price_high)=($sigma, $price);
440             }
441 94 100       207 my $npd1=defined($d1) ? $pipi * exp(-0.5*$d1*$d1) : 0.0;
442 94         120 my $vega=$seyt * $st * $npd1;
443 94 50       240 return ($sigma, $vega==0.0 ? undef : $tol/$vega, $n) if $done;
    100          
444 77 100       154 last if $vega==0.0;
445 76         84 $sigma+=$diff/$vega;
446 76 100       202 $sigma=$sigma_low if $sigma<$sigma_low;
447 76 50 66     219 last if $diff>0.0 && $sigma>0.5*($sigma_low+$sigma_high);
448 76         78 $n++;
449 76 50       141 last if $n>=$max_iter;
450 76         148 ($price, $seyt, $xert, $d1) = _precompute1(
451             $st, $lsx, $put, $adj_market, $sigma, @precomp_args
452             );
453             }
454              
455             # If Newton-Raphson fails, try the bisection method
456 1         6 while($n<$max_iter) {
457 16         25 $sigma=0.5 * ($sigma_low + $sigma_high);
458 16         30 ($price) = _precompute1(
459             $st, $lsx, $put, $adj_market, $sigma, @precomp_args
460             );
461 16 100       47 if(abs($option_price - $price) < $tol) {
462             return wantarray ?
463 1 50       8 ($sigma, $tol * ($sigma_high-$sigma_low) / ($price_high-$price_low), $n) :
464             $sigma;
465             }
466 15 100       86 if($price > $option_price) {
467 9         13 ($sigma_high, $price_high) = ($sigma, $price);
468             }
469             else {
470 6         9 ($sigma_low, $price_low) = ($sigma, $price);
471             }
472 15         34 $n++;
473             }
474 0           confess "_implied_volatility() failed to converge";
475             }
476              
477             1;
478