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,100 @@
1
+ require 'technical-analysis'
2
+ require 'spec_helper'
3
+
4
+ describe 'Indicators' do
5
+ describe "CCI" do
6
+ input_data = SpecHelper.get_test_data(:high, :low, :close)
7
+ indicator = TechnicalAnalysis::Cci
8
+
9
+ describe 'Commodity Channel Index' do
10
+ it 'Calculates CCI (20 day)' do
11
+ output = indicator.calculate(input_data, period: 20, constant: 0.015)
12
+ normalized_output = output.map(&:to_hash)
13
+
14
+ expected_output = [
15
+ {:date_time=>"2019-01-09T00:00:00.000Z", :cci=>-48.14847062019609},
16
+ {:date_time=>"2019-01-08T00:00:00.000Z", :cci=>-72.7408611895969},
17
+ {:date_time=>"2019-01-07T00:00:00.000Z", :cci=>-103.45330536502108},
18
+ {:date_time=>"2019-01-04T00:00:00.000Z", :cci=>-119.01911861945885},
19
+ {:date_time=>"2019-01-03T00:00:00.000Z", :cci=>-162.69069349674928},
20
+ {:date_time=>"2019-01-02T00:00:00.000Z", :cci=>-62.42850721332871},
21
+ {:date_time=>"2018-12-31T00:00:00.000Z", :cci=>-62.94237272962061},
22
+ {:date_time=>"2018-12-28T00:00:00.000Z", :cci=>-82.72457326337747},
23
+ {:date_time=>"2018-12-27T00:00:00.000Z", :cci=>-109.82143904961333},
24
+ {:date_time=>"2018-12-26T00:00:00.000Z", :cci=>-130.89740843118958},
25
+ {:date_time=>"2018-12-24T00:00:00.000Z", :cci=>-205.86763488625635},
26
+ {:date_time=>"2018-12-21T00:00:00.000Z", :cci=>-204.3001270602558},
27
+ {:date_time=>"2018-12-20T00:00:00.000Z", :cci=>-175.655233047097},
28
+ {:date_time=>"2018-12-19T00:00:00.000Z", :cci=>-145.86611021295013},
29
+ {:date_time=>"2018-12-18T00:00:00.000Z", :cci=>-108.36683776743406},
30
+ {:date_time=>"2018-12-17T00:00:00.000Z", :cci=>-123.22931274779911},
31
+ {:date_time=>"2018-12-14T00:00:00.000Z", :cci=>-114.79798652194032},
32
+ {:date_time=>"2018-12-13T00:00:00.000Z", :cci=>-77.37092752385674},
33
+ {:date_time=>"2018-12-12T00:00:00.000Z", :cci=>-93.5619842292165},
34
+ {:date_time=>"2018-12-11T00:00:00.000Z", :cci=>-105.1287325078536},
35
+ {:date_time=>"2018-12-10T00:00:00.000Z", :cci=>-118.83020945347108},
36
+ {:date_time=>"2018-12-07T00:00:00.000Z", :cci=>-102.13101656480995},
37
+ {:date_time=>"2018-12-06T00:00:00.000Z", :cci=>-87.66403875835518},
38
+ {:date_time=>"2018-12-04T00:00:00.000Z", :cci=>-60.69535791887537},
39
+ {:date_time=>"2018-12-03T00:00:00.000Z", :cci=>-32.43699792850786},
40
+ {:date_time=>"2018-11-30T00:00:00.000Z", :cci=>-68.8774176049022},
41
+ {:date_time=>"2018-11-29T00:00:00.000Z", :cci=>-67.42425893465922},
42
+ {:date_time=>"2018-11-28T00:00:00.000Z", :cci=>-79.16162769465076},
43
+ {:date_time=>"2018-11-27T00:00:00.000Z", :cci=>-117.06521007698558},
44
+ {:date_time=>"2018-11-26T00:00:00.000Z", :cci=>-130.57777507098388},
45
+ {:date_time=>"2018-11-23T00:00:00.000Z", :cci=>-145.81148745067057},
46
+ {:date_time=>"2018-11-21T00:00:00.000Z", :cci=>-143.70909871161282},
47
+ {:date_time=>"2018-11-20T00:00:00.000Z", :cci=>-166.092016017792},
48
+ {:date_time=>"2018-11-19T00:00:00.000Z", :cci=>-129.79321417259732},
49
+ {:date_time=>"2018-11-16T00:00:00.000Z", :cci=>-109.8703962546515},
50
+ {:date_time=>"2018-11-15T00:00:00.000Z", :cci=>-144.29736082195598},
51
+ {:date_time=>"2018-11-14T00:00:00.000Z", :cci=>-176.53554346437872},
52
+ {:date_time=>"2018-11-13T00:00:00.000Z", :cci=>-170.11758119513328},
53
+ {:date_time=>"2018-11-12T00:00:00.000Z", :cci=>-179.88996064655686},
54
+ {:date_time=>"2018-11-09T00:00:00.000Z", :cci=>-121.3842764199079},
55
+ {:date_time=>"2018-11-08T00:00:00.000Z", :cci=>-88.26723659204252},
56
+ {:date_time=>"2018-11-07T00:00:00.000Z", :cci=>-107.40409620543349},
57
+ {:date_time=>"2018-11-06T00:00:00.000Z", :cci=>-198.71238766942466},
58
+ {:date_time=>"2018-11-05T00:00:00.000Z", :cci=>-281.5255251804358}
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)}.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('cci')
71
+ end
72
+
73
+ it 'Returns the name' do
74
+ indicator_name = indicator.indicator_name
75
+ expect(indicator_name).to eq('Commodity Channel Index')
76
+ end
77
+
78
+ it 'Returns the valid options' do
79
+ valid_options = indicator.valid_options
80
+ expect(valid_options).to eq(%i(period constant))
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
@@ -0,0 +1,100 @@
1
+ require 'technical-analysis'
2
+ require 'spec_helper'
3
+
4
+ describe 'Indicators' do
5
+ describe "CMF" do
6
+ input_data = SpecHelper.get_test_data(:high, :low, :close, :volume)
7
+ indicator = TechnicalAnalysis::Cmf
8
+
9
+ describe 'Chaikin Money Flow' do
10
+ it 'Calculates CMF (20 day)' do
11
+ output = indicator.calculate(input_data, period: 20)
12
+ normalized_output = output.map(&:to_hash)
13
+
14
+ expected_output = [
15
+ {:date_time=>"2019-01-09T00:00:00.000Z", :cmf=>-0.14148236474171028},
16
+ {:date_time=>"2019-01-08T00:00:00.000Z", :cmf=>-0.10900349402409147},
17
+ {:date_time=>"2019-01-07T00:00:00.000Z", :cmf=>-0.16209459049078995},
18
+ {:date_time=>"2019-01-04T00:00:00.000Z", :cmf=>-0.14338098793972473},
19
+ {:date_time=>"2019-01-03T00:00:00.000Z", :cmf=>-0.23384083275693518},
20
+ {:date_time=>"2019-01-02T00:00:00.000Z", :cmf=>-0.1171779554311941},
21
+ {:date_time=>"2018-12-31T00:00:00.000Z", :cmf=>-0.1421967277504723},
22
+ {:date_time=>"2018-12-28T00:00:00.000Z", :cmf=>-0.14870217725852253},
23
+ {:date_time=>"2018-12-27T00:00:00.000Z", :cmf=>-0.09771633750350824},
24
+ {:date_time=>"2018-12-26T00:00:00.000Z", :cmf=>-0.11185040161958644},
25
+ {:date_time=>"2018-12-24T00:00:00.000Z", :cmf=>-0.13433878933016613},
26
+ {:date_time=>"2018-12-21T00:00:00.000Z", :cmf=>-0.12311876857928804},
27
+ {:date_time=>"2018-12-20T00:00:00.000Z", :cmf=>-0.08053545285645361},
28
+ {:date_time=>"2018-12-19T00:00:00.000Z", :cmf=>-0.07883316711924936},
29
+ {:date_time=>"2018-12-18T00:00:00.000Z", :cmf=>-0.08160027269601758},
30
+ {:date_time=>"2018-12-17T00:00:00.000Z", :cmf=>-0.0635610565928198},
31
+ {:date_time=>"2018-12-14T00:00:00.000Z", :cmf=>0.008829457014340984},
32
+ {:date_time=>"2018-12-13T00:00:00.000Z", :cmf=>-0.005177700749048257},
33
+ {:date_time=>"2018-12-12T00:00:00.000Z", :cmf=>-0.041279122544240626},
34
+ {:date_time=>"2018-12-11T00:00:00.000Z", :cmf=>-0.05299093511730075},
35
+ {:date_time=>"2018-12-10T00:00:00.000Z", :cmf=>-0.02994416009907359},
36
+ {:date_time=>"2018-12-07T00:00:00.000Z", :cmf=>-0.09289096149170357},
37
+ {:date_time=>"2018-12-06T00:00:00.000Z", :cmf=>-0.008556645577315109},
38
+ {:date_time=>"2018-12-04T00:00:00.000Z", :cmf=>-0.044697234566322144},
39
+ {:date_time=>"2018-12-03T00:00:00.000Z", :cmf=>0.006195178249247199},
40
+ {:date_time=>"2018-11-30T00:00:00.000Z", :cmf=>-0.08707816577338795},
41
+ {:date_time=>"2018-11-29T00:00:00.000Z", :cmf=>-0.02808273355873217},
42
+ {:date_time=>"2018-11-28T00:00:00.000Z", :cmf=>-0.008559410227273146},
43
+ {:date_time=>"2018-11-27T00:00:00.000Z", :cmf=>-0.039334642581608396},
44
+ {:date_time=>"2018-11-26T00:00:00.000Z", :cmf=>-0.07707518115228632},
45
+ {:date_time=>"2018-11-23T00:00:00.000Z", :cmf=>-0.12097582444999905},
46
+ {:date_time=>"2018-11-21T00:00:00.000Z", :cmf=>-0.0864519745264971},
47
+ {:date_time=>"2018-11-20T00:00:00.000Z", :cmf=>-0.09451983283878523},
48
+ {:date_time=>"2018-11-19T00:00:00.000Z", :cmf=>-0.02107439975862456},
49
+ {:date_time=>"2018-11-16T00:00:00.000Z", :cmf=>0.004132959703610273},
50
+ {:date_time=>"2018-11-15T00:00:00.000Z", :cmf=>-0.016262278292090777},
51
+ {:date_time=>"2018-11-14T00:00:00.000Z", :cmf=>-0.06224056395025631},
52
+ {:date_time=>"2018-11-13T00:00:00.000Z", :cmf=>-0.00325588286845078},
53
+ {:date_time=>"2018-11-12T00:00:00.000Z", :cmf=>0.06492697386482489},
54
+ {:date_time=>"2018-11-09T00:00:00.000Z", :cmf=>0.08638139363431603},
55
+ {:date_time=>"2018-11-08T00:00:00.000Z", :cmf=>0.11517576782439708},
56
+ {:date_time=>"2018-11-07T00:00:00.000Z", :cmf=>0.0839939173853672},
57
+ {:date_time=>"2018-11-06T00:00:00.000Z", :cmf=>-0.002328367522189358},
58
+ {:date_time=>"2018-11-05T00:00:00.000Z", :cmf=>0.010519910116535688}
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)}.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('cmf')
71
+ end
72
+
73
+ it 'Returns the name' do
74
+ indicator_name = indicator.indicator_name
75
+ expect(indicator_name).to eq('Chaikin Money Flow')
76
+ end
77
+
78
+ it 'Returns the valid options' do
79
+ valid_options = indicator.valid_options
80
+ expect(valid_options).to eq(%i(period))
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
@@ -0,0 +1,119 @@
1
+ require 'technical-analysis'
2
+ require 'spec_helper'
3
+
4
+ describe 'Indicators' do
5
+ describe "CR" do
6
+ input_data = SpecHelper.get_test_data(:close)
7
+ indicator = TechnicalAnalysis::Cr
8
+
9
+ describe 'Cumulative Return' do
10
+ it 'Calculates CR' do
11
+ output = indicator.calculate(input_data, price_key: :close)
12
+ normalized_output = output.map(&:to_hash)
13
+
14
+ expected_output = [
15
+ {:date_time=>"2019-01-09T00:00:00.000Z", :cr=>-0.3242385507118614},
16
+ {:date_time=>"2019-01-08T00:00:00.000Z", :cr=>-0.33552254595142594},
17
+ {:date_time=>"2019-01-07T00:00:00.000Z", :cr=>-0.34795257195750867},
18
+ {:date_time=>"2019-01-04T00:00:00.000Z", :cr=>-0.34649799444615864},
19
+ {:date_time=>"2019-01-03T00:00:00.000Z", :cr=>-0.3732534050337198},
20
+ {:date_time=>"2019-01-02T00:00:00.000Z", :cr=>-0.30391854365936444},
21
+ {:date_time=>"2018-12-31T00:00:00.000Z", :cr=>-0.30471194957464626},
22
+ {:date_time=>"2018-12-28T00:00:00.000Z", :cr=>-0.3113677436417332},
23
+ {:date_time=>"2018-12-27T00:00:00.000Z", :cr=>-0.3117203684929695},
24
+ {:date_time=>"2018-12-26T00:00:00.000Z", :cr=>-0.3072244016397056},
25
+ {:date_time=>"2018-12-24T00:00:00.000Z", :cr=>-0.35280116366200903},
26
+ {:date_time=>"2018-12-21T00:00:00.000Z", :cr=>-0.3356107021642351},
27
+ {:date_time=>"2018-12-20T00:00:00.000Z", :cr=>-0.3087230572574602},
28
+ {:date_time=>"2018-12-19T00:00:00.000Z", :cr=>-0.29082734605721344},
29
+ {:date_time=>"2018-12-18T00:00:00.000Z", :cr=>-0.2679948869396571},
30
+ {:date_time=>"2018-12-17T00:00:00.000Z", :cr=>-0.277383523603826},
31
+ {:date_time=>"2018-12-14T00:00:00.000Z", :cr=>-0.2705954952175255},
32
+ {:date_time=>"2018-12-13T00:00:00.000Z", :cr=>-0.2464847710142373},
33
+ {:date_time=>"2018-12-12T00:00:00.000Z", :cr=>-0.2546392206990788},
34
+ {:date_time=>"2018-12-11T00:00:00.000Z", :cr=>-0.2567108917000926},
35
+ {:date_time=>"2018-12-10T00:00:00.000Z", :cr=>-0.2524353153788514},
36
+ {:date_time=>"2018-12-07T00:00:00.000Z", :cr=>-0.25732798518975625},
37
+ {:date_time=>"2018-12-06T00:00:00.000Z", :cr=>-0.22986732489972234},
38
+ {:date_time=>"2018-12-04T00:00:00.000Z", :cr=>-0.2211839379380262},
39
+ {:date_time=>"2018-12-03T00:00:00.000Z", :cr=>-0.185348437431128},
40
+ {:date_time=>"2018-11-30T00:00:00.000Z", :cr=>-0.2128531758275664},
41
+ {:date_time=>"2018-11-29T00:00:00.000Z", :cr=>-0.20857759950632518},
42
+ {:date_time=>"2018-11-28T00:00:00.000Z", :cr=>-0.20245074271609295},
43
+ {:date_time=>"2018-11-27T00:00:00.000Z", :cr=>-0.23198307400714063},
44
+ {:date_time=>"2018-11-26T00:00:00.000Z", :cr=>-0.2303081059637678},
45
+ {:date_time=>"2018-11-23T00:00:00.000Z", :cr=>-0.24057830475602773},
46
+ {:date_time=>"2018-11-21T00:00:00.000Z", :cr=>-0.22078723498038524},
47
+ {:date_time=>"2018-11-20T00:00:00.000Z", :cr=>-0.21990567285229431},
48
+ {:date_time=>"2018-11-19T00:00:00.000Z", :cr=>-0.18076431436505483},
49
+ {:date_time=>"2018-11-16T00:00:00.000Z", :cr=>-0.14695640675276592},
50
+ {:date_time=>"2018-11-15T00:00:00.000Z", :cr=>-0.15630096531053028},
51
+ {:date_time=>"2018-11-14T00:00:00.000Z", :cr=>-0.17662097236302726},
52
+ {:date_time=>"2018-11-13T00:00:00.000Z", :cr=>-0.15268656058535732},
53
+ {:date_time=>"2018-11-12T00:00:00.000Z", :cr=>-0.14413540794287485},
54
+ {:date_time=>"2018-11-09T00:00:00.000Z", :cr=>-0.09873495834618948},
55
+ {:date_time=>"2018-11-08T00:00:00.000Z", :cr=>-0.08101555957156079},
56
+ {:date_time=>"2018-11-07T00:00:00.000Z", :cr=>-0.07458015603649674},
57
+ {:date_time=>"2018-11-06T00:00:00.000Z", :cr=>-0.10182042579450784},
58
+ {:date_time=>"2018-11-05T00:00:00.000Z", :cr=>-0.11142945299069952},
59
+ {:date_time=>"2018-11-02T00:00:00.000Z", :cr=>-0.0854674483184203},
60
+ {:date_time=>"2018-11-01T00:00:00.000Z", :cr=>-0.020496319478115244},
61
+ {:date_time=>"2018-10-31T00:00:00.000Z", :cr=>-0.035306563230043594},
62
+ {:date_time=>"2018-10-30T00:00:00.000Z", :cr=>-0.05981399039097277},
63
+ {:date_time=>"2018-10-29T00:00:00.000Z", :cr=>-0.06448626966985496},
64
+ {:date_time=>"2018-10-26T00:00:00.000Z", :cr=>-0.046590558469608113},
65
+ {:date_time=>"2018-10-25T00:00:00.000Z", :cr=>-0.031163221228016014},
66
+ {:date_time=>"2018-10-24T00:00:00.000Z", :cr=>-0.05192400934455856},
67
+ {:date_time=>"2018-10-23T00:00:00.000Z", :cr=>-0.018248336051483294},
68
+ {:date_time=>"2018-10-22T00:00:00.000Z", :cr=>-0.027416582183629384},
69
+ {:date_time=>"2018-10-19T00:00:00.000Z", :cr=>-0.03332304844183895},
70
+ {:date_time=>"2018-10-18T00:00:00.000Z", :cr=>-0.04782474544893549},
71
+ {:date_time=>"2018-10-17T00:00:00.000Z", :cr=>-0.025036364437783783},
72
+ {:date_time=>"2018-10-16T00:00:00.000Z", :cr=>-0.02080486622294706},
73
+ {:date_time=>"2018-10-15T00:00:00.000Z", :cr=>-0.041918279190725924},
74
+ {:date_time=>"2018-10-12T00:00:00.000Z", :cr=>-0.02098117864856522},
75
+ {:date_time=>"2018-10-11T00:00:00.000Z", :cr=>-0.054745008154449756},
76
+ {:date_time=>"2018-10-10T00:00:00.000Z", :cr=>-0.04632608983118081},
77
+ {:date_time=>"2018-10-09T00:00:00.000Z", :cr=>0.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([], price_key: :close)}.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('cr')
90
+ end
91
+
92
+ it 'Returns the name' do
93
+ indicator_name = indicator.indicator_name
94
+ expect(indicator_name).to eq('Cumulative Return')
95
+ end
96
+
97
+ it 'Returns the valid options' do
98
+ valid_options = indicator.valid_options
99
+ expect(valid_options).to eq(%i(price_key))
100
+ end
101
+
102
+ it 'Validates options' do
103
+ valid_options = { price_key: :close }
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,100 @@
1
+ require 'technical-analysis'
2
+ require 'spec_helper'
3
+
4
+ describe 'Indicators' do
5
+ describe "DC" do
6
+ input_data = SpecHelper.get_test_data(:close)
7
+ indicator = TechnicalAnalysis::Dc
8
+
9
+ describe 'Donchian Channel' do
10
+ it 'Calculates DC (20 day)' do
11
+ output = indicator.calculate(input_data, period: 20, price_key: :close)
12
+ normalized_output = output.map(&:to_hash)
13
+
14
+ expected_output = [
15
+ {:date_time=>"2019-01-09T00:00:00.000Z", :lower_bound=>142.19, :upper_bound=>170.95},
16
+ {:date_time=>"2019-01-08T00:00:00.000Z", :lower_bound=>142.19, :upper_bound=>170.95},
17
+ {:date_time=>"2019-01-07T00:00:00.000Z", :lower_bound=>142.19, :upper_bound=>170.95},
18
+ {:date_time=>"2019-01-04T00:00:00.000Z", :lower_bound=>142.19, :upper_bound=>174.72},
19
+ {:date_time=>"2019-01-03T00:00:00.000Z", :lower_bound=>142.19, :upper_bound=>176.69},
20
+ {:date_time=>"2019-01-02T00:00:00.000Z", :lower_bound=>146.83, :upper_bound=>184.82},
21
+ {:date_time=>"2018-12-31T00:00:00.000Z", :lower_bound=>146.83, :upper_bound=>184.82},
22
+ {:date_time=>"2018-12-28T00:00:00.000Z", :lower_bound=>146.83, :upper_bound=>184.82},
23
+ {:date_time=>"2018-12-27T00:00:00.000Z", :lower_bound=>146.83, :upper_bound=>184.82},
24
+ {:date_time=>"2018-12-26T00:00:00.000Z", :lower_bound=>146.83, :upper_bound=>184.82},
25
+ {:date_time=>"2018-12-24T00:00:00.000Z", :lower_bound=>146.83, :upper_bound=>184.82},
26
+ {:date_time=>"2018-12-21T00:00:00.000Z", :lower_bound=>150.73, :upper_bound=>184.82},
27
+ {:date_time=>"2018-12-20T00:00:00.000Z", :lower_bound=>156.83, :upper_bound=>184.82},
28
+ {:date_time=>"2018-12-19T00:00:00.000Z", :lower_bound=>160.89, :upper_bound=>184.82},
29
+ {:date_time=>"2018-12-18T00:00:00.000Z", :lower_bound=>163.94, :upper_bound=>185.86},
30
+ {:date_time=>"2018-12-17T00:00:00.000Z", :lower_bound=>163.94, :upper_bound=>193.53},
31
+ {:date_time=>"2018-12-14T00:00:00.000Z", :lower_bound=>165.48, :upper_bound=>193.53},
32
+ {:date_time=>"2018-12-13T00:00:00.000Z", :lower_bound=>168.49, :upper_bound=>193.53},
33
+ {:date_time=>"2018-12-12T00:00:00.000Z", :lower_bound=>168.49, :upper_bound=>193.53},
34
+ {:date_time=>"2018-12-11T00:00:00.000Z", :lower_bound=>168.49, :upper_bound=>194.17},
35
+ {:date_time=>"2018-12-10T00:00:00.000Z", :lower_bound=>168.49, :upper_bound=>204.47},
36
+ {:date_time=>"2018-12-07T00:00:00.000Z", :lower_bound=>168.49, :upper_bound=>208.49},
37
+ {:date_time=>"2018-12-06T00:00:00.000Z", :lower_bound=>172.29, :upper_bound=>209.95},
38
+ {:date_time=>"2018-12-04T00:00:00.000Z", :lower_bound=>172.29, :upper_bound=>209.95},
39
+ {:date_time=>"2018-12-03T00:00:00.000Z", :lower_bound=>172.29, :upper_bound=>209.95},
40
+ {:date_time=>"2018-11-30T00:00:00.000Z", :lower_bound=>172.29, :upper_bound=>209.95},
41
+ {:date_time=>"2018-11-29T00:00:00.000Z", :lower_bound=>172.29, :upper_bound=>222.22},
42
+ {:date_time=>"2018-11-28T00:00:00.000Z", :lower_bound=>172.29, :upper_bound=>222.22},
43
+ {:date_time=>"2018-11-27T00:00:00.000Z", :lower_bound=>172.29, :upper_bound=>222.22},
44
+ {:date_time=>"2018-11-26T00:00:00.000Z", :lower_bound=>172.29, :upper_bound=>222.22},
45
+ {:date_time=>"2018-11-23T00:00:00.000Z", :lower_bound=>172.29, :upper_bound=>222.22},
46
+ {:date_time=>"2018-11-21T00:00:00.000Z", :lower_bound=>176.78, :upper_bound=>222.22},
47
+ {:date_time=>"2018-11-20T00:00:00.000Z", :lower_bound=>176.98, :upper_bound=>222.22},
48
+ {:date_time=>"2018-11-19T00:00:00.000Z", :lower_bound=>185.86, :upper_bound=>222.73},
49
+ {:date_time=>"2018-11-16T00:00:00.000Z", :lower_bound=>186.8, :upper_bound=>222.73},
50
+ {:date_time=>"2018-11-15T00:00:00.000Z", :lower_bound=>186.8, :upper_bound=>222.73},
51
+ {:date_time=>"2018-11-14T00:00:00.000Z", :lower_bound=>186.8, :upper_bound=>222.73},
52
+ {:date_time=>"2018-11-13T00:00:00.000Z", :lower_bound=>192.23, :upper_bound=>222.73},
53
+ {:date_time=>"2018-11-12T00:00:00.000Z", :lower_bound=>194.17, :upper_bound=>222.73},
54
+ {:date_time=>"2018-11-09T00:00:00.000Z", :lower_bound=>201.59, :upper_bound=>222.73},
55
+ {:date_time=>"2018-11-08T00:00:00.000Z", :lower_bound=>201.59, :upper_bound=>222.73},
56
+ {:date_time=>"2018-11-07T00:00:00.000Z", :lower_bound=>201.59, :upper_bound=>222.73},
57
+ {:date_time=>"2018-11-06T00:00:00.000Z", :lower_bound=>201.59, :upper_bound=>222.73},
58
+ {:date_time=>"2018-11-05T00:00:00.000Z", :lower_bound=>201.59, :upper_bound=>226.87}
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('dc')
71
+ end
72
+
73
+ it 'Returns the name' do
74
+ indicator_name = indicator.indicator_name
75
+ expect(indicator_name).to eq('Donchian Channel')
76
+ end
77
+
78
+ it 'Returns the valid options' do
79
+ valid_options = indicator.valid_options
80
+ expect(valid_options).to eq(%i(period price_key))
81
+ end
82
+
83
+ it 'Validates options' do
84
+ valid_options = { period: 22, price_key: :close }
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
@@ -0,0 +1,119 @@
1
+ require 'technical-analysis'
2
+ require 'spec_helper'
3
+
4
+ describe 'Indicators' do
5
+ describe "DLR" do
6
+ input_data = SpecHelper.get_test_data(:close)
7
+ indicator = TechnicalAnalysis::Dlr
8
+
9
+ describe 'Daily Log Return' do
10
+ it 'Calculates Daily Log Return' do
11
+ output = indicator.calculate(input_data, price_key: :close)
12
+ normalized_output = output.map(&:to_hash)
13
+
14
+ expected_output = [
15
+ {:date_time=>"2019-01-09T00:00:00.000Z", :dlr=>0.01683917971506794},
16
+ {:date_time=>"2019-01-08T00:00:00.000Z", :dlr=>0.01888364670315034},
17
+ {:date_time=>"2019-01-07T00:00:00.000Z", :dlr=>-0.0022283003244291597},
18
+ {:date_time=>"2019-01-04T00:00:00.000Z", :dlr=>0.04180329782029066},
19
+ {:date_time=>"2019-01-03T00:00:00.000Z", :dlr=>-0.10492438427688831},
20
+ {:date_time=>"2019-01-02T00:00:00.000Z", :dlr=>0.0011404677153263752},
21
+ {:date_time=>"2018-12-31T00:00:00.000Z", :dlr=>0.009618827546033224},
22
+ {:date_time=>"2018-12-28T00:00:00.000Z", :dlr=>0.0005121966947240164},
23
+ {:date_time=>"2018-12-27T00:00:00.000Z", :dlr=>-0.006510938359150324},
24
+ {:date_time=>"2018-12-26T00:00:00.000Z", :dlr=>0.06805256711339175},
25
+ {:date_time=>"2018-12-24T00:00:00.000Z", :dlr=>-0.026214701847591528},
26
+ {:date_time=>"2018-12-21T00:00:00.000Z", :dlr=>-0.039672259323895565},
27
+ {:date_time=>"2018-12-20T00:00:00.000Z", :dlr=>-0.02555848551661011},
28
+ {:date_time=>"2018-12-19T00:00:00.000Z", :dlr=>-0.03168848455571821},
29
+ {:date_time=>"2018-12-18T00:00:00.000Z", :dlr=>0.012908878993777004},
30
+ {:date_time=>"2018-12-17T00:00:00.000Z", :dlr=>-0.0093498343683261},
31
+ {:date_time=>"2018-12-14T00:00:00.000Z", :dlr=>-0.032520774492099586},
32
+ {:date_time=>"2018-12-13T00:00:00.000Z", :dlr=>0.010880860180775654},
33
+ {:date_time=>"2018-12-12T00:00:00.000Z", :dlr=>0.002783290222441408},
34
+ {:date_time=>"2018-12-11T00:00:00.000Z", :dlr=>-0.00573575767570937},
35
+ {:date_time=>"2018-12-10T00:00:00.000Z", :dlr=>0.00656632250750863},
36
+ {:date_time=>"2018-12-07T00:00:00.000Z", :dlr=>-0.03630829170624626},
37
+ {:date_time=>"2018-12-06T00:00:00.000Z", :dlr=>-0.011212092072018474},
38
+ {:date_time=>"2018-12-04T00:00:00.000Z", :dlr=>-0.044985593831335616},
39
+ {:date_time=>"2018-12-03T00:00:00.000Z", :dlr=>0.034345698370823956},
40
+ {:date_time=>"2018-11-30T00:00:00.000Z", :dlr=>-0.005417040583021469},
41
+ {:date_time=>"2018-11-29T00:00:00.000Z", :dlr=>-0.007711763925503673},
42
+ {:date_time=>"2018-11-28T00:00:00.000Z", :dlr=>0.037731825412945244},
43
+ {:date_time=>"2018-11-27T00:00:00.000Z", :dlr=>-0.002178525198011193},
44
+ {:date_time=>"2018-11-26T00:00:00.000Z", :dlr=>0.013433080838346925},
45
+ {:date_time=>"2018-11-23T00:00:00.000Z", :dlr=>-0.02572691808848715},
46
+ {:date_time=>"2018-11-21T00:00:00.000Z", :dlr=>-0.0011307102064021337},
47
+ {:date_time=>"2018-11-20T00:00:00.000Z", :dlr=>-0.04895697028998929},
48
+ {:date_time=>"2018-11-19T00:00:00.000Z", :dlr=>-0.04043883708306672},
49
+ {:date_time=>"2018-11-16T00:00:00.000Z", :dlr=>0.011014814954241668},
50
+ {:date_time=>"2018-11-15T00:00:00.000Z", :dlr=>0.024379198463276127},
51
+ {:date_time=>"2018-11-14T00:00:00.000Z", :dlr=>-0.028654045970026604},
52
+ {:date_time=>"2018-11-13T00:00:00.000Z", :dlr=>-0.010041492241593453},
53
+ {:date_time=>"2018-11-12T00:00:00.000Z", :dlr=>-0.051687201448600596},
54
+ {:date_time=>"2018-11-09T00:00:00.000Z", :dlr=>-0.01946981300300202},
55
+ {:date_time=>"2018-11-08T00:00:00.000Z", :dlr=>-0.006978328672237313},
56
+ {:date_time=>"2018-11-07T00:00:00.000Z", :dlr=>0.029877500317357083},
57
+ {:date_time=>"2018-11-06T00:00:00.000Z", :dlr=>0.010755975020512992},
58
+ {:date_time=>"2018-11-05T00:00:00.000Z", :dlr=>-0.028799017690867113},
59
+ {:date_time=>"2018-11-02T00:00:00.000Z", :dlr=>-0.0686329326726632},
60
+ {:date_time=>"2018-11-01T00:00:00.000Z", :dlr=>0.015235626165565584},
61
+ {:date_time=>"2018-10-31T00:00:00.000Z", :dlr=>0.025732630512992103},
62
+ {:date_time=>"2018-10-30T00:00:00.000Z", :dlr=>0.004981915647820579},
63
+ {:date_time=>"2018-10-29T00:00:00.000Z", :dlr=>-0.018948623129528868},
64
+ {:date_time=>"2018-10-26T00:00:00.000Z", :dlr=>-0.0160517090105079},
65
+ {:date_time=>"2018-10-25T00:00:00.000Z", :dlr=>0.021661496781179467},
66
+ {:date_time=>"2018-10-24T00:00:00.000Z", :dlr=>-0.03490373037505153},
67
+ {:date_time=>"2018-10-23T00:00:00.000Z", :dlr=>0.009382539847836957},
68
+ {:date_time=>"2018-10-22T00:00:00.000Z", :dlr=>0.006091481696142526},
69
+ {:date_time=>"2018-10-19T00:00:00.000Z", :dlr=>0.01511525802908552},
70
+ {:date_time=>"2018-10-18T00:00:00.000Z", :dlr=>-0.023651064679340767},
71
+ {:date_time=>"2018-10-17T00:00:00.000Z", :dlr=>-0.0043307687122485835},
72
+ {:date_time=>"2018-10-16T00:00:00.000Z", :dlr=>0.02179786426382509},
73
+ {:date_time=>"2018-10-15T00:00:00.000Z", :dlr=>-0.021617789532325248},
74
+ {:date_time=>"2018-10-12T00:00:00.000Z", :dlr=>0.03509614368752819},
75
+ {:date_time=>"2018-10-11T00:00:00.000Z", :dlr=>-0.008867076040336814},
76
+ {:date_time=>"2018-10-10T00:00:00.000Z", :dlr=>-0.047433479205543055},
77
+ {:date_time=>"2018-10-09T00:00:00.000Z", :dlr=>0.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([], price_key: :close)}.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('dlr')
90
+ end
91
+
92
+ it 'Returns the name' do
93
+ indicator_name = indicator.indicator_name
94
+ expect(indicator_name).to eq('Daily Log Return')
95
+ end
96
+
97
+ it 'Returns the valid options' do
98
+ valid_options = indicator.valid_options
99
+ expect(valid_options).to eq(%i(price_key))
100
+ end
101
+
102
+ it 'Validates options' do
103
+ valid_options = { price_key: :close }
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