From 82aecc81f393e98b86115e9bdfa46dac1a143fad Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 2 Aug 2022 19:53:10 +0200 Subject: [PATCH] Accept parameters to forceexit --- freqtrade/rpc/api_server/api_schemas.py | 1 + freqtrade/rpc/api_server/api_v1.py | 2 +- freqtrade/rpc/rpc.py | 22 +++++++++++++++++----- scripts/rest_client.py | 10 ++++++++-- 4 files changed, 27 insertions(+), 8 deletions(-) diff --git a/freqtrade/rpc/api_server/api_schemas.py b/freqtrade/rpc/api_server/api_schemas.py index 333f2fe6e..d2a584136 100644 --- a/freqtrade/rpc/api_server/api_schemas.py +++ b/freqtrade/rpc/api_server/api_schemas.py @@ -330,6 +330,7 @@ class ForceEnterPayload(BaseModel): class ForceExitPayload(BaseModel): tradeid: str ordertype: Optional[OrderTypeValues] + amount: Optional[float] class BlacklistPayload(BaseModel): diff --git a/freqtrade/rpc/api_server/api_v1.py b/freqtrade/rpc/api_server/api_v1.py index b3506409d..29e4fb75a 100644 --- a/freqtrade/rpc/api_server/api_v1.py +++ b/freqtrade/rpc/api_server/api_v1.py @@ -161,7 +161,7 @@ def force_entry(payload: ForceEnterPayload, rpc: RPC = Depends(get_rpc)): @router.post('/forcesell', response_model=ResultMsg, tags=['trading']) def forceexit(payload: ForceExitPayload, rpc: RPC = Depends(get_rpc)): ordertype = payload.ordertype.value if payload.ordertype else None - return rpc._rpc_force_exit(payload.tradeid, ordertype) + return rpc._rpc_force_exit(payload.tradeid, ordertype, amount=payload.amount) @router.get('/blacklist', response_model=BlacklistResponse, tags=['info', 'pairlist']) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index d848da546..340adea43 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -660,12 +660,15 @@ class RPC: return {'status': 'No more buy will occur from now. Run /reload_config to reset.'} - def _rpc_force_exit(self, trade_id: str, ordertype: Optional[str] = None) -> Dict[str, str]: + def _rpc_force_exit(self, trade_id: str, ordertype: Optional[str] = None, *, + amount: Optional[float]) -> Dict[str, str]: """ Handler for forceexit . Sells the given trade at current price """ - def _exec_force_exit(trade: Trade) -> None: + + def _exec_force_exit(trade: Trade, ordertype: Optional[str], + _amount: Optional[float] = None) -> None: # Check if there is there is an open order fully_canceled = False if trade.open_order_id: @@ -686,10 +689,19 @@ class RPC: exit_check = ExitCheckTuple(exit_type=ExitType.FORCE_EXIT) order_type = ordertype or self._freqtrade.strategy.order_types.get( "force_exit", self._freqtrade.strategy.order_types["exit"]) + sub_amount: float = None + if _amount and _amount < trade.amount: + # Partial exit ... + min_exit_stake = self._freqtrade.exchange.get_min_pair_stake_amount( + trade.pair, current_rate, trade.stop_loss_pct) + remaining = (trade.amount - _amount) * current_rate + if remaining < min_exit_stake: + raise RPCException(f'Remaining amount of {remaining} would be too small.') + sub_amount = _amount self._freqtrade.execute_trade_exit( - trade, current_rate, exit_check, ordertype=order_type) - # ---- EOF def _exec_forcesell ---- + trade, current_rate, exit_check, ordertype=order_type, + sub_trade_amt=sub_amount) if self._freqtrade.state != State.RUNNING: raise RPCException('trader is not running') @@ -711,7 +723,7 @@ class RPC: logger.warning('force_exit: Invalid argument received') raise RPCException('invalid argument') - _exec_force_exit(trade) + _exec_force_exit(trade, ordertype, amount) Trade.commit() self._freqtrade.wallets.update() return {'result': f'Created sell order for trade {trade_id}.'} diff --git a/scripts/rest_client.py b/scripts/rest_client.py index e5d358c98..989e6a50d 100755 --- a/scripts/rest_client.py +++ b/scripts/rest_client.py @@ -275,14 +275,20 @@ class FtRestClient(): } return self._post("forceenter", data=data) - def forceexit(self, tradeid): + def forceexit(self, tradeid, ordertype=None, amount=None): """Force-exit a trade. :param tradeid: Id of the trade (can be received via status command) + :param ordertype: Order type to use (must be market or limit) + :param amount: Amount to sell. Full sell if not given :return: json object """ - return self._post("forceexit", data={"tradeid": tradeid}) + return self._post("forceexit", data={ + "tradeid": tradeid, + "ordertype": ordertype, + "amount": amount, + }) def strategies(self): """Lists available strategies