File Coverage

blib/lib/App/Chart/IndicatorInfo.pm
Criterion Covered Total %
statement 53 128 41.4
branch 0 20 0.0
condition 0 20 0.0
subroutine 18 29 62.0
pod 0 6 0.0
total 71 203 34.9


line stmt bran cond sub pod time code
1             # Copyright 2009 Kevin Ryde
2              
3             # This file is part of Chart.
4             #
5             # Chart is free software; you can redistribute it and/or modify it under the
6             # terms of the GNU General Public License as published by the Free Software
7             # Foundation; either version 3, or (at your option) any later version.
8             #
9             # Chart is distributed in the hope that it will be useful, but WITHOUT ANY
10             # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11             # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12             # details.
13             #
14             # You should have received a copy of the GNU General Public License along
15             # with Chart. If not, see <http://www.gnu.org/licenses/>.
16              
17             package App::Chart::IndicatorInfo;
18 1     1   443 use 5.010;
  1         2  
19 1     1   4 use strict;
  1         2  
  1         18  
20 1     1   4 use warnings;
  1         2  
  1         28  
21 1     1   296 use Locale::TextDomain ('App-Chart');
  1         17128  
  1         7  
22              
23 1     1   5062 use constant DEBUG => 0;
  1         2  
  1         360  
24              
25             sub new {
26 0     0 0   my ($class, $key) = @_;
27 0           if (DEBUG) { say "IndicatorInfo $key"; }
28 0 0 0       if ($key && $key =~ /^(GT|TA)_/p) {
29 0           $key = ${^POSTMATCH};
30 0           $class = "App::Chart::IndicatorInfo::$1";
31             }
32 0 0 0       if ($key && $key eq 'None') {
33 0           $key = undef;
34             }
35 0           return bless { key => $key }, $class;
36             }
37              
38             sub manual {
39 0     0 0   my ($self) = @_;
40 0   0       my $func = $self->module_func('manual') || return undef;
41 0           return $func->();
42             }
43             sub parameter_info {
44 0     0 0   my ($self) = @_;
45 0   0       my $func = $self->module_func('parameter_info') || return [];
46 0           return $func->();
47             }
48              
49             sub module_func {
50 0     0 0   my ($self, $funcname) = @_;
51 0   0       my $module = $self->module_load || return;
52 0           return $module->can($funcname);
53             }
54             my %warned;
55             sub module_load {
56 0     0 0   my ($self) = @_;
57 0           my $module = $self->module;
58 0           require Module::Load;
59 0 0         if (! eval { Module::Load::load($module); 1 }) {
  0            
  0            
60 0           print "module_load(): Cannot load $module\n";
61 0   0       $warned{$module} ||= do { warn "Cannot load $module: $@"; 1 };
  0            
  0            
62 0           return undef;
63             }
64 0           return $module;
65             }
66             sub module {
67 0     0 0   my ($self) = @_;
68 0   0       return ($self->{'key'} && "App::Chart::Series::Derived::$self->{'key'}");
69             }
70              
71             #------------------------------------------------------------------------------
72             package App::Chart::IndicatorInfo::GT;
73 1     1   7 use strict;
  1         2  
  1         15  
74 1     1   4 use warnings;
  1         4  
  1         25  
75 1     1   4 use Locale::TextDomain ('App-Chart');
  1         3  
  1         3  
76             our @ISA = ('App::Chart::IndicatorInfo');
77              
78             # ENHANCE-ME: @DEFAULT_ARGS shows when OHLCV needed ...
79              
80 1     1   142 use constant manual => __p('manual-node','Other Indicator Packages');
  1         2  
  1         7  
81              
82             sub parameter_info {
83 0     0     my ($self) = @_;
84 0   0       my $module = $self->module_load || return;
85 1     1   333 my @default_args = do { no strict 'refs'; @{"${module}::DEFAULT_ARGS"} };
  1         2  
  1         141  
  0            
  0            
  0            
86 0           my @ret;
87 0           foreach my $arg (@default_args) {
88 0 0         if (Scalar::Util::looks_like_number ($arg)) {
89 0           my $i = @ret;
90 0           push @ret, { name => "Arg$i",
91             key => "GT-arg$i",
92             default => $default_args[$i],
93             };
94             }
95             }
96 0           return \@ret;
97             }
98              
99             sub module {
100 0     0     my ($self) = @_;
101 0           return 'GT::Indicators::' . $self->{'key'};
102             }
103              
104             #------------------------------------------------------------------------------
105             package App::Chart::IndicatorInfo::TA;
106 1     1   5 use strict;
  1         2  
  1         16  
107 1     1   4 use warnings;
  1         2  
  1         26  
108 1     1   4 use Locale::TextDomain ('App-Chart');
  1         2  
  1         5  
109             our @ISA = ('App::Chart::IndicatorInfo');
110              
111 1     1   133 use constant DEBUG => 0;
  1         2  
  1         56  
112              
113 1         3 use constant { manual => __p('manual-node','Other Indicator Packages'),
114             module => 'Finance::TA',
115 1     1   5 };
  1         1  
116              
117             sub parameter_info {
118 0     0     my ($self) = @_;
119 0 0         $self->module_load || return [];
120 0           my @ret;
121              
122 0           my $func = $self->{'key'};
123 0           my ($fh, $fi) = _funcbits ($self);
124 0           foreach my $i (0 .. $fi->{'nbOptInput'} - 1) {
125 0           my ($info, $retcode);
126 0 0         ($retcode = Finance::TA::TA_GetOptInputParameterInfo ($fh, $i, \$info))
127             == $Finance::TA::TA_SUCCESS
128             or die "Function $func parameter $i ",_retcode_str ($retcode);
129              
130             my $elem = { key => "TA_${func}_$info->{'paramName'}",
131             name => $info->{'displayName'},
132 0           default => $info->{'defaultValue'},
133             type => 'integer',
134             };
135 0           push @ret, $elem;
136              
137 0           my $dataset = $info->{'dataSet'};
138 0           if (DEBUG) { say "dataSet $dataset"; }
139              
140 0 0         if ($info->{'type'} == $Finance::TA::TA_OptInput_RealRange) {
141 0           $elem->{'type'} = 'float';
142             }
143              
144             # TA_IntegerRange and TA_RealRange
145             {
146             ## no critic (RequireCheckingReturnValueOfEval)
147 0           eval {
  0            
148 0           $elem->{'minimum'} = $dataset->{'min'};
149             };
150 0           eval {
151             # dummy 100_000 for no maximum
152 0 0         if ((my $max = $dataset->{'max'}) != 100_000) {
153 0           $elem->{'maximum'} = $max;
154             }
155             };
156             # TA_RealRange
157 0           eval {
158 0           $elem->{'decimals'} = $dataset->{'precision'};
159             };
160             }
161              
162             # TA_RealRange and TA_IntegerRange 'suggested_increment',
163             # 'suggested_start', 'suggested_end' are meant for mechanical searching
164             # rather than user controls ...
165              
166             # TA_OPTIN_IS_PERCENT
167             # TA_OPTIN_IS_DEGREE angle
168             # TA_OPTIN_IS_CURRENCY
169             # TA_OPTIN_ADVANCED
170             }
171 0           return \@ret;
172             }
173              
174             sub _funcbits {
175 0     0     my ($self) = @_;
176 0           my ($fh, $fi, $retcode);
177 0 0         ($retcode = Finance::TA::TA_GetFuncHandle ($self->{'key'}, \$fh))
178             == $Finance::TA::TA_SUCCESS
179             or die "FuncHandle $self->{'key'} ",_retcode_str ($retcode);
180              
181 0 0         ($retcode = Finance::TA::TA_GetFuncInfo ($fh, \$fi))
182             == $Finance::TA::TA_SUCCESS
183             or die "FuncInfo $self->{'key'} ",_retcode_str ($retcode);
184              
185 0           return ($fh, $fi);
186             }
187             sub _retcode_str {
188 0     0     my ($retcode) = @_;
189 0           my $rci = Finance::TA::TA_RetCodeInfo->new ($retcode);
190 0           return "[$rci->{'enumStr'}] $rci->{'infoStr'}";
191             }
192              
193             #------------------------------------------------------------------------------
194             package App::Chart::IndicatorInfo::Undef;
195 1     1   466 use strict;
  1         1  
  1         16  
196 1     1   4 use warnings;
  1         1  
  1         38  
197              
198             use constant
199 1         57 { manual => undef,
200             parameter_info => [],
201 1     1   5 };
  1         1  
202              
203             1;
204             __END__