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
@@ -0,0 +1,313 @@
1
+ Comprehensive Summary: Develop Branch Changes
2
+ Overview
3
+
4
+ The develop branch contains 12 commits spanning from February 2024 to August 2025 (18+ months of development). This represents a major evolution of the SQA project with significant architectural changes and new features.
5
+
6
+ Impact: 104,907 insertions, 2,017 deletions across 47 files
7
+ 🎯 Strategic Direction Change
8
+ From Application to Library
9
+
10
+ Commit: 11351a6 (Feb 2024) - "refocused effort on a library rather than library plus application"
11
+
12
+ Major Architectural Shift:
13
+
14
+ Removed entire CLI command structure:
15
+ Deleted lib/sqa/cli.rb (62 lines)
16
+ Deleted lib/sqa/commands.rb (22 lines)
17
+ Deleted lib/sqa/commands/analysis.rb (309 lines)
18
+ Deleted lib/sqa/commands/base.rb (139 lines)
19
+ Deleted lib/sqa/commands/web.rb (199 lines)
20
+ Deleted lib/sqa/constants.rb (23 lines)
21
+ Removed dry-cli patches (228 lines)
22
+
23
+ Removed configuration testing infrastructure:
24
+ All config test files deleted
25
+ CLI override testing removed
26
+
27
+ Rationale: Simplification - focus on providing a reusable library for quantitative analysis rather than a full application with CLI.
28
+ 🔧 Core Technical Improvements
29
+ 1. DataFrame Refactoring (Major Change)
30
+
31
+ Commit: 9625e31 (Feb 2025) - "Refactor SQA::DataFrame to Integrate with polars-df Gem"
32
+
33
+ Before:
34
+
35
+ # Based on Hashie::Mash wrapper
36
+ class Data < Hashie::Mash
37
+ # Custom wrapper around hash-based data structure
38
+ end
39
+
40
+ After:
41
+
42
+ # Based on Polars (Rust-backed high-performance dataframe)
43
+ def initialize(raw_data = nil, mapping: {}, transformers: {})
44
+ @data = Polars::DataFrame.new(raw_data)
45
+ end
46
+
47
+ Benefits:
48
+
49
+ Blazingly fast - Polars is written in Rust
50
+ Industry-standard DataFrame API (similar to Python's pandas/Polars)
51
+ Better memory efficiency
52
+ Native support for complex data operations
53
+ 84 insertions, 272 deletions (net reduction + improved functionality)
54
+
55
+ 2. Custom Alpha Vantage API Wrapper
56
+
57
+ Commits: 162dbdc, 9fb7727 (Feb 2024)
58
+
59
+ New File: lib/api/alpha_vantage_api.rb (462 lines)
60
+
61
+ Rationale: Replaced the alphavantage gem dependency with custom implementation
62
+
63
+ Features:
64
+
65
+ Direct Faraday-based HTTP client
66
+ Comprehensive API coverage (70+ methods)
67
+ Categories covered:
68
+ Market Data (quotes, intraday, daily, etc.)
69
+ Technical Indicators (AD, ADOSC, ADX, AROON, etc.)
70
+ Economic Indicators (commodities, aluminum, etc.)
71
+ Fundamental Data (balance sheet, earnings, etc.)
72
+ Digital & Forex markets
73
+ Better error handling
74
+ More maintainable and customizable
75
+
76
+ Example Methods:
77
+
78
+ def adx(symbol:, interval:, time_period:)
79
+ def balance_sheet(symbol:)
80
+ def aroon(symbol:, interval:, time_period:)
81
+
82
+ 3. Genetic Programming for Strategy Evaluation
83
+
84
+ Commits: 578032b, 84b8ff5 (Oct 2024) - "SQA-144 Add GeneticProgram class for strategy evaluation"
85
+
86
+ New Files:
87
+
88
+ lib/sqa/gp.rb (107 lines) - Genetic Programming implementation
89
+ docs/genetic_programming.md (104 lines) - Comprehensive documentation
90
+
91
+ Purpose: Use evolutionary algorithms to discover optimal trading strategies
92
+
93
+ Key Concepts:
94
+
95
+ # Fitness functions for trading signals
96
+ fitness_sell = gain - delta # more positive = better
97
+ fitness_buy = loss + delta # more negative = better
98
+ fitness_hold = gain.abs < delta && loss.abs < delta
99
+
100
+ # Mutation constraints
101
+ constraint = {
102
+ indicators: [:rsi, :ma, :raw, :whatever],
103
+ pww: (5..15).to_a, # past window width
104
+ fww: (5..15).to_a, # future window width
105
+ x: (-30..-15).to_a # time instance
106
+ }
107
+
108
+ Integration: Uses the darwinning gem for genetic algorithm implementation
109
+ 4. Black-Scholes Options Pricing
110
+
111
+ New File: lib/sqa/indicator/black_scholes.rb (61 lines)
112
+
113
+ Implementation:
114
+
115
+ def black_scholes(
116
+ option_type, # 'c' for call, 'p' for put
117
+ current_stock_price,
118
+ strike_price,
119
+ time_to_expiration, # in years
120
+ risk_free_rate, # as decimal
121
+ volatility # as decimal
122
+ )
123
+
124
+ Features:
125
+
126
+ European call and put option pricing
127
+ Normal distribution CDF implementation
128
+ Well-documented with volatility calculation examples
129
+ Meaningful parameter names (refactored from cryptic originals)
130
+
131
+ 📚 Documentation Expansion
132
+
133
+ New Documentation Files:
134
+
135
+ docs/genetic_programming.md (104 lines)
136
+ Overview of GP methodology
137
+ Application to stock market predictions
138
+ Ruby implementation examples with darwinning gem
139
+ Fitness function design
140
+ Backtesting considerations
141
+
142
+ docs/factors_that_impact_price.md (26 lines)
143
+ Market factors affecting stock prices
144
+
145
+ docs/options.md (8 lines)
146
+ Options trading basics
147
+
148
+ docs/fx_pro_bit.md (25 lines)
149
+ Foreign exchange and cryptocurrency notes
150
+
151
+ docs/finviz.md (11 lines)
152
+ Note about finviz.com website for market screening
153
+
154
+ docs/i_gotta_an_idea.md (22 lines)
155
+ Project ideas and future directions
156
+
157
+ COMMITS.md (196 lines)
158
+ Conventional Commits specification (latest commit Aug 2025)
159
+ Standardized commit message format
160
+ Semantic versioning alignment
161
+
162
+ 🔄 Dependency Updates
163
+ Added Dependencies (Gemfile)
164
+
165
+ gem 'csv' # CSV Reading and Writing
166
+ gem 'eps' # Machine learning for Ruby
167
+ gem 'polars-df' # Blazingly fast DataFrames
168
+ gem 'raix' # Ruby AI eXtensions
169
+ gem 'regent' # AI Agents in Ruby
170
+ gem 'rspec' # Testing framework
171
+ gem 'toml-rb' # TOML parser
172
+
173
+ Gemspec Changes
174
+
175
+ # Removed
176
+ - 'dry-cli' # CLI framework no longer needed
177
+ - 'sem_version' # Replaced with versionaire
178
+
179
+ # Added
180
+ + 'ruby_llm' # LLM integration
181
+ + 'ruby_llm-mcp' # LLM MCP protocol
182
+ + 'shared_tools' # Shared utilities
183
+
184
+ # Updated
185
+ ~ 'hashie', '~>4.1.0' => 'hashie' # Version constraint relaxed
186
+ ~ spec.required_ruby_version = ">= 2.7" => ">= 3.2" # Ruby 3.2+ required
187
+
188
+ Note: Ruby version requirement increased from 2.7+ to 3.2+
189
+ 🗂️ Data & Configuration
190
+ New Data Files
191
+
192
+ data/talk_talk.json (103,284 lines)
193
+ Massive dataset addition
194
+ Likely stock price or trading data
195
+ Represents 98.5% of all line additions
196
+
197
+ hsa_portfolio.csv (11 lines)
198
+ Sample HSA (Health Savings Account) portfolio data
199
+
200
+ .gitmessage.txt (5 lines)
201
+ Git commit message template
202
+
203
+ .semver (6 lines)
204
+ Semantic versioning configuration
205
+
206
+ Build Automation
207
+
208
+ main.just (81 lines)
209
+
210
+ Justfile for task automation
211
+ Modules for repo, gem, version, git operations
212
+ Tasks: install, test, coverage, flay (static analysis)
213
+ Man page generation with kramdown-man
214
+
215
+ 🧪 Testing Improvements
216
+
217
+ Commits: ee314d6 (Feb 2024) - "corrected some typos; filled out skipped data_frame_test cases"
218
+
219
+ Changes to test/data_frame_test.rb:
220
+
221
+ 46 insertions, 242 deletions (net simplification)
222
+ Previously skipped test cases now implemented
223
+ Found errors in DataFrame requiring research
224
+ Tests updated for Polars-based DataFrame
225
+
226
+ 📊 Version History
227
+
228
+ Version Bump: 0.0.25 → 0.0.31 (6 minor versions)
229
+
230
+ Version System Changes:
231
+
232
+ Removed SQA.version class method
233
+ Simplified to constant: SQA::VERSION = '0.0.31'
234
+ Planning to replace semver gem with versionaire
235
+
236
+ 🤖 AI/ML Integration Direction
237
+
238
+ New AI-Related Dependencies:
239
+
240
+ eps - Machine learning (regression & classification)
241
+ raix - Ruby AI extensions
242
+ regent - AI Agents library
243
+ ruby_llm - LLM integration
244
+ ruby_llm-mcp - LLM MCP protocol support
245
+
246
+ Genetic Programming:
247
+
248
+ Custom GP implementation for strategy discovery
249
+ Darwinning gem integration
250
+ Automated trading strategy evolution
251
+
252
+ Direction: The project is evolving toward AI-assisted quantitative trading strategy development
253
+ 📝 Notable Files Modified
254
+ Stock.rb Refactoring
255
+
256
+ 38 insertions, 127 deletions (net simplification)
257
+ Likely adapted to new DataFrame structure
258
+
259
+ Data Source Adapters
260
+
261
+ lib/sqa/data_frame/alpha_vantage.rb - Simplified (18 ins, 52 del)
262
+ lib/sqa/data_frame/yahoo_finance.rb - Refactored (34 ins, 43 del)
263
+ Both adapted to Polars DataFrame
264
+
265
+ 🎯 Timeline Summary
266
+
267
+ | Date | Focus Area | Key Achievement | |------|-----------|----------------| | Feb 2024 | Architecture | Removed CLI, created Alpha Vantage API wrapper | | Feb 2024 | Testing | Filled DataFrame test gaps | | May 2024 | Versioning | Planned semver → versionaire migration | | Jun 2024 | Documentation | Added market analysis docs | | Oct 2024 | AI/ML | Added Genetic Programming for strategies | | Dec 2024 | Research | Documented finviz.com resource | | Feb 2025 | Performance | Major: Migrated to Polars DataFrame | | Feb 2025 | Dependencies | Added ML/AI gems (eps, raix, regent, ruby_llm) | | Aug 2025 | Standards | Adopted Conventional Commits |
268
+ ⚠️ Breaking Changes
269
+
270
+ Ruby Version: Now requires Ruby 3.2+ (was 2.7+)
271
+ API Changes: DataFrame completely refactored (Hashie → Polars)
272
+ No CLI: Entire command-line interface removed
273
+ Dependencies: Several removed (dry-cli, sem_version)
274
+ Configuration: Test config files removed
275
+
276
+ ✅ Merge Readiness Assessment
277
+ Strengths
278
+
279
+ Well-tested DataFrame refactoring
280
+ Comprehensive documentation
281
+ Clear architectural direction
282
+ Modern dependencies
283
+ Performance improvements with Polars
284
+
285
+ Concerns
286
+
287
+ Massive data file (103k line JSON) - may need .gitignore
288
+ Some commits mention finding errors needing research
289
+ Breaking changes will affect existing users
290
+ Ruby 3.2+ requirement may exclude some users
291
+
292
+ Recommendation
293
+
294
+ Review before merging:
295
+
296
+ Verify all DataFrame tests pass
297
+ Consider excluding data/talk_talk.json from version control
298
+ Document breaking changes in CHANGELOG
299
+ Consider semantic versioning: this should be 1.0.0 (major rewrite)
300
+ Ensure AI/ML features are production-ready
301
+
302
+ 🚀 Future Direction
303
+
304
+ The develop branch shows SQA evolving from a simple CLI tool into a comprehensive AI-powered quantitative trading library with:
305
+
306
+ High-performance data processing (Polars)
307
+ Genetic algorithm strategy discovery
308
+ Options pricing (Black-Scholes)
309
+ LLM integration capabilities
310
+ Machine learning models
311
+ AI agent support
312
+
313
+ This is a significant and ambitious evolution of the project.
@@ -0,0 +1,206 @@
1
+ # Backtesting Framework
2
+
3
+ ## Overview
4
+
5
+ Simulate trading strategies on historical data to evaluate performance before risking real capital.
6
+
7
+ ## Quick Start
8
+
9
+ ```ruby
10
+ require 'sqa'
11
+
12
+ # Load stock data
13
+ stock = SQA::Stock.new(ticker: 'AAPL')
14
+
15
+ # Create backtest
16
+ backtest = SQA::Backtest.new(
17
+ stock: stock,
18
+ strategy: SQA::Strategy::RSI,
19
+ initial_cash: 10_000,
20
+ commission: 1.0
21
+ )
22
+
23
+ # Run simulation
24
+ results = backtest.run
25
+
26
+ # View results
27
+ puts "Total Return: #{results.total_return}%"
28
+ puts "Sharpe Ratio: #{results.sharpe_ratio}"
29
+ puts "Max Drawdown: #{results.max_drawdown}%"
30
+ puts "Win Rate: #{results.win_rate}%"
31
+ ```
32
+
33
+ ## Configuration
34
+
35
+ ### Basic Parameters
36
+
37
+ ```ruby
38
+ backtest = SQA::Backtest.new(
39
+ stock: stock, # SQA::Stock object
40
+ strategy: SQA::Strategy::MACD, # Strategy class
41
+ initial_cash: 10_000, # Starting capital
42
+ commission: 1.0, # Per-trade commission
43
+ position_size: 100 # Shares per trade
44
+ )
45
+ ```
46
+
47
+ ## Results Object
48
+
49
+ The `backtest.run` method returns a results object with:
50
+
51
+ ### Return Metrics
52
+ - `total_return` - Total percentage return
53
+ - `annualized_return` - Return per year
54
+ - `benchmark_return` - Buy-and-hold comparison
55
+
56
+ ### Risk Metrics
57
+ - `sharpe_ratio` - Risk-adjusted return
58
+ - `sortino_ratio` - Downside risk-adjusted return
59
+ - `max_drawdown` - Largest peak-to-trough decline
60
+ - `volatility` - Standard deviation of returns
61
+
62
+ ### Trading Metrics
63
+ - `num_trades` - Total number of trades
64
+ - `win_rate` - Percentage of profitable trades
65
+ - `avg_win` - Average winning trade
66
+ - `avg_loss` - Average losing trade
67
+ - `profit_factor` - Gross profit / gross loss
68
+
69
+ ### Portfolio Metrics
70
+ - `final_value` - Ending portfolio value
71
+ - `portfolio_value` - Value over time (array)
72
+ - `trades` - Full trade history
73
+
74
+ ## Complete Example
75
+
76
+ ```ruby
77
+ # Load data
78
+ stock = SQA::Stock.new(ticker: 'AAPL')
79
+
80
+ # Test multiple strategies
81
+ strategies = [
82
+ SQA::Strategy::RSI,
83
+ SQA::Strategy::MACD,
84
+ SQA::Strategy::BollingerBands
85
+ ]
86
+
87
+ strategies.each do |strategy|
88
+ backtest = SQA::Backtest.new(
89
+ stock: stock,
90
+ strategy: strategy,
91
+ initial_cash: 10_000
92
+ )
93
+
94
+ results = backtest.run
95
+
96
+ puts "\n#{strategy.name} Results:"
97
+ puts "-" * 40
98
+ puts "Return: #{results.total_return.round(2)}%"
99
+ puts "Sharpe: #{results.sharpe_ratio.round(2)}"
100
+ puts "Max DD: #{results.max_drawdown.round(2)}%"
101
+ puts "Trades: #{results.num_trades}"
102
+ puts "Win Rate: #{results.win_rate.round(2)}%"
103
+ end
104
+ ```
105
+
106
+ ## Advanced Usage
107
+
108
+ ### Custom Date Range
109
+
110
+ ```ruby
111
+ # Backtest specific period
112
+ stock = SQA::Stock.new(
113
+ ticker: 'AAPL',
114
+ start_date: '2020-01-01',
115
+ end_date: '2023-12-31'
116
+ )
117
+
118
+ backtest = SQA::Backtest.new(stock: stock, strategy: strategy)
119
+ results = backtest.run
120
+ ```
121
+
122
+ ### Parameter Optimization
123
+
124
+ ```ruby
125
+ # Test different RSI thresholds
126
+ (20..40).step(5).each do |oversold|
127
+ results = test_strategy_with_params(oversold)
128
+ puts "RSI #{oversold}: Return = #{results.total_return}%"
129
+ end
130
+ ```
131
+
132
+ ### Walk-Forward Testing
133
+
134
+ ```ruby
135
+ # Train on first 70%, test on last 30%
136
+ train_end = (stock.df.height * 0.7).to_i
137
+ train_stock = stock.df[0...train_end]
138
+ test_stock = stock.df[train_end..-1]
139
+
140
+ # Optimize on training data
141
+ best_params = optimize_on(train_stock)
142
+
143
+ # Validate on test data
144
+ results = backtest_with_params(test_stock, best_params)
145
+ ```
146
+
147
+ ## Visualization
148
+
149
+ ```ruby
150
+ # Plot equity curve
151
+ require 'gruff'
152
+
153
+ g = Gruff::Line.new
154
+ g.title = "Portfolio Value Over Time"
155
+ g.data("Portfolio", results.portfolio_value)
156
+ g.write('equity_curve.png')
157
+ ```
158
+
159
+ ## Best Practices
160
+
161
+ ### 1. Use Enough Data
162
+ - Minimum: 252 trading days (1 year)
163
+ - Recommended: 1260+ days (5 years)
164
+ - Include different market conditions
165
+
166
+ ### 2. Account for Costs
167
+ ```ruby
168
+ backtest = SQA::Backtest.new(
169
+ commission: 1.0, # Per trade
170
+ slippage: 0.001 # 0.1% slippage
171
+ )
172
+ ```
173
+
174
+ ### 3. Avoid Overfitting
175
+ - Use walk-forward analysis
176
+ - Test on out-of-sample data
177
+ - Limit parameter optimization
178
+
179
+ ### 4. Compare to Benchmark
180
+ ```ruby
181
+ if results.total_return < results.benchmark_return
182
+ puts "⚠️ Strategy underperforms buy-and-hold"
183
+ end
184
+ ```
185
+
186
+ ### 5. Check Multiple Metrics
187
+ Don't rely on return alone:
188
+ - Sharpe ratio (risk-adjusted)
189
+ - Max drawdown (worst case)
190
+ - Win rate (consistency)
191
+ - Profit factor (quality)
192
+
193
+ ## Common Pitfalls
194
+
195
+ ❌ **Survivorship Bias**: Only testing stocks that still exist
196
+ ❌ **Look-Ahead Bias**: Using future data
197
+ ❌ **Curve Fitting**: Over-optimizing parameters
198
+ ❌ **Ignoring Costs**: Unrealistic commission/slippage
199
+ ❌ **Small Sample**: Too few trades for statistical significance
200
+
201
+ ## Related
202
+
203
+ - [Portfolio Management](portfolio.md) - Track positions and P&L
204
+ - [Strategy Generator](strategy-generator.md) - Discover patterns
205
+ - [Risk Management](risk-management.md) - Position sizing and risk metrics
206
+
@@ -0,0 +1,68 @@
1
+ # Ensemble Strategies
2
+
3
+ Combine multiple strategies with voting and meta-learning.
4
+
5
+ ## Basic Ensemble
6
+
7
+ ```ruby
8
+ ensemble = SQA::Ensemble.new(
9
+ strategies: [
10
+ SQA::Strategy::RSI,
11
+ SQA::Strategy::MACD,
12
+ SQA::Strategy::BollingerBands
13
+ ],
14
+ voting_method: :majority
15
+ )
16
+
17
+ signal = ensemble.signal(vector) # => :buy, :sell, or :hold
18
+ ```
19
+
20
+ ## Voting Methods
21
+
22
+ ### Majority Voting
23
+ ```ruby
24
+ voting_method: :majority # Most common signal wins
25
+ ```
26
+
27
+ ### Weighted Voting
28
+ ```ruby
29
+ voting_method: :weighted
30
+ # Weight strategies by past performance
31
+ ```
32
+
33
+ ### Unanimous
34
+ ```ruby
35
+ voting_method: :unanimous # All must agree
36
+ ```
37
+
38
+ ### Confidence-Based
39
+ ```ruby
40
+ voting_method: :confidence # Weight by confidence scores
41
+ ```
42
+
43
+ ## Dynamic Weighting
44
+
45
+ ```ruby
46
+ # Update weights based on performance
47
+ ensemble.update_weight(SQA::Strategy::RSI, 1.5) # Increase weight
48
+ ensemble.update_weight(SQA::Strategy::MACD, 0.5) # Decrease weight
49
+ ```
50
+
51
+ ## Strategy Rotation
52
+
53
+ ```ruby
54
+ # Select best strategy for current market
55
+ selected = ensemble.rotate(stock)
56
+ # Automatically switches based on recent performance
57
+ ```
58
+
59
+ ## Backtest Comparison
60
+
61
+ ```ruby
62
+ comparison = ensemble.backtest_comparison(stock)
63
+
64
+ comparison.each do |name, results|
65
+ puts "#{name}: Return = #{results[:return]}%"
66
+ end
67
+ ```
68
+