mirror of
https://github.com/freqtrade/freqtrade.git
synced 2024-11-12 19:23:55 +00:00
add /stopentry alias for /stopbuy
This commit is contained in:
parent
59a723aec8
commit
b9f35cadb3
|
@ -130,7 +130,7 @@ Telegram is not mandatory. However, this is a great way to control your bot. Mor
|
||||||
|
|
||||||
- `/start`: Starts the trader.
|
- `/start`: Starts the trader.
|
||||||
- `/stop`: Stops 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.
|
- `/status <trade_id>|[table]`: Lists all or specific open trades.
|
||||||
- `/profit [<n>]`: Lists cumulative profit from all finished trades, over the last n days.
|
- `/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`).
|
- `/forceexit <trade_id>|all`: Instantly exits the given trade (Ignoring `minimum_roi`).
|
||||||
|
|
|
@ -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.
|
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
|
### I want to run multiple bots on the same machine
|
||||||
|
|
||||||
|
|
|
@ -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.
|
Stoploss is still calculated from the initial opening price, not averaged price.
|
||||||
Regular stoploss rules still apply (cannot move down).
|
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"
|
!!! Warning "Backtesting"
|
||||||
During backtesting this callback is called for each candle in `timeframe` or `timeframe_detail`, so run-time performance will be affected.
|
During backtesting this callback is called for each candle in `timeframe` or `timeframe_detail`, so run-time performance will be affected.
|
||||||
|
|
|
@ -149,7 +149,7 @@ You can create your own keyboard in `config.json`:
|
||||||
!!! Note "Supported Commands"
|
!!! Note "Supported Commands"
|
||||||
Only the following commands are allowed. Command arguments are not supported!
|
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
|
## Telegram commands
|
||||||
|
|
||||||
|
@ -161,7 +161,7 @@ official commands. You can ask at any moment for help with `/help`.
|
||||||
|----------|-------------|
|
|----------|-------------|
|
||||||
| `/start` | Starts the trader
|
| `/start` | Starts the trader
|
||||||
| `/stop` | Stops 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
|
| `/reload_config` | Reloads the configuration file
|
||||||
| `/show_config` | Shows part of the current configuration with relevant settings to operation
|
| `/show_config` | Shows part of the current configuration with relevant settings to operation
|
||||||
| `/logs [limit]` | Show last log messages.
|
| `/logs [limit]` | Show last log messages.
|
||||||
|
|
|
@ -239,7 +239,7 @@ class FreqtradeBot(LoggingMixin):
|
||||||
'status':
|
'status':
|
||||||
f"{len(open_trades)} open trades active.\n\n"
|
f"{len(open_trades)} open trades active.\n\n"
|
||||||
f"Handle these trades manually on {self.exchange.name}, "
|
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"to handle open trades gracefully. \n"
|
||||||
f"{'Note: Trades are simulated (dry run).' if self.config['dry_run'] else ''}",
|
f"{'Note: Trades are simulated (dry run).' if self.config['dry_run'] else ''}",
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,9 +216,10 @@ def stop(rpc: RPC = Depends(get_rpc)):
|
||||||
return rpc._rpc_stop()
|
return rpc._rpc_stop()
|
||||||
|
|
||||||
|
|
||||||
|
@router.post('/stopentry', response_model=StatusMsg, tags=['botcontrol'])
|
||||||
@router.post('/stopbuy', response_model=StatusMsg, tags=['botcontrol'])
|
@router.post('/stopbuy', response_model=StatusMsg, tags=['botcontrol'])
|
||||||
def stop_buy(rpc: RPC = Depends(get_rpc)):
|
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'])
|
@router.post('/reload_config', response_model=StatusMsg, tags=['botcontrol'])
|
||||||
|
|
|
@ -657,7 +657,7 @@ class RPC:
|
||||||
self._freqtrade.state = State.RELOAD_CONFIG
|
self._freqtrade.state = State.RELOAD_CONFIG
|
||||||
return {'status': 'Reloading 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.
|
Handler to stop buying, but handle open trades gracefully.
|
||||||
"""
|
"""
|
||||||
|
@ -665,7 +665,7 @@ class RPC:
|
||||||
# Set 'max_open_trades' to 0
|
# Set 'max_open_trades' to 0
|
||||||
self._freqtrade.config['max_open_trades'] = 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],
|
def __exec_force_exit(self, trade: Trade, ordertype: Optional[str],
|
||||||
amount: Optional[float] = None) -> None:
|
amount: Optional[float] = None) -> None:
|
||||||
|
|
|
@ -114,18 +114,20 @@ class Telegram(RPCHandler):
|
||||||
# TODO: DRY! - its not good to list all valid cmds here. But otherwise
|
# TODO: DRY! - its not good to list all valid cmds here. But otherwise
|
||||||
# this needs refactoring of the whole telegram module (same
|
# this needs refactoring of the whole telegram module (same
|
||||||
# problem in _help()).
|
# problem in _help()).
|
||||||
valid_keys: List[str] = [r'/start$', r'/stop$', r'/status$', r'/status table$',
|
valid_keys: List[str] = [
|
||||||
r'/trades$', r'/performance$', r'/buys', r'/entries',
|
r'/start$', r'/stop$', r'/status$', r'/status table$',
|
||||||
r'/sells', r'/exits', r'/mix_tags',
|
r'/trades$', r'/performance$', r'/buys', r'/entries',
|
||||||
r'/daily$', r'/daily \d+$', r'/profit$', r'/profit \d+',
|
r'/sells', r'/exits', r'/mix_tags',
|
||||||
r'/stats$', r'/count$', r'/locks$', r'/balance$',
|
r'/daily$', r'/daily \d+$', r'/profit$', r'/profit \d+',
|
||||||
r'/stopbuy$', r'/reload_config$', r'/show_config$',
|
r'/stats$', r'/count$', r'/locks$', r'/balance$',
|
||||||
r'/logs$', r'/whitelist$', r'/whitelist(\ssorted|\sbaseonly)+$',
|
r'/stopbuy$', r'/stopentry$', r'/reload_config$', r'/show_config$',
|
||||||
r'/blacklist$', r'/bl_delete$',
|
r'/logs$', r'/whitelist$', r'/whitelist(\ssorted|\sbaseonly)+$',
|
||||||
r'/weekly$', r'/weekly \d+$', r'/monthly$', r'/monthly \d+$',
|
r'/blacklist$', r'/bl_delete$',
|
||||||
r'/forcebuy$', r'/forcelong$', r'/forceshort$',
|
r'/weekly$', r'/weekly \d+$', r'/monthly$', r'/monthly \d+$',
|
||||||
r'/forcesell$', r'/forceexit$',
|
r'/forcebuy$', r'/forcelong$', r'/forceshort$',
|
||||||
r'/edge$', r'/health$', r'/help$', r'/version$']
|
r'/forcesell$', r'/forceexit$',
|
||||||
|
r'/edge$', r'/health$', r'/help$', r'/version$'
|
||||||
|
]
|
||||||
# Create keys for generation
|
# Create keys for generation
|
||||||
valid_keys_print = [k.replace('$', '') for k in valid_keys]
|
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(['unlock', 'delete_locks'], self._delete_locks),
|
||||||
CommandHandler(['reload_config', 'reload_conf'], self._reload_config),
|
CommandHandler(['reload_config', 'reload_conf'], self._reload_config),
|
||||||
CommandHandler(['show_config', 'show_conf'], self._show_config),
|
CommandHandler(['show_config', 'show_conf'], self._show_config),
|
||||||
CommandHandler('stopbuy', self._stopbuy),
|
CommandHandler(['stopbuy', 'stopentry'], self._stopentry),
|
||||||
CommandHandler('whitelist', self._whitelist),
|
CommandHandler('whitelist', self._whitelist),
|
||||||
CommandHandler('blacklist', self._blacklist),
|
CommandHandler('blacklist', self._blacklist),
|
||||||
CommandHandler(['blacklist_delete', 'bl_delete'], self._blacklist_delete),
|
CommandHandler(['blacklist_delete', 'bl_delete'], self._blacklist_delete),
|
||||||
|
@ -984,7 +986,7 @@ class Telegram(RPCHandler):
|
||||||
self._send_msg(f"Status: `{msg['status']}`")
|
self._send_msg(f"Status: `{msg['status']}`")
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _stopbuy(self, update: Update, context: CallbackContext) -> None:
|
def _stopentry(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /stop_buy.
|
Handler for /stop_buy.
|
||||||
Sets max_open_trades to 0 and gracefully sells all open trades
|
Sets max_open_trades to 0 and gracefully sells all open trades
|
||||||
|
@ -992,7 +994,7 @@ class Telegram(RPCHandler):
|
||||||
:param update: message update
|
:param update: message update
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
msg = self._rpc._rpc_stopbuy()
|
msg = self._rpc._rpc_stopentry()
|
||||||
self._send_msg(f"Status: `{msg['status']}`")
|
self._send_msg(f"Status: `{msg['status']}`")
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
|
@ -1488,7 +1490,7 @@ class Telegram(RPCHandler):
|
||||||
"------------\n"
|
"------------\n"
|
||||||
"*/start:* `Starts the trader`\n"
|
"*/start:* `Starts the trader`\n"
|
||||||
"*/stop:* Stops 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, "
|
"*/forceexit <trade_id>|all:* `Instantly exits the given trade or all trades, "
|
||||||
"regardless of profit`\n"
|
"regardless of profit`\n"
|
||||||
"*/fx <trade_id>|all:* `Alias to /forceexit`\n"
|
"*/fx <trade_id>|all:* `Alias to /forceexit`\n"
|
||||||
|
|
|
@ -663,7 +663,7 @@ def test_rpc_stop(mocker, default_conf) -> None:
|
||||||
assert freqtradebot.state == State.STOPPED
|
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('freqtrade.rpc.telegram.Telegram', MagicMock())
|
||||||
mocker.patch.multiple(
|
mocker.patch.multiple(
|
||||||
'freqtrade.exchange.Exchange',
|
'freqtrade.exchange.Exchange',
|
||||||
|
@ -676,8 +676,8 @@ def test_rpc_stopbuy(mocker, default_conf) -> None:
|
||||||
freqtradebot.state = State.RUNNING
|
freqtradebot.state = State.RUNNING
|
||||||
|
|
||||||
assert freqtradebot.config['max_open_trades'] != 0
|
assert freqtradebot.config['max_open_trades'] != 0
|
||||||
result = rpc._rpc_stopbuy()
|
result = rpc._rpc_stopentry()
|
||||||
assert {'status': 'No more buy will occur from now. Run /reload_config to reset.'} == result
|
assert {'status': 'No more entries will occur from now. Run /reload_config to reset.'} == result
|
||||||
assert freqtradebot.config['max_open_trades'] == 0
|
assert freqtradebot.config['max_open_trades'] == 0
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -422,13 +422,20 @@ def test_api_reloadconf(botclient):
|
||||||
assert ftbot.state == State.RELOAD_CONFIG
|
assert ftbot.state == State.RELOAD_CONFIG
|
||||||
|
|
||||||
|
|
||||||
def test_api_stopbuy(botclient):
|
def test_api_stopentry(botclient):
|
||||||
ftbot, client = botclient
|
ftbot, client = botclient
|
||||||
assert ftbot.config['max_open_trades'] != 0
|
assert ftbot.config['max_open_trades'] != 0
|
||||||
|
|
||||||
rc = client_post(client, f"{BASE_URI}/stopbuy")
|
rc = client_post(client, f"{BASE_URI}/stopbuy")
|
||||||
assert_response(rc)
|
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
|
assert ftbot.config['max_open_trades'] == 0
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -103,7 +103,8 @@ def test_telegram_init(default_conf, mocker, caplog) -> None:
|
||||||
"['stats'], ['daily'], ['weekly'], ['monthly'], "
|
"['stats'], ['daily'], ['weekly'], ['monthly'], "
|
||||||
"['count'], ['locks'], ['unlock', 'delete_locks'], "
|
"['count'], ['locks'], ['unlock', 'delete_locks'], "
|
||||||
"['reload_config', 'reload_conf'], ['show_config', 'show_conf'], "
|
"['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']"
|
"['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)
|
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||||
|
|
||||||
assert freqtradebot.config['max_open_trades'] != 0
|
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 freqtradebot.config['max_open_trades'] == 0
|
||||||
assert msg_mock.call_count == 1
|
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]
|
in msg_mock.call_args_list[0][0][0]
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user