3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在量化投资中,传统的动量策略通常采用固定的回看窗口(如20日或60日)。然而,市场状态在不断变化:在剧烈波动的震荡市中,长周期动量容易滞后,需要缩短窗口以快速反应;在趋势明显的平稳市中,则需要拉长窗口以过滤噪音。本文将教你如何在JoinQuant(聚宽)平台上,通过计算短长期波动率比值来识别市场状态,并动态切换 15日、25日、35日 的动量回看窗口。
以下是完整的策略代码,可直接复制到聚宽回测环境中运行:
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)
# 股票池:沪深300成分股
g.security_list = get_index_stocks('000300.XSHG')
# 持仓目标数量
g.target_num = 5
# 设定交易税费
set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
# 每周第一个交易日运行调仓
run_weekly(my_rebalance, weekday=1, time='09:30')
def my_rebalance(context):
# 获取股票池
stocks = g.security_list
# 1. 获取历史价格数据(用于计算波动率和动量)
# 长期波动率需要60天,35日动量需要35天,因此至少取65天数据
hist = history(65, unit='1d', field='close', security_list=stocks, df=True)
# 2. 计算每只股票的短长期波动率比值
# 短期标准差 (10日)
std_short = hist.iloc[-10:].std()
# 长期标准差 (60日)
std_long = hist.iloc[-60:].std()
# 避免分母为0
std_long = std_long.replace(0, np.nan)
vr = std_short / std_long
# 3. 动态计算每只股票的动量值
momentum_series = pd.Series(index=stocks, dtype=float)
for stock in stocks:
stock_vr = vr[stock]
if pd.isna(stock_vr):
continue
# 根据波动率比值切换回看窗口
if stock_vr > 1.2:
lookback = 15 # 高波动,用短周期
elif stock_vr < 0.8:
lookback = 35 # 低波动,用长周期
else:
lookback = 25 # 常态,用中周期
# 计算动量:(当前价 - N日前价) / N日前价
current_price = hist[stock].iloc[-1]
past_price = hist[stock].iloc[-lookback]
if past_price > 0:
momentum_series[stock] = (current_price - past_price) / past_price
# 4. 筛选出动量最高的前5只股票
momentum_series = momentum_series.dropna().sort_values(ascending=False)
buy_list = list(momentum_series.head(g.target_num).index)
# 5. 执行调仓
# 卖出不在买入名单中的持仓
for stock in list(context.portfolio.positions.keys()):
if stock not in buy_list:
order_target(stock, 0)
log.info("卖出: %s" % stock)
# 等权重买入目标股票
if len(buy_list) > 0:
target_value = context.portfolio.total_value / len(buy_list)
for stock in buy_list:
order_target_value(stock, target_value)
log.info("买入/调仓: %s, 目标价值: %.2f" % (stock, target_value))
history 获取历史数据:history(65, unit='1d', field='close', ...) 一次性获取了计算波动率(最大60天)和动量(最大35天)所需的全部收盘价,避免了多次调用API,大幅提升了回测速度。std() 标准差计算:pandas 的 std() 函数直接对 DataFrame 的列进行滑动标准差计算,高效获取短期(10日)和长期(60日)的市场波动率。order_target_value 目标价值下单:order_target_value(stock, target_value) 会自动计算当前持仓与目标价值的差额并进行补仓或减仓,非常适合多股票组合管理。