sqa 0.0.22 → 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 (183) 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 +86 -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 +833 -213
  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/checksums/sqa-0.0.23.gem.sha512 +1 -0
  17. data/checksums/sqa-0.0.24.gem.sha512 +1 -0
  18. data/data/talk_talk.json +103284 -0
  19. data/develop_summary.md +313 -0
  20. data/docs/advanced/backtesting.md +206 -0
  21. data/docs/advanced/ensemble.md +68 -0
  22. data/docs/advanced/fpop.md +153 -0
  23. data/docs/advanced/index.md +112 -0
  24. data/docs/advanced/multi-timeframe.md +67 -0
  25. data/docs/advanced/pattern-matcher.md +75 -0
  26. data/docs/advanced/portfolio-optimizer.md +79 -0
  27. data/docs/advanced/portfolio.md +166 -0
  28. data/docs/advanced/risk-management.md +210 -0
  29. data/docs/advanced/strategy-generator.md +158 -0
  30. data/docs/advanced/streaming.md +209 -0
  31. data/docs/ai_and_ml.md +80 -0
  32. data/docs/api/dataframe.md +1115 -0
  33. data/docs/api/index.md +126 -0
  34. data/docs/assets/css/custom.css +88 -0
  35. data/docs/assets/js/mathjax.js +18 -0
  36. data/docs/concepts/index.md +68 -0
  37. data/docs/contributing/index.md +60 -0
  38. data/docs/data-sources/index.md +66 -0
  39. data/docs/data_frame.md +317 -97
  40. data/docs/factors_that_impact_price.md +26 -0
  41. data/docs/finviz.md +11 -0
  42. data/docs/fx_pro_bit.md +25 -0
  43. data/docs/genetic_programming.md +104 -0
  44. data/docs/getting-started/index.md +123 -0
  45. data/docs/getting-started/installation.md +229 -0
  46. data/docs/getting-started/quick-start.md +244 -0
  47. data/docs/i_gotta_an_idea.md +22 -0
  48. data/docs/index.md +163 -0
  49. data/docs/indicators/index.md +97 -0
  50. data/docs/indicators.md +110 -24
  51. data/docs/options.md +8 -0
  52. data/docs/strategies/bollinger-bands.md +146 -0
  53. data/docs/strategies/consensus.md +64 -0
  54. data/docs/strategies/custom.md +310 -0
  55. data/docs/strategies/ema.md +53 -0
  56. data/docs/strategies/index.md +92 -0
  57. data/docs/strategies/kbs.md +164 -0
  58. data/docs/strategies/macd.md +96 -0
  59. data/docs/strategies/market-profile.md +54 -0
  60. data/docs/strategies/mean-reversion.md +58 -0
  61. data/docs/strategies/rsi.md +95 -0
  62. data/docs/strategies/sma.md +55 -0
  63. data/docs/strategies/stochastic.md +63 -0
  64. data/docs/strategies/volume-breakout.md +54 -0
  65. data/docs/ta_lib.md +160 -0
  66. data/docs/tags.md +7 -0
  67. data/docs/true_strength_index.md +46 -0
  68. data/docs/weighted_moving_average.md +48 -0
  69. data/examples/README.md +354 -0
  70. data/examples/advanced_features_example.rb +350 -0
  71. data/examples/fpop_analysis_example.rb +191 -0
  72. data/examples/genetic_programming_example.rb +148 -0
  73. data/examples/kbs_strategy_example.rb +208 -0
  74. data/examples/pattern_context_example.rb +300 -0
  75. data/examples/rails_app/Gemfile +34 -0
  76. data/examples/rails_app/README.md +416 -0
  77. data/examples/rails_app/app/assets/javascripts/application.js +107 -0
  78. data/examples/rails_app/app/assets/stylesheets/application.css +659 -0
  79. data/examples/rails_app/app/controllers/analysis_controller.rb +11 -0
  80. data/examples/rails_app/app/controllers/api/v1/stocks_controller.rb +227 -0
  81. data/examples/rails_app/app/controllers/application_controller.rb +22 -0
  82. data/examples/rails_app/app/controllers/backtest_controller.rb +11 -0
  83. data/examples/rails_app/app/controllers/dashboard_controller.rb +21 -0
  84. data/examples/rails_app/app/controllers/portfolio_controller.rb +7 -0
  85. data/examples/rails_app/app/views/analysis/show.html.erb +209 -0
  86. data/examples/rails_app/app/views/backtest/show.html.erb +171 -0
  87. data/examples/rails_app/app/views/dashboard/index.html.erb +118 -0
  88. data/examples/rails_app/app/views/dashboard/show.html.erb +408 -0
  89. data/examples/rails_app/app/views/errors/show.html.erb +17 -0
  90. data/examples/rails_app/app/views/layouts/application.html.erb +60 -0
  91. data/examples/rails_app/app/views/portfolio/index.html.erb +33 -0
  92. data/examples/rails_app/bin/rails +6 -0
  93. data/examples/rails_app/config/application.rb +45 -0
  94. data/examples/rails_app/config/boot.rb +5 -0
  95. data/examples/rails_app/config/database.yml +18 -0
  96. data/examples/rails_app/config/environment.rb +11 -0
  97. data/examples/rails_app/config/routes.rb +26 -0
  98. data/examples/rails_app/config.ru +8 -0
  99. data/examples/realtime_stream_example.rb +274 -0
  100. data/examples/sinatra_app/Gemfile +22 -0
  101. data/examples/sinatra_app/QUICKSTART.md +159 -0
  102. data/examples/sinatra_app/README.md +461 -0
  103. data/examples/sinatra_app/app.rb +344 -0
  104. data/examples/sinatra_app/config.ru +5 -0
  105. data/examples/sinatra_app/public/css/style.css +659 -0
  106. data/examples/sinatra_app/public/js/app.js +107 -0
  107. data/examples/sinatra_app/views/analyze.erb +306 -0
  108. data/examples/sinatra_app/views/backtest.erb +325 -0
  109. data/examples/sinatra_app/views/dashboard.erb +419 -0
  110. data/examples/sinatra_app/views/error.erb +58 -0
  111. data/examples/sinatra_app/views/index.erb +118 -0
  112. data/examples/sinatra_app/views/layout.erb +61 -0
  113. data/examples/sinatra_app/views/portfolio.erb +43 -0
  114. data/examples/strategy_generator_example.rb +346 -0
  115. data/hsa_portfolio.csv +11 -0
  116. data/justfile +0 -0
  117. data/lib/api/alpha_vantage_api.rb +462 -0
  118. data/lib/sqa/backtest.rb +329 -0
  119. data/lib/sqa/config.rb +22 -9
  120. data/lib/sqa/data_frame/alpha_vantage.rb +43 -65
  121. data/lib/sqa/data_frame/data.rb +92 -0
  122. data/lib/sqa/data_frame/yahoo_finance.rb +34 -41
  123. data/lib/sqa/data_frame.rb +148 -243
  124. data/lib/sqa/ensemble.rb +359 -0
  125. data/lib/sqa/fpop.rb +199 -0
  126. data/lib/sqa/gp.rb +259 -0
  127. data/lib/sqa/indicator.rb +5 -8
  128. data/lib/sqa/init.rb +16 -9
  129. data/lib/sqa/market_regime.rb +240 -0
  130. data/lib/sqa/multi_timeframe.rb +379 -0
  131. data/lib/sqa/pattern_matcher.rb +497 -0
  132. data/lib/sqa/plugin_manager.rb +20 -0
  133. data/lib/sqa/portfolio.rb +260 -6
  134. data/lib/sqa/portfolio_optimizer.rb +377 -0
  135. data/lib/sqa/risk_manager.rb +442 -0
  136. data/lib/sqa/seasonal_analyzer.rb +209 -0
  137. data/lib/sqa/sector_analyzer.rb +300 -0
  138. data/lib/sqa/stock.rb +67 -96
  139. data/lib/sqa/strategy/bollinger_bands.rb +42 -0
  140. data/lib/sqa/strategy/common.rb +0 -2
  141. data/lib/sqa/strategy/consensus.rb +5 -2
  142. data/lib/sqa/strategy/kbs_strategy.rb +470 -0
  143. data/lib/sqa/strategy/macd.rb +46 -0
  144. data/lib/sqa/strategy/mp.rb +1 -1
  145. data/lib/sqa/strategy/stochastic.rb +60 -0
  146. data/lib/sqa/strategy/volume_breakout.rb +57 -0
  147. data/lib/sqa/strategy.rb +5 -0
  148. data/lib/sqa/strategy_generator.rb +947 -0
  149. data/lib/sqa/stream.rb +361 -0
  150. data/lib/sqa/version.rb +1 -7
  151. data/lib/sqa.rb +41 -14
  152. data/main.just +81 -0
  153. data/mkdocs.yml +288 -0
  154. data/trace.log +0 -0
  155. metadata +279 -48
  156. data/bin/sqa +0 -6
  157. data/lib/sqa/activity.rb +0 -10
  158. data/lib/sqa/analysis.rb +0 -306
  159. data/lib/sqa/cli.rb +0 -173
  160. data/lib/sqa/constants.rb +0 -23
  161. data/lib/sqa/indicator/average_true_range.rb +0 -43
  162. data/lib/sqa/indicator/bollinger_bands.rb +0 -28
  163. data/lib/sqa/indicator/candlestick_pattern_recognizer.rb +0 -60
  164. data/lib/sqa/indicator/donchian_channel.rb +0 -29
  165. data/lib/sqa/indicator/double_top_bottom_pattern.rb +0 -34
  166. data/lib/sqa/indicator/elliott_wave_theory.rb +0 -57
  167. data/lib/sqa/indicator/exponential_moving_average.rb +0 -25
  168. data/lib/sqa/indicator/exponential_moving_average_trend.rb +0 -36
  169. data/lib/sqa/indicator/fibonacci_retracement.rb +0 -23
  170. data/lib/sqa/indicator/head_and_shoulders_pattern.rb +0 -26
  171. data/lib/sqa/indicator/market_profile.rb +0 -32
  172. data/lib/sqa/indicator/mean_reversion.rb +0 -37
  173. data/lib/sqa/indicator/momentum.rb +0 -28
  174. data/lib/sqa/indicator/moving_average_convergence_divergence.rb +0 -29
  175. data/lib/sqa/indicator/peaks_and_valleys.rb +0 -29
  176. data/lib/sqa/indicator/predict_next_value.rb +0 -202
  177. data/lib/sqa/indicator/relative_strength_index.rb +0 -47
  178. data/lib/sqa/indicator/simple_moving_average.rb +0 -24
  179. data/lib/sqa/indicator/simple_moving_average_trend.rb +0 -32
  180. data/lib/sqa/indicator/stochastic_oscillator.rb +0 -68
  181. data/lib/sqa/indicator/true_range.rb +0 -39
  182. data/lib/sqa/trade.rb +0 -26
  183. data/lib/sqa/web.rb +0 -159
data/lib/sqa/analysis.rb DELETED
@@ -1,306 +0,0 @@
1
- # lib/sqa/command/analysis.rb
2
-
3
- module SQA
4
- class Analysis < CLI
5
- include TTY::Option
6
-
7
- command "Analysis"
8
-
9
- desc "Provide an Analysis of a Portfolio"
10
-
11
-
12
- def initialize
13
- # TODO: something
14
- end
15
- end
16
- end
17
-
18
- __END__
19
-
20
-
21
-
22
- ###################################################
23
- ## This is the old thing that got me started ...
24
-
25
- #!/usr/bin/env ruby
26
- # experiments/stocks/analysis.rb
27
- #
28
- # Some technical indicators from FinTech gem
29
- #
30
- # optional date CLI option in format YYYY-mm-dd
31
- # if not present uses Date.today
32
- #
33
-
34
-
35
- INVEST = 1000.00
36
-
37
- require 'pathname'
38
-
39
- require_relative 'stock'
40
- require_relative 'datastore'
41
-
42
-
43
- STOCKS = Pathname.pwd + "stocks.txt"
44
- TRADES = Pathname.pwd + "trades.csv"
45
-
46
- TRADES_FILE = File.open(TRADES, 'a')
47
-
48
- unless STOCKS.exist?
49
- puts
50
- puts "ERROR: The 'stocks.txt' file does not exist."
51
- puts
52
- exot(-1)
53
- end
54
-
55
- require 'debug_me'
56
- include DebugMe
57
-
58
- require 'csv'
59
- require 'date'
60
- require 'tty-table'
61
-
62
- require 'fin_tech'
63
- require 'previous_dow'
64
-
65
- class NilClass
66
- def blank?() = true
67
- end
68
-
69
- class String
70
- def blank?() = strip().empty?
71
- end
72
-
73
- class Array
74
- def blank?() = empty?
75
- end
76
-
77
-
78
- def tickers
79
- return @tickers unless @tickers.blank?
80
-
81
- @tickers = []
82
-
83
- STOCKS.readlines.each do |a_line|
84
- ticker_symbol = a_line.chomp.strip.split()&.first&.downcase
85
- next if ticker_symbol.blank? || '#' == ticker_symbol
86
- @tickers << ticker_symbol unless @tickers.include?(ticker_symbol)
87
- end
88
-
89
- @tickers.sort!
90
- end
91
-
92
- given_date = ARGV.first ? Date.parse(ARGV.first) : Date.today
93
-
94
- start_date = Date.new(2019, 1, 1)
95
- end_date = previous_dow(:friday, given_date)
96
-
97
- ASOF = end_date.to_s.tr('-','')
98
-
99
-
100
- #######################################################################
101
- # download a CSV file from https://query1.finance.yahoo.com
102
- # given a stock ticker symbol as a String
103
- # start and end dates
104
- #
105
- # For ticker "aapl" the downloaded file will be named "aapl.csv"
106
- # That filename will be renamed to "aapl_YYYYmmdd.csv" where the
107
- # date suffix is the end_date of the historical data.
108
- #
109
- def download_historical_prices(ticker, start_date, end_date)
110
- data_path = Pathname.pwd + "#{ticker}_#{ASOF}.csv"
111
- return if data_path.exist?
112
-
113
- mew_path = Pathname.pwd + "#{ticker}.csv"
114
-
115
- start_timestamp = start_date.to_time.to_i
116
- end_timestamp = end_date.to_time.to_i
117
- ticker_upcase = ticker.upcase
118
- filename = "#{ticker.downcase}.csv"
119
-
120
- `curl -o #{filename} "https://query1.finance.yahoo.com/v7/finance/download/#{ticker_upcase}?period1=#{start_timestamp}&period2=#{end_timestamp}&interval=1d&events=history&includeAdjustedClose=true"`
121
-
122
- mew_path.rename data_path
123
- end
124
-
125
-
126
- #######################################################################
127
- # Read the CSV file associated with the give ticker symbol
128
- # and the ASOF date.
129
- #
130
- def read_csv(ticker)
131
- filename = "#{ticker.downcase}_#{ASOF}.csv"
132
- data = []
133
-
134
- CSV.foreach(filename, headers: true) do |row|
135
- data << row.to_h
136
- end
137
-
138
- data
139
- end
140
-
141
- ##########################
142
- # record a recommend trade
143
-
144
- def trade(ticker, signal, shares, price)
145
- TRADES_FILE.puts "#{ticker},#{ASOF},#{signal},#{shares},#{price}"
146
- end
147
-
148
- #######################################################################
149
- ###
150
- ## Main
151
- #
152
-
153
-
154
- tickers.each do |ticker|
155
- download_historical_prices(ticker, start_date, end_date)
156
- end
157
-
158
- result = {}
159
-
160
- mwfd = 14 # moving_window_forcast_days
161
-
162
- headers = %w[ Ticker AdjClose Trend Slope M'tum RSI Analysis MACD Target Signal $]
163
- values = []
164
-
165
- tickers.each do |ticker|
166
-
167
- data = read_csv ticker
168
- prices = data.map{|r| r["Adj Close"].to_f}
169
- volumes = data.map{|r| r["volume"].to_f}
170
-
171
- if data.blank?
172
- puts
173
- puts "ERROR: cannot get data for #{ticker}"
174
- puts
175
- next
176
- end
177
-
178
-
179
- result[ticker] = {
180
- date: data.last["Date"],
181
- adj_close: data.last["Adj Close"].to_f
182
- }
183
-
184
- result[ticker][:market] = FinTech.classify_market_profile(
185
- volumes.last(mwfd),
186
- prices.last(mwfd),
187
- prices.last(mwfd).first,
188
- prices.last
189
- )
190
-
191
- fr = FinTech.fibonacci_retracement( prices.last(mwfd).first,
192
- prices.last).map{|x| x.round(3)}
193
-
194
-
195
- puts "\n#{result[ticker][:market]} .. #{ticker}\t#{fr}"
196
- print "\t"
197
- print FinTech.head_and_shoulders_pattern?(prices.last(mwfd))
198
- print "\t"
199
- print FinTech.double_top_bottom_pattern?(prices.last(mwfd))
200
- print "\t"
201
- mr = FinTech.mean_reversion?(prices, mwfd, 0.5)
202
- print mr
203
-
204
- if mr
205
- print "\t"
206
- print FinTech.mr_mean(prices, mwfd).round(3)
207
- end
208
-
209
- print "\t"
210
- print FinTech.identify_wave_condition?(prices, 2*mwfd, 1.0)
211
- puts
212
-
213
- print "\t"
214
- print FinTech.ema_analysis(prices, mwfd).except(:ema_values)
215
-
216
- puts
217
-
218
- row = [ ticker ]
219
-
220
- # result[ticker][:moving_averages] = FinTech.sma(data, mwfd)
221
- result[ticker][:trend] = FinTech.sma_trend(data, mwfd)
222
- result[ticker][:momentum] = FinTech.momentum(prices, mwfd)
223
- result[ticker][:rsi] = FinTech.rsi(data, mwfd)
224
- result[ticker][:bollinger_bands] = FinTech.bollinger_bands(data, mwfd, 2)
225
- result[ticker][:macd] = FinTech.macd(data, mwfd, 2*mwfd, mwfd/2)
226
-
227
- price = result[ticker][:adj_close].round(3)
228
-
229
- row << price
230
- row << result[ticker][:trend][:trend]
231
- row << result[ticker][:trend][:angle].round(3)
232
- row << result[ticker][:momentum].round(3)
233
- row << result[ticker][:rsi][:rsi].round(3)
234
- row << result[ticker][:rsi][:meaning]
235
- row << result[ticker][:macd].first.round(3)
236
- row << result[ticker][:macd].last.round(3)
237
-
238
- analysis = result[ticker][:rsi][:meaning]
239
-
240
- signal = ""
241
- macd_diff = result[ticker][:macd].first
242
- target = result[ticker][:macd].last
243
- current = result[ticker][:adj_close]
244
-
245
- trend_down = "down" == result[ticker][:trend][:trend]
246
-
247
- if current < target
248
- signal = "buy" unless "Over Bought" == analysis
249
- elsif (current > target) && trend_down
250
- signal = "sell" unless "Over Sold" == analysis
251
- end
252
-
253
- if "buy" == signal
254
- pps = target - price
255
- shares = INVEST.to_i / price.to_i
256
- upside = (shares * pps).round(2)
257
- trade(ticker, signal, shares, price)
258
- elsif "sell" == signal
259
- pps = target - price
260
- shares = INVEST.to_i / price.to_i
261
- upside = (shares * pps).round(2)
262
- trade(ticker, signal, shares, price)
263
- else
264
- upside = ""
265
- end
266
-
267
- row << signal
268
- row << upside
269
-
270
- values << row
271
- end
272
-
273
- # debug_me{[
274
- # :result
275
- # ]}
276
-
277
-
278
- the_table = TTY::Table.new(headers, values)
279
-
280
- puts
281
- puts "Analysis as of Friday Close: #{end_date}"
282
-
283
- puts the_table.render(
284
- :unicode,
285
- {
286
- padding: [0, 0, 0, 0],
287
- alignments: [
288
- :left, # ticker
289
- :right, # adj close
290
- :center, # trend
291
- :right, # slope
292
- :right, # momentum
293
- :right, # rsi
294
- :center, # meaning / analysis
295
- :right, # macd
296
- :right, # target
297
- :center, # signal
298
- :right # upside
299
- ],
300
- }
301
- )
302
- puts
303
-
304
- TRADES_FILE.close
305
-
306
-
data/lib/sqa/cli.rb DELETED
@@ -1,173 +0,0 @@
1
- # lib/sqa/cli.rb
2
-
3
-
4
- require_relative '../sqa'
5
-
6
- # SMELL: Architectyre has become confused between CLI and Command
7
-
8
- # TODO: Fix the mess between CLI and Command
9
-
10
-
11
- module SQA
12
- class CLI
13
- include TTY::Option
14
-
15
- header "Stock Quantitative Analysis (SQA)"
16
- footer "WARNING: This is a toy, a play thing, not intended for serious use."
17
-
18
- program "sqa"
19
- desc "A collection of things"
20
-
21
- example "sqa -c ~/.sqa.yml -p portfolio.csv -t trades.csv --data-dir ~/sqa_data"
22
-
23
-
24
- option :config_file do
25
- short "-c string"
26
- long "--config string"
27
- desc "Path to the config file"
28
- end
29
-
30
- option :log_level do
31
- short "-l string"
32
- long "--log_level string"
33
- # default SQA.config.log_level
34
- desc "Set the log level (debug, info, warn, error, fatal)"
35
- end
36
-
37
- option :portfolio do
38
- short "-p string"
39
- long "--portfolio string"
40
- # default SQA.config.portfolio_filename
41
- desc "Set the filename of the portfolio"
42
- end
43
-
44
-
45
- option :trades do
46
- short "-t string"
47
- long "--trades string"
48
- # default SQA.config.trades_filename
49
- desc "Set the filename into which trades are stored"
50
- end
51
-
52
-
53
- option :data_dir do
54
- long "--data-dir string"
55
- # default SQA.config.data_dir
56
- desc "Set the directory for the SQA data"
57
- end
58
-
59
- option :dump_config do
60
- long "--dump-config path_to_file"
61
- desc "Dump the current configuration"
62
- end
63
-
64
- flag :help do
65
- short "-h"
66
- long "--help"
67
- desc "Print usage"
68
- end
69
-
70
- flag :version do
71
- long "--version"
72
- desc "Print version"
73
- end
74
-
75
- flag :debug do
76
- short "-d"
77
- long "--debug"
78
- # default SQA.config.debug
79
- desc "Turn on debugging output"
80
- end
81
-
82
- flag :verbose do
83
- short "-v"
84
- long "--verbose"
85
- # default SQA.config.debug
86
- desc "Print verbosely"
87
- end
88
-
89
- class << self
90
- @@subclasses = []
91
- @@commands_available = []
92
-
93
- def names
94
- '['+ @@commands_available.join('|')+']'
95
- end
96
-
97
- def inherited(subclass)
98
- super
99
- @@subclasses << subclass
100
- @@commands_available << subclass.command.join
101
- end
102
-
103
- def command_descriptions
104
- help_block = "Optional Command Available:"
105
-
106
- @@commands_available.size.times do |x|
107
- klass = @@subclasses[x]
108
- help_block << "\n " + @@commands_available[x] + " - "
109
- help_block << klass.desc.join
110
- end
111
-
112
- help_block
113
- end
114
-
115
-
116
- ##################################################
117
- def run(argv = ARGV)
118
- cli = new
119
- parser = cli.parse(argv)
120
- params = parser.params
121
-
122
- if params[:help]
123
- print parser.help
124
- exit(0)
125
-
126
- elsif params.errors.any?
127
- puts params.errors.summary
128
- exit(1)
129
-
130
- elsif params[:version]
131
- puts SQA.version
132
- exit(0)
133
-
134
- elsif params[:dump_config]
135
- SQA.config.config_file = params[:dump_config]
136
- `touch #{SQA.config.config_file}`
137
- SQA.config.dump_file
138
- exit(0)
139
-
140
- elsif params[:config_file]
141
- # Override the defaults <- envars <- config file content
142
- params[:config_file] = SQA.homify params[:config_file]
143
- SQA.config.config_file = params[:config_file]
144
- SQA.config.from_file
145
- end
146
-
147
- # Override the defaults <- envars <- config file <- cli parameters
148
- SQA.config.merge!(remove_temps params.to_h)
149
-
150
- if SQA.debug? || SQA.verbose?
151
- debug_me("config after CLI parameters"){[
152
- "SQA.config"
153
- ]}
154
- end
155
- end
156
-
157
- def remove_temps(a_hash)
158
- temps = %i[ help version dump ]
159
- # debug_me{[ :a_hash ]}
160
- a_hash.reject{|k, _| temps.include? k}
161
- end
162
- end
163
- end
164
- end
165
-
166
- require_relative 'analysis'
167
- require_relative 'web'
168
-
169
- # First Load TTY-Option's command content with all available commands
170
- # then these have access to the entire ObjectSpace ...
171
- SQA::CLI.command SQA::CLI.names
172
- SQA::CLI.example SQA::CLI.command_descriptions
173
-
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,43 +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
- # debug_me{[ :period, :true_ranges ]}
17
-
18
- window_span = period - 1
19
-
20
- true_ranges.size.times do |inx|
21
- start_inx = inx - window_span
22
- end_inx = start_inx + window_span
23
-
24
- start_inx = 0 if start_inx < 0
25
-
26
- window = true_ranges[start_inx..end_inx]
27
-
28
- # debug_me{[
29
- # :inx,
30
- # :start_inx,
31
- # :end_inx,
32
- # :window,
33
- # "window.mean"
34
- # ]}
35
-
36
- atr_values << window.mean
37
- end
38
-
39
- atr_values # Array
40
- end
41
- alias_method :atr, :average_true_range
42
-
43
- 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
-