The Learning Library
Contents

Module 16 — Commodity ETP & Crypto Intraday Playbooks

Part III · Intraday Design, Alpha & Playbooks · Priority 🎯 Core Status: Draft v0.2 · Scope: commodity ETFs/ETPs (physical trusts, futures pools/ETNs) + BTC/ETH spot & linear perps · Horizon: M1/M5 (M15 where appropriate), same-session flat; H1/H4/D1 completed bars causal context only Prerequisites: M1, M5, M7, M10, M11, M12, M15, M22, M23


Overview

You start this module with the venue and the asset you actually trade, not with an indicator.

On the ETP lane, you do not buy physical commodity. You buy a U.S.-listed commodity ETP share trading 09:30 to 16:00 ET at market prices drifting from net asset value (NAV). Creation and redemption occur solely in large institutional units via authorized participants SEC ETF bulletin. The legal wrapper dictates your true economics:

On the crypto lane, you select between spot (direct asset ownership settled in coin) and linear perpetuals (derivative contracts settled in quote currency, anchored to spot via recurring funding payments) DataWallet on perps vs spot. On institutional venues like Coinbase International Exchange, this boundary is explicit: PERP versus SPOT carry distinct tick sizes, lot rules, and funding endpoints Coinbase International Exchange on instruments. Perpetuals charge periodic rent via venue-specific funding schedules TradingCopilot on funding rates. Holding across funding boundaries without booking carry invalidates your backtest.

                      THE VENUE OPERATING MANUAL & THE BOUNCER

   ┌─────────────────────────────────────────────────────────────────┐
   │                  UPSTREAM STRATEGIES (THE BANDS)                │
   │      [ M10 Trend ]       [ M11 Reversion ]       [ M12 Pairs ]  │
   └────────────────────────────────┬────────────────────────────────┘


   ┌─────────────────────────────────────────────────────────────────┐
   │               THE PLAYBOOK ROUTER (THE BOUNCER)                 │
   │                                                                 │
   │  Venue Gate:    Is the bar cheap? (Spread-to-ATR <= 0.18)       │
   │  Regime Gate:   Does volatility authorize this sleeve? (M15)    │
   │  Clock Gate:    RTH Canal Lock (ETP) OR UTC Synthetic (Crypto)  │
   │  Safety Gate:   LULD Pauses (ETP) OR Funding Timestamps (Perp)  │
   └────────────────────────────────┬────────────────────────────────┘


   ┌─────────────────────────────────────────────────────────────────┐
   │                    VENUE EXECUTION DESK                         │
   │  - Signal at Close[t] ──► Fill at Next Open[t+1]                │
   │  - Observed Spread Deducted ──► Mandatory Same-Session Flatten  │
   └─────────────────────────────────────────────────────────────────┘

The trading clock governs price validity:

  1. ETP Regular Trading Hours (RTH): Core session 09:30–16:00 ET with opening auctions at 09:30 and closing imbalance periods 15:50–16:00 ET NYSE trading informationNYSE holidays and trading hours. Governed by LULD price bands (5% Tier 1 bands triggering 5-minute Trading Pauses) and market-wide circuit breakers LULD Plan.
  2. Crypto UTC Synthetic Session: Operating on a 24/7 tape requires declaring a deterministic synthetic boundary (e.g., 00:00 to 23:50 UTC with forced flatten at 23:50 UTC) Obside on day trading crypto.

📌 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).

The preregistered hypothesis is narrow: a venue-specific intraday playbook that synthesizes frozen upstream sleeves (M10 trend, M11 mean reversion, M12 relative value) with an M15 regime router under explicit venue contracts generates positive net expectancy across purged out-of-sample testing after accounting for observed spreads, fees, slippage stress, and conservative execution.

Evidence status: hypothesis, mechanics-supported. Wrapper structures, NAV tracking, exchange auction rules, LULD mechanics, and perpetual funding calculations are documented market realities DataWallet on perps vs spotUSO overview. Replay simulations must prove net profitability after transaction costs.

Primary failure modes include:

  • Interchangeability Mirage: Treating physical trusts, futures pools, spot, and perpetuals as identical symbols, ignoring roll yield and funding carry.
  • Cost Mirage Feasibility: Trading when spread consumes more than 18% of ATR or 12% of target distance M7M13.
  • Ambiguous-Bar Optimism: Booking favorable outcomes when a single bar touches both stop and target ohlcv.io on bar resolution.
  • Same-Close Execution Bias: Filling at signal generation close rather than next bar open Saral on next-bar-open execution.

💡 Intuition: A playbook functions as a venue operating manual, and the router is the bouncer. Upstream alpha strategies (M10/M11/M12) are bands waiting backstage. The playbook bouncer decides which band takes the stage based on venue house rules (RTH canal locks, LULD pauses, crypto funding leases). You standardize the audit checklist, not the venue assumptions.


How It Works

A complete playbook integrates three venue truths, one regime decision, and one execution contract.

1. Venue & Wrapper Realities

2. The Cost Surface (Triage Before Trading)

Every candidate bar must pass two cost gates:

  • Spread-to-ATR: observed_spread / ATR_M5 <= 0.18 (Wage vs. Invoice).
  • Cost-to-Target: (spread + fee + slip) / target_dist <= 0.12 (Friction vs. Expectancy).

3. Regime Routing (M15 Switch)

The M15 router evaluates volatility and liquidity metrics:

  • 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).

4. Causal Bar-Based Execution Contract

  • Signals evaluate at close t; fills execute at open t+1.
  • Full observed spread deducted per side.
  • Ambiguous bars resolve adverse-first (stop booked).
  • Mandatory flatten at 15:55 ET (ETP) or 23:50 UTC (Crypto).
flowchart TD
    wrapper["Wrapper/contract truth<br/>physical vs futures pool vs ETN<br/>spot vs linear perp"] --> clock["Session clock<br/>ETP RTH 09:30-16:00 ET<br/>perp UTC synthetic 00:00-23:50 UTC"]
    data["OHLCV + spread<br/>M1/M5/M15 completed bars"] --> atr["ATR + realized vol<br/>spread percentile<br/>vol-of-vol"]
    clock --> atlas["Hour/minute atlas<br/>spread/ATR/pass rate"]
    wrapper --> exec["Execution contract<br/>close t -> open t+1<br/>spread deducted<br/>ambiguous adverse-or-exclude<br/>forced flatten"]
    data --> router["M15 regime router<br/>quiet/normal/expansion/<br/>late expansion/stressed"]
    atr --> ratio1["Spread-to-ATR<br/>cost vs normal bar"]
    atlas --> ratio1
    atr --> ratio2["Cost-to-target<br/>cost vs intended win"]
    atlas --> ratio2
    ratio1 --> gate1{"Spread-to-ATR<br/>below ceiling?"}
    ratio2 --> gate2{"Cost-to-target<br/>below ceiling?"}
    router --> gate3{"Regime permits<br/>this sleeve this bar?"}
    exec --> gate1
    exec --> gate2
    gate1 -->|"no"| reject["Block bar<br/>no new entry<br/>manage exits only"]
    gate2 -->|"no"| reject
    gate3 -->|"no"| reject
    gate1 -->|"yes"| ready["Eligible bar<br/>permitted sleeve<br/>may trigger at next open"]
    gate2 -->|"yes"| ready
    gate3 -->|"yes"| ready
    ready --> signal["Frozen sleeve trigger<br/>M10 breakout/continuation<br/>M11 reversion<br/>M12 same-session pair"]
    signal --> fill["Bar-based fill<br/>open t+1, gap-aware"]
    fill --> ambig{"Both barriers<br/>touched in one HLC bar?"}
    ambig -->|"no"| book["Book stop or target<br/>net of spread + stress"]
    ambig -->|"yes"| adverse["Adverse-first or exclude<br/>count ambiguous share"]
    book --> flatten{"Final eligible bar<br/>of declared session?"}
    adverse --> flatten
    flatten -->|"yes"| flat["Forced flatten<br/>same session<br/>no overnight"]
    flatten -->|"no"| hold["Hold to next bar<br/>time stop still ticking"]

    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 wrapper,data,clock data
    class atr,atlas,router,exec,ratio1,ratio2,signal,fill,book,adverse,flat,hold process
    class gate1,gate2,gate3,ambig,flatten decision
    class reject risk
    class ready ok

Strategy Rules

1. Shared 9-Point Template

Every playbook card freezes the following 9 points:

  1. Market, Timeframe, and Data: Identity, wrapper, venue, data schema, primary TF (M5).
  2. Mechanics vs. Hypothesis: Distinct separation of engineering facts from statistical claims.
  3. Technical Indicators: Deterministic functions of OHLCV + observed spread.
  4. Causal HTF Context & LTF Trigger: Completed H1/H4/D1 joined at release timestamp; M5 execution.
  5. Exact Entry, Stop, Target, Time Stop, Flatten: Precise order mechanics and session bounds.
  6. Spread/Cost Filter & Execution Rules: Gate thresholds, ambiguous resolution, gap fills.
  7. Position Sizing & Risk Controls: Volatility-scaled fixed-fractional sizing M23.
  8. ML Extensions: Proportional meta-labeling or HMM routing walked forward causally.
  9. Failure Modes & Ablations: Mandatory stress testing, placebos, and reject triggers.

2. Synthesis Playbook Cards

Card Asset Class Venue & Clock Upstream Alpha Synthesis
P-ETP Commodity ETPs (GLD/PDBC proxy) NYSE Arca RTH (09:30–16:00 ET) M10 Opening Range Breakout + M11 VWAP/Bollinger Reversion routed via M15 Volatility Buckets
P-CRYPTO BTC/ETH Spot & Linear Perp Approved CEX UTC Synthetic (00:00–23:50 UTC) M11 UTC VWAP Fade + M10 Momentum Breakout routed via M15 Volatility Buckets with Funding Exclusions

Building It In Python

# Project card definitions — freeze venue truth before execution
from dataclasses import dataclass

@dataclass(frozen=True)
class PlaybookCard:
    lane: str
    instrument: str
    wrapper: str
    venue: str
    account: str
    data_source: str
    primary_tf: str
    session: str
    funding_rule: str
    price_basis: str
    spread_units: str
    cost_ceiling_spread_to_atr: float
    cost_ceiling_cost_to_target: float
    max_hold_bars: int
    execution: str

CARD_ETP = PlaybookCard(
    lane="etp", instrument="GLD-like physical trust",
    wrapper="physical_grantor_trust", venue="NYSE Arca", account="broker-RTH",
    data_source="OHLCV+spread, schema 9f3c",
    primary_tf="M5", session="09:30-16:00 ET, flatten 15:55 ET",
    funding_rule="n/a", price_basis="market price last",
    spread_units="full spread price units",
    cost_ceiling_spread_to_atr=0.18, cost_ceiling_cost_to_target=0.12,
    max_hold_bars=12, execution="close t -> open t+1, adverse ambiguous, gap at open"
)

CARD_PERP = PlaybookCard(
    lane="crypto_perp", instrument="BTC-PERP linear perp",
    wrapper="linear_perp", venue="CEX-A", account="cex-cross-margin",
    data_source="OHLCV+spread, schema a4e1",
    primary_tf="M5", session="synthetic 00:00-23:50 UTC, flatten 23:50 UTC",
    funding_rule="exclude entries spanning 00/08/16 UTC funding",
    price_basis="perp last", spread_units="full spread price units",
    cost_ceiling_spread_to_atr=0.18, cost_ceiling_cost_to_target=0.12,
    max_hold_bars=12, execution="close t -> open t+1, adverse ambiguous, gap at open"
)
# Causal HTF join and cost triage gates
import pandas as pd
import numpy as np

def asof_join_m5_with_h1(m5: pd.DataFrame, h1_features: pd.DataFrame) -> pd.DataFrame:
    h1_on_m5 = h1_features.reindex(m5.index, method="ffill")
    return m5.join(h1_on_m5, rsuffix="_h1")

def cost_gates(bars: pd.DataFrame, fee_bps: float = 1.5, slip_bps: float = 2.0) -> pd.DataFrame:
    mid = (bars["high"] + bars["low"]) / 2.0
    fee = mid * (fee_bps / 1e4)
    slip = mid * (slip_bps / 1e4)
    bars = bars.copy()
    bars["spread_to_atr"] = bars["spread"] / bars["atr"].replace(0, np.nan)
    target = 0.9 * bars["atr"]
    bars["cost_to_target"] = (bars["spread"] + fee + slip) / target.replace(0, np.nan)
    bars["spread_p75"] = bars["spread"].rolling(78, min_periods=20).quantile(0.75)
    bars["gate_cheap"] = (bars["spread_to_atr"] <= 0.18) & (bars["cost_to_target"] <= 0.12)
    bars["gate_spread_percentile"] = bars["spread"] <= bars["spread_p75"]
    bars["eligible"] = bars["gate_cheap"] & bars["gate_spread_percentile"]
    return bars
# Bar-based replay engine with adverse ambiguous handling and forced flatten
def next_open_fill_replay(bars: pd.DataFrame, signal_on_close: pd.Series,
                          stop_atr: float = 2.0, target_atr: float = 1.5,
                          max_hold: int = 12, flatten_bar_str: str = "15:55"):
    positions = []
    # Vectorized / sequential walk forward through M5 bars
    for i in range(len(bars) - 1):
        if signal_on_close.iloc[i] and bars["eligible"].iloc[i]:
            entry_bar = i + 1
            entry_price = bars["open"].iloc[entry_bar] + (bars["spread"].iloc[entry_bar] / 2.0)
            stop_price = entry_price - (stop_atr * bars["atr"].iloc[i])
            target_price = entry_price + (target_atr * bars["atr"].iloc[i])

            # Walk forward across holding period
            for hold in range(1, max_hold + 1):
                cur = entry_bar + hold
                if cur >= len(bars):
                    break
                h, l, ts = bars["high"].iloc[cur], bars["low"].iloc[cur], bars.index[cur]

                # Check Ambiguous First
                if h >= target_price and l <= stop_price:
                    positions.append({"pnl": stop_price - entry_price, "exit": "ambiguous_stop", "bar": cur})
                    break
                elif l <= stop_price:
                    positions.append({"pnl": stop_price - entry_price, "exit": "stop", "bar": cur})
                    break
                elif h >= target_price:
                    positions.append({"pnl": target_price - entry_price, "exit": "target", "bar": cur})
                    break
                elif ts.strftime("%H:%M") == flatten_bar_str or hold == max_hold:
                    exit_price = bars["close"].iloc[cur] - (bars["spread"].iloc[cur] / 2.0)
                    positions.append({"pnl": exit_price - entry_price, "exit": "flatten", "bar": cur})
                    break
    return pd.DataFrame(positions)

Testing It Honestly

Institutional validation requires auditing four parallel ledgers:

  1. Purged Out-of-Sample Folds: Chronological splits with embargoes preventing look-ahead leakage.
  2. Always-On Baseline: Sleeves executed without regime permissions.
  3. Opposite-Route Placebo: Inverted regime routing (quiet executes trend; expansion executes reversion).
  4. Cost Stress Grid: Evaluated at p50 spread, p90 spread, and $1.5\times$ spread stress.
                         THE AUDIT STRESS SPECTRUM

   [ p50 Spread ] ──► Normal Market Conditions  ──► Must show robust net positive R
   [ p75 Spread ] ──► Moderate Liquidity Drag   ──► Must maintain positive expectancy
   [ p90 Spread ] ──► Severe Stress / Gaps      ──► Must NOT invert to large losses
   [ 1.5x Spread ]──► Crisis Shock Simulation   ──► Evaluates structural survival

Institutional Pitfall Checklist

# Trap Mechanism of Error Institutional Defense
P1 Wrapper Blending Averaging physical trust premium with futures roll yield Declare wrapper explicitly in project card Fidelity on special rules
P2 LULD Pause Illusion Assuming executions continue during halts Halt bars logged; fills re-priced at post-auction reopen LULD Plan
P3 Crypto Mark/Last Confusion Executing at mark price while exchange executes at last Execute strictly on last; use mark for liquidation distance DataWallet on perps vs spot
P4 HTF Look-Ahead Using forming H1 bars to filter current M5 trades Join H1 causally with right-label + 1-bar lag M9
P5 Ambiguous Bar Optimism Booking winners when bar touches stop and target Enforce conservative adverse-first resolution ohlcv.io on bar resolution
P6 Cost-to-Target Creep Tightening stop without re-pricing target ratio Recompute cost_to_target per bar dynamically

Variants & Extensions

Variant Modification Valid Use Case Required Ablation
M1/M15 Horizon Deltas Execute on M1 or M15 bars M5 invoice exceeds ceiling during thin hours M1 vs. M5 vs. M15 feasibility frontier M7
HTF Causal Gate Add completed H1/D1 trend/vol filter Strong macro directional momentum exists Gated vs. Ungated net P&L comparison
Router Architecture Swap Bucket for GMM or HMM Non-linear volatility regimes exist Bucket vs. GMM vs. HMM under identical overlay
Futures Pool Delta Switch from GLD to PDBC/USO proxy Broker restricts physical metal access Roll-week exclusion vs. standard execution USO overview
Perp Funding Carry Mode Book realized funding instead of excluding Holding through 8h funding timestamps Exclusion vs. Carry-booked net P&L TradingCopilot on funding rates

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).

Standard Acceptance Rubric (Applied Separately per Lane)

Rubric Gate Pass Standard Verification Artifact
Net OOS Expectancy Net expectancy > 0 R after spread + fee stress Purged rolling OOS walk-forward ledger
Session Economics Expectancy per eligible session > 0 Hourly session atlas
Cost Resilience Net expectancy not inverted at p90 spread Cost-stress sensitivity grid
Execution Integrity Ambiguous share < 12%; adverse-first resolution Ambiguous bar audit log ohlcv.io on bar resolution
Causal Lineage HTF features joined strictly at release timestamp Temporal lineage unit test M9
Paper Bridge Paper trading matches backtest within 15% tolerance Replay vs. Paper P&L reconciliation

Key Takeaways

  • A playbook is a venue operating manual: It synthesizes frozen M10/M11/M12 sleeves with an M15 router under venue-specific constraints.
  • Wrappers dictate economics: Physical trusts, futures pools, and ETNs behave differently; never treat them as identical tickers Fidelity on special rulesUSO overview.
  • Crypto spot and perps are distinct instruments: Spot represents asset 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.
  • Completed HTF bars only: Slower timeframes provide context; they never postpone session flatten mandates.
  • Standardize the rubric, not the assumptions: Both lanes pass under an identical acceptance checklist with lane-local cost parameters.

References