File Coverage

blib/lib/Performance/Probability.pm
Criterion Covered Total %
statement 100 115 86.9
branch 10 18 55.5
condition 2 6 33.3
subroutine 14 14 100.0
pod 1 1 100.0
total 127 154 82.4


line stmt bran cond sub pod time code
1             package Performance::Probability;
2              
3 2     2   127845 use 5.010;
  2         5  
4 2     2   7 use strict;
  2         2  
  2         30  
5 2     2   4 use warnings;
  2         5  
  2         37  
6              
7 2     2   693 use Math::BivariateCDF;
  2         772  
  2         68  
8 2     2   718 use Math::Gauss::XS;
  2         651  
  2         69  
9 2     2   684 use Machine::Epsilon;
  2         469  
  2         73  
10              
11 2     2   7 use Exporter;
  2         2  
  2         1575  
12              
13             our @ISA = qw(Exporter);
14              
15             our @EXPORT_OK = qw(get_performance_probability);
16              
17             our $VERSION = '0.04';
18              
19             =head1 NAME
20              
21             Performance::Probability - The performance probability is a likelihood measure of a client reaching his/her current profit and loss.
22              
23             =head1 VERSION
24              
25             0.04
26              
27             =head1 SYNOPSYS
28              
29             use Performance::Probability qw(get_performance_probability);
30              
31             my $probability = Performance::Probability::get_performance_probability(
32             types => [qw/CALL PUT/],
33             payout => [100, 100],
34             bought_price => [75, 55],
35             pnl => 1000.0,
36             underlying => [qw/EURUSD EURUSD/],
37             start_time => [1461847439, 1461930839], #time in epoch
38             sell_time => [1461924960, 1461931561], #time in epoch
39             );
40              
41             =head1 DESCRIPTION
42              
43             The performance probability is a likelihood measure of a client reaching his/her current profit and loss.
44              
45             =cut
46              
47             #Profit in case of winning. ( Payout minus bought price ).
48             sub _build_wk {
49              
50 1     1   2 my $bought_price = shift;
51 1         11 my $payout = shift;
52              
53 1         2 my @w_k;
54              
55             my $i;
56              
57 1         1 for ($i = 0; $i < @{$payout}; ++$i) {
  101         107  
58 100         64 my $tmp_w_k = $payout->[$i] - $bought_price->[$i];
59 100         64 push @w_k, $tmp_w_k;
60             }
61              
62 1         2 return \@w_k;
63             }
64              
65             #Loss in case of losing. (Minus bought price).
66             sub _build_lk {
67              
68 1     1   1 my $bought_price = shift;
69 1         1 my @l_k;
70              
71             my $i;
72              
73 1         2 for ($i = 0; $i < @{$bought_price}; ++$i) {
  101         116  
74 100         68 push @l_k, 0 - $bought_price->[$i];
75             }
76              
77 1         1 return \@l_k;
78             }
79              
80             #Winning probability. ( Bought price / Payout ).
81             sub _build_pk {
82              
83 1     1   1 my $bought_price = shift;
84 1         2 my $payout = shift;
85              
86 1         1 my @p_k;
87              
88             my $i;
89              
90 1         2 for ($i = 0; $i < @{$bought_price}; ++$i) {
  101         113  
91 100         89 my $tmp_pk = $bought_price->[$i] / $payout->[$i];
92 100         75 push @p_k, $tmp_pk;
93             }
94              
95 1         2 return \@p_k;
96             }
97              
98             #Sigma( profit * winning probability + loss * losing probability ).
99             sub _mean {
100              
101 1     1   0 my $pk = shift;
102 1         2 my $lk = shift;
103 1         0 my $wk = shift;
104              
105 1         1 my $i;
106 1         2 my $sum = 0;
107              
108 1         3 for ($i = 0; $i < @{$wk}; ++$i) {
  101         110  
109 100         105 $sum = $sum + ($wk->[$i] * $pk->[$i]) + ($lk->[$i] * (1 - $pk->[$i]));
110             }
111              
112 1         4 return $sum;
113             }
114              
115             #Sigma( (profit**2) * winning probability + (loss**2) * losing probability ).
116             sub _variance_x_square {
117              
118 1     1   1 my $pk = shift;
119 1         1 my $lk = shift;
120 1         1 my $wk = shift;
121              
122 1         1 my $sum = 0;
123 1         1 my $i;
124              
125 1         4 for ($i = 0; $i < @{$wk}; ++$i) {
  101         111  
126 100         104 $sum = $sum + (($wk->[$i]**2) * $pk->[$i]) + (($lk->[$i]**2) * (1 - $pk->[$i]));
127             }
128              
129 1         2 return $sum;
130             }
131              
132             #Sum of Covariance(i,j). See the documentation for the details.
133             #Covariance(i, j) is the covariance between contract i and j with time overlap.
134             sub _covariance {
135              
136 1     1   1 my ($start_time, $sell_time, $underlying, $types, $pk, $lk, $wk) = @_;
137              
138 1         1 my ($i, $j);
139 1         1 my $covariance = 0;
140              
141 1         2 for ($i = 0; $i < @{$start_time}; ++$i) {
  101         115  
142 100         67 for ($j = 0; $j < @{$sell_time}; ++$j) {
  10100         10940  
143 10000 100 66     22495 if ($i != $j and $underlying->[$i] eq $underlying->[$j]) {
144              
145             #check for time overlap.
146 9900 100       9682 my $min_end_time = $sell_time->[$i] < $sell_time->[$j] ? $sell_time->[$i] : $sell_time->[$j];
147 9900 100       8924 my $max_start_time = $start_time->[$i] > $start_time->[$j] ? $start_time->[$i] : $start_time->[$j];
148 9900         5766 my $b_interval = $min_end_time - $max_start_time;
149              
150 9900 50       11855 if ($b_interval > 0) {
151              
152             #calculate first and second contracts durations. please see the documentation for details
153              
154 0         0 my $first_contract_duration = ($sell_time->[$i] - $start_time->[$i]);
155 0         0 my $second_contract_duration = ($sell_time->[$j] - $start_time->[$j]);
156              
157 0         0 my $i_strike = 0.0 - Math::Gauss::XS::inv_cdf($pk->[$i]);
158 0         0 my $j_strike = 0.0 - Math::Gauss::XS::inv_cdf($pk->[$j]);
159              
160 0         0 my $corr_ij = $b_interval / (sqrt($first_contract_duration) * sqrt($second_contract_duration));
161              
162 0 0       0 if ($types->[$i] ne $types->[$j]) {
163 0         0 $corr_ij = -1 * $corr_ij;
164             }
165              
166 0 0 0     0 if ($corr_ij < -1 or $corr_ij > 1) {
167 0         0 next;
168             }
169              
170 0         0 my $p_ij = Math::BivariateCDF::bivnor($i_strike, $j_strike, $corr_ij);
171              
172 0         0 my $covariance_ij =
173             ($p_ij - $pk->[$i] * $pk->[$j]) * ($wk->[$i] - $lk->[$i]) * ($wk->[$j] - $lk->[$j]);
174              
175 0         0 $covariance = $covariance + $covariance_ij;
176             }
177             }
178             }
179             }
180              
181 1         6 return $covariance;
182             }
183              
184             =head2 get_performance_probability
185              
186             Calculate performance probability ( modified sharpe ratio )
187              
188             =cut
189              
190             sub get_performance_probability {
191              
192 1     1 1 1253 my $params = shift;
193              
194 1         2 my $pnl = $params->{pnl};
195              
196 1 50       3 if (not defined $pnl) {
197 0         0 die "pnl is a required parameter.";
198             }
199              
200             #Below variables are all arrays.
201 1         2 my $start_time = $params->{start_time};
202 1         1 my $sell_time = $params->{sell_time};
203 1         1 my $types = $params->{types};
204 1         1 my $underlying = $params->{underlying};
205 1         1 my $bought_price = $params->{bought_price};
206 1         1 my $payout = $params->{payout};
207              
208 1 50       2 if (grep { $_ != scalar(@$start_time) } (scalar(@$sell_time), scalar(@$types), scalar(@$underlying), scalar(@$bought_price), scalar(@$payout))) {
  5         8  
209 0         0 die "start_time, sell_time, types, underlying, bought_price and payout are required parameters and need to be arrays of same lengths.";
210             }
211              
212 1         1 my $i = 0;
213 1         1 for ($i = 0; $i < @{$start_time}; ++$i) {
  101         118  
214 100 50       137 if ($sell_time->[$i] - $start_time->[$i] == 0) {
215 0         0 die "Contract duration ( sell_time minus start_time ) cannot be zero.";
216             }
217             }
218              
219 1         2 my $pk = _build_pk($bought_price, $payout);
220 1         2 my $lk = _build_lk($bought_price);
221 1         2 my $wk = _build_wk($bought_price, $payout);
222              
223 1         2 my $mean = _mean($pk, $lk, $wk);
224              
225 1         2 my $variance = _variance_x_square($pk, $lk, $wk);
226              
227 1         2 my $covariance = _covariance($start_time, $sell_time, $underlying, $types, $pk, $lk, $wk);
228              
229             #Calculate the performance probability here.
230 1         2 my $prob = 0;
231              
232 1         11 my $epsilon = machine_epsilon();
233              
234 1         89 $prob = $pnl - $mean;
235 1         4 $prob = $prob / (sqrt(($variance - ($mean**2.0)) + 2.0 * $covariance) + $epsilon);
236              
237 1         13 $prob = 1.0 - Math::Gauss::XS::cdf($prob, 0.0, 1.0);
238              
239 1         24 return $prob;
240             }
241              
242             1;