问题描述
/
解决方案
报错原因解析
在 ptrade 平台中,get_market_detail() 用于获取市场编码对应的详细信息(如产品名称、类型代码、时间规则等)。由于这些信息属于静态或极低频更新的数据,为了避免策略在盘中高频回调函数(如 handle_data 或 tick_data)中反复调用该接口从而消耗系统资源,平台在底层做了严格的限制:该接口在回测和交易模块中,仅允许在盘前(before_trading_start)和盘后(after_trading_end)事件函数中调用。
如果你在 handle_data 中调用了它,就会触发你遇到的报错。
before_trading_start 与 after_trading_end 的限制对比
对于“这两个函数的限制一样吗?”这个问题,答案是:在调用 get_market_detail() 的权限上,它们的限制是完全一样的(都允许调用);但在自身的执行机制和使用场景上,它们有明显的区别。
1. 相同点(共性限制)
- 调用权限:都可以合法调用
get_market_detail()、get_market_list()等静态信息获取接口。 - 使用场景:都仅在回测和交易模块中可用。
- 执行频率:在每个交易日内,这两个函数都只会被触发执行一次(非高频循环)。
- 可选性:这两个函数都是可选的,如果策略不需要盘前准备或盘后处理,可以不在代码中定义它们。
2. 不同点(核心区别)
| 特性 | before_trading_start (盘前事件) |
after_trading_end (盘后事件) |
|---|---|---|
| 执行时间 (回测) | 每个回测交易日的 8:30 分执行。 | 每天交易结束之后调用(通常模拟 15:30)。 |
| 执行时间 (交易) | 开启交易时立即执行,隔日开始每天 9:10 (默认) 执行。 | 由券商配置决定,一般为 15:30。 |
| 主要用途 | 盘前初始化、获取当日股票池、获取静态市场信息、计算前一日指标等。 | 盘后数据统计、持仓核对、导出对账文件 (get_trades_file)、清理全局变量等。 |
| 注意事项 | 交易环境中,9:10前开启交易时,受行情未更新影响,调用实时行情接口可能数据有误。 | 此时市场已收盘,无法进行任何有效的委托下单操作。 |
正确的代码示例
为了解决你的报错,你应该将 get_market_detail() 的调用移至盘前或盘后函数中,并将获取到的结果存储在全局对象 g 中,以便在盘中 handle_data 使用。
def initialize(context):
g.security = '600570.SS'
set_universe(g.security)
g.market_info = None
def before_trading_start(context, data):
# 正确用法:在盘前获取市场详细信息
g.market_info = get_market_detail('XSHG')
log.info("盘前获取到的上海市场信息:\n%s" % g.market_info)
def handle_data(context, data):
# 错误用法:在这里调用 get_market_detail 会报错!
# info = get_market_detail('XSHG')
# 正确用法:使用盘前已经获取并存储在 g 中的数据
if g.market_info is not None:
pass # 执行你的策略逻辑
def after_trading_end(context, data):
# 这里也可以合法调用
market_info_after = get_market_detail('XSHE')
log.info("盘后获取到的深圳市场信息:\n%s" % market_info_after)
总结:将静态数据的获取前置到 before_trading_start 是 ptrade 策略编写的最佳实践,既能解决报错,又能提升盘中 handle_data 的执行效率。