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   5246 use strict;
  4         5  
  4         134  
4 4     4   20 use warnings;
  4         8  
  4         105  
5 4     4   17 use Carp;
  4         8  
  4         2684  
6              
7             1;
8              
9 0     0 0 0 sub tag { (shift)->{tag} }
10              
11             sub recommended {
12 1     1 0 530 my $class = shift;
13              
14 1         4 $class->new(14);
15             }
16              
17             sub new {
18 5     5 0 11 my $class = shift;
19 5         17 my $this = bless {
20             }, $class;
21              
22 5         8 my $days = shift;
23 5 100       20 if( defined $days ) {
24 1         4 $this->set_days( $days );
25             }
26              
27 5         21 return $this;
28             }
29              
30             sub set_days {
31 5     5 0 8 my $this = shift;
32 5         10 my $arg = int(shift);
33              
34 5 50       37 croak "days must be a positive non-zero integer" if $arg <= 0;
35              
36 5         32 $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         37 $this->{days} = $arg;
42 5         15 $this->{R1} = ($arg-1)/$arg;
43 5         17 $this->{R} = 1/$arg;
44             }
45              
46             sub insert {
47 1124     1124 0 1713 my $this = shift;
48              
49 1124         1618 my $y_close = $this->{y_close};
50 1124         2592 while( defined( my $point = shift ) ) {
51 1124 50 33     4972 croak "insert takes three tuple [high, low, close]" unless ref $point eq "ARRAY" and @$point == 3;
52 1124         1547 my ($t_high, $t_low, $t_close) = @$point;
53              
54 1124 100       2087 if( defined $y_close ) {
55 1119         1928 my $A = abs( $t_high - $t_low );
56 1119         1350 my $B = abs( $t_high - $y_close );
57 1119         1488 my $C = abs( $t_low - $y_close );
58              
59 1119         1127 my $true_range = $A;
60 1119 100       2271 $true_range = $B if $B > $true_range;
61 1119 100       1963 $true_range = $C if $C > $true_range;
62              
63 1119 100       2373 if( defined(my $atr = $this->{ATR}) ) {
64 1065         2659 $this->{ATR} = $this->{R1} * $atr + $this->{R} * $true_range;
65              
66             } else {
67 54         67 my $p;
68 54         86 my $N = $this->{days};
69 54 100 66     295 if( ref($p = $this->{_p}) and (@$p >= $N-1) ) {
70 4         9 my $sum = 0;
71 4         29 $sum += $_ for @$p;
72 4         10 $sum += $true_range;
73              
74 4         12 $this->{ATR} = $sum / $N;
75 4         16 delete $this->{_p};
76              
77             } else {
78 50         60 push @{$this->{_p}}, $true_range;
  50         164  
79             }
80             }
81              
82             } else {
83 5         12 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       20 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         19 $this->{_p} = [$true_range];
94             }
95              
96 1124         3311 $y_close = $t_close;
97             }
98              
99 1124         2790 $this->{y_close} = $y_close;
100             }
101              
102             sub query {
103 1085     1085 0 1362 my $this = shift;
104              
105 1085         7375 return $this->{ATR};
106             }
107              
108             __END__