From a031216eccf881099b3dfc3fed324e30ba3290fc Mon Sep 17 00:00:00 2001 From: Kavinkumar <33546454+mkavinkumar1@users.noreply.github.com> Date: Wed, 2 Mar 2022 13:05:00 +0530 Subject: [PATCH] updated backtesting --- freqtrade/freqtradebot.py | 2 +- freqtrade/optimize/backtesting.py | 80 ++++++++++++++++++++----------- freqtrade/persistence/models.py | 13 ++--- 3 files changed, 59 insertions(+), 36 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index c125cb85d..810c5d5fa 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -492,7 +492,7 @@ class FreqtradeBot(LoggingMixin): logger.info('Remaining amount would be too small') return if amount > trade.amount: - logger.info("Amount is higher than available.") + logger.info(f"Amount is higher than available. {amount} > {trade.amount}") return self.execute_trade_exit(trade, current_rate, sell_reason=SellCheckTuple( sell_type=SellType.CUSTOM_SELL), sub_trade_amt=amount) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index eca643732..051cba05a 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -383,13 +383,13 @@ class Backtesting: def _get_adjust_trade_entry_for_candle(self, trade: LocalTrade, row: Tuple ) -> LocalTrade: - - current_profit = trade.calc_profit_ratio(row[OPEN_IDX]) - min_stake = self.exchange.get_min_pair_stake_amount(trade.pair, row[OPEN_IDX], -0.1) + current_rate = row[OPEN_IDX] + current_profit = trade.calc_profit_ratio(current_rate) + min_stake = self.exchange.get_min_pair_stake_amount(trade.pair, current_rate, -0.1) max_stake = self.wallets.get_available_stake_amount() stake_amount = strategy_safe_wrapper(self.strategy.adjust_trade_position, default_retval=None)( - trade=trade, current_time=row[DATE_IDX].to_pydatetime(), current_rate=row[OPEN_IDX], + trade=trade, current_time=row[DATE_IDX].to_pydatetime(), current_rate=current_rate, current_profit=current_profit, min_stake=min_stake, max_stake=max_stake) # Check if we should increase our position @@ -398,6 +398,16 @@ class Backtesting: if pos_trade is not None: self.wallets.update() return pos_trade + if stake_amount is not None and stake_amount < 0.0: + amount = -stake_amount / current_rate + logger.info("partial_sell_bt") + if amount > trade.amount: + logger.info(f"Amount is higher than available. {amount} > {trade.amount}") + return trade + pos_trade = self._exit_trade(trade, row, current_rate, amount) + if pos_trade is not None: + self.wallets.update() + return pos_trade return trade @@ -416,7 +426,6 @@ class Backtesting: check_adjust_buy = (count_of_buys <= self.strategy.max_entry_position_adjustment) if check_adjust_buy: trade = self._get_adjust_trade_entry_for_candle(trade, sell_row) - sell_candle_time = sell_row[DATE_IDX].to_pydatetime() sell = self.strategy.should_sell(trade, sell_row[OPEN_IDX], # type: ignore sell_candle_time, sell_row[BUY_IDX], @@ -467,31 +476,44 @@ class Backtesting: ): trade.sell_reason = sell_row[EXIT_TAG_IDX] - self.order_id_counter += 1 - order = Order( - id=self.order_id_counter, - ft_trade_id=trade.id, - order_date=sell_candle_time, - order_update_date=sell_candle_time, - ft_is_open=True, - ft_pair=trade.pair, - order_id=str(self.order_id_counter), - symbol=trade.pair, - ft_order_side="sell", - side="sell", - order_type=order_type, - status="open", - price=closerate, - average=closerate, - amount=trade.amount, - filled=0, - remaining=trade.amount, - cost=trade.amount * closerate, - ) - trade.orders.append(order) - return trade + return self._exit_trade(trade, sell_row, closerate) - return None + def _exit_trade(self, trade: LocalTrade,sell_row: Tuple, + closerate: float, amount: float = None) -> Optional[LocalTrade]: + self.order_id_counter += 1 + if amount: + a = trade.select_filled_orders('buy')[-1].safe_filled + logger.info(f'{closerate}, {amount}, {a}, selling'+'\n'*3) + + else: + logger.info(f'{closerate}, {amount}, {trade.open_rate}, selling'+'\n'*3) + sell_candle_time = sell_row[DATE_IDX].to_pydatetime() + order_type = self.strategy.order_types['sell'] + order = Order( + id=self.order_id_counter, + ft_trade_id=trade.id, + order_date=sell_candle_time, + order_update_date=sell_candle_time, + ft_is_open=True, + ft_pair=trade.pair, + order_id=str(self.order_id_counter), + symbol=trade.pair, + ft_order_side="sell", + side="sell", + order_type=order_type, + status="open", + price=closerate, + average=closerate, + amount=amount or trade.amount, + filled=0, + remaining=trade.amount, + cost=trade.amount * closerate, + ) + trade.orders.append(order) + if amount: + trade.process_sell_sub_trade(order, is_non_bt = False) + trade.recalc_trade_from_orders() + return trade def _get_sell_trade_entry(self, trade: LocalTrade, sell_row: Tuple) -> Optional[LocalTrade]: if self.timeframe_detail and trade.pair in self.detail_data: diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index d8de94fc9..e24350aa4 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -516,26 +516,26 @@ class LocalTrade(): raise ValueError(f'Unknown order type: {order.order_type}') Trade.commit() - def process_sell_sub_trade(self, order: Order, is_closed: bool = True) -> None: + def process_sell_sub_trade(self, order: Order, is_closed: bool = True, is_non_bt: bool = True) -> None: orders = (self.select_filled_orders('buy')) if len(orders) < 1: # Todo /test_freqtradebot.py::test_execute_trade_exit_market_order self.close(order.safe_price) - Trade.commit() + if is_non_bt: Trade.commit() logger.info("*:"*500) return logger.info('debug') for o in orders:logger.info(o.to_json()) logger.info(order.to_json()) - sell_amount = order.filled if is_closed else order.amount + sell_amount = order.safe_filled sell_rate = order.safe_price sell_stake_amount = sell_rate * sell_amount * (1 - self.fee_close) if is_closed: if sell_amount >= self.amount: # Todo tests/rpc/test_rpc.py::test_rpc_trade_statistics self.close(sell_rate) - Trade.commit() + if is_non_bt: Trade.commit() return profit = 0.0 idx = -1 @@ -559,12 +559,12 @@ class LocalTrade(): b_order2.average = (b_order2.average * amount2 - profit) / amount2 b_order2.order_update_date = datetime.now(timezone.utc) self.update_order(b_order2) - Order.query.session.commit() + if is_non_bt: Order.query.session.commit() self.recalc_trade_from_orders() self.close_profit_abs = profit self.close_profit = sell_stake_amount / (sell_stake_amount - profit) - 1 - Trade.commit() + if is_non_bt: Trade.commit() def calc_profit2(self, open_rate: float, close_rate: float, amount: float) -> float: @@ -706,6 +706,7 @@ class LocalTrade(): def recalc_trade_from_orders(self): if len(self.select_filled_orders('buy')) < 2: # Just in case, still recalc open trade value + # needs to remove self.recalc_open_trade_value() return total_amount = 0.0