ib-technical-analysis 0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +56 -0
- data/Gemfile +6 -0
- data/Guardfile +24 -0
- data/LICENSE +21 -0
- data/README.md +140 -0
- data/bin/console +100 -0
- data/bin/console.yml +3 -0
- data/bin/gateway +113 -0
- data/bin/history.irb +186 -0
- data/ib-technical-analysis.gemspec +38 -0
- data/lib/calculation_helpers.rb +149 -0
- data/lib/ib/bar.rb +23 -0
- data/lib/ta_support.rb +157 -0
- data/lib/technical-analysis.rb +11 -0
- data/lib/technical_analysis/bar_calculation.rb +4 -0
- data/lib/technical_analysis/lane.rb +46 -0
- data/lib/technical_analysis/momentum/lane-stochastic.rb +105 -0
- data/lib/technical_analysis/momentum/rsi.rb +76 -0
- data/lib/technical_analysis/momentum/tsi.rb +79 -0
- data/lib/technical_analysis/moving-average/base.rb +59 -0
- data/lib/technical_analysis/moving-average/exp-ma.rb +53 -0
- data/lib/technical_analysis/moving-average/ka-ma.rb +90 -0
- data/lib/technical_analysis/moving-average/simple-ma.rb +42 -0
- data/lib/technical_analysis/moving-average/weighted-ma.rb +25 -0
- data/lib/technical_analysis/moving_average.rb +85 -0
- data/lib/technical_analysis/version.rb +4 -0
- metadata +183 -0
data/bin/history.irb
ADDED
@@ -0,0 +1,186 @@
|
|
1
|
+
exit
|
2
|
+
exit
|
3
|
+
exit
|
4
|
+
exit
|
5
|
+
exit
|
6
|
+
exit
|
7
|
+
exit
|
8
|
+
exit
|
9
|
+
exit
|
10
|
+
exit#
|
11
|
+
exit
|
12
|
+
exit
|
13
|
+
exit
|
14
|
+
exit
|
15
|
+
exit
|
16
|
+
exit
|
17
|
+
q
|
18
|
+
exit
|
19
|
+
exit
|
20
|
+
exit
|
21
|
+
exit
|
22
|
+
exit
|
23
|
+
exit
|
24
|
+
exit
|
25
|
+
exit
|
26
|
+
exit
|
27
|
+
exit
|
28
|
+
ATS.keys
|
29
|
+
ATS.first
|
30
|
+
p ATS.first
|
31
|
+
p ATS.first
|
32
|
+
puts ATS.first
|
33
|
+
puts ATS.first.result
|
34
|
+
puts ATS.first
|
35
|
+
irb ATS.first
|
36
|
+
@momentum
|
37
|
+
methods
|
38
|
+
@momentum
|
39
|
+
exit
|
40
|
+
puts ATS.first
|
41
|
+
puts ATS.first.result
|
42
|
+
p ATS.first
|
43
|
+
p ATS.first.result
|
44
|
+
p ATS.first..call :result
|
45
|
+
p= ATS.first
|
46
|
+
p
|
47
|
+
purs p.result
|
48
|
+
p= ATS[:"mini-dax"]
|
49
|
+
puts p.result
|
50
|
+
z= const_set
|
51
|
+
Base
|
52
|
+
Base.const_set 'G'
|
53
|
+
Base.const_set 'G', 6
|
54
|
+
G
|
55
|
+
z= Base.const_set 'G', 6
|
56
|
+
z
|
57
|
+
IB::Base::G
|
58
|
+
z= IB.const_set 'GU', 6
|
59
|
+
GU
|
60
|
+
z= 'jleor'
|
61
|
+
z.capitalize
|
62
|
+
exit
|
63
|
+
Dax
|
64
|
+
Russel
|
65
|
+
exit
|
66
|
+
ATS.keys
|
67
|
+
ATS[:dax]
|
68
|
+
puts Russel.result
|
69
|
+
puts Russell.result
|
70
|
+
puts Russell.result[:result]
|
71
|
+
puts Russell.result.map{|y| y[:result]}
|
72
|
+
puts dax.result.map{|y| y[:result]}
|
73
|
+
puts Dax.result.map{|y| y[:result]}
|
74
|
+
print Dax.result.map{|y| y[:result]}
|
75
|
+
print Dax.result.map{|y| y[:result].to_d}
|
76
|
+
print Dax.result.map{|y| y[:result].to_f}
|
77
|
+
print Russell.result.map{|y| y[:result].to_f}
|
78
|
+
exit
|
79
|
+
exit
|
80
|
+
Dax.result
|
81
|
+
puts Dax.result
|
82
|
+
exit
|
83
|
+
puts Dax.result
|
84
|
+
puts Dax.result.result
|
85
|
+
puts Dax.result
|
86
|
+
print Dax.result.result
|
87
|
+
print Dax.result.result.to_i
|
88
|
+
print Russell.result.result.to_i
|
89
|
+
exti
|
90
|
+
extit
|
91
|
+
exit
|
92
|
+
print Dax.raw_data.result.to_i
|
93
|
+
print Dax.contract
|
94
|
+
print exit
|
95
|
+
print Dax.raw_data.result.to_i
|
96
|
+
print Dax.contract
|
97
|
+
print Dax.current_price_signal
|
98
|
+
print Dax.current_price_signal
|
99
|
+
Dax.current_price_signal
|
100
|
+
exit
|
101
|
+
print Dax.current_price_signal
|
102
|
+
Dax.current_price_signal
|
103
|
+
print Dax.contract
|
104
|
+
Dax.contract
|
105
|
+
Dax.contract ; nil
|
106
|
+
irb Dax
|
107
|
+
@contract
|
108
|
+
exit
|
109
|
+
Dax.contract.to_human
|
110
|
+
Dax.contract.to_human
|
111
|
+
exit
|
112
|
+
exit
|
113
|
+
IB::BAR_SIZES
|
114
|
+
IB::BAR_SIZES.keys
|
115
|
+
exit
|
116
|
+
Dax.contract.to_human
|
117
|
+
Dax.raw_data.first
|
118
|
+
exit
|
119
|
+
i = IB::Bar.new
|
120
|
+
i.methods
|
121
|
+
require 'technical-analysis'
|
122
|
+
z.capitalize
|
123
|
+
z= 'jleor'
|
124
|
+
z = Symbols::Futures.mini_dax
|
125
|
+
zz= z.eod duration: '50 D'
|
126
|
+
zz= z.eod( duration: '50 D').each
|
127
|
+
zz= z.calculate( :ema, period: 15 , use: :close )
|
128
|
+
require 'ib-technical-analysis'
|
129
|
+
TechnicalAnalysis::Momentum::Lane
|
130
|
+
zz= z.eod duration: '50 D'
|
131
|
+
indicator = TechnicalAnalysis::MovingAverage::KaMA.new period: 30, fast: 5, slow: 15, data: zz
|
132
|
+
exit
|
133
|
+
z = Symbols::Futures.mini_dax
|
134
|
+
zz= z.eod duration: '50 D'
|
135
|
+
indicator = TechnicalAnalysis::MovingAverage::KaMA.new period: 30, fast: 5, slow: 15, data: zz
|
136
|
+
exit
|
137
|
+
z = Symbols::Futures.mini_dax
|
138
|
+
zz= z.eod duration: '50 D'
|
139
|
+
indicator = TechnicalAnalysis::MovingAverage::KaMA.new period: 30, fast: 5, slow: 15, data: zz
|
140
|
+
exit
|
141
|
+
exit
|
142
|
+
exit
|
143
|
+
z = Symbols::Futures.mini_dax
|
144
|
+
zz= z.eod duration: '50 D'
|
145
|
+
indicator = TechnicalAnalysis::MovingAverage::KaMA.new period: 30, fast: 5, slow: 15, data: zz
|
146
|
+
indicator = TechnicalAnalysis::MovingAverage::KaMA.new period: 30, fast: 5, slow: 15, data: zz.close
|
147
|
+
exit
|
148
|
+
z = Symbols::Futures.mini_dax
|
149
|
+
zz= z.eod duration: '50 D'
|
150
|
+
indicator = TechnicalAnalysis::MovingAverage::KaMA.new period: 30, fast: 5, slow: 15, data: zz.close
|
151
|
+
indicator = TechnicalAnalysis::MovingAverage::KaMA.new period: 30, fast: 5, slow: 15, data: zz
|
152
|
+
exit
|
153
|
+
z = Symbols::Futures.mini_dax
|
154
|
+
zz= z.eod duration: '50 D'
|
155
|
+
indicator = TechnicalAnalysis::MovingAverage::KaMA.new period: 30, fast: 5, slow: 15, data: zz
|
156
|
+
zz.first
|
157
|
+
zz.first.pivot
|
158
|
+
exit
|
159
|
+
exit
|
160
|
+
exit
|
161
|
+
Dax.result
|
162
|
+
Russell
|
163
|
+
exit
|
164
|
+
Dax
|
165
|
+
Dax
|
166
|
+
Dax.result
|
167
|
+
Dax.raw_data.result
|
168
|
+
Dax.raw_data.result.to_i
|
169
|
+
exit
|
170
|
+
z = Symbols::Futures.mini_dax
|
171
|
+
zz= z.eod duration: '50 D'
|
172
|
+
Symbols::Stocks.all
|
173
|
+
z= Symbols::Stocks.msft
|
174
|
+
zz= z.eod duration: '50 D'
|
175
|
+
z.close
|
176
|
+
zz.close
|
177
|
+
Symbols::Forex.all
|
178
|
+
IB::BAR_SIZES
|
179
|
+
IB::BAR_SIZES.key(hour)
|
180
|
+
IB::BAR_SIZES.key(:hour)
|
181
|
+
IB::BAR_SIZES.keys
|
182
|
+
IB::BAR_SIZES.values
|
183
|
+
exit
|
184
|
+
exit
|
185
|
+
TradingSystem::Base
|
186
|
+
exit
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require_relative 'lib/technical_analysis/version'
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "ib-technical-analysis"
|
5
|
+
spec.version = TechnicalAnalysis::VERSION
|
6
|
+
spec.authors = ["Hartmut Bischoff"]
|
7
|
+
spec.email = ["topofocus@gmail.com"]
|
8
|
+
|
9
|
+
spec.summary = %q{.Tools to perform technical analysis on financial data .}
|
10
|
+
spec.homepage = "https://ib-ruby.github.io/ib-doc/"
|
11
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 3.0.0")
|
12
|
+
|
13
|
+
# spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com"
|
14
|
+
|
15
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
16
|
+
spec.metadata["source_code_uri"] = "https://github.cm/ib-ruby/ib-technical-analysis"
|
17
|
+
spec.metadata["changelog_uri"] = "https://github.cm/ib-ruby/ib-technical-analysis/changelog.md"
|
18
|
+
|
19
|
+
# Specify which files should be added to the gem when it is released.
|
20
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
21
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
22
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
23
|
+
end
|
24
|
+
spec.bindir = "exe"
|
25
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
26
|
+
spec.require_paths = ["lib"]
|
27
|
+
|
28
|
+
|
29
|
+
spec.add_dependency "ib-api"
|
30
|
+
spec.add_dependency "ib-extensions"
|
31
|
+
spec.add_development_dependency "bundler", "~> 2.0"
|
32
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
33
|
+
spec.add_development_dependency 'rspec-collection_matchers'
|
34
|
+
spec.add_development_dependency 'rspec-its'
|
35
|
+
|
36
|
+
spec.add_development_dependency "guard"
|
37
|
+
spec.add_development_dependency "guard-rspec"
|
38
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
require 'dry/core/class_attributes'
|
2
|
+
|
3
|
+
module TechnicalAnalysis
|
4
|
+
module BarCalculation
|
5
|
+
|
6
|
+
def true_range previous_close
|
7
|
+
[
|
8
|
+
(high - low),
|
9
|
+
(high - previous_close).abs,
|
10
|
+
(low - previous_close).abs
|
11
|
+
].max
|
12
|
+
end
|
13
|
+
|
14
|
+
def typical_price
|
15
|
+
( high + low + close ) / 3.0
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
module MovingAverage
|
22
|
+
EMA = Struct.new :time, :value
|
23
|
+
WMA = Struct.new :time, :value
|
24
|
+
|
25
|
+
|
26
|
+
# Calculates the exponential moving average (EMA) for the data over the given period
|
27
|
+
# https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
|
28
|
+
#
|
29
|
+
#
|
30
|
+
# z = Symbols::Futures.mini_dax.eod( duration: '30 d').each
|
31
|
+
# e= nil
|
32
|
+
# ema= z.map{|y| e= TechnicalAnalysis::MovingAverage.ema( y.close, z.map(&:close), 30, e ) }
|
33
|
+
#
|
34
|
+
# or
|
35
|
+
#
|
36
|
+
# EMA = Struct.new :time, :ema
|
37
|
+
# e = nil
|
38
|
+
# ema = z.map do |y|
|
39
|
+
# EMA.new y.time,
|
40
|
+
# e = TechnicalAnalysis::MovingAverage.ema y.close, z.map(&:close), 30, e
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
|
44
|
+
def self.ema current_value, data, period, prev_ema
|
45
|
+
if prev_ema.nil?
|
46
|
+
data.sum / data.size.to_f # Average
|
47
|
+
else
|
48
|
+
(current_value - prev_ema) * (2.0 / (period + 1.0)) + prev_ema
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Calculates the weighted moving average
|
53
|
+
#
|
54
|
+
# Parameter is the data-array.
|
55
|
+
#
|
56
|
+
# Takes an optional Block. Specify a method name that returns the data item
|
57
|
+
#
|
58
|
+
# z = Symbols::Futures.mini_dax.eod( duration: '30 d').each
|
59
|
+
# TechnicalAnalysis::ArrayCalculation.wma( z ){ :close }
|
60
|
+
#
|
61
|
+
def self.wma(data)
|
62
|
+
intermediate_values = []
|
63
|
+
data.each_with_index do |datum, i|
|
64
|
+
datum = datum.send yield if block_given?
|
65
|
+
intermediate_values << datum * (i + 1) / (data.size * (data.size + 1) / 2).to_f
|
66
|
+
end
|
67
|
+
intermediate_values.sum
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
## reopen IB::Bar and include BarCalculation ( as Mixin )
|
73
|
+
|
74
|
+
module IB
|
75
|
+
class Bar
|
76
|
+
include TechnicalAnalysis::BarCalculation
|
77
|
+
end
|
78
|
+
# z= Symbols::Futures.mini_dax.eod( duration: '30 d').each
|
79
|
+
#
|
80
|
+
# loop do
|
81
|
+
# bar= z.next
|
82
|
+
# puts bar.time, z.peek.true_range(bar.close)
|
83
|
+
# end.
|
84
|
+
|
85
|
+
# z.rewind
|
86
|
+
#
|
87
|
+
# z.map{ |y| x.typical_price }
|
88
|
+
#
|
89
|
+
end # module
|
90
|
+
|
91
|
+
module TASupport
|
92
|
+
refine Enumerator do
|
93
|
+
#
|
94
|
+
# first include
|
95
|
+
# using TASupport
|
96
|
+
# in your script.
|
97
|
+
#
|
98
|
+
# After fetching stock-data from a file, a database or the broker and
|
99
|
+
# converting it into an Enumerator (simply using array.each)
|
100
|
+
#
|
101
|
+
# calculate
|
102
|
+
#
|
103
|
+
# is just performed on the object
|
104
|
+
#
|
105
|
+
# The result is returned as array of structs.
|
106
|
+
#
|
107
|
+
# z = Symbols::Futures.mini_dax.eod( duration: '50 d').each
|
108
|
+
# z.calculate { :close }
|
109
|
+
#
|
110
|
+
# zz= z.calculate( :ema ){ :typical_price }
|
111
|
+
#
|
112
|
+
# zz= z.calculate( :ema, period: 3 ) { :close }
|
113
|
+
# zz.first
|
114
|
+
# => #<struct TechnicalAnalysis::MovingAverage::EMA time=Wed, 10 Mar 2021, value=0.149441e5
|
115
|
+
def calculate indicator= :ema, **params
|
116
|
+
struct = TechnicalAnalysis::MovingAverage.send :const_get, indicator.to_s.upcase
|
117
|
+
buffer, start = nil, []
|
118
|
+
choice = if block_given?
|
119
|
+
yield
|
120
|
+
elsif peek.respond_to?(:time)
|
121
|
+
:close
|
122
|
+
else
|
123
|
+
nil
|
124
|
+
end
|
125
|
+
data = choice.nil? ? self.to_a : map{|y| y.send choice }
|
126
|
+
period = params[:period] || 30
|
127
|
+
calc_ema = ->(item){ buffer= TechnicalAnalysis::MovingAverage.ema item, data, period, buffer }
|
128
|
+
|
129
|
+
if peek.respond_to? :time
|
130
|
+
map{ | d |
|
131
|
+
value = case indicator
|
132
|
+
when :ema
|
133
|
+
calc_ema[ d.send choice ]
|
134
|
+
when :wma
|
135
|
+
TechnicalAnalysis::MovingAverage.wma start << d.send( choice )
|
136
|
+
end
|
137
|
+
struct.new d.time , value
|
138
|
+
}#map
|
139
|
+
else
|
140
|
+
case indicator
|
141
|
+
when :ema
|
142
|
+
map{ | d | calc_ema[ choice.nil? ? d : d.send( choice ) ] }
|
143
|
+
when :wma
|
144
|
+
map{ |d| TechnicalAnalysis::MovingAverage.wma( start << choice.nil? ? d : d.send( choice ) ) }
|
145
|
+
end # case
|
146
|
+
end # branch
|
147
|
+
end # def
|
148
|
+
end # refine
|
149
|
+
end # module
|
data/lib/ib/bar.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module IB
|
2
|
+
class Bar
|
3
|
+
def true_range previous_close
|
4
|
+
[
|
5
|
+
(high - low),
|
6
|
+
(high - previous_close).abs,
|
7
|
+
(low - previous_close).abs
|
8
|
+
].max
|
9
|
+
end
|
10
|
+
|
11
|
+
def typical_price
|
12
|
+
( high + low + close ) / 3.0
|
13
|
+
end
|
14
|
+
|
15
|
+
def pivot
|
16
|
+
{ pp: p=( high + close + low ).to_f / 3 ,
|
17
|
+
r1: ( 2 * p ).to_f - low.to_f,
|
18
|
+
r2: p + ( high - low ).to_f,
|
19
|
+
s1: ( 2 * p ).to_f - high.to_f,
|
20
|
+
s2: p - ( high - low ).to_f }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/ta_support.rb
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
|
2
|
+
module TASupport
|
3
|
+
refine Enumerator do
|
4
|
+
#
|
5
|
+
# first include
|
6
|
+
# using TASupport
|
7
|
+
# in your script.
|
8
|
+
#
|
9
|
+
# After fetching stock-data from a file, a database or the broker and
|
10
|
+
# converting it into an Enumerator (simply using array.each)
|
11
|
+
#
|
12
|
+
# calculate
|
13
|
+
#
|
14
|
+
# is just performed on the object
|
15
|
+
#
|
16
|
+
# The result is returned as array of structs.
|
17
|
+
#
|
18
|
+
# z = Symbols::Futures.mini_dax.eod( duration: '150 d').each
|
19
|
+
# z.calculate use: :close
|
20
|
+
#
|
21
|
+
# zz= z.calculate :ema, use: :typical_price
|
22
|
+
#
|
23
|
+
# zz= z.calculate( :ema, period: 3, use: :close
|
24
|
+
# zz.first
|
25
|
+
# => #<struct TechnicalAnalysis::MovingAverage::EMA time=Wed, 10 Mar 2021, value=0.149441e5
|
26
|
+
#
|
27
|
+
# Input-data are converted to float and then applied to the indicator-calculations
|
28
|
+
#
|
29
|
+
# A block can be provided to execute commands after calculating each single indicator value
|
30
|
+
# This is provided to enable backtests on the data
|
31
|
+
#
|
32
|
+
# The block gets the input-data **and** the calculated indicator struct.
|
33
|
+
#
|
34
|
+
# i.e.
|
35
|
+
# buffer=[]
|
36
|
+
# zz= z.calculate( :ema, use: :typical_price ) do | raw, struct |
|
37
|
+
# buffer << struct.value
|
38
|
+
# buffer.shift if buffer.size >2
|
39
|
+
# momentum_indicator = (buffer.first - buffer.last) <=> 0
|
40
|
+
# crossing = case momentum_indicator
|
41
|
+
# when +1
|
42
|
+
# buffer.first > raw.close && buffer.last < raw.close
|
43
|
+
# when -1
|
44
|
+
# buffer.first < raw.close && buffer.last > raw.close
|
45
|
+
# end
|
46
|
+
# buy_or_sell = momentum_indicator == 1 ? "buy" : "sell"
|
47
|
+
# puts "#{buy_or_sell}-Signal: EMA-Indicator-Crossing @ #{struct.time}" if crossing
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
#
|
51
|
+
def calculate indicator= :ema, **params
|
52
|
+
struct = if indicator.to_s[-2,2]=='ma'
|
53
|
+
TechnicalAnalysis::MovingAverage.send :const_get, indicator.to_s.upcase
|
54
|
+
elsif indicator.to_s[-2,2]=='si' || indicator== :lane
|
55
|
+
TechnicalAnalysis::Momentum.send :const_get, indicator.to_s.upcase
|
56
|
+
end
|
57
|
+
buffer, start, default_value = nil, [], nil
|
58
|
+
|
59
|
+
## strict-mode
|
60
|
+
strict_mode = params[:strict] || false
|
61
|
+
|
62
|
+
choice = if params[:use].present?
|
63
|
+
params[:use]
|
64
|
+
elsif peek.respond_to?(:time)
|
65
|
+
:close
|
66
|
+
else
|
67
|
+
nil
|
68
|
+
end
|
69
|
+
## fill in defaults
|
70
|
+
case indicator
|
71
|
+
when :ema, :wma, :sma, :rsi
|
72
|
+
period = params[:period] || 15
|
73
|
+
when :kama
|
74
|
+
period = params[:period] || 15
|
75
|
+
fast = params[:fast] || 2
|
76
|
+
slow= params[:slow] || 30
|
77
|
+
when :tsi
|
78
|
+
high = params[:high] || 25
|
79
|
+
low = params[:low] || 13
|
80
|
+
when :lane
|
81
|
+
period = params[:period] || 10
|
82
|
+
fast = params[:fast] || 3
|
83
|
+
slow= params[:slow] || 3
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
# start (array of processed values) is updated in every iteration
|
88
|
+
# applies to indicators
|
89
|
+
# kama
|
90
|
+
# sma
|
91
|
+
# wma
|
92
|
+
#
|
93
|
+
a = peek
|
94
|
+
date_field = if a.respond_to? :time
|
95
|
+
:time
|
96
|
+
elsif a.respond_to? :date_time
|
97
|
+
:date_time
|
98
|
+
elsif a.respond_to? :date
|
99
|
+
:date
|
100
|
+
else
|
101
|
+
nil
|
102
|
+
end
|
103
|
+
indicator_method = case indicator
|
104
|
+
when :sma, :simple_ma
|
105
|
+
TechnicalAnalysis::MovingAverage::SimpleMA.new period: period, strict: strict_mode
|
106
|
+
when :ema, :exp_ma
|
107
|
+
TechnicalAnalysis::MovingAverage::ExpMA.new period: period, strict: strict_mode
|
108
|
+
when :wma
|
109
|
+
TechnicalAnalysis::MovingAverage::Wma.new period: period, strict: strict_mode
|
110
|
+
when :kama
|
111
|
+
TechnicalAnalysis::MovingAverage::KaMA.new period: period, strict: strict_mode,
|
112
|
+
fast: fast, slow: slow
|
113
|
+
when :rsi
|
114
|
+
TechnicalAnalysis::Momentum::Rsi.new period: period
|
115
|
+
when :tsi
|
116
|
+
TechnicalAnalysis::Momentum::Tsi.new low: low, high: high
|
117
|
+
when :lane
|
118
|
+
TechnicalAnalysis::Momentum::Lane.new slow: slow, fast: fast, period: period,
|
119
|
+
take: choice
|
120
|
+
end
|
121
|
+
## iterate across the enumerator and return the result of the calculations
|
122
|
+
map.with_index { | d, i |
|
123
|
+
# central point to convert to float
|
124
|
+
unless indicator == :lane
|
125
|
+
raw_data = if date_field.present? || choice.present?
|
126
|
+
d.send(choice).to_f
|
127
|
+
else
|
128
|
+
d.to_f
|
129
|
+
end
|
130
|
+
indicator_method.add_item(raw_data)
|
131
|
+
else
|
132
|
+
indicator_method.add_item(d)
|
133
|
+
end
|
134
|
+
|
135
|
+
next if indicator_method.current.nil? # creates a nil entry
|
136
|
+
value = indicator_method.current # return this value
|
137
|
+
## data-format of the returned array-elements
|
138
|
+
result = if date_field.present?
|
139
|
+
struct.new d.send(date_field), value
|
140
|
+
else
|
141
|
+
value
|
142
|
+
end
|
143
|
+
# expose the input-data and the calculated indicator to the block
|
144
|
+
yielder = yield( d, result) if block_given?
|
145
|
+
yielder.nil? ? result : yielder # return the expression from the block if present
|
146
|
+
}.compact # map
|
147
|
+
end # def
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
## notes on Enumerators
|
152
|
+
#- z:= An Enumerator
|
153
|
+
#- z.size == z.count
|
154
|
+
#- z.entries == z.to_a
|
155
|
+
#- z.take n returns an array of the first n elements
|
156
|
+
#- z.sum, if enumerator-objects define a "+" method
|
157
|
+
#
|