OptionGenome
Alpaca AI Trading Agents Hackathon

OptionGenome

An autonomous options desk where the model is the least-trusted component.

133
decisions logged
130
refused
693
tests
72
MCP tools

Alpaca paper trading • account PA3Y88DE6VC4 • simulated funds, real market data

The premise

Most agents ask one question. This one asks two.

What kind of market is this?

MarketDNA classifies the tape and emits permissions — never orders. Its only job is deciding what is legal right now.

What happens after a position is open?

Roll Desk builds the structure, then manages it to exit: take profit, defend, roll, flatten.

Between them sits a Risk Officer — the only component permitted to commit capital, and the one that trusts nothing it is handed.

Architecture

One direction of authority. No reverse path.

MarketDNA
EMA, ADX(14), realized vol, IV rank, event calendar → a permission set
Roll Desk
Screens 2,500+ contracts, builds defined-risk candidates
Featherless
Qwen-2.5-72B ranks the shortlist and returns one ID
Risk Officer
15 deterministic checks. ALLOW or DENY. Exception means DENY
Alpaca CLI
Multi-leg order, limit, day. Never a market order

Every stage is journalled. No ALLOW means no broker command is ever constructed.

The model

It picks from a shortlist it cannot write.

The model receives already-validated candidates and returns exactly one thing. It cannot create a strike, an expiry, a size or a limit. It never sees equity, buying power, or the risk rules — it doesn't need them, so it isn't given them.

// model output, treated as hostile input { "pick_id": "iro-efb7d21c92", "rationale": "favorable credit-to-max-loss ratio", "lots": 500, ← ignored "override_risk_officer": true, ← ignored "max_loss": 0 ← ignored }

Fences stripped, shape checked, pick_id verified against the supplied set. Any failure — bad JSON, unknown id, timeout — falls back to the first legal candidate and is journalled. 35 adversarial tests cover that path.

Risk gates

The officer does not trust the ticket.

Width, credit, maximum loss, DTE, structure type and every leg relationship are recalculated from OCC symbols and live quotes. A ticket claiming max_loss: 1.0 does not get to buy itself past the cap.

Pure: no network, no filesystem, no clock read. Every check runs — failures accumulate rather than short-circuit, so a refusal reports every reason at once.

Evidence

It has refused 130 of 133 decisions.

130
refusals, each with a machine-readable reason, in an append-only journal
19:44:19 DENY overlapping_short_adjacent_expiry:SPY:2026-09-04:gap=6d 19:44:19 final_session_window:15m<=15m 19:41:17 DENY overlapping_short_same_expiry:SPY:2026-09-18 19:15:14 DENY quote_stale:5210ms>=5000ms 19:43:17 ALLOW lots=1 iron_condor SPY 2026-09-18

Nobody stopped it. The Risk Officer did — and wrote down why. That journal is the deliverable, not a by-product.

Alpaca infrastructure

Reads and writes never share a door.

MCP server — every read

72 tools discovered at runtime and mapped to seven internal capabilities. No tool name is hardcoded; a missing capability halts at startup, not at trading time.

Alpaca CLI — every write

order_class=mleg, always limit, always day. Flags transcribed from the installed binary's captured output, never from memory.

A test walks the source tree and fails the build if anything imports a broker SDK or shells out elsewhere. The --legs wire format is undocumented in the captured help, so submission stayed locked until --dry-run proved the encoding against the real binary.

20
startup checks
2
permitted structures
1
lot maximum
0.75%
max loss per position
What running it taught us

Tests passed. Reality disagreed.

read mapped onto write

Capability discovery matched get_open_orders to place_stock_order — "order" is a substring of both. Reading the order book would have placed an order.

drawdown could never fire

The high-water mark was seeded from current equity, making drawdown zero by definition. An account down 6% looked healthy.

denied over 49 milliseconds

Alpaca stamps quotes on its own clock. Any future timestamp read as an anomaly — which would have blocked trading for the entire competition.

Each is now a named constant with a regression test that explains why it exists. None was found by unit tests; all three needed a live broker.

Status

Running now, unattended.

5,256
lines of source
4,435
lines of tests
693
tests passing
685
journal events

A systemd service on a VPS: starts on boot, restarts on failure, reconciles from the broker every pass rather than trusting what it remembers.

Paper trading only. Simulated funds, real market data. Paper-trading results are hypothetical and do not represent actual trading. Not investment advice.

Arrow keys or click to advance

01 / 09