File Coverage

blib/lib/Finance/BDT.pm
Criterion Covered Total %
statement 73 79 92.4
branch 10 16 62.5
condition 1 2 50.0
subroutine 10 11 90.9
pod 0 7 0.0
total 94 115 81.7


line stmt bran cond sub pod time code
1             package Finance::BDT;
2              
3 1     1   33177 use strict;
  1         2  
  1         39  
4 1     1   6 use warnings;
  1         2  
  1         31  
5              
6 1     1   5407 use Data::Dumper;
  1         18048  
  1         91  
7 1     1   10 use constant EPSILON => 0.00001;
  1         2  
  1         1442  
8              
9             our $VERSION = '0.01';
10             our $DEBUG;
11              
12             my (@P, @y, $vol, @r, @d, @A, $epsilon);
13              
14 0     0 0 0 sub clear { @P = @y = @r = @d = @A = (); $vol = $epsilon = undef }
  0         0  
15             sub bdt {
16 1     1 0 21 my (%params) = @_;
17 1         1 @y = @{$params{-yields}};
  1         5  
18 1   50     5 $epsilon = $params{-epsilon} || EPSILON;
19 1         3 $vol = $params{-volatility}; ## constant volatility
20              
21             ## @P: the set of discount prices
22 1         5 for (0..$#y) { $P[$_] = [] } ## initialize @P as a 2-D array
  9         16  
23 1         6 for (0..$#y) { $P[0][$_] = exp( -$y[$_] * $_) } ## derive bond prices from the yields
  9         38  
24              
25 1 50       4 if ($DEBUG) {
26 0         0 print "Bond Price: ";
27 0         0 for (0..$#y) { printf "%.5f ", $P[0][$_] }
  0         0  
28 0         0 print "\n";
29             }
30              
31             ## @r: the rates at each period
32 1         3 for (0..$#y) { $r[$_] = [] } ## initialize @r as a 2-D array
  9         14  
33 1         13 $r[0] = [$y[1]]; ## we start knowing this
34              
35             ## @d: the discount rates
36 1         3 for (0..$#y) { $d[$_] = [] } ## initialize @r as a 2-D array
  9         13  
37              
38             ## @A: the state asset prices
39 1         3 for (0..$#y) { $A[$_] = [] } ## initialize @A as a 2-D array
  9         13  
40 1         3 $A[1][0] = $P[0][1] * 0.5;
41 1         3 $A[1][1] = $P[0][1] * 0.5;
42              
43              
44             #### Now the real work starts
45 1         3 for (1..$#y-1) {
46 7         14 $r[$_] = iterator($_, $r[$_-1][0]);
47 7         15 &gen_discount_function($_);
48 7 50       14 print Dumper $d[$_] if $DEBUG;
49 7         12 &gen_state_prices($_+1);
50 7 50       23 print Dumper $A[$_] if $DEBUG;
51             }
52              
53 1         6 return(\@r, \@d, \@A);
54             }
55              
56             sub gen_discount_function {
57 7     7 0 8 my ($period) = @_;
58 7         10 for (0..$period) {
59 35         62 $d[$period][$_] = exp(- $r[$period][$_] );
60             }
61             }
62              
63              
64             sub gen_state_prices {
65 7     7 0 8 my ($period) = @_;
66 7         18 $A[$period][0] = $A[$period - 1][0] * .5 * $d[$period - 1][0]; ## the bottom lattice
67 7         18 $A[$period][$period] = $A[$period - 1][$period - 1] * .5 * $d[$period - 1][$period - 1]; ## the top lattice
68              
69             ## the middle lattices:
70 7         19 for (1 .. $period - 1) {
71 28         75 $A[$period][$_] = ($A[$period - 1][$_-1] * .5 * $d[$period - 1][$_ - 1] +
72             $A[$period - 1][$_] * .5 * $d[$period - 1][$_] );
73             }
74             }
75              
76              
77             sub bond {
78 10     10 0 12 my ($period, $r, $vol) = @_;
79 10         12 my $u1 = exp(2 * $vol);
80 10         24 my $bond = $P[0][$period - 1] * (.5 * exp(-$r) + .5 * exp(-$r * $u1) );
81 10 50       17 printf("bond(%i, %.7f, %.7f, %.7f)\n", $period, $r, $u1, $vol) if $DEBUG;
82 10         24 return ($bond, [$r, $r * $u1]);
83             }
84              
85             sub bond2 {
86 68     68 0 78 my ($period, $r, $vol) = @_;
87             # print "period: $period, $r, $vol\n";
88 68         57 my $bond = 0;
89 68         78 my @r;
90 68         79 my $u = exp( 2 * $vol);
91              
92             # $bond = $A[2][0] * exp(-$r) + $A[2][1] * exp(-$r * $u) + $A[2][2] * exp(-$r * $u**2);
93             # @r = ($r, $r * $u, $r * $u**2);
94              
95 68         500 $r[$_] = $r * $u ** $_ for (0..$period-1);
96 68         138 for (0..$period-1) {
97 375         679 $bond += $A[$period - 1][$_] * exp( - $r[$_] );
98             }
99 68         243 return ($bond, \@r);
100             }
101              
102             sub iterator {
103 7     7 0 10 my ($period, $guess) = @_;
104              
105             ## try the first guess
106             ## uses a binary search to find the correct rates
107 7         8 my $diff = 1; ## for starters
108 7         15 my ($low, $high) = ($guess / 2, $guess * 2);
109 7         5 my ($bond, $r); ## the calculated bond price, and the respective rates
110              
111 7         14 while (abs($diff) > $epsilon) {
112             ## till we reach a certain limit ...
113              
114 78 100       170 ($bond, $r) = $period == 1 ? bond($period + 1, $guess, $vol) : bond2($period + 1, $guess, $vol);
115 78         132 $diff = $bond - $P[0][$period + 1];
116 78 50       122 print "[$high, $low, $guess, $bond] " if $DEBUG;
117              
118 78 100       115 if ($diff < 0) {
119 40         38 $high = $guess;
120             }
121             else {
122 38         43 $low = $guess;
123             }
124 78         144 $guess = ($low + $high) / 2;
125              
126              
127             }
128              
129 7 50       13 print "\nSuccess: P:$period, B:$bond, B:$P[0][$period + 1], R:@$r\n" if $DEBUG;
130              
131 7         18 return $r;
132             }
133              
134              
135             1;
136             __END__