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   8130 use strict;
  3         18  
  3         69  
4 3     3   14 use warnings;
  3         3  
  3         64  
5 3     3   12 use Carp;
  3         5  
  3         141  
6              
7 3     3   1092 use Math::Business::ATR;
  3         6  
  3         2219  
8              
9             1;
10              
11 0     0 0 0 sub tag { (shift)->{tag} }
12              
13             sub recommended {
14 4     4 0 577 my $class = shift;
15              
16 4         71 $class->new(14);
17             }
18              
19             sub new {
20 4     4 0 10 my $class = shift;
21 4         23 my $this = bless {
22             ATR => new Math::Business::ATR,
23             }, $class;
24              
25 4         9 my $days = shift;
26 4 50       10 if( defined $days ) {
27 4         20 $this->set_days( $days );
28             }
29              
30 4         19 return $this;
31             }
32              
33             sub set_days {
34 4     4 0 6 my $this = shift;
35 4         8 my $arg = int(shift);
36              
37 4 50       44 croak "days must be a positive non-zero integer" if $arg <= 0;
38              
39 4         23 $this->{ATR}->set_days($arg);
40 4         8 $this->{days} = $arg;
41 4         9 $this->{R} = ($arg-1)/$arg;
42 4         8 $this->{R1} = 1/$arg;
43              
44 4         11 $this->{tag} = "DMI($this->{days})";
45             }
46              
47             sub insert {
48 1109     1109 0 55972 my $this = shift;
49              
50 1109         1601 my $y_point = $this->{y};
51 1109         2103 while( defined( my $point = shift ) ) {
52 1112 50 33     3613 croak "insert takes three tuple (high, low, close)" unless ref $point eq "ARRAY" and @$point == 3;
53 1112         1856 my ($t_high, $t_low, $t_close) = @$point;
54              
55 1112 100       1805 if( defined $y_point ) {
56 1108         1396 my $atr = $this->{ATR};
57 1108         2431 $atr->insert($point);
58              
59 1108         1551 my ($y_high, $y_low, $y_close) = @$y_point;
60              
61 1108         1382 my ($PDM, $MDM) = (0,0);
62 1108         1326 my $A = $t_high - $y_high;
63 1108         1376 my $B = $y_low - $t_low;
64              
65 1108 100 100     3083 if( $A > 0 and $A > $B ) {
    100 66        
66 468         534 $PDM = $A;
67 468         528 $MDM = 0;
68              
69             } elsif( $B > 0 and $B > $A ) {
70 412         471 $PDM = 0;
71 412         474 $MDM = $B;
72             }
73              
74 1108 100       1670 if( defined(my $pdm = $this->{aPDM}) ) {
75 1063         1191 my $mdm = $this->{aMDM};
76              
77 1063         1176 my $R = $this->{R};
78 1063         1195 my $R1 = $this->{R1};
79              
80 1063         1501 my $aPDM = $this->{aPDM} = $R * $pdm + $R1 * $PDM;
81 1063         1492 my $aMDM = $this->{aMDM} = $R * $mdm + $R1 * $MDM;
82              
83 1063         1845 my $ATR = $atr->query;
84              
85 1063 50       1807 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         1424 my $PDI = $this->{PDI} = $aPDM / $ATR;
91 1063         1296 my $MDI = $this->{MDI} = $aMDM / $ATR;
92              
93 1063         1295 my $DI = abs( $PDI - $MDI );
94 1063 100       1524 my $DX = $DI ? $DI / ($PDI + $MDI) : 0;
95             # 0/0 is indeterminent form, but I think 0 makes sense
96              
97 1063         1830 $this->{ADX} = $R * $this->{ADX} + $R1 * $DX;
98             }
99              
100             } else {
101 45         55 my $p;
102 45         63 my $N = $this->{days};
103 45 100 100     117 if( ref($p = $this->{_p}) and (@$p >= $N-1) ) {
104 3         5 my $psum = 0;
105 3         14 $psum += $_ for @$p;
106 3         4 $psum += $PDM;
107              
108 3         5 my $m = $this->{_m};
109 3         6 my $msum = 0;
110 3         19 $msum += $_ for @$m;
111 3         7 $msum += $MDM;
112              
113 3         15 my $aPDM = $this->{aPDM} = $psum / $N;
114 3         17 my $aMDM = $this->{aMDM} = $msum / $N;
115              
116 3         12 my $ATR = $atr->query;
117 3 50       16 if( $ATR == 0 ) {
118 0         0 $this->{PDI} = $this->{MDI} = $this->{ADX} = 0;
119              
120             } else {
121 3         8 my $PDI = $this->{PDI} = $aPDM / $ATR;
122 3         7 my $MDI = $this->{MDI} = $aMDM / $ATR;
123              
124 3         5 my $DI = abs( $PDI - $MDI );
125 3 100       13 my $DX = $DI ? $DI / ($PDI + $MDI) : 0;
126             # 0/0 is indeterminent form, but I think 0 makes sense
127              
128 3         6 $this->{ADX} = $DX; # is this right? No idea... I assume this is well documented in his book
129             }
130              
131 3         6 delete $this->{_p};
132 3         8 delete $this->{_m};
133              
134             } else {
135 42         46 push @{$this->{_p}}, $PDM;
  42         70  
136 42         47 push @{$this->{_m}}, $MDM;
  42         79  
137             }
138             }
139             }
140              
141 1112         2043 $y_point = $point;
142             }
143              
144 1109         1675 $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 4706 my $this = shift;
152              
153 2017 100       4467 return ($this->{PDI}, $this->{MDI}, $this->{ADX}) if wantarray;
154 1009         1525 return $this->{ADX};
155             }
156              
157             __END__