3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在量化多因子选股策略(如红利增强策略)中,高换手率往往会因为印花税和佣金(滑点)吞噬掉大部分超额收益。为了解决这一痛点,我们可以引入排名缓冲机制(Rank Buffer)。其核心逻辑是:买入时要求极高(必须进入前N名),卖出时要求宽松(跌出M名才卖,M > N)。同时,在调仓时,我们优先保留已在持仓中的赢家,仅对新纳入的股票进行增量资金配置。
以下是在聚宽(JoinQuant)平台实现该机制的完整方案与 Python 策略源码。
dividend_payable / market_cap 或 book_to_price_ratio)对股票池进行打分排名。请在聚宽回测环境中运行以下代码(按天回测,建议开启真实价格模式 set_option('use_real_price', True)):
import pandas as pd
import numpy as np
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')
# 策略参数设置
g.N = 10 # 严格买入线:前10名
g.M = 20 # 宽松卖出线:前20名(缓冲区间为 11-20 名)
# 定时运行:每月第一个交易日开盘调仓
run_monthly(my_rebalance, monthday=1, time='09:30')
def get_dividend_rank(context):
# 获取沪深300成分股
stocks = get_index_stocks('000300.XSHG')
# 查询财务数据:获取最新一季度的账面价值与市值比(作为红利/价值增强因子)
# 也可以使用聚宽因子库中的 book_to_price_ratio
q = query(
valuation.code,
valuation.pb_ratio
).filter(
valuation.code.in_(stocks)
)
df = get_fundamentals(q)
# 账面市值比 = 1 / 市净率 (PB)
df['bp_ratio'] = 1.0 / df['pb_ratio']
df = df.dropna().sort_values(by='bp_ratio', ascending=False) # 降序排列,值越大红利属性越强
# 返回股票代码的排名列表
return list(df['code'])
def my_rebalance(context):
# 1. 获取最新的红利因子排名
ranked_stocks = get_dividend_rank(context)
if not ranked_stocks:
return
# 2. 获取当前持仓列表
current_positions = list(context.portfolio.positions.keys())
# 3. 确定卖出决策(宽松:跌出前 M 名的卖出)
to_sell = []
keep_holding = []
for stock in current_positions:
if stock in ranked_stocks:
rank = ranked_stocks.index(stock) + 1 # 索引从0开始,排名从1开始
if rank > g.M:
to_sell.append(stock)
else:
keep_holding.append(stock) # 保留赢家持仓
else:
to_sell.append(stock) # 不在成分股内的强制卖出
# 执行卖出操作
for stock in to_sell:
order_target(stock, 0)
log.info("股票 %s 跌出前 %d 名(卖出线),执行平仓" % (stock, g.M))
# 4. 确定买入决策(严格:只有前 N 名且不在当前持仓中的才买入)
candidate_buys = ranked_stocks[:g.N]
to_buy = [stock for stock in candidate_buys if stock not in keep_holding]
# 5. 增量资金分配与调仓
# 计算当前保留持仓的股票数量和新买入的股票数量
total_target_count = len(keep_holding) + len(to_buy)
if total_target_count == 0:
return
# 获取当前总资产
total_value = context.portfolio.total_value
# 每只股票的目标分配价值(等权重分配)
target_value_per_stock = total_value / total_target_count
# 对保留的赢家持仓进行价值微调(增量调仓,防止过度交易)
for stock in keep_holding:
# 只有当当前持仓价值与目标价值偏差大于20%时才调整,进一步降低换手率
current_stock_value = context.portfolio.positions[stock].value
if abs(current_stock_value - target_value_per_stock) / target_value_per_stock > 0.20:
order_target_value(stock, target_value_per_stock)
# 对新纳入的股票进行买入
for stock in to_buy:
# 确保有足够可用资金
if context.portfolio.available_cash > target_value_per_stock * 0.8:
order_target_value(stock, target_value_per_stock)
log.info("新赢家股票 %s 进入前 %d 名(买入线),执行建仓" % (stock, g.N))
order_target_value 结合偏差阈值(如代码中的 0.20 偏差限制),策略不会因为每日微小的净值波动去频繁调整已有持仓的权重,只有在新股建仓或持仓严重偏离时才交易,对实盘非常友好。