File Coverage

blib/lib/Math/Business/BlackScholesMerton/NonBinaries.pm
Criterion Covered Total %
statement 70 70 100.0
branch 4 4 100.0
condition n/a
subroutine 15 15 100.0
pod 8 8 100.0
total 97 97 100.0


line stmt bran cond sub pod time code
1             package Math::Business::BlackScholesMerton::NonBinaries;
2              
3 3     3   259016 use strict;
  3         23  
  3         98  
4 3     3   20 use warnings;
  3         8  
  3         112  
5              
6 3     3   28 use List::Util qw(min max);
  3         20  
  3         288  
7 3     3   948 use Math::CDF qw(pnorm);
  3         5965  
  3         4251  
8              
9             our $VERSION = '1.23'; ## VERSION
10              
11             =head1 NAME
12              
13             Math::Business::BlackScholesMerton::NonBinaries
14              
15             =head1 SYNOPSIS
16              
17             use Math::Business::BlackScholesMerton::NonBinaries;
18              
19             # price of a Call spread option
20             my $price_call_option = Math::Business::BlackScholesMerton::NonBinaries::vanilla_call(
21             1.35, # stock price
22             1.34, # barrier
23             (7/365), # time
24             0.002, # payout currency interest rate (0.05 = 5%)
25             0.001, # quanto drift adjustment (0.05 = 5%)
26             0.11, # volatility (0.3 = 30%)
27             );
28              
29             =head1 DESCRIPTION
30              
31             Contains non-binary option pricing formula.
32              
33             =cut
34              
35             =head2 vanilla_call
36              
37             USAGE
38             my $price = vanilla_call($S, $K, $t, $r_q, $mu, $sigma);
39              
40             DESCRIPTION
41             Price of a Vanilla Call
42              
43             =cut
44              
45             sub vanilla_call {
46 2     2 1 1485 my ($S, $K, $t, $r_q, $mu, $sigma) = @_;
47              
48 2         12 my $d1 = (log($S / $K) + ($mu + $sigma * $sigma / 2.0) * $t) / ($sigma * sqrt($t));
49 2         6 my $d2 = $d1 - ($sigma * sqrt($t));
50              
51 2         22 return exp(-$r_q * $t) * ($S * exp($mu * $t) * pnorm($d1) - $K * pnorm($d2));
52             }
53              
54             =head2 vanilla_put
55              
56             USAGE
57             my $price = vanilla_put($S, $K, $t, $r_q, $mu, sigma)
58              
59             DESCRIPTION
60             Price a standard Vanilla Put
61              
62             =cut
63              
64             sub vanilla_put {
65 2     2 1 1590 my ($S, $K, $t, $r_q, $mu, $sigma) = @_;
66              
67 2         11 my $d1 = (log($S / $K) + ($mu + $sigma * $sigma / 2.0) * $t) / ($sigma * sqrt($t));
68 2         8 my $d2 = $d1 - ($sigma * sqrt($t));
69              
70 2         46 return -1 * exp(-$r_q * $t) * ($S * exp($mu * $t) * pnorm(-$d1) - $K * pnorm(-$d2));
71             }
72              
73             =head2 lbfloatcall
74              
75             USAGE
76             my $price = lbfloatcall($S, $K, $t, $r_q, $mu, $sigma, $S_max, $S_min)
77              
78             DESCRIPTION
79             Price of a Lookback Float Call
80              
81             =cut
82              
83             sub lbfloatcall {
84 3     3 1 2561 my ($S, $K, $t, $r_q, $mu, $sigma, $S_max, $S_min) = @_;
85              
86 3         8 $S_max = undef;
87 3         10 my $d1 = _d1_function($S, $S_min, $t, $r_q, $mu, $sigma);
88 3         10 my $d2 = $d1 - ($sigma * sqrt($t));
89              
90 3         61 my $value = exp(-$r_q * $t) * ($S * exp($mu * $t) * pnorm($d1) - $S_min * pnorm($d2) + _l_min($S, $S_min, $t, $r_q, $mu, $sigma));
91              
92 3         11 return $value;
93             }
94              
95             =head2 lbfloatput
96              
97             USAGE
98             my $price = lbfloatcall($S, $K, $t, $r_q, $mu, $sigma, $S_max, $S_min)
99              
100             DESCRIPTION
101             Price of a Lookback Float Put
102              
103             =cut
104              
105             sub lbfloatput { # Floating Strike Put
106 3     3 1 1911 my ($S, $K, $t, $r_q, $mu, $sigma, $S_max, $S_min) = @_;
107              
108 3         8 $S_min = undef;
109 3         11 my $d1 = _d1_function($S, $S_max, $t, $r_q, $mu, $sigma);
110 3         9 my $d2 = $d1 - ($sigma * sqrt($t));
111              
112 3         37 my $value = exp(-$r_q * $t) * ($S_max * pnorm(-$d2) - $S * exp($mu * $t) * pnorm(-$d1) + _l_max($S, $S_max, $t, $r_q, $mu, $sigma));
113              
114 3         10 return $value;
115             }
116              
117             =head2 lbfixedcall
118              
119             USAGE
120             my $price = lbfixedcall($S, $K, $t, $r_q, $mu, $sigma, $S_max, $S_min)
121              
122             DESCRIPTION
123             Price of a Lookback Fixed Call
124              
125             =cut
126              
127             sub lbfixedcall {
128 2     2 1 2376 my ($S, $K, $t, $r_q, $mu, $sigma, $S_max, $S_min) = @_;
129              
130 2         6 $S_min = undef;
131 2         12 my $K_max = max($S_max, $K);
132 2         25 my $d1 = _d1_function($S, $K_max, $t, $r_q, $mu, $sigma);
133 2         8 my $d2 = $d1 - ($sigma * sqrt($t));
134              
135 2         58 my $value =
136             exp(-$r_q * $t) * (max($S_max - $K, 0.0) + $S * exp($mu * $t) * pnorm($d1) - $K_max * pnorm($d2) + _l_max($S, $K_max, $t, $r_q, $mu, $sigma));
137              
138 2         7 return $value;
139             }
140              
141             =head2 lbfixedput
142              
143             USAGE
144             my $price = lbfixedput($S, $K, $t, $r_q, $mu, $sigma, $S_max, $S_min)
145              
146             DESCRIPTION
147             Price of a Lookback Fixed Put
148              
149             =cut
150              
151             sub lbfixedput {
152 2     2 1 1830 my ($S, $K, $t, $r_q, $mu, $sigma, $S_max, $S_min) = @_;
153              
154 2         17 $S_max = undef;
155 2         12 my $K_min = min($S_min, $K);
156 2         8 my $d1 = _d1_function($S, $K_min, $t, $r_q, $mu, $sigma);
157 2         7 my $d2 = $d1 - ($sigma * sqrt($t));
158              
159 2         28 my $value = exp(-$r_q * $t) *
160             (max($K - $S_min, 0.0) + $K_min * pnorm(-$d2) - $S * exp($mu * $t) * pnorm(-$d1) + _l_min($S, $K_min, $t, $r_q, $mu, $sigma));
161              
162 2         7 return $value;
163             }
164              
165             =head2 lbhighlow
166              
167             USAGE
168             my $price = lbhighlow($S, $K, $t, $r_q, $mu, $sigma, $S_max, $S_min)
169              
170             DESCRIPTION
171             Price of a Lookback High Low
172              
173             =cut
174              
175             sub lbhighlow {
176 1     1 1 871 my ($S, $K, $t, $r_q, $mu, $sigma, $S_max, $S_min) = @_;
177              
178 1         6 my $value = lbfloatcall($S, $S_min, $t, $r_q, $mu, $sigma, $S_max, $S_min) + lbfloatput($S, $S_max, $t, $r_q, $mu, $sigma, $S_max, $S_min);
179              
180 1         4 return $value;
181             }
182              
183             =head2 _d1_function
184              
185             returns the d1 term common to many BlackScholesMerton formulae.
186              
187             =cut
188              
189             sub _d1_function {
190 20     20   52 my ($S, $K, $t, $r_q, $mu, $sigma) = @_;
191              
192 20         123 my $value = (log($S / $K) + ($mu + $sigma * $sigma * 0.5) * $t) / ($sigma * sqrt($t));
193              
194 20         55 return $value;
195             }
196              
197             =head2 _l_max
198              
199             This is a common function use to calculate the lookbacks options price. See [5] for details.
200              
201             =cut
202              
203             sub _l_max {
204 5     5   20 my ($S, $K, $t, $r_q, $mu, $sigma) = @_;
205              
206 5         17 my $d1 = _d1_function($S, $K, $t, $r_q, $mu, $sigma);
207 5         10 my $value;
208              
209 5 100       16 if ($mu) {
210 3         34 $value =
211             $S *
212             ($sigma**2) /
213             (2.0 * $mu) *
214             (-($S / $K)**(-2.0 * $mu / ($sigma**2)) * pnorm($d1 - 2.0 * $mu / $sigma * sqrt($t)) + exp($mu * $t) * pnorm($d1));
215             } else {
216 2         6 $value = $S * ($sigma * sqrt($t)) * (dnorm($d1) + $d1 * pnorm($d1));
217             }
218              
219 5         15 return $value;
220             }
221              
222             =head2 _l_min
223              
224             This is a common function use to calculate the lookbacks options price. See [5] for details.
225              
226             =cut
227              
228             sub _l_min {
229 5     5   18 my ($S, $K, $t, $r_q, $mu, $sigma) = @_;
230              
231 5         24 my $d1 = _d1_function($S, $K, $t, $r_q, $mu, $sigma);
232 5         12 my $value;
233              
234 5 100       16 if ($mu) {
235 3         33 $value =
236             $S *
237             ($sigma**2) /
238             (2.0 * $mu) *
239             (($S / $K)**(-2.0 * $mu / ($sigma**2)) * pnorm(-$d1 + 2.0 * $mu / $sigma * sqrt($t)) - exp($mu * $t) * pnorm(-$d1));
240             } else {
241 2         6 $value = $S * ($sigma * sqrt($t)) * (dnorm($d1) + $d1 * (pnorm($d1) - 1));
242             }
243              
244 5         14 return $value;
245             }
246              
247             =head2 dnorm
248              
249             Standard normal density function
250              
251             =cut
252              
253             sub dnorm { # Standard normal density function
254 4     4 1 7 my $x = shift;
255 4         11 my $pi = 3.14159265359;
256              
257 4         25 my $value = exp(-$x**2 / 2) / sqrt(2.0 * $pi);
258              
259 4         15 return $value;
260             }
261              
262             1;