🚀 AI 一键生成 qmt 策略代码

如何在 QMT 选股策略中,利用 get_his_st_data API 自动排除有过 ST 历史的股票?

qmt | 发布时间: 2025/12/4
以下内容由 EasyQuant 生成。

问题描述

如何在选股时,过滤掉那些以前被ST过的股票?

解决方案

在 QMT 中,要过滤掉历史上曾经被标记为 ST(包括 ST、*ST、PT)的股票,可以使用 ContextInfo.get_his_st_data(stockCode) 接口。

核心逻辑

  1. 接口功能ContextInfo.get_his_st_data(stockCode) 会返回指定股票的 ST 历史记录。
  2. 返回值判断
    • 如果该股票历史上从未被 ST 过,函数返回一个空字典 {}
    • 如果该股票历史上曾经被 ST 过,函数返回一个包含具体 ST 时间段的字典。
  3. 过滤方法:遍历股票列表,检查该函数的返回值是否为空。如果为空(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

注意事项

  1. 数据依赖get_his_st_data 依赖于本地的基础财务和板块数据。在使用前,请确保在 QMT 客户端的【数据管理】中补充了完整的历史数据。
  2. 回测与实盘
    • 该逻辑在回测和实盘中均有效。
    • 如果在回测中使用,请注意 get_stock_list_in_sector 获取的是最新成分股还是历史成分股。如果需要严格的历史回测,建议配合 ContextInfo.get_sector(sector, realtime) 使用。
  3. 性能优化:由于 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