ruby-technical-analysis 0.1.1 → 1.0.4

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.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/lib/ruby-technical-analysis.rb +1 -0
  3. data/lib/ruby_technical_analysis/indicator.rb +41 -0
  4. data/lib/ruby_technical_analysis/indicators/bollinger_bands.rb +50 -0
  5. data/lib/ruby_technical_analysis/indicators/chaikin_money_flow.rb +47 -0
  6. data/lib/ruby_technical_analysis/indicators/chande_momentum_oscillator.rb +56 -0
  7. data/lib/ruby_technical_analysis/indicators/commodity_channel_index.rb +70 -0
  8. data/lib/ruby_technical_analysis/indicators/envelopes_ema.rb +48 -0
  9. data/lib/ruby_technical_analysis/indicators/intraday_momentum_index.rb +45 -0
  10. data/lib/ruby_technical_analysis/indicators/macd.rb +86 -0
  11. data/lib/ruby_technical_analysis/indicators/mass_index.rb +70 -0
  12. data/lib/ruby_technical_analysis/indicators/moving_averages.rb +71 -0
  13. data/lib/ruby_technical_analysis/indicators/pivot_points.rb +75 -0
  14. data/lib/ruby_technical_analysis/indicators/price_channel.rb +48 -0
  15. data/lib/ruby_technical_analysis/indicators/qstick.rb +44 -0
  16. data/lib/ruby_technical_analysis/indicators/rate_of_change.rb +40 -0
  17. data/lib/ruby_technical_analysis/indicators/relative_momentum_index.rb +79 -0
  18. data/lib/ruby_technical_analysis/indicators/relative_strength_index.rb +74 -0
  19. data/lib/ruby_technical_analysis/indicators/statistical_methods.rb +40 -0
  20. data/lib/ruby_technical_analysis/indicators/stochastic_oscillator.rb +99 -0
  21. data/lib/ruby_technical_analysis/indicators/volume_oscillator.rb +50 -0
  22. data/lib/ruby_technical_analysis/indicators/volume_rate_of_change.rb +48 -0
  23. data/lib/ruby_technical_analysis/indicators/wilders_smoothing.rb +47 -0
  24. data/lib/ruby_technical_analysis/indicators/williams_percent_r.rb +69 -0
  25. data/lib/ruby_technical_analysis.rb +24 -7
  26. data/spec/ruby_technical_analysis/indicator_spec.rb +76 -0
  27. data/spec/ruby_technical_analysis/indicators/bollinger_bands_spec.rb +67 -0
  28. data/spec/ruby_technical_analysis/indicators/chaikin_money_flow_spec.rb +63 -0
  29. data/spec/ruby_technical_analysis/indicators/chande_momentum_oscillator_spec.rb +59 -0
  30. data/spec/ruby_technical_analysis/indicators/commodity_channel_index_spec.rb +66 -0
  31. data/spec/ruby_technical_analysis/indicators/envelopes_ema_spec.rb +69 -0
  32. data/spec/ruby_technical_analysis/indicators/intraday_momentum_spec.rb +63 -0
  33. data/spec/ruby_technical_analysis/indicators/macd_spec.rb +61 -0
  34. data/spec/ruby_technical_analysis/indicators/mass_index_spec.rb +67 -0
  35. data/spec/ruby_technical_analysis/indicators/moving_averages_spec.rb +81 -0
  36. data/spec/ruby_technical_analysis/indicators/pivot_points_spec.rb +43 -0
  37. data/spec/ruby_technical_analysis/indicators/price_channel_spec.rb +64 -0
  38. data/spec/ruby_technical_analysis/indicators/qstick_spec.rb +59 -0
  39. data/spec/ruby_technical_analysis/indicators/rate_of_change_spec.rb +59 -0
  40. data/spec/ruby_technical_analysis/indicators/relative_momentum_index_spec.rb +67 -0
  41. data/spec/ruby_technical_analysis/indicators/relative_strength_index_spec.rb +59 -0
  42. data/spec/ruby_technical_analysis/indicators/statistical_methods_spec.rb +91 -0
  43. data/spec/ruby_technical_analysis/indicators/stochastic_oscillator_spec.rb +106 -0
  44. data/spec/ruby_technical_analysis/indicators/volume_oscillator_spec.rb +98 -0
  45. data/spec/ruby_technical_analysis/indicators/volume_rate_of_change_spec.rb +67 -0
  46. data/spec/ruby_technical_analysis/indicators/wiilders_smoothing_spec.rb +67 -0
  47. data/spec/ruby_technical_analysis/indicators/williams_percent_r_spec.rb +71 -0
  48. data/spec/spec_helper.rb +1 -0
  49. metadata +100 -40
  50. data/.rubocop.yml +0 -34
  51. data/CHANGELOG.md +0 -5
  52. data/CODE_OF_CONDUCT.md +0 -84
  53. data/Gemfile +0 -12
  54. data/LICENSE.txt +0 -21
  55. data/README.md +0 -36
  56. data/Rakefile +0 -16
  57. data/lib/ruby-technical-analysis/indicators/bollinger_bands.rb +0 -25
  58. data/lib/ruby-technical-analysis/indicators/chaikin_money_flow.rb +0 -70
  59. data/lib/ruby-technical-analysis/indicators/chande_momentum_oscillator.rb +0 -34
  60. data/lib/ruby-technical-analysis/indicators/commodity_channel_index.rb +0 -64
  61. data/lib/ruby-technical-analysis/indicators/envelopes_ema.rb +0 -24
  62. data/lib/ruby-technical-analysis/indicators/intraday_momentum_index.rb +0 -48
  63. data/lib/ruby-technical-analysis/indicators/macd.rb +0 -47
  64. data/lib/ruby-technical-analysis/indicators/mass_index.rb +0 -73
  65. data/lib/ruby-technical-analysis/indicators/pivot_points.rb +0 -23
  66. data/lib/ruby-technical-analysis/indicators/price_channel.rb +0 -37
  67. data/lib/ruby-technical-analysis/indicators/qstick.rb +0 -40
  68. data/lib/ruby-technical-analysis/indicators/rate_of_change.rb +0 -18
  69. data/lib/ruby-technical-analysis/indicators/relative_momentum_index.rb +0 -66
  70. data/lib/ruby-technical-analysis/indicators/relative_strength_index.rb +0 -63
  71. data/lib/ruby-technical-analysis/indicators/stochastic_oscillator.rb +0 -65
  72. data/lib/ruby-technical-analysis/indicators/volume_oscillator.rb +0 -38
  73. data/lib/ruby-technical-analysis/indicators/volume_rate_of_change.rb +0 -26
  74. data/lib/ruby-technical-analysis/indicators/wilders_smoothing.rb +0 -27
  75. data/lib/ruby-technical-analysis/indicators/williams_percent_r.rb +0 -52
  76. data/lib/ruby-technical-analysis/moving_averages.rb +0 -85
  77. data/lib/ruby-technical-analysis/statistical_methods.rb +0 -24
  78. data/lib/ruby-technical-analysis/version.rb +0 -5
  79. 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