|
|
|
@@ -22,8 +22,8 @@ from freqtrade.exchange.common import (API_FETCH_ORDER_RETRY_COUNT, API_RETRY_CO
|
|
|
|
|
calculate_backoff, remove_credentials)
|
|
|
|
|
from freqtrade.exchange.exchange import amount_to_contract_precision
|
|
|
|
|
from freqtrade.resolvers.exchange_resolver import ExchangeResolver
|
|
|
|
|
from tests.conftest import (generate_test_data_raw, get_mock_coro, get_patched_exchange, log_has,
|
|
|
|
|
log_has_re, num_log_has_re)
|
|
|
|
|
from tests.conftest import (EXMS, generate_test_data_raw, get_mock_coro, get_patched_exchange,
|
|
|
|
|
log_has, log_has_re, num_log_has_re)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Make sure to always keep one exchange here which is NOT subclassed!!
|
|
|
|
@@ -150,9 +150,9 @@ def test_remove_credentials(default_conf, caplog) -> None:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_init_ccxt_kwargs(default_conf, mocker, caplog):
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={}))
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
|
|
|
|
|
aei_mock = mocker.patch('freqtrade.exchange.Exchange.additional_exchange_init')
|
|
|
|
|
mocker.patch(f'{EXMS}._load_markets', MagicMock(return_value={}))
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_stakecurrency')
|
|
|
|
|
aei_mock = mocker.patch(f'{EXMS}.additional_exchange_init')
|
|
|
|
|
|
|
|
|
|
caplog.set_level(logging.INFO)
|
|
|
|
|
conf = copy.deepcopy(default_conf)
|
|
|
|
@@ -218,12 +218,12 @@ def test_init_exception(default_conf, mocker):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_exchange_resolver(default_conf, mocker, caplog):
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=MagicMock()))
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._load_async_markets')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_pairs')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_pricing')
|
|
|
|
|
mocker.patch(f'{EXMS}._init_ccxt', MagicMock(return_value=MagicMock()))
|
|
|
|
|
mocker.patch(f'{EXMS}._load_async_markets')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pairs')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_timeframes')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_stakecurrency')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pricing')
|
|
|
|
|
|
|
|
|
|
exchange = ExchangeResolver.load_exchange('zaif', default_conf)
|
|
|
|
|
assert isinstance(exchange, Exchange)
|
|
|
|
@@ -362,9 +362,8 @@ def test_price_to_precision(price, precision_mode, precision, expected):
|
|
|
|
|
def test_price_get_one_pip(default_conf, mocker, price, precision_mode, precision, expected):
|
|
|
|
|
markets = PropertyMock(return_value={'ETH/BTC': {'precision': {'price': precision}}})
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, id="binance")
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.markets', markets)
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.precisionMode',
|
|
|
|
|
PropertyMock(return_value=precision_mode))
|
|
|
|
|
mocker.patch(f'{EXMS}.markets', markets)
|
|
|
|
|
mocker.patch(f'{EXMS}.precisionMode', PropertyMock(return_value=precision_mode))
|
|
|
|
|
pair = 'ETH/BTC'
|
|
|
|
|
assert pytest.approx(exchange.price_get_one_pip(pair, price)) == expected
|
|
|
|
|
|
|
|
|
@@ -376,10 +375,7 @@ def test__get_stake_amount_limit(mocker, default_conf) -> None:
|
|
|
|
|
markets = {'ETH/BTC': {'symbol': 'ETH/BTC'}}
|
|
|
|
|
|
|
|
|
|
# no pair found
|
|
|
|
|
mocker.patch(
|
|
|
|
|
'freqtrade.exchange.Exchange.markets',
|
|
|
|
|
PropertyMock(return_value=markets)
|
|
|
|
|
)
|
|
|
|
|
mocker.patch(f'{EXMS}.markets', PropertyMock(return_value=markets))
|
|
|
|
|
with pytest.raises(ValueError, match=r'.*get market information.*'):
|
|
|
|
|
exchange.get_min_pair_stake_amount('BNB/BTC', 1, stoploss)
|
|
|
|
|
|
|
|
|
@@ -388,10 +384,7 @@ def test__get_stake_amount_limit(mocker, default_conf) -> None:
|
|
|
|
|
'cost': {'min': None, 'max': None},
|
|
|
|
|
'amount': {'min': None, 'max': None},
|
|
|
|
|
}
|
|
|
|
|
mocker.patch(
|
|
|
|
|
'freqtrade.exchange.Exchange.markets',
|
|
|
|
|
PropertyMock(return_value=markets)
|
|
|
|
|
)
|
|
|
|
|
mocker.patch(f'{EXMS}.markets', PropertyMock(return_value=markets))
|
|
|
|
|
result = exchange.get_min_pair_stake_amount('ETH/BTC', 1, stoploss)
|
|
|
|
|
assert result is None
|
|
|
|
|
result = exchange.get_max_pair_stake_amount('ETH/BTC', 1)
|
|
|
|
@@ -402,10 +395,7 @@ def test__get_stake_amount_limit(mocker, default_conf) -> None:
|
|
|
|
|
'cost': {'min': 2, 'max': 10000},
|
|
|
|
|
'amount': {'min': None, 'max': None},
|
|
|
|
|
}
|
|
|
|
|
mocker.patch(
|
|
|
|
|
'freqtrade.exchange.Exchange.markets',
|
|
|
|
|
PropertyMock(return_value=markets)
|
|
|
|
|
)
|
|
|
|
|
mocker.patch(f'{EXMS}.markets', PropertyMock(return_value=markets))
|
|
|
|
|
# min
|
|
|
|
|
result = exchange.get_min_pair_stake_amount('ETH/BTC', 1, stoploss)
|
|
|
|
|
expected_result = 2 * (1 + 0.05) / (1 - abs(stoploss))
|
|
|
|
@@ -422,10 +412,7 @@ def test__get_stake_amount_limit(mocker, default_conf) -> None:
|
|
|
|
|
'cost': {'min': None, 'max': None},
|
|
|
|
|
'amount': {'min': 2, 'max': 10000},
|
|
|
|
|
}
|
|
|
|
|
mocker.patch(
|
|
|
|
|
'freqtrade.exchange.Exchange.markets',
|
|
|
|
|
PropertyMock(return_value=markets)
|
|
|
|
|
)
|
|
|
|
|
mocker.patch(f'{EXMS}.markets', PropertyMock(return_value=markets))
|
|
|
|
|
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss)
|
|
|
|
|
expected_result = 2 * 2 * (1 + 0.05) / (1 - abs(stoploss))
|
|
|
|
|
assert pytest.approx(result) == expected_result
|
|
|
|
@@ -441,10 +428,7 @@ def test__get_stake_amount_limit(mocker, default_conf) -> None:
|
|
|
|
|
'cost': {'min': 2, 'max': None},
|
|
|
|
|
'amount': {'min': 2, 'max': None},
|
|
|
|
|
}
|
|
|
|
|
mocker.patch(
|
|
|
|
|
'freqtrade.exchange.Exchange.markets',
|
|
|
|
|
PropertyMock(return_value=markets)
|
|
|
|
|
)
|
|
|
|
|
mocker.patch(f'{EXMS}.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))
|
|
|
|
|
assert pytest.approx(result) == expected_result
|
|
|
|
@@ -457,10 +441,7 @@ def test__get_stake_amount_limit(mocker, default_conf) -> None:
|
|
|
|
|
'cost': {'min': 8, 'max': 10000},
|
|
|
|
|
'amount': {'min': 2, 'max': 500},
|
|
|
|
|
}
|
|
|
|
|
mocker.patch(
|
|
|
|
|
'freqtrade.exchange.Exchange.markets',
|
|
|
|
|
PropertyMock(return_value=markets)
|
|
|
|
|
)
|
|
|
|
|
mocker.patch(f'{EXMS}.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))
|
|
|
|
|
assert pytest.approx(result) == expected_result
|
|
|
|
@@ -496,10 +477,7 @@ def test__get_stake_amount_limit(mocker, default_conf) -> None:
|
|
|
|
|
default_conf['trading_mode'] = 'futures'
|
|
|
|
|
default_conf['margin_mode'] = 'isolated'
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, id="binance")
|
|
|
|
|
mocker.patch(
|
|
|
|
|
'freqtrade.exchange.Exchange.markets',
|
|
|
|
|
PropertyMock(return_value=markets)
|
|
|
|
|
)
|
|
|
|
|
mocker.patch(f'{EXMS}.markets', PropertyMock(return_value=markets))
|
|
|
|
|
|
|
|
|
|
# Contract size 0.01
|
|
|
|
|
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, -1)
|
|
|
|
@@ -509,10 +487,7 @@ def test__get_stake_amount_limit(mocker, default_conf) -> None:
|
|
|
|
|
assert result == 10
|
|
|
|
|
|
|
|
|
|
markets["ETH/BTC"]["contractSize"] = '10'
|
|
|
|
|
mocker.patch(
|
|
|
|
|
'freqtrade.exchange.Exchange.markets',
|
|
|
|
|
PropertyMock(return_value=markets)
|
|
|
|
|
)
|
|
|
|
|
mocker.patch(f'{EXMS}.markets', PropertyMock(return_value=markets))
|
|
|
|
|
# With Leverage, Contract size 10
|
|
|
|
|
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, -1, 12.0)
|
|
|
|
|
assert pytest.approx(result) == (expected_result / 12) * 10.0
|
|
|
|
@@ -531,10 +506,7 @@ def test_get_min_pair_stake_amount_real_data(mocker, default_conf) -> None:
|
|
|
|
|
'cost': {'min': 0.0001, 'max': 4000},
|
|
|
|
|
'amount': {'min': 0.001, 'max': 10000},
|
|
|
|
|
}
|
|
|
|
|
mocker.patch(
|
|
|
|
|
'freqtrade.exchange.Exchange.markets',
|
|
|
|
|
PropertyMock(return_value=markets)
|
|
|
|
|
)
|
|
|
|
|
mocker.patch(f'{EXMS}.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))
|
|
|
|
|
assert round(result, 8) == round(expected_result, 8)
|
|
|
|
@@ -592,12 +564,12 @@ def test_set_sandbox_exception(default_conf, mocker):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test__load_async_markets(default_conf, mocker, caplog):
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_pairs')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._load_markets')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_pricing')
|
|
|
|
|
mocker.patch(f'{EXMS}._init_ccxt')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pairs')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_timeframes')
|
|
|
|
|
mocker.patch(f'{EXMS}._load_markets')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_stakecurrency')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pricing')
|
|
|
|
|
exchange = Exchange(default_conf)
|
|
|
|
|
exchange._api_async.load_markets = get_mock_coro(None)
|
|
|
|
|
exchange._load_async_markets()
|
|
|
|
@@ -614,19 +586,19 @@ 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"))
|
|
|
|
|
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')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._load_async_markets')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_pricing')
|
|
|
|
|
mocker.patch(f'{EXMS}._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pairs')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_timeframes')
|
|
|
|
|
mocker.patch(f'{EXMS}._load_async_markets')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_stakecurrency')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pricing')
|
|
|
|
|
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)
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch(f'{EXMS}._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
default_conf['exchange']['pair_whitelist'] = ['ETH/BTC']
|
|
|
|
|
ex = Exchange(default_conf)
|
|
|
|
|
|
|
|
|
@@ -684,11 +656,11 @@ def test_validate_stakecurrency(default_conf, stake_currency, mocker, caplog):
|
|
|
|
|
'ETH/BTC': {'quote': 'BTC'}, 'LTC/BTC': {'quote': 'BTC'},
|
|
|
|
|
'XRP/ETH': {'quote': 'ETH'}, 'NEO/USDT': {'quote': 'USDT'},
|
|
|
|
|
})
|
|
|
|
|
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')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._load_async_markets')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_pricing')
|
|
|
|
|
mocker.patch(f'{EXMS}._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pairs')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_timeframes')
|
|
|
|
|
mocker.patch(f'{EXMS}._load_async_markets')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pricing')
|
|
|
|
|
Exchange(default_conf)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -699,17 +671,17 @@ def test_validate_stakecurrency_error(default_conf, mocker, caplog):
|
|
|
|
|
'ETH/BTC': {'quote': 'BTC'}, 'LTC/BTC': {'quote': 'BTC'},
|
|
|
|
|
'XRP/ETH': {'quote': 'ETH'}, 'NEO/USDT': {'quote': 'USDT'},
|
|
|
|
|
})
|
|
|
|
|
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')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._load_async_markets')
|
|
|
|
|
mocker.patch(f'{EXMS}._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pairs')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_timeframes')
|
|
|
|
|
mocker.patch(f'{EXMS}._load_async_markets')
|
|
|
|
|
with pytest.raises(OperationalException,
|
|
|
|
|
match=r'XRP is not available as stake on .*'
|
|
|
|
|
'Available currencies are: BTC, ETH, USDT'):
|
|
|
|
|
Exchange(default_conf)
|
|
|
|
|
|
|
|
|
|
type(api_mock).load_markets = MagicMock(side_effect=ccxt.NetworkError('No connection.'))
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch(f'{EXMS}._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
|
|
|
|
|
with pytest.raises(OperationalException,
|
|
|
|
|
match=r'Could not load markets, therefore cannot start\. Please.*'):
|
|
|
|
@@ -757,11 +729,11 @@ def test_validate_pairs(default_conf, mocker): # test exchange.validate_pairs d
|
|
|
|
|
id_mock = PropertyMock(return_value='test_exchange')
|
|
|
|
|
type(api_mock).id = id_mock
|
|
|
|
|
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._load_async_markets')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_pricing')
|
|
|
|
|
mocker.patch(f'{EXMS}._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_timeframes')
|
|
|
|
|
mocker.patch(f'{EXMS}._load_async_markets')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_stakecurrency')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pricing')
|
|
|
|
|
Exchange(default_conf)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -770,10 +742,10 @@ def test_validate_pairs_not_available(default_conf, mocker):
|
|
|
|
|
type(api_mock).markets = PropertyMock(return_value={
|
|
|
|
|
'XRP/BTC': {'inactive': True, 'base': 'XRP', 'quote': 'BTC'}
|
|
|
|
|
})
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._load_async_markets')
|
|
|
|
|
mocker.patch(f'{EXMS}._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_timeframes')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_stakecurrency')
|
|
|
|
|
mocker.patch(f'{EXMS}._load_async_markets')
|
|
|
|
|
|
|
|
|
|
with pytest.raises(OperationalException, match=r'not available'):
|
|
|
|
|
Exchange(default_conf)
|
|
|
|
@@ -782,19 +754,19 @@ def test_validate_pairs_not_available(default_conf, mocker):
|
|
|
|
|
def test_validate_pairs_exception(default_conf, mocker, caplog):
|
|
|
|
|
caplog.set_level(logging.INFO)
|
|
|
|
|
api_mock = MagicMock()
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.name', PropertyMock(return_value='Binance'))
|
|
|
|
|
mocker.patch(f'{EXMS}.name', PropertyMock(return_value='Binance'))
|
|
|
|
|
|
|
|
|
|
type(api_mock).markets = PropertyMock(return_value={})
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', api_mock)
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_pricing')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._load_async_markets')
|
|
|
|
|
mocker.patch(f'{EXMS}._init_ccxt', api_mock)
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_timeframes')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_stakecurrency')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pricing')
|
|
|
|
|
mocker.patch(f'{EXMS}._load_async_markets')
|
|
|
|
|
|
|
|
|
|
with pytest.raises(OperationalException, match=r'Pair ETH/BTC is not available on Binance'):
|
|
|
|
|
Exchange(default_conf)
|
|
|
|
|
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.markets', PropertyMock(return_value={}))
|
|
|
|
|
mocker.patch(f'{EXMS}.markets', PropertyMock(return_value={}))
|
|
|
|
|
Exchange(default_conf)
|
|
|
|
|
assert log_has('Unable to validate pairs (assuming they are correct).', caplog)
|
|
|
|
|
|
|
|
|
@@ -806,11 +778,11 @@ def test_validate_pairs_restricted(default_conf, mocker, caplog):
|
|
|
|
|
'XRP/BTC': {'quote': 'BTC', 'info': {'prohibitedIn': ['US']}},
|
|
|
|
|
'NEO/BTC': {'quote': 'BTC', 'info': 'TestString'}, # info can also be a string ...
|
|
|
|
|
})
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._load_async_markets')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_pricing')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
|
|
|
|
|
mocker.patch(f'{EXMS}._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_timeframes')
|
|
|
|
|
mocker.patch(f'{EXMS}._load_async_markets')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pricing')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_stakecurrency')
|
|
|
|
|
|
|
|
|
|
Exchange(default_conf)
|
|
|
|
|
assert log_has("Pair XRP/BTC is restricted for some users on this exchange."
|
|
|
|
@@ -825,11 +797,11 @@ def test_validate_pairs_stakecompatibility(default_conf, mocker, caplog):
|
|
|
|
|
'XRP/BTC': {'quote': 'BTC'}, 'NEO/BTC': {'quote': 'BTC'},
|
|
|
|
|
'HELLO-WORLD': {'quote': 'BTC'},
|
|
|
|
|
})
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._load_async_markets')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_pricing')
|
|
|
|
|
mocker.patch(f'{EXMS}._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_timeframes')
|
|
|
|
|
mocker.patch(f'{EXMS}._load_async_markets')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_stakecurrency')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pricing')
|
|
|
|
|
|
|
|
|
|
Exchange(default_conf)
|
|
|
|
|
|
|
|
|
@@ -842,11 +814,11 @@ def test_validate_pairs_stakecompatibility_downloaddata(default_conf, mocker, ca
|
|
|
|
|
'XRP/BTC': {'quote': 'BTC'}, 'NEO/BTC': {'quote': 'BTC'},
|
|
|
|
|
'HELLO-WORLD': {'quote': 'BTC'},
|
|
|
|
|
})
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._load_async_markets')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_pricing')
|
|
|
|
|
mocker.patch(f'{EXMS}._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_timeframes')
|
|
|
|
|
mocker.patch(f'{EXMS}._load_async_markets')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_stakecurrency')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pricing')
|
|
|
|
|
|
|
|
|
|
Exchange(default_conf)
|
|
|
|
|
assert type(api_mock).load_markets.call_count == 1
|
|
|
|
@@ -860,10 +832,10 @@ def test_validate_pairs_stakecompatibility_fail(default_conf, mocker, caplog):
|
|
|
|
|
'XRP/BTC': {'quote': 'BTC'}, 'NEO/BTC': {'quote': 'BTC'},
|
|
|
|
|
'HELLO-WORLD': {'quote': 'USDT'},
|
|
|
|
|
})
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._load_async_markets')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
|
|
|
|
|
mocker.patch(f'{EXMS}._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_timeframes')
|
|
|
|
|
mocker.patch(f'{EXMS}._load_async_markets')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_stakecurrency')
|
|
|
|
|
|
|
|
|
|
with pytest.raises(OperationalException, match=r"Stake-currency 'BTC' not compatible with.*"):
|
|
|
|
|
Exchange(default_conf)
|
|
|
|
@@ -883,11 +855,11 @@ def test_validate_timeframes(default_conf, mocker, timeframe):
|
|
|
|
|
'1h': '1h'})
|
|
|
|
|
type(api_mock).timeframes = timeframes
|
|
|
|
|
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={}))
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_pairs')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_pricing')
|
|
|
|
|
mocker.patch(f'{EXMS}._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch(f'{EXMS}._load_markets', MagicMock(return_value={}))
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pairs')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_stakecurrency')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pricing')
|
|
|
|
|
Exchange(default_conf)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -903,9 +875,9 @@ def test_validate_timeframes_failed(default_conf, mocker):
|
|
|
|
|
'1h': '1h'})
|
|
|
|
|
type(api_mock).timeframes = timeframes
|
|
|
|
|
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={}))
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock())
|
|
|
|
|
mocker.patch(f'{EXMS}._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch(f'{EXMS}._load_markets', MagicMock(return_value={}))
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pairs', MagicMock())
|
|
|
|
|
with pytest.raises(OperationalException,
|
|
|
|
|
match=r"Invalid timeframe '3m'. This exchange supports.*"):
|
|
|
|
|
Exchange(default_conf)
|
|
|
|
@@ -925,10 +897,10 @@ def test_validate_timeframes_emulated_ohlcv_1(default_conf, mocker):
|
|
|
|
|
# delete timeframes so magicmock does not autocreate it
|
|
|
|
|
del api_mock.timeframes
|
|
|
|
|
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={}))
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_pairs')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
|
|
|
|
|
mocker.patch(f'{EXMS}._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch(f'{EXMS}._load_markets', MagicMock(return_value={}))
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pairs')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_stakecurrency')
|
|
|
|
|
with pytest.raises(OperationalException,
|
|
|
|
|
match=r'The ccxt library does not provide the list of timeframes '
|
|
|
|
|
r'for the exchange .* and this exchange '
|
|
|
|
@@ -945,11 +917,11 @@ def test_validate_timeframes_emulated_ohlcvi_2(default_conf, mocker):
|
|
|
|
|
# delete timeframes so magicmock does not autocreate it
|
|
|
|
|
del api_mock.timeframes
|
|
|
|
|
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._load_markets',
|
|
|
|
|
mocker.patch(f'{EXMS}._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch(f'{EXMS}._load_markets',
|
|
|
|
|
MagicMock(return_value={'timeframes': None}))
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock())
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pairs', MagicMock())
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_stakecurrency')
|
|
|
|
|
with pytest.raises(OperationalException,
|
|
|
|
|
match=r'The ccxt library does not provide the list of timeframes '
|
|
|
|
|
r'for the exchange .* and this exchange '
|
|
|
|
@@ -969,12 +941,12 @@ def test_validate_timeframes_not_in_config(default_conf, mocker):
|
|
|
|
|
'1h': '1h'})
|
|
|
|
|
type(api_mock).timeframes = timeframes
|
|
|
|
|
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={}))
|
|
|
|
|
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')
|
|
|
|
|
mocker.patch(f'{EXMS}._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch(f'{EXMS}._load_markets', MagicMock(return_value={}))
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pairs')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_stakecurrency')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pricing')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_required_startup_candles')
|
|
|
|
|
Exchange(default_conf)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -985,13 +957,13 @@ def test_validate_pricing(default_conf, mocker):
|
|
|
|
|
'fetchTicker': True,
|
|
|
|
|
}
|
|
|
|
|
type(api_mock).has = PropertyMock(return_value=has)
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={}))
|
|
|
|
|
mocker.patch('freqtrade.exchange.exchange.Exchange.validate_trading_mode_and_margin_mode')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_pairs')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.name', 'Binance')
|
|
|
|
|
mocker.patch(f'{EXMS}._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch(f'{EXMS}._load_markets', MagicMock(return_value={}))
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_trading_mode_and_margin_mode')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pairs')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_timeframes')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_stakecurrency')
|
|
|
|
|
mocker.patch(f'{EXMS}.name', 'Binance')
|
|
|
|
|
ExchangeResolver.load_exchange('binance', default_conf)
|
|
|
|
|
has.update({'fetchTicker': False})
|
|
|
|
|
with pytest.raises(OperationalException, match="Ticker pricing not available for .*"):
|
|
|
|
@@ -1020,13 +992,13 @@ def test_validate_ordertypes(default_conf, mocker):
|
|
|
|
|
api_mock = MagicMock()
|
|
|
|
|
|
|
|
|
|
type(api_mock).has = PropertyMock(return_value={'createMarketOrder': True})
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={}))
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_pairs')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_pricing')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.name', 'Bittrex')
|
|
|
|
|
mocker.patch(f'{EXMS}._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch(f'{EXMS}._load_markets', MagicMock(return_value={}))
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pairs')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_timeframes')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_stakecurrency')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pricing')
|
|
|
|
|
mocker.patch(f'{EXMS}.name', 'Bittrex')
|
|
|
|
|
|
|
|
|
|
default_conf['order_types'] = {
|
|
|
|
|
'entry': 'limit',
|
|
|
|
@@ -1037,7 +1009,7 @@ def test_validate_ordertypes(default_conf, mocker):
|
|
|
|
|
Exchange(default_conf)
|
|
|
|
|
|
|
|
|
|
type(api_mock).has = PropertyMock(return_value={'createMarketOrder': False})
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch(f'{EXMS}._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
|
|
|
|
|
default_conf['order_types'] = {
|
|
|
|
|
'entry': 'limit',
|
|
|
|
@@ -1080,12 +1052,12 @@ def test_validate_ordertypes_stop_advanced(default_conf, mocker, exchange_name,
|
|
|
|
|
default_conf['trading_mode'] = TradingMode.FUTURES
|
|
|
|
|
default_conf['margin_mode'] = MarginMode.ISOLATED
|
|
|
|
|
type(api_mock).has = PropertyMock(return_value={'createMarketOrder': True})
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={}))
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_pairs')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_pricing')
|
|
|
|
|
mocker.patch(f'{EXMS}._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch(f'{EXMS}._load_markets', MagicMock(return_value={}))
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pairs')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_timeframes')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_stakecurrency')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pricing')
|
|
|
|
|
default_conf['order_types'] = {
|
|
|
|
|
'entry': 'limit',
|
|
|
|
|
'exit': 'limit',
|
|
|
|
@@ -1103,12 +1075,12 @@ def test_validate_ordertypes_stop_advanced(default_conf, mocker, exchange_name,
|
|
|
|
|
|
|
|
|
|
def test_validate_order_types_not_in_config(default_conf, mocker):
|
|
|
|
|
api_mock = MagicMock()
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={}))
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_pairs')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_pricing')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
|
|
|
|
|
mocker.patch(f'{EXMS}._init_ccxt', MagicMock(return_value=api_mock))
|
|
|
|
|
mocker.patch(f'{EXMS}._load_markets', MagicMock(return_value={}))
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pairs')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_timeframes')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pricing')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_stakecurrency')
|
|
|
|
|
|
|
|
|
|
conf = copy.deepcopy(default_conf)
|
|
|
|
|
Exchange(conf)
|
|
|
|
@@ -1116,14 +1088,14 @@ def test_validate_order_types_not_in_config(default_conf, mocker):
|
|
|
|
|
|
|
|
|
|
def test_validate_required_startup_candles(default_conf, mocker, caplog):
|
|
|
|
|
api_mock = MagicMock()
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.name', PropertyMock(return_value='Binance'))
|
|
|
|
|
mocker.patch(f'{EXMS}.name', PropertyMock(return_value='Binance'))
|
|
|
|
|
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', api_mock)
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._load_async_markets')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_pairs')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_pricing')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
|
|
|
|
|
mocker.patch(f'{EXMS}._init_ccxt', api_mock)
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_timeframes')
|
|
|
|
|
mocker.patch(f'{EXMS}._load_async_markets')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pairs')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_pricing')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_stakecurrency')
|
|
|
|
|
|
|
|
|
|
default_conf['startup_candle_count'] = 20
|
|
|
|
|
ex = Exchange(default_conf)
|
|
|
|
@@ -1220,11 +1192,10 @@ def test_create_dry_run_order_fees(
|
|
|
|
|
fee,
|
|
|
|
|
):
|
|
|
|
|
mocker.patch(
|
|
|
|
|
'freqtrade.exchange.Exchange.get_fee',
|
|
|
|
|
side_effect=lambda symbol, taker_or_maker: 2.0 if taker_or_maker == 'taker' else 1.0
|
|
|
|
|
f'{EXMS}.get_fee',
|
|
|
|
|
side_effect=lambda symbol, taker_or_maker: 2.0 if taker_or_maker == 'taker' else 1.0
|
|
|
|
|
)
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._dry_is_price_crossed',
|
|
|
|
|
return_value=price_side == 'other')
|
|
|
|
|
mocker.patch(f'{EXMS}._dry_is_price_crossed', return_value=price_side == 'other')
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf)
|
|
|
|
|
|
|
|
|
|
order = exchange.create_dry_run_order(
|
|
|
|
@@ -1241,8 +1212,7 @@ def test_create_dry_run_order_fees(
|
|
|
|
|
else:
|
|
|
|
|
assert order['fee'] is None
|
|
|
|
|
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._dry_is_price_crossed',
|
|
|
|
|
return_value=price_side != 'other')
|
|
|
|
|
mocker.patch(f'{EXMS}._dry_is_price_crossed', return_value=price_side != 'other')
|
|
|
|
|
|
|
|
|
|
order1 = exchange.fetch_dry_run_order(order['id'])
|
|
|
|
|
assert order1['fee']['rate'] == fee
|
|
|
|
@@ -1303,8 +1273,7 @@ def test_create_dry_run_order_limit_fill(default_conf, mocker, side, price, fill
|
|
|
|
|
order_book_l2_usd.reset_mock()
|
|
|
|
|
|
|
|
|
|
# Empty orderbook test
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.fetch_l2_order_book',
|
|
|
|
|
return_value={'asks': [], 'bids': []})
|
|
|
|
|
mocker.patch(f'{EXMS}.fetch_l2_order_book', return_value={'asks': [], 'bids': []})
|
|
|
|
|
exchange._dry_run_open_orders[order['id']]['status'] = 'open'
|
|
|
|
|
order_closed = exchange.fetch_dry_run_order(order['id'])
|
|
|
|
|
|
|
|
|
@@ -1372,8 +1341,8 @@ def test_create_order(default_conf, mocker, side, ordertype, rate, marketprice,
|
|
|
|
|
})
|
|
|
|
|
default_conf['dry_run'] = False
|
|
|
|
|
default_conf['margin_mode'] = 'isolated'
|
|
|
|
|
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)
|
|
|
|
|
mocker.patch(f'{EXMS}.amount_to_precision', lambda s, x, y: y)
|
|
|
|
|
mocker.patch(f'{EXMS}.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()
|
|
|
|
@@ -1452,8 +1421,8 @@ def test_buy_prod(default_conf, mocker, exchange_name):
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
default_conf['dry_run'] = False
|
|
|
|
|
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)
|
|
|
|
|
mocker.patch(f'{EXMS}.amount_to_precision', lambda s, x, y: y)
|
|
|
|
|
mocker.patch(f'{EXMS}.price_to_precision', lambda s, x, y: y)
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
|
|
|
|
|
|
|
|
|
order = exchange.create_order(pair='ETH/BTC', ordertype=order_type, side="buy",
|
|
|
|
@@ -1536,8 +1505,8 @@ def test_buy_considers_time_in_force(default_conf, mocker, exchange_name):
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
default_conf['dry_run'] = False
|
|
|
|
|
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)
|
|
|
|
|
mocker.patch(f'{EXMS}.amount_to_precision', lambda s, x, y: y)
|
|
|
|
|
mocker.patch(f'{EXMS}.price_to_precision', lambda s, x, y: y)
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
|
|
|
|
|
|
|
|
|
order_type = 'limit'
|
|
|
|
@@ -1602,8 +1571,8 @@ def test_sell_prod(default_conf, mocker, exchange_name):
|
|
|
|
|
})
|
|
|
|
|
default_conf['dry_run'] = False
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
mocker.patch(f'{EXMS}.amount_to_precision', lambda s, x, y: y)
|
|
|
|
|
mocker.patch(f'{EXMS}.price_to_precision', lambda s, x, y: y)
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
|
|
|
|
|
|
|
|
|
order = exchange.create_order(pair='ETH/BTC', ordertype=order_type,
|
|
|
|
@@ -1675,8 +1644,8 @@ def test_sell_considers_time_in_force(default_conf, mocker, exchange_name):
|
|
|
|
|
})
|
|
|
|
|
api_mock.options = {}
|
|
|
|
|
default_conf['dry_run'] = False
|
|
|
|
|
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)
|
|
|
|
|
mocker.patch(f'{EXMS}.amount_to_precision', lambda s, x, y: y)
|
|
|
|
|
mocker.patch(f'{EXMS}.price_to_precision', lambda s, x, y: y)
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
|
|
|
|
|
|
|
|
|
order_type = 'limit'
|
|
|
|
@@ -1742,7 +1711,7 @@ def test_get_balances_prod(default_conf, mocker, exchange_name):
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize("exchange_name", EXCHANGES)
|
|
|
|
|
def test_fetch_positions(default_conf, mocker, exchange_name):
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.validate_trading_mode_and_margin_mode')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_trading_mode_and_margin_mode')
|
|
|
|
|
api_mock = MagicMock()
|
|
|
|
|
api_mock.fetch_positions = MagicMock(return_value=[
|
|
|
|
|
{'symbol': 'ETH/USDT:USDT', 'leverage': 5},
|
|
|
|
@@ -1798,7 +1767,7 @@ def test_fetch_trading_fees(default_conf, mocker):
|
|
|
|
|
default_conf['trading_mode'] = TradingMode.FUTURES
|
|
|
|
|
default_conf['margin_mode'] = MarginMode.ISOLATED
|
|
|
|
|
api_mock.fetch_trading_fees = MagicMock(return_value=tick)
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.exchange_has', return_value=True)
|
|
|
|
|
mocker.patch(f'{EXMS}.exchange_has', return_value=True)
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
|
|
|
|
|
|
|
|
|
assert '1INCH/USDT:USDT' in exchange._trading_fees
|
|
|
|
@@ -1813,7 +1782,7 @@ def test_fetch_trading_fees(default_conf, mocker):
|
|
|
|
|
api_mock.fetch_trading_fees = MagicMock(return_value={})
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
|
|
|
|
exchange.fetch_trading_fees()
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.exchange_has', return_value=True)
|
|
|
|
|
mocker.patch(f'{EXMS}.exchange_has', return_value=True)
|
|
|
|
|
assert exchange.fetch_trading_fees() == {}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1833,7 +1802,7 @@ def test_fetch_bids_asks(default_conf, mocker):
|
|
|
|
|
}
|
|
|
|
|
exchange_name = 'binance'
|
|
|
|
|
api_mock.fetch_bids_asks = MagicMock(return_value=tick)
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.exchange_has', return_value=True)
|
|
|
|
|
mocker.patch(f'{EXMS}.exchange_has', return_value=True)
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
|
|
|
|
# retrieve original ticker
|
|
|
|
|
bidsasks = exchange.fetch_bids_asks()
|
|
|
|
@@ -1866,7 +1835,7 @@ def test_fetch_bids_asks(default_conf, mocker):
|
|
|
|
|
api_mock.fetch_bids_asks = MagicMock(return_value={})
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
|
|
|
|
exchange.fetch_bids_asks()
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.exchange_has', return_value=True)
|
|
|
|
|
mocker.patch(f'{EXMS}.exchange_has', return_value=True)
|
|
|
|
|
assert exchange.fetch_bids_asks() == {}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1885,7 +1854,7 @@ def test_get_tickers(default_conf, mocker, exchange_name):
|
|
|
|
|
'last': 41,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
mocker.patch('freqtrade.exchange.exchange.Exchange.exchange_has', return_value=True)
|
|
|
|
|
mocker.patch(f'{EXMS}.exchange_has', return_value=True)
|
|
|
|
|
api_mock.fetch_tickers = MagicMock(return_value=tick)
|
|
|
|
|
api_mock.fetch_bids_asks = MagicMock(return_value={})
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
|
|
|
@@ -1928,7 +1897,7 @@ def test_get_tickers(default_conf, mocker, exchange_name):
|
|
|
|
|
api_mock.fetch_bids_asks.reset_mock()
|
|
|
|
|
default_conf['trading_mode'] = TradingMode.FUTURES
|
|
|
|
|
default_conf['margin_mode'] = MarginMode.ISOLATED
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.exchange_has', return_value=True)
|
|
|
|
|
mocker.patch(f'{EXMS}.exchange_has', return_value=True)
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
|
|
|
|
|
|
|
|
|
exchange.get_tickers()
|
|
|
|
@@ -1937,7 +1906,7 @@ def test_get_tickers(default_conf, mocker, exchange_name):
|
|
|
|
|
|
|
|
|
|
api_mock.fetch_tickers.reset_mock()
|
|
|
|
|
api_mock.fetch_bids_asks.reset_mock()
|
|
|
|
|
mocker.patch('freqtrade.exchange.exchange.Exchange.exchange_has', return_value=False)
|
|
|
|
|
mocker.patch(f'{EXMS}.exchange_has', return_value=False)
|
|
|
|
|
assert exchange.get_tickers() == {}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -2191,7 +2160,7 @@ def test_refresh_latest_ohlcv_cache(mocker, default_conf, candle_type, time_mach
|
|
|
|
|
time_machine.move_to(start + timedelta(hours=99, minutes=30))
|
|
|
|
|
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf)
|
|
|
|
|
mocker.patch("freqtrade.exchange.Exchange.ohlcv_candle_limit", return_value=100)
|
|
|
|
|
mocker.patch(f"{EXMS}.ohlcv_candle_limit", return_value=100)
|
|
|
|
|
assert exchange._startup_candle_count == 0
|
|
|
|
|
|
|
|
|
|
exchange._api_async.fetch_ohlcv = get_mock_coro(ohlcv)
|
|
|
|
@@ -2241,7 +2210,7 @@ def test_refresh_latest_ohlcv_cache(mocker, default_conf, candle_type, time_mach
|
|
|
|
|
# New candle on exchange - return 100 candles - but skip one candle so we actually get 2 candles
|
|
|
|
|
# in one go
|
|
|
|
|
new_startdate = (start + timedelta(hours=2)).strftime('%Y-%m-%d %H:%M')
|
|
|
|
|
# mocker.patch("freqtrade.exchange.Exchange.ohlcv_candle_limit", return_value=100)
|
|
|
|
|
# mocker.patch(f"{EXMS}.ohlcv_candle_limit", return_value=100)
|
|
|
|
|
ohlcv = generate_test_data_raw('1h', 100, new_startdate)
|
|
|
|
|
exchange._api_async.fetch_ohlcv = get_mock_coro(ohlcv)
|
|
|
|
|
res = exchange.refresh_latest_ohlcv(pairs)
|
|
|
|
@@ -2342,7 +2311,7 @@ async def test__async_kucoin_get_candle_history(default_conf, mocker, caplog):
|
|
|
|
|
"symbol=ETH-BTC&type=5min&startAt=1640268735&endAt=1640418735"
|
|
|
|
|
"429 Too Many Requests" '{"code":"429000","msg":"Too Many Requests"}'))
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="kucoin")
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.name', PropertyMock(return_value='KuCoin'))
|
|
|
|
|
mocker.patch(f'{EXMS}.name', PropertyMock(return_value='KuCoin'))
|
|
|
|
|
|
|
|
|
|
msg = "Kucoin 429 error, avoid triggering DDosProtection backoff delay"
|
|
|
|
|
assert not num_log_has_re(msg, caplog)
|
|
|
|
@@ -2500,8 +2469,7 @@ def test_get_entry_rate(mocker, default_conf, caplog, side, ask, bid,
|
|
|
|
|
default_conf['entry_pricing']['price_last_balance'] = last_ab
|
|
|
|
|
default_conf['entry_pricing']['price_side'] = side
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf)
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker',
|
|
|
|
|
return_value={'ask': ask, 'last': last, 'bid': bid})
|
|
|
|
|
mocker.patch(f'{EXMS}.fetch_ticker', return_value={'ask': ask, 'last': last, 'bid': bid})
|
|
|
|
|
|
|
|
|
|
assert exchange.get_rate('ETH/BTC', side="entry", is_short=False, refresh=True) == expected
|
|
|
|
|
assert not log_has("Using cached entry rate for ETH/BTC.", caplog)
|
|
|
|
@@ -2522,8 +2490,7 @@ def test_get_exit_rate(default_conf, mocker, caplog, side, bid, ask,
|
|
|
|
|
default_conf['exit_pricing']['price_side'] = side
|
|
|
|
|
if last_ab is not None:
|
|
|
|
|
default_conf['exit_pricing']['price_last_balance'] = last_ab
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker',
|
|
|
|
|
return_value={'ask': ask, 'bid': bid, 'last': last})
|
|
|
|
|
mocker.patch(f'{EXMS}.fetch_ticker', return_value={'ask': ask, 'bid': bid, 'last': last})
|
|
|
|
|
pair = "ETH/BTC"
|
|
|
|
|
|
|
|
|
|
# Test regular mode
|
|
|
|
@@ -2556,8 +2523,7 @@ def test_get_ticker_rate_error(mocker, entry, default_conf, caplog, side, is_sho
|
|
|
|
|
default_conf['exit_pricing']['price_side'] = side
|
|
|
|
|
default_conf['exit_pricing']['price_last_balance'] = last_ab
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf)
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker',
|
|
|
|
|
return_value={'ask': ask, 'last': last, 'bid': bid})
|
|
|
|
|
mocker.patch(f'{EXMS}.fetch_ticker', return_value={'ask': ask, 'last': last, 'bid': bid})
|
|
|
|
|
|
|
|
|
|
with pytest.raises(PricingError):
|
|
|
|
|
exchange.get_rate('ETH/BTC', refresh=True, side=entry, is_short=is_short)
|
|
|
|
@@ -2581,7 +2547,7 @@ def test_get_exit_rate_orderbook(
|
|
|
|
|
default_conf['exit_pricing']['use_order_book'] = True
|
|
|
|
|
default_conf['exit_pricing']['order_book_top'] = 1
|
|
|
|
|
pair = "ETH/BTC"
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.fetch_l2_order_book', order_book_l2)
|
|
|
|
|
mocker.patch(f'{EXMS}.fetch_l2_order_book', order_book_l2)
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf)
|
|
|
|
|
rate = exchange.get_rate(pair, refresh=True, side="exit", is_short=is_short)
|
|
|
|
|
assert not log_has("Using cached exit rate for ETH/BTC.", caplog)
|
|
|
|
@@ -2599,8 +2565,7 @@ def test_get_exit_rate_orderbook_exception(default_conf, mocker, caplog):
|
|
|
|
|
default_conf['exit_pricing']['order_book_top'] = 1
|
|
|
|
|
pair = "ETH/BTC"
|
|
|
|
|
# Test What happens if the exchange returns an empty orderbook.
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.fetch_l2_order_book',
|
|
|
|
|
return_value={'bids': [[]], 'asks': [[]]})
|
|
|
|
|
mocker.patch(f'{EXMS}.fetch_l2_order_book', return_value={'bids': [[]], 'asks': [[]]})
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf)
|
|
|
|
|
with pytest.raises(PricingError):
|
|
|
|
|
exchange.get_rate(pair, refresh=True, side="exit", is_short=False)
|
|
|
|
@@ -2614,8 +2579,7 @@ def test_get_exit_rate_exception(default_conf, mocker, is_short):
|
|
|
|
|
# Ticker on one side can be empty in certain circumstances.
|
|
|
|
|
default_conf['exit_pricing']['price_side'] = 'ask'
|
|
|
|
|
pair = "ETH/BTC"
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker',
|
|
|
|
|
return_value={'ask': None, 'bid': 0.12, 'last': None})
|
|
|
|
|
mocker.patch(f'{EXMS}.fetch_ticker', return_value={'ask': None, 'bid': 0.12, 'last': None})
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf)
|
|
|
|
|
with pytest.raises(PricingError, match=r"Exit-Rate for ETH/BTC was empty."):
|
|
|
|
|
exchange.get_rate(pair, refresh=True, side="exit", is_short=is_short)
|
|
|
|
@@ -2623,8 +2587,7 @@ def test_get_exit_rate_exception(default_conf, mocker, is_short):
|
|
|
|
|
exchange._config['exit_pricing']['price_side'] = 'bid'
|
|
|
|
|
assert exchange.get_rate(pair, refresh=True, side="exit", is_short=is_short) == 0.12
|
|
|
|
|
# Reverse sides
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker',
|
|
|
|
|
return_value={'ask': 0.13, 'bid': None, 'last': None})
|
|
|
|
|
mocker.patch(f'{EXMS}.fetch_ticker', return_value={'ask': 0.13, 'bid': None, 'last': None})
|
|
|
|
|
with pytest.raises(PricingError, match=r"Exit-Rate for ETH/BTC was empty."):
|
|
|
|
|
exchange.get_rate(pair, refresh=True, side="exit", is_short=is_short)
|
|
|
|
|
|
|
|
|
@@ -2990,7 +2953,7 @@ async def test__async_get_trade_history_time_empty(default_conf, mocker, caplog,
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize("exchange_name", EXCHANGES)
|
|
|
|
|
def test_get_historic_trades(default_conf, mocker, caplog, exchange_name, trades_history):
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.exchange_has', return_value=True)
|
|
|
|
|
mocker.patch(f'{EXMS}.exchange_has', return_value=True)
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
|
|
|
|
|
|
|
|
|
pair = 'ETH/BTC'
|
|
|
|
@@ -3012,7 +2975,7 @@ def test_get_historic_trades(default_conf, mocker, caplog, exchange_name, trades
|
|
|
|
|
@pytest.mark.parametrize("exchange_name", EXCHANGES)
|
|
|
|
|
def test_get_historic_trades_notsupported(default_conf, mocker, caplog, exchange_name,
|
|
|
|
|
trades_history):
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.exchange_has', return_value=False)
|
|
|
|
|
mocker.patch(f'{EXMS}.exchange_has', return_value=False)
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
|
|
|
|
|
|
|
|
|
pair = 'ETH/BTC'
|
|
|
|
@@ -3028,7 +2991,7 @@ def test_get_historic_trades_notsupported(default_conf, mocker, caplog, exchange
|
|
|
|
|
def test_cancel_order_dry_run(default_conf, mocker, exchange_name):
|
|
|
|
|
default_conf['dry_run'] = True
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange._dry_is_price_crossed', return_value=True)
|
|
|
|
|
mocker.patch(f'{EXMS}._dry_is_price_crossed', return_value=True)
|
|
|
|
|
assert exchange.cancel_order(order_id='123', pair='TKN/BTC') == {}
|
|
|
|
|
assert exchange.cancel_stoploss_order(order_id='123', pair='TKN/BTC') == {}
|
|
|
|
|
|
|
|
|
@@ -3156,24 +3119,24 @@ def test_cancel_stoploss_order(default_conf, mocker, exchange_name):
|
|
|
|
|
@pytest.mark.parametrize("exchange_name", EXCHANGES)
|
|
|
|
|
def test_cancel_stoploss_order_with_result(default_conf, mocker, exchange_name):
|
|
|
|
|
default_conf['dry_run'] = False
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.fetch_stoploss_order', return_value={'for': 123})
|
|
|
|
|
mocker.patch(f'{EXMS}.fetch_stoploss_order', return_value={'for': 123})
|
|
|
|
|
mocker.patch('freqtrade.exchange.Gate.fetch_stoploss_order', return_value={'for': 123})
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
|
|
|
|
|
|
|
|
|
res = {'fee': {}, 'status': 'canceled', 'amount': 1234}
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.cancel_stoploss_order', return_value=res)
|
|
|
|
|
mocker.patch(f'{EXMS}.cancel_stoploss_order', return_value=res)
|
|
|
|
|
mocker.patch('freqtrade.exchange.Gate.cancel_stoploss_order', return_value=res)
|
|
|
|
|
co = exchange.cancel_stoploss_order_with_result(order_id='_', pair='TKN/BTC', amount=555)
|
|
|
|
|
assert co == res
|
|
|
|
|
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.cancel_stoploss_order', return_value='canceled')
|
|
|
|
|
mocker.patch(f'{EXMS}.cancel_stoploss_order', return_value='canceled')
|
|
|
|
|
mocker.patch('freqtrade.exchange.Gate.cancel_stoploss_order', return_value='canceled')
|
|
|
|
|
# Fall back to fetch_stoploss_order
|
|
|
|
|
co = exchange.cancel_stoploss_order_with_result(order_id='_', pair='TKN/BTC', amount=555)
|
|
|
|
|
assert co == {'for': 123}
|
|
|
|
|
|
|
|
|
|
exc = InvalidOrderException("")
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.fetch_stoploss_order', side_effect=exc)
|
|
|
|
|
mocker.patch(f'{EXMS}.fetch_stoploss_order', side_effect=exc)
|
|
|
|
|
mocker.patch('freqtrade.exchange.Gate.fetch_stoploss_order', side_effect=exc)
|
|
|
|
|
co = exchange.cancel_stoploss_order_with_result(order_id='_', pair='TKN/BTC', amount=555)
|
|
|
|
|
assert co['amount'] == 555
|
|
|
|
@@ -3181,7 +3144,7 @@ def test_cancel_stoploss_order_with_result(default_conf, mocker, exchange_name):
|
|
|
|
|
|
|
|
|
|
with pytest.raises(InvalidOrderException):
|
|
|
|
|
exc = InvalidOrderException("Did not find order")
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.cancel_stoploss_order', side_effect=exc)
|
|
|
|
|
mocker.patch(f'{EXMS}.cancel_stoploss_order', side_effect=exc)
|
|
|
|
|
mocker.patch('freqtrade.exchange.Gate.cancel_stoploss_order', side_effect=exc)
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
|
|
|
|
exchange.cancel_stoploss_order_with_result(order_id='_', pair='TKN/BTC', amount=123)
|
|
|
|
@@ -3315,7 +3278,7 @@ def test_get_trades_for_order(default_conf, mocker, exchange_name, trading_mode,
|
|
|
|
|
default_conf["dry_run"] = False
|
|
|
|
|
default_conf["trading_mode"] = trading_mode
|
|
|
|
|
default_conf["margin_mode"] = 'isolated'
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.exchange_has', return_value=True)
|
|
|
|
|
mocker.patch(f'{EXMS}.exchange_has', return_value=True)
|
|
|
|
|
api_mock = MagicMock()
|
|
|
|
|
|
|
|
|
|
api_mock.fetch_my_trades = MagicMock(return_value=[{'id': 'TTR67E-3PFBD-76IISV',
|
|
|
|
@@ -3358,7 +3321,7 @@ def test_get_trades_for_order(default_conf, mocker, exchange_name, trading_mode,
|
|
|
|
|
'get_trades_for_order', 'fetch_my_trades',
|
|
|
|
|
order_id=order_id, pair='ETH/USDT:USDT', since=since)
|
|
|
|
|
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.exchange_has', MagicMock(return_value=False))
|
|
|
|
|
mocker.patch(f'{EXMS}.exchange_has', MagicMock(return_value=False))
|
|
|
|
|
assert exchange.get_trades_for_order(order_id, 'ETH/USDT:USDT', since) == []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -3550,7 +3513,7 @@ def test_get_markets(default_conf, mocker, markets_static,
|
|
|
|
|
|
|
|
|
|
def test_get_markets_error(default_conf, mocker):
|
|
|
|
|
ex = get_patched_exchange(mocker, default_conf)
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.markets', PropertyMock(return_value=None))
|
|
|
|
|
mocker.patch(f'{EXMS}.markets', PropertyMock(return_value=None))
|
|
|
|
|
with pytest.raises(OperationalException, match="Markets were not loaded."):
|
|
|
|
|
ex.get_markets('LTC', 'USDT', True, False)
|
|
|
|
|
|
|
|
|
@@ -3695,7 +3658,7 @@ def test_market_is_tradable(
|
|
|
|
|
quote, spot, margin, futures, trademode, add_dict, exchange, expected_result
|
|
|
|
|
) -> None:
|
|
|
|
|
default_conf['trading_mode'] = trademode
|
|
|
|
|
mocker.patch('freqtrade.exchange.exchange.Exchange.validate_trading_mode_and_margin_mode')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_trading_mode_and_margin_mode')
|
|
|
|
|
ex = get_patched_exchange(mocker, default_conf, id=exchange)
|
|
|
|
|
market = {
|
|
|
|
|
'symbol': market_symbol,
|
|
|
|
@@ -3740,7 +3703,7 @@ def test_order_has_fee(order, expected) -> None:
|
|
|
|
|
(0.34, 'USDT', 0.01)),
|
|
|
|
|
])
|
|
|
|
|
def test_extract_cost_curr_rate(mocker, default_conf, order, expected) -> None:
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.calculate_fee_rate', MagicMock(return_value=0.01))
|
|
|
|
|
mocker.patch(f'{EXMS}.calculate_fee_rate', MagicMock(return_value=0.01))
|
|
|
|
|
ex = get_patched_exchange(mocker, default_conf)
|
|
|
|
|
assert ex.extract_cost_curr_rate(order['fee'], order['symbol'], cost=20, amount=1) == expected
|
|
|
|
|
|
|
|
|
@@ -3785,7 +3748,7 @@ def test_extract_cost_curr_rate(mocker, default_conf, order, expected) -> None:
|
|
|
|
|
'fee': {'currency': None, 'cost': 0.005}}, None, None),
|
|
|
|
|
])
|
|
|
|
|
def test_calculate_fee_rate(mocker, default_conf, order, expected, unknown_fee_rate) -> None:
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', return_value={'last': 0.081})
|
|
|
|
|
mocker.patch(f'{EXMS}.fetch_ticker', return_value={'last': 0.081})
|
|
|
|
|
if unknown_fee_rate:
|
|
|
|
|
default_conf['exchange']['unknown_fee_rate'] = unknown_fee_rate
|
|
|
|
|
|
|
|
|
@@ -3857,7 +3820,7 @@ def test__get_funding_fees_from_exchange(default_conf, mocker, exchange_name):
|
|
|
|
|
])
|
|
|
|
|
type(api_mock).has = PropertyMock(return_value={'fetchFundingHistory': True})
|
|
|
|
|
|
|
|
|
|
# mocker.patch('freqtrade.exchange.Exchange.get_funding_fees', lambda pair, since: y)
|
|
|
|
|
# mocker.patch(f'{EXMS}.get_funding_fees', lambda pair, since: y)
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
|
|
|
|
date_time = datetime.strptime("2021-09-01T00:00:01.000Z", '%Y-%m-%dT%H:%M:%S.%fZ')
|
|
|
|
|
unix_time = int(date_time.timestamp())
|
|
|
|
@@ -4257,8 +4220,7 @@ def test__fetch_and_calculate_funding_fees(
|
|
|
|
|
type(api_mock).has = PropertyMock(return_value={'fetchFundingRateHistory': True})
|
|
|
|
|
|
|
|
|
|
ex = get_patched_exchange(mocker, default_conf, api_mock, id=exchange)
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.timeframes', PropertyMock(
|
|
|
|
|
return_value=['1h', '4h', '8h']))
|
|
|
|
|
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)
|
|
|
|
|
assert pytest.approx(funding_fees) == expected_fees
|
|
|
|
@@ -4268,7 +4230,7 @@ def test__fetch_and_calculate_funding_fees(
|
|
|
|
|
assert pytest.approx(funding_fees) == -expected_fees
|
|
|
|
|
|
|
|
|
|
# Return empty "refresh_latest"
|
|
|
|
|
mocker.patch("freqtrade.exchange.Exchange.refresh_latest_ohlcv", return_value={})
|
|
|
|
|
mocker.patch(f"{EXMS}.refresh_latest_ohlcv", return_value={})
|
|
|
|
|
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(
|
|
|
|
@@ -4294,7 +4256,7 @@ def test__fetch_and_calculate_funding_fees_datetime_called(
|
|
|
|
|
return_value=funding_rate_history_octohourly)
|
|
|
|
|
type(api_mock).has = PropertyMock(return_value={'fetchOHLCV': True})
|
|
|
|
|
type(api_mock).has = PropertyMock(return_value={'fetchFundingRateHistory': True})
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.timeframes', PropertyMock(return_value=['4h', '8h']))
|
|
|
|
|
mocker.patch(f'{EXMS}.timeframes', PropertyMock(return_value=['4h', '8h']))
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange)
|
|
|
|
|
d1 = datetime.strptime("2021-09-01 00:00:00 +0000", '%Y-%m-%d %H:%M:%S %z')
|
|
|
|
|
|
|
|
|
@@ -4317,7 +4279,7 @@ def test__get_contract_size(mocker, default_conf, pair, expected_size, trading_m
|
|
|
|
|
default_conf['trading_mode'] = trading_mode
|
|
|
|
|
default_conf['margin_mode'] = 'isolated'
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.markets', {
|
|
|
|
|
mocker.patch(f'{EXMS}.markets', {
|
|
|
|
|
'LTC/USD': {
|
|
|
|
|
'symbol': 'LTC/USD',
|
|
|
|
|
'contractSize': None,
|
|
|
|
@@ -4353,7 +4315,7 @@ def test__order_contracts_to_amount(
|
|
|
|
|
api_mock = MagicMock()
|
|
|
|
|
default_conf['trading_mode'] = trading_mode
|
|
|
|
|
default_conf['margin_mode'] = 'isolated'
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.markets', markets)
|
|
|
|
|
mocker.patch(f'{EXMS}.markets', markets)
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
|
|
|
|
|
|
|
|
|
orders = [
|
|
|
|
@@ -4475,7 +4437,7 @@ def test__trades_contracts_to_amount(
|
|
|
|
|
api_mock = MagicMock()
|
|
|
|
|
default_conf['trading_mode'] = trading_mode
|
|
|
|
|
default_conf['margin_mode'] = 'isolated'
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.markets', markets)
|
|
|
|
|
mocker.patch(f'{EXMS}.markets', markets)
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
|
|
|
|
|
|
|
|
|
trades = [
|
|
|
|
@@ -4511,7 +4473,7 @@ def test__amount_to_contracts(
|
|
|
|
|
default_conf['trading_mode'] = 'spot'
|
|
|
|
|
default_conf['margin_mode'] = 'isolated'
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.markets', {
|
|
|
|
|
mocker.patch(f'{EXMS}.markets', {
|
|
|
|
|
'LTC/USD': {
|
|
|
|
|
'symbol': 'LTC/USD',
|
|
|
|
|
'contractSize': None,
|
|
|
|
@@ -4769,7 +4731,7 @@ def test_get_max_pair_stake_amount(
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.markets', markets)
|
|
|
|
|
mocker.patch(f'{EXMS}.markets', markets)
|
|
|
|
|
assert exchange.get_max_pair_stake_amount('XRP/USDT:USDT', 2.0) == 20000
|
|
|
|
|
assert exchange.get_max_pair_stake_amount('XRP/USDT:USDT', 2.0, 5) == 4000
|
|
|
|
|
assert exchange.get_max_pair_stake_amount('LTC/USDT:USDT', 2.0) == float('inf')
|
|
|
|
@@ -4779,7 +4741,7 @@ def test_get_max_pair_stake_amount(
|
|
|
|
|
|
|
|
|
|
default_conf['trading_mode'] = 'spot'
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.markets', markets)
|
|
|
|
|
mocker.patch(f'{EXMS}.markets', markets)
|
|
|
|
|
assert exchange.get_max_pair_stake_amount('BTC/USDT', 2.0) == 20000
|
|
|
|
|
assert exchange.get_max_pair_stake_amount('ADA/USDT', 2.0) == 500
|
|
|
|
|
|
|
|
|
@@ -4790,7 +4752,7 @@ def test_load_leverage_tiers(mocker, default_conf, leverage_tiers, exchange_name
|
|
|
|
|
api_mock.fetch_leverage_tiers = MagicMock()
|
|
|
|
|
type(api_mock).has = PropertyMock(return_value={'fetchLeverageTiers': True})
|
|
|
|
|
default_conf['dry_run'] = False
|
|
|
|
|
mocker.patch('freqtrade.exchange.exchange.Exchange.validate_trading_mode_and_margin_mode')
|
|
|
|
|
mocker.patch(f'{EXMS}.validate_trading_mode_and_margin_mode')
|
|
|
|
|
|
|
|
|
|
api_mock.fetch_leverage_tiers = MagicMock(return_value={
|
|
|
|
|
'ADA/USDT:USDT': [
|
|
|
|
@@ -4943,7 +4905,7 @@ def test_get_maintenance_ratio_and_amt_exceptions(mocker, default_conf, leverage
|
|
|
|
|
api_mock = MagicMock()
|
|
|
|
|
default_conf['trading_mode'] = 'futures'
|
|
|
|
|
default_conf['margin_mode'] = 'isolated'
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.exchange_has', return_value=True)
|
|
|
|
|
mocker.patch(f'{EXMS}.exchange_has', return_value=True)
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
|
|
|
|
|
|
|
|
|
exchange._leverage_tiers = leverage_tiers
|
|
|
|
@@ -4980,7 +4942,7 @@ def test_get_maintenance_ratio_and_amt(
|
|
|
|
|
api_mock = MagicMock()
|
|
|
|
|
default_conf['trading_mode'] = 'futures'
|
|
|
|
|
default_conf['margin_mode'] = 'isolated'
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.exchange_has', return_value=True)
|
|
|
|
|
mocker.patch(f'{EXMS}.exchange_has', return_value=True)
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
|
|
|
|
exchange._leverage_tiers = leverage_tiers
|
|
|
|
|
exchange.get_maintenance_ratio_and_amt(pair, value) == (mmr, maintAmt)
|
|
|
|
@@ -5019,7 +4981,7 @@ def test_get_max_leverage_futures(default_conf, mocker, leverage_tiers):
|
|
|
|
|
@pytest.mark.parametrize("exchange_name", ['bittrex', 'binance', 'kraken', 'gate', 'okx', 'bybit'])
|
|
|
|
|
def test__get_params(mocker, default_conf, exchange_name):
|
|
|
|
|
api_mock = MagicMock()
|
|
|
|
|
mocker.patch('freqtrade.exchange.Exchange.exchange_has', return_value=True)
|
|
|
|
|
mocker.patch(f'{EXMS}.exchange_has', return_value=True)
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
|
|
|
|
exchange._params = {'test': True}
|
|
|
|
|
|
|
|
|
@@ -5324,8 +5286,8 @@ def test_stoploss_contract_size(mocker, default_conf, contract_size, order_amoun
|
|
|
|
|
'symbol': 'ETH/BTC',
|
|
|
|
|
})
|
|
|
|
|
default_conf['dry_run'] = False
|
|
|
|
|
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)
|
|
|
|
|
mocker.patch(f'{EXMS}.amount_to_precision', lambda s, x, y: y)
|
|
|
|
|
mocker.patch(f'{EXMS}.price_to_precision', lambda s, x, y: y)
|
|
|
|
|
|
|
|
|
|
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
|
|
|
|
exchange.get_contract_size = MagicMock(return_value=contract_size)
|
|
|
|
|