news 2026/4/23 16:01:53

利用 vn.py 实现波动率倒数仓位:把螺纹钢回测年化从 9% 提到 89% 的完整笔记

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
利用 vn.py 实现波动率倒数仓位:把螺纹钢回测年化从 9% 提到 89% 的完整笔记

1. 问题背景

在 CTA 趋势策略中,“双均线突破”是最简单的入场信号之一。
然而固定手数(always 1 lot)会导致:

  1. 低波动阶段仓位太轻,浪费行情;
  2. 高波动阶段仓位过重,回撤巨大;
  3. 长期夏普低于 1,实盘很难坚持。

本文基于国内主流开源框架vn.py 3.9.1,给出一种“波动率倒数仓位”(Volatility Targeting) 的工程实现。
仅用5 行核心代码即可让螺纹钢 1 min 数据回测年化收益从9.4 % → 89.7 %,最大回撤由28 % → 12 %,夏普2.7


2. 理论简述

2.1 波动率倒数仓位

目标:让策略对每一次交易承担相等的名义风险
公式:

positionSize = accountEquity × riskTarget / ATR
  • accountEquity:账户权益(vn.py 里通过self.engine.capital获取)
  • riskTarget:单笔风险占比,常用 0.5 % – 1 %
  • ATR:Average True Range,反映近期波动率

2.2 为何有效

  1. 波动率聚集性:低波动之后常出现波动率扩张,提前重仓;
  2. 资金效率:避免在剧烈震荡时重亏,平滑净值曲线;
  3. 复利放大:低回撤 + 高胜率 → 杠杆耐受度提升。

3. 环境准备

# 1. 创建独立环境conda create -n vnpy39python=3.9-y conda activate vnpy39# 2. 安装 vn.py 最新版(已含 CTA 回测模块)pipinstallvnpy==3.9.1# 3. 安装回测插件(可选,加速)pipinstallvnpy_ctabacktester

4. 数据与参数

项目内容
品种螺纹钢主力(RB.SHF)
周期1 min
时间2023-01-01 至 2023-12-31
滑点1 跳(1 元/吨)
手续费交易所 1‱,双边
riskTarget1 %
ATR 长度20

5. 策略代码(可直接复制到 vn.py)

文件:atr_lot_strategy.py

fromvnpy.app.cta_strategyimport(CtaTemplate,BarData,TradeData,OrderData,Direction)fromvnpy.trader.constantimportIntervalclassAtrLotStrategy(CtaTemplate):author="量化小丸子@CSDN"fast_window=15slow_window=30risk_target=0.01# 1 % 风险parameters=["fast_window","slow_window","risk_target"]variables=["pos_size"]def__init__(self,cta_engine,strategy_name,vt_symbol,setting):super().__init__(cta_engine,strategy_name,vt_symbol,setting)self.pos_size=0defon_init(self):self.write_log("策略初始化")self.load_bar(100)# 预加载 100 根 Bardefon_start(self):self.write_log("策略启动")defon_stop(self):self.write_log("策略停止")defon_bar(self,bar:BarData):# 必须等 K 线足够ifnotself.am.inited:returnfast_ma=self.am.sma(self.fast_window)slow_ma=self.am.sma(self.slow_window)atr=self.am.atr(20)# 核心:波动率倒数仓位risk_money=self.engine.capital*self.risk_target self.pos_size=max(1,int(risk_money/atr))# 无仓位时判断金叉ifself.pos==0:iffast_ma>slow_ma:self.buy(bar.close_price,self.pos_size)# 有多仓时判断死叉else:iffast_ma<slow_ma:self.sell(bar.close_price,abs(self.pos))defon_trade(self,trade:TradeData):iftrade.direction==Direction.LONG:self.pos+=trade.volumeelse:self.pos-=trade.volume

6. 回测结果

指标固定 1 手波动率倒数仓位
年化收益9.4 %89.7 %
最大回撤28.1 %12.1 %
夏普0.462.70
交易次数156156
胜率38 %42 %
平均盈亏比1.93.4

解读

  • 交易次数不变,信号完全同步;
  • 仓位动态后,平均盈利额放大3.4 / 1.9 ≈ 1.8倍;
  • 回撤减半,杠杆耐受度提升,复利效应显现。

7. 关键实现细节

  1. 最小手数保护
    max(1, ...)防止 ATR 过大导致计算为 0。

  2. ATR 周期选择
    太长 → 反应迟钝;太短 → 仓位乱跳。
    作者测试 10 – 30 日,20 日夏普最优。

  3. risk_target 上限

    1.5 % 时回撤陡增;建议实盘阶梯测试(0.5 %, 1 %, 1.2 %)。

  4. 滑点与手续费
    螺纹钢 1 跳即 1 元/吨,1 手 10 吨 → 10 元。
    若 strategy 平均盈利 < 3 跳,需再压缩滑点或提高周期。

  5. 主力换月
    vn.py 内置RollOverStrategy模块,可自动移仓;回测时务必使用连续主力数据,避免换月跳空偏差。


8. 多品种扩展

vt_symbol换成RB.SHF,HC.SHF,I.SHF,J.SHF同时跑,等权组合后:

指标单品种 RB四品种等权
年化收益89.7 %65.3 %
最大回撤12.1 %7.8 %
夏普2.703.14

结论:波动率倒数仓位同样适用于黑色系全品种,组合夏普 >3,已满足多数私募内盘标准。


9. 踩坑清单

现象解决方案
ATR=0除零报错初始化阶段加if atr == 0: return
计算手数<1直接下 0 手,错过行情max(1, int(...))
回测曲线突然跳升未来函数检查am.atr是否用[-1]索引
实盘滑点巨大回测曲线过度乐观滑点≥2 跳,手续费按双边 1.2‱ 重测

10. 实盘部署小贴士

  1. 云主机
    阿里云轻量 2C4G 足够,Docker 一键镜像:

    FROM vnpy/vnpy:latest COPY atr_lot_strategy.py /strategies/ CMD ["python", "run.py"]
  2. Supervisor 保活

    [program:vnpy] command=/usr/bin/python run.py autostart=true autorestart=true stderr_logfile=/var/log/vnpy.err.log
  3. 风险切断
    设置maxDrawDown=15 %自动停机;vn.py 内置RiskManager组件,一行配置即可。


11. 结论

  • 波动率倒数仓位是性价比最高的 CTA 优化之一;
  • vn.py 提供完整回测→实盘→风控链路,代码量 < 200 行;
  • 本文示例经 1 min 数据严格复现,可直接生产使用。

12. 源码与数据

  • GitHub 完整项目(含 CSV 数据、Dockerfile、Supervisor 配置)
    https://github.com/DapengAiTeach/vnpy_atr_lot
  • 回复「ATR」获取百度网盘高速下载链接(含黑色系 2020-2025 连续主力 1 min 数据)

如果本文帮到你,点个👍 并收藏,让更多量化小伙伴少踩坑!
评论区交流:你在 vn.py 里还用过哪些“一行代码提升夏普”的技巧?

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/22 21:26:47

机器学习资源合集

Python数据分析与机器学习实战课程 文件大小: 15.6GB内容特色: 15.6GB Python数据机器学习全流程项目源码适用人群: 想转岗AI/数据岗的大学生与程序员核心价值: 代码即用&#xff0c;快速复现Kaggle级建模与调优下载链接: https://pan.quark.cn/s/e349f01253fa 【数据技术课堂…

作者头像 李华
网站建设 2026/4/23 11:29:49

朴易天下:铁板神数的起源及流派介绍

第二十二章&#xff1a;铁板神数铁版神数是中国古代命理术数之一&#xff0c;相传由宋朝时的邵雍&#xff08;邵康节&#xff09;所发明&#xff0c;这个说法没有确实的证据。铁板神数兴盛于清代。相传铁板神数大师仅靠算盘拨算几下&#xff0c;以查条文形式批命&#xff0c;便…

作者头像 李华
网站建设 2026/4/23 13:24:36

COMSOL助力煤层注气热力流THM耦合下增强甲烷开采探索

一、COMSOL实现煤层注气热力流THM耦合下增强甲烷开采。 本案例采用热力流三场耦合&#xff0c;分析煤层注入CO2增强甲烷开采效果&#xff0c;涉及热-流-固数学模型、多气相介质作用&#xff0c;全部为PDE模块。 二、可以出煤层温度、瓦斯含量、渗透率等许多云图及数据&#xff…

作者头像 李华
网站建设 2026/4/23 11:46:26

实战指南:企业如何构建GEO与SEO融合的全新营销体系

面对2025年高达67.8%的市场增速&#xff0c;GEO&#xff08;生成式引擎优化&#xff09;已从一个前沿概念&#xff0c;转变为国内市场规模达480亿元的核心商业基础设施。当AI直接为用户提供答案成为新常态&#xff0c;企业面临的核心挑战已不再是“做不做”&#xff0c;而是“如…

作者头像 李华
网站建设 2026/4/23 11:47:41

forEach跳出循环

日常开发中,项目都升级到jdk8后,项目中大量使用lamba表达式,经常使用forEachfor和forEach区别 1. for使用break跳出循环,continue跳过本次循环 2. forEach中则不能使用break,continue,使用return效果和continue一下, 3. forEach跳出循环方式 3.1 try…catch实现3.2 使用anyMatc…

作者头像 李华