A safe autonomous LLM trading agent separates judgment from execution absolutely: the language model reads market state and selects a play, while deterministic code owns every number — position sizing, risk limits, order placement. The model cannot pass a position size, breach a cap, or trade outside its mandate, because those actions do not exist in its tool surface.
This is an architecture write-up of a system we designed and built for a client: a fully autonomous agent that runs unattended on a schedule, reads a live market feed, applies a written trading mandate, and places orders through a major retail CFD broker's REST and streaming API. It runs as a demo/evaluation deployment. Nothing here is financial advice, and no performance figures are discussed — this is about the engineering.
What is the core architectural pattern for an autonomous LLM agent that runs unattended?
We call it a one-person hedge fund on shift work. Every hour during market hours, an orchestrator spawns a fresh, stateless LLM session into a repository. The model retains nothing between runs. Continuity lives entirely on disk, and the first action of every shift is to reconcile that disk state against the broker API before anything else happens.
The on-disk memory has four parts. A shift-handover outlook file carries the current regime read, the watchlist, and mandatory notes for the next session. One file per open position holds its thesis, invalidation condition, management plan, and running log. An append-only daily journal records every decision. A closed-position archive preserves outcomes.
The split of authority is precise: the broker API is the source of truth for what positions exist; the files are the source of truth for why they exist. Neither can override the other, and a disagreement between them is a halt condition rather than something the agent resolves on its own judgment.
We chose statelessness over a long-running process deliberately. A persistent session accumulates context, drifts, and eventually carries stale beliefs it has no mechanism to discard. A fresh session that reconstructs the world from two independent sources every hour cannot drift, because it has nothing to drift from.
How do you stop an LLM from risking too much on a single trade?
By removing the capability rather than checking for its misuse. Our agent cannot pass a position size — the parameter does not exist in the tool signature. The executor derives size independently from stop distance, value-per-point with FX conversion into the account currency, current equity, and a risk percentage read from a machine-readable mandate file.
Around that sit the hard rails, all enforced in code and none negotiable by the model: maximum risk per trade, maximum concurrent positions, maximum exposure per correlation group, a margin ceiling, a daily-loss circuit breaker, and a mandatory stop attached to every position at open. There is no code path that opens an unprotected position.
Two further controls sit outside the trading logic entirely. A kill-switch file makes every write operation refuse the moment it exists, giving a human an instant, unambiguous stop that requires no deployment. And the API client is hard-locked to the demo environment in code — requesting the live environment raises before any network call is made.
We chose an absent parameter over a validated one because validation is a check someone can forget to apply, while an unrepresentable action is a check nobody can forget. This mirrors the guidance in Anthropic's own tool-design engineering notes: shape the tool surface so the wrong call cannot be constructed, rather than relying on the model to decline it.
What tools does an autonomous trading agent actually need?
Four, each returning pre-digested verdicts rather than raw data. A session-cached broker client handles account state and order placement with a rate-limit guard and deal-confirmation polling. An analytics CLI computes technical state. A calendar tool manages event risk. A headline sweep covers narrative risk. Every output carries a data-freshness flag the agent is bound by rule to respect.
The analytics CLI runs over a local candle store and computes EMA, RSI, MACD, ATR, Bollinger bands, swing levels, a volatility-regime classification, and a cross-market dashboard. The agent never parses raw price series — it receives computed indicator state, which removes an entire class of arithmetic error from the reasoning layer.
The economic-calendar tool maps blackout windows to specific instruments, so an event affecting one market does not silently gate an unrelated one. It fails safe by design: if the calendar is unreachable, the agent must assume a high-impact event is imminent and stand down. Unavailable infrastructure produces caution, never permission.
The headline sweep follows a single rule we consider load-bearing: headlines veto, never trigger. News can stop a trade the technicals support; it can never start one on its own. That asymmetry is deliberate, because narrative is precisely the input a language model is most likely to over-weight into a decision.
Why build your own market data recorder instead of querying the broker?
Because the broker caps historical data retrieval at a fixed weekly allowance, which is far too small to backfill indicators on demand across a multi-instrument watchlist. Recording continuously is cheaper than rationing a quota, and it yields a local store with no rate limit, no latency, and no dependency on an external call succeeding at decision time.
The recorder is a standalone service under systemd with its own broker session and its own reconnect logic, entirely separate from the trading agent's session. It writes only closed candles — never a forming bar — so no downstream consumer can ever compute an indicator from a partial period.
Running it as a supervised unit rather than a cron job means systemd restarts it automatically on crash or disconnect, which for a streaming socket is the difference between a gap of seconds and a gap of hours. Market data you did not record is not recoverable later.
Candles land in a local SQLite store. We chose SQLite over a hosted time-series database because the access pattern is one writer and several short-lived readers per hour — exactly the shape write-ahead logging handles without contention. A network database would have added an operational dependency and a failure mode in exchange for scale we do not need.
How do you encode trading rules so an LLM applies them consistently?
Mechanically, not in prose. A playbook-check mode evaluates every playbook's entry gates in code, with all thresholds read from the mandate file. It returns a per-instrument verdict — VALID, RESTING_ORDER, WATCH, or NOT — naming the exact gate that failed, plus a ready-to-run order command with stop distance and reward-to-risk already computed.
The agent's role is therefore not to decide whether a setup qualifies. That determination is deterministic and reproducible. The agent's role is to apply the named vetoes: a VALID verdict is taken unless one of five listed conditions applies — calendar blackout, stale data, a cap or correlation limit, the kill-switch, or, for fade plays only, a fresh news driver or crowded sentiment.
Enumerating the vetoes matters as much as enumerating the gates. An open-ended instruction to use good judgment invites a model to generate additional objections indefinitely; a closed list of five gives the reasoning layer a bounded, auditable job with a verifiable answer.
Three named playbooks run on top of this: trend-continuation with resting-limit entries, mean-reversion at statistical extremes, and post-event fade. Each has its own gates, its own management plan, and its own performance accounting.
Why should every number in an agent system live in one file?
Because documentation and code that hold separate copies of a threshold will diverge, and the divergence is silent. Our mandate keeps every number — risk percentages, position caps, correlation groups, margin ceilings, session windows — in a single machine-readable file that both the executor and the written knowledge base read at runtime.
This means a threshold cannot be changed in the documentation without changing system behaviour, and cannot be changed in behaviour without changing what the documentation states. The rulebook the agent reads and the limits the executor enforces are guaranteed to be the same rulebook.
Alongside the mandate sits the rest of the written knowledge layer: the playbooks, a decision guide covering how to weigh conflicting signals, and state-file conventions defining exactly how each memory file is structured. It is a written operating procedure, versioned like code, because that is what it is.
How does an hourly agent trade setups it is not present to see?
With resting limit orders at pre-computed zones, stops attached at placement. An agent that wakes once an hour cannot witness intra-hour price action, so rather than polling faster, we delegate the waiting to the venue. The broker monitors those levels continuously, at no cost, with no missed ticks.
This is a cadence-honest design. It matches the frequency at which the system genuinely makes decisions to the frequency at which it claims to act, rather than pretending an hourly visitor can react to second-by-second movement. The agent decides where and on what terms; the exchange infrastructure handles when.
It also has a risk property we value more than the execution benefit: because the stop is attached at placement, a position that fills while no session is running is protected from its first moment. There is never a window in which an open position is waiting for an agent to wake up and manage it.
Who approves changes when the agent learns something?
A human does, always. A weekly review procedure computes statistics per playbook, compares performance against two deliberately unglamorous benchmarks — "did nothing" and "buy-and-hold the index" — and writes rule-change proposals into a folder for review. It proposes; it never applies. The agent has no path to editing its own rulebook or its own tools.
Both benchmarks exist to prevent flattering self-assessment. A strategy that cannot beat doing nothing is worse than nothing, and one that cannot beat holding the index is an expensive way to own the index. Measured only against itself, any system looks busy and competent.
Designing this approval loop on day one rather than retrofitting it is the decision we would most defend. The moment an autonomous system can modify its own constraints, every safety property you reasoned about becomes a property you merely hope for. Keeping the loop human-gated is what makes the rest of the architecture's guarantees real.
Operationally, the review is supported by an end-of-day report rendered as proper HTML with a plain-text alternative and delivered by email — the daily surface through which a human stays oriented without reading the journal files directly.
What does the operations layer of an unattended AI agent look like?
Scheduling is timezone-aware and deliberately wider than the trading window, with the mandate trimming the edges — so daylight-saving transitions cannot silently shift the session. Overlap protection guarantees a single active run: if one cycle is still working, the next does not start alongside it and race it for the same positions.
Headless execution permissions are verified against a real spawned run before being trusted to a schedule, because a permission prompt in an unattended context is a silent hang rather than a visible error. Unattended systems fail quietly, so every failure mode has to be provoked deliberately during commissioning.
A small routing stub lets one repository serve two audiences: a scheduled run is directed into the full agent operating procedure, while a human opening the same repo for development work gets a normal engineering session. The agent's rulebook and the developer's workspace coexist without either contaminating the other.
Human changes to agent-facing files are recorded in the daily journal under an operator-maintenance convention, so the next scheduled session sees exactly what changed underneath it and why. In a system whose memory is its files, an unlogged edit by a human is indistinguishable from corruption.
What does this architecture demonstrate about building autonomous AI systems?
That autonomy and safety are not a trade-off when the boundary is drawn correctly. The LLM here has genuine latitude — it reads regime, weighs conflicting signals, applies vetoes, and writes the reasoning that its successor will inherit. It simply has no ability to compute a size, exceed a limit, or place an unprotected order, because those capabilities live in code that does not accept its opinion.
The transferable pattern is not specific to markets. Stateless sessions with files as memory, reconcile-before-act, every number in one machine-readable place, deterministic evaluation of anything that can be evaluated deterministically, and a governance loop where the system proposes and a human approves — that combination applies to any domain where an agent takes consequential actions unattended.
It is the same discipline behind the 80-line agent loop we shipped against a live B2B catalogue: own the decision boundary, write the small amount of plumbing yourself, and let the model do only the part that genuinely needs a model. When an agent operates unattended against real consequences, that boundary is the entire product — and it is also what keeps an agent that works in staging from degrading in production after a few days.