feat: add typedDict for LeverageTiers - fix unbound upper bound for get_max_leverage

This commit is contained in:
Matthias
2026-01-25 11:12:20 +01:00
parent 87b313cd53
commit 52fc180c75
3 changed files with 34 additions and 4 deletions

View File

@@ -73,6 +73,7 @@ from freqtrade.exchange.exchange_types import (
CcxtPosition,
FtHas,
FundingRate,
LeverageTier,
OHLCVResponse,
OrderBook,
Ticker,
@@ -194,7 +195,7 @@ class Exchange:
self._exchange_ws: ExchangeWS | None = None
self._markets: dict = {}
self._trading_fees: dict[str, Any] = {}
self._leverage_tiers: dict[str, list[dict]] = {}
self._leverage_tiers: dict[str, list[LeverageTier]] = {}
# Lock event loop. This is necessary to avoid race-conditions when using force* commands
# Due to funding fee fetching.
self._loop_lock = Lock()
@@ -3621,7 +3622,7 @@ class Exchange:
pair_tiers.append(self.parse_leverage_tier(tier))
self._leverage_tiers[pair] = pair_tiers
def parse_leverage_tier(self, tier) -> dict:
def parse_leverage_tier(self, tier) -> LeverageTier:
info = tier.get("info", {})
return {
"minNotional": tier["minNotional"],
@@ -3662,7 +3663,11 @@ class Exchange:
for tier in pair_tiers:
# Adjust notional by leverage to do a proper comparison
min_stake = tier["minNotional"] / (prior_max_lev or tier["maxLeverage"])
max_stake = tier["maxNotional"] / tier["maxLeverage"]
max_stake = (
tier["maxNotional"] / tier["maxLeverage"]
if tier["maxNotional"] is not None
else float("inf")
)
prior_max_lev = tier["maxLeverage"]
if min_stake <= stake_amount <= max_stake:
return tier["maxLeverage"]

View File

@@ -115,5 +115,27 @@ class CcxtPosition(TypedDict):
CcxtOrder = dict[str, Any]
class LeverageTier(TypedDict):
"""
Represents a single leverage tier returned by the exchange.
Attributes:
minNotional: Minimum notional value (quote currency) for which this tier applies.
maxNotional: Maximum notional value (quote currency) for which this tier applies.
When ``maxNotional`` is ``None``, the tier is unbounded on the upper side,
i.e. there is no maximum notional limit for this tier
maintenanceMarginRate: Maintenance margin rate for this tier (fraction, e.g. 0.005 for 0.5%)
maxLeverage: Maximum leverage allowed for this tier
maintAmt: Optional fixed maintenance margin amount, if provided by the exchange
"""
minNotional: float
maxNotional: float | None
maintenanceMarginRate: float
maxLeverage: float
maintAmt: float | None
# pair, timeframe, candleType, OHLCV, drop last?,
OHLCVResponse = tuple[str, str, CandleType, list, bool]

View File

@@ -182,7 +182,10 @@ class Okx(Exchange):
return float("inf")
pair_tiers = self._leverage_tiers[pair]
return pair_tiers[-1]["maxNotional"] / leverage
last_max_notional = pair_tiers[-1]["maxNotional"]
if last_max_notional is None:
return float("inf")
return last_max_notional / leverage
def _get_stop_params(self, side: BuySell, ordertype: str, stop_price: float) -> dict:
params = super()._get_stop_params(side, ordertype, stop_price)