Introduction
What is it?
Section titled “What is it?”The Backtester is a suite of tools designed for rapid prototyping and testing of systematic trading strategies. It can run simple event studies to quantify market “edges” all the way to full blown multi-currency, multi-timeframe, multi-strategy portfolio simulations.
Why might you consider using the Backtester when there are plenty of alternatives? With the Backtester, you aren’t locked into a proprietary scripting language. It is written in C#, one of the most widely used and popular general-purpose programming languages available. It is data agnostic—you aren’t locked into a proprietary data feed. You aren’t limited to testing a single market at a time through a visual interface. As an experienced trader said to me many years ago, “To make money in the markets you have to think outside the box. And if you are using ____, you are stuck in their box.”
Many commerical platforms promise low or no-code system design; however, that same initial ease of use will inevitably become a roadblock as you progress. The backtester is more of a general purpose toolbox. It can not only help reseach questions about markets but can also underpin the types of programs required to run a systematic investment process day-in and day-out. If you are already familiar with .NET and C#, you will be productive almost immediately. For those who aren’t, the rise of AI coding assistants have made the learning curve less steep.
Design philosophy
Section titled “Design philosophy”Many backtesters, particularly those written in R or Python, are often vector-based. For example, you might have an array containing a discrete signal (e.g. +1, 0, -1 for long, flat or short respectively) or a continuous variable (a z-score for example). This array can then be multiplied against market returns to calculate trading strategy performance. While vector-based simulations run extremely fast, they rely on simplying assumptions that may not be appropriate for all use cases.
Another common architecture is event driven. Here you write code that responds to events like the market opening, a trade being printed, or the completion of a bar. An event driven approach mimics the real world and is particularly useful for real-time trading; however, it can sometimes be tedious for research where you typically want to iterate as fast as possible without worrying about how you might actually deploy a model in production. An event driven backtester typically requires data to be added at the completion of each new interval (e.g. the close of each new bar) and then indicators are recalculated. A vector-based backtester on the other hand can calculate an indicator across the full dataset in a single call.
The Backtester employs a hybrid approach. Indicators are calculated in advance at the start of the simulation. Then the backtester steps through the data by date, calling various events. This approach allows for simplicity, while at the same time allowing you to respond to events like you would in real-time (e.g. opening or closing a position). The Backtester is also designed to hide as much complexity as possible to speed strategy development while still allowing the user access to low-level classes and functionality for fine-grained control if and when needed.
So what does a strategy look like in practice?
A simple moving average strategy
Section titled “A simple moving average strategy”class SimpleSma : Strategy{ protected override void OnStrategyStart() { Col1 = Sma(Close, 50); Col2 = Sma(Close, 200); }
protected override void OnBarClose() { if (Col1.Last > Col2.Last) { Buy(); } else { Sell(); } }}After a cursory glance at this code, even if you are not a C# expert, you can probably guess this is a long-only simple moving average strategy. The Strategy class abstracts away a lot of the complexity so you can focus on trading logic without having to worry about indicator calculations, lining up dates, or keeping track of entries and exits. This strategy can be applied to a portfolio of a hundred markets as easily as it can one.