🚀 AI 一键生成 joinquant 策略代码

JoinQuant 避坑指南:set_universe 函数到底有什么用?

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

问题描述

set_universe 函数如何使用,为什么它不影响我的股票池?

解决方案

JoinQuant set_universe 函数使用详解与常见误区

在 JoinQuant(聚宽)平台中,set_universe 是一个容易引起误解的函数。很多用户认为调用它之后,策略就会自动只交易这些股票,或者所有数据获取函数都会默认使用这个列表,但事实并非如此。

以下是关于该函数的详细解释、它为什么“不生效”的原因,以及现代策略开发的推荐做法。

1. set_universe 的真实作用

根据官方文档,set_universe 的功能非常有限:

  • 功能:设置或更新 context.universe 属性。
  • 唯一实际用途只用于设定 history() 函数的默认 security_list

也就是说,只有当你调用 history() 函数且不传入股票列表参数时,系统才会去读取 set_universe 设定的列表。对于其他数据函数(如 get_price, attribute_history)或交易函数,它没有任何直接影响。

代码示例:set_universe 如何生效

def initialize(context):
    # 设定股票池
    set_universe(['000001.XSHE', '600000.XSHG'])

def handle_data(context, data):
    # 场景 A:生效
    # 调用 history 时不传股票列表,它会默认使用 set_universe 设置的列表
    h = history(5, '1d', 'close') 
    print(h.columns) # 输出:Index(['000001.XSHE', '600000.XSHG'], dtype='object')

    # 场景 B:不生效(被覆盖)
    # 如果 history 传入了具体的列表,set_universe 的设置会被忽略
    h2 = history(5, '1d', 'close', security_list=['000002.XSHE'])
    
    # 场景 C:完全无关
    # attribute_history 必须显式传入股票代码,不受 set_universe 影响
    # get_price 同理
    p = attribute_history('000001.XSHE', 5)

2. 为什么它不影响你的“股票池”?

你感觉它“不生效”,通常是因为以下几个原因:

  1. 它不会自动过滤交易set_universe 不会限制 order 函数。即使你设置了 universe,你依然可以下单买入 universe 之外的股票。
  2. 它不影响主流数据 API:现代策略更多使用 attribute_historyget_price,这些函数都需要显式传入股票代码,它们不会自动读取 context.universe
  3. 它不具备筛选功能:它只是一个静态列表赋值。它不会自动剔除停牌、ST 或涨跌停的股票。

3. 推荐的“股票池”管理方式

在现代 JoinQuant 策略开发中,建议不再使用 set_universe。推荐的做法是使用全局变量(如 g.stocks)来管理股票池,并在需要时显式传递给数据或交易函数。

最佳实践代码示例

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

def initialize(context):
    # 1. 设定基准
    set_benchmark('000300.XSHG')
    # 2. 开启真实价格
    set_option('use_real_price', True)
    
    # 3. 【推荐做法】使用全局变量 g 定义股票池
    # 例如:获取沪深300成分股
    g.stocks = get_index_stocks('000300.XSHG')
    
    # 每天开盘前运行选股逻辑
    run_daily(before_market_open, time='09:00')

def before_market_open(context):
    # 4. 动态更新股票池(例如剔除停牌和ST)
    current_data = get_current_data()
    g.trade_list = []
    
    for stock in g.stocks:
        # 过滤停牌和ST
        if not current_data[stock].paused and not current_data[stock].is_st:
            g.trade_list.append(stock)
    
    print(f"今日可交易股票数量: {len(g.trade_list)}")

def handle_data(context, data):
    # 5. 在交易逻辑中显式使用 g.trade_list
    # 示例:买入列表中的第一只股票
    if len(g.trade_list) > 0:
        target_stock = g.trade_list[0]
        order_value(target_stock, 10000)


Q&A

Q: context.universe 变量还有用吗?
A: context.universe 本质上只是一个存储列表的属性。如果你使用 set_universe,这个属性会被赋值。你可以在代码中读取 context.universe 来获取这个列表,但它不会自动产生任何魔法效果。建议使用 g.xxx 变量替代,逻辑更清晰。

Q: 如果我想用 history 函数,必须用 set_universe 吗?
A: 不需要。history 函数允许通过 security_list 参数直接传入股票列表(如 history(5, '1d', 'close', security_list=g.stocks))。显式传参比依赖隐式的默认值更安全,代码可读性也更高。

Q: 如何获取全市场的股票作为股票池?
A: 可以使用 get_all_securities(['stock']).index.tolist() 获取全市场股票代码列表,然后赋值给 g.stocks。但请注意,全市场股票数量巨大,直接循环处理会导致回测非常慢,建议先通过财务数据或行情指标进行筛选(如使用 get_fundamentals)。