technical-analysis 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/technical-analysis.rb +3 -0
- data/lib/technical_analysis.rb +41 -0
- data/lib/technical_analysis/helpers/array_helper.rb +27 -0
- data/lib/technical_analysis/helpers/stock_calculation.rb +25 -0
- data/lib/technical_analysis/helpers/validation.rb +33 -0
- data/lib/technical_analysis/indicators/adi.rb +101 -0
- data/lib/technical_analysis/indicators/adtv.rb +98 -0
- data/lib/technical_analysis/indicators/adx.rb +168 -0
- data/lib/technical_analysis/indicators/ao.rb +105 -0
- data/lib/technical_analysis/indicators/atr.rb +109 -0
- data/lib/technical_analysis/indicators/bb.rb +126 -0
- data/lib/technical_analysis/indicators/cci.rb +105 -0
- data/lib/technical_analysis/indicators/cmf.rb +105 -0
- data/lib/technical_analysis/indicators/cr.rb +95 -0
- data/lib/technical_analysis/indicators/dc.rb +108 -0
- data/lib/technical_analysis/indicators/dlr.rb +97 -0
- data/lib/technical_analysis/indicators/dpo.rb +106 -0
- data/lib/technical_analysis/indicators/dr.rb +96 -0
- data/lib/technical_analysis/indicators/eom.rb +104 -0
- data/lib/technical_analysis/indicators/fi.rb +95 -0
- data/lib/technical_analysis/indicators/ichimoku.rb +179 -0
- data/lib/technical_analysis/indicators/indicator.rb +138 -0
- data/lib/technical_analysis/indicators/kc.rb +124 -0
- data/lib/technical_analysis/indicators/kst.rb +132 -0
- data/lib/technical_analysis/indicators/macd.rb +144 -0
- data/lib/technical_analysis/indicators/mfi.rb +119 -0
- data/lib/technical_analysis/indicators/mi.rb +121 -0
- data/lib/technical_analysis/indicators/nvi.rb +102 -0
- data/lib/technical_analysis/indicators/obv.rb +104 -0
- data/lib/technical_analysis/indicators/obv_mean.rb +110 -0
- data/lib/technical_analysis/indicators/rsi.rb +133 -0
- data/lib/technical_analysis/indicators/sma.rb +98 -0
- data/lib/technical_analysis/indicators/sr.rb +122 -0
- data/lib/technical_analysis/indicators/trix.rb +127 -0
- data/lib/technical_analysis/indicators/tsi.rb +139 -0
- data/lib/technical_analysis/indicators/uo.rb +130 -0
- data/lib/technical_analysis/indicators/vi.rb +117 -0
- data/lib/technical_analysis/indicators/vpt.rb +95 -0
- data/lib/technical_analysis/indicators/wr.rb +103 -0
- data/spec/helpers/array_helper_spec.rb +31 -0
- data/spec/helpers/validaton_spec.rb +22 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/ta_test_data.csv +64 -0
- data/spec/technical_analysis/indicators/adi_spec.rb +116 -0
- data/spec/technical_analysis/indicators/adtv_spec.rb +98 -0
- data/spec/technical_analysis/indicators/adx_spec.rb +92 -0
- data/spec/technical_analysis/indicators/ao_spec.rb +86 -0
- data/spec/technical_analysis/indicators/atr_spec.rb +105 -0
- data/spec/technical_analysis/indicators/bb_spec.rb +100 -0
- data/spec/technical_analysis/indicators/cci_spec.rb +100 -0
- data/spec/technical_analysis/indicators/cmf_spec.rb +100 -0
- data/spec/technical_analysis/indicators/cr_spec.rb +119 -0
- data/spec/technical_analysis/indicators/dc_spec.rb +100 -0
- data/spec/technical_analysis/indicators/dlr_spec.rb +119 -0
- data/spec/technical_analysis/indicators/dpo_spec.rb +90 -0
- data/spec/technical_analysis/indicators/dr_spec.rb +119 -0
- data/spec/technical_analysis/indicators/eom_spec.rb +105 -0
- data/spec/technical_analysis/indicators/fi_spec.rb +118 -0
- data/spec/technical_analysis/indicators/ichimoku_spec.rb +95 -0
- data/spec/technical_analysis/indicators/indicator_spec.rb +120 -0
- data/spec/technical_analysis/indicators/kc_spec.rb +110 -0
- data/spec/technical_analysis/indicators/kst_spec.rb +78 -0
- data/spec/technical_analysis/indicators/macd_spec.rb +86 -0
- data/spec/technical_analysis/indicators/mfi_spec.rb +105 -0
- data/spec/technical_analysis/indicators/mi_spec.rb +79 -0
- data/spec/technical_analysis/indicators/nvi_spec.rb +119 -0
- data/spec/technical_analysis/indicators/obv_mean_spec.rb +109 -0
- data/spec/technical_analysis/indicators/obv_spec.rb +119 -0
- data/spec/technical_analysis/indicators/rsi_spec.rb +105 -0
- data/spec/technical_analysis/indicators/sma_spec.rb +115 -0
- data/spec/technical_analysis/indicators/sr_spec.rb +104 -0
- data/spec/technical_analysis/indicators/trix_spec.rb +76 -0
- data/spec/technical_analysis/indicators/tsi_spec.rb +87 -0
- data/spec/technical_analysis/indicators/uo_spec.rb +91 -0
- data/spec/technical_analysis/indicators/vi_spec.rb +105 -0
- data/spec/technical_analysis/indicators/vpt_spec.rb +118 -0
- data/spec/technical_analysis/indicators/wr_spec.rb +106 -0
- metadata +177 -0
@@ -0,0 +1,119 @@
|
|
1
|
+
module TechnicalAnalysis
|
2
|
+
# Monoey Flow Index
|
3
|
+
class Mfi < 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
|
+
"mfi"
|
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
|
+
"Money Flow 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 + 1
|
43
|
+
end
|
44
|
+
|
45
|
+
# Calculates the money flow index (MFI) for the data over the given period
|
46
|
+
# https://en.wikipedia.org/wiki/Money_flow_index
|
47
|
+
#
|
48
|
+
# @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close, :volume)
|
49
|
+
# @param period [Integer] The given period to calculate the MFI
|
50
|
+
#
|
51
|
+
# @return [Array<MfiValue>] An array of MfiValue instances
|
52
|
+
def self.calculate(data, period: 14)
|
53
|
+
period = period.to_i
|
54
|
+
Validation.validate_numeric_data(data, :high, :low, :close, :volume)
|
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
|
+
prev_typical_price = StockCalculation.typical_price(data.first)
|
62
|
+
raw_money_flows = []
|
63
|
+
|
64
|
+
data.shift
|
65
|
+
|
66
|
+
data.each do |v|
|
67
|
+
typical_price = StockCalculation.typical_price(v)
|
68
|
+
|
69
|
+
if typical_price < prev_typical_price
|
70
|
+
money_flow = (-1.0 * typical_price * v[:volume])
|
71
|
+
elsif typical_price > prev_typical_price
|
72
|
+
money_flow = (typical_price * v[:volume])
|
73
|
+
else
|
74
|
+
money_flow = 0.0
|
75
|
+
end
|
76
|
+
|
77
|
+
raw_money_flows << money_flow
|
78
|
+
|
79
|
+
if raw_money_flows.size == period
|
80
|
+
positive_period_flows = ArrayHelper.sum(raw_money_flows.map { |rmf| rmf.positive? ? rmf : 0 })
|
81
|
+
negative_period_flows = ArrayHelper.sum(raw_money_flows.map { |rmf| rmf.negative? ? rmf.abs : 0 })
|
82
|
+
|
83
|
+
money_flow_ratio = (positive_period_flows / negative_period_flows)
|
84
|
+
mfi = (100.00 - (100.00 / (1.0 + money_flow_ratio)))
|
85
|
+
|
86
|
+
output << MfiValue.new(date_time: v[:date_time], mfi: mfi)
|
87
|
+
|
88
|
+
raw_money_flows.shift
|
89
|
+
end
|
90
|
+
|
91
|
+
prev_typical_price = typical_price
|
92
|
+
end
|
93
|
+
|
94
|
+
output.sort_by(&:date_time).reverse
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
# The value class to be returned by calculations
|
100
|
+
class MfiValue
|
101
|
+
|
102
|
+
# @return [String] the date_time of the obversation as it was provided
|
103
|
+
attr_accessor :date_time
|
104
|
+
|
105
|
+
# @return [Float] the mfi calculation value
|
106
|
+
attr_accessor :mfi
|
107
|
+
|
108
|
+
def initialize(date_time: nil, mfi: nil)
|
109
|
+
@date_time = date_time
|
110
|
+
@mfi = mfi
|
111
|
+
end
|
112
|
+
|
113
|
+
# @return [Hash] the attributes as a hash
|
114
|
+
def to_hash
|
115
|
+
{ date_time: @date_time, mfi: @mfi }
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
module TechnicalAnalysis
|
2
|
+
# Mass Index
|
3
|
+
class Mi < 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
|
+
"mi"
|
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
|
+
"Mass 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(ema_period sum_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(ema_period: 9, sum_period: 25)
|
42
|
+
(ema_period.to_i * 2) + sum_period.to_i - 2
|
43
|
+
end
|
44
|
+
|
45
|
+
# Calculates the mass index (MI) for the data over the given period
|
46
|
+
# https://en.wikipedia.org/wiki/Mass_index
|
47
|
+
#
|
48
|
+
# @param data [Array] Array of hashes with keys (:date_time, :high, :low)
|
49
|
+
# @param ema_period [Integer] The given period to calculate the EMA and EMA of EMA
|
50
|
+
# @param sum_period [Integer] The given period to calculate the sum of EMA ratios
|
51
|
+
#
|
52
|
+
# @return [Array<MiValue>] An array of MiValue instances
|
53
|
+
def self.calculate(data, ema_period: 9, sum_period: 25)
|
54
|
+
ema_period = ema_period.to_i
|
55
|
+
sum_period = sum_period.to_i
|
56
|
+
Validation.validate_numeric_data(data, :high, :low)
|
57
|
+
Validation.validate_length(data, min_data_size(ema_period: ema_period, sum_period: sum_period))
|
58
|
+
Validation.validate_date_time_key(data)
|
59
|
+
|
60
|
+
data = data.sort_by { |row| row[:date_time] }
|
61
|
+
|
62
|
+
double_emas = []
|
63
|
+
high_low_diffs = []
|
64
|
+
output = []
|
65
|
+
ratio_of_emas = []
|
66
|
+
single_emas = []
|
67
|
+
|
68
|
+
data.each do |v|
|
69
|
+
high_low_diff = v[:high] - v[:low]
|
70
|
+
high_low_diffs << high_low_diff
|
71
|
+
|
72
|
+
if high_low_diffs.size == ema_period
|
73
|
+
single_ema = StockCalculation.ema(high_low_diff, high_low_diffs, ema_period, single_emas.last)
|
74
|
+
single_emas << single_ema
|
75
|
+
|
76
|
+
if single_emas.size == ema_period
|
77
|
+
double_ema = StockCalculation.ema(single_emas.last, single_emas, ema_period, double_emas.last)
|
78
|
+
double_emas << double_ema
|
79
|
+
|
80
|
+
ratio_of_emas << (single_ema / double_ema)
|
81
|
+
|
82
|
+
if ratio_of_emas.size == sum_period
|
83
|
+
output << MiValue.new(date_time: v[:date_time], mi: ArrayHelper.sum(ratio_of_emas))
|
84
|
+
|
85
|
+
double_emas.shift
|
86
|
+
ratio_of_emas.shift
|
87
|
+
end
|
88
|
+
|
89
|
+
single_emas.shift
|
90
|
+
end
|
91
|
+
|
92
|
+
high_low_diffs.shift
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
output.sort_by(&:date_time).reverse
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
# The value class to be returned by calculations
|
102
|
+
class MiValue
|
103
|
+
|
104
|
+
# @return [String] the date_time of the obversation as it was provided
|
105
|
+
attr_accessor :date_time
|
106
|
+
|
107
|
+
# @return [Float] the mi calculation value
|
108
|
+
attr_accessor :mi
|
109
|
+
|
110
|
+
def initialize(date_time: nil, mi: nil)
|
111
|
+
@date_time = date_time
|
112
|
+
@mi = mi
|
113
|
+
end
|
114
|
+
|
115
|
+
# @return [Hash] the attributes as a hash
|
116
|
+
def to_hash
|
117
|
+
{ date_time: @date_time, mi: @mi }
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module TechnicalAnalysis
|
2
|
+
# Negative Volume Index
|
3
|
+
class Nvi < 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
|
+
"nvi"
|
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
|
+
"Negative Volume 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 negative volume index (NVI) for the data
|
47
|
+
# https://en.wikipedia.org/wiki/Negative_volume_index
|
48
|
+
#
|
49
|
+
# @param data [Array] Array of hashes with keys (:date_time, :close, :volume)
|
50
|
+
#
|
51
|
+
# @return [Array<NviValue>] An array of NviValue instances
|
52
|
+
def self.calculate(data)
|
53
|
+
Validation.validate_numeric_data(data, :close, :volume)
|
54
|
+
Validation.validate_length(data, min_data_size({}))
|
55
|
+
Validation.validate_date_time_key(data)
|
56
|
+
|
57
|
+
data = data.sort_by { |row| row[:date_time] }
|
58
|
+
|
59
|
+
nvi_cumulative = 1_000.00
|
60
|
+
output = []
|
61
|
+
prev_price = data.shift
|
62
|
+
|
63
|
+
output << NviValue.new(date_time: prev_price[:date_time], nvi: nvi_cumulative) # Start with default of 1_000
|
64
|
+
|
65
|
+
data.each do |v|
|
66
|
+
volume_change = ((v[:volume] - prev_price[:volume]) / prev_price[:volume])
|
67
|
+
|
68
|
+
if volume_change < 0
|
69
|
+
price_change = ((v[:close] - prev_price[:close]) / prev_price[:close]) * 100.00
|
70
|
+
nvi_cumulative += price_change
|
71
|
+
end
|
72
|
+
|
73
|
+
output << NviValue.new(date_time: v[:date_time], nvi: nvi_cumulative)
|
74
|
+
prev_price = v
|
75
|
+
end
|
76
|
+
|
77
|
+
output.sort_by(&:date_time).reverse
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
# The value class to be returned by calculations
|
83
|
+
class NviValue
|
84
|
+
|
85
|
+
# @return [String] the date_time of the obversation as it was provided
|
86
|
+
attr_accessor :date_time
|
87
|
+
|
88
|
+
# @return [Float] the nvi calculation value
|
89
|
+
attr_accessor :nvi
|
90
|
+
|
91
|
+
def initialize(date_time: nil, nvi: nil)
|
92
|
+
@date_time = date_time
|
93
|
+
@nvi = nvi
|
94
|
+
end
|
95
|
+
|
96
|
+
# @return [Hash] the attributes as a hash
|
97
|
+
def to_hash
|
98
|
+
{ date_time: @date_time, nvi: @nvi }
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module TechnicalAnalysis
|
2
|
+
# On-balance Volume
|
3
|
+
class Obv < 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
|
+
"obv"
|
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
|
+
"On-balance 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
|
+
[]
|
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 on-balance volume (OBV) for the data over the given period
|
47
|
+
# https://en.wikipedia.org/wiki/On-balance_volume
|
48
|
+
#
|
49
|
+
# @param data [Array] Array of hashes with keys (:date_time, :close, :volume)
|
50
|
+
#
|
51
|
+
# @return [Array<ObvValue>] An array of ObvValue instances
|
52
|
+
def self.calculate(data)
|
53
|
+
Validation.validate_numeric_data(data, :close, :volume)
|
54
|
+
Validation.validate_length(data, min_data_size({}))
|
55
|
+
Validation.validate_date_time_key(data)
|
56
|
+
|
57
|
+
data = data.sort_by { |row| row[:date_time] }
|
58
|
+
|
59
|
+
current_obv = 0
|
60
|
+
output = []
|
61
|
+
prior_close = nil
|
62
|
+
prior_volume = nil
|
63
|
+
|
64
|
+
data.each do |v|
|
65
|
+
volume = v[:volume]
|
66
|
+
close = v[:close]
|
67
|
+
|
68
|
+
unless prior_close.nil?
|
69
|
+
current_obv += volume if close > prior_close
|
70
|
+
current_obv -= volume if close < prior_close
|
71
|
+
end
|
72
|
+
|
73
|
+
output << ObvValue.new(date_time: v[:date_time], obv: current_obv)
|
74
|
+
|
75
|
+
prior_volume = volume
|
76
|
+
prior_close = close
|
77
|
+
end
|
78
|
+
|
79
|
+
output.sort_by(&:date_time).reverse
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
# The value class to be returned by calculations
|
85
|
+
class ObvValue
|
86
|
+
|
87
|
+
# @return [String] the date_time of the obversation as it was provided
|
88
|
+
attr_accessor :date_time
|
89
|
+
|
90
|
+
# @return [Float] the obv calculation value
|
91
|
+
attr_accessor :obv
|
92
|
+
|
93
|
+
def initialize(date_time: nil, obv: nil)
|
94
|
+
@date_time = date_time
|
95
|
+
@obv = obv
|
96
|
+
end
|
97
|
+
|
98
|
+
# @return [Hash] the attributes as a hash
|
99
|
+
def to_hash
|
100
|
+
{ date_time: @date_time, obv: @obv }
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|