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   17630 use strict;
  3         8  
  3         103  
4 3     3   18 use warnings;
  3         6  
  3         88  
5 3     3   16 use Carp;
  3         6  
  3         178  
6              
7 3     3   1887 use Math::Business::ATR;
  3         8  
  3         2728  
8              
9             1;
10              
11 0     0 0 0 sub tag { (shift)->{tag} }
12              
13             sub recommended {
14 4     4 0 1096 my $class = shift;
15              
16 4         25 $class->new(14);
17             }
18              
19             sub new {
20 4     4 0 9 my $class = shift;
21 4         28 my $this = bless {
22             ATR => new Math::Business::ATR,
23             }, $class;
24              
25 4         11 my $days = shift;
26 4 50       12 if( defined $days ) {
27 4         17 $this->set_days( $days );
28             }
29              
30 4         18 return $this;
31             }
32              
33             sub set_days {
34 4     4 0 9 my $this = shift;
35 4         9 my $arg = int(shift);
36              
37 4 50       19 croak "days must be a positive non-zero integer" if $arg <= 0;
38              
39 4         34 $this->{ATR}->set_days($arg);
40 4         18 $this->{days} = $arg;
41 4         20 $this->{R} = ($arg-1)/$arg;
42 4         10 $this->{R1} = 1/$arg;
43              
44 4         23 $this->{tag} = "DMI($this->{days})";
45             }
46              
47             sub insert {
48 1109     1109 0 170618 my $this = shift;
49              
50 1109         1698 my $y_point = $this->{y};
51 1109         2640 while( defined( my $point = shift ) ) {
52 1112 50 33     12526 croak "insert takes three tuple (high, low, close)" unless ref $point eq "ARRAY" and @$point == 3;
53 1112         1660 my ($t_high, $t_low, $t_close) = @$point;
54              
55 1112 100       2096 if( defined $y_point ) {
56 1108         2636 my $atr = $this->{ATR};
57 1108         2888 $atr->insert($point);
58              
59 1108         1675 my ($y_high, $y_low, $y_close) = @$y_point;
60              
61 1108         1384 my ($PDM, $MDM) = (0,0);
62 1108         1384 my $A = $t_high - $y_high;
63 1108         1263 my $B = $y_low - $t_low;
64              
65 1108 100 100     5272 if( $A > 0 and $A > $B ) {
    100 66        
66 468         518 $PDM = $A;
67 468         609 $MDM = 0;
68              
69             } elsif( $B > 0 and $B > $A ) {
70 412         541 $PDM = 0;
71 412         668 $MDM = $B;
72             }
73              
74 1108 100       2214 if( defined(my $pdm = $this->{aPDM}) ) {
75 1063         1422 my $mdm = $this->{aMDM};
76              
77 1063         1434 my $R = $this->{R};
78 1063         1242 my $R1 = $this->{R1};
79              
80 1063         1956 my $aPDM = $this->{aPDM} = $R * $pdm + $R1 * $PDM;
81 1063         1830 my $aMDM = $this->{aMDM} = $R * $mdm + $R1 * $MDM;
82              
83 1063         2971 my $ATR = $atr->query;
84              
85 1063 50       3023 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         1916 my $PDI = $this->{PDI} = $aPDM / $ATR;
91 1063         1354 my $MDI = $this->{MDI} = $aMDM / $ATR;
92              
93 1063         1259 my $DI = abs( $PDI - $MDI );
94 1063 100       2061 my $DX = $DI ? $DI / ($PDI + $MDI) : 0;
95             # 0/0 is indeterminent form, but I think 0 makes sense
96              
97 1063         2888 $this->{ADX} = $R * $this->{ADX} + $R1 * $DX;
98             }
99              
100             } else {
101 45         54 my $p;
102 45         81 my $N = $this->{days};
103 45 100 100     248 if( ref($p = $this->{_p}) and (@$p >= $N-1) ) {
104 3         7 my $psum = 0;
105 3         19 $psum += $_ for @$p;
106 3         17 $psum += $PDM;
107              
108 3         6 my $m = $this->{_m};
109 3         7 my $msum = 0;
110 3         27 $msum += $_ for @$m;
111 3         6 $msum += $MDM;
112              
113 3         10 my $aPDM = $this->{aPDM} = $psum / $N;
114 3         29 my $aMDM = $this->{aMDM} = $msum / $N;
115              
116 3         16 my $ATR = $atr->query;
117 3 50       18 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         9 my $MDI = $this->{MDI} = $aMDM / $ATR;
123              
124 3         10 my $DI = abs( $PDI - $MDI );
125 3 100       11 my $DX = $DI ? $DI / ($PDI + $MDI) : 0;
126             # 0/0 is indeterminent form, but I think 0 makes sense
127              
128 3         7 $this->{ADX} = $DX; # is this right? No idea... I assume this is well documented in his book
129             }
130              
131 3         9 delete $this->{_p};
132 3         18 delete $this->{_m};
133              
134             } else {
135 42         88 push @{$this->{_p}}, $PDM;
  42         107  
136 42         74 push @{$this->{_m}}, $MDM;
  42         137  
137             }
138             }
139             }
140              
141 1112         3476 $y_point = $point;
142             }
143              
144 1109         2715 $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 5924 my $this = shift;
152              
153 2017 100       7177 return ($this->{PDI}, $this->{MDI}, $this->{ADX}) if wantarray;
154 1009         2310 return $this->{ADX};
155             }
156              
157             __END__