Merge branch 'develop' into volumeList_enhanced_filter

This commit is contained in:
Matthias
2019-11-09 15:34:47 +01:00
52 changed files with 958 additions and 672 deletions

View File

@@ -10,7 +10,7 @@ from freqtrade.data.btanalysis import (BT_DATA_COLUMNS,
create_cum_profit,
extract_trades_of_period,
load_backtest_data, load_trades,
load_trades_from_db)
load_trades_from_db, analyze_trade_parallelism)
from freqtrade.data.history import load_data, load_pair_history
from tests.test_persistence import create_mock_trades
@@ -32,7 +32,7 @@ def test_load_backtest_data(testdatadir):
@pytest.mark.usefixtures("init_persistence")
def test_load_trades_db(default_conf, fee, mocker):
def test_load_trades_from_db(default_conf, fee, mocker):
create_mock_trades(fee)
# remove init so it does not init again
@@ -84,6 +84,17 @@ def test_extract_trades_of_period(testdatadir):
assert trades1.iloc[-1].close_time == Arrow(2017, 11, 14, 15, 25, 0).datetime
def test_analyze_trade_parallelism(default_conf, mocker, testdatadir):
filename = testdatadir / "backtest-result_test.json"
bt_data = load_backtest_data(filename)
res = analyze_trade_parallelism(bt_data, "5m")
assert isinstance(res, DataFrame)
assert 'open_trades' in res.columns
assert res['open_trades'].max() == 3
assert res['open_trades'].min() == 0
def test_load_trades(default_conf, mocker):
db_mock = mocker.patch("freqtrade.data.btanalysis.load_trades_from_db", MagicMock())
bt_mock = mocker.patch("freqtrade.data.btanalysis.load_backtest_data", MagicMock())

View File

@@ -103,9 +103,7 @@ def test_load_data_startup_candles(mocker, caplog, default_conf, testdatadir) ->
datadir=testdatadir, timerange=timerange,
startup_candles=20,
)
assert log_has(
'Using indicator startup period: 20 ...', caplog
)
assert ltfmock.call_count == 1
assert ltfmock.call_args_list[0][1]['timerange'] != timerange
# startts is 20 minutes earlier
@@ -354,8 +352,12 @@ def test_load_partial_missing(testdatadir, caplog) -> None:
start = arrow.get('2018-01-01T00:00:00')
end = arrow.get('2018-01-11T00:00:00')
tickerdata = history.load_data(testdatadir, '5m', ['UNITTEST/BTC'],
startup_candles=20,
timerange=TimeRange('date', 'date',
start.timestamp, end.timestamp))
assert log_has(
'Using indicator startup period: 20 ...', caplog
)
# timedifference in 5 minutes
td = ((end - start).total_seconds() // 60 // 5) + 1
assert td != len(tickerdata['UNITTEST/BTC'])

View File

@@ -14,13 +14,13 @@ from pandas import DataFrame
from freqtrade import (DependencyException, InvalidOrderException,
OperationalException, TemporaryError)
from freqtrade.exchange import Binance, Exchange, Kraken
from freqtrade.exchange.exchange import (API_RETRY_COUNT, timeframe_to_minutes,
from freqtrade.exchange.common import API_RETRY_COUNT
from freqtrade.exchange.exchange import (market_is_active, symbol_is_pair,
timeframe_to_minutes,
timeframe_to_msecs,
timeframe_to_next_date,
timeframe_to_prev_date,
timeframe_to_seconds,
symbol_is_pair,
market_is_active)
timeframe_to_seconds)
from freqtrade.resolvers.exchange_resolver import ExchangeResolver
from tests.conftest import get_patched_exchange, log_has, log_has_re
@@ -1586,8 +1586,9 @@ def test_name(default_conf, mocker, exchange_name):
@pytest.mark.parametrize("exchange_name", EXCHANGES)
def test_get_trades_for_order(default_conf, mocker, exchange_name):
order_id = 'ABCD-ABCD'
since = datetime(2018, 5, 5, tzinfo=timezone.utc)
since = datetime(2018, 5, 5, 0, 0, 0)
default_conf["dry_run"] = False
mocker.patch('freqtrade.exchange.Exchange.exchange_has', return_value=True)
api_mock = MagicMock()
@@ -1623,7 +1624,8 @@ def test_get_trades_for_order(default_conf, mocker, exchange_name):
assert api_mock.fetch_my_trades.call_args[0][0] == 'LTC/BTC'
# Same test twice, hardcoded number and doing the same calculation
assert api_mock.fetch_my_trades.call_args[0][1] == 1525478395000
assert api_mock.fetch_my_trades.call_args[0][1] == int(since.timestamp() - 5) * 1000
assert api_mock.fetch_my_trades.call_args[0][1] == int(since.replace(
tzinfo=timezone.utc).timestamp() - 5) * 1000
ccxt_exceptionhandlers(mocker, default_conf, api_mock, exchange_name,
'get_trades_for_order', 'fetch_my_trades',

View File

@@ -3,7 +3,6 @@ import logging
from unittest.mock import MagicMock
import pytest
from pandas import DataFrame
from freqtrade.data.history import get_timeframe
from freqtrade.optimize.backtesting import Backtesting
@@ -313,7 +312,7 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data) -> None:
pair = "UNITTEST/BTC"
# Dummy data as we mock the analyze functions
data_processed = {pair: DataFrame()}
data_processed = {pair: frame.copy()}
min_date, max_date = get_timeframe({pair: frame})
results = backtesting.backtest(
{

View File

@@ -714,9 +714,9 @@ def test_backtest_multi_pair(default_conf, fee, mocker, tres, pair, testdatadir)
results = backtesting.backtest(backtest_conf)
# Make sure we have parallel trades
assert len(evaluate_result_multi(results, '5min', 2)) > 0
assert len(evaluate_result_multi(results, '5m', 2)) > 0
# make sure we don't have trades with more than configured max_open_trades
assert len(evaluate_result_multi(results, '5min', 3)) == 0
assert len(evaluate_result_multi(results, '5m', 3)) == 0
backtest_conf = {
'stake_amount': default_conf['stake_amount'],
@@ -727,7 +727,7 @@ def test_backtest_multi_pair(default_conf, fee, mocker, tres, pair, testdatadir)
'end_date': max_date,
}
results = backtesting.backtest(backtest_conf)
assert len(evaluate_result_multi(results, '5min', 1)) == 0
assert len(evaluate_result_multi(results, '5m', 1)) == 0
def test_backtest_record(default_conf, fee, mocker):

View File

@@ -1,4 +1,5 @@
# pragma pylint: disable=missing-docstring,W0212,C0103
import locale
from datetime import datetime
from pathlib import Path
from unittest.mock import MagicMock, PropertyMock
@@ -149,6 +150,7 @@ def test_hyperoptresolver(mocker, default_conf, caplog) -> None:
patched_configuration_load_config_file(mocker, default_conf)
hyperopt = DefaultHyperOpt
delattr(hyperopt, 'populate_indicators')
delattr(hyperopt, 'populate_buy_trend')
delattr(hyperopt, 'populate_sell_trend')
mocker.patch(
@@ -156,8 +158,11 @@ def test_hyperoptresolver(mocker, default_conf, caplog) -> None:
MagicMock(return_value=hyperopt(default_conf))
)
x = HyperOptResolver(default_conf, ).hyperopt
assert not hasattr(x, 'populate_indicators')
assert not hasattr(x, 'populate_buy_trend')
assert not hasattr(x, 'populate_sell_trend')
assert log_has("Hyperopt class does not provide populate_indicators() method. "
"Using populate_indicators from the strategy.", caplog)
assert log_has("Hyperopt class does not provide populate_sell_trend() method. "
"Using populate_sell_trend from the strategy.", caplog)
assert log_has("Hyperopt class does not provide populate_buy_trend() method. "
@@ -561,8 +566,9 @@ def test_generate_optimizer(mocker, default_conf) -> None:
}
response_expected = {
'loss': 1.9840569076926293,
'results_explanation': ' 1 trades. Avg profit 2.31%. Total profit 0.00023300 BTC '
'( 2.31Σ%). Avg duration 100.0 mins.',
'results_explanation': (' 1 trades. Avg profit 2.31%. Total profit 0.00023300 BTC '
'( 2.31\N{GREEK CAPITAL LETTER SIGMA}%). Avg duration 100.0 mins.'
).encode(locale.getpreferredencoding(), 'replace').decode('utf-8'),
'params': optimizer_param,
'total_profit': 0.00023300
}

View File

@@ -10,13 +10,13 @@ import pytest
from jsonschema import Draft4Validator, ValidationError, validate
from freqtrade import OperationalException, constants
from freqtrade.configuration import (Arguments, Configuration,
from freqtrade.configuration import (Arguments, Configuration, check_exchange,
remove_credentials,
validate_config_consistency)
from freqtrade.configuration.check_exchange import check_exchange
from freqtrade.configuration.config_validation import validate_config_schema
from freqtrade.configuration.deprecated_settings import (check_conflicting_settings,
process_deprecated_setting,
process_temporary_deprecated_settings)
from freqtrade.configuration.deprecated_settings import (
check_conflicting_settings, process_deprecated_setting,
process_temporary_deprecated_settings)
from freqtrade.configuration.directory_operations import (create_datadir,
create_userdata_dir)
from freqtrade.configuration.load_config import load_config_file
@@ -545,12 +545,24 @@ def test_check_exchange(default_conf, caplog) -> None:
# Test no exchange...
default_conf.get('exchange').update({'name': ''})
default_conf['runmode'] = RunMode.OTHER
default_conf['runmode'] = RunMode.UTIL_EXCHANGE
with pytest.raises(OperationalException,
match=r'This command requires a configured exchange.*'):
check_exchange(default_conf)
def test_remove_credentials(default_conf, caplog) -> None:
conf = deepcopy(default_conf)
conf['dry_run'] = False
remove_credentials(conf)
assert conf['dry_run'] is True
assert conf['exchange']['key'] == ''
assert conf['exchange']['secret'] == ''
assert conf['exchange']['password'] == ''
assert conf['exchange']['uid'] == ''
def test_cli_verbose_with_params(default_conf, mocker, caplog) -> None:
patched_configuration_load_config_file(mocker, default_conf)

View File

@@ -14,7 +14,6 @@ import requests
from freqtrade import (DependencyException, InvalidOrderException,
OperationalException, TemporaryError, constants)
from freqtrade.constants import MATH_CLOSE_PREC
from freqtrade.data.dataprovider import DataProvider
from freqtrade.freqtradebot import FreqtradeBot
from freqtrade.persistence import Trade
from freqtrade.rpc import RPCMessageType
@@ -49,16 +48,6 @@ def test_freqtradebot_state(mocker, default_conf, markets) -> None:
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:
mock_cleanup = MagicMock()
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
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:
patch_RPCManager(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')
def test_get_trade_stake_amount_unlimited_amount(default_conf,
ticker,
limit_buy_order,
fee,
markets,
mocker) -> None:
def test_get_trade_stake_amount_unlimited_amount(default_conf, ticker,
limit_buy_order, fee, mocker) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)
patch_wallet(mocker, free=default_conf['stake_amount'])
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
markets=PropertyMock(return_value=markets),
get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
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
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_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']}),
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
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:
patch_RPCManager(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']}),
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,
limit_buy_order, fee, markets) -> None:
limit_buy_order, fee) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)
default_conf['stake_amount'] = 0.0000098751
@@ -387,7 +306,6 @@ def test_total_open_trades_stakes(mocker, default_conf, ticker,
get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee,
markets=PropertyMock(return_value=markets)
)
freqtrade = FreqtradeBot(default_conf)
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
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_exchange(mocker)
mocker.patch.multiple(
@@ -530,7 +448,6 @@ def test_create_trades(default_conf, ticker, limit_buy_order, fee, markets, mock
get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee,
markets=PropertyMock(return_value=markets)
)
# 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,
fee, markets, mocker) -> None:
fee, mocker) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)
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,
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee,
markets=PropertyMock(return_value=markets)
)
freqtrade = FreqtradeBot(default_conf)
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,
fee, markets, mocker) -> None:
fee, mocker) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)
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,
buy=buy_mock,
get_fee=fee,
markets=PropertyMock(return_value=markets)
)
default_conf['stake_amount'] = 0.0005
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,
fee, markets, mocker) -> None:
fee, mocker) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)
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,
buy=buy_mock,
get_fee=fee,
markets=PropertyMock(return_value=markets)
)
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']}),
get_balance=MagicMock(return_value=default_conf['stake_amount']),
get_fee=fee,
markets=PropertyMock(return_value=markets)
)
default_conf['max_open_trades'] = 0
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,
markets, mocker, caplog) -> None:
mocker, caplog) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)
mocker.patch.multiple(
@@ -646,7 +559,6 @@ def test_create_trades_no_pairs_let(default_conf, ticker, limit_buy_order, fee,
get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee,
markets=PropertyMock(return_value=markets)
)
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,
markets, mocker, caplog) -> None:
mocker, caplog) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)
mocker.patch.multiple(
@@ -668,7 +580,6 @@ def test_create_trades_no_pairs_in_whitelist(default_conf, ticker, limit_buy_ord
get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee,
markets=PropertyMock(return_value=markets)
)
default_conf['exchange']['pair_whitelist'] = []
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))
def test_create_trades_multiple_trades(default_conf, ticker,
fee, markets, mocker, max_open) -> None:
fee, mocker, max_open) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)
default_conf['max_open_trades'] = max_open
@@ -708,7 +619,6 @@ def test_create_trades_multiple_trades(default_conf, ticker,
get_ticker=ticker,
buy=MagicMock(return_value={'id': "12355555"}),
get_fee=fee,
markets=PropertyMock(return_value=markets)
)
freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade)
@@ -719,7 +629,7 @@ def test_create_trades_multiple_trades(default_conf, ticker,
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_exchange(mocker)
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,
buy=MagicMock(return_value={'id': "12355555"}),
get_fee=fee,
markets=PropertyMock(return_value=markets)
)
freqtrade = FreqtradeBot(default_conf)
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,
markets, fee, mocker, caplog) -> None:
fee, mocker, caplog) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_ticker=ticker,
markets=PropertyMock(return_value=markets),
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_order=MagicMock(return_value=limit_buy_order),
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_exchange(mocker)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_ticker=ticker,
markets=PropertyMock(return_value=markets),
buy=MagicMock(side_effect=TemporaryError)
)
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()
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)
patch_exchange(mocker)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_ticker=ticker,
markets=PropertyMock(return_value=markets),
buy=MagicMock(side_effect=OperationalException)
)
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']
def test_process_trade_handling(
default_conf, ticker, limit_buy_order, markets, fee, mocker) -> None:
def test_process_trade_handling(default_conf, ticker, limit_buy_order, fee, mocker) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_ticker=ticker,
markets=PropertyMock(return_value=markets),
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_order=MagicMock(return_value=limit_buy_order),
get_fee=fee,
@@ -846,15 +750,14 @@ def test_process_trade_handling(
assert len(trades) == 1
def test_process_trade_no_whitelist_pair(
default_conf, ticker, limit_buy_order, markets, fee, mocker) -> None:
def test_process_trade_no_whitelist_pair(default_conf, ticker, limit_buy_order,
fee, mocker) -> None:
""" Test process with trade not in pair list """
patch_RPCManager(mocker)
patch_exchange(mocker)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_ticker=ticker,
markets=PropertyMock(return_value=markets),
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_order=MagicMock(return_value=limit_buy_order),
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))
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_exchange(mocker)
@@ -902,7 +805,6 @@ def test_process_informative_pairs_added(default_conf, ticker, markets, mocker)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_ticker=ticker,
markets=PropertyMock(return_value=markets),
buy=MagicMock(side_effect=TemporaryError),
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
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_exchange(mocker)
freqtrade = FreqtradeBot(default_conf)
@@ -970,7 +872,6 @@ def test_execute_buy(mocker, default_conf, fee, markets, limit_buy_order) -> Non
}),
buy=buy_mm,
get_fee=fee,
markets=PropertyMock(return_value=markets)
)
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,
markets, limit_buy_order, limit_sell_order) -> None:
limit_buy_order, limit_sell_order) -> None:
stoploss_limit = MagicMock(return_value={'id': 13434334})
patch_RPCManager(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']}),
sell=MagicMock(return_value={'id': limit_sell_order['id']}),
get_fee=fee,
markets=PropertyMock(return_value=markets),
stoploss_limit=stoploss_limit
)
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,
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
patch_RPCManager(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']}),
sell=MagicMock(return_value={'id': limit_sell_order['id']}),
get_fee=fee,
markets=PropertyMock(return_value=markets),
get_order=MagicMock(return_value={'status': 'canceled'}),
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,
markets, limit_buy_order, limit_sell_order):
limit_buy_order, limit_sell_order):
rpc_mock = patch_RPCManager(mocker)
patch_exchange(mocker)
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']}),
sell=sell_mock,
get_fee=fee,
markets=PropertyMock(return_value=markets),
get_order=MagicMock(return_value={'status': 'canceled'}),
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,
markets, limit_buy_order,
limit_sell_order) -> None:
limit_buy_order, limit_sell_order) -> None:
# When trailing stoploss is set
stoploss_limit = MagicMock(return_value={'id': 13434334})
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']}),
sell=MagicMock(return_value={'id': limit_sell_order['id']}),
get_fee=fee,
markets=PropertyMock(return_value=markets),
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,
markets, limit_buy_order, limit_sell_order) -> None:
limit_buy_order, limit_sell_order) -> None:
# When trailing stoploss is set
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']}),
sell=MagicMock(return_value={'id': limit_sell_order['id']}),
get_fee=fee,
markets=PropertyMock(return_value=markets),
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
def test_handle_trade(default_conf, limit_buy_order, limit_sell_order,
fee, markets, mocker) -> None:
def test_handle_trade(default_conf, limit_buy_order, limit_sell_order, fee, mocker) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)
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']}),
sell=MagicMock(return_value={'id': limit_sell_order['id']}),
get_fee=fee,
markets=PropertyMock(return_value=markets)
)
freqtrade = FreqtradeBot(default_conf)
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
def test_handle_overlpapping_signals(default_conf, ticker, limit_buy_order,
fee, markets, mocker) -> None:
def test_handle_overlpapping_signals(default_conf, ticker, limit_buy_order, fee, mocker) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)
mocker.patch.multiple(
@@ -1778,7 +1670,6 @@ def test_handle_overlpapping_signals(default_conf, ticker, limit_buy_order,
get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee,
markets=PropertyMock(return_value=markets)
)
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,
fee, markets, mocker) -> None:
fee, mocker) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)
mocker.patch.multiple(
@@ -1892,7 +1783,6 @@ def test_close_trade(default_conf, ticker, limit_buy_order, limit_sell_order,
get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee,
markets=PropertyMock(return_value=markets)
)
freqtrade = FreqtradeBot(default_conf)
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
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)
patch_exchange(mocker)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_ticker=ticker,
get_fee=fee,
markets=PropertyMock(return_value=markets)
)
patch_whitelist(mocker, 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
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)
patch_exchange(mocker)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_ticker=ticker,
get_fee=fee,
markets=PropertyMock(return_value=markets)
)
patch_whitelist(mocker, 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,
ticker_sell_down,
markets, mocker) -> None:
ticker_sell_down, mocker) -> None:
rpc_mock = patch_RPCManager(mocker)
patch_exchange(mocker)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_ticker=ticker,
get_fee=fee,
markets=PropertyMock(return_value=markets)
)
patch_whitelist(mocker, 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
def test_execute_sell_sloe_cancel_exception(mocker, default_conf, ticker, fee,
markets, caplog) -> None:
def test_execute_sell_sloe_cancel_exception(mocker, default_conf, ticker, fee, caplog) -> None:
freqtrade = get_patched_freqtradebot(mocker, default_conf)
mocker.patch('freqtrade.exchange.Exchange.cancel_order', side_effect=InvalidOrderException())
sellmock = MagicMock()
@@ -2384,7 +2269,6 @@ def test_execute_sell_sloe_cancel_exception(mocker, default_conf, ticker, fee,
'freqtrade.exchange.Exchange',
get_ticker=ticker,
get_fee=fee,
markets=PropertyMock(return_value=markets),
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)
def test_execute_sell_with_stoploss_on_exchange(default_conf,
ticker, fee, ticker_sell_up,
markets, mocker) -> None:
def test_execute_sell_with_stoploss_on_exchange(default_conf, ticker, fee, ticker_sell_up,
mocker) -> None:
default_conf['exchange']['name'] = 'binance'
rpc_mock = patch_RPCManager(mocker)
@@ -2423,7 +2306,6 @@ def test_execute_sell_with_stoploss_on_exchange(default_conf,
'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,
stoploss_limit=stoploss_limit,
@@ -2458,10 +2340,8 @@ def test_execute_sell_with_stoploss_on_exchange(default_conf,
assert rpc_mock.call_count == 2
def test_may_execute_sell_after_stoploss_on_exchange_hit(default_conf,
ticker, fee,
limit_buy_order,
markets, mocker) -> None:
def test_may_execute_sell_after_stoploss_on_exchange_hit(default_conf, ticker, fee,
limit_buy_order, mocker) -> None:
default_conf['exchange']['name'] = 'binance'
rpc_mock = patch_RPCManager(mocker)
patch_exchange(mocker)
@@ -2469,7 +2349,6 @@ def test_may_execute_sell_after_stoploss_on_exchange_hit(default_conf,
'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,
)
@@ -2526,124 +2405,14 @@ def test_may_execute_sell_after_stoploss_on_exchange_hit(default_conf,
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,
ticker_sell_up, markets, mocker) -> None:
ticker_sell_up, mocker) -> None:
rpc_mock = patch_RPCManager(mocker)
patch_exchange(mocker)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_ticker=ticker,
get_fee=fee,
markets=PropertyMock(return_value=markets)
)
patch_whitelist(mocker, 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,
fee, markets, mocker) -> None:
fee, mocker) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)
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']}),
get_fee=fee,
markets=PropertyMock(return_value=markets)
)
default_conf['ask_strategy'] = {
'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,
fee, markets, mocker) -> None:
fee, mocker) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)
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']}),
get_fee=fee,
markets=PropertyMock(return_value=markets)
)
default_conf['ask_strategy'] = {
'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
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_exchange(mocker)
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']}),
get_fee=fee,
markets=PropertyMock(return_value=markets)
)
default_conf['ask_strategy'] = {
'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
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_exchange(mocker)
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']}),
get_fee=fee,
markets=PropertyMock(return_value=markets)
)
default_conf['ask_strategy'] = {
'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,
fee, markets, mocker) -> None:
fee, mocker) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)
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']}),
get_fee=fee,
markets=PropertyMock(return_value=markets)
)
default_conf['ask_strategy'] = {
'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
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):
default_conf['bid_strategy']['check_depth_of_market']['enabled'] = True
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,
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee,
markets=PropertyMock(return_value=markets)
)
# Save state of current whitelist
@@ -3450,6 +3213,8 @@ def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order, fee,
assert trade.open_date is not None
assert trade.exchange == 'bittrex'
assert len(Trade.query.all()) == 1
# Simulate fulfilled LIMIT_BUY order for trade
trade.update(limit_buy_order)
@@ -3458,7 +3223,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,
fee, markets, mocker, order_book_l2):
fee, mocker, order_book_l2):
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
default_conf['bid_strategy']['check_depth_of_market']['bids_to_ask_delta'] = 100
@@ -3470,7 +3235,6 @@ def test_order_book_depth_of_market_high_delta(default_conf, ticker, limit_buy_o
get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee,
markets=PropertyMock(return_value=markets)
)
# Save state of current whitelist
freqtrade = FreqtradeBot(default_conf)
@@ -3481,7 +3245,7 @@ def test_order_book_depth_of_market_high_delta(default_conf, ticker, limit_buy_o
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
instead of the ask rate
@@ -3490,7 +3254,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})
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
markets=PropertyMock(return_value=markets),
get_order_book=order_book_l2,
get_ticker=ticker_mock,
@@ -3506,7 +3269,7 @@ def test_order_book_bid_strategy1(mocker, default_conf, order_book_l2, markets)
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)
instead of the order book rate (even if enabled)
@@ -3515,7 +3278,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})
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
markets=PropertyMock(return_value=markets),
get_order_book=order_book_l2,
get_ticker=ticker_mock,
@@ -3532,14 +3294,13 @@ def test_order_book_bid_strategy2(mocker, default_conf, order_book_l2, markets)
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
"""
patch_exchange(mocker)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
markets=PropertyMock(return_value=markets),
get_order_book=order_book_l2
)
default_conf['telegram']['enabled'] = False
@@ -3554,7 +3315,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,
fee, markets, mocker, order_book_l2) -> None:
fee, mocker, order_book_l2) -> None:
"""
test order book ask strategy
"""
@@ -3576,7 +3337,6 @@ def test_order_book_ask_strategy(default_conf, limit_buy_order, limit_sell_order
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
sell=MagicMock(return_value={'id': limit_sell_order['id']}),
get_fee=fee,
markets=PropertyMock(return_value=markets)
)
freqtrade = FreqtradeBot(default_conf)
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

View File

@@ -35,6 +35,8 @@ def create_mock_trades(fee):
fee_open=fee.return_value,
fee_close=fee.return_value,
open_rate=0.123,
close_rate=0.128,
close_profit=0.005,
exchange='bittrex',
is_open=False,
open_order_id='dry_run_sell_12345'
@@ -59,7 +61,7 @@ def test_init_create_session(default_conf):
# Check if init create a session
init(default_conf['db_url'], default_conf['dry_run'])
assert hasattr(Trade, 'session')
assert 'Session' in type(Trade.session).__name__
assert 'scoped_session' in type(Trade.session).__name__
def test_init_custom_db_url(default_conf, mocker):
@@ -835,3 +837,38 @@ def test_stoploss_reinitialization(default_conf, fee):
assert trade_adj.stop_loss_pct == -0.04
assert trade_adj.initial_stop_loss == 0.96
assert trade_adj.initial_stop_loss_pct == -0.04
@pytest.mark.usefixtures("init_persistence")
def test_total_open_trades_stakes(fee):
res = Trade.total_open_trades_stakes()
assert res == 0
create_mock_trades(fee)
res = Trade.total_open_trades_stakes()
assert res == 0.002
@pytest.mark.usefixtures("init_persistence")
def test_get_overall_performance(fee):
create_mock_trades(fee)
res = Trade.get_overall_performance()
assert len(res) == 1
assert 'pair' in res[0]
assert 'profit' in res[0]
assert 'count' in res[0]
@pytest.mark.usefixtures("init_persistence")
def test_get_best_pair(fee):
res = Trade.get_best_pair()
assert res is None
create_mock_trades(fee)
res = Trade.get_best_pair()
assert len(res) == 2
assert res[0] == 'ETC/BTC'
assert res[1] == 0.005

View File

@@ -19,7 +19,7 @@ def test_setup_utils_configuration():
config = setup_utils_configuration(get_args(args), RunMode.OTHER)
assert "exchange" in config
assert config['exchange']['dry_run'] is True
assert config['dry_run'] is True
assert config['exchange']['key'] == ''
assert config['exchange']['secret'] == ''

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