Merge branch 'develop' into feature/advanced-status-command

This commit is contained in:
Sébastien Moreau
2017-11-05 10:32:53 -05:00
committed by GitHub
22 changed files with 570 additions and 274 deletions

View File

@@ -7,6 +7,7 @@ from pandas import DataFrame
from freqtrade.analyze import parse_ticker_dataframe, populate_buy_trend, populate_indicators, \
get_buy_signal
@pytest.fixture
def result():
with open('freqtrade/tests/testdata/btc-eth.json') as data_file:
@@ -14,18 +15,22 @@ def result():
return parse_ticker_dataframe(data['result'])
def test_dataframe_has_correct_columns(result):
assert result.columns.tolist() == \
['close', 'high', 'low', 'open', 'date', 'volume']
def test_dataframe_has_correct_length(result):
assert len(result.index) == 5751
def test_populates_buy_trend(result):
dataframe = populate_buy_trend(populate_indicators(result))
assert 'buy' in dataframe.columns
assert 'buy_price' in dataframe.columns
def test_returns_latest_buy_signal(mocker):
buydf = DataFrame([{'buy': 1, 'date': datetime.today()}])
mocker.patch('freqtrade.analyze.analyze_ticker', return_value=buydf)

View File

@@ -7,11 +7,14 @@ import pytest
import arrow
from pandas import DataFrame
from freqtrade import exchange
from freqtrade.analyze import analyze_ticker
from freqtrade.exchange import Bittrex
from freqtrade.main import should_sell
from freqtrade.persistence import Trade
logging.disable(logging.DEBUG) # disable debug logs that slow backtesting a lot
logging.disable(logging.DEBUG) # disable debug logs that slow backtesting a lot
def format_results(results):
return 'Made {} buys. Average profit {:.2f}%. Total profit was {:.3f}. Average duration {:.1f} mins.'.format(
@@ -21,15 +24,18 @@ def format_results(results):
results.duration.mean() * 5
)
def print_pair_results(pair, results):
print('For currency {}:'.format(pair))
print(format_results(results[results.currency == pair]))
@pytest.fixture
def pairs():
return ['btc-neo', 'btc-eth', 'btc-omg', 'btc-edg', 'btc-pay',
'btc-pivx', 'btc-qtum', 'btc-mtl', 'btc-etc', 'btc-ltc']
@pytest.fixture
def conf():
return {
@@ -42,23 +48,29 @@ def conf():
"stoploss": -0.40
}
def backtest(conf, pairs, mocker):
trades = []
exchange._API = Bittrex({'key': '', 'secret': ''})
mocked_history = mocker.patch('freqtrade.analyze.get_ticker_history')
mocker.patch.dict('freqtrade.main._CONF', conf)
mocker.patch('arrow.utcnow', return_value=arrow.get('2017-08-20T14:50:00'))
for pair in pairs:
with open('freqtrade/tests/testdata/'+pair+'.json') as data_file:
data = json.load(data_file)
mocker.patch('freqtrade.analyze.get_ticker_history', return_value=data)
mocker.patch('arrow.utcnow', return_value=arrow.get('2017-08-20T14:50:00'))
mocked_history.return_value = json.load(data_file)
ticker = analyze_ticker(pair)[['close', 'date', 'buy']].copy()
# for each buy point
for row in ticker[ticker.buy == 1].itertuples(index=True):
trade = Trade(open_rate=row.close, open_date=row.date, amount=1)
trade = Trade(
open_rate=row.close,
open_date=row.date,
amount=1,
fee=exchange.get_fee()*2
)
# calculate win/lose forwards from buy point
for row2 in ticker[row.Index:].itertuples(index=True):
if should_sell(trade, row2.close, row2.date):
current_profit = (row2.close - trade.open_rate) / trade.open_rate
current_profit = trade.calc_profit(row2.close)
trades.append((pair, current_profit, row2.Index - row.Index))
break
@@ -66,11 +78,13 @@ def backtest(conf, pairs, mocker):
results = DataFrame.from_records(trades, columns=labels)
return results
@pytest.mark.skipif(not os.environ.get('BACKTEST', False), reason="BACKTEST not set")
def test_backtest(conf, pairs, mocker, report=True):
results = backtest(conf, pairs, mocker)
print('====================== BACKTESTING REPORT ================================')
[print_pair_results(pair, results) for pair in pairs]
for pair in pairs:
print_pair_results(pair, results)
print('TOTAL OVER ALL TRADES:')
print(format_results(results))

View File

@@ -1,18 +1,18 @@
# pragma pylint: disable=missing-docstring
from operator import itemgetter
import logging
import os
from functools import reduce
from math import exp
import pytest
from pandas import DataFrame
from qtpylib.indicators import crossed_above
from operator import itemgetter
import pytest
from hyperopt import fmin, tpe, hp, Trials, STATUS_OK
from pandas import DataFrame
from freqtrade.tests.test_backtesting import backtest, format_results
from freqtrade.vendor.qtpylib.indicators import crossed_above
logging.disable(logging.DEBUG) # disable debug logs that slow backtesting a lot
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 = 1200
@@ -23,6 +23,7 @@ def pairs():
return ['btc-neo', 'btc-eth', 'btc-omg', 'btc-edg', 'btc-pay',
'btc-pivx', 'btc-qtum', 'btc-mtl', 'btc-etc', 'btc-ltc']
@pytest.fixture
def conf():
return {
@@ -35,15 +36,15 @@ def conf():
"stoploss": -0.05
}
def buy_strategy_generator(params):
print(params)
def populate_buy_trend(dataframe: DataFrame) -> DataFrame:
conditions = []
# GUARDS AND TRENDS
if params['below_sma']['enabled']:
conditions.append(dataframe['close'] < dataframe['sma'])
if params['over_sma']['enabled']:
conditions.append(dataframe['close'] > dataframe['sma'])
if params['uptrend_long_ema']['enabled']:
conditions.append(dataframe['ema50'] > dataframe['ema100'])
if params['mfi']['enabled']:
conditions.append(dataframe['mfi'] < params['mfi']['value'])
if params['fastd']['enabled']:
@@ -52,6 +53,8 @@ def buy_strategy_generator(params):
conditions.append(dataframe['adx'] > params['adx']['value'])
if params['cci']['enabled']:
conditions.append(dataframe['cci'] < params['cci']['value'])
if params['rsi']['enabled']:
conditions.append(dataframe['rsi'] < params['rsi']['value'])
if params['over_sar']['enabled']:
conditions.append(dataframe['close'] > dataframe['sar'])
if params['uptrend_sma']['enabled']:
@@ -64,6 +67,8 @@ def buy_strategy_generator(params):
'lower_bb': dataframe['tema'] <= dataframe['blower'],
'faststoch10': (dataframe['fastd'] >= 10) & (prev_fastd < 10),
'ao_cross_zero': (crossed_above(dataframe['ao'], 0.0)),
'ema5_cross_ema10': (crossed_above(dataframe['ema5'], dataframe['ema10'])),
'macd_cross_signal': (crossed_above(dataframe['macd'], dataframe['macdsignal'])),
}
conditions.append(triggers.get(params['trigger']['type']))
@@ -75,11 +80,14 @@ def buy_strategy_generator(params):
return dataframe
return populate_buy_trend
@pytest.mark.skipif(not os.environ.get('BACKTEST', False), reason="BACKTEST not set")
def test_hyperopt(conf, pairs, mocker):
mocked_buy_trend = mocker.patch('freqtrade.analyze.populate_buy_trend')
def optimizer(params):
buy_strategy = buy_strategy_generator(params)
mocker.patch('freqtrade.analyze.populate_buy_trend', side_effect=buy_strategy)
mocked_buy_trend.side_effect = buy_strategy_generator(params)
results = backtest(conf, pairs, mocker)
result = format_results(results)
@@ -100,25 +108,25 @@ def test_hyperopt(conf, pairs, mocker):
space = {
'mfi': hp.choice('mfi', [
{'enabled': False},
{'enabled': True, 'value': hp.uniform('mfi-value', 2, 40)}
{'enabled': True, 'value': hp.uniform('mfi-value', 5, 15)}
]),
'fastd': hp.choice('fastd', [
{'enabled': False},
{'enabled': True, 'value': hp.uniform('fastd-value', 2, 40)}
{'enabled': True, 'value': hp.uniform('fastd-value', 5, 40)}
]),
'adx': hp.choice('adx', [
{'enabled': False},
{'enabled': True, 'value': hp.uniform('adx-value', 2, 40)}
{'enabled': True, 'value': hp.uniform('adx-value', 10, 30)}
]),
'cci': hp.choice('cci', [
{'enabled': False},
{'enabled': True, 'value': hp.uniform('cci-value', -200, -100)}
{'enabled': True, 'value': hp.uniform('cci-value', -150, -100)}
]),
'below_sma': hp.choice('below_sma', [
'rsi': hp.choice('rsi', [
{'enabled': False},
{'enabled': True}
{'enabled': True, 'value': hp.uniform('rsi-value', 20, 30)}
]),
'over_sma': hp.choice('over_sma', [
'uptrend_long_ema': hp.choice('uptrend_long_ema', [
{'enabled': False},
{'enabled': True}
]),
@@ -133,11 +141,13 @@ def test_hyperopt(conf, pairs, mocker):
'trigger': hp.choice('trigger', [
{'type': 'lower_bb'},
{'type': 'faststoch10'},
{'type': 'ao_cross_zero'}
{'type': 'ao_cross_zero'},
{'type': 'ema5_cross_ema10'},
{'type': 'macd_cross_signal'},
]),
}
trials = Trials()
best = fmin(fn=optimizer, space=space, algo=tpe.suggest, max_evals=40, trials=trials)
best = fmin(fn=optimizer, space=space, algo=tpe.suggest, max_evals=4, trials=trials)
print('\n\n\n\n====================== HYPEROPT BACKTESTING REPORT ================================')
print('Best parameters {}'.format(best))
newlist = sorted(trials.results, key=itemgetter('loss'))

View File

@@ -1,5 +1,6 @@
# pragma pylint: disable=missing-docstring
import copy
from datetime import datetime
from unittest.mock import MagicMock, call
import pytest
@@ -48,6 +49,7 @@ def conf():
validate(configuration, CONF_SCHEMA)
return configuration
def test_create_trade(conf, mocker):
mocker.patch.dict('freqtrade.main._CONF', conf)
buy_signal = mocker.patch('freqtrade.main.get_buy_signal', side_effect=lambda _: True)
@@ -59,29 +61,43 @@ def test_create_trade(conf, mocker):
'ask': 0.072661,
'last': 0.07256061
}),
buy=MagicMock(return_value='mocked_order_id'))
buy=MagicMock(return_value='mocked_limit_buy'))
# Save state of current whitelist
whitelist = copy.deepcopy(conf['exchange']['pair_whitelist'])
init(conf, 'sqlite://')
for pair in ['BTC_ETH', 'BTC_TKN', 'BTC_TRST', 'BTC_SWT']:
for _ in ['BTC_ETH', 'BTC_TKN', 'BTC_TRST', 'BTC_SWT']:
trade = create_trade(15.0)
Trade.session.add(trade)
Trade.session.flush()
assert trade is not None
assert trade.open_rate == 0.072661
assert trade.pair == pair
assert trade.exchange == Exchanges.BITTREX.name
assert trade.amount == 206.43811673387373
assert trade.stake_amount == 15.0
assert trade.is_open
assert trade.open_date is not None
assert trade.exchange == Exchanges.BITTREX.name
# Simulate fulfilled LIMIT_BUY order for trade
trade.update({
'id': 'mocked_limit_buy',
'type': 'LIMIT_BUY',
'pair': 'mocked',
'opened': datetime.utcnow(),
'rate': 0.072661,
'amount': 206.43811673387373,
'remaining': 0.0,
'closed': datetime.utcnow(),
})
assert trade.open_rate == 0.072661
assert trade.amount == 206.43811673387373
assert whitelist == conf['exchange']['pair_whitelist']
buy_signal.assert_has_calls(
[call('BTC_ETH'), call('BTC_TKN'), call('BTC_TRST'), call('BTC_SWT')]
)
def test_handle_trade(conf, mocker):
mocker.patch.dict('freqtrade.main._CONF', conf)
mocker.patch.multiple('freqtrade.main.telegram', init=MagicMock(), send_msg=MagicMock())
@@ -92,14 +108,29 @@ def test_handle_trade(conf, mocker):
'ask': 0.172661,
'last': 0.17256061
}),
buy=MagicMock(return_value='mocked_order_id'))
sell=MagicMock(return_value='mocked_limit_sell'))
trade = Trade.query.filter(Trade.is_open.is_(True)).first()
assert trade
handle_trade(trade)
assert trade.open_order_id == 'mocked_limit_sell'
# Simulate fulfilled LIMIT_SELL order for trade
trade.update({
'id': 'mocked_sell_limit',
'type': 'LIMIT_SELL',
'pair': 'mocked',
'opened': datetime.utcnow(),
'rate': 0.17256061,
'amount': 206.43811673387373,
'remaining': 0.0,
'closed': datetime.utcnow(),
})
assert trade.close_rate == 0.17256061
assert trade.close_profit == 137.4872490056564
assert trade.close_profit == 1.3698725
assert trade.close_date is not None
assert trade.open_order_id == 'dry_run'
def test_close_trade(conf, mocker):
mocker.patch.dict('freqtrade.main._CONF', conf)
@@ -113,14 +144,17 @@ def test_close_trade(conf, mocker):
assert closed
assert not trade.is_open
def test_balance_fully_ask_side(mocker):
mocker.patch.dict('freqtrade.main._CONF', {'bid_strategy': {'ask_last_balance': 0.0}})
assert get_target_bid({'ask': 20, 'last': 10}) == 20
def test_balance_fully_last_side(mocker):
mocker.patch.dict('freqtrade.main._CONF', {'bid_strategy': {'ask_last_balance': 1.0}})
assert get_target_bid({'ask': 20, 'last': 10}) == 10
def test_balance_when_last_bigger_than_ask(mocker):
mocker.patch.dict('freqtrade.main._CONF', {'bid_strategy': {'ask_last_balance': 1.0}})
assert get_target_bid({'ask': 5, 'last': 10}) == 5

View File

@@ -1,20 +0,0 @@
# pragma pylint: disable=missing-docstring
from freqtrade.exchange import Exchanges
from freqtrade.persistence import Trade
def test_exec_sell_order(mocker):
api_mock = mocker.patch('freqtrade.main.exchange.sell', side_effect='mocked_order_id')
trade = Trade(
pair='BTC_ETH',
stake_amount=1.00,
open_rate=0.50,
amount=10.00,
exchange=Exchanges.BITTREX,
open_order_id='mocked'
)
profit = trade.exec_sell_order(1.00, 10.00)
api_mock.assert_called_once_with('BTC_ETH', 1.0, 10.0)
assert profit == 100.0
assert trade.close_rate == 1.0
assert trade.close_profit == profit
assert trade.close_date is not None

View File

@@ -11,12 +11,9 @@ from telegram import Bot, Update, Message, Chat
from freqtrade.main import init, create_trade
from freqtrade.misc import update_state, State, get_state, CONF_SCHEMA
from freqtrade.persistence import Trade
from freqtrade.rpc.telegram import _status, _status_table, _profit, _forcesell, _performance, \
_count, _start, _stop
logging.getLogger('requests.packages.urllib3').setLevel(logging.INFO)
logging.getLogger('telegram').setLevel(logging.INFO)
logger = logging.getLogger(__name__)
from freqtrade.rpc.telegram import (
_status, _status_table, _profit, _forcesell, _performance, _count, _start, _stop, _balance
)
@pytest.fixture
@@ -54,6 +51,7 @@ def conf():
validate(configuration, CONF_SCHEMA)
return configuration
@pytest.fixture
def update():
_update = Update(0)
@@ -69,7 +67,10 @@ def test_status_handle(conf, update, mocker):
mocker.patch.dict('freqtrade.main._CONF', conf)
mocker.patch('freqtrade.main.get_buy_signal', side_effect=lambda _: True)
msg_mock = MagicMock()
mocker.patch.multiple('freqtrade.main.telegram', _CONF=conf, init=MagicMock(), send_msg=msg_mock)
mocker.patch.multiple('freqtrade.main.telegram',
_CONF=conf,
init=MagicMock(),
send_msg=msg_mock)
mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(),
get_ticker=MagicMock(return_value={
@@ -86,8 +87,26 @@ def test_status_handle(conf, update, mocker):
Trade.session.add(trade)
Trade.session.flush()
# Trigger status while we don't know the open_rate yet
_status(bot=MagicBot(), update=update)
assert msg_mock.call_count == 2
# Simulate fulfilled LIMIT_BUY order for trade
trade.update({
'id': 'mocked_limit_buy',
'type': 'LIMIT_BUY',
'pair': 'mocked',
'opened': datetime.utcnow(),
'rate': 0.07256060,
'amount': 206.43811673387373,
'remaining': 0.0,
'closed': datetime.utcnow(),
})
Trade.session.flush()
# Trigger status while we have a fulfilled order for the open trade
_status(bot=MagicBot(), update=update)
assert msg_mock.call_count == 3
assert '[BTC_ETH]' in msg_mock.call_args_list[-1][0][0]
@@ -127,7 +146,10 @@ def test_profit_handle(conf, update, mocker):
mocker.patch.dict('freqtrade.main._CONF', conf)
mocker.patch('freqtrade.main.get_buy_signal', side_effect=lambda _: True)
msg_mock = MagicMock()
mocker.patch.multiple('freqtrade.main.telegram', _CONF=conf, init=MagicMock(), send_msg=msg_mock)
mocker.patch.multiple('freqtrade.main.telegram',
_CONF=conf,
init=MagicMock(),
send_msg=msg_mock)
mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(),
get_ticker=MagicMock(return_value={
@@ -135,14 +157,36 @@ def test_profit_handle(conf, update, mocker):
'ask': 0.072661,
'last': 0.07256061
}),
buy=MagicMock(return_value='mocked_order_id'))
buy=MagicMock(return_value='mocked_limit_buy'))
init(conf, 'sqlite://')
# Create some test data
trade = create_trade(15.0)
assert trade
trade.close_rate = 0.07256061
trade.close_profit = 100.00
# Simulate fulfilled LIMIT_BUY order for trade
trade.update({
'id': 'mocked_limit_buy',
'type': 'LIMIT_BUY',
'pair': 'mocked',
'opened': datetime.utcnow(),
'rate': 0.07256061,
'amount': 206.43811673387373,
'remaining': 0.0,
'closed': datetime.utcnow(),
})
# Simulate fulfilled LIMIT_SELL order for trade
trade.update({
'id': 'mocked_limit_sell',
'type': 'LIMIT_SELL',
'pair': 'mocked',
'opened': datetime.utcnow(),
'rate': 0.0802134,
'amount': 206.43811673387373,
'remaining': 0.0,
'closed': datetime.utcnow(),
})
trade.close_date = datetime.utcnow()
trade.open_order_id = None
trade.is_open = False
@@ -151,13 +195,18 @@ def test_profit_handle(conf, update, mocker):
_profit(bot=MagicBot(), update=update)
assert msg_mock.call_count == 2
assert '(100.00%)' in msg_mock.call_args_list[-1][0][0]
assert '*ROI:* `1.507013 (10.05%)`' in msg_mock.call_args_list[-1][0][0]
assert 'Best Performing:* `BTC_ETH: 10.05%`' in msg_mock.call_args_list[-1][0][0]
def test_forcesell_handle(conf, update, mocker):
mocker.patch.dict('freqtrade.main._CONF', conf)
mocker.patch('freqtrade.main.get_buy_signal', side_effect=lambda _: True)
msg_mock = MagicMock()
mocker.patch.multiple('freqtrade.main.telegram', _CONF=conf, init=MagicMock(), send_msg=msg_mock)
mocker.patch.multiple('freqtrade.main.telegram',
_CONF=conf,
init=MagicMock(),
send_msg=msg_mock)
mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(),
get_ticker=MagicMock(return_value={
@@ -171,6 +220,19 @@ def test_forcesell_handle(conf, update, mocker):
# Create some test data
trade = create_trade(15.0)
assert trade
# Simulate fulfilled LIMIT_BUY order for trade
trade.update({
'id': 'mocked_limit_buy',
'type': 'LIMIT_BUY',
'pair': 'mocked',
'opened': datetime.utcnow(),
'rate': 0.07256060,
'amount': 206.43811673387373,
'remaining': 0.0,
'closed': datetime.utcnow(),
})
Trade.session.add(trade)
Trade.session.flush()
@@ -179,13 +241,17 @@ def test_forcesell_handle(conf, update, mocker):
assert msg_mock.call_count == 2
assert 'Selling [BTC/ETH]' in msg_mock.call_args_list[-1][0][0]
assert '0.072561' in msg_mock.call_args_list[-1][0][0]
assert '0.072561 (profit: ~-0.5%)' in msg_mock.call_args_list[-1][0][0]
def test_performance_handle(conf, update, mocker):
mocker.patch.dict('freqtrade.main._CONF', conf)
mocker.patch('freqtrade.main.get_buy_signal', side_effect=lambda _: True)
msg_mock = MagicMock()
mocker.patch.multiple('freqtrade.main.telegram', _CONF=conf, init=MagicMock(), send_msg=msg_mock)
mocker.patch.multiple('freqtrade.main.telegram',
_CONF=conf,
init=MagicMock(),
send_msg=msg_mock)
mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(),
get_ticker=MagicMock(return_value={
@@ -199,10 +265,32 @@ def test_performance_handle(conf, update, mocker):
# Create some test data
trade = create_trade(15.0)
assert trade
trade.close_rate = 0.07256061
trade.close_profit = 100.00
# Simulate fulfilled LIMIT_BUY order for trade
trade.update({
'id': 'mocked_limit_buy',
'type': 'LIMIT_BUY',
'pair': 'mocked',
'opened': datetime.utcnow(),
'rate': 0.07256061,
'amount': 206.43811673387373,
'remaining': 0.0,
'closed': datetime.utcnow(),
})
# Simulate fulfilled LIMIT_SELL order for trade
trade.update({
'id': 'mocked_limit_sell',
'type': 'LIMIT_SELL',
'pair': 'mocked',
'opened': datetime.utcnow(),
'rate': 0.0802134,
'amount': 206.43811673387373,
'remaining': 0.0,
'closed': datetime.utcnow(),
})
trade.close_date = datetime.utcnow()
trade.open_order_id = None
trade.is_open = False
Trade.session.add(trade)
Trade.session.flush()
@@ -210,7 +298,8 @@ def test_performance_handle(conf, update, mocker):
_performance(bot=MagicBot(), update=update)
assert msg_mock.call_count == 2
assert 'Performance' in msg_mock.call_args_list[-1][0][0]
assert 'BTC_ETH 100.00%' 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]
def test_count_handle(conf, update, mocker):
@@ -245,8 +334,13 @@ def test_count_handle(conf, update, mocker):
def test_start_handle(conf, update, mocker):
mocker.patch.dict('freqtrade.main._CONF', conf)
msg_mock = MagicMock()
mocker.patch.multiple('freqtrade.main.telegram', _CONF=conf, init=MagicMock(), send_msg=msg_mock)
mocker.patch.multiple('freqtrade.main.exchange', _CONF=conf, init=MagicMock())
mocker.patch.multiple('freqtrade.main.telegram',
_CONF=conf,
init=MagicMock(),
send_msg=msg_mock)
mocker.patch.multiple('freqtrade.main.exchange',
_CONF=conf,
init=MagicMock())
init(conf, 'sqlite://')
update_state(State.STOPPED)
@@ -255,11 +349,17 @@ def test_start_handle(conf, update, mocker):
assert get_state() == State.RUNNING
assert msg_mock.call_count == 0
def test_stop_handle(conf, update, mocker):
mocker.patch.dict('freqtrade.main._CONF', conf)
msg_mock = MagicMock()
mocker.patch.multiple('freqtrade.main.telegram', _CONF=conf, init=MagicMock(), send_msg=msg_mock)
mocker.patch.multiple('freqtrade.main.exchange', _CONF=conf, init=MagicMock())
mocker.patch.multiple('freqtrade.main.telegram',
_CONF=conf,
init=MagicMock(),
send_msg=msg_mock)
mocker.patch.multiple('freqtrade.main.exchange',
_CONF=conf,
init=MagicMock())
init(conf, 'sqlite://')
update_state(State.RUNNING)
@@ -268,3 +368,25 @@ def test_stop_handle(conf, update, mocker):
assert get_state() == State.STOPPED
assert msg_mock.call_count == 1
assert 'Stopping trader' in msg_mock.call_args_list[0][0][0]
def test_balance_handle(conf, update, mocker):
mock_balance = [{
'Currency': 'BTC',
'Balance': 10.0,
'Available': 12.0,
'Pending': 0.0,
'CryptoAddress': 'XXXX'}]
mocker.patch.dict('freqtrade.main._CONF', conf)
msg_mock = MagicMock()
mocker.patch.multiple('freqtrade.main.telegram',
_CONF=conf,
init=MagicMock(),
send_msg=msg_mock)
mocker.patch.multiple('freqtrade.main.exchange',
get_balances=MagicMock(return_value=mock_balance))
_balance(bot=MagicBot(), update=update)
assert msg_mock.call_count == 1
assert '*Currency*: BTC' in msg_mock.call_args_list[0][0][0]
assert 'Balance' in msg_mock.call_args_list[0][0][0]