File Coverage

blib/lib/Math/Business/DMI.pm
Criterion Covered Total %
statement 88 96 91.6
branch 21 26 80.7
condition 9 12 75.0
subroutine 9 12 75.0
pod 0 8 0.0
total 127 154 82.4


line stmt bran cond sub pod time code
1             package Math::Business::DMI;
2              
3 3     3   6679 use strict;
  3         14  
  3         56  
4 3     3   9 use warnings;
  3         4  
  3         68  
5 3     3   10 use Carp;
  3         3  
  3         131  
6              
7 3     3   885 use Math::Business::ATR;
  3         6  
  3         1691  
8              
9             1;
10              
11 0     0 0 0 sub tag { (shift)->{tag} }
12              
13             sub recommended {
14 4     4 0 508 my $class = shift;
15              
16 4         32 $class->new(14);
17             }
18              
19             sub new {
20 4     4 0 8 my $class = shift;
21 4         21 my $this = bless {
22             ATR => new Math::Business::ATR,
23             }, $class;
24              
25 4         8 my $days = shift;
26 4 50       12 if( defined $days ) {
27 4         17 $this->set_days( $days );
28             }
29              
30 4         21 return $this;
31             }
32              
33             sub set_days {
34 4     4 0 7 my $this = shift;
35 4         9 my $arg = int(shift);
36              
37 4 50       39 croak "days must be a positive non-zero integer" if $arg <= 0;
38              
39 4         25 $this->{ATR}->set_days($arg);
40 4         7 $this->{days} = $arg;
41 4         10 $this->{R} = ($arg-1)/$arg;
42 4         9 $this->{R1} = 1/$arg;
43              
44 4         13 $this->{tag} = "DMI($this->{days})";
45             }
46              
47             sub insert {
48 1109     1109 0 41357 my $this = shift;
49              
50 1109         1232 my $y_point = $this->{y};
51 1109         1754 while( defined( my $point = shift ) ) {
52 1112 50 33     2870 croak "insert takes three tuple (high, low, close)" unless ref $point eq "ARRAY" and @$point == 3;
53 1112         1547 my ($t_high, $t_low, $t_close) = @$point;
54              
55 1112 100       1328 if( defined $y_point ) {
56 1108         1107 my $atr = $this->{ATR};
57 1108         1860 $atr->insert($point);
58              
59 1108         1248 my ($y_high, $y_low, $y_close) = @$y_point;
60              
61 1108         1143 my ($PDM, $MDM) = (0,0);
62 1108         1062 my $A = $t_high - $y_high;
63 1108         1058 my $B = $y_low - $t_low;
64              
65 1108 100 100     2400 if( $A > 0 and $A > $B ) {
    100 66        
66 468         428 $PDM = $A;
67 468         445 $MDM = 0;
68              
69             } elsif( $B > 0 and $B > $A ) {
70 412         377 $PDM = 0;
71 412         357 $MDM = $B;
72             }
73              
74 1108 100       1305 if( defined(my $pdm = $this->{aPDM}) ) {
75 1063         955 my $mdm = $this->{aMDM};
76              
77 1063         949 my $R = $this->{R};
78 1063         921 my $R1 = $this->{R1};
79              
80 1063         1233 my $aPDM = $this->{aPDM} = $R * $pdm + $R1 * $PDM;
81 1063         1186 my $aMDM = $this->{aMDM} = $R * $mdm + $R1 * $MDM;
82              
83 1063         1496 my $ATR = $atr->query;
84              
85 1063 50       1303 if( $ATR == 0 ) {
86 0         0 my $DX = $this->{PDI} = $this->{MDI} = 0;
87 0         0 $this->{ADX} = $R * $this->{ADX} + $R1 * $DX;
88              
89             } else {
90 1063         1122 my $PDI = $this->{PDI} = $aPDM / $ATR;
91 1063         1028 my $MDI = $this->{MDI} = $aMDM / $ATR;
92              
93 1063         1028 my $DI = abs( $PDI - $MDI );
94 1063 100       1224 my $DX = $DI ? $DI / ($PDI + $MDI) : 0;
95             # 0/0 is indeterminent form, but I think 0 makes sense
96              
97 1063         1424 $this->{ADX} = $R * $this->{ADX} + $R1 * $DX;
98             }
99              
100             } else {
101 45         47 my $p;
102 45         61 my $N = $this->{days};
103 45 100 100     116 if( ref($p = $this->{_p}) and (@$p >= $N-1) ) {
104 3         5 my $psum = 0;
105 3         12 $psum += $_ for @$p;
106 3         3 $psum += $PDM;
107              
108 3         5 my $m = $this->{_m};
109 3         3 my $msum = 0;
110 3         11 $msum += $_ for @$m;
111 3         11 $msum += $MDM;
112              
113 3         13 my $aPDM = $this->{aPDM} = $psum / $N;
114 3         14 my $aMDM = $this->{aMDM} = $msum / $N;
115              
116 3         9 my $ATR = $atr->query;
117 3 50       12 if( $ATR == 0 ) {
118 0         0 $this->{PDI} = $this->{MDI} = $this->{ADX} = 0;
119              
120             } else {
121 3         9 my $PDI = $this->{PDI} = $aPDM / $ATR;
122 3         5 my $MDI = $this->{MDI} = $aMDM / $ATR;
123              
124 3         6 my $DI = abs( $PDI - $MDI );
125 3 100       10 my $DX = $DI ? $DI / ($PDI + $MDI) : 0;
126             # 0/0 is indeterminent form, but I think 0 makes sense
127              
128 3         5 $this->{ADX} = $DX; # is this right? No idea... I assume this is well documented in his book
129             }
130              
131 3         5 delete $this->{_p};
132 3         7 delete $this->{_m};
133              
134             } else {
135 42         45 push @{$this->{_p}}, $PDM;
  42         84  
136 42         49 push @{$this->{_m}}, $MDM;
  42         69  
137             }
138             }
139             }
140              
141 1112         1696 $y_point = $point;
142             }
143              
144 1109         1323 $this->{y} = $y_point;
145             }
146              
147 0     0 0 0 sub query_pdi { my $this = shift; return $this->{PDI}; }
  0         0  
148 0     0 0 0 sub query_mdi { my $this = shift; return $this->{MDI}; }
  0         0  
149              
150             sub query {
151 2017     2017 0 3564 my $this = shift;
152              
153 2017 100       3483 return ($this->{PDI}, $this->{MDI}, $this->{ADX}) if wantarray;
154 1009         1185 return $this->{ADX};
155             }
156              
157             __END__