When you create a C# Coded Model in Quantacula, you're creating a new .NET class derived from the UserModelBase base class. Here we'll delve into how Quantacula interacts with your model during the backtesting process. The diagram below breaks down the backtesting process into two domains, the Backtester and your UserModelBase. The boxes in UserModelBase below represent the five virtual methods you can override in your model's code to hook into the different stages of the backtesting process.
The Quantacula backtester begins the process by calling the BeginBacktest method in your model. This method is optional, but if you did provide an implementation, you should note that it will only be called once, for the first symbol in your backtest universe. This method provides you a place to initialize static variables or perform other operations that you need to undertake one time before the backtest begins.
After calling BeginBacktest, Quantacula calls the Initialize method in your model, once for every symbol in the backtest universe. As described in the Quantacula help, this is where you should create the instances of any indicators or other objects you declared in your model. By this point you might begin to realize, Quantacula creates a new instance of your model's class for every symbol in the backtest.
Quantacula then creates a synchronization object that is responsible for keeping the historical data in the backtest universe aligned during the bar by bar processing. For each bar of historical data, the synchronizer collects a list of symbols (participants) that have data for the bar currently being processed.
The per-bar processing begins by performing a market open processing. This executes any simulated orders that were placed on the previous bar and updating the equity and cash levels.
After processing the market open, the backtester iterates through this bar's participating symbols, and calls the Execute method in your model for each one of them. It is within your implementation of the Execute method that simulated trades are placed, via calls to the PlaceTrade method.
After executing your model for each participant, the backtester perform a market close processing. This checks to see if symbols are dropped out of dynamic universes, such as the Wealth-Data Dow 30 or Nasdaq 100, and if so, it closes any open positions in those symbols at market close. The market close processing also updates the equity curve to reflect the current values of open positions.
The backtester continues the bar-by-bar processing until there is no more historical data left to process. After this stage, it calls the Cleanup method in your model, for each of the symbols in the backtest universe.
Finally, Quantacula calls the BacktestComplete method. If you override this method, note that it will be called only on the last symbol in the backtest universe. Here you can process any summary information you might have collected during the backtest process.
In a future post we'll see how these pieces come together and implement a model that collects performance statistics on an indicator, over all the symbols in the backtest universe.