问题描述
339204功能号一天执行300万次左右。
解决方案
在 ptrade 量化交易平台中,如果某个功能号(底层 API 接口)一天被执行了 300 万次,这绝对是一个异常的高频调用。一天交易时间(4小时 = 14400秒),300万次意味着每秒调用超过 200 次!这不仅会导致策略被券商服务端限流或封禁,还可能拖垮整个交易环境。
以下是导致此类问题的常见原因排查指南及优化方案:
一、 常见高频调用原因排查
1. 主推事件(回调函数)中的无限死循环
这是导致瞬间产生海量调用的最常见原因。ptrade 提供了 on_order_response(委托主推)和 on_trade_response(成交主推)。
危险操作:如果在这些回调函数中直接调用了下单(order)或撤单(cancel_order)接口,且没有严格的条件限制,就会产生:下单 -> 触发主推 -> 主推中再次下单 -> 再次触发主推 的无限死循环。
官方文档警告:“当在主推里调用委托接口时,需要进行判断处理避免无限迭代循环问题”。
2. tick_data 或 run_interval 中无条件查询
tick_data每 3 秒执行一次。run_interval最小间隔也是 3 秒。
如果在这些高频函数中,每次都无条件地调用查询接口(如get_position,get_orders,get_snapshot),一天下来会产生巨大的调用量。如果策略中订阅了多只股票,且在循环中逐个查询,调用量会呈指数级增长。
3. handle_data 分钟线中的密集循环
如果策略是分钟级别运行,且股票池(universe)非常大,在 handle_data 中对每只股票都调用一次耗时的查询接口(如 get_history、get_fundamentals),也会导致调用量激增。
二、 优化方案与代码规范
1. 严格控制主推事件中的逻辑
在 on_order_response 和 on_trade_response 中,务必使用全局状态变量(如 g.flag)或严格的业务逻辑判断,阻断连续下单。
def initialize(context):
g.security = '600570.SS'
set_universe(g.security)
g.order_placed = False # 增加状态标识
def on_order_response(context, order_list):
for order in order_list:
# 仅在特定状态下且未下单时才进行后续操作
if order['status'] == '6' and not g.order_placed: # 假设6为已撤
# 重新下单前,必须修改状态标识,防止死循环
g.order_placed = True
order(g.security, 100)
2. 降低高频函数中的查询频率
在 tick_data 或 run_interval 中,尽量依赖传入的 data 参数,而不是主动发起查询。如果必须查询,增加时间间隔控制。
import time
def initialize(context):
g.security = '600570.SS'
set_universe(g.security)
g.last_query_time = 0
def tick_data(context, data):
current_time = time.time()
# 限制每 30 秒才主动查询一次持仓,而不是每 3 秒查询一次
if current_time - g.last_query_time > 30:
pos = get_position(g.security)
g.last_query_time = current_time
# 执行相关逻辑...
3. 批量获取数据,避免在循环中单次调用
许多 ptrade API 支持传入列表(List)来批量获取数据。例如 get_snapshot、get_price 等。永远不要在 for 循环中单只股票单只股票地调用 API。
错误示范(极高频调用):
def handle_data(context, data):
for sec in g.security_list: # 假设有500只股票
snapshot = get_snapshot(sec) # 每分钟调用500次!
正确示范(单次调用):
def handle_data(context, data):
# 一次性获取所有股票的快照,每分钟仅调用1次
snapshots = get_snapshot(g.security_list)
for sec in g.security_list:
if sec in snapshots:
sec_data = snapshots[sec]
# 处理逻辑...
4. 注意财务数据接口的限流
官方文档明确指出:get_fundamentals 接口有流量限制,每秒不得调用超过 100 次。如果需要大量获取,必须加入 time.sleep() 进行保护。
三、 总结
一天 300 万次的调用通常是代码逻辑缺陷(如死循环)导致的。请立即停止该策略的实盘运行,检查 on_order_response、tick_data 和 run_interval 中的代码,加入状态锁(Flag)和批量查询逻辑,确保 API 调用频率在合理范围内。