ExApi(token, account=None) 提供同步 API,内部 I/O 由同步调用推进。
一个实例,一条更新循环#
- 所有调用必须在创建实例的线程中执行。
- 不能在运行中的 asyncio 事件循环里直接调用。
- 长时间 CPU 计算或阻塞业务代码会延迟更新和故障检查。
with ExApi(token) as api:
quote = api.watch_quote(symbol)
bars = api.watch_kline(symbol, "1m")
while api.wait_update():
# Inspect all watches after the same update.
if quote.is_changing("last_price"):
consume_quote(quote.data())
if bars.is_changing():
consume_bars(bars.data())示例中的 consume_quote、consume_bars 是你的业务函数。多个订阅共用一个更新循环;使用独立线程运行同步程序时,应在那个线程里创建、使用并关闭整个实例。跨线程、关闭后调用或在 asyncio 事件循环中直接调用,可能抛出 RuntimeError。
wait_update 的语义#
wait_update(deadline=None) -> bool 等待并发布下一批用户可见更新。
| 结果 | 含义 |
|---|---|
True | 已提交一批可见更新 |
False | 到达调用方指定的绝对期限,仍没有更新 |
| 异常 | SDK 运行错误,不用 False 表示致命错误 |
不指定期限时,调用可能持续等待。
它也负责推进连接恢复、CTP 同步及交易回报。一批更新可能只涉及部分观察对象,返回 True 后仍应分别检查需要的对象。创建观察句柄不代表已有可交易的、最新的数据;K 线初始化读取见 K 线窗口。
有限等待#
下面的片段放在已创建 api 和 quote 的生命周期内:
import time
while True:
if not api.wait_update(deadline=time.time() + 5):
print("本次等待到期,继续等待")
continue
if quote.is_changing():
print(quote.data())- 时间格式:
deadline是 Unix 秒的绝对时间,不能直接传5表示五秒。 - 超时含义:
False只表示本次等待到期,不代表断线。需要持续运行时,不要写成while api.wait_update(deadline=...):,否则一次超时就会结束循环。 - 任务总时限:在循环外计算一次总截止时间,并在循环中检查;不要在每次更新后重新延长期限。
data 返回独立快照#
Quote、资金、持仓、订单、成交均通过快照读取;保存的快照不随未来wait_update()改变。- K 线返回独立 pandas DataFrame,带有
attrs["symbol"]与attrs["period"]。在快照上增加指标列不会保留到下一次data()。 - 持仓、订单、成交返回只读 Mapping,即使指定了单个合约,也不是单个对象。
- 断线时仍保留最后一次快照。数据存在不等于有效;交易先检查
trading_status(),行情先检查timestamp。
is_changing 检查最近一次提交#
is_changing(key=None) 的参数 | 检查内容 |
|---|---|
| 不传字段 | 业务字段变化,默认不包含资金的 updated_at |
| 字符串 | 单字段变化 |
| 字符串列表 | 其中任意字段变化 |
变化与“收到了消息”不同,相同字段值的重复回报不会产生字段变化:
- K 线:只比较末行;新 K 线收盘价与前一根相同,不触发
"close"变化。判断新周期检查"timestamp",不能将它当作整个 DataFrame 的变更检测。 - 资金:金额未变时,
funds.is_changing()可以是False;检查funds.is_changing("updated_at")可观察资金查询完成时间变化。 - 持仓、订单和成交映射:检查成员字段,成员增减也构成变化;按合约创建的句柄仅检查该合约。
if quote.is_changing(["last_price", "volume"]):
current = quote.data()
print(current.last_price, current.volume)同一合约多次订阅行情返回同一句柄。K 线按 (symbol, period, data_length) 区分句柄;不同长度是不同窗口。仅使用 data()、is_changing() 等公开方法。
清理资源#
优先使用 with ExApi(...) as api:,也可以在 try/finally 中调用 api.close()。
关闭不等于撤单:关闭只释放资源,不会撤销已提交委托。如有未结束订单,退出前需依据业务规则明确处理。