Merge branch 'develop' into develop

This commit is contained in:
Michael Egger 2017-11-19 04:51:36 +01:00 committed by GitHub
commit a509ebc68c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 218 additions and 104 deletions

View File

@ -1,3 +1,10 @@
[MASTER]
extension-pkg-whitelist=numpy,talib
[BASIC]
good-names=logger
ignore=vendor
[TYPECHECK]
ignored-modules=numpy,talib

View File

@ -1,3 +1,4 @@
""" FreqTrade bot """
__version__ = '0.14.2'
from . import main

View File

@ -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"

View File

@ -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,

View File

@ -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:

View File

@ -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)

View File

@ -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,
)

View File

@ -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

View File

@ -1,4 +1,4 @@
# pragma pylint: disable=missing-docstring
# pragma pylint: disable=missing-docstring,W0621
import json
import arrow
import pytest

View File

@ -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)

View File

@ -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'])

View File

@ -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))

View File

@ -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,

View File

@ -1,4 +1,4 @@
# pragma pylint: disable=missing-docstring
# pragma pylint: disable=missing-docstring,C0103
import time
import os
from argparse import Namespace

View File

@ -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

View File

@ -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 '<code>BTC_ETH\t10.05%</code>' 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 '<code>BTC_ETH\t10.05%</code>' 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