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.
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 +43 -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 +54 -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
@@ -0,0 +1,43 @@
1
+ module RubyTechnicalAnalysis
2
+ # Price Channel
3
+ #
4
+ # Find more information at: https://www.investopedia.com/terms/p/price-channel.asp
5
+ class PriceChannel < Indicator
6
+ attr_reader :period
7
+
8
+ # @param series [Array] An array of arrays containing high, low prices, e.g. [[high, low], [high, low]]
9
+ # @param period [Integer] The number of periods to use in the calculation
10
+ def initialize(series: [], period: 20)
11
+ @period = period
12
+
13
+ super(series: series)
14
+ end
15
+
16
+ # @return [Array] An array containing the current upper and lower price channel values
17
+ def call
18
+ calculate_price_channel
19
+ end
20
+
21
+ private
22
+
23
+ def _highs
24
+ @_highs ||= series.last(period + 1).map { |value| value.at(0) }
25
+ end
26
+
27
+ def _lows
28
+ @_lows ||= series.last(period + 1).map { |value| value.at(1) }
29
+ end
30
+
31
+ def upper_price_channel
32
+ _highs[0..period - 1].max
33
+ end
34
+
35
+ def lower_price_channel
36
+ _lows[0..period - 1].min
37
+ end
38
+
39
+ def calculate_price_channel
40
+ [upper_price_channel, lower_price_channel]
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,44 @@
1
+ module RubyTechnicalAnalysis
2
+ # Qstick
3
+ #
4
+ # Find more information at: https://www.investopedia.com/terms/q/qstick.asp
5
+ class QStick < Indicator
6
+ attr_reader :period
7
+
8
+ # @param series [Array] An array of arrays containing open, close prices, e.g. [[open, close], [open, close]]
9
+ # @param period [Integer] The number of periods to use in the calculation
10
+ def initialize(series: [], period: 20)
11
+ @period = period
12
+
13
+ super(series: series)
14
+ end
15
+
16
+ # @return [Float] The current Qstick value
17
+ def call
18
+ calculate_qstick
19
+ end
20
+
21
+ # @return [Boolean] Whether or not the object is valid
22
+ def valid?
23
+ period <= series.length
24
+ end
25
+
26
+ private
27
+
28
+ def _opens
29
+ @_opens ||= series.last(period).map { |value| value.at(0) }
30
+ end
31
+
32
+ def _closes
33
+ @_closes ||= series.last(period).map { |value| value.at(1) }
34
+ end
35
+
36
+ def cmo_sum
37
+ _closes.zip(_opens).sum { |close, open| close - open }
38
+ end
39
+
40
+ def calculate_qstick
41
+ (cmo_sum.to_f / period).round(4)
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,40 @@
1
+ module RubyTechnicalAnalysis
2
+ # Rate Of Change
3
+ #
4
+ # Find more information at: https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/roc
5
+ class RateOfChange < Indicator
6
+ attr_reader :period
7
+
8
+ # @param series [Array] An array of prices, typically closing prices
9
+ # @param period [Integer] The number of periods to use in the calculation
10
+ def initialize(series: [], period: 30)
11
+ @period = period
12
+
13
+ super(series: series)
14
+ end
15
+
16
+ # @return [Float] The current ROC value
17
+ def call
18
+ calculate_roc
19
+ end
20
+
21
+ # @return [Boolean] Whether or not the object is valid
22
+ def valid?
23
+ period + 1 <= series.length
24
+ end
25
+
26
+ private
27
+
28
+ def calculate_roc
29
+ (((current_price - lookback_price).to_f / lookback_price) * 100).round(2)
30
+ end
31
+
32
+ def current_price
33
+ series.last
34
+ end
35
+
36
+ def lookback_price
37
+ series.last(period + 1).first
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,79 @@
1
+ module RubyTechnicalAnalysis
2
+ # Relative Momentum Index
3
+ class RelativeMomentumIndex < Indicator
4
+ attr_reader :period_mom, :period_rmi
5
+
6
+ # @param series [Array] An array of prices, typically closing prices
7
+ # @param period_mom [Integer] The number of periods to use in the momentum calculation
8
+ # @param period_rmi [Integer] The number of periods to use in the RMI calculation
9
+ def initialize(series: [], period_mom: 14, period_rmi: 20)
10
+ @period_mom = period_mom
11
+ @period_rmi = period_rmi
12
+ @rmi = []
13
+ @rmi_intermediate = []
14
+ @smooth_up = []
15
+ @smooth_down = []
16
+ @wilders_is_set = false
17
+
18
+ super(series: series)
19
+ end
20
+
21
+ # @return [Float] The current RMI value
22
+ def call
23
+ calculate_rmi
24
+ end
25
+
26
+ # @return [Boolean] Whether or not the object is valid
27
+ def valid?
28
+ period_mom + period_rmi <= series.length
29
+ end
30
+
31
+ private
32
+
33
+ def _pmpr
34
+ @_pmpr ||= (period_mom + period_rmi)
35
+ end
36
+
37
+ def _smooth_coef_one
38
+ @_smooth_coef_one ||= (1.0 / period_rmi).round(4)
39
+ end
40
+
41
+ def _smooth_coef_two
42
+ @_smooth_coef_two ||= (1 - _smooth_coef_one)
43
+ end
44
+
45
+ def calculate_channels(cla)
46
+ period_rmi.times.map do |index|
47
+ diff = (cla.at(index) - cla.at(period_mom + index)).round(4)
48
+ [diff.negative? ? diff.abs : 0, diff.positive? ? diff : 0]
49
+ end.transpose
50
+ end
51
+
52
+ def calculate_initial_smoothing(up_ch, down_ch)
53
+ @smooth_up << RubyTechnicalAnalysis::WildersSmoothing.call(series: up_ch, period: period_rmi)
54
+ @smooth_down << RubyTechnicalAnalysis::WildersSmoothing.call(series: down_ch, period: period_rmi)
55
+ @wilders_is_set = true
56
+ end
57
+
58
+ def calculate_subsequent_smoothing(up_ch, down_ch)
59
+ @smooth_up << (_smooth_coef_one * up_ch.last + _smooth_coef_two * @smooth_up.last).round(4)
60
+ @smooth_down << (_smooth_coef_one * down_ch.last + _smooth_coef_two * @smooth_down.last).round(4)
61
+ end
62
+
63
+ def calculate_smoothing(up_ch, down_ch)
64
+ @wilders_is_set ? calculate_subsequent_smoothing(up_ch, down_ch) : calculate_initial_smoothing(up_ch, down_ch)
65
+ end
66
+
67
+ def calculate_rmi
68
+ (0..(series.size - _pmpr)).flat_map do |index|
69
+ cla = series[index..(index + _pmpr - 1)]
70
+ up_ch, down_ch = calculate_channels(cla)
71
+
72
+ calculate_smoothing(up_ch, down_ch)
73
+
74
+ @rmi_intermediate << (@smooth_up.last.to_f / @smooth_down.last)
75
+ @rmi << ((@rmi_intermediate.last.to_f / (1 + @rmi_intermediate.last)) * 100).round(4)
76
+ end.last
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,74 @@
1
+ module RubyTechnicalAnalysis
2
+ # Relative Strength Index
3
+ #
4
+ # Find more information at: https://www.fidelity.com/viewpoints/active-investor/how-to-use-RSI
5
+ class RelativeStrengthIndex < Indicator
6
+ attr_reader :period
7
+
8
+ # @param series [Array] An array of prices, typically closing prices
9
+ # @param period [Integer] The number of periods to use in the calculation
10
+ def initialize(series: [], period: 14)
11
+ @period = period
12
+ @rsi = []
13
+ @smooth_up = []
14
+ @smooth_down = []
15
+ @wilders_is_set = false
16
+
17
+ super(series: series)
18
+ end
19
+
20
+ # @return [Float] The current RSI value
21
+ def call
22
+ calculate_rsi
23
+ end
24
+
25
+ # @return [Boolean] Whether or not the object is valid
26
+ def valid?
27
+ period < series.length
28
+ end
29
+
30
+ private
31
+
32
+ def _smooth_coef_one
33
+ @_smooth_coef_one ||= (1.0 / period).round(4)
34
+ end
35
+
36
+ def _smooth_coef_two
37
+ @_smooth_coef_two ||= (1 - _smooth_coef_one)
38
+ end
39
+
40
+ def calculate_channels(cla)
41
+ period.times.map do |index|
42
+ diff = (cla.at(index) - cla.at(index + 1)).round(4)
43
+
44
+ [diff.negative? ? diff.abs : 0, diff.positive? ? diff : 0]
45
+ end.transpose
46
+ end
47
+
48
+ def calculate_initial_smoothing(up_ch, down_ch)
49
+ @smooth_up << RubyTechnicalAnalysis::WildersSmoothing.call(series: up_ch, period: period)
50
+ @smooth_down << RubyTechnicalAnalysis::WildersSmoothing.call(series: down_ch, period: period)
51
+
52
+ @wilders_is_set = true
53
+ end
54
+
55
+ def calculate_subsequent_smoothing(up_ch, down_ch)
56
+ @smooth_up << (_smooth_coef_one * up_ch.last + _smooth_coef_two * @smooth_up.last).round(4)
57
+ @smooth_down << (_smooth_coef_one * down_ch.last + _smooth_coef_two * @smooth_down.last).round(4)
58
+ end
59
+
60
+ def calculate_smoothing(up_ch, down_ch)
61
+ @wilders_is_set ? calculate_subsequent_smoothing(up_ch, down_ch) : calculate_initial_smoothing(up_ch, down_ch)
62
+ end
63
+
64
+ def calculate_rsi
65
+ (0..(series.size - period - 1)).flat_map do |index|
66
+ cla = series[index..index + period]
67
+ up_ch, down_ch = calculate_channels(cla)
68
+
69
+ calculate_smoothing(up_ch, down_ch)
70
+ @rsi << (100.00 - (100.00 / ((@smooth_up.last.to_f / @smooth_down.last) + 1))).round(4)
71
+ end.last
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,40 @@
1
+ module RubyTechnicalAnalysis
2
+ # Statistical Methods
3
+ class StatisticalMethods < Indicator
4
+ # @param series [Array] An array of prices, typically closing prices
5
+ # def initialize(series: [])
6
+ # super(series: series)
7
+ # end
8
+
9
+ # Mean
10
+ # @return [Float] The mean of the price series
11
+ def mean
12
+ series.reduce(:+) / series.length.to_f
13
+ end
14
+
15
+ # Standard Deviation
16
+ # @return [Float] The standard deviation of the price series
17
+ def standard_deviation
18
+ return 0 if series.uniq.length == 1
19
+
20
+ Math.sqrt(variance)
21
+ end
22
+
23
+ # Variance
24
+ # @return [Float] The variance of the price series
25
+ def variance
26
+ squared_differences.reduce(:+) / series.length.to_f
27
+ end
28
+
29
+ # @return [Boolean] Whether or not the object is valid
30
+ def valid?
31
+ series.length > 0
32
+ end
33
+
34
+ private
35
+
36
+ def squared_differences
37
+ series.map { |value| (value - mean)**2 }
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,99 @@
1
+ module RubyTechnicalAnalysis
2
+ # Stochastic Oscillator
3
+ #
4
+ # Find more information at: https://www.investopedia.com/terms/s/stochasticoscillator.asp
5
+ class StochasticOscillator < Indicator
6
+ attr_reader :k_periods, :k_slow_periods, :d_periods
7
+
8
+ # @param series [Array] An array of arrays containing high, low, close prices, e.g. [[high, low, close], [high, low, close]]
9
+ # @param k_periods [Integer] The number of periods to use in the calculation
10
+ # @param k_slow_periods [Integer] The number of periods to use in the calculation
11
+ # @param d_periods [Integer] The number of periods to use in the calculation
12
+ def initialize(series: [], k_periods: 14, k_slow_periods: 3, d_periods: 3)
13
+ @k_periods = k_periods
14
+ @k_slow_periods = k_slow_periods
15
+ @d_periods = d_periods
16
+ @lowest_lows = []
17
+ @highest_highs = []
18
+ @close_minus_lowest_lows = []
19
+ @highest_highs_minus_lowest_lows = []
20
+ @ks_sums_close_minus_lowest_lows = []
21
+ @ks_sums_highest_highs_minus_lowest_lows = []
22
+ @ks_sums_quotients_times_one_hundred = []
23
+ @d_periods_sma = []
24
+
25
+ super(series: series)
26
+ end
27
+
28
+ # @return [Float] The current Stochastic Oscillator value
29
+ def call
30
+ calculate_stochastic_oscillator
31
+ end
32
+
33
+ # @return [Boolean] Whether or not the object is valid
34
+ def valid?
35
+ k_periods + d_periods <= series.length
36
+ end
37
+
38
+ private
39
+
40
+ def calculate_lowest_lows(lows, window_start)
41
+ @lowest_lows << lows[window_start..(window_start + k_periods - 1)].min
42
+ end
43
+
44
+ def calculate_highest_highs(highs, window_start)
45
+ @highest_highs << highs[window_start..(window_start + k_periods - 1)].max
46
+ end
47
+
48
+ def calculate_close_minus_lowest_lows(closes, window_start)
49
+ @close_minus_lowest_lows <<
50
+ (closes.at(window_start + k_periods - 1) - @lowest_lows.last).round(4)
51
+ end
52
+
53
+ def calculate_highest_highs_minus_lowest_lows
54
+ @highest_highs_minus_lowest_lows << (@highest_highs.last - @lowest_lows.last).round(4)
55
+ end
56
+
57
+ def calculate_ks_sums_close_minus_lowest_lows
58
+ @ks_sums_close_minus_lowest_lows <<
59
+ @close_minus_lowest_lows.last(k_slow_periods).sum.round(4)
60
+ end
61
+
62
+ def calculate_ks_sums_highest_highs_minus_lowest_lows
63
+ @ks_sums_highest_highs_minus_lowest_lows <<
64
+ @highest_highs_minus_lowest_lows.last(k_slow_periods).sum.round(4)
65
+ end
66
+
67
+ def calculate_ks_sums_quotients_times_one_hundred
68
+ @ks_sums_quotients_times_one_hundred <<
69
+ ((@ks_sums_close_minus_lowest_lows.last.to_f / @ks_sums_highest_highs_minus_lowest_lows.last) * 100).round(4)
70
+ end
71
+
72
+ def caculate_d_periods_sma
73
+ @d_periods_sma << if @ks_sums_quotients_times_one_hundred.length >= d_periods
74
+ (@ks_sums_quotients_times_one_hundred.last(d_periods).sum.to_f / d_periods).round(4)
75
+ else
76
+ -1000
77
+ end
78
+ end
79
+
80
+ def calculate_stochastic_oscillator
81
+ highs, lows, closes = extract_highs_lows_closes
82
+
83
+ (0..(highs.length - k_periods)).flat_map do |index|
84
+ calculate_lowest_lows(lows, index)
85
+ calculate_highest_highs(highs, index)
86
+ calculate_close_minus_lowest_lows(closes, index)
87
+ calculate_highest_highs_minus_lowest_lows
88
+
89
+ if @close_minus_lowest_lows.length >= k_slow_periods
90
+ calculate_ks_sums_close_minus_lowest_lows
91
+ calculate_ks_sums_highest_highs_minus_lowest_lows
92
+ calculate_ks_sums_quotients_times_one_hundred
93
+ end
94
+
95
+ caculate_d_periods_sma
96
+ end.last
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,50 @@
1
+ module RubyTechnicalAnalysis
2
+ # Volume Oscillator
3
+ #
4
+ # Find more information at: https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/volume-oscillator
5
+ class VolumeOscillator < Indicator
6
+ attr_reader :short_ma_period, :long_ma_period
7
+
8
+ # @param series [Array] An array of volume values
9
+ # @param short_ma_period [Integer] The number of periods to use in the calculation of the short moving average
10
+ # @param long_ma_period [Integer] The number of periods to use in the calculation of the long moving average
11
+ def initialize(series: [], short_ma_period: 20, long_ma_period: 60)
12
+ @short_ma_period = short_ma_period
13
+ @long_ma_period = long_ma_period
14
+
15
+ super(series: series)
16
+ end
17
+
18
+ # @return [Float] The current volume oscillator value
19
+ def call
20
+ calculate_volume_oscillator
21
+ end
22
+
23
+ # @return [Boolean] Whether or not the object is valid
24
+ def valid?
25
+ short_ma_period < long_ma_period && long_ma_period <= series.length
26
+ end
27
+
28
+ private
29
+
30
+ def short_ma_a
31
+ (0..(series.length - short_ma_period)).map do |index|
32
+ RubyTechnicalAnalysis::MovingAverages.new(series: series[index..(index + short_ma_period - 1)], period: short_ma_period).sma
33
+ end
34
+ end
35
+
36
+ def _long_ma_a
37
+ @_long_ma_a ||= (0..(series.length - long_ma_period)).map do |index|
38
+ RubyTechnicalAnalysis::MovingAverages.new(series: series[index..(index + long_ma_period - 1)], period: long_ma_period).sma
39
+ end
40
+ end
41
+
42
+ def short_minus_long_ma_a
43
+ (short_ma_a.last - _long_ma_a.last).round(2)
44
+ end
45
+
46
+ def calculate_volume_oscillator
47
+ ((short_minus_long_ma_a.to_f / _long_ma_a.last) * 100).round(2)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,48 @@
1
+ module RubyTechnicalAnalysis
2
+ # Volume Rate of Change
3
+ #
4
+ # Find more information at: https://www.investopedia.com/articles/technical/02/091002.asp
5
+ class VolumeRateOfChange < Indicator
6
+ attr_reader :period
7
+
8
+ # @param series [Array] An array of volume values
9
+ # @param period [Integer] The number of periods to use in the calculation
10
+ def initialize(series: [], period: 25)
11
+ @period = period
12
+
13
+ super(series: series)
14
+ end
15
+
16
+ # @return [Float] The current volume rate of change value
17
+ def call
18
+ calculate_volume_rate_of_change
19
+ end
20
+
21
+ # @return [Boolean] Whether or not the object is valid
22
+ def valid?
23
+ period < series.length
24
+ end
25
+
26
+ private
27
+
28
+ def _calculable_series_length
29
+ @_calculable_series_length ||= series.length - period
30
+ end
31
+
32
+ def _vol_shifted
33
+ @_vol_shifted ||= _calculable_series_length.times.map do
34
+ series.at(_calculable_series_length - 1)
35
+ end
36
+ end
37
+
38
+ def delta_volume
39
+ _calculable_series_length.times.map do
40
+ series.last - _vol_shifted.last
41
+ end
42
+ end
43
+
44
+ def calculate_volume_rate_of_change
45
+ ((delta_volume.last.to_f / _vol_shifted.last) * 100).round(4)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,47 @@
1
+ module RubyTechnicalAnalysis
2
+ # Wilders Smoothing
3
+ class WildersSmoothing < Indicator
4
+ attr_reader :period
5
+
6
+ # @param series [Array] An array of prices
7
+ # @param period [Integer] The number of periods to use in the calculation
8
+ def initialize(series: [], period: 5)
9
+ @period = period
10
+
11
+ super(series: series)
12
+ end
13
+
14
+ # @return [Float] The current Wilders Smoothing value
15
+ def call
16
+ calculate_wilders_smoothing
17
+ end
18
+
19
+ # @return [Boolean] Whether or not the object is valid
20
+ def valid?
21
+ period < series.length
22
+ end
23
+
24
+ private
25
+
26
+ def _sma_first_period
27
+ @_sma_first_period ||=
28
+ Array(RubyTechnicalAnalysis::MovingAverages.new(series: series.first(period), period: period).sma)
29
+ end
30
+
31
+ def smoothing_length
32
+ (series.size - period - 1)
33
+ end
34
+
35
+ def calculate_wilders_smoothing
36
+ ws = _sma_first_period
37
+
38
+ (0..smoothing_length).each do |index|
39
+ current_smoothing = ws.at(index)
40
+
41
+ ws << ((series.at(index + period) - current_smoothing) * (1.0 / period)) + current_smoothing
42
+ end
43
+
44
+ ws.last
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,69 @@
1
+ module RubyTechnicalAnalysis
2
+ # Williams %R
3
+ #
4
+ # Find more information at: https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/williams-r
5
+ class WilliamsPercentR < Indicator
6
+ attr_reader :period
7
+
8
+ # @param series [Array] An array of arrays containing high, low, close prices, e.g. [[high, low, close], [high, low, close]]
9
+ # @param period [Integer] The number of periods to use in the calculation
10
+ def initialize(series: [], period: 14)
11
+ @period = period
12
+ @highest_highs = []
13
+ @lowest_lows = []
14
+ @highest_highs_minus_close = []
15
+ @highest_highs_minus_lowest_lows = []
16
+ @pct_r = []
17
+
18
+ super(series: series)
19
+ end
20
+
21
+ # @return [Float] The current Williams %R value
22
+ def call
23
+ calculate_williams_percent_r
24
+ end
25
+
26
+ # @return [Boolean] Whether or not the object is valid
27
+ def valid?
28
+ period < series.length
29
+ end
30
+
31
+ private
32
+
33
+ def calculate_lowest_lows(lows, window_start)
34
+ @lowest_lows << lows[window_start..(period - 1 + window_start)].min
35
+ end
36
+
37
+ def calculate_highest_highs(highs, window_start)
38
+ @highest_highs << highs[window_start..(period - 1 + window_start)].max
39
+ end
40
+
41
+ def calculate_highest_highs_minus_close(closes, window_start)
42
+ @highest_highs_minus_close <<
43
+ (@highest_highs.last - closes.at(period - 1 + window_start)).round(2)
44
+ end
45
+
46
+ def calculate_highest_highs_minus_lowest_lows
47
+ @highest_highs_minus_lowest_lows << (@highest_highs.last - @lowest_lows.last).round(4)
48
+ end
49
+
50
+ def calculate_pct_r
51
+ @pct_r <<
52
+ ((@highest_highs_minus_close.last.to_f / @highest_highs_minus_lowest_lows.last) * -100).round(2)
53
+ end
54
+
55
+ def calculate_williams_percent_r
56
+ highs, lows, closes = extract_highs_lows_closes
57
+
58
+ (0..highs.length - period).each do |index|
59
+ calculate_highest_highs(highs, index)
60
+ calculate_lowest_lows(lows, index)
61
+ calculate_highest_highs_minus_close(closes, index)
62
+ calculate_highest_highs_minus_lowest_lows
63
+ calculate_pct_r
64
+ end
65
+
66
+ @pct_r.last
67
+ end
68
+ end
69
+ end
@@ -1,8 +1,25 @@
1
- # frozen_string_literal: true
1
+ # Base class
2
+ require "ruby_technical_analysis/indicator"
2
3
 
3
- Dir[File.join(__dir__, "ruby-technical-analysis/**/", "*.rb")].sort.each { |f| require f }
4
-
5
- # module for Ruby Technical Analysis
6
- module RubyTechnicalAnalysis
7
- class Error < StandardError; end
8
- end
4
+ # Indicators
5
+ require "ruby_technical_analysis/indicators/bollinger_bands"
6
+ require "ruby_technical_analysis/indicators/chaikin_money_flow"
7
+ require "ruby_technical_analysis/indicators/chande_momentum_oscillator"
8
+ require "ruby_technical_analysis/indicators/commodity_channel_index"
9
+ require "ruby_technical_analysis/indicators/envelopes_ema"
10
+ require "ruby_technical_analysis/indicators/intraday_momentum_index"
11
+ require "ruby_technical_analysis/indicators/macd"
12
+ require "ruby_technical_analysis/indicators/mass_index"
13
+ require "ruby_technical_analysis/indicators/moving_averages"
14
+ require "ruby_technical_analysis/indicators/pivot_points"
15
+ require "ruby_technical_analysis/indicators/price_channel"
16
+ require "ruby_technical_analysis/indicators/qstick"
17
+ require "ruby_technical_analysis/indicators/rate_of_change"
18
+ require "ruby_technical_analysis/indicators/relative_momentum_index"
19
+ require "ruby_technical_analysis/indicators/relative_strength_index"
20
+ require "ruby_technical_analysis/indicators/statistical_methods"
21
+ require "ruby_technical_analysis/indicators/stochastic_oscillator"
22
+ require "ruby_technical_analysis/indicators/volume_oscillator"
23
+ require "ruby_technical_analysis/indicators/volume_rate_of_change"
24
+ require "ruby_technical_analysis/indicators/wilders_smoothing"
25
+ require "ruby_technical_analysis/indicators/williams_percent_r"