tafunc 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2a16c9b54df3d232237180720227c7eaf76d4bf3
4
+ data.tar.gz: 0e43e95d6331b02987609f857b904428f9af528e
5
+ SHA512:
6
+ metadata.gz: a3b3b56efb395dbce0b9b5eef73733063ca71b6bafc7a5b9c8d4925f7c56fc8b9e63fb8578026e8b4a318301dacb123eb48c5cdbe703404d4654b0efbeccc3e0
7
+ data.tar.gz: c77ba939c0afe776b67e030b0be892089c0111be7ef5144cb37ee752253402650530a0d44a9868350e903929f4cc5dd9f8859084feba9042b6b288582ba946fe
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "shoulda", ">= 0"
10
+ gem "rdoc", "~> 3.12"
11
+ gem "bundler", "~> 1.0"
12
+ gem "jeweler", "~> 1.8.7"
13
+ gem "talib_ruby", ">= 1.0.5"
14
+ gem "activesupport", ">= 4.0.0"
15
+ end
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 YAMAMOTO, Masayuki
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,113 @@
1
+ # TAFunc - another talib_ruby wrapper and extension README.
2
+
3
+ TAFunc provides utility extensions for talib_ruby.
4
+
5
+ ## Requirements
6
+ * [TA-Lib library](http://ta-lib.org) itself. On Mac, just do ``[sudo] brew install ta-lib``
7
+ * activesupport/core_ext (just for underscore method)
8
+ * ``talib_ruby`` gem which is modified ver. of 1.0.5 for TaLib::Function.{groups, functions} (see my github repository: https://github.com/mephistobooks/talib-ruby/tree/patch-1217a)
9
+ * Ruby 2.0 (I tested in this environment)
10
+ *
11
+
12
+ ## Installation
13
+
14
+
15
+ ## Description
16
+
17
+ According to ``ta_abstract.h`` of TA-Lib, there are some ways of wrapping library. Mlamby-san's [indicator](https://github.com/mlamby/indicator), which contains useful extension, takes static code generation approach using [XML at SourceForge]() to get TA method information.
18
+
19
+ On the contrary, the approach of TAFunc is more dynamic and meta-programming. No xml is needed. No static code generation.
20
+
21
+
22
+ ## Usage
23
+
24
+ ```
25
+ ma = TaLib::TAFunc.new( :MA ) do |taf|
26
+ taf.param_in_real = ARRAY_OF_HISTORICAL_DATA
27
+ taf.param_opt_in_period = 2
28
+ end
29
+
30
+ ma.call
31
+
32
+ ```
33
+
34
+ ```
35
+ result = [1.0, 2.0, 3.0, 4.0].tafunc( :MA ) do |taf|
36
+ taf.param_in_real = ARRAY_OF_HISTORICAL_DATA
37
+ taf.param_opt_in_time_period = 2
38
+ end
39
+ ```
40
+
41
+
42
+ ```
43
+ TaLib::TAFunc.new( :MACDEXT ).hints
44
+ ==== Momentum Indicators ====
45
+ <MACDEXT>
46
+ inputs:
47
+ param_in_real
48
+
49
+ options:
50
+ param_opt_in_fast_period
51
+ param_opt_in_fast_ma_type
52
+ param_opt_in_slow_period
53
+ param_opt_in_slow_ma_type
54
+ param_opt_in_signal_period
55
+ param_opt_in_signal_ma_type
56
+
57
+ outputs:
58
+ param_out_macd
59
+ param_out_macd_signal
60
+ param_out_macd_hist
61
+
62
+
63
+ => ["Momentum Indicators"]
64
+ ```
65
+
66
+ ```
67
+ >> TaLib::TAFunc.groups
68
+ => ["Math Operators", "Math Transform", "Overlap Studies", "Volatility Indicators", "Momentum Indicators", "Cycle Indicators", "Volume Indicators", "Pattern Recognition", "Statistic Functions", "Price Transform"]
69
+ >> TaLib::TAFunc.function
70
+ TaLib::TAFunc.function_exists? TaLib::TAFunc.functions
71
+ TaLib::TAFunc.function_find
72
+
73
+ >> TaLib::TAFunc.group_of_function( :MA )
74
+ => "Overlap Studies"
75
+ >> TaLib::TAFunc.new( :MA ).hints
76
+ ==== Overlap Studies ====
77
+ <MA>
78
+ inputs:
79
+ param_in_real
80
+
81
+ options:
82
+ param_opt_in_time_period
83
+ param_opt_in_ma_type
84
+
85
+ outputs:
86
+ param_out_real
87
+
88
+
89
+ => ["Overlap Studies"]
90
+ ```
91
+
92
+ See in ``examples`` directory and test code for details.
93
+
94
+ ## References
95
+ * TA-Lib
96
+ * TACODE.org is also nice documentation which discribes many of TA methods.
97
+ *
98
+
99
+ ## Contributing to TAFunc
100
+
101
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
102
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
103
+ * Fork the project.
104
+ * Start a feature/bugfix branch.
105
+ * Commit and push until you are happy with your contribution.
106
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
107
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
108
+
109
+ ## Copyright
110
+
111
+ Copyright (c) 2013 YAMAMOTO, Masayuki. License is MIT. See LICENSE.txt for
112
+ further details.
113
+
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "tafunc"
18
+ gem.homepage = "http://github.com/mephistobooks/tafunc"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{TAFunc: another talib_ruby wrapper and extensions}
21
+ gem.description = %Q{Useful methods are added to TaLib, TaLib::Function, and TaLib::TAFunc.}
22
+ gem.email = "martin.route66.blues+github@gmail.com"
23
+ gem.authors = ["YAMAMOTO, Masayuki"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+
35
+ #require 'rcov/rcovtask'
36
+ #Rcov::RcovTask.new do |test|
37
+ # test.libs << 'test'
38
+ # test.pattern = 'test/**/test_*.rb'
39
+ # test.verbose = true
40
+ # test.rcov_opts << '--exclude "gems/*"'
41
+ #end
42
+
43
+ task :default => :test
44
+
45
+ require 'rdoc/task'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "tafunc #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,30 @@
1
+ #require 'rubygems'
2
+ require 'tafunc'
3
+
4
+ # init input data
5
+ a = Array.new
6
+ 10.times { |i| a.push i.to_f }
7
+
8
+ hi = (7..17).inject([]) { |list, i| list << i }
9
+ lo = (3..15).inject([]) { |list, i| list << i }
10
+ cl = (6..16).inject([]) { |list, i| list << i }
11
+
12
+ 5.times do |k|
13
+
14
+ b = Array.new(10)
15
+ l = TaLib::TAFunc.new("ADX")
16
+ #l = TaLib::Function.new("ADX")
17
+ # setup input price
18
+ # open = nil, volume = nil, open_interest = nil
19
+ l.param_in_price_hlc = [nil, hi, lo, cl, nil, nil]
20
+
21
+ # setup optional parameter
22
+ l.opt_int(0,k+2);
23
+
24
+ # setup output parameter
25
+ l.out_real(0,b);
26
+ l.call(0,9)
27
+
28
+ p "k=#{k+2}"
29
+ p b
30
+ end
@@ -0,0 +1,13 @@
1
+ require "tafunc.rb"
2
+
3
+
4
+ #
5
+ puts "<TA Genre>"
6
+ puts TaLib::TAFunc.groups.join(', ')
7
+ TaLib::TAFunc.hints( group: "Statistic Functions" )
8
+
9
+ #
10
+ TaLib::TAFunc.new("MACD").hints
11
+
12
+
13
+ #
@@ -0,0 +1,25 @@
1
+ require "tafunc.rb"
2
+
3
+
4
+ # sample input data.
5
+ a = Array.new
6
+ 10.times { |i| a.push i.to_f }
7
+
8
+ #
9
+ 10.times do |k|
10
+ b = Array.new(10)
11
+
12
+ l = TaLib::TAFunc.new("MA") do |ma|
13
+ ma.param_in_real = a # setup input parameter
14
+ ma.param_opt_in_time_period = k+2 # setup optional parameter
15
+ ma.param_out_real = b # setup output parameter
16
+ end
17
+
18
+ #l.call( 0, 9 )
19
+ l.call( 0..9 )
20
+
21
+ #
22
+ p "k=#{k+2}"
23
+ p b
24
+ end
25
+
@@ -0,0 +1,40 @@
1
+ require "tafunc.rb"
2
+
3
+
4
+ # sample input data.
5
+ #a = Array.new
6
+ #10.times { |i| a.push i.to_f }
7
+ a = [ 1.0, 2.0, 3.0, 4.0, 5.0, 0.0, 0.0, 3.0, 4.0, ]
8
+ #a = [ 1.0, 1.0, 2.0, 3.0, 5.0, 1.0, 1.0, 2.0, 3.0, 5.0, ]
9
+
10
+ #
11
+ 5.times do |k|
12
+ b = Array.new(10)
13
+ b_1 = Array.new(10)
14
+ b_2 = Array.new(10)
15
+
16
+ l = TaLib::TAFunc.new("MACDEXT") do |macd|
17
+ macd.param_in_real = a # setup input parameter
18
+ macd.param_opt_in_fast_period = k+2 # setup optional parameter
19
+ macd.param_opt_in_fast_ma_type= TaLib::TA_MAType_EMA
20
+ macd.param_opt_in_slow_period = k+3 # setup optional parameter
21
+ macd.param_opt_in_slow_ma_type= TaLib::TA_MAType_EMA
22
+ macd.param_opt_in_signal_period = k+1 # setup optional parameter
23
+ macd.param_opt_in_signal_ma_type= TaLib::TA_MAType_EMA
24
+ macd.param_out_macd = b # setup output parameter
25
+ macd.param_out_macd_signal = b_1 # setup output parameter
26
+ macd.param_out_macd_hist = b_2 # setup output parameter
27
+ end
28
+
29
+ ret = l.call
30
+
31
+ #
32
+ p "k=#{k+2}"
33
+ #p " BegIdx:#{ret[:start_idx].to_s}, #oE:#{ret[:num_elements].to_s}"
34
+ p ret
35
+ puts "MACD #{b.map{|e| (e.nil?)? nil : sprintf("%.2f",e.to_s.to_f) }}"
36
+ puts "sign #{b_1.map{|e| (e.nil?)? nil : sprintf("%.2f",e.to_s.to_f) }}"
37
+ puts "hist #{b_2.map{|e| (e.nil?)? nil : sprintf("%.2f",e.to_s.to_f) }}"
38
+
39
+ end
40
+
@@ -0,0 +1,770 @@
1
+ #
2
+ # filename: tafunc.rb
3
+ #
4
+ #
5
+ require "talib_ruby"
6
+ require 'active_support/core_ext'
7
+ require 'pp'
8
+
9
+ #require "tafunc_array"
10
+
11
+
12
+ # extension for taLib_ruby structures.
13
+ #
14
+ #
15
+ class Struct
16
+
17
+ # get structs of TA_*.
18
+ # ==== Returns
19
+ # array of TA_* structs.
20
+ def self.ta_types; self.constants.grep( /TA_.*/ ); end
21
+
22
+ end
23
+
24
+
25
+ # talib_ruby main module.
26
+ # class Function is defined in this module.
27
+ #
28
+ module TaLib
29
+
30
+ # get value-table for TA_Input_* of TA-Lib.
31
+ # ==== Return
32
+ # Table of Input types: { val => :sym }.
33
+ # TA_Input_{Integer,Real,Price}
34
+ #
35
+ def self.input_types
36
+ ret = {}
37
+ self.constants.grep( /^TA_Input/ ).each{|c| ret[const_get(c)] = c }
38
+ return ret
39
+ end
40
+
41
+ # get value-type table for TA_OptInput_* of TA-Lib.
42
+ # ==== Return
43
+ # Table of optinput types: { val => :sym }.
44
+ # TA_OptInput_{Real,Integer}{Range,List}
45
+ #
46
+ def self.optinput_types
47
+ ret = {}
48
+ self.constants.grep( /^TA_OptInput/ ).each{|c| ret[const_get(c)] = c }
49
+ return ret
50
+ end
51
+
52
+ # get value-type table for TA_Output_* of TA-Lib.
53
+ # ==== Return
54
+ # Table of output types: { val => :sym }.
55
+ # TA_Output_{Integer,Real}
56
+ #
57
+ def self.output_types
58
+ ret = {}
59
+ self.constants.grep( /^TA_Output/ ).each{|c| ret[const_get(c)] = c }
60
+ return ret
61
+ end
62
+
63
+ # get value-type table for TA_MAType_* of TA-Lib
64
+ # ==== Return
65
+ # Table of MA types: { val => :sym }.
66
+ #
67
+ def self.ma_types
68
+ ret = {}
69
+ self.constants.grep( /^TA_MAType_/ ).each{|c| ret[const_get(c)] = c }
70
+ return ret
71
+ end
72
+
73
+ end
74
+
75
+
76
+ # Util extension for default TaLib::Function by open-class.
77
+ #
78
+ #
79
+ class TaLib::Function
80
+
81
+ # class methods Function.groups and Function.functions are defined
82
+ # in talib.c of talib_ruby.
83
+
84
+ # :nodoc:
85
+ # ==== Return
86
+ # { :group => group_in_which_function_exists,
87
+ # :function => name_of_function }
88
+ private
89
+ def self.__group_of_function( func )
90
+ func = func.to_s if func.class != String
91
+ ret = { :group => nil, :function => nil, }
92
+
93
+ self.functions.each do |k,v|
94
+ if tmp = v.grep(/^#{func}$/i).first
95
+ then ret[:group] = k; ret[:function] = tmp; break
96
+ end
97
+ end
98
+ return ret
99
+ end
100
+
101
+ public
102
+ # find func from hash.
103
+ # ==== Args
104
+ # func :: name of function which you want to search from the table.
105
+ # (Symbol can match with String. So you can use also Symbol)
106
+ # ==== Return
107
+ # String :: function name found.
108
+ # nil :: no such function.
109
+ def self.function_find( func )
110
+ return __group_of_function( func )[:function]
111
+ end
112
+
113
+ # check if a function is existed.
114
+ # ==== Args
115
+ # func :: name of function which you want to search from the table.
116
+ # ==== Return
117
+ # true :: there exists
118
+ # false :: no such function.
119
+ def self.function_exists?( func )
120
+ return not(self.function_find(func).nil?)
121
+ end
122
+
123
+ public
124
+ # get the group of specified function.
125
+ #
126
+ def self.group_of_function( func )
127
+ return __group_of_function( func )[:group]
128
+ end
129
+
130
+
131
+ ####
132
+
133
+ # TA Function name.
134
+ attr_reader :name if defined?( name ).nil? # @name
135
+
136
+ ####
137
+
138
+ # the interfaces of each TA function.
139
+ # Define ifs_ins, ifs_outs, and ifs_opts with
140
+ # TaLib::Function#{in[s],out[s],opt[s]}.
141
+ #
142
+ ifs = ["in","out","opt"]
143
+ ifs.each do |funcif|
144
+
145
+ ##
146
+ # :method: ifs_ins
147
+ # Helper method of Function#{in,ins}.
148
+ # ==== Args
149
+ # none.
150
+ # ==== Return
151
+ # input interface (parameters) of current Function object.
152
+ # ex. [#<struct Struct::TA_InputParameterInfo type=1,
153
+ # param_name="inReal", flags=0>]
154
+ # type corresponds to TaLib.input_type[type].
155
+ #
156
+
157
+ ##
158
+ # :method: ifs_opts
159
+ # Helper method of Function#{opt,opts}
160
+ # ==== Args
161
+ # none.
162
+ # ==== Return
163
+ # option interface (parameters) of current Function object.
164
+
165
+ ##
166
+ # :method: ifs_outs
167
+ # Helper method of Function#{out,outs}
168
+ # ==== Args
169
+ # none.
170
+ # ==== Return
171
+ # output interface (parameters) of current Function object.
172
+ #
173
+
174
+ ##
175
+
176
+ define_method("ifs_#{funcif}s") {
177
+ eval("self.#{funcif}s.times.map {|i| self.#{funcif}(i) }")
178
+ }
179
+ end
180
+
181
+ ##
182
+ # :method: ifs_all
183
+ # list all of ifs_ins, ifs_outs, ifs_opts.
184
+ # ==== Args
185
+ # none.
186
+ # ==== Return
187
+ # Array of current object (an instance of Function) interfaces.
188
+
189
+ ##
190
+
191
+ define_method("ifs_all") {
192
+ ifs.map{|ifname|
193
+ eval("ifs_#{ifname}s")
194
+ }.flatten
195
+ }
196
+
197
+ ####
198
+
199
+ # Function#call(idx1,idx2) is defined.
200
+
201
+ end
202
+
203
+
204
+ # more Util extensions for TaLib::Function.
205
+ #
206
+ #
207
+ class TaLib::TAFunc < TaLib::Function
208
+
209
+ # :nodoc:
210
+ PPREFIX = "param_"
211
+ table_for_param = {
212
+ "in" => ["int","real","price"],
213
+ "opt" => ["int","real"],
214
+ "out" => ["int","real"],
215
+ }
216
+ table_for_param_regex = {
217
+ "in" => ["Price","Integer","Real"],
218
+ "opt" => ["Integer","Real"],
219
+ "out" => ["Integer","Real"],
220
+ }
221
+ def etype_attr
222
+ {
223
+ "in" => { 0 => "price",
224
+ 1 => "real",
225
+ 2 => "int", },
226
+ "opt" => { 0 => "real",
227
+ 1 => "real",
228
+ 2 => "int",
229
+ 3 => "int", },
230
+ "out" => { 0 => "real",
231
+ 1 => "int", },
232
+ }
233
+ end
234
+
235
+ private
236
+ # generate interface methods (parameters) of each Function, dynamically.
237
+ # (used only by #initialize)
238
+ #
239
+ # generated methods are param_in_*, param_opt_*, param_out_*. These are
240
+ # due to each Function's specification.
241
+ #
242
+ # ex. for MACDEXT, param_in_real (getter), and param_in_real= (setter)
243
+ # are generated as input parameter. This is singleton methods.
244
+ #
245
+ # To see the generated methods, use #param_methods, #param_attr or
246
+ # something.
247
+ # ==== Args
248
+ # none.
249
+ # ==== Return
250
+ # none.
251
+ # ==== TODO
252
+ # * hove to change ( wh = :val ) interface for getter?
253
+ # (maybe confused to setter.)
254
+ def __define_ifmethods
255
+
256
+ #
257
+ types = {
258
+ :ifs_ins => :input_types,
259
+ :ifs_opts => :optinput_types,
260
+ :ifs_outs => :output_types,
261
+ }
262
+ types_dir = {
263
+ :ifs_ins => 'in',
264
+ :ifs_opts => 'opt',
265
+ :ifs_outs => 'out',
266
+ }
267
+
268
+ # param_accessors generator.
269
+ #
270
+ #
271
+ types.each do |ifs_method, type_method|
272
+ send(ifs_method).each do |e|
273
+ case
274
+ when TaLib.send(type_method)[e.type].to_s =~ /(Price)|(Integer)|(Real)/
275
+ idx = send(ifs_method).index(e)
276
+ typ = etype_attr[types_dir[ifs_method]][e.type]
277
+
278
+ define_singleton_method( PPREFIX+
279
+ e.param_name.underscore ) {|wh=:val|
280
+ unless wh =~ /^(val)|(type)$/ # :sym matches "sym".
281
+ raise "#{__method__} is getter and cannot recognaize"+
282
+ " the argument: #{wh}"
283
+ end
284
+
285
+ #
286
+ (send("param_"+types_dir[ifs_method])[idx].nil?)? nil : \
287
+ send("param_"+types_dir[ifs_method])[idx][wh]
288
+ }
289
+ if typ =~ /Price/i
290
+ then
291
+ # define param_in_price_hlc= , etc.
292
+ #
293
+ #
294
+ #define_singleton_method( PPREFIX+
295
+ # e.param_name.underscore+'=') {|vo,vh,vl,vc,vv,voi|
296
+ define_singleton_method( PPREFIX+
297
+ e.param_name.underscore+'=') {|vv|
298
+ #pp vv
299
+
300
+ #
301
+ vv.each do |v_e|
302
+ if v_e.nil? or v_e==[]
303
+ next
304
+ elsif v_e.class != Array
305
+ then raise "#{__method__} error!"+
306
+ " #{v_e.to_s}(#{v_e.class.to_s}) must be array."
307
+ end
308
+ end if vv.class == Array
309
+
310
+ # in_price,
311
+ send( types_dir[ifs_method]+"_"+typ,
312
+ idx,
313
+ { :open => vv[0],
314
+ :high => vv[1],
315
+ :low => vv[2],
316
+ :close => vv[3],
317
+ :volume => vv[4],
318
+ :oi => vv[5], } )
319
+ }
320
+
321
+ else
322
+ define_singleton_method( PPREFIX+
323
+ e.param_name.underscore+'=') {|v|
324
+ send( types_dir[ifs_method]+"_"+typ, idx, v )
325
+ }
326
+
327
+ end
328
+
329
+ else
330
+ raise "Initialization error #{TaLib.input_types[e.type]} #{e}!"
331
+ end
332
+ end
333
+
334
+ end
335
+
336
+ # # accessor generator
337
+ # # for input parameter of the current TA function.
338
+ # self.ifs_ins.each {|e|
339
+ # case
340
+ # when TaLib.input_types[e.type].to_s =~ /(Price)|(Integer)|(Real)/
341
+ # #
342
+ # # This is NG: self.class.class_eval { ... }.
343
+ # # Because same instance methods are re-difined on TAFunc when
344
+ # # we do TAFunc.new multiple times.
345
+ # #
346
+ # # So, we have to create singleton-methods on each object of
347
+ # # TAFunc by ~~``self.singleton_class.instance_eval``~~.
348
+ # #
349
+ # #
350
+ # idx = ifs_ins.index(e)
351
+ # typ = etype_attr['in'][e.type]
352
+ #
353
+ # define_singleton_method( PPREFIX+
354
+ # e.param_name.underscore ) {|wh=:val|
355
+ # #idx = ifs_ins.index(e)
356
+ # unless wh =~ /^(val)|(type)$/ # :sym matches "sym".
357
+ # raise "#{__method__} is getter and cannot recognaize"+
358
+ # " the argument: #{wh}"
359
+ # end
360
+ #
361
+ # (@param_in[idx].nil?)? nil : @param_in[idx][wh]
362
+ # }
363
+ # define_singleton_method( PPREFIX+
364
+ # e.param_name.underscore+'=') {|v|
365
+ # #eval("in_price( ifs_ins.index(e), v )")
366
+ # #eval("in_#{etype_attr['in'][e.type]}( ifs_ins.index(e), v )")
367
+ # #puts "#{__method__}: #{idx}, #{v}"
368
+ # #puts "raw method: in_#{etype_attr['in'][e.type]}"
369
+ #
370
+ # send("in_"+typ, idx, v )
371
+ # }
372
+ # else
373
+ # raise "Initialization error #{TaLib.input_types[e.type]} #{e}!"
374
+ # end
375
+ # }
376
+ #
377
+ # # accessor generator
378
+ # # for option parameter of current TA function.
379
+ # self.ifs_opts.each {|e|
380
+ # case
381
+ # when TaLib.optinput_types[e.type].to_s =~ /(Integer)|(Real)/
382
+ # idx = ifs_opts.index(e)
383
+ # typ = etype_attr['opt'][e.type]
384
+ #
385
+ # define_singleton_method( PPREFIX+
386
+ # e.param_name.underscore ) {|wh=:val|
387
+ # unless wh =~ /^(val)|(type)$/ # :sym matches "sym".
388
+ # raise "#{__method__} is getter and cannot recognaize"+
389
+ # " the argument: #{wh}"
390
+ # end
391
+ #
392
+ # (@param_opt[idx].nil?)? nil : @param_opt[idx][wh]
393
+ # }
394
+ # define_singleton_method( PPREFIX+
395
+ # e.param_name.underscore + '=' ) {|v|
396
+ # #eval("opt_int( ifs_opts.index(e), v )")
397
+ # send( "opt_"+typ, idx, v )
398
+ # }
399
+ # else
400
+ # raise "Initialization error #{TaLib.optinput_types[e.type]} #{e}!"
401
+ # end
402
+ # }
403
+ #
404
+ # # accessor generator
405
+ # # for output parameter of current TA function.
406
+ # self.ifs_outs.each {|e|
407
+ # case
408
+ # when TaLib.output_types[e.type].to_s =~ /(Integer)|(Real)/
409
+ # idx = ifs_outs.index(e)
410
+ # typ = etype_attr['out'][e.type]
411
+ #
412
+ # define_singleton_method( PPREFIX+
413
+ # e.param_name.underscore ) {|wh=:val|
414
+ # unless wh =~ /^(val)|(type)$/ # :sym matches "sym".
415
+ # raise "#{__method__} is getter and cannot recognaize"+
416
+ # " the argument: #{wh}"
417
+ # end
418
+ #
419
+ # (@param_out[idx].nil?)? nil : @param_out[idx][wh]
420
+ # }
421
+ # define_singleton_method( PPREFIX+
422
+ # e.param_name.underscore + '=' ) {|v|
423
+ # #eval("out_int( ifs_outs.index(e), v )")
424
+ # send( "out_"+typ, idx, v )
425
+ # }
426
+ # else
427
+ # raise "Initialization error #{TaLib.output_types[e.type]} #{e}!"
428
+ # end
429
+ # }
430
+ end
431
+
432
+ public
433
+ # get defined singleton methods of param_{in,opt,out}_*.
434
+ #
435
+ #
436
+ def param_methods( kind = "(in|opt|out)" )
437
+ kind = kind.to_s if kind.class == Symbol
438
+ self.singleton_methods.grep(/^param_#{kind}_.+$/)
439
+ end
440
+ def param_attr( kind = "(in|opt|out)" )
441
+ self.param_methods( kind ).grep(/[^=]$/)
442
+ end
443
+
444
+
445
+ public
446
+ #
447
+ # ==== Args
448
+ # func :: The function name.
449
+ #
450
+ def initialize( func, arr_in: [], arr_out: [] )
451
+ func = func.to_s if func.class == Symbol
452
+ func_renamed = self.class.function_find( func )
453
+ case
454
+ when func.class != String
455
+ raise "Type error for the function name: #{func.class}(#{func})!"+
456
+ " This should be in String."
457
+ when TaLib::Function.function_exists?( func ) == false
458
+ raise "No such function: #{func}!"+
459
+ " Choose one of"+
460
+ " #{TaLib::Function.functions.values.flatten.join(' ')}."
461
+ end
462
+
463
+ #
464
+ super( func_renamed )
465
+
466
+ # for recording parameter setting.
467
+ # { idx => { :val => some_val,
468
+ # :type => type_name, }
469
+ #
470
+ @param_in = {}
471
+ @param_opt = {}
472
+ @param_out = {}
473
+
474
+ # define method for the function: func.
475
+ # for example, param_in_real, param_opt_in_fast_period methods, etc.
476
+ #
477
+ __define_ifmethods
478
+
479
+ # this must be after __define_ifmethods because we want to use
480
+ # generated interface methods in yield block.
481
+ #
482
+ yield self if block_given?
483
+
484
+ end
485
+
486
+ public
487
+ # current parameter values of each object of Function.
488
+ # for @param_in, @param_opt, @param_out.
489
+ # ==== See Also
490
+ # * TaLib::Function#ifs_all/ifs_ins/ifs_opts/ifs_outs.
491
+ # * TaLib::TAFunc.#hints
492
+ attr_reader :param_in, :param_opt, :param_out
493
+
494
+ private
495
+ #alias :in_int_orig :in_int
496
+ #alias :in_real_orig :in_real
497
+ #alias :in_price_orig :in_price
498
+
499
+ #alias :opt_int_orig :opt_int
500
+ #alias :opt_real_orig :opt_real
501
+
502
+ #alias :out_int_orig :out_int
503
+ #alias :out_real_orig :out_real
504
+
505
+ table_for_param.keys.each{|k|
506
+ table_for_param[k].each{|v|
507
+ unless self.method_defined?( "#{k}_#{v}_orig".to_sym )
508
+ then alias_method( "#{k}_#{v}_orig".to_sym, "#{k}_#{v}".to_sym )
509
+ else raise "Error in re-defining at #{self.to_s}:"+
510
+ " #{k}_#{v}_orig already exists!"
511
+ end
512
+ }
513
+ }
514
+
515
+ private
516
+ def __param_in_record( idx, val )
517
+ @param_in[idx] = {
518
+ val: val,
519
+ type: TaLib.input_types[ifs_ins[idx].type], }
520
+ end
521
+ def __param_opt_record( idx, val )
522
+ @param_opt[idx] = { val: val,
523
+ type: TaLib.optinput_types[ifs_opts[idx].type], }
524
+ end
525
+ def __param_out_record( idx, val )
526
+ @param_out[idx] = { val: val,
527
+ type: TaLib.output_types[ifs_outs[idx].type], }
528
+ end
529
+
530
+ public
531
+ ##
532
+ # wrap the original {in,opt,out}_{int,real,price} to record values.
533
+ # For example,
534
+ # def in_real( idx, val )
535
+ # __in_param_record( idx, val )
536
+ # in_real_orig(idx, val)
537
+ # end
538
+ #
539
+ #
540
+ ##
541
+ table_for_param.keys.each{|k|
542
+ table_for_param[k].each{|v|
543
+ if v == 'price'
544
+ then define_method( k+"_"+v ) {|idx,val|
545
+ # attention: val must be lvalue when out_*.
546
+ eval("__param_#{k}_record( idx, val )")
547
+ eval("#{k}_#{v}_orig(idx,"+
548
+ " val[:open], val[:high], val[:low], val[:close],"+
549
+ " val[:volume], val[:oi] )")
550
+ }
551
+
552
+ # real or int
553
+ else define_method( k+"_"+v ) {|idx,val|
554
+ # attention: val must be lvalue when out_*.
555
+ eval("__param_#{k}_record( idx, val )")
556
+ eval("#{k}_#{v}_orig(idx, val)")
557
+ }
558
+ end
559
+ }
560
+ }
561
+
562
+ ####
563
+ public
564
+ # wrap Function#call to accept various kinds of args.
565
+ # ==== Args
566
+ # *r :: range of input array in several ways:
567
+ # no args: from pram_in_*
568
+ # m, n: direct indexes
569
+ # m..n: range object
570
+ # array: array
571
+ # ==== Return
572
+ # due to the function.
573
+ def call( *r )
574
+ m, n = nil, nil
575
+
576
+ # specifies m and n, simulation range in input data.
577
+ case
578
+ when r.size == 0 # no args.
579
+ raise "No setting of param_in_* for #{name}!" if @param_in[0].nil?
580
+ m, n = 0, @param_in[0][:val].size-1
581
+ when r.first.class == Range # Range is given.
582
+ m, n = r.first.first, r.first.last
583
+ when r.size == 2 # 2 indexes are given.
584
+ #puts "couple of index."
585
+ m, n = r.first, r.last
586
+ when r.first.class == Array # Array is given.
587
+ #puts "array."
588
+ self.param_in_real = r.first if @param_in[0].nil?
589
+ m, n = 0, r.first.size-1
590
+ else
591
+ raise "Strange args: #{r}! Should be in one of Nothing,"+
592
+ " two indexes, Array or Range."
593
+ end
594
+
595
+ #puts "idx: #{m}, #{n}"
596
+ param_size = case @param_in[0][:type]
597
+ when :TA_Input_Price
598
+ [ @param_in[0][:val][:open],
599
+ @param_in[0][:val][:high],
600
+ @param_in[0][:val][:low],
601
+ @param_in[0][:val][:close],
602
+ ].map{|e| (e.nil?)? 0 : e.size }.max
603
+ when :TA_Input_Real
604
+ self.param_in_real.size
605
+ when :TA_Input_Integer
606
+ raise "Not yet implemented."
607
+ else
608
+ raise "Strange type for input parameter:"+
609
+ " #{@param_in[0][:type]}."
610
+ end
611
+
612
+ case
613
+ when m > n
614
+ raise "calculation range(#{m},#{n}) is currently not supported!"
615
+ when n >= param_size
616
+ raise "#{n} is too big!"+
617
+ " less than or equal to #{self.param_in_real.size-1}"
618
+ end
619
+
620
+ #
621
+ tmp = super( m, n )
622
+ ret = param_out_setting
623
+ ret.merge!( { :start_idx => tmp[0], :num_elements => tmp[1], } )
624
+
625
+ #
626
+ return ret
627
+
628
+ end
629
+
630
+ # auto prepare output arrays.
631
+ # ==== Requirements
632
+ # all in-parameters have already been set.
633
+ # ==== Args
634
+ # h :: output hash to be set.
635
+ # force_mode: :: force to create new array for output (default: false)
636
+ # ==== Return
637
+ # h :: { :output_parameter1 => [ nil, nil, ... ],
638
+ # :output_parameter2 => [ nil, nil, ... ], }
639
+ # ==== TODO
640
+ # * currently tested only MA, MACDEXT.
641
+ #
642
+ def param_out_setting( h = {}, force_mode: false )
643
+
644
+
645
+ # get output attributes (arrays to prepare).
646
+ tmp = self.param_attr( :out )
647
+
648
+ # prepare arrays and set them.
649
+ tmp.each{|a|
650
+ #
651
+ if force_mode or self.send( a ).nil?
652
+ then h[a] = Array.new( self.param_in_real.size )
653
+ self.send( (a.to_s+'=').to_sym, h[a] )
654
+ else h[a] = self.send( a ) # call getter.
655
+ end
656
+ }
657
+
658
+ return h
659
+ end
660
+
661
+ ####
662
+
663
+ # Wrapper of the class method: hints.
664
+ # ==== See Also
665
+ # * self.hints
666
+ def hints( verbose: false, group: "all", function: name )
667
+ self.class.hints( verbose: verbose, group: group, function: function )
668
+ end
669
+
670
+ # self.hints provides the information about TA-Lib function.
671
+ # The information of them are extracted from talib library itself.
672
+ # ==== ATTENTION
673
+ # library (talib_ruby) must support TaLib::Function.{groups,functions}.
674
+ # ==== Args
675
+ # verbose: :: parameter name only when false, or entire structs when true.
676
+ # group: :: group name of functions.
677
+ # function: :: name of function.
678
+ # ==== Description
679
+ # * one of group or function should be specified.
680
+ # * these args can be String, Array of String, or "all"
681
+ # *
682
+ # ==== Return
683
+ #
684
+ def self.hints( verbose: false, group: "all", function: "all" )
685
+ group_list = nil
686
+ case
687
+ when group == "all"
688
+ group_list = self.groups
689
+ when group.class == String
690
+ group_list = [group]
691
+ when group.class == Array
692
+ group_list = group
693
+ else
694
+ raise "Type error #{group.class} for group!"+
695
+ " Please specify group in String or Array of String."
696
+ end
697
+
698
+ func_list = nil
699
+ tmp = self.functions
700
+ case
701
+ when function == "all"
702
+ func_list = tmp.values.flatten
703
+ when function.class == Array
704
+ func_list = function
705
+ group_list = []
706
+ func_list.each{|f|
707
+ group_list.push( tmp.keys.map{|e|
708
+ (tmp[e].grep(f).size>0)? e : nil }.compact )
709
+ }
710
+ group_list.flatten!
711
+ when function.class == String
712
+ func_list = [function]
713
+ group_list = tmp.keys.map{|e|
714
+ (tmp[e].grep(function).size>0)? e : nil
715
+ }.compact
716
+ else
717
+ end
718
+
719
+ #
720
+ group_list = group_list.sort.uniq
721
+ func_list = func_list.sort.uniq
722
+ #pp group_list
723
+ #pp func_list
724
+
725
+ #
726
+ group_list.each{|grp|
727
+ puts "==== #{grp} ===="
728
+ self.functions[grp].each{|func|
729
+ #puts func
730
+ if func_list.grep(func).size > 0
731
+ tmp = self.new(func)
732
+
733
+ puts "<#{func}>"
734
+ puts "inputs:"
735
+ if verbose
736
+ then pp tmp.ifs_ins
737
+ else tmp.ifs_ins.each{|e|
738
+ puts PPREFIX+e.param_name.underscore }
739
+ end
740
+ puts ""
741
+
742
+ puts "options:"
743
+ if verbose
744
+ then pp tmp.ifs_opts
745
+ else tmp.ifs_opts.each{|e|
746
+ puts PPREFIX+e.param_name.underscore }
747
+ end
748
+ puts ""
749
+
750
+ puts "outputs:"
751
+ if verbose
752
+ then pp tmp.ifs_outs
753
+ else tmp.ifs_outs.each{|e|
754
+ puts PPREFIX+e.param_name.underscore }
755
+ end
756
+ puts ""
757
+
758
+ puts ""
759
+ end
760
+ }
761
+ }
762
+
763
+ end
764
+
765
+
766
+ end
767
+
768
+
769
+
770
+ #### endof filename: tafunc.rb