Files
siloqy/prod/bingx/schemas.py
Codex 84e4a50e3f repo hygiene: track the PINK launcher import closure
67 production .py modules that the running PINK service imports but which
were never committed: prod/bingx/ (HTTP client, market/user streams,
journal, config), prod/clean_arch/ adapters/persistence/runtime/dita/dita_v2
production modules and their co-located tests. Rule going forward: every
module imported by launch_dolphin_pink.py / pink_direct.py must appear in
git ls-files. Excludes _backup dirs, __pycache__, and non-code files.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 15:09:32 +02:00

81 lines
3.0 KiB
Python

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,
)