4.6.9 Advanced. How The Strategy Backtesting Engine works
At historic calculation, the Backtesting Engine calculates every bar of the chart in order, it opens, emulates real-time within the bar and closes the bar. At the bar close the Backtesting Engine calculates all the strategy signals. The strategy calculation results in the collection of orders generated by the signals during the next calculation. MarketThisBar orders are also executed here at the bar close.
Then, the new bar opens, Backtesting Engine fills MarketNextBar orders using Open of the bar, and after that, upon every tick within the bar it fills price and algorithm orders. Then, Backtesting Engine closes the bar, calculates the signals and the whole process repeats once again. In Open Next Bar mode all the signals are calculated at the bar open in the context of the closed bar. In IOG mode the strategy calculates signals without IOG attribute, as usual, and signals with IOG – at every tick within the bar and every tick in real-time.
Orders, generated by the signals without IOG, are active from open to close of the bar. Orders generated in IOG mode - are active from the signal calculation to the signal calculation.
If at least one strategy signal applies to other chart symbols, then the strategy signal calculation is executed as usual more often, then it can be suggested. It is connected with the bars that are at different price data series can be closed at different time. Also, in real-time, bars at different price data series can come with different frequency that is why the strategy signals calculation is executed at every bar close at any used calculation data series. With IOG enabled, the calculation is executed on every tick of any used data series. But not all these calculations result in actual sending of the orders for execution in Backtesting Engine when IOG is disabled. Order sending is executed only after the Open tick of the main data series comes. And the last calculation before the orders sending at Open is considered valid.
In Backtest mode several orders can be filled on the same tick in order of priority.
Order priority, depending on the current position, can be shown in the following priority table:
If the priority of the two orders is the same, then the preference will be given to the one that was generated first by the strategy. Signal calculation priority in a strategy is determined by their order in Format Objects dialog window under the Signals tab.
Signal calculation order can be changed by clicking Move Up and Move Down buttons.
A number of simple rules are used for the orders execution. The rules are built in the Backtesting Engine:
- Time in force of the entry order ends right after its execution and cannot be executed again until its next generation by the signal.
- Reverse order always closes the previous position and opens the new one per a specified or automatically calculated number of contracts.
- Time in force of the exit order continues after its execution* (it can be executed again, for another entry, even if it was already executed). One and the same exit can be applied to one and the same entry only once*, otherwise, partial entry execution will not be possible.
(*) – exit mode for the signal can be changed using the attribute [ExitFromOneEntryOnce(ExitFromOneEntryOnce.FillAndKillExitOrder)]. In this mode time in force of the exit ends right after the execution, but can be applied to the same entry several times. This mode for the exits can be useful for the close in parts position strategy simplification without applying a big number of exit orders.
- By default, the Backtesting Engine forbids repeated entry of the position, but in the Strategy Properties dialog window repeated entry can be allowed in one of the two pyramiding modes by selecting Allow up to XXX entry orders in the same.
- Different orders are allowed to repeatedly enter only when the order is generated by a different entry order.
- Regardless of the entry that generated the order positions increasing is allowed by one and the same order, repeatedly.
- The number of contracts in the open position cannot exceed the Maximum shares/contracts per position settings. If the next executed entry exceeds this limit, the Backtesting Engine will automatically cut the quantity of contracts to the level specified in the strategy settings. For example, we have an open position for 60, 000 contracts. One more entry for 10, 000 contracts is executed. The Backtesting Engine will cut the number of contracts of this order to 5, 000 and the limit condition will be executed. The following entries to the same position cannot be executed until at least one exit is executed even though the pyramiding limit is not been reached.
The Backtesting Engine also calculates the number of contracts for the orders if it was not specified at the generation of the order in the Send() method.
Calculation of contracts for the entry
The calculation of the number of contracts for the entries, by default, is executed according to the strategy settings (Strategy Properties dialog window, at Properties tab, Trade size sector). Contracts calculation for the entry can be executed upon one of the two algorithms:
- Fixed Share/Contracts – fixed number of entry contracts is set.
- Dollars per Trade XXX round down to nearest YYY shares/contracts. Minimum number shares/contracts ZZZ (enter at$ XXX with lots of YYY contracts. The minimum pack is ZZZ of contracts).
For example: enter at $1000 with lots of 10 shares, but the minimum is 20 shares. As the calculation price of the contracts number, the maximum price from the last known received price that satisfies the order is used (in general Close case, or for IOG – the last tick, at which the calculation was executed) and the order price (if it is a price order). For a StopLimit order, the Limit price is used for the calculation.
For entries where there is a limit for the position in the strategy setting: Maximum shares/contracts per position, if the next entry at its execution exceeds the specified limit of contracts per position, the number of contracts for this entry will be cut to the limit, when the limit is satisfied. For example: the limit is 65,000 contracts per position. The position for 60,000 contracts is opened already and the strategy tries to execute an entry for 10,000 more contracts. In this case, the strategy will automatically cut the number of contracts for this entry to 5,000.
A reverse order is the entry of the opposite position to the opened one. The number of contracts specified for the entry, in this case, contracts for the current position close are added.
Calculation of contracts for the exits
If the number of contracts is not specified for the order, in OrderExit.FromEntry, then by default the exit always contains the number of contracts necessary for the position to close or enter. If the specified number of contracts to enter is larger than is necessary for the position to close or open, the number of contracts will be cut to the required level.
- Exits by default have OrderExit.FromAll type. In this case, the order should fill each entry at the specified number of contracts. It works as following:
- buy1 5 contracts
- buy2 1 contract
- buy3 2 contracts
The script sends the exit Sell FromAll for 2 contracts. The final order will be: Sell 5 contracts:
- 2 contracts from buy1
- 1 contract from buy2 (this entry is always open at 1 contract and it is not possible to exit from it at 2 contracts)
- 2 contracts from buy3
After the exit execution only one entry remains open, Buy1 at 3 contracts. Other entries will be closed by that exit.
- If the classic exit calculation mode is enabled, it will not be possible to close Buy1 with this order because it was already applied to this entry. Therefore, another exit order should be used to close this entry or to enable exit calculation mode, ExitFromOneEntryOnce.FillAndKillExitOrder, then on the next bar that entry can be completely closed with the same order.
- OrderExit.Total. closes the entries in order, starting from the first one to the last one, until the specified number of contracts for the exit is executed or there will be no exit at all. It works as following:
There are three entries:
- Buy1 2 contracts
- Buy2 1 contracts
- Buy3 5 contracts
The script sends Sell Total order at 5 contracts. The final order will be Sell at 5 contracts:
- 2 contracts from buy1 and it will close completely with 3 contracts remaining.
- 1 contract from buy2 and it closes completely with 2 contracts remaining.
- 2 contracts from buy3 but it still remain open at 3 contracts as all 5 exit contracts were executed.
After its execution, buy3 at 3 contracts will remain open.
- OrderExit.FromEntry. The particular entry order at the specified number of contracts is closed or cut down to the remaining number of contracts.
- Special exit types: In PerPosition mode, one exit is sent with the number of contracts equal to the number of opened contracts per position.
In PerContracts mode the same number of exits is sent as the number of open entries in the position at the number of contracts which equal the number of not closed entry contracts.