🚀 AI 一键生成 qmt 策略代码

波动率倒数加权:如何根据市场波动自动调整仓位?

qmt | 发布时间: 2025/12/21
以下内容由 EasyQuant 生成。

问题描述

怎么写根据波动率自动调整仓位的代码?

解决方案

这是一个基于**目标波动率(Target Volatility)**进行仓位管理的策略示例。

策略逻辑

  1. 核心思想:当市场波动率(风险)变大时,降低仓位;当市场波动率变小时,增加仓位。
  2. 计算公式
    • 当前波动率 = 过去 N 天收益率的标准差 $\times \sqrt{252}$(年化)。
    • 目标仓位比例 = 目标波动率 / 当前波动率。
    • 限制:通常将最大仓位限制在 100%(1.0),防止加杠杆。

QMT 策略代码

# -*- coding: gbk -*-
import pandas as pd
import numpy as np

def init(ContextInfo):
    """
    初始化函数,设定策略参数
    """
    # 1. 设定交易标的(例如:沪深300ETF)
    ContextInfo.stock_code = '510300.SH'
    
    # 2. 设定股票池
    ContextInfo.set_universe([ContextInfo.stock_code])
    
    # 3. 设定资金账号 (请替换为您真实的资金账号)
    ContextInfo.account_id = 'YOUR_ACCOUNT_ID' 
    ContextInfo.set_account(ContextInfo.account_id)
    
    # 4. 策略参数设置
    ContextInfo.target_volatility = 0.15  # 目标年化波动率 (例如 15%)
    ContextInfo.lookback_window = 20      # 回看窗口 (过去20个交易日)
    ContextInfo.max_position = 1.0        # 最大仓位限制 (100%)
    
    print("策略初始化完成:目标波动率={:.2%}, 回看窗口={}天".format(
        ContextInfo.target_volatility, ContextInfo.lookback_window))

def handlebar(ContextInfo):
    """
    K线周期运行函数
    """
    # 获取当前K线索引
    index = ContextInfo.barpos
    
    # 确保有足够的历史数据进行计算
    # 我们需要 lookback_window + 1 个数据来计算 lookback_window 个收益率
    if index < ContextInfo.lookback_window + 1:
        return

    # 1. 获取历史行情数据 (使用 get_market_data_ex 接口)
    # 获取收盘价,数量为回看窗口+1,前复权
    market_data = ContextInfo.get_market_data_ex(
        ['close'], 
        [ContextInfo.stock_code], 
        period='1d', 
        count=ContextInfo.lookback_window + 1, 
        dividend_type='front',
        subscribe=True
    )
    
    if ContextInfo.stock_code not in market_data:
        return
        
    df = market_data[ContextInfo.stock_code]
    
    # 2. 计算收益率
    # pct_change() 计算日收益率
    df['returns'] = df['close'].pct_change()
    # 去除第一个NaN值
    returns_series = df['returns'].dropna()
    
    # 3. 计算当前年化波动率
    # std() 计算标准差,乘以 sqrt(252) 进行年化
    if len(returns_series) < ContextInfo.lookback_window:
        return # 数据不足时不交易
        
    current_volatility = returns_series.std() * np.sqrt(252)
    
    # 防止波动率为0导致除零错误
    if current_volatility == 0:
        print("当前波动率为0,跳过计算")
        return

    # 4. 计算目标仓位
    # 公式:目标仓位 = 目标波动率 / 当前波动率
    target_percent = ContextInfo.target_volatility / current_volatility
    
    # 限制最大仓位不超过设定值 (例如 1.0)
    target_percent = min(target_percent, ContextInfo.max_position)
    
    # 5. 执行交易
    # 使用 order_target_percent 自动调整仓位到目标比例
    # 注意:回测模式下直接生效,实盘模式下需要确保账号设置正确
    
    # 获取当前时间用于日志
    timetag = ContextInfo.get_bar_timetag(index)
    import datetime
    date_str = datetime.datetime.fromtimestamp(timetag / 1000).strftime('%Y-%m-%d')
    
    print(f"日期: {date_str} | 当前波动率: {current_volatility:.2%} | 目标仓位: {target_percent:.2%}")
    
    # 发送交易指令
    order_target_percent(ContextInfo.stock_code, target_percent, ContextInfo, ContextInfo.account_id)

代码详解

  1. init 函数

    • ContextInfo.target_volatility = 0.15:这是策略的核心锚点。如果市场当前波动率是 30%,为了维持 15% 的风险敞口,策略会将仓位降至 50% (0.15/0.30)。
    • ContextInfo.lookback_window = 20:计算波动率所使用的时间跨度,通常取 20 日(一个月)或 60 日(一季度)。
  2. handlebar 函数

    • 数据获取:使用 get_market_data_ex 获取历史收盘价。注意 count 设置为 lookback_window + 1,因为计算收益率会损失一个数据点。
    • 波动率计算
      • pct_change() 计算每日涨跌幅。
      • std() 计算标准差。
      • np.sqrt(252) 将日波动率转化为年化波动率(假设一年有 252 个交易日)。
    • 仓位计算:简单的除法逻辑 Target / Current。加入了 min(..., 1.0) 确保不会因为波动率极低而产生融资买入(除非您希望加杠杆)。
    • 交易执行order_target_percent 是一个非常方便的函数,它会自动计算当前持仓和目标持仓的差额,并自动发出买入或卖出指令。

注意事项

  1. 资金账号:代码中的 'YOUR_ACCOUNT_ID' 必须替换为您在 QMT 交易界面看到的实际资金账号。
  2. 运行频率:此策略通常在日线周期上运行。如果在分钟线上运行,需要调整波动率的年化系数(例如分钟线需乘以 $\sqrt{252 \times 240}$)。
  3. 交易成本:频繁调整仓位会产生手续费。在实盘中,通常会增加一个阈值(Buffer),例如:只有当目标仓位与当前仓位的偏差超过 5% 时才进行调仓,以减少磨损。

Q&A

Q: 为什么使用 get_market_data_ex 而不是 get_market_data?
A: get_market_data_ex 是 QMT 推荐的新版接口,返回的数据结构更清晰(字典包含 DataFrame),且支持更多参数配置,处理多股数据时更高效。

Q: 如何避免频繁调仓导致的手续费过高?
A: 可以在 order_target_percent 之前加入逻辑判断。例如获取当前持仓比例,计算 abs(目标比例 - 当前比例),只有当差值大于 0.05 (5%) 时才触发下单函数。

Q: 这个策略适合什么品种?
A: 波动率目标策略(Target Volatility)非常适合指数ETF(如沪深300、中证500)或CTA策略。对于个股,由于存在特质性风险(如暴雷),单纯依赖波动率调整仓位可能不够安全。