krakenfutures: backfill leverage tier notionals

This commit is contained in:
matstedt
2026-01-23 18:53:08 +01:00
committed by Matthias
parent 0d4dadd63f
commit 6ed470884b
3 changed files with 98 additions and 1 deletions
+56
View File
@@ -206,6 +206,62 @@ class Krakenfutures(Exchange):
logger.warning(f"Could not update funding fees for {pair}.")
return 0.0
def get_leverage_tiers(self) -> dict[str, list[dict]]:
"""
Kraken Futures returns leverage tiers with contract-based thresholds.
CCXT maps tiers to min/maxNotional using "numNonContractUnits", but many markets
only expose "contracts". Fill missing min/maxNotional from contract data and
maxPositionSize to keep get_max_leverage functional.
"""
tiers = super().get_leverage_tiers()
if not tiers:
return tiers
for pair, pair_tiers in tiers.items():
self._fill_leverage_tier_notionals(pair, pair_tiers)
return tiers
def _fill_leverage_tier_notionals(self, pair: str, pair_tiers: list[dict]) -> None:
if not pair_tiers:
return
self._fill_missing_min_notional(pair_tiers)
self._fill_missing_max_notional(pair, pair_tiers)
def _fill_missing_min_notional(self, pair_tiers: list[dict]) -> None:
for tier in pair_tiers:
if tier.get("minNotional") is None:
info = tier.get("info") or {}
contracts = self._safe_float(info.get("contracts"))
if contracts is not None:
tier["minNotional"] = contracts
def _fill_missing_max_notional(self, pair: str, pair_tiers: list[dict]) -> None:
for i in range(len(pair_tiers) - 1):
if pair_tiers[i].get("maxNotional") is None:
next_min = pair_tiers[i + 1].get("minNotional")
if next_min is not None:
pair_tiers[i]["maxNotional"] = next_min
last = pair_tiers[-1]
if last.get("maxNotional") is None:
max_notional = self._max_notional_from_market(pair)
if max_notional is not None:
last["maxNotional"] = max_notional
elif last.get("minNotional") is not None:
# Avoid None values, even if we cannot infer the real max.
last["maxNotional"] = last["minNotional"]
def _max_notional_from_market(self, pair: str) -> float | None:
market = self.markets.get(pair)
if not market:
return None
max_pos = self._safe_float(market.get("info", {}).get("maxPositionSize"))
if max_pos is None:
return None
contract_size = self._safe_float(market.get("contractSize")) or 1.0
return max_pos * contract_size
@staticmethod
def _safe_float(v: Any) -> float | None:
try: