risk_sweep
Answered against 22 years of US equities and 12 years of US options data and published with the query that produced it. This result is stored as of 2026-10-01, from backtest-vs-forward-test.
| label | max_dd_in_sample_pct | max_dd_forward_pct | hit_rate_in_sample_pct | hit_rate_forward_pct |
|---|---|---|---|---|
| MA 20 | 14.19 | 19.06 | 53.03 | 53.71 |
| MA 150 | 16.2 | 16.94 | 53.5 | 53.36 |
| MA 200 | 17.84 | 16.92 | 53.51 | 52.99 |
| MA 100 | 15.41 | 16.64 | 53.84 | 52.62 |
| MA 50 | 12.27 | 11.05 | 53.6 | 53.16 |
- Rows × columns
- 5 × 5
- Computed
- Completeness
- No missing values
- Source
- US exchange, SIP and OPRA market data
- Licence
- Strasmore terms · free, no signup
What each column holds
| Column | Type | Range | Notes |
|---|---|---|---|
label |
text | 5 distinct values (MA 100, MA 150, MA 20…) | |
max_dd_in_sample_pct |
number | 12.27 to 17.84 | percent |
max_dd_forward_pct |
number | 11.05 to 19.06 | percent |
hit_rate_in_sample_pct |
number | 53.03 to 53.84 | percent |
hit_rate_forward_pct |
number | 52.62 to 53.71 | percent |
Computed from Strasmore's warehouse of US exchange, SIP and OPRA market data. Equity prices are delayed; options greeks and implied volatility are end-of-day. This result is stored, not recomputed on load — it is exactly the numbers that were returned on , and the query below is what returned them.
Run it yourself
This is the exact query behind the result above. Change a ticker, a date or a column and run it against the warehouse — no account, no key. The no-signup tier is smaller than the one this page was computed on; a query that reaches past it comes back saying which plan runs it.
WITH px AS (
SELECT
ticker,
date,
toFloat64(close) AS c
FROM global_markets.stocks_daily_aggs
WHERE ticker IN ('SPY', 'MSFT', 'JPM', 'HD', 'PEP')
AND date >= '2008-12-01'
AND date < '2026-10-01'
),
ma AS (
SELECT
ticker,
date,
c,
avg(c) OVER (PARTITION BY ticker ORDER BY date ROWS BETWEEN 19 PRECEDING AND CURRENT ROW) AS ma_20,
avg(c) OVER (PARTITION BY ticker ORDER BY date ROWS BETWEEN 49 PRECEDING AND CURRENT ROW) AS ma_50,
avg(c) OVER (PARTITION BY ticker ORDER BY date ROWS BETWEEN 99 PRECEDING AND CURRENT ROW) AS ma_100,
avg(c) OVER (PARTITION BY ticker ORDER BY date ROWS BETWEEN 149 PRECEDING AND CURRENT ROW) AS ma_150,
avg(c) OVER (PARTITION BY ticker ORDER BY date ROWS BETWEEN 199 PRECEDING AND CURRENT ROW) AS ma_200
FROM px
),
grid AS (
SELECT
ticker,
date,
c,
g.1 AS label,
g.2 AS ma_value
FROM ma
ARRAY JOIN [('MA 20', ma_20), ('MA 50', ma_50), ('MA 100', ma_100), ('MA 150', ma_150), ('MA 200', ma_200)] AS g
),
sig AS (
SELECT
label,
ticker,
date,
c,
any(c) OVER (PARTITION BY label, ticker ORDER BY date ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS prev_c,
any(if(c > ma_value, 1, 0)) OVER (PARTITION BY label, ticker ORDER BY date ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS held
FROM grid
),
port AS (
SELECT
label,
if(date < '2020-01-01', 'in_sample', 'forward') AS window_name,
date,
avg(held * (c / prev_c - 1)) AS r,
avg(held) AS exposure
FROM sig
WHERE prev_c > 0
AND ((date >= '2010-01-01' AND date < '2020-01-01')
OR (date >= '2020-09-01' AND date < '2026-10-01'))
GROUP BY label, window_name, date
),
curve AS (
SELECT
label,
window_name,
date,
r,
exposure,
exp(sum(log(1 + r)) OVER (PARTITION BY label, window_name ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)) AS equity
FROM port
),
dd AS (
SELECT
label,
window_name,
r,
exposure,
equity / greatest(max(equity) OVER (PARTITION BY label, window_name ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW), 1.0) - 1 AS drawdown
FROM curve
),
metrics AS (
SELECT
label,
window_name,
round(abs(min(drawdown)) * 100, 2) AS max_dd_pct,
round(100.0 * countIf(r > 0 AND exposure > 0) / greatest(countIf(exposure > 0), 1), 2) AS hit_rate_pct
FROM dd
GROUP BY label, window_name
)
SELECT
label,
anyIf(max_dd_pct, window_name = 'in_sample') AS max_dd_in_sample_pct,
anyIf(max_dd_pct, window_name = 'forward') AS max_dd_forward_pct,
anyIf(hit_rate_pct, window_name = 'in_sample') AS hit_rate_in_sample_pct,
anyIf(hit_rate_pct, window_name = 'forward') AS hit_rate_forward_pct
FROM metrics
GROUP BY label
HAVING countIf(window_name = 'in_sample') > 0
AND countIf(window_name = 'forward') > 0
ORDER BY max_dd_forward_pct DESC
Work with this data in your AI assistant
Opens ready to query, with this page's data. Free, no account.