From 1de5c0412cbb98b7fddd88412492a4770bde0d4e Mon Sep 17 00:00:00 2001 From: Kavinkumar <33546454+mkavinkumar1@users.noreply.github.com> Date: Wed, 16 Feb 2022 18:45:38 +0530 Subject: [PATCH 01/17] draft for partial sell --- freqtrade/freqtradebot.py | 20 ++++++++++++-------- freqtrade/persistence/models.py | 15 ++++++++++++++- freqtrade/rpc/telegram.py | 30 +++++++++++++++++++++++++++--- 3 files changed, 53 insertions(+), 12 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index fce85baa3..71daf741c 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -478,9 +478,9 @@ class FreqtradeBot(LoggingMixin): if stake_amount is not None and stake_amount < 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" - f" for pair {trade.pair}, feature not implemented.") + proposed_exit_rate = self.exchange.get_rate(pair, refresh=True, side="buy") + self.execute_trade_exit(trade, proposed_exit_rate, sell_reason=SellCheckTuple( + sell_type=SellType.CUSTOM_SELL), partial=stake_amount) def _check_depth_of_market_buy(self, pair: str, conf: Dict) -> bool: """ @@ -620,7 +620,7 @@ class FreqtradeBot(LoggingMixin): # Updating wallets self.wallets.update() - self._notify_enter(trade, order, order_type) + self._notify_enter(trade, order, order_type, partial=pos_adjust) if pos_adjust: if order_status == 'closed': @@ -677,7 +677,7 @@ class FreqtradeBot(LoggingMixin): return enter_limit_requested, stake_amount def _notify_enter(self, trade: Trade, order: Dict, order_type: Optional[str] = None, - fill: bool = False) -> None: + fill: bool = False, partial: bool = False) -> None: """ Sends rpc notification when a buy occurred. """ @@ -693,7 +693,7 @@ class FreqtradeBot(LoggingMixin): 'trade_id': trade.id, 'type': RPCMessageType.BUY_FILL if fill else RPCMessageType.BUY, 'buy_tag': trade.buy_tag, - 'exchange': self.exchange.name.capitalize(), + 'exchange': trade.exchange.capitalize(), 'pair': trade.pair, 'limit': open_rate, # Deprecated (?) 'open_rate': open_rate, @@ -704,6 +704,7 @@ class FreqtradeBot(LoggingMixin): 'amount': safe_value_fallback(order, 'filled', 'amount') or trade.amount, 'open_date': trade.open_date or datetime.utcnow(), 'current_rate': current_rate, + 'partial': partial, } # Send the message @@ -1153,6 +1154,7 @@ class FreqtradeBot(LoggingMixin): *, exit_tag: Optional[str] = None, ordertype: Optional[str] = None, + partial: float = None, ) -> bool: """ Executes a trade exit for the given trade and limit @@ -1225,7 +1227,7 @@ class FreqtradeBot(LoggingMixin): self.strategy.lock_pair(trade.pair, datetime.now(timezone.utc), reason='Auto lock') - self._notify_exit(trade, order_type) + self._notify_exit(trade, order_type, partial=bool(partial)) # In case of market sell orders the order can be closed immediately if order.get('status', 'unknown') in ('closed', 'expired'): self.update_trade_state(trade, trade.open_order_id, order) @@ -1233,7 +1235,7 @@ class FreqtradeBot(LoggingMixin): return True - def _notify_exit(self, trade: Trade, order_type: str, fill: bool = False) -> None: + def _notify_exit(self, trade: Trade, order_type: str, fill: bool = False, partial: bool = False) -> None: """ Sends rpc notification when a sell occurred. """ @@ -1264,8 +1266,10 @@ class FreqtradeBot(LoggingMixin): 'sell_reason': trade.sell_reason, 'open_date': trade.open_date, 'close_date': trade.close_date or datetime.utcnow(), + 'stake_amount': trade.stake_amount, 'stake_currency': self.config['stake_currency'], 'fiat_currency': self.config.get('fiat_display_currency', None), + 'partial': partial, } if 'fiat_display_currency' in self.config: diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index 5f2db1050..61f60301f 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -476,7 +476,18 @@ class LocalTrade(): elif order_type in ('market', 'limit') and order['side'] == 'sell': if self.is_open: logger.info(f'{order_type.upper()}_SELL has been fulfilled for {self}.') - self.close(safe_value_fallback(order, 'average', 'price')) + self.open_order_id = None + if partial: + orders=(self.select_filled_orders('buy')) + lbuy=orders[-2] + lamount = (lbuy.filled or lbuy.amount) + lbuy.average=(lbuy.average * lamount - self.calc_profit2(orders[-1].rate, order.rate, order.filled or order.amount))/lamount + Order.query.session.commit() + self.orders.remove(orders[-1]) + self.recalc_trade_from_orders() + Trade.commit() + else: + self.close(safe_value_fallback(order, 'average', 'price')) elif order_type in ('stop_loss_limit', 'stop-loss', 'stop-loss-limit', 'stop'): self.stoploss_order_id = None self.close_rate_requested = self.stop_loss @@ -488,6 +499,8 @@ class LocalTrade(): raise ValueError(f'Unknown order type: {order_type}') Trade.commit() + def calc_profit2(self, open_rate: float, close_rate: float, amount: Float) ->float: + return Decimal(self.amount) *( (1-self.fee_close)* Decimal(close_rate) -(1+self.fee_open)* Decimal(open_rate) ) def close(self, rate: float, *, show_msg: bool = True) -> None: """ Sets close_rate to the given rate, calculates total profit diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 0a634ffae..fa2d2aecd 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -235,17 +235,30 @@ class Telegram(RPCHandler): if msg['type'] == RPCMessageType.BUY_FILL: message += f"*Open Rate:* `{msg['open_rate']:.8f}`\n" + total = msg['amount'] * msg['open_rate'] elif msg['type'] == RPCMessageType.BUY: message += f"*Open Rate:* `{msg['limit']:.8f}`\n"\ f"*Current Rate:* `{msg['current_rate']:.8f}`\n" - + total = msg['amount'] * msg['limit'] + if self._rpc._fiat_converter: + total_fiat = self._rpc._fiat_converter.convert_amount( + total, msg['stake_currency'], msg['fiat_currency']) + else: + total_fiat = 0 message += f"*Total:* `({round_coin_value(msg['stake_amount'], msg['stake_currency'])}" if msg.get('fiat_currency', None): - message += f", {round_coin_value(msg['stake_amount_fiat'], msg['fiat_currency'])}" + message += f", {round_coin_value(total, msg['fiat_currency'])}" - message += ")`" + message += ")`\n" + if msg['partial']: + message += f"*Balance:* `({round_coin_value(msg['stake_amount'], msg['stake_currency'])}" + + if msg.get('fiat_currency', None): + message += f", {round_coin_value(msg['stake_amount_fiat'], msg['fiat_currency'])}" + + message += ")`" return message def _format_sell_msg(self, msg: Dict[str, Any]) -> str: @@ -287,7 +300,18 @@ class Telegram(RPCHandler): elif msg['type'] == RPCMessageType.SELL_FILL: message += f"*Close Rate:* `{msg['close_rate']:.8f}`" + if self._rpc._fiat_converter: + msg['stake_amount_fiat'] = self._rpc._fiat_converter.convert_amount( + msg['stake_amount'], msg['stake_currency'], msg['fiat_currency']) + else: + msg['stake_amount_fiat'] = 0 + if msg['partial']: + message += f"*Balance:* `({round_coin_value(msg['stake_amount'], msg['stake_currency'])}" + if msg.get('fiat_currency', None): + message += f", {round_coin_value(msg['stake_amount_fiat'], msg['fiat_currency'])}" + + message += ")`" return message def compose_message(self, msg: Dict[str, Any], msg_type: RPCMessageType) -> str: From 8bc94ab37809624e8c2841b778cce809b2fbcb66 Mon Sep 17 00:00:00 2001 From: Kavinkumar <33546454+mkavinkumar1@users.noreply.github.com> Date: Fri, 18 Feb 2022 12:41:35 +0530 Subject: [PATCH 02/17] parameter fix --- freqtrade/persistence/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index 61f60301f..7cb6dff36 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -452,7 +452,7 @@ class LocalTrade(): f"Trailing stoploss saved us: " f"{float(self.stop_loss) - float(self.initial_stop_loss):.8f}.") - def update(self, order: Dict) -> None: + def update(self, order: Dict, partial:bool=False) -> None: """ Updates this entity with amount and actual open/close rates. :param order: order retrieved by exchange.fetch_order() From 6021dffb4afde541490260d1eb1a1d9b30f7630b Mon Sep 17 00:00:00 2001 From: Kavinkumar <33546454+mkavinkumar1@users.noreply.github.com> Date: Fri, 18 Feb 2022 16:06:50 +0530 Subject: [PATCH 03/17] updated unit test --- freqtrade/persistence/models.py | 4 ++-- freqtrade/rpc/telegram.py | 20 ++++++++++---------- tests/test_freqtradebot.py | 11 +++++++++++ 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index 7cb6dff36..0b701aa45 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -452,7 +452,7 @@ class LocalTrade(): f"Trailing stoploss saved us: " f"{float(self.stop_loss) - float(self.initial_stop_loss):.8f}.") - def update(self, order: Dict, partial:bool=False) -> None: + def update(self, order: Dict, sub_trade:bool=False) -> None: """ Updates this entity with amount and actual open/close rates. :param order: order retrieved by exchange.fetch_order() @@ -477,7 +477,7 @@ class LocalTrade(): if self.is_open: logger.info(f'{order_type.upper()}_SELL has been fulfilled for {self}.') self.open_order_id = None - if partial: + if sub_trade: orders=(self.select_filled_orders('buy')) lbuy=orders[-2] lamount = (lbuy.filled or lbuy.amount) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index fa2d2aecd..6c9ad083a 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -251,9 +251,9 @@ class Telegram(RPCHandler): if msg.get('fiat_currency', None): message += f", {round_coin_value(total, msg['fiat_currency'])}" - message += ")`\n" - if msg['partial']: - message += f"*Balance:* `({round_coin_value(msg['stake_amount'], msg['stake_currency'])}" + message += ")`" + if msg.get('sub_trade'): + message += f"\n*Balance:* `({round_coin_value(msg['stake_amount'], msg['stake_currency'])}" if msg.get('fiat_currency', None): message += f", {round_coin_value(msg['stake_amount_fiat'], msg['fiat_currency'])}" @@ -300,13 +300,13 @@ class Telegram(RPCHandler): elif msg['type'] == RPCMessageType.SELL_FILL: message += f"*Close Rate:* `{msg['close_rate']:.8f}`" - if self._rpc._fiat_converter: - msg['stake_amount_fiat'] = self._rpc._fiat_converter.convert_amount( - msg['stake_amount'], msg['stake_currency'], msg['fiat_currency']) - else: - msg['stake_amount_fiat'] = 0 - if msg['partial']: - message += f"*Balance:* `({round_coin_value(msg['stake_amount'], msg['stake_currency'])}" + if msg.get('sub_trade'): + if self._rpc._fiat_converter: + msg['stake_amount_fiat'] = self._rpc._fiat_converter.convert_amount( + msg['stake_amount'], msg['stake_currency'], msg['fiat_currency']) + else: + msg['stake_amount_fiat'] = 0 + message += f"\n*Balance:* `({round_coin_value(msg['stake_amount'], msg['stake_currency'])}" if msg.get('fiat_currency', None): message += f", {round_coin_value(msg['stake_amount_fiat'], msg['fiat_currency'])}" diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 4bbf26362..cf02da6bc 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -2619,6 +2619,9 @@ def test_execute_trade_exit_up(default_conf_usdt, ticker_usdt, fee, ticker_usdt_ 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, + 'partial': False, + 'stake_amount': 60.0, + } == last_msg @@ -2673,6 +2676,8 @@ def test_execute_trade_exit_down(default_conf_usdt, ticker_usdt, fee, ticker_usd 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, + 'partial': False, + 'stake_amount': 60.0, } == last_msg @@ -2741,6 +2746,8 @@ def test_execute_trade_exit_custom_exit_price(default_conf_usdt, ticker_usdt, fe 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, + 'partial': False, + 'stake_amount': 60.0, } == last_msg @@ -2801,6 +2808,8 @@ def test_execute_trade_exit_down_stoploss_on_exchange_dry_run( 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, + 'partial': False, + 'stake_amount': 60.0, } == last_msg @@ -3019,6 +3028,8 @@ def test_execute_trade_exit_market_order(default_conf_usdt, ticker_usdt, fee, 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, + 'partial': False, + 'stake_amount': 60.0, } == last_msg From da48ac9dab2f68ae9dce431fe77ff80e9e39305c Mon Sep 17 00:00:00 2001 From: Kavinkumar <33546454+mkavinkumar1@users.noreply.github.com> Date: Fri, 18 Feb 2022 17:26:42 +0530 Subject: [PATCH 04/17] updated --- tests/test_freqtradebot.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index cf02da6bc..66c983240 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -2619,7 +2619,7 @@ def test_execute_trade_exit_up(default_conf_usdt, ticker_usdt, fee, ticker_usdt_ 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, - 'partial': False, + 'sub_trade': False, 'stake_amount': 60.0, } == last_msg @@ -2676,7 +2676,7 @@ def test_execute_trade_exit_down(default_conf_usdt, ticker_usdt, fee, ticker_usd 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, - 'partial': False, + 'sub_trade': False, 'stake_amount': 60.0, } == last_msg @@ -2746,7 +2746,7 @@ def test_execute_trade_exit_custom_exit_price(default_conf_usdt, ticker_usdt, fe 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, - 'partial': False, + 'sub_trade': False, 'stake_amount': 60.0, } == last_msg @@ -2808,7 +2808,7 @@ def test_execute_trade_exit_down_stoploss_on_exchange_dry_run( 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, - 'partial': False, + 'sub_trade': False, 'stake_amount': 60.0, } == last_msg @@ -3028,7 +3028,7 @@ def test_execute_trade_exit_market_order(default_conf_usdt, ticker_usdt, fee, 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, - 'partial': False, + 'sub_trade': False, 'stake_amount': 60.0, } == last_msg From 250664d8b303f37d356ba1a8a80baa17a81c06aa Mon Sep 17 00:00:00 2001 From: Kavinkumar <33546454+mkavinkumar1@users.noreply.github.com> Date: Sat, 19 Feb 2022 18:55:07 +0530 Subject: [PATCH 05/17] included unit test --- freqtrade/freqtradebot.py | 34 ++++++++++++++------------ freqtrade/persistence/models.py | 23 ++++++++++++++---- freqtrade/rpc/telegram.py | 4 ++-- tests/rpc/test_rpc_telegram.py | 18 +++++++++----- tests/test_freqtradebot.py | 42 +++++++++++++++++++++++++++++++-- 5 files changed, 91 insertions(+), 30 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 71daf741c..789a3edaa 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -480,7 +480,7 @@ class FreqtradeBot(LoggingMixin): # We should decrease our position proposed_exit_rate = self.exchange.get_rate(pair, refresh=True, side="buy") self.execute_trade_exit(trade, proposed_exit_rate, sell_reason=SellCheckTuple( - sell_type=SellType.CUSTOM_SELL), partial=stake_amount) + sell_type=SellType.CUSTOM_SELL), sub_trade_amt=stake_amount) def _check_depth_of_market_buy(self, pair: str, conf: Dict) -> bool: """ @@ -620,7 +620,7 @@ class FreqtradeBot(LoggingMixin): # Updating wallets self.wallets.update() - self._notify_enter(trade, order, order_type, partial=pos_adjust) + self._notify_enter(trade, order, order_type, sub_trade=pos_adjust) if pos_adjust: if order_status == 'closed': @@ -677,7 +677,7 @@ class FreqtradeBot(LoggingMixin): return enter_limit_requested, stake_amount def _notify_enter(self, trade: Trade, order: Dict, order_type: Optional[str] = None, - fill: bool = False, partial: bool = False) -> None: + fill: bool = False, sub_trade: bool = False) -> None: """ Sends rpc notification when a buy occurred. """ @@ -704,13 +704,13 @@ class FreqtradeBot(LoggingMixin): 'amount': safe_value_fallback(order, 'filled', 'amount') or trade.amount, 'open_date': trade.open_date or datetime.utcnow(), 'current_rate': current_rate, - 'partial': partial, + 'sub_trade': sub_trade, } # Send the message self.rpc.send_msg(msg) - def _notify_enter_cancel(self, trade: Trade, order_type: str, reason: str) -> None: + def _notify_enter_cancel(self, trade: Trade, order_type: str, reason: str, sub_trade: bool = False) -> None: """ Sends rpc notification when a buy cancel occurred. """ @@ -731,6 +731,7 @@ class FreqtradeBot(LoggingMixin): 'open_date': trade.open_date, 'current_rate': current_rate, 'reason': reason, + 'sub_trade': sub_trade, } # Send the message @@ -1154,7 +1155,7 @@ class FreqtradeBot(LoggingMixin): *, exit_tag: Optional[str] = None, ordertype: Optional[str] = None, - partial: float = None, + sub_trade_amt: float = None, ) -> bool: """ Executes a trade exit for the given trade and limit @@ -1192,7 +1193,7 @@ class FreqtradeBot(LoggingMixin): # Emergency sells (default to market!) order_type = self.strategy.order_types.get("emergencysell", "market") - amount = self._safe_exit_amount(trade.pair, trade.amount) + amount = sub_trade_amt or self._safe_exit_amount(trade.pair, trade.amount) time_in_force = self.strategy.order_time_in_force['sell'] if not strategy_safe_wrapper(self.strategy.confirm_trade_exit, default_retval=True)( @@ -1227,15 +1228,15 @@ class FreqtradeBot(LoggingMixin): self.strategy.lock_pair(trade.pair, datetime.now(timezone.utc), reason='Auto lock') - self._notify_exit(trade, order_type, partial=bool(partial)) + self._notify_exit(trade, order_type, sub_trade=bool(sub_trade_amt)) # In case of market sell orders the order can be closed immediately if order.get('status', 'unknown') in ('closed', 'expired'): - self.update_trade_state(trade, trade.open_order_id, order) + self.update_trade_state(trade, trade.open_order_id, order, sub_trade=bool(sub_trade_amt)) Trade.commit() return True - def _notify_exit(self, trade: Trade, order_type: str, fill: bool = False, partial: bool = False) -> None: + def _notify_exit(self, trade: Trade, order_type: str, fill: bool = False, sub_trade: bool = False) -> None: """ Sends rpc notification when a sell occurred. """ @@ -1269,7 +1270,8 @@ class FreqtradeBot(LoggingMixin): 'stake_amount': trade.stake_amount, 'stake_currency': self.config['stake_currency'], 'fiat_currency': self.config.get('fiat_display_currency', None), - 'partial': partial, + 'sub_trade': sub_trade, + 'stake_amount': trade.stake_amount, } if 'fiat_display_currency' in self.config: @@ -1280,7 +1282,7 @@ class FreqtradeBot(LoggingMixin): # Send the message self.rpc.send_msg(msg) - def _notify_exit_cancel(self, trade: Trade, order_type: str, reason: str) -> None: + def _notify_exit_cancel(self, trade: Trade, order_type: str, reason: str, sub_trade: bool = False) -> None: """ Sends rpc notification when a sell cancel occurred. """ @@ -1315,6 +1317,8 @@ class FreqtradeBot(LoggingMixin): 'stake_currency': self.config['stake_currency'], 'fiat_currency': self.config.get('fiat_display_currency', None), 'reason': reason, + 'sub_trade': sub_trade, + 'stake_amount': trade.stake_amount, } if 'fiat_display_currency' in self.config: @@ -1330,7 +1334,7 @@ class FreqtradeBot(LoggingMixin): # def update_trade_state(self, trade: Trade, order_id: str, action_order: Dict[str, Any] = None, - stoploss_order: bool = False, send_msg: bool = True) -> bool: + stoploss_order: bool = False, send_msg: bool = True, sub_trade : bool = False) -> bool: """ Checks trades with open orders and updates the amount if necessary Handles closing both buy and sell orders. @@ -1363,7 +1367,7 @@ class FreqtradeBot(LoggingMixin): order = self.handle_order_fee(trade, order) - trade.update(order) + trade.update(order,sub_trade=sub_trade) trade.recalc_trade_from_orders() Trade.commit() @@ -1527,4 +1531,4 @@ class FreqtradeBot(LoggingMixin): # Bracket between min_custom_price_allowed and max_custom_price_allowed return max( min(valid_custom_price, max_custom_price_allowed), - min_custom_price_allowed) + min_custom_price_allowed) \ No newline at end of file diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index 0b701aa45..4e9e9e93a 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -116,7 +116,7 @@ class Order(_DECL_BASE): ft_order_side = Column(String(25), nullable=False) ft_pair = Column(String(25), nullable=False) ft_is_open = Column(Boolean, nullable=False, default=True, index=True) - + is_recovered = Column(Boolean, nullable=False, default=False) order_id = Column(String(255), nullable=False, index=True) status = Column(String(255), nullable=True) symbol = Column(String(25), nullable=True) @@ -481,9 +481,17 @@ class LocalTrade(): orders=(self.select_filled_orders('buy')) lbuy=orders[-2] lamount = (lbuy.filled or lbuy.amount) - lbuy.average=(lbuy.average * lamount - self.calc_profit2(orders[-1].rate, order.rate, order.filled or order.amount))/lamount + o_rate = float(safe_value_fallback(order, 'average', 'price')) + o_amount = float(safe_value_fallback(order, 'filled', 'amount')) + o1_rate = orders[-1].average or orders[-1].price + lbuy.average=(lbuy.average * lamount - self.calc_profit2(o1_rate, o_rate, o_amount))/lamount + orders[-1].is_recovered=True + self.update_order(orders[-1]) + + + # self.orders.remove(orders[-1]) + self.update_order(lbuy) Order.query.session.commit() - self.orders.remove(orders[-1]) self.recalc_trade_from_orders() Trade.commit() else: @@ -499,8 +507,11 @@ class LocalTrade(): raise ValueError(f'Unknown order type: {order_type}') Trade.commit() - def calc_profit2(self, open_rate: float, close_rate: float, amount: Float) ->float: - return Decimal(self.amount) *( (1-self.fee_close)* Decimal(close_rate) -(1+self.fee_open)* Decimal(open_rate) ) + def calc_profit2(self, open_rate: float, close_rate: float, amount: float) ->float: + return float (Decimal(amount) * \ + ( Decimal(1-self.fee_close)* Decimal(close_rate) - \ + Decimal(1+self.fee_open)* Decimal(open_rate) )) + def close(self, rate: float, *, show_msg: bool = True) -> None: """ Sets close_rate to the given rate, calculates total profit @@ -638,6 +649,7 @@ class LocalTrade(): for o in self.orders: if (o.ft_is_open or (o.ft_order_side != 'buy') or + o.is_recovered==True or (o.status not in NON_OPEN_EXCHANGE_STATES)): continue @@ -695,6 +707,7 @@ class LocalTrade(): return [o for o in self.orders if ((o.ft_order_side == order_side) or (order_side is None)) and o.ft_is_open is False and (o.filled or 0) > 0 and + o.is_recovered==False and o.status in NON_OPEN_EXCHANGE_STATES] @property diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 6c9ad083a..4da5007a7 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -246,10 +246,10 @@ class Telegram(RPCHandler): total, msg['stake_currency'], msg['fiat_currency']) else: total_fiat = 0 - message += f"*Total:* `({round_coin_value(msg['stake_amount'], msg['stake_currency'])}" + message += f"*Total:* `({round_coin_value(total, msg['stake_currency'])}" if msg.get('fiat_currency', None): - message += f", {round_coin_value(total, msg['fiat_currency'])}" + message += f", {round_coin_value(total_fiat, msg['fiat_currency'])}" message += ")`" if msg.get('sub_trade'): diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 67a6c72fe..d7c81d2bc 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -1037,6 +1037,8 @@ def test_telegram_forcesell_handle(default_conf, update, ticker, fee, 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, + 'stake_amount': 0.0009999999999054, + 'sub_trade': False } == last_msg @@ -1102,6 +1104,8 @@ def test_telegram_forcesell_down_handle(default_conf, update, ticker, fee, 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, + 'stake_amount': 0.0009999999999054, + 'sub_trade': False } == last_msg @@ -1157,6 +1161,8 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, mocker) -> None 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, + 'stake_amount': 0.0009999999999054, + 'sub_trade': False } == msg @@ -1734,7 +1740,7 @@ def test_send_msg_buy_notification(default_conf, mocker, caplog) -> None: 'pair': 'ETH/BTC', 'limit': 1.099e-05, 'order_type': 'limit', - 'stake_amount': 0.001, + 'stake_amount': 0.01465333, 'stake_amount_fiat': 0.0, 'stake_currency': 'BTC', 'fiat_currency': 'USD', @@ -1751,7 +1757,7 @@ def test_send_msg_buy_notification(default_conf, mocker, caplog) -> None: '*Amount:* `1333.33333333`\n' \ '*Open Rate:* `0.00001099`\n' \ '*Current Rate:* `0.00001099`\n' \ - '*Total:* `(0.00100000 BTC, 12.345 USD)`' + '*Total:* `(0.01465333 BTC, 180.895 USD)`' freqtradebot.config['telegram']['notification_settings'] = {'buy': 'off'} caplog.clear() @@ -1825,7 +1831,7 @@ def test_send_msg_buy_fill_notification(default_conf, mocker) -> None: 'buy_tag': 'buy_signal_01', 'exchange': 'Binance', 'pair': 'ETH/BTC', - 'stake_amount': 0.001, + 'stake_amount': 0.01465333, # 'stake_amount_fiat': 0.0, 'stake_currency': 'BTC', 'fiat_currency': 'USD', @@ -1839,7 +1845,7 @@ def test_send_msg_buy_fill_notification(default_conf, mocker) -> None: '*Buy Tag:* `buy_signal_01`\n' \ '*Amount:* `1333.33333333`\n' \ '*Open Rate:* `0.00001099`\n' \ - '*Total:* `(0.00100000 BTC, 12.345 USD)`' + '*Total:* `(0.01465333 BTC, 180.895 USD)`' def test_send_msg_sell_notification(default_conf, mocker) -> None: @@ -2031,7 +2037,7 @@ def test_send_msg_buy_notification_no_fiat(default_conf, mocker) -> None: 'pair': 'ETH/BTC', 'limit': 1.099e-05, 'order_type': 'limit', - 'stake_amount': 0.001, + 'stake_amount': 0.01465333, 'stake_amount_fiat': 0.0, 'stake_currency': 'BTC', 'fiat_currency': None, @@ -2044,7 +2050,7 @@ def test_send_msg_buy_notification_no_fiat(default_conf, mocker) -> None: '*Amount:* `1333.33333333`\n' '*Open Rate:* `0.00001099`\n' '*Current Rate:* `0.00001099`\n' - '*Total:* `(0.00100000 BTC)`') + '*Total:* `(0.01465333 BTC)`') def test_send_msg_sell_notification_no_fiat(default_conf, mocker) -> None: diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 66c983240..334e04b14 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -4320,7 +4320,6 @@ def test_position_adjust(mocker, default_conf_usdt, fee) -> None: get_fee=fee, ) pair = 'ETH/USDT' - # Initial buy closed_successful_buy_order = { 'pair': pair, @@ -4385,7 +4384,7 @@ def test_position_adjust(mocker, default_conf_usdt, fee) -> None: 'status': None, 'price': 9, 'amount': 12, - 'cost': 100, + 'cost': 108, 'ft_is_open': True, 'id': '651', 'order_id': '651' @@ -4532,7 +4531,46 @@ def test_position_adjust(mocker, default_conf_usdt, fee) -> None: # Make sure the closed order is found as the second order. order = trade.select_order('buy', False) assert order.order_id == '652' + closed_sell_dca_order_1 = { + 'ft_pair': pair, + 'status': 'closed', + 'ft_order_side': 'sell', + 'side': 'sell', + 'type': 'limit', + 'price': 8, + 'average': 8, + 'amount': 15, + 'filled': 15, + 'cost': 120, + 'ft_is_open': False, + 'id': '653', + 'order_id': '653' + } + mocker.patch('freqtrade.exchange.Exchange.create_order', + MagicMock(return_value=closed_sell_dca_order_1)) + mocker.patch('freqtrade.exchange.Exchange.fetch_order', + MagicMock(return_value=closed_sell_dca_order_1)) + mocker.patch('freqtrade.exchange.Exchange.fetch_order_or_stoploss_order', + MagicMock(return_value=closed_sell_dca_order_1)) + assert freqtrade.execute_trade_exit(trade=trade, limit=8, + sell_reason=SellCheckTuple(sell_type=SellType.STOP_LOSS),sub_trade_amt=15) + # Assert trade is as expected (averaged dca) + trade = Trade.query.first() + print(trade.open_rate,trade.amount,trade.stake_amount,'DEBUG') + assert trade + assert trade.open_order_id is None + assert trade.amount == 22 + assert trade.stake_amount == 203.5625 + assert pytest.approx(trade.open_rate) == 9.252840909090908 + + orders = Order.query.all() + assert orders + assert len(orders) == 4 + + # Make sure the closed order is found as the second order. + order = trade.select_order('sell', False) + assert order.order_id == '653' def test_process_open_trade_positions_exception(mocker, default_conf_usdt, fee, caplog) -> None: default_conf_usdt.update({ From d25f999901f030dc0f405814f3e55efe9691dd40 Mon Sep 17 00:00:00 2001 From: Kavinkumar <33546454+mkavinkumar1@users.noreply.github.com> Date: Sun, 20 Feb 2022 10:14:50 +0530 Subject: [PATCH 06/17] Updated order attribute --- freqtrade/persistence/models.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index 4e9e9e93a..61abde616 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -116,7 +116,8 @@ class Order(_DECL_BASE): ft_order_side = Column(String(25), nullable=False) ft_pair = Column(String(25), nullable=False) ft_is_open = Column(Boolean, nullable=False, default=True, index=True) - is_recovered = Column(Boolean, nullable=False, default=False) + is_processed = Column(Boolean, nullable=True, default=False) + order_id = Column(String(255), nullable=False, index=True) status = Column(String(255), nullable=True) symbol = Column(String(25), nullable=True) @@ -485,7 +486,7 @@ class LocalTrade(): o_amount = float(safe_value_fallback(order, 'filled', 'amount')) o1_rate = orders[-1].average or orders[-1].price lbuy.average=(lbuy.average * lamount - self.calc_profit2(o1_rate, o_rate, o_amount))/lamount - orders[-1].is_recovered=True + orders[-1].is_processed=True self.update_order(orders[-1]) @@ -649,7 +650,7 @@ class LocalTrade(): for o in self.orders: if (o.ft_is_open or (o.ft_order_side != 'buy') or - o.is_recovered==True or + o.is_processed==True or (o.status not in NON_OPEN_EXCHANGE_STATES)): continue @@ -707,7 +708,7 @@ class LocalTrade(): return [o for o in self.orders if ((o.ft_order_side == order_side) or (order_side is None)) and o.ft_is_open is False and (o.filled or 0) > 0 and - o.is_recovered==False and + o.is_processed!=True and o.status in NON_OPEN_EXCHANGE_STATES] @property From fcddb0969474b27c619732495af25717c779b3f8 Mon Sep 17 00:00:00 2001 From: Kavinkumar <33546454+mkavinkumar1@users.noreply.github.com> Date: Mon, 21 Feb 2022 11:57:15 +0530 Subject: [PATCH 07/17] updated logic --- freqtrade/freqtradebot.py | 24 +++++++----- freqtrade/persistence/models.py | 68 +++++++++++++++++++++------------ freqtrade/rpc/telegram.py | 6 ++- tests/rpc/test_rpc_telegram.py | 6 +-- tests/test_freqtradebot.py | 20 +++++----- 5 files changed, 75 insertions(+), 49 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 789a3edaa..c6ad061f1 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -478,7 +478,7 @@ class FreqtradeBot(LoggingMixin): if stake_amount is not None and stake_amount < 0.0: # We should decrease our position - proposed_exit_rate = self.exchange.get_rate(pair, refresh=True, side="buy") + proposed_exit_rate = self.exchange.get_rate(trade.pair, refresh=True, side="buy") self.execute_trade_exit(trade, proposed_exit_rate, sell_reason=SellCheckTuple( sell_type=SellType.CUSTOM_SELL), sub_trade_amt=stake_amount) @@ -710,7 +710,8 @@ class FreqtradeBot(LoggingMixin): # Send the message self.rpc.send_msg(msg) - def _notify_enter_cancel(self, trade: Trade, order_type: str, reason: str, sub_trade: bool = False) -> None: + def _notify_enter_cancel(self, trade: Trade, order_type: str, reason: str, + sub_trade: bool = False) -> None: """ Sends rpc notification when a buy cancel occurred. """ @@ -1231,12 +1232,14 @@ class FreqtradeBot(LoggingMixin): self._notify_exit(trade, order_type, sub_trade=bool(sub_trade_amt)) # In case of market sell orders the order can be closed immediately if order.get('status', 'unknown') in ('closed', 'expired'): - self.update_trade_state(trade, trade.open_order_id, order, sub_trade=bool(sub_trade_amt)) + self.update_trade_state(trade, trade.open_order_id, order, + sub_trade=bool(sub_trade_amt)) Trade.commit() return True - def _notify_exit(self, trade: Trade, order_type: str, fill: bool = False, sub_trade: bool = False) -> None: + def _notify_exit(self, trade: Trade, order_type: str, fill: bool = False, + sub_trade: bool = False) -> None: """ Sends rpc notification when a sell occurred. """ @@ -1271,8 +1274,7 @@ class FreqtradeBot(LoggingMixin): 'stake_currency': self.config['stake_currency'], 'fiat_currency': self.config.get('fiat_display_currency', None), 'sub_trade': sub_trade, - 'stake_amount': trade.stake_amount, - } + } if 'fiat_display_currency' in self.config: msg.update({ @@ -1282,7 +1284,8 @@ class FreqtradeBot(LoggingMixin): # Send the message self.rpc.send_msg(msg) - def _notify_exit_cancel(self, trade: Trade, order_type: str, reason: str, sub_trade: bool = False) -> None: + def _notify_exit_cancel(self, trade: Trade, order_type: str, reason: str, + sub_trade: bool = False) -> None: """ Sends rpc notification when a sell cancel occurred. """ @@ -1334,7 +1337,8 @@ class FreqtradeBot(LoggingMixin): # def update_trade_state(self, trade: Trade, order_id: str, action_order: Dict[str, Any] = None, - stoploss_order: bool = False, send_msg: bool = True, sub_trade : bool = False) -> bool: + stoploss_order: bool = False, send_msg: bool = True, + sub_trade: bool = False) -> bool: """ Checks trades with open orders and updates the amount if necessary Handles closing both buy and sell orders. @@ -1367,7 +1371,7 @@ class FreqtradeBot(LoggingMixin): order = self.handle_order_fee(trade, order) - trade.update(order,sub_trade=sub_trade) + trade.update(order, sub_trade=sub_trade) trade.recalc_trade_from_orders() Trade.commit() @@ -1531,4 +1535,4 @@ class FreqtradeBot(LoggingMixin): # Bracket between min_custom_price_allowed and max_custom_price_allowed return max( min(valid_custom_price, max_custom_price_allowed), - min_custom_price_allowed) \ No newline at end of file + min_custom_price_allowed) diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index 61abde616..e1b309091 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -116,7 +116,7 @@ class Order(_DECL_BASE): ft_order_side = Column(String(25), nullable=False) ft_pair = Column(String(25), nullable=False) ft_is_open = Column(Boolean, nullable=False, default=True, index=True) - is_processed = Column(Boolean, nullable=True, default=False) + is_realized = Column(Boolean, nullable=True, default=False) order_id = Column(String(255), nullable=False, index=True) status = Column(String(255), nullable=True) @@ -453,7 +453,7 @@ class LocalTrade(): f"Trailing stoploss saved us: " f"{float(self.stop_loss) - float(self.initial_stop_loss):.8f}.") - def update(self, order: Dict, sub_trade:bool=False) -> None: + def update(self, order: Dict, sub_trade: bool = False) -> None: """ Updates this entity with amount and actual open/close rates. :param order: order retrieved by exchange.fetch_order() @@ -479,22 +479,8 @@ class LocalTrade(): logger.info(f'{order_type.upper()}_SELL has been fulfilled for {self}.') self.open_order_id = None if sub_trade: - orders=(self.select_filled_orders('buy')) - lbuy=orders[-2] - lamount = (lbuy.filled or lbuy.amount) - o_rate = float(safe_value_fallback(order, 'average', 'price')) - o_amount = float(safe_value_fallback(order, 'filled', 'amount')) - o1_rate = orders[-1].average or orders[-1].price - lbuy.average=(lbuy.average * lamount - self.calc_profit2(o1_rate, o_rate, o_amount))/lamount - orders[-1].is_processed=True - self.update_order(orders[-1]) - - - # self.orders.remove(orders[-1]) - self.update_order(lbuy) - Order.query.session.commit() - self.recalc_trade_from_orders() - Trade.commit() + self.process_sell_sub_trade(order) + return else: self.close(safe_value_fallback(order, 'average', 'price')) elif order_type in ('stop_loss_limit', 'stop-loss', 'stop-loss-limit', 'stop'): @@ -508,10 +494,44 @@ class LocalTrade(): raise ValueError(f'Unknown order type: {order_type}') Trade.commit() - def calc_profit2(self, open_rate: float, close_rate: float, amount: float) ->float: - return float (Decimal(amount) * \ - ( Decimal(1-self.fee_close)* Decimal(close_rate) - \ - Decimal(1+self.fee_open)* Decimal(open_rate) )) + def process_sell_sub_trade(self, order: Dict) -> None: + orders = (self.select_filled_orders('buy')) + sell_rate = float(safe_value_fallback(order, 'average', 'price')) + sell_amount = float(safe_value_fallback(order, 'filled', 'amount')) + profit = 0 + idx = -1 + while sell_amount: + border = orders[idx] + buy_amount = border.filled or border.amount + buy_rate = border.average or border.price + if sell_amount < buy_amount: + amount = sell_amount + else: + if len(orders) == 1 and sell_amount == buy_amount: + self.close(safe_value_fallback(order, 'average', 'price')) + Trade.commit() + return + border.is_realized = True + self.update_order(border) + idx -= 1 + amount = buy_amount + sell_amount -= amount + profit += self.calc_profit2(buy_rate, sell_rate, amount) + border2 = orders[idx] + if not border.is_realized: + border2.filled -= amount + amount2 = border2.filled or border2.amount + border2.average = (border2.average * amount2 - profit) / amount2 + self.update_order(border2) + Order.query.session.commit() + self.recalc_trade_from_orders() + Trade.commit() + + def calc_profit2(self, open_rate: float, close_rate: float, + amount: float) -> float: + return float(Decimal(amount) * + (Decimal(1 - self.fee_close) * Decimal(close_rate) - + Decimal(1 + self.fee_open) * Decimal(open_rate))) def close(self, rate: float, *, show_msg: bool = True) -> None: """ @@ -650,7 +670,7 @@ class LocalTrade(): for o in self.orders: if (o.ft_is_open or (o.ft_order_side != 'buy') or - o.is_processed==True or + o.is_realized or (o.status not in NON_OPEN_EXCHANGE_STATES)): continue @@ -708,7 +728,7 @@ class LocalTrade(): return [o for o in self.orders if ((o.ft_order_side == order_side) or (order_side is None)) and o.ft_is_open is False and (o.filled or 0) > 0 and - o.is_processed!=True and + not o.is_realized and o.status in NON_OPEN_EXCHANGE_STATES] @property diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 4da5007a7..367dafd12 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -253,7 +253,8 @@ class Telegram(RPCHandler): message += ")`" if msg.get('sub_trade'): - message += f"\n*Balance:* `({round_coin_value(msg['stake_amount'], msg['stake_currency'])}" + bal = round_coin_value(msg['stake_amount'], msg['stake_currency']) + message += f"\n*Balance:* `({bal}" if msg.get('fiat_currency', None): message += f", {round_coin_value(msg['stake_amount_fiat'], msg['fiat_currency'])}" @@ -306,7 +307,8 @@ class Telegram(RPCHandler): msg['stake_amount'], msg['stake_currency'], msg['fiat_currency']) else: msg['stake_amount_fiat'] = 0 - message += f"\n*Balance:* `({round_coin_value(msg['stake_amount'], msg['stake_currency'])}" + bal = round_coin_value(msg['stake_amount'], msg['stake_currency']) + message += f"\n*Balance:* `({bal}" if msg.get('fiat_currency', None): message += f", {round_coin_value(msg['stake_amount_fiat'], msg['fiat_currency'])}" diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index d7c81d2bc..eaff9891a 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -1037,7 +1037,7 @@ def test_telegram_forcesell_handle(default_conf, update, ticker, fee, 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, - 'stake_amount': 0.0009999999999054, + 'stake_amount': 0.0009999999999054, 'sub_trade': False } == last_msg @@ -1104,7 +1104,7 @@ def test_telegram_forcesell_down_handle(default_conf, update, ticker, fee, 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, - 'stake_amount': 0.0009999999999054, + 'stake_amount': 0.0009999999999054, 'sub_trade': False } == last_msg @@ -1161,7 +1161,7 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, mocker) -> None 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, - 'stake_amount': 0.0009999999999054, + 'stake_amount': 0.0009999999999054, 'sub_trade': False } == msg diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 334e04b14..bdb56bac8 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -2621,8 +2621,7 @@ def test_execute_trade_exit_up(default_conf_usdt, ticker_usdt, fee, ticker_usdt_ 'close_rate': ANY, 'sub_trade': False, 'stake_amount': 60.0, - - } == last_msg + } == last_msg def test_execute_trade_exit_down(default_conf_usdt, ticker_usdt, fee, ticker_usdt_sell_down, @@ -2677,8 +2676,8 @@ def test_execute_trade_exit_down(default_conf_usdt, ticker_usdt, fee, ticker_usd 'close_date': ANY, 'close_rate': ANY, 'sub_trade': False, - 'stake_amount': 60.0, - } == last_msg + 'stake_amount': 60.0, + } == last_msg def test_execute_trade_exit_custom_exit_price(default_conf_usdt, ticker_usdt, fee, @@ -2747,8 +2746,8 @@ def test_execute_trade_exit_custom_exit_price(default_conf_usdt, ticker_usdt, fe 'close_date': ANY, 'close_rate': ANY, 'sub_trade': False, - 'stake_amount': 60.0, - } == last_msg + 'stake_amount': 60.0, + } == last_msg def test_execute_trade_exit_down_stoploss_on_exchange_dry_run( @@ -2809,7 +2808,7 @@ def test_execute_trade_exit_down_stoploss_on_exchange_dry_run( 'close_date': ANY, 'close_rate': ANY, 'sub_trade': False, - 'stake_amount': 60.0, + 'stake_amount': 60.0, } == last_msg @@ -3029,7 +3028,7 @@ def test_execute_trade_exit_market_order(default_conf_usdt, ticker_usdt, fee, 'close_date': ANY, 'close_rate': ANY, 'sub_trade': False, - 'stake_amount': 60.0, + 'stake_amount': 60.0, } == last_msg @@ -4553,11 +4552,11 @@ def test_position_adjust(mocker, default_conf_usdt, fee) -> None: mocker.patch('freqtrade.exchange.Exchange.fetch_order_or_stoploss_order', MagicMock(return_value=closed_sell_dca_order_1)) assert freqtrade.execute_trade_exit(trade=trade, limit=8, - sell_reason=SellCheckTuple(sell_type=SellType.STOP_LOSS),sub_trade_amt=15) + sell_reason=SellCheckTuple(sell_type=SellType.STOP_LOSS), + sub_trade_amt=15) # Assert trade is as expected (averaged dca) trade = Trade.query.first() - print(trade.open_rate,trade.amount,trade.stake_amount,'DEBUG') assert trade assert trade.open_order_id is None assert trade.amount == 22 @@ -4572,6 +4571,7 @@ def test_position_adjust(mocker, default_conf_usdt, fee) -> None: order = trade.select_order('sell', False) assert order.order_id == '653' + def test_process_open_trade_positions_exception(mocker, default_conf_usdt, fee, caplog) -> None: default_conf_usdt.update({ "position_adjustment_enable": True, From 5cfc670adaebd0b7e5a2180a5b99cbec31088859 Mon Sep 17 00:00:00 2001 From: Kavinkumar <33546454+mkavinkumar1@users.noreply.github.com> Date: Mon, 21 Feb 2022 12:16:08 +0530 Subject: [PATCH 08/17] fix for total sell --- freqtrade/persistence/models.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index e1b309091..00c2758ea 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -501,28 +501,28 @@ class LocalTrade(): profit = 0 idx = -1 while sell_amount: - border = orders[idx] - buy_amount = border.filled or border.amount - buy_rate = border.average or border.price + b_order = orders[idx] + buy_amount = b_order.filled or b_order.amount + buy_rate = b_order.average or b_order.price if sell_amount < buy_amount: amount = sell_amount else: - if len(orders) == 1 and sell_amount == buy_amount: + if len(orders) == 1 and sell_amount == self.amount: self.close(safe_value_fallback(order, 'average', 'price')) Trade.commit() return - border.is_realized = True - self.update_order(border) + b_order.is_realized = True + self.update_order(b_order) idx -= 1 amount = buy_amount sell_amount -= amount profit += self.calc_profit2(buy_rate, sell_rate, amount) - border2 = orders[idx] - if not border.is_realized: - border2.filled -= amount - amount2 = border2.filled or border2.amount - border2.average = (border2.average * amount2 - profit) / amount2 - self.update_order(border2) + b_order2 = orders[idx] + if not b_order.is_realized: + b_order2.filled -= amount + amount2 = b_order2.filled or b_order2.amount + b_order2.average = (b_order2.average * amount2 - profit) / amount2 + self.update_order(b_order2) Order.query.session.commit() self.recalc_trade_from_orders() Trade.commit() From a8b1d1e10b6b967cc5c00901c81fb48c5927ec5b Mon Sep 17 00:00:00 2001 From: Kavinkumar <33546454+mkavinkumar1@users.noreply.github.com> Date: Mon, 21 Feb 2022 12:35:25 +0530 Subject: [PATCH 09/17] fix for mypy --- freqtrade/persistence/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index 00c2758ea..fd625d5fa 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -498,7 +498,7 @@ class LocalTrade(): orders = (self.select_filled_orders('buy')) sell_rate = float(safe_value_fallback(order, 'average', 'price')) sell_amount = float(safe_value_fallback(order, 'filled', 'amount')) - profit = 0 + profit = 0.0 idx = -1 while sell_amount: b_order = orders[idx] From 16b3b97ac76489d49d939249d4069ec47894e67b Mon Sep 17 00:00:00 2001 From: Kavinkumar <33546454+mkavinkumar1@users.noreply.github.com> Date: Mon, 21 Feb 2022 18:25:04 +0530 Subject: [PATCH 10/17] zero division error fixes and rpc fixes --- freqtrade/freqtradebot.py | 6 +++--- freqtrade/rpc/telegram.py | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index c6ad061f1..ed32f4e84 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -701,7 +701,7 @@ class FreqtradeBot(LoggingMixin): 'stake_amount': trade.stake_amount, 'stake_currency': self.config['stake_currency'], 'fiat_currency': self.config.get('fiat_display_currency', None), - 'amount': safe_value_fallback(order, 'filled', 'amount') or trade.amount, + 'amount': order.get('filled') or order.get('amount') 'open_date': trade.open_date or datetime.utcnow(), 'current_rate': current_rate, 'sub_trade': sub_trade, @@ -1384,11 +1384,11 @@ class FreqtradeBot(LoggingMixin): if not trade.is_open: if send_msg and not stoploss_order and not trade.open_order_id: - self._notify_exit(trade, '', True) + self._notify_exit(trade, '', True, sub_trade=sub_trade) self.handle_protections(trade.pair) elif send_msg and not trade.open_order_id: # Buy fill - self._notify_enter(trade, order, fill=True) + self._notify_enter(trade, order, fill=True, sub_trade=sub_trade) return False diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 367dafd12..da8f7be7c 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -414,12 +414,13 @@ class Telegram(RPCHandler): else: sumA = 0 sumB = 0 + first_order_price = filled_orders[0]["average"] or filled_orders[0]["price"] for y in range(x): sumA += (filled_orders[y]["amount"] * filled_orders[y]["average"]) sumB += filled_orders[y]["amount"] prev_avg_price = sumA/sumB - price_to_1st_entry = ((cur_entry_average - filled_orders[0]["average"]) - / filled_orders[0]["average"]) + price_to_1st_entry = ((cur_entry_average - first_order_price) + / first_order_price) minus_on_entry = (cur_entry_average - prev_avg_price)/prev_avg_price dur_entry = cur_entry_datetime - arrow.get(filled_orders[x-1]["order_filled_date"]) days = dur_entry.days From 11b5509a9846c1e8fe97cbc3081e2fd7c9d794a7 Mon Sep 17 00:00:00 2001 From: Kavinkumar <33546454+mkavinkumar1@users.noreply.github.com> Date: Mon, 21 Feb 2022 18:28:44 +0530 Subject: [PATCH 11/17] typo --- freqtrade/freqtradebot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index ed32f4e84..cee30acba 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -701,7 +701,7 @@ class FreqtradeBot(LoggingMixin): 'stake_amount': trade.stake_amount, 'stake_currency': self.config['stake_currency'], 'fiat_currency': self.config.get('fiat_display_currency', None), - 'amount': order.get('filled') or order.get('amount') + 'amount': order.get('filled') or order.get('amount'), 'open_date': trade.open_date or datetime.utcnow(), 'current_rate': current_rate, 'sub_trade': sub_trade, From c9f9404c4ae45ee19e3c64ff0e3d4d9765ac7c53 Mon Sep 17 00:00:00 2001 From: Kavinkumar <33546454+mkavinkumar1@users.noreply.github.com> Date: Mon, 21 Feb 2022 18:35:11 +0530 Subject: [PATCH 12/17] zero division error --- freqtrade/rpc/telegram.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index da8f7be7c..9909b2920 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -416,7 +416,7 @@ class Telegram(RPCHandler): sumB = 0 first_order_price = filled_orders[0]["average"] or filled_orders[0]["price"] for y in range(x): - sumA += (filled_orders[y]["amount"] * filled_orders[y]["average"]) + sumA += (filled_orders[y]["amount"] * (filled_orders[y]["average"] or filled_orders[y]["price"])) sumB += filled_orders[y]["amount"] prev_avg_price = sumA/sumB price_to_1st_entry = ((cur_entry_average - first_order_price) @@ -562,7 +562,9 @@ class Telegram(RPCHandler): reload_able=True, callback_path="update_status_table", query=update.callback_query) except RPCException as e: - self._send_msg(str(e)) + self._send_msg(str(e), reload_able=True, + callback_path="update_status_table", + query=update.callback_query) @authorized_only def _daily(self, update: Update, context: CallbackContext) -> None: From b4dbf4a96c68be7b9cfda60eebde037640dacfb5 Mon Sep 17 00:00:00 2001 From: Kavinkumar <33546454+mkavinkumar1@users.noreply.github.com> Date: Mon, 21 Feb 2022 19:49:02 +0530 Subject: [PATCH 13/17] typo --- freqtrade/rpc/telegram.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 9909b2920..ecbacf1e0 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -416,7 +416,8 @@ class Telegram(RPCHandler): sumB = 0 first_order_price = filled_orders[0]["average"] or filled_orders[0]["price"] for y in range(x): - sumA += (filled_orders[y]["amount"] * (filled_orders[y]["average"] or filled_orders[y]["price"])) + sumA += (filled_orders[y]["amount"] * (filled_orders[y]["average"] + or filled_orders[y]["price"])) sumB += filled_orders[y]["amount"] prev_avg_price = sumA/sumB price_to_1st_entry = ((cur_entry_average - first_order_price) From 4dce0fa3f2c93a38984c8fd90624263a4b128b97 Mon Sep 17 00:00:00 2001 From: Kavinkumar <33546454+mkavinkumar1@users.noreply.github.com> Date: Tue, 22 Feb 2022 19:29:54 +0530 Subject: [PATCH 14/17] used calculated current_rate --- freqtrade/freqtradebot.py | 3 +-- freqtrade/persistence/models.py | 11 +++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index cee30acba..58f0302c1 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -478,8 +478,7 @@ class FreqtradeBot(LoggingMixin): if stake_amount is not None and stake_amount < 0.0: # We should decrease our position - proposed_exit_rate = self.exchange.get_rate(trade.pair, refresh=True, side="buy") - self.execute_trade_exit(trade, proposed_exit_rate, sell_reason=SellCheckTuple( + self.execute_trade_exit(trade, current_rate, sell_reason=SellCheckTuple( sell_type=SellType.CUSTOM_SELL), sub_trade_amt=stake_amount) def _check_depth_of_market_buy(self, pair: str, conf: Dict) -> bool: diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index fd625d5fa..0a75261e8 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -116,7 +116,7 @@ class Order(_DECL_BASE): ft_order_side = Column(String(25), nullable=False) ft_pair = Column(String(25), nullable=False) ft_is_open = Column(Boolean, nullable=False, default=True, index=True) - is_realized = Column(Boolean, nullable=True, default=False) + is_fully_realized = Column(Boolean, nullable=True, default=False) order_id = Column(String(255), nullable=False, index=True) status = Column(String(255), nullable=True) @@ -506,20 +506,19 @@ class LocalTrade(): buy_rate = b_order.average or b_order.price if sell_amount < buy_amount: amount = sell_amount + b_order.filled -= amount else: if len(orders) == 1 and sell_amount == self.amount: self.close(safe_value_fallback(order, 'average', 'price')) Trade.commit() return - b_order.is_realized = True + b_order.is_fully_realized = True self.update_order(b_order) idx -= 1 amount = buy_amount sell_amount -= amount profit += self.calc_profit2(buy_rate, sell_rate, amount) b_order2 = orders[idx] - if not b_order.is_realized: - b_order2.filled -= amount amount2 = b_order2.filled or b_order2.amount b_order2.average = (b_order2.average * amount2 - profit) / amount2 self.update_order(b_order2) @@ -670,7 +669,7 @@ class LocalTrade(): for o in self.orders: if (o.ft_is_open or (o.ft_order_side != 'buy') or - o.is_realized or + o.is_fully_realized or (o.status not in NON_OPEN_EXCHANGE_STATES)): continue @@ -728,7 +727,7 @@ class LocalTrade(): return [o for o in self.orders if ((o.ft_order_side == order_side) or (order_side is None)) and o.ft_is_open is False and (o.filled or 0) > 0 and - not o.is_realized and + not o.is_fully_realized and o.status in NON_OPEN_EXCHANGE_STATES] @property From 30398007cce364fb5c0b2548f9297dd7755fddb3 Mon Sep 17 00:00:00 2001 From: Kavinkumar <33546454+mkavinkumar1@users.noreply.github.com> Date: Wed, 23 Feb 2022 15:48:53 +0530 Subject: [PATCH 15/17] typo --- freqtrade/freqtradebot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 58f0302c1..d6460f144 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -479,7 +479,7 @@ class FreqtradeBot(LoggingMixin): if stake_amount is not None and stake_amount < 0.0: # We should decrease our position self.execute_trade_exit(trade, current_rate, sell_reason=SellCheckTuple( - sell_type=SellType.CUSTOM_SELL), sub_trade_amt=stake_amount) + sell_type=SellType.CUSTOM_SELL), sub_trade_amt=-stake_amount) def _check_depth_of_market_buy(self, pair: str, conf: Dict) -> bool: """ From c4f9a9099867cc54b0346fcb9a69794d67a775f6 Mon Sep 17 00:00:00 2001 From: Kavinkumar <33546454+mkavinkumar1@users.noreply.github.com> Date: Wed, 23 Feb 2022 18:04:06 +0530 Subject: [PATCH 16/17] debug --- freqtrade/persistence/models.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index 0a75261e8..bb3f6938f 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -478,11 +478,12 @@ class LocalTrade(): if self.is_open: logger.info(f'{order_type.upper()}_SELL has been fulfilled for {self}.') self.open_order_id = None - if sub_trade: + if sub_trade or 1: + log.info(f'debug1:{sub_trade}') self.process_sell_sub_trade(order) return - else: - self.close(safe_value_fallback(order, 'average', 'price')) + # else: + # self.close(safe_value_fallback(order, 'average', 'price')) elif order_type in ('stop_loss_limit', 'stop-loss', 'stop-loss-limit', 'stop'): self.stoploss_order_id = None self.close_rate_requested = self.stop_loss @@ -508,7 +509,7 @@ class LocalTrade(): amount = sell_amount b_order.filled -= amount else: - if len(orders) == 1 and sell_amount == self.amount: + if sell_amount == self.amount: self.close(safe_value_fallback(order, 'average', 'price')) Trade.commit() return From 06d14b81dde8c402880899928704dfe8bd665946 Mon Sep 17 00:00:00 2001 From: Kavinkumar <33546454+mkavinkumar1@users.noreply.github.com> Date: Wed, 23 Feb 2022 18:09:50 +0530 Subject: [PATCH 17/17] typo --- freqtrade/persistence/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index bb3f6938f..42dfb8ac5 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -479,7 +479,7 @@ class LocalTrade(): logger.info(f'{order_type.upper()}_SELL has been fulfilled for {self}.') self.open_order_id = None if sub_trade or 1: - log.info(f'debug1:{sub_trade}') + logger.info(f'debug1:{sub_trade}') self.process_sell_sub_trade(order) return # else: