TuringTrader 16 and the v2 Engine
TuringTrader 16 is our biggest release, yet. It's been almost two years, since our honest review of what we achieved with the v1 engine. Since then, we released TuringTrader.js, with which we tested some of the key elements of the new v2 engine.
First, you might notice the new version number. While the previous version was 0.15, we boldly call this one 16. TuringTrader has been in production use since early 2019. That's more than four years, and we are fairly sure that the quality of the product will not change significantly in the coming years. The new version number reflects that, indicating that we proudly consider this a full release.
With the v2 engine, we are clearly focussing on the features needed to run our own businesses, namely TuringTrader.com and Bertram Solutions. And while we believe that many traders out there have the exact same needs as we do, we anticipate that the v2 engien is not for everyone.
TuringTrader's v2 engine is a great choice for you, if you:
- research multi-asset strategies
- develop meta-strategies
- think in terms of asset allocation
- work on end-of-day data
At the same time, we abandoned some use cases with the v2 engine:
- option support
- streaming architecture
- support for intraday trading
All of these features are still available in the v1 engine, which is still included in the distribution. We have a large codebase of algorithms running on the v1 engine, so there are no plans to abandon that engine any time soon. In fact, we added features to make sure that v1 and v2 code can be mixed. For example, you can instantiate v1 algorithms as childs of a v2 strategy.
The new engine brings a few challenges. This is especially true for the showcases and the documentation. It will take us a little while to bring this all to new order. But it will happen in due time. Promised.
The v2 engine brings a few notable new features. All of these concepts are based on our learnings from implementing several hundred strategies on the v1 engine.
Trading Calendar and Timezone
The trading calendar is a central part of the v2 engine. This calendar defines the engine's rhythm by specifyign the opening days for the exchange you are trading at. We include the calendar for the US stock exchanges, but it is possible to define your own for other markets.
When the v2 engine loads data, it aligns them to the trading calendar. This is incredibly useful, especially when bringing in data from sources that don't follow the exchange's schedule. Without this feature, it is hard to bring in macro-economic data from FRED, or backfilling asset quotes with global indices.
Related to this feature is a shift in paradigm. While the v1 engine assumed to run on the exchange's time zone, the v2 engine has everything running in your local time zone. The trading calendar makes sure that timestamps are converted properly between the two.
Block-Based Processing and Multi-Threading
The next essential change is the way the engine processes data. The v1 engine was built around a streaming architecture, where each new bar would be trickle through the assets, indicators, and strategy logic. In contrast, the v2 engine runs everything block-based, calculating indicators all at once for the whole simulation period.
The major advantage of doing so, is that indicators are now calculated on separate tasks, allowing for multi-threading of indicator-heavy strategies. Further, this new paradigm greatly simplifies the rules to follow when using 'automagic' indicators. There is no need to triple-check that indicators are called exactly once on each bar. And finally, this opens the door to mixing and matching bar periods. With the v2 engine, we can simply sub-sample time series to create weekly, or monthly bars, and seemlessly integrate these slower series with daily bars.
Allocation-Based Trading Paradigm
This is another big one. With the v2 engine, we focus on asset allocations, not shares. In other words, we specify the target allocation, and let the engine figure out if shares need to be bought or sold to reach that allocation. In contrast to this, the v1 engine is centered buying and selling shares. This change was motivated by our finding that pretty much all of our algorithms started with an asset allocation, and that we kept writing the same boilerplate code to convert the target allocation to shares bought or sold.
Along with this shift in paradigm come two more important changes. For once, the v2 engine assumes fractional shares throughout. This makes it significantly easier to backtest over long periods, especially when using inverse or leveraged assets. Further, the v2 engine determines the number of shares to buy or sell at the time of filling the order, while the v1 engine calculated the shares to trade at the time of submitting the order. This helps improve the simulation accuracy, especially in conjunction with leveraged assets.
However, this new paradigm requires one more step to perform live trading: mapping the fractional asset allocation back to an (integer) number of shares held in the investor's account.
When we first implemented algorithms as data sources in summer 2019, we imagined this feature as a way to bring in synthetical data models. Since then, our view has changed significantly, as witnessed by our post just a year later. And by now, we can't live without this feature and pretty much every strategy that we develop uses it. All because it is incredibly useful for conquering complexity.
The typical use case for us is to combine multiple simple models, e.g., a high-powered stock-trading strategy and a managed bond strategy, into a more complex portfolio. This component-based approach makes it easier to tackle complexity, promotes code-reuse and avoids redundancy, and overall increases development productivity.
With the v2 engine, it really makes no difference, if your strategy uses BIL as its risk-off asset, or a managed bond strategy that you have developed separately. Your strategy will continue to trade the sub-strategy as a single asset. But the strategy reports will unravel the trades from any sub-strategies and show the tradeable assets instead.
But these are all just words. What ultimately matters is how coding a strategy looks like. By now, we have ported about 30 strategies to the new engine. And in our experience, coding for the v2 engine is significantly easier and more concise. Here is an example comparing the exact same strategy coded for both engines:
What stands out is that the code for v2 has much better locality, mostly because of the relaxed rules on indicators. Further, the money-management code is mush cleaner, driven by v2's allocation-based paradigm.
We believe TuringTrader 16 is a big step forward, and that the v2 engine will make it easier for any quant to develop and test meaningful strategies.
Stay tuned and happy coding!