3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
是的,完全正确。 如果您在“现在”这个时间点筛选好了一个固定的股票列表(例如现在的上证50成分股,或者现在某个概念板块的股票),然后把这个固定的列表直接写死在代码里,去回测过去几年的历史数据,这绝对属于使用了未来函数(具体来说是引入了“幸存者偏差”和“未来数据”)。
在量化回测中,最核心的原则是:在历史的任意一个时间点 $T$,策略只能使用 $T$ 时刻及之前能够获取到的信息。
如果您用今天的选股结果去回测5年前的市场:
为了避免这种未来函数,JoinQuant 平台在设计 API 时已经做好了防范机制。在 JoinQuant 中,获取股票池通常使用以下函数:
get_index_stocks(index_symbol, date=None):获取指数成分股get_industry_stocks(industry_code, date=None):获取行业成分股get_concept_stocks(concept_code, date=None):获取概念成分股关键点在于 date 参数:
date 参数(即 date=None),系统会自动将 date 设定为回测当前的逻辑时间(context.current_dt)。get_index_stocks('000300.XSHG') 返回的是 2018 年 1 月 1 日当天的沪深300成分股,而不是今天的成分股。在策略外部或者初始化时写死了一个现在的股票列表:
def initialize(context):
# 错误!这是写死了现在的股票,回测过去时就是未来函数
g.my_stocks = ['000001.XSHE', '600519.XSHG', '000858.XSHE']
def handle_data(context, data):
# 每天都在交易这几只固定的股票
for stock in g.my_stocks:
order_target_value(stock, 10000)
在定时运行函数或 handle_data 中,动态获取当天的成分股:
def initialize(context):
# 开启避免未来数据模式(强烈建议)
set_option("avoid_future_data", True)
# 每天开盘前动态更新股票池
run_daily(update_stock_list, time='09:00')
def update_stock_list(context):
# 正确!在回测中,这里会自动获取 context.current_dt 当天的沪深300成分股
g.my_stocks = get_index_stocks('000300.XSHG')
log.info(f"当前日期的股票池数量: {len(g.my_stocks)}")
def handle_data(context, data):
# 交易当天真实的成分股
for stock in g.my_stocks:
# 交易逻辑...
pass
get_index_stocks 等 API 动态获取历史当天的成分股。initialize 中加入 set_option("avoid_future_data", True),让平台帮您拦截可能引入未来数据的 API 调用。