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.
- checksums.yaml +4 -4
- data/.goose/memory/development.txt +3 -0
- data/.semver +6 -0
- data/ARCHITECTURE.md +648 -0
- data/CHANGELOG.md +82 -0
- data/CLAUDE.md +653 -0
- data/COMMITS.md +196 -0
- data/DATAFRAME_ARCHITECTURE_REVIEW.md +421 -0
- data/NEXT-STEPS.md +154 -0
- data/README.md +812 -262
- data/TASKS.md +358 -0
- data/TEST_RESULTS.md +140 -0
- data/TODO.md +42 -0
- data/_notes.txt +25 -0
- data/bin/sqa-console +11 -0
- data/data/talk_talk.json +103284 -0
- data/develop_summary.md +313 -0
- data/docs/advanced/backtesting.md +206 -0
- data/docs/advanced/ensemble.md +68 -0
- data/docs/advanced/fpop.md +153 -0
- data/docs/advanced/index.md +112 -0
- data/docs/advanced/multi-timeframe.md +67 -0
- data/docs/advanced/pattern-matcher.md +75 -0
- data/docs/advanced/portfolio-optimizer.md +79 -0
- data/docs/advanced/portfolio.md +166 -0
- data/docs/advanced/risk-management.md +210 -0
- data/docs/advanced/strategy-generator.md +158 -0
- data/docs/advanced/streaming.md +209 -0
- data/docs/ai_and_ml.md +80 -0
- data/docs/api/dataframe.md +1115 -0
- data/docs/api/index.md +126 -0
- data/docs/assets/css/custom.css +88 -0
- data/docs/assets/js/mathjax.js +18 -0
- data/docs/concepts/index.md +68 -0
- data/docs/contributing/index.md +60 -0
- data/docs/data-sources/index.md +66 -0
- data/docs/data_frame.md +317 -97
- data/docs/factors_that_impact_price.md +26 -0
- data/docs/finviz.md +11 -0
- data/docs/fx_pro_bit.md +25 -0
- data/docs/genetic_programming.md +104 -0
- data/docs/getting-started/index.md +123 -0
- data/docs/getting-started/installation.md +229 -0
- data/docs/getting-started/quick-start.md +244 -0
- data/docs/i_gotta_an_idea.md +22 -0
- data/docs/index.md +163 -0
- data/docs/indicators/index.md +97 -0
- data/docs/indicators.md +110 -24
- data/docs/options.md +8 -0
- data/docs/strategies/bollinger-bands.md +146 -0
- data/docs/strategies/consensus.md +64 -0
- data/docs/strategies/custom.md +310 -0
- data/docs/strategies/ema.md +53 -0
- data/docs/strategies/index.md +92 -0
- data/docs/strategies/kbs.md +164 -0
- data/docs/strategies/macd.md +96 -0
- data/docs/strategies/market-profile.md +54 -0
- data/docs/strategies/mean-reversion.md +58 -0
- data/docs/strategies/rsi.md +95 -0
- data/docs/strategies/sma.md +55 -0
- data/docs/strategies/stochastic.md +63 -0
- data/docs/strategies/volume-breakout.md +54 -0
- data/docs/tags.md +7 -0
- data/docs/true_strength_index.md +46 -0
- data/docs/weighted_moving_average.md +48 -0
- data/examples/README.md +354 -0
- data/examples/advanced_features_example.rb +350 -0
- data/examples/fpop_analysis_example.rb +191 -0
- data/examples/genetic_programming_example.rb +148 -0
- data/examples/kbs_strategy_example.rb +208 -0
- data/examples/pattern_context_example.rb +300 -0
- data/examples/rails_app/Gemfile +34 -0
- data/examples/rails_app/README.md +416 -0
- data/examples/rails_app/app/assets/javascripts/application.js +107 -0
- data/examples/rails_app/app/assets/stylesheets/application.css +659 -0
- data/examples/rails_app/app/controllers/analysis_controller.rb +11 -0
- data/examples/rails_app/app/controllers/api/v1/stocks_controller.rb +227 -0
- data/examples/rails_app/app/controllers/application_controller.rb +22 -0
- data/examples/rails_app/app/controllers/backtest_controller.rb +11 -0
- data/examples/rails_app/app/controllers/dashboard_controller.rb +21 -0
- data/examples/rails_app/app/controllers/portfolio_controller.rb +7 -0
- data/examples/rails_app/app/views/analysis/show.html.erb +209 -0
- data/examples/rails_app/app/views/backtest/show.html.erb +171 -0
- data/examples/rails_app/app/views/dashboard/index.html.erb +118 -0
- data/examples/rails_app/app/views/dashboard/show.html.erb +408 -0
- data/examples/rails_app/app/views/errors/show.html.erb +17 -0
- data/examples/rails_app/app/views/layouts/application.html.erb +60 -0
- data/examples/rails_app/app/views/portfolio/index.html.erb +33 -0
- data/examples/rails_app/bin/rails +6 -0
- data/examples/rails_app/config/application.rb +45 -0
- data/examples/rails_app/config/boot.rb +5 -0
- data/examples/rails_app/config/database.yml +18 -0
- data/examples/rails_app/config/environment.rb +11 -0
- data/examples/rails_app/config/routes.rb +26 -0
- data/examples/rails_app/config.ru +8 -0
- data/examples/realtime_stream_example.rb +274 -0
- data/examples/sinatra_app/Gemfile +22 -0
- data/examples/sinatra_app/QUICKSTART.md +159 -0
- data/examples/sinatra_app/README.md +461 -0
- data/examples/sinatra_app/app.rb +344 -0
- data/examples/sinatra_app/config.ru +5 -0
- data/examples/sinatra_app/public/css/style.css +659 -0
- data/examples/sinatra_app/public/js/app.js +107 -0
- data/examples/sinatra_app/views/analyze.erb +306 -0
- data/examples/sinatra_app/views/backtest.erb +325 -0
- data/examples/sinatra_app/views/dashboard.erb +419 -0
- data/examples/sinatra_app/views/error.erb +58 -0
- data/examples/sinatra_app/views/index.erb +118 -0
- data/examples/sinatra_app/views/layout.erb +61 -0
- data/examples/sinatra_app/views/portfolio.erb +43 -0
- data/examples/strategy_generator_example.rb +346 -0
- data/hsa_portfolio.csv +11 -0
- data/justfile +0 -0
- data/lib/api/alpha_vantage_api.rb +462 -0
- data/lib/sqa/backtest.rb +329 -0
- data/lib/sqa/data_frame/alpha_vantage.rb +43 -65
- data/lib/sqa/data_frame/data.rb +92 -0
- data/lib/sqa/data_frame/yahoo_finance.rb +35 -43
- data/lib/sqa/data_frame.rb +148 -243
- data/lib/sqa/ensemble.rb +359 -0
- data/lib/sqa/fpop.rb +199 -0
- data/lib/sqa/gp.rb +259 -0
- data/lib/sqa/indicator.rb +5 -8
- data/lib/sqa/init.rb +15 -8
- data/lib/sqa/market_regime.rb +240 -0
- data/lib/sqa/multi_timeframe.rb +379 -0
- data/lib/sqa/pattern_matcher.rb +497 -0
- data/lib/sqa/portfolio.rb +260 -6
- data/lib/sqa/portfolio_optimizer.rb +377 -0
- data/lib/sqa/risk_manager.rb +442 -0
- data/lib/sqa/seasonal_analyzer.rb +209 -0
- data/lib/sqa/sector_analyzer.rb +300 -0
- data/lib/sqa/stock.rb +67 -125
- data/lib/sqa/strategy/bollinger_bands.rb +42 -0
- data/lib/sqa/strategy/consensus.rb +5 -2
- data/lib/sqa/strategy/kbs_strategy.rb +470 -0
- data/lib/sqa/strategy/macd.rb +46 -0
- data/lib/sqa/strategy/mp.rb +1 -1
- data/lib/sqa/strategy/stochastic.rb +60 -0
- data/lib/sqa/strategy/volume_breakout.rb +57 -0
- data/lib/sqa/strategy.rb +5 -0
- data/lib/sqa/strategy_generator.rb +947 -0
- data/lib/sqa/stream.rb +361 -0
- data/lib/sqa/version.rb +1 -7
- data/lib/sqa.rb +23 -16
- data/main.just +81 -0
- data/mkdocs.yml +288 -0
- data/trace.log +0 -0
- metadata +261 -51
- data/bin/sqa +0 -6
- data/lib/patches/dry-cli.rb +0 -228
- data/lib/sqa/activity.rb +0 -10
- data/lib/sqa/cli.rb +0 -62
- data/lib/sqa/commands/analysis.rb +0 -309
- data/lib/sqa/commands/base.rb +0 -139
- data/lib/sqa/commands/web.rb +0 -199
- data/lib/sqa/commands.rb +0 -22
- data/lib/sqa/constants.rb +0 -23
- data/lib/sqa/indicator/average_true_range.rb +0 -33
- data/lib/sqa/indicator/bollinger_bands.rb +0 -28
- data/lib/sqa/indicator/candlestick_pattern_recognizer.rb +0 -60
- data/lib/sqa/indicator/donchian_channel.rb +0 -29
- data/lib/sqa/indicator/double_top_bottom_pattern.rb +0 -34
- data/lib/sqa/indicator/elliott_wave_theory.rb +0 -57
- data/lib/sqa/indicator/exponential_moving_average.rb +0 -25
- data/lib/sqa/indicator/exponential_moving_average_trend.rb +0 -36
- data/lib/sqa/indicator/fibonacci_retracement.rb +0 -23
- data/lib/sqa/indicator/head_and_shoulders_pattern.rb +0 -26
- data/lib/sqa/indicator/market_profile.rb +0 -32
- data/lib/sqa/indicator/mean_reversion.rb +0 -37
- data/lib/sqa/indicator/momentum.rb +0 -28
- data/lib/sqa/indicator/moving_average_convergence_divergence.rb +0 -29
- data/lib/sqa/indicator/peaks_and_valleys.rb +0 -29
- data/lib/sqa/indicator/predict_next_value.rb +0 -202
- data/lib/sqa/indicator/relative_strength_index.rb +0 -47
- data/lib/sqa/indicator/simple_moving_average.rb +0 -24
- data/lib/sqa/indicator/simple_moving_average_trend.rb +0 -32
- data/lib/sqa/indicator/stochastic_oscillator.rb +0 -68
- data/lib/sqa/indicator/true_range.rb +0 -39
- data/lib/sqa/trade.rb +0 -26
data/examples/README.md
ADDED
|
@@ -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"
|