Files
siloqy/prod/bingx/schemas.py

81 lines
3.0 KiB
Python
Raw Normal View History

from __future__ import annotations
from dataclasses import dataclass
from decimal import Decimal
def _as_decimal(value: object, default: str = "0") -> Decimal:
if value is None:
return Decimal(default)
return Decimal(str(value))
def unwrap_order_payload(payload: dict[str, object]) -> dict[str, object]:
row = payload.get("order") if isinstance(payload, dict) else None
return row if isinstance(row, dict) else payload
@dataclass(frozen=True)
class BingxContract:
symbol: str
venue_symbol: str
quote_asset: str
base_asset: str
price_precision: int
quantity_precision: int
min_quantity: Decimal
min_notional: Decimal
tick_size: Decimal
step_size: Decimal
maker_fee: Decimal
taker_fee: Decimal
max_leverage: int
@classmethod
def from_http(cls, payload: dict[str, object]) -> "BingxContract":
venue_symbol = str(payload.get("symbol") or payload.get("ticker") or "")
normalized = venue_symbol.replace("-", "")
price_precision = int(payload.get("pricePrecision") or payload.get("price_scale") or 2)
quantity_precision = int(
payload.get("quantityPrecision") or payload.get("quantity_scale") or 3,
)
tick_size = _as_decimal(
payload.get("tickSize") or payload.get("priceStep") or f"1e-{price_precision}",
)
step_size = _as_decimal(
payload.get("stepSize") or payload.get("quantityStep") or f"1e-{quantity_precision}",
)
return cls(
symbol=normalized,
venue_symbol=venue_symbol,
quote_asset=str(payload.get("currency") or payload.get("quoteAsset") or "USDT"),
base_asset=str(payload.get("asset") or payload.get("baseAsset") or normalized[:-4]),
price_precision=price_precision,
quantity_precision=quantity_precision,
min_quantity=_as_decimal(payload.get("minQty") or payload.get("minQuantity") or step_size),
min_notional=_as_decimal(payload.get("minNotional") or payload.get("minQuoteAmount") or "2"),
tick_size=tick_size,
step_size=step_size,
maker_fee=_as_decimal(payload.get("makerFeeRate") or payload.get("makerFee") or "0.0002"),
taker_fee=_as_decimal(payload.get("takerFeeRate") or payload.get("takerFee") or "0.0005"),
max_leverage=int(payload.get("maxLongLeverage") or payload.get("maxLeverage") or 1),
)
@dataclass(frozen=True)
class BingxOrderAck:
order_id: str
client_order_id: str
symbol: str
status: str | None
@classmethod
def from_http(cls, payload: dict[str, object]) -> "BingxOrderAck":
row = unwrap_order_payload(payload)
return cls(
order_id=str(row.get("orderId") or row.get("id") or ""),
client_order_id=str(row.get("clientOrderID") or row.get("clientOrderId") or ""),
symbol=str(row.get("symbol") or ""),
status=str(row.get("status")) if row.get("status") is not None else None,
)