Merge branch 'freqtrade:develop' into feature/multiple_open_orders

This commit is contained in:
Axel CHERUBIN
2023-08-02 23:48:13 -04:00
committed by GitHub
181 changed files with 3275 additions and 1744 deletions
+2 -8
View File
@@ -1389,8 +1389,6 @@ def test_convert_data_trades(mocker, testdatadir):
def test_start_list_data(testdatadir, capsys):
args = [
"list-data",
"--data-format-ohlcv",
"json",
"--datadir",
str(testdatadir),
]
@@ -1398,14 +1396,14 @@ def test_start_list_data(testdatadir, capsys):
pargs['config'] = None
start_list_data(pargs)
captured = capsys.readouterr()
assert "Found 17 pair / timeframe combinations." in captured.out
assert "Found 16 pair / timeframe combinations." in captured.out
assert "\n| Pair | Timeframe | Type |\n" in captured.out
assert "\n| UNITTEST/BTC | 1m, 5m, 8m, 30m | spot |\n" in captured.out
args = [
"list-data",
"--data-format-ohlcv",
"json",
"feather",
"--pairs", "XRP/ETH",
"--datadir",
str(testdatadir),
@@ -1421,8 +1419,6 @@ def test_start_list_data(testdatadir, capsys):
args = [
"list-data",
"--data-format-ohlcv",
"json",
"--trading-mode", "futures",
"--datadir",
str(testdatadir),
@@ -1439,8 +1435,6 @@ def test_start_list_data(testdatadir, capsys):
args = [
"list-data",
"--data-format-ohlcv",
"json",
"--pairs", "XRP/ETH",
"--datadir",
str(testdatadir),
+17 -16
View File
@@ -526,6 +526,7 @@ def get_default_conf(testdatadir):
"disableparamexport": True,
"internals": {},
"export": "none",
"dataformat_ohlcv": "feather",
"candle_type_def": CandleType.SPOT,
}
return configuration
@@ -2999,85 +3000,85 @@ def mark_ohlcv():
def funding_rate_history_hourly():
return [
{
"symbol": "ADA/USDT",
"symbol": "ADA/USDT:USDT",
"fundingRate": -0.000008,
"timestamp": 1630454400000,
"datetime": "2021-09-01T00:00:00.000Z"
},
{
"symbol": "ADA/USDT",
"symbol": "ADA/USDT:USDT",
"fundingRate": -0.000004,
"timestamp": 1630458000000,
"datetime": "2021-09-01T01:00:00.000Z"
},
{
"symbol": "ADA/USDT",
"symbol": "ADA/USDT:USDT",
"fundingRate": 0.000012,
"timestamp": 1630461600000,
"datetime": "2021-09-01T02:00:00.000Z"
},
{
"symbol": "ADA/USDT",
"symbol": "ADA/USDT:USDT",
"fundingRate": -0.000003,
"timestamp": 1630465200000,
"datetime": "2021-09-01T03:00:00.000Z"
},
{
"symbol": "ADA/USDT",
"symbol": "ADA/USDT:USDT",
"fundingRate": -0.000007,
"timestamp": 1630468800000,
"datetime": "2021-09-01T04:00:00.000Z"
},
{
"symbol": "ADA/USDT",
"symbol": "ADA/USDT:USDT",
"fundingRate": 0.000003,
"timestamp": 1630472400000,
"datetime": "2021-09-01T05:00:00.000Z"
},
{
"symbol": "ADA/USDT",
"symbol": "ADA/USDT:USDT",
"fundingRate": 0.000019,
"timestamp": 1630476000000,
"datetime": "2021-09-01T06:00:00.000Z"
},
{
"symbol": "ADA/USDT",
"symbol": "ADA/USDT:USDT",
"fundingRate": 0.000003,
"timestamp": 1630479600000,
"datetime": "2021-09-01T07:00:00.000Z"
},
{
"symbol": "ADA/USDT",
"symbol": "ADA/USDT:USDT",
"fundingRate": -0.000003,
"timestamp": 1630483200000,
"datetime": "2021-09-01T08:00:00.000Z"
},
{
"symbol": "ADA/USDT",
"symbol": "ADA/USDT:USDT",
"fundingRate": 0,
"timestamp": 1630486800000,
"datetime": "2021-09-01T09:00:00.000Z"
},
{
"symbol": "ADA/USDT",
"symbol": "ADA/USDT:USDT",
"fundingRate": 0.000013,
"timestamp": 1630490400000,
"datetime": "2021-09-01T10:00:00.000Z"
},
{
"symbol": "ADA/USDT",
"symbol": "ADA/USDT:USDT",
"fundingRate": 0.000077,
"timestamp": 1630494000000,
"datetime": "2021-09-01T11:00:00.000Z"
},
{
"symbol": "ADA/USDT",
"symbol": "ADA/USDT:USDT",
"fundingRate": 0.000072,
"timestamp": 1630497600000,
"datetime": "2021-09-01T12:00:00.000Z"
},
{
"symbol": "ADA/USDT",
"symbol": "ADA/USDT:USDT",
"fundingRate": 0.000097,
"timestamp": 1630501200000,
"datetime": "2021-09-01T13:00:00.000Z"
@@ -3089,13 +3090,13 @@ def funding_rate_history_hourly():
def funding_rate_history_octohourly():
return [
{
"symbol": "ADA/USDT",
"symbol": "ADA/USDT:USDT",
"fundingRate": -0.000008,
"timestamp": 1630454400000,
"datetime": "2021-09-01T00:00:00.000Z"
},
{
"symbol": "ADA/USDT",
"symbol": "ADA/USDT:USDT",
"fundingRate": -0.000003,
"timestamp": 1630483200000,
"datetime": "2021-09-01T08:00:00.000Z"
+15 -3
View File
@@ -343,12 +343,24 @@ def test_calculate_expectancy(testdatadir):
filename = testdatadir / "backtest_results/backtest-result.json"
bt_data = load_backtest_data(filename)
expectancy = calculate_expectancy(DataFrame())
expectancy, expectancy_ratio = calculate_expectancy(DataFrame())
assert expectancy == 0.0
assert expectancy_ratio == 100
expectancy = calculate_expectancy(bt_data)
expectancy, expectancy_ratio = calculate_expectancy(bt_data)
assert isinstance(expectancy, float)
assert pytest.approx(expectancy) == 0.07151374226574791
assert isinstance(expectancy_ratio, float)
assert pytest.approx(expectancy) == 5.820687070932315e-06
assert pytest.approx(expectancy_ratio) == 0.07151374226574791
data = {
'profit_abs': [100, 200, 50, -150, 300, -100, 80, -30]
}
df = DataFrame(data)
expectancy, expectancy_ratio = calculate_expectancy(df)
assert pytest.approx(expectancy) == 56.25
assert pytest.approx(expectancy_ratio) == 0.60267857
def test_calculate_sortino(testdatadir):
+73 -6
View File
@@ -135,6 +135,73 @@ def test_ohlcv_fill_up_missing_data2(caplog):
f"{len(data)} - after: {len(data2)}.*", caplog)
def test_ohlcv_to_dataframe_1M():
# Monthly ticks from 2019-09-01 to 2023-07-01
ticks = [
[1567296000000, 8042.08, 10475.54, 7700.67, 8041.96, 608742.1109999999],
[1569888000000, 8285.31, 10408.48, 7172.76, 9150.0, 2439561.887],
[1572566400000, 9149.88, 9550.0, 6510.19, 7542.93, 4042674.725],
[1575158400000, 7541.08, 7800.0, 6427.0, 7189.0, 4063882.296],
[1577836800000, 7189.43, 9599.0, 6863.44, 9364.51, 5165281.358],
[1580515200000, 9364.5, 10540.0, 8450.0, 8531.98, 4581788.124],
[1583020800000, 8532.5, 9204.0, 3621.81, 6407.1, 10859497.479],
[1585699200000, 6407.1, 9479.77, 6140.0, 8624.76, 11276526.968],
[1588291200000, 8623.61, 10080.0, 7940.0, 9446.43, 12469561.02],
[1590969600000, 9446.49, 10497.25, 8816.4, 9138.87, 6684044.201],
[1593561600000, 9138.88, 11488.0, 8900.0, 11343.68, 5709327.926],
[1596240000000, 11343.67, 12499.42, 10490.0, 11658.11, 6746487.129],
[1598918400000, 11658.11, 12061.07, 9808.58, 10773.0, 6442697.051],
[1601510400000, 10773.0, 14140.0, 10371.03, 13783.73, 7404103.004],
[1604188800000, 13783.73, 19944.0, 13195.0, 19720.0, 12328272.549],
[1606780800000, 19722.09, 29376.7, 17555.0, 28951.68, 10067314.24],
[1609459200000, 28948.19, 42125.51, 27800.0, 33126.21, 12408873.079],
[1612137600000, 33125.11, 58472.14, 32322.47, 45163.36, 8784474.482],
[1614556800000, 45162.64, 61950.0, 44972.49, 58807.24, 9459821.267],
[1617235200000, 58810.99, 64986.11, 46930.43, 57684.16, 7895051.389],
[1619827200000, 57688.29, 59654.0, 28688.0, 37243.38, 16790964.443],
[1622505600000, 37244.36, 41413.0, 28780.01, 35031.39, 23474519.886],
[1625097600000, 35031.39, 48168.6, 29242.24, 41448.11, 16932491.175],
[1627776000000, 41448.1, 50600.0, 37291.0, 47150.32, 13645800.254],
[1630454400000, 47150.32, 52950.0, 39503.58, 43796.57, 10734742.869],
[1633046400000, 43799.49, 67150.0, 43260.01, 61348.61, 9111112.847],
[1635724800000, 61347.14, 69198.7, 53245.0, 56975.0, 7111424.463],
[1638316800000, 56978.06, 59100.0, 40888.89, 46210.56, 8404449.024],
[1640995200000, 46210.57, 48000.0, 32853.83, 38439.04, 11047479.277],
[1643673600000, 38439.04, 45847.5, 34303.7, 43155.0, 10910339.91],
[1646092800000, 43155.0, 48200.0, 37134.0, 45506.0, 10459721.586],
[1648771200000, 45505.9, 47448.0, 37550.0, 37614.5, 8463568.862],
[1651363200000, 37614.4, 40071.7, 26631.0, 31797.8, 14463715.774],
[1654041600000, 31797.9, 31986.1, 17593.2, 19923.5, 20710810.306],
[1656633600000, 19923.3, 24700.0, 18780.1, 23290.1, 20582518.513],
[1659312000000, 23290.1, 25200.0, 19508.0, 20041.5, 17221921.557],
[1661990400000, 20041.4, 22850.0, 18084.3, 19411.7, 21935261.414],
[1664582400000, 19411.6, 21088.0, 17917.8, 20482.0, 16625843.584],
[1667260800000, 20482.1, 21473.7, 15443.2, 17153.3, 18460614.013],
[1669852800000, 17153.4, 18400.0, 16210.0, 16537.6, 9702408.711],
[1672531200000, 16537.5, 23962.7, 16488.0, 23119.4, 14732180.645],
[1675209600000, 23119.5, 25347.6, 21338.0, 23129.6, 15025197.415],
[1677628800000, 23129.7, 29184.8, 19521.6, 28454.9, 23317458.541],
[1680307200000, 28454.8, 31059.0, 26919.3, 29223.0, 14654208.219],
[1682899200000, 29223.0, 29840.0, 25751.0, 27201.1, 13328157.284],
[1685577600000, 27201.1, 31500.0, 24777.0, 30460.2, 14099299.273],
[1688169600000, 30460.2, 31850.0, 28830.0, 29338.8, 8760361.377]
]
data = ohlcv_to_dataframe(ticks, '1M', pair="UNITTEST/USDT",
fill_missing=False, drop_incomplete=False)
assert len(data) == len(ticks)
assert data.iloc[0]['date'].strftime('%Y-%m-%d') == '2019-09-01'
assert data.iloc[-1]['date'].strftime('%Y-%m-%d') == '2023-07-01'
# Test with filling missing data
data = ohlcv_to_dataframe(ticks, '1M', pair="UNITTEST/USDT",
fill_missing=True, drop_incomplete=False)
assert len(data) == len(ticks)
assert data.iloc[0]['date'].strftime('%Y-%m-%d') == '2019-09-01'
assert data.iloc[-1]['date'].strftime('%Y-%m-%d') == '2023-07-01'
def test_ohlcv_drop_incomplete(caplog):
timeframe = '1d'
ticks = [
@@ -304,8 +371,8 @@ def test_convert_ohlcv_format(default_conf, testdatadir, tmpdir, file_base, cand
files_temp = []
files_new = []
for file in file_base:
file_orig = testdatadir / f"{prependix}{file}.json"
file_temp = tmpdir1 / f"{prependix}{file}.json"
file_orig = testdatadir / f"{prependix}{file}.feather"
file_temp = tmpdir1 / f"{prependix}{file}.feather"
file_new = tmpdir1 / f"{prependix}{file}.json.gz"
IDataHandler.create_dir_if_needed(file_temp)
copyfile(file_orig, file_temp)
@@ -315,6 +382,8 @@ def test_convert_ohlcv_format(default_conf, testdatadir, tmpdir, file_base, cand
files_new.append(file_new)
default_conf['datadir'] = tmpdir1
default_conf['candle_types'] = [candletype]
if candletype == CandleType.SPOT:
default_conf['pairs'] = ['XRP/ETH', 'XRP/USDT', 'UNITTEST/USDT']
else:
@@ -325,10 +394,9 @@ def test_convert_ohlcv_format(default_conf, testdatadir, tmpdir, file_base, cand
convert_ohlcv_format(
default_conf,
convert_from='json',
convert_from='feather',
convert_to='jsongz',
erase=False,
candle_type=candletype
)
for file in (files_temp + files_new):
assert file.exists()
@@ -340,9 +408,8 @@ def test_convert_ohlcv_format(default_conf, testdatadir, tmpdir, file_base, cand
convert_ohlcv_format(
default_conf,
convert_from='jsongz',
convert_to='json',
convert_to='feather',
erase=True,
candle_type=candletype
)
for file in (files_temp):
assert file.exists()
+8 -14
View File
@@ -20,7 +20,7 @@ from tests.conftest import log_has, log_has_re
def test_datahandler_ohlcv_get_pairs(testdatadir):
pairs = JsonDataHandler.ohlcv_get_pairs(testdatadir, '5m', candle_type=CandleType.SPOT)
pairs = FeatherDataHandler.ohlcv_get_pairs(testdatadir, '5m', candle_type=CandleType.SPOT)
# Convert to set to avoid failures due to sorting
assert set(pairs) == {'UNITTEST/BTC', 'XLM/BTC', 'ETH/BTC', 'TRX/BTC', 'LTC/BTC',
'XMR/BTC', 'ZEC/BTC', 'ADA/BTC', 'ETC/BTC', 'NXT/BTC',
@@ -32,7 +32,7 @@ def test_datahandler_ohlcv_get_pairs(testdatadir):
pairs = HDF5DataHandler.ohlcv_get_pairs(testdatadir, '5m', candle_type=CandleType.SPOT)
assert set(pairs) == {'UNITTEST/BTC'}
pairs = JsonDataHandler.ohlcv_get_pairs(testdatadir, '1h', candle_type=CandleType.MARK)
pairs = FeatherDataHandler.ohlcv_get_pairs(testdatadir, '1h', candle_type=CandleType.MARK)
assert set(pairs) == {'UNITTEST/USDT:USDT', 'XRP/USDT:USDT'}
pairs = JsonGzDataHandler.ohlcv_get_pairs(testdatadir, '1h', candle_type=CandleType.FUTURES)
@@ -79,7 +79,7 @@ def test_rebuild_pair_from_filename(input, expected):
def test_datahandler_ohlcv_get_available_data(testdatadir):
paircombs = JsonDataHandler.ohlcv_get_available_data(testdatadir, TradingMode.SPOT)
paircombs = FeatherDataHandler.ohlcv_get_available_data(testdatadir, TradingMode.SPOT)
# Convert to set to avoid failures due to sorting
assert set(paircombs) == {
('UNITTEST/BTC', '5m', CandleType.SPOT),
@@ -98,10 +98,9 @@ def test_datahandler_ohlcv_get_available_data(testdatadir):
('XRP/ETH', '5m', CandleType.SPOT),
('UNITTEST/BTC', '30m', CandleType.SPOT),
('UNITTEST/BTC', '8m', CandleType.SPOT),
('NOPAIR/XXX', '4m', CandleType.SPOT),
}
paircombs = JsonDataHandler.ohlcv_get_available_data(testdatadir, TradingMode.FUTURES)
paircombs = FeatherDataHandler.ohlcv_get_available_data(testdatadir, TradingMode.FUTURES)
# Convert to set to avoid failures due to sorting
assert set(paircombs) == {
('UNITTEST/USDT:USDT', '1h', 'mark'),
@@ -140,16 +139,11 @@ def test_jsondatahandler_ohlcv_purge(mocker, testdatadir):
def test_jsondatahandler_ohlcv_load(testdatadir, caplog):
dh = JsonDataHandler(testdatadir)
df = dh.ohlcv_load('XRP/ETH', '5m', 'spot')
assert len(df) == 712
df_mark = dh.ohlcv_load('UNITTEST/USDT:USDT', '1h', candle_type="mark")
assert len(df_mark) == 100
df = dh.ohlcv_load('UNITTEST/BTC', '1m', 'spot')
assert len(df) > 0
df_no_mark = dh.ohlcv_load('UNITTEST/USDT', '1h', 'spot')
assert len(df_no_mark) == 0
# Failure case (empty array)
# # Failure case (empty array)
df1 = dh.ohlcv_load('NOPAIR/XXX', '4m', 'spot')
assert len(df1) == 0
assert log_has("Could not load data for NOPAIR/XXX.", caplog)
@@ -444,7 +438,7 @@ def test_generic_datahandler_ohlcv_load_and_resave(
tmpdir2 = tmpdir1 / 'futures'
tmpdir2.mkdir()
# Load data from one common file
dhbase = get_datahandler(testdatadir, 'json')
dhbase = get_datahandler(testdatadir, 'feather')
ohlcv = dhbase._ohlcv_load(pair, timeframe, None, candle_type=candle_type)
assert isinstance(ohlcv, DataFrame)
assert len(ohlcv) > 0
+6 -5
View File
@@ -63,9 +63,10 @@ def test_historic_ohlcv(mocker, default_conf, ohlcv_history):
def test_historic_ohlcv_dataformat(mocker, default_conf, ohlcv_history):
hdf5loadmock = MagicMock(return_value=ohlcv_history)
jsonloadmock = MagicMock(return_value=ohlcv_history)
featherloadmock = MagicMock(return_value=ohlcv_history)
mocker.patch("freqtrade.data.history.hdf5datahandler.HDF5DataHandler._ohlcv_load", hdf5loadmock)
mocker.patch("freqtrade.data.history.jsondatahandler.JsonDataHandler._ohlcv_load", jsonloadmock)
mocker.patch("freqtrade.data.history.featherdatahandler.FeatherDataHandler._ohlcv_load",
featherloadmock)
default_conf["runmode"] = RunMode.BACKTEST
exchange = get_patched_exchange(mocker, default_conf)
@@ -73,17 +74,17 @@ def test_historic_ohlcv_dataformat(mocker, default_conf, ohlcv_history):
data = dp.historic_ohlcv("UNITTEST/BTC", "5m")
assert isinstance(data, DataFrame)
hdf5loadmock.assert_not_called()
jsonloadmock.assert_called_once()
featherloadmock.assert_called_once()
# Switching to dataformat hdf5
hdf5loadmock.reset_mock()
jsonloadmock.reset_mock()
featherloadmock.reset_mock()
default_conf["dataformat_ohlcv"] = "hdf5"
dp = DataProvider(default_conf, exchange)
data = dp.historic_ohlcv("UNITTEST/BTC", "5m")
assert isinstance(data, DataFrame)
hdf5loadmock.assert_called_once()
jsonloadmock.assert_not_called()
featherloadmock.assert_not_called()
@pytest.mark.parametrize('candle_type', [
+18 -16
View File
@@ -68,7 +68,7 @@ def test_load_data_7min_timeframe(caplog, testdatadir) -> None:
def test_load_data_1min_timeframe(ohlcv_history, mocker, caplog, testdatadir) -> None:
mocker.patch(f'{EXMS}.get_historic_ohlcv', return_value=ohlcv_history)
file = testdatadir / 'UNITTEST_BTC-1m.json'
file = testdatadir / 'UNITTEST_BTC-1m.feather'
load_data(datadir=testdatadir, timeframe='1m', pairs=['UNITTEST/BTC'])
assert file.is_file()
assert not log_has(
@@ -79,7 +79,7 @@ def test_load_data_1min_timeframe(ohlcv_history, mocker, caplog, testdatadir) ->
def test_load_data_mark(ohlcv_history, mocker, caplog, testdatadir) -> None:
mocker.patch(f'{EXMS}.get_historic_ohlcv', return_value=ohlcv_history)
file = testdatadir / 'futures/UNITTEST_USDT_USDT-1h-mark.json'
file = testdatadir / 'futures/UNITTEST_USDT_USDT-1h-mark.feather'
load_data(datadir=testdatadir, timeframe='1h', pairs=['UNITTEST/BTC'], candle_type='mark')
assert file.is_file()
assert not log_has(
@@ -90,7 +90,7 @@ def test_load_data_mark(ohlcv_history, mocker, caplog, testdatadir) -> None:
def test_load_data_startup_candles(mocker, testdatadir) -> None:
ltfmock = mocker.patch(
'freqtrade.data.history.jsondatahandler.JsonDataHandler._ohlcv_load',
'freqtrade.data.history.featherdatahandler.FeatherDataHandler._ohlcv_load',
MagicMock(return_value=DataFrame()))
timerange = TimeRange('date', None, 1510639620, 0)
load_pair_history(pair='UNITTEST/BTC', timeframe='1m',
@@ -112,7 +112,7 @@ def test_load_data_with_new_pair_1min(ohlcv_history_list, mocker, caplog,
tmpdir1 = Path(tmpdir)
mocker.patch(f'{EXMS}.get_historic_ohlcv', return_value=ohlcv_history_list)
exchange = get_patched_exchange(mocker, default_conf)
file = tmpdir1 / 'MEME_BTC-1m.json'
file = tmpdir1 / 'MEME_BTC-1m.feather'
# do not download a new pair if refresh_pairs isn't set
load_pair_history(datadir=tmpdir1, timeframe='1m', pair='MEME/BTC', candle_type=candle_type)
@@ -280,10 +280,10 @@ def test_download_pair_history(
mocker.patch(f'{EXMS}.get_historic_ohlcv', return_value=ohlcv_history_list)
exchange = get_patched_exchange(mocker, default_conf)
tmpdir1 = Path(tmpdir)
file1_1 = tmpdir1 / f'{subdir}MEME_BTC-1m{file_tail}.json'
file1_5 = tmpdir1 / f'{subdir}MEME_BTC-5m{file_tail}.json'
file2_1 = tmpdir1 / f'{subdir}CFI_BTC-1m{file_tail}.json'
file2_5 = tmpdir1 / f'{subdir}CFI_BTC-5m{file_tail}.json'
file1_1 = tmpdir1 / f'{subdir}MEME_BTC-1m{file_tail}.feather'
file1_5 = tmpdir1 / f'{subdir}MEME_BTC-5m{file_tail}.feather'
file2_1 = tmpdir1 / f'{subdir}CFI_BTC-1m{file_tail}.feather'
file2_5 = tmpdir1 / f'{subdir}CFI_BTC-5m{file_tail}.feather'
assert not file1_1.is_file()
assert not file2_1.is_file()
@@ -326,7 +326,7 @@ def test_download_pair_history2(mocker, default_conf, testdatadir) -> None:
[1509836580000, 0.00161, 0.00161, 0.00161, 0.00161, 82.390199]
]
json_dump_mock = mocker.patch(
'freqtrade.data.history.jsondatahandler.JsonDataHandler.ohlcv_store',
'freqtrade.data.history.featherdatahandler.FeatherDataHandler.ohlcv_store',
return_value=None)
mocker.patch(f'{EXMS}.get_historic_ohlcv', return_value=tick)
exchange = get_patched_exchange(mocker, default_conf)
@@ -386,7 +386,7 @@ def test_load_partial_missing(testdatadir, caplog) -> None:
def test_init(default_conf) -> None:
assert {} == load_data(
datadir=Path(''),
datadir=Path(),
pairs=[],
timeframe=default_conf['timeframe']
)
@@ -395,14 +395,14 @@ def test_init(default_conf) -> None:
def test_init_with_refresh(default_conf, mocker) -> None:
exchange = get_patched_exchange(mocker, default_conf)
refresh_data(
datadir=Path(''),
datadir=Path(),
pairs=[],
timeframe=default_conf['timeframe'],
exchange=exchange,
candle_type=CandleType.SPOT
)
assert {} == load_data(
datadir=Path(''),
datadir=Path(),
pairs=[],
timeframe=default_conf['timeframe']
)
@@ -627,8 +627,8 @@ def test_download_trades_history(trades_history, mocker, default_conf, testdatad
def test_convert_trades_to_ohlcv(testdatadir, tmpdir, caplog):
tmpdir1 = Path(tmpdir)
pair = 'XRP/ETH'
file1 = tmpdir1 / 'XRP_ETH-1m.json'
file5 = tmpdir1 / 'XRP_ETH-5m.json'
file1 = tmpdir1 / 'XRP_ETH-1m.feather'
file5 = tmpdir1 / 'XRP_ETH-5m.feather'
filetrades = tmpdir1 / 'XRP_ETH-trades.json.gz'
copyfile(testdatadir / file1.name, file1)
copyfile(testdatadir / file5.name, file5)
@@ -641,6 +641,7 @@ def test_convert_trades_to_ohlcv(testdatadir, tmpdir, caplog):
tr = TimeRange.parse_timerange('20191011-20191012')
convert_trades_to_ohlcv([pair], timeframes=['1m', '5m'],
data_format_trades='jsongz',
datadir=tmpdir1, timerange=tr, erase=True)
assert log_has("Deleting existing data for pair XRP/ETH, interval 1m.", caplog)
@@ -648,11 +649,12 @@ def test_convert_trades_to_ohlcv(testdatadir, tmpdir, caplog):
df_1m = load_pair_history(datadir=tmpdir1, timeframe="1m", pair=pair)
df_5m = load_pair_history(datadir=tmpdir1, timeframe="5m", pair=pair)
assert df_1m.equals(dfbak_1m)
assert df_5m.equals(dfbak_5m)
assert_frame_equal(dfbak_1m, df_1m, check_exact=True)
assert_frame_equal(dfbak_5m, df_5m, check_exact=True)
assert not log_has('Could not convert NoDatapair to OHLCV.', caplog)
convert_trades_to_ohlcv(['NoDatapair'], timeframes=['1m', '5m'],
data_format_trades='jsongz',
datadir=tmpdir1, timerange=tr, erase=True)
assert log_has('Could not convert NoDatapair to OHLCV.', caplog)
+23 -9
View File
@@ -43,6 +43,7 @@ EXCHANGES = {
'hasQuoteVolumeFutures': True,
'leverage_tiers_public': False,
'leverage_in_spot_market': False,
'trades_lookback_hours': 4,
'private_methods': [
'fapiPrivateGetPositionSideDual',
'fapiPrivateGetMultiAssetsMargin'
@@ -92,12 +93,13 @@ EXCHANGES = {
}]
},
'kraken': {
'pair': 'BTC/USDT',
'stake_currency': 'USDT',
'pair': 'BTC/USD',
'stake_currency': 'USD',
'hasQuoteVolume': True,
'timeframe': '1h',
'leverage_tiers_public': False,
'leverage_in_spot_market': True,
'trades_lookback_hours': 12,
},
'kucoin': {
'pair': 'XRP/USDT',
@@ -291,11 +293,7 @@ def set_test_proxy(config: Config, use_proxy: bool) -> Config:
if use_proxy and (proxy := os.environ.get('CI_WEB_PROXY')):
config1 = deepcopy(config)
config1['exchange']['ccxt_config'] = {
"aiohttp_proxy": proxy,
'proxies': {
'https': proxy,
'http': proxy,
}
"httpsProxy": proxy,
}
return config1
@@ -342,7 +340,7 @@ def exchange_futures(request, exchange_conf, class_mocker):
@pytest.mark.longrun
class TestCCXTExchange():
class TestCCXTExchange:
def test_load_markets(self, exchange: EXCHANGE_FIXTURE_TYPE):
exch, exchangename = exchange
@@ -546,6 +544,8 @@ class TestCCXTExchange():
if exchangename in ('bittrex'):
# For some weired reason, this test returns random lengths for bittrex.
pytest.skip("Exchange doesn't provide stable ohlcv history")
if exchangename in ('bitvavo'):
pytest.skip("Exchange Downtime ")
if not exc._ft_has['ohlcv_has_history']:
pytest.skip("Exchange does not support candle history")
@@ -640,7 +640,21 @@ class TestCCXTExchange():
assert isinstance(funding_fee, float)
# assert funding_fee > 0
# TODO: tests fetch_trades (?)
def test_ccxt__async_get_trade_history(self, exchange: EXCHANGE_FIXTURE_TYPE):
exch, exchangename = exchange
if not (lookback := EXCHANGES[exchangename].get('trades_lookback_hours')):
pytest.skip('test_fetch_trades not enabled for this exchange')
pair = EXCHANGES[exchangename]['pair']
since = int((datetime.now(timezone.utc) - timedelta(hours=lookback)).timestamp() * 1000)
res = exch.loop.run_until_complete(
exch._async_get_trade_history(pair, since, None, None)
)
assert len(res) == 2
res_pair, res_trades = res
assert res_pair == pair
assert isinstance(res_trades, list)
assert res_trades[0][0] >= since
assert len(res_trades) > 1200
def test_ccxt_get_fee(self, exchange: EXCHANGE_FIXTURE_TYPE):
exch, exchangename = exchange
+4 -4
View File
@@ -4343,11 +4343,11 @@ def test__fetch_and_calculate_funding_fees(
ex = get_patched_exchange(mocker, default_conf, api_mock, id=exchange)
mocker.patch(f'{EXMS}.timeframes', PropertyMock(return_value=['1h', '4h', '8h']))
funding_fees = ex._fetch_and_calculate_funding_fees(
pair='ADA/USDT', amount=amount, is_short=True, open_date=d1, close_date=d2)
pair='ADA/USDT:USDT', amount=amount, is_short=True, open_date=d1, close_date=d2)
assert pytest.approx(funding_fees) == expected_fees
# Fees for Longs are inverted
funding_fees = ex._fetch_and_calculate_funding_fees(
pair='ADA/USDT', amount=amount, is_short=False, open_date=d1, close_date=d2)
pair='ADA/USDT:USDT', amount=amount, is_short=False, open_date=d1, close_date=d2)
assert pytest.approx(funding_fees) == -expected_fees
# Return empty "refresh_latest"
@@ -4355,7 +4355,7 @@ def test__fetch_and_calculate_funding_fees(
ex = get_patched_exchange(mocker, default_conf, api_mock, id=exchange)
with pytest.raises(ExchangeError, match="Could not find funding rates."):
ex._fetch_and_calculate_funding_fees(
pair='ADA/USDT', amount=amount, is_short=False, open_date=d1, close_date=d2)
pair='ADA/USDT:USDT', amount=amount, is_short=False, open_date=d1, close_date=d2)
@pytest.mark.parametrize('exchange,expected_fees', [
@@ -5424,7 +5424,7 @@ def test_stoploss_contract_size(mocker, default_conf, contract_size, order_amoun
assert api_mock.create_order.call_args_list[0][1]['amount'] == order_amount
assert order['amount'] == 100
assert order['cost'] == 100
assert order['cost'] == order_amount
assert order['filled'] == 100
assert order['remaining'] == 100
+44 -2
View File
@@ -21,7 +21,7 @@ from freqtrade.data.history import get_timerange
from freqtrade.enums import CandleType, ExitType, RunMode
from freqtrade.exceptions import DependencyException, OperationalException
from freqtrade.exchange.exchange import timeframe_to_next_date
from freqtrade.optimize.backtest_caching import get_strategy_run_id
from freqtrade.optimize.backtest_caching import get_backtest_metadata_filename, get_strategy_run_id
from freqtrade.optimize.backtesting import Backtesting
from freqtrade.persistence import LocalTrade, Trade
from freqtrade.resolvers import StrategyResolver
@@ -601,6 +601,9 @@ def test_backtest__enter_trade_futures(default_conf_usdt, fee, mocker) -> None:
trade = backtesting._enter_trade(pair, row=row, direction='short')
assert pytest.approx(trade.liquidation_price) == 0.11787191
assert pytest.approx(trade.orders[0].cost) == (
trade.stake_amount * trade.leverage + trade.fee_open)
assert pytest.approx(trade.orders[-1].stake_amount) == trade.stake_amount
# Stake-amount too high!
mocker.patch(f"{EXMS}.get_min_pair_stake_amount", return_value=600.0)
@@ -1437,9 +1440,11 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog, testdatadir):
strattable_mock = MagicMock()
strat_summary = MagicMock()
mocker.patch.multiple('freqtrade.optimize.optimize_reports',
mocker.patch.multiple('freqtrade.optimize.optimize_reports.bt_output',
text_table_bt_results=text_table_mock,
text_table_strategy=strattable_mock,
)
mocker.patch.multiple('freqtrade.optimize.optimize_reports.optimize_reports',
generate_pair_metrics=MagicMock(),
generate_exit_reason_stats=sell_reason_mock,
generate_strategy_comparison=strat_summary,
@@ -1993,3 +1998,40 @@ def test_get_strategy_run_id(default_conf_usdt):
strategy = StrategyResolver.load_strategy(default_conf_usdt)
x = get_strategy_run_id(strategy)
assert isinstance(x, str)
def test_get_backtest_metadata_filename():
# Test with a file path
filename = Path('backtest_results.json')
expected = Path('backtest_results.meta.json')
assert get_backtest_metadata_filename(filename) == expected
# Test with a file path with multiple dots in the name
filename = Path('/path/to/backtest.results.json')
expected = Path('/path/to/backtest.results.meta.json')
assert get_backtest_metadata_filename(filename) == expected
# Test with a file path with no parent directory
filename = Path('backtest_results.json')
expected = Path('backtest_results.meta.json')
assert get_backtest_metadata_filename(filename) == expected
# Test with a string file path
filename = '/path/to/backtest_results.json'
expected = Path('/path/to/backtest_results.meta.json')
assert get_backtest_metadata_filename(filename) == expected
# Test with a string file path with no extension
filename = '/path/to/backtest_results'
expected = Path('/path/to/backtest_results.meta')
assert get_backtest_metadata_filename(filename) == expected
# Test with a string file path with multiple dots in the name
filename = '/path/to/backtest.results.json'
expected = Path('/path/to/backtest.results.meta.json')
assert get_backtest_metadata_filename(filename) == expected
# Test with a string file path with no parent directory
filename = 'backtest_results.json'
expected = Path('backtest_results.meta.json')
assert get_backtest_metadata_filename(filename) == expected
+37 -7
View File
@@ -14,15 +14,17 @@ from freqtrade.data.btanalysis import (get_latest_backtest_filename, load_backte
load_backtest_stats)
from freqtrade.edge import PairInfo
from freqtrade.enums import ExitType
from freqtrade.optimize.optimize_reports import (_get_resample_from_period, generate_backtest_stats,
generate_daily_stats, generate_edge_table,
generate_exit_reason_stats, generate_pair_metrics,
from freqtrade.optimize.optimize_reports import (generate_backtest_stats, generate_daily_stats,
generate_edge_table, generate_exit_reason_stats,
generate_pair_metrics,
generate_periodic_breakdown_stats,
generate_strategy_comparison,
generate_trading_stats, show_sorted_pairlist,
store_backtest_analysis_results,
store_backtest_stats, text_table_bt_results,
text_table_exit_reason, text_table_strategy)
from freqtrade.optimize.optimize_reports.optimize_reports import (_get_resample_from_period,
calc_streak)
from freqtrade.resolvers.strategy_resolver import StrategyResolver
from freqtrade.util import dt_ts
from freqtrade.util.datetime_helpers import dt_from_ts, dt_utc
@@ -209,9 +211,10 @@ def test_generate_backtest_stats(default_conf, testdatadir, tmpdir):
def test_store_backtest_stats(testdatadir, mocker):
dump_mock = mocker.patch('freqtrade.optimize.optimize_reports.file_dump_json')
dump_mock = mocker.patch('freqtrade.optimize.optimize_reports.bt_storage.file_dump_json')
store_backtest_stats(testdatadir, {'metadata': {}}, '2022_01_01_15_05_13')
data = {'metadata': {}, 'strategy': {}, 'strategy_comparison': []}
store_backtest_stats(testdatadir, data, '2022_01_01_15_05_13')
assert dump_mock.call_count == 3
assert isinstance(dump_mock.call_args_list[0][0][0], Path)
@@ -219,7 +222,7 @@ def test_store_backtest_stats(testdatadir, mocker):
dump_mock.reset_mock()
filename = testdatadir / 'testresult.json'
store_backtest_stats(filename, {'metadata': {}}, '2022_01_01_15_05_13')
store_backtest_stats(filename, data, '2022_01_01_15_05_13')
assert dump_mock.call_count == 3
assert isinstance(dump_mock.call_args_list[0][0][0], Path)
# result will be testdatadir / testresult-<timestamp>.json
@@ -228,7 +231,8 @@ def test_store_backtest_stats(testdatadir, mocker):
def test_store_backtest_candles(testdatadir, mocker):
dump_mock = mocker.patch('freqtrade.optimize.optimize_reports.file_dump_joblib')
dump_mock = mocker.patch(
'freqtrade.optimize.optimize_reports.bt_storage.file_dump_joblib')
candle_dict = {'DefStrat': {'UNITTEST/BTC': pd.DataFrame()}}
@@ -346,6 +350,32 @@ def test_generate_trading_stats(testdatadir):
assert res['losses'] == 0
def test_calc_streak(testdatadir):
df = pd.DataFrame({
'profit_ratio': [0.05, -0.02, -0.03, -0.05, 0.01, 0.02, 0.03, 0.04, -0.02, -0.03],
})
# 4 consecutive wins, 3 consecutive losses
res = calc_streak(df)
assert res == (4, 3)
assert isinstance(res[0], int)
assert isinstance(res[1], int)
# invert situation
df1 = df.copy()
df1['profit_ratio'] = df1['profit_ratio'] * -1
assert calc_streak(df1) == (3, 4)
df_empty = pd.DataFrame({
'profit_ratio': [],
})
assert df_empty.empty
assert calc_streak(df_empty) == (0, 0)
filename = testdatadir / "backtest_results/backtest-result.json"
bt_data = load_backtest_data(filename)
assert calc_streak(bt_data) == (7, 18)
def test_text_table_exit_reason():
results = pd.DataFrame(
+2 -2
View File
@@ -559,14 +559,14 @@ def test_calc_open_close_trade_price(
exit_order = limit_order[trade.exit_side]
oobj = Order.parse_from_ccxt_object(entry_order, 'ADA/USDT', trade.entry_side)
oobj.trade = trade
oobj._trade_live = trade
oobj.update_from_ccxt_object(entry_order)
trade.update_trade(oobj)
trade.funding_fees = funding_fees
oobj = Order.parse_from_ccxt_object(exit_order, 'ADA/USDT', trade.exit_side)
oobj.trade = trade
oobj._trade_live = trade
oobj.update_from_ccxt_object(exit_order)
trade.update_trade(oobj)
+8 -2
View File
@@ -1,8 +1,11 @@
from datetime import datetime, timezone
import pytest
from freqtrade.persistence.trade_model import Trade
@pytest.mark.usefixtures("init_persistence")
def test_trade_fromjson():
"""Test the Trade.from_json() method."""
trade_string = """{
@@ -168,14 +171,17 @@ def test_trade_fromjson():
]
}"""
trade = Trade.from_json(trade_string)
Trade.session.add(trade)
Trade.commit()
assert trade.id == 25
assert trade.pair == 'ETH/USDT'
assert trade.open_date == datetime(2022, 10, 18, 9, 12, 42, tzinfo=timezone.utc)
assert trade.open_date_utc == datetime(2022, 10, 18, 9, 12, 42, tzinfo=timezone.utc)
assert isinstance(trade.open_date, datetime)
assert trade.exit_reason == 'no longer good'
assert trade.realized_profit == 2.76315361
assert len(trade.orders) == 5
last_o = trade.orders[-1]
assert last_o.order_filled_date == datetime(2022, 10, 18, 9, 45, 22, tzinfo=timezone.utc)
assert last_o.order_filled_utc == datetime(2022, 10, 18, 9, 45, 22, tzinfo=timezone.utc)
assert isinstance(last_o.order_date, datetime)
+4
View File
@@ -1200,6 +1200,10 @@ def test_spreadfilter_invalid_data(mocker, default_conf, markets, tickers, caplo
"[{'ProducerPairList': 'ProducerPairList - default'}]",
None
),
({"method": "RemotePairList", "number_assets": 10, "pairlist_url": "https://example.com"},
"[{'RemotePairList': 'RemotePairList - 10 pairs from RemotePairlist.'}]",
None
),
])
def test_pricefilter_desc(mocker, whitelist_conf, markets, pairlistconfig,
desc_expected, exception_expected):
+161 -4
View File
@@ -1,5 +1,5 @@
import json
from unittest.mock import MagicMock
from unittest.mock import MagicMock, PropertyMock
import pytest
import requests
@@ -7,7 +7,7 @@ import requests
from freqtrade.exceptions import OperationalException
from freqtrade.plugins.pairlist.RemotePairList import RemotePairList
from freqtrade.plugins.pairlistmanager import PairListManager
from tests.conftest import get_patched_exchange, get_patched_freqtradebot, log_has
from tests.conftest import EXMS, get_patched_exchange, get_patched_freqtradebot, log_has
@pytest.fixture(scope="function")
@@ -16,11 +16,12 @@ def rpl_config(default_conf):
default_conf['exchange']['pair_whitelist'] = [
'ETH/USDT',
'BTC/USDT',
'XRP/USDT',
]
default_conf['exchange']['pair_blacklist'] = [
'BLK/USDT'
]
return default_conf
@@ -34,7 +35,7 @@ def test_gen_pairlist_with_local_file(mocker, rpl_config):
mock_file_path.exists.return_value = True
jsonparse = json.loads(mock_file.read.return_value)
mocker.patch('freqtrade.plugins.pairlist.RemotePairList.json.load', return_value=jsonparse)
mocker.patch('freqtrade.plugins.pairlist.RemotePairList.rapidjson.load', return_value=jsonparse)
rpl_config['pairlists'] = [
{
@@ -183,3 +184,159 @@ def test_fetch_pairlist_mock_response_valid(mocker, rpl_config):
assert pairs == ["ETH/USDT", "XRP/USDT", "LTC/USDT", "EOS/USDT"]
assert time_elapsed == 0.4
assert remote_pairlist._refresh_period == 60
def test_remote_pairlist_init_wrong_mode(mocker, rpl_config):
rpl_config['pairlists'] = [
{
"method": "RemotePairList",
"mode": "blacklis",
"number_assets": 20,
"pairlist_url": "http://example.com/pairlist",
"keep_pairlist_on_failure": True,
}
]
with pytest.raises(
OperationalException,
match=r'`mode` not configured correctly. Supported Modes are "whitelist","blacklist"'
):
get_patched_freqtradebot(mocker, rpl_config)
rpl_config['pairlists'] = [
{
"method": "RemotePairList",
"mode": "blacklist",
"number_assets": 20,
"pairlist_url": "http://example.com/pairlist",
"keep_pairlist_on_failure": True,
}
]
with pytest.raises(
OperationalException,
match=r'A `blacklist` mode RemotePairList can not be.*first.*'
):
get_patched_freqtradebot(mocker, rpl_config)
def test_remote_pairlist_init_wrong_proc_mode(mocker, rpl_config):
rpl_config['pairlists'] = [
{
"method": "RemotePairList",
"processing_mode": "filler",
"mode": "whitelist",
"number_assets": 20,
"pairlist_url": "http://example.com/pairlist",
"keep_pairlist_on_failure": True,
}
]
get_patched_exchange(mocker, rpl_config)
with pytest.raises(
OperationalException,
match=r'`processing_mode` not configured correctly. Supported Modes are "filter","append"'
):
get_patched_freqtradebot(mocker, rpl_config)
def test_remote_pairlist_blacklist(mocker, rpl_config, caplog, markets, tickers):
mock_response = MagicMock()
mock_response.json.return_value = {
"pairs": ["XRP/USDT"],
"refresh_period": 60
}
mock_response.headers = {
"content-type": "application/json"
}
rpl_config['pairlists'] = [
{
"method": "StaticPairList",
},
{
"method": "RemotePairList",
"mode": "blacklist",
"pairlist_url": "http://example.com/pairlist",
"number_assets": 3
}
]
mocker.patch.multiple(EXMS,
markets=PropertyMock(return_value=markets),
exchange_has=MagicMock(return_value=True),
get_tickers=tickers
)
mocker.patch("freqtrade.plugins.pairlist.RemotePairList.requests.get",
return_value=mock_response)
exchange = get_patched_exchange(mocker, rpl_config)
pairlistmanager = PairListManager(exchange, rpl_config)
remote_pairlist = RemotePairList(exchange, pairlistmanager, rpl_config,
rpl_config["pairlists"][1], 1)
pairs, time_elapsed = remote_pairlist.fetch_pairlist()
assert pairs == ["XRP/USDT"]
whitelist = remote_pairlist.filter_pairlist(rpl_config['exchange']['pair_whitelist'], {})
assert whitelist == ["ETH/USDT"]
assert log_has(f"Blacklist - Filtered out pairs: {pairs}", caplog)
@pytest.mark.parametrize("processing_mode", ["filter", "append"])
def test_remote_pairlist_whitelist(mocker, rpl_config, processing_mode, markets, tickers):
mock_response = MagicMock()
mock_response.json.return_value = {
"pairs": ["XRP/USDT"],
"refresh_period": 60
}
mock_response.headers = {
"content-type": "application/json"
}
rpl_config['pairlists'] = [
{
"method": "StaticPairList",
},
{
"method": "RemotePairList",
"mode": "whitelist",
"processing_mode": processing_mode,
"pairlist_url": "http://example.com/pairlist",
"number_assets": 3
}
]
mocker.patch.multiple(EXMS,
markets=PropertyMock(return_value=markets),
exchange_has=MagicMock(return_value=True),
get_tickers=tickers
)
mocker.patch("freqtrade.plugins.pairlist.RemotePairList.requests.get",
return_value=mock_response)
exchange = get_patched_exchange(mocker, rpl_config)
pairlistmanager = PairListManager(exchange, rpl_config)
remote_pairlist = RemotePairList(exchange, pairlistmanager, rpl_config,
rpl_config["pairlists"][1], 1)
pairs, time_elapsed = remote_pairlist.fetch_pairlist()
assert pairs == ["XRP/USDT"]
whitelist = remote_pairlist.filter_pairlist(rpl_config['exchange']['pair_whitelist'], {})
assert whitelist == (["XRP/USDT"] if processing_mode == "filter" else ['ETH/USDT', 'XRP/USDT'])
+6 -1
View File
@@ -96,7 +96,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None:
'order_date': ANY, 'order_timestamp': ANY, 'order_filled_date': ANY,
'order_filled_timestamp': ANY, 'order_type': 'limit', 'price': 1.098e-05,
'is_open': False, 'pair': 'ETH/BTC', 'order_id': ANY,
'remaining': ANY, 'status': ANY, 'ft_is_entry': True,
'remaining': ANY, 'status': ANY, 'ft_is_entry': True, 'ft_fee_base': None,
}],
}
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
@@ -401,6 +401,8 @@ def test_rpc_trade_statistics(default_conf_usdt, ticker, fee, mocker) -> None:
assert res['first_trade_timestamp'] == 0
assert res['latest_trade_date'] == ''
assert res['latest_trade_timestamp'] == 0
assert res['expectancy'] == 0
assert res['expectancy_ratio'] == 100
# Create some test data
create_mock_trades_usdt(fee)
@@ -412,6 +414,9 @@ def test_rpc_trade_statistics(default_conf_usdt, ticker, fee, mocker) -> None:
assert pytest.approx(stats['profit_all_coin']) == -77.45964918
assert pytest.approx(stats['profit_all_percent_mean']) == -57.86
assert pytest.approx(stats['profit_all_fiat']) == -85.205614098
assert pytest.approx(stats['winrate']) == 0.666666667
assert pytest.approx(stats['expectancy']) == 0.913333333
assert pytest.approx(stats['expectancy_ratio']) == 0.223308883
assert stats['trade_count'] == 7
assert stats['first_trade_humanized'] == '2 days ago'
assert stats['latest_trade_humanized'] == '17 minutes ago'
+73 -17
View File
@@ -829,7 +829,8 @@ def test_api_edge_disabled(botclient, mocker, ticker, fee, markets):
'profit_closed_percent_mean': -0.75, 'profit_closed_ratio_sum': -0.015,
'profit_closed_percent_sum': -1.5, 'profit_closed_ratio': -6.739057628404269e-06,
'profit_closed_percent': -0.0, 'winning_trades': 0, 'losing_trades': 2,
'profit_factor': 0.0, 'trading_volume': 91.074,
'profit_factor': 0.0, 'winrate': 0.0, 'expectancy': -0.0033695635,
'expectancy_ratio': -1.0, 'trading_volume': 91.074,
}
),
(
@@ -844,7 +845,8 @@ def test_api_edge_disabled(botclient, mocker, ticker, fee, markets):
'profit_closed_percent_mean': 0.75, 'profit_closed_ratio_sum': 0.015,
'profit_closed_percent_sum': 1.5, 'profit_closed_ratio': 7.391275897987988e-07,
'profit_closed_percent': 0.0, 'winning_trades': 2, 'losing_trades': 0,
'profit_factor': None, 'trading_volume': 91.074,
'profit_factor': None, 'winrate': 1.0, 'expectancy': 0.0003695635,
'expectancy_ratio': 100, 'trading_volume': 91.074,
}
),
(
@@ -859,7 +861,9 @@ def test_api_edge_disabled(botclient, mocker, ticker, fee, markets):
'profit_closed_percent_mean': 0.25, 'profit_closed_ratio_sum': 0.005,
'profit_closed_percent_sum': 0.5, 'profit_closed_ratio': -5.429078808526421e-06,
'profit_closed_percent': -0.0, 'winning_trades': 1, 'losing_trades': 1,
'profit_factor': 0.02775724835771106, 'trading_volume': 91.074,
'profit_factor': 0.02775724835771106, 'winrate': 0.5,
'expectancy': -0.0027145635000000003, 'expectancy_ratio': -0.48612137582114445,
'trading_volume': 91.074,
}
)
])
@@ -916,6 +920,9 @@ def test_api_profit(botclient, mocker, ticker, fee, markets, is_short, expected)
'winning_trades': expected['winning_trades'],
'losing_trades': expected['losing_trades'],
'profit_factor': expected['profit_factor'],
'winrate': expected['winrate'],
'expectancy': expected['expectancy'],
'expectancy_ratio': expected['expectancy_ratio'],
'max_drawdown': ANY,
'max_drawdown_abs': ANY,
'trading_volume': expected['trading_volume'],
@@ -1464,30 +1471,47 @@ def test_api_pair_history(botclient, mocker):
"&timerange=20180111-20180112")
assert_response(rc, 422)
# Invalid strategy
rc = client_get(client,
f"{BASE_URI}/pair_history?pair=UNITTEST%2FBTC&timeframe={timeframe}"
"&timerange=20180111-20180112&strategy={CURRENT_TEST_STRATEGY}11")
assert_response(rc, 502)
# Working
rc = client_get(client,
f"{BASE_URI}/pair_history?pair=UNITTEST%2FBTC&timeframe={timeframe}"
f"&timerange=20180111-20180112&strategy={CURRENT_TEST_STRATEGY}")
assert_response(rc, 200)
assert rc.json()['length'] == 289
assert len(rc.json()['data']) == rc.json()['length']
assert 'columns' in rc.json()
assert 'data' in rc.json()
result = rc.json()
assert result['length'] == 289
assert len(result['data']) == result['length']
assert 'columns' in result
assert 'data' in result
data = result['data']
assert len(data) == 289
# analyed DF has 28 columns
assert len(result['columns']) == 28
assert len(data[0]) == 28
date_col_idx = [idx for idx, c in enumerate(result['columns']) if c == 'date'][0]
rsi_col_idx = [idx for idx, c in enumerate(result['columns']) if c == 'rsi'][0]
assert data[0][date_col_idx] == '2018-01-11 00:00:00'
assert data[0][rsi_col_idx] is not None
assert data[0][rsi_col_idx] > 0
assert lfm.call_count == 1
assert rc.json()['pair'] == 'UNITTEST/BTC'
assert rc.json()['strategy'] == CURRENT_TEST_STRATEGY
assert rc.json()['data_start'] == '2018-01-11 00:00:00+00:00'
assert rc.json()['data_start_ts'] == 1515628800000
assert rc.json()['data_stop'] == '2018-01-12 00:00:00+00:00'
assert rc.json()['data_stop_ts'] == 1515715200000
assert result['pair'] == 'UNITTEST/BTC'
assert result['strategy'] == CURRENT_TEST_STRATEGY
assert result['data_start'] == '2018-01-11 00:00:00+00:00'
assert result['data_start_ts'] == 1515628800000
assert result['data_stop'] == '2018-01-12 00:00:00+00:00'
assert result['data_stop_ts'] == 1515715200000
# No data found
rc = client_get(client,
f"{BASE_URI}/pair_history?pair=UNITTEST%2FBTC&timeframe={timeframe}"
f"&timerange=20200111-20200112&strategy={CURRENT_TEST_STRATEGY}")
assert_response(rc, 502)
assert rc.json()['error'] == ("Error querying /api/v1/pair_history: "
"No data for UNITTEST/BTC, 5m in 20200111-20200112 found.")
assert rc.json()['detail'] == ("No data for UNITTEST/BTC, 5m in 20200111-20200112 found.")
def test_api_plot_config(botclient, mocker):
@@ -1524,6 +1548,10 @@ def test_api_plot_config(botclient, mocker):
assert_response(rc)
assert rc.json()['subplots'] == {}
rc = client_get(client, f"{BASE_URI}/plot_config?strategy=NotAStrategy")
assert_response(rc, 502)
assert rc.json()['detail'] is not None
mocker.patch('freqtrade.rpc.api_server.api_v1.get_rpc_optional', return_value=None)
rc = client_get(client, f"{BASE_URI}/plot_config")
@@ -1774,7 +1802,7 @@ def test_list_available_pairs(botclient):
rc = client_get(client, f"{BASE_URI}/available_pairs")
assert_response(rc)
assert rc.json()['length'] == 13
assert rc.json()['length'] == 12
assert isinstance(rc.json()['pairs'], list)
rc = client_get(client, f"{BASE_URI}/available_pairs?timeframe=5m")
@@ -1976,7 +2004,7 @@ def test_api_backtest_history(botclient, mocker, testdatadir):
result = rc.json()
assert len(result) == 3
fn = result[0]['filename']
assert fn == "backtest-result_multistrat.json"
assert fn == "backtest-result_multistrat"
strategy = result[0]['strategy']
rc = client_get(client, f"{BASE_URI}/backtest/history/result?filename={fn}&strategy={strategy}")
assert_response(rc)
@@ -1990,6 +2018,34 @@ def test_api_backtest_history(botclient, mocker, testdatadir):
assert result2['backtest_result']['strategy'][strategy]
def test_api_delete_backtest_history_entry(botclient, mocker, tmp_path: Path):
ftbot, client = botclient
# Create a temporary directory and file
bt_results_base = tmp_path / "backtest_results"
bt_results_base.mkdir()
file_path = bt_results_base / "test.json"
file_path.touch()
meta_path = file_path.with_suffix('.meta.json')
meta_path.touch()
rc = client_delete(client, f"{BASE_URI}/backtest/history/randomFile.json")
assert_response(rc, 503)
assert rc.json()['detail'] == 'Bot is not in the correct state.'
ftbot.config['user_data_dir'] = tmp_path
ftbot.config['runmode'] = RunMode.WEBSERVER
rc = client_delete(client, f"{BASE_URI}/backtest/history/randomFile.json")
assert rc.status_code == 404
assert rc.json()['detail'] == 'File not found.'
rc = client_delete(client, f"{BASE_URI}/backtest/history/{file_path.name}")
assert rc.status_code == 200
assert not file_path.exists()
assert not meta_path.exists()
def test_health(botclient):
ftbot, client = botclient
+2
View File
@@ -799,6 +799,8 @@ async def test_telegram_profit_handle(
assert '*Best Performing:* `ETH/USDT: 9.45%`' in msg_mock.call_args_list[-1][0][0]
assert '*Max Drawdown:*' in msg_mock.call_args_list[-1][0][0]
assert '*Profit factor:*' in msg_mock.call_args_list[-1][0][0]
assert '*Winrate:*' in msg_mock.call_args_list[-1][0][0]
assert '*Expectancy (Ratio):*' in msg_mock.call_args_list[-1][0][0]
assert '*Trading volume:* `126 USDT`' in msg_mock.call_args_list[-1][0][0]
+7 -3
View File
@@ -381,7 +381,7 @@ def test__send_msg(default_conf, mocker, caplog):
webhook._send_msg(msg)
assert post.call_count == 1
assert post.call_args[1] == {'data': msg}
assert post.call_args[1] == {'data': msg, 'timeout': 10}
assert post.call_args[0] == (default_conf['webhook']['url'], )
post = MagicMock(side_effect=RequestException)
@@ -399,7 +399,7 @@ def test__send_msg_with_json_format(default_conf, mocker, caplog):
mocker.patch("freqtrade.rpc.webhook.post", post)
webhook._send_msg(msg)
assert post.call_args[1] == {'json': msg}
assert post.call_args[1] == {'json': msg, 'timeout': 10}
def test__send_msg_with_raw_format(default_conf, mocker, caplog):
@@ -411,7 +411,11 @@ def test__send_msg_with_raw_format(default_conf, mocker, caplog):
mocker.patch("freqtrade.rpc.webhook.post", post)
webhook._send_msg(msg)
assert post.call_args[1] == {'data': msg['data'], 'headers': {'Content-Type': 'text/plain'}}
assert post.call_args[1] == {
'data': msg['data'],
'headers': {'Content-Type': 'text/plain'},
'timeout': 10
}
def test_send_msg_discord(default_conf, mocker):
+4 -4
View File
@@ -21,10 +21,10 @@ def test_binance_mig_data_conversion(default_conf_usdt, tmpdir, testdatadir):
futures_dst = tmpdir / 'futures'
futures_dst.mkdir()
files = [
'-1h-mark.json',
'-1h-futures.json',
'-8h-funding_rate.json',
'-8h-mark.json',
'-1h-mark.feather',
'-1h-futures.feather',
'-8h-funding_rate.feather',
'-8h-mark.feather',
]
# Copy files to tmpdir and rename to old naming
+57 -3
View File
@@ -2788,7 +2788,7 @@ def test_manage_open_orders_entry(
freqtrade.strategy.check_entry_timeout = MagicMock(return_value=False)
freqtrade.strategy.adjust_entry_price = MagicMock(return_value=1234)
# check it does cancel buy orders over the time limit
# check it does cancel entry orders over the time limit
freqtrade.manage_open_orders()
assert cancel_order_mock.call_count == 1
assert rpc_mock.call_count == 2
@@ -2800,7 +2800,7 @@ def test_manage_open_orders_entry(
).all()
nb_trades = len(trades)
assert nb_trades == 0
# Custom user buy-timeout is never called
# Custom user entry-timeout is never called
assert freqtrade.strategy.check_entry_timeout.call_count == 0
# Entry adjustment is never called
assert freqtrade.strategy.adjust_entry_price.call_count == 0
@@ -5048,7 +5048,7 @@ def test_get_real_amount_in_point(default_conf_usdt, buy_order_fee, fee, mocker,
(8.0, 0.1, 8.0, None),
(8.0, 0.1, 7.9, 0.1),
])
def test_apply_fee_conditional(default_conf_usdt, fee, mocker,
def test_apply_fee_conditional(default_conf_usdt, fee, mocker, caplog,
amount, fee_abs, wallet, amount_exp):
walletmock = mocker.patch('freqtrade.wallets.Wallets.update')
mocker.patch('freqtrade.wallets.Wallets.get_free', return_value=wallet)
@@ -5073,6 +5073,60 @@ def test_apply_fee_conditional(default_conf_usdt, fee, mocker,
# Amount is kept as is
assert freqtrade.apply_fee_conditional(trade, 'LTC', amount, fee_abs, order) == amount_exp
assert walletmock.call_count == 1
if fee_abs != 0 and amount_exp is None:
assert log_has_re(r"Fee amount.*Eating.*dust\.", caplog)
@pytest.mark.parametrize('amount,fee_abs,wallet,amount_exp', [
(8.0, 0.0, 16, None),
(8.0, 0.0, 0, None),
(8.0, 0.1, 8, 0.1),
(8.0, 0.1, 20, None),
(8.0, 0.1, 16.0, None),
(8.0, 0.1, 7.9, 0.1),
(8.0, 0.1, 12, 0.1),
(8.0, 0.1, 15.9, 0.1),
])
def test_apply_fee_conditional_multibuy(default_conf_usdt, fee, mocker, caplog,
amount, fee_abs, wallet, amount_exp):
walletmock = mocker.patch('freqtrade.wallets.Wallets.update')
mocker.patch('freqtrade.wallets.Wallets.get_free', return_value=wallet)
trade = Trade(
pair='LTC/ETH',
amount=amount,
exchange='binance',
open_rate=0.245441,
fee_open=fee.return_value,
fee_close=fee.return_value,
open_order_id="123456"
)
# One closed order
order = Order(
ft_order_side='buy',
order_id='10',
ft_pair=trade.pair,
ft_is_open=False,
filled=amount,
status="closed"
)
trade.orders.append(order)
# Add additional order - this should NOT eat into dust unless the wallet was bigger already.
order1 = Order(
ft_order_side='buy',
order_id='100',
ft_pair=trade.pair,
ft_is_open=True,
)
trade.orders.append(order1)
freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
walletmock.reset_mock()
# The new trade amount will be 2x amount - fee / wallet will have to be adapted to this.
assert freqtrade.apply_fee_conditional(trade, 'LTC', amount, fee_abs, order1) == amount_exp
assert walletmock.call_count == 1
if fee_abs != 0 and amount_exp is None:
assert log_has_re(r"Fee amount.*Eating.*dust\.", caplog)
@pytest.mark.parametrize("delta, is_high_delta", [
+53 -2
View File
@@ -429,6 +429,7 @@ def test_dca_order_adjust(default_conf_usdt, ticker_usdt, leverage, fee, mocker)
assert pytest.approx(trade.stop_loss) == 1.99 * (1 - 0.1 / leverage)
assert pytest.approx(trade.initial_stop_loss) == 1.96 * (1 - 0.1 / leverage)
assert trade.initial_stop_loss_pct == -0.1
assert pytest.approx(trade.orders[-1].stake_amount) == trade.stake_amount
# 2nd order - not filling
freqtrade.strategy.adjust_trade_position = MagicMock(return_value=120)
@@ -473,13 +474,38 @@ def test_dca_order_adjust(default_conf_usdt, ticker_usdt, leverage, fee, mocker)
assert pytest.approx(trade.orders[1].amount) == 30.150753768 * leverage
assert pytest.approx(trade.orders[-1].amount) == 61.538461232 * leverage
# Full exit
mocker.patch(f'{EXMS}._dry_is_price_crossed', return_value=False)
freqtrade.strategy.custom_exit = MagicMock(return_value='Exit now')
freqtrade.strategy.adjust_entry_price = MagicMock(return_value=2.02)
freqtrade.process()
trade = Trade.get_trades().first()
assert len(trade.orders) == 5
assert trade.orders[-1].side == trade.exit_side
assert trade.orders[-1].status == 'open'
assert trade.orders[-1].price == 2.02
assert pytest.approx(trade.amount) == 91.689215 * leverage
assert pytest.approx(trade.orders[-1].amount) == 91.689215 * leverage
assert freqtrade.strategy.adjust_entry_price.call_count == 0
# Process again, should not adjust entry price
freqtrade.process()
trade = Trade.get_trades().first()
assert len(trade.orders) == 5
assert trade.orders[-1].status == 'open'
assert trade.orders[-1].price == 2.02
# Adjust entry price cannot be called - this is an exit order
assert freqtrade.strategy.adjust_entry_price.call_count == 0
@pytest.mark.parametrize('leverage', [1, 2])
def test_dca_exiting(default_conf_usdt, ticker_usdt, fee, mocker, caplog, leverage) -> None:
default_conf_usdt['position_adjustment_enable'] = True
spot = leverage == 1
if not spot:
default_conf_usdt['trading_mode'] = 'futures'
default_conf_usdt['margin_mode'] = 'isolated'
freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
freqtrade.trading_mode = TradingMode.FUTURES
assert freqtrade.trading_mode == TradingMode.FUTURES if not spot else TradingMode.SPOT
mocker.patch.multiple(
EXMS,
fetch_ticker=ticker_usdt,
@@ -487,8 +513,11 @@ def test_dca_exiting(default_conf_usdt, ticker_usdt, fee, mocker, caplog, levera
amount_to_precision=lambda s, x, y: y,
price_to_precision=lambda s, x, y: y,
get_min_pair_stake_amount=MagicMock(return_value=10),
get_funding_fees=MagicMock(return_value=0),
)
mocker.patch(f"{EXMS}.get_max_leverage", return_value=10)
starting_amount = freqtrade.wallets.get_total('USDT')
assert starting_amount == 1000
patch_get_signal(freqtrade)
freqtrade.strategy.leverage = MagicMock(return_value=leverage)
@@ -498,8 +527,14 @@ def test_dca_exiting(default_conf_usdt, ticker_usdt, fee, mocker, caplog, levera
trade = Trade.get_trades().first()
assert len(trade.orders) == 1
assert pytest.approx(trade.stake_amount) == 60
assert trade.leverage == leverage
assert pytest.approx(trade.amount) == 30.0 * leverage
assert trade.open_rate == 2.0
assert pytest.approx(freqtrade.wallets.get_free('USDT')) == starting_amount - 60
if spot:
assert pytest.approx(freqtrade.wallets.get_total('USDT')) == starting_amount - 60
else:
assert freqtrade.wallets.get_total('USDT') == starting_amount
# Too small size
freqtrade.strategy.adjust_trade_position = MagicMock(return_value=-59)
@@ -521,6 +556,15 @@ def test_dca_exiting(default_conf_usdt, ticker_usdt, fee, mocker, caplog, levera
assert pytest.approx(trade.amount) == 20.099 * leverage
assert trade.open_rate == 2.0
assert trade.is_open
assert trade.realized_profit > 0.098 * leverage
expected_profit = starting_amount - 40.1980 + trade.realized_profit
assert pytest.approx(freqtrade.wallets.get_free('USDT')) == expected_profit
if spot:
assert pytest.approx(freqtrade.wallets.get_total('USDT')) == expected_profit
else:
# total won't change in futures mode, only free / used will.
assert freqtrade.wallets.get_total('USDT') == starting_amount + trade.realized_profit
caplog.clear()
# Sell more than what we got (we got ~20 coins left)
@@ -545,3 +589,10 @@ def test_dca_exiting(default_conf_usdt, ticker_usdt, fee, mocker, caplog, levera
assert pytest.approx(trade.stake_amount) == 40.198
assert trade.is_open
assert log_has_re('Amount to exit is 0.0 due to exchange limits - not exiting.', caplog)
expected_profit = starting_amount - 40.1980 + trade.realized_profit
assert pytest.approx(freqtrade.wallets.get_free('USDT')) == expected_profit
if spot:
assert pytest.approx(freqtrade.wallets.get_total('USDT')) == expected_profit
else:
# total won't change in futures mode, only free / used will.
assert freqtrade.wallets.get_total('USDT') == starting_amount + trade.realized_profit
+19 -15
View File
@@ -1,6 +1,5 @@
# pragma pylint: disable=missing-docstring,C0103
import datetime
from copy import deepcopy
from pathlib import Path
from unittest.mock import MagicMock
@@ -9,7 +8,7 @@ import pandas as pd
import pytest
from freqtrade.misc import (dataframe_to_json, decimals_per_coin, deep_merge_dicts, file_dump_json,
file_load_json, format_ms_time, json_to_dataframe, pair_to_filename,
file_load_json, is_file_in_dir, json_to_dataframe, pair_to_filename,
parse_db_uri_for_logging, plural, render_template,
render_template_with_fallback, round_coin_value, safe_value_fallback,
safe_value_fallback2)
@@ -65,6 +64,24 @@ def test_file_load_json(mocker, testdatadir) -> None:
assert ret
def test_is_file_in_dir(tmp_path):
# Create a temporary directory and file
dir_path = tmp_path / "subdir"
dir_path.mkdir()
file_path = dir_path / "test.txt"
file_path.touch()
# Test that the function returns True when the file is in the directory
assert is_file_in_dir(file_path, dir_path) is True
# Test that the function returns False when the file is not in the directory
assert is_file_in_dir(file_path, tmp_path) is False
file_path2 = tmp_path / "../../test2.txt"
assert is_file_in_dir(file_path2, tmp_path) is False
@pytest.mark.parametrize("pair,expected_result", [
("ETH/BTC", 'ETH_BTC'),
("ETH/USDT", 'ETH_USDT'),
@@ -91,19 +108,6 @@ def test_pair_to_filename(pair, expected_result):
assert pair_s == expected_result
def test_format_ms_time() -> None:
# Date 2018-04-10 18:02:01
date_in_epoch_ms = 1523383321000
date = format_ms_time(date_in_epoch_ms)
assert type(date) is str
res = datetime.datetime(2018, 4, 10, 18, 2, 1, tzinfo=datetime.timezone.utc)
assert date == res.astimezone(None).strftime('%Y-%m-%dT%H:%M:%S')
res = datetime.datetime(2017, 12, 13, 8, 2, 1, tzinfo=datetime.timezone.utc)
# Date 2017-12-13 08:02:01
date_in_epoch_ms = 1513152121000
assert format_ms_time(date_in_epoch_ms) == res.astimezone(None).strftime('%Y-%m-%dT%H:%M:%S')
def test_safe_value_fallback():
dict1 = {'keya': None, 'keyb': 2, 'keyc': 5, 'keyd': None}
assert safe_value_fallback(dict1, 'keya', 'keyb') == 2
+29 -1
View File
@@ -8,7 +8,8 @@ from sqlalchemy import select
from freqtrade.constants import UNLIMITED_STAKE_AMOUNT
from freqtrade.exceptions import DependencyException
from freqtrade.persistence import Trade
from tests.conftest import EXMS, create_mock_trades, get_patched_freqtradebot, patch_wallet
from tests.conftest import (EXMS, create_mock_trades, create_mock_trades_usdt,
get_patched_freqtradebot, patch_wallet)
def test_sync_wallet_at_boot(mocker, default_conf):
@@ -341,6 +342,33 @@ def test_sync_wallet_futures_live(mocker, default_conf):
assert 'ETH/USDT:USDT' not in freqtrade.wallets._positions
def test_sync_wallet_dry(mocker, default_conf_usdt, fee):
default_conf_usdt['dry_run'] = True
freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
assert len(freqtrade.wallets._wallets) == 1
assert len(freqtrade.wallets._positions) == 0
assert freqtrade.wallets.get_total('USDT') == 1000
create_mock_trades_usdt(fee, is_short=None)
freqtrade.wallets.update()
assert len(freqtrade.wallets._wallets) == 5
assert len(freqtrade.wallets._positions) == 0
bal = freqtrade.wallets.get_all_balances()
assert bal['NEO'].total == 10
assert bal['XRP'].total == 10
assert bal['LTC'].total == 2
assert bal['USDT'].total == 922.74
assert freqtrade.wallets.get_starting_balance() == default_conf_usdt['dry_run_wallet']
total = freqtrade.wallets.get_total('LTC')
free = freqtrade.wallets.get_free('LTC')
used = freqtrade.wallets.get_used('LTC')
assert free != 0
assert free + used == total
def test_sync_wallet_futures_dry(mocker, default_conf, fee):
default_conf['dry_run'] = True
default_conf['trading_mode'] = 'futures'
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
-102
View File
@@ -1,102 +0,0 @@
[
[1636959600000, 1.21431, 1.2198, 1.20895, 1.20895, null],
[1636963200000, 1.20902, 1.21106, 1.19972, 1.20968, null],
[1636966800000, 1.20968, 1.21876, 1.20791, 1.20998, null],
[1636970400000, 1.20999, 1.21043, 1.20442, 1.20859, null],
[1636974000000, 1.20858, 1.20933, 1.20154, 1.20581, null],
[1636977600000, 1.20584, 1.20775, 1.20065, 1.20337, null],
[1636981200000, 1.20342, 1.2097, 1.19327, 1.19792, null],
[1636984800000, 1.19796, 1.1982, 1.18611, 1.19024, null],
[1636988400000, 1.19025, 1.19177, 1.18373, 1.18771, null],
[1636992000000, 1.18768, 1.19109, 1.18095, 1.1887, null],
[1636995600000, 1.18869, 1.18968, 1.18355, 1.18387, null],
[1636999200000, 1.18388, 1.18729, 1.17753, 1.18138, null],
[1637002800000, 1.18145, 1.18684, 1.17799, 1.18463, null],
[1637006400000, 1.18464, 1.18474, 1.17368, 1.17652, null],
[1637010000000, 1.17653, 1.18185, 1.16557, 1.17979, null],
[1637013600000, 1.17979, 1.18113, 1.16934, 1.18014, null],
[1637017200000, 1.18014, 1.18015, 1.16999, 1.17214, null],
[1637020800000, 1.17214, 1.17217, 1.12958, 1.14209, null],
[1637024400000, 1.14255, 1.14666, 1.10933, 1.14198, null],
[1637028000000, 1.14197, 1.14419, 1.12766, 1.12999, null],
[1637031600000, 1.12999, 1.13522, 1.11142, 1.12177, null],
[1637035200000, 1.12176, 1.13211, 1.10579, 1.1288, null],
[1637038800000, 1.12871, 1.13243, 1.12142, 1.12316, null],
[1637042400000, 1.12323, 1.1262, 1.11489, 1.12429, null],
[1637046000000, 1.12406, 1.12727, 1.11835, 1.1249, null],
[1637049600000, 1.12485, 1.13047, 1.1211, 1.12931, null],
[1637053200000, 1.12931, 1.13346, 1.10256, 1.10267, null],
[1637056800000, 1.10266, 1.10412, 1.04149, 1.0928, null],
[1637060400000, 1.09277, 1.09856, 1.08371, 1.09093, null],
[1637064000000, 1.09094, 1.09512, 1.079, 1.08003, null],
[1637067600000, 1.0802, 1.09914, 1.08016, 1.09515, null],
[1637071200000, 1.09518, 1.11627, 1.0937, 1.10985, null],
[1637074800000, 1.10985, 1.11353, 1.09618, 1.10071, null],
[1637078400000, 1.09989, 1.10852, 1.09763, 1.10461, null],
[1637082000000, 1.10459, 1.10837, 1.09662, 1.09847, null],
[1637085600000, 1.09858, 1.10506, 1.08687, 1.08716, null],
[1637089200000, 1.08677, 1.10096, 1.08151, 1.09271, null],
[1637092800000, 1.09245, 1.09269, 1.06592, 1.08025, null],
[1637096400000, 1.08026, 1.09732, 1.07953, 1.09527, null],
[1637100000000, 1.09527, 1.10506, 1.09524, 1.09933, null],
[1637103600000, 1.09933, 1.10205, 1.08761, 1.08785, null],
[1637107200000, 1.08763, 1.09518, 1.07646, 1.07999, null],
[1637110800000, 1.07997, 1.0978, 1.07651, 1.07936, null],
[1637114400000, 1.07932, 1.08758, 1.07352, 1.07603, null],
[1637118000000, 1.07604, 1.08542, 1.05931, 1.06764, null],
[1637121600000, 1.06788, 1.07848, 1.06045, 1.07608, null],
[1637125200000, 1.07613, 1.08797, 1.07293, 1.08377, null],
[1637128800000, 1.08379, 1.08567, 1.07428, 1.07942, null],
[1637132400000, 1.07958, 1.09472, 1.07356, 1.08713, null],
[1637136000000, 1.08714, 1.09149, 1.08018, 1.08021, null],
[1637139600000, 1.08021, 1.08021, 1.0668, 1.07032, null],
[1637143200000, 1.07042, 1.10563, 1.07034, 1.10255, null],
[1637146800000, 1.10284, 1.10954, 1.09767, 1.10685, null],
[1637150400000, 1.10669, 1.10848, 1.10157, 1.10537, null],
[1637154000000, 1.10537, 1.11263, 1.09554, 1.09585, null],
[1637157600000, 1.09569, 1.10051, 1.08402, 1.08431, null],
[1637161200000, 1.08444, 1.08942, 1.07569, 1.08489, null],
[1637164800000, 1.08498, 1.09581, 1.07939, 1.09485, null],
[1637168400000, 1.09443, 1.09793, 1.08778, 1.0944, null],
[1637172000000, 1.09445, 1.10227, 1.09376, 1.0992, null],
[1637175600000, 1.0992, 1.10189, 1.09216, 1.09474, null],
[1637179200000, 1.09476, 1.10198, 1.09045, 1.0993, null],
[1637182800000, 1.09934, 1.09959, 1.08755, 1.0948, null],
[1637186400000, 1.09483, 1.09519, 1.08532, 1.0923, null],
[1637190000000, 1.0923, 1.09876, 1.0874, 1.095, null],
[1637193600000, 1.09503, 1.10673, 1.09047, 1.10441, null],
[1637197200000, 1.10437, 1.16166, 1.09815, 1.12902, null],
[1637200800000, 1.12875, 1.15094, 1.1242, 1.13764, null],
[1637204400000, 1.13795, 1.14262, 1.12341, 1.12423, null],
[1637208000000, 1.12424, 1.14806, 1.11333, 1.1142, null],
[1637211600000, 1.11435, 1.12608, 1.11085, 1.11436, null],
[1637215200000, 1.11398, 1.11718, 1.10538, 1.11388, null],
[1637218800000, 1.1139, 1.11452, 1.09674, 1.1072, null],
[1637222400000, 1.10725, 1.10999, 1.10209, 1.10706, null],
[1637226000000, 1.10712, 1.10712, 1.07747, 1.08658, null],
[1637229600000, 1.08692, 1.09865, 1.0807, 1.09767, null],
[1637233200000, 1.09768, 1.10211, 1.08348, 1.08409, null],
[1637236800000, 1.08423, 1.09498, 1.08002, 1.08259, null],
[1637240400000, 1.0827, 1.08773, 1.06597, 1.07719, null],
[1637244000000, 1.07718, 1.08075, 1.06678, 1.07077, null],
[1637247600000, 1.07029, 1.07824, 1.04568, 1.05497, null],
[1637251200000, 1.05591, 1.06325, 1.03957, 1.04032, null],
[1637254800000, 1.04051, 1.05342, 1.01557, 1.04158, null],
[1637258400000, 1.04153, 1.05436, 1.04122, 1.05208, null],
[1637262000000, 1.05207, 1.05948, 1.04961, 1.05515, null],
[1637265600000, 1.05516, 1.05927, 1.04767, 1.04808, null],
[1637269200000, 1.04789, 1.05622, 1.04191, 1.04587, null],
[1637272800000, 1.04575, 1.05336, 1.03405, 1.03941, null],
[1637276400000, 1.03931, 1.04614, 1.02868, 1.0411, null],
[1637280000000, 1.04093, 1.05672, 1.0295, 1.05495, null],
[1637283600000, 1.05495, 1.0553, 1.03548, 1.03595, null],
[1637287200000, 1.0359, 1.04585, 1.02026, 1.02312, null],
[1637290800000, 1.0242, 1.02908, 1.01788, 1.02871, null],
[1637294400000, 1.02871, 1.04474, 1.02584, 1.04247, null],
[1637298000000, 1.04251, 1.04654, 1.03685, 1.0449, null],
[1637301600000, 1.0449, 1.04971, 1.04109, 1.04452, null],
[1637305200000, 1.04456, 1.04875, 1.03802, 1.04268, null],
[1637308800000, 1.04239, 1.06573, 1.04164, 1.05717, null],
[1637312400000, 1.05721, 1.06464, 1.05619, 1.05896, null],
[1637316000000, 1.05893, 1.05918, 1.04976, 1.05188, null]
]
Binary file not shown.
-102
View File
@@ -1,102 +0,0 @@
[
[ 1637110800000, 1.0801, 1.09758, 1.07654, 1.07925, 3153694.607359 ],
[ 1637114400000, 1.07896, 1.0875, 1.07351, 1.07616, 2697616.070908 ],
[ 1637118000000, 1.07607, 1.08521, 1.05896, 1.06804, 4014666.826073 ],
[ 1637121600000, 1.06848, 1.07846, 1.06067, 1.07629, 3764015.567745 ],
[ 1637125200000, 1.07647, 1.08791, 1.07309, 1.0839, 1669038.113726 ],
[ 1637128800000, 1.08414, 1.0856, 1.07431, 1.0794, 1921068.874499 ],
[ 1637132400000, 1.0798, 1.09499, 1.07363, 1.08721, 2491096.863582 ],
[ 1637136000000, 1.08688, 1.09133, 1.08004, 1.08011, 1983486.794272 ],
[ 1637139600000, 1.08017, 1.08027, 1.06667, 1.07039, 3429247.985309 ],
[ 1637143200000, 1.07054, 1.10699, 1.07038, 1.10284, 4554151.954177 ],
[ 1637146800000, 1.10315, 1.10989, 1.09781, 1.1071, 2012983.10465 ],
[ 1637150400000, 1.10627, 1.10849, 1.10155, 1.10539, 1117804.08918 ],
[ 1637154000000, 1.10545, 1.11299, 1.09574, 1.09604, 2252781.33926 ],
[ 1637157600000, 1.09583, 1.10037, 1.08402, 1.08404, 1882359.279342 ],
[ 1637161200000, 1.08433, 1.08924, 1.07583, 1.08543, 1826745.82579 ],
[ 1637164800000, 1.08571, 1.09622, 1.07946, 1.09496, 1651730.678891 ],
[ 1637168400000, 1.09509, 1.0979, 1.0878, 1.0945, 1081210.614598 ],
[ 1637172000000, 1.09483, 1.10223, 1.09362, 1.09922, 1065998.492028 ],
[ 1637175600000, 1.09916, 1.10201, 1.09226, 1.09459, 924935.492048 ],
[ 1637179200000, 1.09458, 1.10196, 1.09051, 1.09916, 1253539.625345 ],
[ 1637182800000, 1.09939, 1.09948, 1.08751, 1.09485, 1066269.190094 ],
[ 1637186400000, 1.0949, 1.095, 1.08537, 1.09229, 924726.680514 ],
[ 1637190000000, 1.0923, 1.09877, 1.08753, 1.09522, 1150213.905599 ],
[ 1637193600000, 1.09538, 1.10675, 1.09058, 1.10453, 1489867.578178 ],
[ 1637197200000, 1.10446, 1.16313, 1.0978, 1.12907, 10016166.026355 ],
[ 1637200800000, 1.1287, 1.15367, 1.12403, 1.1381, 7167920.053752 ],
[ 1637204400000, 1.13818, 1.14242, 1.12358, 1.1244, 2665326.190545 ],
[ 1637208000000, 1.12432, 1.14864, 1.11061, 1.11447, 9340547.947608 ],
[ 1637211600000, 1.114, 1.12618, 1.10911, 1.11412, 11759138.472952 ],
[ 1637215200000, 1.11381, 1.11701, 1.10507, 1.1136, 3104670.727264 ],
[ 1637218800000, 1.11433, 1.1145, 1.09682, 1.10715, 2522287.830673 ],
[ 1637222400000, 1.1073, 1.11, 1.10224, 1.10697, 2021691.204473 ],
[ 1637226000000, 1.10622, 1.10707, 1.07727, 1.08674, 3679010.223352 ],
[ 1637229600000, 1.08651, 1.09861, 1.08065, 1.09771, 2041421.476307 ],
[ 1637233200000, 1.09784, 1.102, 1.08339, 1.08399, 1920597.122813 ],
[ 1637236800000, 1.08458, 1.09523, 1.07961, 1.08263, 2403158.337373 ],
[ 1637240400000, 1.08309, 1.08959, 1.06094, 1.07703, 4425686.808376 ],
[ 1637244000000, 1.07702, 1.08064, 1.063, 1.07049, 3361334.048801 ],
[ 1637247600000, 1.07126, 1.07851, 1.04538, 1.0562, 5865602.611111 ],
[ 1637251200000, 1.05616, 1.06326, 1.0395, 1.04074, 4206860.947352 ],
[ 1637254800000, 1.04023, 1.0533, 1.01478, 1.0417, 5641193.647291 ],
[ 1637258400000, 1.04177, 1.05444, 1.04132, 1.05204, 1819341.083656 ],
[ 1637262000000, 1.05201, 1.05962, 1.04964, 1.05518, 1567923.362515 ],
[ 1637265600000, 1.05579, 1.05924, 1.04772, 1.04773, 1794108.065606 ],
[ 1637269200000, 1.0484, 1.05622, 1.04183, 1.04544, 1936537.403899 ],
[ 1637272800000, 1.04543, 1.05331, 1.03396, 1.03892, 2839486.418143 ],
[ 1637276400000, 1.03969, 1.04592, 1.02886, 1.04086, 3116275.899177 ],
[ 1637280000000, 1.0409, 1.05681, 1.02922, 1.05481, 4671209.916896 ],
[ 1637283600000, 1.05489, 1.05538, 1.03539, 1.03599, 2566357.247547 ],
[ 1637287200000, 1.03596, 1.04606, 1.02038, 1.02428, 3441834.238546 ],
[ 1637290800000, 1.02483, 1.0291, 1.01785, 1.0285, 2678602.729339 ],
[ 1637294400000, 1.0287, 1.0446, 1.0259, 1.04264, 2303621.340808 ],
[ 1637298000000, 1.04313, 1.04676, 1.03662, 1.04499, 2426475.439485 ],
[ 1637301600000, 1.0451, 1.04971, 1.041, 1.04448, 2088365.810515 ],
[ 1637305200000, 1.04473, 1.04845, 1.03801, 1.04227, 2222396.213472 ],
[ 1637308800000, 1.04211, 1.06965, 1.04168, 1.05711, 3267643.936025 ],
[ 1637312400000, 1.0569, 1.06578, 1.05626, 1.05844, 1512848.016057 ],
[ 1637316000000, 1.05814, 1.05916, 1.04923, 1.05464, 1710694.805693 ],
[ 1637319600000, 1.05484, 1.05731, 1.0458, 1.05359, 1587100.45253 ],
[ 1637323200000, 1.05382, 1.06063, 1.05156, 1.05227, 1409095.236152 ],
[ 1637326800000, 1.05256, 1.06489, 1.04996, 1.06471, 1879315.174541 ],
[ 1637330400000, 1.06491, 1.1036, 1.06489, 1.09439, 6212842.71216 ],
[ 1637334000000, 1.09441, 1.10252, 1.082, 1.08879, 4833417.181969 ],
[ 1637337600000, 1.08866, 1.09485, 1.07538, 1.09045, 2554438.746366 ],
[ 1637341200000, 1.09058, 1.09906, 1.08881, 1.09039, 1961024.28963 ],
[ 1637344800000, 1.09063, 1.09447, 1.08555, 1.09041, 1427538.639232 ],
[ 1637348400000, 1.09066, 1.09521, 1.088, 1.09332, 847724.821691 ],
[ 1637352000000, 1.09335, 1.09489, 1.08402, 1.08501, 1035043.133874 ],
[ 1637355600000, 1.08474, 1.08694, 1.08, 1.08606, 969952.892274 ],
[ 1637359200000, 1.08601, 1.09, 1.08201, 1.08476, 1105782.581808 ],
[ 1637362800000, 1.08463, 1.09245, 1.08201, 1.08971, 1334467.438673 ],
[ 1637366400000, 1.0897, 1.09925, 1.08634, 1.09049, 2460070.020396 ],
[ 1637370000000, 1.0908, 1.10002, 1.09002, 1.09845, 1210028.489394 ],
[ 1637373600000, 1.09785, 1.09791, 1.08944, 1.08962, 1261987.295847 ],
[ 1637377200000, 1.08951, 1.0919, 1.08429, 1.08548, 1124938.783404 ],
[ 1637380800000, 1.08536, 1.09, 1.08424, 1.08783, 1330935.680168 ],
[ 1637384400000, 1.0877, 1.08969, 1.08266, 1.08617, 874900.746037 ],
[ 1637388000000, 1.08622, 1.09224, 1.0843, 1.0889, 1240184.759178 ],
[ 1637391600000, 1.08917, 1.0909, 1.08408, 1.08535, 706148.380072 ],
[ 1637395200000, 1.08521, 1.08857, 1.07829, 1.08349, 1713832.050838 ],
[ 1637398800000, 1.08343, 1.08841, 1.08272, 1.0855, 696597.06327 ],
[ 1637402400000, 1.08553, 1.0898, 1.08353, 1.08695, 1104159.802108 ],
[ 1637406000000, 1.08703, 1.09838, 1.08635, 1.09695, 1404001.384389 ],
[ 1637409600000, 1.09695, 1.10175, 1.09024, 1.09278, 1219090.620484 ],
[ 1637413200000, 1.093, 1.09577, 1.08615, 1.08792, 994797.546591 ],
[ 1637416800000, 1.08793, 1.09239, 1.08572, 1.08725, 1251685.429497 ],
[ 1637420400000, 1.08721, 1.08767, 1.06029, 1.06556, 3955719.53631 ],
[ 1637424000000, 1.06553, 1.07385, 1.06169, 1.07257, 1868359.179534 ],
[ 1637427600000, 1.07266, 1.0745, 1.06759, 1.07261, 1015134.469304 ],
[ 1637431200000, 1.07255, 1.0974, 1.06819, 1.09369, 4377675.964829 ],
[ 1637434800000, 1.09368, 1.09562, 1.08899, 1.09036, 914791.699929 ],
[ 1637438400000, 1.09085, 1.09262, 1.08855, 1.09214, 661436.936672 ],
[ 1637442000000, 1.0924, 1.09475, 1.08874, 1.09282, 593143.283519 ],
[ 1637445600000, 1.09301, 1.09638, 1.09154, 1.09611, 603952.916221 ],
[ 1637449200000, 1.09569, 1.09828, 1.09301, 1.09747, 676053.591571 ],
[ 1637452800000, 1.09742, 1.09822, 1.09011, 1.0902, 1375704.506469 ],
[ 1637456400000, 1.0901, 1.09311, 1.08619, 1.08856, 928706.03929 ],
[ 1637460000000, 1.08855, 1.08941, 1.07401, 1.08035, 2669150.388642 ],
[ 1637463600000, 1.08016, 1.08341, 1.07448, 1.07672, 1604049.131307 ],
[ 1637467200000, 1.07685, 1.08229, 1.07552, 1.0765, 1153357.274076 ]
]
Binary file not shown.
-102
View File
@@ -1,102 +0,0 @@
[
[1636956000000, 1.20932, 1.21787, 1.20763, 1.21431, null],
[1636959600000, 1.21431, 1.2198, 1.20895, 1.20895, null],
[1636963200000, 1.20902, 1.21106, 1.19972, 1.20968, null],
[1636966800000, 1.20968, 1.21876, 1.20791, 1.20998, null],
[1636970400000, 1.20999, 1.21043, 1.20442, 1.20859, null],
[1636974000000, 1.20858, 1.20933, 1.20154, 1.20581, null],
[1636977600000, 1.20584, 1.20775, 1.20065, 1.20337, null],
[1636981200000, 1.20342, 1.2097, 1.19327, 1.19792, null],
[1636984800000, 1.19796, 1.1982, 1.18611, 1.19024, null],
[1636988400000, 1.19025, 1.19177, 1.18373, 1.18771, null],
[1636992000000, 1.18768, 1.19109, 1.18095, 1.1887, null],
[1636995600000, 1.18869, 1.18968, 1.18355, 1.18387, null],
[1636999200000, 1.18388, 1.18729, 1.17753, 1.18138, null],
[1637002800000, 1.18145, 1.18684, 1.17799, 1.18463, null],
[1637006400000, 1.18464, 1.18474, 1.17368, 1.17652, null],
[1637010000000, 1.17653, 1.18185, 1.16557, 1.17979, null],
[1637013600000, 1.17979, 1.18113, 1.16934, 1.18014, null],
[1637017200000, 1.18014, 1.18015, 1.16999, 1.17214, null],
[1637020800000, 1.17214, 1.17217, 1.12958, 1.14209, null],
[1637024400000, 1.14255, 1.14666, 1.10933, 1.14198, null],
[1637028000000, 1.14197, 1.14419, 1.12766, 1.12999, null],
[1637031600000, 1.12999, 1.13522, 1.11142, 1.12177, null],
[1637035200000, 1.12176, 1.13211, 1.10579, 1.1288, null],
[1637038800000, 1.12871, 1.13243, 1.12142, 1.12316, null],
[1637042400000, 1.12323, 1.1262, 1.11489, 1.12429, null],
[1637046000000, 1.12406, 1.12727, 1.11835, 1.1249, null],
[1637049600000, 1.12485, 1.13047, 1.1211, 1.12931, null],
[1637053200000, 1.12931, 1.13346, 1.10256, 1.10267, null],
[1637056800000, 1.10266, 1.10412, 1.04149, 1.0928, null],
[1637060400000, 1.09277, 1.09856, 1.08371, 1.09093, null],
[1637064000000, 1.09094, 1.09512, 1.079, 1.08003, null],
[1637067600000, 1.0802, 1.09914, 1.08016, 1.09515, null],
[1637071200000, 1.09518, 1.11627, 1.0937, 1.10985, null],
[1637074800000, 1.10985, 1.11353, 1.09618, 1.10071, null],
[1637078400000, 1.09989, 1.10852, 1.09763, 1.10461, null],
[1637082000000, 1.10459, 1.10837, 1.09662, 1.09847, null],
[1637085600000, 1.09858, 1.10506, 1.08687, 1.08716, null],
[1637089200000, 1.08677, 1.10096, 1.08151, 1.09271, null],
[1637092800000, 1.09245, 1.09269, 1.06592, 1.08025, null],
[1637096400000, 1.08026, 1.09732, 1.07953, 1.09527, null],
[1637100000000, 1.09527, 1.10506, 1.09524, 1.09933, null],
[1637103600000, 1.09933, 1.10205, 1.08761, 1.08785, null],
[1637107200000, 1.08763, 1.09518, 1.07646, 1.07999, null],
[1637110800000, 1.07997, 1.0978, 1.07651, 1.07936, null],
[1637114400000, 1.07932, 1.08758, 1.07352, 1.07603, null],
[1637118000000, 1.07604, 1.08542, 1.05931, 1.06764, null],
[1637121600000, 1.06788, 1.07848, 1.06045, 1.07608, null],
[1637125200000, 1.07613, 1.08797, 1.07293, 1.08377, null],
[1637128800000, 1.08379, 1.08567, 1.07428, 1.07942, null],
[1637132400000, 1.07958, 1.09472, 1.07356, 1.08713, null],
[1637136000000, 1.08714, 1.09149, 1.08018, 1.08021, null],
[1637139600000, 1.08021, 1.08021, 1.0668, 1.07032, null],
[1637143200000, 1.07042, 1.10563, 1.07034, 1.10255, null],
[1637146800000, 1.10284, 1.10954, 1.09767, 1.10685, null],
[1637150400000, 1.10669, 1.10848, 1.10157, 1.10537, null],
[1637154000000, 1.10537, 1.11263, 1.09554, 1.09585, null],
[1637157600000, 1.09569, 1.10051, 1.08402, 1.08431, null],
[1637161200000, 1.08444, 1.08942, 1.07569, 1.08489, null],
[1637164800000, 1.08498, 1.09581, 1.07939, 1.09485, null],
[1637168400000, 1.09443, 1.09793, 1.08778, 1.0944, null],
[1637172000000, 1.09445, 1.10227, 1.09376, 1.0992, null],
[1637175600000, 1.0992, 1.10189, 1.09216, 1.09474, null],
[1637179200000, 1.09476, 1.10198, 1.09045, 1.0993, null],
[1637182800000, 1.09934, 1.09959, 1.08755, 1.0948, null],
[1637186400000, 1.09483, 1.09519, 1.08532, 1.0923, null],
[1637190000000, 1.0923, 1.09876, 1.0874, 1.095, null],
[1637193600000, 1.09503, 1.10673, 1.09047, 1.10441, null],
[1637197200000, 1.10437, 1.16166, 1.09815, 1.12902, null],
[1637200800000, 1.12875, 1.15094, 1.1242, 1.13764, null],
[1637204400000, 1.13795, 1.14262, 1.12341, 1.12423, null],
[1637208000000, 1.12424, 1.14806, 1.11333, 1.1142, null],
[1637211600000, 1.11435, 1.12608, 1.11085, 1.11436, null],
[1637215200000, 1.11398, 1.11718, 1.10538, 1.11388, null],
[1637218800000, 1.1139, 1.11452, 1.09674, 1.1072, null],
[1637222400000, 1.10725, 1.10999, 1.10209, 1.10706, null],
[1637226000000, 1.10712, 1.10712, 1.07747, 1.08658, null],
[1637229600000, 1.08692, 1.09865, 1.0807, 1.09767, null],
[1637233200000, 1.09768, 1.10211, 1.08348, 1.08409, null],
[1637236800000, 1.08423, 1.09498, 1.08002, 1.08259, null],
[1637240400000, 1.0827, 1.08773, 1.06597, 1.07719, null],
[1637244000000, 1.07718, 1.08075, 1.06678, 1.07077, null],
[1637247600000, 1.07029, 1.07824, 1.04568, 1.05497, null],
[1637251200000, 1.05591, 1.06325, 1.03957, 1.04032, null],
[1637254800000, 1.04051, 1.05342, 1.01557, 1.04158, null],
[1637258400000, 1.04153, 1.05436, 1.04122, 1.05208, null],
[1637262000000, 1.05207, 1.05948, 1.04961, 1.05515, null],
[1637265600000, 1.05516, 1.05927, 1.04767, 1.04808, null],
[1637269200000, 1.04789, 1.05622, 1.04191, 1.04587, null],
[1637272800000, 1.04575, 1.05336, 1.03405, 1.03941, null],
[1637276400000, 1.03931, 1.04614, 1.02868, 1.0411, null],
[1637280000000, 1.04093, 1.05672, 1.0295, 1.05495, null],
[1637283600000, 1.05495, 1.0553, 1.03548, 1.03595, null],
[1637287200000, 1.0359, 1.04585, 1.02026, 1.02312, null],
[1637290800000, 1.0242, 1.02908, 1.01788, 1.02871, null],
[1637294400000, 1.02871, 1.04474, 1.02584, 1.04247, null],
[1637298000000, 1.04251, 1.04654, 1.03685, 1.0449, null],
[1637301600000, 1.0449, 1.04971, 1.04109, 1.04452, null],
[1637305200000, 1.04456, 1.04875, 1.03802, 1.04268, null],
[1637308800000, 1.04239, 1.06573, 1.04164, 1.05717, null],
[1637312400000, 1.05721, 1.06464, 1.05619, 1.06051, null]
]
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -1 +0,0 @@
[[1637193600017,0.0001,0.0,0.0,0.0,0.0],[1637222400007,0.0001,0.0,0.0,0.0,0.0],[1637251200011,0.0001,0.0,0.0,0.0,0.0],[1637280000000,0.0001,0.0,0.0,0.0,0.0],[1637308800000,0.0001,0.0,0.0,0.0,0.0],[1637337600005,0.0001,0.0,0.0,0.0,0.0],[1637366400012,0.00013046,0.0,0.0,0.0,0.0],[1637395200000,0.0001,0.0,0.0,0.0,0.0],[1637424000007,0.0001,0.0,0.0,0.0,0.0],[1637452800000,0.00013862,0.0,0.0,0.0,0.0],[1637481600006,0.0001,0.0,0.0,0.0,0.0],[1637510400000,0.00019881,0.0,0.0,0.0,0.0],[1637539200004,0.00013991,0.0,0.0,0.0,0.0],[1637568000000,0.0001,0.0,0.0,0.0,0.0],[1637596800000,0.0001,0.0,0.0,0.0,0.0],[1637625600004,0.0001,0.0,0.0,0.0,0.0],[1637654400010,0.0001,0.0,0.0,0.0,0.0],[1637683200005,0.00017402,0.0,0.0,0.0,0.0],[1637712000001,0.00016775,0.0,0.0,0.0,0.0],[1637740800003,0.00033523,0.0,0.0,0.0,0.0],[1637769600010,0.0001,0.0,0.0,0.0,0.0],[1637798400000,0.00020066,0.0,0.0,0.0,0.0],[1637827200010,0.00034381,0.0,0.0,0.0,0.0],[1637856000000,0.00032096,0.0,0.0,0.0,0.0],[1637884800000,0.00058316,0.0,0.0,0.0,0.0],[1637913600000,0.0001646,0.0,0.0,0.0,0.0],[1637942400016,0.0001,0.0,0.0,0.0,0.0],[1637971200005,0.0001,0.0,0.0,0.0,0.0],[1638000000008,0.0001,0.0,0.0,0.0,0.0],[1638028800007,0.0001,0.0,0.0,0.0,0.0],[1638057600018,0.0001,0.0,0.0,0.0,0.0],[1638086400000,0.0001,0.0,0.0,0.0,0.0],[1638115200004,0.0001,0.0,0.0,0.0,0.0],[1638144000002,0.0001,0.0,0.0,0.0,0.0],[1638172800004,0.0001,0.0,0.0,0.0,0.0],[1638201600000,0.0001,0.0,0.0,0.0,0.0],[1638230400000,0.0001,0.0,0.0,0.0,0.0],[1638259200006,0.0001,0.0,0.0,0.0,0.0],[1638288000000,0.0001,0.0,0.0,0.0,0.0],[1638316800000,0.0001,0.0,0.0,0.0,0.0],[1638345600000,0.0001,0.0,0.0,0.0,0.0],[1638374400001,0.0001,0.0,0.0,0.0,0.0],[1638403200000,0.0001,0.0,0.0,0.0,0.0],[1638432000007,0.0001,0.0,0.0,0.0,0.0],[1638460800008,0.0001,0.0,0.0,0.0,0.0],[1638489600004,0.0001,0.0,0.0,0.0,0.0],[1638518400002,0.0001,0.0,0.0,0.0,0.0],[1638547200006,0.0001,0.0,0.0,0.0,0.0],[1638576000006,0.0001,0.0,0.0,0.0,0.0],[1638604800004,-0.00219334,0.0,0.0,0.0,0.0],[1638633600000,0.0001,0.0,0.0,0.0,0.0],[1638662400003,0.00006147,0.0,0.0,0.0,0.0],[1638691200008,0.0001,0.0,0.0,0.0,0.0],[1638720000007,0.0001,0.0,0.0,0.0,0.0],[1638748800009,0.0001,0.0,0.0,0.0,0.0],[1638777600001,0.0001,0.0,0.0,0.0,0.0],[1638806400000,0.0001,0.0,0.0,0.0,0.0],[1638835200018,0.0001,0.0,0.0,0.0,0.0],[1638864000000,0.0001,0.0,0.0,0.0,0.0],[1638892800000,0.0001,0.0,0.0,0.0,0.0],[1638921600000,0.0001,0.0,0.0,0.0,0.0],[1638950400018,0.0001,0.0,0.0,0.0,0.0],[1638979200010,0.0001,0.0,0.0,0.0,0.0],[1639008000010,0.0001,0.0,0.0,0.0,0.0],[1639036800000,0.0001,0.0,0.0,0.0,0.0],[1639065600000,0.0001,0.0,0.0,0.0,0.0],[1639094400000,0.0001,0.0,0.0,0.0,0.0],[1639123200008,0.0001,0.0,0.0,0.0,0.0],[1639152000012,0.00008995,0.0,0.0,0.0,0.0],[1639180800009,0.0001,0.0,0.0,0.0,0.0],[1639209600008,-0.00002574,0.0,0.0,0.0,0.0],[1639238400000,-0.00002024,0.0,0.0,0.0,0.0],[1639267200001,-0.00008282,0.0,0.0,0.0,0.0],[1639296000015,0.0001,0.0,0.0,0.0,0.0],[1639324800011,0.00008752,0.0,0.0,0.0,0.0],[1639353600006,0.0001,0.0,0.0,0.0,0.0],[1639382400019,0.0001,0.0,0.0,0.0,0.0],[1639411200000,0.0001,0.0,0.0,0.0,0.0],[1639440000004,0.00007825,0.0,0.0,0.0,0.0],[1639468800000,0.00007108,0.0,0.0,0.0,0.0],[1639497600015,0.0001,0.0,0.0,0.0,0.0],[1639526400000,0.0001,0.0,0.0,0.0,0.0],[1639555200008,0.0001,0.0,0.0,0.0,0.0],[1639584000005,0.0001,0.0,0.0,0.0,0.0],[1639612800006,0.0001,0.0,0.0,0.0,0.0],[1639641600009,0.0001,0.0,0.0,0.0,0.0],[1639670400000,0.0001,0.0,0.0,0.0,0.0],[1639699200000,0.0001,0.0,0.0,0.0,0.0],[1639728000005,0.0001,0.0,0.0,0.0,0.0],[1639756800006,0.0001,0.0,0.0,0.0,0.0],[1639785600014,0.0001,0.0,0.0,0.0,0.0]]
Binary file not shown.
File diff suppressed because one or more lines are too long
+15 -2
View File
@@ -3,8 +3,8 @@ from datetime import datetime, timedelta, timezone
import pytest
import time_machine
from freqtrade.util import dt_floor_day, dt_from_ts, dt_now, dt_ts, dt_utc, shorten_date
from freqtrade.util.datetime_helpers import dt_humanize
from freqtrade.util import (dt_floor_day, dt_from_ts, dt_humanize, dt_now, dt_ts, dt_utc,
format_ms_time, shorten_date)
def test_dt_now():
@@ -57,3 +57,16 @@ def test_dt_humanize() -> None:
assert dt_humanize(dt_now()) == 'just now'
assert dt_humanize(dt_now(), only_distance=True) == 'instantly'
assert dt_humanize(dt_now() - timedelta(hours=16), only_distance=True) == '16 hours'
def test_format_ms_time() -> None:
# Date 2018-04-10 18:02:01
date_in_epoch_ms = 1523383321000
date = format_ms_time(date_in_epoch_ms)
assert type(date) is str
res = datetime(2018, 4, 10, 18, 2, 1, tzinfo=timezone.utc)
assert date == res.astimezone(None).strftime('%Y-%m-%dT%H:%M:%S')
res = datetime(2017, 12, 13, 8, 2, 1, tzinfo=timezone.utc)
# Date 2017-12-13 08:02:01
date_in_epoch_ms = 1513152121000
assert format_ms_time(date_in_epoch_ms) == res.astimezone(None).strftime('%Y-%m-%dT%H:%M:%S')