跳转到内容

订单管理与风控闸门

订单管理系统(OMS)位于策略与券商之间,职责有三:

  1. 订单状态机:订单从创建到终结的全生命周期管理;
  2. 券商对接:API 封装、重试、幂等性处理;
  3. 下单前风控(pre-trade risk):所有订单的最后一道检查闸门。

订单的状态转移必须显式定义:

created → submitted → acknowledged → partially_filled → filled
↘ rejected ↘ cancelled
↘ expired

工程要点:

  • 状态持久化:每次状态变更写入持久存储,进程重启后可恢复——"重启后不知道自己有哪些未完成订单"是实盘最危险的失忆;
  • 状态由回报驱动:本地状态只信任券商回报(acknowledged / filled),不对"应该成交了"做乐观推断;
  • 超时处理:submitted 超过阈值无回报,主动查询而非等待。

重复下单是最常见的实盘事故:网络超时后重试,第一笔其实已成交——结果买了双倍。处理:

  • 每个逻辑订单带唯一 client_order_id,重试复用同一 ID;
  • 重试前先查询订单状态,不做盲目重发;
  • 对账时用 client_order_id 对齐本地与券商记录。
idempotent-order.py
import uuid
import time
class OMS:
def __init__(self, broker):
self.broker = broker
self.orders: dict[str, dict] = {} # client_order_id → 状态
def place(self, symbol: str, side: str, size: float) -> str:
oid = str(uuid.uuid4())
self.orders[oid] = {"symbol": symbol, "side": side, "size": size,
"status": "created", "ts": time.time()}
resp = self.broker.submit(client_order_id=oid, symbol=symbol,
side=side, size=size) # 幂等 ID
self.orders[oid]["status"] = resp["status"]
return oid
def retry(self, oid: str) -> str:
"""重试前先查询,不做盲目重发"""
status = self.broker.query(oid)
if status is None: # 确认未受理才重发
resp = self.broker.submit(client_order_id=oid, **self.orders[oid])
self.orders[oid]["status"] = resp["status"]
return self.orders[oid]["status"]

所有风控检查在下单前同步执行,超限直接拒单并告警:

  • 单笔订单金额上限
  • 单日累计亏损上限(触发后当日停止交易)
  • 持仓集中度(单一标的/行业占比上限)
  • 订单价格合理性检查(偏离现价超过阈值拒单——防"胖手指")
  • 目标持仓一致性(本单是否与目标组合一致,见均值—方差与其失败)
  • 交易时段与规则检查(该时段该市场是否可交易,见第十二卷)
  • 订单状态机持久化,重启可恢复;
  • 幂等 client_order_id + 重试前查询,杜绝重复下单;
  • 闸门清单固化为代码,每条超限都告警并记录。
  • 所有风控检查在下单前同步执行,超限直接拒单并告警
  • 订单状态必须持久化,重启后可恢复
  • 券商 API 的幂等性问题:重复下单是最常见的实盘事故