Improve futures detection, add ccxt-compat test
This commit is contained in:
parent
4e9b83e170
commit
75eccea88d
@ -3,7 +3,7 @@ import json
|
|||||||
import logging
|
import logging
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, List, Optional, Tuple
|
from typing import Any, Dict, List, Optional, Tuple
|
||||||
|
|
||||||
import arrow
|
import arrow
|
||||||
import ccxt
|
import ccxt
|
||||||
@ -119,6 +119,10 @@ class Binance(Exchange):
|
|||||||
except ccxt.BaseError as e:
|
except ccxt.BaseError as e:
|
||||||
raise OperationalException(e) from e
|
raise OperationalException(e) from e
|
||||||
|
|
||||||
|
def market_is_future(self, market: Dict[str, Any]) -> bool:
|
||||||
|
# TODO-lev: This should be unified in ccxt to "swap"...
|
||||||
|
return market.get('future', False) is True
|
||||||
|
|
||||||
@retrier
|
@retrier
|
||||||
def fill_leverage_brackets(self):
|
def fill_leverage_brackets(self):
|
||||||
"""
|
"""
|
||||||
|
@ -340,7 +340,7 @@ class Exchange:
|
|||||||
return self.markets.get(pair, {}).get('base', '')
|
return self.markets.get(pair, {}).get('base', '')
|
||||||
|
|
||||||
def market_is_future(self, market: Dict[str, Any]) -> bool:
|
def market_is_future(self, market: Dict[str, Any]) -> bool:
|
||||||
return market.get('future', False) is True or market.get('futures') is True
|
return market.get('swap', False) is True
|
||||||
|
|
||||||
def market_is_spot(self, market: Dict[str, Any]) -> bool:
|
def market_is_spot(self, market: Dict[str, Any]) -> bool:
|
||||||
return market.get('spot', False) is True
|
return market.get('spot', False) is True
|
||||||
|
@ -159,3 +159,7 @@ class Ftx(Exchange):
|
|||||||
if order['type'] == 'stop':
|
if order['type'] == 'stop':
|
||||||
return safe_value_fallback2(order, order, 'id_stop', 'id')
|
return safe_value_fallback2(order, order, 'id_stop', 'id')
|
||||||
return order['id']
|
return order['id']
|
||||||
|
|
||||||
|
def market_is_future(self, market: Dict[str, Any]) -> bool:
|
||||||
|
# TODO-lev: This should be unified in ccxt to "swap"...
|
||||||
|
return market.get('future', False) is True
|
||||||
|
@ -778,6 +778,7 @@ def get_markets():
|
|||||||
'quote': 'USDT',
|
'quote': 'USDT',
|
||||||
'spot': True,
|
'spot': True,
|
||||||
'future': True,
|
'future': True,
|
||||||
|
'swap': True,
|
||||||
'margin': True,
|
'margin': True,
|
||||||
'type': 'spot',
|
'type': 'spot',
|
||||||
'precision': {
|
'precision': {
|
||||||
@ -805,6 +806,7 @@ def get_markets():
|
|||||||
'active': False,
|
'active': False,
|
||||||
'spot': True,
|
'spot': True,
|
||||||
'future': True,
|
'future': True,
|
||||||
|
'swap': True,
|
||||||
'margin': True,
|
'margin': True,
|
||||||
'type': 'spot',
|
'type': 'spot',
|
||||||
'precision': {
|
'precision': {
|
||||||
|
@ -26,6 +26,7 @@ EXCHANGES = {
|
|||||||
'pair': 'BTC/USDT',
|
'pair': 'BTC/USDT',
|
||||||
'hasQuoteVolume': True,
|
'hasQuoteVolume': True,
|
||||||
'timeframe': '5m',
|
'timeframe': '5m',
|
||||||
|
'futures': True,
|
||||||
},
|
},
|
||||||
'kraken': {
|
'kraken': {
|
||||||
'pair': 'BTC/USDT',
|
'pair': 'BTC/USDT',
|
||||||
@ -82,13 +83,19 @@ def exchange(request, exchange_conf):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(params=EXCHANGES, scope="class")
|
@pytest.fixture(params=EXCHANGES, scope="class")
|
||||||
def exchange_futures(request, exchange_conf):
|
def exchange_futures(request, exchange_conf, class_mocker):
|
||||||
if not EXCHANGES[request.param].get('futures') is True:
|
if not EXCHANGES[request.param].get('futures') is True:
|
||||||
yield None, request.param
|
yield None, request.param
|
||||||
else:
|
else:
|
||||||
exchange_conf['exchange']['name'] = request.param
|
exchange_conf['exchange']['name'] = request.param
|
||||||
exchange_conf['trading_mode'] = 'futures'
|
exchange_conf['trading_mode'] = 'futures'
|
||||||
exchange_conf['collateral'] = 'cross'
|
exchange_conf['collateral'] = 'cross'
|
||||||
|
# TODO-lev This mock should no longer be necessary once futures are enabled.
|
||||||
|
class_mocker.patch(
|
||||||
|
'freqtrade.exchange.exchange.Exchange.validate_trading_mode_and_collateral')
|
||||||
|
class_mocker.patch(
|
||||||
|
'freqtrade.exchange.binance.Binance.fill_leverage_brackets')
|
||||||
|
|
||||||
exchange = ExchangeResolver.load_exchange(request.param, exchange_conf, validate=True)
|
exchange = ExchangeResolver.load_exchange(request.param, exchange_conf, validate=True)
|
||||||
|
|
||||||
yield exchange, request.param
|
yield exchange, request.param
|
||||||
@ -103,6 +110,20 @@ class TestCCXTExchange():
|
|||||||
markets = exchange.markets
|
markets = exchange.markets
|
||||||
assert pair in markets
|
assert pair in markets
|
||||||
assert isinstance(markets[pair], dict)
|
assert isinstance(markets[pair], dict)
|
||||||
|
assert exchange.market_is_spot(markets[pair])
|
||||||
|
|
||||||
|
def test_load_markets_futures(self, exchange_futures):
|
||||||
|
exchange, exchangename = exchange_futures
|
||||||
|
if not exchange:
|
||||||
|
# exchange_futures only returns values for supported exchanges
|
||||||
|
return
|
||||||
|
pair = EXCHANGES[exchangename]['pair']
|
||||||
|
pair = EXCHANGES[exchangename].get('futures_pair', pair)
|
||||||
|
markets = exchange.markets
|
||||||
|
assert pair in markets
|
||||||
|
assert isinstance(markets[pair], dict)
|
||||||
|
|
||||||
|
assert exchange.market_is_future(markets[pair])
|
||||||
|
|
||||||
def test_ccxt_fetch_tickers(self, exchange):
|
def test_ccxt_fetch_tickers(self, exchange):
|
||||||
exchange, exchangename = exchange
|
exchange, exchangename = exchange
|
||||||
|
@ -2985,6 +2985,10 @@ def test_timeframe_to_next_date():
|
|||||||
("BTC-PERP", 'BTC', 'USD', "ftx", False, False, True, 'spot', {}, False),
|
("BTC-PERP", 'BTC', 'USD', "ftx", False, False, True, 'spot', {}, False),
|
||||||
("BTC-PERP", 'BTC', 'USD', "ftx", False, False, True, 'margin', {}, False),
|
("BTC-PERP", 'BTC', 'USD', "ftx", False, False, True, 'margin', {}, False),
|
||||||
("BTC-PERP", 'BTC', 'USD', "ftx", False, False, True, 'futures', {}, True),
|
("BTC-PERP", 'BTC', 'USD', "ftx", False, False, True, 'futures', {}, True),
|
||||||
|
|
||||||
|
("BTC/USDT:USDT", 'BTC', 'USD', "okex", False, False, True, 'spot', {}, False),
|
||||||
|
("BTC/USDT:USDT", 'BTC', 'USD', "okex", False, False, True, 'margin', {}, False),
|
||||||
|
("BTC/USDT:USDT", 'BTC', 'USD', "okex", False, False, True, 'futures', {}, True),
|
||||||
])
|
])
|
||||||
def test_market_is_tradable(
|
def test_market_is_tradable(
|
||||||
mocker, default_conf, market_symbol, base,
|
mocker, default_conf, market_symbol, base,
|
||||||
@ -2999,6 +3003,7 @@ def test_market_is_tradable(
|
|||||||
'quote': quote,
|
'quote': quote,
|
||||||
'spot': spot,
|
'spot': spot,
|
||||||
'future': futures,
|
'future': futures,
|
||||||
|
'swap': futures,
|
||||||
'margin': margin,
|
'margin': margin,
|
||||||
**(add_dict),
|
**(add_dict),
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user