问题描述
为什么同样的代码在回测模块和交易模块中返回的日期结果不同?
解决方案
ptrade 中 get_stock_status 的 query_date 行为差异
在 ptrade 量化交易平台中,get_stock_status 函数用于获取指定日期股票的 ST、停牌(HALT)或退市(DELISTING)等状态属性。很多开发者会发现,当不传入 query_date 参数时,同样的代码在回测模块和交易模块中表现不一致。这是因为 ptrade 引擎对默认日期的处理机制不同。
核心差异解析
根据 ptrade API 文档,query_date 参数的默认值为 None,表示“当前日期”。但“当前日期”在不同模块下的定义是不同的:
-
回测模块 (Backtesting):
当query_date=None时,系统会自动取回测的当前周期日期(即context.blotter.current_dt)。这意味着你的策略在模拟历史的某一天时,获取的是那一天的真实历史状态,从而保证了回测的准确性,避免了引入“未来函数”。 -
交易模块 (Trading) 与 研究模块 (Research):
当query_date=None时,系统会直接取服务器的系统当前时间(即真实的今天)。因为在实盘交易中,你需要的永远是当下的最新状态。
为什么会产生这种设计?
这种设计是为了让同一套策略代码能够无缝在回测和实盘中切换。如果你在代码中硬编码了 query_date(例如 query_date='20231001'),那么在回测推进到 2023 年 11 月时,你获取的依然是 10 月 1 日的状态,这显然是不符合逻辑的。通过将默认值设为 None,ptrade 框架接管了时间轴的管理。
代码示例与最佳实践
为了保证策略在回测和实盘中都能正确运行,强烈建议在调用 get_stock_status 时,如果不指定特定历史日期,直接保持 query_date=None。
def initialize(context):
g.security = ['600397.SS', '600701.SS', '000001.SZ']
set_universe(g.security)
def handle_data(context, data):
stocks_list = g.security
filter_stocks = []
# 最佳实践:不传入 query_date,让框架自动处理时间轴
# 回测时:获取回测当天的 ST 状态
# 交易时:获取真实今天的 ST 状态
st_status = get_stock_status(stocks_list, 'ST')
# 将不是 ST 的股票筛选出来
for i in stocks_list:
if st_status[i] is not True:
filter_stocks.append(i)
log.info('筛选不是ST的股票列表: %s' % filter_stocks)
总结
- 回测环境:
query_date=None= 模拟的历史当天。 - 交易/研究环境:
query_date=None= 现实的今天。 - 建议:除非有特殊需求需要查询过去某天的状态,否则请省略
query_date参数,以确保策略代码的通用性和正确性。