Initial idea backtesting order timeout
This commit is contained in:
parent
6ed237a72a
commit
c12e5a3b6c
@ -380,6 +380,10 @@ class Backtesting:
|
|||||||
|
|
||||||
return trade
|
return trade
|
||||||
|
|
||||||
|
def _get_order_filled(self, rate: float, row: Tuple) -> bool:
|
||||||
|
""" Rate is within candle, therefore filled"""
|
||||||
|
return row[LOW_IDX] < rate < row[HIGH_IDX]
|
||||||
|
|
||||||
def _get_sell_trade_entry_for_candle(self, trade: LocalTrade,
|
def _get_sell_trade_entry_for_candle(self, trade: LocalTrade,
|
||||||
sell_row: Tuple) -> Optional[LocalTrade]:
|
sell_row: Tuple) -> Optional[LocalTrade]:
|
||||||
|
|
||||||
@ -405,6 +409,7 @@ class Backtesting:
|
|||||||
closerate = self._get_close_rate(sell_row, trade, sell, trade_dur)
|
closerate = self._get_close_rate(sell_row, trade, sell, trade_dur)
|
||||||
# call the custom exit price,with default value as previous closerate
|
# call the custom exit price,with default value as previous closerate
|
||||||
current_profit = trade.calc_profit_ratio(closerate)
|
current_profit = trade.calc_profit_ratio(closerate)
|
||||||
|
order_closed = True
|
||||||
if sell.sell_type in (SellType.SELL_SIGNAL, SellType.CUSTOM_SELL):
|
if sell.sell_type in (SellType.SELL_SIGNAL, SellType.CUSTOM_SELL):
|
||||||
# Custom exit pricing only for sell-signals
|
# Custom exit pricing only for sell-signals
|
||||||
closerate = strategy_safe_wrapper(self.strategy.custom_exit_price,
|
closerate = strategy_safe_wrapper(self.strategy.custom_exit_price,
|
||||||
@ -412,8 +417,7 @@ class Backtesting:
|
|||||||
pair=trade.pair, trade=trade,
|
pair=trade.pair, trade=trade,
|
||||||
current_time=sell_row[DATE_IDX],
|
current_time=sell_row[DATE_IDX],
|
||||||
proposed_rate=closerate, current_profit=current_profit)
|
proposed_rate=closerate, current_profit=current_profit)
|
||||||
# Use the maximum between close_rate and low as we cannot sell outside of a candle.
|
order_closed = self._get_order_filled(closerate, sell_row)
|
||||||
closerate = min(max(closerate, sell_row[LOW_IDX]), sell_row[HIGH_IDX])
|
|
||||||
|
|
||||||
# Confirm trade exit:
|
# Confirm trade exit:
|
||||||
time_in_force = self.strategy.order_time_in_force['sell']
|
time_in_force = self.strategy.order_time_in_force['sell']
|
||||||
@ -437,6 +441,21 @@ class Backtesting:
|
|||||||
trade.sell_reason = sell_row[EXIT_TAG_IDX]
|
trade.sell_reason = sell_row[EXIT_TAG_IDX]
|
||||||
|
|
||||||
trade.close(closerate, show_msg=False)
|
trade.close(closerate, show_msg=False)
|
||||||
|
order = Order(
|
||||||
|
ft_is_open=order_closed,
|
||||||
|
ft_pair=trade.pair,
|
||||||
|
symbol=trade.pair,
|
||||||
|
ft_order_side="buy",
|
||||||
|
side="buy",
|
||||||
|
order_type="market",
|
||||||
|
status="closed",
|
||||||
|
price=closerate,
|
||||||
|
average=closerate,
|
||||||
|
amount=trade.amount,
|
||||||
|
filled=trade.amount,
|
||||||
|
cost=trade.amount * closerate
|
||||||
|
)
|
||||||
|
trade.orders.append(order)
|
||||||
return trade
|
return trade
|
||||||
|
|
||||||
return None
|
return None
|
||||||
@ -480,9 +499,6 @@ class Backtesting:
|
|||||||
pair=pair, current_time=current_time,
|
pair=pair, current_time=current_time,
|
||||||
proposed_rate=row[OPEN_IDX], entry_tag=entry_tag) # default value is the open rate
|
proposed_rate=row[OPEN_IDX], entry_tag=entry_tag) # default value is the open rate
|
||||||
|
|
||||||
# Move rate to within the candle's low/high rate
|
|
||||||
propose_rate = min(max(propose_rate, row[LOW_IDX]), row[HIGH_IDX])
|
|
||||||
|
|
||||||
min_stake_amount = self.exchange.get_min_pair_stake_amount(pair, propose_rate, -0.05) or 0
|
min_stake_amount = self.exchange.get_min_pair_stake_amount(pair, propose_rate, -0.05) or 0
|
||||||
max_stake_amount = self.wallets.get_available_stake_amount()
|
max_stake_amount = self.wallets.get_available_stake_amount()
|
||||||
|
|
||||||
@ -534,9 +550,10 @@ class Backtesting:
|
|||||||
orders=[]
|
orders=[]
|
||||||
)
|
)
|
||||||
trade.adjust_stop_loss(trade.open_rate, self.strategy.stoploss, initial=True)
|
trade.adjust_stop_loss(trade.open_rate, self.strategy.stoploss, initial=True)
|
||||||
|
order_filled = self._get_order_filled(propose_rate, row)
|
||||||
|
|
||||||
order = Order(
|
order = Order(
|
||||||
ft_is_open=False,
|
ft_is_open=order_filled,
|
||||||
ft_pair=trade.pair,
|
ft_pair=trade.pair,
|
||||||
symbol=trade.pair,
|
symbol=trade.pair,
|
||||||
ft_order_side="buy",
|
ft_order_side="buy",
|
||||||
@ -552,6 +569,8 @@ class Backtesting:
|
|||||||
filled=amount,
|
filled=amount,
|
||||||
cost=stake_amount + trade.fee_open
|
cost=stake_amount + trade.fee_open
|
||||||
)
|
)
|
||||||
|
if not order_filled:
|
||||||
|
trade.open_order_id = 'buy'
|
||||||
trade.orders.append(order)
|
trade.orders.append(order)
|
||||||
if pos_adjust:
|
if pos_adjust:
|
||||||
trade.recalc_trade_from_orders()
|
trade.recalc_trade_from_orders()
|
||||||
@ -647,6 +666,15 @@ class Backtesting:
|
|||||||
indexes[pair] = row_index
|
indexes[pair] = row_index
|
||||||
self.dataprovider._set_dataframe_max_index(row_index)
|
self.dataprovider._set_dataframe_max_index(row_index)
|
||||||
|
|
||||||
|
# Check order filling
|
||||||
|
for open_trade in list(open_trades[pair]):
|
||||||
|
# TODO: should open orders be stored in a separate list?
|
||||||
|
if open_trade.open_order_id:
|
||||||
|
# FIXME: check order filling
|
||||||
|
# * Get open order
|
||||||
|
# * check if filled
|
||||||
|
open_trade.open_order_id = None
|
||||||
|
|
||||||
# without positionstacking, we can only have one open trade per pair.
|
# without positionstacking, we can only have one open trade per pair.
|
||||||
# max_open_trades must be respected
|
# max_open_trades must be respected
|
||||||
# don't open on the last row
|
# don't open on the last row
|
||||||
|
Loading…
Reference in New Issue
Block a user