From 127e50c932092717744e7e558c41d26807c8e4d2 Mon Sep 17 00:00:00 2001 From: gcarq Date: Mon, 25 Jun 2018 00:04:27 +0200 Subject: [PATCH] use dict as argument for rpc.send_msg --- freqtrade/freqtradebot.py | 35 ++++++++++------ freqtrade/main.py | 12 +++--- freqtrade/rpc/api_server.py | 3 +- freqtrade/rpc/rpc.py | 2 +- freqtrade/rpc/rpc_manager.py | 13 +++--- freqtrade/rpc/telegram.py | 6 +-- freqtrade/tests/rpc/test_rpc_manager.py | 8 ++-- freqtrade/tests/rpc/test_rpc_telegram.py | 32 ++++++++------- freqtrade/tests/test_freqtradebot.py | 52 +++++++++++++----------- 9 files changed, 91 insertions(+), 72 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index e25ed66cf..c00aa68f5 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -93,7 +93,9 @@ class FreqtradeBot(object): # Log state transition state = self.state if state != old_state: - self.rpc.send_msg(f'*Status:* `{state.name.lower()}`') + self.rpc.send_msg({ + 'status': f'{state.name.lower()}' + }) logger.info('Changing state to: %s', state.name) if state == State.STOPPED: @@ -169,9 +171,9 @@ class FreqtradeBot(object): except OperationalException: tb = traceback.format_exc() hint = 'Issue `/start` if you think it is safe to restart.' - self.rpc.send_msg( - f'*Status:* OperationalException:\n```\n{tb}```{hint}' - ) + self.rpc.send_msg({ + 'status': f'OperationalException:\n```\n{tb}```{hint}' + }) logger.exception('OperationalException. Stopping trader ...') self.state = State.STOPPED return state_changed @@ -356,11 +358,12 @@ class FreqtradeBot(object): ) # Create trade entity and return - self.rpc.send_msg( - f"""*{exc_name}:* Buying [{pair_s}]({pair_url}) \ -with limit `{buy_limit:.8f} ({stake_amount:.6f} \ -{stake_currency}, {stake_amount_fiat:.3f} {fiat_currency})`""" - ) + self.rpc.send_msg({ + 'status': + f"""*{exc_name}:* Buying [{pair_s}]({pair_url}) \ + with limit `{buy_limit:.8f} ({stake_amount:.6f} \ + {stake_currency}, {stake_amount_fiat:.3f} {fiat_currency})`""" + }) # Fee is applied twice because we make a LIMIT_BUY and LIMIT_SELL fee = self.exchange.get_fee(symbol=pair, taker_or_maker='maker') trade = Trade( @@ -540,7 +543,9 @@ with limit `{buy_limit:.8f} ({stake_amount:.6f} \ Trade.session.delete(trade) Trade.session.flush() logger.info('Buy order timeout for %s.', trade) - self.rpc.send_msg(f'*Timeout:* Unfilled buy order for {pair_s} cancelled') + self.rpc.send_msg({ + 'status': f'Unfilled buy order for {pair_s} cancelled due to timeout' + }) return True # if trade is partially complete, edit the stake details for the trade @@ -549,7 +554,9 @@ with limit `{buy_limit:.8f} ({stake_amount:.6f} \ trade.stake_amount = trade.amount * trade.open_rate trade.open_order_id = None logger.info('Partial buy order timeout for %s.', trade) - self.rpc.send_msg(f'*Timeout:* Remaining buy order for {pair_s} cancelled') + self.rpc.send_msg({ + 'status': f'Remaining buy order for {pair_s} cancelled due to timeout' + }) return False # FIX: 20180110, should cancel_order() be cond. or unconditionally called? @@ -567,7 +574,9 @@ with limit `{buy_limit:.8f} ({stake_amount:.6f} \ trade.close_date = None trade.is_open = True trade.open_order_id = None - self.rpc.send_msg(f'*Timeout:* Unfilled sell order for {pair_s} cancelled') + self.rpc.send_msg({ + 'status': f'Unfilled sell order for {pair_s} cancelled due to timeout' + }) logger.info('Sell order timeout for %s.', trade) return True @@ -627,5 +636,5 @@ with limit `{buy_limit:.8f} ({stake_amount:.6f} \ ) # Send the message - self.rpc.send_msg(message) + self.rpc.send_msg({'status': message}) Trade.session.flush() diff --git a/freqtrade/main.py b/freqtrade/main.py index 9d17a403a..74d8da031 100755 --- a/freqtrade/main.py +++ b/freqtrade/main.py @@ -59,7 +59,9 @@ def main(sysargv: List[str]) -> None: logger.exception('Fatal exception!') finally: if freqtrade: - freqtrade.rpc.send_msg('*Status:* `Process died ...`') + freqtrade.rpc.send_msg({ + 'status': 'process died' + }) freqtrade.cleanup() sys.exit(return_code) @@ -73,11 +75,9 @@ def reconfigure(freqtrade: FreqtradeBot, args: Namespace) -> FreqtradeBot: # Create new instance freqtrade = FreqtradeBot(Configuration(args).get_config()) - freqtrade.rpc.send_msg( - '*Status:* `Config reloaded ...`'.format( - freqtrade.state.name.lower() - ) - ) + freqtrade.rpc.send_msg({ + 'status': 'config reloaded' + }) return freqtrade diff --git a/freqtrade/rpc/api_server.py b/freqtrade/rpc/api_server.py index be9f8a6fd..7a006b202 100644 --- a/freqtrade/rpc/api_server.py +++ b/freqtrade/rpc/api_server.py @@ -2,6 +2,7 @@ import json import threading import logging # import json +from typing import Dict from flask import Flask, request, jsonify # from flask_restful import Resource, Api @@ -81,7 +82,7 @@ class ApiServer(RPC): def cleanup(self) -> None: pass - def send_msg(self, msg: str) -> None: + def send_msg(self, msg: Dict[str, str]) -> None: pass """ diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index c31d46878..754c511d4 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -59,7 +59,7 @@ class RPC(object): """ Cleanup pending module resources """ @abstractmethod - def send_msg(self, msg: str) -> None: + def send_msg(self, msg: Dict[str, str]) -> None: """ Sends a message to all registered rpc modules """ def _rpc_trade_status(self) -> List[Dict]: diff --git a/freqtrade/rpc/rpc_manager.py b/freqtrade/rpc/rpc_manager.py index c3433fe56..ebefeadb2 100644 --- a/freqtrade/rpc/rpc_manager.py +++ b/freqtrade/rpc/rpc_manager.py @@ -2,7 +2,7 @@ This module contains class to manage RPC communications (Telegram, Slack, Rest ....) """ import logging -from typing import List +from typing import List, Dict from freqtrade.rpc.rpc import RPC @@ -38,11 +38,14 @@ class RPCManager(object): mod.cleanup() del mod - def send_msg(self, msg: str) -> None: + def send_msg(self, msg: Dict[str, str]) -> None: """ - Send given markdown message to all registered rpc modules - :param msg: message - :return: None + Send given message to all registered rpc modules. + A message consists of one or more key value pairs of strings. + e.g.: + { + 'status': 'stopping bot' + } """ logger.info('Sending rpc message: %s', msg) for mod in self.registered_modules: diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index add9968dc..3dd0d34c7 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -4,7 +4,7 @@ This module manage Telegram communication """ import logging -from typing import Any, Callable +from typing import Any, Callable, Dict import arrow from pandas import DataFrame @@ -113,9 +113,9 @@ class Telegram(RPC): """ self._updater.stop() - def send_msg(self, msg: str) -> None: + def send_msg(self, msg: Dict[str, str]) -> None: """ Send a message to telegram channel """ - self._send_msg(msg) + self._send_msg('*Status:* `{status}`'.format(**msg)) @authorized_only def _status(self, bot: Bot, update: Update) -> None: diff --git a/freqtrade/tests/rpc/test_rpc_manager.py b/freqtrade/tests/rpc/test_rpc_manager.py index 805424d26..f9c5de035 100644 --- a/freqtrade/tests/rpc/test_rpc_manager.py +++ b/freqtrade/tests/rpc/test_rpc_manager.py @@ -102,9 +102,9 @@ def test_send_msg_telegram_disabled(mocker, default_conf, caplog) -> None: freqtradebot = get_patched_freqtradebot(mocker, conf) rpc_manager = RPCManager(freqtradebot) - rpc_manager.send_msg('test') + rpc_manager.send_msg({'status': 'test'}) - assert log_has('Sending rpc message: test', caplog.record_tuples) + assert log_has("Sending rpc message: {'status': 'test'}", caplog.record_tuples) assert telegram_mock.call_count == 0 @@ -117,7 +117,7 @@ def test_send_msg_telegram_enabled(mocker, default_conf, caplog) -> None: freqtradebot = get_patched_freqtradebot(mocker, default_conf) rpc_manager = RPCManager(freqtradebot) - rpc_manager.send_msg('test') + rpc_manager.send_msg({'status': 'test'}) - assert log_has('Sending rpc message: test', caplog.record_tuples) + assert log_has("Sending rpc message: {'status': 'test'}", caplog.record_tuples) assert telegram_mock.call_count == 1 diff --git a/freqtrade/tests/rpc/test_rpc_telegram.py b/freqtrade/tests/rpc/test_rpc_telegram.py index bcf7c8e32..5d24bd82c 100644 --- a/freqtrade/tests/rpc/test_rpc_telegram.py +++ b/freqtrade/tests/rpc/test_rpc_telegram.py @@ -700,12 +700,13 @@ def test_forcesell_handle(default_conf, update, ticker, fee, telegram._forcesell(bot=MagicMock(), update=update) assert rpc_mock.call_count == 2 - assert 'Selling' in rpc_mock.call_args_list[-1][0][0] - assert '[ETH/BTC]' in rpc_mock.call_args_list[-1][0][0] - assert 'Amount' in rpc_mock.call_args_list[-1][0][0] - assert '0.00001172' in rpc_mock.call_args_list[-1][0][0] - assert 'profit: 6.11%, 0.00006126' in rpc_mock.call_args_list[-1][0][0] - assert '0.919 USD' in rpc_mock.call_args_list[-1][0][0] + last_call = rpc_mock.call_args_list[-1][0][0]['status'] + assert 'Selling' in last_call + assert '[ETH/BTC]' in last_call + assert 'Amount' in last_call + assert '0.00001172' in last_call + assert 'profit: 6.11%, 0.00006126' in last_call + assert '0.919 USD' in last_call def test_forcesell_down_handle(default_conf, update, ticker, fee, @@ -745,13 +746,14 @@ def test_forcesell_down_handle(default_conf, update, ticker, fee, update.message.text = '/forcesell 1' telegram._forcesell(bot=MagicMock(), update=update) + last_call = rpc_mock.call_args_list[-1][0][0]['status'] assert rpc_mock.call_count == 2 - assert 'Selling' in rpc_mock.call_args_list[-1][0][0] - assert '[ETH/BTC]' in rpc_mock.call_args_list[-1][0][0] - assert 'Amount' in rpc_mock.call_args_list[-1][0][0] - assert '0.00001044' in rpc_mock.call_args_list[-1][0][0] - assert 'loss: -5.48%, -0.00005492' in rpc_mock.call_args_list[-1][0][0] - assert '-0.824 USD' in rpc_mock.call_args_list[-1][0][0] + assert 'Selling' in last_call + assert '[ETH/BTC]' in last_call + assert 'Amount' in last_call + assert '0.00001044' in last_call + assert 'loss: -5.48%, -0.00005492' in last_call + assert '-0.824 USD' in last_call def test_forcesell_all_handle(default_conf, update, ticker, fee, markets, mocker) -> None: @@ -785,9 +787,9 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, markets, mocker assert rpc_mock.call_count == 4 for args in rpc_mock.call_args_list: - assert '0.00001098' in args[0][0] - assert 'loss: -0.59%, -0.00000591 BTC' in args[0][0] - assert '-0.089 USD' in args[0][0] + assert '0.00001098' in args[0][0]['status'] + assert 'loss: -0.59%, -0.00000591 BTC' in args[0][0]['status'] + assert '-0.089 USD' in args[0][0]['status'] def test_forcesell_handle_invalid(default_conf, update, mocker) -> None: diff --git a/freqtrade/tests/test_freqtradebot.py b/freqtrade/tests/test_freqtradebot.py index 1cb2bfca2..1dc035a46 100644 --- a/freqtrade/tests/test_freqtradebot.py +++ b/freqtrade/tests/test_freqtradebot.py @@ -725,7 +725,7 @@ def test_process_operational_exception(default_conf, ticker, markets, mocker) -> result = freqtrade._process() assert result is False assert freqtrade.state == State.STOPPED - assert 'OperationalException' in msg_mock.call_args_list[-1][0][0] + assert 'OperationalException' in msg_mock.call_args_list[-1][0][0]['status'] def test_process_trade_handling( @@ -1345,13 +1345,14 @@ def test_execute_sell_up(default_conf, ticker, fee, ticker_sell_up, markets, moc freqtrade.execute_sell(trade=trade, limit=ticker_sell_up()['bid']) assert rpc_mock.call_count == 2 - assert 'Selling' in rpc_mock.call_args_list[-1][0][0] - assert '[ETH/BTC]' in rpc_mock.call_args_list[-1][0][0] - assert 'Amount' in rpc_mock.call_args_list[-1][0][0] - assert 'Profit' in rpc_mock.call_args_list[-1][0][0] - assert '0.00001172' in rpc_mock.call_args_list[-1][0][0] - assert 'profit: 6.11%, 0.00006126' in rpc_mock.call_args_list[-1][0][0] - assert '0.919 USD' in rpc_mock.call_args_list[-1][0][0] + last_call = rpc_mock.call_args_list[-1][0][0]['status'] + assert 'Selling' in last_call + assert '[ETH/BTC]' in last_call + assert 'Amount' in last_call + assert 'Profit' in last_call + assert '0.00001172' in last_call + assert 'profit: 6.11%, 0.00006126' in last_call + assert '0.919 USD' in last_call def test_execute_sell_down(default_conf, ticker, fee, ticker_sell_down, markets, mocker) -> None: @@ -1387,12 +1388,13 @@ def test_execute_sell_down(default_conf, ticker, fee, ticker_sell_down, markets, freqtrade.execute_sell(trade=trade, limit=ticker_sell_down()['bid']) assert rpc_mock.call_count == 2 - assert 'Selling' in rpc_mock.call_args_list[-1][0][0] - assert '[ETH/BTC]' in rpc_mock.call_args_list[-1][0][0] - assert 'Amount' in rpc_mock.call_args_list[-1][0][0] - assert '0.00001044' in rpc_mock.call_args_list[-1][0][0] - assert 'loss: -5.48%, -0.00005492' in rpc_mock.call_args_list[-1][0][0] - assert '-0.824 USD' in rpc_mock.call_args_list[-1][0][0] + last_call = rpc_mock.call_args_list[-1][0][0]['status'] + assert 'Selling' in last_call + assert '[ETH/BTC]' in last_call + assert 'Amount' in last_call + assert '0.00001044' in last_call + assert 'loss: -5.48%, -0.00005492' in last_call + assert '-0.824 USD' in last_call def test_execute_sell_without_conf_sell_up(default_conf, ticker, fee, @@ -1429,12 +1431,13 @@ def test_execute_sell_without_conf_sell_up(default_conf, ticker, fee, freqtrade.execute_sell(trade=trade, limit=ticker_sell_up()['bid']) assert rpc_mock.call_count == 2 - assert 'Selling' in rpc_mock.call_args_list[-1][0][0] - assert '[ETH/BTC]' in rpc_mock.call_args_list[-1][0][0] - assert 'Amount' in rpc_mock.call_args_list[-1][0][0] - assert '0.00001172' in rpc_mock.call_args_list[-1][0][0] - assert '(profit: 6.11%, 0.00006126)' in rpc_mock.call_args_list[-1][0][0] - assert 'USD' not in rpc_mock.call_args_list[-1][0][0] + last_call = rpc_mock.call_args_list[-1][0][0]['status'] + assert 'Selling' in last_call + assert '[ETH/BTC]' in last_call + assert 'Amount' in last_call + assert '0.00001172' in last_call + assert '(profit: 6.11%, 0.00006126)' in last_call + assert 'USD' not in last_call def test_execute_sell_without_conf_sell_down(default_conf, ticker, fee, @@ -1471,10 +1474,11 @@ def test_execute_sell_without_conf_sell_down(default_conf, ticker, fee, freqtrade.execute_sell(trade=trade, limit=ticker_sell_down()['bid']) assert rpc_mock.call_count == 2 - assert 'Selling' in rpc_mock.call_args_list[-1][0][0] - assert '[ETH/BTC]' in rpc_mock.call_args_list[-1][0][0] - assert '0.00001044' in rpc_mock.call_args_list[-1][0][0] - assert 'loss: -5.48%, -0.00005492' in rpc_mock.call_args_list[-1][0][0] + last_call = rpc_mock.call_args_list[-1][0][0]['status'] + assert 'Selling' in last_call + assert '[ETH/BTC]' in last_call + assert '0.00001044' in last_call + assert 'loss: -5.48%, -0.00005492' in last_call def test_sell_profit_only_enable_profit(default_conf, limit_buy_order,