diff --git a/docs/telegram-usage.md b/docs/telegram-usage.md index db98cbb12..face22404 100644 --- a/docs/telegram-usage.md +++ b/docs/telegram-usage.md @@ -16,6 +16,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. | `/reload_conf` | | Reloads the configuration file | `/status` | | Lists all open trades | `/status table` | | List all open trades in a table format @@ -43,7 +44,21 @@ Below, example of Telegram message you will receive for each command. > `Stopping trader ...` > **Status:** `stopped` -## /status +### /stopbuy + +> **status:** `Setting max_open_trades to 0. Run /reload_conf to reset.` + +Prevents the bot from opening new trades by temporarily setting "max_open_trades" to 0. Open trades will be handled via their regular rules (ROI / Sell-signal, stoploss, ...). + +After this, give the bot time to close off open trades (can be checked via `/status table`). +Once all positions are sold, run `/stop` to completely stop the bot. + +`/reload_conf` resets "max_open_trades" to the value set in the configuration and resets this command. + +!!! warning: +The stop-buy signal is ONLY active while the bot is running, and is not persisted anyway, so restarting the bot will cause this to reset. + +### /status For each open trade, the bot will send you the following message. @@ -58,7 +73,7 @@ For each open trade, the bot will send you the following message. > **Current Profit:** `12.95%` > **Open Order:** `None` -## /status table +### /status table Return the status of all open trades in a table format. ``` @@ -68,7 +83,7 @@ Return the status of all open trades in a table format. 123 CVC/BTC 1 h 12.95% ``` -## /count +### /count Return the number of trades used and available. ``` @@ -77,7 +92,7 @@ current max 2 10 ``` -## /profit +### /profit Return a summary of your profit/loss and performance. @@ -94,11 +109,11 @@ Return a summary of your profit/loss and performance. > **Avg. Duration:** `2:33:45` > **Best Performing:** `PAY/BTC: 50.23%` -## /forcesell +### /forcesell > **BITTREX:** Selling BTC/LTC with limit `0.01650000 (profit: ~-4.07%, -0.00008168)` -## /forcebuy +### /forcebuy > **BITTREX**: Buying ETH/BTC with limit `0.03400000` (`1.000000 ETH`, `225.290 USD`) @@ -106,7 +121,7 @@ Note that for this to work, `forcebuy_enable` needs to be set to true. [More details](configuration.md/#understand-forcebuy_enable) -## /performance +### /performance Return the performance of each crypto-currency the bot has sold. > Performance: @@ -117,7 +132,7 @@ Return the performance of each crypto-currency the bot has sold. > 5. `STORJ/BTC 27.24%` > ... -## /balance +### /balance Return the balance of all crypto-currency your have on the exchange. @@ -131,7 +146,7 @@ Return the balance of all crypto-currency your have on the exchange. > **Balance:** 86.64180098 > **Pending:** 0.0 -## /daily +### /daily Per default `/daily` will return the 7 last days. The example below if for `/daily 3`: @@ -145,6 +160,6 @@ Day Profit BTC Profit USD 2018-01-01 0.00269130 BTC 34.986 USD ``` -## /version +### /version > **Version:** `0.14.3` diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index af64c3d67..7ad51fa8e 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -328,6 +328,16 @@ class RPC(object): self._freqtrade.state = State.RELOAD_CONF return {'status': 'reloading config ...'} + def _rpc_stopbuy(self) -> Dict[str, str]: + """ + Handler to stop buying, but handle open trades gracefully. + """ + if self._freqtrade.state == State.RUNNING: + # Set 'max_open_trades' to 0 + self._freqtrade.config['max_open_trades'] = 0 + + return {'status': 'No more buy will occur from now. Run /reload_conf to reset.'} + def _rpc_forcesell(self, trade_id) -> None: """ Handler for forcesell . diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index e599172e4..6771ec803 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -91,6 +91,7 @@ class Telegram(RPC): CommandHandler('daily', self._daily), CommandHandler('count', self._count), CommandHandler('reload_conf', self._reload_conf), + CommandHandler('stopbuy', self._stopbuy), CommandHandler('whitelist', self._whitelist), CommandHandler('help', self._help), CommandHandler('version', self._version), @@ -362,6 +363,18 @@ class Telegram(RPC): msg = self._rpc_reload_conf() self._send_msg('Status: `{status}`'.format(**msg), bot=bot) + @authorized_only + def _stopbuy(self, bot: Bot, update: Update) -> None: + """ + Handler for /stop_buy. + Sets max_open_trades to 0 and gracefully sells all open trades + :param bot: telegram bot + :param update: message update + :return: None + """ + msg = self._rpc_stopbuy() + self._send_msg('Status: `{status}`'.format(**msg), bot=bot) + @authorized_only def _forcesell(self, bot: Bot, update: Update) -> None: """ @@ -481,6 +494,7 @@ class Telegram(RPC): "*/count:* `Show number of trades running compared to allowed number of trades`" \ "\n" \ "*/balance:* `Show account balance per currency`\n" \ + "*/stopbuy:* `Stops buying, but handles open trades gracefully` \n" \ "*/reload_conf:* `Reload configuration file` \n" \ "*/whitelist:* `Show current whitelist` \n" \ "*/help:* `This help message`\n" \ diff --git a/freqtrade/tests/rpc/test_rpc.py b/freqtrade/tests/rpc/test_rpc.py index e1261e02e..baddc0685 100644 --- a/freqtrade/tests/rpc/test_rpc.py +++ b/freqtrade/tests/rpc/test_rpc.py @@ -406,6 +406,26 @@ def test_rpc_stop(mocker, default_conf) -> None: assert freqtradebot.state == State.STOPPED +def test_rpc_stopbuy(mocker, default_conf) -> None: + patch_coinmarketcap(mocker) + patch_exchange(mocker) + mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) + mocker.patch.multiple( + 'freqtrade.exchange.Exchange', + get_ticker=MagicMock() + ) + + freqtradebot = FreqtradeBot(default_conf) + patch_get_signal(freqtradebot, (True, False)) + rpc = RPC(freqtradebot) + 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_conf to reset.'} == result + assert freqtradebot.config['max_open_trades'] == 0 + + def test_rpc_forcesell(default_conf, ticker, fee, mocker, markets) -> None: patch_coinmarketcap(mocker) patch_exchange(mocker) diff --git a/freqtrade/tests/rpc/test_rpc_telegram.py b/freqtrade/tests/rpc/test_rpc_telegram.py index 02f4f4afb..8e8d1f1bb 100644 --- a/freqtrade/tests/rpc/test_rpc_telegram.py +++ b/freqtrade/tests/rpc/test_rpc_telegram.py @@ -74,7 +74,7 @@ def test_init(default_conf, mocker, caplog) -> None: message_str = "rpc.telegram is listening for following commands: [['status'], ['profit'], " \ "['balance'], ['start'], ['stop'], ['forcesell'], ['forcebuy'], " \ "['performance'], ['daily'], ['count'], ['reload_conf'], " \ - "['whitelist'], ['help'], ['version']]" + "['stopbuy'], ['whitelist'], ['help'], ['version']]" assert log_has(message_str, caplog.record_tuples) @@ -662,6 +662,26 @@ def test_stop_handle_already_stopped(default_conf, update, mocker) -> None: assert 'already stopped' in msg_mock.call_args_list[0][0][0] +def test_stopbuy_handle(default_conf, update, mocker) -> None: + patch_coinmarketcap(mocker) + msg_mock = MagicMock() + mocker.patch.multiple( + 'freqtrade.rpc.telegram.Telegram', + _init=MagicMock(), + _send_msg=msg_mock + ) + + freqtradebot = get_patched_freqtradebot(mocker, default_conf) + telegram = Telegram(freqtradebot) + + assert freqtradebot.config['max_open_trades'] != 0 + telegram._stopbuy(bot=MagicMock(), update=update) + assert freqtradebot.config['max_open_trades'] == 0 + assert msg_mock.call_count == 1 + assert 'No more buy will occur from now. Run /reload_conf to reset.' \ + in msg_mock.call_args_list[0][0][0] + + def test_reload_conf_handle(default_conf, update, mocker) -> None: patch_coinmarketcap(mocker) msg_mock = MagicMock()