Anatomy of a Trading Agent: Signal to Settlement
A production trading agent is five subsystems with clean contracts between them — and understanding which subsystem is the source of record is the difference between debugging in minutes and debugging for hours.
The lesson most builders skip
When people first build a trading agent, they focus on the signal. Which indicator? Which threshold? What timeframe? The signal feels like the agent's core intelligence, so it gets all the design attention.
The signal matters. But the signal only fires correctly if the agent knows its own state — whether it is already in a position, what size, at what entry price, with what bracket. And the agent only knows its state if the reconciler has been talking to the exchange.
Most of the bugs that cost real money in production agents are not signal bugs. They are state bugs: the agent thought it was flat when it was long. The agent tried to enter a position it already held. The agent's stop-loss was set to a price that the exchange had already rejected. All of these bugs trace to the same root cause: the agent's model of the world had diverged from the exchange's record.
This lesson is about the architecture that prevents that divergence — five subsystems, one direction of flow, and a reconciler that is always the source of record.
Five subsystems, one-way flow
Follow the topology from top left to bottom right. Each subsystem has one job and hands its output to exactly one downstream consumer.
The market data feed is a read-only pipe. It connects to the exchange's WebSocket or REST API and normalizes the raw tick stream into a consistent format — price, volume, recent candles, order book depth — that the signal engine can consume without knowing anything about the exchange's wire format. The feed never decides anything; it only delivers.
The signal engine takes the normalized market state and produces a directional score: long, short, or flat, with a confidence value between 0 and 1. That is its entire contract. It does not know how the position will be sized. It does not place orders. It reads the feed and outputs a score.
The risk sizer receives the signal engine's output and the current position state from the state store. It answers one question: given this direction and confidence, how big should the position be, and at what stop-loss and take-profit levels? The output is a sized order specification. The risk sizer does not touch the market feed directly; it only consumes the spec it is handed.
The execution layer takes the order spec and submits it to the exchange as a bracket — the entry order plus the stop-loss and take-profit orders. It handles retries, idempotency, and confirmation. When the exchange fills or rejects, the execution layer routes that result to the reconciler.
The reconciler and state store are the ground-truth layer. The reconciler queries the exchange's position endpoint directly, compares it against what the agent believes it holds, and writes the verified state to the state store. Every other subsystem that needs to know the current position reads from the state store — not from execution logs, not from the signal engine's memory, not from the risk sizer's last output. The state store is the agent's single source of record, and the reconciler is what keeps it true.
Each subsystem has one job it must never violate
The NEVER column is as important as the IN → OUT contract. Read it as the thing each subsystem is most tempted to do that would break the whole architecture.
The signal engine is tempted to size positions. It already knows the score; adding a few lines to calculate notional feels efficient. Resist it. The moment the signal engine sizes, you have no way to isolate signal logic from sizing logic when something goes wrong. You also cannot swap risk models without touching the signal code.
The risk sizer is tempted to read the market feed directly. It already knows direction; checking the latest price directly feels natural. But then you have two subsystems consuming raw market data with different normalization, and you cannot easily replay a scenario because the sizer's input is now split across the feed and the handed-down spec.
The execution layer is tempted to modify the order spec it receives. It knows the current order book; adjusting the entry price slightly for better fill seems harmless. It is not. Execution must send exactly what risk gave it, because risk's calculations (sizing, stop-loss, take-profit) are internally consistent. An execution layer that modifies the spec without telling risk creates position state that risk never accounted for.
The reconciler is tempted to originate new orders. It already queries the exchange; placing a corrective order from inside the reconciler seems like the fastest fix. But this bypasses risk, bypasses execution, and creates orders with no tracked state. The reconciler's only authority is to write to the state store and, when it detects an unrecoverable divergence, to signal a halt.
Settlement: from decision to realized PnL
Settlement is the full path from "the signal engine scored long" to "the PnL is recorded in the state store." It passes through all five subsystems.
The signal scores. The risk sizer sizes and sets the bracket levels. The execution layer places the bracket and receives fill confirmations. The reconciler reads the exchange's position endpoint and writes the verified position to the state store. When the position exits — because the take-profit was hit, the stop-loss fired, or the signal reversed — the same path runs in reverse: execution handles the close, reconciler confirms the flat state, the state store records the realized PnL.
That cycle is settlement. Each step must complete before the next one has valid input. A signal that fires while the reconciler has not confirmed the prior position is closed will try to enter a position the agent is already in — the classic double-entry bug.
This is why the loop wire from reconciler to signal engine in the topology diagram is not decorative. It is the enforcement mechanism: the signal engine only sees a flat state store when the reconciler has confirmed the position is closed.
Build it: wire signal → risk → execution through typed contracts
You are going to implement a decide() orchestrator that calls a SignalEngine, a RiskSizer, and an Executor in strict order through typed interfaces. If the signal is below the confidence threshold, bail before touching risk. If risk declines the trade, bail before touching the executor. Return a typed Decision object that captures what each subsystem said.
What is next
You now have the map — five subsystems, clean contracts, reconcile as the source of record. The next question is where this agent lives: which exchange, which asset class, which venue. That choice is not a deployment detail. It shapes your liquidation math, your reconciliation burden, and whether your risk sizer needs a per-symbol margin model. Lesson 673 covers how to evaluate and score venues before writing a line of agent code against them.