Harden residual mid-close: IOC partial fills, exchange reconcile, atomic book.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-08-02 14:41:00 +08:00
parent 640ecc9530
commit 469e7a258a
8 changed files with 729 additions and 238 deletions
+16 -5
View File
@@ -228,9 +228,11 @@ class BinanceTradeClient:
if reduce_only:
params["reduceOnly"] = "true"
data = self._signed(self._eapi, "POST", "/eapi/v1/order", params)
return self._fill_from_eapi(symbol, data)
return self._fill_from_eapi(symbol, data, allow_partial=True)
def _fill_from_eapi(self, symbol: str, data: dict[str, Any]) -> LiveFill:
def _fill_from_eapi(
self, symbol: str, data: dict[str, Any], *, allow_partial: bool = False
) -> LiveFill:
ord_id = str(data.get("orderId") or data.get("id") or "")
avg = safe_float(data.get("avgPrice")) or safe_float(data.get("price"))
sz = safe_float(data.get("executedQty")) or safe_float(data.get("quantity"))
@@ -251,16 +253,25 @@ class BinanceTradeClient:
if avg and avg > 0 and st == "FILLED":
break
if st in ("CANCELED", "REJECTED", "EXPIRED"):
if allow_partial and sz and sz > 1e-12 and avg and avg > 0:
break
raise RuntimeError(f"币安期权订单失败 status={st} {q}")
if st == "PARTIALLY_FILLED":
continue
if not avg or avg <= 0:
raise RuntimeError(f"币安期权无成交均价 orderId={ord_id} last={data}")
st_final = str(data.get("status") or "").upper()
executed = safe_float(data.get("executedQty")) or float(sz or 0)
if st_final and st_final != "FILLED":
raise RuntimeError(
f"币安期权未完全成交 status={st_final} orderId={ord_id} last={data}"
)
if not (
allow_partial
and executed > 1e-12
and st_final in ("CANCELED", "EXPIRED", "PARTIALLY_FILLED")
):
raise RuntimeError(
f"币安期权未完全成交 status={st_final} orderId={ord_id} last={data}"
)
sz = executed
from .money import abs_fee_usdt
fee = abs(safe_float(data.get("fee")) or 0.0)