From 71147d2899203557bec230dfd06085140b30cac0 Mon Sep 17 00:00:00 2001 From: Reigo Reinmets Date: Sat, 11 Dec 2021 18:25:05 +0200 Subject: [PATCH] Attempt to support limit orders for position adjustment. --- freqtrade/freqtradebot.py | 35 ++++++++++++++++++++++++++++----- freqtrade/persistence/models.py | 8 ++++++-- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index b29eca7f3..dce708711 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -469,15 +469,14 @@ class FreqtradeBot(LoggingMixin): def adjust_trade_position(self, trade: Trade): """ Check the implemented trading strategy for adjustment command. - If the strategy triggers the adjustment a new buy/sell-order gets issued. + If the strategy triggers the adjustment, a new order gets issued. Once that completes, the existing trade is modified to match new data. """ - logger.debug(f"adjust_trade_position for pair {trade.pair}") for order in trade.orders: if order.ft_is_open: - logger.debug(f"Order {order} is still open, skipping pair.") return + logger.debug(f"adjust_trade_position for pair {trade.pair}") sell_rate = self.exchange.get_rate(trade.pair, refresh=True, side="sell") current_profit = trade.calc_profit_ratio(sell_rate) stake_to_adjust = strategy_safe_wrapper(self.strategy.adjust_trade_position, default_retval=None)( @@ -491,6 +490,7 @@ class FreqtradeBot(LoggingMixin): if stake_to_adjust != None and stake_to_adjust < 0.0: # We should decrease our position # TODO: Selling part of the trade not implemented yet. + logger.error(f"Unable to decrease trade position / sell partially for pair {trade.pair}, feature not implemented.") return return @@ -528,7 +528,7 @@ class FreqtradeBot(LoggingMixin): logger.debug(f'Executing additional order: amount={amount}, stake={stake_amount}, price={enter_limit_requested}') - order_type = 'market' + order_type = self.strategy.order_types['buy'] order = self.exchange.create_order(pair=pair, ordertype=order_type, side="buy", amount=amount, rate=enter_limit_requested, time_in_force=time_in_force) @@ -573,7 +573,7 @@ class FreqtradeBot(LoggingMixin): # Updating wallets self.wallets.update() - self._notify_enter(trade, order_type) + self._notify_additional_buy(trade, order_obj, order_type) return True @@ -729,6 +729,31 @@ class FreqtradeBot(LoggingMixin): return True + def _notify_additional_buy(self, trade: Trade, order: Order, order_type: Optional[str] = None, + fill: bool = False) -> None: + """ + Sends rpc notification when a buy occurred. + """ + msg = { + 'trade_id': trade.id, + 'type': RPCMessageType.BUY_FILL if fill else RPCMessageType.BUY, + 'buy_tag': "adjust_trade_position", + 'exchange': self.exchange.name.capitalize(), + 'pair': trade.pair, + 'limit': order.price, # Deprecated (?) + 'open_rate': order.price, + 'order_type': order_type, + 'stake_amount': order.cost, + 'stake_currency': self.config['stake_currency'], + 'fiat_currency': self.config.get('fiat_display_currency', None), + 'amount': order.amount, + 'open_date': order.order_filled_date or datetime.utcnow(), + 'current_rate': order.price, + } + + # Send the message + self.rpc.send_msg(msg) + def _notify_enter(self, trade: Trade, order_type: Optional[str] = None, fill: bool = False) -> None: """ diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index 4135ed479..af8a4742f 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -568,8 +568,13 @@ class LocalTrade(): profit_ratio = (close_trade_value / self.open_trade_value) - 1 return float(f"{profit_ratio:.8f}") - def recalc_trade_from_orders(self): + # We need at least 2 orders for averaging amounts and rates. + if len(self.orders) < 2: + # Just in case, still recalc open trade value + self.recalc_open_trade_value() + return + total_amount = 0.0 total_stake = 0.0 for temp_order in self.orders: @@ -590,7 +595,6 @@ class LocalTrade(): if self.stop_loss_pct is not None and self.open_rate is not None: self.adjust_stop_loss(self.open_rate, self.stop_loss_pct) - def select_order(self, order_side: str, is_open: Optional[bool]) -> Optional[Order]: """ Finds latest order for this orderside and status