File Coverage

lib/Math/Business/BlackScholes/Binaries/Greeks/Gamma.pm
Criterion Covered Total %
statement 122 127 96.0
branch 11 16 68.7
condition 2 3 66.6
subroutine 20 20 100.0
pod 0 13 0.0
total 155 179 86.5


line stmt bran cond sub pod time code
1             package Math::Business::BlackScholes::Binaries::Greeks::Gamma;
2 1     1   333 use strict; use warnings;
  1     1   8  
  1         23  
  1         2  
  1         1  
  1         30  
3              
4             our $VERSION = '0.04';
5              
6             =head1 NAME
7              
8             Math::Business::BlackScholes::Binaries::Greeks::Gamma
9              
10             =head1 DESCRIPTION
11              
12             Gets the gamma for different options, Vanilla and Foreign for all our bet types
13              
14             =cut
15              
16             =head1 SUBROUTINES
17              
18             See L
19              
20             =cut
21              
22 1     1   3 use List::Util qw( max );
  1         1  
  1         42  
23 1     1   6 use Math::CDF qw( pnorm );
  1         1  
  1         26  
24 1     1   3 use Math::Trig;
  1         1  
  1         400  
25 1     1   4 use Math::Business::BlackScholes::Binaries;
  1         1  
  1         17  
26 1     1   3 use Math::Business::BlackScholes::Binaries::Greeks::Math qw( ddgauss dgauss );
  1         1  
  1         1387  
27              
28             sub vanilla_call {
29 12     12 0 1918 my ( $S0, $Strike, $t, $r_q, $mu, $vol ) = @_;
30              
31 12         41 my $d1 =
32             ( log( $S0 / $Strike ) + ( $mu + ( ( $vol**2 ) / 2 ) ) * $t ) /
33             ( $vol * sqrt($t) );
34              
35 12         20 my $gamma =
36             dgauss($d1) * exp( ( $mu - $r_q ) * $t ) / ( $S0 * $vol * sqrt($t) );
37              
38 12         18 return $gamma;
39             }
40              
41             sub vanilla_put {
42 6     6 0 2032 return vanilla_call(@_);
43             }
44              
45             sub call {
46 16     16 0 2404 my ( $S, $U, $t, $r_q, $mu, $vol ) = @_;
47              
48 16         59 my $v = $mu - ( $vol**2 ) / 2;
49 16         34 my $a = log( $U / $S );
50              
51 16         21 my $da = -1 / $S;
52 16         22 my $dda = 1 / ( $S * $S );
53              
54 16         34 my $q = ( $a - $v * $t ) / ( $vol * sqrt($t) );
55 16         24 my $dq = $da / ( $vol * sqrt($t) );
56 16         23 my $ddq = $dda / ( $vol * sqrt($t) );
57              
58 16         56 my $gamma =
59             -exp( -$r_q * $t ) * ( ddgauss($q) * $dq * $dq + dgauss($q) * $ddq );
60              
61 16         44 return $gamma;
62             }
63              
64             sub put {
65 16     16 0 2140 my ( $S, $D, $t, $r_q, $mu, $vol ) = @_;
66              
67 16         42 my $v = $mu - ( $vol**2 ) / 2;
68 16         30 my $b = log( $D / $S );
69 16         19 my $db = -1 / $S;
70 16         34 my $ddb = 1 / ( $S * $S );
71              
72 16         36 my $q = ( $b - $v * $t ) / ( $vol * sqrt($t) );
73 16         28 my $dq = $db / ( $vol * sqrt($t) );
74 16         22 my $ddq = $ddb / ( $vol * sqrt($t) );
75              
76 16         48 my $gamma =
77             exp( -$r_q * $t ) * ( ddgauss($q) * $dq * $dq + dgauss($q) * $ddq );
78              
79 16         38 return $gamma;
80             }
81              
82             sub expirymiss {
83 10     10 0 2596 my ( $S, $U, $D, $t, $r_q, $mu, $vol ) = @_;
84              
85 10         27 return call( $S, $U, $t, $r_q, $mu, $vol ) +
86             put( $S, $D, $t, $r_q, $mu, $vol );
87             }
88              
89             sub expiryrange {
90 5     5 0 1639 my ( $S, $U, $D, $t, $r_q, $mu, $vol ) = @_;
91              
92 5         13 return -1 * expirymiss( $S, $U, $D, $t, $r_q, $mu, $vol );
93             }
94              
95             sub onetouch {
96 13     13 0 2630 my ( $S, $U, $t, $r_q, $mu, $vol, $w ) = @_;
97 13 100       35 if ( not defined $w ) {
98 7         10 $w = 0;
99             }
100              
101 13         16 my $sqrt_t = sqrt($t);
102              
103 13         22 my $theta = ( ($mu) / $vol ) + ( 0.5 * $vol );
104              
105 13         17 my $theta_ = ( ($mu) / $vol ) - ( 0.5 * $vol );
106              
107             # Floor v_ squared near zero in case negative interest rates push it negative.
108 13         44 my $v_ = sqrt( max( $Math::Business::BlackScholes::Binaries::SMALL_VALUE_MU, ( $theta_ * $theta_ ) + ( 2 * ( 1 - $w ) * $r_q ) ) );
109              
110 13         31 my $e = ( log( $S / $U ) - ( $vol * $v_ * $t ) ) / ( $vol * $sqrt_t );
111              
112 13         24 my $e_ = ( -log( $S / $U ) - ( $vol * $v_ * $t ) ) / ( $vol * $sqrt_t );
113              
114 13 100       27 my $eta = ( $S > $U ) ? 1 : -1;
115              
116 13         86 my $part1 =
117             ( ( $U / $S )**( ( $theta_ + $v_ ) / $vol ) ) *
118             pnorm( -$eta * $e ) *
119             ( $r_q * ( 1 - $w ) + ($mu) * ( $theta_ + $v_ ) / $vol );
120 13         47 my $part2 =
121             ( ( $U / $S )**( ( $theta_ - $v_ ) / $vol ) ) *
122             pnorm( $eta * $e_ ) *
123             ( $r_q * ( 1 - $w ) + ($mu) * ( $theta_ - $v_ ) / $vol );
124 13         36 my $part3 =
125             $eta *
126             ( ( $U / $S )**( ( $theta_ + $v_ ) / $vol ) ) *
127             dgauss($e) *
128             ( -$e_ * 0.5 / $t + ($mu) / ( $vol * $sqrt_t ) );
129 13         33 my $part4 =
130             $eta *
131             ( ( $U / $S )**( ( $theta_ - $v_ ) / $vol ) ) *
132             dgauss($e_) *
133             ( $e * 0.5 / $t + ($mu) / ( $vol * $sqrt_t ) );
134              
135 13         19 my $gamma = $part1 + $part2 + $part3 + $part4;
136 13         31 return $gamma * 2 * exp( -$w * $r_q * $t ) / ( $vol * $vol * $S * $S );
137             }
138              
139             sub notouch {
140 6     6 0 1910 my ( $S, $U, $t, $r_q, $mu, $vol, $w ) = @_;
141              
142             # No touch bet always pay out at end
143 6         6 $w = 1;
144              
145 6         11 return -1 * onetouch( $S, $U, $t, $r_q, $mu, $vol, $w );
146             }
147              
148             sub upordown {
149 13     13 0 3762 my ( $S, $U, $D, $t, $r_q, $mu, $vol, $w ) = @_;
150              
151             # $w = 0, paid at hit
152             # $w = 1, paid at end
153 13 100       45 if ( not defined $w ) { $w = 0; }
  7         16  
154              
155 13         54 return ot_up_ko_down_pelsser_1997( $S, $U, $D, $t, $r_q, $mu, $vol, $w ) +
156             ot_down_ko_up_pelsser_1997( $S, $U, $D, $t, $r_q, $mu, $vol, $w );
157             }
158              
159             sub xx_common_function_pelsser_1997 {
160 26     26 0 56 my ( $S, $U, $D, $t, $r_q, $mu, $vol, $w, $eta ) = @_;
161              
162 26         27 my $pi = Math::Trig::pi;
163              
164 26         52 my $h = log( $U / $D );
165 26         36 my $x = log( $S / $D );
166              
167             # $eta = 1, onetouch up knockout down
168             # $eta = 0, onetouch down knockout up
169             # This variable used to check stability
170 26 50       55 if ( not defined $eta ) {
171 0         0 die
172             "$0: (xx_common_function_pelsser_1997) Wrong usage of this function for S=$S, U=$U, D=$D, t=$t, r=$r_q, mu=$mu, vol=$vol, w=$w. eta not defined.";
173             }
174 26 100       59 if ( $eta == 0 ) { $x = $h - $x; }
  13         16  
175              
176 26         40 my $mu_ = $mu - ( 0.5 * $vol * $vol );
177 26         95 my $mu_dash =
178             sqrt( max( $Math::Business::BlackScholes::Binaries::SMALL_VALUE_MU, ( $mu_ * $mu_ ) + ( 2 * $vol * $vol * $r_q * ( 1 - $w ) ) ) );
179              
180 26         40 my $series_part = 0;
181 26         33 my $hyp_part = 0;
182              
183 26         72 my $stability_constant =
184             Math::Business::BlackScholes::Binaries::get_stability_constant_pelsser_1997(
185             $S, $U, $D, $t, $r_q, $mu, $vol, $w, $eta, 3 );
186              
187 26         348 my $iterations_required =
188             Math::Business::BlackScholes::Binaries::get_min_iterations_pelsser_1997(
189             $S, $U, $D, $t, $r_q, $mu, $vol, $w );
190              
191 26         1045 for ( my $k = 1 ; $k < $iterations_required ; $k++ ) {
192 570         821 my $lambda_k_dash = (
193             0.5 * (
194             ( $mu_dash * $mu_dash ) / ( $vol * $vol ) +
195             ( $k * $k * $pi * $pi * $vol * $vol ) / ( $h * $h )
196             )
197             );
198              
199 570         910 my $phi =
200             ( $vol * $vol ) / ( $h**4 ) * exp( -$lambda_k_dash * $t ) * ( $k**3 )
201             / $lambda_k_dash;
202              
203 570         845 $series_part += $phi * ( $pi**3 ) * sin( $k * $pi * ( $h - $x ) / $h );
204              
205 570 50 66     1765 if ( $k == 1
206             and ( not( abs( $phi / ( $S**2 ) ) < $stability_constant ) ) )
207             {
208 0         0 die
209             "$0: PELSSER GAMMA formula for S=$S, U=$U, D=$D, t=$t, r=$r_q, mu=$mu, vol=$vol, w=$w, eta=$eta cannot be evaluated because PELSSER GAMMA stability conditions ($phi / ($S * $S) less than $stability_constant) not met. This could be due to barriers too big, volatilities too low, interest/dividend rates too high, or machine accuracy too low.";
210             }
211             }
212              
213             # Need to take care when $mu goes to zero
214 26 50       65 if ( abs($mu_) < $Math::Business::BlackScholes::Binaries::SMALL_VALUE_MU ) {
215 0 0       0 my $sign = ( $mu_ >= 0 ) ? 1 : -1;
216 0         0 $mu_ = $sign * $Math::Business::BlackScholes::Binaries::SMALL_VALUE_MU;
217 0         0 $mu_dash =
218             sqrt( max ( $Math::Business::BlackScholes::Binaries::SMALL_VALUE_MU, ( $mu_ * $mu_ ) + ( 2 * $vol * $vol * $r_q * ( 1 - $w ) ) ) );
219             }
220              
221             $hyp_part =
222 26         133 ( ( $mu_dash**2 ) / ( $vol**4 ) ) *
223             ( Math::Trig::sinh( $mu_dash * $x / ( $vol * $vol ) ) /
224             Math::Trig::sinh( $mu_dash * $h / ( $vol * $vol ) ) );
225              
226 26         367 my $d2c_dwdx = ( $hyp_part + $series_part ) * exp( -$r_q * $t * $w );
227              
228 26         52 return $d2c_dwdx;
229             }
230              
231             sub ot_up_ko_down_pelsser_1997 {
232 13     13 0 31 my ( $S, $U, $D, $t, $r_q, $mu, $vol, $w ) = @_;
233              
234 13         83 my $mu_ = $mu - ( 0.5 * $vol * $vol );
235 13         37 my $h = log( $U / $D );
236 13         27 my $x = log( $S / $D );
237              
238 13         48 my $c =
239             Math::Business::BlackScholes::Binaries::common_function_pelsser_1997( $S,
240             $U, $D, $t, $r_q, $mu, $vol, $w, 1 );
241 13         2178 my $dc_dx =
242             Math::Business::BlackScholes::Binaries::Greeks::Delta::x_common_function_pelsser_1997(
243             $S, $U, $D, $t, $r_q, $mu, $vol, $w, 1 );
244 13         43 my $d2c_dx2 =
245             xx_common_function_pelsser_1997( $S, $U, $D, $t, $r_q, $mu, $vol, $w, 1 );
246              
247 13         51 my $dVu_dx = -(
248             ( $mu_ / ( $vol * $vol ) ) *
249             Math::Business::BlackScholes::Binaries::common_function_pelsser_1997(
250             $S, $U, $D, $t, $r_q, $mu, $vol, $w, 1
251             )
252             );
253 13         2006 $dVu_dx +=
254             Math::Business::BlackScholes::Binaries::Greeks::Delta::x_common_function_pelsser_1997(
255             $S, $U, $D, $t, $r_q, $mu, $vol, $w, 1 );
256 13         48 $dVu_dx *= exp( $mu_ * ( $h - $x ) / ( $vol * $vol ) );
257              
258 13         86 my $d2Vu_dx2 =
259             ( ( ( $mu_**2 ) / ( $vol**4 ) ) *
260             exp( ( $mu_ / ( $vol * $vol ) ) * ( $h - $x ) ) *
261             $c ) -
262             ( 2 *
263             ( $mu_ / ( $vol**2 ) ) *
264             exp( ( $mu_ / ( $vol * $vol ) ) * ( $h - $x ) ) *
265             $dc_dx ) +
266             ( exp( ( $mu_ / ( $vol**2 ) ) * ( $h - $x ) ) * $d2c_dx2 );
267              
268 13         48 return ( 1 / ( $S**2 ) ) * ( $d2Vu_dx2 - $dVu_dx );
269             }
270              
271             sub ot_down_ko_up_pelsser_1997 {
272 13     13 0 29 my ( $S, $U, $D, $t, $r_q, $mu, $vol, $w ) = @_;
273              
274 13         29 my $mu_ = $mu - ( 0.5 * $vol * $vol );
275 13         31 my $h = log( $U / $D );
276 13         24 my $x = log( $S / $D );
277              
278 13         34 my $c =
279             Math::Business::BlackScholes::Binaries::common_function_pelsser_1997( $S,
280             $U, $D, $t, $r_q, $mu, $vol, $w, 0 );
281 13         2108 my $dc_dx =
282             Math::Business::BlackScholes::Binaries::Greeks::Delta::x_common_function_pelsser_1997(
283             $S, $U, $D, $t, $r_q, $mu, $vol, $w, 0 );
284 13         34 my $d2c_dx2 =
285             xx_common_function_pelsser_1997( $S, $U, $D, $t, $r_q, $mu, $vol, $w, 0 );
286              
287 13         47 my $dVl_dx = -(
288             ( $mu_ / ( $vol * $vol ) ) *
289             Math::Business::BlackScholes::Binaries::common_function_pelsser_1997(
290             $S, $U, $D, $t, $r_q, $mu, $vol, $w, 0
291             )
292             );
293 13         2100 $dVl_dx -=
294             Math::Business::BlackScholes::Binaries::Greeks::Delta::x_common_function_pelsser_1997(
295             $S, $U, $D, $t, $r_q, $mu, $vol, $w, 0 );
296 13         38 $dVl_dx *= exp( -$mu_ * $x / ( $vol * $vol ) );
297              
298 13         91 my $d2Vl_dx2 =
299             ( ( ( $mu_**2 ) / ( $vol**4 ) ) * exp( -( $mu_ / ( $vol * $vol ) ) * $x )
300             * $c ) +
301             ( 2 *
302             ( $mu_ / ( $vol**2 ) ) *
303             exp( -( $mu_ / ( $vol * $vol ) ) * $x ) *
304             $dc_dx ) +
305             ( exp( -( $mu_ / ( $vol**2 ) ) * $x ) * $d2c_dx2 );
306              
307 13         58 return ( 1 / ( $S**2 ) ) * ( $d2Vl_dx2 - $dVl_dx );
308             }
309              
310             sub range {
311 6     6 0 3333 my ( $S, $U, $D, $t, $r_q, $mu, $vol, $w ) = @_;
312              
313             # Range always pay out at end
314 6         13 $w = 1;
315              
316 6         22 return -1 * upordown( $S, $U, $D, $t, $r_q, $mu, $vol, $w );
317             }
318              
319             1;
320