🚀 AI 一键生成 joinquant 策略代码

JoinQuant 策略风控:如何在选股时过滤掉所有 ST 和 *ST 股票?

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

问题描述

怎么在我的选股代码里把 ST 和 *ST 的股票去掉?

解决方案

在 JoinQuant(聚宽)平台中,去除 ST 和 *ST 股票最常用且高效的方法是使用 get_current_data() 函数。该函数返回的对象包含一个 is_st 属性,若股票为 ST 或 *ST,该属性为 True,否则为 False

以下是具体的实现方法和代码示例。

核心代码实现

你可以定义一个过滤函数,传入股票列表,返回去除 ST 后的列表:

def filter_st_stocks(stock_list):
    """
    过滤掉ST和*ST的股票
    输入:stock_list (list): 股票代码列表
    输出:list: 去除ST后的股票代码列表
    """
    # 获取当前单位时间(当天)的数据
    current_data = get_current_data()
    
    # 使用列表推导式过滤
    # current_data[stock].is_st 为 True 表示是 ST/*ST 股票,我们需要保留为 False 的
    return [stock for stock in stock_list if not current_data[stock].is_st]

在策略中的完整应用示例

通常我们会在 before_trading_start(开盘前)或选股逻辑中调用此过滤功能。以下是一个完整的策略片段示例:

# -*- coding: utf-8 -*-
import jqdata

def initialize(context):
    set_benchmark('000300.XSHG')
    set_option('use_real_price', True)
    
    # 每天开盘前运行
    run_daily(before_market_open, time='09:00')

def before_market_open(context):
    # 1. 获取初始股票池(例如:沪深300成分股)
    initial_stocks = get_index_stocks('000300.XSHG')
    
    # 2. 调用过滤函数去除 ST 股票
    clean_stocks = filter_st_stocks(initial_stocks)
    
    # 3. (可选) 进一步过滤停牌股票
    clean_stocks = filter_paused_stocks(clean_stocks)
    
    # 将结果存入全局变量 g,供后续使用
    g.buy_list = clean_stocks
    
    log.info(f"初始数量: {len(initial_stocks)}, 去除ST后数量: {len(clean_stocks)}")

# 定义去除 ST 的函数
def filter_st_stocks(stock_list):
    current_data = get_current_data()
    # 保留 is_st 为 False 的股票
    return [stock for stock in stock_list if not current_data[stock].is_st]

# (附赠) 定义去除停牌股票的函数
def filter_paused_stocks(stock_list):
    current_data = get_current_data()
    # 保留 paused 为 False 的股票
    return [stock for stock in stock_list if not current_data[stock].paused]

def handle_data(context, data):
    # 在这里执行具体的买卖逻辑,使用 g.buy_list
    pass

关键点说明

  1. get_current_data(): 这是回测环境/模拟专用的 API。它获取当前时间点(回测中的当天)的股票属性。
  2. .is_st 属性:
    • 该属性会自动判断股票是否包含 ST*ST 标记。
    • 如果是 ST 或 *ST,返回 True
    • 如果是正常股票,返回 False
  3. 名称判断 (不推荐): 虽然可以通过 current_data[stock].name 获取中文名称并判断是否包含 "ST" 字符串,但使用 is_st 属性更加准确且运行效率更高,因为它直接读取了系统预处理的状态位。
  4. 退市整理期: is_st 属性通常也涵盖了退市整理期的股票,因为它们通常带有特殊标记。如果需要更严格的过滤(如去除即将退市的股票),可以结合 get_security_info(code).end_date 进行判断。

Q&A

Q: get_current_data() 只能在按天回测中使用吗?
A: 不仅限于按天回测。get_current_data() 可以在按天 (daily) 和按分钟 (minute) 的回测及模拟交易中使用。但在 initialize 中不能调用,因为它需要基于当前的逻辑时间。

Q: 过滤 ST 股票会引入未来函数吗?
A: 不会。get_current_data() 获取的是策略运行当时(例如开盘前 9:00 或盘中)已知的状态。只要你不在历史回测中去获取“明天”才变成 ST 的状态,就是安全的。聚宽的这个 API 设计是避免未来函数的。

Q: 除了 ST,我还想过滤掉停牌的股票,怎么做?
A: get_current_data() 返回的对象还有一个 paused 属性。如果 current_data[stock].pausedTrue,则表示该股票当前停牌。你可以将两个条件结合起来过滤:

[s for s in stock_list if not current_data[s].is_st and not current_data[s].paused]