File Coverage

blib/lib/Math/Business/ATR.pm
Criterion Covered Total %
statement 55 56 98.2
branch 15 18 83.3
condition 3 6 50.0
subroutine 8 9 88.8
pod 0 6 0.0
total 81 95 85.2


line stmt bran cond sub pod time code
1             package Math::Business::ATR;
2              
3 4     4   3515 use strict;
  4         9  
  4         75  
4 4     4   12 use warnings;
  4         5  
  4         59  
5 4     4   12 use Carp;
  4         4  
  4         1519  
6              
7             1;
8              
9 0     0 0 0 sub tag { (shift)->{tag} }
10              
11             sub recommended {
12 1     1 0 305 my $class = shift;
13              
14 1         2 $class->new(14);
15             }
16              
17             sub new {
18 5     5 0 7 my $class = shift;
19 5         11 my $this = bless {
20             }, $class;
21              
22 5         13 my $days = shift;
23 5 100       14 if( defined $days ) {
24 1         2 $this->set_days( $days );
25             }
26              
27 5         17 return $this;
28             }
29              
30             sub set_days {
31 5     5 0 9 my $this = shift;
32 5         8 my $arg = int(shift);
33              
34 5 50       14 croak "days must be a positive non-zero integer" if $arg <= 0;
35              
36 5         22 $this->{tag} = "ATR($arg)";
37              
38             # NOTE: wilder uses 13/14 * last + 1/14 * current for his exponential average ...
39             # probably wouldn't have been my first choice, but that's how ATR is defined.
40              
41 5         13 $this->{days} = $arg;
42 5         17 $this->{R1} = ($arg-1)/$arg;
43 5         27 $this->{R} = 1/$arg;
44             }
45              
46             sub insert {
47 1124     1124 0 1518 my $this = shift;
48              
49 1124         1043 my $y_close = $this->{y_close};
50 1124         1376 while( defined( my $point = shift ) ) {
51 1124 50 33     2241 croak "insert takes three tuple [high, low, close]" unless ref $point eq "ARRAY" and @$point == 3;
52 1124         1245 my ($t_high, $t_low, $t_close) = @$point;
53              
54 1124 100       1266 if( defined $y_close ) {
55 1119         1396 my $A = abs( $t_high - $t_low );
56 1119         1071 my $B = abs( $t_high - $y_close );
57 1119         1034 my $C = abs( $t_low - $y_close );
58              
59 1119         1012 my $true_range = $A;
60 1119 100       1338 $true_range = $B if $B > $true_range;
61 1119 100       1641 $true_range = $C if $C > $true_range;
62              
63 1119 100       1462 if( defined(my $atr = $this->{ATR}) ) {
64 1065         1444 $this->{ATR} = $this->{R1} * $atr + $this->{R} * $true_range;
65              
66             } else {
67 54         58 my $p;
68 54         61 my $N = $this->{days};
69 54 100 66     139 if( ref($p = $this->{_p}) and (@$p >= $N-1) ) {
70 4         7 my $sum = 0;
71 4         17 $sum += $_ for @$p;
72 4         6 $sum += $true_range;
73              
74 4         9 $this->{ATR} = $sum / $N;
75 4         9 delete $this->{_p};
76              
77             } else {
78 50         44 push @{$this->{_p}}, $true_range;
  50         115  
79             }
80             }
81              
82             } else {
83 5         10 my $true_range = $t_high - $t_low;
84              
85             # NOTE: _p shouldn't exist because this initializer is only used for the very first entry
86 5 50       25 die "something is clearly wrong, see note below above line" if exists $this->{_p};
87              
88             # NOTE: this initializer sucks because the calculation is done
89             # differently than it would be if you had data from the day before.
90             # IMO, we should just return undef for an extra day, but this
91             # appears to be by definition, so we do it:
92              
93 5         14 $this->{_p} = [$true_range];
94             }
95              
96 1124         1674 $y_close = $t_close;
97             }
98              
99 1124         1325 $this->{y_close} = $y_close;
100             }
101              
102             sub query {
103 1085     1085 0 1059 my $this = shift;
104              
105 1085         1390 return $this->{ATR};
106             }
107              
108             __END__