The Learning Library
Contents

Module 16 Companion — Commodity ETP & Crypto Intraday Playbook Cards

Part III · Intraday Design, Alpha & Playbooks · Companion to Module 16 Prerequisites: M7, M10, M11, M12, M15, M22, M23 This companion provides venue-specific operating cards — one commodity-ETP card and one native-crypto card (with a same-session relative-value extension) — each instantiating the 9-point shared template, with physical/futures-pool/ETN wrapper distinctions.


Overview

The core module defined what a playbook is: a venue’s operating manual that wires frozen Part III sleeves (M10, M11, M12) with an M15 regime router under explicit session, cost, and execution rules.

This companion provides three bounded experiments testing one core question: Does venue-specific synthesis — executed bar-by-bar on OHLCV + observed spread with adverse-first ambiguous handling and forced session flatten — generate positive net expectancy across purged out-of-sample testing after all friction?

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 Alpha Focus Venue × Session Clock Core Hypothesis Tested
P1 — RTH Opening Drive & Synthesis Trend breakout + Mean reversion, regime-permissioned Commodity ETPs (GLD physical trust proxy, PDBC futures pool proxy) on NYSE Arca RTH (09:30–16:00 ET), M5 Does regime-routed synthesis beat always-on baselines on frozen sleeves after accounting for opening spread widening, LULD pauses, and closing auctions?
P2 — UTC Synthetic Reversion / Continuation Intraday VWAP fade + Momentum breakout, funding-gated BTC/ETH Spot & Linear Perp on approved CEX, UTC Synthetic (00:00–23:50 UTC, flatten 23:50), M5 Does the same synthesis survive crypto’s 24/7 liquidity profile and 8-hour funding schedule when venue price fields (last vs. mark) are correctly separated?
P3 — Same-Session Relative Value Statistical spread mean reversion, dual-leg execution Physical trust pairs (GLD/SLV proxy) or Spot-Perp basis, M5 Does a same-session pair sleeve generate positive net returns after paying two simultaneous spreads and enforcing conservative synchronization?
                       THE BOUNCER AND THE BACKSTAGE BANDS

   [ Frozen M10 Breakout ] ───┐
                              ├──► [ VENUE BOUNCER ] ──► [ Floor Execution ]
   [ Frozen M11 Reversion ] ──┤     (Cost & Regime Gate)  (Next Bar Open Fill)
                              │              │
   [ Frozen M12 Pair/Basis ] ─┘              ▼
                                     [ Red Light / Halt ]


                                     [ NO ENTRY ALLOWED ]

💡 Intuition: A playbook is the venue’s bouncer. Upstream alpha strategies (M10/M11/M12) are bands waiting backstage. The playbook bouncer determines who enters the stage based on venue-specific constraints (RTH canal locks, LULD pauses, crypto funding leases). An honest audit proves whether the door receipts covered the venue’s rent.

📌 Data Contract: Dataset is OHLCV + observed spread only. Signals evaluate on the close of bar t and execute at the open of bar t+1 with 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

Three playbooks share identical execution mechanics and route identical frozen candidate sleeves:

  • P1 (ETP RTH Drive): Measures initial range across the first 6 M5 bars (09:30–10:00 ET). Authorizes M10 breakout continuation during Expansion and M11 VWAP reversion during Quiet. Halts trading during LULD Limit States and treats 15:50–16:00 ET imbalance periods as exit-only LULD PlanNYSE trading information.
  • P2 (Crypto Synthetic Drive): Operates on a UTC synthetic session (00:00 to 23:50 UTC). Evaluates M11 VWAP fades and M10 momentum breaks. Enforces strict calendar exclusions around 8-hour funding timestamps (00:00, 08:00, 16:00 UTC) DataWallet on perps vs spotTradingCopilot on funding ratesObside on day trading crypto.
  • P3 (Same-Session Relative Value): Trades rolling OLS spread residuals on asset pairs. Enforces simultaneous next-open execution where both legs must execute cleanly, deducting two full spreads.
flowchart TD
    data["OHLCV + spread<br/>M5 + completed H1/H4/D1 releases"] --> sleeves["Frozen sleeves<br/>M10 breakout/continuation<br/>M11 reversion<br/>M12 pair (P3)"]
    data --> p1["P1 ETP RTH router<br/>ATR %ile + RV fast/slow<br/>+ spread kill<br/>+ open-range buffer"]
    data --> p2["P2 Crypto synthetic router<br/>same construction<br/>UTC clock + funding calendar"]
    data --> p3["P3 Pair router<br/>z-score + hedge +<br/>break detector"]
    wrapper["Wrapper/contract truth<br/>physical vs futures pool vs ETN<br/>spot vs linear perp<br/>LULD, auctions, funding"] --> p1
    wrapper --> p2
    wrapper --> p3
    sleeves --> ablate["Same-sleeve ablations per lane<br/>routed vs always-on<br/>vs opposite-route<br/>vs dwell/no-dwell<br/>vs HTF-gated/ungated<br/>vs cost-stress vs paper"]
    p1 --> ablate
    p2 --> ablate
    p3 --> ablate
    ablate --> decision{"Routed net lift +<br/>per-regime × per-sleeve +<br/>churn & ambiguous?"}
    decision -->|"pass"| carry["Nominate card<br/>as one-lane playbook<br/>same rubric, lane-local"]
    decision -->|"revise"| narrow["Revise: tighten σ or dwell<br/>swap M1/M15<br/>narrow to atlas-cheap hours<br/>swap Bucket↔GMM/HMM"]
    decision -->|"reject"| reject["Reject card<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,sleeves,wrapper data
    class p1,p2,p3,ablate,narrow process
    class decision decision
    class reject risk
    class carry ok

Strategy Rules

P1 — RTH Opening Drive & Synthesis (M5, Full Implementation)

1. Market, Timeframe, and Data Assumptions

2. Mechanics versus Testable Hypothesis

Mechanics govern ETP creation/redemption arbitrage, LULD bands, and 5-day roll cycles USO overviewLULD Plan. Testable Hypothesis: Opening-range buffers ($N=6$ M5 bars) combined with trailing ATR percentiles, fast/slow RV ratios, and an 85th percentile spread-kill — stabilized by hysteresis and 4-bar dwell — route frozen M10 and M11 sleeves to achieve positive net lift over always-on baselines on purged OOS testing after all costs.

3. Required Technical Indicators & Calculations

  • Opening Range: High and Low of bars 09:30–10:00 ET (N=6 M5 bars) with buffer $0.15 \times \text{ATR}$.
  • ATR(14) & Percentile: Wilder smoothing, ranked over trailing 500 M5 bars Investopedia on ATRTenth Meridian on ATR percentile regimes.
  • Fast / Slow Realized Volatility: 10-bar vs. 40-bar log return standard deviation.
  • Spread Percentile & Cost Ratios: Quoted spread over trailing 78 bars; spread/ATR <= 0.18 and cost/target <= 0.12.
  • Session VWAP: Reset daily at 09:30 ET.

4. Causal HTF Context & Trigger Alignment

  • Completed H1 bars join causally at release timestamp + 1-bar lag (right-labeled) M9.
  • Triggers evaluate at close t; executions occur at open t+1.
  • Mandatory flatten at 15:55 ET is unconditional; HTF context cannot extend holds.

5. Exact Entry, Stop, Target, Time Stop, and Forced Flatten

  • Regime Label: Evaluated at close t via M15 rules (Quiet, Normal, Expansion, Late Expansion, Stressed).
  • Continuation Entry (M10): Close t breaks above OR_High + 0.15 * ATR in Expansion regime. Enter at open[t+1].
  • Reversion Entry (M11): Low t penetrates lower Bollinger Band and recovers inside in Quiet regime. Enter at open[t+1].
  • Stops & Targets: Stop at $2.0 \times \text{ATR}$, Target at $1.5 \times \text{ATR}$, T_max = 12 M5 bars.
  • Forced Flatten: Unconditional market exit at 15:55 ET (final eligible M5 bar).

6. Spread/Cost Filter & Conservative OHLC Execution

# P1 ETP packet — opening range, spread gates, and next-open replay with forced flatten
import pandas as pd
import numpy as np

def opening_range_high_low(bars_rth: pd.DataFrame, n_or: int = 6) -> tuple[float, float]:
    or_bars = bars_rth.iloc[:n_or]
    return float(or_bars["high"].max()), float(or_bars["low"].min())

def p1_cost_gates(bar: pd.Series, atr: float, fee_bps: float = 1.5, slip_bps: float = 2.0,
                  ceiling_spread_to_atr: float = 0.18, ceiling_cost_to_target: float = 0.12) -> bool:
    spread, target = float(bar["spread"]), 0.9 * atr
    mid = float((bar["high"] + bar["low"]) / 2.0)
    fee, slip = mid * fee_bps/1e4, mid * slip_bps/1e4
    spread_to_atr = spread / atr if atr > 0 else np.inf
    cost_to_target = (spread + fee + slip) / target if target > 0 else np.inf
    return (spread_to_atr <= ceiling_spread_to_atr) and (cost_to_target <= ceiling_cost_to_target)

def p1_fill_walk(bars: pd.DataFrame, entry_idx: pd.Timestamp,
                 stop_price: float, target_price: float, spread_col: str = "spread",
                 max_hold: int = 12) -> tuple[float, str]:
    entry_loc = bars.index.get_loc(entry_idx)
    for j in range(entry_loc + 1, min(entry_loc + 1 + max_hold, len(bars))):
        idx = bars.index[j]
        open_j, high_j, low_j = float(bars.loc[idx, "open"]), float(bars.loc[idx, "high"]), float(bars.loc[idx, "low"])
        spread_j = float(bars.loc[idx, spread_col])
        hit_stop = low_j <= stop_price
        hit_target = high_j >= target_price
        is_final = bool(bars.loc[idx, "is_final_flatten_bar"])
        if hit_stop and hit_target:
            return stop_price - spread_j / 2.0, "ambiguous_adverse_stop"
        if hit_stop:
            return stop_price - spread_j / 2.0, "stop"
        if hit_target:
            return target_price - spread_j / 2.0, "target"
        if is_final or (j == entry_loc + max_hold):
            return float(bars.loc[idx, "close"]) - spread_j / 2.0, "forced_flatten" if is_final else "time_stop"
    return float(bars.loc[entry_idx, "close"]), "no_exit"

7. Position Sizing & Risk Limits

  • Volatility-scaled sizing: (Equity × Risk_Fraction) / Stop_Distance M23.
  • Max 1 open trade per sleeve per session. Max daily loss = $3 \times \text{ATR Risk}$.
  • Trading Pauses trigger immediate flat state and 4-bar cooldown post-resume.

8. ML Extension — Meta-Label Veto

  • Calibrated logistic or shallow XGBoost classifier trained on training folds to accept or veto routed signals.
  • Optimized for net expected R after transaction costs, not accuracy.

9. Failure Modes & Reject Criteria

  • Reject if: Routed net expectancy ≤ 0 after spread and fee stress; ambiguous share > 12%; edge inverts at p90 spread; or opposite placebo matches routed net.

P2 — UTC Synthetic Reversion / Continuation (M5, Delta from P1)

Differences from P1:

# P2 packet — funding calendar join and UTC-synthetic flatten guard
import pandas as pd

def funding_exclusion_mask(m5_index: pd.DatetimeIndex, funding_times_utc: pd.DatetimeIndex,
                           exclude_bars_before: int = 1, exclude_bars_after: int = 1) -> pd.Series:
    mask = pd.Series(False, index=m5_index)
    for ft in funding_times_utc:
        loc = m5_index.get_indexer([ft], method="nearest")
        for b in range(-exclude_bars_before, exclude_bars_after + 1):
            idx = loc[0] + b
            if 0 <= idx < len(m5_index):
                mask.iloc[idx] = True
    return mask

def is_utc_final_flatten_bar(ts: pd.Timestamp, flatten_hhmm: str = "23:50") -> bool:
    return ts.strftime("%H:%M") == flatten_hhmm

P3 — Same-Session Relative Value (M5, Dual-Leg Extension)

Differences from P1/P2:

  • Pair Structure: GLD/SLV proxy or BTC Spot-Perp basis.
  • Model: Rolling OLS hedge ratio ($\beta$) and z-score of residuals over 60 M5 bars.
  • Execution: Simultaneous next-open execution. Both legs must fill cleanly; if one leg is stale, the bar is excluded.
  • Costs: Deducts two full observed spreads on entry and exit.
  • Single-Leg Placebo Check: Pair net must exceed 70% contribution of the best single leg alone.
# Pair hedge and z-score (P3) — trailing OLS hedge, same-session only
import numpy as np

def rolling_hedge_z(y: np.ndarray, x: np.ndarray, lookback: int = 60):
    betas, zs = [], []
    for i in range(lookback, len(y)):
        y_w, x_w = y[i-lookback:i], x[i-lookback:i]
        beta = np.cov(y_w, x_w)[0,1] / np.var(x_w) if np.var(x_w) > 0 else 1.0
        resid = y_w - beta * x_w
        mu, sd = resid.mean(), resid.std(ddof=1)
        z = (y[i] - beta * x[i] - mu) / sd if sd > 0 else 0.0
        betas.append(beta); zs.append(z)
    return np.array(betas), np.array(zs)

Building It In Python

# Complete Playbook Router Pipeline
import polars as pl
import pandas as pd
import numpy as np

def run_playbook_engine(bars: pl.DataFrame, card_type="etp"):
    # 1. Cost & Liquidity Gates
    spread_to_atr = bars["spread"] / bars["atr_14"]
    cost_to_target = (bars["spread"] + 0.004) / (0.9 * bars["atr_14"])
    eligible = (spread_to_atr <= 0.18) & (cost_to_target <= 0.12) & (bars["spread_pctile"] < 0.85)

    # 2. Regime Routing Permissions
    regime = bars["regime_label"]
    cont_on = eligible & regime.is_in(["expansion"])
    rev_on = eligible & regime.is_in(["quiet", "normal"])

    return bars.with_columns([
        cont_on.alias("allow_trend"),
        rev_on.alias("allow_reversion")
    ])

Testing It Honestly

Institutional validation requires auditing four parallel ledgers:

  1. Always-On Baseline: Sleeves executed without regime permissions.
  2. Routed Ledger: Sleeves executed only when authorized by active regime.
  3. Opposite-Route Placebo: Inverted regime routing (quiet executes trend; expansion executes reversion). Must lose net capital.
  4. 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

Variants & Extensions

flowchart TD
    card{"Which lane holds<br/>the exposure?"}
    wrapper{"Which wrapper<br/>or contract?"}
    clock{"Which clock<br/>must be honored?"}
    gate{"Do the two<br/>cost ceilings<br/>pass?"}
    router{"Which router<br/>earns its switch<br/>after overlay?"}
    p1["P1 ETP RTH<br/>OR + VWAP fade<br/>+ premium/track kill"]
    p2s["P2 Spot sub-card<br/>UTC VWAP fade<br/>no funding leg"]
    p2p["P2 Perp sub-card<br/>same trigger<br/>exclude or book funding"]
    p3etp["P3 ETP pair<br/>trust vs trust<br/>dual-spread"]
    p3basis["P3 Basis pair<br/>spot vs perp<br/>+ funding leg"]
    wait["Fix the venue<br/>before the signal"]

    card -->|"commodity ETP"| wrapper
    card -->|"native crypto"| clock
    wrapper -->|"physical trust"| p1
    wrapper -->|"futures pool"| p1
    wrapper -->|"ETN"| p1
    clock --> gate
    gate -->|"no: spread/ATR<br/>or cost/target breach"| wait
    gate -->|"yes"| router
    router -->|"single leg survives"| p2s
    router -->|"perp funding<br/>calendar declared"| p2p
    router -->|"z + beta survives<br/>both legs' invoices"| p3etp
    router -->|"basis survives<br/>both spreads + funding"| p3basis
    wait --> router

Hands-On Project

Deliverables:

  • docs/research/playbook-etp-m16.md (Commodity ETP Card, wrapper diagnostics, TCA bridge).
  • docs/research/playbook-crypto-m16.md (Crypto Spot & Perp Sub-Cards, funding calendar audit).
  • src/research/playbooks_m16.py (Reproducible implementation of all cards and gates).

Project Card TOML Template (Nominated Playbook v1.0)

[identity]
lane = "etp"                      # "etp" | "crypto_spot" | "crypto_perp" | "pair"
instrument = "GLD-like physical trust (primary)"
wrapper_contract = "physical_grantor_trust"
venue = "NYSE Arca"
account = "broker-RTH"
data_source = "OHLCV+spread, consolidated last, schema 9f3c"

[horizon]
primary_tf = "M5"
deltas = ["M1", "M15"]
max_hold_bars = 12
forced_flatten = "15:55 ET (final eligible M5 bar)"

[clock]
timezone = "America/New_York"
eligible_session = "09:30-16:00 ET Core"
auction_rule = "no new entry 15:50-16:00 imbalance; exit-only"
funding_rule = "n/a"
halt_rule = "LULD Limit/Straddle -> manage-only; Trading Pause -> flat, blocked N bars after resume"

[execution]
signal_forms = "close of bar t (completed only)"
fill_eligible = "open of next eligible bar t+1, same declared session"
fill_price = "next open +/- spread/2 per card's spread convention (full, price units)"
ambiguous = "adverse-first (stop) or exclude and report share"
gap_rule = "gap beyond barrier at open -> fill at open then evaluate"
auction_funding = "closing auction handled per auction_rule; funding n/a"

[costs]
spread = "observed per-bar full spread from venue OHLCV+spread"
fees_bps = 1.5
slippage_bps = 2.0
funding = "n/a"
borrow = "n/a (long/flat only)"

[information]
htf_join = "right-label forward-fill with one-bar processing lag (as-of)"
h1_features = ["close > EMA20 bias", "ATR level"]
d1_features = ["ATR percentile (level context only)"]

[risk]
constitution = "M23 volatility-scaled fixed-fractional; risk_fraction from constitution"
per_trade_rule = "ATR-stop distance; regime 0.5-1.0x multiplier"
session_day_venue_book = "session 1.0-1.5x / day 2-3x per-trade loss; venue 1 position/card; book per M25"
kill = "Trading Pause / malformed bar burst / flatten-failure -> kill_flat with cool-down, book verified flat"

[validation]
walk_forward = "purged rolling OOS, embargo = overlap window + feature lookback, chronological, untouched final period"
ablations = ["routed vs always-on", "vs opposite-route", "dwell/no-dwell", "HTF-gated/ungated", "M1/M5/M15", "wrapper/SP: pool vs ETN vs spot/perp", "funding exclude vs booked (perp)", "pair vs single-leg (P3)"]
trial_ledger = "append-only, append on every ceiling/threshold/label-cut change"

[acceptance]
net_expectancy = "routed > 0 R net after spread+stress at adverse-or-exclude with forced flatten"
opportunity_floor = "eligible pass rate >= 40% of bars (card-parameter example)"
cost_resilience = "not inverted at p90 nor at 1.5x spread stress"
paper = "forward >= 2 weeks, sign matches OOS within tolerance, gross-to-net bridge within tolerance"
reject = "any deterministic trigger listed in P1/P2/P3 section 9"

Key Takeaways

  • A playbook is a venue operating manual: It synthesizes frozen upstream alpha with an M15 regime router under venue-specific constraints.
  • Wrappers dictate economics: Physical trusts, futures pools with 5-day roll windows USO overview, and ETNs Fidelity on special rules represent fundamentally different financial assets.
  • Crypto spot and perps are distinct instruments: Spot represents coin ownership; perpetuals carry mark liquidation and funding carry DataWallet on perps vs spotCoinbase International Exchange on instruments.
  • Cost gates decide before sleeves: Block bars where spread-to-ATR > 0.18 or cost-to-target > 0.12.
  • Enforce causal execution: Signal on close t, fill on open t+1, deduct spread, book ambiguous adverse-first, and flatten unconditionally.
  • Pairs require dual friction accounting: Both legs must clear spread invoices simultaneously; verify net returns exceed single-leg placebo contributions.
  • Standardize the rubric, not the assumptions: Both lanes pass under an identical acceptance checklist with lane-local cost parameters.

References