okex loads all leverage tiers at beginning, removed get tiers for pair
This commit is contained in:
parent
8657e99c26
commit
7a0f7da128
@ -1894,28 +1894,6 @@ class Exchange:
|
|||||||
'maintAmt': float(info['cum']) if 'cum' in info else None,
|
'maintAmt': float(info['cum']) if 'cum' in info else None,
|
||||||
}
|
}
|
||||||
|
|
||||||
@retrier
|
|
||||||
def get_leverage_tiers_for_pair(self, pair: str) -> List:
|
|
||||||
# When exchanges can load all their leverage tiers at once in the constructor
|
|
||||||
# then this method does nothing, it should only be implemented when the leverage
|
|
||||||
# tiers requires per symbol fetching to avoid excess api calls
|
|
||||||
if pair not in self._leverage_tiers:
|
|
||||||
self._leverage_tiers[pair] = []
|
|
||||||
if (
|
|
||||||
self._api.has['fetchLeverageTiers'] and
|
|
||||||
not self._ft_has['can_fetch_multiple_tiers'] and
|
|
||||||
self.trading_mode == TradingMode.FUTURES
|
|
||||||
):
|
|
||||||
try:
|
|
||||||
tiers = self._api.fetch_leverage_tiers(pair)
|
|
||||||
for tier in tiers[pair]:
|
|
||||||
self._leverage_tiers[pair].append(self.parse_leverage_tier(tier))
|
|
||||||
|
|
||||||
except ccxt.BadRequest:
|
|
||||||
return []
|
|
||||||
|
|
||||||
return self._leverage_tiers[pair]
|
|
||||||
|
|
||||||
def get_max_leverage(self, pair: str, stake_amount: Optional[float]) -> float:
|
def get_max_leverage(self, pair: str, stake_amount: Optional[float]) -> float:
|
||||||
"""
|
"""
|
||||||
Returns the maximum leverage that a pair can be traded at
|
Returns the maximum leverage that a pair can be traded at
|
||||||
@ -1926,7 +1904,7 @@ class Exchange:
|
|||||||
if self.trading_mode == TradingMode.SPOT:
|
if self.trading_mode == TradingMode.SPOT:
|
||||||
return 1.0
|
return 1.0
|
||||||
|
|
||||||
if self._api.has['fetchLeverageTiers']:
|
if self.trading_mode == TradingMode.FUTURES:
|
||||||
|
|
||||||
# Checks and edge cases
|
# Checks and edge cases
|
||||||
if stake_amount is None:
|
if stake_amount is None:
|
||||||
@ -1934,20 +1912,21 @@ class Exchange:
|
|||||||
f'{self.name}.get_max_leverage requires argument stake_amount'
|
f'{self.name}.get_max_leverage requires argument stake_amount'
|
||||||
)
|
)
|
||||||
|
|
||||||
pair_tiers = self.get_leverage_tiers_for_pair(pair)
|
if pair not in self._leverage_tiers:
|
||||||
num_tiers = len(pair_tiers)
|
# Maybe raise exception because it can't be traded on futures?
|
||||||
if num_tiers < 1:
|
|
||||||
return 1.0
|
return 1.0
|
||||||
|
|
||||||
|
pair_tiers = self._leverage_tiers[pair]
|
||||||
|
|
||||||
if stake_amount == 0:
|
if stake_amount == 0:
|
||||||
return self._leverage_tiers[pair][0]['lev'] # Max lev for lowest amount
|
return self._leverage_tiers[pair][0]['lev'] # Max lev for lowest amount
|
||||||
|
|
||||||
for tier_index in range(num_tiers):
|
for tier_index in range(len(pair_tiers)):
|
||||||
|
|
||||||
tier = pair_tiers[tier_index]
|
tier = pair_tiers[tier_index]
|
||||||
lev = tier['lev']
|
lev = tier['lev']
|
||||||
|
|
||||||
if tier_index < num_tiers - 1:
|
if tier_index < len(pair_tiers) - 1:
|
||||||
next_tier = pair_tiers[tier_index+1]
|
next_tier = pair_tiers[tier_index+1]
|
||||||
next_floor = next_tier['min'] / next_tier['lev']
|
next_floor = next_tier['min'] / next_tier['lev']
|
||||||
if next_floor > stake_amount: # Next tier min too high for stake amount
|
if next_floor > stake_amount: # Next tier min too high for stake amount
|
||||||
@ -2280,13 +2259,13 @@ class Exchange:
|
|||||||
|
|
||||||
if self._api.has['fetchLeverageTiers']:
|
if self._api.has['fetchLeverageTiers']:
|
||||||
|
|
||||||
pair_tiers = self.get_leverage_tiers_for_pair(pair)
|
if pair not in self._leverage_tiers:
|
||||||
|
|
||||||
if len(pair_tiers) < 1:
|
|
||||||
raise InvalidOrderException(
|
raise InvalidOrderException(
|
||||||
f"Maintenance margin rate for {pair} is unavailable for {self.name}"
|
f"Maintenance margin rate for {pair} is unavailable for {self.name}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
pair_tiers = self._leverage_tiers[pair]
|
||||||
|
|
||||||
for tier in reversed(pair_tiers):
|
for tier in reversed(pair_tiers):
|
||||||
if nominal_value >= tier['min']:
|
if nominal_value >= tier['min']:
|
||||||
return (tier['mmr'], tier['maintAmt'])
|
return (tier['mmr'], tier['maintAmt'])
|
||||||
|
@ -59,14 +59,25 @@ class Okx(Exchange):
|
|||||||
return float('inf') # Not actually inf, but this probably won't matter for SPOT
|
return float('inf') # Not actually inf, but this probably won't matter for SPOT
|
||||||
|
|
||||||
if pair not in self._leverage_tiers:
|
if pair not in self._leverage_tiers:
|
||||||
tiers = self.get_leverage_tiers_for_pair(pair)
|
return float('inf')
|
||||||
if not tiers: # Not a leveraged market
|
|
||||||
return float('inf')
|
|
||||||
else:
|
|
||||||
self._leverage_tiers[pair] = tiers
|
|
||||||
|
|
||||||
pair_tiers = self._leverage_tiers[pair]
|
pair_tiers = self._leverage_tiers[pair]
|
||||||
return pair_tiers[-1]['max'] / leverage
|
return pair_tiers[-1]['max'] / leverage
|
||||||
|
|
||||||
def load_leverage_tiers(self) -> Dict[str, List[Dict]]:
|
def load_leverage_tiers(self) -> Dict[str, List[Dict]]:
|
||||||
return {}
|
if self.trading_mode == TradingMode.FUTURES:
|
||||||
|
markets = self.markets
|
||||||
|
symbols = []
|
||||||
|
|
||||||
|
for symbol, market in markets.items():
|
||||||
|
if (market["swap"] and market["linear"]):
|
||||||
|
symbols.append(market["symbol"])
|
||||||
|
|
||||||
|
tiers = {}
|
||||||
|
for symbol in symbols:
|
||||||
|
res = self._api.fetchLeverageTiers(symbol)
|
||||||
|
tiers[symbol] = res[symbol]
|
||||||
|
|
||||||
|
return tiers
|
||||||
|
else:
|
||||||
|
return {}
|
||||||
|
@ -4300,115 +4300,6 @@ def test_parse_leverage_tier(mocker, default_conf):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_get_leverage_tiers_for_pair(
|
|
||||||
mocker,
|
|
||||||
default_conf,
|
|
||||||
leverage_tiers,
|
|
||||||
):
|
|
||||||
|
|
||||||
api_mock = MagicMock()
|
|
||||||
api_mock.fetch_leverage_tiers = MagicMock(return_value={
|
|
||||||
'DOGE/USDT:USDT': [
|
|
||||||
{
|
|
||||||
'tier': 1,
|
|
||||||
'notionalFloor': 0,
|
|
||||||
'notionalCap': 500,
|
|
||||||
'maintenanceMarginRatio': 0.02,
|
|
||||||
'maxLeverage': 75,
|
|
||||||
'info': {
|
|
||||||
'baseMaxLoan': '',
|
|
||||||
'imr': '0.013',
|
|
||||||
'instId': '',
|
|
||||||
'maxLever': '75',
|
|
||||||
'maxSz': '500',
|
|
||||||
'minSz': '0',
|
|
||||||
'mmr': '0.01',
|
|
||||||
'optMgnFactor': '0',
|
|
||||||
'quoteMaxLoan': '',
|
|
||||||
'tier': '1',
|
|
||||||
'uly': 'DOGE-USDT'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'tier': 2,
|
|
||||||
'notionalFloor': 501,
|
|
||||||
'notionalCap': 1000,
|
|
||||||
'maintenanceMarginRatio': 0.025,
|
|
||||||
'maxLeverage': 50,
|
|
||||||
'info': {
|
|
||||||
'baseMaxLoan': '',
|
|
||||||
'imr': '0.02',
|
|
||||||
'instId': '',
|
|
||||||
'maxLever': '50',
|
|
||||||
'maxSz': '1000',
|
|
||||||
'minSz': '501',
|
|
||||||
'mmr': '0.015',
|
|
||||||
'optMgnFactor': '0',
|
|
||||||
'quoteMaxLoan': '',
|
|
||||||
'tier': '2',
|
|
||||||
'uly': 'DOGE-USDT'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
})
|
|
||||||
|
|
||||||
# Spot
|
|
||||||
type(api_mock)._ft_has = PropertyMock(return_value={'fetchLeverageTiers': True})
|
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
|
||||||
exchange._ft_has['can_fetch_multiple_tiers'] = False
|
|
||||||
assert exchange.get_leverage_tiers_for_pair('DOGE/USDT:USDT') == []
|
|
||||||
|
|
||||||
# 'can_fetch_multiple_tiers': True
|
|
||||||
default_conf['trading_mode'] = 'futures'
|
|
||||||
default_conf['margin_mode'] = 'isolated'
|
|
||||||
type(api_mock).has = PropertyMock(return_value={'fetchLeverageTiers': True})
|
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
|
||||||
exchange._ft_has['can_fetch_multiple_tiers'] = True
|
|
||||||
assert exchange.get_leverage_tiers_for_pair('DOGE/USDT:USDT') == []
|
|
||||||
|
|
||||||
# 'fetchLeverageTiers': False
|
|
||||||
type(api_mock).has = PropertyMock(return_value={'fetchLeverageTiers': False})
|
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
|
||||||
exchange._ft_has['can_fetch_multiple_tiers'] = False
|
|
||||||
assert exchange.get_leverage_tiers_for_pair('DOGE/USDT:USDT') == []
|
|
||||||
|
|
||||||
# 'fetchLeverageTiers': True
|
|
||||||
type(api_mock).has = PropertyMock(return_value={'fetchLeverageTiers': True})
|
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
|
||||||
exchange._ft_has['can_fetch_multiple_tiers'] = False
|
|
||||||
assert exchange.get_leverage_tiers_for_pair('DOGE/USDT:USDT') == [
|
|
||||||
{
|
|
||||||
'min': 0,
|
|
||||||
'max': 500,
|
|
||||||
'mmr': 0.02,
|
|
||||||
'lev': 75,
|
|
||||||
'maintAmt': None
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'min': 501,
|
|
||||||
'max': 1000,
|
|
||||||
'mmr': 0.025,
|
|
||||||
'lev': 50,
|
|
||||||
'maintAmt': None
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
# exception_handlers
|
|
||||||
type(api_mock).has = PropertyMock(return_value={'fetchLeverageTiers': True})
|
|
||||||
default_conf['dry_run'] = False
|
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
|
||||||
|
|
||||||
ccxt_exceptionhandlers(
|
|
||||||
mocker,
|
|
||||||
default_conf,
|
|
||||||
api_mock,
|
|
||||||
"binance",
|
|
||||||
"get_leverage_tiers_for_pair",
|
|
||||||
"fetch_leverage_tiers",
|
|
||||||
pair='DOGE/USDT:USDT',
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_maintenance_ratio_and_amt_exceptions(mocker, default_conf, leverage_tiers):
|
def test_get_maintenance_ratio_and_amt_exceptions(mocker, default_conf, leverage_tiers):
|
||||||
api_mock = MagicMock()
|
api_mock = MagicMock()
|
||||||
default_conf['trading_mode'] = 'futures'
|
default_conf['trading_mode'] = 'futures'
|
||||||
@ -4423,7 +4314,6 @@ def test_get_maintenance_ratio_and_amt_exceptions(mocker, default_conf, leverage
|
|||||||
exchange.get_maintenance_ratio_and_amt('1000SHIB/USDT', -1)
|
exchange.get_maintenance_ratio_and_amt('1000SHIB/USDT', -1)
|
||||||
|
|
||||||
exchange._leverage_tiers = {}
|
exchange._leverage_tiers = {}
|
||||||
exchange.get_leverage_tiers_for_pair = MagicMock(return_value=[])
|
|
||||||
|
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
InvalidOrderException,
|
InvalidOrderException,
|
||||||
|
@ -162,5 +162,4 @@ def test_get_max_pair_stake_amount_okex(default_conf, mocker, leverage_tiers):
|
|||||||
assert exchange.get_max_pair_stake_amount('BTC/USDT', 1.0) == 1000000000
|
assert exchange.get_max_pair_stake_amount('BTC/USDT', 1.0) == 1000000000
|
||||||
assert exchange.get_max_pair_stake_amount('BTC/USDT', 1.0, 10.0) == 100000000
|
assert exchange.get_max_pair_stake_amount('BTC/USDT', 1.0, 10.0) == 100000000
|
||||||
|
|
||||||
exchange.get_leverage_tiers_for_pair = MagicMock(return_value=None)
|
|
||||||
assert exchange.get_max_pair_stake_amount('TTT/USDT', 1.0) == float('inf') # Not in tiers
|
assert exchange.get_max_pair_stake_amount('TTT/USDT', 1.0) == float('inf') # Not in tiers
|
||||||
|
Loading…
Reference in New Issue
Block a user