technical-analysis 0.1.0

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 +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