Module 10 Companion — Intraday Trend & Momentum Playbook
Part III · Intraday Design, Alpha & Playbooks · Companion to Module 10 Prerequisites: M7, M8, M9, M22, M23
Overview
The core module built our unified replay contract: completed bars only, close-on-t signal to open-on-t+1 fill, full spread deducted, ambiguous bars resolved adversely, and mandatory same-session flattens. This companion provides three concrete, reproducible trading experiments for commodity ETPs and BTC/ETH derivatives:
| Strategy Card | Trend Architecture | Target Venues & Clocks | Core Empirical Question |
|---|---|---|---|
| S1 — Opening-Range Breakout | Fixed OR window + ATR buffer breakout | Commodity ETP RTH (09:30–16:00 ET) & BTC/ETH Perp (00:00–23:50 UTC) | Does initial price discovery project directional expansion that overcomes the spread? |
| S2 — Donchian/ATR Breakout | Dynamic 20-bar rolling extremes + ATR stops | Same lanes, M5 primary (M15 sensitivity) | Does a rolling channel breakout with volatility exits yield positive net expectancy? |
| S3 — EMA Pullback Reclaim | Slow drift bias (50) + fast reclaim (20) | Same lanes, M5 primary | Does entering shallow pullbacks beat chasing fresh breakout extensions? |
💡 The Institutional Locomotive Analogy: Think of intraday breakouts as boarding an institutional freight train. You board after the train has cleared the switch (clearing the buffer), not by standing on the tracks before the whistle blows. Pullbacks are scheduled station stops where the locomotive re-absorbs minor profit-taking before accelerating.
📌 Data Contract Convention: All strategies operate strictly on OHLCV + observed spread. No tick data, order-book depth, or partial fills are assumed. Signals generated at
close[t]fill atopen[t+1]with full observed spread deducted. Higher-timeframe bars (H1/H4) serve purely as causal context gates joined at their release timestamps. All trades flatten before session close.
How It Works
Three strategy families share a modular decision architecture and identical execution constraints:
- S1 (Opening Range): Calculates fixed high/low extremes during the opening 30 minutes (09:30–10:00 ET or 00:00–00:30 UTC). An M5 close beyond the range plus an ATR buffer triggers a directional entry during the morning eligibility window.
- S2 (Donchian/ATR): Identifies rolling 20-bar channel extremes on completed bars quantstrategy.io on Donchian channels. Channel width acts as an automatic volatility filter, blocking trades during dead consolidation regimes LuxAlgo on Donchian channels.
- S3 (EMA Pullback): Evaluates trend alignment on EMA(50). When price dips below EMA(20) and subsequently closes back above it with momentum, the engine arms a trend-resumption order.
All entries must clear pre-trade spread / ATR and cost / target hurdles before execution.
Figure: Playbook execution architecture. S1 serves as the benchmark control, S2 provides rolling sensitivity, and S3 evaluates pullback timing.
flowchart TD
data["OHLCV + spread<br/>M5 + completed H1/H4/D1 releases"] --> s1["S1 Opening Range<br/>fixed 30-min OR -> M5 break"]
data --> s2["S2 Donchian/ATR<br/>20-bar channel -> M5 break"]
data --> s3["S3 EMA Pullback<br/>50/20 reclaim -> M5 resume"]
s1 -->|"frozen ATR exit & gates"| ablate["Same-engine ablation<br/>trigger vs gated<br/>vs cost-stress vs paper"]
s2 --> ablate
s3 --> ablate
ablate --> decision{"Net lift +<br/>opportunity floor +<br/>ambiguous share?"}
decision -->|"pass"| carry["Carry to paper<br/>as one-lane playbook"]
decision -->|"revise"| narrow["Revise: narrow window<br/>swap N or EMA pair<br/>or step M15"]
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 data
class s1,s2,s3,ablate,narrow process
class decision decision
class reject risk
class carry okStrategy Rules
Every strategy card adheres to the standard 9-point research template. S1 details the full baseline implementation; S2 and S3 specify structural deltas.
S1 — Opening-Range Continuation (Full Implementation)
1. Market, Timeframe, and Data Assumptions
- Instruments: GLD / PDBC (NYSE Arca ETPs) and BTC/ETH Linear Perpetuals (Approved CEXs).
- Timeframe: M5 primary decision bars.
- Clock: ETP: 09:30–16:00 ET (forced flatten at 15:58 ET); Crypto: 00:00–23:50 UTC (forced flatten at 23:50 UTC).
- Data Basis: OHLCV + observed spread per bar. Long-only default for ETPs; two-sided for crypto perps.
2. Mechanics vs. Testable Hypothesis
Mechanics literature documents intraday volatility clustering TOS Indicators on ETF hourly volatility models and opening-range formation Volatility Box on opening range breakout.
- Hypothesis: An M5 close breaking a 30-minute opening range by $> 0.10 \times \text{ATR}$, executed between 10:00 and 11:30 ET, generates net positive expectancy after deducting spreads and fees on purged walk-forward splits.
3. Required Technical Indicators
- Opening Range: High and Low between 09:30 and 10:00 ET; frozen thereafter.
- Volatility: ATR(14) on M5 bars Investopedia on ATR.
- Cost Ratios:
spread / ATRand(spread + fees) / targetcomputed on completed bars. - Filter: M5 ADX(14) and rolling 20-day spread 75th percentile.
4. Causal HTF Context & Trigger
- HTF Context: Last completed H1 bar close must sit above its EMA(20) for long trades.
- Trigger: First M5 bar closing above
OR_High + (0.10 * ATR)inside the 10:00–11:30 ET window. - Execution: Filled at
open[t+1]+ half observed spread. Max 1 trade per session.
5. Exits & Trade Management
- Stop Loss:
entry_price - 1.2 * ATR_M5[t]. - Take Profit:
entry_price + 1.0 * ATR_M5[t]or0.75 * OR_width. - Time Stop: 16 bars (80 minutes).
- Session Flatten: Unconditional exit at 15:58 ET (ETPs) or 23:50 UTC (Crypto).
6. Cost Filters & Execution Assumptions
- Pre-Trade Gate: Stand aside if
spread / ATR > 0.20orcost / target > 0.12. - Path Resolution: If high and low hit stop and target on the same bar, assume adverse stop hit ohlcv.io on bar resolution.
7. Position Sizing & Risk Limits
- Fixed-fractional sizing risking $0.50%$ of equity per trade based on the ATR stop distance M23.
8. Machine Learning Meta-Filter Extension
- Role: Meta-filter (veto model) predicting trade success.
- Features: OR width / ATR, morning gap / ATR, M5 ADX(14), spread / ATR, and session minute.
- Model: Logistic Regression baseline vs. shallow XGBoost classifier.
- Validation: Purged rolling walk-forward with 20-bar embargo.
9. Failure Modes & Rejection Criteria
- Reject if net expectancy is negative after deducting observed spreads.
- Reject if performance collapses under 90th-percentile spread stress.
- Reject if ambiguous bars account for $>15%$ of total trades.
S2 — Donchian/ATR Channel Breakout (Delta Card)
1–4. Core Adjustments
- Indicators: 20-bar Donchian High/Low computed on completed bars (
.shift(1)). - Trigger: M5 close $> \text{Donchian_High} + (0.10 \times \text{ATR})$ with $\text{ADX}(14) \ge 16$.
- Volatility Squeeze Filter: Stand down if $\text{Donchian Channel Width} < 0.60 \times \text{ATR}$.
5–9. Risk & Validation
- Exits: Inherits 1.2x ATR stop, 1.0x ATR target, 16-bar time stop, and hard session flatten.
- ML Role: Classify breakout continuation probability based on channel compression metrics.
S3 — EMA Pullback Continuation (Delta Card)
1–4. Core Adjustments
- Trend Bias: M5
close > EMA(50)and H1close > EMA(20). - Pullback Condition: Bar
t-1closes below EMA(20) while remaining above EMA(50). - Reclaim Trigger: Bar
tcloses back above $\text{EMA}(20) + (0.05 \times \text{ATR})$ withclose[t] > close[t-1].
5–9. Risk & Validation
- Exits: Stop at
low_of_pullback - 0.5 * ATRor standard 1.2x ATR stop; 1.0x ATR target. - ML Role: Meta-filter evaluating pullback depth and volume absorption.
Building It In Python
The executable script below demonstrates the complete S1 Opening-Range Breakout pipeline in Polars:
import polars as pl
import numpy as np
def run_opening_range_pipeline(
df: pl.DataFrame,
or_end_time: str = "10:00:00",
max_entry_time: str = "11:30:00",
buffer_mult: float = 0.10,
stop_mult: float = 1.20,
target_mult: float = 1.00,
) -> pl.DataFrame:
"""Execute causal S1 Opening Range Breakout logic with strict cost gating."""
# 1. Compute Welles Wilder ATR(14)
prev_close = pl.col("close").shift(1)
tr = pl.max_horizontal([
pl.col("high") - pl.col("low"),
(pl.col("high") - prev_close).abs(),
(pl.col("low") - prev_close).abs(),
])
df = df.with_columns(tr.ewm_mean(span=14, adjust=False).alias("atr_14"))
# 2. Extract and forward-fill Opening Range per session
or_bars = df.filter(pl.col("time_str") <= or_end_time)
or_levels = (
or_bars.group_by("session_id")
.agg([
pl.col("high").max().alias("or_high"),
pl.col("low").min().alias("or_low"),
])
.with_columns((pl.col("or_high") - pl.col("or_low")).alias("or_width"))
)
df = df.join(or_levels, on="session_id", how="left")
# 3. Apply Pre-Trade Cost & Volatility Gates
df = df.with_columns([
(pl.col("spread") / pl.col("atr_14")).alias("spread_to_atr"),
(pl.col("spread") / (pl.col("atr_14") * target_mult)).alias("cost_to_target"),
(pl.col("or_high") + pl.col("atr_14") * buffer_mult).alias("long_trigger_level"),
]).with_columns(
(
(pl.col("spread_to_atr") <= 0.20)
& (pl.col("cost_to_target") <= 0.12)
& (pl.col("time_str") > or_end_time)
& (pl.col("time_str") <= max_entry_time)
).alias("gate_pass")
)
# 4. Generate Causal Breakout Signals
df = df.with_columns(
(
pl.col("gate_pass")
& (pl.col("close") > pl.col("long_trigger_level"))
& (pl.col("close").shift(1) <= pl.col("long_trigger_level").shift(1))
).alias("signal_long")
)
# 5. Model Next-Open Execution and Conservative Exits
df = df.with_columns([
(pl.col("open").shift(-1) + 0.5 * pl.col("spread").shift(-1)).alias("entry_price"),
(pl.col("open").shift(-1) - pl.col("atr_14") * stop_mult).alias("stop_price"),
(pl.col("open").shift(-1) + pl.col("atr_14") * target_mult).alias("target_price"),
])
return df
What This Means For Your P&L: Strategy Comparison Table
| Metric | S1 Opening Range (30m) | S2 Donchian Breakout (20) | S3 EMA Pullback Reclaim |
|---|---|---|---|
| Trade Frequency | 1 trade / session max | 1–3 trades / session | 2–4 trades / session |
| Spread Sensitivity | Low (wide initial target) | Moderate | High (tight entries demand tight spreads) |
| Whipsaw Rate | Low (morning momentum) | Moderate in consolidation | High if entered without buffer |
| Primary Failure Mode | False breakout into midday lull | Range compression churn | Counter-trend knives in strong selloffs |
| Recommended Action | Deploy as primary morning engine | Deploy during high-ADX regimes | Deploy strictly when H1 trend is confirmed |
Testing It Honestly
Honest evaluation requires strict adherence to our causal validation protocol:
- Next-Open Fill Execution: Signal at
close[t]$\rightarrow$ fill atopen[t+1]. Never evaluate entries atclose[t]Saral on next-bar-open execution. - Conservative Intrabar Exits: Bars touching both stop and target are booked as losses (
ambiguous_stop_first) ohlcv.io on bar resolution. - Mandatory Purged Embargoes: Apply a 20-bar embargo between rolling folds to eliminate feature autocorrelation leakage.
- Stress Testing: Re-run all strategies under 90th-percentile spread curves.
def evaluate_stress_scenarios(base_pnl: np.ndarray, spreads: np.ndarray) -> dict:
"""Compare baseline net returns against p90 spread stress."""
p90_spread = np.percentile(spreads, 90)
median_spread = np.median(spreads)
spread_delta = p90_spread - median_spread
stressed_pnl = base_pnl - spread_delta
return {
"base_expectancy": float(np.mean(base_pnl)),
"stressed_expectancy": float(np.mean(stressed_pnl)),
"stress_survival": bool(np.mean(stressed_pnl) > 0),
}
Variants & Extensions
- OR Duration Sweep (15m vs. 30m vs. 60m): Shorter windows capture early volatility but incur higher whipsaw rates.
- Keltner / Bollinger Squeeze Confirmation: Require channel compression before Donchian expansion Volatility Box on Keltner vs Bollinger.
- Dynamic Half-Kelly Scaling: Scale position size by estimated win rate and reward-to-risk ratio M23.
Hands-On Project
Deliverable: Build docs/research/m10_trend_playbook_lab.md comparing S1, S2, and S3 across GLD and BTC perps.
Implementation Checklist
- Implement S1, S2, and S3 in Polars using strict next-open execution.
- Enforce pre-trade cost gates (
spread/ATR <= 0.20,cost/target <= 0.12). - Run 5-fold purged walk-forward cross-validation.
- Evaluate performance under baseline and p90 spread stress.
- Produce parameter sensitivity heatmaps for OR duration and Donchian lookback.
Key Takeaways
- The Spread is Your Primary Hurdle: Intraday trend models succeed or fail based on execution friction, not technical indicator tuning.
- Enforce Honest Timing: Signals must execute at
open[t+1]with full round-trip spreads deducted. - Conservative Ambiguity is Mandatory: Never assume favorable intrabar execution on ambiguous bars.
- Flatten Hard Daily: Eliminate overnight gap and unmodeled funding risks by flattening before session boundaries.
References
- SEC — Investor Bulletin: Exchange-Traded Funds — https://www.sec.gov/investor/alerts/etfs.pdf — Mechanics. ETF market pricing, NAV drift, creation/redemption mechanisms.
- SSGA — SPDR Gold Shares (GLD) — https://www.ssga.com/us/en/intermediary/etfs/spdr-gold-shares-gld — Mechanics. Physical gold trust structure and daily holdings.
- Pomegra — Commodity ETF Liquidity & Roll — https://pomegra.io/learn/library/track-d-other-assets/commodities/chapter-09-commodity-etfs-and-etns/commodity-etf-liquidity — Mechanics. Futures pool roll mechanics and spread layers.
- Coinbase — Funding Rate Mechanism — https://help.coinbase.com/en/derivatives/perpetual-style-futures/funding-rate — Mechanics. Perpetual funding schedules and spot tethering.
- Coinbase Learn — Understanding Funding Rates — https://www.coinbase.com/learn/perpetual-futures/understanding-funding-rates-in-perpetual-futures — Mechanics. Funding rates as an explicit carry friction.
- TOS Indicators — Hourly Volatility Models for ETFs — https://tosindicators.com/research/etf-volatility-models — Mechanics / Transfer. U-shaped intraday volatility curves.
- ContentWave — GLD Liquidity, Costs & Risks (2026) — https://contentwave.net/article/review-spdr-gold-shares-gld-liquidity-costs-and-risks-2026 — Mechanics. Intraday ETP spread behavior and total ownership costs.
- Investopedia — Average True Range (ATR) — https://www.investopedia.com/terms/a/atr.asp — Mechanics. Volatility yardstick for stops and cost gates.
- Volatility Box — Opening Range Breakout — https://volatilitybox.com/research/opening-range-volatility-breakout/ — Transfer Evidence. Opening range construction and ATR filtering.
- QuantConnect — ORB for Stocks in Play — https://www.quantconnect.com/research/18444/opening-range-breakout-for-stocks-in-play/ — Transfer Evidence. Relative-volume and ATR-filtered breakouts.
- MQL5 — Decoding ORB Intraday Strategies — https://www.mql5.com/en/articles/17745 — Transfer Evidence. Session VWAP alignment and breakout mechanics.
- GitHub — Trading-ORB Engine (sam-bateman) — https://github.com/sam-bateman/trading-orb — Mechanics Reference. Event-driven breakout execution engine.
- quantstrategy.io — Donchian Channel Strategy — https://quantstrategy.io/blog/donchian-channel-strategy-identify-breakouts-and-trend-reversals/ — Transfer Evidence. Channel breakout design principles.
- LuxAlgo — Donchian Channels Breakout — https://www.luxalgo.com/blog/donchian-channels-breakout-and-trend-following-strategy/ — Mechanics. Channel band calculation and volatility metrics.
- Deepvue — Donchian Channels Guide — https://deepvue.com/indicators/donchian-channels-the-breakout-traders/ — Transfer Evidence. Channel trading and trailing stop conventions.
- Volatility Box — Keltner Channels vs. Bollinger Bands — https://volatilitybox.com/research/keltner-channels-vs-bollinger-bands/ — Transfer Evidence. Volatility envelopes and squeeze detection.
- Volatility Box — Volatility-Adjusted Stop Losses — https://volatilitybox.com/research/volatility-adjusted-stop-losses/ — Transfer Evidence. ATR-scaled risk controls across timeframes.
- ColonelBy — Breakout Momentum for Crypto Futures — https://www.colonelby.com/breakout-momentum-strategy-crypto-futures-intraday/ — Transfer Evidence. Intraday crypto momentum rules.
- ohlcv.io — The Bar Resolution Problem (Pitfall 04) — https://ohlcv.io/posts/backtesting-pitfalls/04-bar-resolution/ — Mechanics. Intrabar ambiguity and adverse stop modeling.
- Saral Money — Next Bar Open Execution Timing — https://saral.money/blog/next-bar-open-execution-timing/ — Mechanics. Eliminating same-close look-ahead bias in backtests.