> ## Documentation Index
> Fetch the complete documentation index at: https://docs.omnibook.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Strategy templates

> Season 1 SDK skeletons for the 60-second BTC Yes/No CLOB. Market making first, then taking, vol, and lead-lag.

Internal catalog for the Season 1 SDK. These are teaching skeletons, not advertised edges.

**Market:** 60-second BTC Yes/No (Up/Down) binary, rolling windows, CLOB.\
**Series:** `ob-btc-ud-60s`. Yes = Up, No = Down. One Yes + one No = \$1.

IDs are stable. Cross-references (`#7`, `#11`, `#17`) keep the original numbers even though families are grouped out of numeric order.

***

## How to read a template

Every runnable template below is a thin wrapper around [#0 Fair-value engine](#0-fair-value-engine). Each one is specified as:

| Field         | Meaning                                                          |
| ------------- | ---------------------------------------------------------------- |
| **Thesis**    | What you are selling or buying, in one sentence                  |
| **Habitat**   | Where the template is allowed to be on. Off elsewhere            |
| **Edge**      | Where the PnL is supposed to come from                           |
| **Guards**    | Mandatory pull / widen / kill conditions                         |
| **Dies when** | The failure mode that empties the account if you skip the guards |
| **Ship**      | `library` · `first` · `core` · `later` · `gated` · `internal`    |

`gated` means do not put it in the default bundle. `internal` means stress-test on the venue before any user sees it.

***

## Venue facts the templates assume

These are the Omnibook rules that change the math. Do not treat this book as a generic 60-second digital.

| Fact                        | Value                                                 | Why it matters                                                                            |
| --------------------------- | ----------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| Round length                | 60s                                                   | Finite, known `τ`. Avellaneda–Stoikov is well-posed                                       |
| Tick                        | Integer cents, **1–99**                               | 0 and 100 are settlement bounds, not quotes                                               |
| Open / strike `K`           | Last-good oracle median at round open                 | Frozen for the round                                                                      |
| Close                       | **TWAP of the last 10s** of the same sequenced oracle | Last-print digital math is wrong inside the window                                        |
| Tie                         | Close ≤ open → **No**                                 | Slight structural No bias                                                                 |
| Oracle                      | Median of Binance, Bybit, OKX, Kraken, Bitget perps   | A single-venue spike often does not print                                                 |
| Cadence                     | 4 Hz, quorum 3 of 5 fresh                             | Lag is often “waiting for the third venue,” not a slow index                              |
| Fees (live 60s, schedule 2) | **Maker 0 / taker 250**                               | Kalshi-style: `fee ≈ ceil(rate · qty · p · (100−p) / 1e6)` ¢                              |
| Orders at freeze            | Unfilled limits cancel, never roll                    | Every round is a cold book                                                                |
| Trading in TWAP             | Stays open through the last 10s                       | [#16](#16-settlement-window-liquidity) and [#22](#22-oracle-print-anticipation) live here |

Taker 250 is \~2.5% of `p(100−p)`. At 50¢ that is about **0.63¢ per share**; in the wings it collapses. Maker is free, so posting is the only structure that keeps thin edges. Re-model every taker template if Season 1 pricing hardens.

Each template below has a Python SDK skeleton. Teaching code. Not a hosted bot. Paste onto the [shared loop](#shared-skeleton) and swap the `quotes_for` function.

***

## Shared skeleton

Websocket (oracle + book + trades), order lifecycle, position tracker, kill switch. Every runnable template is a `quotes_for(state)` on top of this.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
import math, os, time
from omnibook import Client

TAKER_RATE = 250
TWAP_S = 10.0


def n_cdf(x):
    return 0.5 * (1.0 + math.erf(x / math.sqrt(2.0)))


def clamp_tick(p):
    return max(1, min(99, int(round(p))))


def px(x):
    v = float(x)
    return v / 1e8 if v > 1e6 else v


def tau_s(rnd):
    return max(int(rnd["freeze_ts"]) / 1e9 - time.time(), 0.0)


def taker_fee_cents(qty, tick):
    return math.ceil(TAKER_RATE * qty * tick * (100 - tick) / 1e6)


def path_fair(spot, strike, sigma, tau):
    if spot <= 0 or strike <= 0 or sigma <= 0 or tau <= 0:
        return 1.0 if spot > strike else 0.0 if spot < strike else 0.5
    d = math.log(spot / strike) / (sigma * math.sqrt(tau))
    return n_cdf(d)


def fair_now(spot, strike, sigma, tau, twap_so_far=None, t_in=0.0):
    if tau <= TWAP_S and twap_so_far is not None:
        w_left = max(0.0, (TWAP_S - t_in) / TWAP_S)
        close = (1.0 - w_left) * twap_so_far + w_left * spot
        return path_fair(close, strike, sigma, max(w_left * TWAP_S, 1e-6))
    return path_fair(spot, strike, sigma, tau)


def is_jump(spot, prev, sigma, dt, n=4.0):
    if prev <= 0:
        return False
    return abs(math.log(spot / prev)) > n * sigma * math.sqrt(max(dt, 1e-6))


def replace_quotes(client, live, market_id, quotes, qty):
    for oid in live:
        try:
            client.cancel_order(oid)
        except Exception:
            pass
    live.clear()
    now = int(time.time() * 1000)
    for i, q in enumerate(quotes):
        o = client.place_order(
            client_order_id=str(now + i),
            market_id=market_id,
            side=q["side"],
            outcome=q["outcome"],
            type="limit",
            tick=q["tick"],
            qty=qty,
            tif="gtc",
            post_only=True,
        )
        if o.get("order_id"):
            live.append(o["order_id"])


def run(quotes_for, qty=5):
    live = []
    with Client(api_key=os.environ["OMNIBOOK_API_KEY"], api_secret=os.environ["OMNIBOOK_API_SECRET"]) as client:
        rnd = client.get_rounds(limit=1)["rounds"][0]
        market_id = rnd["market_id"]
        with client.websocket() as ws:
            ws.subscribe(channels=["rounds", "oracle", "user"])
            ws.subscribe(channels=["orderbook_snapshot", "trades"], market_ids=[market_id])
            state = {"round": rnd, "spot": None, "prev": None, "book": None, "inv": 0}
            for msg in ws:
                ch = msg.get("channel")
                if ch == "rounds":
                    state["round"] = msg
                    market_id = msg.get("market_id", market_id)
                elif ch == "oracle":
                    state["prev"] = state["spot"]
                    state["spot"] = px(msg.get("price") or msg.get("median") or 0)
                elif ch in ("orderbook_snapshot", "orderbook_delta"):
                    state["book"] = msg
                decision = quotes_for(state)
                if decision == "kill":
                    replace_quotes(client, live, market_id, [], qty)
                elif isinstance(decision, list):
                    replace_quotes(client, live, market_id, decision, qty)
```

`quotes_for` returns a list of `{side, outcome, tick}`, `"kill"`, or `None` (leave resting). Taker templates call `place_order(..., post_only=False)` instead of `replace_quotes`.

***

## 7. 99¢ short vol

**Thesis:** Edge is real and large. At \$100k BTC with \~50% annualized vol, per-second `σ ≈ 0.9bp`. Ten seconds left, 10bps above strike, `d = 3.5`, `N(−3.5) ≈ 0.02%`. Someone is paying 1¢ for a 2bp event.

Two caveats to bake into the template:

1. BTC 1-min returns are fat-tailed. Gaussian understates the tail by roughly an order of magnitude.
2. Needs a hard realized-vol kill switch or one jump erases a month.

**TWAP changes the tail.** A last-print settle makes a 10bp wick in the last second a full loss. A 10s TWAP does not: a 1s wick is \~10% of the window. The event you are short is a *sustained* move through the remaining weight, not a single print. That makes the edge cleaner than the Gaussian headline, and it makes the kill switch a “move that holds,” not a “print that spikes.”

**Habitat:** Fair already through 95¢, `τ` small, realized-vol calm. Off in #15 chaos.

**Edge:** Selling an overpriced digital on a move that the TWAP will not fully credit.

**Guards:** Hard kill on realized vol and on a move that persists across consecutive oracle prints. Position cap such that one full loss is a known fraction of daily budget, not of the account.

**Dies when:** You size like the Gaussian 2bp event is the risk.

**Ship:** First. Top of this page.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# templates/07_short_vol.py
from skeleton import is_jump, tau_s, fair_now, px, TWAP_S

def quotes_for(s, sigma=0.00009):
    rnd, spot = s.get("round") or {}, s.get("spot")
    if not spot or rnd.get("status") != "trading":
        return "kill"
    tau = tau_s(rnd)
    strike = px(rnd["strike"])
    fair = 100 * fair_now(spot, strike, sigma, tau, s.get("twap_so_far"), max(TWAP_S - tau, 0.0))
    if fair < 95 or s.get("regime") == "chaos":
        return "kill"
    if is_jump(spot, s.get("prev") or spot, sigma, 0.25) or s.get("held_move"):
        return "kill"
    # Sell the 1c No tail. Needs No inventory. Size so one full loss is a known daily fraction.
    return [{"side": "sell", "outcome": "no", "tick": 1}]
```

***

## Catalog

All 26 templates ship. **#7 99¢ short vol is first.** Then market making. Taking, lead-lag, and the rest of vol sit under that.

### Featured

| ID | Template      | Ship  | One-line                                                     |
| -- | ------------- | ----- | ------------------------------------------------------------ |
| 7  | 99¢ short vol | first | Sell the 1¢ wing. TWAP dilutes wicks. First bot on this page |

### Market making

| ID | Template                    | Ship    | One-line                                             |
| -- | --------------------------- | ------- | ---------------------------------------------------- |
| 0  | Fair-value engine           | library | Required by every bot. Path-fair, then TWAP residual |
| 15 | Regime-switch spread        | first   | Risk scaffold. Every other MM inherits this          |
| 10 | Pinned-wing MM              | first   | First user bot. Quote only outside 5¢ / 95¢          |
| 13 | Queue-join, don't penny     | first   | Join the touch. Teaches queue without toxic flow     |
| 12 | Cold-start seeder           | core    | First two-sided quote on an empty 60s book           |
| 1  | One-tick-ahead MM           | core    | Penny the touch; pull on jumps; inventory-skew       |
| 2  | Gamma-aware spread          | core    | Spread `∝ 1/√τ` near the strike                      |
| 11 | Complement-hedged quoting   | core    | Two-book coupler. Highest-value MM                   |
| 14 | Markout-filtered MM         | core    | Widen when own 1s/5s markout goes red                |
| 16 | Settlement-window liquidity | later   | Last 10s: sell lock-in above TWAP-fair               |
| 17 | Symmetric box quoting       | later   | Bid 49/49. Only with #20                             |
| 20 | Completion-chasing box      | later   | Walk the broken leg. Makes #17 survivable            |
| 18 | Skewed box                  | later   | 50/48 off OFI                                        |
| 19 | Box ladder                  | later   | 49/48/47 both sides                                  |
| 9  | Fair-anchored adaptive grid | gated   | Grid on model fair. Highest variance                 |

### Then the rest

| ID | Template                      | Family   | Ship     | One-line                                                 |
| -- | ----------------------------- | -------- | -------- | -------------------------------------------------------- |
| 3  | Stale-quote sniper            | Taking   | core     | Lift quotes the oracle has already made wrong            |
| 4  | Order-flow imbalance          | Taking   | first    | Take on OFI z-score. Onboarding taker                    |
| 5  | Crossed-book / complement arb | Taking   | first    | Lift both asks when `ask_yes + ask_no < 100` net of fees |
| 6  | Implied vs realized           | Vol      | core     | Invert the quote for σ, fade or chase                    |
| 8  | Delta-hedged binary           | Vol      | later    | Hedge delta on a perp, keep the vol                      |
| 21 | Cross-venue spot lead-lag     | Lead-lag | later    | Lead venue vs the *median*, not vs a slow index          |
| 22 | Oracle-print anticipation     | Lead-lag | internal | Running 10s TWAP. Residual shrinks every 250ms           |
| 23 | Near-round leads far-round    | Lead-lag | later    | Needs a second live series. Design only today            |
| 24 | Yes book leads No book        | Lead-lag | later    | Trade the lag before it becomes #5                       |
| 25 | Correlated-asset lead-lag     | Lead-lag | later    | Teaching example. Weak at 60s                            |

### Ship order

1. **First bot:** #7 99¢ short vol
2. **MM library / first:** #0 → #15 → #10 → #13
3. **Core MM:** #12 → #1 → #2 → #11 → #14
4. **Box MM:** #17 with #20, then #18 / #19 → #16. Gate #9
5. **Taking:** #4 → #5 → #3
6. **Vol:** #6 → #8
7. **Lead-lag:** #21 → #24 → #23 / #25. #22 stays internal

***

## 0. Fair-value engine

Not a strategy. The base class every template wraps. Ship as a library with the SDK, not as a runnable bot.

### Path-fair (τ > 10s)

While the close is still a future 10-second TWAP that has not started, a digital on the open is a usable first shot:

```
d    = ln(S_t / K) / (σ √τ)
fair = N(d)
```

* `K` is the round's open print (oracle median at open)
* `S_t` is the live oracle median, not a single exchange
* `τ` is seconds to freeze
* `σ` is EWMA of 1s log returns of that same oracle
* `N` is the standard normal CDF; `φ` is its density
* Binary delta is `φ(d) / (S σ √τ)`, which explodes as `τ → 0` on a last-print settle

### Settlement-fair (τ ≤ 10s)

Close is not `S_T`. Close is the time-weighted average of the sequenced oracle over the final 10 seconds (4 Hz, each print holds until the next). After `t` seconds of the window:

```
TWAP_so_far = running average of elapsed prints
w_left      = (10 − t) / 10
close       = (1 − w_left) · TWAP_so_far + w_left · TWAP_remaining
```

Fair is `P(close > K)`, which is a statement about the *remaining* average, not about the next tick. The residual is bounded and shrinks every \~250ms. A Gaussian on `ln(S_t / K)` overstates gamma in the window and understates how solved the last seconds are. [#22](#22-oracle-print-anticipation) is this object traded directly.

Use path-fair to quote the first 50 seconds. Switch the library to settlement-fair when the TWAP window opens. Do not let templates that assume a last-print digital keep running unmodified through the last 10s.

**PnL labels the library should emit:** realized-vol premium, inventory, complement, markout, arb, settlement-residual. Never “grid profit.”

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# templates/00_fair.py  (library, not a bot)
from math import log, sqrt
from skeleton import n_cdf, path_fair, fair_now, TWAP_S


def d_and_fair(spot, strike, sigma, tau):
    d = log(spot / strike) / (sigma * sqrt(tau)) if tau > 0 and sigma > 0 else 0.0
    return d, n_cdf(d)


def engine(spot, strike, sigma, tau, twap_so_far=None, t_in=0.0):
    mode = "settlement" if tau <= TWAP_S else "path"
    p = fair_now(spot, strike, sigma, tau, twap_so_far, t_in)
    d, _ = d_and_fair(spot, strike, sigma, max(tau, 1e-6))
    return {"fair": p, "d": d, "mode": mode, "yes_tick": max(1, min(99, round(100 * p)))}
```

***

## Market making

### 1. One-tick-ahead MM

**Thesis:** Quote one tick inside best bid/ask and earn the spread if the book is slow relative to fair.

**Habitat:** Mid-round, `|d|` not exploding, both books two-sided.

**Edge:** Queue position plus a one-tick improvement, paid by impatient flow.

**Guards:** Two, or it is a donation:

1. Pull or widen when `|ΔS|` exceeds `n · σ √Δt` on the last oracle print.
2. Skew the reservation price by inventory. Avellaneda–Stoikov is well-posed here because `τ` is finite and small:

```
r      = fair − q · γ · σ² · τ
spread ≈ γ σ² τ + (2/γ) ln(1 + γ/k)
```

`q` is signed inventory, `γ` risk aversion, `k` order-arrival density. Recenter `r` every oracle print.

**Dies when:** You penny into a jump and hold the wrong wing into settlement.

**Ship:** Core. Do not make this the first MM a new user runs, that is [#10](#10-pinned-wing-mm).

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# templates/01_one_tick.py
from skeleton import clamp_tick, is_jump, tau_s

def quotes_for(s, sigma=0.00009, gamma=0.08, k=1.5, qty_inv=0):
    spot, prev, book, rnd = s["spot"], s["prev"], s["book"], s["round"]
    if not spot or not book:
        return None
    tau = max(tau_s(rnd), 0.1)
    if is_jump(spot, prev or spot, sigma, 0.25):
        return "kill"
    fair = 100 * s.get("fair", 0.5)
    q = s.get("inv", 0)
    r = fair - q * gamma * sigma**2 * tau
    bid, ask = book["bids"][0][0], 100 - book["bids_no"][0][0] if "bids_no" in book else book.get("ask_yes", fair + 1)
    return [
        {"side": "buy", "outcome": "yes", "tick": clamp_tick(min(ask - 1, r - 1))},
        {"side": "buy", "outcome": "no", "tick": clamp_tick(100 - max(bid + 1, r + 1))},
    ]
```

### 2. Gamma-aware spread

**Thesis:** Spread widens as `1/√τ` when near the strike and stays flat when far.

**Habitat:** Fair in the 20–80 band, especially the last 20s.

**Edge:** You stop being the last quote at 50¢ with 8 seconds left.

**Guards:** Inherit [#15](#15-regime-switch-spread). Flatten or pull when `|d| < 0.3` and `τ < 15`.

**Dies when:** The last 10 seconds near 50¢. That is where accounts die. This template exists to teach that.

**Ship:** Core.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# templates/02_gamma.py
from math import sqrt
from skeleton import clamp_tick, tau_s

def quotes_for(s, sigma=0.00009):
    tau = max(tau_s(s["round"]), 0.1)
    d = abs(s.get("d", 0.0))
    if d < 0.3 and tau < 15:
        return "kill"
    half = max(1, round((1.0 / sqrt(tau)) * (2 if d < 1 else 1)))
    mid = clamp_tick(100 * s.get("fair", 0.5))
    return [
        {"side": "buy", "outcome": "yes", "tick": clamp_tick(mid - half)},
        {"side": "buy", "outcome": "no", "tick": clamp_tick(100 - (mid + half))},
    ]
```

### 9. Fair-anchored adaptive grid

**Thesis:** Levels at `fair ± k·Δ` for `k = 1..n`, re-centered every tick. Spacing `Δ ∝ delta · σ_S · √Δt`, so the grid widens near the strike and collapses in the tails. Geometric size outward.

**Habitat:** Only while `|d| ≥ 1`. Auto-disable inside that band.

**Edge:** Realized-vol premium from mean-reversion of *fair*, not of last trade. Label it that way.

**Guards:** Hard disable at `|d| < 1`. Inventory cap per side. Jump pull from #1.

**Dies when:** You anchor to last-traded price and accumulate the losing side into settlement.

> **Grid warning.** A grid on a binary is short gamma with no theta to pay for it. Spot grids work because price mean-reverts around a level. A binary's level is fair value, which is itself running toward 0 or 100. Anchor to last-traded price and you accumulate the losing side into settlement. Anchor to model fair. Always.

Highest-variance template in the set. Gate it behind the conservative bundle.

**Ship:** Gated.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# templates/09_grid.py
from skeleton import clamp_tick

def quotes_for(s, n=3, delta=2):
    d = abs(s.get("d", 0.0))
    if d < 1:
        return "kill"
    mid = clamp_tick(100 * s.get("fair", 0.5))
    out = []
    for k in range(1, n + 1):
        out.append({"side": "buy", "outcome": "yes", "tick": clamp_tick(mid - k * delta)})
        out.append({"side": "buy", "outcome": "no", "tick": clamp_tick(100 - (mid + k * delta))})
    return out
```

### 10. Pinned-wing MM

**Thesis:** Quote only where fair sits outside 5¢ / 95¢. Fair is stable, noise is bounded by the 1¢ floor, fill rate is high because impatient exiters live there.

**Habitat:** `|fair − 50| ≥ 45`. Off as soon as fair re-enters the middle.

**Edge:** Collect spread where delta is small and markout is bounded.

**Guards:** Still pull on a jump that would drag fair back through 10¢ / 90¢. Size small enough that one reverse-through does not matter.

**Dies when:** You keep quoting the wing after fair has left it.

**Ship:** First. Correct first MM template for a new user. Market-making mirror of [#7](#7-99-short-vol).

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# templates/10_pinned_wing.py
from skeleton import clamp_tick, is_jump

def quotes_for(s, sigma=0.00009):
    fair = 100 * s.get("fair", 0.5)
    if abs(fair - 50) < 45:
        return "kill"
    if is_jump(s["spot"], s["prev"] or s["spot"], sigma, 0.25):
        return "kill"
    if fair >= 95:
        return [{"side": "buy", "outcome": "yes", "tick": 96}, {"side": "buy", "outcome": "no", "tick": 2}]
    return [{"side": "buy", "outcome": "yes", "tick": 2}, {"side": "buy", "outcome": "no", "tick": 96}]
```

### 11. Complement-hedged quoting

**Thesis:** Quote Yes and No books simultaneously. A fill buying Yes at `p` is instantly layable as a sell of No at `100 − p`. Near-zero net delta, spread collected on both books.

**Habitat:** Both books alive. Any `τ`. Strongest when the two books disagree.

**Edge:** Two-book coupler. If a meaningful share of flow runs this (and the [box family](#the-box-family)), the books stay tight to 100 with no seeding required.

**Guards:** Never rest a hedge that would *cross* into a locked-in loser after fees. If the lay is not there, you are running [#17](#17-symmetric-box-quoting) by accident, switch logic, do not pretend you are hedged.

**Dies when:** One book fills and you fail to lay the other, then treat the leftover as “inventory” instead of a broken box.

**Ship:** Core. Venue-specific and probably the highest-value template shipped.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# templates/11_complement.py
from skeleton import clamp_tick, taker_fee_cents

def quotes_for(s, qty=5):
    book = s.get("book") or {}
    yes_bid = book.get("yes_bid", clamp_tick(100 * s.get("fair", 0.5) - 1))
    no_bid = book.get("no_bid", clamp_tick(100 - yes_bid - 2))
    if yes_bid + no_bid + taker_fee_cents(qty, yes_bid) + taker_fee_cents(qty, no_bid) >= 100:
        return [
            {"side": "buy", "outcome": "yes", "tick": yes_bid},
            {"side": "buy", "outcome": "no", "tick": no_bid},
        ]
    return None
```

### 12. Cold-start seeder

**Thesis:** Rolling windows mean a fresh empty book every 60 seconds. Race to post the first two-sided quote at round open with a wide spread, tighten as competitors arrive.

**Habitat:** First 1–3 seconds after open, or any moment both sides are empty.

**Edge:** Uncontested queue position. Maker-fee-free, so the wide-to-tight path is cheap.

**Guards:** Seed from [#0](#0-fair-value-engine), not from 50/50. Open print can already be off the pre-open path. Pull the stale seed if the first oracle print after open moves `d` by more than a threshold.

**Dies when:** You seed 50/50 into a round that opened 20bp through, and you are the quote everyone lifts.

**Ship:** Core.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# templates/12_seeder.py
from skeleton import clamp_tick, tau_s

def quotes_for(s):
    book = s.get("book") or {}
    empty = not book.get("yes_bid") and not book.get("no_bid")
    tau = tau_s(s["round"])
    if not empty and tau < 57:
        return None
    mid = clamp_tick(100 * s.get("fair", 0.5))
    return [
        {"side": "buy", "outcome": "yes", "tick": clamp_tick(mid - 8)},
        {"side": "buy", "outcome": "no", "tick": clamp_tick(100 - (mid + 8))},
    ]
```

### 13. Queue-join, don't penny

**Thesis:** Join best bid/ask rather than improving. Cancel only on fair-value drift past threshold.

**Habitat:** Any two-sided book. Default MM when you do not have an edge on queue.

**Edge:** Queue priority without winning the adverse-selection contest that pennying starts.

**Guards:** Cancel when `|quote − fair|` exceeds `k` ticks. Do not “hold the queue” through a jump.

**Dies when:** You confuse being first in queue with being right.

**Ship:** First. Teaches queue priority. Produces far less toxic flow than #1.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# templates/13_queue_join.py
from skeleton import clamp_tick

def quotes_for(s, k=3):
    book = s.get("book") or {}
    yes_bid = book.get("yes_bid")
    no_bid = book.get("no_bid")
    if not yes_bid or not no_bid:
        return None
    fair = 100 * s.get("fair", 0.5)
    if abs(yes_bid - fair) > k:
        return "kill"
    return [
        {"side": "buy", "outcome": "yes", "tick": yes_bid},
        {"side": "buy", "outcome": "no", "tick": no_bid},
    ]
```

### 14. Markout-filtered MM

**Thesis:** Track 1s and 5s markout on own fills, bucketed by size and time-in-round. Widen or pull when rolling markout goes negative past threshold.

**Habitat:** Always-on overlay. Every other MM template should expose hooks for it.

**Edge:** This is the template that turns a losing MM into a breakeven one, and the one most users will not build themselves.

**Guards:** The markout itself is the guard. Persist buckets across rounds so a single quiet round does not reset the lesson.

**Dies when:** You measure markout in last-trade space instead of mark-to-fair, and you congratulate yourself for “winning” into a moving strike.

**Ship:** Core.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# templates/14_markout.py
def quotes_for(s, widen=2):
    inner = s["inner_quotes"](s)
    if inner in (None, "kill"):
        return inner
    if s.get("markout_1s", 0) < 0 or s.get("markout_5s", 0) < 0:
        for q in inner:
            q["tick"] = max(1, q["tick"] - widen) if q["outcome"] == "yes" and q["side"] == "buy" else q["tick"]
        return inner
    return inner
```

### 15. Regime-switch spread

**Thesis:** Three vol regimes off realized 1s oracle returns, one spread multiplier each, hard kill at the top regime.

**Habitat:** Always-on. This is where the risk-limit scaffolding lives that every other template inherits.

**Edge:** None on its own. Survival. Trivial to write, expensive to skip.

**Guards:**

| Regime | Realized 1s vol      | Action                                      |
| ------ | -------------------- | ------------------------------------------- |
| Calm   | below low threshold  | Base spread                                 |
| Fast   | mid                  | Widen by `m_fast`                           |
| Chaos  | above high threshold | Hard kill: cancel all, flatten if specified |

**Dies when:** The kill is a widen instead of a cancel, and you are still the quote through the jump.

**Ship:** First. Required dependency, not an optional style.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# templates/15_regime.py
def quotes_for(s, sigma_1s=0.0, low=0.00005, high=0.0002):
    if sigma_1s >= high:
        return "kill"
    inner = s["inner_quotes"](s)
    if inner in (None, "kill"):
        return inner
    if sigma_1s >= low:
        for q in inner:
            if q["side"] == "buy":
                q["tick"] = max(1, q["tick"] - 2)
    return inner
```

### 16. Settlement-window liquidity

**Thesis:** Last 10 seconds, quote 96/99 to holders who want to lock in early rather than carry settlement risk. Selling certainty above true *settlement*-fair.

**Habitat:** TWAP window only (`τ ≤ 10`), fair already in the wings, and settlement-fair (not path-fair) says the lock-in is rich.

**Edge:** Impatient winners pay to stop being exposed to the remaining TWAP weight.

**Guards:** Jump filter on the *remaining* TWAP residual, or this inherits the fat-tail problem from [#7](#7-99-short-vol). A 20bp wick that lasts 1s of a 10s window moves close by \~2bp; a 20bp move that holds the rest of the window moves close by the leftover weight. Filter the second, ignore the first.

**Dies when:** You use path-fair in the window and sell 99¢ while the running TWAP is still on the wrong side of `K`.

**Ship:** Later. Needs #0's settlement-fair switch.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# templates/16_settlement_window.py
from skeleton import tau_s

def quotes_for(s):
    tau = tau_s(s["round"])
    fair = 100 * s.get("fair", 0.5)
    if tau > 10 or abs(fair - 50) < 40 or s.get("mode") != "settlement":
        return "kill"
    if fair >= 90:
        return [{"side": "sell", "outcome": "yes", "tick": 98}]
    return [{"side": "sell", "outcome": "no", "tick": 98}]
```

***

## The box family

Mechanically these are all Yes/No book couplers, same as [#11](#11-complement-hedged-quoting). If a meaningful share of flow runs them, the two books stay tight to 100 with no seeding required.

> **Lifting vs posting.** Lifting both asks at 49 is not chop capture, it is arb ([#5](#5-crossed-book--complement-arb)). Posting both bids at 49 is the actual strategy. Do not conflate them in the docs.

Maker is free and taker is not. Boxes only work as **posted** bids. A lifted 49/49 box pays taker on both legs: `Q(49) = 2499`, so \~0.63¢/share/side, \~1.25¢ per completed box, against 2¢ gross. Net is a rounding error. Posted, the 2¢ survives.

Tie resolves No. A completed 49/49 box still pays; a *broken* Yes leg into a tie is the bad one. Slight structural lean: missing the No bid is more dangerous than missing the Yes bid.

### 17. Symmetric box quoting

**Thesis:** Post 49 bid Yes and 49 bid No. Position being built is long the box at 98. Cash-and-carry when complete, directional when not.

The entire strategy is one number: **P(both legs fill)**.

Fill probability is anti-correlated with outcome. In a trending tape only the losing side fills. BTC rips, everyone dumps No into your bid, nobody sells you Yes, you are left long No alone at 49 with fair at 20. You never get a broken leg on the winning side. Honest description: **short trend, long chop, with the fills themselves selecting against you.**

**Habitat:** Only valid when `|d| < ~0.5`, roughly the first 20–30 seconds of a round near the strike. Auto-disable on `|d|` threshold, not on a clock.

**Edge:** 2¢ on 98¢ risked, \~2% per completed box, **if** both legs fill and you posted.

**Guards:**

* Disable on `|d|` (not on a timer).
* Size as if the typical outcome is a *broken* leg, not a completed box.
* Pair with [#20](#20-completion-chasing-box) or do not ship.

**Dies when:** You count completed-box PnL and ignore the inventory from broken legs. That inventory is the strategy.

**Fees.** Gross is 2¢ on 98¢. Per-contract-per-side rake eats it if you lift. On the current maker-0 schedule, posted boxes clear; taker boxes do not. This template is the sharpest test of whether the fee schedule permits MM at all. Model it again before Season 1 pricing hardens.

**Ship:** Later, and only with #20.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# templates/17_box.py  (ship only with 20_complete.py)
def quotes_for(s):
    if abs(s.get("d", 0.0)) > 0.5:
        return "kill"
    return [
        {"side": "buy", "outcome": "yes", "tick": 49},
        {"side": "buy", "outcome": "no", "tick": 49},
    ]
```

### 18. Skewed box

**Thesis:** Bid 50/48 instead of 49/49 based on OFI or short-horizon momentum. Deliberately unbalanced. Accept a directional lean to raise fill probability on the side judged safe.

**Habitat:** Same `|d|` band as #17, plus a signed OFI or lead-lag signal from [#4](#4-order-flow-imbalance) / [#21](#21-cross-venue-spot-lead-lag).

**Edge:** Higher P(complete) in a mild trend, paid for with a 2¢ structural lean (50+48=98, same cash, worse if you are wrong about the skew).

**Guards:** If the signal flips, the 50-bid is the one you pull first. Disable with #17 on `|d|`.

**Dies when:** You skew into the trend instead of against the side that is about to dump on you.

**Ship:** Later. Bridges #17 and #4.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# templates/18_skew_box.py
def quotes_for(s):
    if abs(s.get("d", 0.0)) > 0.5:
        return "kill"
    ofi = s.get("ofi_z", 0.0)
    yes, no = (50, 48) if ofi > 0 else (48, 50)
    return [{"side": "buy", "outcome": "yes", "tick": yes}, {"side": "buy", "outcome": "no", "tick": no}]
```

### 19. Box ladder

**Thesis:** 49/48/47 both sides, geometric size. Wider rungs fill only in high realized vol, which is exactly when boxes complete.

**Habitat:** Same as #17, with more room to sit.

**Edge:** Self-scaling to the chop being harvested. The 47s are not “more edge”; they are the fills you only want when the book is already violent.

**Guards:** Cap the 47 rung. A filled 47 with no complement is a worse broken leg than a filled 49.

**Dies when:** Geometric size is inverted (largest at 47) and a one-way tape fills the whole ladder on one side.

**Ship:** Later.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# templates/19_box_ladder.py
def quotes_for(s):
    if abs(s.get("d", 0.0)) > 0.5:
        return "kill"
    return [
        {"side": "buy", "outcome": o, "tick": t}
        for o in ("yes", "no")
        for t in (49, 48, 47)
    ]
```

### 20. Completion-chasing box

**Thesis:** When one leg fills and the other does not, walk the unfilled bid up toward fair on a timer instead of holding naked. Pays away part of the 2¢, converts broken legs into completed boxes.

**Habitat:** Any time #17/#18/#19 is on and one leg is live.

**Edge:** Survival. Parameter is how much of the box to give up versus how long to sit directional.

**Guards:** Never chase through fair. Never chase into a taker lift that turns a 2¢ box into a negative-edge #5. Stop at maker-posted prices only, unless settlement-fair says the leftover is already a loser.

**Dies when:** You chase with market orders and donate the box plus taker fees.

**Ship:** Later. Makes #17 survivable. Most users will not build it. Do not ship #17 without it.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# templates/20_complete.py
def quotes_for(s):
    filled, missing = s.get("box_filled"), s.get("box_missing")
    if not filled or not missing:
        return None
    fair = int(100 * s.get("fair", 0.5))
    chase = min(missing["tick"] + 1, fair - 1) if missing["outcome"] == "yes" else min(missing["tick"] + 1, 99 - fair)
    if chase <= missing["tick"]:
        return "kill"
    return [{"side": "buy", "outcome": missing["outcome"], "tick": chase}]
```

***

## Taking

### 3. Stale-quote sniper

**Thesis:** Oracle updates, book has not. Lift anything more than `k` ticks off model.

**Habitat:** Any time path-fair (or settlement-fair in the window) jumps and resting quotes do not.

**Edge:** Other people's stale limits. Highest hit-rate right after an oracle print, especially when quorum flips a median the book was quoting against.

**Guards:** Size by remaining `τ` and by how stale (ticks off fair), not by available size. Do not chase a book that is already moving.

**Dies when:** You snipe last-trade “stale” against an oracle that has not moved, i.e. you are lifting fair.

**Ship:** Core.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# templates/03_sniper.py  (taker: post_only=False, tif=ioc)
def quotes_for(s, k=3):
    fair = 100 * s.get("fair", 0.5)
    ask = (s.get("book") or {}).get("yes_ask")
    if ask is None or ask >= fair - k:
        return None
    return [{"side": "buy", "outcome": "yes", "tick": ask, "tif": "ioc", "post_only": False}]
```

### 4. Order-flow imbalance

**Thesis:** Sign trades on the feed, take direction on OFI z-score.

**Habitat:** Mid-round, both books printing. Weak in the last 10s where settlement-fair dominates flow.

**Edge:** Simplest non-arb signal. Short-horizon aggression predicts the next fair tick more often than not, until it does not.

**Guards:** Fade the signal when `|d|` is already large (flow is exiting, not informing). Kill in #15's chaos regime.

**Dies when:** You treat informed wing-exits as “imbalance to chase.”

**Ship:** First. Good onboarding template.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# templates/04_ofi.py
def quotes_for(s, z=2.0):
    if abs(s.get("d", 0.0)) > 1.5 or s.get("regime") == "chaos":
        return "kill"
    ofi = s.get("ofi_z", 0.0)
    if abs(ofi) < z:
        return None
    side = "yes" if ofi > 0 else "no"
    ask = (s.get("book") or {}).get(f"{side}_ask")
    if not ask:
        return None
    return [{"side": "buy", "outcome": side, "tick": ask, "tif": "ioc", "post_only": False}]
```

### 5. Crossed-book / complement arb

**Thesis:** If `ask_yes + ask_no < 100` **net of taker fees**, take both. Locked box, cash-and-carry.

**Habitat:** Any time the two books gap. More common at open ([#12](#12-cold-start-seeder) racing) and around jumps.

**Edge:** Mechanical. Not a prediction.

**Guards:** Compute fees on *both* legs with `Q(p) = p(100−p)`. A 49+50 = 99 looker is not an arb after two taker charges near 50¢. In the wings the same 1¢ gap often *is* an arb because `Q(p)` is small.

Once multiple strikes are listed, monotonicity arbs come free: `P(up > 10bps) ≥ P(up > 25bps)`. Not live today.

**Dies when:** You lift the 99 without the fee model and call it arb.

**Ship:** First.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# templates/05_arb.py
from skeleton import taker_fee_cents

def quotes_for(s, qty=5):
    b = s.get("book") or {}
    ay, an = b.get("yes_ask"), b.get("no_ask")
    if ay is None or an is None:
        return None
    cost = ay + an + taker_fee_cents(qty, ay) + taker_fee_cents(qty, an)
    if cost >= 100:
        return None
    return [
        {"side": "buy", "outcome": "yes", "tick": ay, "tif": "ioc", "post_only": False},
        {"side": "buy", "outcome": "no", "tick": an, "tif": "ioc", "post_only": False},
    ]
```

***

## Lead-lag

The general form: some series moves first, the binary's price moves second, and the gap is tradeable. On a 60-second contract the gaps are milliseconds to a few seconds, so every template here is a latency race. Ship them with realistic expectations attached.

### 21. Cross-venue spot lead-lag

**Thesis:** Deepest venue leads. Binance BTCUSDT perp typically moves before thinner books. If the settlement oracle were a slow single source, that lead would be a direct predictor of the print.

**On this venue it is not.** The oracle is a 5-venue median at 4 Hz with a 3-of-5 quorum. A Binance spike the other four have not printed often **does not move `S_t` at all**. The tradeable object is not “Binance minus a lagging index.” It is:

```
z = (S_lead − S_median) / σ_spread
```

plus a count of how many of the five have printed the move. Take the binary only when `z` clears a threshold, **at least two other venues have begun to confirm**, and `τ` is long enough that the median can catch up before freeze. Inside the TWAP window, switch the target from path-fair to settlement-fair.

**Habitat:** First 50s, news or liquidation tapes, when venue dispersion is wide.

**Edge:** Oracle update lag, which is a venue parameter (median + quorum + 250ms publish), not a market fact. Publish the oracle cadence and this template becomes a fair game rather than a gotcha.

**Guards:** Require confirmation from a second venue. Kill when the lead *reverts* before the median moves, that is the usual case, and it is why naive Binance-lead bots bleed.

**Dies when:** You treat Binance as the oracle.

**Ship:** Later. Rewrite any draft that assumes a single-source index.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# templates/21_lead_lag.py
def quotes_for(s, z_min=2.0):
    lead, median = s.get("s_lead"), s.get("spot")
    n_confirm = s.get("n_confirm", 0)
    if lead is None or median is None or n_confirm < 2:
        return None
    z = (lead - median) / max(s.get("sigma_spread", 1.0), 1e-9)
    if abs(z) < z_min:
        return None
    side = "yes" if z > 0 else "no"
    ask = (s.get("book") or {}).get(f"{side}_ask")
    return [{"side": "buy", "outcome": side, "tick": ask, "tif": "ioc", "post_only": False}] if ask else None
```

### 22. Oracle-print anticipation

**Thesis:** Narrower version of #21 aimed at the settlement mechanic rather than the path. Settlement is a 10s TWAP of a 4 Hz feed (\~40 prints). That value is partially determined before the window closes.

After `k` prints:

```
locked       = TWAP of the k prints already in the window
w_left       = (40 − k) / 40          # time-weighted; use actual hold durations
undetermined = w_left · (future average)
```

The most the remaining prints can move `close` is `w_left` times a bounded move. Residual uncertainty shrinks deterministically. Trade `P(close > K)` against the book.

**Habitat:** Last 10 seconds only.

**Edge:** The sharpest lead-lag on the venue. Users who compute the running TWAP from the public oracle websocket can mark settlement-fair more tightly than a book still quoting path-fair.

**Guards:** This is the one to stress-test internally before shipping. If a user can compute the settlement print early with high confidence, the last seconds of every round are a solved game. Decide whether that is a feature (publish the running TWAP) or a hole (it already is public math on a public feed).

**Dies when:** You ship it as a user bot before the venue has decided the policy.

**Ship:** Internal.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# templates/22_twap_anticipate.py  (internal)
from skeleton import fair_now, TWAP_S, tau_s

def quotes_for(s):
    tau = tau_s(s["round"])
    if tau > TWAP_S:
        return None
    p = 100 * fair_now(s["spot"], s["round"]["strike"], s.get("sigma", 0.00009), tau, s.get("twap_so_far"), TWAP_S - tau)
    ask = (s.get("book") or {}).get("yes_ask")
    if ask and ask < p - 1:
        return [{"side": "buy", "outcome": "yes", "tick": ask, "tif": "ioc", "post_only": False}]
    return None
```

### 23. Near-round leads far-round

**Thesis:** With rolling windows, multiple rounds are live at once with different strikes and expiries. They share one underlying path. The near-expiry round has far higher gamma, so its price moves first and hardest on a given spot tick. The far round is mechanically slower to reprice.

Trade: near-round fair as a predictor of far-round fair, sized by the ratio of their deltas. Venue-internal, no external feed needed, and therefore the most accessible lead-lag template for users without co-location.

**Habitat:** Not live. Season 1 is a single 60s BTC series. The catalog already names `ob-btc-ud-5m`, `ob-eth-ud-60s`, and others, this template waits for a second book.

**Edge:** Cross-gamma. Only once two expiries or two strikes share a path.

**Guards:** Do not fake it by treating consecutive 60s rounds as a spread. They do not overlap; the last one's strike is dead.

**Dies when:** You ship a runnable bot against one book.

**Ship:** Later. Design only until a second series lists.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# templates/23_near_far.py  (not live: needs a second series)
def quotes_for(s):
    if "far_market_id" not in s:
        return None
    if s.get("near_fair", 0.5) > s.get("far_fair", 0.5) + 0.02:
        return [{"side": "buy", "outcome": "yes", "tick": s["far_ask"], "tif": "ioc", "post_only": False}]
    return None
```

### 24. Yes book leads No book

**Thesis:** The two books do not update symmetrically. Directional flow hits the side matching sentiment first, so one book carries the information and the other lags. Detect via cross-book price disagreement `|p_yes + p_no − 100|` with a sign, then take the lagging book.

**Habitat:** Any time the sum leaves 100 by more than `k` ticks but is not yet a fee-adjusted arb.

**Edge:** Overlaps with [#5](#5-crossed-book--complement-arb), but distinct: #5 waits for a completed arb, this one trades the lag before it becomes an arb. Higher frequency, lower per-trade edge, and it can be wrong.

**Guards:** If the gap is already an arb after fees, do #5 instead. If #11 is quoting both sides, this signal is often *you*.

**Dies when:** You lift the lagging book into a gap that is a posting artifact, not information.

**Ship:** Later.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# templates/24_yes_leads_no.py
from skeleton import taker_fee_cents

def quotes_for(s, k=2, qty=5):
    b = s.get("book") or {}
    py, pn = b.get("yes_bid"), b.get("no_bid")
    if py is None or pn is None:
        return None
    gap = py + pn - 100
    if abs(gap) < k:
        return None
    ay, an = b.get("yes_ask"), b.get("no_ask")
    if ay and an and ay + an + taker_fee_cents(qty, ay) + taker_fee_cents(qty, an) < 100:
        return None
    lag = "no" if gap > 0 else "yes"
    ask = b.get(f"{lag}_ask")
    return [{"side": "buy", "outcome": lag, "tick": ask, "tif": "ioc", "post_only": False}] if ask else None
```

### 25. Correlated-asset lead-lag

**Thesis:** ETH, SOL, and BTC move together at short horizons with asymmetric lead. During news-driven moves, the asset where the news originates leads. Also applies to funding-rate spikes and large perp liquidations, which telegraph short-horizon BTC direction.

**Habitat:** Teaching example. Weakest template of the group at 60-second horizons. Include it so users see a signal that backtests better than it trades.

**Edge:** Usually none after latency and after the BTC oracle has already printed the move.

**Guards:** If you must run it, require the lead asset to move *before* the BTC median, and flatten when BTC has already repriced.

**Dies when:** The backtest uses minute bars.

**Ship:** Later. Not runnable until those series list, and even then a teaching bot.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# templates/25_corr.py  (teaching; not live)
def quotes_for(s):
    if s.get("lead_asset_moved_first") and not s.get("btc_already_repriced"):
        side = "yes" if s.get("lead_sign", 0) > 0 else "no"
        ask = (s.get("book") or {}).get(f"{side}_ask")
        return [{"side": "buy", "outcome": side, "tick": ask, "tif": "ioc", "post_only": False}] if ask else None
    return None
```

***

## Volatility

### 6. Implied vs realized

**Thesis:** Invert the quote for implied `σ`, compare to realized.

* Implied rich → price compressed toward 50 → buy the leader (the side fair already prefers)
* Implied cheap → fade the leader (the book is too certain)

**Habitat:** Mid-round, `|d|` moderate. Invert with path-fair, not a 30-day option vol.

**Edge:** The book is a vol quote. Most users will not see that. Ship the general form so they see [#7](#7-99-short-vol) is the tail case of the same object.

**Guards:** Realized must be the *oracle's* 1s EWMA, same as #0. Do not mix Binance realized with median implied.

**Dies when:** You invert a 99¢ wing and call it 5-vol. Wings are price floors, not vol quotes. Hand those to #7 / #10.

**Ship:** Core.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# templates/06_iv_rv.py
from math import log, sqrt
from skeleton import n_cdf, tau_s

def implied_sigma(mid_prob, spot, strike, tau):
    lo, hi = 1e-6, 0.01
    for _ in range(40):
        mid = 0.5 * (lo + hi)
        p = n_cdf(log(spot / strike) / (mid * sqrt(tau)))
        lo, hi = (mid, hi) if p < mid_prob else (lo, mid)
    return 0.5 * (lo + hi)

def quotes_for(s):
    mid = (s.get("book") or {}).get("yes_mid") or s.get("fair", 0.5)
    iv = implied_sigma(mid, s["spot"], s["round"]["strike"], max(tau_s(s["round"]), 0.1))
    rv = s.get("sigma", 0.00009)
    leader = "yes" if s.get("fair", 0.5) >= 0.5 else "no"
    ask = (s.get("book") or {}).get(f"{leader}_ask")
    if iv > rv * 1.15 and ask:
        return [{"side": "buy", "outcome": leader, "tick": ask, "tif": "ioc", "post_only": False}]
    return None
```

### 8. Delta-hedged binary

**Thesis:** Hedge `φ(d) / (S σ √τ)` on a perp elsewhere, hold the binary as pure vol.

**Habitat:** Users who already run options books. Needs an external hedge venue and a funding/fee model for the perp.

**Edge:** Isolated vol. On this venue the interesting vol is the last-10s TWAP residual, not the 60s path. Hedge path-delta in the first 50s; shrink the hedge as settlement-fair takes over, or you will be hedging a delta the TWAP has already killed.

**Guards:** Binary delta explodes as `τ → 0` on last-print math. Use settlement-fair delta in the window or the hedge will overtrade.

**Dies when:** You hedge last-print delta through the TWAP window and churn the perp to death.

**Ship:** Later.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# templates/08_delta_hedge.py  (perp hedge is off-venue)
from math import exp, sqrt, pi, log
from skeleton import tau_s

def binary_delta(spot, strike, sigma, tau):
    d = log(spot / strike) / (sigma * sqrt(tau))
    phi = exp(-0.5 * d * d) / sqrt(2.0 * pi)
    return phi / (spot * sigma * sqrt(tau))

def quotes_for(s):
    tau = max(tau_s(s["round"]), 1e-6)
    if tau <= 10:
        return "kill"
    s["hedge_delta"] = binary_delta(s["spot"], s["round"]["strike"], s.get("sigma", 0.00009), tau)
    return None
```

***

## Shared risk (every template inherits this)

Lifted from #15 so it is not optional:

1. **Kill switch.** Chaos-regime cancel. Manual flatten. Daily loss cap.
2. **Inventory cap.** Per side, per round, and net Yes−No.
3. **Jump pull.** `|ΔS| > n · σ √Δt` cancels resting quotes before the next fair compute.
4. **Settlement-fair switch.** At `τ = 10s`, #0 flips models. Templates that cannot speak settlement-fair must flatten or pull.
5. **Fee model.** Taker 250 via `Q(p)`. No taker template ships without it. No box template ships as a lifter.
6. **PnL attribution.** Edge label required. If you cannot name the edge, you are not running a template.

***

## What changed from the draft

The source note is `omnibook-strategy-templates-2.md`. Polishes applied here:

* Bound every template to Omnibook rules (5-venue median, 4 Hz, 10s TWAP close, 1–99¢, maker 0 / taker 250, tie → No).
* Split #0 into path-fair vs settlement-fair. Last-print digital math is wrong in the window.
* Rewrote #21: Binance-lead is not oracle-lead on a median-of-five.
* Made #22 concrete (running TWAP, leftover weight) and marked **internal**.
* Marked #23 / #25 as not live (single series today).
* Added real fee arithmetic to #5 and the box family. Posted boxes work; lifted boxes do not.
* Noted TWAP *helps* #7 (wicks dilute) and *defines* #16 / #22.
* Forced #17 to ship with #20.
* Added a consistent field layout, a catalog table, and a ship order.

IDs, family grouping, and the original warnings (grid, lifting vs posting, short-trend/long-chop) are unchanged on purpose.

Listing order is market making on top, then taking / vol / lead-lag. Every template stays in the set.

***
