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   4071 use strict;
  4         12  
  4         91  
4 4     4   16 use warnings;
  4         7  
  4         74  
5 4     4   16 use Carp;
  4         5  
  4         1943  
6              
7             1;
8              
9 0     0 0 0 sub tag { (shift)->{tag} }
10              
11             sub recommended {
12 1     1 0 351 my $class = shift;
13              
14 1         4 $class->new(14);
15             }
16              
17             sub new {
18 5     5 0 9 my $class = shift;
19 5         12 my $this = bless {
20             }, $class;
21              
22 5         8 my $days = shift;
23 5 100       17 if( defined $days ) {
24 1         3 $this->set_days( $days );
25             }
26              
27 5         17 return $this;
28             }
29              
30             sub set_days {
31 5     5 0 10 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         24 $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         12 $this->{days} = $arg;
42 5         15 $this->{R1} = ($arg-1)/$arg;
43 5         25 $this->{R} = 1/$arg;
44             }
45              
46             sub insert {
47 1124     1124 0 1834 my $this = shift;
48              
49 1124         1288 my $y_close = $this->{y_close};
50 1124         1802 while( defined( my $point = shift ) ) {
51 1124 50 33     2889 croak "insert takes three tuple [high, low, close]" unless ref $point eq "ARRAY" and @$point == 3;
52 1124         1643 my ($t_high, $t_low, $t_close) = @$point;
53              
54 1124 100       1576 if( defined $y_close ) {
55 1119         1785 my $A = abs( $t_high - $t_low );
56 1119         1382 my $B = abs( $t_high - $y_close );
57 1119         1301 my $C = abs( $t_low - $y_close );
58              
59 1119         1304 my $true_range = $A;
60 1119 100       2084 $true_range = $B if $B > $true_range;
61 1119 100       1675 $true_range = $C if $C > $true_range;
62              
63 1119 100       1753 if( defined(my $atr = $this->{ATR}) ) {
64 1065         1856 $this->{ATR} = $this->{R1} * $atr + $this->{R} * $true_range;
65              
66             } else {
67 54         60 my $p;
68 54         63 my $N = $this->{days};
69 54 100 66     147 if( ref($p = $this->{_p}) and (@$p >= $N-1) ) {
70 4         8 my $sum = 0;
71 4         19 $sum += $_ for @$p;
72 4         5 $sum += $true_range;
73              
74 4         12 $this->{ATR} = $sum / $N;
75 4         10 delete $this->{_p};
76              
77             } else {
78 50         56 push @{$this->{_p}}, $true_range;
  50         109  
79             }
80             }
81              
82             } else {
83 5         11 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       13 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         12 $this->{_p} = [$true_range];
94             }
95              
96 1124         2108 $y_close = $t_close;
97             }
98              
99 1124         1693 $this->{y_close} = $y_close;
100             }
101              
102             sub query {
103 1085     1085 0 1375 my $this = shift;
104              
105 1085         1854 return $this->{ATR};
106             }
107              
108             __END__