问题描述
run_daily会在每一个交易日执行,可是股票在某个交易日停牌了,此时函数就会报错。
解决方案
在JoinQuant(聚宽)平台的回测中,run_daily 函数确实会在设定的每个交易日按时执行。如果你的策略池中包含了当天停牌的股票,直接对其进行下单或获取某些特定行情数据时可能会导致报错或产生不符合预期的交易行为。
要跳过停牌的股票,最标准且高效的方法是在 run_daily 调用的执行函数中,使用 get_current_data() API 来获取当前标的的状态,并通过判断其 paused 属性来决定是否跳过。
核心解决方法
使用 get_current_data() 获取当前数据对象,然后判断 current_data[security].paused 是否为 True。如果为 True,说明该股票今日停牌,直接 continue 跳过即可。
Python 源码示例
下面是一个完整的策略示例,展示了如何在 run_daily 调用的函数中过滤掉停牌的股票:
# 导入聚宽函数库
import jqdata
def initialize(context):
# 设定沪深300作为基准
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 设定我们要操作的股票池
g.stocks = ['000001.XSHE', '000002.XSHE', '000004.XSHE']
# 每天开盘时运行 market_open 函数
run_daily(market_open, time='09:30')
def market_open(context):
# 获取当前所有标的的数据
current_data = get_current_data()
for security in g.stocks:
# 【核心判断】检查该股票今天是否停牌
if current_data[security].paused:
log.info("股票 %s 今日停牌,跳过交易逻辑。" % security)
continue # 跳过该股票,继续循环下一个股票
# 如果未停牌,则继续执行你的交易逻辑
# 例如:获取当前价格
current_price = current_data[security].last_price
# 简单的买入逻辑示例
if context.portfolio.available_cash > 10000:
order_value(security, 10000)
log.info("买入 %s" % security)
为什么推荐使用 get_current_data()?
- 无未来函数:
get_current_data()获取的是当前单位时间(当天/当前分钟)的已知数据(如是否停牌、涨跌停价等),完全符合实盘逻辑。 - 按需加载,速度快:返回的
dict里面的数据是按需获取的,只有当你调用current_data[security]时,该标的的数据才会被获取,不会拖慢回测速度。 - 信息全面:除了
paused(是否停牌),你还可以通过它获取is_st(是否ST)、high_limit(涨停价)、low_limit(跌停价)等重要状态,方便做进一步的股票过滤(例如同时跳过停牌和ST的股票)。
补充:过滤ST股票
如果你希望同时跳过停牌和ST股票,可以将判断条件修改为:
if current_data[security].paused or current_data[security].is_st:
continue