File Coverage

blib/lib/Math/Business/RSI.pm
Criterion Covered Total %
statement 82 83 98.8
branch 20 28 71.4
condition n/a
subroutine 14 15 93.3
pod 0 10 0.0
total 116 136 85.2


line stmt bran cond sub pod time code
1             package Math::Business::RSI;
2              
3 3     3   13552 use strict;
  3         9  
  3         128  
4 3     3   15 use warnings;
  3         5  
  3         159  
5 3     3   17 use Carp;
  3         6  
  3         246  
6              
7 3     3   1645 use Math::Business::SMA;
  3         9  
  3         125  
8 3     3   1074 use Math::Business::EMA;
  3         14  
  3         3561  
9              
10             1;
11              
12 0     0 0 0 sub tag { (shift)->{tag} }
13              
14             sub recommended {
15 1     1 0 5 my $class = shift;
16              
17 1         4 $class->new(14);
18             }
19              
20             sub new {
21 5     5 0 385470 my $class = shift;
22 5         33 my $this = bless {
23             U => Math::Business::EMA->new,
24             D => Math::Business::EMA->new,
25             RSI => undef,
26             cy => undef,
27             }, $class;
28              
29 5         12 my $alpha = shift;
30 5 100       16 if( defined $alpha ) {
31 4         13 $this->set_alpha( $alpha );
32             }
33              
34 5         24 return $this;
35             }
36              
37             sub set_alpha {
38 4     4 0 8 my $this = shift;
39 4         8 my $alpha = shift;
40              
41             # NOTE: this alpha is different than you might think ... it's really inverse alpha
42             # Wilder uses alpha=14 instead of alpha=(1/14) like you might expect
43              
44 4         11 my $days = 2*$alpha - 1; # so days is 2*$alpha-1 instead of the expected 2*(1/$alpha)-1
45              
46 4         29 eval { $this->set_days( $days ) };
  4         22  
47 4 50       10 croak "set_alpha() is basically set_days(2*$alpha-1), which complained: $@" if $@;
48 4         34 $this->set_tag;
49             }
50              
51             sub set_standard {
52 1     1 0 16 my $this = shift;
53 1         4 my $rm = ref $this->{U};
54              
55 1 50       6 if( $rm =~ m/SMA/ ) {
56 1         19 $this->{U} = Math::Business::EMA->new;
57 1         4 $this->{D} = Math::Business::EMA->new;
58              
59 1 50       23 if( my $d = $this->{days} ) {
60 1         3 $this->set_days($d);
61             }
62             }
63 1         4 $this->set_tag;
64             }
65              
66             sub set_cutler {
67 1     1 0 6 my $this = shift;
68 1         2 my $rm = ref $this->{U};
69              
70 1 50       6 if( $rm =~ m/EMA/ ) {
71 1         9 $this->{U} = Math::Business::SMA->new;
72 1         4 $this->{D} = Math::Business::SMA->new;
73              
74 1 50       5 if( my $d = $this->{days} ) {
75 1         3 $this->set_days($d);
76             }
77             }
78 1         4 $this->set_tag;
79             }
80              
81             sub set_days {
82 7     7 0 18 my $this = shift;
83 7         15 my $arg = int(shift);
84              
85 7 50       26 croak "days must be a positive non-zero integer" if $arg <= 0;
86              
87 7         45 $this->{U}->set_days($this->{days} = $arg);
88 7         26 $this->{D}->set_days($arg);
89 7         15 delete $this->{cy};
90 7         11 delete $this->{RSI};
91 7         25 $this->set_tag;
92             }
93              
94             sub set_tag {
95 13     13 0 22 my $this = shift;
96              
97 13 100       92 if( $this->{U}->isa("Math::Business::EMA") ) {
98 11         36 $this->{tag} = "RSI($this->{days})";
99              
100             } else {
101 2         6 $this->{tag} = "RSI($this->{days},cutler)";
102             }
103             }
104              
105             sub insert {
106 2527     2527 0 4943 my $this = shift;
107 2527         4560 my $close_yesterday = $this->{cy};
108              
109 2527         4313 my $EMA_U = $this->{U};
110 2527         4378 my $EMA_D = $this->{D};
111              
112 2527 50       5661 croak "You must set the number of days before you try to insert" if not $this->{days};
113 2527         5755 while( defined( my $close_today = shift ) ) {
114 3277 100       6524 if( defined $close_yesterday ) {
115 3271         10998 my $delta = $close_today - $close_yesterday;
116              
117 3271         6775 my ($U,$D) = (0,0);
118 3271 100       7321 if( $delta > 0 ) {
    100          
119 1619         2580 $U = $delta;
120 1619         2392 $D = 0;
121              
122             } elsif( $delta < 0 ) {
123 1635         2390 $U = 0;
124 1635         2552 $D = abs $delta;
125             }
126              
127 3271         8997 $EMA_U->insert($U);
128 3271         7165 $EMA_D->insert($D);
129             }
130              
131 3277 100       7120 if( defined(my $eu = $EMA_U->query) ) {
132 3187         6624 my $ed = $EMA_D->query;
133 3187 50       7196 my $rs = (($ed == 0) ? 100 : $eu/$ed ); # NOTE: This is by definition apparently.
134              
135 3187         6643 $this->{RSI} = 100 - 100/(1+$rs);
136             }
137              
138 3277         10442 $close_yesterday = $close_today;
139             }
140              
141 2527         6050 $this->{cy} = $close_yesterday;
142             }
143              
144             sub query {
145 2528     2528 0 4094 my $this = shift;
146              
147 2528         6082 return $this->{RSI};
148             }
149              
150             __END__