第二十五讲:进阶话题——基于波动率的动态仓位调整

各位同学,欢迎来到进阶话题。前面我们讲了基差套利的入场、出场、止损,但有个核心问题一直没细聊——仓位到底该下多重?

说实话,这个问题比选品种、定阈值都关键。你策略再牛,仓位管理一塌糊涂,照样爆仓。我见过太多人,策略回测曲线漂亮得像教科书,实盘一上,三天就扛不住了。为什么?仓位没动态调。

今天我们就聊一个进阶玩法:基于波动率的动态仓位调整。说白了,就是让市场告诉你,现在该下多少注。

为什么需要动态仓位?

先问个问题:你平时怎么定仓位?

很多人是固定手数,比如每次开10手。或者固定资金比例,比如总资金的5%。这两种方式,在波动率平稳时还行。但市场一抽风,问题就来了。

举个例子。假设你开仓1手,止损10个点。波动率低的时候,一天波动也就20点,很舒服。突然某天波动率翻倍,一天能跑50点。你原来的止损位,可能开盘就被打穿。仓位还是那个仓位,但风险已经变了。

我2019年做螺纹钢基差套利时就吃过这个亏。当时波动率很低,我按常规仓位下了30手。结果政策一出,波动率瞬间飙升,账户回撤直接超过5%。虽然方向没错,但仓位太重,被迫减仓,利润全吐回去了。

所以,仓位必须跟着波动率走。波动率低,多下点;波动率高,少下点。这才是科学的资金管理。

核心逻辑:波动率与仓位成反比

动态仓位调整的核心公式其实很简单:

目标仓位 = 基准仓位 × (基准波动率 / 当前波动率)

这里:

  • 基准波动率:你回测时市场的平均波动水平
  • 当前波动率:最近N天的实际波动率
  • 基准仓位:你在基准波动率下愿意下的仓位

举个例子。你回测时市场日均波动20点,你设的基准仓位是10手。现在市场波动率变成40点,那目标仓位就是:

10手 × (20 / 40) = 5手

波动率翻倍,仓位减半。反过来,波动率降到10点,仓位就变成20手。这样,每笔交易承担的风险金额基本一致

核心思想:不是控制仓位大小,而是控制每笔交易的风险敞口。波动率变了,仓位跟着变,风险才能稳定。

波动率怎么算?

波动率的计算方法很多,我个人最常用的是历史波动率(HV)ATR(平均真实波幅)

1. 历史波动率(HV)

就是过去N天收益率的标准差。一般取20天或60天。计算很简单:

import numpy as np
import pandas as pd

def calc_hv(price, window=20):
    log_ret = np.log(price / price.shift(1))
    hv = log_ret.rolling(window).std() * np.sqrt(252)  # 年化
    return hv

这里乘以sqrt(252)是为了年化,方便不同品种之间比较。实际做仓位调整时,用日波动率就够了,不用年化。

2. ATR(平均真实波幅)

ATR是技术分析里常用的波动率指标。它考虑了跳空缺口,比单纯看收盘价更全面。

def calc_atr(high, low, close, window=14):
    tr = np.maximum(high - low, 
                    np.abs(high - close.shift(1)),
                    np.abs(low - close.shift(1)))
    atr = tr.rolling(window).mean()
    return atr

我个人习惯用ATR。为什么?因为它直观。ATR=50,意味着今天平均波动50个点。你设止损30点,那大概率会被打。用ATR来定仓位,更贴近实际交易。

小技巧:如果你做的是跨期套利,建议用价差的ATR,而不是单腿的。因为套利的核心是价差波动,不是单边波动。我早期犯过这个错,用单腿波动率去管套利仓位,结果经常偏大或偏小。

完整的动态仓位调整流程

好了,理论讲完,上实战代码。下面是一个完整的动态仓位调整函数:

def dynamic_position_size(signal, price_df, base_pos=10, 
                          atr_window=20, risk_factor=0.02):
    """
    基于ATR的动态仓位调整
    signal: 信号DataFrame,包含entry_time, direction
    price_df: 价格数据,包含high, low, close
    base_pos: 基准仓位
    atr_window: ATR计算窗口
    risk_factor: 风险因子,控制每笔交易风险占总资金比例
    """
    # 计算ATR
    atr = calc_atr(price_df['high'], price_df['low'], 
                   price_df['close'], atr_window)
    
    # 计算基准ATR(回测期间的平均值)
    base_atr = atr.median()  # 用中位数更稳健
    
    # 生成仓位调整因子
    atr_ratio = base_atr / atr
    
    # 限制调整范围,防止极端值
    atr_ratio = atr_ratio.clip(0.3, 3.0)
    
    # 计算最终仓位
    signal['position_size'] = (base_pos * atr_ratio).round().astype(int)
    
    # 风险校验:确保每笔风险不超过总资金的2%
    capital = 1000000  # 假设总资金100万
    risk_per_unit = atr * risk_factor  # 每手风险金额
    max_pos = capital * 0.02 / risk_per_unit
    
    signal['position_size'] = signal[['position_size', max_pos]].min(axis=1)
    
    return signal

这段代码做了三件事:

  1. 计算当前ATR和基准ATR的比值
  2. 用比值调整仓位,并限制在0.3倍到3倍之间
  3. 用固定比例风险模型做二次校验,防止仓位过大

注意:限制调整范围非常重要。我见过有人不设限,结果波动率极低时仓位放大到10倍,市场一恢复波动,直接爆仓。0.3到3倍是个比较合理的范围,你可以根据自己的风险偏好调整。

波动率调整的几种变体

上面讲的是最基础的版本。实际应用中,还有几种变体,我简单介绍一下:

1. 指数平滑波动率

用EWMA(指数加权移动平均)代替简单移动平均。这样近期的波动率权重更大,反应更快。

def calc_ewma_vol(price, lambda_=0.94):
    log_ret = np.log(price / price.shift(1))
    var = log_ret.ewm(span=2/(1-lambda_)-1).var()
    return np.sqrt(var)

lambda取0.94是RiskMetrics的标准做法。我个人觉得做套利的话,反应太快反而容易过度调整,0.97左右更合适。

2. 分位数调整

不是直接用波动率比值,而是看当前波动率处于历史分布的什么位置。比如:

def quantile_adjustment(atr, window=252):
    rank = atr.rolling(window).rank(pct=True)
    # 分位数越低,仓位越大;分位数越高,仓位越小
    pos_factor = 1 - rank  # 或者用 2 - 2*rank 等
    return pos_factor.clip(0.2, 2.0)

这种方法的好处是,不受极端值影响。即使波动率突然飙到天上去,调整因子也不会无限趋近于0。

3. 波动率锥(Volatility Cone)

这是比较高级的玩法。不同时间周期的波动率表现不同,比如短期波动率高、长期波动率低。波动率锥就是看当前波动率在同类周期中的位置。

具体实现比较复杂,这里不展开。简单说,就是分别计算5天、10天、20天、60天的波动率,然后看它们的历史分布。如果20天波动率处于90%分位,那说明中期波动率异常高,仓位应该大幅降低。

实战中的注意事项

讲几个我踩过的坑:

第一,不要频繁调整仓位。 波动率每天变,仓位也跟着每天变?那交易成本就够你受的。我建议每周调整一次,或者只在开仓时调整。持仓期间除非波动率发生重大变化(比如超过2倍),否则不动。

第二,注意波动率的聚集效应。 波动率高的时期往往持续一段时间。如果你在波动率飙升时减仓,之后波动率一直高,你就一直轻仓,可能错过行情。我的做法是:用慢速波动率(比如60天ATR)做仓位基准,用快速波动率(比如10天ATR)做风险预警。两者结合,既不过度反应,也不反应迟钝。

第三,不同品种的波动率特性不同。 股指期货的波动率比商品期货低,但爆发力强。商品里,原油和黄金的波动率特性又不一样。我建议每个品种单独计算基准波动率,不要用统一标准。

总结一下:动态仓位调整不是万能药,但它能让你在波动率变化时保持风险一致。我做了这么多年交易,最大的体会就是——活得久比赚得快更重要。动态仓位调整,就是帮你活得久的工具之一。

知识体系图

下面这张图总结了本章的核心逻辑:

基于波动率的动态仓位调整知识体系 输入数据 价格序列 (H/L/C) 基准仓位 风险因子 波动率计算 历史波动率 (HV) ATR EWMA波动率 仓位调整:基准仓位 × (基准波动率 / 当前波动率) 风险校验:每笔风险 ≤ 总资金2% 最终仓位 图:动态仓位调整的完整流程,从输入到输出共5个步骤

嗯,这张图把整个流程串起来了。从输入数据开始,经过波动率计算、仓位调整、风险校验,最后输出最终仓位。每一步都有对应的代码实现,你可以直接拿去用。

好了,这一讲就到这里。动态仓位调整是个大话题,今天只讲了最核心的部分。如果你在实际应用中遇到问题,欢迎交流。记住,仓位管理不是限制你赚钱,而是保护你不亏大钱


公众号:蓝海资料掘金营,微信deep3321