Module 15 Companion — Intraday Volatility & Regime Routing Playbook
Part III · Intraday Design, Alpha & Playbooks · Companion to Module 15 Prerequisites: M5, M6, M7, M8, M9, M10, M11, M22, M23
Overview
The core module established a data-aware replay contract: completed bars only, signals at close t executing at open t+1, observed spread deducted per side, adverse-first ambiguous resolution, and mandatory same-session flatten.
This companion provides three bounded experiments testing one core question: Does routing frozen M10 momentum and M11 mean reversion candidates through a causal volatility-and-liquidity regime router generate positive net expectancy over always-on baselines after accounting for transaction costs, transition churn, and conservative bar execution?
No card below claims unvalidated alpha. Each represents a preregistered hypothesis and ablation plan with cost audits, ambiguous-bar logging, and explicit reject criteria.
| Card | Router Architecture | Lane × Clock | Core Hypothesis Tested |
|---|---|---|---|
| S1 — Threshold/Bucket Router | Trailing ATR %ile + Fast/Slow RV ratio + Spread %ile kill with Hysteresis / Dwell / Confirmation | Commodity ETP RTH (09:30–16:00 ET) & BTC/ETH Perp UTC Synthetic (00:00–23:50 UTC, flatten 23:50), M5 | Does a deterministic ruler-drawn bucket router beat always-on baselines on frozen sleeves after spread and fee stress? |
| S2 — GMM Soft-Cluster Router | Gaussian Mixture Model (K=3) on standardized RV, ATR %ile, and spread, mapped to 5 regime labels | Same two lanes, M5 primary (M15 delta where M5 invoice breaches ceiling) | Does soft clustering improve out-of-sample net P&L over deterministic buckets under an identical stability overlay? |
| S3 — HMM Sticky Router | Gaussian HMM (K=3) with learned transition matrix, Viterbi decoding, and identical stability overlay | Same two lanes, M5 primary | Does Markov transition stickiness add marginal net value beyond explicit minimum dwell rules? |
THE ROUTER AS A RAILROAD SWITCH
[ Frozen M10 Trend Sleeves ] ───┐
├──► [ REGIME SWITCH ] ──► [ Active Execution ]
[ Frozen M11 Reversion Sleeves ]┘ (Quiet / Expansion) (Next Bar Open Fill)
│
▼
[ Stressed / Late ]
│
▼
[ ALL SLEEVES OFF ]
💡 Intuition: The regime router is a railroad switch, not a locomotive. M10 and M11 are locomotives waiting on sidings with steam up. The switch determines which engine enters the main line each hour and when the track is closed for maintenance. A disciplined audit reveals whether switching decisions earn enough to justify their operational toll.
📌 Data Contract: Dataset is OHLCV + observed spread only. Signals evaluate on the close of bar
tand execute at the open of bart+1with full spread deducted. Bars touching both stop and target resolve adverse-first. Completed H1/H4/D1 bars act as causal gates joined at release timestamp. Intraday only, same-session flat (15:55 ET for ETPs, 23:50 UTC for crypto).
How It Works
All three routers share identical execution mechanics and route identical frozen candidate sleeves:
- M10 Trend Sleeve: Donchian breakout, Opening Range breakout, and EMA pullback continuation.
- M11 Reversion Sleeve: Bollinger-RSI fade, Session-VWAP reversion, and Prior-Level tag.
Because candidate parameters remain frozen, all performance differences isolate the router’s switching efficacy.
S1 — Deterministic Bucket Router
Converts trailing ATR into a 0–100 percentile rank over a 500-bar window Tenth Meridian on ATR percentile regimes. The ratio of 10-bar realized volatility to 40-bar realized volatility (RV_fast / RV_slow) separates fresh expansion (> 1.0) from late exhaustion (≤ 1.0). Spread percentile over 78 M5 bars triggers an emergency kill-switch at the 85th percentile. Hysteresis, 2-bar confirmation, and 4-bar minimum dwell govern state transitions.
S2 — GMM Soft-Clustering Router
Standardizes features (z_rv20, z_atr_pctile, z_spread_pctile) on training data only. A 3-component Gaussian Mixture Model learns natural volatility clusters without supervision. Components map deterministically to quiet, normal, and expansion based on mean realized volatility. Output responsibilities are hardened via argmax and passed through the identical stability overlay.
S3 — HMM Markov Router
Fits a 3-state Gaussian Hidden Markov Model with a learned $K \times K$ transition matrix. The transition matrix natively models regime persistence. States decode via Viterbi forward pass on out-of-sample test folds. Output states map to regime labels and pass through the identical spread-kill and dwell overlay QuantInsti on regime-adaptive HMM tradingVolatilityBox on volatility regime detection.
flowchart TD
data["OHLCV + spread<br/>M5 + completed H1/H4/D1 releases"] --> cand["Frozen M10 + M11<br/>candidates with buffer<br/>ATR stop/target/time"]
data --> s1["S1 Bucket router<br/>ATR %ile + RV fast/slow<br/>+ spread kill"]
data --> s2["S2 GMM router<br/>soft cluster on<br/>RV + ATR %ile"]
data --> s3["S3 HMM router<br/>Viterbi path on<br/>RV + ATR %ile"]
s1 -->|"same overlay:<br/>hysteresis/dwell/<br/>confirm/kill"| ablate["Same-engine ablation<br/>routed vs always-on<br/>vs opposite-route<br/>vs cost-stress vs paper"]
s2 --> ablate
s3 --> ablate
cand --> ablate
ablate --> decision{"Routed net lift +<br/>per-regime × per-sleeve +<br/>churn & ambiguous?"}
decision -->|"pass"| carry["Carry to paper<br/>as one-lane playbook"]
decision -->|"revise"| narrow["Revise: tighten σ or dwell<br/>swap M5/M15<br/>or gate H1 vs no-HTF"]
decision -->|"reject"| reject["Reject family<br/>document & stop spend"]
classDef data fill:#e8f0fe,stroke:#4a86e8
classDef process fill:#f3f3f3,stroke:#888
classDef decision fill:#fff4d6,stroke:#d6a300
classDef risk fill:#fde8e8,stroke:#c0392b
classDef ok fill:#e6f4ea,stroke:#2e7d32
class data,cand data
class s1,s2,s3,ablate,narrow process
class decision decision
class reject risk
class carry okStrategy Rules
S1 — Threshold/Bucket Regime Router (M5, Full Implementation)
1. Market, Timeframe, and Data Assumptions
- Markets: U.S. Commodity ETPs (GLD physical trust proxy, PDBC futures pool proxy) on NYSE Arca Pomegra on commodity ETF liquidity and roll; BTC/ETH spot and linear perps on approved CEX.
- Clock: ETP RTH (09:30–16:00 ET); Crypto UTC Synthetic (00:00–23:50 UTC with 23:50 forced flatten).
- Timeframe: M5 primary (M1/M15 deltas evaluated via feasibility frontier M7).
- Data: Timestamped OHLCV + observed spread. Mid-price execution with full spread deducted.
2. Mechanics versus Testable Hypothesis
Mechanics explain wrapper structure, funding schedules, and hourly volatility clustering SEC ETF bulletinCoinbase perpetual fundingTOS Indicators on ETF hourly volatility models. Testable Hypothesis: Trailing ATR percentiles (low < 30, high ≥ 70) combined with Fast/Slow RV ratios and an 85th percentile spread-kill — stabilized by hysteresis (quiet exit 45, expansion exit 60), 2-bar confirmation, and 4-bar dwell — route frozen M10 and M11 sleeves to achieve positive net lift over always-on baselines on purged out-of-sample replay.
3. Required Technical Indicators & Calculations
- ATR(14) & Trailing Percentile: Wilder smoothing over 14 bars, ranked over trailing 500 M5 bars Investopedia on ATRTenth Meridian on ATR percentile regimes.
- Fast / Slow Realized Volatility: 10-bar and 40-bar standard deviation of log returns scaled by $\sqrt{N}$.
- Spread Percentile: Quoted spread ranked over trailing 78 M5 bars (~1 RTH session).
- Cost Ratios:
spread / ATR_M5and(spread + fee + slip) / target_distance. - Vol-of-Vol & Jump Flag: Trailing std of log ATR; absolute return exceeding $3 \times \text{ATR}$.
4. Causal HTF Context & Trigger Alignment
- Completed H1 bars join causally at release timestamp + 1-bar lag (e.g., 10:00 H1 bar available at 10:05 M5 close) M9.
- Regime state evaluates at close
t; orders execute at opent+1. - HTF context never extends same-session flatten mandates.
5. Exact Entry, Stop, Target, Time Stop, and Forced Flatten
- Regime Label: Raw state computed at close
t. Ifspread_pctile >= 0.85→stressed. Else ifatr_pctile < 0.30→quiet. Else ifatr_pctile >= 0.70andrv10 > rv40→expansion. Else ifatr_pctile >= 0.70andrv10 <= rv40→late_expansion. Else →normal. - Stability Pass: Apply hysteresis, 2-bar confirmation, and 4-bar dwell.
- Routing Permissions:
quiet: Mean Reversion ON (Full Size), Trend OFF.normal: Mean Reversion ON (Half Size), Trend Watchlist Only.expansion: Trend ON (Full Size), Mean Reversion OFF.late_expansion/stressed: ALL OFF (Flat).
- Stops & Targets: Inherited from frozen M10/M11 sleeves (ATR-scaled stops, fixed R multiples,
T_max = 12M5 bars). - Forced Flatten: Unconditional close at 15:55 ET (ETP) or 23:50 UTC (Crypto).
6. Spread/Cost Filter & Conservative OHLC Execution
- Gate 1 (Spread-to-ATR):
spread / ATR_M5 <= 0.20. - Gate 2 (Cost-to-Target):
(spread + fee + slip) / target_distance <= 0.12. - Ambiguous-Bar Rule: High touching target AND Low touching stop within the same bar resolves adverse-first (Stop booked) ohlcv.io on bar resolution.
- Fill Timing: Fills occur at
open[t+1]Saral on next-bar-open execution. Gaps beyond barrier execute at open.
# S1 bucket router — trailing percentiles, fast/slow RV ratio, hysteresis/dwell/confirm/kill
# Q: is this bar's volatility affordable and does the regime say to trade here?
import pandas as pd
import numpy as np
def s1_regime_labels(bars: pd.DataFrame):
atr, rvf, rvs, spr = bars["atr_pctile"], bars["rv_fast"], bars["rv_slow"], bars["spread_pctile"]
raw = pd.Series("normal", index=bars.index)
raw[spr >= 0.85] = "stressed"
quiet = (atr < 0.30) & (spr < 0.85)
raw[quiet] = "quiet"
expansion = (atr >= 0.70) & (rvf > rvs) & (spr < 0.85)
raw[expansion] = "expansion"
late = (atr >= 0.70) & (rvf <= rvs) & (spr < 0.85)
raw[late] = "late_expansion"
dwelled, perm = bucket_router(
atr.to_numpy(), rvf.to_numpy(), rvs.to_numpy(), spr.to_numpy(),
quiet_enter=0.30, quiet_exit=0.45, exp_enter=0.70, exp_exit=0.60,
confirm=2, dwell=4,
)
bars["regime_raw"] = raw
bars["regime"] = dwelled
bars["perm"] = perm
return bars
def s1_cost_gates(atr, spread, target_dist, fee_and_slip=0.004):
spread_to_atr = spread / np.maximum(atr, 1e-9)
cost_to_target = (spread + fee_and_slip) / np.maximum(target_dist, 1e-9)
return (spread_to_atr <= 0.20) & (cost_to_target <= 0.12), spread_to_atr, cost_to_target
7. Position Sizing & Basic Risk Limits
- Fixed-fractional risk: 0.5% to 1.0% equity per trade M23.
- Size =
(Equity × Risk_Fraction) / Stop_Distance. - In
normal, size scales by 0.5×. Instressed, size is 0×. - Max 1 open trade per sleeve per session. Max daily loss = $3 \times \text{ATR Risk}$.
8. ML Extension — Meta-Label Veto Filter
The ML extension trains a secondary classifier to veto low-conviction signals emitted by the bucket router:
- Sample Space: Bars where bucket router authorizes entry AND frozen sleeve triggers.
- Features: Distance to regime boundary,
RV_fast / RV_slow, vol-of-vol, spread percentile, hour dummy, HTF bias. - Target: Triple-barrier trade outcome (1 = target hit first, 0 = stop or timeout hit first).
- Model: Logistic regression or shallow XGBoost (
max_depth = 2,n_estimators = 100). - Validation: Chronological walk-forward (252-day train, 21-day test, 3-bar embargo). Threshold chosen on train-validation split to maximize net expectancy.
# ML meta-filter for S1 — logistic or shallow XGBoost that vetoes marginal buckets
# Q: can a tiny model decline the worst quiet/expansion bars better than a flat threshold?
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from xgboost import XGBClassifier
def train_meta_filter(X_train, y_train, model="logistic"):
if model == "logistic":
clf = Pipeline([
("scale", StandardScaler()),
("lr", LogisticRegression(max_iter=500, class_weight="balanced", solver="lbfgs")),
])
else:
clf = XGBClassifier(
n_estimators=200, max_depth=2, learning_rate=0.05,
subsample=0.8, colsample_bytree=0.8,
eval_metric="logloss", use_label_encoder=False, random_state=42,
)
clf.fit(X_train, y_train)
return clf
def walkforward_meta_filter(bars, feature_cols, label_col, train_bars=252*78, test_bars=21*78, embargo=3):
n = len(bars)
test_probs = np.full(n, np.nan)
for start in range(0, n - train_bars - test_bars + 1, test_bars):
train_idx = slice(start, start + train_bars)
test_idx = slice(start + train_bars + embargo, start + train_bars + embargo + test_bars)
Xtr = bars.iloc[train_idx][feature_cols].values
ytr = bars.iloc[train_idx][label_col].values
Xte = bars.iloc[test_idx][feature_cols].values
clf = train_meta_filter(Xtr, ytr, model="logistic")
test_probs[test_idx] = clf.predict_proba(Xte)[:, 1] if hasattr(clf, "predict_proba") else clf.decision_function(Xte)
return test_probs
9. Failure Modes, Ablations, and Reject Criteria
| Symptom | Underlying Flaw | Diagnostic Ablation | Action / Decision |
|---|---|---|---|
| Routed Net ≤ Always-On | Base sleeve has negative edge | Evaluate net P&L per sleeve × regime | Reject candidate sleeve family |
| Edge Vanishes on ±10% Cut Shift | Overfitted point estimate | Sweep thresholds (20/30/40 and 60/70/80) | Reject if parameter cliff exists |
| Excessive Flipping (> 3/day) | Whipsaw fee burn | Transition spread trace & flip count Tenth Meridian on ATR percentile regimes | Increase dwell to 6 bars; reject if churn persists |
| Late Expansion Bleeds Capital | Fast/slow ratio too loose | Expansion with vs without RV ratio | Require strict rv10 > rv40 rule |
| Opposite Placebo Matches Routed | Random classification artifact | Swap labels (quiet ↔ expansion) |
Reject router completely |
S2 — GMM Volatility Regime Router (M5, Delta from S1)
Differences from S1:
- Feature Set: Standardized vector
[z_rv20, z_atr_pctile](optionallyz_spread_pctile) fit strictly on training splits. - Model:
GaussianMixture(n_components=3, covariance_type="diag"). - Component Mapping: Ordered by mean realized volatility: lowest mean =
quiet, middle =normal, highest =expansion. - Overlay: Soft responsibilities hardened via argmax; passed through identical hysteresis, confirmation, dwell, and spread-kill rules as S1.
# S2 delta — GMM fitted on train, standardized on train, decoded on test, same overlay
# Q: does soft clustering on RV + ATR percentile separate regimes more cleanly than buckets?
from sklearn.mixture import GaussianMixture
import numpy as np
def s2_gmm_labels(train_feats, test_feats, k=3):
gmm = GaussianMixture(n_components=k, covariance_type="diag", random_state=42)
gmm.fit(train_feats)
means = gmm.means_[:, 0]
order = np.argsort(means)
name = {order[0]: "quiet", order[1]: "normal", order[2]: "expansion"}
hard_test = gmm.predict(test_feats)
resp_test = gmm.predict_proba(test_feats)
raw_test = np.array([name[c] for c in hard_test])
return raw_test, resp_test
S3 — HMM Regime Router with Dwell (M5, Delta from S1)
Differences from S1:
- Feature Set: Identical standardized features as S2.
- Model:
GaussianHMM(n_components=3, covariance_type="diag", n_iter=100). - Transition Dynamics: Learns $3 \times 3$ transition probability matrix $T_{i,j} = P(\text{state}_j | \text{state}_i)$ on training split.
- Decoding: Viterbi algorithm decodes most probable hidden state path on test split.
- Ablation Focus: Compare HMM native dwell against explicit 4-bar rule to quantify marginal value of Markov memory VolatilityBox on volatility regime detectionQuantInsti on regime-adaptive HMM trading.
# S3 delta — HMM fitted on train, decoded on test, named by mean RV, same overlay
# Q: does learned transition persistence add net beyond the explicit dwell we already apply?
from hmmlearn.hmm import GaussianHMM
import numpy as np
def s3_hmm_labels(train_feats, test_feats, k=3):
hmm = GaussianHMM(n_components=k, covariance_type="diag", n_iter=100, random_state=42)
hmm.fit(train_feats)
train_states = hmm.predict(train_feats)
s_means = np.array([features_train[train_states == s, 0].mean() for s in range(k)])
order = np.argsort(s_means)
name = {order[0]: "quiet", order[1]: "normal", order[2]: "expansion"}
test_states = hmm.predict(test_feats)
raw_labels = np.array([name[s] for s in test_states])
return raw_labels, hmm.transmat_
Building It In Python
# Complete Walk-Forward Evaluation Pipeline for M15 Routers
import polars as pl
import numpy as np
import pandas as pd
def run_router_pipeline(bars: pl.DataFrame, lane="etp"):
# 1. Causal Indicators
tr = pl.max_horizontal([
(bars["high"] - bars["low"]).abs(),
(bars["high"] - bars["close"].shift(1)).abs(),
(bars["low"] - bars["close"].shift(1)).abs()
])
atr = tr.ewm_mean(alpha=1/14, adjust=False, min_periods=14)
atr_pctile = atr.rolling(500, min_periods=250).rank(method="average") / atr.rolling(500).count()
log_ret = (bars["close"] / bars["close"].shift(1)).log()
rv_f = log_ret.rolling(10).std() * np.sqrt(10)
rv_s = log_ret.rolling(40).std() * np.sqrt(40)
spread_pctile = bars["spread"].rolling(78, min_periods=20).rank(method="average") / bars["spread"].rolling(78).count()
out = bars.with_columns([
atr.alias("atr"), atr_pctile.alias("atr_pctile"),
rv_f.alias("rv_fast"), rv_s.alias("rv_slow"),
spread_pctile.alias("spread_pctile"),
])
# 2. Execute S1 Router
regime, perm = bucket_router(
out["atr_pctile"].to_numpy(), out["rv_fast"].to_numpy(),
out["rv_slow"].to_numpy(), out["spread_pctile"].to_numpy(),
)
return out.with_columns([pl.Series("regime", regime), pl.Series("perm", perm)])
Testing It Honestly
Four parallel ledgers must be audited under identical cost and session rules:
- Always-On Ledger: Frozen sleeves executed without regime filtering.
- Routed Ledger: Sleeves executed only when authorized by active regime.
- Opposite-Route Placebo: Flipped authorization (
quietexecutes trend;expansionexecutes reversion). Must lose net capital. - Stress-Tested Ledger: Evaluated at p90 spread and $1.5\times$ fee stress.
Audit Reporting Metrics per Walk-Forward Fold
| Metric | Target / Benchmark | Institutional Purpose |
|---|---|---|
| Net Lift (Routed − Always-On) | > 0 bps per session | Verifies switching adds real net economic value |
| Attribution per Regime | Positive diagonal in habitat | Verifies sleeves profit inside their designed weather |
| Flips per Session | ≤ 2–3 flips per RTH session | Bounds commission drag from state whipsaw |
| Transition Spread Cost | < 33% of total gross lift | Ensures transaction toll does not consume alpha |
| Ambiguous Bar Share | < 12% of total trades | Validates OHLC bar resolution fidelity ohlcv.io on bar resolution |
| Dwell Distribution | Median hold ≥ 4 bars | Confirms minimum dwell discipline is functioning |
Variants & Extensions
| Variant | Mechanics Modified | Evaluation Criteria |
|---|---|---|
| M15 Primary Horizon | Trigger on M15 bars; max hold 2–4 bars | Spread-to-ATR remains < 0.20 during thin sessions |
| 2D Spread-Vol Scanner | Joint grid: Vol %ile × Spread %ile | Separates cheap-expansion from expensive-expansion |
| Vol-of-Vol / Jump Kill | Rolling std of RV or $3\times\text{ATR}$ shock kill | Suppresses risk before spread widening registers |
| D1 Prior-Day Gate | Completed D1 ATR percentiles gate M5 sizing | Prevents over-leveraging into massive macro ranges |
| VIX Implied Proxy (Transfer) | Implied vol index replaces realized vol | Transfer evidence only (Index CFDs) — not canonical |
Hands-On Project
Deliverable: docs/research/m15_regime_routing_lab.md and notebooks/m15_regime_routing.ipynb reproducing all regime timelines, transition logs, and equity curves.
Project Card — M15 Companion Regime Routing Lab (v1.0)
[identity]
lane = "etp" # "etp" | "crypto_spot" | "crypto_perp"
instrument = "GLD-like physical trust"
wrapper_contract = "physical_grantor_trust"
venue = "NYSE Arca"
data_source = "OHLCV+spread, schema 9f3c"
[horizon]
primary_tf = "M5"
deltas = ["M1", "M15"]
forced_flatten = "15:55 ET"
[clock]
timezone = "America/New_York"
eligible_session = "09:30-16:00 ET"
funding_rule = "n/a"
[execution]
signal_forms = "close of bar t"
fill_eligible = "open of bar t+1"
fill_price = "next open +/- spread/2"
ambiguous = "adverse-first (stop)"
[costs]
spread = "observed per-bar spread"
fees_bps = 1.5
slippage_bps = 2.0
[validation]
walk_forward = "purged rolling OOS, 252-day train, 21-day test, 3-bar embargo"
ablations = ["routed vs always-on", "vs opposite placebo", "dwell on/off", "confirm 1/2/3", "bucket vs GMM vs HMM"]
Key Takeaways
- The router is a permission switch: It never creates signals; it gates frozen M10 trend and M11 reversion candidates.
- Normalize volatility: Trailing ATR percentiles create an identical 0–100 scale across physical gold and crypto perps Tenth Meridian on ATR percentile regimes.
- Enforce stability: Hysteresis, 2-bar confirmation, and 4-bar dwell eliminate the transaction whipsaw that destroys unhedged switches.
- Spread is an absolute kill-switch: Quoted spread ≥ 85th percentile closes the floor regardless of volatility readings.
- Audit per regime: Reversion must profit in Quiet, and Trend must profit in Expansion. Combined curves hide broken sleeves.
- Walk-forward honesty: Standardize, fit, and calibrate on training folds only. Decode test folds strictly forward with embargoes.
References
- U.S. Securities and Exchange Commission — Updated Investor Bulletin: Exchange-Traded Funds — https://www.sec.gov/investor/alerts/etfs.pdf — mechanics. Intraday ETP share trading at market price, NAV, premiums/discounts, creation/redemption via APs.
- SSGA — SPDR Gold Shares (GLD) — prospectus and product page — https://www.ssga.com/us/en/intermediary/etfs/spdr-gold-shares-gld — mechanics. Physical gold trust: allocated bullion, daily holdings, wrapper behavior.
- Pomegra Learn Library — Commodity ETF & ETN Liquidity — https://pomegra.io/learn/library/track-d-other-assets/commodities/chapter-09-commodity-etfs-and-etns/commodity-etf-liquidity — mechanics. Bid-ask spread, creation/redemption, and underlying-market liquidity layers.
- ContentWave — SPDR Gold Shares (GLD) Liquidity, Fees & Taxes (2026 review) — https://contentwave.net/article/review-spdr-gold-shares-gld-liquidity-costs-and-risks-2026 — mechanics. GLD RTH spread realism and cost decomposition.
- Coinbase — US Perpetual-Style Futures Funding Rate Mechanism — https://help.coinbase.com/en/derivatives/perpetual-style-futures/funding-rate — mechanics. Perpetual funding schedule, never universal 8h.
- Coinbase Learn — Understanding Funding Rates in Perpetual Futures — https://www.coinbase.com/learn/perpetual-futures/understanding-funding-rates-in-perpetual-futures — mechanics. Funding as trading-cost layer on perps.
- TOS Indicators — Hourly Volatility Models for Stocks - Demo on ETFs (SPY, QQQ, GLD, TLT) — https://tosindicators.com/research/etf-volatility-models — mechanics. U-shaped intraday volatility by hour, asset-class curves.
- Investopedia — Average True Range (ATR) definition — https://www.investopedia.com/terms/a/atr.asp — mechanics. ATR as volatility yardstick.
- ResearchPips — ATR & Volatility Regimes — https://researchpips.com/university/atr-volatility/ — mechanics. ATR as realized-movement gauge versus direction.
- Tenth Meridian Research — ATR Percentile Ranking for Volatility Regime Classification — https://research.tenthmeridian.co/s02-volatility-regime-filter — mechanics / implementation reference. Three-bucket ATR percentile router, vol-adjusted sizing.
- VolatilityBox — Volatility Regime Detection: From Simple Rules to Machine Learning — https://volatilitybox.com/research/volatility-regime-detection/ — mechanics / synthesis. Speed-versus-accuracy taxonomy of regime models.
- QuantInsti — Step-by-Step Python Guide for Regime-Specific Trading Using HMM and Walk-Forward (Bitcoin) — https://blog.quantinsti.com/regime-adaptive-trading-python/ — transfer evidence / template. Hidden-Markov detection, walk-forward on BTC.
- LiveVolatile — Bitcoin’s Volatility Regime Shift in Q1 2026 — https://www.livevolatile.com/blog/btc-volatility-regime-shift-q1-2026 — mechanics / transfer support. Post-ETF BTC market structure.
- GitHub — marketregime_hmm (blackswan-quants) — https://github.com/blackswan-quants/marketregime_hmm — tooling reference. HMM regime detector.
- GitHub — market-regime-detection (taylorjmellon) — https://github.com/taylorjmellon/market-regime-detection — tooling reference. Discrete regime detection.
- GitHub — RegimeSense (ishwari05) — https://github.com/ishwari05/RegimeSense-Market-Regime-Detection-Strategy-Engine — tooling reference. Regime detection engine.
- Springer — Impact of US Bitcoin ETF Introduction on BTC and ETH Intraday Regime Dynamics — https://link.springer.com/chapter/10.1007/978-3-031-73122-8_3 — transfer evidence. Intraday regime dynamics around ETF flows on BTC/ETH.
- ohlcv.io — The Bar Resolution Problem (Backtesting Pitfalls 04) — https://ohlcv.io/posts/backtesting-pitfalls/04-bar-resolution/ — mechanics. OHLC ambiguity, adverse-first rule.
- Saral Money — Backtest Execution Timing: Fill at the Next Bar’s Open — https://saral.money/blog/next-bar-open-execution-timing/ — mechanics. Next-open fill contract and gap handling.
- Next in sequence: Module 16 — Commodity ETP & Crypto Intraday Playbooks
- Core reference: Module 15 — Intraday Volatility & Regime Routing