diff --git a/README.md b/README.md index dcd978ae3..60157a25f 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,7 @@ Telegram is not mandatory. However, this is a great way to control your bot. Mor - `/status |[table]`: Lists all or specific open trades. - `/profit []`: Lists cumulative profit from all finished trades, over the last n days. - `/force_exit |all`: Instantly exits the given trade (Ignoring `minimum_roi`). +- `/fe |all`: Alias to `/force_exit` - `/performance`: Show performance of each finished trade grouped by pair - `/balance`: Show account balance per currency. - `/daily `: Shows profit or loss per day, over the last n days. diff --git a/docs/rest-api.md b/docs/rest-api.md index fccd8a8c7..2b395a0ad 100644 --- a/docs/rest-api.md +++ b/docs/rest-api.md @@ -147,8 +147,8 @@ python3 scripts/rest_client.py --config rest_config.json [optional par | `profit` | Display a summary of your profit/loss from close trades and some stats about your performance. | `force_exit ` | Instantly exits the given trade (Ignoring `minimum_roi`). | `force_exit all` | Instantly exits all open trades (Ignoring `minimum_roi`). -| `forceenter [rate]` | Instantly enters the given pair. Rate is optional. (`forcebuy_enable` must be set to True) -| `forceenter [rate]` | Instantly longs or shorts the given pair. Rate is optional. (`forcebuy_enable` must be set to True) +| `force_enter [rate]` | Instantly enters the given pair. Rate is optional. (`forcebuy_enable` must be set to True) +| `force_enter [rate]` | Instantly longs or shorts the given pair. Rate is optional. (`forcebuy_enable` must be set to True) | `performance` | Show performance of each finished trade grouped by pair. | `balance` | Show account balance per currency. | `daily ` | Shows profit or loss per day, over the last n days (n defaults to 7). @@ -216,7 +216,7 @@ forcebuy :param pair: Pair to buy (ETH/BTC) :param price: Optional - price to buy -forceenter +force_enter Force entering a trade :param pair: Pair to buy (ETH/BTC) diff --git a/docs/strategy_migration.md b/docs/strategy_migration.md index 4db65bcec..2ae4c17e2 100644 --- a/docs/strategy_migration.md +++ b/docs/strategy_migration.md @@ -9,6 +9,8 @@ You can use the quick summary as checklist. Please refer to the detailed section ## Quick summary / migration checklist +Note : `force_exit`, `force_enter`, `emergency_exit` are changed to `force_exit`, `force_enter`, `emergency_exit` respectively. + * Strategy methods: * [`populate_buy_trend()` -> `populate_entry_trend()`](#populate_buy_trend) * [`populate_sell_trend()` -> `populate_exit_trend()`](#populate_sell_trend) @@ -331,6 +333,7 @@ After: #### `order_types` `order_types` have changed all wordings from `buy` to `entry` - and `sell` to `exit`. +And two words are joined with `_`. ``` python hl_lines="2-6" order_types = { diff --git a/freqtrade/configuration/config_validation.py b/freqtrade/configuration/config_validation.py index 073103f1c..602db2c9d 100644 --- a/freqtrade/configuration/config_validation.py +++ b/freqtrade/configuration/config_validation.py @@ -243,7 +243,7 @@ def _validate_time_in_force(conf: Dict[str, Any]) -> None: def _validate_order_types(conf: Dict[str, Any]) -> None: order_types = conf.get('order_types', {}) - if any(x in order_types for x in ['buy', 'sell', 'emergencysell', 'forcebuy', 'forcesell']): + if any(x in order_types for x in ['buy', 'sell', 'emergencysell', 'forcebuy', 'forcesell', 'emergencyexit', 'forceexit', 'forceentry']): if conf.get('trading_mode', TradingMode.SPOT) != TradingMode.SPOT: raise OperationalException( "Please migrate your order_types settings to use the new wording.") @@ -258,6 +258,9 @@ def _validate_order_types(conf: Dict[str, Any]) -> None: ('emergencysell', 'emergency_exit'), ('forcesell', 'force_exit'), ('forcebuy', 'force_entry'), + ('emergencyexit', 'emergency_exit'), + ('forceexit', 'force_exit'), + ('forceentry', 'force_entry'), ]: process_deprecated_setting(conf, 'order_types', o, 'order_types', n) diff --git a/freqtrade/rpc/api_server/api_schemas.py b/freqtrade/rpc/api_server/api_schemas.py index 4002e955a..dc8e0cd23 100644 --- a/freqtrade/rpc/api_server/api_schemas.py +++ b/freqtrade/rpc/api_server/api_schemas.py @@ -316,7 +316,7 @@ class ForceEnterPayload(BaseModel): entry_tag: Optional[str] -class Force_exitPayload(BaseModel): +class ForceExitPayload(BaseModel): tradeid: str ordertype: Optional[OrderTypeValues] diff --git a/freqtrade/rpc/api_server/api_v1.py b/freqtrade/rpc/api_server/api_v1.py index aaefe3a5e..8bda34dc6 100644 --- a/freqtrade/rpc/api_server/api_v1.py +++ b/freqtrade/rpc/api_server/api_v1.py @@ -15,7 +15,7 @@ from freqtrade.rpc import RPC from freqtrade.rpc.api_server.api_schemas import (AvailablePairs, Balances, BlacklistPayload, BlacklistResponse, Count, Daily, DeleteLockRequest, DeleteTrade, ForceEnterPayload, - ForceEnterResponse, Force_exitPayload, Health, + ForceEnterResponse, ForceExitPayload, Health, Locks, Logs, OpenTradeSchema, PairHistory, PerformanceEntry, Ping, PlotConfig, Profit, ResultMsg, ShowConfig, Stats, StatusMsg, @@ -136,7 +136,7 @@ def show_config(rpc: Optional[RPC] = Depends(get_rpc_optional), config=Depends(g # /forcebuy is deprecated with short addition. use Force_entry instead -@router.post('/forceenter', response_model=ForceEnterResponse, tags=['trading']) +@router.post('/force_enter', response_model=ForceEnterResponse, tags=['trading']) @router.post('/forcebuy', response_model=ForceEnterResponse, tags=['trading']) def force_entry(payload: ForceEnterPayload, rpc: RPC = Depends(get_rpc)): ordertype = payload.ordertype.value if payload.ordertype else None @@ -156,7 +156,7 @@ def force_entry(payload: ForceEnterPayload, rpc: RPC = Depends(get_rpc)): @router.post('/force_exit', response_model=ResultMsg, tags=['trading']) @router.post('/forcesell', response_model=ResultMsg, tags=['trading']) -def forcesell(payload: Force_exitPayload, rpc: RPC = Depends(get_rpc)): +def forcesell(payload: ForceExitPayload, rpc: RPC = Depends(get_rpc)): ordertype = payload.ordertype.value if payload.ordertype else None return rpc._rpc_force_exit(payload.tradeid, ordertype) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index a365b1b7e..490ab846e 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -115,7 +115,7 @@ class Telegram(RPCHandler): r'/stopbuy$', r'/reload_config$', r'/show_config$', r'/logs$', r'/whitelist$', r'/blacklist$', r'/bl_delete$', r'/weekly$', r'/weekly \d+$', r'/monthly$', r'/monthly \d+$', - r'/forcebuy$', r'/forcelong$', r'/forceshort$', + r'/forcebuy$', r'/forcelong$', r'/forceshort$', r'/force_exit$', r'/edge$', r'/health$', r'/help$', r'/version$'] # Create keys for generation valid_keys_print = [k.replace('$', '') for k in valid_keys] @@ -153,11 +153,11 @@ class Telegram(RPCHandler): CommandHandler('balance', self._balance), CommandHandler('start', self._start), CommandHandler('stop', self._stop), - CommandHandler(['forcesell', 'force_exit'], self._force_exit), + CommandHandler(['forcesell', 'force_exit', 'fe'], self._force_exit), CommandHandler(['forcebuy', 'forcelong'], partial( - self._forceenter, order_side=SignalDirection.LONG)), + self._force_enter, order_side=SignalDirection.LONG)), CommandHandler('forceshort', partial( - self._forceenter, order_side=SignalDirection.SHORT)), + self._force_enter, order_side=SignalDirection.SHORT)), CommandHandler('trades', self._trades), CommandHandler('delete', self._delete_trade), CommandHandler('performance', self._performance), @@ -197,7 +197,7 @@ class Telegram(RPCHandler): pattern='update_exit_reason_performance'), CallbackQueryHandler(self._mix_tag_performance, pattern='update_mix_tag_performance'), CallbackQueryHandler(self._count, pattern='update_count'), - CallbackQueryHandler(self._forceenter_inline), + CallbackQueryHandler(self._force_enter_inline), ] for handle in handles: self._updater.dispatcher.add_handler(handle) @@ -946,14 +946,14 @@ class Telegram(RPCHandler): except RPCException as e: self._send_msg(str(e)) - def _forceenter_action(self, pair, price: Optional[float], order_side: SignalDirection): + def _force_enter_action(self, pair, price: Optional[float], order_side: SignalDirection): if pair != 'cancel': try: self._rpc._rpc_force_entry(pair, price, order_side=order_side) except RPCException as e: self._send_msg(str(e)) - def _forceenter_inline(self, update: Update, _: CallbackContext) -> None: + def _force_enter_inline(self, update: Update, _: CallbackContext) -> None: if update.callback_query: query = update.callback_query if query.data and '_||_' in query.data: @@ -961,7 +961,7 @@ class Telegram(RPCHandler): order_side = SignalDirection(side) query.answer() query.edit_message_text(text=f"Manually entering {order_side} for {pair}") - self._forceenter_action(pair, None, order_side) + self._force_enter_action(pair, None, order_side) @staticmethod def _layout_inline_keyboard(buttons: List[InlineKeyboardButton], @@ -969,7 +969,7 @@ class Telegram(RPCHandler): return [buttons[i:i + cols] for i in range(0, len(buttons), cols)] @authorized_only - def _forceenter( + def _force_enter( self, update: Update, context: CallbackContext, order_side: SignalDirection) -> None: """ Handler for /forcelong and `/forceshort @@ -981,7 +981,7 @@ class Telegram(RPCHandler): if context.args: pair = context.args[0] price = float(context.args[1]) if len(context.args) > 1 else None - self._forceenter_action(pair, price, order_side) + self._force_enter_action(pair, price, order_side) else: whitelist = self._rpc._rpc_whitelist()['whitelist'] pair_buttons = [ @@ -1359,12 +1359,12 @@ class Telegram(RPCHandler): :param update: message update :return: None """ - forceenter_text = ("*/forcelong []:* `Instantly buys the given pair. " + force_enter_text = ("*/forcelong []:* `Instantly buys the given pair. " "Optionally takes a rate at which to buy " "(only applies to limit orders).` \n" ) if self._rpc._freqtrade.trading_mode != TradingMode.SPOT: - forceenter_text += ("*/forceshort []:* `Instantly shorts the given pair. " + force_enter_text += ("*/forceshort []:* `Instantly shorts the given pair. " "Optionally takes a rate at which to sell " "(only applies to limit orders).` \n") message = ( @@ -1375,7 +1375,8 @@ class Telegram(RPCHandler): "*/stopbuy:* `Stops buying, but handles open trades gracefully` \n" "*/force_exit |all:* `Instantly exits the given trade or all trades, " "regardless of profit`\n" - f"{forceenter_text if self._config.get('forcebuy_enable', False) else ''}" + "*/fe |all:* `Alias to /force_exit`" + f"{force_enter_text if self._config.get('forcebuy_enable', False) else ''}" "*/delete :* `Instantly delete the given trade in the database`\n" "*/whitelist:* `Show current whitelist` \n" "*/blacklist [pair]:* `Show current blacklist, or adds one or more pairs " diff --git a/scripts/rest_client.py b/scripts/rest_client.py index e23954dd4..9c5f820b9 100755 --- a/scripts/rest_client.py +++ b/scripts/rest_client.py @@ -261,7 +261,7 @@ class FtRestClient(): } return self._post("forcebuy", data=data) - def forceenter(self, pair, side, price=None): + def force_enter(self, pair, side, price=None): """Force entering a trade :param pair: Pair to buy (ETH/BTC) @@ -273,7 +273,7 @@ class FtRestClient(): "side": side, "price": price, } - return self._post("forceenter", data=data) + return self._post("force_enter", data=data) def forcesell(self, tradeid): """Force-sell a trade. diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index 992e4edf7..3f3cc69e2 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -1075,7 +1075,7 @@ def test_api_whitelist(botclient): @pytest.mark.parametrize('endpoint', [ 'forcebuy', - 'forceenter', + 'force_enter', ]) def test_api_force_entry(botclient, mocker, fee, endpoint): ftbot, client = botclient diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 4124e7279..f7d7940e7 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -1231,7 +1231,7 @@ def test_forcesell_handle_invalid(default_conf, update, mocker) -> None: assert 'invalid argument' in msg_mock.call_args_list[0][0][0] -def test_forceenter_handle(default_conf, update, mocker) -> None: +def test_force_enter_handle(default_conf, update, mocker) -> None: mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0) fbuy_mock = MagicMock(return_value=None) @@ -1243,7 +1243,7 @@ def test_forceenter_handle(default_conf, update, mocker) -> None: # /forcelong ETH/BTC context = MagicMock() context.args = ["ETH/BTC"] - telegram._forceenter(update=update, context=context, order_side=SignalDirection.LONG) + telegram._force_enter(update=update, context=context, order_side=SignalDirection.LONG) assert fbuy_mock.call_count == 1 assert fbuy_mock.call_args_list[0][0][0] == 'ETH/BTC' @@ -1256,7 +1256,7 @@ def test_forceenter_handle(default_conf, update, mocker) -> None: # /forcelong ETH/BTC 0.055 context = MagicMock() context.args = ["ETH/BTC", "0.055"] - telegram._forceenter(update=update, context=context, order_side=SignalDirection.LONG) + telegram._force_enter(update=update, context=context, order_side=SignalDirection.LONG) assert fbuy_mock.call_count == 1 assert fbuy_mock.call_args_list[0][0][0] == 'ETH/BTC' @@ -1264,20 +1264,20 @@ def test_forceenter_handle(default_conf, update, mocker) -> None: assert fbuy_mock.call_args_list[0][0][1] == 0.055 -def test_forceenter_handle_exception(default_conf, update, mocker) -> None: +def test_force_enter_handle_exception(default_conf, update, mocker) -> None: mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0) telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf) patch_get_signal(freqtradebot) update.message.text = '/forcebuy ETH/Nonepair' - telegram._forceenter(update=update, context=MagicMock(), order_side=SignalDirection.LONG) + telegram._force_enter(update=update, context=MagicMock(), order_side=SignalDirection.LONG) assert msg_mock.call_count == 1 assert msg_mock.call_args_list[0][0][0] == 'Force_entry not enabled.' -def test_forceenter_no_pair(default_conf, update, mocker) -> None: +def test_force_enter_no_pair(default_conf, update, mocker) -> None: mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0) fbuy_mock = MagicMock(return_value=None) @@ -1289,7 +1289,7 @@ def test_forceenter_no_pair(default_conf, update, mocker) -> None: context = MagicMock() context.args = [] - telegram._forceenter(update=update, context=context, order_side=SignalDirection.LONG) + telegram._force_enter(update=update, context=context, order_side=SignalDirection.LONG) assert fbuy_mock.call_count == 0 assert msg_mock.call_count == 1 @@ -1301,7 +1301,7 @@ def test_forceenter_no_pair(default_conf, update, mocker) -> None: update = MagicMock() update.callback_query = MagicMock() update.callback_query.data = 'XRP/USDT_||_long' - telegram._forceenter_inline(update, None) + telegram._force_enter_inline(update, None) assert fbuy_mock.call_count == 1