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,98 @@
1
+ require 'technical-analysis'
2
+ require 'spec_helper'
3
+
4
+ describe 'Indicators' do
5
+ describe "ADTV" do
6
+ input_data = SpecHelper.get_test_data(:volume)
7
+ indicator = TechnicalAnalysis::Adtv
8
+
9
+ describe 'Average Daily Trading Volume' do
10
+ it 'Calculates ADTV (22 day)' do
11
+ output = indicator.calculate(input_data, period: 22, volume_key: :volume)
12
+ normalized_output = output.map(&:to_hash)
13
+
14
+ expected_output = [
15
+ {:date_time=>"2019-01-09T00:00:00.000Z", :adtv=>49513676.36363637},
16
+ {:date_time=>"2019-01-08T00:00:00.000Z", :adtv=>49407791.81818182},
17
+ {:date_time=>"2019-01-07T00:00:00.000Z", :adtv=>49431352.72727273},
18
+ {:date_time=>"2019-01-04T00:00:00.000Z", :adtv=>48793455.45454545},
19
+ {:date_time=>"2019-01-03T00:00:00.000Z", :adtv=>47975301.36363637},
20
+ {:date_time=>"2019-01-02T00:00:00.000Z", :adtv=>45721516.81818182},
21
+ {:date_time=>"2018-12-31T00:00:00.000Z", :adtv=>46189911.36363637},
22
+ {:date_time=>"2018-12-28T00:00:00.000Z", :adtv=>46492490.90909091},
23
+ {:date_time=>"2018-12-27T00:00:00.000Z", :adtv=>46625296.36363637},
24
+ {:date_time=>"2018-12-26T00:00:00.000Z", :adtv=>45353256.36363637},
25
+ {:date_time=>"2018-12-24T00:00:00.000Z", :adtv=>44124274.09090909},
26
+ {:date_time=>"2018-12-21T00:00:00.000Z", :adtv=>45511067.27272727},
27
+ {:date_time=>"2018-12-20T00:00:00.000Z", :adtv=>43062381.81818182},
28
+ {:date_time=>"2018-12-19T00:00:00.000Z", :adtv=>41780250.0},
29
+ {:date_time=>"2018-12-18T00:00:00.000Z", :adtv=>41719976.81818182},
30
+ {:date_time=>"2018-12-17T00:00:00.000Z", :adtv=>42937879.09090909},
31
+ {:date_time=>"2018-12-14T00:00:00.000Z", :adtv=>43095846.81818182},
32
+ {:date_time=>"2018-12-13T00:00:00.000Z", :adtv=>43567240.90909091},
33
+ {:date_time=>"2018-12-12T00:00:00.000Z", :adtv=>43683765.90909091},
34
+ {:date_time=>"2018-12-11T00:00:00.000Z", :adtv=>43220792.72727273},
35
+ {:date_time=>"2018-12-10T00:00:00.000Z", :adtv=>42644592.72727273},
36
+ {:date_time=>"2018-12-07T00:00:00.000Z", :adtv=>41281670.90909091},
37
+ {:date_time=>"2018-12-06T00:00:00.000Z", :adtv=>42390465.90909091},
38
+ {:date_time=>"2018-12-04T00:00:00.000Z", :adtv=>44587813.63636363},
39
+ {:date_time=>"2018-12-03T00:00:00.000Z", :adtv=>45124760.0},
40
+ {:date_time=>"2018-11-30T00:00:00.000Z", :adtv=>45010174.09090909},
41
+ {:date_time=>"2018-11-29T00:00:00.000Z", :adtv=>44876704.54545455},
42
+ {:date_time=>"2018-11-28T00:00:00.000Z", :adtv=>45067164.09090909},
43
+ {:date_time=>"2018-11-27T00:00:00.000Z", :adtv=>45123980.0},
44
+ {:date_time=>"2018-11-26T00:00:00.000Z", :adtv=>44572670.90909091},
45
+ {:date_time=>"2018-11-23T00:00:00.000Z", :adtv=>44360389.09090909},
46
+ {:date_time=>"2018-11-21T00:00:00.000Z", :adtv=>45044807.27272727},
47
+ {:date_time=>"2018-11-20T00:00:00.000Z", :adtv=>44938230.0},
48
+ {:date_time=>"2018-11-19T00:00:00.000Z", :adtv=>43356214.09090909},
49
+ {:date_time=>"2018-11-16T00:00:00.000Z", :adtv=>42936325.90909091},
50
+ {:date_time=>"2018-11-15T00:00:00.000Z", :adtv=>42322760.0},
51
+ {:date_time=>"2018-11-14T00:00:00.000Z", :adtv=>41528709.54545455},
52
+ {:date_time=>"2018-11-13T00:00:00.000Z", :adtv=>40152941.81818182},
53
+ {:date_time=>"2018-11-12T00:00:00.000Z", :adtv=>39824262.72727273},
54
+ {:date_time=>"2018-11-09T00:00:00.000Z", :adtv=>39911139.54545455},
55
+ {:date_time=>"2018-11-08T00:00:00.000Z", :adtv=>40218699.09090909},
56
+ {:date_time=>"2018-11-07T00:00:00.000Z", :adtv=>40280851.81818182}
57
+ ]
58
+
59
+ expect(normalized_output).to eq(expected_output)
60
+ end
61
+
62
+ it "Throws exception if not enough data" do
63
+ expect {indicator.calculate(input_data, period: input_data.size+1, volume_key: :volume)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError)
64
+ end
65
+
66
+ it 'Returns the symbol' do
67
+ indicator_symbol = indicator.indicator_symbol
68
+ expect(indicator_symbol).to eq('adtv')
69
+ end
70
+
71
+ it 'Returns the name' do
72
+ indicator_name = indicator.indicator_name
73
+ expect(indicator_name).to eq('Average Daily Trading Volume')
74
+ end
75
+
76
+ it 'Returns the valid options' do
77
+ valid_options = indicator.valid_options
78
+ expect(valid_options).to eq(%i(period volume_key))
79
+ end
80
+
81
+ it 'Validates options' do
82
+ valid_options = { period: 22, volume_key: :close }
83
+ options_validated = indicator.validate_options(valid_options)
84
+ expect(options_validated).to eq(true)
85
+ end
86
+
87
+ it 'Throws exception for invalid options' do
88
+ invalid_options = { test: 10 }
89
+ expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError)
90
+ end
91
+
92
+ it 'Calculates minimum data size' do
93
+ options = { period: 4 }
94
+ expect(indicator.min_data_size(options)).to eq(4)
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,92 @@
1
+ require 'technical-analysis'
2
+ require 'spec_helper'
3
+
4
+ describe 'Indicators' do
5
+ describe "ADX" do
6
+ input_data = SpecHelper.get_test_data(:high, :low, :close)
7
+ indicator = TechnicalAnalysis::Adx
8
+
9
+ describe 'Average Directional Index' do
10
+ it 'Calculates ADX (14 day)' do
11
+ output = indicator.calculate(input_data, period: 14)
12
+ normalized_output = output.map(&:to_hash)
13
+
14
+ expected_output = [
15
+ {:date_time=>"2019-01-09T00:00:00.000Z", :adx=>46.70506819299097, :di_neg=>33.86727845364526, :di_pos=>18.75156069669946},
16
+ {:date_time=>"2019-01-08T00:00:00.000Z", :adx=>48.08801057392937, :di_neg=>35.92768510004254, :di_pos=>16.527665969119678},
17
+ {:date_time=>"2019-01-07T00:00:00.000Z", :adx=>48.9421751918944, :di_neg=>37.61461933766297, :di_pos=>13.69466932452777},
18
+ {:date_time=>"2019-01-04T00:00:00.000Z", :adx=>49.12087007192141, :di_neg=>38.89182421063156, :di_pos=>13.835071344467728},
19
+ {:date_time=>"2019-01-03T00:00:00.000Z", :adx=>49.24387794011257, :di_neg=>41.7490776508834, :di_pos=>11.582515799387362},
20
+ {:date_time=>"2019-01-02T00:00:00.000Z", :adx=>48.68078018528377, :di_neg=>34.52657095260412, :di_pos=>13.967710052992748},
21
+ {:date_time=>"2018-12-31T00:00:00.000Z", :adx=>49.16434766454135, :di_neg=>33.6937638052496, :di_pos=>14.788354298902822},
22
+ {:date_time=>"2018-12-28T00:00:00.000Z", :adx=>49.94663571159158, :di_neg=>34.986926565583936, :di_pos=>14.325926339774329},
23
+ {:date_time=>"2018-12-27T00:00:00.000Z", :adx=>50.56577696054131, :di_neg=>36.643305871956294, :di_pos=>12.91725635739372},
24
+ {:date_time=>"2018-12-26T00:00:00.000Z", :adx=>50.77292582473832, :di_neg=>39.7700574645743, :di_pos=>14.019478193733173},
25
+ {:date_time=>"2018-12-24T00:00:00.000Z", :adx=>50.9960092169505, :di_neg=>45.054464306949185, :di_pos=>8.701290502977864},
26
+ {:date_time=>"2018-12-21T00:00:00.000Z", :adx=>49.71673521777664, :di_neg=>44.050625611685426, :di_pos=>9.239278206391834},
27
+ {:date_time=>"2018-12-20T00:00:00.000Z", :adx=>48.516140209610576, :di_neg=>41.59440646182574, :di_pos=>10.25145625667257},
28
+ {:date_time=>"2018-12-19T00:00:00.000Z", :adx=>47.59783553446671, :di_neg=>40.351684937107876, :di_pos=>11.15761353425932},
29
+ {:date_time=>"2018-12-18T00:00:00.000Z", :adx=>46.89941641847421, :di_neg=>37.76941014220763, :di_pos=>12.407839995022263},
30
+ {:date_time=>"2018-12-17T00:00:00.000Z", :adx=>46.61906677289316, :di_neg=>39.53590570860133, :di_pos=>12.988161325358192},
31
+ {:date_time=>"2018-12-14T00:00:00.000Z", :adx=>46.31715176995973, :di_neg=>39.11005826049996, :di_pos=>13.935609588410411},
32
+ {:date_time=>"2018-12-13T00:00:00.000Z", :adx=>46.2293890478109, :di_neg=>36.454819093692386, :di_pos=>14.957814674775397},
33
+ {:date_time=>"2018-12-12T00:00:00.000Z", :adx=>46.56913524205153, :di_neg=>38.04051607484649, :di_pos=>14.793647188928983},
34
+ {:date_time=>"2018-12-11T00:00:00.000Z", :adx=>46.76678475437397, :di_neg=>39.55530357861321, :di_pos=>15.225390789013932},
35
+ {:date_time=>"2018-12-10T00:00:00.000Z", :adx=>46.94782223161259, :di_neg=>41.80590109058211, :di_pos=>14.07235093039379},
36
+ {:date_time=>"2018-12-07T00:00:00.000Z", :adx=>46.74133929346658, :di_neg=>39.25064431094187, :di_pos=>15.206157858128352},
37
+ {:date_time=>"2018-12-06T00:00:00.000Z", :adx=>46.94041765413575, :di_neg=>39.72706616642713, :di_pos=>16.369223356492178},
38
+ {:date_time=>"2018-12-04T00:00:00.000Z", :adx=>47.348231515991635, :di_neg=>35.733971514512405, :di_pos=>17.589281738284058},
39
+ {:date_time=>"2018-12-03T00:00:00.000Z", :adx=>48.37288589247055, :di_neg=>33.43673559814864, :di_pos=>19.42230137516784},
40
+ {:date_time=>"2018-11-30T00:00:00.000Z", :adx=>50.05442754589659, :di_neg=>36.030275362364435, :di_pos=>15.306518521740204},
41
+ {:date_time=>"2018-11-29T00:00:00.000Z", :adx=>50.79951939347192, :di_neg=>36.64084491661032, :di_pos=>15.900754457889013},
42
+ {:date_time=>"2018-11-28T00:00:00.000Z", :adx=>51.67073961575017, :di_neg=>38.80264418160902, :di_pos=>15.0920401856127},
43
+ {:date_time=>"2018-11-27T00:00:00.000Z", :adx=>52.261232848231245, :di_neg=>41.98206441213049, :di_pos=>8.75082128345464},
44
+ {:date_time=>"2018-11-26T00:00:00.000Z", :adx=>51.24268374123445, :di_neg=>43.821787689533835, :di_pos=>9.134296699373357},
45
+ {:date_time=>"2018-11-23T00:00:00.000Z", :adx=>50.14578470293022, :di_neg=>44.05855841207259, :di_pos=>9.605544411876144},
46
+ {:date_time=>"2018-11-21T00:00:00.000Z", :adx=>49.0645966148012, :di_neg=>41.4968168736661, :di_pos=>10.08777861559222},
47
+ {:date_time=>"2018-11-20T00:00:00.000Z", :adx=>48.15507276775653, :di_neg=>43.093658309800155, :di_pos=>10.47596701425822},
48
+ {:date_time=>"2018-11-19T00:00:00.000Z", :adx=>47.17558554786226, :di_neg=>37.739607295468765, :di_pos=>11.632425406517202},
49
+ {:date_time=>"2018-11-16T00:00:00.000Z", :adx=>46.73690113316023, :di_neg=>36.39042671024342, :di_pos=>12.707203247013513},
50
+ {:date_time=>"2018-11-15T00:00:00.000Z", :adx=>46.621508959519026, :di_neg=>38.52265796697687, :di_pos=>10.26180913708443}
51
+ ]
52
+
53
+ expect(normalized_output).to eq(expected_output)
54
+ end
55
+
56
+ it "Throws exception if not enough data" do
57
+ expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError)
58
+ end
59
+
60
+ it 'Returns the symbol' do
61
+ indicator_symbol = indicator.indicator_symbol
62
+ expect(indicator_symbol).to eq('adx')
63
+ end
64
+
65
+ it 'Returns the name' do
66
+ indicator_name = indicator.indicator_name
67
+ expect(indicator_name).to eq('Average Directional Index')
68
+ end
69
+
70
+ it 'Returns the valid options' do
71
+ valid_options = indicator.valid_options
72
+ expect(valid_options).to eq(%i(period))
73
+ end
74
+
75
+ it 'Validates options' do
76
+ valid_options = { period: 22 }
77
+ options_validated = indicator.validate_options(valid_options)
78
+ expect(options_validated).to eq(true)
79
+ end
80
+
81
+ it 'Throws exception for invalid options' do
82
+ invalid_options = { test: 10 }
83
+ expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError)
84
+ end
85
+
86
+ it 'Calculates minimum data size' do
87
+ options = { period: 4 }
88
+ expect(indicator.min_data_size(options)).to eq(8)
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,86 @@
1
+ require 'technical-analysis'
2
+ require 'spec_helper'
3
+
4
+ describe 'Indicators' do
5
+ describe "AO" do
6
+ input_data = SpecHelper.get_test_data(:high, :low)
7
+ indicator = TechnicalAnalysis::Ao
8
+
9
+ describe 'Awesome Oscillator' do
10
+ it 'Calculates AO (5 day short period, 34 day long period)' do
11
+ output = indicator.calculate(input_data, short_period: 5, long_period: 34)
12
+ normalized_output = output.map(&:to_hash)
13
+
14
+ expected_output = [
15
+ {:date_time=>"2019-01-09T00:00:00.000Z", :ao=>-17.518757058823525},
16
+ {:date_time=>"2019-01-08T00:00:00.000Z", :ao=>-17.8071908823529},
17
+ {:date_time=>"2019-01-07T00:00:00.000Z", :ao=>-17.41204382352936},
18
+ {:date_time=>"2019-01-04T00:00:00.000Z", :ao=>-16.838043823529347},
19
+ {:date_time=>"2019-01-03T00:00:00.000Z", :ao=>-16.804919117647017},
20
+ {:date_time=>"2019-01-02T00:00:00.000Z", :ao=>-16.73956617647059},
21
+ {:date_time=>"2018-12-31T00:00:00.000Z", :ao=>-19.633272058823536},
22
+ {:date_time=>"2018-12-28T00:00:00.000Z", :ao=>-21.924007352941203},
23
+ {:date_time=>"2018-12-27T00:00:00.000Z", :ao=>-22.97706617647063},
24
+ {:date_time=>"2018-12-26T00:00:00.000Z", :ao=>-22.471330882352987},
25
+ {:date_time=>"2018-12-24T00:00:00.000Z", :ao=>-21.124477941176536},
26
+ {:date_time=>"2018-12-21T00:00:00.000Z", :ao=>-19.609007352941205},
27
+ {:date_time=>"2018-12-20T00:00:00.000Z", :ao=>-18.88406617647061},
28
+ {:date_time=>"2018-12-19T00:00:00.000Z", :ao=>-18.17277205882357},
29
+ {:date_time=>"2018-12-18T00:00:00.000Z", :ao=>-18.17262500000004},
30
+ {:date_time=>"2018-12-17T00:00:00.000Z", :ao=>-18.865919117647138},
31
+ {:date_time=>"2018-12-14T00:00:00.000Z", :ao=>-20.12868382352943},
32
+ {:date_time=>"2018-12-13T00:00:00.000Z", :ao=>-20.811713235294178},
33
+ {:date_time=>"2018-12-12T00:00:00.000Z", :ao=>-21.92503676470585},
34
+ {:date_time=>"2018-12-11T00:00:00.000Z", :ao=>-21.579664411764696},
35
+ {:date_time=>"2018-12-10T00:00:00.000Z", :ao=>-20.365870294117656},
36
+ {:date_time=>"2018-12-07T00:00:00.000Z", :ao=>-19.51995852941178},
37
+ {:date_time=>"2018-12-06T00:00:00.000Z", :ao=>-19.071752647058815},
38
+ {:date_time=>"2018-12-04T00:00:00.000Z", :ao=>-19.392987941176415},
39
+ {:date_time=>"2018-12-03T00:00:00.000Z", :ao=>-21.886519117646998},
40
+ {:date_time=>"2018-11-30T00:00:00.000Z", :ao=>-25.05331323529407},
41
+ {:date_time=>"2018-11-29T00:00:00.000Z", :ao=>-27.130989705882314},
42
+ {:date_time=>"2018-11-28T00:00:00.000Z", :ao=>-28.547813235294086},
43
+ {:date_time=>"2018-11-27T00:00:00.000Z", :ao=>-29.739166176470576},
44
+ {:date_time=>"2018-11-26T00:00:00.000Z", :ao=>-28.26261029411762}
45
+ ]
46
+
47
+ expect(normalized_output).to eq(expected_output)
48
+ end
49
+
50
+ it "Throws exception if not enough data" do
51
+ expect {indicator.calculate(input_data, long_period: input_data.size+1)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError)
52
+ end
53
+
54
+ it 'Returns the symbol' do
55
+ indicator_symbol = indicator.indicator_symbol
56
+ expect(indicator_symbol).to eq('ao')
57
+ end
58
+
59
+ it 'Returns the name' do
60
+ indicator_name = indicator.indicator_name
61
+ expect(indicator_name).to eq('Awesome Oscillator')
62
+ end
63
+
64
+ it 'Returns the valid options' do
65
+ valid_options = indicator.valid_options
66
+ expect(valid_options).to eq(%i(short_period long_period))
67
+ end
68
+
69
+ it 'Validates options' do
70
+ valid_options = { short_period: 5, long_period: 34 }
71
+ options_validated = indicator.validate_options(valid_options)
72
+ expect(options_validated).to eq(true)
73
+ end
74
+
75
+ it 'Throws exception for invalid options' do
76
+ invalid_options = { test: 10 }
77
+ expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError)
78
+ end
79
+
80
+ it 'Calculates minimum data size' do
81
+ options = { long_period: 20 }
82
+ expect(indicator.min_data_size(options)).to eq(20)
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,105 @@
1
+ require 'technical-analysis'
2
+ require 'spec_helper'
3
+
4
+ describe 'Indicators' do
5
+ describe "ATR" do
6
+ input_data = SpecHelper.get_test_data(:high, :low, :close)
7
+ indicator = TechnicalAnalysis::Atr
8
+
9
+ describe 'Average True Range' do
10
+ it 'Calculates ATR (14 day)' do
11
+ output = indicator.calculate(input_data, period: 14)
12
+ normalized_output = output.map(&:to_hash)
13
+
14
+ expected_output = [
15
+ {:date_time=>"2019-01-09T00:00:00.000Z", :atr=>6.103013600253306},
16
+ {:date_time=>"2019-01-08T00:00:00.000Z", :atr=>6.195553107965099},
17
+ {:date_time=>"2019-01-07T00:00:00.000Z", :atr=>6.3729033470393395},
18
+ {:date_time=>"2019-01-04T00:00:00.000Z", :atr=>6.637742066042365},
19
+ {:date_time=>"2019-01-03T00:00:00.000Z", :atr=>6.6591145326610075},
20
+ {:date_time=>"2019-01-02T00:00:00.000Z", :atr=>5.946738727481086},
21
+ {:date_time=>"2018-12-31T00:00:00.000Z", :atr=>6.048795552671939},
22
+ {:date_time=>"2018-12-28T00:00:00.000Z", :atr=>6.273318287492855},
23
+ {:date_time=>"2018-12-27T00:00:00.000Z", :atr=>6.450496617299998},
24
+ {:date_time=>"2018-12-26T00:00:00.000Z", :atr=>6.400534818630767},
25
+ {:date_time=>"2018-12-24T00:00:00.000Z", :atr=>6.084422112371596},
26
+ {:date_time=>"2018-12-21T00:00:00.000Z", :atr=>6.170916121015564},
27
+ {:date_time=>"2018-12-20T00:00:00.000Z", :atr=>5.989448130324453},
28
+ {:date_time=>"2018-12-19T00:00:00.000Z", :atr=>5.926328755734025},
29
+ {:date_time=>"2018-12-18T00:00:00.000Z", :atr=>5.739123275405874},
30
+ {:date_time=>"2018-12-17T00:00:00.000Z", :atr=>5.904440450437095},
31
+ {:date_time=>"2018-12-14T00:00:00.000Z", :atr=>5.926320485086102},
32
+ {:date_time=>"2018-12-13T00:00:00.000Z", :atr=>5.946037445477343},
33
+ {:date_time=>"2018-12-12T00:00:00.000Z", :atr=>6.1365018643602145},
34
+ {:date_time=>"2018-12-11T00:00:00.000Z", :atr=>6.355463546234078},
35
+ {:date_time=>"2018-12-10T00:00:00.000Z", :atr=>6.475883819021315},
36
+ {:date_time=>"2018-12-07T00:00:00.000Z", :atr=>6.4540287281768025},
37
+ {:date_time=>"2018-12-06T00:00:00.000Z", :atr=>6.456646322651943},
38
+ {:date_time=>"2018-12-04T00:00:00.000Z", :atr=>6.471003732086706},
39
+ {:date_time=>"2018-12-03T00:00:00.000Z", :atr=>6.311080942247224},
40
+ {:date_time=>"2018-11-30T00:00:00.000Z", :atr=>6.307317937804704},
41
+ {:date_time=>"2018-11-29T00:00:00.000Z", :atr=>6.538650086866604},
42
+ {:date_time=>"2018-11-28T00:00:00.000Z", :atr=>6.649315478164034},
43
+ {:date_time=>"2018-11-27T00:00:00.000Z", :atr=>6.618493591868961},
44
+ {:date_time=>"2018-11-26T00:00:00.000Z", :atr=>6.828377714320418},
45
+ {:date_time=>"2018-11-23T00:00:00.000Z", :atr=>6.9928683077296805},
46
+ {:date_time=>"2018-11-21T00:00:00.000Z", :atr=>7.1707812544781175},
47
+ {:date_time=>"2018-11-20T00:00:00.000Z", :atr=>7.43622596636105},
48
+ {:date_time=>"2018-11-19T00:00:00.000Z", :atr=>7.212089502234975},
49
+ {:date_time=>"2018-11-16T00:00:00.000Z", :atr=>7.109942540868436},
50
+ {:date_time=>"2018-11-15T00:00:00.000Z", :atr=>7.233053505550622},
51
+ {:date_time=>"2018-11-14T00:00:00.000Z", :atr=>7.391749929054517},
52
+ {:date_time=>"2018-11-13T00:00:00.000Z", :atr=>7.302653769751019},
53
+ {:date_time=>"2018-11-12T00:00:00.000Z", :atr=>7.423634828962634},
54
+ {:date_time=>"2018-11-09T00:00:00.000Z", :atr=>7.173145200421298},
55
+ {:date_time=>"2018-11-08T00:00:00.000Z", :atr=>7.244925600453705},
56
+ {:date_time=>"2018-11-07T00:00:00.000Z", :atr=>7.542996800488605},
57
+ {:date_time=>"2018-11-06T00:00:00.000Z", :atr=>7.63938116975696},
58
+ {:date_time=>"2018-11-05T00:00:00.000Z", :atr=>7.98625664435365},
59
+ {:date_time=>"2018-11-02T00:00:00.000Z", :atr=>7.884430232380852},
60
+ {:date_time=>"2018-11-01T00:00:00.000Z", :atr=>7.199386404102457},
61
+ {:date_time=>"2018-10-31T00:00:00.000Z", :atr=>7.326262281341107},
62
+ {:date_time=>"2018-10-30T00:00:00.000Z", :atr=>7.339820918367347},
63
+ {:date_time=>"2018-10-29T00:00:00.000Z", :atr=>7.449807142857144}
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+1)}.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('atr')
76
+ end
77
+
78
+ it 'Returns the name' do
79
+ indicator_name = indicator.indicator_name
80
+ expect(indicator_name).to eq('Average True Range')
81
+ end
82
+
83
+ it 'Returns the valid options' do
84
+ valid_options = indicator.valid_options
85
+ expect(valid_options).to eq(%i(period))
86
+ end
87
+
88
+ it 'Validates options' do
89
+ valid_options = { period: 22 }
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
@@ -0,0 +1,100 @@
1
+ require 'technical-analysis'
2
+ require 'spec_helper'
3
+
4
+ describe 'Indicators' do
5
+ describe "BB" do
6
+ input_data = SpecHelper.get_test_data(:close)
7
+ indicator = TechnicalAnalysis::Bb
8
+
9
+ describe 'Bollinger Bands' do
10
+ it 'Calculates BB (20, 2)' do
11
+ output = indicator.calculate(input_data, period: 20, standard_deviations: 2, price_key: :close)
12
+ normalized_output = output.map(&:to_hash)
13
+
14
+ expected_output = [
15
+ {:date_time=>"2019-01-09T00:00:00.000Z", :lower_band=>141.02036711220762, :middle_band=>157.35499999999996, :upper_band=>173.6896328877923},
16
+ {:date_time=>"2019-01-08T00:00:00.000Z", :lower_band=>141.07714470666247, :middle_band=>158.1695, :upper_band=>175.26185529333753},
17
+ {:date_time=>"2019-01-07T00:00:00.000Z", :lower_band=>141.74551015326722, :middle_band=>159.05649999999997, :upper_band=>176.36748984673272},
18
+ {:date_time=>"2019-01-04T00:00:00.000Z", :lower_band=>142.5717393007821, :middle_band=>160.39600000000002, :upper_band=>178.22026069921793},
19
+ {:date_time=>"2019-01-03T00:00:00.000Z", :lower_band=>143.53956406332316, :middle_band=>161.8175, :upper_band=>180.09543593667684},
20
+ {:date_time=>"2019-01-02T00:00:00.000Z", :lower_band=>145.3682834538487, :middle_band=>163.949, :upper_band=>182.52971654615132},
21
+ {:date_time=>"2018-12-31T00:00:00.000Z", :lower_band=>145.53555575730587, :middle_band=>164.98199999999997, :upper_band=>184.42844424269407},
22
+ {:date_time=>"2018-12-28T00:00:00.000Z", :lower_band=>145.90334076589886, :middle_band=>166.0725, :upper_band=>186.24165923410112},
23
+ {:date_time=>"2018-12-27T00:00:00.000Z", :lower_band=>146.65592111904317, :middle_band=>167.308, :upper_band=>187.96007888095681},
24
+ {:date_time=>"2018-12-26T00:00:00.000Z", :lower_band=>148.0390209273478, :middle_band=>168.2125, :upper_band=>188.38597907265222},
25
+ {:date_time=>"2018-12-24T00:00:00.000Z", :lower_band=>149.41938426834125, :middle_band=>169.08499999999998, :upper_band=>188.7506157316587},
26
+ {:date_time=>"2018-12-21T00:00:00.000Z", :lower_band=>153.6905118237551, :middle_band=>170.35799999999998, :upper_band=>187.02548817624486},
27
+ {:date_time=>"2018-12-20T00:00:00.000Z", :lower_band=>157.58081627897096, :middle_band=>171.6605, :upper_band=>185.74018372102907},
28
+ {:date_time=>"2018-12-19T00:00:00.000Z", :lower_band=>160.2737711222648, :middle_band=>172.66799999999998, :upper_band=>185.06222887773515},
29
+ {:date_time=>"2018-12-18T00:00:00.000Z", :lower_band=>161.48722339827833, :middle_band=>173.91649999999998, :upper_band=>186.34577660172164},
30
+ {:date_time=>"2018-12-17T00:00:00.000Z", :lower_band=>160.6411151779543, :middle_band=>175.28949999999995, :upper_band=>189.9378848220456},
31
+ {:date_time=>"2018-12-14T00:00:00.000Z", :lower_band=>161.3586392867227, :middle_band=>176.66299999999998, :upper_band=>191.96736071327726},
32
+ {:date_time=>"2018-12-13T00:00:00.000Z", :lower_band=>162.73753871102127, :middle_band=>177.72899999999998, :upper_band=>192.7204612889787},
33
+ {:date_time=>"2018-12-12T00:00:00.000Z", :lower_band=>162.83769519003326, :middle_band=>178.79299999999998, :upper_band=>194.7483048099667},
34
+ {:date_time=>"2018-12-11T00:00:00.000Z", :lower_band=>163.37450359253498, :middle_band=>180.04649999999998, :upper_band=>196.71849640746498},
35
+ {:date_time=>"2018-12-10T00:00:00.000Z", :lower_band=>162.797082234342, :middle_band=>181.8385, :upper_band=>200.879917765658},
36
+ {:date_time=>"2018-12-07T00:00:00.000Z", :lower_band=>162.2270311355715, :middle_band=>183.783, :upper_band=>205.33896886442847},
37
+ {:date_time=>"2018-12-06T00:00:00.000Z", :lower_band=>162.58630667652835, :middle_band=>185.856, :upper_band=>209.12569332347164},
38
+ {:date_time=>"2018-12-04T00:00:00.000Z", :lower_band=>163.34919566513827, :middle_band=>187.30850000000004, :upper_band=>211.2678043348618},
39
+ {:date_time=>"2018-12-03T00:00:00.000Z", :lower_band=>164.3311203741903, :middle_band=>188.55350000000004, :upper_band=>212.77587962580978},
40
+ {:date_time=>"2018-11-30T00:00:00.000Z", :lower_band=>164.11704019466114, :middle_band=>189.68650000000005, :upper_band=>215.25595980533896},
41
+ {:date_time=>"2018-11-29T00:00:00.000Z", :lower_band=>163.04822623308377, :middle_band=>191.8685, :upper_band=>220.68877376691626},
42
+ {:date_time=>"2018-11-28T00:00:00.000Z", :lower_band=>163.2435966888823, :middle_band=>193.83400000000003, :upper_band=>224.42440331111777},
43
+ {:date_time=>"2018-11-27T00:00:00.000Z", :lower_band=>164.31484291109825, :middle_band=>195.45200000000006, :upper_band=>226.58915708890186},
44
+ {:date_time=>"2018-11-26T00:00:00.000Z", :lower_band=>167.03813268520582, :middle_band=>197.35200000000003, :upper_band=>227.66586731479424},
45
+ {:date_time=>"2018-11-23T00:00:00.000Z", :lower_band=>169.9836589081704, :middle_band=>199.436, :upper_band=>228.8883410918296},
46
+ {:date_time=>"2018-11-21T00:00:00.000Z", :lower_band=>173.9574856242928, :middle_band=>201.81150000000002, :upper_band=>229.66551437570726},
47
+ {:date_time=>"2018-11-20T00:00:00.000Z", :lower_band=>177.92765761752017, :middle_band=>203.72700000000003, :upper_band=>229.5263423824799},
48
+ {:date_time=>"2018-11-19T00:00:00.000Z", :lower_band=>182.16105406114465, :middle_band=>206.0145, :upper_band=>229.86794593885534},
49
+ {:date_time=>"2018-11-16T00:00:00.000Z", :lower_band=>185.04223870650642, :middle_band=>207.75399999999996, :upper_band=>230.4657612934935},
50
+ {:date_time=>"2018-11-15T00:00:00.000Z", :lower_band=>186.80906188255153, :middle_band=>209.04299999999998, :upper_band=>231.27693811744842},
51
+ {:date_time=>"2018-11-14T00:00:00.000Z", :lower_band=>189.47053333403466, :middle_band=>210.27349999999996, :upper_band=>231.07646666596526},
52
+ {:date_time=>"2018-11-13T00:00:00.000Z", :lower_band=>193.84357681067348, :middle_band=>211.993, :upper_band=>230.1424231893265},
53
+ {:date_time=>"2018-11-12T00:00:00.000Z", :lower_band=>197.38090736241395, :middle_band=>213.48899999999998, :upper_band=>229.597092637586},
54
+ {:date_time=>"2018-11-09T00:00:00.000Z", :lower_band=>201.29218743765117, :middle_band=>214.6485, :upper_band=>228.00481256234886},
55
+ {:date_time=>"2018-11-08T00:00:00.000Z", :lower_band=>202.68427348053234, :middle_band=>215.5305, :upper_band=>228.37672651946764},
56
+ {:date_time=>"2018-11-07T00:00:00.000Z", :lower_band=>203.4002295525166, :middle_band=>215.82850000000002, :upper_band=>228.25677044748343},
57
+ {:date_time=>"2018-11-06T00:00:00.000Z", :lower_band=>204.03232701561498, :middle_band=>216.14900000000003, :upper_band=>228.26567298438508},
58
+ {:date_time=>"2018-11-05T00:00:00.000Z", :lower_band=>205.76564218562143, :middle_band=>217.30400000000003, :upper_band=>228.84235781437863}
59
+ ]
60
+
61
+ expect(normalized_output).to eq(expected_output)
62
+ end
63
+
64
+ it "Throws exception if not enough data" do
65
+ expect {indicator.calculate(input_data, period: input_data.size+1, price_key: :close)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError)
66
+ end
67
+
68
+ it 'Returns the symbol' do
69
+ indicator_symbol = indicator.indicator_symbol
70
+ expect(indicator_symbol).to eq('bb')
71
+ end
72
+
73
+ it 'Returns the name' do
74
+ indicator_name = indicator.indicator_name
75
+ expect(indicator_name).to eq('Bollinger Bands')
76
+ end
77
+
78
+ it 'Returns the valid options' do
79
+ valid_options = indicator.valid_options
80
+ expect(valid_options).to eq(%i(period standard_deviations price_key))
81
+ end
82
+
83
+ it 'Validates options' do
84
+ valid_options = { period: 22 }
85
+ options_validated = indicator.validate_options(valid_options)
86
+ expect(options_validated).to eq(true)
87
+ end
88
+
89
+ it 'Throws exception for invalid options' do
90
+ invalid_options = { test: 10 }
91
+ expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError)
92
+ end
93
+
94
+ it 'Calculates minimum data size' do
95
+ options = { period: 4 }
96
+ expect(indicator.min_data_size(options)).to eq(4)
97
+ end
98
+ end
99
+ end
100
+ end