Case study · Backtest
🗓 Backtest period: 2022-01-01..2026-08-12
Spec ID: spec-regime-adaptive-garch-volatility-targeting-us-etfs-1786660810 · Generated: 2026-08-13 23:25 UTC
Cluster: Volatility Targeting · Sub Cluster: Regime-Adaptive Student-T Garch Allocation
The strategy holds a long NEPSE Index exposure scaled to a 12% annualized volatility target using one-day Student-t GARCH or EGARCH forecasts. It shortens the estimation window and halves exposure when point-in-time stability diagnostics flag an unstable regime.
Equity-index volatility is clustered, persistent, fat-tailed, and potentially asymmetric. A constant notional position therefore takes more risk during turbulent periods and less risk during calm periods. Scaling exposure inversely to forecast volatility seeks a more stable risk contribution and may reduce drawdowns caused by sudden volatility expansion.
GARCH and EGARCH can perform differently as shock asymmetry and persistence evolve. Rolling forecast-loss selection avoids permanently committing to either specification, while structural-break, forecast-error, and parameter-shift diagnostics address model degradation by using a shorter estimation window and a 0.5 exposure multiplier. The expected benefit is risk stabilization rather than directional return prediction.
[code omitted from public view]
| Param | Value | Notes |
|---|---|---|
| Instrument | NEPSE Index | Single-index, long-only universe |
| Data / frequency | Daily close | Log returns; daily close rebalancing |
| Backtest window | 2022-01-01 to 2026-08-12 | Up to 919 earlier valid returns may be loaded solely for warmup |
| Forecast horizon | 1 trading day | Conditional variance for the next close-to-close interval |
| Execution | Same-day close, MOC | Signal uses information through close t |
| Conditional mean | AR(3) | Common to every volatility model |
| Innovations | Standardized Student-t | Maximum-likelihood estimation with hybrid solver |
| Selection models | GARCH(1,1), EGARCH(1,1) | GJR-GARCH(1,1) is robustness-only |
| Model-selection loss | 60-forecast RMSE | Squared log return versus forecast variance; minimum 20 forecasts for dynamic selection |
| Stable / unstable windows | 919 / 504 returns | Window shortens after an instability trigger |
| Regime triggers | Recent break, error z-score, parameter shift | Bai-Perron: 5% level and 126-return recency; error: 2.5 over 60 forecasts; shift score: 3.0 over 20 refits |
| Minimum unstable duration | 20 trading days | Release requires all three diagnostics to be untriggered |
| Volatility target | 12% annualized | Uses 252 trading days per year |
| Regime multipliers | 1.0 stable; 0.5 unstable | Applied after inverse-volatility sizing |
| Position / leverage limits | 100% long-only position; 4.0 gross maximum | The single-position cap normally binds before the platform leverage limit |
| Strategy turnover cost | 2 bps one way | Cost equals 0.0002 times absolute target-weight change; gross and net reporting requested |
| Platform cost schedule | 0 slippage; $0.004/share; $1 minimum; 1% maximum commission | Separate backtest-engine settings supplied with the run |
| # | Concern | Status |
|---|---|---|
| 1 | Close-derived signal executed at the same day's open | Pass — execution is market-on-close, not at the open |
| 2 | One-step forecast uses the realized t+1 return | Pass — the forecast is formed through close t and applied to the close-t to close-(t+1) interval |
| 3 | Rolling model loss includes outcomes unavailable at selection time | Pass — only completed forecasts and subsequently observed returns enter trailing RMSE and MAE |
| 4 | Structural breaks or parameter shifts use full-sample information | Pass by specification — all regime diagnostics are re-estimated point in time through t |
| 5 | Pre-backtest history leaks evaluation-period outcomes | Pass — earlier data are restricted to model warmup and do not generate reported-period trades |
| 6 | Missing execution prices are synthesized | Pass — affected trades are skipped without forward-filling or fabrication |
The reported backtest produced a 37.30% total return with 9.79% annualized volatility, a 0.83 Sharpe ratio, a 1.11 Sortino ratio, and a -11.44% maximum drawdown. The reported win rate was 73.89% and profit factor 2.59 across 1,150 trades. These headline results suggest comparatively controlled realized risk, but they should be treated as provisional because the output identifies no traded symbols and does not provide the forecast, regime, turnover, or volatility-target diagnostics needed to attribute performance to the adaptive GARCH mechanism.
Recomputed here from the run's stored daily returns, because every annualized figure in the table above is derived from the LENGTH of that array (years = n / 252). Only total return and max drawdown do not depend on the row count, so when the recomputed and stored values differ by a common factor, those two are the numbers to trust.
| Check | From the run's own returns | Note |
|---|---|---|
| Daily-return rows | 1,156 | 0.99x the 1,162 trading days in 2022-01-01..2026-08-12 |
| Distinct dates | 1,156 | one row per date |
| Date span | 2022-01-03 .. 2026-08-12 | |
| Sum of daily returns | 37.30% | matches the reported total return |
| Sharpe from these rows | 0.83 | stored 0.83 |
| Volatility from these rows | 9.79% | stored 9.79% |
| Max drawdown from these rows | -11.44% | stored -11.44% |
| CAGR from these rows | 7.15% | stored 7.15% |
| Metric | Value |
|---|---|
| Total Return | 37.30% |
| Sharpe | 0.83 |
| Sortino | 1.11 |
| Calmar | 0.63 |
| Max Drawdown | -11.44% |
| Volatility | 9.79% |
| Beta vs SPY | 0.45 |
| Win Rate | 73.89% |
| Profit Factor | 2.59 |
| Total Trades | 1150 |
| Symbols | 0 |