14 — Operating Modes¶
1. Why modes are a state machine, not a setting¶
Six modes span the distance between "read historical data" and "spend my money without asking." That is not a dropdown. Treating it as one invites the failure this whole system is built to avoid: a mode changing by accident, by bug, or by a click made without understanding what it authorises.
So modes are modelled as a state machine with explicit, auditable transitions, three properties of which are load-bearing:
- Escalation requires a ceremony; de-escalation is instant. Moving toward automation takes deliberate steps and satisfied preconditions. Moving away takes one tap and never fails.
- Capability is granted by the mode, not checked against it. A mode does not "allow" live orders past a check — in lower modes the live execution adapter is not constructed at all, so there is nothing to bypass.
- Every transition is a ledger event, hash-chained alongside trades, with the actor, timestamp, and preconditions recorded.
2. The six modes¶
| # | Mode | Money | Broker | Who decides | Who executes |
|---|---|---|---|---|---|
| 1 | Backtest | None | None | Strategy, historically | Simulated fills |
| 2 | Paper | Virtual | None | You, or a strategy | Simulated fills |
| 3 | Recommend | None | Read-only | AI proposes | Nobody — output only |
| 4 | Manual live | Real | IBKR | AI proposes, you approve each order | Broker, after your approval |
| 5 | Semi-automated | Real | IBKR | AI, within hard limits | Broker, automatically inside limits |
| 6 | Automated | Real | IBKR | AI, within hard limits | Broker, automatically |
Modes 1–3 are the complete product for a user who never enables real money. Modes 4–6 are the optional continuation.
Mode 1 — Backtest¶
Replays the point-in-time store through the same strategy, compliance, risk, and fill code the live path uses (08). No broker adapter is constructed. Its purpose is falsification: to find out that an idea would not have worked.
Mode 2 — Paper (built — see the running app)¶
A simulated brokerage account with the realism described in 06: next-session fills, spread, square-root market impact, participation caps, dividends, corporate actions, and 0% on cash. This is where a track record is earned.
Mode 3 — Recommend¶
The full agent pipeline runs and produces recommendations with complete reasoning (04), but no order object is created. The broker connection, if configured, is read-only: positions and balances flow in for portfolio context; nothing flows out. This is the first mode where a real IBKR account may be connected, and it is deliberately the one where the outbound path does not exist.
Mode 4 — Manual live¶
The AI prepares an order; you approve it individually. Approval requires a fresh authentication assertion and shows the full order ticket, the compliance verdict, the risk plan, and the post-trade portfolio state. An unapproved order expires rather than resting — a stale approval prompt answered an hour later is answering a question about a market that has moved.
Mode 5 — Semi-automated¶
The AI executes without per-order approval, but only inside limits you set: maximum order value, maximum daily notional, maximum position and sector weight, permitted markets and sectors, and daily/weekly/monthly loss limits. Anything outside the envelope falls back to Mode 4 behaviour for that order — it asks. The envelope is enforced at the adapter layer, below and independent of the risk engine, so a risk-engine bug cannot widen it.
Mode 6 — Automated¶
As Mode 5 with a wider envelope and no fallback-to-ask. Requires periodic re-confirmation — it cannot be enabled once and forgotten, because an automation you have stopped thinking about is the one that hurts you.
3. Transitions¶
stateDiagram-v2
[*] --> Backtest
Backtest --> Paper: no gate
Paper --> Recommend: no gate
Recommend --> ManualLive: ENABLEMENT CEREMONY
ManualLive --> SemiAuto: track record + limits set
SemiAuto --> Automated: explicit opt-in + re-confirmation schedule
Automated --> SemiAuto: instant
SemiAuto --> ManualLive: instant
ManualLive --> Recommend: instant, revokes credentials
Recommend --> Paper: instant
Paper --> Backtest: instant
Automated --> Recommend: EMERGENCY STOP
SemiAuto --> Recommend: EMERGENCY STOP
ManualLive --> Recommend: EMERGENCY STOP
Note the asymmetry. Every upward edge carries a precondition; every downward edge is unconditional and immediate. The emergency stop collapses straight to Recommend from any live mode, cancels working orders, and revokes stored broker credentials — not merely "stops sending."
The enablement ceremony (Recommend → Manual live)¶
Crossing into real money once, deliberately:
- Track record — at least 12 months of paper trading under the current model and rule-pack versions, with the reliability diagram shown honestly whatever it says (11).
- Benchmark — paper performance clears the naive compliant equal-weight benchmark after costs. Beating cash is not the bar; beating the simple alternative is.
- Correctness — zero unresolved defects in ledger, compliance, or risk.
- Acknowledgement — a written statement, typed not clicked, of what can be lost.
- Fresh authentication and entry of IBKR credentials directly into encrypted storage.
- Cooling-off period — a mandatory delay between enabling and the first live order. The point is to separate the decision from the impulse.
Failing any precondition blocks the transition and says which one failed.
4. What each mode may construct¶
The mechanism that makes modes real rather than advisory:
def build_execution_path(mode: Mode) -> ExecutionPath:
"""The only place a live adapter can come into existence."""
if mode in (Mode.BACKTEST, Mode.PAPER):
return SimulatedExecution()
if mode is Mode.RECOMMEND:
return NoExecution(broker=IBKRReadOnly() if configured else None)
# Live modes only; requires credentials that lower modes cannot decrypt.
return LiveExecution(
adapter=IBKRAdapter(credentials=vault.unlock(mode)),
caps=HardCaps.for_mode(mode),
approval=PerOrderApproval() if mode is Mode.MANUAL_LIVE else None,
)
In Modes 1–3 no object capable of sending an order exists in the process. This is the same argument as ADR-0004 on compliance and ADR-0007 on broker isolation: a capability that is absent cannot be reached by a bug, a prompt injection, or a mistaken click.
Credentials reinforce it. The vault key derivation includes the mode, so a process running in Recommend cannot decrypt live credentials even if it somehow tried.
5. Mode is visible, always¶
Every screen carries an unmistakable mode indicator, and the four live-capable modes use visually distinct treatments rather than a subtle label. The moment a user forgets which mode they are in, every safety property above becomes theoretical.
| Mode | Indicator |
|---|---|
| Backtest | Grey chip, "BACKTEST — historical replay" |
| Paper | Amber chip, "PAPER — virtual money" |
| Recommend | Teal chip, "RECOMMEND — no orders sent" |
| Manual live | Red chip, "LIVE — you approve every order" |
| Semi-automated | Red chip, "LIVE — auto within limits", with remaining daily notional |
| Automated | Red chip, "LIVE — automated", with the next re-confirmation date |
The emergency stop is present in all modes, in the same place.
6. Where the current build sits¶
The running application implements Mode 2 end to end, and Portfolio.mode has exactly one legal value. Modes 1 and 3 are designed and unbuilt; Modes 4–6 are designed, unbuilt, and gated behind the ceremony above.
The roadmap sequence is unchanged: 12 builds Backtest and Recommend before any live mode is written, because the track record that gates live trading can only be produced by the modes below it.