use dict as argument for rpc.send_msg

This commit is contained in:
gcarq 2018-06-25 00:04:27 +02:00
parent 96a405feb7
commit 4cb1aa1d97
8 changed files with 89 additions and 68 deletions

View File

@ -91,7 +91,9 @@ class FreqtradeBot(object):
# Log state transition # Log state transition
state = self.state state = self.state
if state != old_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) logger.info('Changing state to: %s', state.name)
if state == State.STOPPED: if state == State.STOPPED:
@ -167,9 +169,9 @@ class FreqtradeBot(object):
except OperationalException: except OperationalException:
tb = traceback.format_exc() tb = traceback.format_exc()
hint = 'Issue `/start` if you think it is safe to restart.' hint = 'Issue `/start` if you think it is safe to restart.'
self.rpc.send_msg( self.rpc.send_msg({
f'*Status:* OperationalException:\n```\n{tb}```{hint}' 'status': f'OperationalException:\n```\n{tb}```{hint}'
) })
logger.exception('OperationalException. Stopping trader ...') logger.exception('OperationalException. Stopping trader ...')
self.state = State.STOPPED self.state = State.STOPPED
return state_changed return state_changed
@ -362,11 +364,12 @@ class FreqtradeBot(object):
) )
# Create trade entity and return # Create trade entity and return
self.rpc.send_msg( self.rpc.send_msg({
f"""*{exc_name}:* Buying [{pair_s}]({pair_url}) \ 'status':
with limit `{buy_limit:.8f} ({stake_amount:.6f} \ f"""*{exc_name}:* Buying [{pair_s}]({pair_url}) \
{stake_currency}, {stake_amount_fiat:.3f} {fiat_currency})`""" 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 is applied twice because we make a LIMIT_BUY and LIMIT_SELL
fee = self.exchange.get_fee(symbol=pair, taker_or_maker='maker') fee = self.exchange.get_fee(symbol=pair, taker_or_maker='maker')
trade = Trade( trade = Trade(
@ -551,7 +554,9 @@ with limit `{buy_limit:.8f} ({stake_amount:.6f} \
Trade.session.delete(trade) Trade.session.delete(trade)
Trade.session.flush() Trade.session.flush()
logger.info('Buy order timeout for %s.', trade) 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 return True
# if trade is partially complete, edit the stake details for the trade # if trade is partially complete, edit the stake details for the trade
@ -560,7 +565,9 @@ with limit `{buy_limit:.8f} ({stake_amount:.6f} \
trade.stake_amount = trade.amount * trade.open_rate trade.stake_amount = trade.amount * trade.open_rate
trade.open_order_id = None trade.open_order_id = None
logger.info('Partial buy order timeout for %s.', trade) 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 return False
# FIX: 20180110, should cancel_order() be cond. or unconditionally called? # FIX: 20180110, should cancel_order() be cond. or unconditionally called?
@ -578,7 +585,9 @@ with limit `{buy_limit:.8f} ({stake_amount:.6f} \
trade.close_date = None trade.close_date = None
trade.is_open = True trade.is_open = True
trade.open_order_id = None 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) logger.info('Sell order timeout for %s.', trade)
return True return True
@ -634,5 +643,5 @@ with limit `{buy_limit:.8f} ({stake_amount:.6f} \
gain = "profit" if fmt_exp_profit > 0 else "loss" gain = "profit" if fmt_exp_profit > 0 else "loss"
message += f'` ({gain}: {fmt_exp_profit:.2f}%, {profit_trade:.8f})`' message += f'` ({gain}: {fmt_exp_profit:.2f}%, {profit_trade:.8f})`'
# Send the message # Send the message
self.rpc.send_msg(message) self.rpc.send_msg({'status': message})
Trade.session.flush() Trade.session.flush()

View File

@ -59,7 +59,9 @@ def main(sysargv: List[str]) -> None:
logger.exception('Fatal exception!') logger.exception('Fatal exception!')
finally: finally:
if freqtrade: if freqtrade:
freqtrade.rpc.send_msg('*Status:* `Process died ...`') freqtrade.rpc.send_msg({
'status': 'process died'
})
freqtrade.cleanup() freqtrade.cleanup()
sys.exit(return_code) sys.exit(return_code)
@ -73,8 +75,9 @@ def reconfigure(freqtrade: FreqtradeBot, args: Namespace) -> FreqtradeBot:
# Create new instance # Create new instance
freqtrade = FreqtradeBot(Configuration(args).get_config()) freqtrade = FreqtradeBot(Configuration(args).get_config())
freqtrade.rpc.send_msg( freqtrade.rpc.send_msg({
'*Status:* `Config reloaded {freqtrade.state.name.lower()}...`') 'status': 'config reloaded'
})
return freqtrade return freqtrade

View File

@ -61,7 +61,7 @@ class RPC(object):
""" Cleanup pending module resources """ """ Cleanup pending module resources """
@abstractmethod @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 """ """ Sends a message to all registered rpc modules """
def _rpc_trade_status(self) -> List[Dict]: def _rpc_trade_status(self) -> List[Dict]:

View File

@ -2,7 +2,7 @@
This module contains class to manage RPC communications (Telegram, Slack, ...) This module contains class to manage RPC communications (Telegram, Slack, ...)
""" """
import logging import logging
from typing import List from typing import List, Dict
from freqtrade.rpc.rpc import RPC from freqtrade.rpc.rpc import RPC
@ -32,11 +32,14 @@ class RPCManager(object):
mod.cleanup() mod.cleanup()
del mod 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 Send given message to all registered rpc modules.
:param msg: message A message consists of one or more key value pairs of strings.
:return: None e.g.:
{
'status': 'stopping bot'
}
""" """
logger.info('Sending rpc message: %s', msg) logger.info('Sending rpc message: %s', msg)
for mod in self.registered_modules: for mod in self.registered_modules:

View File

@ -4,7 +4,7 @@
This module manage Telegram communication This module manage Telegram communication
""" """
import logging import logging
from typing import Any, Callable from typing import Any, Callable, Dict
from tabulate import tabulate from tabulate import tabulate
from telegram import Bot, ParseMode, ReplyKeyboardMarkup, Update from telegram import Bot, ParseMode, ReplyKeyboardMarkup, Update
@ -110,9 +110,9 @@ class Telegram(RPC):
""" """
self._updater.stop() 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 """ """ Send a message to telegram channel """
self._send_msg(msg) self._send_msg('*Status:* `{status}`'.format(**msg))
@authorized_only @authorized_only
def _status(self, bot: Bot, update: Update) -> None: def _status(self, bot: Bot, update: Update) -> None:

View File

@ -102,9 +102,9 @@ def test_send_msg_telegram_disabled(mocker, default_conf, caplog) -> None:
freqtradebot = get_patched_freqtradebot(mocker, conf) freqtradebot = get_patched_freqtradebot(mocker, conf)
rpc_manager = RPCManager(freqtradebot) 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 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) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
rpc_manager = RPCManager(freqtradebot) 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 assert telegram_mock.call_count == 1

View File

@ -757,12 +757,13 @@ def test_forcesell_handle(default_conf, update, ticker, fee,
telegram._forcesell(bot=MagicMock(), update=update) telegram._forcesell(bot=MagicMock(), update=update)
assert rpc_mock.call_count == 2 assert rpc_mock.call_count == 2
assert 'Selling' in rpc_mock.call_args_list[-1][0][0] last_call = rpc_mock.call_args_list[-1][0][0]['status']
assert '[ETH/BTC]' in rpc_mock.call_args_list[-1][0][0] assert 'Selling' in last_call
assert 'Amount' in rpc_mock.call_args_list[-1][0][0] assert '[ETH/BTC]' in last_call
assert '0.00001172' in rpc_mock.call_args_list[-1][0][0] assert 'Amount' in last_call
assert 'profit: 6.11%, 0.00006126' in rpc_mock.call_args_list[-1][0][0] assert '0.00001172' in last_call
assert '0.919 USD' in rpc_mock.call_args_list[-1][0][0] 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, def test_forcesell_down_handle(default_conf, update, ticker, fee,
@ -802,13 +803,14 @@ def test_forcesell_down_handle(default_conf, update, ticker, fee,
update.message.text = '/forcesell 1' update.message.text = '/forcesell 1'
telegram._forcesell(bot=MagicMock(), update=update) telegram._forcesell(bot=MagicMock(), update=update)
last_call = rpc_mock.call_args_list[-1][0][0]['status']
assert rpc_mock.call_count == 2 assert rpc_mock.call_count == 2
assert 'Selling' in rpc_mock.call_args_list[-1][0][0] assert 'Selling' in last_call
assert '[ETH/BTC]' in rpc_mock.call_args_list[-1][0][0] assert '[ETH/BTC]' in last_call
assert 'Amount' in rpc_mock.call_args_list[-1][0][0] assert 'Amount' in last_call
assert '0.00001044' in rpc_mock.call_args_list[-1][0][0] assert '0.00001044' in last_call
assert 'loss: -5.48%, -0.00005492' in rpc_mock.call_args_list[-1][0][0] assert 'loss: -5.48%, -0.00005492' in last_call
assert '-0.824 USD' in rpc_mock.call_args_list[-1][0][0] assert '-0.824 USD' in last_call
def test_forcesell_all_handle(default_conf, update, ticker, fee, markets, mocker) -> None: def test_forcesell_all_handle(default_conf, update, ticker, fee, markets, mocker) -> None:
@ -842,9 +844,9 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, markets, mocker
assert rpc_mock.call_count == 4 assert rpc_mock.call_count == 4
for args in rpc_mock.call_args_list: for args in rpc_mock.call_args_list:
assert '0.00001098' in args[0][0] assert '0.00001098' in args[0][0]['status']
assert 'loss: -0.59%, -0.00000591 BTC' in args[0][0] assert 'loss: -0.59%, -0.00000591 BTC' in args[0][0]['status']
assert '-0.089 USD' in args[0][0] assert '-0.089 USD' in args[0][0]['status']
def test_forcesell_handle_invalid(default_conf, update, mocker) -> None: def test_forcesell_handle_invalid(default_conf, update, mocker) -> None:

View File

@ -755,7 +755,7 @@ def test_process_operational_exception(default_conf, ticker, markets, mocker) ->
result = freqtrade._process() result = freqtrade._process()
assert result is False assert result is False
assert freqtrade.state == State.STOPPED 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( def test_process_trade_handling(
@ -1375,13 +1375,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']) freqtrade.execute_sell(trade=trade, limit=ticker_sell_up()['bid'])
assert rpc_mock.call_count == 2 assert rpc_mock.call_count == 2
assert 'Selling' in rpc_mock.call_args_list[-1][0][0] last_call = rpc_mock.call_args_list[-1][0][0]['status']
assert '[ETH/BTC]' in rpc_mock.call_args_list[-1][0][0] assert 'Selling' in last_call
assert 'Amount' in rpc_mock.call_args_list[-1][0][0] assert '[ETH/BTC]' in last_call
assert 'Profit' in rpc_mock.call_args_list[-1][0][0] assert 'Amount' in last_call
assert '0.00001172' in rpc_mock.call_args_list[-1][0][0] assert 'Profit' in last_call
assert 'profit: 6.11%, 0.00006126' in rpc_mock.call_args_list[-1][0][0] assert '0.00001172' in last_call
assert '0.919 USD' in rpc_mock.call_args_list[-1][0][0] 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: def test_execute_sell_down(default_conf, ticker, fee, ticker_sell_down, markets, mocker) -> None:
@ -1417,12 +1418,13 @@ def test_execute_sell_down(default_conf, ticker, fee, ticker_sell_down, markets,
freqtrade.execute_sell(trade=trade, limit=ticker_sell_down()['bid']) freqtrade.execute_sell(trade=trade, limit=ticker_sell_down()['bid'])
assert rpc_mock.call_count == 2 assert rpc_mock.call_count == 2
assert 'Selling' in rpc_mock.call_args_list[-1][0][0] last_call = rpc_mock.call_args_list[-1][0][0]['status']
assert '[ETH/BTC]' in rpc_mock.call_args_list[-1][0][0] assert 'Selling' in last_call
assert 'Amount' in rpc_mock.call_args_list[-1][0][0] assert '[ETH/BTC]' in last_call
assert '0.00001044' in rpc_mock.call_args_list[-1][0][0] assert 'Amount' in last_call
assert 'loss: -5.48%, -0.00005492' in rpc_mock.call_args_list[-1][0][0] assert '0.00001044' in last_call
assert '-0.824 USD' in rpc_mock.call_args_list[-1][0][0] 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, def test_execute_sell_without_conf_sell_up(default_conf, ticker, fee,
@ -1459,12 +1461,13 @@ def test_execute_sell_without_conf_sell_up(default_conf, ticker, fee,
freqtrade.execute_sell(trade=trade, limit=ticker_sell_up()['bid']) freqtrade.execute_sell(trade=trade, limit=ticker_sell_up()['bid'])
assert rpc_mock.call_count == 2 assert rpc_mock.call_count == 2
assert 'Selling' in rpc_mock.call_args_list[-1][0][0] last_call = rpc_mock.call_args_list[-1][0][0]['status']
assert '[ETH/BTC]' in rpc_mock.call_args_list[-1][0][0] assert 'Selling' in last_call
assert 'Amount' in rpc_mock.call_args_list[-1][0][0] assert '[ETH/BTC]' in last_call
assert '0.00001172' in rpc_mock.call_args_list[-1][0][0] assert 'Amount' in last_call
assert '(profit: 6.11%, 0.00006126)' in rpc_mock.call_args_list[-1][0][0] assert '0.00001172' in last_call
assert 'USD' not in rpc_mock.call_args_list[-1][0][0] 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, def test_execute_sell_without_conf_sell_down(default_conf, ticker, fee,
@ -1501,10 +1504,11 @@ def test_execute_sell_without_conf_sell_down(default_conf, ticker, fee,
freqtrade.execute_sell(trade=trade, limit=ticker_sell_down()['bid']) freqtrade.execute_sell(trade=trade, limit=ticker_sell_down()['bid'])
assert rpc_mock.call_count == 2 assert rpc_mock.call_count == 2
assert 'Selling' in rpc_mock.call_args_list[-1][0][0] last_call = rpc_mock.call_args_list[-1][0][0]['status']
assert '[ETH/BTC]' in rpc_mock.call_args_list[-1][0][0] assert 'Selling' in last_call
assert '0.00001044' in rpc_mock.call_args_list[-1][0][0] assert '[ETH/BTC]' in last_call
assert 'loss: -5.48%, -0.00005492' in rpc_mock.call_args_list[-1][0][0] 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, def test_sell_profit_only_enable_profit(default_conf, limit_buy_order,