draft for partial sell

This commit is contained in:
Kavinkumar 2022-02-16 18:45:38 +05:30
parent a77c11c7e0
commit 1de5c0412c
3 changed files with 53 additions and 12 deletions

View File

@ -478,9 +478,9 @@ class FreqtradeBot(LoggingMixin):
if stake_amount is not None and stake_amount < 0.0: if stake_amount is not None and stake_amount < 0.0:
# We should decrease our position # We should decrease our position
# TODO: Selling part of the trade not implemented yet. proposed_exit_rate = self.exchange.get_rate(pair, refresh=True, side="buy")
logger.error(f"Unable to decrease trade position / sell partially" self.execute_trade_exit(trade, proposed_exit_rate, sell_reason=SellCheckTuple(
f" for pair {trade.pair}, feature not implemented.") sell_type=SellType.CUSTOM_SELL), partial=stake_amount)
def _check_depth_of_market_buy(self, pair: str, conf: Dict) -> bool: def _check_depth_of_market_buy(self, pair: str, conf: Dict) -> bool:
""" """
@ -620,7 +620,7 @@ class FreqtradeBot(LoggingMixin):
# Updating wallets # Updating wallets
self.wallets.update() self.wallets.update()
self._notify_enter(trade, order, order_type) self._notify_enter(trade, order, order_type, partial=pos_adjust)
if pos_adjust: if pos_adjust:
if order_status == 'closed': if order_status == 'closed':
@ -677,7 +677,7 @@ class FreqtradeBot(LoggingMixin):
return enter_limit_requested, stake_amount return enter_limit_requested, stake_amount
def _notify_enter(self, trade: Trade, order: Dict, order_type: Optional[str] = None, 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. Sends rpc notification when a buy occurred.
""" """
@ -693,7 +693,7 @@ class FreqtradeBot(LoggingMixin):
'trade_id': trade.id, 'trade_id': trade.id,
'type': RPCMessageType.BUY_FILL if fill else RPCMessageType.BUY, 'type': RPCMessageType.BUY_FILL if fill else RPCMessageType.BUY,
'buy_tag': trade.buy_tag, 'buy_tag': trade.buy_tag,
'exchange': self.exchange.name.capitalize(), 'exchange': trade.exchange.capitalize(),
'pair': trade.pair, 'pair': trade.pair,
'limit': open_rate, # Deprecated (?) 'limit': open_rate, # Deprecated (?)
'open_rate': open_rate, 'open_rate': open_rate,
@ -704,6 +704,7 @@ class FreqtradeBot(LoggingMixin):
'amount': safe_value_fallback(order, 'filled', 'amount') or trade.amount, 'amount': safe_value_fallback(order, 'filled', 'amount') or trade.amount,
'open_date': trade.open_date or datetime.utcnow(), 'open_date': trade.open_date or datetime.utcnow(),
'current_rate': current_rate, 'current_rate': current_rate,
'partial': partial,
} }
# Send the message # Send the message
@ -1153,6 +1154,7 @@ class FreqtradeBot(LoggingMixin):
*, *,
exit_tag: Optional[str] = None, exit_tag: Optional[str] = None,
ordertype: Optional[str] = None, ordertype: Optional[str] = None,
partial: float = None,
) -> bool: ) -> bool:
""" """
Executes a trade exit for the given trade and limit 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), self.strategy.lock_pair(trade.pair, datetime.now(timezone.utc),
reason='Auto lock') 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 # In case of market sell orders the order can be closed immediately
if order.get('status', 'unknown') in ('closed', 'expired'): 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)
@ -1233,7 +1235,7 @@ class FreqtradeBot(LoggingMixin):
return True 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. Sends rpc notification when a sell occurred.
""" """
@ -1264,8 +1266,10 @@ class FreqtradeBot(LoggingMixin):
'sell_reason': trade.sell_reason, 'sell_reason': trade.sell_reason,
'open_date': trade.open_date, 'open_date': trade.open_date,
'close_date': trade.close_date or datetime.utcnow(), 'close_date': trade.close_date or datetime.utcnow(),
'stake_amount': trade.stake_amount,
'stake_currency': self.config['stake_currency'], 'stake_currency': self.config['stake_currency'],
'fiat_currency': self.config.get('fiat_display_currency', None), 'fiat_currency': self.config.get('fiat_display_currency', None),
'partial': partial,
} }
if 'fiat_display_currency' in self.config: if 'fiat_display_currency' in self.config:

View File

@ -476,6 +476,17 @@ class LocalTrade():
elif order_type in ('market', 'limit') and order['side'] == 'sell': elif order_type in ('market', 'limit') and order['side'] == 'sell':
if self.is_open: if self.is_open:
logger.info(f'{order_type.upper()}_SELL has been fulfilled for {self}.') logger.info(f'{order_type.upper()}_SELL has been fulfilled for {self}.')
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')) self.close(safe_value_fallback(order, 'average', 'price'))
elif order_type in ('stop_loss_limit', 'stop-loss', 'stop-loss-limit', 'stop'): elif order_type in ('stop_loss_limit', 'stop-loss', 'stop-loss-limit', 'stop'):
self.stoploss_order_id = None self.stoploss_order_id = None
@ -488,6 +499,8 @@ class LocalTrade():
raise ValueError(f'Unknown order type: {order_type}') raise ValueError(f'Unknown order type: {order_type}')
Trade.commit() 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: def close(self, rate: float, *, show_msg: bool = True) -> None:
""" """
Sets close_rate to the given rate, calculates total profit Sets close_rate to the given rate, calculates total profit

View File

@ -235,13 +235,26 @@ class Telegram(RPCHandler):
if msg['type'] == RPCMessageType.BUY_FILL: if msg['type'] == RPCMessageType.BUY_FILL:
message += f"*Open Rate:* `{msg['open_rate']:.8f}`\n" message += f"*Open Rate:* `{msg['open_rate']:.8f}`\n"
total = msg['amount'] * msg['open_rate']
elif msg['type'] == RPCMessageType.BUY: elif msg['type'] == RPCMessageType.BUY:
message += f"*Open Rate:* `{msg['limit']:.8f}`\n"\ message += f"*Open Rate:* `{msg['limit']:.8f}`\n"\
f"*Current Rate:* `{msg['current_rate']:.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'])}" message += f"*Total:* `({round_coin_value(msg['stake_amount'], msg['stake_currency'])}"
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'])}"
if msg.get('fiat_currency', None): if msg.get('fiat_currency', None):
message += f", {round_coin_value(msg['stake_amount_fiat'], msg['fiat_currency'])}" message += f", {round_coin_value(msg['stake_amount_fiat'], msg['fiat_currency'])}"
@ -287,7 +300,18 @@ class Telegram(RPCHandler):
elif msg['type'] == RPCMessageType.SELL_FILL: elif msg['type'] == RPCMessageType.SELL_FILL:
message += f"*Close Rate:* `{msg['close_rate']:.8f}`" 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 return message
def compose_message(self, msg: Dict[str, Any], msg_type: RPCMessageType) -> str: def compose_message(self, msg: Dict[str, Any], msg_type: RPCMessageType) -> str: