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,120 @@
1
+ require 'technical-analysis'
2
+ require 'spec_helper'
3
+
4
+ describe 'Indicators' do
5
+ describe "Indicator" do
6
+ indicator = TechnicalAnalysis::Indicator
7
+
8
+ it 'Returns nil on a nonexistant indicator' do
9
+ nonexistant_indicator = indicator.find('test')
10
+ expect(nonexistant_indicator).to eq(nil)
11
+ end
12
+
13
+ it 'Finds an indicator' do
14
+ sma = indicator.find('sma')
15
+ expect(sma).to eq(TechnicalAnalysis::Sma)
16
+ end
17
+
18
+ describe 'Calculations' do
19
+ it 'Returns nil on a nonexistant calculation' do
20
+ calculation = indicator.calculate('sma', [], :test, { period: 20, price_key: :close })
21
+ expect(calculation).to eq(nil)
22
+ end
23
+
24
+ it 'Calculates indicator_name' do
25
+ indicator_name = indicator.calculate('sma', [], :indicator_name, { period: 20, price_key: :close })
26
+ expect(indicator_name).to eq('Simple Moving Average')
27
+ end
28
+
29
+ it 'Calculates indicator_symbol' do
30
+ indicator_name = indicator.calculate('sma', [], :indicator_symbol, { period: 20, price_key: :close })
31
+ expect(indicator_name).to eq('sma')
32
+ end
33
+
34
+ it 'Calculates min_data_size' do
35
+ min_data_size = indicator.calculate('sma', [], :min_data_size, { period: 20, price_key: :close })
36
+ expect(min_data_size).to eq(20)
37
+ end
38
+
39
+ it 'Calculates valid_options' do
40
+ valid_options = indicator.calculate('sma', [], :valid_options, { period: 20, price_key: :close })
41
+ expect(valid_options).to eq(%i(period price_key))
42
+ end
43
+
44
+ it 'Calculates validate_options' do
45
+ options_validated = indicator.calculate('sma', [], :validate_options, { period: 20, price_key: :close })
46
+ expect(options_validated).to eq(true)
47
+ end
48
+
49
+ it 'Calculates technicals' do
50
+ input_data = SpecHelper.get_test_data(:close)
51
+ output = indicator.calculate('sma', input_data, :technicals, { period: 5, price_key: :close })
52
+ normalized_output = output.map(&:to_hash)
53
+
54
+ expected_output = [
55
+ {:date_time=>"2019-01-09T00:00:00.000Z", :sma=>148.488},
56
+ {:date_time=>"2019-01-08T00:00:00.000Z", :sma=>149.41},
57
+ {:date_time=>"2019-01-07T00:00:00.000Z", :sma=>150.808},
58
+ {:date_time=>"2019-01-04T00:00:00.000Z", :sma=>152.468},
59
+ {:date_time=>"2019-01-03T00:00:00.000Z", :sma=>154.046},
60
+ {:date_time=>"2019-01-02T00:00:00.000Z", :sma=>157.04199999999997},
61
+ {:date_time=>"2018-12-31T00:00:00.000Z", :sma=>154.824},
62
+ {:date_time=>"2018-12-28T00:00:00.000Z", :sma=>153.422},
63
+ {:date_time=>"2018-12-27T00:00:00.000Z", :sma=>153.54199999999997},
64
+ {:date_time=>"2018-12-26T00:00:00.000Z", :sma=>154.49},
65
+ {:date_time=>"2018-12-24T00:00:00.000Z", :sma=>156.27},
66
+ {:date_time=>"2018-12-21T00:00:00.000Z", :sma=>159.692},
67
+ {:date_time=>"2018-12-20T00:00:00.000Z", :sma=>162.642},
68
+ {:date_time=>"2018-12-19T00:00:00.000Z", :sma=>165.46599999999998},
69
+ {:date_time=>"2018-12-18T00:00:00.000Z", :sma=>167.108},
70
+ {:date_time=>"2018-12-17T00:00:00.000Z", :sma=>167.61999999999998},
71
+ {:date_time=>"2018-12-14T00:00:00.000Z", :sma=>168.752},
72
+ {:date_time=>"2018-12-13T00:00:00.000Z", :sma=>169.35399999999998},
73
+ {:date_time=>"2018-12-12T00:00:00.000Z", :sma=>170.108},
74
+ {:date_time=>"2018-12-11T00:00:00.000Z", :sma=>171.626},
75
+ {:date_time=>"2018-12-10T00:00:00.000Z", :sma=>174.864},
76
+ {:date_time=>"2018-12-07T00:00:00.000Z", :sma=>176.66},
77
+ {:date_time=>"2018-12-06T00:00:00.000Z", :sma=>178.872},
78
+ {:date_time=>"2018-12-04T00:00:00.000Z", :sma=>180.11600000000004},
79
+ {:date_time=>"2018-12-03T00:00:00.000Z", :sma=>179.62600000000003},
80
+ {:date_time=>"2018-11-30T00:00:00.000Z", :sma=>177.58599999999998},
81
+ {:date_time=>"2018-11-29T00:00:00.000Z", :sma=>176.32799999999997},
82
+ {:date_time=>"2018-11-28T00:00:00.000Z", :sma=>175.77400000000003},
83
+ {:date_time=>"2018-11-27T00:00:00.000Z", :sma=>174.982},
84
+ {:date_time=>"2018-11-26T00:00:00.000Z", :sma=>177.30599999999998},
85
+ {:date_time=>"2018-11-23T00:00:00.000Z", :sma=>181.088},
86
+ {:date_time=>"2018-11-21T00:00:00.000Z", :sma=>184.91199999999998},
87
+ {:date_time=>"2018-11-20T00:00:00.000Z", :sma=>186.916},
88
+ {:date_time=>"2018-11-19T00:00:00.000Z", :sma=>189.96599999999998},
89
+ {:date_time=>"2018-11-16T00:00:00.000Z", :sma=>191.628},
90
+ {:date_time=>"2018-11-15T00:00:00.000Z", :sma=>193.816},
91
+ {:date_time=>"2018-11-14T00:00:00.000Z", :sma=>197.23200000000003},
92
+ {:date_time=>"2018-11-13T00:00:00.000Z", :sma=>201.862},
93
+ {:date_time=>"2018-11-12T00:00:00.000Z", :sma=>204.17000000000002},
94
+ {:date_time=>"2018-11-09T00:00:00.000Z", :sma=>205.654},
95
+ {:date_time=>"2018-11-08T00:00:00.000Z", :sma=>206.256},
96
+ {:date_time=>"2018-11-07T00:00:00.000Z", :sma=>209.002},
97
+ {:date_time=>"2018-11-06T00:00:00.000Z", :sma=>210.78400000000002},
98
+ {:date_time=>"2018-11-05T00:00:00.000Z", :sma=>212.69},
99
+ {:date_time=>"2018-11-02T00:00:00.000Z", :sma=>214.82000000000002},
100
+ {:date_time=>"2018-11-01T00:00:00.000Z", :sma=>216.584},
101
+ {:date_time=>"2018-10-31T00:00:00.000Z", :sma=>216.1},
102
+ {:date_time=>"2018-10-30T00:00:00.000Z", :sma=>215.346},
103
+ {:date_time=>"2018-10-29T00:00:00.000Z", :sma=>217.23200000000003},
104
+ {:date_time=>"2018-10-26T00:00:00.000Z", :sma=>218.914},
105
+ {:date_time=>"2018-10-25T00:00:00.000Z", :sma=>219.51600000000002},
106
+ {:date_time=>"2018-10-24T00:00:00.000Z", :sma=>218.76},
107
+ {:date_time=>"2018-10-23T00:00:00.000Z", :sma=>219.97999999999996},
108
+ {:date_time=>"2018-10-22T00:00:00.000Z", :sma=>219.86400000000003},
109
+ {:date_time=>"2018-10-19T00:00:00.000Z", :sma=>219.206},
110
+ {:date_time=>"2018-10-18T00:00:00.000Z", :sma=>219.766},
111
+ {:date_time=>"2018-10-17T00:00:00.000Z", :sma=>219.452},
112
+ {:date_time=>"2018-10-16T00:00:00.000Z", :sma=>218.48600000000002},
113
+ {:date_time=>"2018-10-15T00:00:00.000Z", :sma=>219.43}
114
+ ]
115
+
116
+ expect(normalized_output).to eq(expected_output)
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,110 @@
1
+ require 'technical-analysis'
2
+ require 'spec_helper'
3
+
4
+ describe 'Indicators' do
5
+ describe "KC" do
6
+ input_data = SpecHelper.get_test_data(:high, :low, :close)
7
+ indicator = TechnicalAnalysis::Kc
8
+
9
+ describe 'Keltner Channel' do
10
+ it 'Calculates KC (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", :lower_band=>147.1630066666667, :middle_band=>151.9909966666667, :upper_band=>156.8189866666667},
16
+ {:date_time=>"2019-01-08T00:00:00.000Z", :lower_band=>146.74034, :middle_band=>151.57433, :upper_band=>156.40832},
17
+ {:date_time=>"2019-01-07T00:00:00.000Z", :lower_band=>146.46500666666665, :middle_band=>151.82199666666665, :upper_band=>157.17898666666665},
18
+ {:date_time=>"2019-01-04T00:00:00.000Z", :lower_band=>147.12967333333333, :middle_band=>152.87466333333333, :upper_band=>158.61965333333333},
19
+ {:date_time=>"2019-01-03T00:00:00.000Z", :lower_band=>148.32933333333335, :middle_band=>154.43533333333335, :upper_band=>160.54133333333334},
20
+ {:date_time=>"2019-01-02T00:00:00.000Z", :lower_band=>150.65666666666667, :middle_band=>156.70466666666667, :upper_band=>162.75266666666667},
21
+ {:date_time=>"2018-12-31T00:00:00.000Z", :lower_band=>151.35733333333334, :middle_band=>157.50533333333334, :upper_band=>163.65333333333334},
22
+ {:date_time=>"2018-12-28T00:00:00.000Z", :lower_band=>152.14066666666668, :middle_band=>158.38066666666668, :upper_band=>164.6206666666667},
23
+ {:date_time=>"2018-12-27T00:00:00.000Z", :lower_band=>153.69466666666665, :middle_band=>159.83966666666666, :upper_band=>165.98466666666667},
24
+ {:date_time=>"2018-12-26T00:00:00.000Z", :lower_band=>155.643, :middle_band=>161.408, :upper_band=>167.17299999999997},
25
+ {:date_time=>"2018-12-24T00:00:00.000Z", :lower_band=>157.75833333333333, :middle_band=>162.9513333333333, :upper_band=>168.1443333333333},
26
+ {:date_time=>"2018-12-21T00:00:00.000Z", :lower_band=>159.51333333333332, :middle_band=>164.8863333333333, :upper_band=>170.2593333333333},
27
+ {:date_time=>"2018-12-20T00:00:00.000Z", :lower_band=>161.50599999999997, :middle_band=>166.64499999999998, :upper_band=>171.784},
28
+ {:date_time=>"2018-12-19T00:00:00.000Z", :lower_band=>163.27366666666666, :middle_band=>168.16766666666666, :upper_band=>173.06166666666667},
29
+ {:date_time=>"2018-12-18T00:00:00.000Z", :lower_band=>165.09500666666668, :middle_band=>169.76499666666666, :upper_band=>174.43498666666665},
30
+ {:date_time=>"2018-12-17T00:00:00.000Z", :lower_band=>166.80200666666667, :middle_band=>171.53099666666668, :upper_band=>176.2599866666667},
31
+ {:date_time=>"2018-12-14T00:00:00.000Z", :lower_band=>168.39800666666667, :middle_band=>172.89499666666666, :upper_band=>177.39198666666664},
32
+ {:date_time=>"2018-12-13T00:00:00.000Z", :lower_band=>169.60834, :middle_band=>174.23533, :upper_band=>178.86232},
33
+ {:date_time=>"2018-12-12T00:00:00.000Z", :lower_band=>170.07734, :middle_band=>175.03833, :upper_band=>179.99932},
34
+ {:date_time=>"2018-12-11T00:00:00.000Z", :lower_band=>170.30667333333332, :middle_band=>175.36666333333332, :upper_band=>180.42665333333332},
35
+ {:date_time=>"2018-12-10T00:00:00.000Z", :lower_band=>170.73033999999998, :middle_band=>175.78033, :upper_band=>180.83032},
36
+ {:date_time=>"2018-12-07T00:00:00.000Z", :lower_band=>171.55567333333335, :middle_band=>176.37916333333334, :upper_band=>181.20265333333333},
37
+ {:date_time=>"2018-12-06T00:00:00.000Z", :lower_band=>172.54667333333333, :middle_band=>177.12316333333334, :upper_band=>181.69965333333334},
38
+ {:date_time=>"2018-12-04T00:00:00.000Z", :lower_band=>172.85467333333332, :middle_band=>177.59116333333333, :upper_band=>182.32765333333333},
39
+ {:date_time=>"2018-12-03T00:00:00.000Z", :lower_band=>173.76899999999998, :middle_band=>178.4645, :upper_band=>183.16},
40
+ {:date_time=>"2018-11-30T00:00:00.000Z", :lower_band=>174.4907, :middle_band=>179.36415, :upper_band=>184.2376},
41
+ {:date_time=>"2018-11-29T00:00:00.000Z", :lower_band=>175.45836666666665, :middle_band=>180.50881666666666, :upper_band=>185.55926666666667},
42
+ {:date_time=>"2018-11-28T00:00:00.000Z", :lower_band=>176.01870000000002, :middle_band=>181.41415, :upper_band=>186.8096},
43
+ {:date_time=>"2018-11-27T00:00:00.000Z", :lower_band=>177.53838, :middle_band=>182.87081999999998, :upper_band=>188.20325999999997},
44
+ {:date_time=>"2018-11-26T00:00:00.000Z", :lower_band=>179.58538000000001, :middle_band=>185.13482000000002, :upper_band=>190.68426000000002},
45
+ {:date_time=>"2018-11-23T00:00:00.000Z", :lower_band=>182.7750466666667, :middle_band=>188.23148666666668, :upper_band=>193.68792666666667},
46
+ {:date_time=>"2018-11-21T00:00:00.000Z", :lower_band=>186.36671333333337, :middle_band=>191.71065333333337, :upper_band=>197.05459333333337},
47
+ {:date_time=>"2018-11-20T00:00:00.000Z", :lower_band=>189.16371333333333, :middle_band=>194.72865333333334, :upper_band=>200.29359333333335},
48
+ {:date_time=>"2018-11-19T00:00:00.000Z", :lower_band=>191.99738, :middle_band=>197.26932, :upper_band=>202.54126},
49
+ {:date_time=>"2018-11-16T00:00:00.000Z", :lower_band=>193.36638000000002, :middle_band=>198.68932, :upper_band=>204.01226},
50
+ {:date_time=>"2018-11-15T00:00:00.000Z", :lower_band=>194.71534666666665, :middle_band=>200.30933666666664, :upper_band=>205.90332666666663},
51
+ {:date_time=>"2018-11-14T00:00:00.000Z", :lower_band=>197.70434666666668, :middle_band=>203.34633666666667, :upper_band=>208.98832666666667},
52
+ {:date_time=>"2018-11-13T00:00:00.000Z", :lower_band=>201.13368, :middle_band=>206.30367, :upper_band=>211.47366000000002},
53
+ {:date_time=>"2018-11-12T00:00:00.000Z", :lower_band=>203.012, :middle_band=>208.2, :upper_band=>213.38799999999998},
54
+ {:date_time=>"2018-11-09T00:00:00.000Z", :lower_band=>203.93166666666667, :middle_band=>209.87366666666668, :upper_band=>215.8156666666667},
55
+ {:date_time=>"2018-11-08T00:00:00.000Z", :lower_band=>204.77, :middle_band=>211.08800000000002, :upper_band=>217.40600000000003},
56
+ {:date_time=>"2018-11-07T00:00:00.000Z", :lower_band=>205.72966666666667, :middle_band=>212.17366666666666, :upper_band=>218.61766666666665},
57
+ {:date_time=>"2018-11-06T00:00:00.000Z", :lower_band=>206.34433333333334, :middle_band=>213.16433333333333, :upper_band=>219.98433333333332},
58
+ {:date_time=>"2018-11-05T00:00:00.000Z", :lower_band=>207.47566666666665, :middle_band=>214.84766666666664, :upper_band=>222.21966666666663},
59
+ {:date_time=>"2018-11-02T00:00:00.000Z", :lower_band=>209.61566666666667, :middle_band=>216.80766666666668, :upper_band=>223.99966666666668},
60
+ {:date_time=>"2018-11-01T00:00:00.000Z", :lower_band=>211.10266666666666, :middle_band=>217.85566666666668, :upper_band=>224.6086666666667},
61
+ {:date_time=>"2018-10-31T00:00:00.000Z", :lower_band=>210.5626666666667, :middle_band=>217.4346666666667, :upper_band=>224.30666666666667},
62
+ {:date_time=>"2018-10-30T00:00:00.000Z", :lower_band=>210.85700000000003, :middle_band=>217.67600000000002, :upper_band=>224.495},
63
+ {:date_time=>"2018-10-29T00:00:00.000Z", :lower_band=>211.63036000000005, :middle_band=>218.48109000000005, :upper_band=>225.33182000000005},
64
+ {:date_time=>"2018-10-26T00:00:00.000Z", :lower_band=>213.14902666666669, :middle_band=>219.0957566666667, :upper_band=>225.0424866666667},
65
+ {:date_time=>"2018-10-25T00:00:00.000Z", :lower_band=>213.71936000000002, :middle_band=>219.51809000000003, :upper_band=>225.31682000000004},
66
+ {:date_time=>"2018-10-24T00:00:00.000Z", :lower_band=>213.0756933333333, :middle_band=>219.1294233333333, :upper_band=>225.1831533333333},
67
+ {:date_time=>"2018-10-23T00:00:00.000Z", :lower_band=>213.17802666666663, :middle_band=>219.29275666666663, :upper_band=>225.40748666666664},
68
+ {:date_time=>"2018-10-22T00:00:00.000Z", :lower_band=>214.05418666666668, :middle_band=>219.8162966666667, :upper_band=>225.5784066666667}
69
+ ]
70
+
71
+ expect(normalized_output).to eq(expected_output)
72
+ end
73
+
74
+ it "Throws exception if not enough data" do
75
+ expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError)
76
+ end
77
+
78
+ it 'Returns the symbol' do
79
+ indicator_symbol = indicator.indicator_symbol
80
+ expect(indicator_symbol).to eq('kc')
81
+ end
82
+
83
+ it 'Returns the name' do
84
+ indicator_name = indicator.indicator_name
85
+ expect(indicator_name).to eq('Keltner Channel')
86
+ end
87
+
88
+ it 'Returns the valid options' do
89
+ valid_options = indicator.valid_options
90
+ expect(valid_options).to eq(%i(period))
91
+ end
92
+
93
+ it 'Validates options' do
94
+ valid_options = { period: 22 }
95
+ options_validated = indicator.validate_options(valid_options)
96
+ expect(options_validated).to eq(true)
97
+ end
98
+
99
+ it 'Throws exception for invalid options' do
100
+ invalid_options = { test: 10 }
101
+ expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError)
102
+ end
103
+
104
+ it 'Calculates minimum data size' do
105
+ options = { period: 4 }
106
+ expect(indicator.min_data_size(options)).to eq(4)
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,78 @@
1
+ require 'technical-analysis'
2
+ require 'spec_helper'
3
+
4
+ describe 'Indicators' do
5
+ describe "KST" do
6
+ input_data = SpecHelper.get_test_data(:close)
7
+ indicator = TechnicalAnalysis::Kst
8
+
9
+ describe 'Know Sure Thing' do
10
+ it 'Calculates KST' do
11
+ output = indicator.calculate(input_data, roc1: 10, roc2: 15, roc3: 20, roc4: 30, sma1: 10, sma2: 10, sma3: 10, sma4: 15, price_key: :close)
12
+ normalized_output = output.map(&:to_hash)
13
+
14
+ expected_output = [
15
+ {:date_time=>"2019-01-09T00:00:00.000Z", :kst=>-140.9140022298261},
16
+ {:date_time=>"2019-01-08T00:00:00.000Z", :kst=>-148.9261153101682},
17
+ {:date_time=>"2019-01-07T00:00:00.000Z", :kst=>-155.71040741442587},
18
+ {:date_time=>"2019-01-04T00:00:00.000Z", :kst=>-157.83675223915662},
19
+ {:date_time=>"2019-01-03T00:00:00.000Z", :kst=>-157.0260814891967},
20
+ {:date_time=>"2019-01-02T00:00:00.000Z", :kst=>-150.77021075475108},
21
+ {:date_time=>"2018-12-31T00:00:00.000Z", :kst=>-152.43337072156913},
22
+ {:date_time=>"2018-12-28T00:00:00.000Z", :kst=>-154.278039839607},
23
+ {:date_time=>"2018-12-27T00:00:00.000Z", :kst=>-152.69243922992774},
24
+ {:date_time=>"2018-12-26T00:00:00.000Z", :kst=>-151.25248412993977},
25
+ {:date_time=>"2018-12-24T00:00:00.000Z", :kst=>-150.769274028613},
26
+ {:date_time=>"2018-12-21T00:00:00.000Z", :kst=>-145.9029270207904},
27
+ {:date_time=>"2018-12-20T00:00:00.000Z", :kst=>-143.4025404878081},
28
+ {:date_time=>"2018-12-19T00:00:00.000Z", :kst=>-141.34365936138443},
29
+ {:date_time=>"2018-12-18T00:00:00.000Z", :kst=>-141.36803679622636},
30
+ {:date_time=>"2018-12-17T00:00:00.000Z", :kst=>-140.69442915235626},
31
+ {:date_time=>"2018-12-14T00:00:00.000Z", :kst=>-141.6235541026754},
32
+ {:date_time=>"2018-12-13T00:00:00.000Z", :kst=>-143.06704590371226},
33
+ {:date_time=>"2018-12-12T00:00:00.000Z", :kst=>-146.67417088368043},
34
+ {:date_time=>"2018-12-11T00:00:00.000Z", :kst=>-150.14198896419614}
35
+ ]
36
+
37
+ expect(normalized_output).to eq(expected_output)
38
+ end
39
+
40
+ it "Throws exception if not enough data" do
41
+ roc4 = 60
42
+ sma4 = 30
43
+ expect {indicator.calculate(input_data, roc4: roc4, sma4: sma4, price_key: :close)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError)
44
+ end
45
+
46
+ it 'Returns the symbol' do
47
+ indicator_symbol = indicator.indicator_symbol
48
+ expect(indicator_symbol).to eq('kst')
49
+ end
50
+
51
+ it 'Returns the name' do
52
+ indicator_name = indicator.indicator_name
53
+ expect(indicator_name).to eq('Know Sure Thing')
54
+ end
55
+
56
+ it 'Returns the valid options' do
57
+ valid_options = indicator.valid_options
58
+ expect(valid_options).to eq(%i(period roc1 roc2 roc3 roc4 sma1 sma2 sma3 sma4 price_key))
59
+ end
60
+
61
+ it 'Validates options' do
62
+ valid_options = { roc1: 10, roc2: 15, roc3: 20, roc4: 30, sma1: 10, sma2: 10, sma3: 10, sma4: 15, price_key: :kst }
63
+ options_validated = indicator.validate_options(valid_options)
64
+ expect(options_validated).to eq(true)
65
+ end
66
+
67
+ it 'Throws exception for invalid options' do
68
+ invalid_options = { test: 10 }
69
+ expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError)
70
+ end
71
+
72
+ it 'Calculates minimum data size' do
73
+ options = { roc4: 30, sma4: 15 }
74
+ expect(indicator.min_data_size(options)).to eq(44)
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,86 @@
1
+ require 'technical-analysis'
2
+ require 'spec_helper'
3
+
4
+ describe 'Indicators' do
5
+ describe "MACD" do
6
+ input_data = SpecHelper.get_test_data(:close)
7
+ indicator = TechnicalAnalysis::Macd
8
+
9
+ describe 'Moving Average Convergence Divergence' do
10
+ it 'Calculates MACD (12, 26, 9)' do
11
+ output = indicator.calculate(input_data, fast_period: 12, slow_period: 26, signal_period: 9, price_key: :close)
12
+ normalized_output = output.map(&:to_hash)
13
+
14
+ expected_output = [
15
+ {:date_time=>"2019-01-09T00:00:00.000Z", :macd_histogram=>0.8762597178840466, :macd_line=>-8.126908458242355, :signal_line=>-9.003168176126401},
16
+ {:date_time=>"2019-01-08T00:00:00.000Z", :macd_histogram=>0.4770591535283888, :macd_line=>-8.745173952069024, :signal_line=>-9.222233105597413},
17
+ {:date_time=>"2019-01-07T00:00:00.000Z", :macd_histogram=>0.19504942363819744, :macd_line=>-9.146448470341312, :signal_line=>-9.34149789397951},
18
+ {:date_time=>"2019-01-04T00:00:00.000Z", :macd_histogram=>0.15180609943062073, :macd_line=>-9.238454150458438, :signal_line=>-9.390260249889058},
19
+ {:date_time=>"2019-01-03T00:00:00.000Z", :macd_histogram=>0.17310243476363496, :macd_line=>-9.255109339983079, :signal_line=>-9.428211774746714},
20
+ {:date_time=>"2019-01-02T00:00:00.000Z", :macd_histogram=>0.9477761010428516, :macd_line=>-8.523711282394771, :signal_line=>-9.471487383437623},
21
+ {:date_time=>"2018-12-31T00:00:00.000Z", :macd_histogram=>0.6406312657329245, :macd_line=>-9.06780014296541, :signal_line=>-9.708431408698335},
22
+ {:date_time=>"2018-12-28T00:00:00.000Z", :macd_histogram=>0.25655639311731626, :macd_line=>-9.61203283201425, :signal_line=>-9.868589225131567},
23
+ {:date_time=>"2018-12-27T00:00:00.000Z", :macd_histogram=>-0.0803864814327433, :macd_line=>-10.013114804843639, :signal_line=>-9.932728323410895},
24
+ {:date_time=>"2018-12-26T00:00:00.000Z", :macd_histogram=>-0.45861878631368036, :macd_line=>-10.371250489366389, :signal_line=>-9.912631703052709},
25
+ {:date_time=>"2018-12-24T00:00:00.000Z", :macd_histogram=>-0.9833848403830618, :macd_line=>-10.78136184685735, :signal_line=>-9.797977006474289},
26
+ {:date_time=>"2018-12-21T00:00:00.000Z", :macd_histogram=>-0.5430624653584708, :macd_line=>-10.095193261736995, :signal_line=>-9.552130796378524},
27
+ {:date_time=>"2018-12-20T00:00:00.000Z", :macd_histogram=>-0.053279185610067614, :macd_line=>-9.469644365648975, :signal_line=>-9.416365180038907},
28
+ {:date_time=>"2018-12-19T00:00:00.000Z", :macd_histogram=>0.24847825431282367, :macd_line=>-9.154567129323567, :signal_line=>-9.40304538363639},
29
+ {:date_time=>"2018-12-18T00:00:00.000Z", :macd_histogram=>0.4325264668638127, :macd_line=>-9.032638480350784, :signal_line=>-9.465164947214596},
30
+ {:date_time=>"2018-12-17T00:00:00.000Z", :macd_histogram=>0.30024902798283826, :macd_line=>-9.273047535947711, :signal_line=>-9.57329656393055},
31
+ {:date_time=>"2018-12-14T00:00:00.000Z", :macd_histogram=>0.420215327266785, :macd_line=>-9.228143493659474, :signal_line=>-9.648358820926259},
32
+ {:date_time=>"2018-12-13T00:00:00.000Z", :macd_histogram=>0.5600105875119272, :macd_line=>-9.193402065231027, :signal_line=>-9.753412652742954},
33
+ {:date_time=>"2018-12-12T00:00:00.000Z", :macd_histogram=>0.3211326876237397, :macd_line=>-9.572282611997196, :signal_line=>-9.893415299620935},
34
+ {:date_time=>"2018-12-11T00:00:00.000Z", :macd_histogram=>0.24542334510443808, :macd_line=>-9.728275126422432, :signal_line=>-9.97369847152687},
35
+ {:date_time=>"2018-12-10T00:00:00.000Z", :macd_histogram=>0.29703273753484893, :macd_line=>-9.738021570268131, :signal_line=>-10.03505430780298},
36
+ {:date_time=>"2018-12-07T00:00:00.000Z", :macd_histogram=>0.40173122915939885, :macd_line=>-9.707581263027294, :signal_line=>-10.109312492186692},
37
+ {:date_time=>"2018-12-06T00:00:00.000Z", :macd_histogram=>0.7952363015170398, :macd_line=>-9.414508997959501, :signal_line=>-10.209745299476541},
38
+ {:date_time=>"2018-12-04T00:00:00.000Z", :macd_histogram=>0.8707231988258766, :macd_line=>-9.537831176029925, :signal_line=>-10.408554374855802},
39
+ {:date_time=>"2018-12-03T00:00:00.000Z", :macd_histogram=>0.8691503265374259, :macd_line=>-9.757084848024846, :signal_line=>-10.626235174562272},
40
+ {:date_time=>"2018-11-30T00:00:00.000Z", :macd_histogram=>0.12072991006954936, :macd_line=>-10.722792846127078, :signal_line=>-10.843522756196627},
41
+ {:date_time=>"2018-11-29T00:00:00.000Z", :macd_histogram=>-0.29036883404714864, :macd_line=>-11.164074067761163, :signal_line=>-10.873705233714015},
42
+ {:date_time=>"2018-11-28T00:00:00.000Z", :macd_histogram=>-0.8625734517317483, :macd_line=>-11.663686476933975, :signal_line=>-10.801113025202227},
43
+ {:date_time=>"2018-11-27T00:00:00.000Z", :macd_histogram=>-1.6877775772534704, :macd_line=>-12.27324723952276, :signal_line=>-10.58546966226929},
44
+ {:date_time=>"2018-11-26T00:00:00.000Z", :macd_histogram=>-2.0270413850598707, :macd_line=>-12.190566653015793, :signal_line=>-10.163525267955922}
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, slow_period: input_data.size+1, signal_period: input_data.size+1, price_key: :close)}.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('macd')
57
+ end
58
+
59
+ it 'Returns the name' do
60
+ indicator_name = indicator.indicator_name
61
+ expect(indicator_name).to eq('Moving Average Convergence Divergence')
62
+ end
63
+
64
+ it 'Returns the valid options' do
65
+ valid_options = indicator.valid_options
66
+ expect(valid_options).to eq(%i(fast_period slow_period signal_period price_key))
67
+ end
68
+
69
+ it 'Validates options' do
70
+ valid_options = { fast_period: 12, slow_period: 26, signal_period: 9, price_key: :close }
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 = { fast_period: 12, slow_period: 24, signal_period: 10, price_key: :close }
82
+ expect(indicator.min_data_size(options)).to eq(33)
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 "MFI" do
6
+ input_data = SpecHelper.get_test_data(:high, :low, :close, :volume)
7
+ indicator = TechnicalAnalysis::Mfi
8
+
9
+ describe 'Money Flow Index' do
10
+ it 'Calculates MFI (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", :mfi=>50.72343663578981},
16
+ {:date_time=>"2019-01-08T00:00:00.000Z", :mfi=>50.1757147722236},
17
+ {:date_time=>"2019-01-07T00:00:00.000Z", :mfi=>44.40424662233335},
18
+ {:date_time=>"2019-01-04T00:00:00.000Z", :mfi=>37.81171947764313},
19
+ {:date_time=>"2019-01-03T00:00:00.000Z", :mfi=>36.12141791144509},
20
+ {:date_time=>"2019-01-02T00:00:00.000Z", :mfi=>44.40322811326429},
21
+ {:date_time=>"2018-12-31T00:00:00.000Z", :mfi=>50.84666407662511},
22
+ {:date_time=>"2018-12-28T00:00:00.000Z", :mfi=>43.66248537462054},
23
+ {:date_time=>"2018-12-27T00:00:00.000Z", :mfi=>37.56125308902594},
24
+ {:date_time=>"2018-12-26T00:00:00.000Z", :mfi=>30.54886108664553},
25
+ {:date_time=>"2018-12-24T00:00:00.000Z", :mfi=>22.795547568232564},
26
+ {:date_time=>"2018-12-21T00:00:00.000Z", :mfi=>29.111701049682864},
27
+ {:date_time=>"2018-12-20T00:00:00.000Z", :mfi=>31.23926122664477},
28
+ {:date_time=>"2018-12-19T00:00:00.000Z", :mfi=>39.506183778454634},
29
+ {:date_time=>"2018-12-18T00:00:00.000Z", :mfi=>47.447534147092476},
30
+ {:date_time=>"2018-12-17T00:00:00.000Z", :mfi=>48.23034273673764},
31
+ {:date_time=>"2018-12-14T00:00:00.000Z", :mfi=>47.94902504034211},
32
+ {:date_time=>"2018-12-13T00:00:00.000Z", :mfi=>49.219385053554596},
33
+ {:date_time=>"2018-12-12T00:00:00.000Z", :mfi=>43.77747404533765},
34
+ {:date_time=>"2018-12-11T00:00:00.000Z", :mfi=>35.65846689890073},
35
+ {:date_time=>"2018-12-10T00:00:00.000Z", :mfi=>28.368262151706787},
36
+ {:date_time=>"2018-12-07T00:00:00.000Z", :mfi=>36.043235982173},
37
+ {:date_time=>"2018-12-06T00:00:00.000Z", :mfi=>43.83608665179891},
38
+ {:date_time=>"2018-12-04T00:00:00.000Z", :mfi=>42.20999531156955},
39
+ {:date_time=>"2018-12-03T00:00:00.000Z", :mfi=>41.56028762200471},
40
+ {:date_time=>"2018-11-30T00:00:00.000Z", :mfi=>34.05798943239071},
41
+ {:date_time=>"2018-11-29T00:00:00.000Z", :mfi=>34.06816082393442},
42
+ {:date_time=>"2018-11-28T00:00:00.000Z", :mfi=>32.76065853310956},
43
+ {:date_time=>"2018-11-27T00:00:00.000Z", :mfi=>31.964707056845796},
44
+ {:date_time=>"2018-11-26T00:00:00.000Z", :mfi=>31.547361595662196},
45
+ {:date_time=>"2018-11-23T00:00:00.000Z", :mfi=>30.0162422598642},
46
+ {:date_time=>"2018-11-21T00:00:00.000Z", :mfi=>26.562703378271138},
47
+ {:date_time=>"2018-11-20T00:00:00.000Z", :mfi=>33.960148214906965},
48
+ {:date_time=>"2018-11-19T00:00:00.000Z", :mfi=>41.216526023725},
49
+ {:date_time=>"2018-11-16T00:00:00.000Z", :mfi=>41.22749344358184},
50
+ {:date_time=>"2018-11-15T00:00:00.000Z", :mfi=>35.21136683265594},
51
+ {:date_time=>"2018-11-14T00:00:00.000Z", :mfi=>28.384945303826555},
52
+ {:date_time=>"2018-11-13T00:00:00.000Z", :mfi=>34.34229761188338},
53
+ {:date_time=>"2018-11-12T00:00:00.000Z", :mfi=>34.42914208336833},
54
+ {:date_time=>"2018-11-09T00:00:00.000Z", :mfi=>34.82129345577579},
55
+ {:date_time=>"2018-11-08T00:00:00.000Z", :mfi=>39.93886476277229},
56
+ {:date_time=>"2018-11-07T00:00:00.000Z", :mfi=>40.83081970751587},
57
+ {:date_time=>"2018-11-06T00:00:00.000Z", :mfi=>35.50426811855657},
58
+ {:date_time=>"2018-11-05T00:00:00.000Z", :mfi=>34.78216906343063},
59
+ {:date_time=>"2018-11-02T00:00:00.000Z", :mfi=>41.95906812943111},
60
+ {:date_time=>"2018-11-01T00:00:00.000Z", :mfi=>46.69168911629936},
61
+ {:date_time=>"2018-10-31T00:00:00.000Z", :mfi=>45.214622261116865},
62
+ {:date_time=>"2018-10-30T00:00:00.000Z", :mfi=>36.38768375444253},
63
+ {:date_time=>"2018-10-29T00:00:00.000Z", :mfi=>35.973926377719295}
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)}.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('mfi')
76
+ end
77
+
78
+ it 'Returns the name' do
79
+ indicator_name = indicator.indicator_name
80
+ expect(indicator_name).to eq('Money Flow 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))
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