The core technology behind MachinaTrader algorithmic trading is an event-based, streaming analysis system called the Machina Engine. The Machina Engine models the stream of time as accurately as possible, and presents market data (called “events”) to your algorithm in chronological order.
During live strategy trading – when you let your strategy algorithm trade in the “live” market – the Machina Engine presents your algorithm with the stream of actual, real-time market data. These live market events are a stream of individual market trades, called ticks.
During backtesting, the past market events – the individual trades (or ticks) – are consolidated into price candles. These price candles are revealed to your strategy algorithm incrementally (candle by candle), in the same order as they occurred in the past.
[mkb-info] Traders commonly refer to price candles. To avoid confusion between charts and code, we will refer to candles when talking about price charts, and TradeBars (or bars) when talking about the code objects that represent price candles.[/mkb-info]
Ticks, Bars and the Time Frontier
In terms of “time”, there are two “types” of market data: point values, and period values. In the Machina Engine, Ticks are point values, and Bars have a period.
Ticks and Bars have different properties that determine when the Engine will emit the data to your algorithm. Coordinating and emitting this data is controlled by the Engine’s Time Frontier.
The Time Frontier
MachinaTrader allows your algorithm to handle market data for multiple timeframes (candle periods). This results in a condition where one timeframe is ready to emit but another timeframe, with a longer candle period, may still be constructing its bar. To coordinate these different timeframes the Machina Engine reveals market events (ticks or bars) incrementally, based on their End Time.
Only when a bar’s EndTime has passed, will it be transmitted to your algorithm’s
OnTradeBar() method. Your algorithm is only permitted to access market data from before this Time Frontier, thereby preventing you from accidentally looking into the future.
Time property in your algorithm is always equal to this Time Frontier. This Time Frontier is also used as the timestamp for any logging and debugging messages.
Bar Data – Period Values
Bar data is an Engine code object representing the aggregation of a candle period of market data. When backtesting, we deal with trade bars that are the aggregation of billions of past trades (ticks).
In real-time, there may be periods during which no trades are executed in the market. Perhaps the exchange was down for maintenance, or perhaps there just was no market activity. For this reason, the Machina Engine does not make any assumption when building trade bars, and the close value of a bar is not assumed until the start of the next bar.
When there are no ticks during a period, the previous bar is copied and emitted to your algorithm at the requested period (resolution). In MachinaTrader, this is the default behavior for bar data and it is referred to as “filling data forward”. You can configure whether this is enabled when you request the security data
[Minerva Info] The Machina Engine always retrieves 1-minute bar data. To create other timeframes the 1-minute bars must be consolidated into longer period bars.
Tick Data – Point Values
An individual trade made in the market is called a Tick. It is a discrete event (typically, a market order) that does not have a period of time attached to it. A Tick object has the same value of
EndTime because it has no period. Tick objects represent instantaneous point values and cannot be filled forward.
The Machina Engine has two primary event handlers for presenting the time-stream of market events:
Slice object represents market data for a period of time, a “time-slice”, which is your algorithm’s primary bar resolution (candle timeframe).
Slice object represents market data at a moment in time, a “time-slice”, which may be a single tick event, or may be a trade bar for your algorithm’s primary bar resolution.
Private Beta and Beyond
[minerva info] When MachinaTrader implements websockets – beyond Backtesting – tick events will be emitted as soon as they arrive at the Machina Engine. At that time, the
OnData() event handler will become useful for processing real-time tick events.
Meanwhile, for Backtesting
OnTradeBar() is the most suitable method because backtests only process historic trade bars, and have no concept of tick events.
No matter which event handler you use, your algorithm will receive data in chronological order according to simulated algorithm time. By only letting your algorithm see the present and past moments, we can prevent the most common quantitative-analysis error, look-ahead bias.
Batch vs Stream Analysis
Backtesting platforms come in two general varieties: “batch processing” or “event streaming”.
Batch processing a backtest is simpler, from a coding perspective. All market data is loaded into an array and passed to your algorithm for analysis. Because your algorithm has access, at any moment, to both past and future data points, it is easy to introduce look-ahead bias. Most beginner analysis tools are batch systems.
Machina Engine is a streaming analysis system. In live trading, data points are generated chronologically. MachinaTrader models this time-stream in backtesting by incrementally revealing trade bars to your algorithm.
For example, the Engine presents your algorithm with a series of 15-minute bars – one after the other – for processing, indicator updates, trade decision-making, and chart drawing. Of course, you do not have to wait 15-minutes between trade bars because your algorithm is presented with a new bar as soon as it finishes processing the current bar.
Because of this, you do not have access to price data beyond the Time Frontier. Although streaming analysis is slightly trickier to understand, it allows your algorithm to seamlessly work in backtests and live algorithmic trading with no code changes.
Algorithm Time and Time Zone
Recall the discussion of the Time Frontier, earlier:
Timeproperty in your algorithm is always equal to this Time Frontier. This Time Frontier is also used as the timestamp for any logging and debugging messages.
Algorithm time is always the
EndTime of the current
Slice being processed, and is converted to UTC for all exchanges and markets.
This algorithm time is accessed from the
Time property of MEAlgorithm.
// Time of bar being processed Time;
// UTC Conversion of Algorithm Time UtcTime;