File Coverage

lib/Math/Business/BlackScholes/Binaries/Greeks/Delta.pm
Criterion Covered Total %
statement 97 102 95.1
branch 11 16 68.7
condition 2 3 66.6
subroutine 20 20 100.0
pod 0 13 0.0
total 130 154 84.4


line stmt bran cond sub pod time code
1             package Math::Business::BlackScholes::Binaries::Greeks::Delta;
2 1     1   80537 use strict;
  1         11  
  1         29  
3 1     1   5 use warnings;
  1         2  
  1         47  
4              
5             our $VERSION = '0.06'; ## VERSION
6              
7             =head1 NAME
8              
9             Math::Business::BlackScholes::Binaries::Greeks::Delta
10              
11             =head1 DESCRIPTION
12              
13             Gets the delta for different options, Vanilla and Foreign for all contract types
14              
15             =head1 COMMENTS
16              
17             It is tricky to decide what form to use. Should the delta be with respect to
18             1/$S, or with respect to $S? For the binary bets, whether foreign or domestic
19             we are differentiating with respect to $S.
20              
21             For a vanilla, the correct way should be with respect to 1/$S (so that we know
22             how many units of the domestic currency to hedge), but to keep things standard,
23             we do it with respect to $S.
24              
25             For example take USDJPY vanilla call with premium in USD. Thus this is a vanilla
26             contract on JPY. Thus delta with respect to 1/$S tells us how many units of JPY
27             to hedge, but with respect to $S, there really isn't a meaning and needs to be
28             converted back before interpretation.
29              
30             =cut
31              
32             =head1 SUBROUTINES
33              
34             See L
35              
36             =cut
37              
38 1     1   5 use List::Util qw(max);
  1         2  
  1         119  
39 1     1   466 use Math::CDF qw(pnorm);
  1         2889  
  1         58  
40 1     1   522 use Math::Trig;
  1         13360  
  1         156  
41 1     1   609 use Math::Business::BlackScholesMerton::Binaries;
  1         3850  
  1         37  
42 1     1   422 use Math::Business::BlackScholes::Binaries::Greeks::Math qw( dgauss );
  1         2  
  1         1607  
43              
44             sub vanilla_call {
45 6     6 0 15545 my ($S, $K, $t, $r_q, $mu, $vol) = @_;
46              
47 6         28 my $d1 = (log($S / $K) + ($mu + $vol * $vol / 2.0) * $t) / ($vol * sqrt($t));
48              
49 6         39 return exp(($mu - $r_q) * $t) * pnorm($d1);
50             }
51              
52             sub vanilla_put {
53 6     6 0 15592 my ($S, $K, $t, $r_q, $mu, $vol) = @_;
54              
55 6         25 my $d1 = (log($S / $K) + ($mu + $vol * $vol / 2.0) * $t) / ($vol * sqrt($t));
56              
57 6         40 return -exp(($mu - $r_q) * $t) * pnorm(-$d1);
58             }
59              
60             sub call {
61 16     16 0 15738 my ($S, $U, $t, $r_q, $mu, $vol) = @_;
62              
63 16         103 my $d2 = (log($S / $U) + ($mu - $vol * $vol / 2.0) * $t) / ($vol * sqrt($t));
64              
65 16         61 return exp(-$r_q * $t) * dgauss($d2) / ($vol * sqrt($t) * $S);
66             }
67              
68             sub put {
69 16     16 0 16267 my ($S, $D, $t, $r_q, $mu, $vol) = @_;
70              
71 16         77 my $d2 = (log($S / $D) + ($mu - $vol * $vol / 2.0) * $t) / ($vol * sqrt($t));
72              
73 16         52 return -exp(-$r_q * $t) * dgauss($d2) / ($vol * sqrt($t) * $S);
74             }
75              
76             sub expirymiss {
77 10     10 0 16131 my ($S, $U, $D, $t, $r_q, $mu, $vol) = @_;
78              
79 10         33 return call($S, $U, $t, $r_q, $mu, $vol) + put($S, $D, $t, $r_q, $mu, $vol);
80             }
81              
82             sub expiryrange {
83 5     5 0 13561 my ($S, $U, $D, $t, $r_q, $mu, $vol) = @_;
84              
85 5         18 return -1 * expirymiss($S, $U, $D, $t, $r_q, $mu, $vol);
86             }
87              
88             sub onetouch {
89 13     13 0 18196 my ($S, $U, $t, $r_q, $mu, $vol, $w) = @_;
90              
91             # w = 0, rebate paid at hit.
92             # w = 1, rebate paid at end.
93 13 100       38 if (not defined $w) {
94 7         13 $w = 0;
95             }
96              
97 13         24 my $sqrt_t = sqrt($t);
98              
99 13         31 my $theta_ = ($mu / $vol) - (0.5 * $vol);
100              
101             # Floor v_ squared near zero in case negative interest rates push it negative.
102 13         56 my $v_ = sqrt(max($Math::Business::BlackScholesMerton::Binaries::SMALL_VALUE_MU, ($theta_ * $theta_) + (2 * (1 - $w) * $r_q)));
103              
104 13         48 my $e = (log($S / $U) - ($vol * $v_ * $t)) / ($vol * $sqrt_t);
105              
106 13         38 my $e_ = (-log($S / $U) - ($vol * $v_ * $t)) / ($vol * $sqrt_t);
107              
108 13 100       38 my $eta = ($S > $U) ? 1 : -1;
109              
110 13         95 my $part1 =
111             ($theta_ + $v_) * pnorm(-$eta * $e) + $eta * dgauss($e) / $sqrt_t;
112 13         71 my $part2 =
113             ($theta_ - $v_) * pnorm($eta * $e_) + $eta * dgauss($e_) / $sqrt_t;
114              
115 13         48 my $delta = (($U / $S)**(($theta_ + $v_) / $vol)) * $part1 + (($U / $S)**(($theta_ - $v_) / $vol)) * $part2;
116              
117 13         46 return -$delta * exp(-$w * $r_q * $t) / ($vol * $S);
118             }
119              
120             sub notouch {
121 6     6 0 17284 my ($S, $U, $t, $r_q, $mu, $vol, $w) = @_;
122              
123             # No touch bet always pay out at end
124 6         11 $w = 1;
125              
126 6         18 return -1 * onetouch($S, $U, $t, $r_q, $mu, $vol, $w);
127             }
128              
129             sub upordown {
130 13     13 0 22814 my ($S, $U, $D, $t, $r_q, $mu, $vol, $w) = @_;
131              
132             # $w = 0, paid at hit
133             # $w = 1, paid at end
134 13 100       48 if (not defined $w) { $w = 0; }
  7         18  
135              
136 13         47 return ot_up_ko_down_pelsser_1997($S, $U, $D, $t, $r_q, $mu, $vol, $w) + ot_down_ko_up_pelsser_1997($S, $U, $D, $t, $r_q, $mu, $vol, $w);
137             }
138              
139             sub x_common_function_pelsser_1997 {
140 104     104 0 249 my ($S, $U, $D, $t, $r_q, $mu, $vol, $w, $eta) = @_;
141              
142 104         151 my $pi = Math::Trig::pi;
143              
144 104         233 my $h = log($U / $D);
145 104         153 my $x = log($S / $D);
146              
147             # $eta = 1, onetouch up knockout down
148             # $eta = 0, onetouch down knockout up
149             # This variable used to check stability
150 104 50       235 if (not defined $eta) {
151 0         0 die
152             "$0: (x_common_function_pelsser_1997) Wrong usage of this function for S=$S, U=$U, D=$D, t=$t, r_q=$r_q, mu=$mu, vol=$vol, w=$w. eta not defined.";
153             }
154 104 100       238 if ($eta == 0) { $x = $h - $x; }
  52         74  
155              
156 104         166 my $mu_new = $mu - (0.5 * $vol * $vol);
157 104         312 my $mu_dash =
158             sqrt(max($Math::Business::BlackScholesMerton::Binaries::SMALL_VALUE_MU, ($mu_new * $mu_new) + (2 * $vol * $vol * $r_q * (1 - $w))));
159              
160 104         197 my $series_part = 0;
161 104         185 my $hyp_part = 0;
162              
163 104         254 my $stability_constant =
164             Math::Business::BlackScholesMerton::Binaries::get_stability_constant_pelsser_1997($S, $U, $D, $t, $r_q, $mu, $vol, $w, $eta, 2);
165              
166 104         2205 my $iterations_required = Math::Business::BlackScholesMerton::Binaries::get_min_iterations_pelsser_1997($S, $U, $D, $t, $r_q, $mu, $vol, $w);
167              
168 104         7555 for (my $k = 1; $k < $iterations_required; $k++) {
169 2280         4125 my $lambda_k_dash = (0.5 * (($mu_dash * $mu_dash) / ($vol * $vol) + ($k * $k * $pi * $pi * $vol * $vol) / ($h * $h)));
170              
171 2280         4142 my $phi = ($vol * $vol) / ($h * $h * $h) * exp(-$lambda_k_dash * $t) * $k * $k / $lambda_k_dash;
172              
173 2280         3716 $series_part += $phi * $pi * $pi * cos($k * $pi * ($h - $x) / $h);
174              
175             #
176             # For delta, the stability function is $phi/$S, for gamma it is different,
177             # but we shall ignore for now.
178             #
179 2280 50 66     5470 if ($k == 1 and (not(abs($phi / $S) < $stability_constant))) {
180 0         0 die
181             "$0: PELSSER DELTA formula for S=$S, U=$U, D=$D, t=$t, r_q=$r_q, mu=$mu, vol=$vol, w=$w, eta=$eta cannot be evaluated because PELSSER DELTA stability conditions ($phi / $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.";
182             }
183             }
184              
185             # Need to take care when $mu goes to zero
186 104 50       223 if (abs($mu_new) < $Math::Business::BlackScholesMerton::Binaries::SMALL_VALUE_MU) {
187 0 0       0 my $sign = ($mu_new >= 0) ? 1 : -1;
188 0         0 $mu_new = $sign * $Math::Business::BlackScholesMerton::Binaries::SMALL_VALUE_MU;
189 0         0 $mu_dash = sqrt(($mu_new * $mu_new) + (2 * $vol * $vol * $r_q * (1 - $w)));
190             }
191              
192 104         348 $hyp_part = ($mu_dash / ($vol * $vol)) * (Math::Trig::cosh($mu_dash * $x / ($vol * $vol)) / Math::Trig::sinh($mu_dash * $h / ($vol * $vol)));
193              
194 104         1946 my $dc_dx = ($hyp_part + $series_part) * exp(-$r_q * $t * $w);
195              
196 104         242 return $dc_dx;
197             }
198              
199             sub ot_up_ko_down_pelsser_1997 {
200 13     13 0 42 my ($S, $U, $D, $t, $r_q, $mu, $vol, $w) = @_;
201              
202 13         49 my $mu_new = $mu - (0.5 * $vol * $vol);
203 13         46 my $h = log($U / $D);
204 13         30 my $x = log($S / $D);
205              
206 13         68 my $dVu_dx =
207             -(($mu_new / ($vol * $vol)) *
208             Math::Business::BlackScholesMerton::Binaries::common_function_pelsser_1997($S, $U, $D, $t, $r_q, $mu, $vol, $w, 1));
209              
210 13         3787 $dVu_dx += x_common_function_pelsser_1997($S, $U, $D, $t, $r_q, $mu, $vol, $w, 1);
211 13         30 $dVu_dx *= exp($mu_new * ($h - $x) / ($vol * $vol));
212              
213             # dV/dS = dV/dx * dx/dS = dV/dx * 1/S
214 13         52 return $dVu_dx / $S;
215             }
216              
217             sub ot_down_ko_up_pelsser_1997 {
218 13     13 0 41 my ($S, $U, $D, $t, $r_q, $mu, $vol, $w) = @_;
219              
220 13         28 my $mu_new = $mu - (0.5 * $vol * $vol);
221 13         29 my $x = log($S / $D);
222              
223 13         49 my $dVl_dx =
224             -(($mu_new / ($vol * $vol)) *
225             Math::Business::BlackScholesMerton::Binaries::common_function_pelsser_1997($S, $U, $D, $t, $r_q, $mu, $vol, $w, 0));
226              
227 13         3680 $dVl_dx -= x_common_function_pelsser_1997($S, $U, $D, $t, $r_q, $mu, $vol, $w, 0);
228 13         34 $dVl_dx *= exp(-$mu_new * $x / ($vol * $vol));
229              
230             # dV/dS = dV/dx * dx/dS = dV/dx * 1/S
231 13         46 return $dVl_dx / $S;
232             }
233              
234             sub range {
235 6     6 0 17089 my ($S, $U, $D, $t, $r_q, $mu, $vol, $w) = @_;
236              
237             # Range always pay out at end
238 6         11 $w = 1;
239              
240 6         79 return -1 * upordown($S, $U, $D, $t, $r_q, $mu, $vol, $w);
241             }
242              
243             1;
244