File Coverage

blib/lib/Math/Business/Stochastic.pm
Criterion Covered Total %
statement 108 125 86.4
branch 19 38 50.0
condition 2 3 66.6
subroutine 13 14 92.8
pod 0 9 0.0
total 142 189 75.1


line stmt bran cond sub pod time code
1             package Math::Business::Stochastic;
2              
3 1     1   859 use strict;
  1         2  
  1         35  
4 1     1   6 use warnings;
  1         2  
  1         29  
5 1     1   967 use diagnostics;
  1         186619  
  1         13  
6              
7             our $VERSION = '0.03';
8              
9 1     1   504 use Carp;
  1         2  
  1         96  
10 1     1   5 use List::Util qw(max min sum);
  1         2  
  1         1143  
11              
12             1;
13              
14             sub new {
15 1     1 0 421 bless {
16             val => [],
17             days => 0,
18             };
19             }
20              
21             sub set_days {
22 1     1 0 2 my $this = shift;
23 1         1 my ($k,$d,$sd) = @_;
24              
25 1 50       5 croak "k must be a positive non-zero integers" if int($k) <= 0;
26 1 50       4 croak "d must be a positive non-zero integers" if int($d) <= 0;
27 1 50       3 croak "sd must be a positive non-zero integers" if int($sd) <= 0;
28              
29 1         3 $this->{k} = int($k);
30 1         1 $this->{d} = int($d);
31 1         3 $this->{sd} = int($sd);
32 1         3 $this->{days} = int($k) + int($d) + int($sd) - 2;
33             }
34              
35 23     23 0 282 sub query_k { my $this = shift; return $this->{cur_k}; }
  23         112  
36 23     23 0 7722 sub query_d { my $this = shift; return $this->{cur_d}; }
  23         102  
37 23     23 0 7175 sub query_sd { my $this = shift; return $this->{cur_sd}; }
  23         106  
38              
39             sub insert {
40 22     22 0 6607 my $this = shift;
41 22         40 my ($high,$low,$close) = @_;
42              
43 22 50       61 croak "You must set the number of days before you try to insert" if not $this->{days};
44 22 50       42 croak "You must specify the high,low,close values" unless defined $close;
45 22 50       55 croak "High value must be higher than low value" unless $high >= $low;
46 22 50       47 croak "Low value must be lower than close value" unless $low <= $close;
47 22 50       43 croak "High value must be higher than close value" unless $high >= $close;
48              
49 22         23 push @{ $this->{val_high} }, $high;
  22         53  
50 22         27 push @{ $this->{val_low} }, $low;
  22         44  
51 22         27 push @{ $this->{val} }, $close;
  22         39  
52              
53 22         47 $this->recalc;
54             }
55              
56             sub start_with {
57 0     0 0 0 my $this = shift;
58 0         0 $this->{val_high} = shift;
59 0         0 $this->{val_low} = shift;
60 0         0 $this->{val} = shift;
61              
62 0 0       0 croak "bad arg to start_with" unless ref($this->{val_high}) eq "ARRAY";
63 0 0       0 croak "bad arg to start_with" unless ref($this->{val_low}) eq "ARRAY";
64 0 0       0 croak "bad arg to start_with" unless ref($this->{val}) eq "ARRAY";
65 0 0       0 croak "bad arg to start_with" unless @{$this->{val_high}} == @{$this->{val}};
  0         0  
  0         0  
66 0 0       0 croak "bad arg to start_with" unless @{$this->{val_low}} == @{$this->{val}};
  0         0  
  0         0  
67              
68 0         0 $this->recalc;
69             }
70              
71             sub recalc {
72 22     22 0 28 my $this = shift;
73              
74 22         24 shift @{ $this->{val_high} } while @{ $this->{val_high} } > $this->{days};
  35         92  
  13         30  
75 22         27 shift @{ $this->{val_low} } while @{ $this->{val_low} } > $this->{days};
  35         92  
  13         26  
76 22         25 shift @{ $this->{val} } while @{ $this->{val} } > $this->{days};
  35         86  
  13         27  
77              
78 22 100       27 if( $this->{k} <= @{ $this->{val} } ) {
  22         55  
79 18         19 push @{ $this->{val_max} }, max( picklast($this->{k},@{$this->{val_high}}) );
  18         37  
  18         46  
80 18         28 push @{ $this->{val_min} }, min( picklast($this->{k},@{$this->{val_low}}) );
  18         35  
  18         42  
81 18         26 push @{ $this->{val_close_minus_min} }, $this->{val}->[-1] - $this->{val_min}->[-1];
  18         47  
82 18         22 push @{ $this->{val_max_minus_min} }, $this->{val_max}->[-1] - $this->{val_min}->[-1];
  18         40  
83 18         20 shift @{ $this->{val_max} } while @{ $this->{val_max} } > $this->{k};
  31         82  
  13         23  
84 18         18 shift @{ $this->{val_min} } while @{ $this->{val_min} } > $this->{k};
  31         71  
  13         26  
85 18         19 shift @{ $this->{val_close_minus_min} } while @{ $this->{val_close_minus_min} } > $this->{k};
  31         72  
  13         25  
86 18         19 shift @{ $this->{val_max_minus_min} } while @{ $this->{val_max_minus_min} } > $this->{k};
  31         74  
  13         19  
87             }
88 22 100       41 if( $this->{k}+$this->{d}-1 <= @{ $this->{val} } ) {
  22         51  
89 16         19 push @{ $this->{val_d} }, sum(picklast($this->{d},@{$this->{val_close_minus_min}})) / sum(picklast($this->{d},@{$this->{val_max_minus_min}})) * 100;
  16         31  
  16         33  
  16         36  
90 16         27 shift @{ $this->{val_d} } while @{ $this->{val_d} } > $this->{sd};
  29         75  
  13         25  
91             }
92              
93 22 50 66     109 if( not defined $this->{val_max_minus_min}->[-1] or $this->{val_max_minus_min}->[-1] > 0 ) {
94 22 100       25 if( @{ $this->{val} } == $this->{days} ) {
  22 100       53  
  8 100       45  
95 14         42 $this->{cur_k} = ($this->{val}->[-1] - $this->{val_min}->[-1]) / ($this->{val_max_minus_min}->[-1]) * 100;
96 14         20 $this->{cur_d} = $this->{val_d}->[-1];
97 14         22 $this->{cur_sd} = sum(picklast($this->{sd},@{$this->{val_d}})) / $this->{sd};
  14         34  
98             }
99 6         19 elsif( @{ $this->{val} } >= $this->{days} - $this->{sd} + 1 ) {
100 2         7 $this->{cur_k} = ($this->{val}->[-1] - $this->{val_min}->[-1]) / ($this->{val_max_minus_min}->[-1]) * 100;
101 2         6 $this->{cur_d} = $this->{val_d}->[-1];
102 2         7 $this->{cur_sd} = undef;
103             }
104             elsif( @{ $this->{val} } >= $this->{days} - $this->{sd} - $this->{d} + 2 ) {
105 2         8 $this->{cur_k} = ($this->{val}->[-1] - $this->{val_min}->[-1]) / ($this->{val_max_minus_min}->[-1]) * 100;
106 2         3 $this->{cur_d} = undef;
107 2         6 $this->{cur_sd} = undef;
108             }
109             else {
110 4         6 $this->{cur_k} = undef;
111 4         7 $this->{cur_d} = undef;
112 4         11 $this->{cur_sd} = undef;
113             }
114             }
115             else {
116 0         0 $this->{cur_k} = undef;
117 0         0 $this->{cur_d} = undef;
118 0         0 $this->{cur_sd} = undef;
119             }
120             }
121              
122             sub picklast {
123 82     82 0 103 my $n = int(shift);
124 82         332 return splice @_,-$n;
125             }
126              
127             __END__