|
|
|
|
@ -1,4 +1,4 @@
|
|
|
|
|
from datetime import datetime, timedelta, timezone
|
|
|
|
|
from datetime import datetime, timedelta
|
|
|
|
|
from random import randint
|
|
|
|
|
from unittest.mock import AsyncMock, MagicMock, PropertyMock
|
|
|
|
|
|
|
|
|
|
@ -8,9 +8,10 @@ import pytest
|
|
|
|
|
|
|
|
|
|
from freqtrade.enums import CandleType, MarginMode, TradingMode
|
|
|
|
|
from freqtrade.exceptions import DependencyException, InvalidOrderException, OperationalException
|
|
|
|
|
from freqtrade.exchange.exchange_utils_timeframe import timeframe_to_seconds
|
|
|
|
|
from freqtrade.persistence import Trade
|
|
|
|
|
from freqtrade.util.datetime_helpers import dt_from_ts, dt_ts, dt_utc
|
|
|
|
|
from tests.conftest import EXMS, get_mock_coro, get_patched_exchange, log_has_re
|
|
|
|
|
from tests.conftest import EXMS, get_patched_exchange
|
|
|
|
|
from tests.exchange.test_exchange import ccxt_exceptionhandlers
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -733,17 +734,17 @@ def test__set_leverage_binance(mocker, default_conf):
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def make_storage(start: datetime, end: datetime, timeframe: str = "1min"):
|
|
|
|
|
date = pd.date_range(start, end, freq=timeframe)
|
|
|
|
|
def make_storage(start: datetime, end: datetime, timeframe: str):
|
|
|
|
|
date = pd.date_range(start, end, freq=timeframe.replace("m", "min"))
|
|
|
|
|
df = pd.DataFrame(
|
|
|
|
|
data=dict(date=date, open=1.0, high=1.0, low=1.0, close=1.0),
|
|
|
|
|
)
|
|
|
|
|
return df
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def patch_ohlcv(mocker, start, archive_end, api_end):
|
|
|
|
|
archive_storage = make_storage(start, archive_end)
|
|
|
|
|
api_storage = make_storage(start, api_end)
|
|
|
|
|
def patch_ohlcv(mocker, start, archive_end, api_end, timeframe):
|
|
|
|
|
archive_storage = make_storage(start, archive_end, timeframe)
|
|
|
|
|
api_storage = make_storage(start, api_end, timeframe)
|
|
|
|
|
|
|
|
|
|
ohlcv = [[dt_ts(start), 1, 1, 1, 1]]
|
|
|
|
|
# (pair, timeframe, candle_type, ohlcv, True)
|
|
|
|
|
@ -768,6 +769,7 @@ def patch_ohlcv(mocker, start, archive_end, api_end):
|
|
|
|
|
timeframe,
|
|
|
|
|
since_ms,
|
|
|
|
|
until_ms,
|
|
|
|
|
stop_on_404=False,
|
|
|
|
|
):
|
|
|
|
|
since = dt_from_ts(since_ms)
|
|
|
|
|
until = dt_from_ts(until_ms) if until_ms else archive_end + timedelta(seconds=1)
|
|
|
|
|
@ -909,10 +911,21 @@ def patch_ohlcv(mocker, start, archive_end, api_end):
|
|
|
|
|
dt_utc(2020, 1, 1),
|
|
|
|
|
dt_utc(2020, 1, 2),
|
|
|
|
|
dt_utc(2020, 1, 1),
|
|
|
|
|
dt_utc(2020, 1, 1, 23, 59),
|
|
|
|
|
dt_utc(2020, 1, 1, 23),
|
|
|
|
|
False,
|
|
|
|
|
False,
|
|
|
|
|
True,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
"1m",
|
|
|
|
|
False,
|
|
|
|
|
dt_utc(2020, 1, 1),
|
|
|
|
|
dt_utc(2020, 1, 1, 3, 50, 30),
|
|
|
|
|
dt_utc(2020, 1, 1),
|
|
|
|
|
dt_utc(2020, 1, 1, 3, 50),
|
|
|
|
|
False,
|
|
|
|
|
True,
|
|
|
|
|
False,
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
)
|
|
|
|
|
@ -935,7 +948,7 @@ def test_get_historic_ohlcv_binance(
|
|
|
|
|
archive_end = dt_utc(2020, 1, 2)
|
|
|
|
|
api_end = dt_utc(2020, 1, 3)
|
|
|
|
|
candle_mock, api_mock, archive_mock = patch_ohlcv(
|
|
|
|
|
mocker, start=start, archive_end=archive_end, api_end=api_end
|
|
|
|
|
mocker, start=start, archive_end=archive_end, api_end=api_end, timeframe=timeframe
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
candle_type = CandleType.SPOT
|
|
|
|
|
@ -952,6 +965,9 @@ def test_get_historic_ohlcv_binance(
|
|
|
|
|
else:
|
|
|
|
|
assert df["date"].iloc[0] == first_date
|
|
|
|
|
assert df["date"].iloc[-1] == last_date
|
|
|
|
|
assert (
|
|
|
|
|
df["date"].diff().iloc[1:] == timedelta(seconds=timeframe_to_seconds(timeframe))
|
|
|
|
|
).all()
|
|
|
|
|
|
|
|
|
|
if candle_called:
|
|
|
|
|
candle_mock.assert_called_once()
|
|
|
|
|
@ -961,45 +977,6 @@ def test_get_historic_ohlcv_binance(
|
|
|
|
|
api_mock.assert_called_once()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.xfail(reason="Need refactor")
|
|
|
|
|
@pytest.mark.parametrize("candle_type", [CandleType.MARK, ""])
|
|
|
|
|
async def test__async_get_historic_ohlcv_binance(default_conf, mocker, caplog, candle_type):
|
|
|
|
|
ohlcv = [
|
|
|
|
|
[
|
|
|
|
|
int((datetime.now(timezone.utc).timestamp() - 1000) * 1000),
|
|
|
|
|
1, # open
|
|
|
|
|
2, # high
|
|
|
|
|
3, # low
|
|
|
|
|
4, # close
|
|
|
|
|
5, # volume (in quote currency)
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, exchange="binance")
|
|
|
|
|
# Monkey-patch async function
|
|
|
|
|
exchange._api_async.fetch_ohlcv = get_mock_coro(ohlcv)
|
|
|
|
|
|
|
|
|
|
pair = "ETH/BTC"
|
|
|
|
|
respair, restf, restype, res, _ = await exchange._async_get_historic_ohlcv(
|
|
|
|
|
pair, "5m", 1500000000000, is_new_pair=False, candle_type=candle_type
|
|
|
|
|
)
|
|
|
|
|
assert respair == pair
|
|
|
|
|
assert restf == "5m"
|
|
|
|
|
assert restype == candle_type
|
|
|
|
|
# Call with very old timestamp - causes tons of requests
|
|
|
|
|
assert exchange._api_async.fetch_ohlcv.call_count > 400
|
|
|
|
|
# assert res == ohlcv
|
|
|
|
|
exchange._api_async.fetch_ohlcv.reset_mock()
|
|
|
|
|
_, _, _, res, _ = await exchange._async_get_historic_ohlcv(
|
|
|
|
|
pair, "5m", 1500000000000, is_new_pair=True, candle_type=candle_type
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Called twice - one "init" call - and one to get the actual data.
|
|
|
|
|
assert exchange._api_async.fetch_ohlcv.call_count == 2
|
|
|
|
|
assert res == ohlcv
|
|
|
|
|
assert log_has_re(r"Candle-data for ETH/BTC available starting with .*", caplog)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
|
"pair,notional_value,mm_ratio,amt",
|
|
|
|
|
[
|
|
|
|
|
|