Assuming that prices move within three steps:
Green candle: open -> low -> high -> close
Red candle: open -> high -> low -> close
Orders are now filled in correct order as the limit/stop price is reached while traversing this path, and only the remaining path is considered if an order triggers or cancels other orders.
Here's how the result of the backtest smoke test changed because of this one trade, where the exit candle visits both stop loss and take profit prices:
Before (left): stop loss hit was always checked before take profit within a candle, so the trade was a loss
After (right): based on the candle direction (downwards), it's most likely that the price visited the upper wick first before going down, so the take profit is hit before the stop loss and the trade is profitable
Here's another example of how the order execution used to work:
This trade was entered with a market buy order on candle open, and stop loss and take profit were equally far from the entry point. On the same candle where the entry took place, the logic used to be that if it's a green candle, only prices above the entry are checked for exit hits (and vice versa for red candles). So this trade was profitable. Now we check the remaining path the price takes after the entry (according to the three steps described above) in order. Since it's a green candle, the bottom tail is expected to be covered first, and stop loss to be hit before the take profit, turning the trade to a loss.
These changes make it also easier if we at some point want to add a more generic low-level API layer, that simply processes any orders the strategy function provides, without the constraints of single position/entrypoint/exitpoint per asset managed with entryOrder, stopLoss and takeProfit.
Making backtest order execution more realistic.
Assuming that prices move within three steps: Green candle: open -> low -> high -> close Red candle: open -> high -> low -> close
Orders are now filled in correct order as the limit/stop price is reached while traversing this path, and only the remaining path is considered if an order triggers or cancels other orders.
Here's how the result of the backtest smoke test changed because of this one trade, where the exit candle visits both stop loss and take profit prices:
Here's another example of how the order execution used to work: This trade was entered with a market buy order on candle open, and stop loss and take profit were equally far from the entry point. On the same candle where the entry took place, the logic used to be that if it's a green candle, only prices above the entry are checked for exit hits (and vice versa for red candles). So this trade was profitable. Now we check the remaining path the price takes after the entry (according to the three steps described above) in order. Since it's a green candle, the bottom tail is expected to be covered first, and stop loss to be hit before the take profit, turning the trade to a loss.
These changes make it also easier if we at some point want to add a more generic low-level API layer, that simply processes any orders the strategy function provides, without the constraints of single position/entrypoint/exitpoint per asset managed with
entryOrder
,stopLoss
andtakeProfit
.