Architecture of an algorithmic trading system
5/31/2026 · R. B. Atai
An algorithmic trading system can look like a set of separate modules: data loading, strategy, backtesting, execution, risk management, logs, monitoring. But in real operation, the important part is not the list of components. It is the boundaries between them. Those boundaries are where the link between a convincing research result and the real market most often breaks.
The same idea moves through several environments: research, backtest, paper trading, and production. If each environment uses different data, different execution rules, and different risk checks, the system tests one strategy and trades another. Architecture matters not for the diagram, but for reproducibility: the signal, position sizing, limit check, and order submission should keep the same meaning all the way from hypothesis to live capital.
A good trading architecture therefore looks less like a "smart model" and more like an engineering loop with clear contracts. Data must arrive in a verifiable format. The strategy should generate a decision, not talk to the exchange directly. The backtest should model real execution constraints. The execution engine should know order state, not just send HTTP requests. Risk management should sit before the trade, after the trade, and over the whole system.
Data ingestion: the market entry layer
Data ingestion is not "download candles". It is the layer that turns the external market into an internal stream of events: trades, order book updates, candles, funding, instrument status, fees, trading constraints, and, when needed, news or corporate events.
The main task of this layer is to preserve the meaning of data during normalization. Exchanges differ in symbols, price and quantity precision, timestamps, order types, request limits, and aggregation rules. Even a simple candle can have different interval boundaries, a different policy for empty bars, and a different treatment of late corrections. If these differences are hidden too early, the strategy receives a tidy table that no longer corresponds to a specific venue.
That is why it is useful to separate the raw layer from the normalized layer. The raw layer stores original messages, or a representation as close to them as possible: what arrived, when it arrived, from which source, with which sequence number or update id. The normalized layer maps data into the internal model: unified symbol ids, timestamps, event types, prices, volumes, and quality status.
For streaming data, gaps and event order are especially important. Coinbase documentation explicitly warns that sequence numbers can indicate dropped or out-of-order messages, and the consumer must be able to restore correct state. 6 Binance describes a separate procedure for maintaining a local order book: first WebSocket, then a REST snapshot, then applying buffered depth events by update id. 5 This is not a minor technical detail. It is part of the trading model: if the order book is built incorrectly, execution and slippage are calculated on imaginary liquidity.
Database and storage
A trading system usually does not have one "database for everything". There are several different classes of storage, and mixing them is dangerous.
The first class is the market data store. It is needed for historical quotes, trades, order book data, funding, instrument reference data, and all data used for research and backtesting. Append-only logic, versioning, gap checks, the ability to rebuild candles from a lower-level feed, and the ability to know which version of history produced a specific result all matter here.
The second class is operational state. This includes orders, executions, positions, balances, cash movements, fees, API errors, risk-limit state, and internal system events. These data are needed not only for reports, but also for reconciliation: does the system's view match what the exchange or broker sees?
The third class is research artifacts: strategy parameters, optimization results, walk-forward windows, metric reports, and experiment sets. They should not be stored as unnamed CSV files like "final_v3". If a backtest result cannot be linked to the data version, strategy code, parameters, and cost model, it cannot be reproduced. And if it cannot be reproduced, it should not reach production.
Strategy engine
The strategy engine turns data and state into trading intent. In a good architecture, the strategy does not send an order directly to the exchange. It says: given this market, portfolio, and risk state, I want this exposure, this target position, or this set of orders.
This separation may look formal, but it protects the system from a central confusion: signal and execution are different tasks. The signal answers "what do I want to do". Execution answers "how can this be done safely and realistically on a specific venue". If the strategy itself knows the exchange API, calculates limits, and handles partial fills, it becomes almost impossible to move honestly from backtest to live.
The strategy engine is best designed as a deterministic layer. The same input should produce the same decision. If there is randomness, it should be explicitly fixed by a seed, model version, or state. If ML models are used, they need a feature version, model version, training time, and a prohibition on data that would not yet have been available at decision time.
The practical contract is simple: the strategy receives only the data that would have been available at that moment, and it does not know whether its decision will be executed in backtest, paper trading, or production. Then the same strategy engine can be checked in different environments without rewriting the logic itself.
Backtesting engine
The backtesting engine is not there to show a beautiful equity curve. It is there to test a hypothesis under conditions as close as possible to future execution. The more assumptions are hidden inside the backtest, the higher the risk that the system optimizes for the simulator rather than the market.
The first requirement is the absence of look-ahead bias. The strategy must not see a future close, late data corrections, a universe composition known only today, or corporate actions applied as if they had been known in advance. The second requirement is an honest cost model: fees, spread, slippage, funding, borrow cost, market impact, and liquidity constraints. The third is the correct event sequence: signal, limit check, order placement, execution, position update, result recording.
A vectorized backtest is convenient for research, but it often models event queues poorly. An event-driven backtest is slower, but closer to production: it forces the strategy to live in the same event order in which it will trade. For medium-term strategies, the vectorized approach may be enough. But for intraday, order book, and execution-sensitive systems, it is easy to get a result without an event model that does not survive the first launch on a real exchange.
Over-optimization is a separate problem. Bailey, Borwein, López de Prado, and Zhu describe backtest overfitting as a situation in which a strategy is selected using historical simulation and then degrades out of sample; they propose estimating the probability of overfitting through special cross-validation procedures for investment backtests. 7 The architectural implication is simple: the backtesting engine should store not only the "best result", but also the experiment trail, so it is visible how many variants were tried before the attractive curve appeared.
Execution engine
The execution engine is the layer that turns trading intent into real orders. It operates in a much messier world than the strategy engine: latency, repeated requests, partial fills, cancellations, rejects, rate limits, position desynchronization, different order types, and different states of the same order on the exchange side.
A minimal execution engine must be able to manage the order lifecycle: created, submitted, acknowledged, partially filled, filled, cancelled, rejected, expired. It needs idempotency: retrying a request after a timeout should not accidentally open a double position. It needs reconciliation: if the system thinks an order was cancelled while the exchange shows a fill, the external source of truth must win.
For institutional markets, FIX is often the standard boundary. FIX Trading Community describes the FIX Protocol as a global open standard for exchanging trading information: orders, executions, and market data, independent of any specific transport. 3 In crypto infrastructure, REST and WebSocket APIs of a specific venue are more common, but the engineering task is the same: separate the internal order model from the external protocol.
A good practice is to build execution through adapters. Inside the system, there is a unified OrderIntent, OrderState, Fill, and Position. Outside, there is Binance, Coinbase, a broker FIX gateway, or a sandbox. Then the strategy and risk layer are not rewritten for each venue, and venue-specific differences remain inside the execution adapter.
Exchange APIs as an external boundary
An exchange API is not just transport. It is the external boundary of the system, where authentication, rate limits, WebSocket subscription limits, heartbeat rules, latency, maintenance windows, different error formats, and sudden behavior changes appear.
Binance documentation, for example, separates REST market data endpoints and WebSocket streams, specifies incoming message limits, ping/pong logic, and the procedure for restoring a local order book. 4 Coinbase separately describes production and sandbox endpoints, subscription channels, heartbeat, sequence numbers, and the need to handle gaps. 6 These details directly affect architecture: ingestion must be able to recover, execution must distinguish a reject from a timeout, and monitoring must detect heartbeat loss before the strategy starts making decisions on stale data.
Fragmentation is especially visible in crypto. The same pair on different venues can have different fees, depth, tick size, minimum order size, update speed, and trading halt behavior. That is why the API layer should not leak into the strategy. The strategy can know that it works with an instrument and available liquidity, but specific LOT_SIZE rules, request signatures, or cancel response formats should live below it.
Risk management as a cross-cutting loop
Risk management should not be the last module at the end of the pipeline. In a trading system, risk must be a cross-cutting loop: before the trade, during execution, after the trade, and at the level of the whole system.
Pre-trade risk checks answer questions such as: does the order exceed the size limit, does it violate max position, is there enough balance or margin, has the daily loss limit been breached, is the instrument disabled, are the data stale, has the connection to the exchange been lost? Post-trade checks verify the actual position, PnL, fees, exposure, concentration, and deviation from expected state.
Regulatory practice has long formalized these requirements. ESMA guidelines on automated trading require investment firms to have effective systems and controls, including pre-trade and post-trade controls, algorithm testing, access management, and procedures for failures. 1 SEC Rule 15c3-5 requires broker-dealers with market access to maintain a system of risk controls and supervisory procedures to limit the financial and regulatory risks of market access. 2
For an application such as ai-trader, the practical conclusion is not to imitate a regulatory document, but to make the risk layer a mandatory part of the order path: a signal does not become an order until it passes limits, and a drawdown breach, position mismatch, or loss of market data must be able to stop trading without human intervention.
Logging
Logging in a trading system is not a stream of messages saying "something happened". It is an audit trail that lets you reconstruct why the system made a decision, what input it saw, which risk check the order passed, what was sent to the exchange, and what response came back.
Logs should connect events through traceable identifiers: signal id, decision id, order id, exchange order id, fill id, strategy version, data version. Without that connection, investigation turns into a manual search by time, and time in trading systems is often imperfect: different services may have different clocks, and events may arrive in a different order from the one in which they were created.
It is important to log not only errors. Successful decisions are needed too: why the strategy did not enter, why the risk layer rejected an order, why execution chose a limit order instead of a market order, why the position was reduced. The absence of a trade is sometimes more important than the trade itself, especially when comparing live results with the backtest.
At the same time, logging should not become a new source of risk. API secrets, private keys, and full authentication payloads do not belong in logs. Production needs logging levels, masking of sensitive fields, separate storage for audit events, and a clear retention policy.
Monitoring
Monitoring does not answer the question "what happened in the logs". It answers "is the system currently operating within acceptable limits". That is the difference between historical investigation and operational control.
In SRE practice, monitoring is built around symptoms visible to the user or system, not only around internal causes; the Google SRE Book separately emphasizes metrics, alerts, and signals that reflect the actual state of the service. 8 For a trading system, such symptoms include market data freshness, ingestion-to-signal latency, signal-to-order latency, reject rate, mismatch between local and exchange position, reconciliation errors, stale orders, heartbeat, drawdown, exposure, and live-vs-backtest drift.
Poor monitoring says "the API returned an error". Good monitoring says "the strategy is still making decisions, but market data for this instrument have not updated for 40 seconds" or "the local position differs from the exchange position after the last fill". The first is just an event. The second is a state in which the system should degrade, stop, or move into safe mode.
Alerts on silence are especially important. If a service fails loudly, it is easier to notice. If a WebSocket stops sending updates while the process remains alive and the strategy keeps reading old state, the error looks like normal operation. Monitoring therefore needs to watch not only exceptions, but also data freshness, event rate, and state invariants.
Paper trading and production: one code path, different loops
Paper trading is useful only when it tests the same path that will go into production. If the paper environment is a separate simplified implementation where orders are "filled" immediately at the last price, it tests the interface more than the trading system.
The better approach is to keep one signal path: data ingestion, strategy engine, risk checks, order intent, execution adapter, order state, fills, positions, logs, monitoring. The difference between paper and production should be in the execution adapter and the source of confirmations. In the paper adapter, fills are simulated by a defined model. In the production adapter, fills come from the exchange or broker. The rest of the system should see the same event types.
This approach enables staged rollout. First, the strategy passes historical backtesting. Then paper trading on live data checks data freshness, event order, risk limits, and operational behavior. After that, a minimal position size, limited universe, stricter limits, and stronger monitoring can be enabled. Production trading is not one large switch, but a gradual removal of constraints as the system proves that its live behavior resembles the expected behavior.
Even here, paper trading is not proof of profitability. It does not reproduce the full order queue, market impact, or liquidity stress. Its task is more modest and more useful: to check that the trading loop does not diverge from reality before the error starts costing money.
Conclusion
The architecture of an algorithmic trading system does not start with choosing a framework or a signal model. It starts with a question: can the same logic travel from data to order without changing meaning?
Data ingestion makes sure the market is represented honestly. Storage provides reproducibility. The strategy engine separates the idea from execution. The backtesting engine tests the hypothesis with real constraints in mind. The execution engine manages the order lifecycle. Exchange adapters isolate the chaos of external APIs. Risk management limits damage before it becomes irreversible. Logging gives the system memory, monitoring gives it operational sight. Paper trading connects research and production without a blind jump.
A strong system does not have to be complex. But it must have clear boundaries, verifiable invariants, and one decision path. Otherwise, a strategy may look functional in research while in reality it trades not the market, but a set of architectural assumptions.