One of the biggest lessons I’ve learned is the importance of separating the trading models–the mathematical or algorithmic logic that analyzes data and decides how to trade–from the trading system–the general framework that provides interfaces for receiving data and interacting with the market to the trading models. The nature of high-frequency trading is such that it is critical to be able to rapidly iterate to adapt models to market conditions. If a trading system has what truly model logic is strewn throughout, it can become a nightmare to modify model behavior; new, fundamentally different, models may have to be foregone because implementing them will take too much time.
The above point, I’m sure the reader is thinking, sounds obvious: of course, concerns should be separated. The problem is that it is often very difficult in practice to distinguish what should belong to the model from what should belong to the trading system before it becomes an issue. Let me give an example:
Suppose we have built a model that takes one tick of market data (either an execution or another message altering the limit order book), does some calculations, and then decides whether or not to place an order. Prima facie, this looks like a reasonable general model, but it is not: in some cases, it will leave us making trading decisions based on a false view of the market. The reason for this is that while a stream of market data is serial, the events the data represents are not: some of the events are truly simultaneous. For example, a large market order that sweeps the book will generate a set of executions at the range of limits the order filled at, all of which happened at the time the market order was placed. A model that trades off of the first of these ticks will have an incorrect belief about the current price. A correct implementation would allow a model to detect simultaneous events and delay a trading decision until they have all been processed.
A general trading model should be the source for every behavior that we could conceivably want to control or vary, and its interface with the trading system should be very carefully defined and limited so that it can be easily tested. On the other hand, a trading system should be static, primarily the connectivity with markets, databases, and other computers, an order management system, and interfaces for the models to access these resources. If I was starting an HFT system from scratch, I would treat the development of the trading system as if I were writing an API–as opposed to a focused system for a specific task–to allow myself maximum flexibility during the process of model development.
The order management system (OMS), mentioned previously, is one of the most important parts of the trading system and, like the trading model interface, it is one where the most obvious implementations will lead to headaches down the road. The primary mistake made in designing an OMS that I’ve seen, and not just ones used for HFT, is in coupling the intention to place an order with the actual placement of an order. This can happen because the system was designed without an explicit OMS, so models generate orders that are sent directly to the market, with no intermediary object that has information about all open orders. It can also happen when the OMS is designed as a simple conduit for reaching the market, so logic that requires orders to be in a certain state must block waiting for a response. There are two main problems with these OMS designs: one, a blocked model will be unable to react to changing market conditions and will likely build up a backlog of stale market data. At the same time, it waits for trading confirmations, and two, these designs preclude the possibility of optimizing the trading behavior across all of the models that are using the OMS (An example of such an optimization might be two models placing orders in opposite directions for the same security. An intelligent OMS might combine them into a single net order depending on their limited prices and whether it expects positive or negative net commissions).
In general, the best implementation I’ve found for an OMS is to separate the intentions of a trading model–such as “place limit orders at $10.15 and $10.10″ or “buy 300 shares of INTC immediately”–from the resulting actual positions. With this design, a trading model can, asynchronous from actual trading, update its intentions, and the OMS can intelligently work to implement them, notifying the model when they are fulfilled. This leaves the model free to continuously process data and potentially change intentions before they are fulfilled. An extremely “intelligent” OMS, however, might be better thought of as a special kind of model that gathers and transforms the trading requests of all of the other models, since it is likely that an “intelligent” OMS would need to be tuned and otherwise parameterized. Further discussion of implementing a high-performance OMS will be the subject of future posts.
Before beginning the task of modeling financial markets, it is important to understand the capabilities and limitations of the trading system that will drive the models. Oftentimes, a model that is extremely profitable in theory is impossible to implement because of system latency or the fundamental nature of limit order books.