🚀 AI 一键生成 joinquant 策略代码
立即体验

聚宽平台如何编写弱转强首板策略?(附集合竞价与涨停过滤 Python 源码)

joinquant | 发布时间: 2026/8/8
以下内容由 EasyQuant 生成。

问题描述

聚宽弱转强首板策略:如何使用集合竞价和涨停 API 过滤信号?
如何在聚宽中用昨日涨停、排除一字板、集合竞价高开幅度和成交量等条件识别弱转强首板机会,并避免未来函数?

解决方案

聚宽弱转强首板策略核心逻辑

弱转强是短线交易中的经典模式。其核心在于:股票在前一日表现较弱(例如尾盘勉强涨停、多次炸板,或者经历分歧),但在次日集合竞价时,通过高开幅度放量直接展现出极强的买盘意愿,从而完成“弱转强”的蜕变。首板(即昨日是近期第一个涨停)的弱转强往往具有极高的性价比。

在聚宽(JoinQuant)平台实现该策略,需要解决以下几个技术难点:

  1. 识别昨日首板:昨日涨停,且前天未涨停。
  2. 排除一字板:一字板无法买入,且不属于分歧转一致的弱转强。
  3. 获取今日集合竞价数据:在 09:25 至 09:30 之间获取开盘价、竞价成交量,必须严格避免未来函数

核心 API 与避免未来函数指南

1. 避免未来函数的关键:set_option('avoid_future_data', True)

initialize 中开启避免未来数据模式。如果尝试在 09:30 前获取当天的收盘价或全天成交量,系统会直接抛出 FutureDataError 异常。

2. 安全获取集合竞价:get_call_auction

聚宽提供了 get_call_auction 接口,可以安全地获取每日 09:25 的集合竞价数据(包括竞价成交量 volume 和竞价成交价 current)。

3. 获取实时涨跌停价:get_current_data

在盘中或开盘前,使用 get_current_data() 获取当天的 high_limit(涨停价)和 low_limit(跌停价),用于判断是否一字板或是否封板。


策略 Python 源码实现

以下是一个完整的聚宽弱转强首板策略框架,运行频率建议设置为分钟频

import pandas as pd
import numpy as np
from jqdata import *

def initialize(context):
    # 1. 基础设置
    set_benchmark('000300.XSHG')
    set_option('use_real_price', True)  # 开启真实价格模式
    set_option('avoid_future_data', True)  # 开启避免未来数据模式
    
    # 过滤低级别日志
    log.set_level('order', 'info')
    
    # 2. 手续费设置
    set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
    
    # 3. 定时任务
    # 每天 09:30 运行选股与交易逻辑
    run_daily(market_open, time='09:30')

def before_trading_start(context):
    # 每日开盘前准备数据
    g.all_stocks = list(get_all_securities(['stock'], date=context.current_dt).index)
    g.target_list = []
    
    # 获取昨日首板股票
    yesterday = context.previous_date
    # 获取前天日期
    trade_days = get_trade_days(end_date=yesterday, count=2)
    before_yesterday = trade_days[0]
    
    # 获取昨日和前天的收盘价及涨停价
    # 注意:使用 history 获取历史天数据不包含当天,安全无未来函数
    df_close = history(2, unit='1d', field='close', security_list=g.all_stocks, df=True)
    df_high_limit = history(2, unit='1d', field='high_limit', security_list=g.all_stocks, df=True)
    df_open = history(2, unit='1d', field='open', security_list=g.all_stocks, df=True)
    
    for stock in g.all_stocks:
        try:
            # 排除科创板和创业板(可选,此处以主板为例)
            if stock.startswith('300') or stock.startswith('688'):
                continue
                
            # 昨日收盘价、涨停价、开盘价
            y_close = df_close[stock][-1]
            y_limit = df_high_limit[stock][-1]
            y_open = df_open[stock][-1]
            
            # 前天收盘价、涨停价
            by_close = df_close[stock][-2]
            by_limit = df_high_limit[stock][-2]
            
            # 条件1:昨日首板(昨日涨停,且前天未涨停)
            is_yesterday_limit = (y_close >= y_limit)
            is_before_yesterday_limit = (by_close >= by_limit)
            
            # 条件2:排除昨日一字板(昨日开盘价不等于涨停价)
            is_not_y_one_line = (y_open < y_limit)
            
            if is_yesterday_limit and not is_before_yesterday_limit and is_not_y_one_line:
                g.target_list.append(stock)
        except:
            continue
            
    log.info(f"昨日首板候选股票数量: {len(g.target_list)}")

def market_open(context):
    if not g.target_list:
        return
        
    today_str = context.current_dt.strftime('%Y-%m-%d')
    
    # 获取候选股今日集合竞价数据
    try:
        auction_df = get_call_auction(g.target_list, start_date=today_str, end_date=today_str, fields=['time', 'current', 'volume'])
    except Exception as e:
        log.error(f"获取集合竞价失败: {e}")
        return
        
    if auction_df.empty:
        return
        
    # 获取昨日收盘价用于计算开盘涨幅
    yesterday_close = history(1, unit='1d', field='close', security_list=g.target_list, df=False)
    
    buy_list = []
    current_data = get_current_data()
    
    for stock in g.target_list:
        # 排除停牌
        if current_data[stock].paused:
            continue
            
        # 提取该股今日集合竞价
        stock_auction = auction_df[auction_df['code'] == stock]
        if stock_auction.empty:
            continue
            
        open_price = stock_auction['current'].values[0]
        auction_volume = stock_auction['volume'].values[0]
        y_close = yesterday_close[stock][-1]
        
        # 计算高开幅度
        open_pct = (open_price - y_close) / y_close
        
        # 条件3:集合竞价弱转强过滤
        # - 高开幅度在 2% 到 5% 之间(既有强势表态,又不过分透支涨幅)
        # - 集合竞价成交量放量(此处以竞价成交额大于100万手或特定量能为基准,示例简化为成交股数 > 50000股)
        if 0.02 <= open_pct <= 0.05 and auction_volume > 50000:
            # 排除今日一字涨停开盘
            if open_price < current_data[stock].high_limit:
                buy_list.append(stock)
                
    # 执行买入逻辑(均分资金)
    if buy_list:
        log.info(f"今日弱转强买入目标: {buy_list}")
        cash_per_stock = context.portfolio.available_cash / len(buy_list)
        for stock in buy_list:
            order_value(stock, cash_per_stock)