Merge pull request #2457 from freqtrade/integration_tests

split up test_freqtradebot.py
This commit is contained in:
hroff-1902 2019-10-31 22:05:03 +03:00 committed by GitHub
commit 5b87393a95
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 289 additions and 291 deletions

View File

@ -14,7 +14,6 @@ import requests
from freqtrade import (DependencyException, InvalidOrderException, from freqtrade import (DependencyException, InvalidOrderException,
OperationalException, TemporaryError, constants) OperationalException, TemporaryError, constants)
from freqtrade.constants import MATH_CLOSE_PREC from freqtrade.constants import MATH_CLOSE_PREC
from freqtrade.data.dataprovider import DataProvider
from freqtrade.freqtradebot import FreqtradeBot from freqtrade.freqtradebot import FreqtradeBot
from freqtrade.persistence import Trade from freqtrade.persistence import Trade
from freqtrade.rpc import RPCMessageType from freqtrade.rpc import RPCMessageType
@ -49,16 +48,6 @@ def test_freqtradebot_state(mocker, default_conf, markets) -> None:
assert freqtrade.state is State.STOPPED assert freqtrade.state is State.STOPPED
def test_worker_state(mocker, default_conf, markets) -> None:
mocker.patch('freqtrade.exchange.Exchange.markets', PropertyMock(return_value=markets))
worker = get_patched_worker(mocker, default_conf)
assert worker.state is State.RUNNING
default_conf.pop('initial_state')
worker = Worker(args=None, config=default_conf)
assert worker.state is State.STOPPED
def test_cleanup(mocker, default_conf, caplog) -> None: def test_cleanup(mocker, default_conf, caplog) -> None:
mock_cleanup = MagicMock() mock_cleanup = MagicMock()
mocker.patch('freqtrade.persistence.cleanup', mock_cleanup) mocker.patch('freqtrade.persistence.cleanup', mock_cleanup)
@ -68,69 +57,6 @@ def test_cleanup(mocker, default_conf, caplog) -> None:
assert mock_cleanup.call_count == 1 assert mock_cleanup.call_count == 1
def test_worker_running(mocker, default_conf, caplog) -> None:
mock_throttle = MagicMock()
mocker.patch('freqtrade.worker.Worker._throttle', mock_throttle)
mocker.patch('freqtrade.persistence.Trade.stoploss_reinitialization', MagicMock())
worker = get_patched_worker(mocker, default_conf)
state = worker._worker(old_state=None)
assert state is State.RUNNING
assert log_has('Changing state to: RUNNING', caplog)
assert mock_throttle.call_count == 1
# Check strategy is loaded, and received a dataprovider object
assert worker.freqtrade.strategy
assert worker.freqtrade.strategy.dp
assert isinstance(worker.freqtrade.strategy.dp, DataProvider)
def test_worker_stopped(mocker, default_conf, caplog) -> None:
mock_throttle = MagicMock()
mocker.patch('freqtrade.worker.Worker._throttle', mock_throttle)
mock_sleep = mocker.patch('time.sleep', return_value=None)
worker = get_patched_worker(mocker, default_conf)
worker.state = State.STOPPED
state = worker._worker(old_state=State.RUNNING)
assert state is State.STOPPED
assert log_has('Changing state to: STOPPED', caplog)
assert mock_throttle.call_count == 0
assert mock_sleep.call_count == 1
def test_throttle(mocker, default_conf, caplog) -> None:
def throttled_func():
return 42
caplog.set_level(logging.DEBUG)
worker = get_patched_worker(mocker, default_conf)
start = time.time()
result = worker._throttle(throttled_func, min_secs=0.1)
end = time.time()
assert result == 42
assert end - start > 0.1
assert log_has('Throttling throttled_func for 0.10 seconds', caplog)
result = worker._throttle(throttled_func, min_secs=-1)
assert result == 42
def test_throttle_with_assets(mocker, default_conf) -> None:
def throttled_func(nb_assets=-1):
return nb_assets
worker = get_patched_worker(mocker, default_conf)
result = worker._throttle(throttled_func, min_secs=0.1, nb_assets=666)
assert result == 666
result = worker._throttle(throttled_func, min_secs=0.1)
assert result == -1
def test_order_dict_dry_run(default_conf, mocker, caplog) -> None: def test_order_dict_dry_run(default_conf, mocker, caplog) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
@ -224,18 +150,13 @@ def test_get_trade_stake_amount_no_stake_amount(default_conf, mocker) -> None:
freqtrade._get_trade_stake_amount('ETH/BTC') freqtrade._get_trade_stake_amount('ETH/BTC')
def test_get_trade_stake_amount_unlimited_amount(default_conf, def test_get_trade_stake_amount_unlimited_amount(default_conf, ticker,
ticker, limit_buy_order, fee, mocker) -> None:
limit_buy_order,
fee,
markets,
mocker) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
patch_wallet(mocker, free=default_conf['stake_amount']) patch_wallet(mocker, free=default_conf['stake_amount'])
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
markets=PropertyMock(return_value=markets),
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee get_fee=fee
@ -296,7 +217,7 @@ def test_edge_overrides_stake_amount(mocker, edge_conf) -> None:
assert freqtrade._get_trade_stake_amount('LTC/BTC') == (999.9 * 0.5 * 0.01) / 0.21 assert freqtrade._get_trade_stake_amount('LTC/BTC') == (999.9 * 0.5 * 0.01) / 0.21
def test_edge_overrides_stoploss(limit_buy_order, fee, markets, caplog, mocker, edge_conf) -> None: def test_edge_overrides_stoploss(limit_buy_order, fee, caplog, mocker, edge_conf) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
@ -317,7 +238,6 @@ def test_edge_overrides_stoploss(limit_buy_order, fee, markets, caplog, mocker,
}), }),
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
############################################# #############################################
@ -337,7 +257,7 @@ def test_edge_overrides_stoploss(limit_buy_order, fee, markets, caplog, mocker,
assert trade.sell_reason == SellType.STOP_LOSS.value assert trade.sell_reason == SellType.STOP_LOSS.value
def test_edge_should_ignore_strategy_stoploss(limit_buy_order, fee, markets, def test_edge_should_ignore_strategy_stoploss(limit_buy_order, fee,
mocker, edge_conf) -> None: mocker, edge_conf) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
@ -358,7 +278,6 @@ def test_edge_should_ignore_strategy_stoploss(limit_buy_order, fee, markets,
}), }),
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets),
) )
############################################# #############################################
@ -377,7 +296,7 @@ def test_edge_should_ignore_strategy_stoploss(limit_buy_order, fee, markets,
def test_total_open_trades_stakes(mocker, default_conf, ticker, def test_total_open_trades_stakes(mocker, default_conf, ticker,
limit_buy_order, fee, markets) -> None: limit_buy_order, fee) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
default_conf['stake_amount'] = 0.0000098751 default_conf['stake_amount'] = 0.0000098751
@ -387,7 +306,6 @@ def test_total_open_trades_stakes(mocker, default_conf, ticker,
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
@ -522,7 +440,7 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None:
assert result == min(8, 2 * 2) / 0.9 assert result == min(8, 2 * 2) / 0.9
def test_create_trades(default_conf, ticker, limit_buy_order, fee, markets, mocker) -> None: def test_create_trades(default_conf, ticker, limit_buy_order, fee, mocker) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
@ -530,7 +448,6 @@ def test_create_trades(default_conf, ticker, limit_buy_order, fee, markets, mock
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
# Save state of current whitelist # Save state of current whitelist
@ -556,7 +473,7 @@ def test_create_trades(default_conf, ticker, limit_buy_order, fee, markets, mock
def test_create_trades_no_stake_amount(default_conf, ticker, limit_buy_order, def test_create_trades_no_stake_amount(default_conf, ticker, limit_buy_order,
fee, markets, mocker) -> None: fee, mocker) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
patch_wallet(mocker, free=default_conf['stake_amount'] * 0.5) patch_wallet(mocker, free=default_conf['stake_amount'] * 0.5)
@ -565,7 +482,6 @@ def test_create_trades_no_stake_amount(default_conf, ticker, limit_buy_order,
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
@ -575,7 +491,7 @@ def test_create_trades_no_stake_amount(default_conf, ticker, limit_buy_order,
def test_create_trades_minimal_amount(default_conf, ticker, limit_buy_order, def test_create_trades_minimal_amount(default_conf, ticker, limit_buy_order,
fee, markets, mocker) -> None: fee, mocker) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
buy_mock = MagicMock(return_value={'id': limit_buy_order['id']}) buy_mock = MagicMock(return_value={'id': limit_buy_order['id']})
@ -584,7 +500,6 @@ def test_create_trades_minimal_amount(default_conf, ticker, limit_buy_order,
get_ticker=ticker, get_ticker=ticker,
buy=buy_mock, buy=buy_mock,
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
default_conf['stake_amount'] = 0.0005 default_conf['stake_amount'] = 0.0005
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
@ -596,7 +511,7 @@ def test_create_trades_minimal_amount(default_conf, ticker, limit_buy_order,
def test_create_trades_too_small_stake_amount(default_conf, ticker, limit_buy_order, def test_create_trades_too_small_stake_amount(default_conf, ticker, limit_buy_order,
fee, markets, mocker) -> None: fee, mocker) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
buy_mock = MagicMock(return_value={'id': limit_buy_order['id']}) buy_mock = MagicMock(return_value={'id': limit_buy_order['id']})
@ -605,7 +520,6 @@ def test_create_trades_too_small_stake_amount(default_conf, ticker, limit_buy_or
get_ticker=ticker, get_ticker=ticker,
buy=buy_mock, buy=buy_mock,
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
default_conf['stake_amount'] = 0.000000005 default_conf['stake_amount'] = 0.000000005
@ -625,7 +539,6 @@ def test_create_trades_limit_reached(default_conf, ticker, limit_buy_order,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_balance=MagicMock(return_value=default_conf['stake_amount']), get_balance=MagicMock(return_value=default_conf['stake_amount']),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
default_conf['max_open_trades'] = 0 default_conf['max_open_trades'] = 0
default_conf['stake_amount'] = constants.UNLIMITED_STAKE_AMOUNT default_conf['stake_amount'] = constants.UNLIMITED_STAKE_AMOUNT
@ -638,7 +551,7 @@ def test_create_trades_limit_reached(default_conf, ticker, limit_buy_order,
def test_create_trades_no_pairs_let(default_conf, ticker, limit_buy_order, fee, def test_create_trades_no_pairs_let(default_conf, ticker, limit_buy_order, fee,
markets, mocker, caplog) -> None: mocker, caplog) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
@ -646,7 +559,6 @@ def test_create_trades_no_pairs_let(default_conf, ticker, limit_buy_order, fee,
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
default_conf['exchange']['pair_whitelist'] = ["ETH/BTC"] default_conf['exchange']['pair_whitelist'] = ["ETH/BTC"]
@ -660,7 +572,7 @@ def test_create_trades_no_pairs_let(default_conf, ticker, limit_buy_order, fee,
def test_create_trades_no_pairs_in_whitelist(default_conf, ticker, limit_buy_order, fee, def test_create_trades_no_pairs_in_whitelist(default_conf, ticker, limit_buy_order, fee,
markets, mocker, caplog) -> None: mocker, caplog) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
@ -668,7 +580,6 @@ def test_create_trades_no_pairs_in_whitelist(default_conf, ticker, limit_buy_ord
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
default_conf['exchange']['pair_whitelist'] = [] default_conf['exchange']['pair_whitelist'] = []
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
@ -699,7 +610,7 @@ def test_create_trades_no_signal(default_conf, fee, mocker) -> None:
@pytest.mark.parametrize("max_open", range(0, 5)) @pytest.mark.parametrize("max_open", range(0, 5))
def test_create_trades_multiple_trades(default_conf, ticker, def test_create_trades_multiple_trades(default_conf, ticker,
fee, markets, mocker, max_open) -> None: fee, mocker, max_open) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
default_conf['max_open_trades'] = max_open default_conf['max_open_trades'] = max_open
@ -708,7 +619,6 @@ def test_create_trades_multiple_trades(default_conf, ticker,
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': "12355555"}), buy=MagicMock(return_value={'id': "12355555"}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
@ -719,7 +629,7 @@ def test_create_trades_multiple_trades(default_conf, ticker,
assert len(trades) == max_open assert len(trades) == max_open
def test_create_trades_preopen(default_conf, ticker, fee, markets, mocker) -> None: def test_create_trades_preopen(default_conf, ticker, fee, mocker) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
default_conf['max_open_trades'] = 4 default_conf['max_open_trades'] = 4
@ -728,7 +638,6 @@ def test_create_trades_preopen(default_conf, ticker, fee, markets, mocker) -> No
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': "12355555"}), buy=MagicMock(return_value={'id': "12355555"}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
@ -747,13 +656,12 @@ def test_create_trades_preopen(default_conf, ticker, fee, markets, mocker) -> No
def test_process_trade_creation(default_conf, ticker, limit_buy_order, def test_process_trade_creation(default_conf, ticker, limit_buy_order,
markets, fee, mocker, caplog) -> None: fee, mocker, caplog) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
markets=PropertyMock(return_value=markets),
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_order=MagicMock(return_value=limit_buy_order), get_order=MagicMock(return_value=limit_buy_order),
get_fee=fee, get_fee=fee,
@ -782,13 +690,12 @@ def test_process_trade_creation(default_conf, ticker, limit_buy_order,
) )
def test_process_exchange_failures(default_conf, ticker, markets, mocker) -> None: def test_process_exchange_failures(default_conf, ticker, mocker) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
markets=PropertyMock(return_value=markets),
buy=MagicMock(side_effect=TemporaryError) buy=MagicMock(side_effect=TemporaryError)
) )
sleep_mock = mocker.patch('time.sleep', side_effect=lambda _: None) sleep_mock = mocker.patch('time.sleep', side_effect=lambda _: None)
@ -800,13 +707,12 @@ def test_process_exchange_failures(default_conf, ticker, markets, mocker) -> Non
assert sleep_mock.has_calls() assert sleep_mock.has_calls()
def test_process_operational_exception(default_conf, ticker, markets, mocker) -> None: def test_process_operational_exception(default_conf, ticker, mocker) -> None:
msg_mock = patch_RPCManager(mocker) msg_mock = patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
markets=PropertyMock(return_value=markets),
buy=MagicMock(side_effect=OperationalException) buy=MagicMock(side_effect=OperationalException)
) )
worker = Worker(args=None, config=default_conf) worker = Worker(args=None, config=default_conf)
@ -819,14 +725,12 @@ def test_process_operational_exception(default_conf, ticker, markets, mocker) ->
assert 'OperationalException' in msg_mock.call_args_list[-1][0][0]['status'] assert 'OperationalException' in msg_mock.call_args_list[-1][0][0]['status']
def test_process_trade_handling( def test_process_trade_handling(default_conf, ticker, limit_buy_order, fee, mocker) -> None:
default_conf, ticker, limit_buy_order, markets, fee, mocker) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
markets=PropertyMock(return_value=markets),
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_order=MagicMock(return_value=limit_buy_order), get_order=MagicMock(return_value=limit_buy_order),
get_fee=fee, get_fee=fee,
@ -846,15 +750,14 @@ def test_process_trade_handling(
assert len(trades) == 1 assert len(trades) == 1
def test_process_trade_no_whitelist_pair( def test_process_trade_no_whitelist_pair(default_conf, ticker, limit_buy_order,
default_conf, ticker, limit_buy_order, markets, fee, mocker) -> None: fee, mocker) -> None:
""" Test process with trade not in pair list """ """ Test process with trade not in pair list """
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
markets=PropertyMock(return_value=markets),
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_order=MagicMock(return_value=limit_buy_order), get_order=MagicMock(return_value=limit_buy_order),
get_fee=fee, get_fee=fee,
@ -891,7 +794,7 @@ def test_process_trade_no_whitelist_pair(
assert len(freqtrade.active_pair_whitelist) == len(set(freqtrade.active_pair_whitelist)) assert len(freqtrade.active_pair_whitelist) == len(set(freqtrade.active_pair_whitelist))
def test_process_informative_pairs_added(default_conf, ticker, markets, mocker) -> None: def test_process_informative_pairs_added(default_conf, ticker, mocker) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
@ -902,7 +805,6 @@ def test_process_informative_pairs_added(default_conf, ticker, markets, mocker)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
markets=PropertyMock(return_value=markets),
buy=MagicMock(side_effect=TemporaryError), buy=MagicMock(side_effect=TemporaryError),
refresh_latest_ohlcv=refresh_mock, refresh_latest_ohlcv=refresh_mock,
) )
@ -948,7 +850,7 @@ def test_balance_bigger_last_ask(mocker, default_conf) -> None:
assert freqtrade.get_target_bid('ETH/BTC') == 5 assert freqtrade.get_target_bid('ETH/BTC') == 5
def test_execute_buy(mocker, default_conf, fee, markets, limit_buy_order) -> None: def test_execute_buy(mocker, default_conf, fee, limit_buy_order) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
@ -970,7 +872,6 @@ def test_execute_buy(mocker, default_conf, fee, markets, limit_buy_order) -> Non
}), }),
buy=buy_mm, buy=buy_mm,
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
pair = 'ETH/BTC' pair = 'ETH/BTC'
@ -1067,7 +968,7 @@ def test_add_stoploss_on_exchange(mocker, default_conf, limit_buy_order) -> None
def test_handle_stoploss_on_exchange(mocker, default_conf, fee, caplog, def test_handle_stoploss_on_exchange(mocker, default_conf, fee, caplog,
markets, limit_buy_order, limit_sell_order) -> None: limit_buy_order, limit_sell_order) -> None:
stoploss_limit = MagicMock(return_value={'id': 13434334}) stoploss_limit = MagicMock(return_value={'id': 13434334})
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
@ -1081,7 +982,6 @@ def test_handle_stoploss_on_exchange(mocker, default_conf, fee, caplog,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
sell=MagicMock(return_value={'id': limit_sell_order['id']}), sell=MagicMock(return_value={'id': limit_sell_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets),
stoploss_limit=stoploss_limit stoploss_limit=stoploss_limit
) )
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
@ -1168,7 +1068,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf, fee, caplog,
def test_handle_sle_cancel_cant_recreate(mocker, default_conf, fee, caplog, def test_handle_sle_cancel_cant_recreate(mocker, default_conf, fee, caplog,
markets, limit_buy_order, limit_sell_order) -> None: limit_buy_order, limit_sell_order) -> None:
# Sixth case: stoploss order was cancelled but couldn't create new one # Sixth case: stoploss order was cancelled but couldn't create new one
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
@ -1182,7 +1082,6 @@ def test_handle_sle_cancel_cant_recreate(mocker, default_conf, fee, caplog,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
sell=MagicMock(return_value={'id': limit_sell_order['id']}), sell=MagicMock(return_value={'id': limit_sell_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets),
get_order=MagicMock(return_value={'status': 'canceled'}), get_order=MagicMock(return_value={'status': 'canceled'}),
stoploss_limit=MagicMock(side_effect=DependencyException()), stoploss_limit=MagicMock(side_effect=DependencyException()),
) )
@ -1203,7 +1102,7 @@ def test_handle_sle_cancel_cant_recreate(mocker, default_conf, fee, caplog,
def test_create_stoploss_order_invalid_order(mocker, default_conf, caplog, fee, def test_create_stoploss_order_invalid_order(mocker, default_conf, caplog, fee,
markets, limit_buy_order, limit_sell_order): limit_buy_order, limit_sell_order):
rpc_mock = patch_RPCManager(mocker) rpc_mock = patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
sell_mock = MagicMock(return_value={'id': limit_sell_order['id']}) sell_mock = MagicMock(return_value={'id': limit_sell_order['id']})
@ -1217,7 +1116,6 @@ def test_create_stoploss_order_invalid_order(mocker, default_conf, caplog, fee,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
sell=sell_mock, sell=sell_mock,
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets),
get_order=MagicMock(return_value={'status': 'canceled'}), get_order=MagicMock(return_value={'status': 'canceled'}),
stoploss_limit=MagicMock(side_effect=InvalidOrderException()), stoploss_limit=MagicMock(side_effect=InvalidOrderException()),
) )
@ -1340,8 +1238,7 @@ def test_handle_stoploss_on_exchange_trailing(mocker, default_conf, fee, caplog,
def test_handle_stoploss_on_exchange_trailing_error(mocker, default_conf, fee, caplog, def test_handle_stoploss_on_exchange_trailing_error(mocker, default_conf, fee, caplog,
markets, limit_buy_order, limit_buy_order, limit_sell_order) -> None:
limit_sell_order) -> None:
# When trailing stoploss is set # When trailing stoploss is set
stoploss_limit = MagicMock(return_value={'id': 13434334}) stoploss_limit = MagicMock(return_value={'id': 13434334})
patch_exchange(mocker) patch_exchange(mocker)
@ -1356,7 +1253,6 @@ def test_handle_stoploss_on_exchange_trailing_error(mocker, default_conf, fee, c
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
sell=MagicMock(return_value={'id': limit_sell_order['id']}), sell=MagicMock(return_value={'id': limit_sell_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets),
stoploss_limit=stoploss_limit stoploss_limit=stoploss_limit
) )
@ -1409,7 +1305,7 @@ def test_handle_stoploss_on_exchange_trailing_error(mocker, default_conf, fee, c
def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog, def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog,
markets, limit_buy_order, limit_sell_order) -> None: limit_buy_order, limit_sell_order) -> None:
# When trailing stoploss is set # When trailing stoploss is set
stoploss_limit = MagicMock(return_value={'id': 13434334}) stoploss_limit = MagicMock(return_value={'id': 13434334})
@ -1427,7 +1323,6 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
sell=MagicMock(return_value={'id': limit_sell_order['id']}), sell=MagicMock(return_value={'id': limit_sell_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets),
stoploss_limit=stoploss_limit stoploss_limit=stoploss_limit
) )
@ -1728,8 +1623,7 @@ def test_update_trade_state_sell(default_conf, trades_for_order, limit_sell_orde
assert not trade.is_open assert not trade.is_open
def test_handle_trade(default_conf, limit_buy_order, limit_sell_order, def test_handle_trade(default_conf, limit_buy_order, limit_sell_order, fee, mocker) -> None:
fee, markets, mocker) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
@ -1742,7 +1636,6 @@ def test_handle_trade(default_conf, limit_buy_order, limit_sell_order,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
sell=MagicMock(return_value={'id': limit_sell_order['id']}), sell=MagicMock(return_value={'id': limit_sell_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
@ -1769,8 +1662,7 @@ def test_handle_trade(default_conf, limit_buy_order, limit_sell_order,
assert trade.close_date is not None assert trade.close_date is not None
def test_handle_overlpapping_signals(default_conf, ticker, limit_buy_order, def test_handle_overlpapping_signals(default_conf, ticker, limit_buy_order, fee, mocker) -> None:
fee, markets, mocker) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
@ -1778,7 +1670,6 @@ def test_handle_overlpapping_signals(default_conf, ticker, limit_buy_order,
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
@ -1884,7 +1775,7 @@ def test_handle_trade_use_sell_signal(
def test_close_trade(default_conf, ticker, limit_buy_order, limit_sell_order, def test_close_trade(default_conf, ticker, limit_buy_order, limit_sell_order,
fee, markets, mocker) -> None: fee, mocker) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
@ -1892,7 +1783,6 @@ def test_close_trade(default_conf, ticker, limit_buy_order, limit_sell_order,
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
@ -2222,14 +2112,13 @@ def test_handle_timedout_limit_sell(mocker, default_conf) -> None:
assert cancel_order_mock.call_count == 1 assert cancel_order_mock.call_count == 1
def test_execute_sell_up(default_conf, ticker, fee, ticker_sell_up, markets, mocker) -> None: def test_execute_sell_up(default_conf, ticker, fee, ticker_sell_up, mocker) -> None:
rpc_mock = patch_RPCManager(mocker) rpc_mock = patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
patch_whitelist(mocker, default_conf) patch_whitelist(mocker, default_conf)
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
@ -2269,14 +2158,13 @@ def test_execute_sell_up(default_conf, ticker, fee, ticker_sell_up, markets, moc
} == last_msg } == last_msg
def test_execute_sell_down(default_conf, ticker, fee, ticker_sell_down, markets, mocker) -> None: def test_execute_sell_down(default_conf, ticker, fee, ticker_sell_down, mocker) -> None:
rpc_mock = patch_RPCManager(mocker) rpc_mock = patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
patch_whitelist(mocker, default_conf) patch_whitelist(mocker, default_conf)
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
@ -2318,15 +2206,13 @@ def test_execute_sell_down(default_conf, ticker, fee, ticker_sell_down, markets,
def test_execute_sell_down_stoploss_on_exchange_dry_run(default_conf, ticker, fee, def test_execute_sell_down_stoploss_on_exchange_dry_run(default_conf, ticker, fee,
ticker_sell_down, ticker_sell_down, mocker) -> None:
markets, mocker) -> None:
rpc_mock = patch_RPCManager(mocker) rpc_mock = patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
patch_whitelist(mocker, default_conf) patch_whitelist(mocker, default_conf)
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
@ -2374,8 +2260,7 @@ def test_execute_sell_down_stoploss_on_exchange_dry_run(default_conf, ticker, fe
} == last_msg } == last_msg
def test_execute_sell_sloe_cancel_exception(mocker, default_conf, ticker, fee, def test_execute_sell_sloe_cancel_exception(mocker, default_conf, ticker, fee, caplog) -> None:
markets, caplog) -> None:
freqtrade = get_patched_freqtradebot(mocker, default_conf) freqtrade = get_patched_freqtradebot(mocker, default_conf)
mocker.patch('freqtrade.exchange.Exchange.cancel_order', side_effect=InvalidOrderException()) mocker.patch('freqtrade.exchange.Exchange.cancel_order', side_effect=InvalidOrderException())
sellmock = MagicMock() sellmock = MagicMock()
@ -2384,7 +2269,6 @@ def test_execute_sell_sloe_cancel_exception(mocker, default_conf, ticker, fee,
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets),
sell=sellmock sell=sellmock
) )
@ -2404,9 +2288,8 @@ def test_execute_sell_sloe_cancel_exception(mocker, default_conf, ticker, fee,
assert log_has('Could not cancel stoploss order abcd', caplog) assert log_has('Could not cancel stoploss order abcd', caplog)
def test_execute_sell_with_stoploss_on_exchange(default_conf, def test_execute_sell_with_stoploss_on_exchange(default_conf, ticker, fee, ticker_sell_up,
ticker, fee, ticker_sell_up, mocker) -> None:
markets, mocker) -> None:
default_conf['exchange']['name'] = 'binance' default_conf['exchange']['name'] = 'binance'
rpc_mock = patch_RPCManager(mocker) rpc_mock = patch_RPCManager(mocker)
@ -2423,7 +2306,6 @@ def test_execute_sell_with_stoploss_on_exchange(default_conf,
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets),
symbol_amount_prec=lambda s, x, y: y, symbol_amount_prec=lambda s, x, y: y,
symbol_price_prec=lambda s, x, y: y, symbol_price_prec=lambda s, x, y: y,
stoploss_limit=stoploss_limit, stoploss_limit=stoploss_limit,
@ -2458,10 +2340,8 @@ def test_execute_sell_with_stoploss_on_exchange(default_conf,
assert rpc_mock.call_count == 2 assert rpc_mock.call_count == 2
def test_may_execute_sell_after_stoploss_on_exchange_hit(default_conf, def test_may_execute_sell_after_stoploss_on_exchange_hit(default_conf, ticker, fee,
ticker, fee, limit_buy_order, mocker) -> None:
limit_buy_order,
markets, mocker) -> None:
default_conf['exchange']['name'] = 'binance' default_conf['exchange']['name'] = 'binance'
rpc_mock = patch_RPCManager(mocker) rpc_mock = patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
@ -2469,7 +2349,6 @@ def test_may_execute_sell_after_stoploss_on_exchange_hit(default_conf,
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets),
symbol_amount_prec=lambda s, x, y: y, symbol_amount_prec=lambda s, x, y: y,
symbol_price_prec=lambda s, x, y: y, symbol_price_prec=lambda s, x, y: y,
) )
@ -2526,124 +2405,14 @@ def test_may_execute_sell_after_stoploss_on_exchange_hit(default_conf,
assert rpc_mock.call_count == 2 assert rpc_mock.call_count == 2
def test_may_execute_sell_stoploss_on_exchange_multi(default_conf,
ticker, fee,
limit_buy_order,
markets, mocker) -> None:
"""
Tests workflow of selling stoploss_on_exchange.
Sells
* first trade as stoploss
* 2nd trade is kept
* 3rd trade is sold via sell-signal
"""
default_conf['max_open_trades'] = 3
default_conf['exchange']['name'] = 'binance'
patch_RPCManager(mocker)
patch_exchange(mocker)
stoploss_limit = {
'id': 123,
'info': {}
}
stoploss_order_open = {
"id": "123",
"timestamp": 1542707426845,
"datetime": "2018-11-20T09:50:26.845Z",
"lastTradeTimestamp": None,
"symbol": "BTC/USDT",
"type": "stop_loss_limit",
"side": "sell",
"price": 1.08801,
"amount": 90.99181074,
"cost": 0.0,
"average": 0.0,
"filled": 0.0,
"remaining": 0.0,
"status": "open",
"fee": None,
"trades": None
}
stoploss_order_closed = stoploss_order_open.copy()
stoploss_order_closed['status'] = 'closed'
# Sell first trade based on stoploss, keep 2nd and 3rd trade open
stoploss_order_mock = MagicMock(
side_effect=[stoploss_order_closed, stoploss_order_open, stoploss_order_open])
# Sell 3rd trade (not called for the first trade)
should_sell_mock = MagicMock(side_effect=[
SellCheckTuple(sell_flag=False, sell_type=SellType.NONE),
SellCheckTuple(sell_flag=True, sell_type=SellType.SELL_SIGNAL)]
)
cancel_order_mock = MagicMock()
mocker.patch('freqtrade.exchange.Binance.stoploss_limit', stoploss_limit)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_ticker=ticker,
get_fee=fee,
markets=PropertyMock(return_value=markets),
symbol_amount_prec=lambda s, x, y: y,
symbol_price_prec=lambda s, x, y: y,
get_order=stoploss_order_mock,
cancel_order=cancel_order_mock,
)
wallets_mock = MagicMock()
mocker.patch.multiple(
'freqtrade.freqtradebot.FreqtradeBot',
create_stoploss_order=MagicMock(return_value=True),
update_trade_state=MagicMock(),
_notify_sell=MagicMock(),
)
mocker.patch("freqtrade.strategy.interface.IStrategy.should_sell", should_sell_mock)
mocker.patch("freqtrade.wallets.Wallets.update", wallets_mock)
freqtrade = FreqtradeBot(default_conf)
freqtrade.strategy.order_types['stoploss_on_exchange'] = True
# Switch ordertype to market to close trade immediately
freqtrade.strategy.order_types['sell'] = 'market'
patch_get_signal(freqtrade)
# Create some test data
freqtrade.create_trades()
wallets_mock.reset_mock()
Trade.session = MagicMock()
trades = Trade.query.all()
# Make sure stoploss-order is open and trade is bought (since we mock update_trade_state)
for trade in trades:
trade.stoploss_order_id = 3
trade.open_order_id = None
freqtrade.process_maybe_execute_sells(trades)
assert should_sell_mock.call_count == 2
# Only order for 3rd trade needs to be cancelled
assert cancel_order_mock.call_count == 1
# Wallets should only be called once per sell cycle
assert wallets_mock.call_count == 1
trade = trades[0]
assert trade.sell_reason == SellType.STOPLOSS_ON_EXCHANGE.value
assert not trade.is_open
trade = trades[1]
assert not trade.sell_reason
assert trade.is_open
trade = trades[2]
assert trade.sell_reason == SellType.SELL_SIGNAL.value
assert not trade.is_open
def test_execute_sell_market_order(default_conf, ticker, fee, def test_execute_sell_market_order(default_conf, ticker, fee,
ticker_sell_up, markets, mocker) -> None: ticker_sell_up, mocker) -> None:
rpc_mock = patch_RPCManager(mocker) rpc_mock = patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
patch_whitelist(mocker, default_conf) patch_whitelist(mocker, default_conf)
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
@ -2689,7 +2458,7 @@ def test_execute_sell_market_order(default_conf, ticker, fee,
def test_sell_profit_only_enable_profit(default_conf, limit_buy_order, def test_sell_profit_only_enable_profit(default_conf, limit_buy_order,
fee, markets, mocker) -> None: fee, mocker) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
@ -2701,7 +2470,6 @@ def test_sell_profit_only_enable_profit(default_conf, limit_buy_order,
}), }),
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
default_conf['ask_strategy'] = { default_conf['ask_strategy'] = {
'use_sell_signal': True, 'use_sell_signal': True,
@ -2721,7 +2489,7 @@ def test_sell_profit_only_enable_profit(default_conf, limit_buy_order,
def test_sell_profit_only_disable_profit(default_conf, limit_buy_order, def test_sell_profit_only_disable_profit(default_conf, limit_buy_order,
fee, markets, mocker) -> None: fee, mocker) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
@ -2733,7 +2501,6 @@ def test_sell_profit_only_disable_profit(default_conf, limit_buy_order,
}), }),
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
default_conf['ask_strategy'] = { default_conf['ask_strategy'] = {
'use_sell_signal': True, 'use_sell_signal': True,
@ -2751,7 +2518,7 @@ def test_sell_profit_only_disable_profit(default_conf, limit_buy_order,
assert trade.sell_reason == SellType.SELL_SIGNAL.value assert trade.sell_reason == SellType.SELL_SIGNAL.value
def test_sell_profit_only_enable_loss(default_conf, limit_buy_order, fee, markets, mocker) -> None: def test_sell_profit_only_enable_loss(default_conf, limit_buy_order, fee, mocker) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
@ -2763,7 +2530,6 @@ def test_sell_profit_only_enable_loss(default_conf, limit_buy_order, fee, market
}), }),
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
default_conf['ask_strategy'] = { default_conf['ask_strategy'] = {
'use_sell_signal': True, 'use_sell_signal': True,
@ -2781,7 +2547,7 @@ def test_sell_profit_only_enable_loss(default_conf, limit_buy_order, fee, market
assert freqtrade.handle_trade(trade) is False assert freqtrade.handle_trade(trade) is False
def test_sell_profit_only_disable_loss(default_conf, limit_buy_order, fee, markets, mocker) -> None: def test_sell_profit_only_disable_loss(default_conf, limit_buy_order, fee, mocker) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
@ -2793,7 +2559,6 @@ def test_sell_profit_only_disable_loss(default_conf, limit_buy_order, fee, marke
}), }),
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
default_conf['ask_strategy'] = { default_conf['ask_strategy'] = {
'use_sell_signal': True, 'use_sell_signal': True,
@ -3115,7 +2880,7 @@ def test_tsl_only_offset_reached(default_conf, limit_buy_order, fee,
def test_disable_ignore_roi_if_buy_signal(default_conf, limit_buy_order, def test_disable_ignore_roi_if_buy_signal(default_conf, limit_buy_order,
fee, markets, mocker) -> None: fee, mocker) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
@ -3127,7 +2892,6 @@ def test_disable_ignore_roi_if_buy_signal(default_conf, limit_buy_order,
}), }),
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
default_conf['ask_strategy'] = { default_conf['ask_strategy'] = {
'ignore_roi_if_buy_signal': False 'ignore_roi_if_buy_signal': False
@ -3422,7 +3186,7 @@ def test_get_real_amount_open_trade(default_conf, mocker):
assert freqtrade.get_real_amount(trade, order) == amount assert freqtrade.get_real_amount(trade, order) == amount
def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order, fee, markets, mocker, def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order, fee, mocker,
order_book_l2): order_book_l2):
default_conf['bid_strategy']['check_depth_of_market']['enabled'] = True default_conf['bid_strategy']['check_depth_of_market']['enabled'] = True
default_conf['bid_strategy']['check_depth_of_market']['bids_to_ask_delta'] = 0.1 default_conf['bid_strategy']['check_depth_of_market']['bids_to_ask_delta'] = 0.1
@ -3434,7 +3198,6 @@ def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order, fee,
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
# Save state of current whitelist # Save state of current whitelist
@ -3458,7 +3221,7 @@ def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order, fee,
def test_order_book_depth_of_market_high_delta(default_conf, ticker, limit_buy_order, def test_order_book_depth_of_market_high_delta(default_conf, ticker, limit_buy_order,
fee, markets, mocker, order_book_l2): fee, mocker, order_book_l2):
default_conf['bid_strategy']['check_depth_of_market']['enabled'] = True default_conf['bid_strategy']['check_depth_of_market']['enabled'] = True
# delta is 100 which is impossible to reach. hence check_depth_of_market will return false # delta is 100 which is impossible to reach. hence check_depth_of_market will return false
default_conf['bid_strategy']['check_depth_of_market']['bids_to_ask_delta'] = 100 default_conf['bid_strategy']['check_depth_of_market']['bids_to_ask_delta'] = 100
@ -3470,7 +3233,6 @@ def test_order_book_depth_of_market_high_delta(default_conf, ticker, limit_buy_o
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
# Save state of current whitelist # Save state of current whitelist
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
@ -3481,7 +3243,7 @@ def test_order_book_depth_of_market_high_delta(default_conf, ticker, limit_buy_o
assert trade is None assert trade is None
def test_order_book_bid_strategy1(mocker, default_conf, order_book_l2, markets) -> None: def test_order_book_bid_strategy1(mocker, default_conf, order_book_l2) -> None:
""" """
test if function get_target_bid will return the order book price test if function get_target_bid will return the order book price
instead of the ask rate instead of the ask rate
@ -3490,7 +3252,6 @@ def test_order_book_bid_strategy1(mocker, default_conf, order_book_l2, markets)
ticker_mock = MagicMock(return_value={'ask': 0.045, 'last': 0.046}) ticker_mock = MagicMock(return_value={'ask': 0.045, 'last': 0.046})
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
markets=PropertyMock(return_value=markets),
get_order_book=order_book_l2, get_order_book=order_book_l2,
get_ticker=ticker_mock, get_ticker=ticker_mock,
@ -3506,7 +3267,7 @@ def test_order_book_bid_strategy1(mocker, default_conf, order_book_l2, markets)
assert ticker_mock.call_count == 0 assert ticker_mock.call_count == 0
def test_order_book_bid_strategy2(mocker, default_conf, order_book_l2, markets) -> None: def test_order_book_bid_strategy2(mocker, default_conf, order_book_l2) -> None:
""" """
test if function get_target_bid will return the ask rate (since its value is lower) test if function get_target_bid will return the ask rate (since its value is lower)
instead of the order book rate (even if enabled) instead of the order book rate (even if enabled)
@ -3515,7 +3276,6 @@ def test_order_book_bid_strategy2(mocker, default_conf, order_book_l2, markets)
ticker_mock = MagicMock(return_value={'ask': 0.042, 'last': 0.046}) ticker_mock = MagicMock(return_value={'ask': 0.042, 'last': 0.046})
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
markets=PropertyMock(return_value=markets),
get_order_book=order_book_l2, get_order_book=order_book_l2,
get_ticker=ticker_mock, get_ticker=ticker_mock,
@ -3532,14 +3292,13 @@ def test_order_book_bid_strategy2(mocker, default_conf, order_book_l2, markets)
assert ticker_mock.call_count == 0 assert ticker_mock.call_count == 0
def test_check_depth_of_market_buy(default_conf, mocker, order_book_l2, markets) -> None: def test_check_depth_of_market_buy(default_conf, mocker, order_book_l2) -> None:
""" """
test check depth of market test check depth of market
""" """
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
markets=PropertyMock(return_value=markets),
get_order_book=order_book_l2 get_order_book=order_book_l2
) )
default_conf['telegram']['enabled'] = False default_conf['telegram']['enabled'] = False
@ -3554,7 +3313,7 @@ def test_check_depth_of_market_buy(default_conf, mocker, order_book_l2, markets)
def test_order_book_ask_strategy(default_conf, limit_buy_order, limit_sell_order, def test_order_book_ask_strategy(default_conf, limit_buy_order, limit_sell_order,
fee, markets, mocker, order_book_l2) -> None: fee, mocker, order_book_l2) -> None:
""" """
test order book ask strategy test order book ask strategy
""" """
@ -3576,7 +3335,6 @@ def test_order_book_ask_strategy(default_conf, limit_buy_order, limit_sell_order
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
sell=MagicMock(return_value={'id': limit_sell_order['id']}), sell=MagicMock(return_value={'id': limit_sell_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)

159
tests/test_integration.py Normal file
View File

@ -0,0 +1,159 @@
from unittest.mock import MagicMock
from freqtrade.persistence import Trade
from freqtrade.strategy.interface import SellCheckTuple, SellType
from tests.conftest import get_patched_freqtradebot, patch_get_signal
from freqtrade.rpc.rpc import RPC
def test_may_execute_sell_stoploss_on_exchange_multi(default_conf, ticker, fee,
limit_buy_order, mocker) -> None:
"""
Tests workflow of selling stoploss_on_exchange.
Sells
* first trade as stoploss
* 2nd trade is kept
* 3rd trade is sold via sell-signal
"""
default_conf['max_open_trades'] = 3
default_conf['exchange']['name'] = 'binance'
stoploss_limit = {
'id': 123,
'info': {}
}
stoploss_order_open = {
"id": "123",
"timestamp": 1542707426845,
"datetime": "2018-11-20T09:50:26.845Z",
"lastTradeTimestamp": None,
"symbol": "BTC/USDT",
"type": "stop_loss_limit",
"side": "sell",
"price": 1.08801,
"amount": 90.99181074,
"cost": 0.0,
"average": 0.0,
"filled": 0.0,
"remaining": 0.0,
"status": "open",
"fee": None,
"trades": None
}
stoploss_order_closed = stoploss_order_open.copy()
stoploss_order_closed['status'] = 'closed'
# Sell first trade based on stoploss, keep 2nd and 3rd trade open
stoploss_order_mock = MagicMock(
side_effect=[stoploss_order_closed, stoploss_order_open, stoploss_order_open])
# Sell 3rd trade (not called for the first trade)
should_sell_mock = MagicMock(side_effect=[
SellCheckTuple(sell_flag=False, sell_type=SellType.NONE),
SellCheckTuple(sell_flag=True, sell_type=SellType.SELL_SIGNAL)]
)
cancel_order_mock = MagicMock()
mocker.patch('freqtrade.exchange.Binance.stoploss_limit', stoploss_limit)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_ticker=ticker,
get_fee=fee,
symbol_amount_prec=lambda s, x, y: y,
symbol_price_prec=lambda s, x, y: y,
get_order=stoploss_order_mock,
cancel_order=cancel_order_mock,
)
mocker.patch.multiple(
'freqtrade.freqtradebot.FreqtradeBot',
create_stoploss_order=MagicMock(return_value=True),
update_trade_state=MagicMock(),
_notify_sell=MagicMock(),
)
mocker.patch("freqtrade.strategy.interface.IStrategy.should_sell", should_sell_mock)
wallets_mock = mocker.patch("freqtrade.wallets.Wallets.update", MagicMock())
freqtrade = get_patched_freqtradebot(mocker, default_conf)
freqtrade.strategy.order_types['stoploss_on_exchange'] = True
# Switch ordertype to market to close trade immediately
freqtrade.strategy.order_types['sell'] = 'market'
patch_get_signal(freqtrade)
# Create some test data
freqtrade.create_trades()
wallets_mock.reset_mock()
Trade.session = MagicMock()
trades = Trade.query.all()
# Make sure stoploss-order is open and trade is bought (since we mock update_trade_state)
for trade in trades:
trade.stoploss_order_id = 3
trade.open_order_id = None
freqtrade.process_maybe_execute_sells(trades)
assert should_sell_mock.call_count == 2
# Only order for 3rd trade needs to be cancelled
assert cancel_order_mock.call_count == 1
# Wallets should only be called once per sell cycle
assert wallets_mock.call_count == 1
trade = trades[0]
assert trade.sell_reason == SellType.STOPLOSS_ON_EXCHANGE.value
assert not trade.is_open
trade = trades[1]
assert not trade.sell_reason
assert trade.is_open
trade = trades[2]
assert trade.sell_reason == SellType.SELL_SIGNAL.value
assert not trade.is_open
def test_forcebuy_last_unlimited(default_conf, ticker, fee, limit_buy_order, mocker) -> None:
"""
Tests workflow
"""
default_conf['max_open_trades'] = 5
default_conf['forcebuy_enable'] = True
default_conf['stake_amount'] = 'unlimited'
default_conf['exchange']['name'] = 'binance'
default_conf['telegram']['enabled'] = True
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
mocker.patch('freqtrade.wallets.Wallets.get_free', MagicMock(
side_effect=[1000, 800, 600, 400, 200]
))
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_ticker=ticker,
get_fee=fee,
symbol_amount_prec=lambda s, x, y: y,
symbol_price_prec=lambda s, x, y: y,
)
mocker.patch.multiple(
'freqtrade.freqtradebot.FreqtradeBot',
create_stoploss_order=MagicMock(return_value=True),
update_trade_state=MagicMock(),
_notify_sell=MagicMock(),
)
freqtrade = get_patched_freqtradebot(mocker, default_conf)
rpc = RPC(freqtrade)
freqtrade.strategy.order_types['stoploss_on_exchange'] = True
# Switch ordertype to market to close trade immediately
freqtrade.strategy.order_types['sell'] = 'market'
patch_get_signal(freqtrade)
# Create 4 trades
freqtrade.create_trades()
trades = Trade.query.all()
assert len(trades) == 4
rpc._rpc_forcebuy('TKN/BTC', None)
trades = Trade.query.all()
assert len(trades) == 5
for trade in trades:
assert trade.stake_amount == 200

81
tests/test_worker.py Normal file
View File

@ -0,0 +1,81 @@
import logging
import time
from unittest.mock import MagicMock, PropertyMock
from freqtrade.data.dataprovider import DataProvider
from freqtrade.state import State
from freqtrade.worker import Worker
from tests.conftest import get_patched_worker, log_has
def test_worker_state(mocker, default_conf, markets) -> None:
mocker.patch('freqtrade.exchange.Exchange.markets', PropertyMock(return_value=markets))
worker = get_patched_worker(mocker, default_conf)
assert worker.state is State.RUNNING
default_conf.pop('initial_state')
worker = Worker(args=None, config=default_conf)
assert worker.state is State.STOPPED
def test_worker_running(mocker, default_conf, caplog) -> None:
mock_throttle = MagicMock()
mocker.patch('freqtrade.worker.Worker._throttle', mock_throttle)
mocker.patch('freqtrade.persistence.Trade.stoploss_reinitialization', MagicMock())
worker = get_patched_worker(mocker, default_conf)
state = worker._worker(old_state=None)
assert state is State.RUNNING
assert log_has('Changing state to: RUNNING', caplog)
assert mock_throttle.call_count == 1
# Check strategy is loaded, and received a dataprovider object
assert worker.freqtrade.strategy
assert worker.freqtrade.strategy.dp
assert isinstance(worker.freqtrade.strategy.dp, DataProvider)
def test_worker_stopped(mocker, default_conf, caplog) -> None:
mock_throttle = MagicMock()
mocker.patch('freqtrade.worker.Worker._throttle', mock_throttle)
mock_sleep = mocker.patch('time.sleep', return_value=None)
worker = get_patched_worker(mocker, default_conf)
worker.state = State.STOPPED
state = worker._worker(old_state=State.RUNNING)
assert state is State.STOPPED
assert log_has('Changing state to: STOPPED', caplog)
assert mock_throttle.call_count == 0
assert mock_sleep.call_count == 1
def test_throttle(mocker, default_conf, caplog) -> None:
def throttled_func():
return 42
caplog.set_level(logging.DEBUG)
worker = get_patched_worker(mocker, default_conf)
start = time.time()
result = worker._throttle(throttled_func, min_secs=0.1)
end = time.time()
assert result == 42
assert end - start > 0.1
assert log_has('Throttling throttled_func for 0.10 seconds', caplog)
result = worker._throttle(throttled_func, min_secs=-1)
assert result == 42
def test_throttle_with_assets(mocker, default_conf) -> None:
def throttled_func(nb_assets=-1):
return nb_assets
worker = get_patched_worker(mocker, default_conf)
result = worker._throttle(throttled_func, min_secs=0.1, nb_assets=666)
assert result == 666
result = worker._throttle(throttled_func, min_secs=0.1)
assert result == -1