问题描述
解决方案
在 QMT 中,判断一只股票当前是否属于某个指数(如沪深300)的成分股,最稳健的方法是使用 ContextInfo.get_sector 接口。
该接口可以获取指定指数在指定时间点的成分股列表。通过传入当前 K 线的时间戳,可以确保在回测时获取的是当时的历史成分股,而在实盘时获取的是最新的成分股。
核心逻辑
- 获取当前 K 线的时间戳(
ContextInfo.get_bar_timetag)。 - 调用
ContextInfo.get_sector获取沪深300(代码000300.SH)在该时间点的成分股列表。 - 使用 Python 的
in关键字判断目标股票是否在列表中。
代码示例
以下是一个完整的策略示例,展示了如何在下单前进行成分股检查:
# -*- coding: gbk -*-
def init(ContextInfo):
# 设置账号
ContextInfo.set_account('您的资金账号')
# 设置要操作的股票,这里以浦发银行为例
ContextInfo.stock = '600000.SH'
# 沪深300指数代码
ContextInfo.index_code = '000300.SH'
def handlebar(ContextInfo):
# 获取当前 K 线索引
index = ContextInfo.barpos
# 获取当前 K 线的时间戳(毫秒)
# 这一点非常重要:传入时间戳可以保证回测时获取的是历史时刻的成分股,避免未来函数
realtime = ContextInfo.get_bar_timetag(index)
# 获取沪深300在当前时间的成分股列表
# get_sector 返回的是一个包含股票代码的 list,如 ['000001.SZ', '600000.SH', ...]
hs300_constituents = ContextInfo.get_sector(ContextInfo.index_code, realtime)
target_stock = ContextInfo.stock
# 判断逻辑
if target_stock in hs300_constituents:
print(f"时间: {realtime}, {target_stock} 是沪深300成分股,准备执行买入逻辑。")
# 这里写具体的下单逻辑,例如:
# passorder(23, 1101, ContextInfo.accountID, target_stock, 5, -1, 100, ContextInfo)
else:
print(f"时间: {realtime}, {target_stock} 已被剔除或不是沪深300成分股,跳过交易。")
关键点说明
- 指数代码:沪深300的指数代码在 QMT 中通常为
'000300.SH'。 - 时间参数 (
realtime):ContextInfo.get_sector(sector, realtime)的第二个参数是时间戳。- 回测模式:必须传入当前 Bar 的时间戳,否则可能会获取到今天的最新成分股,导致回测数据不准确(即“未来函数”)。
- 实盘模式:传入当前时间戳即可获取最新数据。
- 返回值:
get_sector返回的是一个 Python列表 (list),包含成分股代码(如'600000.SH'),直接使用if stock in list语法即可判断。
Q&A
Q: 除了 get_sector,还有其他方法判断成分股吗?
A: 还有一个函数 is_sector_stock(sectorname, market, stockcode),例如 is_sector_stock('沪深300', 'SH', '600000')。但这个函数通常依赖于板块名称字符串,且在处理历史回测时的成分股变动(Point-in-Time 数据)方面,不如 get_sector 配合时间戳来得精确和直观。因此推荐使用 get_sector。
Q: 如果我想判断是否是中证500成分股怎么办?
A: 只需将代码中的 ContextInfo.index_code 修改为中证500的代码 '000905.SH' 即可。
Q: 这个检查会消耗很多时间吗?
A: get_sector 是本地数据查询,速度非常快,不会显著影响策略运行效率。但在高频 tick 级别的回调中,建议不要每笔 tick 都去获取一次成分股列表,可以在 init 中或者每天开盘时获取一次并缓存,或者在分钟/日线级别调用。