technical-analysis 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/technical-analysis.rb +3 -0
- data/lib/technical_analysis.rb +41 -0
- data/lib/technical_analysis/helpers/array_helper.rb +27 -0
- data/lib/technical_analysis/helpers/stock_calculation.rb +25 -0
- data/lib/technical_analysis/helpers/validation.rb +33 -0
- data/lib/technical_analysis/indicators/adi.rb +101 -0
- data/lib/technical_analysis/indicators/adtv.rb +98 -0
- data/lib/technical_analysis/indicators/adx.rb +168 -0
- data/lib/technical_analysis/indicators/ao.rb +105 -0
- data/lib/technical_analysis/indicators/atr.rb +109 -0
- data/lib/technical_analysis/indicators/bb.rb +126 -0
- data/lib/technical_analysis/indicators/cci.rb +105 -0
- data/lib/technical_analysis/indicators/cmf.rb +105 -0
- data/lib/technical_analysis/indicators/cr.rb +95 -0
- data/lib/technical_analysis/indicators/dc.rb +108 -0
- data/lib/technical_analysis/indicators/dlr.rb +97 -0
- data/lib/technical_analysis/indicators/dpo.rb +106 -0
- data/lib/technical_analysis/indicators/dr.rb +96 -0
- data/lib/technical_analysis/indicators/eom.rb +104 -0
- data/lib/technical_analysis/indicators/fi.rb +95 -0
- data/lib/technical_analysis/indicators/ichimoku.rb +179 -0
- data/lib/technical_analysis/indicators/indicator.rb +138 -0
- data/lib/technical_analysis/indicators/kc.rb +124 -0
- data/lib/technical_analysis/indicators/kst.rb +132 -0
- data/lib/technical_analysis/indicators/macd.rb +144 -0
- data/lib/technical_analysis/indicators/mfi.rb +119 -0
- data/lib/technical_analysis/indicators/mi.rb +121 -0
- data/lib/technical_analysis/indicators/nvi.rb +102 -0
- data/lib/technical_analysis/indicators/obv.rb +104 -0
- data/lib/technical_analysis/indicators/obv_mean.rb +110 -0
- data/lib/technical_analysis/indicators/rsi.rb +133 -0
- data/lib/technical_analysis/indicators/sma.rb +98 -0
- data/lib/technical_analysis/indicators/sr.rb +122 -0
- data/lib/technical_analysis/indicators/trix.rb +127 -0
- data/lib/technical_analysis/indicators/tsi.rb +139 -0
- data/lib/technical_analysis/indicators/uo.rb +130 -0
- data/lib/technical_analysis/indicators/vi.rb +117 -0
- data/lib/technical_analysis/indicators/vpt.rb +95 -0
- data/lib/technical_analysis/indicators/wr.rb +103 -0
- data/spec/helpers/array_helper_spec.rb +31 -0
- data/spec/helpers/validaton_spec.rb +22 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/ta_test_data.csv +64 -0
- data/spec/technical_analysis/indicators/adi_spec.rb +116 -0
- data/spec/technical_analysis/indicators/adtv_spec.rb +98 -0
- data/spec/technical_analysis/indicators/adx_spec.rb +92 -0
- data/spec/technical_analysis/indicators/ao_spec.rb +86 -0
- data/spec/technical_analysis/indicators/atr_spec.rb +105 -0
- data/spec/technical_analysis/indicators/bb_spec.rb +100 -0
- data/spec/technical_analysis/indicators/cci_spec.rb +100 -0
- data/spec/technical_analysis/indicators/cmf_spec.rb +100 -0
- data/spec/technical_analysis/indicators/cr_spec.rb +119 -0
- data/spec/technical_analysis/indicators/dc_spec.rb +100 -0
- data/spec/technical_analysis/indicators/dlr_spec.rb +119 -0
- data/spec/technical_analysis/indicators/dpo_spec.rb +90 -0
- data/spec/technical_analysis/indicators/dr_spec.rb +119 -0
- data/spec/technical_analysis/indicators/eom_spec.rb +105 -0
- data/spec/technical_analysis/indicators/fi_spec.rb +118 -0
- data/spec/technical_analysis/indicators/ichimoku_spec.rb +95 -0
- data/spec/technical_analysis/indicators/indicator_spec.rb +120 -0
- data/spec/technical_analysis/indicators/kc_spec.rb +110 -0
- data/spec/technical_analysis/indicators/kst_spec.rb +78 -0
- data/spec/technical_analysis/indicators/macd_spec.rb +86 -0
- data/spec/technical_analysis/indicators/mfi_spec.rb +105 -0
- data/spec/technical_analysis/indicators/mi_spec.rb +79 -0
- data/spec/technical_analysis/indicators/nvi_spec.rb +119 -0
- data/spec/technical_analysis/indicators/obv_mean_spec.rb +109 -0
- data/spec/technical_analysis/indicators/obv_spec.rb +119 -0
- data/spec/technical_analysis/indicators/rsi_spec.rb +105 -0
- data/spec/technical_analysis/indicators/sma_spec.rb +115 -0
- data/spec/technical_analysis/indicators/sr_spec.rb +104 -0
- data/spec/technical_analysis/indicators/trix_spec.rb +76 -0
- data/spec/technical_analysis/indicators/tsi_spec.rb +87 -0
- data/spec/technical_analysis/indicators/uo_spec.rb +91 -0
- data/spec/technical_analysis/indicators/vi_spec.rb +105 -0
- data/spec/technical_analysis/indicators/vpt_spec.rb +118 -0
- data/spec/technical_analysis/indicators/wr_spec.rb +106 -0
- 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
|