Merge remote-tracking branch 'upstream/develop' into feature/fetch-public-trades
This commit is contained in:
@@ -820,12 +820,6 @@ def test_download_data_trades(mocker):
|
||||
"--trading-mode", "futures",
|
||||
"--dl-trades"
|
||||
]
|
||||
pargs = get_args(args)
|
||||
pargs['config'] = None
|
||||
start_download_data(pargs)
|
||||
assert dl_mock.call_args[1]['timerange'].starttype == "date"
|
||||
assert dl_mock.call_count == 2
|
||||
assert convert_mock.call_count == 2
|
||||
|
||||
|
||||
def test_download_data_data_invalid(mocker):
|
||||
@@ -843,10 +837,11 @@ def test_download_data_data_invalid(mocker):
|
||||
start_download_data(pargs)
|
||||
|
||||
|
||||
def test_start_convert_trades(mocker, caplog):
|
||||
def test_start_convert_trades(mocker):
|
||||
convert_mock = mocker.patch('freqtrade.commands.data_commands.convert_trades_to_ohlcv',
|
||||
MagicMock(return_value=[]))
|
||||
patch_exchange(mocker)
|
||||
mocker.patch(f'{EXMS}.get_markets')
|
||||
mocker.patch(f'{EXMS}.markets', PropertyMock(return_value={}))
|
||||
args = [
|
||||
"trades-to-ohlcv",
|
||||
|
||||
+5
-5
@@ -142,8 +142,8 @@ def generate_trades_history(n_rows, start_date: Optional[datetime] = None, days=
|
||||
return df
|
||||
|
||||
|
||||
def generate_test_data(timeframe: str, size: int, start: str = '2020-07-05'):
|
||||
np.random.seed(42)
|
||||
def generate_test_data(timeframe: str, size: int, start: str = '2020-07-05', random_seed=42):
|
||||
np.random.seed(random_seed)
|
||||
|
||||
base = np.random.normal(20, 2, size=size)
|
||||
if timeframe == '1y':
|
||||
@@ -174,10 +174,10 @@ def generate_test_data(timeframe: str, size: int, start: str = '2020-07-05'):
|
||||
return df
|
||||
|
||||
|
||||
def generate_test_data_raw(timeframe: str, size: int, start: str = '2020-07-05'):
|
||||
def generate_test_data_raw(timeframe: str, size: int, start: str = '2020-07-05', random_seed=42):
|
||||
""" Generates data in the ohlcv format used by ccxt """
|
||||
df = generate_test_data(timeframe, size, start)
|
||||
df['date'] = df.loc[:, 'date'].view(np.int64) // 1000 // 1000
|
||||
df = generate_test_data(timeframe, size, start, random_seed)
|
||||
df['date'] = df.loc[:, 'date'].astype(np.int64) // 1000 // 1000
|
||||
return list(list(x) for x in zip(*(df[x].values.tolist() for x in df.columns)))
|
||||
|
||||
|
||||
|
||||
@@ -542,7 +542,9 @@ def test_convert_trades_to_ohlcv(testdatadir, tmp_path, caplog):
|
||||
|
||||
convert_trades_to_ohlcv([pair], timeframes=['1m', '5m'],
|
||||
data_format_trades='jsongz',
|
||||
datadir=tmp_path, timerange=tr, erase=True)
|
||||
datadir=tmp_path, timerange=tr, erase=True,
|
||||
data_format_ohlcv='feather',
|
||||
candle_type=CandleType.SPOT)
|
||||
|
||||
assert log_has("Deleting existing data for pair XRP/ETH, interval 1m.", caplog)
|
||||
# Load new data
|
||||
@@ -556,5 +558,7 @@ def test_convert_trades_to_ohlcv(testdatadir, tmp_path, caplog):
|
||||
|
||||
convert_trades_to_ohlcv(['NoDatapair'], timeframes=['1m', '5m'],
|
||||
data_format_trades='jsongz',
|
||||
datadir=tmp_path, timerange=tr, erase=True)
|
||||
datadir=tmp_path, timerange=tr, erase=True,
|
||||
data_format_ohlcv='feather',
|
||||
candle_type=CandleType.SPOT)
|
||||
assert log_has(msg, caplog)
|
||||
|
||||
@@ -261,11 +261,11 @@ def test_datahandler_trades_not_supported(datahandler, testdatadir, ):
|
||||
def test_jsondatahandler_trades_load(testdatadir, caplog):
|
||||
dh = JsonGzDataHandler(testdatadir)
|
||||
logmsg = "Old trades format detected - converting"
|
||||
dh.trades_load('XRP/ETH')
|
||||
dh.trades_load('XRP/ETH', TradingMode.SPOT)
|
||||
assert not log_has(logmsg, caplog)
|
||||
|
||||
# Test conversation is happening
|
||||
dh.trades_load('XRP/OLD')
|
||||
dh.trades_load('XRP/OLD', TradingMode.SPOT)
|
||||
assert log_has(logmsg, caplog)
|
||||
|
||||
|
||||
@@ -300,16 +300,16 @@ def test_datahandler_trades_get_pairs(testdatadir, datahandler, expected):
|
||||
|
||||
def test_hdf5datahandler_trades_load(testdatadir):
|
||||
dh = get_datahandler(testdatadir, 'hdf5')
|
||||
trades = dh.trades_load('XRP/ETH')
|
||||
trades = dh.trades_load('XRP/ETH', TradingMode.SPOT)
|
||||
assert isinstance(trades, DataFrame)
|
||||
|
||||
trades1 = dh.trades_load('UNITTEST/NONEXIST')
|
||||
trades1 = dh.trades_load('UNITTEST/NONEXIST', TradingMode.SPOT)
|
||||
assert isinstance(trades1, DataFrame)
|
||||
assert trades1.empty
|
||||
# data goes from 2019-10-11 - 2019-10-13
|
||||
timerange = TimeRange.parse_timerange('20191011-20191012')
|
||||
|
||||
trades2 = dh._trades_load('XRP/ETH', timerange)
|
||||
trades2 = dh._trades_load('XRP/ETH', TradingMode.SPOT, timerange)
|
||||
assert len(trades) > len(trades2)
|
||||
# Check that ID is None (If it's nan, it's wrong)
|
||||
assert trades2.iloc[0]['type'] is None
|
||||
@@ -451,13 +451,13 @@ def test_hdf5datahandler_ohlcv_purge(mocker, testdatadir):
|
||||
@pytest.mark.parametrize('datahandler', ['jsongz', 'hdf5', 'feather', 'parquet'])
|
||||
def test_datahandler_trades_load(testdatadir, datahandler):
|
||||
dh = get_datahandler(testdatadir, datahandler)
|
||||
trades = dh.trades_load('XRP/ETH')
|
||||
trades = dh.trades_load('XRP/ETH', TradingMode.SPOT)
|
||||
assert isinstance(trades, DataFrame)
|
||||
assert trades.iloc[0]['timestamp'] == 1570752011620
|
||||
assert trades.iloc[0]['date'] == Timestamp('2019-10-11 00:00:11.620000+0000')
|
||||
assert trades.iloc[-1]['cost'] == 0.1986231
|
||||
|
||||
trades1 = dh.trades_load('UNITTEST/NONEXIST')
|
||||
trades1 = dh.trades_load('UNITTEST/NONEXIST', TradingMode.SPOT)
|
||||
assert isinstance(trades, DataFrame)
|
||||
assert trades1.empty
|
||||
|
||||
@@ -465,15 +465,15 @@ def test_datahandler_trades_load(testdatadir, datahandler):
|
||||
@pytest.mark.parametrize('datahandler', ['jsongz', 'hdf5', 'feather', 'parquet'])
|
||||
def test_datahandler_trades_store(testdatadir, tmp_path, datahandler):
|
||||
dh = get_datahandler(testdatadir, datahandler)
|
||||
trades = dh.trades_load('XRP/ETH')
|
||||
trades = dh.trades_load('XRP/ETH', TradingMode.SPOT)
|
||||
|
||||
dh1 = get_datahandler(tmp_path, datahandler)
|
||||
dh1.trades_store('XRP/NEW', trades)
|
||||
dh1.trades_store('XRP/NEW', trades, TradingMode.SPOT)
|
||||
|
||||
file = tmp_path / f'XRP_NEW-trades.{dh1._get_file_extension()}'
|
||||
assert file.is_file()
|
||||
# Load trades back
|
||||
trades_new = dh1.trades_load('XRP/NEW')
|
||||
trades_new = dh1.trades_load('XRP/NEW', TradingMode.SPOT)
|
||||
assert_frame_equal(trades, trades_new, check_exact=True)
|
||||
assert len(trades_new) == len(trades)
|
||||
|
||||
@@ -483,11 +483,11 @@ def test_datahandler_trades_purge(mocker, testdatadir, datahandler):
|
||||
mocker.patch.object(Path, "exists", MagicMock(return_value=False))
|
||||
unlinkmock = mocker.patch.object(Path, "unlink", MagicMock())
|
||||
dh = get_datahandler(testdatadir, datahandler)
|
||||
assert not dh.trades_purge('UNITTEST/NONEXIST')
|
||||
assert not dh.trades_purge('UNITTEST/NONEXIST', TradingMode.SPOT)
|
||||
assert unlinkmock.call_count == 0
|
||||
|
||||
mocker.patch.object(Path, "exists", MagicMock(return_value=True))
|
||||
assert dh.trades_purge('UNITTEST/NONEXIST')
|
||||
assert dh.trades_purge('UNITTEST/NONEXIST', TradingMode.SPOT)
|
||||
assert unlinkmock.call_count == 1
|
||||
|
||||
|
||||
|
||||
@@ -78,11 +78,6 @@ def test_download_data_main_trades(mocker):
|
||||
"trading_mode": "futures",
|
||||
})
|
||||
|
||||
download_data_main(config)
|
||||
assert dl_mock.call_args[1]['timerange'].starttype == "date"
|
||||
assert dl_mock.call_count == 2
|
||||
assert convert_mock.call_count == 2
|
||||
|
||||
|
||||
def test_download_data_main_data_invalid(mocker):
|
||||
patch_exchange(mocker, id="kraken")
|
||||
|
||||
+22
-18
@@ -23,7 +23,7 @@ from freqtrade.data.history.history_utils import (_download_pair_history, _downl
|
||||
validate_backtest_data)
|
||||
from freqtrade.data.history.idatahandler import get_datahandler
|
||||
from freqtrade.data.history.jsondatahandler import JsonDataHandler, JsonGzDataHandler
|
||||
from freqtrade.enums import CandleType
|
||||
from freqtrade.enums import CandleType, TradingMode
|
||||
from freqtrade.exchange import timeframe_to_minutes
|
||||
from freqtrade.misc import file_dump_json
|
||||
from freqtrade.resolvers import StrategyResolver
|
||||
@@ -168,20 +168,21 @@ def test_json_pair_data_filename(pair, timeframe, expected_result, candle_type):
|
||||
assert fn == Path(expected_result + '.gz')
|
||||
|
||||
|
||||
@pytest.mark.parametrize("pair,expected_result", [
|
||||
("ETH/BTC", 'freqtrade/hello/world/ETH_BTC-trades.json'),
|
||||
("Fabric Token/ETH", 'freqtrade/hello/world/Fabric_Token_ETH-trades.json'),
|
||||
("ETHH20", 'freqtrade/hello/world/ETHH20-trades.json'),
|
||||
(".XBTBON2H", 'freqtrade/hello/world/_XBTBON2H-trades.json'),
|
||||
("ETHUSD.d", 'freqtrade/hello/world/ETHUSD_d-trades.json'),
|
||||
("ACC_OLD_BTC", 'freqtrade/hello/world/ACC_OLD_BTC-trades.json'),
|
||||
@pytest.mark.parametrize("pair,trading_mode,expected_result", [
|
||||
("ETH/BTC", '', 'freqtrade/hello/world/ETH_BTC-trades.json'),
|
||||
("ETH/USDT:USDT", 'futures', 'freqtrade/hello/world/futures/ETH_USDT_USDT-trades.json'),
|
||||
("Fabric Token/ETH", '', 'freqtrade/hello/world/Fabric_Token_ETH-trades.json'),
|
||||
("ETHH20", '', 'freqtrade/hello/world/ETHH20-trades.json'),
|
||||
(".XBTBON2H", '', 'freqtrade/hello/world/_XBTBON2H-trades.json'),
|
||||
("ETHUSD.d", '', 'freqtrade/hello/world/ETHUSD_d-trades.json'),
|
||||
("ACC_OLD_BTC", '', 'freqtrade/hello/world/ACC_OLD_BTC-trades.json'),
|
||||
])
|
||||
def test_json_pair_trades_filename(pair, expected_result):
|
||||
fn = JsonDataHandler._pair_trades_filename(Path('freqtrade/hello/world'), pair)
|
||||
def test_json_pair_trades_filename(pair, trading_mode, expected_result):
|
||||
fn = JsonDataHandler._pair_trades_filename(Path('freqtrade/hello/world'), pair, trading_mode)
|
||||
assert isinstance(fn, Path)
|
||||
assert fn == Path(expected_result)
|
||||
|
||||
fn = JsonGzDataHandler._pair_trades_filename(Path('freqtrade/hello/world'), pair)
|
||||
fn = JsonGzDataHandler._pair_trades_filename(Path('freqtrade/hello/world'), pair, trading_mode)
|
||||
assert isinstance(fn, Path)
|
||||
assert fn == Path(expected_result + '.gz')
|
||||
|
||||
@@ -559,7 +560,8 @@ def test_refresh_backtest_trades_data(mocker, default_conf, markets, caplog, tes
|
||||
unavailable_pairs = refresh_backtest_trades_data(exchange=ex,
|
||||
pairs=["ETH/BTC", "XRP/BTC", "XRP/ETH"],
|
||||
datadir=testdatadir,
|
||||
timerange=timerange, erase=True
|
||||
timerange=timerange, erase=True,
|
||||
trading_mode=TradingMode.SPOT,
|
||||
)
|
||||
|
||||
assert dl_mock.call_count == 2
|
||||
@@ -584,7 +586,7 @@ def test_download_trades_history(trades_history, mocker, default_conf, testdatad
|
||||
assert not file1.is_file()
|
||||
|
||||
assert _download_trades_history(data_handler=data_handler, exchange=exchange,
|
||||
pair='ETH/BTC')
|
||||
pair='ETH/BTC', trading_mode=TradingMode.SPOT)
|
||||
assert log_has("Current Amount of trades: 0", caplog)
|
||||
assert log_has("New Amount of trades: 6", caplog)
|
||||
assert ght_mock.call_count == 1
|
||||
@@ -597,8 +599,9 @@ def test_download_trades_history(trades_history, mocker, default_conf, testdatad
|
||||
since_time = int(trades_history[-3][0] // 1000)
|
||||
since_time2 = int(trades_history[-1][0] // 1000)
|
||||
timerange = TimeRange('date', None, since_time, 0)
|
||||
assert _download_trades_history(data_handler=data_handler, exchange=exchange,
|
||||
pair='ETH/BTC', timerange=timerange)
|
||||
assert _download_trades_history(
|
||||
data_handler=data_handler, exchange=exchange, pair='ETH/BTC',
|
||||
timerange=timerange, trading_mode=TradingMode.SPOT)
|
||||
|
||||
assert ght_mock.call_count == 1
|
||||
# Check this in seconds - since we had to convert to seconds above too.
|
||||
@@ -611,7 +614,7 @@ def test_download_trades_history(trades_history, mocker, default_conf, testdatad
|
||||
caplog.clear()
|
||||
|
||||
assert not _download_trades_history(data_handler=data_handler, exchange=exchange,
|
||||
pair='ETH/BTC')
|
||||
pair='ETH/BTC', trading_mode=TradingMode.SPOT)
|
||||
assert log_has_re('Failed to download and store historic trades for pair: "ETH/BTC".*', caplog)
|
||||
|
||||
file2 = tmp_path / 'XRP_ETH-trades.json.gz'
|
||||
@@ -623,8 +626,9 @@ def test_download_trades_history(trades_history, mocker, default_conf, testdatad
|
||||
since_time = int(trades_history[0][0] // 1000) - 500
|
||||
timerange = TimeRange('date', None, since_time, 0)
|
||||
|
||||
assert _download_trades_history(data_handler=data_handler, exchange=exchange,
|
||||
pair='XRP/ETH', timerange=timerange)
|
||||
assert _download_trades_history(
|
||||
data_handler=data_handler, exchange=exchange, pair='XRP/ETH',
|
||||
timerange=timerange, trading_mode=TradingMode.SPOT)
|
||||
|
||||
assert ght_mock.call_count == 1
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import pytest
|
||||
|
||||
from freqtrade.data.converter.trade_converter_kraken import import_kraken_trades_from_csv
|
||||
from freqtrade.data.history.idatahandler import get_datahandler
|
||||
from freqtrade.enums import TradingMode
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from tests.conftest import EXMS, log_has, log_has_re, patch_exchange
|
||||
|
||||
@@ -40,7 +41,7 @@ def test_import_kraken_trades_from_csv(testdatadir, tmp_path, caplog, default_co
|
||||
assert dstfile.is_file()
|
||||
|
||||
dh = get_datahandler(tmp_path, 'feather')
|
||||
trades = dh.trades_load('BCH_EUR')
|
||||
trades = dh.trades_load('BCH_EUR', TradingMode.SPOT)
|
||||
assert len(trades) == 340
|
||||
|
||||
assert trades['date'].min().to_pydatetime() == datetime(2023, 1, 1, 0, 3, 56,
|
||||
|
||||
@@ -7,6 +7,7 @@ from unittest.mock import MagicMock, Mock, PropertyMock, patch
|
||||
|
||||
import ccxt
|
||||
import pytest
|
||||
from numpy import NaN
|
||||
from pandas import DataFrame
|
||||
|
||||
from freqtrade.enums import CandleType, MarginMode, RunMode, TradingMode
|
||||
@@ -4203,6 +4204,7 @@ def test_get_max_leverage_from_margin(default_conf, mocker, pair, nominal_value,
|
||||
(10, 0.0001, 2.0, 1.0, 0.002, 0.002),
|
||||
(10, 0.0002, 2.0, 0.01, 0.004, 0.00004),
|
||||
(10, 0.0002, 2.5, None, 0.005, None),
|
||||
(10, 0.0002, NaN, None, 0.0, None),
|
||||
])
|
||||
def test_calculate_funding_fees(
|
||||
default_conf,
|
||||
@@ -4312,8 +4314,8 @@ def test_combine_funding_and_mark(
|
||||
assert len(df) == 1
|
||||
|
||||
# Empty funding rates
|
||||
funding_rates = DataFrame([], columns=['date', 'open'])
|
||||
df = exchange.combine_funding_and_mark(funding_rates, mark_rates, futures_funding_rate)
|
||||
funding_rates2 = DataFrame([], columns=['date', 'open'])
|
||||
df = exchange.combine_funding_and_mark(funding_rates2, mark_rates, futures_funding_rate)
|
||||
if futures_funding_rate is not None:
|
||||
assert len(df) == 3
|
||||
assert df.iloc[0]['open_fund'] == futures_funding_rate
|
||||
@@ -4322,6 +4324,12 @@ def test_combine_funding_and_mark(
|
||||
else:
|
||||
assert len(df) == 0
|
||||
|
||||
# Empty mark candles
|
||||
mark_candles = DataFrame([], columns=['date', 'open'])
|
||||
df = exchange.combine_funding_and_mark(funding_rates, mark_candles, futures_funding_rate)
|
||||
|
||||
assert len(df) == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize('exchange,rate_start,rate_end,d1,d2,amount,expected_fees', [
|
||||
('binance', 0, 2, "2021-09-01 01:00:00", "2021-09-01 04:00:00", 30.0, 0.0),
|
||||
|
||||
@@ -57,28 +57,30 @@ def test_backtest_position_adjustment(default_conf, fee, mocker, testdatadir) ->
|
||||
),
|
||||
'close_date': pd.to_datetime([dt_utc(2018, 1, 29, 22, 00, 0),
|
||||
dt_utc(2018, 1, 30, 4, 10, 0)], utc=True),
|
||||
'open_rate': [0.10401764894444211, 0.10302485],
|
||||
'close_rate': [0.10453904066847439, 0.103541],
|
||||
'open_rate': [0.10401764891917063, 0.10302485],
|
||||
'close_rate': [0.10453904064307624, 0.10354126528822055],
|
||||
'fee_open': [0.0025, 0.0025],
|
||||
'fee_close': [0.0025, 0.0025],
|
||||
'trade_duration': [200, 40],
|
||||
'profit_ratio': [0.0, 0.0],
|
||||
'profit_abs': [0.0, 0.0],
|
||||
'exit_reason': [ExitType.ROI.value, ExitType.ROI.value],
|
||||
'initial_stop_loss_abs': [0.0940005, 0.09272236],
|
||||
'initial_stop_loss_abs': [0.0940005, 0.092722365],
|
||||
'initial_stop_loss_ratio': [-0.1, -0.1],
|
||||
'stop_loss_abs': [0.0940005, 0.09272236],
|
||||
'stop_loss_abs': [0.0940005, 0.092722365],
|
||||
'stop_loss_ratio': [-0.1, -0.1],
|
||||
'min_rate': [0.10370188, 0.10300000000000001],
|
||||
'max_rate': [0.10481985, 0.1038888],
|
||||
'max_rate': [0.10481985, 0.10388887000000001],
|
||||
'is_open': [False, False],
|
||||
'enter_tag': ['', ''],
|
||||
'leverage': [1.0, 1.0],
|
||||
'is_short': [False, False],
|
||||
'open_timestamp': [1517251200000, 1517283000000],
|
||||
'close_timestamp': [1517265300000, 1517285400000],
|
||||
'close_timestamp': [1517263200000, 1517285400000],
|
||||
})
|
||||
pd.testing.assert_frame_equal(results.drop(columns=['orders']), expected)
|
||||
results_no = results.drop(columns=['orders'])
|
||||
pd.testing.assert_frame_equal(results_no, expected, check_exact=True)
|
||||
|
||||
data_pair = processed[pair]
|
||||
assert len(results.iloc[0]['orders']) == 6
|
||||
assert len(results.iloc[1]['orders']) == 2
|
||||
|
||||
@@ -498,7 +498,7 @@ def test__get_resample_from_period():
|
||||
|
||||
assert _get_resample_from_period('day') == '1d'
|
||||
assert _get_resample_from_period('week') == '1W-MON'
|
||||
assert _get_resample_from_period('month') == '1M'
|
||||
assert _get_resample_from_period('month') == '1ME'
|
||||
with pytest.raises(ValueError, match=r"Period noooo is not supported."):
|
||||
_get_resample_from_period('noooo')
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ from freqtrade.plugins.pairlist.pairlist_helpers import dynamic_expand_pairlist,
|
||||
from freqtrade.plugins.pairlistmanager import PairListManager
|
||||
from freqtrade.resolvers import PairListResolver
|
||||
from freqtrade.util.datetime_helpers import dt_now
|
||||
from tests.conftest import (EXMS, create_mock_trades_usdt, get_patched_exchange,
|
||||
from tests.conftest import (EXMS, create_mock_trades_usdt, generate_test_data, get_patched_exchange,
|
||||
get_patched_freqtradebot, log_has, log_has_re, num_log_has)
|
||||
|
||||
|
||||
@@ -748,6 +748,104 @@ def test_PerformanceFilter_error(mocker, whitelist_conf, caplog) -> None:
|
||||
assert log_has("PerformanceFilter is not available in this mode.", caplog)
|
||||
|
||||
|
||||
def test_VolatilityFilter_error(mocker, whitelist_conf) -> None:
|
||||
volatility_filter = {"method": "VolatilityFilter", "lookback_days": -1}
|
||||
whitelist_conf['pairlists'] = [{"method": "StaticPairList"}, volatility_filter]
|
||||
|
||||
mocker.patch(f'{EXMS}.exchange_has', MagicMock(return_value=True))
|
||||
exchange_mock = MagicMock()
|
||||
exchange_mock.ohlcv_candle_limit = MagicMock(return_value=1000)
|
||||
|
||||
with pytest.raises(OperationalException,
|
||||
match=r"VolatilityFilter requires lookback_days to be >= 1*"):
|
||||
PairListManager(exchange_mock, whitelist_conf, MagicMock())
|
||||
|
||||
volatility_filter = {"method": "VolatilityFilter", "lookback_days": 2000}
|
||||
whitelist_conf['pairlists'] = [{"method": "StaticPairList"}, volatility_filter]
|
||||
with pytest.raises(OperationalException,
|
||||
match=r"VolatilityFilter requires lookback_days to not exceed exchange max"):
|
||||
PairListManager(exchange_mock, whitelist_conf, MagicMock())
|
||||
|
||||
volatility_filter = {"method": "VolatilityFilter", "sort_direction": "Random"}
|
||||
whitelist_conf['pairlists'] = [{"method": "StaticPairList"}, volatility_filter]
|
||||
with pytest.raises(OperationalException,
|
||||
match=r"VolatilityFilter requires sort_direction to be either "
|
||||
r"None .*'asc'.*'desc'"):
|
||||
PairListManager(exchange_mock, whitelist_conf, MagicMock())
|
||||
|
||||
|
||||
@pytest.mark.parametrize('pairlist,expected_pairlist', [
|
||||
({"method": "VolatilityFilter", "sort_direction": "asc"},
|
||||
['XRP/BTC', 'ETH/BTC', 'LTC/BTC', 'TKN/BTC']),
|
||||
({"method": "VolatilityFilter", "sort_direction": "desc"},
|
||||
['TKN/BTC', 'LTC/BTC', 'ETH/BTC', 'XRP/BTC']),
|
||||
({"method": "VolatilityFilter", "sort_direction": "desc", 'min_volatility': 0.4},
|
||||
['TKN/BTC', 'LTC/BTC', 'ETH/BTC']),
|
||||
({"method": "VolatilityFilter", "sort_direction": "asc", 'min_volatility': 0.4},
|
||||
['ETH/BTC', 'LTC/BTC', 'TKN/BTC']),
|
||||
({"method": "VolatilityFilter", "sort_direction": "desc", 'max_volatility': 0.5},
|
||||
['LTC/BTC', 'ETH/BTC', 'XRP/BTC']),
|
||||
({"method": "VolatilityFilter", "sort_direction": "asc", 'max_volatility': 0.5},
|
||||
['XRP/BTC', 'ETH/BTC', 'LTC/BTC']),
|
||||
({"method": "RangeStabilityFilter", "sort_direction": "asc"},
|
||||
['ETH/BTC', 'XRP/BTC', 'LTC/BTC', 'TKN/BTC']),
|
||||
({"method": "RangeStabilityFilter", "sort_direction": "desc"},
|
||||
['TKN/BTC', 'LTC/BTC', 'XRP/BTC', 'ETH/BTC']),
|
||||
({"method": "RangeStabilityFilter", "sort_direction": "asc", 'min_rate_of_change': 0.4},
|
||||
['XRP/BTC', 'LTC/BTC', 'TKN/BTC']),
|
||||
({"method": "RangeStabilityFilter", "sort_direction": "desc", 'min_rate_of_change': 0.4},
|
||||
['TKN/BTC', 'LTC/BTC', 'XRP/BTC']),
|
||||
])
|
||||
def test_VolatilityFilter_RangeStabilityFilter_sort(
|
||||
mocker, whitelist_conf, tickers, time_machine, pairlist, expected_pairlist) -> None:
|
||||
whitelist_conf['pairlists'] = [
|
||||
{'method': 'VolumePairList', 'number_assets': 10},
|
||||
pairlist
|
||||
]
|
||||
|
||||
df1 = generate_test_data('1d', 10, '2022-01-05 00:00:00+00:00', random_seed=42)
|
||||
df2 = generate_test_data('1d', 10, '2022-01-05 00:00:00+00:00', random_seed=2)
|
||||
df3 = generate_test_data('1d', 10, '2022-01-05 00:00:00+00:00', random_seed=3)
|
||||
df4 = generate_test_data('1d', 10, '2022-01-05 00:00:00+00:00', random_seed=4)
|
||||
df5 = generate_test_data('1d', 10, '2022-01-05 00:00:00+00:00', random_seed=5)
|
||||
df6 = generate_test_data('1d', 10, '2022-01-05 00:00:00+00:00', random_seed=6)
|
||||
|
||||
assert not df1.equals(df2)
|
||||
time_machine.move_to('2022-01-15 00:00:00+00:00')
|
||||
|
||||
ohlcv_data = {
|
||||
('ETH/BTC', '1d', CandleType.SPOT): df1,
|
||||
('TKN/BTC', '1d', CandleType.SPOT): df2,
|
||||
('LTC/BTC', '1d', CandleType.SPOT): df3,
|
||||
('XRP/BTC', '1d', CandleType.SPOT): df4,
|
||||
('HOT/BTC', '1d', CandleType.SPOT): df5,
|
||||
('BLK/BTC', '1d', CandleType.SPOT): df6,
|
||||
|
||||
}
|
||||
ohlcv_mock = MagicMock(return_value=ohlcv_data)
|
||||
mocker.patch.multiple(
|
||||
EXMS,
|
||||
exchange_has=MagicMock(return_value=True),
|
||||
refresh_latest_ohlcv=ohlcv_mock,
|
||||
get_tickers=tickers
|
||||
|
||||
)
|
||||
|
||||
exchange = get_patched_exchange(mocker, whitelist_conf)
|
||||
exchange.ohlcv_candle_limit = MagicMock(return_value=1000)
|
||||
plm = PairListManager(exchange, whitelist_conf, MagicMock())
|
||||
|
||||
assert exchange.ohlcv_candle_limit.call_count == 2
|
||||
plm.refresh_pairlist()
|
||||
assert ohlcv_mock.call_count == 1
|
||||
assert exchange.ohlcv_candle_limit.call_count == 2
|
||||
assert plm.whitelist == expected_pairlist
|
||||
|
||||
plm.refresh_pairlist()
|
||||
assert exchange.ohlcv_candle_limit.call_count == 2
|
||||
assert ohlcv_mock.call_count == 1
|
||||
|
||||
|
||||
def test_ShuffleFilter_init(mocker, whitelist_conf, caplog) -> None:
|
||||
whitelist_conf['pairlists'] = [
|
||||
{"method": "StaticPairList"},
|
||||
@@ -1095,6 +1193,13 @@ def test_rangestabilityfilter_checks(mocker, default_conf, markets, tickers):
|
||||
match='RangeStabilityFilter requires lookback_days to be >= 1'):
|
||||
get_patched_freqtradebot(mocker, default_conf)
|
||||
|
||||
default_conf['pairlists'] = [{'method': 'VolumePairList', 'number_assets': 10},
|
||||
{'method': 'RangeStabilityFilter', 'sort_direction': 'something'}]
|
||||
|
||||
with pytest.raises(OperationalException,
|
||||
match='RangeStabilityFilter requires sort_direction to be either None.*'):
|
||||
get_patched_freqtradebot(mocker, default_conf)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('min_rate_of_change,max_rate_of_change,expected_length', [
|
||||
(0.01, 0.99, 5),
|
||||
|
||||
@@ -1022,22 +1022,22 @@ def test_auto_hyperopt_interface_loadparams(default_conf, mocker, caplog):
|
||||
|
||||
|
||||
@pytest.mark.parametrize('function,raises', [
|
||||
('populate_entry_trend', True),
|
||||
('populate_entry_trend', False),
|
||||
('advise_entry', False),
|
||||
('populate_exit_trend', True),
|
||||
('populate_exit_trend', False),
|
||||
('advise_exit', False),
|
||||
])
|
||||
def test_pandas_warning_direct(ohlcv_history, function, raises):
|
||||
def test_pandas_warning_direct(ohlcv_history, function, raises, recwarn):
|
||||
|
||||
df = _STRATEGY.populate_indicators(ohlcv_history, {'pair': 'ETH/BTC'})
|
||||
if raises:
|
||||
with pytest.warns(FutureWarning):
|
||||
# Test for Future warning
|
||||
# FutureWarning: Setting an item of incompatible dtype is
|
||||
# deprecated and will raise in a future error of pandas
|
||||
# https://github.com/pandas-dev/pandas/issues/56503
|
||||
getattr(_STRATEGY, function)(df, {'pair': 'ETH/BTC'})
|
||||
assert len(recwarn) == 1
|
||||
# https://github.com/pandas-dev/pandas/issues/56503
|
||||
# Fixed in 2.2.x
|
||||
getattr(_STRATEGY, function)(df, {'pair': 'ETH/BTC'})
|
||||
else:
|
||||
assert len(recwarn) == 0
|
||||
|
||||
getattr(_STRATEGY, function)(df, {'pair': 'ETH/BTC'})
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user