sqa 0.0.24 → 0.0.31

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 (180) hide show
  1. checksums.yaml +4 -4
  2. data/.goose/memory/development.txt +3 -0
  3. data/.semver +6 -0
  4. data/ARCHITECTURE.md +648 -0
  5. data/CHANGELOG.md +82 -0
  6. data/CLAUDE.md +653 -0
  7. data/COMMITS.md +196 -0
  8. data/DATAFRAME_ARCHITECTURE_REVIEW.md +421 -0
  9. data/NEXT-STEPS.md +154 -0
  10. data/README.md +812 -262
  11. data/TASKS.md +358 -0
  12. data/TEST_RESULTS.md +140 -0
  13. data/TODO.md +42 -0
  14. data/_notes.txt +25 -0
  15. data/bin/sqa-console +11 -0
  16. data/data/talk_talk.json +103284 -0
  17. data/develop_summary.md +313 -0
  18. data/docs/advanced/backtesting.md +206 -0
  19. data/docs/advanced/ensemble.md +68 -0
  20. data/docs/advanced/fpop.md +153 -0
  21. data/docs/advanced/index.md +112 -0
  22. data/docs/advanced/multi-timeframe.md +67 -0
  23. data/docs/advanced/pattern-matcher.md +75 -0
  24. data/docs/advanced/portfolio-optimizer.md +79 -0
  25. data/docs/advanced/portfolio.md +166 -0
  26. data/docs/advanced/risk-management.md +210 -0
  27. data/docs/advanced/strategy-generator.md +158 -0
  28. data/docs/advanced/streaming.md +209 -0
  29. data/docs/ai_and_ml.md +80 -0
  30. data/docs/api/dataframe.md +1115 -0
  31. data/docs/api/index.md +126 -0
  32. data/docs/assets/css/custom.css +88 -0
  33. data/docs/assets/js/mathjax.js +18 -0
  34. data/docs/concepts/index.md +68 -0
  35. data/docs/contributing/index.md +60 -0
  36. data/docs/data-sources/index.md +66 -0
  37. data/docs/data_frame.md +317 -97
  38. data/docs/factors_that_impact_price.md +26 -0
  39. data/docs/finviz.md +11 -0
  40. data/docs/fx_pro_bit.md +25 -0
  41. data/docs/genetic_programming.md +104 -0
  42. data/docs/getting-started/index.md +123 -0
  43. data/docs/getting-started/installation.md +229 -0
  44. data/docs/getting-started/quick-start.md +244 -0
  45. data/docs/i_gotta_an_idea.md +22 -0
  46. data/docs/index.md +163 -0
  47. data/docs/indicators/index.md +97 -0
  48. data/docs/indicators.md +110 -24
  49. data/docs/options.md +8 -0
  50. data/docs/strategies/bollinger-bands.md +146 -0
  51. data/docs/strategies/consensus.md +64 -0
  52. data/docs/strategies/custom.md +310 -0
  53. data/docs/strategies/ema.md +53 -0
  54. data/docs/strategies/index.md +92 -0
  55. data/docs/strategies/kbs.md +164 -0
  56. data/docs/strategies/macd.md +96 -0
  57. data/docs/strategies/market-profile.md +54 -0
  58. data/docs/strategies/mean-reversion.md +58 -0
  59. data/docs/strategies/rsi.md +95 -0
  60. data/docs/strategies/sma.md +55 -0
  61. data/docs/strategies/stochastic.md +63 -0
  62. data/docs/strategies/volume-breakout.md +54 -0
  63. data/docs/tags.md +7 -0
  64. data/docs/true_strength_index.md +46 -0
  65. data/docs/weighted_moving_average.md +48 -0
  66. data/examples/README.md +354 -0
  67. data/examples/advanced_features_example.rb +350 -0
  68. data/examples/fpop_analysis_example.rb +191 -0
  69. data/examples/genetic_programming_example.rb +148 -0
  70. data/examples/kbs_strategy_example.rb +208 -0
  71. data/examples/pattern_context_example.rb +300 -0
  72. data/examples/rails_app/Gemfile +34 -0
  73. data/examples/rails_app/README.md +416 -0
  74. data/examples/rails_app/app/assets/javascripts/application.js +107 -0
  75. data/examples/rails_app/app/assets/stylesheets/application.css +659 -0
  76. data/examples/rails_app/app/controllers/analysis_controller.rb +11 -0
  77. data/examples/rails_app/app/controllers/api/v1/stocks_controller.rb +227 -0
  78. data/examples/rails_app/app/controllers/application_controller.rb +22 -0
  79. data/examples/rails_app/app/controllers/backtest_controller.rb +11 -0
  80. data/examples/rails_app/app/controllers/dashboard_controller.rb +21 -0
  81. data/examples/rails_app/app/controllers/portfolio_controller.rb +7 -0
  82. data/examples/rails_app/app/views/analysis/show.html.erb +209 -0
  83. data/examples/rails_app/app/views/backtest/show.html.erb +171 -0
  84. data/examples/rails_app/app/views/dashboard/index.html.erb +118 -0
  85. data/examples/rails_app/app/views/dashboard/show.html.erb +408 -0
  86. data/examples/rails_app/app/views/errors/show.html.erb +17 -0
  87. data/examples/rails_app/app/views/layouts/application.html.erb +60 -0
  88. data/examples/rails_app/app/views/portfolio/index.html.erb +33 -0
  89. data/examples/rails_app/bin/rails +6 -0
  90. data/examples/rails_app/config/application.rb +45 -0
  91. data/examples/rails_app/config/boot.rb +5 -0
  92. data/examples/rails_app/config/database.yml +18 -0
  93. data/examples/rails_app/config/environment.rb +11 -0
  94. data/examples/rails_app/config/routes.rb +26 -0
  95. data/examples/rails_app/config.ru +8 -0
  96. data/examples/realtime_stream_example.rb +274 -0
  97. data/examples/sinatra_app/Gemfile +22 -0
  98. data/examples/sinatra_app/QUICKSTART.md +159 -0
  99. data/examples/sinatra_app/README.md +461 -0
  100. data/examples/sinatra_app/app.rb +344 -0
  101. data/examples/sinatra_app/config.ru +5 -0
  102. data/examples/sinatra_app/public/css/style.css +659 -0
  103. data/examples/sinatra_app/public/js/app.js +107 -0
  104. data/examples/sinatra_app/views/analyze.erb +306 -0
  105. data/examples/sinatra_app/views/backtest.erb +325 -0
  106. data/examples/sinatra_app/views/dashboard.erb +419 -0
  107. data/examples/sinatra_app/views/error.erb +58 -0
  108. data/examples/sinatra_app/views/index.erb +118 -0
  109. data/examples/sinatra_app/views/layout.erb +61 -0
  110. data/examples/sinatra_app/views/portfolio.erb +43 -0
  111. data/examples/strategy_generator_example.rb +346 -0
  112. data/hsa_portfolio.csv +11 -0
  113. data/justfile +0 -0
  114. data/lib/api/alpha_vantage_api.rb +462 -0
  115. data/lib/sqa/backtest.rb +329 -0
  116. data/lib/sqa/data_frame/alpha_vantage.rb +43 -65
  117. data/lib/sqa/data_frame/data.rb +92 -0
  118. data/lib/sqa/data_frame/yahoo_finance.rb +35 -43
  119. data/lib/sqa/data_frame.rb +148 -243
  120. data/lib/sqa/ensemble.rb +359 -0
  121. data/lib/sqa/fpop.rb +199 -0
  122. data/lib/sqa/gp.rb +259 -0
  123. data/lib/sqa/indicator.rb +5 -8
  124. data/lib/sqa/init.rb +15 -8
  125. data/lib/sqa/market_regime.rb +240 -0
  126. data/lib/sqa/multi_timeframe.rb +379 -0
  127. data/lib/sqa/pattern_matcher.rb +497 -0
  128. data/lib/sqa/portfolio.rb +260 -6
  129. data/lib/sqa/portfolio_optimizer.rb +377 -0
  130. data/lib/sqa/risk_manager.rb +442 -0
  131. data/lib/sqa/seasonal_analyzer.rb +209 -0
  132. data/lib/sqa/sector_analyzer.rb +300 -0
  133. data/lib/sqa/stock.rb +67 -125
  134. data/lib/sqa/strategy/bollinger_bands.rb +42 -0
  135. data/lib/sqa/strategy/consensus.rb +5 -2
  136. data/lib/sqa/strategy/kbs_strategy.rb +470 -0
  137. data/lib/sqa/strategy/macd.rb +46 -0
  138. data/lib/sqa/strategy/mp.rb +1 -1
  139. data/lib/sqa/strategy/stochastic.rb +60 -0
  140. data/lib/sqa/strategy/volume_breakout.rb +57 -0
  141. data/lib/sqa/strategy.rb +5 -0
  142. data/lib/sqa/strategy_generator.rb +947 -0
  143. data/lib/sqa/stream.rb +361 -0
  144. data/lib/sqa/version.rb +1 -7
  145. data/lib/sqa.rb +23 -16
  146. data/main.just +81 -0
  147. data/mkdocs.yml +288 -0
  148. data/trace.log +0 -0
  149. metadata +261 -51
  150. data/bin/sqa +0 -6
  151. data/lib/patches/dry-cli.rb +0 -228
  152. data/lib/sqa/activity.rb +0 -10
  153. data/lib/sqa/cli.rb +0 -62
  154. data/lib/sqa/commands/analysis.rb +0 -309
  155. data/lib/sqa/commands/base.rb +0 -139
  156. data/lib/sqa/commands/web.rb +0 -199
  157. data/lib/sqa/commands.rb +0 -22
  158. data/lib/sqa/constants.rb +0 -23
  159. data/lib/sqa/indicator/average_true_range.rb +0 -33
  160. data/lib/sqa/indicator/bollinger_bands.rb +0 -28
  161. data/lib/sqa/indicator/candlestick_pattern_recognizer.rb +0 -60
  162. data/lib/sqa/indicator/donchian_channel.rb +0 -29
  163. data/lib/sqa/indicator/double_top_bottom_pattern.rb +0 -34
  164. data/lib/sqa/indicator/elliott_wave_theory.rb +0 -57
  165. data/lib/sqa/indicator/exponential_moving_average.rb +0 -25
  166. data/lib/sqa/indicator/exponential_moving_average_trend.rb +0 -36
  167. data/lib/sqa/indicator/fibonacci_retracement.rb +0 -23
  168. data/lib/sqa/indicator/head_and_shoulders_pattern.rb +0 -26
  169. data/lib/sqa/indicator/market_profile.rb +0 -32
  170. data/lib/sqa/indicator/mean_reversion.rb +0 -37
  171. data/lib/sqa/indicator/momentum.rb +0 -28
  172. data/lib/sqa/indicator/moving_average_convergence_divergence.rb +0 -29
  173. data/lib/sqa/indicator/peaks_and_valleys.rb +0 -29
  174. data/lib/sqa/indicator/predict_next_value.rb +0 -202
  175. data/lib/sqa/indicator/relative_strength_index.rb +0 -47
  176. data/lib/sqa/indicator/simple_moving_average.rb +0 -24
  177. data/lib/sqa/indicator/simple_moving_average_trend.rb +0 -32
  178. data/lib/sqa/indicator/stochastic_oscillator.rb +0 -68
  179. data/lib/sqa/indicator/true_range.rb +0 -39
  180. data/lib/sqa/trade.rb +0 -26
data/lib/sqa/commands.rb DELETED
@@ -1,22 +0,0 @@
1
- # sqa/lib/sqa/commands.rb
2
-
3
- # Adds command options to SQA.config
4
- require_relative "plugin_manager"
5
-
6
- module SQA::Commands
7
- # Establish the command registry
8
- extend Dry::CLI::Registry
9
- end
10
-
11
- Commands = SQA::Commands
12
-
13
-
14
- load_these_first = [
15
- "#{__dir__}/commands/base.rb",
16
- ].each { |file| require_relative file }
17
-
18
- Dir.glob("#{__dir__}/commands/*.rb")
19
- .reject{|file| load_these_first.include? file}
20
- .each do |file|
21
- require_relative file
22
- end
data/lib/sqa/constants.rb DELETED
@@ -1,23 +0,0 @@
1
- # lib/sqa/constants.rb
2
-
3
- module SQA
4
- module Constants
5
- Signal = {
6
- hold: 0,
7
- buy: 1,
8
- sell: 2
9
- }.freeze
10
-
11
- Trend = {
12
- up: 0,
13
- down: 1
14
- }.freeze
15
-
16
- Swing = {
17
- valley: 0,
18
- peak: 1,
19
- }.freeze
20
- end
21
-
22
- include Constants
23
- end
@@ -1,33 +0,0 @@
1
- # lib/sqa/indicator/average_true_range.rb
2
-
3
- # See Also: true_range
4
-
5
- class SQA::Indicator; class << self
6
-
7
- def average_true_range(
8
- high_prices, # Array of the day's high price
9
- low_prices, # Array of the day's low price
10
- close_prices, # Array of the day's closing price
11
- period # Integer the number of days to consider
12
- )
13
- true_ranges = true_range(high_prices, low_prices, close_prices)
14
- atr_values = []
15
-
16
- window_span = period - 1
17
-
18
- true_ranges.size.times do |inx|
19
- start_inx = inx - window_span
20
- end_inx = start_inx + window_span
21
-
22
- start_inx = 0 if start_inx < 0
23
-
24
- window = true_ranges[start_inx..end_inx]
25
-
26
- atr_values << window.mean
27
- end
28
-
29
- atr_values # Array
30
- end
31
- alias_method :atr, :average_true_range
32
-
33
- end; end
@@ -1,28 +0,0 @@
1
- # lib/sqa/indicator/bollinger_bands.rb
2
-
3
- class SQA::Indicator; class << self
4
-
5
- def bollinger_bands(
6
- prices, # Array of prices
7
- period, # Integer number of entries to consider
8
- num_std_devs=2 # Integer number of standard deviations
9
- )
10
- moving_averages = simple_moving_average(prices, period)
11
- standard_deviations = []
12
-
13
- prices.each_cons(period) do |window|
14
- standard_deviation = Math.sqrt(window.map { |price| (price - moving_averages.last) ** 2 }.sum / period)
15
- standard_deviations << standard_deviation
16
- end
17
-
18
- upper_band = moving_averages.last + (num_std_devs * standard_deviations.last)
19
- lower_band = moving_averages.last - (num_std_devs * standard_deviations.last)
20
-
21
- {
22
- upper_band: upper_band, # Array
23
- lower_band: lower_band # Array
24
- }
25
- end
26
- alias_method :bb, :bollinger_bands
27
-
28
- end; end
@@ -1,60 +0,0 @@
1
- # lib/sqa/indicator/candlestick_pattern_recognizer.rb
2
-
3
- class SQA::Indicator; class << self
4
-
5
- def candlestick_pattern_recognizer(
6
- open_prices, # Array day's ppen price
7
- high_prices, # Array day's high price
8
- low_prices, # Array day's low price
9
- close_prices # Array day's closing price
10
- )
11
- patterns = []
12
-
13
- close_prices.each_with_index do |close, index|
14
- if index >= 2
15
- previous_close = close_prices[index - 1]
16
- previous_open = open_prices[index - 1]
17
- previous_high = high_prices[index - 1]
18
- previous_low = low_prices[index - 1]
19
-
20
- second_previous_close = close_prices[index - 2]
21
- second_previous_open = open_prices[index - 2]
22
- second_previous_high = high_prices[index - 2]
23
- second_previous_low = low_prices[index - 2]
24
-
25
- if close > previous_close &&
26
- previous_close < previous_open &&
27
- close < previous_open &&
28
- close > previous_low &&
29
- close > second_previous_close
30
- patterns << :bullish_engulfing
31
-
32
- elsif close < previous_close &&
33
- previous_close > previous_open &&
34
- close > previous_open &&
35
- close < previous_high &&
36
- close < second_previous_close
37
- patterns << :bearish_engulfing
38
-
39
- elsif close > previous_close &&
40
- previous_close < previous_open &&
41
- close < previous_open &&
42
- close < previous_low &&
43
- close < second_previous_close
44
- patterns << :bearish_harami
45
-
46
- elsif close < previous_close &&
47
- previous_close > previous_open &&
48
- close > previous_open &&
49
- close > previous_high &&
50
- close > second_previous_close
51
- patterns << :bullish_harami
52
- end
53
- end
54
- end
55
-
56
- patterns
57
- end
58
-
59
- end; end
60
-
@@ -1,29 +0,0 @@
1
- # lib/sqa/indicator/donchian_channel.rb
2
-
3
- class SQA::Indicator; class << self
4
-
5
- def donchian_channel(
6
- prices, # Array of prices
7
- period # Integer number of entries to consider
8
- )
9
- max = -999999999
10
- min = 999999999
11
- donchian_channel = []
12
-
13
- prices.each_with_index do |value, index|
14
- value = value.to_f
15
- max = value if value > max
16
- min = value if value < min
17
-
18
- if index >= period - 1
19
- donchian_channel << [max, min, (max + min) / 2]
20
- max = -999999999
21
- min = 999999999
22
- end
23
- end
24
-
25
- donchian_channel
26
- end
27
-
28
- end; end
29
-
@@ -1,34 +0,0 @@
1
- # lib/sqa/indicator/double_top_bottom_pattern.rb
2
-
3
- class SQA::Indicator; class << self
4
-
5
- def double_top_bottom_pattern(
6
- prices # Array of prices
7
- )
8
- return :no_pattern if prices.length < 5
9
-
10
- data = prices.last(5)
11
-
12
- first_peak = data[0]
13
- valley = data[1]
14
- second_peak = data[2]
15
- neckline = data[3]
16
- confirmation_price = data[4]
17
-
18
- if first_peak < second_peak &&
19
- valley > first_peak &&
20
- valley > second_peak &&
21
- confirmation_price < neckline
22
- :double_top
23
- elsif first_peak > second_peak &&
24
- valley < first_peak &&
25
- valley < second_peak &&
26
- confirmation_price > neckline
27
- :double_bottom
28
- else
29
- :no_pattern
30
- end
31
- end
32
-
33
- end; end
34
-
@@ -1,57 +0,0 @@
1
- # lib/sqa/indicator/elliott_wave_theory.rb
2
-
3
- # TIDI: This is very simplistic. It may be completely wrong even
4
- # as simplistic as it is. Consider using the sma_trend to
5
- # acquire the up and down patterns. Run those through a
6
- # classifier. Might even have to review the concept of a
7
- # trend with regard to varying the periods to turn
8
- # many small patterns into fewer larger patterns. Then
9
- # maybe the 12345 and abc patterns will be extractable.
10
- # On the whole I think the consensus is that EWT is not
11
- # that useful for predictive trading.
12
-
13
- class SQA::Indicator; class << self
14
-
15
- def elliott_wave_theory(
16
- prices # Array of prices
17
- )
18
- waves = []
19
- wave_start = 0
20
-
21
- (1..prices.length-2).each do |x|
22
- turning_point = prices[x] > prices[x-1] && prices[x] > prices[x+1] ||
23
- prices[x] < prices[x-1] && prices[x] < prices[x+1]
24
-
25
- if turning_point
26
- waves << prices[wave_start..x]
27
- wave_start = x + 1
28
- end
29
- end
30
-
31
- analysis = []
32
-
33
- waves.each do |wave|
34
- analysis << {
35
- wave: wave,
36
- pattern: ewt_identify_pattern(wave)
37
- }
38
- end
39
-
40
- analysis
41
- end
42
-
43
-
44
- private def ewt_identify_pattern(wave)
45
- if wave.length == 5
46
- :impulse
47
- elsif wave.length == 3
48
- :corrective_zigzag
49
- elsif wave.length > 5
50
- :corrective_complex
51
- else
52
- :unknown
53
- end
54
- end
55
-
56
- end; end
57
-
@@ -1,25 +0,0 @@
1
- # lib/sqa/indicator/exponential_moving_average.rb
2
-
3
- class SQA::Indicator; class << self
4
-
5
- def exponential_moving_average(
6
- prices, # Array of prices
7
- period # Integer number of entries to consider
8
- )
9
-
10
- ema_values = []
11
- ema_values << prices.first
12
-
13
- multiplier = (2.0 / (period + 1))
14
-
15
- (1...prices.length).each do |x|
16
- ema = (prices[x] - ema_values.last) * multiplier + ema_values.last
17
- ema_values << ema
18
- end
19
-
20
- ema_values
21
- end
22
- alias_method :ema, :exponential_moving_average
23
-
24
- end; end
25
-
@@ -1,36 +0,0 @@
1
- # lib/sqa/indicator/exponential_moving_average_trend.rb
2
-
3
- class SQA::Indicator; class << self
4
-
5
- def exponential_moving_average_trend(
6
- prices, # Array of prices
7
- period # Integer number of entries to consider
8
- )
9
-
10
- ema_values = exponential_moving_average(
11
- prices,
12
- period
13
- )
14
-
15
- last_ema = ema_values.last
16
- previous_ema = ema_values[-2]
17
-
18
- trend = if last_ema > previous_ema
19
- :up
20
- elsif last_ema < previous_ema
21
- :down
22
- else
23
- :neutral
24
- end
25
-
26
- {
27
- ema: ema_values,
28
- trend: trend,
29
- support: ema_values.min,
30
- resistance: ema_values.max
31
- }
32
- end
33
- alias_method :ema_trend, :exponential_moving_average_trend
34
-
35
- end; end
36
-
@@ -1,23 +0,0 @@
1
- # lib/sqa/indicator/fibonacci_retracement.rb
2
-
3
- class SQA::Indicator; class << self
4
-
5
- def fibonacci_retracement(
6
- swing_high, # Float peak price in a period - peak
7
- swing_low # Float bottom price in a period - valley
8
- )
9
- retracement_levels = []
10
-
11
- fibonacci_levels = [0.236, 0.382, 0.5, 0.618, 0.786]
12
-
13
- fibonacci_levels.each do |level|
14
- retracement_levels << swing_low + (swing_high - swing_low) * level
15
- end
16
-
17
-
18
- retracement_levels # Array
19
- end
20
- alias_method :fr, :fibonacci_retracement
21
-
22
- end; end
23
-
@@ -1,26 +0,0 @@
1
- # lib/sqa/indicator/head_and_shoulders_pattern.rb
2
-
3
- class SQA::Indicator; class << self
4
-
5
-
6
- def head_and_shoulders_pattern?(
7
- prices # Array of prices
8
- )
9
-
10
- return false if prices.length < 5
11
-
12
- data = prices.last(5)
13
-
14
- left_shoulder = data[0]
15
- head = data[1]
16
- right_shoulder = data[2]
17
- neckline = data[3]
18
- right_peak = data[4]
19
-
20
- head > left_shoulder &&
21
- head > right_shoulder &&
22
- right_peak < neckline
23
- end
24
-
25
- end; end
26
-
@@ -1,32 +0,0 @@
1
- # lib/sqa/indicator/market_profile.rb
2
-
3
- class SQA::Indicator; class << self
4
-
5
- def market_profile(
6
- volumes, # Array of volumes
7
- prices, # Array of prices
8
- support_threshold, # Float stock's support price estimate
9
- resistance_threshold # Float stock's resistance price estimate
10
- )
11
- total_volume = volumes.sum
12
- average_volume = volumes.mean
13
- max_volume = volumes.max
14
-
15
- support_levels = prices.select { |price| price <= support_threshold }
16
- resistance_levels = prices.select { |price| price >= resistance_threshold }
17
-
18
- if support_levels.empty? &&
19
- resistance_levels.empty?
20
- :neutral
21
- elsif support_levels.empty?
22
- :resistance
23
- elsif resistance_levels.empty?
24
- :support
25
- else
26
- :mixed
27
- end
28
- end
29
- alias_method :mp, :market_profile
30
-
31
- end; end
32
-
@@ -1,37 +0,0 @@
1
- # lib/sqa/indicator/mean_reversion.rb
2
-
3
- class SQA::Indicator; class << self
4
-
5
- # @param prices [Array]
6
- # @param lookback_period [Integer]
7
- # @param deviation_threshold [Float]
8
- #
9
- # @return [Boolean] True if the stock exhibits mean reversion behavior,
10
- # false otherwise.
11
- #
12
- def mean_reversion?(
13
- prices, # Array of prices
14
- lookback_period, # Integer number of events to consider
15
- deviation_threshold # Float delta change at which a price is considered to be over extended
16
- )
17
-
18
- return false if prices.length < lookback_period
19
-
20
- mean = mr_mean(prices, lookback_period)
21
- deviation = prices[-1] - mean
22
-
23
- if deviation.abs > deviation_threshold
24
- return true
25
- else
26
- return false
27
- end
28
- end
29
-
30
-
31
- def mr_mean(prices, lookback_period)
32
- prices.last(lookback_period).sum / lookback_period.to_f
33
- end
34
-
35
- end; end
36
-
37
-
@@ -1,28 +0,0 @@
1
- # lib/sqa/indicator/momentum.rb
2
-
3
- class SQA::Indicator; class << self
4
-
5
- # @param prices [Array]
6
- # @param period [Integer]
7
- #
8
- # @return [Float]
9
- #
10
- def momentum(
11
- prices, # Array of prices
12
- period # Integer number of entries to consider
13
- )
14
-
15
- momentums = []
16
-
17
- prices.each_cons(period) do |window|
18
- current_price = window.last.to_f
19
- past_price = window.first.to_f
20
- momentums << 10.0 * ( (current_price - past_price) / past_price)
21
- end
22
-
23
- momentums # Array
24
- end
25
- alias_method :m, :momentum
26
-
27
- end; end
28
-
@@ -1,29 +0,0 @@
1
- # lib/sqa/indicator/moving_average_convergence_divergence.rb
2
-
3
- class SQA::Indicator; class << self
4
-
5
- def moving_average_convergence_divergence(
6
- prices,
7
- short_period,
8
- long_period,
9
- signal_period
10
- )
11
-
12
- short_ma = simple_moving_average(prices, short_period)
13
- long_ma = simple_moving_average(prices, long_period)
14
- signal_line = simple_moving_average(short_ma, signal_period)
15
- macd_line = []
16
-
17
- prices.size.times do |x|
18
- macd_line << short_ma[x] - long_ma[x]
19
- end
20
-
21
- {
22
- macd: macd_line, # Array
23
- signal: signal_line # Array
24
- }
25
- end
26
- alias_method :macd, :moving_average_convergence_divergence
27
-
28
- end; end
29
-
@@ -1,29 +0,0 @@
1
-
2
- class SQA::Indicator; class << self
3
-
4
- def peaks_and_valleys(
5
- prices, # Array of prices
6
- delta # Integer distance delta (# of higher or lower prices to either side)
7
- )
8
- peaks = []
9
- valleys = []
10
- period = 2 * delta + 1
11
-
12
- prices.each_cons(period) do |window|
13
- price = window[delta]
14
-
15
- next if window.count(price) == period
16
-
17
- peaks << price if window.max == price
18
- valleys << price if window.min == price
19
- end
20
-
21
- {
22
- period: period,
23
- peaks: peaks,
24
- valleys: valleys
25
- }
26
- end
27
- alias_method :pav, :peaks_and_valleys
28
-
29
- end; end