3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
这是一个基于 JoinQuant (聚宽) 平台的次新股(上市不久的股票)交易策略。
该策略的核心逻辑是捕捉小盘次新股的溢价效应。次新股由于套牢盘少、股本扩张潜力大,在A股市场中常被资金追捧,尤其是流通市值较小的次新股。
# -*- coding: utf-8 -*-
# 导入聚宽函数库
import jqdata
import datetime
def initialize(context):
"""
初始化函数,设定基准、手续费、滑点等
"""
# 设定沪深300作为基准
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 过滤掉order系列API产生的比error级别低的log
log.set_level('order', 'error')
# 设定股票类每笔交易时的手续费
set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
# 设定全局变量
g.stock_num = 5 # 持仓股票数量
# 每天开盘前运行
run_daily(before_market_open, time='09:00')
# 每天开盘时运行
run_daily(market_open, time='09:30')
def before_market_open(context):
"""
开盘前选股逻辑
"""
# 获取当前日期
current_date = context.current_dt.date()
# 1. 获取所有股票信息
all_securities = get_all_securities(types=['stock'], date=current_date)
# 2. 筛选上市时间在 20天 到 150天 之间的次新股
# 避开上市最初期的连续一字板(通常难以买入且风险极高),选择开板后的次新股
sub_new_stocks = []
for code, row in all_securities.iterrows():
start_date = row['start_date']
days_listed = (current_date - start_date).days
if 20 < days_listed < 150:
sub_new_stocks.append(code)
if not sub_new_stocks:
g.target_list = []
return
# 3. 过滤停牌和ST股票
current_data = get_current_data()
sub_new_stocks = [stock for stock in sub_new_stocks
if not current_data[stock].paused
and not current_data[stock].is_st
and 'ST' not in current_data[stock].name
and '*' not in current_data[stock].name]
if not sub_new_stocks:
g.target_list = []
return
# 4. 按流通市值从小到大排序,选取前 g.stock_num 只
# 查询财务数据:流通市值 (circulating_market_cap)
q = query(
valuation.code
).filter(
valuation.code.in_(sub_new_stocks)
).order_by(
valuation.circulating_market_cap.asc()
).limit(
g.stock_num * 2 # 多取一些备用,防止涨跌停无法买入
)
df = get_fundamentals(q, date=current_date)
if len(df) > 0:
g.target_list = list(df['code'])
else:
g.target_list = []
log.info("今日备选次新股: %s" % g.target_list)
def market_open(context):
"""
交易逻辑
"""
target_list = g.target_list
current_data = get_current_data()
# 1. 卖出不在目标列表中的股票
for stock in context.portfolio.positions:
if stock not in target_list:
# 检查是否跌停,跌停无法卖出
if current_data[stock].last_price > current_data[stock].low_limit:
order_target_value(stock, 0)
log.info("卖出不再符合条件的股票: %s" % stock)
# 2. 买入目标股票
# 计算每只股票的目标资金
if len(target_list) > 0:
# 实际上我们只持有 g.stock_num 只,但 target_list 可能更多(备选)
# 我们需要遍历 target_list,直到买满 g.stock_num 只或者资金用完
position_count = len(context.portfolio.positions)
target_cash_per_stock = context.portfolio.total_value / g.stock_num
for stock in target_list:
# 如果持仓已满,停止买入
if len(context.portfolio.positions) >= g.stock_num and stock not in context.portfolio.positions:
break
# 过滤涨停的股票(无法买入)
if current_data[stock].last_price >= current_data[stock].high_limit:
continue
# 过滤停牌的股票
if current_data[stock].paused:
continue
# 调仓到目标金额
order_target_value(stock, target_cash_per_stock)
def after_market_close(context):
pass
上市时间筛选 (days_listed):
20 < days_listed < 150。小市值因子 (circulating_market_cap):
valuation.circulating_market_cap.asc() 进行排序。涨跌停处理:
market_open 中,使用了 get_current_data() 获取当天的涨跌停价格。风险提示:
Q: 如何修改策略以交易刚刚上市几天的股票?
A: 修改 before_market_open 函数中的天数判断。将 if 20 < days_listed < 150: 改为 if 0 < days_listed < 20:。但请注意,上市前5天不设涨跌幅限制(科创板/创业板),且主板新股初期通常一字涨停,回测成交可能与实盘有较大偏差。
Q: 为什么使用流通市值而不是总市值?
A: 对于次新股,大量的原始股处于限售期。真正能在市场上交易的只有流通股。流通市值更能反映当前市场上该股票的供需关系和炒作所需的资金体量。
Q: 这个策略适合大资金吗?
A: 不适合。该策略专门针对小盘股,流动性有限。如果资金量过大,买入和卖出都会产生较大的冲击成本(滑点),导致收益大幅下降。