merged lev-freqtradebot with lev-strat
This commit is contained in:
@@ -5,7 +5,7 @@ from unittest.mock import MagicMock, PropertyMock
|
||||
import ccxt
|
||||
import pytest
|
||||
|
||||
from freqtrade.enums import TradingMode
|
||||
from freqtrade.enums import Collateral, TradingMode
|
||||
from freqtrade.exceptions import DependencyException, InvalidOrderException, OperationalException
|
||||
from tests.conftest import get_mock_coro, get_patched_exchange, log_has_re
|
||||
from tests.exchange.test_exchange import ccxt_exceptionhandlers
|
||||
@@ -48,13 +48,20 @@ def test_stoploss_order_binance(
|
||||
amount=1,
|
||||
stop_price=190,
|
||||
side=side,
|
||||
order_types={'stoploss_on_exchange_limit_ratio': 1.05}
|
||||
order_types={'stoploss_on_exchange_limit_ratio': 1.05},
|
||||
leverage=1.0
|
||||
)
|
||||
|
||||
api_mock.create_order.reset_mock()
|
||||
order_types = {} if limitratio is None else {'stoploss_on_exchange_limit_ratio': limitratio}
|
||||
order = exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220,
|
||||
order_types=order_types, side=side)
|
||||
order = exchange.stoploss(
|
||||
pair='ETH/BTC',
|
||||
amount=1,
|
||||
stop_price=220,
|
||||
order_types=order_types,
|
||||
side=side,
|
||||
leverage=1.0
|
||||
)
|
||||
|
||||
assert 'id' in order
|
||||
assert 'info' in order
|
||||
@@ -71,17 +78,31 @@ def test_stoploss_order_binance(
|
||||
with pytest.raises(DependencyException):
|
||||
api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds("0 balance"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'binance')
|
||||
exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side=side)
|
||||
exchange.stoploss(
|
||||
pair='ETH/BTC',
|
||||
amount=1,
|
||||
stop_price=220,
|
||||
order_types={},
|
||||
side=side,
|
||||
leverage=1.0)
|
||||
|
||||
with pytest.raises(InvalidOrderException):
|
||||
api_mock.create_order = MagicMock(
|
||||
side_effect=ccxt.InvalidOrder("binance Order would trigger immediately."))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'binance')
|
||||
exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side=side)
|
||||
exchange.stoploss(
|
||||
pair='ETH/BTC',
|
||||
amount=1,
|
||||
stop_price=220,
|
||||
order_types={},
|
||||
side=side,
|
||||
leverage=1.0
|
||||
)
|
||||
|
||||
ccxt_exceptionhandlers(mocker, default_conf, api_mock, "binance",
|
||||
"stoploss", "create_order", retries=1,
|
||||
pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side=side)
|
||||
pair='ETH/BTC', amount=1, stop_price=220, order_types={},
|
||||
side=side, leverage=1.0)
|
||||
|
||||
|
||||
def test_stoploss_order_dry_run_binance(default_conf, mocker):
|
||||
@@ -94,12 +115,25 @@ def test_stoploss_order_dry_run_binance(default_conf, mocker):
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'binance')
|
||||
|
||||
with pytest.raises(OperationalException):
|
||||
order = exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=190, side="sell",
|
||||
order_types={'stoploss_on_exchange_limit_ratio': 1.05})
|
||||
order = exchange.stoploss(
|
||||
pair='ETH/BTC',
|
||||
amount=1,
|
||||
stop_price=190,
|
||||
side="sell",
|
||||
order_types={'stoploss_on_exchange_limit_ratio': 1.05},
|
||||
leverage=1.0
|
||||
)
|
||||
|
||||
api_mock.create_order.reset_mock()
|
||||
|
||||
order = exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side="sell")
|
||||
order = exchange.stoploss(
|
||||
pair='ETH/BTC',
|
||||
amount=1,
|
||||
stop_price=220,
|
||||
order_types={},
|
||||
side="sell",
|
||||
leverage=1.0
|
||||
)
|
||||
|
||||
assert 'id' in order
|
||||
assert 'info' in order
|
||||
@@ -194,6 +228,9 @@ def test_fill_leverage_brackets_binance(default_conf, mocker):
|
||||
[1000000.0, 0.5]],
|
||||
|
||||
})
|
||||
default_conf['dry_run'] = False
|
||||
default_conf['trading_mode'] = TradingMode.FUTURES
|
||||
default_conf['collateral'] = Collateral.ISOLATED
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="binance")
|
||||
exchange.fill_leverage_brackets()
|
||||
|
||||
@@ -236,12 +273,59 @@ def test_fill_leverage_brackets_binance(default_conf, mocker):
|
||||
)
|
||||
|
||||
|
||||
def test_fill_leverage_brackets_binance_dryrun(default_conf, mocker):
|
||||
api_mock = MagicMock()
|
||||
default_conf['trading_mode'] = TradingMode.FUTURES
|
||||
default_conf['collateral'] = Collateral.ISOLATED
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="binance")
|
||||
exchange.fill_leverage_brackets()
|
||||
|
||||
leverage_brackets = {
|
||||
"1000SHIB/USDT": [
|
||||
[0.0, 0.01],
|
||||
[5000.0, 0.025],
|
||||
[25000.0, 0.05],
|
||||
[100000.0, 0.1],
|
||||
[250000.0, 0.125],
|
||||
[1000000.0, 0.5]
|
||||
],
|
||||
"1INCH/USDT": [
|
||||
[0.0, 0.012],
|
||||
[5000.0, 0.025],
|
||||
[25000.0, 0.05],
|
||||
[100000.0, 0.1],
|
||||
[250000.0, 0.125],
|
||||
[1000000.0, 0.5]
|
||||
],
|
||||
"AAVE/USDT": [
|
||||
[0.0, 0.01],
|
||||
[50000.0, 0.02],
|
||||
[250000.0, 0.05],
|
||||
[1000000.0, 0.1],
|
||||
[2000000.0, 0.125],
|
||||
[5000000.0, 0.1665],
|
||||
[10000000.0, 0.25]
|
||||
],
|
||||
"ADA/BUSD": [
|
||||
[0.0, 0.025],
|
||||
[100000.0, 0.05],
|
||||
[500000.0, 0.1],
|
||||
[1000000.0, 0.15],
|
||||
[2000000.0, 0.25],
|
||||
[5000000.0, 0.5]
|
||||
]
|
||||
}
|
||||
|
||||
for key, value in leverage_brackets.items():
|
||||
assert exchange._leverage_brackets[key] == value
|
||||
|
||||
|
||||
def test__set_leverage_binance(mocker, default_conf):
|
||||
|
||||
api_mock = MagicMock()
|
||||
api_mock.set_leverage = MagicMock()
|
||||
type(api_mock).has = PropertyMock(return_value={'setLeverage': True})
|
||||
|
||||
default_conf['dry_run'] = False
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="binance")
|
||||
exchange._set_leverage(3.0, trading_mode=TradingMode.MARGIN)
|
||||
|
||||
@@ -288,3 +372,15 @@ async def test__async_get_historic_ohlcv_binance(default_conf, mocker, caplog):
|
||||
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("trading_mode,collateral,config", [
|
||||
("", "", {}),
|
||||
("margin", "cross", {"options": {"defaultType": "margin"}}),
|
||||
("futures", "isolated", {"options": {"defaultType": "future"}}),
|
||||
])
|
||||
def test__ccxt_config(default_conf, mocker, trading_mode, collateral, config):
|
||||
default_conf['trading_mode'] = trading_mode
|
||||
default_conf['collateral'] = collateral
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="binance")
|
||||
assert exchange._ccxt_config == config
|
||||
|
@@ -132,6 +132,7 @@ def test_init_ccxt_kwargs(default_conf, mocker, caplog):
|
||||
|
||||
assert log_has("Applying additional ccxt config: {'TestKWARG': 11, 'TestKWARG44': 11}", caplog)
|
||||
assert ex._api.headers == {'hello': 'world'}
|
||||
assert ex._ccxt_config == {}
|
||||
Exchange._headers = {}
|
||||
|
||||
# TODO-lev: Test with options
|
||||
@@ -403,7 +404,6 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None:
|
||||
# With Leverage
|
||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 1, stoploss, 3.0)
|
||||
assert isclose(result, expected_result/3)
|
||||
# TODO-lev: Min stake for base, kraken and ftx
|
||||
|
||||
# min amount is set
|
||||
markets["ETH/BTC"]["limits"] = {
|
||||
@@ -420,27 +420,21 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None:
|
||||
# With Leverage
|
||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss, 5.0)
|
||||
assert isclose(result, expected_result/5)
|
||||
# TODO-lev: Min stake for base, kraken and ftx
|
||||
|
||||
# min amount and cost are set (cost is minimal)
|
||||
markets["ETH/BTC"]["limits"] = {
|
||||
'cost': {'min': 2},
|
||||
'amount': {'min': 2}
|
||||
}
|
||||
mocker.patch(
|
||||
'freqtrade.exchange.Exchange.markets',
|
||||
PropertyMock(return_value=markets)
|
||||
)
|
||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss)
|
||||
expected_result = max(2, 2 * 2) * (1+0.05) / (1-abs(stoploss))
|
||||
result=exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss)
|
||||
expected_result=max(2, 2 * 2) * (1+0.05) / (1-abs(stoploss))
|
||||
assert isclose(result, expected_result)
|
||||
# With Leverage
|
||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss, 10)
|
||||
result=exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss, 10)
|
||||
assert isclose(result, expected_result/10)
|
||||
# TODO-lev: Min stake for base, kraken and ftx
|
||||
|
||||
# min amount and cost are set (amount is minial)
|
||||
markets["ETH/BTC"]["limits"] = {
|
||||
markets["ETH/BTC"]["limits"]={
|
||||
'cost': {'min': 8},
|
||||
'amount': {'min': 2}
|
||||
}
|
||||
@@ -448,39 +442,28 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None:
|
||||
'freqtrade.exchange.Exchange.markets',
|
||||
PropertyMock(return_value=markets)
|
||||
)
|
||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss)
|
||||
expected_result = max(8, 2 * 2) * (1+0.05) / (1-abs(stoploss))
|
||||
result=exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss)
|
||||
expected_result=max(8, 2 * 2) * (1+0.05) / (1-abs(stoploss))
|
||||
assert isclose(result, expected_result)
|
||||
# With Leverage
|
||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss, 7.0)
|
||||
result=exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss, 7.0)
|
||||
assert isclose(result, expected_result/7.0)
|
||||
# TODO-lev: Min stake for base, kraken and ftx
|
||||
|
||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, -0.4)
|
||||
expected_result = max(8, 2 * 2) * 1.5
|
||||
result=exchange.get_min_pair_stake_amount('ETH/BTC', 2, -0.4)
|
||||
expected_result=max(8, 2 * 2) * 1.5
|
||||
assert isclose(result, expected_result)
|
||||
# With Leverage
|
||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, -0.4, 8.0)
|
||||
result=exchange.get_min_pair_stake_amount('ETH/BTC', 2, -0.4, 8.0)
|
||||
assert isclose(result, expected_result/8.0)
|
||||
# TODO-lev: Min stake for base, kraken and ftx
|
||||
|
||||
# Really big stoploss
|
||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, -1)
|
||||
expected_result = max(8, 2 * 2) * 1.5
|
||||
assert isclose(result, expected_result)
|
||||
# With Leverage
|
||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, -1, 12.0)
|
||||
result=exchange.get_min_pair_stake_amount('ETH/BTC', 2, -1, 12.0)
|
||||
assert isclose(result, expected_result/12)
|
||||
# TODO-lev: Min stake for base, kraken and ftx
|
||||
|
||||
|
||||
def test_get_min_pair_stake_amount_real_data(mocker, default_conf) -> None:
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="binance")
|
||||
stoploss = -0.05
|
||||
markets = {'ETH/BTC': {'symbol': 'ETH/BTC'}}
|
||||
stoploss=-0.05
|
||||
markets={'ETH/BTC': {'symbol': 'ETH/BTC'}}
|
||||
|
||||
# Real Binance data
|
||||
markets["ETH/BTC"]["limits"] = {
|
||||
markets["ETH/BTC"]["limits"]={
|
||||
'cost': {'min': 0.0001},
|
||||
'amount': {'min': 0.001}
|
||||
}
|
||||
@@ -488,28 +471,27 @@ def test_get_min_pair_stake_amount_real_data(mocker, default_conf) -> None:
|
||||
'freqtrade.exchange.Exchange.markets',
|
||||
PropertyMock(return_value=markets)
|
||||
)
|
||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 0.020405, stoploss)
|
||||
expected_result = max(0.0001, 0.001 * 0.020405) * (1+0.05) / (1-abs(stoploss))
|
||||
result=exchange.get_min_pair_stake_amount('ETH/BTC', 0.020405, stoploss)
|
||||
expected_result=max(0.0001, 0.001 * 0.020405) * (1+0.05) / (1-abs(stoploss))
|
||||
assert round(result, 8) == round(expected_result, 8)
|
||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 0.020405, stoploss, 3.0)
|
||||
result=exchange.get_min_pair_stake_amount('ETH/BTC', 0.020405, stoploss, 3.0)
|
||||
assert round(result, 8) == round(expected_result/3, 8)
|
||||
# TODO-lev: Min stake for base, kraken and ftx
|
||||
|
||||
|
||||
def test_set_sandbox(default_conf, mocker):
|
||||
"""
|
||||
Test working scenario
|
||||
"""
|
||||
api_mock = MagicMock()
|
||||
api_mock.load_markets = MagicMock(return_value={
|
||||
api_mock=MagicMock()
|
||||
api_mock.load_markets=MagicMock(return_value = {
|
||||
'ETH/BTC': '', 'LTC/BTC': '', 'XRP/BTC': '', 'NEO/BTC': ''
|
||||
})
|
||||
url_mock = PropertyMock(return_value={'test': "api-public.sandbox.gdax.com",
|
||||
url_mock=PropertyMock(return_value = {'test': "api-public.sandbox.gdax.com",
|
||||
'api': 'https://api.gdax.com'})
|
||||
type(api_mock).urls = url_mock
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
||||
liveurl = exchange._api.urls['api']
|
||||
default_conf['exchange']['sandbox'] = True
|
||||
type(api_mock).urls=url_mock
|
||||
exchange=get_patched_exchange(mocker, default_conf, api_mock)
|
||||
liveurl=exchange._api.urls['api']
|
||||
default_conf['exchange']['sandbox']=True
|
||||
exchange.set_sandbox(exchange._api, default_conf['exchange'], 'Logname')
|
||||
assert exchange._api.urls['api'] != liveurl
|
||||
|
||||
@@ -518,16 +500,16 @@ def test_set_sandbox_exception(default_conf, mocker):
|
||||
"""
|
||||
Test Fail scenario
|
||||
"""
|
||||
api_mock = MagicMock()
|
||||
api_mock.load_markets = MagicMock(return_value={
|
||||
api_mock=MagicMock()
|
||||
api_mock.load_markets=MagicMock(return_value = {
|
||||
'ETH/BTC': '', 'LTC/BTC': '', 'XRP/BTC': '', 'NEO/BTC': ''
|
||||
})
|
||||
url_mock = PropertyMock(return_value={'api': 'https://api.gdax.com'})
|
||||
type(api_mock).urls = url_mock
|
||||
url_mock=PropertyMock(return_value = {'api': 'https://api.gdax.com'})
|
||||
type(api_mock).urls=url_mock
|
||||
|
||||
with pytest.raises(OperationalException, match=r'does not provide a sandbox api'):
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
||||
default_conf['exchange']['sandbox'] = True
|
||||
with pytest.raises(OperationalException, match = r'does not provide a sandbox api'):
|
||||
exchange=get_patched_exchange(mocker, default_conf, api_mock)
|
||||
default_conf['exchange']['sandbox']=True
|
||||
exchange.set_sandbox(exchange._api, default_conf['exchange'], 'Logname')
|
||||
|
||||
|
||||
@@ -537,13 +519,13 @@ def test__load_async_markets(default_conf, mocker, caplog):
|
||||
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes')
|
||||
mocker.patch('freqtrade.exchange.Exchange._load_markets')
|
||||
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
|
||||
exchange = Exchange(default_conf)
|
||||
exchange._api_async.load_markets = get_mock_coro(None)
|
||||
exchange=Exchange(default_conf)
|
||||
exchange._api_async.load_markets=get_mock_coro(None)
|
||||
exchange._load_async_markets()
|
||||
assert exchange._api_async.load_markets.call_count == 1
|
||||
caplog.set_level(logging.DEBUG)
|
||||
|
||||
exchange._api_async.load_markets = Mock(side_effect=ccxt.BaseError("deadbeef"))
|
||||
exchange._api_async.load_markets=Mock(side_effect = ccxt.BaseError("deadbeef"))
|
||||
exchange._load_async_markets()
|
||||
|
||||
assert log_has('Could not load async markets. Reason: deadbeef', caplog)
|
||||
@@ -551,8 +533,8 @@ def test__load_async_markets(default_conf, mocker, caplog):
|
||||
|
||||
def test__load_markets(default_conf, mocker, caplog):
|
||||
caplog.set_level(logging.INFO)
|
||||
api_mock = MagicMock()
|
||||
api_mock.load_markets = MagicMock(side_effect=ccxt.BaseError("SomeError"))
|
||||
api_mock=MagicMock()
|
||||
api_mock.load_markets=MagicMock(side_effect = ccxt.BaseError("SomeError"))
|
||||
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
||||
mocker.patch('freqtrade.exchange.Exchange.validate_pairs')
|
||||
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes')
|
||||
@@ -561,28 +543,28 @@ def test__load_markets(default_conf, mocker, caplog):
|
||||
Exchange(default_conf)
|
||||
assert log_has('Unable to initialize markets.', caplog)
|
||||
|
||||
expected_return = {'ETH/BTC': 'available'}
|
||||
api_mock = MagicMock()
|
||||
api_mock.load_markets = MagicMock(return_value=expected_return)
|
||||
expected_return={'ETH/BTC': 'available'}
|
||||
api_mock=MagicMock()
|
||||
api_mock.load_markets=MagicMock(return_value = expected_return)
|
||||
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
||||
default_conf['exchange']['pair_whitelist'] = ['ETH/BTC']
|
||||
ex = Exchange(default_conf)
|
||||
default_conf['exchange']['pair_whitelist']=['ETH/BTC']
|
||||
ex=Exchange(default_conf)
|
||||
|
||||
assert ex.markets == expected_return
|
||||
|
||||
|
||||
def test_reload_markets(default_conf, mocker, caplog):
|
||||
caplog.set_level(logging.DEBUG)
|
||||
initial_markets = {'ETH/BTC': {}}
|
||||
updated_markets = {'ETH/BTC': {}, "LTC/BTC": {}}
|
||||
initial_markets={'ETH/BTC': {}}
|
||||
updated_markets={'ETH/BTC': {}, "LTC/BTC": {}}
|
||||
|
||||
api_mock = MagicMock()
|
||||
api_mock.load_markets = MagicMock(return_value=initial_markets)
|
||||
default_conf['exchange']['markets_refresh_interval'] = 10
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="binance",
|
||||
mock_markets=False)
|
||||
exchange._load_async_markets = MagicMock()
|
||||
exchange._last_markets_refresh = arrow.utcnow().int_timestamp
|
||||
api_mock=MagicMock()
|
||||
api_mock.load_markets=MagicMock(return_value = initial_markets)
|
||||
default_conf['exchange']['markets_refresh_interval']=10
|
||||
exchange=get_patched_exchange(mocker, default_conf, api_mock, id = "binance",
|
||||
mock_markets = False)
|
||||
exchange._load_async_markets=MagicMock()
|
||||
exchange._last_markets_refresh=arrow.utcnow().int_timestamp
|
||||
|
||||
assert exchange.markets == initial_markets
|
||||
|
||||
@@ -591,9 +573,9 @@ def test_reload_markets(default_conf, mocker, caplog):
|
||||
assert exchange.markets == initial_markets
|
||||
assert exchange._load_async_markets.call_count == 0
|
||||
|
||||
api_mock.load_markets = MagicMock(return_value=updated_markets)
|
||||
api_mock.load_markets=MagicMock(return_value = updated_markets)
|
||||
# more than 10 minutes have passed, reload is executed
|
||||
exchange._last_markets_refresh = arrow.utcnow().int_timestamp - 15 * 60
|
||||
exchange._last_markets_refresh=arrow.utcnow().int_timestamp - 15 * 60
|
||||
exchange.reload_markets()
|
||||
assert exchange.markets == updated_markets
|
||||
assert exchange._load_async_markets.call_count == 1
|
||||
@@ -603,10 +585,10 @@ def test_reload_markets(default_conf, mocker, caplog):
|
||||
def test_reload_markets_exception(default_conf, mocker, caplog):
|
||||
caplog.set_level(logging.DEBUG)
|
||||
|
||||
api_mock = MagicMock()
|
||||
api_mock.load_markets = MagicMock(side_effect=ccxt.NetworkError("LoadError"))
|
||||
default_conf['exchange']['markets_refresh_interval'] = 10
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="binance")
|
||||
api_mock=MagicMock()
|
||||
api_mock.load_markets=MagicMock(side_effect = ccxt.NetworkError("LoadError"))
|
||||
default_conf['exchange']['markets_refresh_interval']=10
|
||||
exchange=get_patched_exchange(mocker, default_conf, api_mock, id = "binance")
|
||||
|
||||
# less than 10 minutes have passed, no reload
|
||||
exchange.reload_markets()
|
||||
@@ -614,11 +596,11 @@ def test_reload_markets_exception(default_conf, mocker, caplog):
|
||||
assert log_has_re(r"Could not reload markets.*", caplog)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("stake_currency", ['ETH', 'BTC', 'USDT'])
|
||||
@ pytest.mark.parametrize("stake_currency", ['ETH', 'BTC', 'USDT'])
|
||||
def test_validate_stakecurrency(default_conf, stake_currency, mocker, caplog):
|
||||
default_conf['stake_currency'] = stake_currency
|
||||
api_mock = MagicMock()
|
||||
type(api_mock).load_markets = MagicMock(return_value={
|
||||
default_conf['stake_currency']=stake_currency
|
||||
api_mock=MagicMock()
|
||||
type(api_mock).load_markets=MagicMock(return_value = {
|
||||
'ETH/BTC': {'quote': 'BTC'}, 'LTC/BTC': {'quote': 'BTC'},
|
||||
'XRP/ETH': {'quote': 'ETH'}, 'NEO/USDT': {'quote': 'USDT'},
|
||||
})
|
||||
@@ -630,9 +612,9 @@ def test_validate_stakecurrency(default_conf, stake_currency, mocker, caplog):
|
||||
|
||||
|
||||
def test_validate_stakecurrency_error(default_conf, mocker, caplog):
|
||||
default_conf['stake_currency'] = 'XRP'
|
||||
api_mock = MagicMock()
|
||||
type(api_mock).load_markets = MagicMock(return_value={
|
||||
default_conf['stake_currency']='XRP'
|
||||
api_mock=MagicMock()
|
||||
type(api_mock).load_markets=MagicMock(return_value = {
|
||||
'ETH/BTC': {'quote': 'BTC'}, 'LTC/BTC': {'quote': 'BTC'},
|
||||
'XRP/ETH': {'quote': 'ETH'}, 'NEO/USDT': {'quote': 'USDT'},
|
||||
})
|
||||
@@ -1004,7 +986,13 @@ def test_create_dry_run_order(default_conf, mocker, side, exchange_name):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
|
||||
order = exchange.create_dry_run_order(
|
||||
pair='ETH/BTC', ordertype='limit', side=side, amount=1, rate=200)
|
||||
pair='ETH/BTC',
|
||||
ordertype='limit',
|
||||
side=side,
|
||||
amount=1,
|
||||
rate=200,
|
||||
leverage=1.0
|
||||
)
|
||||
assert 'id' in order
|
||||
assert f'dry_run_{side}_' in order["id"]
|
||||
assert order["side"] == side
|
||||
@@ -1027,7 +1015,13 @@ def test_create_dry_run_order_limit_fill(default_conf, mocker, side, startprice,
|
||||
)
|
||||
|
||||
order = exchange.create_dry_run_order(
|
||||
pair='LTC/USDT', ordertype='limit', side=side, amount=1, rate=startprice)
|
||||
pair='LTC/USDT',
|
||||
ordertype='limit',
|
||||
side=side,
|
||||
amount=1,
|
||||
rate=startprice,
|
||||
leverage=1.0
|
||||
)
|
||||
assert order_book_l2_usd.call_count == 1
|
||||
assert 'id' in order
|
||||
assert f'dry_run_{side}_' in order["id"]
|
||||
@@ -1073,7 +1067,13 @@ def test_create_dry_run_order_market_fill(default_conf, mocker, side, rate, amou
|
||||
)
|
||||
|
||||
order = exchange.create_dry_run_order(
|
||||
pair='LTC/USDT', ordertype='market', side=side, amount=amount, rate=rate)
|
||||
pair='LTC/USDT',
|
||||
ordertype='market',
|
||||
side=side,
|
||||
amount=amount,
|
||||
rate=rate,
|
||||
leverage=1.0
|
||||
)
|
||||
assert 'id' in order
|
||||
assert f'dry_run_{side}_' in order["id"]
|
||||
assert order["side"] == side
|
||||
@@ -1083,10 +1083,7 @@ def test_create_dry_run_order_market_fill(default_conf, mocker, side, rate, amou
|
||||
assert round(order["average"], 4) == round(endprice, 4)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("side", [
|
||||
("buy"),
|
||||
("sell")
|
||||
])
|
||||
@pytest.mark.parametrize("side", ["buy", "sell"])
|
||||
@pytest.mark.parametrize("ordertype,rate,marketprice", [
|
||||
("market", None, None),
|
||||
("market", 200, True),
|
||||
@@ -1108,9 +1105,17 @@ def test_create_order(default_conf, mocker, side, ordertype, rate, marketprice,
|
||||
mocker.patch('freqtrade.exchange.Exchange.amount_to_precision', lambda s, x, y: y)
|
||||
mocker.patch('freqtrade.exchange.Exchange.price_to_precision', lambda s, x, y: y)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange._set_leverage = MagicMock()
|
||||
exchange.set_margin_mode = MagicMock()
|
||||
|
||||
order = exchange.create_order(
|
||||
pair='ETH/BTC', ordertype=ordertype, side=side, amount=1, rate=200)
|
||||
pair='ETH/BTC',
|
||||
ordertype=ordertype,
|
||||
side=side,
|
||||
amount=1,
|
||||
rate=200,
|
||||
leverage=1.0
|
||||
)
|
||||
|
||||
assert 'id' in order
|
||||
assert 'info' in order
|
||||
@@ -1120,6 +1125,21 @@ def test_create_order(default_conf, mocker, side, ordertype, rate, marketprice,
|
||||
assert api_mock.create_order.call_args[0][2] == side
|
||||
assert api_mock.create_order.call_args[0][3] == 1
|
||||
assert api_mock.create_order.call_args[0][4] is rate
|
||||
assert exchange._set_leverage.call_count == 0
|
||||
assert exchange.set_margin_mode.call_count == 0
|
||||
|
||||
exchange.trading_mode = TradingMode.FUTURES
|
||||
order = exchange.create_order(
|
||||
pair='ETH/BTC',
|
||||
ordertype=ordertype,
|
||||
side=side,
|
||||
amount=1,
|
||||
rate=200,
|
||||
leverage=3.0
|
||||
)
|
||||
|
||||
assert exchange._set_leverage.call_count == 1
|
||||
assert exchange.set_margin_mode.call_count == 1
|
||||
|
||||
|
||||
def test_buy_dry_run(default_conf, mocker):
|
||||
@@ -2658,7 +2678,14 @@ def test_get_fee(default_conf, mocker, exchange_name):
|
||||
def test_stoploss_order_unsupported_exchange(default_conf, mocker):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id='bittrex')
|
||||
with pytest.raises(OperationalException, match=r"stoploss is not implemented .*"):
|
||||
exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side="sell")
|
||||
exchange.stoploss(
|
||||
pair='ETH/BTC',
|
||||
amount=1,
|
||||
stop_price=220,
|
||||
order_types={},
|
||||
side="sell",
|
||||
leverage=1.0
|
||||
)
|
||||
|
||||
with pytest.raises(OperationalException, match=r"stoploss is not implemented .*"):
|
||||
exchange.stoploss_adjust(1, {}, side="sell")
|
||||
@@ -3006,7 +3033,6 @@ def test_calculate_fee_rate(mocker, default_conf, order, expected) -> None:
|
||||
(3, 5, 5),
|
||||
(4, 5, 2),
|
||||
(5, 5, 1),
|
||||
|
||||
])
|
||||
def test_calculate_backoff(retrycount, max_retries, expected):
|
||||
assert calculate_backoff(retrycount, max_retries) == expected
|
||||
@@ -3018,7 +3044,7 @@ def test_calculate_backoff(retrycount, max_retries, expected):
|
||||
(20.0, 5.0, 4.0),
|
||||
(100.0, 100.0, 1.0)
|
||||
])
|
||||
def test_apply_leverage_to_stake_amount(
|
||||
def test_get_stake_amount_considering_leverage(
|
||||
exchange,
|
||||
stake_amount,
|
||||
leverage,
|
||||
@@ -3027,7 +3053,8 @@ def test_apply_leverage_to_stake_amount(
|
||||
default_conf
|
||||
):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange)
|
||||
assert exchange._apply_leverage_to_stake_amount(stake_amount, leverage) == min_stake_with_lev
|
||||
assert exchange._get_stake_amount_considering_leverage(
|
||||
stake_amount, leverage) == min_stake_with_lev
|
||||
|
||||
|
||||
@pytest.mark.parametrize("exchange_name,trading_mode", [
|
||||
@@ -3040,6 +3067,7 @@ def test__set_leverage(mocker, default_conf, exchange_name, trading_mode):
|
||||
api_mock = MagicMock()
|
||||
api_mock.set_leverage = MagicMock()
|
||||
type(api_mock).has = PropertyMock(return_value={'setLeverage': True})
|
||||
default_conf['dry_run'] = False
|
||||
|
||||
ccxt_exceptionhandlers(
|
||||
mocker,
|
||||
@@ -3063,6 +3091,7 @@ def test_set_margin_mode(mocker, default_conf, collateral):
|
||||
api_mock = MagicMock()
|
||||
api_mock.set_margin_mode = MagicMock()
|
||||
type(api_mock).has = PropertyMock(return_value={'setMarginMode': True})
|
||||
default_conf['dry_run'] = False
|
||||
|
||||
ccxt_exceptionhandlers(
|
||||
mocker,
|
||||
@@ -3117,7 +3146,8 @@ def test_validate_trading_mode_and_collateral(
|
||||
collateral,
|
||||
exception_thrown
|
||||
):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(
|
||||
mocker, default_conf, id=exchange_name, mock_supported_modes=False)
|
||||
if (exception_thrown):
|
||||
with pytest.raises(OperationalException):
|
||||
exchange.validate_trading_mode_and_collateral(trading_mode, collateral)
|
||||
|
@@ -37,8 +37,14 @@ def test_stoploss_order_ftx(default_conf, mocker, order_price, exchangelimitrati
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'ftx')
|
||||
|
||||
# stoploss_on_exchange_limit_ratio is irrelevant for ftx market orders
|
||||
order = exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=190, side=side,
|
||||
order_types={'stoploss_on_exchange_limit_ratio': exchangelimitratio})
|
||||
order = exchange.stoploss(
|
||||
pair='ETH/BTC',
|
||||
amount=1,
|
||||
stop_price=190,
|
||||
side=side,
|
||||
order_types={'stoploss_on_exchange_limit_ratio': exchangelimitratio},
|
||||
leverage=1.0
|
||||
)
|
||||
|
||||
assert api_mock.create_order.call_args_list[0][1]['symbol'] == 'ETH/BTC'
|
||||
assert api_mock.create_order.call_args_list[0][1]['type'] == STOPLOSS_ORDERTYPE
|
||||
@@ -52,7 +58,14 @@ def test_stoploss_order_ftx(default_conf, mocker, order_price, exchangelimitrati
|
||||
|
||||
api_mock.create_order.reset_mock()
|
||||
|
||||
order = exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side=side)
|
||||
order = exchange.stoploss(
|
||||
pair='ETH/BTC',
|
||||
amount=1,
|
||||
stop_price=220,
|
||||
order_types={},
|
||||
side=side,
|
||||
leverage=1.0
|
||||
)
|
||||
|
||||
assert 'id' in order
|
||||
assert 'info' in order
|
||||
@@ -65,8 +78,13 @@ def test_stoploss_order_ftx(default_conf, mocker, order_price, exchangelimitrati
|
||||
assert api_mock.create_order.call_args_list[0][1]['params']['stopPrice'] == 220
|
||||
|
||||
api_mock.create_order.reset_mock()
|
||||
order = exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220,
|
||||
order_types={'stoploss': 'limit'}, side=side)
|
||||
order = exchange.stoploss(
|
||||
pair='ETH/BTC',
|
||||
amount=1,
|
||||
stop_price=220,
|
||||
order_types={'stoploss': 'limit'}, side=side,
|
||||
leverage=1.0
|
||||
)
|
||||
|
||||
assert 'id' in order
|
||||
assert 'info' in order
|
||||
@@ -83,17 +101,32 @@ def test_stoploss_order_ftx(default_conf, mocker, order_price, exchangelimitrati
|
||||
with pytest.raises(DependencyException):
|
||||
api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds("0 balance"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'ftx')
|
||||
exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side=side)
|
||||
exchange.stoploss(
|
||||
pair='ETH/BTC',
|
||||
amount=1,
|
||||
stop_price=220,
|
||||
order_types={},
|
||||
side=side,
|
||||
leverage=1.0
|
||||
)
|
||||
|
||||
with pytest.raises(InvalidOrderException):
|
||||
api_mock.create_order = MagicMock(
|
||||
side_effect=ccxt.InvalidOrder("ftx Order would trigger immediately."))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'ftx')
|
||||
exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side=side)
|
||||
exchange.stoploss(
|
||||
pair='ETH/BTC',
|
||||
amount=1,
|
||||
stop_price=220,
|
||||
order_types={},
|
||||
side=side,
|
||||
leverage=1.0
|
||||
)
|
||||
|
||||
ccxt_exceptionhandlers(mocker, default_conf, api_mock, "ftx",
|
||||
"stoploss", "create_order", retries=1,
|
||||
pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side=side)
|
||||
pair='ETH/BTC', amount=1, stop_price=220, order_types={},
|
||||
side=side, leverage=1.0)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('side', [("sell"), ("buy")])
|
||||
@@ -107,7 +140,14 @@ def test_stoploss_order_dry_run_ftx(default_conf, mocker, side):
|
||||
|
||||
api_mock.create_order.reset_mock()
|
||||
|
||||
order = exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side=side)
|
||||
order = exchange.stoploss(
|
||||
pair='ETH/BTC',
|
||||
amount=1,
|
||||
stop_price=220,
|
||||
order_types={},
|
||||
side=side,
|
||||
leverage=1.0
|
||||
)
|
||||
|
||||
assert 'id' in order
|
||||
assert 'info' in order
|
||||
@@ -228,26 +268,3 @@ def test_fill_leverage_brackets_ftx(default_conf, mocker):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="ftx")
|
||||
exchange.fill_leverage_brackets()
|
||||
assert exchange._leverage_brackets == {}
|
||||
|
||||
|
||||
@pytest.mark.parametrize("trading_mode", [
|
||||
(TradingMode.MARGIN),
|
||||
(TradingMode.FUTURES)
|
||||
])
|
||||
def test__set_leverage(mocker, default_conf, trading_mode):
|
||||
|
||||
api_mock = MagicMock()
|
||||
api_mock.set_leverage = MagicMock()
|
||||
type(api_mock).has = PropertyMock(return_value={'setLeverage': True})
|
||||
|
||||
ccxt_exceptionhandlers(
|
||||
mocker,
|
||||
default_conf,
|
||||
api_mock,
|
||||
"ftx",
|
||||
"_set_leverage",
|
||||
"set_leverage",
|
||||
pair="XRP/USDT",
|
||||
leverage=5.0,
|
||||
trading_mode=trading_mode
|
||||
)
|
||||
|
@@ -197,7 +197,9 @@ def test_stoploss_order_kraken(default_conf, mocker, ordertype, side, adjustedpr
|
||||
order_types={
|
||||
'stoploss': ordertype,
|
||||
'stoploss_on_exchange_limit_ratio': 0.99
|
||||
})
|
||||
},
|
||||
leverage=1.0
|
||||
)
|
||||
|
||||
assert 'id' in order
|
||||
assert 'info' in order
|
||||
@@ -221,17 +223,32 @@ def test_stoploss_order_kraken(default_conf, mocker, ordertype, side, adjustedpr
|
||||
with pytest.raises(DependencyException):
|
||||
api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds("0 balance"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'kraken')
|
||||
exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side=side)
|
||||
exchange.stoploss(
|
||||
pair='ETH/BTC',
|
||||
amount=1,
|
||||
stop_price=220,
|
||||
order_types={},
|
||||
side=side,
|
||||
leverage=1.0
|
||||
)
|
||||
|
||||
with pytest.raises(InvalidOrderException):
|
||||
api_mock.create_order = MagicMock(
|
||||
side_effect=ccxt.InvalidOrder("kraken Order would trigger immediately."))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'kraken')
|
||||
exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side=side)
|
||||
exchange.stoploss(
|
||||
pair='ETH/BTC',
|
||||
amount=1,
|
||||
stop_price=220,
|
||||
order_types={},
|
||||
side=side,
|
||||
leverage=1.0
|
||||
)
|
||||
|
||||
ccxt_exceptionhandlers(mocker, default_conf, api_mock, "kraken",
|
||||
"stoploss", "create_order", retries=1,
|
||||
pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side=side)
|
||||
pair='ETH/BTC', amount=1, stop_price=220, order_types={},
|
||||
side=side, leverage=1.0)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('side', ['buy', 'sell'])
|
||||
@@ -245,7 +262,14 @@ def test_stoploss_order_dry_run_kraken(default_conf, mocker, side):
|
||||
|
||||
api_mock.create_order.reset_mock()
|
||||
|
||||
order = exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side=side)
|
||||
order = exchange.stoploss(
|
||||
pair='ETH/BTC',
|
||||
amount=1,
|
||||
stop_price=220,
|
||||
order_types={},
|
||||
side=side,
|
||||
leverage=1.0
|
||||
)
|
||||
|
||||
assert 'id' in order
|
||||
assert 'info' in order
|
||||
@@ -307,15 +331,3 @@ def test_fill_leverage_brackets_kraken(default_conf, mocker):
|
||||
'XLTCUSDT': [1],
|
||||
'LTC/ETH': [1]
|
||||
}
|
||||
|
||||
|
||||
def test__set_leverage_kraken(default_conf, mocker):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="kraken")
|
||||
exchange._set_leverage(1)
|
||||
assert 'leverage' not in exchange._params
|
||||
exchange._set_leverage(3)
|
||||
assert exchange._params['leverage'] == 3
|
||||
exchange._set_leverage(1.0)
|
||||
assert 'leverage' not in exchange._params
|
||||
exchange._set_leverage(3.0)
|
||||
assert exchange._params['leverage'] == 3
|
||||
|
Reference in New Issue
Block a user