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,79 @@
1
+ require 'technical-analysis'
2
+ require 'spec_helper'
3
+
4
+ describe 'Indicators' do
5
+ describe "MI" do
6
+ input_data = SpecHelper.get_test_data(:high, :low)
7
+ indicator = TechnicalAnalysis::Mi
8
+
9
+ describe 'Simple Mass Index' do
10
+ it 'Calculates MI' do
11
+ output = indicator.calculate(input_data, ema_period: 9, sum_period: 25)
12
+ normalized_output = output.map(&:to_hash)
13
+
14
+ expected_output = [
15
+ {:date_time=>"2019-01-09T00:00:00.000Z", :mi=>24.77520633216394},
16
+ {:date_time=>"2019-01-08T00:00:00.000Z", :mi=>24.80084030980544},
17
+ {:date_time=>"2019-01-07T00:00:00.000Z", :mi=>24.924292786436485},
18
+ {:date_time=>"2019-01-04T00:00:00.000Z", :mi=>25.026285600546654},
19
+ {:date_time=>"2019-01-03T00:00:00.000Z", :mi=>25.018142841959207},
20
+ {:date_time=>"2019-01-02T00:00:00.000Z", :mi=>25.04245599370965},
21
+ {:date_time=>"2018-12-31T00:00:00.000Z", :mi=>25.03284918462693},
22
+ {:date_time=>"2018-12-28T00:00:00.000Z", :mi=>25.020764664334674},
23
+ {:date_time=>"2018-12-27T00:00:00.000Z", :mi=>24.964776002066408},
24
+ {:date_time=>"2018-12-26T00:00:00.000Z", :mi=>24.791003528125515},
25
+ {:date_time=>"2018-12-24T00:00:00.000Z", :mi=>24.564590708470064},
26
+ {:date_time=>"2018-12-21T00:00:00.000Z", :mi=>24.454674020826847},
27
+ {:date_time=>"2018-12-20T00:00:00.000Z", :mi=>24.303447406952383},
28
+ {:date_time=>"2018-12-19T00:00:00.000Z", :mi=>24.12156756268421},
29
+ {:date_time=>"2018-12-18T00:00:00.000Z", :mi=>23.94958830559542},
30
+ {:date_time=>"2018-12-17T00:00:00.000Z", :mi=>23.879826345759078},
31
+ {:date_time=>"2018-12-14T00:00:00.000Z", :mi=>23.792012619835983},
32
+ {:date_time=>"2018-12-13T00:00:00.000Z", :mi=>23.82241708019551},
33
+ {:date_time=>"2018-12-12T00:00:00.000Z", :mi=>23.835760161850434},
34
+ {:date_time=>"2018-12-11T00:00:00.000Z", :mi=>23.89261610689666},
35
+ {:date_time=>"2018-12-10T00:00:00.000Z", :mi=>23.890966368346767},
36
+ {:date_time=>"2018-12-07T00:00:00.000Z", :mi=>23.8163614080134},
37
+ {:date_time=>"2018-12-06T00:00:00.000Z", :mi=>23.82917406071097}
38
+ ]
39
+
40
+ expect(normalized_output).to eq(expected_output)
41
+ end
42
+
43
+ it "Throws exception if not enough data" do
44
+ expect {indicator.calculate(input_data, ema_period: input_data.size+1)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError)
45
+ end
46
+
47
+ it 'Returns the symbol' do
48
+ indicator_symbol = indicator.indicator_symbol
49
+ expect(indicator_symbol).to eq('mi')
50
+ end
51
+
52
+ it 'Returns the name' do
53
+ indicator_name = indicator.indicator_name
54
+ expect(indicator_name).to eq('Mass Index')
55
+ end
56
+
57
+ it 'Returns the valid options' do
58
+ valid_options = indicator.valid_options
59
+ expect(valid_options).to eq(%i(ema_period sum_period))
60
+ end
61
+
62
+ it 'Validates options' do
63
+ valid_options = { ema_period: 9, sum_period: 25 }
64
+ options_validated = indicator.validate_options(valid_options)
65
+ expect(options_validated).to eq(true)
66
+ end
67
+
68
+ it 'Throws exception for invalid options' do
69
+ invalid_options = { test: 10 }
70
+ expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError)
71
+ end
72
+
73
+ it 'Calculates minimum data size' do
74
+ options = { ema_period: 10, sum_period: 20 }
75
+ expect(indicator.min_data_size(options)).to eq(38)
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,119 @@
1
+ require 'technical-analysis'
2
+ require 'spec_helper'
3
+
4
+ describe 'Indicators' do
5
+ describe "NVI" do
6
+ input_data = SpecHelper.get_test_data(:close, :volume)
7
+ indicator = TechnicalAnalysis::Nvi
8
+
9
+ describe 'Negative Volume Index' do
10
+ it 'Calculates NVI' do
11
+ output = indicator.calculate(input_data)
12
+ normalized_output = output.map(&:to_hash)
13
+
14
+ expected_output = [
15
+ {:date_time=>"2019-01-09T00:00:00.000Z", :nvi=>1002.8410612825647},
16
+ {:date_time=>"2019-01-08T00:00:00.000Z", :nvi=>1002.8410612825647},
17
+ {:date_time=>"2019-01-07T00:00:00.000Z", :nvi=>1000.9347542454526},
18
+ {:date_time=>"2019-01-04T00:00:00.000Z", :nvi=>1001.1573361960799},
19
+ {:date_time=>"2019-01-03T00:00:00.000Z", :nvi=>996.888400265283},
20
+ {:date_time=>"2019-01-02T00:00:00.000Z", :nvi=>996.888400265283},
21
+ {:date_time=>"2018-12-31T00:00:00.000Z", :nvi=>996.888400265283},
22
+ {:date_time=>"2018-12-28T00:00:00.000Z", :nvi=>995.9218765502475},
23
+ {:date_time=>"2018-12-27T00:00:00.000Z", :nvi=>995.8706437612625},
24
+ {:date_time=>"2018-12-26T00:00:00.000Z", :nvi=>996.519622574013},
25
+ {:date_time=>"2018-12-24T00:00:00.000Z", :nvi=>996.519622574013},
26
+ {:date_time=>"2018-12-21T00:00:00.000Z", :nvi=>999.1070305219995},
27
+ {:date_time=>"2018-12-20T00:00:00.000Z", :nvi=>999.1070305219995},
28
+ {:date_time=>"2018-12-19T00:00:00.000Z", :nvi=>999.1070305219995},
29
+ {:date_time=>"2018-12-18T00:00:00.000Z", :nvi=>999.1070305219995},
30
+ {:date_time=>"2018-12-17T00:00:00.000Z", :nvi=>997.8077746966976},
31
+ {:date_time=>"2018-12-14T00:00:00.000Z", :nvi=>997.8077746966976},
32
+ {:date_time=>"2018-12-13T00:00:00.000Z", :nvi=>997.8077746966976},
33
+ {:date_time=>"2018-12-12T00:00:00.000Z", :nvi=>996.713747493859},
34
+ {:date_time=>"2018-12-11T00:00:00.000Z", :nvi=>996.4350307767862},
35
+ {:date_time=>"2018-12-10T00:00:00.000Z", :nvi=>997.0069647390503},
36
+ {:date_time=>"2018-12-07T00:00:00.000Z", :nvi=>997.0069647390503},
37
+ {:date_time=>"2018-12-06T00:00:00.000Z", :nvi=>1000.5726698672554},
38
+ {:date_time=>"2018-12-04T00:00:00.000Z", :nvi=>1000.5726698672554},
39
+ {:date_time=>"2018-12-03T00:00:00.000Z", :nvi=>1000.5726698672554},
40
+ {:date_time=>"2018-11-30T00:00:00.000Z", :nvi=>1000.5726698672554},
41
+ {:date_time=>"2018-11-29T00:00:00.000Z", :nvi=>1001.1129093548633},
42
+ {:date_time=>"2018-11-28T00:00:00.000Z", :nvi=>1001.8811198113682},
43
+ {:date_time=>"2018-11-27T00:00:00.000Z", :nvi=>1001.8811198113682},
44
+ {:date_time=>"2018-11-26T00:00:00.000Z", :nvi=>1002.0987352047939},
45
+ {:date_time=>"2018-11-23T00:00:00.000Z", :nvi=>1002.0987352047939},
46
+ {:date_time=>"2018-11-21T00:00:00.000Z", :nvi=>1004.6386152817257},
47
+ {:date_time=>"2018-11-20T00:00:00.000Z", :nvi=>1004.7516224011742},
48
+ {:date_time=>"2018-11-19T00:00:00.000Z", :nvi=>1004.7516224011742},
49
+ {:date_time=>"2018-11-16T00:00:00.000Z", :nvi=>1004.7516224011742},
50
+ {:date_time=>"2018-11-15T00:00:00.000Z", :nvi=>1003.6440522637729},
51
+ {:date_time=>"2018-11-14T00:00:00.000Z", :nvi=>1001.1761721781198},
52
+ {:date_time=>"2018-11-13T00:00:00.000Z", :nvi=>1001.1761721781198},
53
+ {:date_time=>"2018-11-12T00:00:00.000Z", :nvi=>1002.1752966566695},
54
+ {:date_time=>"2018-11-09T00:00:00.000Z", :nvi=>1002.1752966566695},
55
+ {:date_time=>"2018-11-08T00:00:00.000Z", :nvi=>1002.1752966566695},
56
+ {:date_time=>"2018-11-07T00:00:00.000Z", :nvi=>1002.8707003242093},
57
+ {:date_time=>"2018-11-06T00:00:00.000Z", :nvi=>1002.8707003242093},
58
+ {:date_time=>"2018-11-05T00:00:00.000Z", :nvi=>1001.7892974768458},
59
+ {:date_time=>"2018-11-02T00:00:00.000Z", :nvi=>1004.6281253156736},
60
+ {:date_time=>"2018-11-01T00:00:00.000Z", :nvi=>1004.6281253156736},
61
+ {:date_time=>"2018-10-31T00:00:00.000Z", :nvi=>1004.6281253156736},
62
+ {:date_time=>"2018-10-30T00:00:00.000Z", :nvi=>1004.6281253156736},
63
+ {:date_time=>"2018-10-29T00:00:00.000Z", :nvi=>1004.1286907133366},
64
+ {:date_time=>"2018-10-26T00:00:00.000Z", :nvi=>1006.0057133670583},
65
+ {:date_time=>"2018-10-25T00:00:00.000Z", :nvi=>1006.0057133670583},
66
+ {:date_time=>"2018-10-24T00:00:00.000Z", :nvi=>1003.8159323451605},
67
+ {:date_time=>"2018-10-23T00:00:00.000Z", :nvi=>1003.8159323451605},
68
+ {:date_time=>"2018-10-22T00:00:00.000Z", :nvi=>1003.8159323451605},
69
+ {:date_time=>"2018-10-19T00:00:00.000Z", :nvi=>1003.2049250951491},
70
+ {:date_time=>"2018-10-18T00:00:00.000Z", :nvi=>1003.2049250951491},
71
+ {:date_time=>"2018-10-17T00:00:00.000Z", :nvi=>1003.2049250951491},
72
+ {:date_time=>"2018-10-16T00:00:00.000Z", :nvi=>1003.6370655407939},
73
+ {:date_time=>"2018-10-15T00:00:00.000Z", :nvi=>1001.4333482054976},
74
+ {:date_time=>"2018-10-12T00:00:00.000Z", :nvi=>1003.5719281883889},
75
+ {:date_time=>"2018-10-11T00:00:00.000Z", :nvi=>1000.0},
76
+ {:date_time=>"2018-10-10T00:00:00.000Z", :nvi=>1000.0},
77
+ {:date_time=>"2018-10-09T00:00:00.000Z", :nvi=>1000.0}
78
+ ]
79
+
80
+ expect(normalized_output).to eq(expected_output)
81
+ end
82
+
83
+ it "Throws exception if not enough data" do
84
+ expect {indicator.calculate([])}.to raise_exception(TechnicalAnalysis::Validation::ValidationError)
85
+ end
86
+
87
+ it 'Returns the symbol' do
88
+ indicator_symbol = indicator.indicator_symbol
89
+ expect(indicator_symbol).to eq('nvi')
90
+ end
91
+
92
+ it 'Returns the name' do
93
+ indicator_name = indicator.indicator_name
94
+ expect(indicator_name).to eq('Negative Volume Index')
95
+ end
96
+
97
+ it 'Returns the valid options' do
98
+ valid_options = indicator.valid_options
99
+ expect(valid_options).to eq([])
100
+ end
101
+
102
+ it 'Validates options' do
103
+ valid_options = {}
104
+ options_validated = indicator.validate_options(valid_options)
105
+ expect(options_validated).to eq(true)
106
+ end
107
+
108
+ it 'Throws exception for invalid options' do
109
+ invalid_options = { test: 10 }
110
+ expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError)
111
+ end
112
+
113
+ it 'Calculates minimum data size' do
114
+ options = {}
115
+ expect(indicator.min_data_size(options)).to eq(1)
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,109 @@
1
+ require 'technical-analysis'
2
+ require 'spec_helper'
3
+
4
+ describe 'Indicators' do
5
+ describe "OBV Mean" do
6
+ input_data = SpecHelper.get_test_data(:close, :volume)
7
+ indicator = TechnicalAnalysis::ObvMean
8
+
9
+ describe 'On-balance Volume Mean' do
10
+ it 'Calculates OBV Mean (10 day)' do
11
+ output = indicator.calculate(input_data, period: 10)
12
+ normalized_output = output.map(&:to_hash)
13
+
14
+ expected_output = [
15
+ {:date_time=>"2019-01-09T00:00:00.000Z", :obv_mean=>-642606913.0},
16
+ {:date_time=>"2019-01-08T00:00:00.000Z", :obv_mean=>-654187384.0},
17
+ {:date_time=>"2019-01-07T00:00:00.000Z", :obv_mean=>-657547495.0},
18
+ {:date_time=>"2019-01-04T00:00:00.000Z", :obv_mean=>-647295525.0},
19
+ {:date_time=>"2019-01-03T00:00:00.000Z", :obv_mean=>-636060876.0},
20
+ {:date_time=>"2019-01-02T00:00:00.000Z", :obv_mean=>-614324095.0},
21
+ {:date_time=>"2018-12-31T00:00:00.000Z", :obv_mean=>-605073347.0},
22
+ {:date_time=>"2018-12-28T00:00:00.000Z", :obv_mean=>-587933850.0},
23
+ {:date_time=>"2018-12-27T00:00:00.000Z", :obv_mean=>-563282378.0},
24
+ {:date_time=>"2018-12-26T00:00:00.000Z", :obv_mean=>-537632267.0},
25
+ {:date_time=>"2018-12-24T00:00:00.000Z", :obv_mean=>-520690509.0},
26
+ {:date_time=>"2018-12-21T00:00:00.000Z", :obv_mean=>-493338562.0},
27
+ {:date_time=>"2018-12-20T00:00:00.000Z", :obv_mean=>-475879438.0},
28
+ {:date_time=>"2018-12-19T00:00:00.000Z", :obv_mean=>-463802236.0},
29
+ {:date_time=>"2018-12-18T00:00:00.000Z", :obv_mean=>-453894366.0},
30
+ {:date_time=>"2018-12-17T00:00:00.000Z", :obv_mean=>-444632138.0},
31
+ {:date_time=>"2018-12-14T00:00:00.000Z", :obv_mean=>-436048331.0},
32
+ {:date_time=>"2018-12-13T00:00:00.000Z", :obv_mean=>-427847140.0},
33
+ {:date_time=>"2018-12-12T00:00:00.000Z", :obv_mean=>-419555627.0},
34
+ {:date_time=>"2018-12-11T00:00:00.000Z", :obv_mean=>-412682868.0},
35
+ {:date_time=>"2018-12-10T00:00:00.000Z", :obv_mean=>-398147027.0},
36
+ {:date_time=>"2018-12-07T00:00:00.000Z", :obv_mean=>-392674222.0},
37
+ {:date_time=>"2018-12-06T00:00:00.000Z", :obv_mean=>-378663120.0},
38
+ {:date_time=>"2018-12-04T00:00:00.000Z", :obv_mean=>-365710262.0},
39
+ {:date_time=>"2018-12-03T00:00:00.000Z", :obv_mean=>-350260027.0},
40
+ {:date_time=>"2018-11-30T00:00:00.000Z", :obv_mean=>-334761235.0},
41
+ {:date_time=>"2018-11-29T00:00:00.000Z", :obv_mean=>-318827806.0},
42
+ {:date_time=>"2018-11-28T00:00:00.000Z", :obv_mean=>-311463969.0},
43
+ {:date_time=>"2018-11-27T00:00:00.000Z", :obv_mean=>-302197756.0},
44
+ {:date_time=>"2018-11-26T00:00:00.000Z", :obv_mean=>-283664797.0},
45
+ {:date_time=>"2018-11-23T00:00:00.000Z", :obv_mean=>-264148349.0},
46
+ {:date_time=>"2018-11-21T00:00:00.000Z", :obv_mean=>-236733893.0},
47
+ {:date_time=>"2018-11-20T00:00:00.000Z", :obv_mean=>-209152907.0},
48
+ {:date_time=>"2018-11-19T00:00:00.000Z", :obv_mean=>-188010709.0},
49
+ {:date_time=>"2018-11-16T00:00:00.000Z", :obv_mean=>-176813851.0},
50
+ {:date_time=>"2018-11-15T00:00:00.000Z", :obv_mean=>-163172458.0},
51
+ {:date_time=>"2018-11-14T00:00:00.000Z", :obv_mean=>-136807276.0},
52
+ {:date_time=>"2018-11-13T00:00:00.000Z", :obv_mean=>-111110335.0},
53
+ {:date_time=>"2018-11-12T00:00:00.000Z", :obv_mean=>-95269809.0},
54
+ {:date_time=>"2018-11-09T00:00:00.000Z", :obv_mean=>-87750647.0},
55
+ {:date_time=>"2018-11-08T00:00:00.000Z", :obv_mean=>-80759219.0},
56
+ {:date_time=>"2018-11-07T00:00:00.000Z", :obv_mean=>-72480397.0},
57
+ {:date_time=>"2018-11-06T00:00:00.000Z", :obv_mean=>-69633236.0},
58
+ {:date_time=>"2018-11-05T00:00:00.000Z", :obv_mean=>-59457699.0},
59
+ {:date_time=>"2018-11-02T00:00:00.000Z", :obv_mean=>-49972807.0},
60
+ {:date_time=>"2018-11-01T00:00:00.000Z", :obv_mean=>-49970286.0},
61
+ {:date_time=>"2018-10-31T00:00:00.000Z", :obv_mean=>-62359854.0},
62
+ {:date_time=>"2018-10-30T00:00:00.000Z", :obv_mean=>-66215087.0},
63
+ {:date_time=>"2018-10-29T00:00:00.000Z", :obv_mean=>-63999351.0},
64
+ {:date_time=>"2018-10-26T00:00:00.000Z", :obv_mean=>-61015077.0},
65
+ {:date_time=>"2018-10-25T00:00:00.000Z", :obv_mean=>-59574127.0},
66
+ {:date_time=>"2018-10-24T00:00:00.000Z", :obv_mean=>-66801824.0},
67
+ {:date_time=>"2018-10-23T00:00:00.000Z", :obv_mean=>-65836555.0}
68
+ ]
69
+
70
+ expect(normalized_output).to eq(expected_output)
71
+ end
72
+
73
+ it "Throws exception if not enough data" do
74
+ expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError)
75
+ end
76
+
77
+ it 'Returns the symbol' do
78
+ indicator_symbol = indicator.indicator_symbol
79
+ expect(indicator_symbol).to eq('obv_mean')
80
+ end
81
+
82
+ it 'Returns the name' do
83
+ indicator_name = indicator.indicator_name
84
+ expect(indicator_name).to eq('On-balance Volume Mean')
85
+ end
86
+
87
+ it 'Returns the valid options' do
88
+ valid_options = indicator.valid_options
89
+ expect(valid_options).to eq(%i(period))
90
+ end
91
+
92
+ it 'Validates options' do
93
+ valid_options = { period: 22 }
94
+ options_validated = indicator.validate_options(valid_options)
95
+ expect(options_validated).to eq(true)
96
+ end
97
+
98
+ it 'Throws exception for invalid options' do
99
+ invalid_options = { test: 10 }
100
+ expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError)
101
+ end
102
+
103
+ it 'Calculates minimum data size' do
104
+ options = { period: 4 }
105
+ expect(indicator.min_data_size(options)).to eq(5)
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,119 @@
1
+ require 'technical-analysis'
2
+ require 'spec_helper'
3
+
4
+ describe 'Indicators' do
5
+ describe "OBV" do
6
+ input_data = SpecHelper.get_test_data(:close, :volume)
7
+ indicator = TechnicalAnalysis::Obv
8
+
9
+ describe 'On-balance Volume' do
10
+ it 'Calculates OBV' do
11
+ output = indicator.calculate(input_data)
12
+ normalized_output = output.map(&:to_hash)
13
+
14
+ expected_output = [
15
+ {:date_time=>"2019-01-09T00:00:00.000Z", :obv=>-591085010},
16
+ {:date_time=>"2019-01-08T00:00:00.000Z", :obv=>-636119380},
17
+ {:date_time=>"2019-01-07T00:00:00.000Z", :obv=>-676742290},
18
+ {:date_time=>"2019-01-04T00:00:00.000Z", :obv=>-622170850},
19
+ {:date_time=>"2019-01-03T00:00:00.000Z", :obv=>-679594500},
20
+ {:date_time=>"2019-01-02T00:00:00.000Z", :obv=>-588487660},
21
+ {:date_time=>"2018-12-31T00:00:00.000Z", :obv=>-624124730},
22
+ {:date_time=>"2018-12-28T00:00:00.000Z", :obv=>-658624120},
23
+ {:date_time=>"2018-12-27T00:00:00.000Z", :obv=>-700364720},
24
+ {:date_time=>"2018-12-26T00:00:00.000Z", :obv=>-648755870},
25
+ {:date_time=>"2018-12-24T00:00:00.000Z", :obv=>-706889720},
26
+ {:date_time=>"2018-12-21T00:00:00.000Z", :obv=>-669720490},
27
+ {:date_time=>"2018-12-20T00:00:00.000Z", :obv=>-574222590},
28
+ {:date_time=>"2018-12-19T00:00:00.000Z", :obv=>-509824360},
29
+ {:date_time=>"2018-12-18T00:00:00.000Z", :obv=>-462226690},
30
+ {:date_time=>"2018-12-17T00:00:00.000Z", :obv=>-495980180},
31
+ {:date_time=>"2018-12-14T00:00:00.000Z", :obv=>-452729760},
32
+ {:date_time=>"2018-12-13T00:00:00.000Z", :obv=>-412109400},
33
+ {:date_time=>"2018-12-12T00:00:00.000Z", :obv=>-443863610},
34
+ {:date_time=>"2018-12-11T00:00:00.000Z", :obv=>-479338290},
35
+ {:date_time=>"2018-12-10T00:00:00.000Z", :obv=>-433370250},
36
+ {:date_time=>"2018-12-07T00:00:00.000Z", :obv=>-495129250},
37
+ {:date_time=>"2018-12-06T00:00:00.000Z", :obv=>-453450570},
38
+ {:date_time=>"2018-12-04T00:00:00.000Z", :obv=>-410745660},
39
+ {:date_time=>"2018-12-03T00:00:00.000Z", :obv=>-369604410},
40
+ {:date_time=>"2018-11-30T00:00:00.000Z", :obv=>-410142110},
41
+ {:date_time=>"2018-11-29T00:00:00.000Z", :obv=>-370717850},
42
+ {:date_time=>"2018-11-28T00:00:00.000Z", :obv=>-329194270},
43
+ {:date_time=>"2018-11-27T00:00:00.000Z", :obv=>-375136020},
44
+ {:date_time=>"2018-11-26T00:00:00.000Z", :obv=>-333979880},
45
+ {:date_time=>"2018-11-23T00:00:00.000Z", :obv=>-378642200},
46
+ {:date_time=>"2018-11-21T00:00:00.000Z", :obv=>-355018230},
47
+ {:date_time=>"2018-11-20T00:00:00.000Z", :obv=>-323921990},
48
+ {:date_time=>"2018-11-19T00:00:00.000Z", :obv=>-256243310},
49
+ {:date_time=>"2018-11-16T00:00:00.000Z", :obv=>-214616490},
50
+ {:date_time=>"2018-11-15T00:00:00.000Z", :obv=>-250807820},
51
+ {:date_time=>"2018-11-14T00:00:00.000Z", :obv=>-297079480},
52
+ {:date_time=>"2018-11-13T00:00:00.000Z", :obv=>-236532140},
53
+ {:date_time=>"2018-11-12T00:00:00.000Z", :obv=>-189806430},
54
+ {:date_time=>"2018-11-09T00:00:00.000Z", :obv=>-138815400},
55
+ {:date_time=>"2018-11-08T00:00:00.000Z", :obv=>-104497640},
56
+ {:date_time=>"2018-11-07T00:00:00.000Z", :obv=>-79208370},
57
+ {:date_time=>"2018-11-06T00:00:00.000Z", :obv=>-112500010},
58
+ {:date_time=>"2018-11-05T00:00:00.000Z", :obv=>-144274730},
59
+ {:date_time=>"2018-11-02T00:00:00.000Z", :obv=>-78202560},
60
+ {:date_time=>"2018-11-01T00:00:00.000Z", :obv=>12844000},
61
+ {:date_time=>"2018-10-31T00:00:00.000Z", :obv=>-40110070},
62
+ {:date_time=>"2018-10-30T00:00:00.000Z", :obv=>-78126880},
63
+ {:date_time=>"2018-10-29T00:00:00.000Z", :obv=>-114614810},
64
+ {:date_time=>"2018-10-26T00:00:00.000Z", :obv=>-68901120},
65
+ {:date_time=>"2018-10-25T00:00:00.000Z", :obv=>-21709420},
66
+ {:date_time=>"2018-10-24T00:00:00.000Z", :obv=>-50736760},
67
+ {:date_time=>"2018-10-23T00:00:00.000Z", :obv=>-10744640},
68
+ {:date_time=>"2018-10-22T00:00:00.000Z", :obv=>-49425810},
69
+ {:date_time=>"2018-10-19T00:00:00.000Z", :obv=>-78177350},
70
+ {:date_time=>"2018-10-18T00:00:00.000Z", :obv=>-111051680},
71
+ {:date_time=>"2018-10-17T00:00:00.000Z", :obv=>-78662400},
72
+ {:date_time=>"2018-10-16T00:00:00.000Z", :obv=>-55969520},
73
+ {:date_time=>"2018-10-15T00:00:00.000Z", :obv=>-84772070},
74
+ {:date_time=>"2018-10-12T00:00:00.000Z", :obv=>-54491620},
75
+ {:date_time=>"2018-10-11T00:00:00.000Z", :obv=>-93986390},
76
+ {:date_time=>"2018-10-10T00:00:00.000Z", :obv=>-41084070},
77
+ {:date_time=>"2018-10-09T00:00:00.000Z", :obv=>0}
78
+ ]
79
+
80
+ expect(normalized_output).to eq(expected_output)
81
+ end
82
+
83
+ it "Throws exception if not enough data" do
84
+ expect {indicator.calculate([])}.to raise_exception(TechnicalAnalysis::Validation::ValidationError)
85
+ end
86
+
87
+ it 'Returns the symbol' do
88
+ indicator_symbol = indicator.indicator_symbol
89
+ expect(indicator_symbol).to eq('obv')
90
+ end
91
+
92
+ it 'Returns the name' do
93
+ indicator_name = indicator.indicator_name
94
+ expect(indicator_name).to eq('On-balance Volume')
95
+ end
96
+
97
+ it 'Returns the valid options' do
98
+ valid_options = indicator.valid_options
99
+ expect(valid_options).to eq([])
100
+ end
101
+
102
+ it 'Validates options' do
103
+ valid_options = {}
104
+ options_validated = indicator.validate_options(valid_options)
105
+ expect(options_validated).to eq(true)
106
+ end
107
+
108
+ it 'Throws exception for invalid options' do
109
+ invalid_options = { test: 10 }
110
+ expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError)
111
+ end
112
+
113
+ it 'Calculates minimum data size' do
114
+ options = {}
115
+ expect(indicator.min_data_size(options)).to eq(1)
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,105 @@
1
+ require 'technical-analysis'
2
+ require 'spec_helper'
3
+
4
+ describe 'Indicators' do
5
+ describe "RSI" do
6
+ input_data = SpecHelper.get_test_data(:close)
7
+ indicator = TechnicalAnalysis::Rsi
8
+
9
+ describe 'Relative Strength Index' do
10
+ it 'Calculates RSI (14 day)' do
11
+ output = indicator.calculate(input_data, period: 14, price_key: :close)
12
+ normalized_output = output.map(&:to_hash)
13
+
14
+ expected_output = [
15
+ {:date_time=>"2019-01-09T00:00:00.000Z", :rsi=>41.01572095202713},
16
+ {:date_time=>"2019-01-08T00:00:00.000Z", :rsi=>38.100858593859655},
17
+ {:date_time=>"2019-01-07T00:00:00.000Z", :rsi=>34.80538400125879},
18
+ {:date_time=>"2019-01-04T00:00:00.000Z", :rsi=>35.00790948034705},
19
+ {:date_time=>"2019-01-03T00:00:00.000Z", :rsi=>27.835833051062522},
20
+ {:date_time=>"2019-01-02T00:00:00.000Z", :rsi=>37.90003559360193},
21
+ {:date_time=>"2018-12-31T00:00:00.000Z", :rsi=>37.66054013673465},
22
+ {:date_time=>"2018-12-28T00:00:00.000Z", :rsi=>35.7297472286003},
23
+ {:date_time=>"2018-12-27T00:00:00.000Z", :rsi=>35.63166885267985},
24
+ {:date_time=>"2018-12-26T00:00:00.000Z", :rsi=>36.28727515078207},
25
+ {:date_time=>"2018-12-24T00:00:00.000Z", :rsi=>22.94077952430888},
26
+ {:date_time=>"2018-12-21T00:00:00.000Z", :rsi=>24.757134961511937},
27
+ {:date_time=>"2018-12-20T00:00:00.000Z", :rsi=>27.973957664061984},
28
+ {:date_time=>"2018-12-19T00:00:00.000Z", :rsi=>30.416532991054595},
29
+ {:date_time=>"2018-12-18T00:00:00.000Z", :rsi=>33.926041361905774},
30
+ {:date_time=>"2018-12-17T00:00:00.000Z", :rsi=>30.880956115136144},
31
+ {:date_time=>"2018-12-14T00:00:00.000Z", :rsi=>31.866930881658718},
32
+ {:date_time=>"2018-12-13T00:00:00.000Z", :rsi=>35.61772436774288},
33
+ {:date_time=>"2018-12-12T00:00:00.000Z", :rsi=>33.146531878947414},
34
+ {:date_time=>"2018-12-11T00:00:00.000Z", :rsi=>32.53565170863392},
35
+ {:date_time=>"2018-12-10T00:00:00.000Z", :rsi=>33.115551932880564},
36
+ {:date_time=>"2018-12-07T00:00:00.000Z", :rsi=>31.82436379692355},
37
+ {:date_time=>"2018-12-06T00:00:00.000Z", :rsi=>35.38441991619841},
38
+ {:date_time=>"2018-12-04T00:00:00.000Z", :rsi=>36.58615110748291},
39
+ {:date_time=>"2018-12-03T00:00:00.000Z", :rsi=>42.06016450933706},
40
+ {:date_time=>"2018-11-30T00:00:00.000Z", :rsi=>35.1442970032345},
41
+ {:date_time=>"2018-11-29T00:00:00.000Z", :rsi=>35.760430191057694},
42
+ {:date_time=>"2018-11-28T00:00:00.000Z", :rsi=>36.61457624117541},
43
+ {:date_time=>"2018-11-27T00:00:00.000Z", :rsi=>29.027101402280678},
44
+ {:date_time=>"2018-11-26T00:00:00.000Z", :rsi=>29.211255846774762},
45
+ {:date_time=>"2018-11-23T00:00:00.000Z", :rsi=>26.558433878585916},
46
+ {:date_time=>"2018-11-21T00:00:00.000Z", :rsi=>28.467396310763007},
47
+ {:date_time=>"2018-11-20T00:00:00.000Z", :rsi=>28.552282046348225},
48
+ {:date_time=>"2018-11-19T00:00:00.000Z", :rsi=>32.554453236286506},
49
+ {:date_time=>"2018-11-16T00:00:00.000Z", :rsi=>36.677863857193564},
50
+ {:date_time=>"2018-11-15T00:00:00.000Z", :rsi=>34.550163030510646},
51
+ {:date_time=>"2018-11-14T00:00:00.000Z", :rsi=>29.78632377839773},
52
+ {:date_time=>"2018-11-13T00:00:00.000Z", :rsi=>32.36268849740294},
53
+ {:date_time=>"2018-11-12T00:00:00.000Z", :rsi=>33.31877385045367},
54
+ {:date_time=>"2018-11-09T00:00:00.000Z", :rsi=>38.99885805229995},
55
+ {:date_time=>"2018-11-08T00:00:00.000Z", :rsi=>41.56699725744853},
56
+ {:date_time=>"2018-11-07T00:00:00.000Z", :rsi=>42.51108193242363},
57
+ {:date_time=>"2018-11-06T00:00:00.000Z", :rsi=>36.875893042068746},
58
+ {:date_time=>"2018-11-05T00:00:00.000Z", :rsi=>34.78189708111985},
59
+ {:date_time=>"2018-11-02T00:00:00.000Z", :rsi=>37.93941116682432},
60
+ {:date_time=>"2018-11-01T00:00:00.000Z", :rsi=>48.08268788472883},
61
+ {:date_time=>"2018-10-31T00:00:00.000Z", :rsi=>44.96841382331871},
62
+ {:date_time=>"2018-10-30T00:00:00.000Z", :rsi=>39.38109368376431},
63
+ {:date_time=>"2018-10-29T00:00:00.000Z", :rsi=>38.27160493827161}
64
+ ]
65
+
66
+ expect(normalized_output).to eq(expected_output)
67
+ end
68
+
69
+ it "Throws exception if not enough data" do
70
+ expect {indicator.calculate(input_data, period: input_data.size+2, price_key: :close)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError)
71
+ end
72
+
73
+ it 'Returns the symbol' do
74
+ indicator_symbol = indicator.indicator_symbol
75
+ expect(indicator_symbol).to eq('rsi')
76
+ end
77
+
78
+ it 'Returns the name' do
79
+ indicator_name = indicator.indicator_name
80
+ expect(indicator_name).to eq('Relative Strength Index')
81
+ end
82
+
83
+ it 'Returns the valid options' do
84
+ valid_options = indicator.valid_options
85
+ expect(valid_options).to eq(%i(period price_key))
86
+ end
87
+
88
+ it 'Validates options' do
89
+ valid_options = { period: 22, price_key: :close }
90
+ options_validated = indicator.validate_options(valid_options)
91
+ expect(options_validated).to eq(true)
92
+ end
93
+
94
+ it 'Throws exception for invalid options' do
95
+ invalid_options = { test: 10 }
96
+ expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError)
97
+ end
98
+
99
+ it 'Calculates minimum data size' do
100
+ options = { period: 4 }
101
+ expect(indicator.min_data_size(options)).to eq(5)
102
+ end
103
+ end
104
+ end
105
+ end