technical-analysis 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +7 -0
  2. data/lib/technical-analysis.rb +3 -0
  3. data/lib/technical_analysis.rb +41 -0
  4. data/lib/technical_analysis/helpers/array_helper.rb +27 -0
  5. data/lib/technical_analysis/helpers/stock_calculation.rb +25 -0
  6. data/lib/technical_analysis/helpers/validation.rb +33 -0
  7. data/lib/technical_analysis/indicators/adi.rb +101 -0
  8. data/lib/technical_analysis/indicators/adtv.rb +98 -0
  9. data/lib/technical_analysis/indicators/adx.rb +168 -0
  10. data/lib/technical_analysis/indicators/ao.rb +105 -0
  11. data/lib/technical_analysis/indicators/atr.rb +109 -0
  12. data/lib/technical_analysis/indicators/bb.rb +126 -0
  13. data/lib/technical_analysis/indicators/cci.rb +105 -0
  14. data/lib/technical_analysis/indicators/cmf.rb +105 -0
  15. data/lib/technical_analysis/indicators/cr.rb +95 -0
  16. data/lib/technical_analysis/indicators/dc.rb +108 -0
  17. data/lib/technical_analysis/indicators/dlr.rb +97 -0
  18. data/lib/technical_analysis/indicators/dpo.rb +106 -0
  19. data/lib/technical_analysis/indicators/dr.rb +96 -0
  20. data/lib/technical_analysis/indicators/eom.rb +104 -0
  21. data/lib/technical_analysis/indicators/fi.rb +95 -0
  22. data/lib/technical_analysis/indicators/ichimoku.rb +179 -0
  23. data/lib/technical_analysis/indicators/indicator.rb +138 -0
  24. data/lib/technical_analysis/indicators/kc.rb +124 -0
  25. data/lib/technical_analysis/indicators/kst.rb +132 -0
  26. data/lib/technical_analysis/indicators/macd.rb +144 -0
  27. data/lib/technical_analysis/indicators/mfi.rb +119 -0
  28. data/lib/technical_analysis/indicators/mi.rb +121 -0
  29. data/lib/technical_analysis/indicators/nvi.rb +102 -0
  30. data/lib/technical_analysis/indicators/obv.rb +104 -0
  31. data/lib/technical_analysis/indicators/obv_mean.rb +110 -0
  32. data/lib/technical_analysis/indicators/rsi.rb +133 -0
  33. data/lib/technical_analysis/indicators/sma.rb +98 -0
  34. data/lib/technical_analysis/indicators/sr.rb +122 -0
  35. data/lib/technical_analysis/indicators/trix.rb +127 -0
  36. data/lib/technical_analysis/indicators/tsi.rb +139 -0
  37. data/lib/technical_analysis/indicators/uo.rb +130 -0
  38. data/lib/technical_analysis/indicators/vi.rb +117 -0
  39. data/lib/technical_analysis/indicators/vpt.rb +95 -0
  40. data/lib/technical_analysis/indicators/wr.rb +103 -0
  41. data/spec/helpers/array_helper_spec.rb +31 -0
  42. data/spec/helpers/validaton_spec.rb +22 -0
  43. data/spec/spec_helper.rb +26 -0
  44. data/spec/ta_test_data.csv +64 -0
  45. data/spec/technical_analysis/indicators/adi_spec.rb +116 -0
  46. data/spec/technical_analysis/indicators/adtv_spec.rb +98 -0
  47. data/spec/technical_analysis/indicators/adx_spec.rb +92 -0
  48. data/spec/technical_analysis/indicators/ao_spec.rb +86 -0
  49. data/spec/technical_analysis/indicators/atr_spec.rb +105 -0
  50. data/spec/technical_analysis/indicators/bb_spec.rb +100 -0
  51. data/spec/technical_analysis/indicators/cci_spec.rb +100 -0
  52. data/spec/technical_analysis/indicators/cmf_spec.rb +100 -0
  53. data/spec/technical_analysis/indicators/cr_spec.rb +119 -0
  54. data/spec/technical_analysis/indicators/dc_spec.rb +100 -0
  55. data/spec/technical_analysis/indicators/dlr_spec.rb +119 -0
  56. data/spec/technical_analysis/indicators/dpo_spec.rb +90 -0
  57. data/spec/technical_analysis/indicators/dr_spec.rb +119 -0
  58. data/spec/technical_analysis/indicators/eom_spec.rb +105 -0
  59. data/spec/technical_analysis/indicators/fi_spec.rb +118 -0
  60. data/spec/technical_analysis/indicators/ichimoku_spec.rb +95 -0
  61. data/spec/technical_analysis/indicators/indicator_spec.rb +120 -0
  62. data/spec/technical_analysis/indicators/kc_spec.rb +110 -0
  63. data/spec/technical_analysis/indicators/kst_spec.rb +78 -0
  64. data/spec/technical_analysis/indicators/macd_spec.rb +86 -0
  65. data/spec/technical_analysis/indicators/mfi_spec.rb +105 -0
  66. data/spec/technical_analysis/indicators/mi_spec.rb +79 -0
  67. data/spec/technical_analysis/indicators/nvi_spec.rb +119 -0
  68. data/spec/technical_analysis/indicators/obv_mean_spec.rb +109 -0
  69. data/spec/technical_analysis/indicators/obv_spec.rb +119 -0
  70. data/spec/technical_analysis/indicators/rsi_spec.rb +105 -0
  71. data/spec/technical_analysis/indicators/sma_spec.rb +115 -0
  72. data/spec/technical_analysis/indicators/sr_spec.rb +104 -0
  73. data/spec/technical_analysis/indicators/trix_spec.rb +76 -0
  74. data/spec/technical_analysis/indicators/tsi_spec.rb +87 -0
  75. data/spec/technical_analysis/indicators/uo_spec.rb +91 -0
  76. data/spec/technical_analysis/indicators/vi_spec.rb +105 -0
  77. data/spec/technical_analysis/indicators/vpt_spec.rb +118 -0
  78. data/spec/technical_analysis/indicators/wr_spec.rb +106 -0
  79. metadata +177 -0
@@ -0,0 +1,105 @@
1
+ module TechnicalAnalysis
2
+ # Awesome Oscillator
3
+ class Ao < Indicator
4
+
5
+ # Returns the symbol of the technical indicator
6
+ #
7
+ # @return [String] A string of the symbol of the technical indicator
8
+ def self.indicator_symbol
9
+ "ao"
10
+ end
11
+
12
+ # Returns the name of the technical indicator
13
+ #
14
+ # @return [String] A string of the name of the technical indicator
15
+ def self.indicator_name
16
+ "Awesome Oscillator"
17
+ end
18
+
19
+ # Returns an array of valid keys for options for this technical indicator
20
+ #
21
+ # @return [Array] An array of keys as symbols for valid options for this technical indicator
22
+ def self.valid_options
23
+ %i(short_period long_period)
24
+ end
25
+
26
+ # Validates the provided options for this technical indicator
27
+ #
28
+ # @param options [Hash] The options for the technical indicator to be validated
29
+ #
30
+ # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not
31
+ def self.validate_options(options)
32
+ Validation.validate_options(options, valid_options)
33
+ end
34
+
35
+ # Calculates the minimum number of observations needed to calculate the technical indicator
36
+ #
37
+ # @param options [Hash] The options for the technical indicator
38
+ #
39
+ # @return [Integer] Returns the minimum number of observations needed to calculate the technical
40
+ # indicator based on the options provided
41
+ def self.min_data_size(long_period: 34, **params)
42
+ long_period.to_i
43
+ end
44
+
45
+ # Calculates the awesome oscillator for the data over the given period
46
+ # https://www.tradingview.com/wiki/Awesome_Oscillator_(AO)
47
+ #
48
+ # @param data [Array] Array of hashes with keys (:date_time, :high, :low)
49
+ # @param short_period [Integer] The given period to calculate the short period SMA
50
+ # @param long_period [Integer] The given period to calculate the long period SMA
51
+ #
52
+ # @return [Array<AoValue>] An array of AoValue instances
53
+ def self.calculate(data, short_period: 5, long_period: 34)
54
+ short_period = short_period.to_i
55
+ long_period = long_period.to_i
56
+ Validation.validate_numeric_data(data, :high, :low)
57
+ Validation.validate_length(data, min_data_size(long_period: long_period))
58
+ Validation.validate_date_time_key(data)
59
+
60
+ data = data.sort_by { |row| row[:date_time] }
61
+
62
+ midpoint_values = []
63
+ output = []
64
+
65
+ data.each do |v|
66
+ midpoint = (v[:high] + v[:low]) / 2
67
+ midpoint_values << midpoint
68
+
69
+ if midpoint_values.size == long_period
70
+ short_period_sma = ArrayHelper.average(midpoint_values.last(short_period))
71
+ long_period_sma = ArrayHelper.average(midpoint_values)
72
+ value = short_period_sma - long_period_sma
73
+
74
+ output << AoValue.new(date_time: v[:date_time], ao: value)
75
+
76
+ midpoint_values.shift
77
+ end
78
+ end
79
+
80
+ output.sort_by(&:date_time).reverse
81
+ end
82
+
83
+ end
84
+
85
+ # The value class to be returned by calculations
86
+ class AoValue
87
+
88
+ # @return [String] the date_time of the obversation as it was provided
89
+ attr_accessor :date_time
90
+
91
+ # @return [Float] the ao calculation value
92
+ attr_accessor :ao
93
+
94
+ def initialize(date_time: nil, ao: nil)
95
+ @date_time = date_time
96
+ @ao = ao
97
+ end
98
+
99
+ # @return [Hash] the attributes as a hash
100
+ def to_hash
101
+ { date_time: @date_time, ao: @ao }
102
+ end
103
+
104
+ end
105
+ end
@@ -0,0 +1,109 @@
1
+ module TechnicalAnalysis
2
+ # Average True Range
3
+ class Atr < Indicator
4
+
5
+ # Returns the symbol of the technical indicator
6
+ #
7
+ # @return [String] A string of the symbol of the technical indicator
8
+ def self.indicator_symbol
9
+ "atr"
10
+ end
11
+
12
+ # Returns the name of the technical indicator
13
+ #
14
+ # @return [String] A string of the name of the technical indicator
15
+ def self.indicator_name
16
+ "Average True Range"
17
+ end
18
+
19
+ # Returns an array of valid keys for options for this technical indicator
20
+ #
21
+ # @return [Array] An array of keys as symbols for valid options for this technical indicator
22
+ def self.valid_options
23
+ %i(period)
24
+ end
25
+
26
+ # Validates the provided options for this technical indicator
27
+ #
28
+ # @param options [Hash] The options for the technical indicator to be validated
29
+ #
30
+ # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not
31
+ def self.validate_options(options)
32
+ Validation.validate_options(options, valid_options)
33
+ end
34
+
35
+ # Calculates the minimum number of observations needed to calculate the technical indicator
36
+ #
37
+ # @param options [Hash] The options for the technical indicator
38
+ #
39
+ # @return [Integer] Returns the minimum number of observations needed to calculate the technical
40
+ # indicator based on the options provided
41
+ def self.min_data_size(period: 14)
42
+ period.to_i + 1
43
+ end
44
+
45
+ # Calculates the average true range (ATR) for the data over the given period
46
+ # https://en.wikipedia.org/wiki/Average_true_range
47
+ #
48
+ # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close)
49
+ # @param period [Integer] The given period to calculate the ATR
50
+ #
51
+ # @return [Array<AtrValue>] An array of AtrValue instances
52
+ def self.calculate(data, period: 14)
53
+ period = period.to_i
54
+ Validation.validate_numeric_data(data, :high, :low, :close)
55
+ Validation.validate_length(data, min_data_size(period: period))
56
+ Validation.validate_date_time_key(data)
57
+
58
+ data = data.sort_by { |row| row[:date_time] }
59
+
60
+ output = []
61
+ period_values = []
62
+ prev_price = data.shift
63
+
64
+ data.each do |v|
65
+ tr = StockCalculation.true_range(v[:high], v[:low], prev_price[:close])
66
+
67
+ period_values << tr
68
+
69
+ if period_values.size == period
70
+ if output.empty?
71
+ atr = ArrayHelper.average(period_values)
72
+ else
73
+ atr = (output.last.atr * (period - 1.0) + tr) / period.to_f
74
+ end
75
+
76
+ output << AtrValue.new(date_time: v[:date_time], atr: atr)
77
+
78
+ period_values.shift
79
+ end
80
+
81
+ prev_price = v
82
+ end
83
+
84
+ output.sort_by(&:date_time).reverse
85
+ end
86
+
87
+ end
88
+
89
+ # The value class to be returned by calculations
90
+ class AtrValue
91
+
92
+ # @return [String] the date_time of the obversation as it was provided
93
+ attr_accessor :date_time
94
+
95
+ # @return [Float] the atr calculation value
96
+ attr_accessor :atr
97
+
98
+ def initialize(date_time: nil, atr: nil)
99
+ @date_time = date_time
100
+ @atr = atr
101
+ end
102
+
103
+ # @return [Hash] the attributes as a hash
104
+ def to_hash
105
+ { date_time: @date_time, atr: @atr }
106
+ end
107
+
108
+ end
109
+ end
@@ -0,0 +1,126 @@
1
+ module TechnicalAnalysis
2
+ # Bollinger Bands
3
+ class Bb < Indicator
4
+
5
+ # Returns the symbol of the technical indicator
6
+ #
7
+ # @return [String] A string of the symbol of the technical indicator
8
+ def self.indicator_symbol
9
+ "bb"
10
+ end
11
+
12
+ # Returns the name of the technical indicator
13
+ #
14
+ # @return [String] A string of the name of the technical indicator
15
+ def self.indicator_name
16
+ "Bollinger Bands"
17
+ end
18
+
19
+ # Returns an array of valid keys for options for this technical indicator
20
+ #
21
+ # @return [Array] An array of keys as symbols for valid options for this technical indicator
22
+ def self.valid_options
23
+ %i(period standard_deviations price_key)
24
+ end
25
+
26
+ # Validates the provided options for this technical indicator
27
+ #
28
+ # @param options [Hash] The options for the technical indicator to be validated
29
+ #
30
+ # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not
31
+ def self.validate_options(options)
32
+ Validation.validate_options(options, valid_options)
33
+ end
34
+
35
+ # Calculates the minimum number of observations needed to calculate the technical indicator
36
+ #
37
+ # @param options [Hash] The options for the technical indicator
38
+ #
39
+ # @return [Integer] Returns the minimum number of observations needed to calculate the technical
40
+ # indicator based on the options provided
41
+ def self.min_data_size(period: 20, **params)
42
+ period.to_i
43
+ end
44
+
45
+ # Calculates the bollinger bands (BB) for the data over the given period
46
+ # https://en.wikipedia.org/wiki/Bollinger_Bands
47
+ #
48
+ # @param data [Array] Array of hashes with keys (:date_time, :value)
49
+ # @param period [Integer] The given period to calculate the BB
50
+ # @param standard_deviations [Float] The given standard deviations to calculate the upper and
51
+ # lower bands of the BB
52
+ # @param price_key [Symbol] The hash key for the price data. Default :value
53
+ #
54
+ # @return [Array<BbValue>] An array of BbValue instances
55
+ def self.calculate(data, period: 20, standard_deviations: 2, price_key: :value)
56
+ period = period.to_i
57
+ standard_deviations = standard_deviations.to_f
58
+ price_key = price_key.to_sym
59
+ Validation.validate_numeric_data(data, price_key)
60
+ Validation.validate_length(data, min_data_size(period: period))
61
+ Validation.validate_date_time_key(data)
62
+
63
+ data = data.sort_by { |row| row[:date_time] }
64
+
65
+ output = []
66
+ period_values = []
67
+
68
+ data.each do |v|
69
+ period_values << v[price_key]
70
+
71
+ if period_values.size == period
72
+ mb = ArrayHelper.average(period_values)
73
+ sd = ArrayHelper.standard_deviation(period_values)
74
+ ub = mb + standard_deviations * sd
75
+ lb = mb - standard_deviations * sd
76
+
77
+ output << BbValue.new(
78
+ date_time: v[:date_time],
79
+ lower_band: lb,
80
+ middle_band: mb,
81
+ upper_band: ub
82
+ )
83
+
84
+ period_values.shift
85
+ end
86
+ end
87
+
88
+ output.sort_by(&:date_time).reverse
89
+ end
90
+
91
+ end
92
+
93
+ # The value class to be returned by calculations
94
+ class BbValue
95
+
96
+ # @return [String] the date_time of the obversation as it was provided
97
+ attr_accessor :date_time
98
+
99
+ # @return [Float] the lower_band calculation value
100
+ attr_accessor :lower_band
101
+
102
+ # @return [Float] the middle_band calculation value
103
+ attr_accessor :middle_band
104
+
105
+ # @return [Float] the upper_band calculation value
106
+ attr_accessor :upper_band
107
+
108
+ def initialize(date_time: nil, lower_band: nil, middle_band: nil, upper_band: nil)
109
+ @date_time = date_time
110
+ @lower_band = lower_band
111
+ @middle_band = middle_band
112
+ @upper_band = upper_band
113
+ end
114
+
115
+ # @return [Hash] the attributes as a hash
116
+ def to_hash
117
+ {
118
+ date_time: @date_time,
119
+ lower_band: @lower_band,
120
+ middle_band: @middle_band,
121
+ upper_band: @upper_band
122
+ }
123
+ end
124
+
125
+ end
126
+ end
@@ -0,0 +1,105 @@
1
+ module TechnicalAnalysis
2
+ class Cci < Indicator
3
+
4
+ # Returns the symbol of the technical indicator
5
+ #
6
+ # @return [String] A string of the symbol of the technical indicator
7
+ def self.indicator_symbol
8
+ "cci"
9
+ end
10
+
11
+ # Returns the name of the technical indicator
12
+ #
13
+ # @return [String] A string of the name of the technical indicator
14
+ def self.indicator_name
15
+ "Commodity Channel Index"
16
+ end
17
+
18
+ # Returns an array of valid keys for options for this technical indicator
19
+ #
20
+ # @return [Array] An array of keys as symbols for valid options for this technical indicator
21
+ def self.valid_options
22
+ %i(period constant)
23
+ end
24
+
25
+ # Validates the provided options for this technical indicator
26
+ #
27
+ # @param options [Hash] The options for the technical indicator to be validated
28
+ #
29
+ # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not
30
+ def self.validate_options(options)
31
+ Validation.validate_options(options, valid_options)
32
+ end
33
+
34
+ # Calculates the minimum number of observations needed to calculate the technical indicator
35
+ #
36
+ # @param options [Hash] The options for the technical indicator
37
+ #
38
+ # @return [Integer] Returns the minimum number of observations needed to calculate the technical
39
+ # indicator based on the options provided
40
+ def self.min_data_size(period: 20, **params)
41
+ period.to_i
42
+ end
43
+
44
+ # Calculates the commodity channel index (CCI) for the data over the given period
45
+ # https://en.wikipedia.org/wiki/Commodity_channel_index
46
+ #
47
+ # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close)
48
+ # @param period [Integer] The given period to calculate the CCI
49
+ # @param constant [Float] The given constant to ensure that approximately 70 to 80 percent of
50
+ # CCI values would fall between −100 and +100
51
+ #
52
+ # @return [Array<CciValue>] An array of CciValue instances
53
+ def self.calculate(data, period: 20, constant: 0.015)
54
+ period = period.to_i
55
+ constant = constant.to_f
56
+ Validation.validate_numeric_data(data, :high, :low, :close)
57
+ Validation.validate_length(data, min_data_size(period: period))
58
+ Validation.validate_date_time_key(data)
59
+
60
+ data = data.sort_by { |row| row[:date_time] }
61
+
62
+ output = []
63
+ typical_prices = []
64
+
65
+ data.each do |v|
66
+ typical_price = StockCalculation.typical_price(v)
67
+ typical_prices << typical_price
68
+
69
+ if typical_prices.size == period
70
+ period_sma = ArrayHelper.average(typical_prices)
71
+ mean_deviation = ArrayHelper.mean(typical_prices.map { |tp| (tp - period_sma).abs })
72
+ cci = (typical_price - period_sma) / (constant * mean_deviation)
73
+
74
+ output << CciValue.new(date_time: v[:date_time], cci: cci)
75
+
76
+ typical_prices.shift
77
+ end
78
+ end
79
+
80
+ output.sort_by(&:date_time).reverse
81
+ end
82
+
83
+ end
84
+
85
+ # The value class to be returned by calculations
86
+ class CciValue
87
+
88
+ # @return [String] the date_time of the obversation as it was provided
89
+ attr_accessor :date_time
90
+
91
+ # @return [Float] the cci calculation value
92
+ attr_accessor :cci
93
+
94
+ def initialize(date_time: nil, cci: nil)
95
+ @date_time = date_time
96
+ @cci = cci
97
+ end
98
+
99
+ # @return [Hash] the attributes as a hash
100
+ def to_hash
101
+ { date_time: @date_time, cci: @cci }
102
+ end
103
+
104
+ end
105
+ end