Merge branch 'develop' into support_multiple_ticker

This commit is contained in:
Jean-Baptiste LE STANG
2018-01-20 19:25:47 +01:00
22 changed files with 767 additions and 253 deletions

View File

@@ -10,7 +10,6 @@ from sqlalchemy import create_engine
import freqtrade.main as main
from freqtrade import DependencyException, OperationalException
from freqtrade.analyze import SignalType
from freqtrade.exchange import Exchanges
from freqtrade.main import (_process, check_handle_timedout, create_trade,
execute_sell, get_target_bid, handle_trade, init)
@@ -52,7 +51,7 @@ def test_main_start_hyperopt(mocker):
def test_process_trade_creation(default_conf, ticker, limit_buy_order, health, mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf)
mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=MagicMock())
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t, i: True)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (True, False))
mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(),
get_ticker=ticker,
@@ -82,7 +81,7 @@ def test_process_trade_creation(default_conf, ticker, limit_buy_order, health, m
def test_process_exchange_failures(default_conf, ticker, health, mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf)
mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=MagicMock())
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t, i: True)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (True, False))
sleep_mock = mocker.patch('time.sleep', side_effect=lambda _: None)
mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(),
@@ -99,7 +98,7 @@ def test_process_operational_exception(default_conf, ticker, health, mocker):
msg_mock = MagicMock()
mocker.patch.dict('freqtrade.main._CONF', default_conf)
mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=msg_mock)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t, i: True)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (True, False))
mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(),
get_ticker=ticker,
@@ -117,8 +116,7 @@ def test_process_operational_exception(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.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('freqtrade.main.get_signal', side_effect=lambda s: (True, False))
mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(),
get_ticker=ticker,
@@ -140,7 +138,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, i: True)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (True, False))
mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=MagicMock())
mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(),
@@ -171,7 +169,7 @@ def test_create_trade(default_conf, ticker, limit_buy_order, mocker):
def test_create_trade_minimal_amount(default_conf, ticker, mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf)
mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=MagicMock())
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t, i: True)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (True, False))
buy_mock = mocker.patch(
'freqtrade.main.exchange.buy', MagicMock(return_value='mocked_limit_buy')
)
@@ -187,7 +185,7 @@ def test_create_trade_minimal_amount(default_conf, ticker, 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, i: True)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (True, False))
mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=MagicMock())
mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(),
@@ -200,7 +198,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, i: True)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (True, False))
mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=MagicMock())
mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(),
@@ -216,7 +214,7 @@ def test_create_trade_no_pairs(default_conf, ticker, mocker):
def test_create_trade_no_pairs_after_blacklist(default_conf, ticker, mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t, i: True)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (True, False))
mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=MagicMock())
mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(),
@@ -233,7 +231,7 @@ def test_create_trade_no_pairs_after_blacklist(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, i: True)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (True, False))
mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=MagicMock())
mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(),
@@ -256,6 +254,7 @@ def test_handle_trade(default_conf, limit_buy_order, limit_sell_order, mocker):
trade.update(limit_buy_order)
assert trade.is_open is True
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (False, True))
assert handle_trade(trade, int(default_conf['ticker_interval'])) is True
assert trade.open_order_id == 'mocked_limit_sell'
@@ -268,11 +267,57 @@ def test_handle_trade(default_conf, limit_buy_order, limit_sell_order, mocker):
assert trade.close_date is not None
def test_handle_overlpapping_signals(default_conf, ticker, mocker, caplog):
default_conf.update({'experimental': {'use_sell_signal': True}})
mocker.patch.dict('freqtrade.main._CONF', default_conf)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (True, True))
mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=MagicMock())
mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(),
get_ticker=ticker,
buy=MagicMock(return_value='mocked_limit_buy'))
mocker.patch('freqtrade.main.min_roi_reached', return_value=False)
init(default_conf, create_engine('sqlite://'))
create_trade(0.001, int(default_conf['ticker_interval']))
# Buy and Sell triggering, so doing nothing ...
trades = Trade.query.all()
assert len(trades) == 0
# Buy is triggering, so buying ...
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (True, False))
create_trade(0.001, int(default_conf['ticker_interval']))
trades = Trade.query.all()
assert len(trades) == 1
assert trades[0].is_open is True
# Buy and Sell are not triggering, so doing nothing ...
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (False, False))
assert handle_trade(trades[0], int(default_conf['ticker_interval'])) is False
trades = Trade.query.all()
assert len(trades) == 1
assert trades[0].is_open is True
# Buy and Sell are triggering, so doing nothing ...
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (True, True))
assert handle_trade(trades[0], int(default_conf['ticker_interval'])) is False
trades = Trade.query.all()
assert len(trades) == 1
assert trades[0].is_open is True
# Sell is triggering, guess what : we are Selling!
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (False, True))
trades = Trade.query.all()
assert handle_trade(trades[0], int(default_conf['ticker_interval'])) is True
def test_handle_trade_roi(default_conf, ticker, mocker, caplog):
default_conf.update({'experimental': {'use_sell_signal': True}})
mocker.patch.dict('freqtrade.main._CONF', default_conf)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t, i: True)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (True, False))
mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=MagicMock())
mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(),
@@ -291,13 +336,12 @@ def test_handle_trade_roi(default_conf, ticker, mocker, caplog):
# we might just want to check if we are in a sell condition without
# executing
# if ROI is reached we must sell
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t, i: False)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (False, True))
assert handle_trade(trade, interval=int(default_conf['ticker_interval']))
assert ('freqtrade', logging.DEBUG, 'Executing sell due to ROI ...') in caplog.record_tuples
# if ROI is reached we must sell even if sell-signal is not signalled
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t, i: True)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (False, True))
assert handle_trade(trade, interval=int(default_conf['ticker_interval']))
assert ('freqtrade', logging.DEBUG, 'Executing sell due to ROI ...') in caplog.record_tuples
@@ -305,7 +349,7 @@ def test_handle_trade_experimental(default_conf, ticker, mocker, caplog):
default_conf.update({'experimental': {'use_sell_signal': True}})
mocker.patch.dict('freqtrade.main._CONF', default_conf)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t, i: True)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (True, False))
mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=MagicMock())
mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(),
@@ -319,11 +363,10 @@ def test_handle_trade_experimental(default_conf, ticker, mocker, caplog):
trade = Trade.query.first()
trade.is_open = True
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t, i: False)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (False, False))
value_returned = handle_trade(trade, int(default_conf['ticker_interval']))
assert ('freqtrade', logging.DEBUG, 'Checking sell_signal ...') in caplog.record_tuples
assert value_returned is False
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t, i: True)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (False, True))
assert handle_trade(trade, int(default_conf['ticker_interval']))
s = 'Executing sell due to sell signal ...'
assert ('freqtrade', logging.DEBUG, s) in caplog.record_tuples
@@ -331,7 +374,7 @@ def test_handle_trade_experimental(default_conf, ticker, mocker, caplog):
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, i: True)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (True, False))
mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=MagicMock())
mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(),
@@ -356,7 +399,8 @@ def test_close_trade(default_conf, ticker, limit_buy_order, limit_sell_order, mo
def test_check_handle_timedout_buy(default_conf, ticker, limit_buy_order_old, mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf)
cancel_order_mock = MagicMock()
mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=MagicMock())
mocker.patch('freqtrade.rpc.init', MagicMock())
rpc_mock = mocker.patch('freqtrade.main.rpc.send_msg', MagicMock())
mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(),
get_ticker=ticker,
@@ -381,6 +425,7 @@ def test_check_handle_timedout_buy(default_conf, ticker, limit_buy_order_old, mo
# check it does cancel buy orders over the time limit
check_handle_timedout(600)
assert cancel_order_mock.call_count == 1
assert rpc_mock.call_count == 1
trades = Trade.query.filter(Trade.open_order_id.is_(trade_buy.open_order_id)).all()
assert len(trades) == 0
@@ -388,7 +433,8 @@ def test_check_handle_timedout_buy(default_conf, ticker, limit_buy_order_old, mo
def test_check_handle_timedout_sell(default_conf, ticker, limit_sell_order_old, mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf)
cancel_order_mock = MagicMock()
mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=MagicMock())
mocker.patch('freqtrade.rpc.init', MagicMock())
rpc_mock = mocker.patch('freqtrade.main.rpc.send_msg', MagicMock())
mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(),
get_ticker=ticker,
@@ -414,6 +460,7 @@ def test_check_handle_timedout_sell(default_conf, ticker, limit_sell_order_old,
# check it does cancel sell orders over the time limit
check_handle_timedout(600)
assert cancel_order_mock.call_count == 1
assert rpc_mock.call_count == 1
assert trade_sell.is_open is True
@@ -421,7 +468,8 @@ def test_check_handle_timedout_partial(default_conf, ticker, limit_buy_order_old
mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf)
cancel_order_mock = MagicMock()
mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=MagicMock())
mocker.patch('freqtrade.rpc.init', MagicMock())
rpc_mock = mocker.patch('freqtrade.main.rpc.send_msg', MagicMock())
mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(),
get_ticker=ticker,
@@ -447,6 +495,7 @@ def test_check_handle_timedout_partial(default_conf, ticker, limit_buy_order_old
# note this is for a partially-complete buy order
check_handle_timedout(600)
assert cancel_order_mock.call_count == 1
assert rpc_mock.call_count == 1
trades = Trade.query.filter(Trade.open_order_id.is_(trade_buy.open_order_id)).all()
assert len(trades) == 1
assert trades[0].amount == 23.0
@@ -470,7 +519,7 @@ def test_balance_bigger_last_ask(mocker):
def test_execute_sell_up(default_conf, ticker, ticker_sell_up, mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t, i: True)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (True, False))
mocker.patch('freqtrade.rpc.init', MagicMock())
rpc_mock = mocker.patch('freqtrade.main.rpc.send_msg', MagicMock())
mocker.patch.multiple('freqtrade.main.exchange',
@@ -503,7 +552,7 @@ def test_execute_sell_up(default_conf, ticker, ticker_sell_up, mocker):
def test_execute_sell_down(default_conf, ticker, ticker_sell_down, mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t, i: True)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (True, False))
mocker.patch('freqtrade.rpc.init', MagicMock())
rpc_mock = mocker.patch('freqtrade.main.rpc.send_msg', MagicMock())
mocker.patch.multiple('freqtrade.rpc.telegram',
@@ -540,7 +589,7 @@ def test_execute_sell_down(default_conf, ticker, ticker_sell_down, mocker):
def test_execute_sell_without_conf_sell_down(default_conf, ticker, ticker_sell_down, mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t, i: True)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s,: (True, False))
mocker.patch('freqtrade.rpc.init', MagicMock())
rpc_mock = mocker.patch('freqtrade.main.rpc.send_msg', MagicMock())
mocker.patch.multiple('freqtrade.main.exchange',
@@ -572,7 +621,7 @@ def test_execute_sell_without_conf_sell_down(default_conf, ticker, ticker_sell_d
def test_execute_sell_without_conf_sell_up(default_conf, ticker, ticker_sell_up, mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t, i: True)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (True, False))
mocker.patch('freqtrade.rpc.init', MagicMock())
rpc_mock = mocker.patch('freqtrade.main.rpc.send_msg', MagicMock())
mocker.patch.multiple('freqtrade.main.exchange',
@@ -609,7 +658,7 @@ def test_sell_profit_only_enable_profit(default_conf, limit_buy_order, mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf)
mocker.patch('freqtrade.main.min_roi_reached', return_value=False)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t, i: True)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (True, False))
mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=MagicMock())
mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(),
@@ -625,6 +674,7 @@ def test_sell_profit_only_enable_profit(default_conf, limit_buy_order, mocker):
trade = Trade.query.first()
trade.update(limit_buy_order)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (False, True))
assert handle_trade(trade, int(default_conf['ticker_interval'])) is True
@@ -636,7 +686,7 @@ def test_sell_profit_only_disable_profit(default_conf, limit_buy_order, mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf)
mocker.patch('freqtrade.main.min_roi_reached', return_value=False)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t, i: True)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (True, False))
mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=MagicMock())
mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(),
@@ -652,6 +702,7 @@ def test_sell_profit_only_disable_profit(default_conf, limit_buy_order, mocker):
trade = Trade.query.first()
trade.update(limit_buy_order)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (False, True))
assert handle_trade(trade, int(default_conf['ticker_interval'])) is True
@@ -663,7 +714,7 @@ def test_sell_profit_only_enable_loss(default_conf, limit_buy_order, mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf)
mocker.patch('freqtrade.main.min_roi_reached', return_value=False)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t, i: True)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (True, False))
mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=MagicMock())
mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(),
@@ -679,6 +730,7 @@ def test_sell_profit_only_enable_loss(default_conf, limit_buy_order, mocker):
trade = Trade.query.first()
trade.update(limit_buy_order)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (False, True))
assert handle_trade(trade, int(default_conf['ticker_interval'])) is False
@@ -690,7 +742,7 @@ def test_sell_profit_only_disable_loss(default_conf, limit_buy_order, mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf)
mocker.patch('freqtrade.main.min_roi_reached', return_value=False)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t, i: True)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (True, False))
mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=MagicMock())
mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(),
@@ -706,4 +758,5 @@ def test_sell_profit_only_disable_loss(default_conf, limit_buy_order, mocker):
trade = Trade.query.first()
trade.update(limit_buy_order)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s: (False, True))
assert handle_trade(trade, int(default_conf['ticker_interval'])) is True