ruby-technical-analysis 0.1.1 → 1.0.3
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 +4 -4
- data/lib/ruby-technical-analysis.rb +1 -0
- data/lib/ruby_technical_analysis/indicator.rb +41 -0
- data/lib/ruby_technical_analysis/indicators/bollinger_bands.rb +50 -0
- data/lib/ruby_technical_analysis/indicators/chaikin_money_flow.rb +47 -0
- data/lib/ruby_technical_analysis/indicators/chande_momentum_oscillator.rb +56 -0
- data/lib/ruby_technical_analysis/indicators/commodity_channel_index.rb +70 -0
- data/lib/ruby_technical_analysis/indicators/envelopes_ema.rb +48 -0
- data/lib/ruby_technical_analysis/indicators/intraday_momentum_index.rb +45 -0
- data/lib/ruby_technical_analysis/indicators/macd.rb +86 -0
- data/lib/ruby_technical_analysis/indicators/mass_index.rb +70 -0
- data/lib/ruby_technical_analysis/indicators/moving_averages.rb +71 -0
- data/lib/ruby_technical_analysis/indicators/pivot_points.rb +75 -0
- data/lib/ruby_technical_analysis/indicators/price_channel.rb +43 -0
- data/lib/ruby_technical_analysis/indicators/qstick.rb +44 -0
- data/lib/ruby_technical_analysis/indicators/rate_of_change.rb +40 -0
- data/lib/ruby_technical_analysis/indicators/relative_momentum_index.rb +79 -0
- data/lib/ruby_technical_analysis/indicators/relative_strength_index.rb +74 -0
- data/lib/ruby_technical_analysis/indicators/statistical_methods.rb +40 -0
- data/lib/ruby_technical_analysis/indicators/stochastic_oscillator.rb +99 -0
- data/lib/ruby_technical_analysis/indicators/volume_oscillator.rb +50 -0
- data/lib/ruby_technical_analysis/indicators/volume_rate_of_change.rb +48 -0
- data/lib/ruby_technical_analysis/indicators/wilders_smoothing.rb +47 -0
- data/lib/ruby_technical_analysis/indicators/williams_percent_r.rb +69 -0
- data/lib/ruby_technical_analysis.rb +24 -7
- data/spec/ruby_technical_analysis/indicator_spec.rb +76 -0
- data/spec/ruby_technical_analysis/indicators/bollinger_bands_spec.rb +67 -0
- data/spec/ruby_technical_analysis/indicators/chaikin_money_flow_spec.rb +63 -0
- data/spec/ruby_technical_analysis/indicators/chande_momentum_oscillator_spec.rb +59 -0
- data/spec/ruby_technical_analysis/indicators/commodity_channel_index_spec.rb +66 -0
- data/spec/ruby_technical_analysis/indicators/envelopes_ema_spec.rb +69 -0
- data/spec/ruby_technical_analysis/indicators/intraday_momentum_spec.rb +63 -0
- data/spec/ruby_technical_analysis/indicators/macd_spec.rb +61 -0
- data/spec/ruby_technical_analysis/indicators/mass_index_spec.rb +67 -0
- data/spec/ruby_technical_analysis/indicators/moving_averages_spec.rb +81 -0
- data/spec/ruby_technical_analysis/indicators/pivot_points_spec.rb +43 -0
- data/spec/ruby_technical_analysis/indicators/price_channel_spec.rb +54 -0
- data/spec/ruby_technical_analysis/indicators/qstick_spec.rb +59 -0
- data/spec/ruby_technical_analysis/indicators/rate_of_change_spec.rb +59 -0
- data/spec/ruby_technical_analysis/indicators/relative_momentum_index_spec.rb +67 -0
- data/spec/ruby_technical_analysis/indicators/relative_strength_index_spec.rb +59 -0
- data/spec/ruby_technical_analysis/indicators/statistical_methods_spec.rb +91 -0
- data/spec/ruby_technical_analysis/indicators/stochastic_oscillator_spec.rb +106 -0
- data/spec/ruby_technical_analysis/indicators/volume_oscillator_spec.rb +98 -0
- data/spec/ruby_technical_analysis/indicators/volume_rate_of_change_spec.rb +67 -0
- data/spec/ruby_technical_analysis/indicators/wiilders_smoothing_spec.rb +67 -0
- data/spec/ruby_technical_analysis/indicators/williams_percent_r_spec.rb +71 -0
- data/spec/spec_helper.rb +1 -0
- metadata +100 -40
- data/.rubocop.yml +0 -34
- data/CHANGELOG.md +0 -5
- data/CODE_OF_CONDUCT.md +0 -84
- data/Gemfile +0 -12
- data/LICENSE.txt +0 -21
- data/README.md +0 -36
- data/Rakefile +0 -16
- data/lib/ruby-technical-analysis/indicators/bollinger_bands.rb +0 -25
- data/lib/ruby-technical-analysis/indicators/chaikin_money_flow.rb +0 -70
- data/lib/ruby-technical-analysis/indicators/chande_momentum_oscillator.rb +0 -34
- data/lib/ruby-technical-analysis/indicators/commodity_channel_index.rb +0 -64
- data/lib/ruby-technical-analysis/indicators/envelopes_ema.rb +0 -24
- data/lib/ruby-technical-analysis/indicators/intraday_momentum_index.rb +0 -48
- data/lib/ruby-technical-analysis/indicators/macd.rb +0 -47
- data/lib/ruby-technical-analysis/indicators/mass_index.rb +0 -73
- data/lib/ruby-technical-analysis/indicators/pivot_points.rb +0 -23
- data/lib/ruby-technical-analysis/indicators/price_channel.rb +0 -37
- data/lib/ruby-technical-analysis/indicators/qstick.rb +0 -40
- data/lib/ruby-technical-analysis/indicators/rate_of_change.rb +0 -18
- data/lib/ruby-technical-analysis/indicators/relative_momentum_index.rb +0 -66
- data/lib/ruby-technical-analysis/indicators/relative_strength_index.rb +0 -63
- data/lib/ruby-technical-analysis/indicators/stochastic_oscillator.rb +0 -65
- data/lib/ruby-technical-analysis/indicators/volume_oscillator.rb +0 -38
- data/lib/ruby-technical-analysis/indicators/volume_rate_of_change.rb +0 -26
- data/lib/ruby-technical-analysis/indicators/wilders_smoothing.rb +0 -27
- data/lib/ruby-technical-analysis/indicators/williams_percent_r.rb +0 -52
- data/lib/ruby-technical-analysis/moving_averages.rb +0 -85
- data/lib/ruby-technical-analysis/statistical_methods.rb +0 -24
- data/lib/ruby-technical-analysis/version.rb +0 -5
- data/sig/ruby-technical-analysis.rbs +0 -4
@@ -1,70 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Chaikin Money Flow indicator
|
4
|
-
# Returns a current singular value
|
5
|
-
module ChaikinMoneyFlow
|
6
|
-
def chaikin_money_flow(period)
|
7
|
-
highs = []
|
8
|
-
lows = []
|
9
|
-
closes = []
|
10
|
-
volumes = []
|
11
|
-
|
12
|
-
each do |h, l, c, v|
|
13
|
-
highs << h
|
14
|
-
lows << l
|
15
|
-
closes << c
|
16
|
-
volumes << v
|
17
|
-
end
|
18
|
-
|
19
|
-
if highs.size < period
|
20
|
-
raise ArgumentError,
|
21
|
-
"High array passed to Chaikin Money Flow cannot be less than the period argument."
|
22
|
-
end
|
23
|
-
|
24
|
-
if lows.size < period
|
25
|
-
raise ArgumentError,
|
26
|
-
"Low array passed to Chaikin Money Flow cannot be less than the period argument."
|
27
|
-
end
|
28
|
-
|
29
|
-
if closes.size < period
|
30
|
-
raise ArgumentError,
|
31
|
-
"Close array passed to Chaikin Money Flow cannot be less than the period argument."
|
32
|
-
end
|
33
|
-
|
34
|
-
if volumes.size < period
|
35
|
-
raise ArgumentError,
|
36
|
-
"Volume array passed to Chaikin Money Flow cannot be less than the period argument."
|
37
|
-
end
|
38
|
-
|
39
|
-
if size < period
|
40
|
-
raise ArgumentError,
|
41
|
-
"Array passed to Bollinger Bands cannot be less than the period argument."
|
42
|
-
end
|
43
|
-
|
44
|
-
highs = highs.last(period)
|
45
|
-
lows = lows.last(period)
|
46
|
-
closes = closes.last(period)
|
47
|
-
volumes = volumes.last(period)
|
48
|
-
|
49
|
-
num_sum = 0
|
50
|
-
vol_sum = 0
|
51
|
-
|
52
|
-
(0..(period - 1)).each do |i|
|
53
|
-
vol_sum += volumes[i]
|
54
|
-
|
55
|
-
cml = closes[i] - lows[i]
|
56
|
-
hmc = highs[i] - closes[i]
|
57
|
-
hml = highs[i] - lows[i]
|
58
|
-
|
59
|
-
num_sum += ((cml - hmc).to_f / hml) * volumes[i]
|
60
|
-
end
|
61
|
-
|
62
|
-
cmf = num_sum.to_f / vol_sum
|
63
|
-
|
64
|
-
cmf.round(5)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
class Array
|
69
|
-
include ChaikinMoneyFlow
|
70
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Chaikin Money Flow indicator
|
4
|
-
# Returns a current singular value
|
5
|
-
module ChandeMomentumOscillator
|
6
|
-
def chande_momentum_oscillator(period)
|
7
|
-
if size < period + 1
|
8
|
-
raise ArgumentError,
|
9
|
-
"Array size is less than the minimum size of the period + 1 for the Chande Momentum Oscillator."
|
10
|
-
end
|
11
|
-
|
12
|
-
closes = last(period + 1)
|
13
|
-
|
14
|
-
up_change_sum = 0
|
15
|
-
down_change_sum = 0
|
16
|
-
|
17
|
-
(1..period).each do |i|
|
18
|
-
if closes[i] >= closes[i - 1]
|
19
|
-
up_change_sum += (closes[i] - closes[i - 1])
|
20
|
-
else
|
21
|
-
down_change_sum += (closes[i - 1] - closes[i])
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
up_sum_minus_down_sum = up_change_sum - down_change_sum
|
26
|
-
up_sum_plus_down_sum = up_change_sum + down_change_sum
|
27
|
-
|
28
|
-
((up_sum_minus_down_sum.to_f / up_sum_plus_down_sum) * 100).round(4)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
class Array
|
33
|
-
include ChandeMomentumOscillator
|
34
|
-
end
|
@@ -1,64 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "../../ruby-technical-analysis/moving_averages"
|
4
|
-
|
5
|
-
# Commodity Channel Index indicator
|
6
|
-
# Returns a current singular value
|
7
|
-
module CommodityChannelIndex
|
8
|
-
def commodity_channel_index(period)
|
9
|
-
min_size = ((period * 2) - 1)
|
10
|
-
|
11
|
-
highs = []
|
12
|
-
lows = []
|
13
|
-
closes = []
|
14
|
-
|
15
|
-
each do |h, l, c|
|
16
|
-
highs << h
|
17
|
-
lows << l
|
18
|
-
closes << c
|
19
|
-
end
|
20
|
-
|
21
|
-
if highs.size < period
|
22
|
-
raise ArgumentError,
|
23
|
-
"High array passed to Chaikin Money Flow cannot be less than the period argument."
|
24
|
-
end
|
25
|
-
|
26
|
-
if lows.size < period
|
27
|
-
raise ArgumentError,
|
28
|
-
"Low array passed to Chaikin Money Flow cannot be less than the period argument."
|
29
|
-
end
|
30
|
-
|
31
|
-
if closes.size < period
|
32
|
-
raise ArgumentError,
|
33
|
-
"Close array passed to Chaikin Money Flow cannot be less than the period argument."
|
34
|
-
end
|
35
|
-
|
36
|
-
highs = highs.last(min_size)
|
37
|
-
lows = lows.last(min_size)
|
38
|
-
closes = closes.last(min_size)
|
39
|
-
|
40
|
-
typical_prices = []
|
41
|
-
tp_sma = []
|
42
|
-
period_sum = 0
|
43
|
-
|
44
|
-
(0..(min_size - 1)).each do |i|
|
45
|
-
typical_prices << (highs[i] + closes[i] + lows[i]) / 3
|
46
|
-
end
|
47
|
-
|
48
|
-
(0..(period - 1)).each do |i|
|
49
|
-
tp_sma << typical_prices[i..(i + period - 1)].sma(period)
|
50
|
-
end
|
51
|
-
|
52
|
-
typical_prices.last(period).each do |tp|
|
53
|
-
period_sum += (tp_sma[-1] - tp).abs
|
54
|
-
end
|
55
|
-
|
56
|
-
ps_next = (period_sum.to_f / period) * 0.015
|
57
|
-
tp_sma_min_tp = typical_prices[-1] - tp_sma[-1]
|
58
|
-
(tp_sma_min_tp.to_f / ps_next)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
class Array
|
63
|
-
include CommodityChannelIndex
|
64
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "../../ruby-technical-analysis/moving_averages"
|
4
|
-
|
5
|
-
# Envelopes EMA indicator
|
6
|
-
# Returns an array of current high, middle and low eema values
|
7
|
-
module EnvelopesEma
|
8
|
-
def envelopes_ema(period, percent)
|
9
|
-
if size < period
|
10
|
-
raise ArgumentError,
|
11
|
-
"Close array passed to Envelopes EMA cannot be less than the period argument."
|
12
|
-
end
|
13
|
-
|
14
|
-
eema = last(period).ema(period)
|
15
|
-
eema_up = (eema.round(3) * ((100 + percent))) / 100
|
16
|
-
eema_down = (eema.round(3) * ((100 - percent))) / 100
|
17
|
-
|
18
|
-
[eema_up.truncate(3), eema.truncate(3), eema_down.truncate(3)]
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
class Array
|
23
|
-
include EnvelopesEma
|
24
|
-
end
|
@@ -1,48 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Intraday Momentum Index indicator
|
4
|
-
# Returns a singular current value
|
5
|
-
module IntradayMomentumIndex
|
6
|
-
def intraday_momentum_index(period)
|
7
|
-
opens = []
|
8
|
-
closes = []
|
9
|
-
|
10
|
-
each do |o, c|
|
11
|
-
opens << o
|
12
|
-
closes << c
|
13
|
-
end
|
14
|
-
|
15
|
-
if opens.size < period
|
16
|
-
raise ArgumentError,
|
17
|
-
"Opens array passed to Intraday Momentum Index cannot be less than the period argument."
|
18
|
-
end
|
19
|
-
|
20
|
-
if closes.size < period
|
21
|
-
raise ArgumentError,
|
22
|
-
"Closes array passed to Intraday Momentum Index cannot be less than the period argument."
|
23
|
-
end
|
24
|
-
|
25
|
-
closes = closes.last(period)
|
26
|
-
opens = opens.last(period)
|
27
|
-
|
28
|
-
gsum = 0.0
|
29
|
-
lsum = 0.0
|
30
|
-
|
31
|
-
(0..(period - 1)).each do |i|
|
32
|
-
cmo = (closes[i] - opens[i]).abs
|
33
|
-
if closes[i] > opens[i]
|
34
|
-
gsum += cmo
|
35
|
-
else
|
36
|
-
lsum += cmo
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
gsum_plus_lsum = gsum + lsum
|
41
|
-
|
42
|
-
((gsum.to_f / gsum_plus_lsum) * 100).round(4)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
class Array
|
47
|
-
include IntradayMomentumIndex
|
48
|
-
end
|
@@ -1,47 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "../../ruby-technical-analysis/moving_averages"
|
4
|
-
|
5
|
-
# Moving Average Convergence Divergence (MACD) indicator
|
6
|
-
# Returns an array of current macd value and signal value
|
7
|
-
module Macd
|
8
|
-
def macd(fast_period, slow_period, signal_period)
|
9
|
-
if size < (slow_period + signal_period)
|
10
|
-
raise ArgumentError,
|
11
|
-
"Closes array passed to MACD cannot be less than the (slow period + signal period) arguments."
|
12
|
-
end
|
13
|
-
|
14
|
-
fast_pct = (2.0 / (fast_period + 1)).truncate(6)
|
15
|
-
slow_pct = (2.0 / (slow_period + 1)).truncate(6)
|
16
|
-
sig_pct = (2.0 / (signal_period + 1)).truncate(6)
|
17
|
-
|
18
|
-
fast_arr = []
|
19
|
-
slow_arr = []
|
20
|
-
|
21
|
-
seed = true
|
22
|
-
each do |i|
|
23
|
-
if seed
|
24
|
-
fast_arr << i
|
25
|
-
slow_arr << i
|
26
|
-
seed = false
|
27
|
-
else
|
28
|
-
fast_arr << ((i * fast_pct) + ((fast_arr[-1]) * (1 - fast_pct))).round(3)
|
29
|
-
slow_arr << ((i * slow_pct) + ((slow_arr[-1]) * (1 - slow_pct))).round(3)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
sig_arr = []
|
34
|
-
|
35
|
-
(0..signal_period - 1).each do |i|
|
36
|
-
sig_arr << (fast_arr[slow_period + i - 1] - slow_arr[slow_period + i - 1]).round(3)
|
37
|
-
end
|
38
|
-
|
39
|
-
signal = ((sig_arr[-1] * sig_pct) + ((sig_arr[-2]) * (1 - sig_pct))).round(3)
|
40
|
-
|
41
|
-
[(fast_arr[-1] - slow_arr[-1]).round(4), signal, (fast_arr[-1] - slow_arr[-1]).round(4) - signal]
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
class Array
|
46
|
-
include Macd
|
47
|
-
end
|
@@ -1,73 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "../../ruby-technical-analysis/moving_averages"
|
4
|
-
|
5
|
-
# Mass Index indicator
|
6
|
-
# Returns a singular current value
|
7
|
-
module MassIndex
|
8
|
-
def mass_index(period)
|
9
|
-
highs = []
|
10
|
-
lows = []
|
11
|
-
|
12
|
-
each do |i|
|
13
|
-
highs << i[0]
|
14
|
-
lows << i[1]
|
15
|
-
end
|
16
|
-
|
17
|
-
if highs.size < period
|
18
|
-
raise ArgumentError,
|
19
|
-
"High array passed to Mass Index cannot be less than (2 * period + 1)."
|
20
|
-
end
|
21
|
-
|
22
|
-
if lows.size < period
|
23
|
-
raise ArgumentError,
|
24
|
-
"Low array passed to Mass Index cannot be less than (2 * period + 1)."
|
25
|
-
end
|
26
|
-
|
27
|
-
full_period = (2 * period + 1)
|
28
|
-
highs = highs.last(full_period)
|
29
|
-
lows = lows.last(full_period)
|
30
|
-
|
31
|
-
hml_arr = []
|
32
|
-
hml_ema_arr = []
|
33
|
-
hml_ema_ema_arr = []
|
34
|
-
|
35
|
-
(0..(highs.size - 1)).each do |i|
|
36
|
-
hml_arr << highs[i] - lows[i]
|
37
|
-
end
|
38
|
-
|
39
|
-
low_multiple = (2.0 / (period + 1)).truncate(4)
|
40
|
-
high_multiple = 1 - low_multiple
|
41
|
-
|
42
|
-
(0..hml_arr.length - 1).each do |i|
|
43
|
-
hml_ema_arr << if i.zero?
|
44
|
-
hml_arr[0].truncate(4)
|
45
|
-
else
|
46
|
-
((hml_arr[i] * low_multiple) + (hml_ema_arr[i - 1] * high_multiple)).truncate(4)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
(0..period + 1).each do |i|
|
51
|
-
hml_ema_ema_arr << if i.zero?
|
52
|
-
hml_ema_arr[period - i - 1]
|
53
|
-
else
|
54
|
-
((hml_ema_arr[period + i - 1] * 0.2) + (hml_ema_ema_arr[-1] * 0.8)).round(4)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
ema_period_two_div_ema_period = []
|
59
|
-
|
60
|
-
mi = 0.0
|
61
|
-
(0..2).each do |i|
|
62
|
-
ema_period_two_div_ema_period <<
|
63
|
-
((hml_ema_arr[(period * 2) + i - 2]) / (hml_ema_ema_arr[period + i - 1])).round(4)
|
64
|
-
mi += ((hml_ema_arr[(period * 2) + i - 2]) / (hml_ema_ema_arr[period + i - 1])).round(4)
|
65
|
-
end
|
66
|
-
|
67
|
-
mi.round(4)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
class Array
|
72
|
-
include MassIndex
|
73
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Pivot Points indicator
|
4
|
-
# Returns an array of the current pivot points for the provided H, L, C array
|
5
|
-
module PivotPoints
|
6
|
-
def pivot_points
|
7
|
-
h = at(0)
|
8
|
-
l = at(1)
|
9
|
-
c = at(2)
|
10
|
-
pp = ((h + l + c) / 3.0).round(2)
|
11
|
-
r1 = ((pp * 2) - l).round(2)
|
12
|
-
s1 = ((pp * 2) - h).round(2)
|
13
|
-
r2 = (pp + (h - l)).round(2)
|
14
|
-
s2 = (pp - (h - l)).round(2)
|
15
|
-
r3 = (h + (2 * (pp - l))).round(2)
|
16
|
-
s3 = (l - (2 * (h - pp))).round(2)
|
17
|
-
[s3, s2, s1, pp, r1, r2, r3]
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
class Array
|
22
|
-
include PivotPoints
|
23
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Price Channel indicator
|
4
|
-
# Returns an array containing the current upper and lower values of the series
|
5
|
-
module PriceChannel
|
6
|
-
def price_channel(period)
|
7
|
-
highs = []
|
8
|
-
lows = []
|
9
|
-
|
10
|
-
each do |i|
|
11
|
-
highs << i[0]
|
12
|
-
lows << i[1]
|
13
|
-
end
|
14
|
-
|
15
|
-
if highs.size < period + 1
|
16
|
-
raise ArgumentError,
|
17
|
-
"The highs array size is less than the period + 1 size required."
|
18
|
-
end
|
19
|
-
|
20
|
-
if lows.size < period + 1
|
21
|
-
raise ArgumentError,
|
22
|
-
"The lows array size is less than the period + 1 size required."
|
23
|
-
end
|
24
|
-
|
25
|
-
highs = highs.last(period + 1)
|
26
|
-
lows = lows.last(period + 1)
|
27
|
-
|
28
|
-
upper_pc = (highs[0..period - 1]).max
|
29
|
-
lower_pc = (lows[0..period - 1]).min
|
30
|
-
|
31
|
-
[upper_pc, lower_pc]
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
class Array
|
36
|
-
include PriceChannel
|
37
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Qstick indicator
|
4
|
-
# Returns a single value
|
5
|
-
module Qstick
|
6
|
-
def qstick(period)
|
7
|
-
opens = []
|
8
|
-
closes = []
|
9
|
-
|
10
|
-
each do |i|
|
11
|
-
opens << i[0]
|
12
|
-
closes << i[1]
|
13
|
-
end
|
14
|
-
|
15
|
-
if opens.size < period
|
16
|
-
raise ArgumentError,
|
17
|
-
"Opens array passed to Qstick cannot be less than the period argument."
|
18
|
-
end
|
19
|
-
|
20
|
-
if closes.size < period
|
21
|
-
raise ArgumentError,
|
22
|
-
"Closes array passed to Qstick cannot be less than the period argument."
|
23
|
-
end
|
24
|
-
|
25
|
-
opens = opens.last(period)
|
26
|
-
closes = closes.last(period)
|
27
|
-
|
28
|
-
cmo_sum = 0.0
|
29
|
-
|
30
|
-
(0..(period - 1)).each do |i|
|
31
|
-
cmo_sum += closes[i] - opens[i]
|
32
|
-
end
|
33
|
-
|
34
|
-
(cmo_sum.to_f / period).round(4)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
class Array
|
39
|
-
include Qstick
|
40
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# RateOfChange indicator
|
4
|
-
# Returns a single value
|
5
|
-
module RateOfChange
|
6
|
-
def rate_of_change(period)
|
7
|
-
if size < (period + 1)
|
8
|
-
raise ArgumentError,
|
9
|
-
"Closes array passed to RateOfChange cannot be less than the period argument + 1."
|
10
|
-
end
|
11
|
-
|
12
|
-
(((self[-1] - last(period + 1)[0]).to_f / last(period + 1)[0]) * 100).round(2)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
class Array
|
17
|
-
include RateOfChange
|
18
|
-
end
|
@@ -1,66 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "wilders_smoothing"
|
4
|
-
|
5
|
-
# Relative Momentum Index indicator
|
6
|
-
# Returns a single value
|
7
|
-
module RelativeMomentumIndex
|
8
|
-
def relative_momentum_index(period_mom, period_rmi)
|
9
|
-
pmpr = period_mom + period_rmi
|
10
|
-
|
11
|
-
if size < pmpr
|
12
|
-
raise ArgumentError,
|
13
|
-
"Closes array passed to Relative Momentum Index cannot be less than the period mom + period rmi arguments."
|
14
|
-
end
|
15
|
-
|
16
|
-
rmi = []
|
17
|
-
rmi_intermediate = []
|
18
|
-
wilders_is_set = false
|
19
|
-
smooth_up = []
|
20
|
-
smooth_down = []
|
21
|
-
|
22
|
-
smooth_coef_one = (1.0 / period_rmi).round(4)
|
23
|
-
smooth_coef_two = (1 - smooth_coef_one)
|
24
|
-
|
25
|
-
(0..(size - pmpr)).each do |i|
|
26
|
-
cla = self[i..(i + pmpr - 1)]
|
27
|
-
up_ch = []
|
28
|
-
down_ch = []
|
29
|
-
|
30
|
-
(0..period_rmi - 1).each do |m|
|
31
|
-
cur_close = cla[m]
|
32
|
-
prev_close = cla[period_mom + m]
|
33
|
-
diff = (cur_close - prev_close).round(4)
|
34
|
-
|
35
|
-
if diff.negative?
|
36
|
-
up_ch << diff.abs
|
37
|
-
down_ch << 0.00
|
38
|
-
elsif diff.positive?
|
39
|
-
up_ch << 0.00
|
40
|
-
down_ch << diff
|
41
|
-
else
|
42
|
-
up_ch << 0.00
|
43
|
-
down_ch << 0.00
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
if wilders_is_set
|
48
|
-
smooth_up << (smooth_coef_one * up_ch[-1] + smooth_coef_two * smooth_up[-1]).round(4)
|
49
|
-
smooth_down << (smooth_coef_one * down_ch[-1] + smooth_coef_two * smooth_down[-1]).round(4)
|
50
|
-
else
|
51
|
-
smooth_up << up_ch.wilders_smoothing(period_rmi)
|
52
|
-
smooth_down << down_ch.wilders_smoothing(period_rmi)
|
53
|
-
wilders_is_set = true
|
54
|
-
end
|
55
|
-
|
56
|
-
rmi_intermediate << (smooth_up[-1].to_f / smooth_down[-1])
|
57
|
-
rmi << ((rmi_intermediate[-1].to_f / (1 + rmi_intermediate[-1])) * 100).round(4)
|
58
|
-
end
|
59
|
-
|
60
|
-
rmi[-1]
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
class Array
|
65
|
-
include RelativeMomentumIndex
|
66
|
-
end
|
@@ -1,63 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "wilders_smoothing"
|
4
|
-
|
5
|
-
# Relative Momentum Index indicator
|
6
|
-
# Returns a single value
|
7
|
-
module RelativeStrengthIndex
|
8
|
-
def rsi(period)
|
9
|
-
if size < (period + 1)
|
10
|
-
raise ArgumentError,
|
11
|
-
"Closes array passed to Relative Strength Index cannot be less than the period + 1 argument."
|
12
|
-
end
|
13
|
-
|
14
|
-
rsi = []
|
15
|
-
wilders_is_set = false
|
16
|
-
smooth_up = []
|
17
|
-
smooth_down = []
|
18
|
-
|
19
|
-
smooth_coef_one = (1.0 / period).round(4)
|
20
|
-
smooth_coef_two = (1 - smooth_coef_one)
|
21
|
-
|
22
|
-
(0..(size - period - 1)).each do |k|
|
23
|
-
cla = self[k..k + period]
|
24
|
-
|
25
|
-
up_ch = []
|
26
|
-
down_ch = []
|
27
|
-
|
28
|
-
(1..period).each do |i|
|
29
|
-
cur_close = cla[i]
|
30
|
-
prev_close = cla[i - 1]
|
31
|
-
close_diff = cur_close - prev_close
|
32
|
-
|
33
|
-
if close_diff > 0.00
|
34
|
-
up_ch << close_diff
|
35
|
-
down_ch << 0.00
|
36
|
-
elsif close_diff < 0.00
|
37
|
-
up_ch << 0.00
|
38
|
-
down_ch << close_diff.abs
|
39
|
-
else
|
40
|
-
up_ch << 0.00
|
41
|
-
down_ch << 0.00
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
if wilders_is_set
|
46
|
-
smooth_up << (smooth_coef_one * up_ch[-1] + smooth_coef_two * smooth_up[-1]).round(4)
|
47
|
-
smooth_down << (smooth_coef_one * down_ch[-1] + smooth_coef_two * smooth_down[-1]).round(4)
|
48
|
-
else
|
49
|
-
smooth_up << up_ch.last(period).wilders_smoothing(period)
|
50
|
-
smooth_down << down_ch.last(period).wilders_smoothing(period)
|
51
|
-
wilders_is_set = true
|
52
|
-
end
|
53
|
-
|
54
|
-
rsi << (100.00 - (100.00 / ((smooth_up[-1].to_f / smooth_down[-1]) + 1))).round(4)
|
55
|
-
end
|
56
|
-
|
57
|
-
rsi[-1]
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
class Array
|
62
|
-
include RelativeStrengthIndex
|
63
|
-
end
|
@@ -1,65 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Stochastic Oscillator indicator
|
4
|
-
# Returns a single value
|
5
|
-
module StochasticOscillator
|
6
|
-
def stochastic_oscillator(k_periods, k_slow_periods, d_periods)
|
7
|
-
highs = []
|
8
|
-
lows = []
|
9
|
-
closes = []
|
10
|
-
|
11
|
-
each do |i|
|
12
|
-
highs << i[0]
|
13
|
-
lows << i[1]
|
14
|
-
closes << i[2]
|
15
|
-
end
|
16
|
-
|
17
|
-
if highs.size < k_periods
|
18
|
-
raise ArgumentError,
|
19
|
-
"High array passed to Stochastic Oscillator cannot be less than the k_periods argument."
|
20
|
-
end
|
21
|
-
|
22
|
-
if lows.size < k_periods
|
23
|
-
raise ArgumentError,
|
24
|
-
"Low array passed to Stochastic Oscillator cannot be less than the k_periods argument."
|
25
|
-
end
|
26
|
-
|
27
|
-
if closes.size < k_periods
|
28
|
-
raise ArgumentError,
|
29
|
-
"Close array passed to Stochastic Oscillator cannot be less than the k_periods argument."
|
30
|
-
end
|
31
|
-
|
32
|
-
lowest_lows = []
|
33
|
-
highest_highs = []
|
34
|
-
close_minus_ll = []
|
35
|
-
hh_minus_ll = []
|
36
|
-
|
37
|
-
ks_sums_close_min_ll = []
|
38
|
-
ks_sums_hh_min_ll = []
|
39
|
-
ks_div_x_100 = []
|
40
|
-
d_periods_sma = []
|
41
|
-
|
42
|
-
(0..(highs.length - k_periods)).each do |i|
|
43
|
-
lowest_lows << lows[i..(i + k_periods - 1)].min
|
44
|
-
highest_highs << highs[i..(i + k_periods - 1)].max
|
45
|
-
close_minus_ll << (closes[i + k_periods - 1] - lowest_lows.last).round(4)
|
46
|
-
hh_minus_ll << (highest_highs.last - lowest_lows.last).round(4)
|
47
|
-
if close_minus_ll.length >= k_slow_periods
|
48
|
-
ks_sums_close_min_ll << close_minus_ll.last(k_slow_periods).inject(:+).round(4)
|
49
|
-
ks_sums_hh_min_ll << hh_minus_ll.last(k_slow_periods).inject(:+).round(4)
|
50
|
-
ks_div_x_100 << ((ks_sums_close_min_ll.last.to_f / ks_sums_hh_min_ll.last) * 100).round(4)
|
51
|
-
end
|
52
|
-
d_periods_sma << if ks_div_x_100.length >= d_periods
|
53
|
-
(ks_div_x_100.last(d_periods).reduce(:+).to_f / d_periods).round(4)
|
54
|
-
else
|
55
|
-
-1000
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
d_periods_sma[-1]
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
class Array
|
64
|
-
include StochasticOscillator
|
65
|
-
end
|