00defined-risk options · alpaca paper tradingoffline

An options deskwhere the AI is theleast-trusted component.

Deflow trades defined-risk option spreads on Alpaca, harvesting the gap between the volatility options are priced at and the volatility stocks actually deliver. Four agents propose. Twelve deterministic circuit breakers decide. No model ever produces a number that reaches the broker.

12
breakers
zero LLM · fail-closed
100%
defined risk
no naked options, ever
2%
max per trade
sized by the gate
-
decisions logged
hash-chained
gate · standing by
idle
loading recent decisions…
max loss
-
2% cap
probability of profit
-
65% floor
net delta
-
±0.35
no model output reached the brokerzero LLM
deterministic · hash-chained
paper
The problem

Autonomous trading agents fail in three predictable ways.

Each of them is a structural property, not a tuning problem - so Deflow is built to make each one impossible rather than unlikely.

01Unbounded

The model sizes the trade

Most agents let a language model choose the strike, the width and the position size. A hallucinated number becomes an order. There is no layer that can say no, because the layer that would say no is the same one that made the decision.

02Undefined

The risk has no floor

Naked options and unhedged directional bets have no worst case. The position works for weeks and then one gap erases the account. Nothing in the system knows what the maximum loss is, because the structure does not have one.

03Unverifiable

The results cannot be checked

A log tells you what a system says it did. It does not tell you whether the story was edited afterwards, and it usually records only the fills - so the refusals, which are most of what a risk system does, leave no trace at all.

The edge

Probability of profit is not an edge.
Expectancy is.

Under the risk-neutral measure every vertical spread is worth exactly what it costs. Score a candidate at its own implied volatility and every trade prices at zero - the correct answer, and a useless one. So Deflow scores each candidate twice, and trades the difference.

Risk-neutral
implied volatility
≈ $0
expected value

What the market says it is worth. Zero expected value, as arbitrage requires - which is why scoring this way ranks every candidate identically.

Physical
forecast realised volatility
the edge
expected value

What it is worth if the underlying keeps moving the way it actually has been. Jump-robust, so one earnings gap cannot masquerade as a regime.

The dollar gap between those two numbers is the variance risk premium - and it is the only reason to put the trade on.

A trade Deflow refuses

79% of the time you keep $320. The other 21% you lose $1,680.

probability of profit
79%
you keep
$320· four times in five
you lose
$1,680· the fifth
expected value
−$112

A high win rate is not an edge. It is a way to lose money slowly and feel good about it. Anything with non-positive expectancy under the physical measure is refused - however high its probability of profit.

What it will trade

Defined-risk structures only. Every short leg sits inside a long of the same right, so the worst case is a property of the geometry rather than a promise - and the wing is what makes the maximum loss knowable before the order is sent.

The desk

Four agents, and only one of them is a language model.

The reasoning layer is shown finished, priced candidates and returns exactly one integer index - bounds-checked. It cannot change a strike, a width, a premium or a size. A total model failure degrades to a deterministic ranker, not to a bad trade.

01

Macro & Volatility Analyst

What is the market doing?

Measures implied against a jump-robust forecast of realised volatility on eight liquid names. Emits a stance, a directional bias - and about half the time, a documented refusal to trade at all.

regime + variance risk premium
the only LLM in the system

Between stages 2 and 3, Featherless AI picks one candidate from the list - or abstains. Its entire output surface is { index, confidence, rationale }. A model that hallucinates index 9999 is ignored, not indexed with.

The risk gate

Twelve breakers.
No network, no prompt, no model.

risk_gate.py imports nothing but the standard library. Given the same proposal and the same book it returns the same verdict, forever.

Test it yourself

This sends a genuinely hostile order to the gate running right now: a 10-lot naked NVDA call carrying $15,000 of undefined downside. Nothing is routed and no state changes.

awaiting a proposal - the verdict and its timing appear here
  1. 01defined_risk_structureevery short covered by a long of the same right
  2. 02max_loss_2pct≤ 2% of equity per trade
  3. 03trade_delta_bound|net delta| ≤ 0.35
  4. 04probability_of_profit65% win rate for credit; expectancy for debit
  5. 05aggregate_risk_6pct≤ 6% of equity at risk across the book
  6. 06symbol_concentration_3pct≤ 3% in any one underlying
  7. 07portfolio_delta_boundbook |delta| ≤ 1.20
  8. 08max_open_positions≤ 6 concurrent structures
  9. 09dte_window7–60 days to expiry
  10. 10payoff_qualitycredit ≥ 15% of wing width
  11. 11daily_drawdown_killswitchhalts new risk at −3% on the session
  12. 12vega_ceiling|vega| ≤ 2.5 per $1,000 of equity

Fails closed

Every field is read with a pessimistic default. A missing max_loss is not zero, it is unbounded. NaN and infinity fail every comparison by design.

Never short-circuits

All twelve run even after one fails, because a veto naming only the first problem hides the rest from the audit trail.

Sizes the trade itself

max_contracts() derives position size from breakers 2, 5 and 6. The model never chooses size, and the gate can only shrink or refuse.

Coverage

Eight names, chosen for penny-wide markets.

A defined-risk desk lives or dies on being able to exit, so the universe is selected for depth of option chain rather than for interesting stories.

-sell premium
-buy convexity
-stand down

Roughly half of every scan ends in a documented refusal to trade. That is the desk working, not the desk idle.

  1. SPY-
    -
    --scanning…
  2. QQQ-
    -
    --scanning…
  3. IWM-
    -
    --scanning…
  4. NVDA-
    -
    --scanning…
  5. AAPL-
    -
    --scanning…
  6. MSFT-
    -
    --scanning…
  7. AMD-
    -
    --scanning…
  8. TSLA-
    -
    --scanning…
Auditability

Results you can check, not results you have to believe.

Every decision - each analyst view, proposal, audit, gate verdict, order and exit - is appended as one line carrying the SHA-256 of the line before it. Edit or delete any historical entry and the chain breaks, and the API reports the exact index where.

GET /api/ledger/verify
{
"valid": true,
"entries": 1284,
"broken_at": null,
"detail": "Chain intact - every
entry hashes to its successor."
}

Tamper-evident

Modify entry 3 of 6 and verification reports broken_at: 3. Delete one and it reports the same. A log tells you what a system says it did; this tells you whether the story was edited afterwards.

Refusals included

Stand-downs, abstentions and vetoes are logged with the numbers that produced them. A desk that records only its fills cannot be audited - and for this strategy, the refusals are most of the behaviour.

Survives concurrency

Appends take an exclusive file lock and re-derive the head underneath it, so two processes sharing a data directory chain onto each other instead of forking. Verified with four concurrent writers.

Built on

All three Alpaca surfaces, each for what it is best at.

Trading API

Orders & market data

Written directly against the HTTP surface so the multi-leg payload is visible in one place: account, positions, daily bars, option-chain snapshots with NBBO and server-side Greeks.

Refuses to initialise against a non-paper endpoint.

Alpaca CLI

Default order route

The official Go binary is the interface an unattended agent actually gets deployed behind - its own 429/5xx backoff, its own credential resolution, and --dry-run to render the exact request without sending it.

Every order carries an idempotent client order id.

MCP server

Structured discovery

Alpaca's FastMCP server spoken as JSON-RPC over stdio with no SDK dependency, resolving tool names at runtime so an upstream rename cannot break the integration.

72 tools discovered; chains, contracts and account state.

Featherless AI

Bounded reasoning

Serverless open-model inference for the one stage that is allowed to be wrong. Qwen2.5-72B picks among finished candidates and explains the choice in English.

Any failure falls back to the deterministic ranker.

A real multi-leg order, as routed
alpaca order submit --order-class mleg --qty 4 --type limit \
  --limit-price -1.35 \
  --legs '[{"symbol":"SPY261016P00540000","ratio_qty":"1",
            "side":"sell","position_intent":"sell_to_open"},
           {"symbol":"SPY261016P00535000","ratio_qty":"1",
            "side":"buy","position_intent":"buy_to_open"}]'

Negative limit price because Alpaca quotes multi-leg packages net - positive is a debit paid, negative is a credit received.

Watch it refuse a trade.

The desk streams every decision live - the regime read on eight names, the open book with Greeks, and a button that fires a naked call at the running risk gate.

One command from a bare clone - python main.py