问题描述
解决方案
在 QMT 中,要过滤掉历史上曾经被标记为 ST(包括 ST、*ST、PT)的股票,可以使用 ContextInfo.get_his_st_data(stockCode) 接口。
核心逻辑
- 接口功能:
ContextInfo.get_his_st_data(stockCode)会返回指定股票的 ST 历史记录。 - 返回值判断:
- 如果该股票历史上从未被 ST 过,函数返回一个空字典
{}。 - 如果该股票历史上曾经被 ST 过,函数返回一个包含具体 ST 时间段的字典。
- 如果该股票历史上从未被 ST 过,函数返回一个空字典
- 过滤方法:遍历股票列表,检查该函数的返回值是否为空。如果为空(
if not st_data),则保留该股票;否则剔除。
策略代码实现
以下是一个完整的 Python 策略示例,展示如何在 init 初始化阶段对“沪深300”成分股进行筛选,剔除掉所有历史上曾被 ST 的股票。
# -*- coding: gbk -*-
def init(ContextInfo):
"""
策略初始化函数
"""
print("正在进行ST历史过滤筛选...")
# 1. 获取初始股票池,这里以 '沪深300' 为例
# 您可以根据需要替换为 '全A' 或其他板块,例如 ContextInfo.get_stock_list_in_sector('沪深A股')
target_sector = '沪深300'
# 注意:get_stock_list_in_sector 第二个参数通常需要传入时间戳,这里演示取最新成分股
# 如果回测需要取特定时间点的成分股,请传入 ContextInfo.get_bar_timetag(ContextInfo.barpos)
raw_stock_list = ContextInfo.get_stock_list_in_sector(target_sector)
print(f"[{target_sector}] 原始成分股数量: {len(raw_stock_list)}")
# 2. 创建一个列表用于存储符合条件的股票
never_st_stocks = []
# 3. 遍历股票列表进行检查
for stock_code in raw_stock_list:
# 获取历史ST数据
# 返回值示例:{'ST': [...], '*ST': [...]} 或 {}
st_history = ContextInfo.get_his_st_data(stock_code)
# 核心判断逻辑:
# 如果 st_history 为空字典 {},在 Python 中 bool({}) 为 False
# 因此 if not st_history 为 True,表示从未ST
if not st_history:
never_st_stocks.append(stock_code)
else:
# 可以在此处打印被剔除的股票(可选)
# print(f"剔除曾ST股票: {stock_code}, 历史记录: {st_history}")
pass
# 4. 设置筛选后的股票池
ContextInfo.set_universe(never_st_stocks)
print(f"筛选后股票数量: {len(never_st_stocks)}")
print(f"剔除数量: {len(raw_stock_list) - len(never_st_stocks)}")
# 打印前5只符合条件的股票作为示例
if len(never_st_stocks) > 0:
print("筛选结果示例:", never_st_stocks[:5])
def handlebar(ContextInfo):
"""
K线周期运行函数
"""
# 在这里编写具体的交易逻辑
# 此时 ContextInfo.get_universe() 获取到的已经是过滤后的股票列表
# 示例:打印当前bar的股票池大小
if ContextInfo.is_new_bar():
current_universe = ContextInfo.get_universe()
# print(f"当前可用股票池大小: {len(current_universe)}")
pass
注意事项
- 数据依赖:
get_his_st_data依赖于本地的基础财务和板块数据。在使用前,请确保在 QMT 客户端的【数据管理】中补充了完整的历史数据。 - 回测与实盘:
- 该逻辑在回测和实盘中均有效。
- 如果在回测中使用,请注意
get_stock_list_in_sector获取的是最新成分股还是历史成分股。如果需要严格的历史回测,建议配合ContextInfo.get_sector(sector, realtime)使用。
- 性能优化:由于
get_his_st_data需要查询历史记录,如果股票池非常大(如全 A 股 5000+ 只),建议不要在handlebar(每根 K 线调用)中循环调用此逻辑,而是在init或定时任务中执行一次即可。
Q&A
Q: get_his_st_data 返回的数据具体长什么样?
A: 如果一只股票曾被 ST,返回的字典结构类似于:
{
'ST': [{'start_date': '20180101', 'end_date': '20180601'}],
'*ST': [{'start_date': '20180602', 'end_date': '20190101'}]
}
如果从未被 ST,则直接返回 {}。
Q: 如果我只想过滤掉当前是 ST 的股票,而不是历史上曾 ST 的,该怎么做?
A: 如果只过滤当前状态,可以使用 ContextInfo.is_st_stock(stockCode)(注意:部分旧版本 API 可能不直接提供此函数,通常通过 get_market_data 获取 stockStatus 或通过名称判断)。但对于本问题的需求(过滤历史上有过污点的股票),必须使用 get_his_st_data。