问题描述
解决方案
在 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
关键点说明
get_current_data(): 这是回测环境/模拟专用的 API。它获取当前时间点(回测中的当天)的股票属性。.is_st属性:- 该属性会自动判断股票是否包含
ST或*ST标记。 - 如果是 ST 或 *ST,返回
True。 - 如果是正常股票,返回
False。
- 该属性会自动判断股票是否包含
- 名称判断 (不推荐): 虽然可以通过
current_data[stock].name获取中文名称并判断是否包含 "ST" 字符串,但使用is_st属性更加准确且运行效率更高,因为它直接读取了系统预处理的状态位。 - 退市整理期:
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].paused 为 True,则表示该股票当前停牌。你可以将两个条件结合起来过滤:
[s for s in stock_list if not current_data[s].is_st and not current_data[s].paused]