Merge upstream
This commit is contained in:
@@ -835,6 +835,23 @@ def test_download_data_trades(mocker, caplog):
|
||||
start_download_data(pargs)
|
||||
|
||||
|
||||
def test_download_data_data_invalid(mocker):
|
||||
patch_exchange(mocker, id="kraken")
|
||||
mocker.patch(
|
||||
'freqtrade.exchange.Exchange.markets', PropertyMock(return_value={})
|
||||
)
|
||||
args = [
|
||||
"download-data",
|
||||
"--exchange", "kraken",
|
||||
"--pairs", "ETH/BTC", "XRP/BTC",
|
||||
"--days", "20",
|
||||
]
|
||||
pargs = get_args(args)
|
||||
pargs['config'] = None
|
||||
with pytest.raises(OperationalException, match=r"Historic klines not available for .*"):
|
||||
start_download_data(pargs)
|
||||
|
||||
|
||||
def test_start_convert_trades(mocker, caplog):
|
||||
convert_mock = mocker.patch('freqtrade.commands.data_commands.convert_trades_to_ohlcv',
|
||||
MagicMock(return_value=[]))
|
||||
|
||||
@@ -158,21 +158,22 @@ def test_testdata_path(testdatadir) -> None:
|
||||
assert str(Path('tests') / 'testdata') in str(testdatadir)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("pair,expected_result,candle_type", [
|
||||
("ETH/BTC", 'freqtrade/hello/world/ETH_BTC-5m.json', ""),
|
||||
("Fabric Token/ETH", 'freqtrade/hello/world/Fabric_Token_ETH-5m.json', ""),
|
||||
("ETHH20", 'freqtrade/hello/world/ETHH20-5m.json', ""),
|
||||
(".XBTBON2H", 'freqtrade/hello/world/_XBTBON2H-5m.json', ""),
|
||||
("ETHUSD.d", 'freqtrade/hello/world/ETHUSD_d-5m.json', ""),
|
||||
("ACC_OLD/BTC", 'freqtrade/hello/world/ACC_OLD_BTC-5m.json', ""),
|
||||
("ETH/BTC", 'freqtrade/hello/world/futures/ETH_BTC-5m-mark.json', "mark"),
|
||||
("ACC_OLD/BTC", 'freqtrade/hello/world/futures/ACC_OLD_BTC-5m-index.json', "index"),
|
||||
@pytest.mark.parametrize("pair,timeframe,expected_result,candle_type", [
|
||||
("ETH/BTC", "5m", "freqtrade/hello/world/ETH_BTC-5m.json", ""),
|
||||
("ETH/USDT", "1M", "freqtrade/hello/world/ETH_USDT-1Mo.json", ""),
|
||||
("Fabric Token/ETH", "5m", "freqtrade/hello/world/Fabric_Token_ETH-5m.json", ""),
|
||||
("ETHH20", "5m", "freqtrade/hello/world/ETHH20-5m.json", ""),
|
||||
(".XBTBON2H", "5m", "freqtrade/hello/world/_XBTBON2H-5m.json", ""),
|
||||
("ETHUSD.d", "5m", "freqtrade/hello/world/ETHUSD_d-5m.json", ""),
|
||||
("ACC_OLD/BTC", "5m", "freqtrade/hello/world/ACC_OLD_BTC-5m.json", ""),
|
||||
("ETH/BTC", "5m", "freqtrade/hello/world/futures/ETH_BTC-5m-mark.json", "mark"),
|
||||
("ACC_OLD/BTC", "5m", "freqtrade/hello/world/futures/ACC_OLD_BTC-5m-index.json", "index"),
|
||||
])
|
||||
def test_json_pair_data_filename(pair, expected_result, candle_type):
|
||||
def test_json_pair_data_filename(pair, timeframe, expected_result, candle_type):
|
||||
fn = JsonDataHandler._pair_data_filename(
|
||||
Path('freqtrade/hello/world'),
|
||||
pair,
|
||||
'5m',
|
||||
timeframe,
|
||||
CandleType.from_string(candle_type)
|
||||
)
|
||||
assert isinstance(fn, Path)
|
||||
@@ -180,7 +181,7 @@ def test_json_pair_data_filename(pair, expected_result, candle_type):
|
||||
fn = JsonGzDataHandler._pair_data_filename(
|
||||
Path('freqtrade/hello/world'),
|
||||
pair,
|
||||
'5m',
|
||||
timeframe,
|
||||
candle_type=CandleType.from_string(candle_type)
|
||||
)
|
||||
assert isinstance(fn, Path)
|
||||
|
||||
@@ -13,6 +13,7 @@ import pytest
|
||||
|
||||
from freqtrade.enums import CandleType
|
||||
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_prev_date
|
||||
from freqtrade.exchange.exchange import timeframe_to_msecs
|
||||
from freqtrade.resolvers.exchange_resolver import ExchangeResolver
|
||||
from tests.conftest import get_default_conf_usdt
|
||||
|
||||
@@ -219,7 +220,7 @@ class TestCCXTExchange():
|
||||
assert len(l2['asks']) == next_limit
|
||||
assert len(l2['asks']) == next_limit
|
||||
|
||||
def test_fetch_ohlcv(self, exchange):
|
||||
def test_ccxt_fetch_ohlcv(self, exchange):
|
||||
exchange, exchangename = exchange
|
||||
pair = EXCHANGES[exchangename]['pair']
|
||||
timeframe = EXCHANGES[exchangename]['timeframe']
|
||||
@@ -231,11 +232,44 @@ class TestCCXTExchange():
|
||||
assert len(ohlcv[pair_tf]) == len(exchange.klines(pair_tf))
|
||||
# assert len(exchange.klines(pair_tf)) > 200
|
||||
# Assume 90% uptime ...
|
||||
assert len(exchange.klines(pair_tf)) > exchange.ohlcv_candle_limit(timeframe) * 0.90
|
||||
assert len(exchange.klines(pair_tf)) > exchange.ohlcv_candle_limit(
|
||||
timeframe, CandleType.SPOT) * 0.90
|
||||
# Check if last-timeframe is within the last 2 intervals
|
||||
now = datetime.now(timezone.utc) - timedelta(minutes=(timeframe_to_minutes(timeframe) * 2))
|
||||
assert exchange.klines(pair_tf).iloc[-1]['date'] >= timeframe_to_prev_date(timeframe, now)
|
||||
|
||||
def test_ccxt__async_get_candle_history(self, exchange):
|
||||
exchange, exchangename = exchange
|
||||
# For some weired reason, this test returns random lengths for bittrex.
|
||||
if not exchange._ft_has['ohlcv_has_history'] or exchangename == 'bittrex':
|
||||
return
|
||||
pair = EXCHANGES[exchangename]['pair']
|
||||
timeframe = EXCHANGES[exchangename]['timeframe']
|
||||
candle_type = CandleType.SPOT
|
||||
timeframe_ms = timeframe_to_msecs(timeframe)
|
||||
now = timeframe_to_prev_date(
|
||||
timeframe, datetime.now(timezone.utc))
|
||||
for offset in (360, 120, 30, 10, 5, 2):
|
||||
since = now - timedelta(days=offset)
|
||||
since_ms = int(since.timestamp() * 1000)
|
||||
|
||||
res = exchange.loop.run_until_complete(exchange._async_get_candle_history(
|
||||
pair=pair,
|
||||
timeframe=timeframe,
|
||||
since_ms=since_ms,
|
||||
candle_type=candle_type
|
||||
)
|
||||
)
|
||||
assert res
|
||||
assert res[0] == pair
|
||||
assert res[1] == timeframe
|
||||
assert res[2] == candle_type
|
||||
candles = res[3]
|
||||
candle_count = exchange.ohlcv_candle_limit(timeframe, candle_type, since_ms) * 0.9
|
||||
candle_count1 = (now.timestamp() * 1000 - since_ms) // timeframe_ms
|
||||
assert len(candles) >= min(candle_count, candle_count1)
|
||||
assert candles[0][0] == since_ms or (since_ms + timeframe_ms)
|
||||
|
||||
def test_ccxt_fetch_funding_rate_history(self, exchange_futures):
|
||||
exchange, exchangename = exchange_futures
|
||||
if not exchange:
|
||||
|
||||
75
tests/exchange/test_ccxt_precise.py
Normal file
75
tests/exchange/test_ccxt_precise.py
Normal file
@@ -0,0 +1,75 @@
|
||||
from ccxt import Precise
|
||||
|
||||
|
||||
ws = Precise('-1.123e-6')
|
||||
ws = Precise('-1.123e-6')
|
||||
xs = Precise('0.00000002')
|
||||
ys = Precise('69696900000')
|
||||
zs = Precise('0')
|
||||
|
||||
|
||||
def test_precise():
|
||||
assert ys * xs == '1393.938'
|
||||
assert xs * ys == '1393.938'
|
||||
|
||||
assert ys + xs == '69696900000.00000002'
|
||||
assert xs + ys == '69696900000.00000002'
|
||||
assert xs - ys == '-69696899999.99999998'
|
||||
assert ys - xs == '69696899999.99999998'
|
||||
assert xs / ys == '0'
|
||||
assert ys / xs == '3484845000000000000'
|
||||
|
||||
assert ws * xs == '-0.00000000000002246'
|
||||
assert xs * ws == '-0.00000000000002246'
|
||||
|
||||
assert ws + xs == '-0.000001103'
|
||||
assert xs + ws == '-0.000001103'
|
||||
|
||||
assert xs - ws == '0.000001143'
|
||||
assert ws - xs == '-0.000001143'
|
||||
|
||||
assert xs / ws == '-0.017809439002671415'
|
||||
assert ws / xs == '-56.15'
|
||||
|
||||
assert zs * ws == '0'
|
||||
assert zs * xs == '0'
|
||||
assert zs * ys == '0'
|
||||
assert ws * zs == '0'
|
||||
assert xs * zs == '0'
|
||||
assert ys * zs == '0'
|
||||
|
||||
assert zs + ws == '-0.000001123'
|
||||
assert zs + xs == '0.00000002'
|
||||
assert zs + ys == '69696900000'
|
||||
assert ws + zs == '-0.000001123'
|
||||
assert xs + zs == '0.00000002'
|
||||
assert ys + zs == '69696900000'
|
||||
|
||||
assert abs(Precise('-500.1')) == '500.1'
|
||||
assert abs(Precise('213')) == '213'
|
||||
|
||||
assert abs(Precise('-500.1')) == '500.1'
|
||||
assert -Precise('213') == '-213'
|
||||
|
||||
assert Precise('10.1') % Precise('0.5') == '0.1'
|
||||
assert Precise('5550') % Precise('120') == '30'
|
||||
|
||||
assert Precise('-0.0') == Precise('0')
|
||||
assert Precise('5.534000') == Precise('5.5340')
|
||||
|
||||
assert min(Precise('-3.1415'), Precise('-2')) == '-3.1415'
|
||||
|
||||
assert max(Precise('3.1415'), Precise('-2')) == '3.1415'
|
||||
|
||||
assert Precise('2') > Precise('1.2345')
|
||||
assert not Precise('-3.1415') > Precise('-2')
|
||||
assert not Precise('3.1415') > Precise('3.1415')
|
||||
assert Precise.string_gt('3.14150000000000000000001', '3.1415')
|
||||
|
||||
assert Precise('3.1415') >= Precise('3.1415')
|
||||
assert Precise('3.14150000000000000000001') >= Precise('3.1415')
|
||||
|
||||
assert not Precise('3.1415') < Precise('3.1415')
|
||||
|
||||
assert Precise('3.1415') <= Precise('3.1415')
|
||||
assert Precise('3.1415') <= Precise('3.14150000000000000000001')
|
||||
@@ -17,9 +17,9 @@ from freqtrade.exceptions import (DDosProtection, DependencyException, InvalidOr
|
||||
from freqtrade.exchange import Binance, Bittrex, Exchange, Kraken
|
||||
from freqtrade.exchange.common import (API_FETCH_ORDER_RETRY_COUNT, API_RETRY_COUNT,
|
||||
calculate_backoff, remove_credentials)
|
||||
from freqtrade.exchange.exchange import (market_is_active, timeframe_to_minutes, timeframe_to_msecs,
|
||||
timeframe_to_next_date, timeframe_to_prev_date,
|
||||
timeframe_to_seconds)
|
||||
from freqtrade.exchange.exchange import (date_minus_candles, market_is_active, timeframe_to_minutes,
|
||||
timeframe_to_msecs, timeframe_to_next_date,
|
||||
timeframe_to_prev_date, timeframe_to_seconds)
|
||||
from freqtrade.resolvers.exchange_resolver import ExchangeResolver
|
||||
from tests.conftest import get_mock_coro, get_patched_exchange, log_has, log_has_re, num_log_has_re
|
||||
|
||||
@@ -356,6 +356,7 @@ def test_amount_to_precision(
|
||||
(234.53, 4, 0.5, 235.0),
|
||||
(0.891534, 4, 0.0001, 0.8916),
|
||||
(64968.89, 4, 0.01, 64968.89),
|
||||
(0.000000003483, 4, 1e-12, 0.000000003483),
|
||||
|
||||
])
|
||||
def test_price_to_precision(default_conf, mocker, price, precision_mode, precision, expected):
|
||||
@@ -990,6 +991,7 @@ def test_validate_timeframes_emulated_ohlcvi_2(default_conf, mocker):
|
||||
|
||||
|
||||
def test_validate_timeframes_not_in_config(default_conf, mocker):
|
||||
# TODO: this test does not assert ...
|
||||
del default_conf["timeframe"]
|
||||
api_mock = MagicMock()
|
||||
id_mock = PropertyMock(return_value='test_exchange')
|
||||
@@ -1005,6 +1007,7 @@ def test_validate_timeframes_not_in_config(default_conf, mocker):
|
||||
mocker.patch('freqtrade.exchange.Exchange.validate_pairs')
|
||||
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
|
||||
mocker.patch('freqtrade.exchange.Exchange.validate_pricing')
|
||||
mocker.patch('freqtrade.exchange.Exchange.validate_required_startup_candles')
|
||||
Exchange(default_conf)
|
||||
|
||||
|
||||
@@ -1135,6 +1138,13 @@ def test_validate_required_startup_candles(default_conf, mocker, caplog):
|
||||
with pytest.raises(OperationalException, match=r'This strategy requires 6000.*'):
|
||||
Exchange(default_conf)
|
||||
|
||||
# Emulate kraken mode
|
||||
ex._ft_has['ohlcv_has_history'] = False
|
||||
with pytest.raises(OperationalException,
|
||||
match=r'This strategy requires 2500.*, '
|
||||
r'which is more than the amount.*'):
|
||||
ex.validate_required_startup_candles(2500, '5m')
|
||||
|
||||
|
||||
def test_exchange_has(default_conf, mocker):
|
||||
exchange = get_patched_exchange(mocker, default_conf)
|
||||
@@ -1926,7 +1936,7 @@ def test_get_historic_ohlcv(default_conf, mocker, caplog, exchange_name, candle_
|
||||
exchange._async_get_candle_history = Mock(wraps=mock_candle_hist)
|
||||
# one_call calculation * 1.8 should do 2 calls
|
||||
|
||||
since = 5 * 60 * exchange.ohlcv_candle_limit('5m') * 1.8
|
||||
since = 5 * 60 * exchange.ohlcv_candle_limit('5m', CandleType.SPOT) * 1.8
|
||||
ret = exchange.get_historic_ohlcv(
|
||||
pair,
|
||||
"5m",
|
||||
@@ -1992,7 +2002,7 @@ def test_get_historic_ohlcv_as_df(default_conf, mocker, exchange_name, candle_ty
|
||||
exchange._async_get_candle_history = Mock(wraps=mock_candle_hist)
|
||||
# one_call calculation * 1.8 should do 2 calls
|
||||
|
||||
since = 5 * 60 * exchange.ohlcv_candle_limit('5m') * 1.8
|
||||
since = 5 * 60 * exchange.ohlcv_candle_limit('5m', CandleType.SPOT) * 1.8
|
||||
ret = exchange.get_historic_ohlcv_as_df(
|
||||
pair,
|
||||
"5m",
|
||||
@@ -2046,7 +2056,7 @@ async def test__async_get_historic_ohlcv(default_conf, mocker, caplog, exchange_
|
||||
)
|
||||
# Required candles
|
||||
candles = (end_ts - start_ts) / 300_000
|
||||
exp = candles // exchange.ohlcv_candle_limit('5m') + 1
|
||||
exp = candles // exchange.ohlcv_candle_limit('5m', CandleType.SPOT) + 1
|
||||
|
||||
# Depending on the exchange, this should be called between 1 and 6 times.
|
||||
assert exchange._api_async.fetch_ohlcv.call_count == exp
|
||||
@@ -3417,7 +3427,7 @@ def test_ohlcv_candle_limit(default_conf, mocker, exchange_name):
|
||||
expected = exchange._ft_has['ohlcv_candle_limit_per_timeframe'][timeframe]
|
||||
# This should only run for bittrex
|
||||
assert exchange_name == 'bittrex'
|
||||
assert exchange.ohlcv_candle_limit(timeframe) == expected
|
||||
assert exchange.ohlcv_candle_limit(timeframe, CandleType.SPOT) == expected
|
||||
|
||||
|
||||
def test_timeframe_to_minutes():
|
||||
@@ -3499,6 +3509,17 @@ def test_timeframe_to_next_date():
|
||||
assert timeframe_to_next_date("5m", date) == date + timedelta(minutes=5)
|
||||
|
||||
|
||||
def test_date_minus_candles():
|
||||
|
||||
date = datetime(2019, 8, 12, 13, 25, 0, tzinfo=timezone.utc)
|
||||
|
||||
assert date_minus_candles("5m", 3, date) == date - timedelta(minutes=15)
|
||||
assert date_minus_candles("5m", 5, date) == date - timedelta(minutes=25)
|
||||
assert date_minus_candles("1m", 6, date) == date - timedelta(minutes=6)
|
||||
assert date_minus_candles("1h", 3, date) == date - timedelta(hours=3, minutes=25)
|
||||
assert date_minus_candles("1h", 3) == timeframe_to_prev_date('1h') - timedelta(hours=3)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"market_symbol,base,quote,exchange,spot,margin,futures,trademode,add_dict,expected_result",
|
||||
[
|
||||
|
||||
@@ -1,12 +1,42 @@
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from unittest.mock import MagicMock, PropertyMock
|
||||
|
||||
import pytest
|
||||
|
||||
from freqtrade.enums import MarginMode, TradingMode
|
||||
from freqtrade.enums.candletype import CandleType
|
||||
from freqtrade.exchange.exchange import timeframe_to_minutes
|
||||
from tests.conftest import get_patched_exchange
|
||||
from tests.exchange.test_exchange import ccxt_exceptionhandlers
|
||||
|
||||
|
||||
def test_okx_ohlcv_candle_limit(default_conf, mocker):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id='okx')
|
||||
timeframes = ('1m', '5m', '1h')
|
||||
start_time = int(datetime(2021, 1, 1, tzinfo=timezone.utc).timestamp() * 1000)
|
||||
|
||||
for timeframe in timeframes:
|
||||
assert exchange.ohlcv_candle_limit(timeframe, CandleType.SPOT) == 300
|
||||
assert exchange.ohlcv_candle_limit(timeframe, CandleType.FUTURES) == 300
|
||||
assert exchange.ohlcv_candle_limit(timeframe, CandleType.MARK) == 100
|
||||
assert exchange.ohlcv_candle_limit(timeframe, CandleType.FUNDING_RATE) == 100
|
||||
|
||||
assert exchange.ohlcv_candle_limit(timeframe, CandleType.SPOT, start_time) == 100
|
||||
assert exchange.ohlcv_candle_limit(timeframe, CandleType.FUTURES, start_time) == 100
|
||||
assert exchange.ohlcv_candle_limit(timeframe, CandleType.MARK, start_time) == 100
|
||||
assert exchange.ohlcv_candle_limit(timeframe, CandleType.FUNDING_RATE, start_time) == 100
|
||||
one_call = int((datetime.now(timezone.utc) - timedelta(
|
||||
minutes=290 * timeframe_to_minutes(timeframe))).timestamp() * 1000)
|
||||
|
||||
assert exchange.ohlcv_candle_limit(timeframe, CandleType.SPOT, one_call) == 300
|
||||
assert exchange.ohlcv_candle_limit(timeframe, CandleType.FUTURES, one_call) == 300
|
||||
|
||||
one_call = int((datetime.now(timezone.utc) - timedelta(
|
||||
minutes=320 * timeframe_to_minutes(timeframe))).timestamp() * 1000)
|
||||
assert exchange.ohlcv_candle_limit(timeframe, CandleType.SPOT, one_call) == 100
|
||||
assert exchange.ohlcv_candle_limit(timeframe, CandleType.FUTURES, one_call) == 100
|
||||
|
||||
|
||||
def test_get_maintenance_ratio_and_amt_okx(
|
||||
default_conf,
|
||||
mocker,
|
||||
|
||||
@@ -522,7 +522,7 @@ tc32 = BTContainer(data=[
|
||||
trailing_stop_positive=0.03,
|
||||
trades=[
|
||||
BTrade(exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3, is_short=True)
|
||||
]
|
||||
]
|
||||
)
|
||||
|
||||
# Test 33: trailing_stop should be triggered by low of next candle, without adjusting stoploss using
|
||||
@@ -662,7 +662,7 @@ tc41 = BTContainer(data=[
|
||||
custom_entry_price=4000,
|
||||
trades=[
|
||||
BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1, is_short=True)
|
||||
]
|
||||
]
|
||||
)
|
||||
|
||||
# Test 42: Custom-entry-price around candle low
|
||||
@@ -762,7 +762,7 @@ tc48 = BTContainer(data=[
|
||||
[2, 4900, 5250, 4500, 5100, 6172, 0, 0], # Order readjust
|
||||
[3, 5100, 5100, 4650, 4750, 6172, 0, 1],
|
||||
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
|
||||
stop_loss=-0.01, roi={"0": 0.10}, profit_perc=-0.087,
|
||||
stop_loss=-0.2, roi={"0": 0.10}, profit_perc=-0.087,
|
||||
use_exit_signal=True, timeout=1000,
|
||||
custom_entry_price=4200, adjust_entry_price=5200,
|
||||
trades=[BTrade(exit_reason=ExitType.EXIT_SIGNAL, open_tick=1, close_tick=4, is_short=False)]
|
||||
@@ -777,7 +777,7 @@ tc49 = BTContainer(data=[
|
||||
[2, 4900, 5250, 4900, 5100, 6172, 0, 0, 0, 0], # Order readjust
|
||||
[3, 5100, 5100, 4650, 4750, 6172, 0, 0, 0, 1],
|
||||
[4, 4750, 4950, 4350, 4750, 6172, 0, 0, 0, 0]],
|
||||
stop_loss=-0.01, roi={"0": 0.10}, profit_perc=0.05,
|
||||
stop_loss=-0.2, roi={"0": 0.10}, profit_perc=0.05,
|
||||
use_exit_signal=True, timeout=1000,
|
||||
custom_entry_price=5300, adjust_entry_price=5000,
|
||||
trades=[BTrade(exit_reason=ExitType.EXIT_SIGNAL, open_tick=1, close_tick=4, is_short=True)]
|
||||
@@ -811,6 +811,35 @@ tc51 = BTContainer(data=[
|
||||
trades=[]
|
||||
)
|
||||
|
||||
# Test 52: Custom-entry-price below all candles - readjust order - stoploss
|
||||
tc52 = BTContainer(data=[
|
||||
# D O H L C V EL XL ES Xs BT
|
||||
[0, 5000, 5050, 4950, 5000, 6172, 1, 0],
|
||||
[1, 5000, 5500, 4951, 5000, 6172, 0, 0], # enter trade (signal on last candle)
|
||||
[2, 4900, 5250, 4500, 5100, 6172, 0, 0], # Order readjust
|
||||
[3, 5100, 5100, 4650, 4750, 6172, 0, 0], # stoploss hit?
|
||||
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
|
||||
stop_loss=-0.03, roi={"0": 0.10}, profit_perc=-0.03,
|
||||
use_exit_signal=True, timeout=1000,
|
||||
custom_entry_price=4200, adjust_entry_price=5200,
|
||||
trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=2, is_short=False)]
|
||||
)
|
||||
|
||||
|
||||
# Test 53: Custom-entry-price short above all candles - readjust order - stoploss
|
||||
tc53 = BTContainer(data=[
|
||||
# D O H L C V EL XL ES Xs BT
|
||||
[0, 5000, 5050, 4950, 5000, 6172, 0, 0, 1, 0],
|
||||
[1, 5000, 5200, 4951, 5000, 6172, 0, 0, 0, 0], # enter trade (signal on last candle)
|
||||
[2, 4900, 5250, 4900, 5100, 6172, 0, 0, 0, 0], # Order readjust
|
||||
[3, 5100, 5100, 4650, 4750, 6172, 0, 0, 0, 1], # stoploss hit?
|
||||
[4, 4750, 4950, 4350, 4750, 6172, 0, 0, 0, 0]],
|
||||
stop_loss=-0.03, roi={"0": 0.10}, profit_perc=-0.03,
|
||||
use_exit_signal=True, timeout=1000,
|
||||
custom_entry_price=5300, adjust_entry_price=5000,
|
||||
trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=2, is_short=True)]
|
||||
)
|
||||
|
||||
TESTS = [
|
||||
tc0,
|
||||
tc1,
|
||||
@@ -864,6 +893,8 @@ TESTS = [
|
||||
tc49,
|
||||
tc50,
|
||||
tc51,
|
||||
tc52,
|
||||
tc53,
|
||||
]
|
||||
|
||||
|
||||
@@ -933,3 +964,5 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data: BTContainer)
|
||||
assert res.open_date == _get_frame_time_from_offset(trade.open_tick)
|
||||
assert res.close_date == _get_frame_time_from_offset(trade.close_tick)
|
||||
assert res.is_short == trade.is_short
|
||||
backtesting.cleanup()
|
||||
del backtesting
|
||||
|
||||
@@ -1169,6 +1169,9 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog, testdatadir):
|
||||
'rejected_signals': 20,
|
||||
'timedout_entry_orders': 0,
|
||||
'timedout_exit_orders': 0,
|
||||
'canceled_trade_entries': 0,
|
||||
'canceled_entry_orders': 0,
|
||||
'replaced_entry_orders': 0,
|
||||
'final_balance': 1000,
|
||||
})
|
||||
mocker.patch('freqtrade.plugins.pairlistmanager.PairListManager.whitelist',
|
||||
@@ -1281,6 +1284,9 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat
|
||||
'rejected_signals': 20,
|
||||
'timedout_entry_orders': 0,
|
||||
'timedout_exit_orders': 0,
|
||||
'canceled_trade_entries': 0,
|
||||
'canceled_entry_orders': 0,
|
||||
'replaced_entry_orders': 0,
|
||||
'final_balance': 1000,
|
||||
},
|
||||
{
|
||||
@@ -1290,6 +1296,9 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat
|
||||
'rejected_signals': 20,
|
||||
'timedout_entry_orders': 0,
|
||||
'timedout_exit_orders': 0,
|
||||
'canceled_trade_entries': 0,
|
||||
'canceled_entry_orders': 0,
|
||||
'replaced_entry_orders': 0,
|
||||
'final_balance': 1000,
|
||||
}
|
||||
])
|
||||
@@ -1432,6 +1441,9 @@ def test_backtest_start_nomock_futures(default_conf_usdt, mocker,
|
||||
'rejected_signals': 20,
|
||||
'timedout_entry_orders': 0,
|
||||
'timedout_exit_orders': 0,
|
||||
'canceled_trade_entries': 0,
|
||||
'canceled_entry_orders': 0,
|
||||
'replaced_entry_orders': 0,
|
||||
'final_balance': 1000,
|
||||
},
|
||||
{
|
||||
@@ -1441,6 +1453,9 @@ def test_backtest_start_nomock_futures(default_conf_usdt, mocker,
|
||||
'rejected_signals': 20,
|
||||
'timedout_entry_orders': 0,
|
||||
'timedout_exit_orders': 0,
|
||||
'canceled_trade_entries': 0,
|
||||
'canceled_entry_orders': 0,
|
||||
'replaced_entry_orders': 0,
|
||||
'final_balance': 1000,
|
||||
}
|
||||
])
|
||||
@@ -1535,6 +1550,9 @@ def test_backtest_start_multi_strat_nomock_detail(default_conf, mocker,
|
||||
'rejected_signals': 20,
|
||||
'timedout_entry_orders': 0,
|
||||
'timedout_exit_orders': 0,
|
||||
'canceled_trade_entries': 0,
|
||||
'canceled_entry_orders': 0,
|
||||
'replaced_entry_orders': 0,
|
||||
'final_balance': 1000,
|
||||
},
|
||||
{
|
||||
@@ -1544,6 +1562,9 @@ def test_backtest_start_multi_strat_nomock_detail(default_conf, mocker,
|
||||
'rejected_signals': 20,
|
||||
'timedout_entry_orders': 0,
|
||||
'timedout_exit_orders': 0,
|
||||
'canceled_trade_entries': 0,
|
||||
'canceled_entry_orders': 0,
|
||||
'replaced_entry_orders': 0,
|
||||
'final_balance': 1000,
|
||||
}
|
||||
])
|
||||
@@ -1607,6 +1628,9 @@ def test_backtest_start_multi_strat_caching(default_conf, mocker, caplog, testda
|
||||
'rejected_signals': 20,
|
||||
'timedout_entry_orders': 0,
|
||||
'timedout_exit_orders': 0,
|
||||
'canceled_trade_entries': 0,
|
||||
'canceled_entry_orders': 0,
|
||||
'replaced_entry_orders': 0,
|
||||
'final_balance': 1000,
|
||||
})
|
||||
mocker.patch('freqtrade.plugins.pairlistmanager.PairListManager.whitelist',
|
||||
|
||||
@@ -368,6 +368,9 @@ def test_hyperopt_format_results(hyperopt):
|
||||
'rejected_signals': 2,
|
||||
'timedout_entry_orders': 0,
|
||||
'timedout_exit_orders': 0,
|
||||
'canceled_trade_entries': 0,
|
||||
'canceled_entry_orders': 0,
|
||||
'replaced_entry_orders': 0,
|
||||
'backtest_start_time': 1619718665,
|
||||
'backtest_end_time': 1619718665,
|
||||
}
|
||||
@@ -438,6 +441,9 @@ def test_generate_optimizer(mocker, hyperopt_conf) -> None:
|
||||
'rejected_signals': 20,
|
||||
'timedout_entry_orders': 0,
|
||||
'timedout_exit_orders': 0,
|
||||
'canceled_trade_entries': 0,
|
||||
'canceled_entry_orders': 0,
|
||||
'replaced_entry_orders': 0,
|
||||
'final_balance': 1000,
|
||||
}
|
||||
|
||||
|
||||
@@ -87,6 +87,9 @@ def test_generate_backtest_stats(default_conf, testdatadir, tmpdir):
|
||||
'rejected_signals': 20,
|
||||
'timedout_entry_orders': 0,
|
||||
'timedout_exit_orders': 0,
|
||||
'canceled_trade_entries': 0,
|
||||
'canceled_entry_orders': 0,
|
||||
'replaced_entry_orders': 0,
|
||||
'backtest_start_time': Arrow.utcnow().int_timestamp,
|
||||
'backtest_end_time': Arrow.utcnow().int_timestamp,
|
||||
'run_id': '123',
|
||||
@@ -139,6 +142,9 @@ def test_generate_backtest_stats(default_conf, testdatadir, tmpdir):
|
||||
'rejected_signals': 20,
|
||||
'timedout_entry_orders': 0,
|
||||
'timedout_exit_orders': 0,
|
||||
'canceled_trade_entries': 0,
|
||||
'canceled_entry_orders': 0,
|
||||
'replaced_entry_orders': 0,
|
||||
'backtest_start_time': Arrow.utcnow().int_timestamp,
|
||||
'backtest_end_time': Arrow.utcnow().int_timestamp,
|
||||
'run_id': '124',
|
||||
|
||||
@@ -470,12 +470,16 @@ def test_VolumePairList_refresh_empty(mocker, markets_empty, whitelist_conf):
|
||||
"BTC", ['ETH/BTC', 'TKN/BTC']),
|
||||
# VolumePairList with no offset = unchanged pairlist
|
||||
([{"method": "VolumePairList", "number_assets": 20, "sort_key": "quoteVolume"},
|
||||
{"method": "OffsetFilter", "offset": 0}],
|
||||
{"method": "OffsetFilter", "offset": 0, "number_assets": 0}],
|
||||
"USDT", ['ETH/USDT', 'NANO/USDT', 'ADAHALF/USDT', 'ADADOUBLE/USDT']),
|
||||
# VolumePairList with offset = 2
|
||||
([{"method": "VolumePairList", "number_assets": 20, "sort_key": "quoteVolume"},
|
||||
{"method": "OffsetFilter", "offset": 2}],
|
||||
"USDT", ['ADAHALF/USDT', 'ADADOUBLE/USDT']),
|
||||
# VolumePairList with offset and limit
|
||||
([{"method": "VolumePairList", "number_assets": 20, "sort_key": "quoteVolume"},
|
||||
{"method": "OffsetFilter", "offset": 1, "number_assets": 2}],
|
||||
"USDT", ['NANO/USDT', 'ADAHALF/USDT']),
|
||||
# VolumePairList with higher offset, than total pairlist
|
||||
([{"method": "VolumePairList", "number_assets": 20, "sort_key": "quoteVolume"},
|
||||
{"method": "OffsetFilter", "offset": 100}],
|
||||
@@ -1152,6 +1156,10 @@ def test_spreadfilter_invalid_data(mocker, default_conf, markets, tickers, caplo
|
||||
"0.01 and above 0.99 over the last days.'}]",
|
||||
None
|
||||
),
|
||||
({"method": "OffsetFilter", "offset": 5, "number_assets": 10},
|
||||
"[{'OffsetFilter': 'OffsetFilter - Taking 10 Pairs, starting from 5.'}]",
|
||||
None
|
||||
),
|
||||
])
|
||||
def test_pricefilter_desc(mocker, whitelist_conf, markets, pairlistconfig,
|
||||
desc_expected, exception_expected):
|
||||
|
||||
@@ -372,11 +372,15 @@ def test_dca_order_adjust(default_conf_usdt, ticker_usdt, fee, mocker) -> None:
|
||||
freqtrade.enter_positions()
|
||||
|
||||
assert len(Trade.get_trades().all()) == 1
|
||||
trade = Trade.get_trades().first()
|
||||
trade: Trade = Trade.get_trades().first()
|
||||
assert len(trade.orders) == 1
|
||||
assert trade.open_order_id is not None
|
||||
assert pytest.approx(trade.stake_amount) == 60
|
||||
assert trade.open_rate == 1.96
|
||||
assert trade.stop_loss_pct is None
|
||||
assert trade.stop_loss == 0.0
|
||||
assert trade.initial_stop_loss == 0.0
|
||||
assert trade.initial_stop_loss_pct is None
|
||||
# No adjustment
|
||||
freqtrade.process()
|
||||
trade = Trade.get_trades().first()
|
||||
@@ -392,6 +396,10 @@ def test_dca_order_adjust(default_conf_usdt, ticker_usdt, fee, mocker) -> None:
|
||||
assert trade.open_order_id is not None
|
||||
# Open rate is not adjusted yet
|
||||
assert trade.open_rate == 1.96
|
||||
assert trade.stop_loss_pct is None
|
||||
assert trade.stop_loss == 0.0
|
||||
assert trade.initial_stop_loss == 0.0
|
||||
assert trade.initial_stop_loss_pct is None
|
||||
|
||||
# Fill order
|
||||
mocker.patch('freqtrade.exchange.Exchange._is_dry_limit_order_filled', return_value=True)
|
||||
@@ -401,6 +409,10 @@ def test_dca_order_adjust(default_conf_usdt, ticker_usdt, fee, mocker) -> None:
|
||||
assert trade.open_order_id is None
|
||||
# Open rate is not adjusted yet
|
||||
assert trade.open_rate == 1.99
|
||||
assert trade.stop_loss_pct == -0.1
|
||||
assert trade.stop_loss == 1.99 * 0.9
|
||||
assert trade.initial_stop_loss == 1.99 * 0.9
|
||||
assert trade.initial_stop_loss_pct == -0.1
|
||||
|
||||
# 2nd order - not filling
|
||||
freqtrade.strategy.adjust_trade_position = MagicMock(return_value=120)
|
||||
|
||||
Reference in New Issue
Block a user