🚀 AI 一键生成 joinquant 策略代码

JoinQuant 新股(IPO)策略编程指南:如何利用 get_security_info 识别次新股?

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

问题描述

如何找到最近一个月上市的新股,并对它们执行交易策略?

解决方案

在聚宽(JoinQuant)平台上,要找到最近一个月上市的新股(次新股),核心思路是利用 get_all_securities 函数获取股票的上市日期(start_date),然后将其与当前回测日期进行比较。

以下是实现该逻辑的完整策略代码。该策略每天开盘时运行,筛选出上市时间在30天以内的股票,并采用等权重买入的简单逻辑。

策略实现思路

  1. 获取数据:使用 get_all_securities(types=['stock'], date=context.current_dt) 获取当前日期所有在市股票的信息。
  2. 筛选日期:计算当前日期与股票 start_date(上市日期)的差值,保留差值小于等于30天的股票。
  3. 过滤标的:为了交易安全,通常需要过滤掉停牌和ST股票。
  4. 执行交易:卖出不再满足“次新股”条件的持仓,买入新筛选出的次新股。

策略代码

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

def initialize(context):
    """
    初始化函数,设定基准和全局配置
    """
    # 设定沪深300作为基准
    set_benchmark('000300.XSHG')
    # 开启动态复权模式(真实价格)
    set_option('use_real_price', True)
    
    # 设定手续费(股票类每笔交易时的手续费是:买入时佣金万分之三,卖出时佣金万分之三加千分之一印花税, 每笔交易佣金最低扣5块钱)
    set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
    
    # 每天开盘时运行选股和交易逻辑
    run_daily(trade_new_stocks, '09:30')

def trade_new_stocks(context):
    """
    每日交易逻辑:筛选近一个月上市的股票并调仓
    """
    # 1. 获取当前回测日期
    current_date = context.current_dt.date()
    
    # 2. 计算30天前的日期
    start_date_limit = current_date - datetime.timedelta(days=30)
    
    # 3. 获取所有股票信息
    # date=current_date 确保只获取当前已经上市的股票
    all_securities = get_all_securities(types=['stock'], date=current_date)
    
    # 4. 筛选出上市时间在 [30天前, 今天] 范围内的股票
    # all_securities['start_date'] 是 datetime.date 类型
    new_stocks_df = all_securities[
        (all_securities['start_date'] >= start_date_limit) & 
        (all_securities['start_date'] <= current_date)
    ]
    
    target_list = new_stocks_df.index.tolist()
    
    # 5. 进一步过滤:剔除停牌和ST股(可选,为了防止买入无法交易或风险过大的股票)
    target_list = filter_basic_stock(context, target_list)
    
    # 打印日志方便调试
    log.info("今日日期: %s, 筛选出的次新股数量: %d" % (current_date, len(target_list)))
    
    # 6. 执行交易
    do_trading(context, target_list)

def filter_basic_stock(context, stock_list):
    """
    过滤停牌和ST股票
    """
    current_data = get_current_data()
    filtered_list = []
    for stock in stock_list:
        # 如果未停牌 且 不是ST
        if not current_data[stock].paused and not current_data[stock].is_st:
            # 还可以增加过滤涨停板无法买入的逻辑,视策略需求而定
            # if current_data[stock].last_price < current_data[stock].high_limit:
            filtered_list.append(stock)
    return filtered_list

def do_trading(context, target_list):
    """
    执行调仓逻辑:等权重买入
    """
    # 1. 卖出不在目标列表中的持仓
    for stock in context.portfolio.positions:
        if stock not in target_list:
            order_target_value(stock, 0)
            log.info("卖出不再是次新股的标的: %s" % stock)
            
    # 2. 买入目标列表中的股票
    if len(target_list) > 0:
        # 简单的资金分配:将总资产平均分配给目标股票
        # 注意:次新股数量可能波动很大,实际策略中可能需要限制最大持仓数量
        position_count = len(target_list)
        value_per_stock = context.portfolio.total_value / position_count
        
        for stock in target_list:
            order_target_value(stock, value_per_stock)
            
    else:
        log.info("今日无符合条件的次新股,空仓运行")

关键API说明

  1. get_all_securities(types=['stock'], date=...):

    • 这是核心函数。它返回一个 DataFrame,其中包含 start_date(上市日期)列。
    • 传入 date 参数非常重要,它确保你获取的是在该日期当时存在的股票列表,避免了幸存者偏差,同时也包含了该日期刚刚上市的新股。
  2. datetime.timedelta(days=30):

    • 用于计算时间差。通过 current_date - timedelta 我们可以得到一个月前的日期界限。
  3. get_current_data():

    • 用于获取当天的实时状态,如是否停牌(paused)或是否为ST(is_st)。新股上市初期波动大,且可能有停牌核查的情况,过滤这些状态能提高回测稳定性。

注意事项

  • 新股涨停限制:A股新股上市初期通常会连续一字涨停。在回测中,如果使用默认的撮合机制,可能会在涨停板上买入成功(取决于回测引擎的撮合设置),但这在实盘中几乎是不可能的。建议在回测设置中开启严格的撮合模式,或者在代码中增加判断:如果 current_price == high_limit 则不买入。
  • 资金分配:上述代码使用了简单的等权重分配。由于新股数量在不同时期差异巨大(有时一个月只有几只,有时几十只),全仓等权分配可能导致单只股票仓位过低或过高。建议设置一个 max_stock_count(最大持仓数)来控制风险。

Q&A

Q: 为什么使用 get_all_securities 而不是 get_fundamentals?
A: get_fundamentals 主要用于查询财务数据(如市值、PE、利润等)。虽然它也能查到股票代码,但 get_all_securities 是专门用于获取证券基础信息(如上市时间、退市时间、中文名称)的API,且数据结构更适合直接进行日期比较,效率更高。

Q: 如何避免在回测中买入一字涨停的新股?
A: 可以在 filter_basic_stock 函数中增加逻辑。使用 get_current_data() 获取 last_price(最新价)和 high_limit(涨停价),如果两者相等,则将其从买入列表中剔除。

Q: 这段代码可以直接用于模拟交易吗?
A: 可以。聚宽的模拟交易环境与回测环境API兼容。但请注意,实盘中新股申购(打新)和二级市场买入次新股是两回事。此策略针对的是在二级市场买入已经上市交易的股票。