add /stopentry alias for /stopbuy

This commit is contained in:
Matthias 2022-08-28 11:32:53 +02:00
parent 59a723aec8
commit b9f35cadb3
11 changed files with 45 additions and 34 deletions

View File

@ -130,7 +130,7 @@ Telegram is not mandatory. However, this is a great way to control your bot. Mor
- `/start`: Starts the trader.
- `/stop`: Stops the trader.
- `/stopbuy`: Stop entering new trades.
- `/stopentry`: Stop entering new trades.
- `/status <trade_id>|[table]`: Lists all or specific open trades.
- `/profit [<n>]`: Lists cumulative profit from all finished trades, over the last n days.
- `/forceexit <trade_id>|all`: Instantly exits the given trade (Ignoring `minimum_roi`).

View File

@ -77,9 +77,9 @@ Freqtrade will not provide incomplete candles to strategies. Using incomplete ca
You can use "current" market data by using the [dataprovider](strategy-customization.md#orderbookpair-maximum)'s orderbook or ticker methods - which however cannot be used during backtesting.
### Is there a setting to only SELL the coins being held and not perform anymore BUYS?
### Is there a setting to only Exit the trades being held and not perform any new Entries?
You can use the `/stopbuy` command in Telegram to prevent future buys, followed by `/forceexit all` (sell all open trades).
You can use the `/stopentry` command in Telegram to prevent future trade entry, followed by `/forceexit all` (sell all open trades).
### I want to run multiple bots on the same machine

View File

@ -654,7 +654,7 @@ Position adjustments will always be applied in the direction of the trade, so a
Stoploss is still calculated from the initial opening price, not averaged price.
Regular stoploss rules still apply (cannot move down).
While `/stopbuy` command stops the bot from entering new trades, the position adjustment feature will continue buying new orders on existing trades.
While `/stopentry` command stops the bot from entering new trades, the position adjustment feature will continue buying new orders on existing trades.
!!! Warning "Backtesting"
During backtesting this callback is called for each candle in `timeframe` or `timeframe_detail`, so run-time performance will be affected.

View File

@ -149,7 +149,7 @@ You can create your own keyboard in `config.json`:
!!! Note "Supported Commands"
Only the following commands are allowed. Command arguments are not supported!
`/start`, `/stop`, `/status`, `/status table`, `/trades`, `/profit`, `/performance`, `/daily`, `/stats`, `/count`, `/locks`, `/balance`, `/stopbuy`, `/reload_config`, `/show_config`, `/logs`, `/whitelist`, `/blacklist`, `/edge`, `/help`, `/version`
`/start`, `/stop`, `/status`, `/status table`, `/trades`, `/profit`, `/performance`, `/daily`, `/stats`, `/count`, `/locks`, `/balance`, `/stopentry`, `/reload_config`, `/show_config`, `/logs`, `/whitelist`, `/blacklist`, `/edge`, `/help`, `/version`
## Telegram commands
@ -161,7 +161,7 @@ official commands. You can ask at any moment for help with `/help`.
|----------|-------------|
| `/start` | Starts the trader
| `/stop` | Stops the trader
| `/stopbuy` | Stops the trader from opening new trades. Gracefully closes open trades according to their rules.
| `/stopbuy | /stopentry` | Stops the trader from opening new trades. Gracefully closes open trades according to their rules.
| `/reload_config` | Reloads the configuration file
| `/show_config` | Shows part of the current configuration with relevant settings to operation
| `/logs [limit]` | Show last log messages.

View File

@ -239,7 +239,7 @@ class FreqtradeBot(LoggingMixin):
'status':
f"{len(open_trades)} open trades active.\n\n"
f"Handle these trades manually on {self.exchange.name}, "
f"or '/start' the bot again and use '/stopbuy' "
f"or '/start' the bot again and use '/stopentry' "
f"to handle open trades gracefully. \n"
f"{'Note: Trades are simulated (dry run).' if self.config['dry_run'] else ''}",
}

View File

@ -216,9 +216,10 @@ def stop(rpc: RPC = Depends(get_rpc)):
return rpc._rpc_stop()
@router.post('/stopentry', response_model=StatusMsg, tags=['botcontrol'])
@router.post('/stopbuy', response_model=StatusMsg, tags=['botcontrol'])
def stop_buy(rpc: RPC = Depends(get_rpc)):
return rpc._rpc_stopbuy()
return rpc._rpc_stopentry()
@router.post('/reload_config', response_model=StatusMsg, tags=['botcontrol'])

View File

@ -657,7 +657,7 @@ class RPC:
self._freqtrade.state = State.RELOAD_CONFIG
return {'status': 'Reloading config ...'}
def _rpc_stopbuy(self) -> Dict[str, str]:
def _rpc_stopentry(self) -> Dict[str, str]:
"""
Handler to stop buying, but handle open trades gracefully.
"""
@ -665,7 +665,7 @@ class RPC:
# Set 'max_open_trades' to 0
self._freqtrade.config['max_open_trades'] = 0
return {'status': 'No more buy will occur from now. Run /reload_config to reset.'}
return {'status': 'No more entries will occur from now. Run /reload_config to reset.'}
def __exec_force_exit(self, trade: Trade, ordertype: Optional[str],
amount: Optional[float] = None) -> None:

View File

@ -114,18 +114,20 @@ class Telegram(RPCHandler):
# TODO: DRY! - its not good to list all valid cmds here. But otherwise
# this needs refactoring of the whole telegram module (same
# problem in _help()).
valid_keys: List[str] = [r'/start$', r'/stop$', r'/status$', r'/status table$',
valid_keys: List[str] = [
r'/start$', r'/stop$', r'/status$', r'/status table$',
r'/trades$', r'/performance$', r'/buys', r'/entries',
r'/sells', r'/exits', r'/mix_tags',
r'/daily$', r'/daily \d+$', r'/profit$', r'/profit \d+',
r'/stats$', r'/count$', r'/locks$', r'/balance$',
r'/stopbuy$', r'/reload_config$', r'/show_config$',
r'/stopbuy$', r'/stopentry$', r'/reload_config$', r'/show_config$',
r'/logs$', r'/whitelist$', r'/whitelist(\ssorted|\sbaseonly)+$',
r'/blacklist$', r'/bl_delete$',
r'/weekly$', r'/weekly \d+$', r'/monthly$', r'/monthly \d+$',
r'/forcebuy$', r'/forcelong$', r'/forceshort$',
r'/forcesell$', r'/forceexit$',
r'/edge$', r'/health$', r'/help$', r'/version$']
r'/edge$', r'/health$', r'/help$', r'/version$'
]
# Create keys for generation
valid_keys_print = [k.replace('$', '') for k in valid_keys]
@ -182,7 +184,7 @@ class Telegram(RPCHandler):
CommandHandler(['unlock', 'delete_locks'], self._delete_locks),
CommandHandler(['reload_config', 'reload_conf'], self._reload_config),
CommandHandler(['show_config', 'show_conf'], self._show_config),
CommandHandler('stopbuy', self._stopbuy),
CommandHandler(['stopbuy', 'stopentry'], self._stopentry),
CommandHandler('whitelist', self._whitelist),
CommandHandler('blacklist', self._blacklist),
CommandHandler(['blacklist_delete', 'bl_delete'], self._blacklist_delete),
@ -984,7 +986,7 @@ class Telegram(RPCHandler):
self._send_msg(f"Status: `{msg['status']}`")
@authorized_only
def _stopbuy(self, update: Update, context: CallbackContext) -> None:
def _stopentry(self, update: Update, context: CallbackContext) -> None:
"""
Handler for /stop_buy.
Sets max_open_trades to 0 and gracefully sells all open trades
@ -992,7 +994,7 @@ class Telegram(RPCHandler):
:param update: message update
:return: None
"""
msg = self._rpc._rpc_stopbuy()
msg = self._rpc._rpc_stopentry()
self._send_msg(f"Status: `{msg['status']}`")
@authorized_only
@ -1488,7 +1490,7 @@ class Telegram(RPCHandler):
"------------\n"
"*/start:* `Starts the trader`\n"
"*/stop:* Stops the trader\n"
"*/stopbuy:* `Stops buying, but handles open trades gracefully` \n"
"*/stopentry:* `Stops entering, but handles open trades gracefully` \n"
"*/forceexit <trade_id>|all:* `Instantly exits the given trade or all trades, "
"regardless of profit`\n"
"*/fx <trade_id>|all:* `Alias to /forceexit`\n"

View File

@ -663,7 +663,7 @@ def test_rpc_stop(mocker, default_conf) -> None:
assert freqtradebot.state == State.STOPPED
def test_rpc_stopbuy(mocker, default_conf) -> None:
def test_rpc_stopentry(mocker, default_conf) -> None:
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
@ -676,8 +676,8 @@ def test_rpc_stopbuy(mocker, default_conf) -> None:
freqtradebot.state = State.RUNNING
assert freqtradebot.config['max_open_trades'] != 0
result = rpc._rpc_stopbuy()
assert {'status': 'No more buy will occur from now. Run /reload_config to reset.'} == result
result = rpc._rpc_stopentry()
assert {'status': 'No more entries will occur from now. Run /reload_config to reset.'} == result
assert freqtradebot.config['max_open_trades'] == 0

View File

@ -422,13 +422,20 @@ def test_api_reloadconf(botclient):
assert ftbot.state == State.RELOAD_CONFIG
def test_api_stopbuy(botclient):
def test_api_stopentry(botclient):
ftbot, client = botclient
assert ftbot.config['max_open_trades'] != 0
rc = client_post(client, f"{BASE_URI}/stopbuy")
assert_response(rc)
assert rc.json() == {'status': 'No more buy will occur from now. Run /reload_config to reset.'}
assert rc.json() == {
'status': 'No more entries will occur from now. Run /reload_config to reset.'}
assert ftbot.config['max_open_trades'] == 0
rc = client_post(client, f"{BASE_URI}/stopentry")
assert_response(rc)
assert rc.json() == {
'status': 'No more entries will occur from now. Run /reload_config to reset.'}
assert ftbot.config['max_open_trades'] == 0

View File

@ -103,7 +103,8 @@ def test_telegram_init(default_conf, mocker, caplog) -> None:
"['stats'], ['daily'], ['weekly'], ['monthly'], "
"['count'], ['locks'], ['unlock', 'delete_locks'], "
"['reload_config', 'reload_conf'], ['show_config', 'show_conf'], "
"['stopbuy'], ['whitelist'], ['blacklist'], ['blacklist_delete', 'bl_delete'], "
"['stopbuy', 'stopentry'], ['whitelist'], ['blacklist'], "
"['blacklist_delete', 'bl_delete'], "
"['logs'], ['edge'], ['health'], ['help'], ['version']"
"]")
@ -896,10 +897,10 @@ def test_stopbuy_handle(default_conf, update, mocker) -> None:
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
assert freqtradebot.config['max_open_trades'] != 0
telegram._stopbuy(update=update, context=MagicMock())
telegram._stopentry(update=update, context=MagicMock())
assert freqtradebot.config['max_open_trades'] == 0
assert msg_mock.call_count == 1
assert 'No more buy will occur from now. Run /reload_config to reset.' \
assert 'No more entries will occur from now. Run /reload_config to reset.' \
in msg_mock.call_args_list[0][0][0]