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
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
<div class="dashboard">
|
|
2
|
+
<div class="dashboard-header">
|
|
3
|
+
<div class="ticker-info">
|
|
4
|
+
<h1><%= @ticker %> - Strategy Backtesting</h1>
|
|
5
|
+
</div>
|
|
6
|
+
<div class="header-actions">
|
|
7
|
+
<button onclick="location.href='/dashboard/<%= @ticker %>'" class="btn btn-secondary">
|
|
8
|
+
<i class="fas fa-chart-line"></i> Dashboard
|
|
9
|
+
</button>
|
|
10
|
+
<button onclick="location.href='/analyze/<%= @ticker %>'" class="btn btn-secondary">
|
|
11
|
+
<i class="fas fa-analytics"></i> Analysis
|
|
12
|
+
</button>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<!-- Strategy Selection -->
|
|
17
|
+
<div class="chart-container">
|
|
18
|
+
<div class="chart-header">
|
|
19
|
+
<h2><i class="fas fa-cogs"></i> Select Strategy</h2>
|
|
20
|
+
</div>
|
|
21
|
+
<div class="strategy-selector">
|
|
22
|
+
<div class="strategy-grid">
|
|
23
|
+
<div class="strategy-option" onclick="selectStrategy('RSI')">
|
|
24
|
+
<div class="strategy-icon"><i class="fas fa-wave-square"></i></div>
|
|
25
|
+
<h3>RSI</h3>
|
|
26
|
+
<p>Relative Strength Index</p>
|
|
27
|
+
</div>
|
|
28
|
+
<div class="strategy-option" onclick="selectStrategy('MACD')">
|
|
29
|
+
<div class="strategy-icon"><i class="fas fa-signal"></i></div>
|
|
30
|
+
<h3>MACD</h3>
|
|
31
|
+
<p>Moving Average Convergence Divergence</p>
|
|
32
|
+
</div>
|
|
33
|
+
<div class="strategy-option" onclick="selectStrategy('SMA')">
|
|
34
|
+
<div class="strategy-icon"><i class="fas fa-chart-line"></i></div>
|
|
35
|
+
<h3>SMA</h3>
|
|
36
|
+
<p>Simple Moving Average</p>
|
|
37
|
+
</div>
|
|
38
|
+
<div class="strategy-option" onclick="selectStrategy('EMA')">
|
|
39
|
+
<div class="strategy-icon"><i class="fas fa-chart-area"></i></div>
|
|
40
|
+
<h3>EMA</h3>
|
|
41
|
+
<p>Exponential Moving Average</p>
|
|
42
|
+
</div>
|
|
43
|
+
<div class="strategy-option" onclick="selectStrategy('BollingerBands')">
|
|
44
|
+
<div class="strategy-icon"><i class="fas fa-chart-candlestick"></i></div>
|
|
45
|
+
<h3>Bollinger Bands</h3>
|
|
46
|
+
<p>Volatility-based bands</p>
|
|
47
|
+
</div>
|
|
48
|
+
<div class="strategy-option" onclick="selectStrategy('KBS')">
|
|
49
|
+
<div class="strategy-icon"><i class="fas fa-brain"></i></div>
|
|
50
|
+
<h3>KBS</h3>
|
|
51
|
+
<p>Knowledge-Based Strategy</p>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<!-- Backtest Results -->
|
|
58
|
+
<div class="chart-container">
|
|
59
|
+
<div class="chart-header">
|
|
60
|
+
<h2><i class="fas fa-chart-bar"></i> Backtest Results</h2>
|
|
61
|
+
</div>
|
|
62
|
+
<div id="backtestResults" class="backtest-results">
|
|
63
|
+
<p class="hint">Select a strategy above to run backtest</p>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<!-- Strategy Comparison -->
|
|
68
|
+
<div class="chart-container">
|
|
69
|
+
<div class="chart-header">
|
|
70
|
+
<h2><i class="fas fa-trophy"></i> Compare All Strategies</h2>
|
|
71
|
+
<button onclick="compareStrategies()" class="btn btn-primary">
|
|
72
|
+
<i class="fas fa-play"></i> Run Comparison
|
|
73
|
+
</button>
|
|
74
|
+
</div>
|
|
75
|
+
<div id="comparisonResults" class="comparison-results">
|
|
76
|
+
<p class="hint">Click "Run Comparison" to backtest all strategies</p>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
<style>
|
|
82
|
+
.strategy-selector {
|
|
83
|
+
padding: 1rem 0;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.strategy-grid {
|
|
87
|
+
display: grid;
|
|
88
|
+
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
|
89
|
+
gap: 1.5rem;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.strategy-option {
|
|
93
|
+
background: var(--light-bg);
|
|
94
|
+
padding: 2rem 1.5rem;
|
|
95
|
+
border-radius: 12px;
|
|
96
|
+
text-align: center;
|
|
97
|
+
cursor: pointer;
|
|
98
|
+
transition: all 0.3s ease;
|
|
99
|
+
border: 2px solid transparent;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.strategy-option:hover {
|
|
103
|
+
transform: translateY(-5px);
|
|
104
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
|
|
105
|
+
border-color: var(--primary-color);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.strategy-icon {
|
|
109
|
+
font-size: 3rem;
|
|
110
|
+
color: var(--primary-color);
|
|
111
|
+
margin-bottom: 1rem;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.strategy-option h3 {
|
|
115
|
+
font-size: 1.25rem;
|
|
116
|
+
margin-bottom: 0.5rem;
|
|
117
|
+
color: var(--text-primary);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.strategy-option p {
|
|
121
|
+
font-size: 0.875rem;
|
|
122
|
+
color: var(--text-secondary);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.backtest-results,
|
|
126
|
+
.comparison-results {
|
|
127
|
+
padding: 1rem 0;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.results-metrics {
|
|
131
|
+
display: grid;
|
|
132
|
+
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
133
|
+
gap: 1.5rem;
|
|
134
|
+
margin-bottom: 2rem;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.result-metric {
|
|
138
|
+
background: var(--light-bg);
|
|
139
|
+
padding: 1.5rem;
|
|
140
|
+
border-radius: 8px;
|
|
141
|
+
border-left: 4px solid var(--primary-color);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.result-metric-label {
|
|
145
|
+
font-size: 0.875rem;
|
|
146
|
+
color: var(--text-secondary);
|
|
147
|
+
text-transform: uppercase;
|
|
148
|
+
letter-spacing: 0.5px;
|
|
149
|
+
margin-bottom: 0.5rem;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.result-metric-value {
|
|
153
|
+
font-size: 2rem;
|
|
154
|
+
font-weight: 700;
|
|
155
|
+
color: var(--text-primary);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.result-metric-value.positive {
|
|
159
|
+
color: var(--positive-color);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.result-metric-value.negative {
|
|
163
|
+
color: var(--negative-color);
|
|
164
|
+
}
|
|
165
|
+
</style>
|
|
166
|
+
|
|
167
|
+
<script>
|
|
168
|
+
const ticker = '<%= @ticker %>';
|
|
169
|
+
let selectedStrategy = null;
|
|
170
|
+
|
|
171
|
+
async function selectStrategy(strategy) {
|
|
172
|
+
selectedStrategy = strategy;
|
|
173
|
+
|
|
174
|
+
// Visual feedback
|
|
175
|
+
document.querySelectorAll('.strategy-option').forEach(el => {
|
|
176
|
+
el.style.borderColor = '';
|
|
177
|
+
});
|
|
178
|
+
event.currentTarget.style.borderColor = 'var(--primary-color)';
|
|
179
|
+
|
|
180
|
+
// Run backtest
|
|
181
|
+
await runBacktest(strategy);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async function runBacktest(strategy) {
|
|
185
|
+
const resultsDiv = document.getElementById('backtestResults');
|
|
186
|
+
resultsDiv.innerHTML = '<p class="loading"><i class="fas fa-spinner fa-spin"></i> Running backtest...</p>';
|
|
187
|
+
|
|
188
|
+
try {
|
|
189
|
+
const formData = new FormData();
|
|
190
|
+
formData.append('strategy', strategy);
|
|
191
|
+
|
|
192
|
+
const response = await fetch(`/api/backtest/${ticker}`, {
|
|
193
|
+
method: 'POST',
|
|
194
|
+
body: formData
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
const results = await response.json();
|
|
198
|
+
|
|
199
|
+
const html = `
|
|
200
|
+
<h3 style="margin-bottom: 1.5rem; color: var(--text-primary);">
|
|
201
|
+
${strategy} Strategy Results
|
|
202
|
+
</h3>
|
|
203
|
+
<div class="results-metrics">
|
|
204
|
+
<div class="result-metric">
|
|
205
|
+
<div class="result-metric-label">Total Return</div>
|
|
206
|
+
<div class="result-metric-value ${results.total_return >= 0 ? 'positive' : 'negative'}">
|
|
207
|
+
${results.total_return.toFixed(2)}%
|
|
208
|
+
</div>
|
|
209
|
+
</div>
|
|
210
|
+
<div class="result-metric">
|
|
211
|
+
<div class="result-metric-label">Annualized Return</div>
|
|
212
|
+
<div class="result-metric-value ${results.annualized_return >= 0 ? 'positive' : 'negative'}">
|
|
213
|
+
${results.annualized_return.toFixed(2)}%
|
|
214
|
+
</div>
|
|
215
|
+
</div>
|
|
216
|
+
<div class="result-metric">
|
|
217
|
+
<div class="result-metric-label">Sharpe Ratio</div>
|
|
218
|
+
<div class="result-metric-value">
|
|
219
|
+
${results.sharpe_ratio.toFixed(2)}
|
|
220
|
+
</div>
|
|
221
|
+
</div>
|
|
222
|
+
<div class="result-metric">
|
|
223
|
+
<div class="result-metric-label">Max Drawdown</div>
|
|
224
|
+
<div class="result-metric-value negative">
|
|
225
|
+
${results.max_drawdown.toFixed(2)}%
|
|
226
|
+
</div>
|
|
227
|
+
</div>
|
|
228
|
+
<div class="result-metric">
|
|
229
|
+
<div class="result-metric-label">Win Rate</div>
|
|
230
|
+
<div class="result-metric-value">
|
|
231
|
+
${results.win_rate.toFixed(2)}%
|
|
232
|
+
</div>
|
|
233
|
+
</div>
|
|
234
|
+
<div class="result-metric">
|
|
235
|
+
<div class="result-metric-label">Total Trades</div>
|
|
236
|
+
<div class="result-metric-value">
|
|
237
|
+
${results.total_trades}
|
|
238
|
+
</div>
|
|
239
|
+
</div>
|
|
240
|
+
<div class="result-metric">
|
|
241
|
+
<div class="result-metric-label">Profit Factor</div>
|
|
242
|
+
<div class="result-metric-value ${results.profit_factor >= 1 ? 'positive' : 'negative'}">
|
|
243
|
+
${results.profit_factor.toFixed(2)}
|
|
244
|
+
</div>
|
|
245
|
+
</div>
|
|
246
|
+
<div class="result-metric">
|
|
247
|
+
<div class="result-metric-label">Avg Win / Loss</div>
|
|
248
|
+
<div class="result-metric-value">
|
|
249
|
+
${results.avg_win.toFixed(2)}% / ${results.avg_loss.toFixed(2)}%
|
|
250
|
+
</div>
|
|
251
|
+
</div>
|
|
252
|
+
</div>
|
|
253
|
+
<div style="padding: 1.5rem; background: var(--light-bg); border-radius: 8px; margin-top: 1rem;">
|
|
254
|
+
<h4 style="margin-bottom: 1rem; color: var(--text-primary);">Strategy Performance Summary</h4>
|
|
255
|
+
<p style="color: var(--text-secondary); line-height: 1.8;">
|
|
256
|
+
The ${strategy} strategy generated a total return of
|
|
257
|
+
<strong class="${results.total_return >= 0 ? 'positive' : 'negative'}">
|
|
258
|
+
${results.total_return.toFixed(2)}%
|
|
259
|
+
</strong> over the backtest period with ${results.total_trades} trades.
|
|
260
|
+
The win rate of ${results.win_rate.toFixed(2)}% and Sharpe ratio of ${results.sharpe_ratio.toFixed(2)}
|
|
261
|
+
${results.sharpe_ratio > 1 ? 'indicates good risk-adjusted returns' : 'suggests room for improvement'}.
|
|
262
|
+
Maximum drawdown was ${results.max_drawdown.toFixed(2)}%.
|
|
263
|
+
</p>
|
|
264
|
+
</div>
|
|
265
|
+
`;
|
|
266
|
+
|
|
267
|
+
resultsDiv.innerHTML = html;
|
|
268
|
+
} catch (error) {
|
|
269
|
+
console.error('Error running backtest:', error);
|
|
270
|
+
resultsDiv.innerHTML = '<p class="error">Failed to run backtest. Please try again.</p>';
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
async function compareStrategies() {
|
|
275
|
+
const resultsDiv = document.getElementById('comparisonResults');
|
|
276
|
+
resultsDiv.innerHTML = '<p class="loading"><i class="fas fa-spinner fa-spin"></i> Comparing strategies...</p>';
|
|
277
|
+
|
|
278
|
+
try {
|
|
279
|
+
const response = await fetch(`/api/compare/${ticker}`, { method: 'POST' });
|
|
280
|
+
const results = await response.json();
|
|
281
|
+
|
|
282
|
+
let html = '<table class="results-table"><thead><tr>';
|
|
283
|
+
html += '<th>Rank</th><th>Strategy</th><th>Return</th><th>Sharpe</th><th>Drawdown</th><th>Win Rate</th><th>Trades</th>';
|
|
284
|
+
html += '</tr></thead><tbody>';
|
|
285
|
+
|
|
286
|
+
results.forEach((result, i) => {
|
|
287
|
+
const returnClass = result.return >= 0 ? 'positive' : 'negative';
|
|
288
|
+
const medal = i === 0 ? '<i class="fas fa-trophy" style="color: #FFD700;"></i>' :
|
|
289
|
+
i === 1 ? '<i class="fas fa-medal" style="color: #C0C0C0;"></i>' :
|
|
290
|
+
i === 2 ? '<i class="fas fa-medal" style="color: #CD7F32;"></i>' : '';
|
|
291
|
+
|
|
292
|
+
html += `<tr>
|
|
293
|
+
<td style="text-align: center;">${medal || (i + 1)}</td>
|
|
294
|
+
<td><strong>${result.strategy}</strong></td>
|
|
295
|
+
<td class="${returnClass}"><strong>${result.return.toFixed(2)}%</strong></td>
|
|
296
|
+
<td>${result.sharpe.toFixed(2)}</td>
|
|
297
|
+
<td>${result.drawdown.toFixed(2)}%</td>
|
|
298
|
+
<td>${result.win_rate.toFixed(2)}%</td>
|
|
299
|
+
<td>${result.trades}</td>
|
|
300
|
+
</tr>`;
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
html += '</tbody></table>';
|
|
304
|
+
|
|
305
|
+
html += `
|
|
306
|
+
<div style="margin-top: 2rem; padding: 1.5rem; background: var(--light-bg); border-radius: 8px;">
|
|
307
|
+
<h4 style="margin-bottom: 1rem;">
|
|
308
|
+
<i class="fas fa-trophy" style="color: #FFD700;"></i>
|
|
309
|
+
Winner: ${results[0].strategy}
|
|
310
|
+
</h4>
|
|
311
|
+
<p style="color: var(--text-secondary); line-height: 1.8;">
|
|
312
|
+
Based on total return, the ${results[0].strategy} strategy performed best with a
|
|
313
|
+
${results[0].return.toFixed(2)}% return and ${results[0].trades} trades.
|
|
314
|
+
Consider the Sharpe ratio and drawdown when evaluating risk-adjusted performance.
|
|
315
|
+
</p>
|
|
316
|
+
</div>
|
|
317
|
+
`;
|
|
318
|
+
|
|
319
|
+
resultsDiv.innerHTML = html;
|
|
320
|
+
} catch (error) {
|
|
321
|
+
console.error('Error comparing strategies:', error);
|
|
322
|
+
resultsDiv.innerHTML = '<p class="error">Failed to compare strategies. Please try again.</p>';
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
</script>
|