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,354 @@
1
+ # SQA Examples
2
+
3
+ This directory contains comprehensive examples demonstrating advanced features of the SQA (Simple Qualitative Analysis) library.
4
+
5
+ ## Available Examples
6
+
7
+ ### 1. Strategy Generator (`strategy_generator_example.rb`)
8
+
9
+ **Reverse engineer profitable trades to discover indicator patterns**
10
+
11
+ This example demonstrates how to mine historical data for profitable entry points and discover which indicator combinations were active at those times. The strategy generator:
12
+
13
+ - Scans historical data for trades that yielded ≥X% gain
14
+ - Identifies which indicators were "active" (e.g., RSI oversold, MACD bullish crossover)
15
+ - Discovers common patterns across profitable trades
16
+ - Generates trading strategies from discovered patterns
17
+ - Backtests generated strategies against traditional strategies
18
+
19
+ **Run it:**
20
+ ```bash
21
+ ./examples/strategy_generator_example.rb
22
+ ```
23
+
24
+ **Key Examples:**
25
+ - Example 1: Basic pattern discovery for 10% gains
26
+ - Example 2: Generate strategies from top patterns
27
+ - Example 3: Compare different gain thresholds (5%, 10%, 15%, 20%)
28
+ - Example 4: Short-term vs long-term patterns
29
+ - Example 5: Export patterns to CSV
30
+ - Example 6: Performance comparison of discovered vs traditional strategies
31
+ - Example 7: Aggressive pattern mining for 20%+ gains
32
+
33
+ **Output:**
34
+ - Discovered patterns with frequency, average gain, and conditions
35
+ - Generated strategy performance metrics
36
+ - CSV export of patterns
37
+ - Comparison table of strategy performance
38
+
39
+ ---
40
+
41
+ ### 2. Genetic Programming (`genetic_programming_example.rb`)
42
+
43
+ **Evolve optimal trading strategy parameters through natural selection**
44
+
45
+ This example shows how to use genetic algorithms to automatically find the best parameters for trading strategies. The genetic program:
46
+
47
+ - Defines parameter space (e.g., RSI period 7-30, thresholds 20-80)
48
+ - Creates random population of strategies
49
+ - Evaluates fitness through backtesting
50
+ - Evolves through selection, crossover, and mutation
51
+ - Tracks evolution history and best individuals
52
+
53
+ **Run it:**
54
+ ```bash
55
+ ./examples/genetic_programming_example.rb
56
+ ```
57
+
58
+ **What it demonstrates:**
59
+ - Evolving RSI strategy parameters (period, buy/sell thresholds)
60
+ - Tournament selection for parent choosing
61
+ - Crossover and mutation operations
62
+ - Fitness evaluation via backtesting
63
+ - Evolution history tracking
64
+
65
+ **Output:**
66
+ - Generation-by-generation evolution progress
67
+ - Best parameters found
68
+ - Fitness scores (total return %)
69
+ - Evolution history chart
70
+
71
+ ---
72
+
73
+ ### 3. Knowledge-Based Strategy (`kbs_strategy_example.rb`)
74
+
75
+ **Build sophisticated rule-based trading systems with RETE forward chaining**
76
+
77
+ This example demonstrates the knowledge-based strategy system using RETE pattern matching for complex trading rules:
78
+
79
+ - Define trading rules with multiple conditions
80
+ - Forward-chaining inference engine
81
+ - Pattern matching on market conditions
82
+ - Confidence-based signal aggregation
83
+ - Custom rule creation via DSL
84
+
85
+ **Run it:**
86
+ ```bash
87
+ ./examples/kbs_strategy_example.rb
88
+ ```
89
+
90
+ **Key Examples:**
91
+ - Example 1: Using default rules (10 built-in patterns)
92
+ - Example 2: Creating custom rules
93
+ - Example 3: Backtesting KBS strategy
94
+ - Example 4: Interactive rule builder with complex conditions
95
+
96
+ **Output:**
97
+ - Trading signals with reasoning
98
+ - Working memory facts
99
+ - Rule firing explanations
100
+ - Backtest performance metrics
101
+
102
+ ---
103
+
104
+ ### 4. Real-Time Streaming (`realtime_stream_example.rb`)
105
+
106
+ **Process live stock price updates and generate on-the-fly trading signals**
107
+
108
+ This example shows how to build real-time trading signal systems:
109
+
110
+ - Event-driven architecture for live data
111
+ - Rolling window of recent prices
112
+ - On-demand indicator calculation
113
+ - Multi-strategy consensus signals
114
+ - WebSocket integration patterns
115
+
116
+ **Run it:**
117
+ ```bash
118
+ ./examples/realtime_stream_example.rb
119
+ ```
120
+
121
+ **Key Examples:**
122
+ - Example 1: Basic streaming setup with callbacks
123
+ - Example 2: Multi-strategy consensus
124
+ - Example 3: Accessing real-time indicators
125
+ - Example 4: Production WebSocket pattern
126
+
127
+ **Output:**
128
+ - Real-time signal notifications
129
+ - Price update monitoring
130
+ - Indicator calculations on-the-fly
131
+ - Production-ready patterns
132
+
133
+ ---
134
+
135
+ ### 5. FPL Analysis (`fpop_analysis_example.rb`)
136
+
137
+ **Analyze Future Period Loss/Profit to identify high-quality trading opportunities**
138
+
139
+ This example demonstrates how to use the FPL (Future Period Loss/Profit) analysis utilities to discover optimal entry points with controlled risk:
140
+
141
+ - Calculate min/max price changes over future periods
142
+ - Filter opportunities by magnitude and risk thresholds
143
+ - Identify inflection points (local minima/maxima)
144
+ - Analyze directional bias (UP, DOWN, UNCERTAIN, FLAT)
145
+ - Risk management with max FPL risk constraints
146
+
147
+ **Run it:**
148
+ ```bash
149
+ ./examples/fpop_analysis_example.rb
150
+ ```
151
+
152
+ **Key Examples:**
153
+ - Example 1: Basic FPL calculation
154
+ - Example 2: DataFrame FPL convenience methods
155
+ - Example 3: Comprehensive FPL analysis
156
+ - Example 4: Quality filtering (magnitude, risk, direction)
157
+ - Example 5: Integration with Strategy Generator
158
+
159
+ **Output:**
160
+ - FPL arrays (min/max deltas per price point)
161
+ - Risk metrics and directional analysis
162
+ - Filtered high-quality opportunities
163
+ - Integration with pattern discovery
164
+
165
+ ---
166
+
167
+ ### 6. Pattern Context System (`pattern_context_example.rb`)
168
+
169
+ **Discover context-aware trading patterns with market regime, seasonal, and sector analysis**
170
+
171
+ This comprehensive example demonstrates the Pattern Context system that addresses the reality that trading patterns are not universal - they depend on market conditions, seasonality, and sector behavior:
172
+
173
+ - **Market Regime Detection**: Identify bull/bear/sideways markets with volatility classification
174
+ - **Seasonal Analysis**: Discover calendar-dependent patterns (monthly/quarterly performance)
175
+ - **Sector Analysis**: Cross-stock pattern discovery with separate KBS blackboards per sector
176
+ - **Walk-Forward Validation**: Prevent overfitting with time-series cross-validation
177
+ - **Context-Aware Patterns**: Patterns know when they're valid (regime, season, sector)
178
+
179
+ **Run it:**
180
+ ```bash
181
+ ./examples/pattern_context_example.rb
182
+ ```
183
+
184
+ **Key Examples:**
185
+ - Example 1: Market regime detection and history
186
+ - Example 2: Seasonal pattern analysis
187
+ - Example 3: Sector analysis with KBS blackboards
188
+ - Example 4: Context-aware pattern discovery
189
+ - Example 5: Walk-forward validation
190
+ - Example 6: Runtime pattern validation
191
+
192
+ **Output:**
193
+ - Market regime classification (bull/bear/sideways)
194
+ - Best/worst months and quarters
195
+ - Sector-wide patterns across multiple stocks
196
+ - Validated patterns that work out-of-sample
197
+ - Runtime validation results
198
+
199
+ ---
200
+
201
+ ## Running All Examples
202
+
203
+ To run all examples in sequence:
204
+
205
+ ```bash
206
+ for example in examples/*.rb; do
207
+ echo "Running $example..."
208
+ ruby "$example"
209
+ echo ""
210
+ done
211
+ ```
212
+
213
+ ## Integration Examples
214
+
215
+ ### Combining Strategy Generator + Genetic Programming
216
+
217
+ ```ruby
218
+ # Discover patterns from history
219
+ generator = SQA::StrategyGenerator.new(stock: stock, min_gain_percent: 10.0)
220
+ patterns = generator.discover_patterns
221
+
222
+ # Use GP to optimize the top pattern's parameters
223
+ top_pattern = patterns.first
224
+ gp = SQA::GeneticProgram.new(stock: stock)
225
+ gp.define_genes(
226
+ rsi_period: (10..20).to_a,
227
+ # ... based on pattern conditions
228
+ )
229
+ best = gp.evolve
230
+ ```
231
+
232
+ ### Combining KBS + Stream
233
+
234
+ ```ruby
235
+ # Create KBS strategy
236
+ kbs = SQA::Strategy::KBS.new
237
+
238
+ # Add to real-time stream
239
+ stream = SQA::Stream.new(ticker: 'AAPL', strategies: [kbs])
240
+ stream.on_signal { |signal, data| execute_trade(signal, data) }
241
+
242
+ # Feed live data
243
+ stream.update(price: 150.25, volume: 1_000_000)
244
+ ```
245
+
246
+ ### Combining FPL + Pattern Discovery
247
+
248
+ ```ruby
249
+ # Use FPL analysis to filter high-quality opportunities
250
+ generator = SQA::StrategyGenerator.new(
251
+ stock: stock,
252
+ min_gain_percent: 8.0,
253
+ fpop: 10,
254
+ max_fpl_risk: 25.0 # Filter by risk
255
+ )
256
+
257
+ patterns = generator.discover_patterns
258
+ # Only includes opportunities with FPL risk ≤ 25%
259
+ ```
260
+
261
+ ### Combining Pattern Context + Sector Analysis
262
+
263
+ ```ruby
264
+ # Discover sector-wide patterns with context
265
+ analyzer = SQA::SectorAnalyzer.new
266
+ tech_stocks = ['AAPL', 'MSFT', 'GOOGL'].map { |t| SQA::Stock.new(ticker: t) }
267
+
268
+ tech_stocks.each { |stock| analyzer.add_stock(stock.ticker, sector: :technology) }
269
+
270
+ # Find patterns that work across the sector
271
+ patterns = analyzer.discover_sector_patterns(
272
+ :technology,
273
+ tech_stocks,
274
+ analyze_regime: true,
275
+ analyze_seasonal: true
276
+ )
277
+
278
+ # Patterns have full context metadata
279
+ patterns.first.context.market_regime # => :bull
280
+ patterns.first.context.sector # => :technology
281
+ patterns.first.context.valid_months # => [10, 11, 12]
282
+ ```
283
+
284
+ ### Full Pipeline: Generate → Optimize → Validate → Stream
285
+
286
+ ```ruby
287
+ # 1. Discover context-aware patterns
288
+ generator = SQA::StrategyGenerator.new(stock: stock, fpop: 10)
289
+ patterns = generator.discover_context_aware_patterns(
290
+ analyze_regime: true,
291
+ analyze_seasonal: true,
292
+ sector: :technology
293
+ )
294
+
295
+ # 2. Walk-forward validate
296
+ validated = generator.walk_forward_validate(
297
+ train_size: 250,
298
+ test_size: 60,
299
+ step_size: 30
300
+ )
301
+
302
+ # 3. Generate strategy from best validated pattern
303
+ discovered_strategy = generator.generate_strategy(pattern_index: 0)
304
+
305
+ # 4. Optimize with GP
306
+ gp = SQA::GeneticProgram.new(stock: stock)
307
+ # ... optimize discovered strategy parameters ...
308
+ optimized_strategy = gp.evolve
309
+
310
+ # 5. Deploy to real-time stream with runtime validation
311
+ stream = SQA::Stream.new(ticker: 'AAPL', strategies: [optimized_strategy])
312
+ stream.on_signal do |signal, data|
313
+ # Check if pattern is valid for current conditions
314
+ regime = SQA::MarketRegime.detect(stock)
315
+ if patterns.first.context.valid_for?(
316
+ date: Date.today,
317
+ regime: regime[:type],
318
+ sector: :technology
319
+ )
320
+ execute_trade(signal, data)
321
+ end
322
+ end
323
+ ```
324
+
325
+ ## Data Requirements
326
+
327
+ All examples require:
328
+ - Alpha Vantage API key: `export AV_API_KEY=your_key_here`
329
+ - Or use local CSV data in `~/sqa_data/`
330
+
331
+ ## Output Files
332
+
333
+ Examples may create output files in `/tmp/`:
334
+ - `/tmp/sqa_discovered_patterns.csv` - Exported patterns
335
+ - `/tmp/sqa_evolution_history.csv` - GP evolution history
336
+ - `/tmp/sqa_backtest_results.csv` - Backtest results
337
+
338
+ ## Next Steps
339
+
340
+ After running these examples:
341
+
342
+ 1. **Customize Parameters**: Adjust thresholds, periods, and constraints
343
+ 2. **Test on Multiple Stocks**: Validate patterns across different securities
344
+ 3. **Walk-Forward Validation**: Test on out-of-sample data
345
+ 4. **Combine Techniques**: Use strategy generator + GP + KBS together
346
+ 5. **Production Deployment**: Connect to real WebSocket data feeds
347
+
348
+ ## Educational Disclaimer
349
+
350
+ ⚠️ **Important**: All examples are for educational purposes only. Past performance does not guarantee future results. Always paper trade and thoroughly test before risking real capital.
351
+
352
+ ## Contributing
353
+
354
+ Found a bug or have an improvement? Please submit an issue or pull request!
@@ -0,0 +1,350 @@
1
+ #!/usr/bin/env ruby
2
+ # examples/advanced_features_example.rb
3
+ # frozen_string_literal: true
4
+
5
+ #####################################################################
6
+ ###
7
+ ## File: advanced_features_example.rb
8
+ ## Desc: Comprehensive examples of advanced SQA features
9
+ ## By: Dewayne VanHoozer (dvanhoozer@gmail.com)
10
+ #
11
+
12
+ require 'sqa'
13
+ require 'ostruct'
14
+
15
+ puts "\n" + "=" * 70
16
+ puts "SQA Advanced Features Examples"
17
+ puts "=" * 70
18
+
19
+ # Initialize SQA
20
+ SQA.init
21
+
22
+ #############################################################
23
+ ## Example 1: Risk Management
24
+ ##
25
+
26
+ puts "\n" + "-" * 70
27
+ puts "Example 1: Risk Management"
28
+ puts "-" * 70
29
+
30
+ # Load stock data
31
+ stock = SQA::Stock.new(ticker: 'AAPL')
32
+ prices = stock.df["adj_close_price"].to_a
33
+
34
+ # Calculate returns
35
+ returns = prices.each_cons(2).map { |a, b| (b - a) / a }
36
+
37
+ puts "\n1.1 Value at Risk (VaR)"
38
+ var_95 = SQA::RiskManager.var(returns, confidence: 0.95, method: :historical)
39
+ var_99 = SQA::RiskManager.var(returns, confidence: 0.99, method: :historical)
40
+ puts " 95% VaR: #{(var_95 * 100).round(2)}% (max expected daily loss)"
41
+ puts " 99% VaR: #{(var_99 * 100).round(2)}% (max expected daily loss)"
42
+
43
+ puts "\n1.2 Conditional VaR (CVaR / Expected Shortfall)"
44
+ cvar_95 = SQA::RiskManager.cvar(returns, confidence: 0.95)
45
+ puts " 95% CVaR: #{(cvar_95 * 100).round(2)}% (avg loss in worst 5% of days)"
46
+
47
+ puts "\n1.3 Position Sizing - Kelly Criterion"
48
+ # Calculate win rate and avg win/loss from recent trades
49
+ winning_returns = returns.select { |r| r > 0 }
50
+ losing_returns = returns.select { |r| r < 0 }
51
+
52
+ win_rate = winning_returns.size.to_f / returns.size
53
+ avg_win = winning_returns.sum / winning_returns.size.to_f
54
+ avg_loss = losing_returns.sum / losing_returns.size.to_f
55
+
56
+ position_size = SQA::RiskManager.kelly_criterion(
57
+ win_rate: win_rate,
58
+ avg_win: avg_win.abs,
59
+ avg_loss: avg_loss.abs,
60
+ capital: 10_000,
61
+ max_fraction: 0.25
62
+ )
63
+ puts " Optimal position size: $#{position_size.round(2)}"
64
+ puts " Win rate: #{(win_rate * 100).round(1)}%"
65
+ puts " Avg win: #{(avg_win * 100).round(2)}%"
66
+ puts " Avg loss: #{(avg_loss * 100).round(2)}%"
67
+
68
+ puts "\n1.4 Maximum Drawdown"
69
+ dd_result = SQA::RiskManager.max_drawdown(prices)
70
+ puts " Max drawdown: #{(dd_result[:max_drawdown] * 100).round(2)}%"
71
+ puts " Peak price: $#{dd_result[:peak_value].round(2)}"
72
+ puts " Trough price: $#{dd_result[:trough_value].round(2)}"
73
+
74
+ puts "\n1.5 Risk Metrics"
75
+ sharpe = SQA::RiskManager.sharpe_ratio(returns, risk_free_rate: 0.02)
76
+ sortino = SQA::RiskManager.sortino_ratio(returns, target_return: 0.0)
77
+ calmar = SQA::RiskManager.calmar_ratio(returns)
78
+ puts " Sharpe Ratio: #{sharpe.round(2)}"
79
+ puts " Sortino Ratio: #{sortino.round(2)}"
80
+ puts " Calmar Ratio: #{calmar.round(2)}"
81
+
82
+ puts "\n1.6 Monte Carlo Simulation"
83
+ simulation = SQA::RiskManager.monte_carlo_simulation(
84
+ initial_capital: 10_000,
85
+ returns: returns,
86
+ periods: 252, # 1 year
87
+ simulations: 1000
88
+ )
89
+ puts " Median outcome (1 year): $#{simulation[:median].round(2)}"
90
+ puts " 95% confidence interval: $#{simulation[:percentile_5].round(2)} - $#{simulation[:percentile_95].round(2)}"
91
+ puts " Best case: $#{simulation[:max].round(2)}"
92
+ puts " Worst case: $#{simulation[:min].round(2)}"
93
+
94
+ #############################################################
95
+ ## Example 2: Portfolio Optimization
96
+ ##
97
+
98
+ puts "\n" + "-" * 70
99
+ puts "Example 2: Portfolio Optimization"
100
+ puts "-" * 70
101
+
102
+ # Load multiple stocks
103
+ tickers = ['AAPL', 'MSFT', 'GOOGL']
104
+ stocks = tickers.map { |t| SQA::Stock.new(ticker: t) }
105
+
106
+ # Get returns for each stock (last 100 days)
107
+ returns_matrix = stocks.map do |stock|
108
+ prices = stock.df["adj_close_price"].to_a.last(100)
109
+ prices.each_cons(2).map { |a, b| (b - a) / a }
110
+ end
111
+
112
+ puts "\n2.1 Maximum Sharpe Ratio Portfolio"
113
+ max_sharpe = SQA::PortfolioOptimizer.maximum_sharpe(returns_matrix, risk_free_rate: 0.02)
114
+ puts " Optimal weights:"
115
+ tickers.each_with_index do |ticker, i|
116
+ puts " #{ticker}: #{(max_sharpe[:weights][i] * 100).round(1)}%"
117
+ end
118
+ puts " Sharpe ratio: #{max_sharpe[:sharpe].round(2)}"
119
+ puts " Expected return: #{(max_sharpe[:return] * 100).round(2)}%"
120
+ puts " Volatility: #{(max_sharpe[:volatility] * 100).round(2)}%"
121
+
122
+ puts "\n2.2 Minimum Variance Portfolio"
123
+ min_var = SQA::PortfolioOptimizer.minimum_variance(returns_matrix)
124
+ puts " Optimal weights:"
125
+ tickers.each_with_index do |ticker, i|
126
+ puts " #{ticker}: #{(min_var[:weights][i] * 100).round(1)}%"
127
+ end
128
+ puts " Volatility: #{(min_var[:volatility] * 100).round(2)}%"
129
+
130
+ puts "\n2.3 Risk Parity Portfolio"
131
+ risk_parity = SQA::PortfolioOptimizer.risk_parity(returns_matrix)
132
+ puts " Optimal weights:"
133
+ tickers.each_with_index do |ticker, i|
134
+ puts " #{ticker}: #{(risk_parity[:weights][i] * 100).round(1)}%"
135
+ end
136
+
137
+ puts "\n2.4 Multi-Objective Optimization"
138
+ multi_obj = SQA::PortfolioOptimizer.multi_objective(
139
+ returns_matrix,
140
+ objectives: {
141
+ maximize_return: 0.4,
142
+ minimize_volatility: 0.3,
143
+ minimize_drawdown: 0.3
144
+ }
145
+ )
146
+ puts " Optimal weights:"
147
+ tickers.each_with_index do |ticker, i|
148
+ puts " #{ticker}: #{(multi_obj[:weights][i] * 100).round(1)}%"
149
+ end
150
+ puts " Expected return: #{(multi_obj[:return] * 100).round(2)}%"
151
+ puts " Volatility: #{(multi_obj[:volatility] * 100).round(2)}%"
152
+ puts " Max drawdown: #{(multi_obj[:max_drawdown] * 100).round(2)}%"
153
+
154
+ #############################################################
155
+ ## Example 3: Ensemble Methods
156
+ ##
157
+
158
+ puts "\n" + "-" * 70
159
+ puts "Example 3: Ensemble Strategy Combination"
160
+ puts "-" * 70
161
+
162
+ # Create ensemble of strategies
163
+ ensemble = SQA::Ensemble.new(
164
+ strategies: [SQA::Strategy::RSI, SQA::Strategy::MACD, SQA::Strategy::SMA],
165
+ voting_method: :majority
166
+ )
167
+
168
+ # Create vector for signal generation
169
+ prices = stock.df["adj_close_price"].to_a
170
+ vector = OpenStruct.new(
171
+ prices: prices,
172
+ close: prices.last,
173
+ rsi: SQAI.rsi(prices, period: 14).last,
174
+ macd: SQAI.macd(prices, fast_period: 12, slow_period: 26).last,
175
+ macd_signal: SQAI.ema(prices, period: 9).last,
176
+ sma_20: SQAI.sma(prices, period: 20).last,
177
+ sma_50: SQAI.sma(prices, period: 50).last
178
+ )
179
+
180
+ puts "\n3.1 Majority Voting"
181
+ signal = ensemble.majority_vote(vector)
182
+ puts " Ensemble signal: #{signal}"
183
+
184
+ puts "\n3.2 Weighted Voting"
185
+ ensemble.instance_variable_set(:@voting_method, :weighted)
186
+ ensemble.instance_variable_set(:@weights, [0.5, 0.3, 0.2]) # Give more weight to RSI
187
+ signal = ensemble.weighted_vote(vector)
188
+ puts " Weighted signal (RSI 50%, MACD 30%, SMA 20%): #{signal}"
189
+
190
+ puts "\n3.3 Strategy Rotation Based on Market Conditions"
191
+ selected_strategy = ensemble.rotate(stock)
192
+ puts " Selected strategy for current market: #{selected_strategy}"
193
+
194
+ #############################################################
195
+ ## Example 4: Multi-Timeframe Analysis
196
+ ##
197
+
198
+ puts "\n" + "-" * 70
199
+ puts "Example 4: Multi-Timeframe Analysis"
200
+ puts "-" * 70
201
+
202
+ mta = SQA::MultiTimeframe.new(stock: stock)
203
+
204
+ puts "\n4.1 Trend Alignment"
205
+ alignment = mta.trend_alignment(lookback: 20)
206
+ puts " Daily trend: #{alignment[:daily]}"
207
+ puts " Weekly trend: #{alignment[:weekly]}"
208
+ puts " Monthly trend: #{alignment[:monthly]}"
209
+ puts " All timeframes aligned? #{alignment[:aligned]}"
210
+ puts " Overall direction: #{alignment[:direction]}"
211
+
212
+ puts "\n4.2 Multi-Timeframe Signal"
213
+ signal = mta.signal(
214
+ strategy_class: SQA::Strategy::RSI,
215
+ higher_timeframe: :weekly,
216
+ lower_timeframe: :daily
217
+ )
218
+ puts " Signal (weekly trend + daily timing): #{signal}"
219
+
220
+ puts "\n4.3 Support/Resistance Across Timeframes"
221
+ levels = mta.support_resistance(tolerance: 0.02)
222
+ puts " Current price: $#{levels[:current_price].round(2)}"
223
+ puts " Support levels (from multiple timeframes):"
224
+ levels[:support].first(3).each do |level|
225
+ puts " $#{level[:price].round(2)} (appears in #{level[:count]} timeframes)"
226
+ end
227
+ puts " Resistance levels (from multiple timeframes):"
228
+ levels[:resistance].first(3).each do |level|
229
+ puts " $#{level[:price].round(2)} (appears in #{level[:count]} timeframes)"
230
+ end
231
+
232
+ puts "\n4.4 Divergence Detection"
233
+ divergences = mta.detect_divergence
234
+ divergences.each do |timeframe, divergence|
235
+ puts " #{timeframe}: #{divergence}"
236
+ end
237
+
238
+ #############################################################
239
+ ## Example 5: Pattern Similarity Search
240
+ ##
241
+
242
+ puts "\n" + "-" * 70
243
+ puts "Example 5: Pattern Similarity Search"
244
+ puts "-" * 70
245
+
246
+ matcher = SQA::PatternMatcher.new(stock: stock)
247
+
248
+ puts "\n5.1 Find Similar Historical Patterns"
249
+ similar = matcher.find_similar(lookback: 10, num_matches: 5, method: :euclidean)
250
+ puts " Found #{similar.size} similar 10-day patterns:"
251
+ similar.each_with_index do |match, i|
252
+ puts " #{i + 1}. Distance: #{match[:distance].round(4)}, Future return: #{(match[:future_return] * 100).round(2)}%"
253
+ end
254
+
255
+ puts "\n5.2 Forecast Based on Similar Patterns"
256
+ forecast = matcher.forecast(lookback: 10, forecast_periods: 5, num_matches: 10)
257
+ current_price = forecast[:current_price]
258
+ forecast_price = forecast[:forecast_price]
259
+ lower, upper = forecast[:confidence_interval_95]
260
+
261
+ puts " Current price: $#{current_price.round(2)}"
262
+ puts " Forecast price (5 days): $#{forecast_price.round(2)} (#{((forecast_price - current_price) / current_price * 100).round(2)}%)"
263
+ puts " 95% confidence interval: $#{lower.round(2)} - $#{upper.round(2)}"
264
+ puts " Based on #{forecast[:num_matches]} similar historical patterns"
265
+
266
+ puts "\n5.3 Chart Pattern Detection"
267
+ [:double_top, :double_bottom, :head_and_shoulders, :triangle].each do |pattern_type|
268
+ patterns = matcher.detect_chart_pattern(pattern_type)
269
+ if patterns.any?
270
+ puts " Found #{patterns.size} #{pattern_type.to_s.gsub('_', ' ')} pattern(s)"
271
+ patterns.first(2).each do |pattern|
272
+ puts " - #{pattern.inspect}"
273
+ end
274
+ else
275
+ puts " No #{pattern_type.to_s.gsub('_', ' ')} patterns detected"
276
+ end
277
+ end
278
+
279
+ puts "\n5.4 Pattern Clustering"
280
+ clusters = matcher.cluster_patterns(pattern_length: 10, num_clusters: 5)
281
+ puts " Clustered patterns into #{clusters.size} groups:"
282
+ clusters.each_with_index do |cluster, i|
283
+ puts " Cluster #{i + 1}: #{cluster.size} similar patterns"
284
+ end
285
+
286
+ #############################################################
287
+ ## Example 6: Combined Advanced Workflow
288
+ ##
289
+
290
+ puts "\n" + "-" * 70
291
+ puts "Example 6: Complete Advanced Workflow"
292
+ puts "-" * 70
293
+ puts "(Combining all features for optimal trading decision)"
294
+
295
+ puts "\n6.1 Risk Assessment"
296
+ var_95 = SQA::RiskManager.var(returns, confidence: 0.95)
297
+ cvar_95 = SQA::RiskManager.cvar(returns, confidence: 0.95)
298
+ puts " VaR (95%): #{(var_95 * 100).round(2)}%"
299
+ puts " CVaR (95%): #{(cvar_95 * 100).round(2)}%"
300
+
301
+ # Position size based on risk
302
+ position_size = SQA::RiskManager.fixed_fractional(capital: 10_000, risk_fraction: 0.02)
303
+ puts " Position size (2% risk): $#{position_size.round(2)}"
304
+
305
+ puts "\n6.2 Multi-Timeframe Confirmation"
306
+ alignment = mta.trend_alignment
307
+ if alignment[:aligned]
308
+ puts " ✓ All timeframes aligned #{alignment[:direction]}"
309
+ else
310
+ puts " ✗ Mixed timeframe signals - exercise caution"
311
+ end
312
+
313
+ puts "\n6.3 Ensemble Strategy Signal"
314
+ signal = ensemble.signal(vector)
315
+ puts " Ensemble recommendation: #{signal.to_s.upcase}"
316
+
317
+ puts "\n6.4 Pattern-Based Forecast"
318
+ forecast = matcher.forecast(lookback: 10, forecast_periods: 5)
319
+ expected_return = forecast[:forecast_return]
320
+ puts " Expected return (5 days): #{(expected_return * 100).round(2)}%"
321
+
322
+ puts "\n6.5 Final Trading Decision"
323
+ decision = if signal == :buy && alignment[:aligned] && expected_return > 0.02
324
+ "STRONG BUY"
325
+ elsif signal == :buy && expected_return > 0.01
326
+ "BUY"
327
+ elsif signal == :sell && expected_return < -0.02
328
+ "STRONG SELL"
329
+ elsif signal == :sell
330
+ "SELL"
331
+ else
332
+ "HOLD"
333
+ end
334
+
335
+ puts " Final decision: #{decision}"
336
+ puts " Position size: $#{position_size.round(2)}"
337
+ puts " Stop loss: $#{(prices.last * (1 + var_95)).round(2)}"
338
+ puts " Target: $#{(prices.last * (1 + expected_return)).round(2)}"
339
+
340
+ puts "\n" + "=" * 70
341
+ puts "Advanced Features Examples Complete!"
342
+ puts "=" * 70
343
+ puts "\nThese examples demonstrate:"
344
+ puts "1. Risk Management: VaR, CVaR, position sizing, risk metrics"
345
+ puts "2. Portfolio Optimization: Sharpe, min variance, risk parity, multi-objective"
346
+ puts "3. Ensemble Methods: Strategy combination, voting, rotation"
347
+ puts "4. Multi-Timeframe Analysis: Trend alignment, multi-TF signals, S/R levels"
348
+ puts "5. Pattern Matching: Similar patterns, forecasting, chart patterns"
349
+ puts "6. Complete workflow combining all features"
350
+ puts "\n"