3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
红利低波(Dividend Low Volatility)是量化投资中非常经典的 Smart Beta 策略。本策略在聚宽(JoinQuant)平台上实现,主要包含以下两个核心模块:
多因子选股模块:
valuation 中的 dividend_payable(应付股利)或直接使用聚宽因子库中的股息率指标进行筛选。indicator.roe 筛选出最新一期 ROE 大于 8% 且近几年表现稳定的上市公司。MA120 均线轻度风控模块:
000300.XSHG)的收盘价。以下是完整的 Python 策略代码,可直接复制到聚宽回测研究环境中运行:
import numpy as np
import pandas as pd
from jqdata import *
def initialize(context):
# 设定沪深300作为基准
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 设定交易税费
set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
# 策略参数设置
g.benchmark_index = '000300.XSHG' # 风控基准指数
g.stock_num = 10 # 持股数量
# 每月第一个交易日开盘运行调仓
run_monthly(my_rebalance, monthday=1, time='09:30')
# 每日运行风控检查
run_daily(risk_control, time='14:50')
def get_dividend_low_vol_pool(context):
"""筛选高股息、稳定ROE、低波动的股票池"""
# 1. 获取全A股作为初始池,过滤掉ST、退市及上市未满一年的股票
all_stocks = list(get_all_securities(['stock'], date=context.current_dt).index)
current_data = get_current_data()
initial_pool = [s for s in all_stocks if not current_data[s].is_st
and not current_data[s].paused
and (context.current_dt.date() - get_security_info(s).start_date).days > 365]
# 2. 查询财务数据:ROE > 8% 且 股息率(用应付股利/市值近似或直接查询估值表)
# 聚宽中可以通过 valuation 表和 indicator 表联合查询
q = query(
valuation.code,
valuation.market_cap,
indicator.roe
).filter(
valuation.code.in_(initial_pool),
indicator.roe > 8 # ROE 大于 8%
)
df_fundamental = get_fundamentals(q, date=context.previous_date)
if df_fundamental.empty:
return []
# 3. 计算过去60天的历史波动率
candidate_stocks = df_fundamental['code'].tolist()
history_price = history(60, unit='1d', field='close', security_list=candidate_stocks, df=True)
# 计算日收益率的标准差作为波动率
returns = history_price.pct_change().dropna()
volatility = returns.std() * np.sqrt(252) # 年化波动率
df_vol = pd.DataFrame({'volatility': volatility})
df_merged = df_fundamental.merge(df_vol, left_on='code', right_index=True)
# 4. 综合排序:选择波动率最低的前 30 只,再从中选择市值/股息性价比高的前 N 只
# 这里简化为直接选择波动率最低的前 g.stock_num 只股票
target_stocks = df_merged.sort_values(by='volatility', ascending=True).head(g.stock_num)['code'].tolist()
return target_stocks
def my_rebalance(context):
"""每月调仓逻辑"""
g.target_list = get_dividend_low_vol_pool(context)
if not g.target_list:
return
# 获取当前持仓
current_positions = list(context.portfolio.positions.keys())
# 卖出不在目标池中的股票
for stock in current_positions:
if stock not in g.target_list:
order_target(stock, 0)
log.info(f"卖出不在红利低波池中的股票: {stock}")
# 执行风控仓位分配
adjust_portfolio_weights(context)
def risk_control(context):
"""每日尾盘风控检查"""
# 获取沪深300过去120天的收盘价
hist = attribute_history(g.benchmark_index, 120, '1d', ['close'])
ma120 = hist['close'].mean()
current_price = hist['close'][-1]
# 判断是否跌破 MA120
if current_price < ma120:
if not g.get('is_risk_mode', False):
log.warn(f"大盘跌破MA120均线(当前价:{current_price:.2f} < MA120:{ma120:.2f}),触发轻度风控,降仓至95%!")
g.is_risk_mode = True
adjust_portfolio_weights(context)
else:
if g.get('is_risk_mode', True):
log.info(f"大盘重回MA120均线之上(当前价:{current_price:.2f} >= MA120:{ma120:.2f}),恢复满仓运行!")
g.is_risk_mode = False
adjust_portfolio_weights(context)
def adjust_portfolio_weights(context):
"""根据风控状态调整仓位"""
if not hasattr(g, 'target_list') or not g.target_list:
return
# 确定总可用资金比例
total_ratio = 0.95 if g.get('is_risk_mode', False) else 1.0
# 计算单只股票的目标价值
total_value = context.portfolio.total_value * total_ratio
single_stock_value = total_value / len(g.target_list)
# 调仓买入
for stock in g.target_list:
order_target_value(stock, single_stock_value)