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
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f408c4203ba656b1aa458266b8ed6ec656f91f2e
4
+ data.tar.gz: 18c7d6c4465b9ddbf6627508672e3a8f3295a597
5
+ SHA512:
6
+ metadata.gz: dcb6a96e644cc93c7f48866aa067c6cac7ca7c226cfeb3a71bd4a1789f258dee846b19c774a95560001cff93a8e6c693d4386a3247ea7aebb404beb37121f7bb
7
+ data.tar.gz: 42e5e7bbfedb0f48a92b5107edfa2fda26c616cdb67bd91984e53fbd47f145fb50323da63268b34722202c71029d75fabfd94dba0136497baf508e874289c877
@@ -0,0 +1,3 @@
1
+ # This allows 'technical_analysis' AND 'technical-analysis" to work for requires
2
+ # Place additional requires in technical_analysis.rb
3
+ require 'technical_analysis'
@@ -0,0 +1,41 @@
1
+ # Helpers
2
+ require 'technical_analysis/helpers/array_helper'
3
+ require 'technical_analysis/helpers/stock_calculation'
4
+ require 'technical_analysis/helpers/validation'
5
+
6
+ # Indicators
7
+ require 'technical_analysis/indicators/indicator'
8
+
9
+ require 'technical_analysis/indicators/adi'
10
+ require 'technical_analysis/indicators/adtv'
11
+ require 'technical_analysis/indicators/adx'
12
+ require 'technical_analysis/indicators/ao'
13
+ require 'technical_analysis/indicators/atr'
14
+ require 'technical_analysis/indicators/bb'
15
+ require 'technical_analysis/indicators/cci'
16
+ require 'technical_analysis/indicators/cmf'
17
+ require 'technical_analysis/indicators/cr'
18
+ require 'technical_analysis/indicators/dc'
19
+ require 'technical_analysis/indicators/dlr'
20
+ require 'technical_analysis/indicators/dpo'
21
+ require 'technical_analysis/indicators/dr'
22
+ require 'technical_analysis/indicators/eom'
23
+ require 'technical_analysis/indicators/fi'
24
+ require 'technical_analysis/indicators/ichimoku'
25
+ require 'technical_analysis/indicators/kc'
26
+ require 'technical_analysis/indicators/kst'
27
+ require 'technical_analysis/indicators/macd'
28
+ require 'technical_analysis/indicators/mfi'
29
+ require 'technical_analysis/indicators/mi'
30
+ require 'technical_analysis/indicators/nvi'
31
+ require 'technical_analysis/indicators/obv'
32
+ require 'technical_analysis/indicators/obv_mean'
33
+ require 'technical_analysis/indicators/rsi'
34
+ require 'technical_analysis/indicators/sma'
35
+ require 'technical_analysis/indicators/sr'
36
+ require 'technical_analysis/indicators/trix'
37
+ require 'technical_analysis/indicators/tsi'
38
+ require 'technical_analysis/indicators/uo'
39
+ require 'technical_analysis/indicators/vi'
40
+ require 'technical_analysis/indicators/vpt'
41
+ require 'technical_analysis/indicators/wr'
@@ -0,0 +1,27 @@
1
+ module TechnicalAnalysis
2
+ class ArrayHelper
3
+
4
+ def self.sum(data)
5
+ data.inject(0, :+)
6
+ end
7
+
8
+ def self.mean(data)
9
+ sum(data) / data.size.to_f
10
+ end
11
+
12
+ def self.average(data)
13
+ sum(data) / data.size.to_f
14
+ end
15
+
16
+ def self.sample_variance(data)
17
+ m = mean(data)
18
+ sum = data.inject(0) { |accum, i| accum + (i - m)**2 }
19
+ sum / (data.size - 1).to_f
20
+ end
21
+
22
+ def self.standard_deviation(data)
23
+ Math.sqrt(sample_variance(data))
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,25 @@
1
+ module TechnicalAnalysis
2
+ class StockCalculation
3
+
4
+ def self.true_range(current_high, current_low, previous_close)
5
+ [
6
+ (current_high - current_low),
7
+ (current_high - previous_close).abs,
8
+ (current_low - previous_close).abs
9
+ ].max
10
+ end
11
+
12
+ def self.typical_price(price)
13
+ (price[:high] + price[:low] + price[:close]) / 3.0
14
+ end
15
+
16
+ def self.ema(current_value, data, period, prev_value)
17
+ if prev_value.nil?
18
+ ArrayHelper.average(data)
19
+ else
20
+ (current_value - prev_value) * (2.0 / (period + 1.0)) + prev_value
21
+ end
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,33 @@
1
+ module TechnicalAnalysis
2
+ class Validation
3
+
4
+ def self.validate_numeric_data(data, *keys)
5
+ keys.each do |key|
6
+ unless data.all? { |v| v[key].is_a? Numeric }
7
+ raise ValidationError.new "Invalid Data. '#{key}' is not valid price data."
8
+ end
9
+ end
10
+ end
11
+
12
+ def self.validate_length(data, size)
13
+ raise ValidationError.new "Not enough data for that period" if data.size < size
14
+ end
15
+
16
+ def self.validate_options(options, valid_options)
17
+ raise ValidationError.new "Options must be a hash." unless options.respond_to? :keys
18
+ raise ValidationError.new "No valid options provided." unless valid_options
19
+
20
+ return true if (options.keys - valid_options).empty?
21
+ raise ValidationError.new "Invalid options provided. Valid options are #{valid_options.join(", ")}"
22
+ end
23
+
24
+ def self.validate_date_time_key(data)
25
+ unless data.all? { |row| row.keys.include? :date_time }
26
+ raise ValidationError.new "Dataset must include date_time field with timestamps"
27
+ end
28
+ end
29
+
30
+ class ValidationError < StandardError; end
31
+
32
+ end
33
+ end
@@ -0,0 +1,101 @@
1
+ module TechnicalAnalysis
2
+ # Accumulation/Distribution Index
3
+ class Adi < 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
+ "adi"
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
+ "Accumulation/Distribution Index"
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
+ []
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
+ return true if options == {}
33
+ raise Validation::ValidationError.new "This indicator doesn't accept any options."
34
+ end
35
+
36
+ # Calculates the minimum number of observations needed to calculate the technical indicator
37
+ #
38
+ # @param options [Hash] The options for the technical indicator
39
+ #
40
+ # @return [Integer] Returns the minimum number of observations needed to calculate the technical
41
+ # indicator based on the options provided
42
+ def self.min_data_size(**params)
43
+ 1
44
+ end
45
+
46
+ # Calculates the Accumulation/Distribution Index (ADI) for the given data
47
+ # https://en.wikipedia.org/wiki/Accumulation/distribution_index
48
+ #
49
+ # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close, :volume)
50
+ # @return [Array<AdiValue>] An array of AdiValue instances
51
+ def self.calculate(data)
52
+ Validation.validate_numeric_data(data, :high, :low, :close, :volume)
53
+ Validation.validate_date_time_key(data)
54
+
55
+ data = data.sort_by { |row| row[:date_time] }
56
+
57
+ ad = 0
58
+ clv = 0
59
+ output = []
60
+ prev_ad = 0
61
+
62
+ data.each_with_index do |values, i|
63
+ if values[:high] == values[:low]
64
+ clv = 0
65
+ else
66
+ clv = ((values[:close] - values[:low]) - (values[:high] - values[:close])) / (values[:high] - values[:low])
67
+ end
68
+
69
+ ad = prev_ad + (clv * values[:volume])
70
+ prev_ad = ad
71
+ date_time = values[:date_time]
72
+
73
+ output << AdiValue.new(date_time: date_time, adi: ad)
74
+ end
75
+
76
+ output.sort_by(&:date_time).reverse
77
+ end
78
+
79
+ end
80
+
81
+ # The value class to be returned by calculations
82
+ class AdiValue
83
+
84
+ # @return [String] the date_time of the obversation as it was provided
85
+ attr_accessor :date_time
86
+
87
+ # @return [Float] the adi calculation value
88
+ attr_accessor :adi
89
+
90
+ def initialize(date_time: nil, adi: nil)
91
+ @date_time = date_time
92
+ @adi = adi
93
+ end
94
+
95
+ # @return [Hash] the attributes as a hash
96
+ def to_hash
97
+ { date_time: @date_time, adi: @adi }
98
+ end
99
+
100
+ end
101
+ end
@@ -0,0 +1,98 @@
1
+ module TechnicalAnalysis
2
+ # Average Daily Trading Volume
3
+ class Adtv < 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
+ "adtv"
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 Daily Trading Volume"
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 volume_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: 22, **params)
42
+ period.to_i
43
+ end
44
+
45
+ # Calculates the average daily trading volume (ADTV) for the data over the given period
46
+ # https://www.investopedia.com/terms/a/averagedailytradingvolume.asp
47
+ #
48
+ # @param data [Array] Array of hashes with keys (:date_time, :value)
49
+ # @param period [Integer] The given number of days used to calculate the ADTV
50
+ # @param volume_key [Symbol] The hash key for the volume data. Default :value
51
+ #
52
+ # @return [Array<AdtvValue>] An array of AdtvValue instances
53
+ def self.calculate(data, period: 22, volume_key: :value)
54
+ period = period.to_i
55
+ volume_key = volume_key.to_sym
56
+ Validation.validate_numeric_data(data, volume_key)
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
+ period_values = []
64
+
65
+ data.each do |v|
66
+ period_values << v[volume_key]
67
+ if period_values.size == period
68
+ output << AdtvValue.new(date_time: v[:date_time], adtv: ArrayHelper.average(period_values))
69
+ period_values.shift
70
+ end
71
+ end
72
+
73
+ output.sort_by(&:date_time).reverse
74
+ end
75
+
76
+ end
77
+
78
+ # The value class to be returned by calculations
79
+ class AdtvValue
80
+
81
+ # @return [String] the date_time of the obversation as it was provided
82
+ attr_accessor :date_time
83
+
84
+ # @return [Float] the adtv calculation value
85
+ attr_accessor :adtv
86
+
87
+ def initialize(date_time: nil, adtv: nil)
88
+ @date_time = date_time
89
+ @adtv = adtv
90
+ end
91
+
92
+ # @return [Hash] the attributes as a hash
93
+ def to_hash
94
+ { date_time: @date_time, adtv: @adtv }
95
+ end
96
+
97
+ end
98
+ end
@@ -0,0 +1,168 @@
1
+ module TechnicalAnalysis
2
+ # Average Direcitonal Index
3
+ class Adx < 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
+ "adx"
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 Directional Index"
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 * 2
43
+ end
44
+
45
+ # Calculates the average directional index (ADX) for the data over the given period
46
+ # https://en.wikipedia.org/wiki/Average_directional_movement_index
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 ADX
50
+ #
51
+ # @return [Array<AdxValue>] An array of AdxValue 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
+ dx_values = []
61
+ output = []
62
+ periodic_values = []
63
+ prev_adx = nil
64
+ prev_price = data.shift
65
+ smoothed_values = []
66
+
67
+ data.each do |v|
68
+ tr = StockCalculation.true_range(v[:high], v[:low], prev_price[:close])
69
+
70
+ dm_pos, dm_neg = calculate_dm(v, prev_price)
71
+
72
+ periodic_values << { tr: tr, dm_pos: dm_pos, dm_neg: dm_neg }
73
+
74
+ if periodic_values.size == period
75
+ tr_period, dm_pos_period, dm_neg_period = smooth_periodic_values(period, periodic_values, smoothed_values)
76
+ smoothed_values << { tr: tr_period, dm_pos: dm_pos_period, dm_neg: dm_neg_period }
77
+
78
+ di_pos = (dm_pos_period / tr_period) * 100.00
79
+ di_neg = (dm_neg_period / tr_period) * 100.00
80
+ dx = ((dm_pos_period - dm_neg_period).abs / (dm_pos_period + dm_neg_period) * 100.00)
81
+
82
+ dx_values << dx
83
+
84
+ if dx_values.size == period
85
+ if prev_adx.nil?
86
+ adx = ArrayHelper.average(dx_values)
87
+ else
88
+ adx = ((prev_adx * 13) + dx) / period.to_f
89
+ end
90
+
91
+ output << AdxValue.new(date_time: v[:date_time], adx: adx, di_pos: di_pos, di_neg: di_neg)
92
+
93
+ prev_adx = adx
94
+ dx_values.shift
95
+ end
96
+
97
+ periodic_values.shift
98
+ end
99
+
100
+ prev_price = v
101
+ end
102
+
103
+ output.sort_by(&:date_time).reverse
104
+ end
105
+
106
+ private_class_method def self.calculate_dm(current_price, prev_price)
107
+ if current_price[:high] - prev_price[:high] > prev_price[:low] - current_price[:low]
108
+ dm_pos = [(current_price[:high] - prev_price[:high]), 0].max
109
+ dm_neg = 0
110
+ elsif prev_price[:low] - current_price[:low] > current_price[:high] - prev_price[:high]
111
+ dm_pos = 0
112
+ dm_neg = [(prev_price[:low] - current_price[:low]), 0].max
113
+ else
114
+ dm_pos = 0
115
+ dm_neg = 0
116
+ end
117
+
118
+ [dm_pos, dm_neg]
119
+ end
120
+
121
+ private_class_method def self.smooth_periodic_values(period, periodic_values, smoothed_values)
122
+ if smoothed_values.empty?
123
+ tr_period = ArrayHelper.sum(periodic_values.map { |pv| pv[:tr] })
124
+ dm_pos_period = ArrayHelper.sum(periodic_values.map { |pv| pv[:dm_pos] })
125
+ dm_neg_period = ArrayHelper.sum(periodic_values.map { |pv| pv[:dm_neg] })
126
+ else
127
+ prev_value = smoothed_values.last
128
+ current_value = periodic_values.last
129
+
130
+ tr_period = prev_value[:tr] - (prev_value[:tr] / period) + current_value[:tr]
131
+ dm_pos_period = prev_value[:dm_pos] - (prev_value[:dm_pos] / period) + current_value[:dm_pos]
132
+ dm_neg_period = prev_value[:dm_neg] - (prev_value[:dm_neg] / period) + current_value[:dm_neg]
133
+ end
134
+
135
+ [tr_period, dm_pos_period, dm_neg_period]
136
+ end
137
+
138
+ # The value class to be returned by calculations
139
+ class AdxValue
140
+
141
+ # @return [String] the date_time of the obversation as it was provided
142
+ attr_accessor :date_time
143
+
144
+ # @return [Float] the adx calculation value
145
+ attr_accessor :adx
146
+
147
+ # @return [Float] the positive directional indicator calculation value
148
+ attr_accessor :di_pos
149
+
150
+ # @return [Float] the negative directional indicator calculation value
151
+ attr_accessor :di_neg
152
+
153
+ def initialize(date_time: nil, adx: nil, di_pos: nil, di_neg: nil)
154
+ @date_time = date_time
155
+ @adx = adx
156
+ @di_pos = di_pos
157
+ @di_neg = di_neg
158
+ end
159
+
160
+ # @return [Hash] the attributes as a hash
161
+ def to_hash
162
+ { date_time: @date_time, adx: @adx, di_pos: @di_pos, di_neg: @di_neg }
163
+ end
164
+
165
+ end
166
+
167
+ end
168
+ end