diff --git a/.pylintrc b/.pylintrc index a876357c4..65ed64830 100644 --- a/.pylintrc +++ b/.pylintrc @@ -1,3 +1,10 @@ +[MASTER] +extension-pkg-whitelist=numpy,talib + [BASIC] good-names=logger -ignore=vendor \ No newline at end of file +ignore=vendor + +[TYPECHECK] +ignored-modules=numpy,talib + diff --git a/freqtrade/__init__.py b/freqtrade/__init__.py index 75254ebcc..522ceeeb0 100644 --- a/freqtrade/__init__.py +++ b/freqtrade/__init__.py @@ -1,3 +1,4 @@ +""" FreqTrade bot """ __version__ = '0.14.2' from . import main diff --git a/freqtrade/analyze.py b/freqtrade/analyze.py index 775f7e79e..de880c9e6 100644 --- a/freqtrade/analyze.py +++ b/freqtrade/analyze.py @@ -1,3 +1,6 @@ +""" +Functions to analyze ticker data with indicators and produce buy and sell signals +""" from enum import Enum import logging from datetime import timedelta @@ -7,11 +10,12 @@ import talib.abstract as ta from pandas import DataFrame, to_datetime from freqtrade.exchange import get_ticker_history -from freqtrade.vendor.qtpylib.indicators import awesome_oscillator, crossed_above, crossed_below +from freqtrade.vendor.qtpylib.indicators import awesome_oscillator, crossed_above logger = logging.getLogger(__name__) class SignalType(Enum): + """ Enum to distinguish between buy and sell signals """ BUY = "buy" SELL = "sell" diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index a6e986f7b..98ade43a0 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -1,9 +1,12 @@ +# pragma pylint: disable=W0603 +""" Cryptocurrency Exchanges support """ import enum import logging from random import randint from typing import List, Dict, Any, Optional import arrow +import requests from cachetools import cached, TTLCache from freqtrade.exchange.bittrex import Bittrex @@ -63,7 +66,12 @@ def validate_pairs(pairs: List[str]) -> None: :param pairs: list of pairs :return: None """ - markets = _API.get_markets() + try: + markets = _API.get_markets() + except requests.exceptions.RequestException as e: + logger.warning('Unable to validate pairs (assuming they are correct). Reason: %s', e) + return + stake_cur = _CONF['stake_currency'] for pair in pairs: if not pair.startswith(stake_cur): @@ -77,7 +85,7 @@ def validate_pairs(pairs: List[str]) -> None: def buy(pair: str, rate: float, amount: float) -> str: if _CONF['dry_run']: global _DRY_RUN_OPEN_ORDERS - order_id = 'dry_run_buy_{}'.format(randint(0, 1e6)) + order_id = 'dry_run_buy_{}'.format(randint(0, 10**6)) _DRY_RUN_OPEN_ORDERS[order_id] = { 'pair': pair, 'rate': rate, @@ -95,7 +103,7 @@ def buy(pair: str, rate: float, amount: float) -> str: def sell(pair: str, rate: float, amount: float) -> str: if _CONF['dry_run']: global _DRY_RUN_OPEN_ORDERS - order_id = 'dry_run_sell_{}'.format(randint(0, 1e6)) + order_id = 'dry_run_sell_{}'.format(randint(0, 10**6)) _DRY_RUN_OPEN_ORDERS[order_id] = { 'pair': pair, 'rate': rate, diff --git a/freqtrade/main.py b/freqtrade/main.py index 58fbdde24..dc66540cb 100755 --- a/freqtrade/main.py +++ b/freqtrade/main.py @@ -12,15 +12,11 @@ from typing import Dict, Optional, List import requests from cachetools import cached, TTLCache -from freqtrade import __version__, exchange, persistence +from freqtrade import __version__, exchange, persistence, rpc from freqtrade.analyze import get_signal, SignalType -from freqtrade.misc import ( - FreqtradeException -) from freqtrade.misc import State, get_state, update_state, parse_args, throttle, \ - load_config + load_config, FreqtradeException from freqtrade.persistence import Trade -from freqtrade.rpc import telegram logger = logging.getLogger('freqtrade') @@ -102,7 +98,7 @@ def _process(dynamic_whitelist: Optional[bool] = False) -> bool: ) time.sleep(30) except RuntimeError: - telegram.send_msg('*Status:* Got RuntimeError:\n```\n{traceback}```{hint}'.format( + rpc.send_msg('*Status:* Got RuntimeError:\n```\n{traceback}```{hint}'.format( traceback=traceback.format_exc(), hint='Issue `/start` if you think it is safe to restart.' )) @@ -123,15 +119,13 @@ def execute_sell(trade: Trade, limit: float) -> None: trade.open_order_id = order_id fmt_exp_profit = round(trade.calc_profit(limit) * 100, 2) - message = '*{}:* Selling [{}]({}) with limit `{:.8f} (profit: ~{:.2f}%)`'.format( + rpc.send_msg('*{}:* Selling [{}]({}) with limit `{:.8f} (profit: ~{:.2f}%)`'.format( trade.exchange, trade.pair.replace('_', '/'), exchange.get_pair_detail_url(trade.pair), limit, fmt_exp_profit - ) - logger.info(message) - telegram.send_msg(message) + )) def min_roi_reached(trade: Trade, current_rate: float, current_time: datetime) -> bool: @@ -218,14 +212,12 @@ def create_trade(stake_amount: float) -> Optional[Trade]: order_id = exchange.buy(pair, buy_limit, amount) # Create trade entity and return - message = '*{}:* Buying [{}]({}) with limit `{:.8f}`'.format( + rpc.send_msg('*{}:* Buying [{}]({}) with limit `{:.8f}`'.format( exchange.get_name().upper(), pair.replace('_', '/'), exchange.get_pair_detail_url(pair), buy_limit - ) - logger.info(message) - telegram.send_msg(message) + )) # Fee is applied twice because we make a LIMIT_BUY and LIMIT_SELL return Trade(pair=pair, stake_amount=stake_amount, @@ -245,7 +237,7 @@ def init(config: dict, db_url: Optional[str] = None) -> None: :return: None """ # Initialize all modules - telegram.init(config) + rpc.init(config) persistence.init(config, db_url) exchange.init(config) @@ -283,11 +275,11 @@ def cleanup(*args, **kwargs) -> None: Cleanup the application state und finish all pending tasks :return: None """ - telegram.send_msg('*Status:* `Stopping trader...`') + rpc.send_msg('*Status:* `Stopping trader...`') logger.info('Stopping trader and cleaning up modules...') update_state(State.STOPPED) persistence.cleanup() - telegram.cleanup() + rpc.cleanup() exit(0) @@ -325,7 +317,7 @@ def main(): new_state = get_state() # Log state transition if new_state != old_state: - telegram.send_msg('*Status:* `{}`'.format(new_state.name.lower())) + rpc.send_msg('*Status:* `{}`'.format(new_state.name.lower())) logger.info('Changing state to: %s', new_state.name) if new_state == State.STOPPED: diff --git a/freqtrade/rpc/__init__.py b/freqtrade/rpc/__init__.py index 35fa001c3..cd7523f78 100644 --- a/freqtrade/rpc/__init__.py +++ b/freqtrade/rpc/__init__.py @@ -1 +1,42 @@ +import logging + from . import telegram + +logger = logging.getLogger(__name__) + + +REGISTERED_MODULES = [] + + +def init(config: dict) -> None: + """ + Initializes all enabled rpc modules + :param config: config to use + :return: None + """ + + if config['telegram'].get('enabled', False): + logger.info('Enabling rpc.telegram ...') + REGISTERED_MODULES.append('telegram') + telegram.init(config) + + +def cleanup() -> None: + """ + Stops all enabled rpc modules + :return: None + """ + if 'telegram' in REGISTERED_MODULES: + logger.debug('Cleaning up rpc.telegram ...') + telegram.cleanup() + + +def send_msg(msg: str) -> None: + """ + Send given markdown message to all registered rpc modules + :param msg: message + :return: None + """ + logger.info(msg) + if 'telegram' in REGISTERED_MODULES: + telegram.send_msg(msg) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 0bc44c23f..cce871b70 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -57,7 +57,7 @@ def init(config: dict) -> None: _UPDATER.dispatcher.add_handler(handle) _UPDATER.start_polling( clean=True, - bootstrap_retries=3, + bootstrap_retries=-1, timeout=30, read_latency=60, ) diff --git a/freqtrade/tests/__init__.py b/freqtrade/tests/__init__.py index c6ac0797c..c5cc708c9 100644 --- a/freqtrade/tests/__init__.py +++ b/freqtrade/tests/__init__.py @@ -1,3 +1,4 @@ +# pragma pylint: disable=missing-docstring import json import os @@ -11,9 +12,9 @@ def load_backtesting_data(ticker_interval: int = 5): ] for pair in pairs: with open('{abspath}/testdata/{pair}-{ticker_interval}.json'.format( - abspath=path, - pair=pair, - ticker_interval=ticker_interval, - )) as fp: - result[pair] = json.load(fp) + abspath=path, + pair=pair, + ticker_interval=ticker_interval, + )) as tickerdata: + result[pair] = json.load(tickerdata) return result diff --git a/freqtrade/tests/test_analyze.py b/freqtrade/tests/test_analyze.py index a691379f6..a2ff1aec2 100644 --- a/freqtrade/tests/test_analyze.py +++ b/freqtrade/tests/test_analyze.py @@ -1,4 +1,4 @@ -# pragma pylint: disable=missing-docstring +# pragma pylint: disable=missing-docstring,W0621 import json import arrow import pytest diff --git a/freqtrade/tests/test_backtesting.py b/freqtrade/tests/test_backtesting.py index 78eeb1f72..5c86107e4 100644 --- a/freqtrade/tests/test_backtesting.py +++ b/freqtrade/tests/test_backtesting.py @@ -1,4 +1,4 @@ -# pragma pylint: disable=missing-docstring +# pragma pylint: disable=missing-docstring,W0212 import logging @@ -23,13 +23,13 @@ logger = logging.getLogger(__name__) def format_results(results: DataFrame): - return 'Made {} buys. Average profit {:.2f}%. ' \ - 'Total profit was {:.3f}. Average duration {:.1f} mins.'.format( - len(results.index), - results.profit.mean() * 100.0, - results.profit.sum(), - results.duration.mean() * 5, - ) + return ('Made {} buys. Average profit {:.2f}%. ' + 'Total profit was {:.3f}. Average duration {:.1f} mins.').format( + len(results.index), + results.profit.mean() * 100.0, + results.profit.sum(), + results.duration.mean() * 5, + ) def preprocess(backdata) -> Dict[str, DataFrame]: @@ -47,11 +47,11 @@ def get_timeframe(data: Dict[str, Dict]) -> Tuple[arrow.Arrow, arrow.Arrow]: """ min_date, max_date = None, None for values in data.values(): - values = sorted(values, key=lambda d: arrow.get(d['T'])) - if not min_date or values[0]['T'] < min_date: - min_date = values[0]['T'] - if not max_date or values[-1]['T'] > max_date: - max_date = values[-1]['T'] + sorted_values = sorted(values, key=lambda d: arrow.get(d['T'])) + if not min_date or sorted_values[0]['T'] < min_date: + min_date = sorted_values[0]['T'] + if not max_date or sorted_values[-1]['T'] > max_date: + max_date = sorted_values[-1]['T'] return arrow.get(min_date), arrow.get(max_date) diff --git a/freqtrade/tests/test_exchange.py b/freqtrade/tests/test_exchange.py index 309ff4a5e..d0083af6a 100644 --- a/freqtrade/tests/test_exchange.py +++ b/freqtrade/tests/test_exchange.py @@ -1,4 +1,4 @@ -# pragma pylint: disable=missing-docstring +# pragma pylint: disable=missing-docstring,C0103 from unittest.mock import MagicMock import pytest @@ -33,4 +33,3 @@ def test_validate_pairs_not_compatible(default_conf, mocker): mocker.patch.dict('freqtrade.exchange._CONF', default_conf) with pytest.raises(RuntimeError, match=r'not compatible'): validate_pairs(default_conf['exchange']['pair_whitelist']) - diff --git a/freqtrade/tests/test_hyperopt.py b/freqtrade/tests/test_hyperopt.py index 367db3fa8..d54e3bd19 100644 --- a/freqtrade/tests/test_hyperopt.py +++ b/freqtrade/tests/test_hyperopt.py @@ -1,4 +1,4 @@ -# pragma pylint: disable=missing-docstring +# pragma pylint: disable=missing-docstring,W0212 import logging import os from functools import reduce @@ -21,6 +21,7 @@ logging.disable(logging.DEBUG) # disable debug logs that slow backtesting a lot # set TARGET_TRADES to suit your number concurrent trades so its realistic to 20days of data TARGET_TRADES = 1100 TOTAL_TRIES = 4 +# pylint: disable=C0103 current_tries = 0 @@ -90,6 +91,7 @@ def test_hyperopt(backtest_conf, mocker): trade_loss = 1 - 0.35 * exp(-(trade_count - TARGET_TRADES) ** 2 / 10 ** 5.2) profit_loss = max(0, 1 - total_profit / 10000) # max profit 10000 + # pylint: disable=W0603 global current_tries current_tries += 1 print('{}/{}: {}'.format(current_tries, TOTAL_TRIES, result)) diff --git a/freqtrade/tests/test_main.py b/freqtrade/tests/test_main.py index 32a0bfb0a..3de35ff46 100644 --- a/freqtrade/tests/test_main.py +++ b/freqtrade/tests/test_main.py @@ -1,4 +1,4 @@ -# pragma pylint: disable=missing-docstring +# pragma pylint: disable=missing-docstring,C0103 import copy from unittest.mock import MagicMock @@ -16,7 +16,7 @@ from freqtrade.persistence import Trade def test_process_trade_creation(default_conf, ticker, health, mocker): mocker.patch.dict('freqtrade.main._CONF', default_conf) - mocker.patch.multiple('freqtrade.main.telegram', init=MagicMock(), send_msg=MagicMock()) + mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=MagicMock()) mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: True) mocker.patch.multiple('freqtrade.main.exchange', validate_pairs=MagicMock(), @@ -26,7 +26,7 @@ def test_process_trade_creation(default_conf, ticker, health, mocker): init(default_conf, create_engine('sqlite://')) trades = Trade.query.filter(Trade.is_open.is_(True)).all() - assert len(trades) == 0 + assert not trades result = _process() assert result is True @@ -45,7 +45,7 @@ def test_process_trade_creation(default_conf, ticker, health, mocker): def test_process_exchange_failures(default_conf, ticker, health, mocker): mocker.patch.dict('freqtrade.main._CONF', default_conf) - mocker.patch.multiple('freqtrade.main.telegram', init=MagicMock(), send_msg=MagicMock()) + mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=MagicMock()) mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: True) sleep_mock = mocker.patch('time.sleep', side_effect=lambda _: None) mocker.patch.multiple('freqtrade.main.exchange', @@ -62,7 +62,7 @@ def test_process_exchange_failures(default_conf, ticker, health, mocker): def test_process_runtime_error(default_conf, ticker, health, mocker): msg_mock = MagicMock() mocker.patch.dict('freqtrade.main._CONF', default_conf) - mocker.patch.multiple('freqtrade.main.telegram', init=MagicMock(), send_msg=msg_mock) + mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=msg_mock) mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: True) mocker.patch.multiple('freqtrade.main.exchange', validate_pairs=MagicMock(), @@ -80,8 +80,9 @@ def test_process_runtime_error(default_conf, ticker, health, mocker): def test_process_trade_handling(default_conf, ticker, limit_buy_order, health, mocker): mocker.patch.dict('freqtrade.main._CONF', default_conf) - mocker.patch.multiple('freqtrade.main.telegram', init=MagicMock(), send_msg=MagicMock()) - signal = mocker.patch('freqtrade.main.get_signal', side_effect=lambda *args: False if args[1] == SignalType.SELL else True) + mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=MagicMock()) + mocker.patch('freqtrade.main.get_signal', + side_effect=lambda *args: False if args[1] == SignalType.SELL else True) mocker.patch.multiple('freqtrade.main.exchange', validate_pairs=MagicMock(), get_ticker=ticker, @@ -91,7 +92,7 @@ def test_process_trade_handling(default_conf, ticker, limit_buy_order, health, m init(default_conf, create_engine('sqlite://')) trades = Trade.query.filter(Trade.is_open.is_(True)).all() - assert len(trades) == 0 + assert not trades result = _process() assert result is True trades = Trade.query.filter(Trade.is_open.is_(True)).all() @@ -104,7 +105,7 @@ def test_process_trade_handling(default_conf, ticker, limit_buy_order, health, m def test_create_trade(default_conf, ticker, limit_buy_order, mocker): mocker.patch.dict('freqtrade.main._CONF', default_conf) mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: True) - mocker.patch.multiple('freqtrade.main.telegram', init=MagicMock(), send_msg=MagicMock()) + mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=MagicMock()) mocker.patch.multiple('freqtrade.main.exchange', validate_pairs=MagicMock(), get_ticker=ticker, @@ -134,7 +135,7 @@ def test_create_trade(default_conf, ticker, limit_buy_order, mocker): def test_create_trade_no_stake_amount(default_conf, ticker, mocker): mocker.patch.dict('freqtrade.main._CONF', default_conf) mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: True) - mocker.patch.multiple('freqtrade.main.telegram', init=MagicMock(), send_msg=MagicMock()) + mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=MagicMock()) mocker.patch.multiple('freqtrade.main.exchange', validate_pairs=MagicMock(), get_ticker=ticker, @@ -147,7 +148,7 @@ def test_create_trade_no_stake_amount(default_conf, ticker, mocker): def test_create_trade_no_pairs(default_conf, ticker, mocker): mocker.patch.dict('freqtrade.main._CONF', default_conf) mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: True) - mocker.patch.multiple('freqtrade.main.telegram', init=MagicMock(), send_msg=MagicMock()) + mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=MagicMock()) mocker.patch.multiple('freqtrade.main.exchange', validate_pairs=MagicMock(), get_ticker=ticker, @@ -163,7 +164,7 @@ def test_create_trade_no_pairs(default_conf, ticker, mocker): def test_handle_trade(default_conf, limit_buy_order, limit_sell_order, mocker): mocker.patch.dict('freqtrade.main._CONF', default_conf) mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: True) - mocker.patch.multiple('freqtrade.main.telegram', init=MagicMock(), send_msg=MagicMock()) + mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=MagicMock()) mocker.patch.multiple('freqtrade.main.exchange', validate_pairs=MagicMock(), get_ticker=MagicMock(return_value={ @@ -195,7 +196,7 @@ def test_handle_trade(default_conf, limit_buy_order, limit_sell_order, mocker): def test_close_trade(default_conf, ticker, limit_buy_order, limit_sell_order, mocker): mocker.patch.dict('freqtrade.main._CONF', default_conf) mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: True) - mocker.patch.multiple('freqtrade.main.telegram', init=MagicMock(), send_msg=MagicMock()) + mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=MagicMock()) mocker.patch.multiple('freqtrade.main.exchange', validate_pairs=MagicMock(), get_ticker=ticker, diff --git a/freqtrade/tests/test_misc.py b/freqtrade/tests/test_misc.py index c26ce7cc5..35ebf0979 100644 --- a/freqtrade/tests/test_misc.py +++ b/freqtrade/tests/test_misc.py @@ -1,4 +1,4 @@ -# pragma pylint: disable=missing-docstring +# pragma pylint: disable=missing-docstring,C0103 import time import os from argparse import Namespace diff --git a/freqtrade/tests/test_rpc.py b/freqtrade/tests/test_rpc.py new file mode 100644 index 000000000..2dcb1d300 --- /dev/null +++ b/freqtrade/tests/test_rpc.py @@ -0,0 +1,58 @@ +# pragma pylint: disable=missing-docstring, too-many-arguments, too-many-ancestors, C0103 +from unittest.mock import MagicMock + +from copy import deepcopy + +from freqtrade.rpc import init, cleanup, send_msg + + +def test_init_telegram_enabled(default_conf, mocker): + module_list = [] + mocker.patch('freqtrade.rpc.REGISTERED_MODULES', module_list) + telegram_mock = mocker.patch('freqtrade.rpc.telegram.init', MagicMock()) + + init(default_conf) + + assert telegram_mock.call_count == 1 + assert 'telegram' in module_list + + +def test_init_telegram_disabled(default_conf, mocker): + module_list = [] + mocker.patch('freqtrade.rpc.REGISTERED_MODULES', module_list) + telegram_mock = mocker.patch('freqtrade.rpc.telegram.init', MagicMock()) + + conf = deepcopy(default_conf) + conf['telegram']['enabled'] = False + init(conf) + + assert telegram_mock.call_count == 0 + assert 'telegram' not in module_list + + +def test_cleanup_telegram_enabled(mocker): + mocker.patch('freqtrade.rpc.REGISTERED_MODULES', ['telegram']) + telegram_mock = mocker.patch('freqtrade.rpc.telegram.cleanup', MagicMock()) + cleanup() + assert telegram_mock.call_count == 1 + + +def test_cleanup_telegram_disabled(mocker): + mocker.patch('freqtrade.rpc.REGISTERED_MODULES', []) + telegram_mock = mocker.patch('freqtrade.rpc.telegram.cleanup', MagicMock()) + cleanup() + assert telegram_mock.call_count == 0 + + +def test_send_msg_telegram_enabled(mocker): + mocker.patch('freqtrade.rpc.REGISTERED_MODULES', ['telegram']) + telegram_mock = mocker.patch('freqtrade.rpc.telegram.send_msg', MagicMock()) + send_msg('test') + assert telegram_mock.call_count == 1 + + +def test_send_msg_telegram_disabled(mocker): + mocker.patch('freqtrade.rpc.REGISTERED_MODULES', []) + telegram_mock = mocker.patch('freqtrade.rpc.telegram.send_msg', MagicMock()) + send_msg('test') + assert telegram_mock.call_count == 0 diff --git a/freqtrade/tests/test_telegram.py b/freqtrade/tests/test_rpc_telegram.py similarity index 89% rename from freqtrade/tests/test_telegram.py rename to freqtrade/tests/test_rpc_telegram.py index 63a01d429..ebedc5962 100644 --- a/freqtrade/tests/test_telegram.py +++ b/freqtrade/tests/test_rpc_telegram.py @@ -1,10 +1,9 @@ -# pragma pylint: disable=missing-docstring, too-many-arguments, too-many-ancestors +# pragma pylint: disable=missing-docstring, too-many-arguments, too-many-ancestors, C0103 import re from datetime import datetime from random import randint from unittest.mock import MagicMock -import pytest from sqlalchemy import create_engine from telegram import Update, Message, Chat from telegram.error import NetworkError @@ -14,10 +13,8 @@ from freqtrade.main import init, create_trade from freqtrade.misc import update_state, State, get_state from freqtrade.persistence import Trade from freqtrade.rpc import telegram -from freqtrade.rpc.telegram import ( - _status, _status_table, _profit, _forcesell, _performance, _count, _start, _stop, _balance, - authorized_only, _help, is_enabled, send_msg, - _version) +from freqtrade.rpc.telegram import authorized_only, is_enabled, send_msg, _status, _status_table, \ + _profit, _forcesell, _performance, _count, _start, _stop, _balance, _version, _help def test_is_enabled(default_conf, mocker): @@ -81,7 +78,8 @@ def test_status_handle(default_conf, update, ticker, mocker): mocker.patch.dict('freqtrade.main._CONF', default_conf) mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: True) msg_mock = MagicMock() - mocker.patch.multiple('freqtrade.main.telegram', + mocker.patch('freqtrade.main.rpc.send_msg', MagicMock()) + mocker.patch.multiple('freqtrade.rpc.telegram', _CONF=default_conf, init=MagicMock(), send_msg=msg_mock) @@ -111,16 +109,17 @@ def test_status_handle(default_conf, update, ticker, mocker): # Trigger status while we have a fulfilled order for the open trade _status(bot=MagicMock(), update=update) - assert msg_mock.call_count == 2 - assert '[BTC_ETH]' in msg_mock.call_args_list[-1][0][0] + assert msg_mock.call_count == 1 + assert '[BTC_ETH]' in msg_mock.call_args_list[0][0][0] def test_status_table_handle(default_conf, update, ticker, mocker): mocker.patch.dict('freqtrade.main._CONF', default_conf) mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: True) msg_mock = MagicMock() + mocker.patch('freqtrade.main.rpc.send_msg', MagicMock()) mocker.patch.multiple( - 'freqtrade.main.telegram', + 'freqtrade.rpc.telegram', _CONF=default_conf, init=MagicMock(), send_msg=msg_mock) @@ -155,14 +154,15 @@ def test_status_table_handle(default_conf, update, ticker, mocker): assert int(fields[0]) == 1 assert fields[1] == 'BTC_ETH' - assert msg_mock.call_count == 2 + assert msg_mock.call_count == 1 def test_profit_handle(default_conf, update, ticker, limit_buy_order, limit_sell_order, mocker): mocker.patch.dict('freqtrade.main._CONF', default_conf) mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: True) msg_mock = MagicMock() - mocker.patch.multiple('freqtrade.main.telegram', + mocker.patch('freqtrade.main.rpc.send_msg', MagicMock()) + mocker.patch.multiple('freqtrade.rpc.telegram', _CONF=default_conf, init=MagicMock(), send_msg=msg_mock) @@ -184,7 +184,7 @@ def test_profit_handle(default_conf, update, ticker, limit_buy_order, limit_sell trade.update(limit_buy_order) _profit(bot=MagicMock(), update=update) - assert msg_mock.call_count == 2 + assert msg_mock.call_count == 1 assert 'no closed trade' in msg_mock.call_args_list[-1][0][0] msg_mock.reset_mock() @@ -205,11 +205,11 @@ def test_profit_handle(default_conf, update, ticker, limit_buy_order, limit_sell def test_forcesell_handle(default_conf, update, ticker, mocker): mocker.patch.dict('freqtrade.main._CONF', default_conf) mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: True) - msg_mock = MagicMock() - mocker.patch.multiple('freqtrade.main.telegram', + rpc_mock = mocker.patch('freqtrade.main.rpc.send_msg', MagicMock()) + mocker.patch.multiple('freqtrade.rpc.telegram', _CONF=default_conf, init=MagicMock(), - send_msg=msg_mock) + send_msg=MagicMock()) mocker.patch.multiple('freqtrade.main.exchange', validate_pairs=MagicMock(), get_ticker=ticker) @@ -225,19 +225,19 @@ def test_forcesell_handle(default_conf, update, ticker, mocker): update.message.text = '/forcesell 1' _forcesell(bot=MagicMock(), update=update) - assert msg_mock.call_count == 2 - assert 'Selling [BTC/ETH]' in msg_mock.call_args_list[-1][0][0] - assert '0.07256061 (profit: ~-0.64%)' in msg_mock.call_args_list[-1][0][0] + assert rpc_mock.call_count == 2 + assert 'Selling [BTC/ETH]' in rpc_mock.call_args_list[-1][0][0] + assert '0.07256061 (profit: ~-0.64%)' in rpc_mock.call_args_list[-1][0][0] def test_forcesell_all_handle(default_conf, update, ticker, mocker): mocker.patch.dict('freqtrade.main._CONF', default_conf) mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: True) - msg_mock = MagicMock() - mocker.patch.multiple('freqtrade.main.telegram', + rpc_mock = mocker.patch('freqtrade.main.rpc.send_msg', MagicMock()) + mocker.patch.multiple('freqtrade.rpc.telegram', _CONF=default_conf, init=MagicMock(), - send_msg=msg_mock) + send_msg=MagicMock()) mocker.patch.multiple('freqtrade.main.exchange', validate_pairs=MagicMock(), get_ticker=ticker) @@ -247,14 +247,13 @@ def test_forcesell_all_handle(default_conf, update, ticker, mocker): for _ in range(4): Trade.session.add(create_trade(15.0)) Trade.session.flush() - - msg_mock.reset_mock() + rpc_mock.reset_mock() update.message.text = '/forcesell all' _forcesell(bot=MagicMock(), update=update) - assert msg_mock.call_count == 4 - for args in msg_mock.call_args_list: + assert rpc_mock.call_count == 4 + for args in rpc_mock.call_args_list: assert '0.07256061 (profit: ~-0.64%)' in args[0][0] @@ -262,7 +261,7 @@ def test_forcesell_handle_invalid(default_conf, update, mocker): mocker.patch.dict('freqtrade.main._CONF', default_conf) mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: True) msg_mock = MagicMock() - mocker.patch.multiple('freqtrade.main.telegram', + mocker.patch.multiple('freqtrade.rpc.telegram', _CONF=default_conf, init=MagicMock(), send_msg=msg_mock) @@ -299,7 +298,8 @@ def test_performance_handle( mocker.patch.dict('freqtrade.main._CONF', default_conf) mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: True) msg_mock = MagicMock() - mocker.patch.multiple('freqtrade.main.telegram', + mocker.patch('freqtrade.main.rpc.send_msg', MagicMock()) + mocker.patch.multiple('freqtrade.rpc.telegram', _CONF=default_conf, init=MagicMock(), send_msg=msg_mock) @@ -324,9 +324,9 @@ def test_performance_handle( Trade.session.flush() _performance(bot=MagicMock(), update=update) - assert msg_mock.call_count == 2 - assert 'Performance' in msg_mock.call_args_list[-1][0][0] - assert 'BTC_ETH\t10.05%' in msg_mock.call_args_list[-1][0][0] + assert msg_mock.call_count == 1 + assert 'Performance' in msg_mock.call_args_list[0][0][0] + assert 'BTC_ETH\t10.05%' in msg_mock.call_args_list[0][0][0] def test_count_handle(default_conf, update, ticker, mocker): @@ -334,7 +334,7 @@ def test_count_handle(default_conf, update, ticker, mocker): mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: True) msg_mock = MagicMock() mocker.patch.multiple( - 'freqtrade.main.telegram', + 'freqtrade.rpc.telegram', _CONF=default_conf, init=MagicMock(), send_msg=msg_mock) @@ -367,7 +367,7 @@ def test_performance_handle_invalid(default_conf, update, mocker): mocker.patch.dict('freqtrade.main._CONF', default_conf) mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: True) msg_mock = MagicMock() - mocker.patch.multiple('freqtrade.main.telegram', + mocker.patch.multiple('freqtrade.rpc.telegram', _CONF=default_conf, init=MagicMock(), send_msg=msg_mock) @@ -385,7 +385,7 @@ def test_performance_handle_invalid(default_conf, update, mocker): def test_start_handle(default_conf, update, mocker): mocker.patch.dict('freqtrade.main._CONF', default_conf) msg_mock = MagicMock() - mocker.patch.multiple('freqtrade.main.telegram', + mocker.patch.multiple('freqtrade.rpc.telegram', _CONF=default_conf, init=MagicMock(), send_msg=msg_mock) @@ -403,7 +403,7 @@ def test_start_handle(default_conf, update, mocker): def test_start_handle_already_running(default_conf, update, mocker): mocker.patch.dict('freqtrade.main._CONF', default_conf) msg_mock = MagicMock() - mocker.patch.multiple('freqtrade.main.telegram', + mocker.patch.multiple('freqtrade.rpc.telegram', _CONF=default_conf, init=MagicMock(), send_msg=msg_mock) @@ -422,7 +422,7 @@ def test_start_handle_already_running(default_conf, update, mocker): def test_stop_handle(default_conf, update, mocker): mocker.patch.dict('freqtrade.main._CONF', default_conf) msg_mock = MagicMock() - mocker.patch.multiple('freqtrade.main.telegram', + mocker.patch.multiple('freqtrade.rpc.telegram', _CONF=default_conf, init=MagicMock(), send_msg=msg_mock) @@ -441,7 +441,7 @@ def test_stop_handle(default_conf, update, mocker): def test_stop_handle_already_stopped(default_conf, update, mocker): mocker.patch.dict('freqtrade.main._CONF', default_conf) msg_mock = MagicMock() - mocker.patch.multiple('freqtrade.main.telegram', + mocker.patch.multiple('freqtrade.rpc.telegram', _CONF=default_conf, init=MagicMock(), send_msg=msg_mock) @@ -473,7 +473,7 @@ def test_balance_handle(default_conf, update, mocker): }] mocker.patch.dict('freqtrade.main._CONF', default_conf) msg_mock = MagicMock() - mocker.patch.multiple('freqtrade.main.telegram', + mocker.patch.multiple('freqtrade.rpc.telegram', _CONF=default_conf, init=MagicMock(), send_msg=msg_mock) @@ -489,7 +489,7 @@ def test_balance_handle(default_conf, update, mocker): def test_help_handle(default_conf, update, mocker): mocker.patch.dict('freqtrade.main._CONF', default_conf) msg_mock = MagicMock() - mocker.patch.multiple('freqtrade.main.telegram', + mocker.patch.multiple('freqtrade.rpc.telegram', _CONF=default_conf, init=MagicMock(), send_msg=msg_mock) @@ -502,7 +502,7 @@ def test_help_handle(default_conf, update, mocker): def test_version_handle(default_conf, update, mocker): mocker.patch.dict('freqtrade.main._CONF', default_conf) msg_mock = MagicMock() - mocker.patch.multiple('freqtrade.main.telegram', + mocker.patch.multiple('freqtrade.rpc.telegram', _CONF=default_conf, init=MagicMock(), send_msg=msg_mock) @@ -514,12 +514,12 @@ def test_version_handle(default_conf, update, mocker): def test_send_msg(default_conf, mocker): mocker.patch.dict('freqtrade.main._CONF', default_conf) - mocker.patch.multiple('freqtrade.main.telegram', + mocker.patch.multiple('freqtrade.rpc.telegram', _CONF=default_conf, init=MagicMock()) bot = MagicMock() send_msg('test', bot) - assert len(bot.method_calls) == 0 + assert not bot.method_calls bot.reset_mock() default_conf['telegram']['enabled'] = True @@ -529,7 +529,7 @@ def test_send_msg(default_conf, mocker): def test_send_msg_network_error(default_conf, mocker): mocker.patch.dict('freqtrade.main._CONF', default_conf) - mocker.patch.multiple('freqtrade.main.telegram', + mocker.patch.multiple('freqtrade.rpc.telegram', _CONF=default_conf, init=MagicMock()) default_conf['telegram']['enabled'] = True