3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
弱转强是短线交易中的经典模式。其核心在于:股票在前一日表现较弱(例如尾盘勉强涨停、多次炸板,或者经历分歧),但在次日集合竞价时,通过高开幅度和放量直接展现出极强的买盘意愿,从而完成“弱转强”的蜕变。首板(即昨日是近期第一个涨停)的弱转强往往具有极高的性价比。
在聚宽(JoinQuant)平台实现该策略,需要解决以下几个技术难点:
set_option('avoid_future_data', True)在 initialize 中开启避免未来数据模式。如果尝试在 09:30 前获取当天的收盘价或全天成交量,系统会直接抛出 FutureDataError 异常。
get_call_auction聚宽提供了 get_call_auction 接口,可以安全地获取每日 09:25 的集合竞价数据(包括竞价成交量 volume 和竞价成交价 current)。
get_current_data在盘中或开盘前,使用 get_current_data() 获取当天的 high_limit(涨停价)和 low_limit(跌停价),用于判断是否一字板或是否封板。
以下是一个完整的聚宽弱转强首板策略框架,运行频率建议设置为分钟频:
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)