This commit is contained in:
2026-09-05 13:53:26 +08:00
parent 63ffc1329b
commit 58e1e3e291
7 changed files with 343 additions and 317 deletions

View File

@@ -3,15 +3,14 @@
from __future__ import annotations
import secrets
import logging as log
from dataclasses import dataclass
from datetime import datetime, timedelta
from threading import Lock
from typing import Any
from cachelib import SimpleCache
import httpx
import logging
from sdk import APIError, ORDER_SIDE_BY_OFFSET, Client, OrderItem
import httpx
from sdk import Client,ORDER_SIDE_BY_OFFSET,APIError,OrderItem
# 表示委托仍在处理、可能继续成交的 QMT 状态。
BUSY_STATUSES = {"48", "49", "50", "51", "52", "55"}
@@ -23,13 +22,12 @@ CANCELABLE_STATUSES = {"49", "50", "51", "52"}
@dataclass(frozen=True, slots=True)
class PlaceOrderRequest:
"""``OrderBook.place`` 提交委托所需的全部参数。"""
client: Any
op: int
code: str
volume: int
order_id: str
strategy_name: str
kind: str = ""
class OrderBook:
@@ -79,30 +77,28 @@ class OrderBook:
):
client.cancel_by_id(item.id)
canceled += 1
log.info("[Order] 超时撤单,代码=%s,方向=%s,柜台订单=%s", item.code, item.side, item.id)
logging.info("[Order] 超时撤单,代码=%s,方向=%s,柜台订单=%s", item.code, item.side, item.id)
continue
# 缓存本次有效订单
data.append(item)
with self.mutex:
self.data = data
self.busy_keys = busy_keys
log.info("[Order] 刷新完成,跟踪=%d,处理中=%d,撤销=%d", len(data), len(busy_keys), canceled)
logging.info("[Order] 刷新完成,跟踪=%d,处理中=%d,撤销=%d", len(data), len(busy_keys), canceled)
def place(self, request: PlaceOrderRequest) -> bool:
"""按最新价提交委托,并立即写入本地方向锁。"""
side = ORDER_SIDE_BY_OFFSET.get(str(request.op), "")
if not side:
log.warning("[Order] 下单失败,代码=%s,原因=未知买卖方向(%s)", request.code, request.op)
logging.warning("[Order] 下单失败,代码=%s,原因=未知买卖方向(%s)", request.code, request.op)
return False
key = self._busy_key(side, request.code)
with self.mutex:
if key in self.busy_keys or self.busy_cache.has(key):
log.info("[Order] 跳过重复下单,代码=%s,方向=%s", request.code, side)
logging.info("[Order] 跳过重复下单,代码=%s,方向=%s", request.code, side)
return False
self.busy_cache.set(key, True, timeout=self.lock_timeout_sec)
@@ -115,31 +111,12 @@ class OrderBook:
order_id=request.order_id,
)
except APIError as exc:
log.exception("[Order] 下单失败,代码=%s,本地订单=%sHTTP状态=%d,错误=%s", request.code, request.order_id, exc.status_code, exc.message or str(exc))
logging.exception("[Order] 下单失败,代码=%s,本地订单=%sHTTP状态=%d,错误=%s", request.code, request.order_id, exc.status_code, exc.message or str(exc))
return False
except (httpx.RequestError, ValueError):
# 响应异常不能证明柜台未受理,保留缓存防重,不自动重试。
log.exception("[Order] 下单请求或响应异常,代码=%s,本地订单=%s", request.code, request.order_id)
logging.exception("[Order] 下单请求或响应异常,代码=%s,本地订单=%s", request.code, request.order_id)
return False
if not isinstance(result, dict):
log.warning("[Order] 下单失败,代码=%s,本地订单=%s原因=响应格式无效", request.code, request.order_id)
return False
order_ref = str(result.get("order_ref") or "").strip().lower()
if result.get("status") != "success" or order_ref in {"", "unknown", "none"}:
log.warning("[Order] 下单被拒绝,代码=%s,本地订单=%s,状态=%s,柜台订单=%s", request.code, request.order_id, result.get("status"), order_ref)
return False
pending = OrderItem(
id=order_ref,
code=request.code,
side=side,
remark=request.order_id,
status="48",
created_at=datetime.now(),
volume=request.volume,
local_order_id=request.order_id,
)
with self.mutex:
self.data.append(pending)
log.info("[Order] 下单已受理,代码=%s,方向=%s,数量=%d,本地订单=%s,柜台订单=%s", request.code, side, request.volume, request.order_id, order_ref)
logging.info("[Order] 下单已受理,代码=%s方向=%s,数量=%d本地订单=%s返回=%s", request.code, side, request.volume, request.order_id, result)
return True