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