Event Based Trading
High-level overview of Apex's event-based design
Introduction
In this article, we’ll take an introductory look at the architecture of Apex, the trading engine featured throughout this Substack. Understanding how Apex is designed is a necessary first step before we explore how strategies are developed for it, which will be the topic of later articles.
A defining feature of Apex is that it is an event-based trading system. This is more than a technical footnote. It is a fundamental choice that shapes the way the engine reacts to market activity, processes data, and affects how strategies are built.
In the following sections, we’ll explain what an event-based system means, how Apex implements it under the hood, and the implications this has for strategy code. By the end, you’ll see why this architectural choice is central to everything Apex does, and why understanding it is essential for building effective, high-speed trading strategies.
Apex Engine
Apex is a framework for building algorithmic, tick-driven trading strategies. It provides the core functionality required to research and build strategies that trade multiple instruments across multiple markets, with a particular focus on reacting to individual trades and order book updates.
At a high level, Apex supplies the foundational components - data models, market access, and order routing. The strategy layer sits on top, consuming market data and generating trading decisions. This relationship is illustrated in the following diagram.
This separation, a common approach in trading systems, creates a clear division of responsibilities. Apex handles infrastructure concerns - such as network access, exchange protocols, and data normalisation - while the strategy layer focuses on trading logic: indicators, signals, decision making, order placement and risk management. The strategy layer is interchangeable; Apex effectively acts as an API upon which many different strategies can be built.
A key design question for any trading platform is how should the strategy interact with external venues. Financial markets are inherently asynchronous. When an order is sent - whether placing a resting order or hitting across the spread - the outcome is not immediately known. Acknowledgements, rejections, and fills arrive later, often unpredictably. The platform must decide how to present this reality to the strategy.
One approach is to hide this complexity and present a simplified, synchronous model, where sending an order appears to produce an instant outcome. While conceptually simpler, this abstraction can obscure important details and introduce limitations into what a strategy can achieve.
Apex takes an alternative approach. The asynchronous nature of trading is exposed directly to the strategy, which consequently must be explicitly designed to handle delayed events. When the strategy submits an order, it is performed as an asynchronous request, with the outcome not immediately known. The result is obtained a short time later, and only then can any necessary follow-up action be taken - for example, resubmitting an order that failed to execute.
This leads to a model of interaction where the strategy is built to respond to a stream of events. This is what defines Apex as an event-based trading system, a design we will review next.
Event Based Trading
Event-based trading systems are built around the idea of responding to events. A strategy is structured as an event handler, registering callbacks to process the different types of events generated by the trading engine. It is the arrival of these events that drives signal evaluation and trading decisions, ultimately leading to actions such as submitting or cancelling orders.
The core idea is illustrated in the following diagram. The trading strategy sits on top of the engine and reacts to a stream of events. It’s the responsibility of the engine to generate the appropriate sequence of events, based on incoming market data and order updates from the connected venues.
In practice, there are four main classes of event:
Market data events - These represent changes in the market, such as trades, updates to the best bid and ask, or deeper order book changes. A strategy does not necessarily need to respond to every update; for example, it may choose to react only to trades and top-of-book (L1) changes.
Order events - These reflect changes to the state of orders created by the strategy. As orders are acknowledged, filled or cancelled, corresponding events are generated and delivered to the strategy.
Timer events - Timer events allow the strategy to perform time-based actions. These may be periodic callbacks, for example, to review all live orders every few seconds, or one-off timers scheduled to trigger at a specific point in the future, such as retrying an order after a short delay.
User events - These are external interventions, such as starting or stopping trading, or issuing a command to cancel all orders. They are typically driven by a user GUI connected to the engine.
These events are often modelled closely in code, typically as classes or enumerations, with the strategy implementing corresponding handler functions for each event type.
A useful way to understand event-based systems is to contrast them with what they are not. There is no central polling loop, continuously querying the market, submitting a batch of orders, and waiting for results. Instead, the flow of control is driven entirely by incoming events - the strategy reacts when something happens, rather than repeatedly checking if something has happened.
Benefits
An event-based approach offers several important advantages for a trading system.
First, it reflects the true low-level nature of financial markets. As noted earlier, markets are inherently asynchronous, with market data, order acknowledgements, and fills arriving unpredictably over time. By being exposed to this directly, strategies operate on the same model as the real world, avoiding the distortions introduced by synchronous abstractions.
Second, acting on market events allows for minimal latency between a market change and the resulting trading decision. Strategies can be programmed to respond to individual trades or order book updates by immediately placing or cancelling orders. This allows for low-latency and high-frequency strategies, that must react to market changes as fast as possible.
Finally, event-based systems are easier to backtest. By recording and reproducing the exact sequence of market data events - principally by replaying captured market data and simulating order execution - a strategy can be evaluated against historical data to see how it would have performed for a period of time in the past.
This final point is illustrated in the following diagram, which shows a backtest configuration. Market data events are now generated by replaying market data files, while any orders created by the strategy now interact with an internal simulated exchange. Any required timers are based on a simulated clock, which advances as market data is replayed.
In addition to backtest mode, event-based models can also be adapted to a simulation or paper-trading mode. This is illustrated next. Here, market data events are generated from a real-time feed received from a live exchange, while order interaction is handled by an internal simulated exchange. Whereas backtests allows us to see how a strategy would have performed in the past, paper trading allows us to observe how it behaves under current market conditions.
Before leaving the topic of event-based models, it is important to acknowledge their challenges.
The main drawback of this whole approach is that event-based code is harder to reason about and to get right. Actions do not produce immediate results; instead, outcomes arrive later via callbacks, often at unpredictable times, and sometimes not at all. This makes control flow less explicit and subtle bugs are common.
So strategy code, which already has to implement the inherent complexity of trading logic - indicators, signals, order placement and so on - must additionally manage asynchronous request and event handling. This includes tracking state across callbacks, handling missing updates, and ensuring that behaviour remains consistent over time.
Even simple tasks become less straightforward. For example, introducing a short pause between two requests cannot be achieved with a blocking sleep call, because event handlers must never block a thread. Instead, delays are implemented by registering a timer callback to be invoked at a later time, at which point the next step in the workflow can proceed.
Apex Implementation
Now that we have outlined event-based models, we will briefly look at how this is implemented in Apex. This is a high-level overview, focusing only on how the core engine delivers events to the strategy.
As mentioned earlier, in an event-based system the strategy acts as an event handler. In Apex, this is implemented as a virtual callback interface. A base class, Bot, defines a set of virtual member functions corresponding to the various events generated by the core engine.
Concrete strategies derive from Bot, implementing some or all of these callbacks to provide the trading logic. In practice, the most important callbacks are those for market data and timers: the former drives indicator evaluation and trading decisions, while the latter is typically used for performing periodic checks on the state of live orders.
In addition to overriding these base class methods, a strategy can specify which market data events it wants to receive callbacks for. For example, it may care only about trades rather than the much higher volume L1 updates. This is important in situations where reducing the number of callbacks is necessary for performance. Within a callback the specific event type can be determined from the EventType object passed as an argument.
Finally, Apex supports several different run modes, which configure the entire engine instance. A strategy can be run in live, backtest, or paper trading mode - without any change to the strategy code. As described earlier, these modes determine the source of market data and how order execution is handled. The callbacks themselves do not change - the strategy never needs to know the run-mode it is operating under.
SUMMARY
This has been a brief introduction to the fundamental design of Apex, with the aim of showing that it’s built as an event-based trading system.
Apex has been built this way for two main reasons. First, it supports the class of fast strategies that need to respond directly to low-level market changes, such as low-latency and high-frequency trading. Second, it allows for the strategy code to run unchanged across live trading, backtest, and paper-trading environments; selecting these modes is just a configuration change.
This event-based design is not uncommon. It reflects the architecture found in professional settings, where reacting to and reproducing real-time events is essential for both correctness and performance. Apex is built with these same principles in mind.
Apex currently uses a virtual callback interface to connect the core engine to strategy code. While this approach is flexible and easy to work with, it does introduce a small but unnecessary overhead. Other techniques, such as template-based, compile-time polymorphism, offer potential performance improvements and is a natural area for future evolution.
Ultimately, successful trading depends on accurately modelling and responding to market reality. By exposing that reality directly, enabling its simulation, and allowing for rapid reaction, Apex provides a foundation for building robust and profitable trading strategies.






