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,95 @@
1
+ module TechnicalAnalysis
2
+ # Volume-price Trend
3
+ class Vpt < 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
+ "vpt"
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
+ "Volume-price Trend"
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
+ 2
44
+ end
45
+
46
+ # Calculates the volume-price trend (VPT) for the data
47
+ # https://en.wikipedia.org/wiki/Volume%E2%80%93price_trend
48
+ #
49
+ # @param data [Array] Array of hashes with keys (:date_time, :close, :volume)
50
+ #
51
+ # @return [Array<VptValue>] An array of VptValue 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
+ output = []
60
+ prev_price = data.shift
61
+ prev_pvt = 0
62
+
63
+ data.each do |v|
64
+ pvt = prev_pvt + (((v[:close] - prev_price[:close]) / prev_price[:close]) * v[:volume])
65
+ output << VptValue.new(date_time: v[:date_time], vpt: pvt)
66
+ prev_price = v
67
+ prev_pvt = pvt
68
+ end
69
+
70
+ output.sort_by(&:date_time).reverse
71
+ end
72
+
73
+ end
74
+
75
+ # The value class to be returned by calculations
76
+ class VptValue
77
+
78
+ # @return [String] the date_time of the obversation as it was provided
79
+ attr_accessor :date_time
80
+
81
+ # @return [Float] the vpt calculation value
82
+ attr_accessor :vpt
83
+
84
+ def initialize(date_time: nil, vpt: nil)
85
+ @date_time = date_time
86
+ @vpt = vpt
87
+ end
88
+
89
+ # @return [Hash] the attributes as a hash
90
+ def to_hash
91
+ { date_time: @date_time, vpt: @vpt }
92
+ end
93
+
94
+ end
95
+ end
@@ -0,0 +1,103 @@
1
+ module TechnicalAnalysis
2
+ # Williams %R
3
+ class Wr < 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
+ "wr"
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
+ "Williams %R"
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
43
+ end
44
+
45
+ # Calculates the Williams %R (WR) for the data over the given period
46
+ # https://en.wikipedia.org/wiki/Williams_%25R
47
+ #
48
+ # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close)
49
+ # @param period [Integer] The given look-back period to calculate the WR
50
+ #
51
+ # @return [Array<WrValue>] An array of WrValue 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
+
63
+ data.each do |v|
64
+ period_values << { high: v[:high], low: v[:low] }
65
+
66
+ if period_values.size == period
67
+ lowest_low = period_values.map { |pv| pv[:low] }.min
68
+ highest_high = period_values.map { |pv| pv[:high] }.max
69
+
70
+ wr = (highest_high - v[:close]) / (highest_high - lowest_low) * -100
71
+
72
+ output << WrValue.new(date_time: v[:date_time], wr: wr)
73
+
74
+ period_values.shift
75
+ end
76
+ end
77
+
78
+ output.sort_by(&:date_time).reverse
79
+ end
80
+
81
+ end
82
+
83
+ # The value class to be returned by calculations
84
+ class WrValue
85
+
86
+ # @return [String] the date_time of the obversation as it was provided
87
+ attr_accessor :date_time
88
+
89
+ # @return [Float] the wr calculation value
90
+ attr_accessor :wr
91
+
92
+ def initialize(date_time: nil, wr: nil)
93
+ @date_time = date_time
94
+ @wr = wr
95
+ end
96
+
97
+ # @return [Hash] the attributes as a hash
98
+ def to_hash
99
+ { date_time: @date_time, wr: @wr }
100
+ end
101
+
102
+ end
103
+ end
@@ -0,0 +1,31 @@
1
+ require 'technical-analysis'
2
+ require 'spec_helper'
3
+
4
+ describe 'ArrayHelper' do
5
+ array_of_numbers = [1, 3, 5, 7, 9].freeze
6
+
7
+ it 'Calculates sum' do
8
+ sum = TechnicalAnalysis::ArrayHelper.sum(array_of_numbers)
9
+ expect(sum).to eq(25)
10
+ end
11
+
12
+ it 'Calculates mean' do
13
+ mean = TechnicalAnalysis::ArrayHelper.mean(array_of_numbers)
14
+ expect(mean).to eq(5)
15
+ end
16
+
17
+ it 'Calculates average' do
18
+ average = TechnicalAnalysis::ArrayHelper.average(array_of_numbers)
19
+ expect(average).to eq(5)
20
+ end
21
+
22
+ it 'Calculates sample_variance' do
23
+ sample_variance = TechnicalAnalysis::ArrayHelper.sample_variance(array_of_numbers)
24
+ expect(sample_variance).to eq(10.0)
25
+ end
26
+
27
+ it 'Calculates standard_deviation' do
28
+ standard_deviation = TechnicalAnalysis::ArrayHelper.standard_deviation(array_of_numbers)
29
+ expect(standard_deviation).to eq(3.1622776601683795)
30
+ end
31
+ end
@@ -0,0 +1,22 @@
1
+ require 'technical-analysis'
2
+ require 'spec_helper'
3
+
4
+ describe 'Validation' do
5
+ describe "date_time validation" do
6
+ input_data = SpecHelper.get_test_data(:close)
7
+
8
+ it 'Throws exception for invalid timestamp key' do
9
+ bad_date_time_key_data = input_data.each { |row| row[:bad_timestamp_key] = row.delete :date_time }
10
+ expect { TechnicalAnalysis::Validation.validate_date_time_key(bad_date_time_key_data) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError)
11
+ end
12
+ end
13
+
14
+ describe "numeric validation" do
15
+ input_data = SpecHelper.get_test_data(:close)
16
+
17
+ it 'Throws exception for non numeric price data' do
18
+ non_numeric_data = input_data.each { |row| row[:close] = row.delete(:close).to_s }
19
+ expect { TechnicalAnalysis::Validation.validate_numeric_data(non_numeric_data, :close) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,26 @@
1
+ require 'csv'
2
+
3
+ class SpecHelper
4
+
5
+ TEST_DATA_PATH = File.join(File.dirname(__FILE__),'ta_test_data.csv')
6
+ FLOAT_KEYS = [:open, :high, :low, :close].freeze
7
+ INTEGER_KEYS = [:volume].freeze
8
+
9
+ def self.get_test_data(*columns)
10
+ @data = CSV.read(TEST_DATA_PATH, headers: true)
11
+ columns = columns.map(&:to_sym)
12
+ output = []
13
+ @data.each do |v|
14
+ col_hash = { date_time: v["date_time"] }
15
+ columns.each do |col|
16
+ value = v[col.to_s]
17
+ value = value.to_f if FLOAT_KEYS.include?(col)
18
+ value = value.to_i if INTEGER_KEYS.include?(col)
19
+ col_hash[col] = value
20
+ end
21
+ output << col_hash
22
+ end
23
+ output
24
+ end
25
+
26
+ end
@@ -0,0 +1,64 @@
1
+ date_time,close,volume,open,high,low
2
+ "2019-01-09T00:00:00.000Z",153.3100,45034370.0000,151.2900,154.5300,149.6300
3
+ "2019-01-08T00:00:00.000Z",150.7500,40622910.0000,149.5600,151.8200,148.5200
4
+ "2019-01-07T00:00:00.000Z",147.9300,54571440.0000,148.7000,148.8300,145.9000
5
+ "2019-01-04T00:00:00.000Z",148.2600,57423650.0000,144.5300,148.5499,143.8000
6
+ "2019-01-03T00:00:00.000Z",142.1900,91106840.0000,143.9800,145.7200,142.0000
7
+ "2019-01-02T00:00:00.000Z",157.9200,35637070.0000,154.8900,158.8500,154.2300
8
+ "2018-12-31T00:00:00.000Z",157.7400,34499390.0000,158.5300,159.3600,156.4800
9
+ "2018-12-28T00:00:00.000Z",156.2300,41740600.0000,157.5000,158.5200,154.5500
10
+ "2018-12-27T00:00:00.000Z",156.1500,51608850.0000,155.8400,156.7700,150.0700
11
+ "2018-12-26T00:00:00.000Z",157.1700,58133850.0000,148.3000,157.2300,146.7200
12
+ "2018-12-24T00:00:00.000Z",146.8300,37169230.0000,148.1500,151.5500,146.5900
13
+ "2018-12-21T00:00:00.000Z",150.7300,95497900.0000,156.8600,158.1600,149.6300
14
+ "2018-12-20T00:00:00.000Z",156.8300,64398230.0000,160.4000,162.1100,155.3000
15
+ "2018-12-19T00:00:00.000Z",160.8900,47597670.0000,166.0000,167.4500,159.0900
16
+ "2018-12-18T00:00:00.000Z",166.0700,33753490.0000,165.3800,167.5300,164.3900
17
+ "2018-12-17T00:00:00.000Z",163.9400,43250420.0000,165.4500,168.3500,162.7300
18
+ "2018-12-14T00:00:00.000Z",165.4800,40620360.0000,169.0000,169.0800,165.2800
19
+ "2018-12-13T00:00:00.000Z",170.9500,31754210.0000,170.4900,172.5700,169.5500
20
+ "2018-12-12T00:00:00.000Z",169.1000,35474680.0000,170.4000,171.9200,169.0200
21
+ "2018-12-11T00:00:00.000Z",168.6300,45968040.0000,171.6600,171.7900,167.0000
22
+ "2018-12-10T00:00:00.000Z",169.6000,61759000.0000,165.0000,170.0900,163.3300
23
+ "2018-12-07T00:00:00.000Z",168.4900,41678680.0000,173.4900,174.4900,168.3000
24
+ "2018-12-06T00:00:00.000Z",174.7200,42704910.0000,171.7600,174.7800,170.4200
25
+ "2018-12-04T00:00:00.000Z",176.6900,41141250.0000,180.9500,182.3899,176.2700
26
+ "2018-12-03T00:00:00.000Z",184.8200,40537700.0000,184.4600,184.9400,181.2100
27
+ "2018-11-30T00:00:00.000Z",178.5800,39424260.0000,180.2900,180.3300,177.0300
28
+ "2018-11-29T00:00:00.000Z",179.5500,41523580.0000,182.6600,182.8000,177.7000
29
+ "2018-11-28T00:00:00.000Z",180.9400,45941750.0000,176.7300,181.2900,174.9300
30
+ "2018-11-27T00:00:00.000Z",174.2400,41156140.0000,171.5100,174.7700,170.8800
31
+ "2018-11-26T00:00:00.000Z",174.6200,44662320.0000,174.2400,174.9500,170.2600
32
+ "2018-11-23T00:00:00.000Z",172.2900,23623970.0000,174.9400,176.5950,172.1000
33
+ "2018-11-21T00:00:00.000Z",176.7800,31096240.0000,179.7300,180.2700,176.5500
34
+ "2018-11-20T00:00:00.000Z",176.9800,67678680.0000,178.3700,181.4700,175.5100
35
+ "2018-11-19T00:00:00.000Z",185.8600,41626820.0000,190.0000,190.7000,184.9900
36
+ "2018-11-16T00:00:00.000Z",193.5300,36191330.0000,190.5000,194.9695,189.4600
37
+ "2018-11-15T00:00:00.000Z",191.4100,46271660.0000,188.3900,191.9700,186.9000
38
+ "2018-11-14T00:00:00.000Z",186.8000,60547340.0000,193.9000,194.4800,185.9300
39
+ "2018-11-13T00:00:00.000Z",192.2300,46725710.0000,191.6300,197.1800,191.4501
40
+ "2018-11-12T00:00:00.000Z",194.1700,50991030.0000,199.0000,199.8500,193.7900
41
+ "2018-11-09T00:00:00.000Z",204.4700,34317760.0000,205.5500,206.0100,202.2500
42
+ "2018-11-08T00:00:00.000Z",208.4900,25289270.0000,209.9800,210.1200,206.7500
43
+ "2018-11-07T00:00:00.000Z",209.9500,33291640.0000,205.9700,210.0600,204.1300
44
+ "2018-11-06T00:00:00.000Z",203.7700,31774720.0000,201.9200,204.7200,201.6900
45
+ "2018-11-05T00:00:00.000Z",201.5900,66072170.0000,204.3000,204.3900,198.1700
46
+ "2018-11-02T00:00:00.000Z",207.4800,91046560.0000,209.5500,213.6500,205.4300
47
+ "2018-11-01T00:00:00.000Z",222.2200,52954070.0000,219.0500,222.3600,216.8100
48
+ "2018-10-31T00:00:00.000Z",218.8600,38016810.0000,216.8800,220.4500,216.6200
49
+ "2018-10-30T00:00:00.000Z",213.3000,36487930.0000,211.1500,215.1800,209.2700
50
+ "2018-10-29T00:00:00.000Z",212.2400,45713690.0000,219.1900,219.6900,206.0900
51
+ "2018-10-26T00:00:00.000Z",216.3000,47191700.0000,215.9000,220.1900,212.6700
52
+ "2018-10-25T00:00:00.000Z",219.8000,29027340.0000,217.7100,221.3800,216.7500
53
+ "2018-10-24T00:00:00.000Z",215.0900,39992120.0000,222.6000,224.2300,214.5400
54
+ "2018-10-23T00:00:00.000Z",222.7300,38681170.0000,215.8300,223.2500,214.7000
55
+ "2018-10-22T00:00:00.000Z",220.6500,28751540.0000,219.7900,223.3600,218.9400
56
+ "2018-10-19T00:00:00.000Z",219.3100,32874330.0000,218.0600,221.2600,217.4300
57
+ "2018-10-18T00:00:00.000Z",216.0200,32389280.0000,217.8600,219.7400,213.0000
58
+ "2018-10-17T00:00:00.000Z",221.1900,22692880.0000,222.3000,222.6400,219.3400
59
+ "2018-10-16T00:00:00.000Z",222.1500,28802550.0000,218.9300,222.9900,216.7627
60
+ "2018-10-15T00:00:00.000Z",217.3600,30280450.0000,221.1600,221.8300,217.2700
61
+ "2018-10-12T00:00:00.000Z",222.1100,39494770.0000,220.4200,222.8800,216.8400
62
+ "2018-10-11T00:00:00.000Z",214.4500,52902320.0000,214.5200,219.5000,212.3200
63
+ "2018-10-10T00:00:00.000Z",216.3600,41084070.0000,225.4600,226.3500,216.0500
64
+ "2018-10-09T00:00:00.000Z",226.8700,26656630.0000,223.6400,227.2700,222.2462
@@ -0,0 +1,116 @@
1
+ require 'technical-analysis'
2
+ require 'spec_helper'
3
+
4
+ describe 'Indicators' do
5
+ describe "ADI" do
6
+ indicator = TechnicalAnalysis::Adi
7
+
8
+ describe 'Accumulation/Distribution Index' do
9
+ it 'Calculates ADI' do
10
+
11
+ input_data = SpecHelper.get_test_data(:volume, :high, :low, :close)
12
+ output = indicator.calculate(input_data)
13
+ normalized_output = output.map(&:to_hash)
14
+
15
+ expected_output = [
16
+ {:date_time=>"2019-01-09T00:00:00.000Z", :adi=>-112451134.66006838},
17
+ {:date_time=>"2019-01-08T00:00:00.000Z", :adi=>-135060226.53761944},
18
+ {:date_time=>"2019-01-07T00:00:00.000Z", :adi=>-149339794.90125585},
19
+ {:date_time=>"2019-01-04T00:00:00.000Z", :adi=>-170386118.17770624},
20
+ {:date_time=>"2019-01-03T00:00:00.000Z", :adi=>-220800308.5532927},
21
+ {:date_time=>"2019-01-02T00:00:00.000Z", :adi=>-139000081.24146464},
22
+ {:date_time=>"2018-12-31T00:00:00.000Z", :adi=>-160289759.42328274},
23
+ {:date_time=>"2018-12-28T00:00:00.000Z", :adi=>-155977335.67328295},
24
+ {:date_time=>"2018-12-27T00:00:00.000Z", :adi=>-149563792.60023466},
25
+ {:date_time=>"2018-12-26T00:00:00.000Z", :adi=>-191621153.9435182},
26
+ {:date_time=>"2018-12-24T00:00:00.000Z", :adi=>-249091249.23371798},
27
+ {:date_time=>"2018-12-21T00:00:00.000Z", :adi=>-215519041.4917826},
28
+ {:date_time=>"2018-12-20T00:00:00.000Z", :adi=>-144651314.99705797},
29
+ {:date_time=>"2018-12-19T00:00:00.000Z", :adi=>-109189734.6005822},
30
+ {:date_time=>"2018-12-18T00:00:00.000Z", :adi=>-82088668.90680213},
31
+ {:date_time=>"2018-12-17T00:00:00.000Z", :adi=>-84453563.11062376},
32
+ {:date_time=>"2018-12-14T00:00:00.000Z", :adi=>-59826989.44514345},
33
+ {:date_time=>"2018-12-13T00:00:00.000Z", :adi=>-23482456.813564237},
34
+ {:date_time=>"2018-12-12T00:00:00.000Z", :adi=>-21169236.217537448},
35
+ {:date_time=>"2018-12-11T00:00:00.000Z", :adi=>12348220.058324995},
36
+ {:date_time=>"2018-12-10T00:00:00.000Z", :adi=>27031122.187761355},
37
+ {:date_time=>"2018-12-07T00:00:00.000Z", :adi=>-25774650.00158758},
38
+ {:date_time=>"2018-12-06T00:00:00.000Z", :adi=>13345403.439446371},
39
+ {:date_time=>"2018-12-04T00:00:00.000Z", :adi=>-28184142.065140743},
40
+ {:date_time=>"2018-12-03T00:00:00.000Z", :adi=>7310177.429459017},
41
+ {:date_time=>"2018-11-30T00:00:00.000Z", :adi=>-30619198.70995107},
42
+ {:date_time=>"2018-11-29T00:00:00.000Z", :adi=>-28229849.61904212},
43
+ {:date_time=>"2018-11-28T00:00:00.000Z", :adi=>-16831219.815120786},
44
+ {:date_time=>"2018-11-27T00:00:00.000Z", :adi=>-57716487.89688186},
45
+ {:date_time=>"2018-11-26T00:00:00.000Z", :adi=>-87657844.24649628},
46
+ {:date_time=>"2018-11-23T00:00:00.000Z", :adi=>-126035061.64521725},
47
+ {:date_time=>"2018-11-21T00:00:00.000Z", :adi=>-104408223.70305927},
48
+ {:date_time=>"2018-11-20T00:00:00.000Z", :adi=>-77157217.68155372},
49
+ {:date_time=>"2018-11-19T00:00:00.000Z", :adi=>-42863658.35269459},
50
+ {:date_time=>"2018-11-16T00:00:00.000Z", :adi=>-13921718.702957403},
51
+ {:date_time=>"2018-11-15T00:00:00.000Z", :adi=>-31201198.431607798},
52
+ {:date_time=>"2018-11-14T00:00:00.000Z", :adi=>-67251111.0548819},
53
+ {:date_time=>"2018-11-13T00:00:00.000Z", :adi=>-19025685.861899547},
54
+ {:date_time=>"2018-11-12T00:00:00.000Z", :adi=>14980297.36136794},
55
+ {:date_time=>"2018-11-09T00:00:00.000Z", :adi=>59576412.70790268},
56
+ {:date_time=>"2018-11-08T00:00:00.000Z", :adi=>53370009.30364728},
57
+ {:date_time=>"2018-11-07T00:00:00.000Z", :adi=>52544543.51729703},
58
+ {:date_time=>"2018-11-06T00:00:00.000Z", :adi=>20488006.51898352},
59
+ {:date_time=>"2018-11-05T00:00:00.000Z", :adi=>8638028.433174696},
60
+ {:date_time=>"2018-11-02T00:00:00.000Z", :adi=>2052056.5039138943},
61
+ {:date_time=>"2018-11-01T00:00:00.000Z", :adi=>47686098.74235708},
62
+ {:date_time=>"2018-10-31T00:00:00.000Z", :adi=>-2596414.5729579534},
63
+ {:date_time=>"2018-10-30T00:00:00.000Z", :adi=>-9048353.606900878},
64
+ {:date_time=>"2018-10-29T00:00:00.000Z", :adi=>-22322304.45292461},
65
+ {:date_time=>"2018-10-26T00:00:00.000Z", :adi=>-17952613.497042313},
66
+ {:date_time=>"2018-10-25T00:00:00.000Z", :adi=>-16320985.571510637},
67
+ {:date_time=>"2018-10-24T00:00:00.000Z", :adi=>-25537009.286413625},
68
+ {:date_time=>"2018-10-23T00:00:00.000Z", :adi=>9915241.57013943},
69
+ {:date_time=>"2018-10-22T00:00:00.000Z", :adi=>-24060850.441556394},
70
+ {:date_time=>"2018-10-19T00:00:00.000Z", :adi=>-17555977.138388995},
71
+ {:date_time=>"2018-10-18T00:00:00.000Z", :adi=>-16955140.819851194},
72
+ {:date_time=>"2018-10-17T00:00:00.000Z", :adi=>-13591269.009762233},
73
+ {:date_time=>"2018-10-16T00:00:00.000Z", :adi=>-16341921.130974408},
74
+ {:date_time=>"2018-10-15T00:00:00.000Z", :adi=>-37374123.7894299},
75
+ {:date_time=>"2018-10-12T00:00:00.000Z", :adi=>-8288954.710482582},
76
+ {:date_time=>"2018-10-11T00:00:00.000Z", :adi=>-37713866.134323865},
77
+ {:date_time=>"2018-10-10T00:00:00.000Z", :adi=>-16199273.599504825},
78
+ {:date_time=>"2018-10-09T00:00:00.000Z", :adi=>22411774.711174767}
79
+ ]
80
+
81
+ expect(normalized_output).to eq(expected_output)
82
+ end
83
+
84
+ it 'Returns the symbol' do
85
+ indicator_symbol = indicator.indicator_symbol
86
+ expect(indicator_symbol).to eq('adi')
87
+ end
88
+
89
+ it 'Returns the name' do
90
+ indicator_name = indicator.indicator_name
91
+ expect(indicator_name).to eq('Accumulation/Distribution Index')
92
+ end
93
+
94
+ it 'Returns the valid options' do
95
+ valid_options = indicator.valid_options
96
+ expect(valid_options).to eq([])
97
+ end
98
+
99
+ it 'Validates options' do
100
+ valid_options = {}
101
+ options_validated = indicator.validate_options(valid_options)
102
+ expect(options_validated).to eq(true)
103
+ end
104
+
105
+ it 'Throws exception for invalid options' do
106
+ invalid_options = { test: 10 }
107
+ expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError)
108
+ end
109
+
110
+ it 'Calculates minimum data size' do
111
+ options = {}
112
+ expect(indicator.min_data_size(options)).to eq(1)
113
+ end
114
+ end
115
+ end
116
+ end