diff --git a/docs/bot-basics.md b/docs/bot-basics.md index a44b611f3..30dc70d02 100644 --- a/docs/bot-basics.md +++ b/docs/bot-basics.md @@ -57,6 +57,8 @@ This loop will be repeated again and again until the bot is stopped. * Calculate indicators (calls `populate_indicators()` once per pair). * Calculate entry / exit signals (calls `populate_entry_trend()` and `populate_exit_trend()` once per pair). * Loops per candle simulating entry and exit points. + * Check for Order timeouts, either via the `unfilledtimeout` configuration, or via `check_entry_timeout()` / `check_exit_timeout()` strategy callbacks. + * Check for trade entry signals (`enter_long` / `enter_short` columns). * Confirm trade entry / exits (calls `confirm_trade_entry()` and `confirm_trade_exit()` if implemented in the strategy). * Call `custom_entry_price()` (if implemented in the strategy) to determine entry price (Prices are moved to be within the opening candle). * In Margin and Futures mode, `leverage()` strategy callback is called to determine the desired leverage. @@ -64,7 +66,6 @@ This loop will be repeated again and again until the bot is stopped. * Check position adjustments for open trades if enabled and call `adjust_trade_position()` to determine if an additional order is requested. * Call `custom_stoploss()` and `custom_exit()` to find custom exit points. * For exits based on exit-signal and custom-exit: Call `custom_exit_price()` to determine exit price (Prices are moved to be within the closing candle). - * Check for Order timeouts, either via the `unfilledtimeout` configuration, or via `check_entry_timeout()` / `check_exit_timeout()` strategy callbacks. * Generate backtest report output !!! Note diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 808e94bad..b63c404fc 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -938,7 +938,15 @@ class Backtesting: indexes[pair] = row_index self.dataprovider._set_dataframe_max_index(row_index) - # 1. Process buys. + for t in list(open_trades[pair]): + # 1. Cancel expired buy/sell orders. + if self.check_order_cancel(t, current_time): + # Close trade due to buy timeout expiration. + open_trade_count -= 1 + open_trades[pair].remove(t) + self.wallets.update() + + # 2. Process buys. # without positionstacking, we can only have one open trade per pair. # max_open_trades must be respected # don't open on the last row @@ -961,7 +969,7 @@ class Backtesting: open_trades[pair].append(trade) for trade in list(open_trades[pair]): - # 2. Process entry orders. + # 3. Process entry orders. order = trade.select_order(trade.enter_side, is_open=True) if order and self._get_order_filled(order.price, row): order.close_bt_order(current_time) @@ -969,11 +977,11 @@ class Backtesting: LocalTrade.add_bt_trade(trade) self.wallets.update() - # 3. Create sell orders (if any) + # 4. Create sell orders (if any) if not trade.open_order_id: self._get_sell_trade_entry(trade, row) # Place sell order if necessary - # 4. Process sell orders. + # 5. Process sell orders. order = trade.select_order(trade.exit_side, is_open=True) if order and self._get_order_filled(order.price, row): trade.open_order_id = None @@ -988,13 +996,6 @@ class Backtesting: self.wallets.update() self.run_protections(enable_protections, pair, current_time) - # 5. Cancel expired buy/sell orders. - if self.check_order_cancel(trade, current_time): - # Close trade due to buy timeout expiration. - open_trade_count -= 1 - open_trades[pair].remove(trade) - self.wallets.update() - # Move time one configured time_interval ahead. self.progress.increment() current_time += timedelta(minutes=self.timeframe_min)