问题描述
/
解决方案
在 ptrade 量化交易平台中,策略在实盘或回测运行中,常会因为网络波动、行情数据缺失、接口调用限制等原因,导致 API 返回异常数据(如 None 或空字典)。如果代码中缺少必要的检查,就会引发运行时错误(如 TypeError, KeyError, ZeroDivisionError 等),导致策略意外终止。
要解决这个问题,可以从以下三个方面入手:
1. 使用 try...except 进行全局或局部异常捕获
ptrade 官方强烈建议在策略中加入异常处理保护。通过捕获异常,可以防止策略因为偶发错误而直接崩溃。
def handle_data(context, data):
try:
# 尝试执行的核心交易逻辑
current_price = data['600570.SS']['close']
# ... 其他逻辑
except Exception as e:
# 捕获异常并打印日志,策略不会因此终止
log.error("策略运行出现异常,错误信息为: %s" % e)
finally:
# 无论是否发生异常都会执行的清理工作(可选)
pass
2. 对 API 返回值进行严格的有效性检查(判空)
ptrade 的许多获取数据的 API 在异常或无数据时会返回 None 或空字典 {}。直接对这些返回值进行索引或属性访问会导致报错。
常见需要检查的接口:
get_snapshot(): 获取失败时返回空字典{}。get_history()/get_price(): 异常时返回None。get_individual_entrust()/get_individual_transaction(): 无数据时返回None。
正确的数据校验示例:
def handle_data(context, data):
security = '600570.SS'
# 1. 检查快照数据
snapshot = get_snapshot(security)
if not snapshot or security not in snapshot:
log.warning("获取 %s 行情快照失败,跳过本次处理" % security)
return
last_px = snapshot[security].get('last_px', 0)
if last_px <= 0:
log.warning("获取到的最新价异常: %s" % last_px)
return
# 2. 检查历史数据
hist_data = get_history(5, '1d', 'close', security)
if hist_data is None or hist_data.empty:
log.warning("获取历史数据失败")
return
3. 交易逻辑的前置条件检查
在调用下单接口(如 order, order_target)之前,必须检查账户状态和计算参数,避免非法委托。
- 资金与持仓检查:买入前检查
context.portfolio.cash,卖出前检查get_position(security).amount。 - 除零保护:在计算均线、指标或仓位比例时,确保分母不为 0。
- 价格精度处理:ptrade 规定股票价格为两位小数,可转债/ETF为三位小数。限价单委托前需使用
round()处理价格精度。
示例:
def handle_data(context, data):
security = '600570.SS'
cash = context.portfolio.cash
current_price = data[security]['close']
# 除零保护与资金检查
if current_price > 0 and cash > current_price * 100:
# 价格精度处理(股票保留2位小数)
limit_price = round(current_price * 1.01, 2)
order(security, 100, limit_price=limit_price)
总结:
在编写 ptrade 策略时,**“防御性编程”**是必不可少的。凡是依赖外部接口返回的数据,使用前必须判空;凡是涉及数学计算,必须考虑边界条件;核心逻辑外层最好包裹 try...except,并配合 log.error 记录现场,以便盘后排查。