A sixty-second options research desk, graded nightly against its own output

A scanning daemon that swept an equity-options universe every sixty seconds, generated candidate trades through pluggable strategy lanes, ranked them on expected value per unit of tail risk, and every night replayed what it had surfaced to score whether it had been right. It ran daily with the operator's own money on the outcome. Repository: sma-cockpit, private — 4,292 tests, 134 design documents.

Domain Short-premium and defined-risk equity options; index proxy plus its mega-cap components, ~21 names, multiple weekly expiries
Cycle Full universe scan ≤ 60s p95 · lightweight monitor tick ≤ 15s p95 · 23/6 availability
Ranking metric Edge-per-tail: expected value ÷ expected shortfall — credit per unit of touch risk
Scale 4,292 tests · 134 design documents · ~21 names × full chains × Monte Carlo ladders per scan, on a bounded 24-core pool
Status Private repository. The trading desk ran daily against live data and was deliberately retired in August 2026 into a clean-sheet successor (compass); a daily world-briefing pipeline it grew still runs, and publishes here

1. Why I built it

The strategy was not the bottleneck. Selling premium and harvesting theta is well understood, and the exit discipline is arithmetic. The bottleneck was attention.

One person cannot watch twenty-one underlyings across every expiry surface, every day, and notice the three setups that are actually worth taking. The opportunities are not hidden; they are simply more numerous than one field of view. Every day, the trades you miss cost exactly as much as the trades you get wrong, and they cost it invisibly.

So the mission document states the purpose in one line, and every component was tested against it: expand the operator's field of view beyond what one person can see.

That framing produced the architecture's defining constraint, recorded as an operator ruling rather than an engineering preference:

The job of the system isn't to size trades, it is to identify trend, setups and trade ideas, and to give permission on what lanes are open. Sizing is mine, based on confidence from the system.

The system surfaces and ranks; the human decides and sizes. This is not timidity about autonomy. It is a division of labour with real architectural consequences: a system that never sizes does not need position state, and a system with no position state cannot silently desynchronise from a broker — the failure mode that quietly destroys more retail automation than bad signals ever do.

2. What I built

Five cooperating jobs on a sixty-second clock, plus a separate futures-scalping loop on its own process and risk budget, writing into one canonical state file and one append-only history database.

3. How it works

flowchart TB
  subgraph tick["Every 60 seconds — parallel per name"]
    FEED["Feed adapters<br/>tape · chain · dealer gamma"]
    IND["Indicator engine<br/>5m / 15m / 1h / 1d frame"]
    REG["Regime spine<br/>per-name dealer-gamma regime"]
  end
  subgraph form["Candidate formation"]
    SIG["Signal engine + TTL<br/>valid_until + invalidation<br/>multi-timeframe confirmed"]
    LANES["Lane registry<br/>uniform Lane.evaluate() contract"]
    MC["Monte Carlo ladders<br/>bounded 24-core pool"]
    CG["Candidate generator<br/>dedupe: same legs = one idea,<br/>best EV wins"]
    CONC["Concentration engine<br/>per-name + per-cluster budgets"]
    RANK["Ranker<br/>edge-per-tail = EV ÷ ES<br/>never pads to hit a count"]
  end
  subgraph learn["Publish and grade"]
    BOARD["20–30 row board<br/>each row → full ticket<br/>3 strike tiers per candidate"]
    HIST[("history.db<br/>append-only decision stamps")]
    GRADE["Nightly grader<br/>replays surfaced candidates<br/>through the committed exit engine"]
    CAL["Calibration book<br/>Beta posteriors per lane"]
  end
  FEED --> IND --> SIG
  FEED --> REG --> SIG
  REG --> LANES
  SIG -- "live signals only" --> LANES
  MC --> LANES
  LANES --> CG --> CONC --> RANK --> BOARD
  BOARD --> HIST --> GRADE --> CAL
  CAL -- "lane trust and size — authority is earned" --> LANES

Ranking on edge-per-tail. The board leads with expected value divided by expected shortfall — credit earned per unit of the risk that actually hurts, rather than per unit of variance. For short-premium structures, where the return distribution is deliberately left-skewed, ranking on anything symmetric rewards exactly the wrong positions. Each row expands to a full ticket, emitted at three strike tiers (wider and safer, balanced, nearer the money), each carrying delta, credit, margin per contract and buffer impact — so the board is simultaneously the day's risk-knob matrix.

The grader closes the loop. Every night the evidence harness replays the candidates the system actually surfaced, through the committed exit engine, scored on expected shortfall, and updates per-lane trust and size from the result. A new lane ships bounded: it may demote but not promote, and it carries a confidence label. It earns wider authority only from graded evidence. Calibration is held as Beta posteriors with an effective-sample floor — below roughly twenty effective observations a path is auto-blocked rather than trusted on a small-sample fluke.

4. What is interesting and unique

The backtester and the nightly grader are the same code path. This is the design decision I would defend hardest. A candidate is graded identically whether it came from history or from this morning — there is no separate research harness that can drift from production semantics. The entire category of "it worked in the backtest" bugs comes from two implementations of the same question, and the only durable fix is to have one.

Dealer-gamma regime as a shared spine rather than a per-strategy read. The decision record considers three options: keep the previous heuristic, compute one shared per-name regime consumed by every lane, or let each lane read regime independently. The shared spine was chosen knowing the cost: it centralises one genuinely contestable estimate, since the sign depends on a customer/dealer classification that is inference, not observation. The trade-off was accepted explicitly because one contestable estimate that is consistent, testable and improvable in one place beats N inconsistent ones — and it shipped bounded, with demote-only influence and a confidence label, until the grader gave it authority.

The board refuses to pad. A thin day surfaces fewer rows, with a named gate reason, rather than filling twenty slots with the twentieth-best idea. Most scanners are judged on whether they produce output, which quietly teaches them to always produce output. The ranking itself is then graded nightly on funnel hit rate.

Deduplication is economic, not structural. Two lanes proposing the same legs are one idea, not two, and the better-priced expression wins. Concentration budgets then apply per name and per correlation cluster before ranking — because ranking first produces a top-twenty list that is one bet expressed twenty times, which looks like diversification right up until it isn't.

Every change is knob-reversible to byte-identical prior behaviour. Each feature sits behind a config flag whose False path is pinned by the test suite to reproduce the previous behaviour exactly. In a live system carrying real risk, the ability to revert a change without a deploy is worth more than the change.

5. Challenges I had to solve

Stale data wearing a fresh timestamp. The single most dangerous failure in a live desk is not a wrong number, it is a right number from four minutes ago presented as current. The answer was structural rather than vigilant: a single canonical state file with exactly one writer per key, session gates, signal TTLs with explicit invalidation, and a hard rule that a missing input publishes a labelled absence. The system declines rather than fabricates; anything without a source renders as a dash. This is a non-functional requirement with a budget attached — zero stale-as-fresh, zero fabricated numbers — not an aspiration.

Keeping a language model away from every number. The deterministic pipeline computes all arithmetic; the model tier may only select, rank and explain among numbers that already exist. What makes this hold is that the deterministic path has no client for model output at all — there is structurally nowhere for a generated number to enter. A rule enforced by architecture survives; a rule enforced by discipline does not.

Latency against breadth. Twenty-one names, full chains and Monte Carlo ladders inside sixty seconds at p95 meant bounding the worker pool at twenty-four cores, bulk chain pulls, and keeping the fast monitor tick on a separate loop that never touches chains or Monte Carlo. Breadth was the product, so the budget had to be met by the architecture rather than by narrowing the universe.

Auditability under a sixty-second cadence. Every surfaced candidate is traceable to the inputs that produced it, via decision stamps and evidence rows in an append-only history database. Without this the nightly grader would be scoring outputs it could not attribute, which is worse than not grading at all because it looks like rigour.

6. What I learned

Measurement pointed at your own output changes what gets built. Once every surfaced candidate is replayed and scored nightly, a component cannot claim value by assertion. The grader is what converts a set of plausible heuristics into a set of ranked ones, and it is the single highest-leverage thing in the system.

Doctrine has to be executable. The architecture document has a section headed constraints — doctrine as architecture, non-negotiable, and its last line is that these are enforced by doctrine tests that must remain green. A rule you can violate without a test failing is a preference. That distinction is the difference between the rules surviving contact with a deadline and not.

Write the "what got harder" column. Each decision record carries context, options with complexity/latency/risk, the trade-off accepted, and consequences split into what became easier and what became harder. The second column is the one a future reader actually needs, and the one you are least inclined to write.

Know when a working system should be replaced. By mid-2026 the desk carried three generations of interface in one tree and design documents recording superseded decisions beside current ones. The cost of a change had stopped being proportional to its size. It was retired on purpose rather than at the point of collapse — into a successor that inherits its knowledge, its data and its measured results, and none of its code. That decision, and the machinery built to execute it, is a separate study.

What was retired is the trading desk specifically: every scheduled trading job is switched off. One downstream pipeline it grew — a daily world briefing — still runs out of the same repository and is published openly.

The repository is private. Tuned parameter values, vendor identities and infrastructure detail are omitted; the methods, contracts and decision records are what is described here. Redacted design documents are available on request.