ruby-technical-analysis 0.1.1 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/lib/ruby-technical-analysis.rb +1 -0
  3. data/lib/ruby_technical_analysis/indicator.rb +41 -0
  4. data/lib/ruby_technical_analysis/indicators/bollinger_bands.rb +50 -0
  5. data/lib/ruby_technical_analysis/indicators/chaikin_money_flow.rb +47 -0
  6. data/lib/ruby_technical_analysis/indicators/chande_momentum_oscillator.rb +56 -0
  7. data/lib/ruby_technical_analysis/indicators/commodity_channel_index.rb +70 -0
  8. data/lib/ruby_technical_analysis/indicators/envelopes_ema.rb +48 -0
  9. data/lib/ruby_technical_analysis/indicators/intraday_momentum_index.rb +45 -0
  10. data/lib/ruby_technical_analysis/indicators/macd.rb +86 -0
  11. data/lib/ruby_technical_analysis/indicators/mass_index.rb +70 -0
  12. data/lib/ruby_technical_analysis/indicators/moving_averages.rb +71 -0
  13. data/lib/ruby_technical_analysis/indicators/pivot_points.rb +75 -0
  14. data/lib/ruby_technical_analysis/indicators/price_channel.rb +48 -0
  15. data/lib/ruby_technical_analysis/indicators/qstick.rb +44 -0
  16. data/lib/ruby_technical_analysis/indicators/rate_of_change.rb +40 -0
  17. data/lib/ruby_technical_analysis/indicators/relative_momentum_index.rb +79 -0
  18. data/lib/ruby_technical_analysis/indicators/relative_strength_index.rb +74 -0
  19. data/lib/ruby_technical_analysis/indicators/statistical_methods.rb +40 -0
  20. data/lib/ruby_technical_analysis/indicators/stochastic_oscillator.rb +99 -0
  21. data/lib/ruby_technical_analysis/indicators/volume_oscillator.rb +50 -0
  22. data/lib/ruby_technical_analysis/indicators/volume_rate_of_change.rb +48 -0
  23. data/lib/ruby_technical_analysis/indicators/wilders_smoothing.rb +47 -0
  24. data/lib/ruby_technical_analysis/indicators/williams_percent_r.rb +69 -0
  25. data/lib/ruby_technical_analysis.rb +24 -7
  26. data/spec/ruby_technical_analysis/indicator_spec.rb +76 -0
  27. data/spec/ruby_technical_analysis/indicators/bollinger_bands_spec.rb +67 -0
  28. data/spec/ruby_technical_analysis/indicators/chaikin_money_flow_spec.rb +63 -0
  29. data/spec/ruby_technical_analysis/indicators/chande_momentum_oscillator_spec.rb +59 -0
  30. data/spec/ruby_technical_analysis/indicators/commodity_channel_index_spec.rb +66 -0
  31. data/spec/ruby_technical_analysis/indicators/envelopes_ema_spec.rb +69 -0
  32. data/spec/ruby_technical_analysis/indicators/intraday_momentum_spec.rb +63 -0
  33. data/spec/ruby_technical_analysis/indicators/macd_spec.rb +61 -0
  34. data/spec/ruby_technical_analysis/indicators/mass_index_spec.rb +67 -0
  35. data/spec/ruby_technical_analysis/indicators/moving_averages_spec.rb +81 -0
  36. data/spec/ruby_technical_analysis/indicators/pivot_points_spec.rb +43 -0
  37. data/spec/ruby_technical_analysis/indicators/price_channel_spec.rb +64 -0
  38. data/spec/ruby_technical_analysis/indicators/qstick_spec.rb +59 -0
  39. data/spec/ruby_technical_analysis/indicators/rate_of_change_spec.rb +59 -0
  40. data/spec/ruby_technical_analysis/indicators/relative_momentum_index_spec.rb +67 -0
  41. data/spec/ruby_technical_analysis/indicators/relative_strength_index_spec.rb +59 -0
  42. data/spec/ruby_technical_analysis/indicators/statistical_methods_spec.rb +91 -0
  43. data/spec/ruby_technical_analysis/indicators/stochastic_oscillator_spec.rb +106 -0
  44. data/spec/ruby_technical_analysis/indicators/volume_oscillator_spec.rb +98 -0
  45. data/spec/ruby_technical_analysis/indicators/volume_rate_of_change_spec.rb +67 -0
  46. data/spec/ruby_technical_analysis/indicators/wiilders_smoothing_spec.rb +67 -0
  47. data/spec/ruby_technical_analysis/indicators/williams_percent_r_spec.rb +71 -0
  48. data/spec/spec_helper.rb +1 -0
  49. metadata +100 -40
  50. data/.rubocop.yml +0 -34
  51. data/CHANGELOG.md +0 -5
  52. data/CODE_OF_CONDUCT.md +0 -84
  53. data/Gemfile +0 -12
  54. data/LICENSE.txt +0 -21
  55. data/README.md +0 -36
  56. data/Rakefile +0 -16
  57. data/lib/ruby-technical-analysis/indicators/bollinger_bands.rb +0 -25
  58. data/lib/ruby-technical-analysis/indicators/chaikin_money_flow.rb +0 -70
  59. data/lib/ruby-technical-analysis/indicators/chande_momentum_oscillator.rb +0 -34
  60. data/lib/ruby-technical-analysis/indicators/commodity_channel_index.rb +0 -64
  61. data/lib/ruby-technical-analysis/indicators/envelopes_ema.rb +0 -24
  62. data/lib/ruby-technical-analysis/indicators/intraday_momentum_index.rb +0 -48
  63. data/lib/ruby-technical-analysis/indicators/macd.rb +0 -47
  64. data/lib/ruby-technical-analysis/indicators/mass_index.rb +0 -73
  65. data/lib/ruby-technical-analysis/indicators/pivot_points.rb +0 -23
  66. data/lib/ruby-technical-analysis/indicators/price_channel.rb +0 -37
  67. data/lib/ruby-technical-analysis/indicators/qstick.rb +0 -40
  68. data/lib/ruby-technical-analysis/indicators/rate_of_change.rb +0 -18
  69. data/lib/ruby-technical-analysis/indicators/relative_momentum_index.rb +0 -66
  70. data/lib/ruby-technical-analysis/indicators/relative_strength_index.rb +0 -63
  71. data/lib/ruby-technical-analysis/indicators/stochastic_oscillator.rb +0 -65
  72. data/lib/ruby-technical-analysis/indicators/volume_oscillator.rb +0 -38
  73. data/lib/ruby-technical-analysis/indicators/volume_rate_of_change.rb +0 -26
  74. data/lib/ruby-technical-analysis/indicators/wilders_smoothing.rb +0 -27
  75. data/lib/ruby-technical-analysis/indicators/williams_percent_r.rb +0 -52
  76. data/lib/ruby-technical-analysis/moving_averages.rb +0 -85
  77. data/lib/ruby-technical-analysis/statistical_methods.rb +0 -24
  78. data/lib/ruby-technical-analysis/version.rb +0 -5
  79. data/sig/ruby-technical-analysis.rbs +0 -4
@@ -0,0 +1,76 @@
1
+ require "spec_helper"
2
+
3
+ module RubyTechnicalAnalysis
4
+ RSpec.describe Indicator do
5
+ describe "#initialize" do
6
+ series = [10, 20, 30, 40, 50]
7
+ indicator = described_class.new(series: series)
8
+
9
+ it "initializes with a series of series" do
10
+ expect(indicator.series).to eq(series)
11
+ end
12
+ end
13
+
14
+ describe "#call" do
15
+ it "is a class method" do
16
+ expect(described_class).to respond_to(:call)
17
+ end
18
+ end
19
+
20
+ # Private methods only tested for base class
21
+
22
+ describe "#extract_series" do
23
+ series = [10, 20, 30, 40, 50]
24
+ indicator = described_class.new(series: series)
25
+
26
+ it "extracts the series from the series" do
27
+ expect(indicator.send(:extract_series)).to eq(series)
28
+ end
29
+ end
30
+
31
+ describe "#extract_highs_lows_closes_volumes" do
32
+ highs = [1, 2, 3, 4, 5]
33
+ lows = [6, 7, 8, 9, 10]
34
+ closes = [11, 12, 13, 14, 15]
35
+ volumes = [100, 200, 300, 400, 500]
36
+
37
+ series = highs.zip(lows, closes, volumes)
38
+ indicator = described_class.new(series: series)
39
+
40
+ it "extracts the highs, lows, closes, and volumes from the series" do
41
+ expect(indicator.send(:extract_highs_lows_closes_volumes)).to eq([highs, lows, closes, volumes])
42
+ end
43
+ end
44
+
45
+ describe "#extract_highs_lows_closes" do
46
+ highs = [1, 2, 3, 4, 5]
47
+ lows = [6, 7, 8, 9, 10]
48
+ closes = [11, 12, 13, 14, 15]
49
+
50
+ series = highs.zip(lows, closes)
51
+ indicator = described_class.new(series: series)
52
+
53
+ it "extracts the highs, lows, and closes from the series" do
54
+ expect(indicator.send(:extract_highs_lows_closes)).to eq([highs, lows, closes])
55
+ end
56
+ end
57
+
58
+ describe "#moving_averages" do
59
+ series = [10, 20, 30, 40, 50]
60
+ indicator = described_class.new(series: series)
61
+
62
+ it "calculates moving averages" do
63
+ expect(indicator.send(:moving_averages, period: 3)).to be_a(RubyTechnicalAnalysis::MovingAverages)
64
+ end
65
+ end
66
+
67
+ describe "#statistical_methods" do
68
+ series = [10, 20, 30, 40, 50]
69
+ indicator = described_class.new(series: series)
70
+
71
+ it "performs statistical calculations" do
72
+ expect(indicator.send(:statistical_methods)).to be_a(RubyTechnicalAnalysis::StatisticalMethods)
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,67 @@
1
+ require "spec_helper"
2
+
3
+ module RubyTechnicalAnalysis
4
+ RSpec.describe BollingerBands do
5
+ let(:series) { [31.875, 32.125, 32.3125, 32.125, 31.875] }
6
+ let(:period) { 5 }
7
+
8
+ let(:bollinger_bands) { described_class.new(series: series, period: period) }
9
+
10
+ describe "#initialize" do
11
+ it "initializes the BollingerBands object" do
12
+ expect(bollinger_bands).to be_an_instance_of(described_class)
13
+ end
14
+
15
+ it "initializes with default period of 20" do
16
+ expect(described_class.new(series: series).period).to eq(20)
17
+ end
18
+
19
+ it "initializes with default standard deviations of 2" do
20
+ expect(described_class.new(series: series).standard_deviations).to eq(2)
21
+ end
22
+ end
23
+
24
+ describe "class methods" do
25
+ describe "#call" do
26
+ let(:bollinger_bands) { described_class.call(series: series, period: period) }
27
+
28
+ it "returns an array containing the current upper, middle, and lower bands of the series" do
29
+ expect(bollinger_bands).to eq([32.397, 32.062, 31.727])
30
+ end
31
+ end
32
+ end
33
+
34
+ describe "instance methods" do
35
+ describe "#call" do
36
+ it "returns an array containing the current upper, middle, and lower bands of the series" do
37
+ expect(bollinger_bands.call).to eq([32.397, 32.062, 31.727])
38
+ end
39
+ end
40
+
41
+ describe "#valid?" do
42
+ it "returns true when the period is less than or equal to the series length" do
43
+ expect(bollinger_bands.valid?).to be(true)
44
+ end
45
+
46
+ it "returns false when the period is greater than the series length" do
47
+ expect(described_class.new(series: series, period: 6).valid?).to be(false)
48
+ end
49
+
50
+ it "returns false when the standard deviations is less than or equal to 0" do
51
+ expect(described_class.new(series: series, standard_deviations: 0).valid?).to be(false)
52
+ end
53
+ end
54
+ end
55
+
56
+ describe "secondary series" do
57
+ series = [31.875, 32.125, 32.3125, 32.125, 31.875, 32.3125]
58
+ period = 5
59
+
60
+ expected_values = [32.508, 32.15, 31.791]
61
+
62
+ it "returns the expected values" do
63
+ expect(described_class.new(series: series, period: period).call).to eq(expected_values)
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,63 @@
1
+ require "spec_helper"
2
+
3
+ module RubyTechnicalAnalysis
4
+ RSpec.describe ChaikinMoneyFlow do
5
+ let(:series) {
6
+ [[8.625, 8.3125, 8.625, 4494], [8.625, 8.4375, 8.5, 2090], [8.625, 8.4375, 8.625, 1306],
7
+ [8.75, 8.625, 8.75, 4242], [8.75, 8.4375, 8.5, 2874]]
8
+ }
9
+ let(:period) { 5 }
10
+
11
+ let(:cmf) { described_class.new(series: series, period: period) }
12
+
13
+ describe "#initialize" do
14
+ it "initializes the ChaikinMoneyFlow object" do
15
+ expect(cmf).to be_an_instance_of(described_class)
16
+ end
17
+
18
+ it "initializes with default period of 21" do
19
+ expect(described_class.new(series: series).period).to eq(21)
20
+ end
21
+ end
22
+
23
+ describe "class methods" do
24
+ describe "#call" do
25
+ let(:cmf) { described_class.call(series: series, period: period) }
26
+
27
+ it "returns the ChaikinMoneyFlow value" do
28
+ expect(cmf.truncate(5)).to eq(0.50786)
29
+ end
30
+ end
31
+ end
32
+
33
+ describe "instance methods" do
34
+ describe "#call" do
35
+ it "returns the ChaikinMoneyFlow value" do
36
+ expect(cmf.call.truncate(5)).to eq(0.50786)
37
+ end
38
+ end
39
+
40
+ describe "#valid?" do
41
+ it "returns true when the period is less than or equal to the series length" do
42
+ expect(cmf.valid?).to be(true)
43
+ end
44
+
45
+ it "returns false when the period is greater than the series length" do
46
+ expect(described_class.new(series: series, period: 6).valid?).to be(false)
47
+ end
48
+ end
49
+ end
50
+
51
+ describe "secondary series" do
52
+ series = [[8.625, 8.3125, 8.625, 4494], [8.625, 8.4375, 8.5, 2090], [8.625, 8.4375, 8.625, 1306],
53
+ [8.75, 8.625, 8.75, 4242], [8.75, 8.4375, 8.5, 2874], [8.5625, 8.5, 8.5, 598]]
54
+ period = 5
55
+
56
+ expected_value = 0.22763
57
+
58
+ it "returns the expected value" do
59
+ expect(described_class.new(series: series, period: period).call.truncate(5)).to eq(expected_value)
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,59 @@
1
+ require "spec_helper"
2
+
3
+ module RubyTechnicalAnalysis
4
+ RSpec.describe ChandeMomentumOscillator do
5
+ let(:series) { [51.0625, 50.125, 52.3125, 52.1875, 53.1875, 53.0625] }
6
+ let(:period) { 5 }
7
+
8
+ let(:oscillator) { described_class.new(series: series, period: period) }
9
+
10
+ describe "#initialize" do
11
+ it "initializes the ChandeMomentumOscillator object" do
12
+ expect(oscillator).to be_an_instance_of(described_class)
13
+ end
14
+
15
+ it "initializes with default period of 20" do
16
+ expect(described_class.new(series: series).period).to eq(20)
17
+ end
18
+ end
19
+
20
+ describe "class methods" do
21
+ describe "#call" do
22
+ let(:oscillator) { described_class.call(series: series, period: period) }
23
+
24
+ it "returns the ChandeMomentumOscillator value" do
25
+ expect(oscillator.truncate(4)).to eq(45.7143)
26
+ end
27
+ end
28
+ end
29
+
30
+ describe "instance methods" do
31
+ describe "#call" do
32
+ it "returns the ChandeMomentumOscillator value" do
33
+ expect(oscillator.call.truncate(4)).to eq(45.7143)
34
+ end
35
+ end
36
+
37
+ describe "#valid?" do
38
+ it "returns true when the period is less than or equal to the series length" do
39
+ expect(oscillator.valid?).to be(true)
40
+ end
41
+
42
+ it "returns false when the period is greater than the series length" do
43
+ expect(described_class.new(series: series, period: 6).valid?).to be(false)
44
+ end
45
+ end
46
+ end
47
+
48
+ describe "secondary series" do
49
+ series = [51.0625, 50.125, 52.3125, 52.1875, 53.1875, 53.0625, 54.0625]
50
+ period = 5
51
+
52
+ expected_value = 88.7324
53
+
54
+ it "returns the expected value" do
55
+ expect(described_class.new(series: series, period: period).call.truncate(4)).to eq(expected_value)
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,66 @@
1
+ require "spec_helper"
2
+
3
+ module RubyTechnicalAnalysis
4
+ RSpec.describe CommodityChannelIndex do
5
+ let(:series) {
6
+ [[15.125, 14.936, 14.936], [15.052, 14.6267, 14.752], [14.8173, 14.5557, 14.5857],
7
+ [14.69, 14.46, 14.6], [14.7967, 14.5483, 14.6983], [14.7940, 13.9347, 13.946],
8
+ [14.093, 13.8223, 13.9827], [14.7, 14.02, 14.45], [14.5255, 14.2652, 14.3452]]
9
+ }
10
+ let(:period) { 5 }
11
+
12
+ let(:cci) { described_class.new(series: series, period: period) }
13
+
14
+ describe "#initialize" do
15
+ it "initializes the CommodityChannelIndex object" do
16
+ expect(cci).to be_an_instance_of(described_class)
17
+ end
18
+
19
+ it "initializes with default period of 20" do
20
+ expect(described_class.new(series: series).period).to eq(20)
21
+ end
22
+ end
23
+
24
+ describe "class methods" do
25
+ describe "#call" do
26
+ let(:cci) { described_class.call(series: series, period: period) }
27
+
28
+ it "returns the CommodityChannelIndex value" do
29
+ expect(cci.truncate(4)).to eq(18.089)
30
+ end
31
+ end
32
+ end
33
+
34
+ describe "instance methods" do
35
+ describe "#call" do
36
+ it "returns the CommodityChannelIndex value" do
37
+ expect(cci.call.truncate(4)).to eq(18.089)
38
+ end
39
+ end
40
+
41
+ describe "#valid?" do
42
+ it "returns true when the series is valid" do
43
+ expect(cci.valid?).to be_truthy
44
+ end
45
+
46
+ it "returns false when the series is not valid" do
47
+ expect(described_class.new(series: [], period: period).valid?).to be(false)
48
+ end
49
+ end
50
+ end
51
+
52
+ describe "secondary series" do
53
+ series = [[15.125, 14.936, 14.936], [15.052, 14.6267, 14.752], [14.8173, 14.5557, 14.5857],
54
+ [14.69, 14.46, 14.6], [14.7967, 14.5483, 14.6983], [14.794, 13.9347, 13.946],
55
+ [14.093, 13.8223, 13.9827], [14.7, 14.02, 14.45], [14.5255, 14.2652, 14.3452],
56
+ [14.6579, 14.3773, 14.4197]]
57
+ period = 5
58
+
59
+ expected_value = 84.4605
60
+
61
+ it "returns the expected value" do
62
+ expect(described_class.new(series: series, period: period).call.truncate(4)).to eq(expected_value)
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,69 @@
1
+ require "spec_helper"
2
+
3
+ module RubyTechnicalAnalysis
4
+ RSpec.describe EnvelopesEma do
5
+ let(:series) { [25, 24.875, 24.781, 24.594, 24.5] }
6
+ let(:period) { 5 }
7
+ let(:percent) { 20 }
8
+
9
+ let(:envelopes_ema) { described_class.new(series: series, period: period, percent: 20) }
10
+
11
+ describe "#initialize" do
12
+ it "initializes the EnvelopesEma object" do
13
+ expect(envelopes_ema).to be_an_instance_of(described_class)
14
+ end
15
+
16
+ it "initializes with default period of 20" do
17
+ expect(described_class.new(series: series).period).to eq(20)
18
+ end
19
+
20
+ it "initializes with default percent of 5" do
21
+ expect(described_class.new(series: series).percent).to eq(5)
22
+ end
23
+ end
24
+
25
+ describe "class methods" do
26
+ describe "#call" do
27
+ let(:envelopes_ema) { described_class.call(series: series, period: period, percent: 20) }
28
+
29
+ it "returns an array containing the current upper, middle, and lower bands of the series" do
30
+ expect(envelopes_ema).to eq([29.637, 24.698, 19.758])
31
+ end
32
+ end
33
+ end
34
+
35
+ describe "instance methods" do
36
+ describe "#call" do
37
+ it "returns an array containing the current upper, middle, and lower bands of the series" do
38
+ expect(envelopes_ema.call).to eq([29.637, 24.698, 19.758])
39
+ end
40
+ end
41
+
42
+ describe "#valid?" do
43
+ it "returns true when the series is valid" do
44
+ expect(envelopes_ema.valid?).to be(true)
45
+ end
46
+
47
+ it "returns false when the series is not valid" do
48
+ expect(described_class.new(series: [], period: period, percent: percent).valid?).to be(false)
49
+ end
50
+
51
+ it "returns false when the percent is greater than 100" do
52
+ expect(described_class.new(series: series, period: period, percent: 101).valid?).to be(false)
53
+ end
54
+ end
55
+ end
56
+
57
+ describe "secondary series" do
58
+ series = [25, 24.875, 24.781, 24.594, 24.5, 24.625]
59
+ period = 5
60
+ percent = 20
61
+
62
+ expected_values = [29.588, 24.657, 19.725]
63
+
64
+ it "returns the expected values" do
65
+ expect(described_class.new(series: series, period: period, percent: percent).call).to eq(expected_values)
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,63 @@
1
+ require "spec_helper"
2
+
3
+ module RubyTechnicalAnalysis
4
+ RSpec.describe IntradayMomentumIndex do
5
+ let(:series) {
6
+ [[18.4833, 18.5], [18.5417, 18.4167], [18.4167, 18.1667], [18.1667, 18.125], [18.1667, 17.9583],
7
+ [18.0417, 18], [18, 17.9583], [17.9167, 17.8333], [17.7917, 17.9583]]
8
+ }
9
+ let(:period) { 7 }
10
+
11
+ let(:imi) { described_class.new(series: series, period: period) }
12
+
13
+ describe "#initialize" do
14
+ it "initializes the IntradayMomentumIndex object" do
15
+ expect(imi).to be_an_instance_of(described_class)
16
+ end
17
+
18
+ it "initializes with default period of 14" do
19
+ expect(described_class.new(series: series).period).to eq(14)
20
+ end
21
+ end
22
+
23
+ describe "class methods" do
24
+ describe "#call" do
25
+ let(:imi) { described_class.call(series: series, period: period) }
26
+
27
+ it "returns the IntradayMomentumIndex value" do
28
+ expect(imi).to eq(19.988)
29
+ end
30
+ end
31
+ end
32
+
33
+ describe "instance methods" do
34
+ describe "#call" do
35
+ it "returns the IntradayMomentumIndex value" do
36
+ expect(imi.call).to eq(19.988)
37
+ end
38
+ end
39
+
40
+ describe "#valid?" do
41
+ it "returns true when the series is valid" do
42
+ expect(imi.valid?).to be(true)
43
+ end
44
+
45
+ it "returns false when the series is not valid" do
46
+ expect(described_class.new(series: [], period: period).valid?).to be(false)
47
+ end
48
+ end
49
+ end
50
+
51
+ describe "secondary series" do
52
+ series = [[18.4833, 18.5], [18.5417, 18.4167], [18.4167, 18.1667], [18.1667, 18.125], [18.1667, 17.9583],
53
+ [18.0417, 18], [18, 17.9583], [17.9167, 17.8333], [17.7917, 17.9583], [18.0417, 18.5417]]
54
+ period = 7
55
+
56
+ expected_value = 61.5228
57
+
58
+ it "returns the expected value" do
59
+ expect(described_class.new(series: series, period: period).call).to eq(expected_value)
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,61 @@
1
+ require "spec_helper"
2
+
3
+ module RubyTechnicalAnalysis
4
+ RSpec.describe Macd do
5
+ let(:series) {
6
+ [166.23, 164.51, 162.41, 161.62, 159.78, 159.69, 159.22, 170.33,
7
+ 174.78, 174.61, 175.84, 172.9, 172.39, 171.66, 174.83, 176.28,
8
+ 172.12, 168.64, 168.88, 172.79, 172.55, 168.88, 167.3, 164.32,
9
+ 160.07, 162.74, 164.85, 165.12, 163.2, 166.56, 166.23, 163.17,
10
+ 159.3, 157.44, 162.95]
11
+ }
12
+
13
+ let(:macd) { described_class.new(series: series) }
14
+
15
+ describe "#initialize" do
16
+ it "initializes the Macd object" do
17
+ expect(macd).to be_an_instance_of(described_class)
18
+ end
19
+
20
+ it "initializes with default fast_period of 12" do
21
+ expect(described_class.new(series: series).fast_period).to eq(12)
22
+ end
23
+
24
+ it "initializes with default slow_period of 26" do
25
+ expect(described_class.new(series: series).slow_period).to eq(26)
26
+ end
27
+
28
+ it "initializes with default signal_period of 9" do
29
+ expect(described_class.new(series: series).signal_period).to eq(9)
30
+ end
31
+ end
32
+
33
+ describe "class methods" do
34
+ describe "#call" do
35
+ let(:macd) { described_class.call(series: series) }
36
+
37
+ it "returns an array containing the current upper, middle, and lower bands of the series" do
38
+ expect(macd).to eq([-1.934, -1.664, -0.27])
39
+ end
40
+ end
41
+ end
42
+
43
+ describe "instance methods" do
44
+ describe "#call" do
45
+ it "returns an array containing the current upper, middle, and lower bands of the series" do
46
+ expect(macd.call).to eq([-1.934, -1.664, -0.27])
47
+ end
48
+ end
49
+
50
+ describe "#valid?" do
51
+ it "returns true when the series is valid" do
52
+ expect(macd.valid?).to be(true)
53
+ end
54
+
55
+ it "returns false when the series is not valid" do
56
+ expect(described_class.new(series: [], fast_period: 12, slow_period: 26, signal_period: 9).valid?).to be(false)
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,67 @@
1
+ require "spec_helper"
2
+
3
+ module RubyTechnicalAnalysis
4
+ RSpec.describe MassIndex do
5
+ let(:series) {
6
+ [[38.125, 37.75], [38, 37.75], [37.9375, 37.8125], [37.875, 37.625], [38.125, 37.5],
7
+ [38.125, 37.5], [37.75, 37.5], [37.625, 37.4375], [37.6875, 37.375], [37.5, 37.375],
8
+ [37.5625, 37.375], [37.625, 36.8125], [36.6875, 36.3125], [36.875, 36.25], [36.9375, 36.5],
9
+ [36.5, 36.25], [36.9375, 36.3125], [37, 36.625], [36.875, 36.5625]]
10
+ }
11
+ let(:period) { 9 }
12
+
13
+ let(:mass_index) { described_class.new(series: series, period: period) }
14
+
15
+ describe "#initialize" do
16
+ it "initializes the MassIndex object" do
17
+ expect(mass_index).to be_an_instance_of(described_class)
18
+ end
19
+
20
+ it "initializes with default period of 9" do
21
+ expect(described_class.new(series: series).period).to eq(9)
22
+ end
23
+ end
24
+
25
+ describe "class methods" do
26
+ describe "#call" do
27
+ let(:mass_index) { described_class.call(series: series, period: period) }
28
+
29
+ it "returns the MassIndex value" do
30
+ expect(mass_index).to eq(3.2236)
31
+ end
32
+ end
33
+ end
34
+
35
+ describe "instance methods" do
36
+ describe "#call" do
37
+ it "returns the MassIndex value" do
38
+ expect(mass_index.call).to eq(3.2236)
39
+ end
40
+ end
41
+
42
+ describe "#valid?" do
43
+ it "returns true when the series is valid" do
44
+ expect(mass_index.valid?).to be(true)
45
+ end
46
+
47
+ it "returns false when the series is not valid" do
48
+ expect(described_class.new(series: [], period: period).valid?).to be(false)
49
+ end
50
+ end
51
+ end
52
+
53
+ describe "secondary series" do
54
+ series = [[38.125, 37.75], [38, 37.75], [37.9375, 37.8125], [37.875, 37.625], [38.125, 37.5],
55
+ [38.125, 37.5], [37.75, 37.75], [37.625, 37.4375], [37.6875, 37.375], [37.75, 37.375],
56
+ [37.5625, 37.375], [37.625, 36.8125], [36.6875, 36.3125], [36.875, 36.25], [36.9375, 36.5],
57
+ [36.5, 36.25], [36.9375, 36.3125], [37, 36.625], [36.875, 36.5625], [36.8125, 36.375]]
58
+ period = 9
59
+
60
+ expected_value = 3.1387
61
+
62
+ it "returns the expected value" do
63
+ expect(described_class.new(series: series, period: period).call).to eq(expected_value)
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,81 @@
1
+ require "spec_helper"
2
+
3
+ module RubyTechnicalAnalysis
4
+ RSpec.describe MovingAverages do
5
+ let(:series) { [25, 24.875, 24.781, 24.594, 24.5] }
6
+ let(:period) { 5 }
7
+
8
+ let(:moving_averages) { described_class.new(series: series, period: period) }
9
+
10
+ describe "#initialize" do
11
+ it "initializes the MovingAverages object" do
12
+ expect(moving_averages).to be_an_instance_of(described_class)
13
+ end
14
+
15
+ it "initializes with default period of 20" do
16
+ expect(described_class.new(series: series).period).to eq(20)
17
+ end
18
+ end
19
+
20
+ describe "#sma" do
21
+ it "returns the simple moving average value" do
22
+ expect(moving_averages.sma.round(3)).to eq(24.75)
23
+ end
24
+
25
+ describe "secondary series" do
26
+ series = [25, 24.875, 24.781, 24.594, 24.5, 24.625]
27
+ period = 5
28
+
29
+ expected_value = 24.675
30
+
31
+ it "returns the expected value" do
32
+ expect(described_class.new(series: series, period: period).sma).to eq(expected_value)
33
+ end
34
+ end
35
+ end
36
+
37
+ describe "#ema" do
38
+ it "returns the exponential moving average value" do
39
+ expect(moving_averages.ema.round(3)).to eq(24.698)
40
+ end
41
+
42
+ describe "secondary series" do
43
+ series = [25, 24.875, 24.781, 24.594, 24.5, 24.625]
44
+ period = 5
45
+
46
+ expected_value = 24.657
47
+
48
+ it "returns the expected value" do
49
+ expect(described_class.new(series: series, period: period).ema.round(3)).to eq(expected_value)
50
+ end
51
+ end
52
+ end
53
+
54
+ describe "#wma" do
55
+ it "returns the weighted moving average value" do
56
+ expect(moving_averages.wma.round(3)).to eq(24.665)
57
+ end
58
+
59
+ describe "secondary series" do
60
+ series = [25, 24.875, 24.781, 24.594, 24.5, 24.625]
61
+ period = 5
62
+
63
+ expected_value = 24.623
64
+
65
+ it "returns the expected value" do
66
+ expect(described_class.new(series: series, period: period).wma.round(3)).to eq(expected_value)
67
+ end
68
+ end
69
+ end
70
+
71
+ describe "#valid?" do
72
+ it "returns true when the series is valid" do
73
+ expect(moving_averages.valid?).to be(true)
74
+ end
75
+
76
+ it "returns false when the series is not valid" do
77
+ expect(described_class.new(series: [], period: period).valid?).to be(false)
78
+ end
79
+ end
80
+ end
81
+ end