问题描述
在回测中,通常都是在初始设置或者运行函数里,通过以下函数获得回测当天的时间:
date = context.current_dt.strftime("%Y-%m-%d")
如果想要另外定义一个函数,比如过滤st股票,在里面引用当天的时间,context.current_dt.strftime("%Y-%m-%d")就不可用了
使用get_current_data()只会获得空字典。
实例:
def filter_st(stocks,day):
datas = get_extras('is_st',stocks,end_date = day ,count=1).T
return datas[~datas.iloc[:,0]].index.tolist()
stocks = get_index_stocks('000905.XSHG')
{
day=context.current_dt.strftime("%Y-%m-%d")或者
day=get_current_data()
}#这里该如何才能获取到字符串格式的当天日期?
filter_st(stocks,day)
解决方案
在JoinQuant(聚宽)的回测环境中,context 对象包含了当前账户、时间等全局状态信息。由于 context 是作为参数传递给系统默认的运行函数(如 initialize、handle_data、before_trading_start 等)的,因此在您自己定义的普通函数中,默认是无法直接访问到 context 的。
要解决这个问题,最标准且推荐的做法是:将 context 或者格式化好的日期字符串作为参数,从系统函数传递给您的自定义函数。
解决方法与代码示例
您可以修改自定义函数,让它接收 context 或者直接接收 day 字符串。以下是修改后的完整代码示例:
# 导入聚宽函数库
import jqdata
# 自定义过滤ST股票的函数,接收 day 参数
def filter_st(stocks, day):
# 获取指定日期的 is_st 数据
datas = get_extras('is_st', stocks, end_date=day, count=1).T
# 过滤掉 is_st 为 True 的股票
return datas[~datas.iloc[:, 0]].index.tolist()
def initialize(context):
# 设定基准
set_benchmark('000300.XSHG')
# 每天开盘前运行
run_daily(before_market_open, time='09:00')
def before_market_open(context):
# 1. 在系统提供的函数中,通过 context 获取当前日期并格式化为字符串
current_day_str = context.current_dt.strftime("%Y-%m-%d")
# 2. 获取初始股票池(例如中证500成分股)
stocks = get_index_stocks('000905.XSHG')
# 3. 将获取到的日期字符串作为参数传递给自定义函数
non_st_stocks = filter_st(stocks, current_day_str)
log.info(f"当前日期: {current_day_str},过滤后的股票数量: {len(non_st_stocks)}")
# 将过滤后的股票存入全局变量供后续交易使用
g.buy_list = non_st_stocks
为什么不能用 get_current_data()?
get_current_data() 是用来获取当前单位时间(当天/当前分钟)的标的快照数据(如涨跌停价、是否停牌、最新价等),它返回的是一个字典,字典的 key 是股票代码,value 是包含价格信息的对象,它并不返回当前的日期字符串。
补充技巧:获取前一个交易日
在很多过滤条件(如财务数据查询、ST过滤)中,为了绝对避免未来函数,通常建议使用前一个交易日的日期。您可以直接使用 context.previous_date:
# 获取前一个交易日并转为字符串
previous_day_str = context.previous_date.strftime("%Y-%m-%d")
non_st_stocks = filter_st(stocks, previous_day_str)
总结来说,保持良好的参数传递习惯,将 context 或从中提取的时间变量一层层传递给您的自定义函数,是解决此类作用域问题的最佳方案。