Merge branch 'develop' into pr/asuiu/8296

This commit is contained in:
Matthias
2023-03-26 10:28:02 +02:00
107 changed files with 5060 additions and 2328 deletions

View File

@@ -11,6 +11,19 @@ from tests.conftest import EXMS, get_mock_coro, get_patched_exchange, log_has_re
from tests.exchange.test_exchange import ccxt_exceptionhandlers
@pytest.mark.parametrize('side,type,time_in_force,expected', [
('buy', 'limit', 'gtc', {'timeInForce': 'GTC'}),
('buy', 'limit', 'IOC', {'timeInForce': 'IOC'}),
('buy', 'market', 'IOC', {}),
('buy', 'limit', 'PO', {'postOnly': True}),
('sell', 'limit', 'PO', {'postOnly': True}),
('sell', 'market', 'PO', {}),
])
def test__get_params_binance(default_conf, mocker, side, type, time_in_force, expected):
exchange = get_patched_exchange(mocker, default_conf, id='binance')
assert exchange._get_params(side, type, 1, False, time_in_force) == expected
@pytest.mark.parametrize('trademode', [TradingMode.FUTURES, TradingMode.SPOT])
@pytest.mark.parametrize('limitratio,expected,side', [
(None, 220 * 0.99, "sell"),
@@ -39,7 +52,7 @@ def test_create_stoploss_order_binance(default_conf, mocker, limitratio, expecte
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'binance')
with pytest.raises(OperationalException):
with pytest.raises(InvalidOrderException):
order = exchange.create_stoploss(
pair='ETH/BTC',
amount=1,
@@ -118,7 +131,7 @@ def test_create_stoploss_order_dry_run_binance(default_conf, mocker):
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'binance')
with pytest.raises(OperationalException):
with pytest.raises(InvalidOrderException):
order = exchange.create_stoploss(
pair='ETH/BTC',
amount=1,
@@ -542,7 +555,6 @@ def test__set_leverage_binance(mocker, default_conf):
"set_leverage",
pair="XRP/USDT",
leverage=5.0,
trading_mode=TradingMode.FUTURES
)

View File

@@ -37,7 +37,7 @@ EXCHANGES = {
'stake_currency': 'USDT',
'use_ci_proxy': True,
'hasQuoteVolume': True,
'timeframe': '5m',
'timeframe': '1h',
'futures': True,
'futures_pair': 'BTC/USDT:USDT',
'hasQuoteVolumeFutures': True,
@@ -66,7 +66,7 @@ EXCHANGES = {
'pair': 'BTC/USDT',
'stake_currency': 'USDT',
'hasQuoteVolume': True,
'timeframe': '5m',
'timeframe': '1h',
'futures': False,
'sample_order': [{
"symbol": "SOLUSDT",
@@ -91,7 +91,7 @@ EXCHANGES = {
'pair': 'BTC/USDT',
'stake_currency': 'USDT',
'hasQuoteVolume': True,
'timeframe': '5m',
'timeframe': '1h',
'leverage_tiers_public': False,
'leverage_in_spot_market': True,
},
@@ -99,7 +99,7 @@ EXCHANGES = {
'pair': 'XRP/USDT',
'stake_currency': 'USDT',
'hasQuoteVolume': True,
'timeframe': '5m',
'timeframe': '1h',
'leverage_tiers_public': False,
'leverage_in_spot_market': True,
'sample_order': [
@@ -141,7 +141,7 @@ EXCHANGES = {
'pair': 'BTC/USDT',
'stake_currency': 'USDT',
'hasQuoteVolume': True,
'timeframe': '5m',
'timeframe': '1h',
'futures': True,
'futures_pair': 'BTC/USDT:USDT',
'hasQuoteVolumeFutures': True,
@@ -215,7 +215,7 @@ EXCHANGES = {
'pair': 'BTC/USDT',
'stake_currency': 'USDT',
'hasQuoteVolume': True,
'timeframe': '5m',
'timeframe': '1h',
'futures': True,
'futures_pair': 'BTC/USDT:USDT',
'hasQuoteVolumeFutures': False,
@@ -226,7 +226,7 @@ EXCHANGES = {
'pair': 'BTC/USDT',
'stake_currency': 'USDT',
'hasQuoteVolume': True,
'timeframe': '5m',
'timeframe': '1h',
'futures_pair': 'BTC/USDT:USDT',
'futures': True,
'leverage_tiers_public': True,
@@ -253,14 +253,14 @@ EXCHANGES = {
'pair': 'ETH/BTC',
'stake_currency': 'BTC',
'hasQuoteVolume': True,
'timeframe': '5m',
'timeframe': '1h',
'futures': False,
},
'bitvavo': {
'pair': 'BTC/EUR',
'stake_currency': 'EUR',
'hasQuoteVolume': True,
'timeframe': '5m',
'timeframe': '1h',
'leverage_tiers_public': False,
'leverage_in_spot_market': False,
},
@@ -463,7 +463,9 @@ class TestCCXTExchange():
if exchangename == 'gate':
# TODO: Gate is unstable here at the moment, ignoring the limit partially.
return
for val in [1, 2, 5, 25, 100]:
for val in [1, 2, 5, 25, 50, 100]:
if val > 50 and exchangename == 'bybit':
continue
l2 = exch.fetch_l2_order_book(pair, val)
if not l2_limit_range or val in l2_limit_range:
if val > 50:

View File

@@ -13,8 +13,8 @@ from pandas import DataFrame
from freqtrade.enums import CandleType, MarginMode, TradingMode
from freqtrade.exceptions import (DDosProtection, DependencyException, ExchangeError,
InvalidOrderException, OperationalException, PricingError,
TemporaryError)
InsufficientFundsError, InvalidOrderException,
OperationalException, PricingError, TemporaryError)
from freqtrade.exchange import (Binance, Bittrex, Exchange, Kraken, amount_to_precision,
date_minus_candles, market_is_active, price_to_precision,
timeframe_to_minutes, timeframe_to_msecs, timeframe_to_next_date,
@@ -1052,9 +1052,9 @@ def test_validate_ordertypes(default_conf, mocker):
('bybit', 'last', True),
('bybit', 'mark', True),
('bybit', 'index', True),
# ('okx', 'last', True),
# ('okx', 'mark', True),
# ('okx', 'index', True),
('okx', 'last', True),
('okx', 'mark', True),
('okx', 'index', True),
('gate', 'last', True),
('gate', 'mark', True),
('gate', 'index', True),
@@ -1612,13 +1612,13 @@ def test_sell_prod(default_conf, mocker, exchange_name):
assert api_mock.create_order.call_args[0][4] == 200
# test exception handling
with pytest.raises(DependencyException):
with pytest.raises(InsufficientFundsError):
api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds("0 balance"))
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
exchange.create_order(pair='ETH/BTC', ordertype=order_type, side="sell", amount=1, rate=200,
leverage=1.0)
with pytest.raises(DependencyException):
with pytest.raises(InvalidOrderException):
api_mock.create_order = MagicMock(side_effect=ccxt.InvalidOrder("Order not found"))
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
exchange.create_order(pair='ETH/BTC', ordertype='limit', side="sell", amount=1, rate=200,
@@ -3400,7 +3400,7 @@ def test_merge_ft_has_dict(default_conf, mocker):
ex = Binance(default_conf)
assert ex._ft_has != Exchange._ft_has_default
assert ex.get_option('stoploss_on_exchange')
assert ex.get_option('order_time_in_force') == ['GTC', 'FOK', 'IOC']
assert ex.get_option('order_time_in_force') == ['GTC', 'FOK', 'IOC', 'PO']
assert ex.get_option('trades_pagination') == 'id'
assert ex.get_option('trades_pagination_arg') == 'fromId'
@@ -3881,29 +3881,6 @@ def test_get_stake_amount_considering_leverage(
stake_amount, leverage) == min_stake_with_lev
@pytest.mark.parametrize("exchange_name,trading_mode", [
("binance", TradingMode.FUTURES),
])
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,
default_conf,
api_mock,
exchange_name,
"_set_leverage",
"set_leverage",
pair="XRP/USDT",
leverage=5.0,
trading_mode=trading_mode
)
@pytest.mark.parametrize("margin_mode", [
(MarginMode.CROSS),
(MarginMode.ISOLATED)

View File

@@ -4,7 +4,7 @@ from unittest.mock import MagicMock
import ccxt
import pytest
from freqtrade.exceptions import DependencyException, InvalidOrderException, OperationalException
from freqtrade.exceptions import DependencyException, InvalidOrderException
from tests.conftest import EXMS, get_patched_exchange
from tests.exchange.test_exchange import ccxt_exceptionhandlers
@@ -31,7 +31,7 @@ def test_create_stoploss_order_huobi(default_conf, mocker, limitratio, expected,
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'huobi')
with pytest.raises(OperationalException):
with pytest.raises(InvalidOrderException):
order = exchange.create_stoploss(pair='ETH/BTC', amount=1, stop_price=190,
order_types={'stoploss_on_exchange_limit_ratio': 1.05},
side=side,
@@ -84,7 +84,7 @@ def test_create_stoploss_order_dry_run_huobi(default_conf, mocker):
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'huobi')
with pytest.raises(OperationalException):
with pytest.raises(InvalidOrderException):
order = exchange.create_stoploss(pair='ETH/BTC', amount=1, stop_price=190,
order_types={'stoploss_on_exchange_limit_ratio': 1.05},
side='sell', leverage=1.0)

View File

@@ -4,7 +4,7 @@ from unittest.mock import MagicMock
import ccxt
import pytest
from freqtrade.exceptions import DependencyException, InvalidOrderException, OperationalException
from freqtrade.exceptions import DependencyException, InvalidOrderException
from tests.conftest import EXMS, get_patched_exchange
from tests.exchange.test_exchange import ccxt_exceptionhandlers
@@ -31,7 +31,7 @@ def test_create_stoploss_order_kucoin(default_conf, mocker, limitratio, expected
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'kucoin')
if order_type == 'limit':
with pytest.raises(OperationalException):
with pytest.raises(InvalidOrderException):
order = exchange.create_stoploss(pair='ETH/BTC', amount=1, stop_price=190,
order_types={
'stoploss': order_type,
@@ -92,7 +92,7 @@ def test_stoploss_order_dry_run_kucoin(default_conf, mocker):
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'kucoin')
with pytest.raises(OperationalException):
with pytest.raises(InvalidOrderException):
order = exchange.create_stoploss(pair='ETH/BTC', amount=1, stop_price=190,
order_types={'stoploss': 'limit',
'stoploss_on_exchange_limit_ratio': 1.05},

View File

@@ -2,11 +2,13 @@ from datetime import datetime, timedelta, timezone
from pathlib import Path
from unittest.mock import MagicMock, PropertyMock
import ccxt
import pytest
from freqtrade.enums import CandleType, MarginMode, TradingMode
from freqtrade.exceptions import RetryableOrderError
from freqtrade.exchange.exchange import timeframe_to_minutes
from tests.conftest import get_mock_coro, get_patched_exchange, log_has
from tests.conftest import EXMS, get_mock_coro, get_patched_exchange, log_has
from tests.exchange.test_exchange import ccxt_exceptionhandlers
@@ -476,3 +478,116 @@ def test_load_leverage_tiers_okx(default_conf, mocker, markets, tmpdir, caplog,
exchange.load_leverage_tiers()
assert log_has(logmsg, caplog)
def test__set_leverage_okx(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
default_conf['trading_mode'] = TradingMode.FUTURES
default_conf['margin_mode'] = MarginMode.ISOLATED
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="okx")
exchange._lev_prep('BTC/USDT:USDT', 3.2, 'buy')
assert api_mock.set_leverage.call_count == 1
# Leverage is rounded to 3.
assert api_mock.set_leverage.call_args_list[0][1]['leverage'] == 3.2
assert api_mock.set_leverage.call_args_list[0][1]['symbol'] == 'BTC/USDT:USDT'
assert api_mock.set_leverage.call_args_list[0][1]['params'] == {
'mgnMode': 'isolated',
'posSide': 'net'}
ccxt_exceptionhandlers(
mocker,
default_conf,
api_mock,
"okx",
"_lev_prep",
"set_leverage",
pair="XRP/USDT:USDT",
leverage=5.0,
side='buy'
)
@pytest.mark.usefixtures("init_persistence")
def test_fetch_stoploss_order_okx(default_conf, mocker):
default_conf['dry_run'] = False
api_mock = MagicMock()
api_mock.fetch_order = MagicMock()
exchange = get_patched_exchange(mocker, default_conf, api_mock, id='okx')
exchange.fetch_stoploss_order('1234', 'ETH/BTC')
assert api_mock.fetch_order.call_count == 1
assert api_mock.fetch_order.call_args_list[0][0][0] == '1234'
assert api_mock.fetch_order.call_args_list[0][0][1] == 'ETH/BTC'
assert api_mock.fetch_order.call_args_list[0][1]['params'] == {'stop': True}
api_mock.fetch_order = MagicMock(side_effect=ccxt.OrderNotFound)
api_mock.fetch_open_orders = MagicMock(return_value=[])
api_mock.fetch_closed_orders = MagicMock(return_value=[])
api_mock.fetch_canceled_orders = MagicMock(creturn_value=[])
with pytest.raises(RetryableOrderError):
exchange.fetch_stoploss_order('1234', 'ETH/BTC')
assert api_mock.fetch_order.call_count == 1
assert api_mock.fetch_open_orders.call_count == 1
assert api_mock.fetch_closed_orders.call_count == 1
assert api_mock.fetch_canceled_orders.call_count == 1
api_mock.fetch_order.reset_mock()
api_mock.fetch_open_orders.reset_mock()
api_mock.fetch_closed_orders.reset_mock()
api_mock.fetch_canceled_orders.reset_mock()
api_mock.fetch_closed_orders = MagicMock(return_value=[
{
'id': '1234',
'status': 'closed',
'info': {'ordId': '123455'}
}
])
mocker.patch(f"{EXMS}.fetch_order", MagicMock(return_value={'id': '123455'}))
resp = exchange.fetch_stoploss_order('1234', 'ETH/BTC')
assert api_mock.fetch_order.call_count == 1
assert api_mock.fetch_open_orders.call_count == 1
assert api_mock.fetch_closed_orders.call_count == 1
assert api_mock.fetch_canceled_orders.call_count == 0
assert resp['id'] == '1234'
assert resp['id_stop'] == '123455'
assert resp['type'] == 'stoploss'
default_conf['dry_run'] = True
exchange = get_patched_exchange(mocker, default_conf, api_mock, id='okx')
dro_mock = mocker.patch(f"{EXMS}.fetch_dry_run_order", MagicMock(return_value={'id': '123455'}))
api_mock.fetch_order.reset_mock()
api_mock.fetch_open_orders.reset_mock()
api_mock.fetch_closed_orders.reset_mock()
api_mock.fetch_canceled_orders.reset_mock()
resp = exchange.fetch_stoploss_order('1234', 'ETH/BTC')
assert api_mock.fetch_order.call_count == 0
assert api_mock.fetch_open_orders.call_count == 0
assert api_mock.fetch_closed_orders.call_count == 0
assert api_mock.fetch_canceled_orders.call_count == 0
assert dro_mock.call_count == 1
@pytest.mark.parametrize('sl1,sl2,sl3,side', [
(1501, 1499, 1501, "sell"),
(1499, 1501, 1499, "buy")
])
def test_stoploss_adjust_okx(mocker, default_conf, sl1, sl2, sl3, side):
exchange = get_patched_exchange(mocker, default_conf, id='okx')
order = {
'type': 'stoploss',
'price': 1500,
'stopLossPrice': 1500,
}
assert exchange.stoploss_adjust(sl1, order, side=side)
assert not exchange.stoploss_adjust(sl2, order, side=side)