当前位置:首页>python>量化实战:用 Python 复现「量价分析」策略,回测跑赢持有 91 个百分点

量化实战:用 Python 复现「量价分析」策略,回测跑赢持有 91 个百分点

  • 2026-10-11 05:37:13
量化实战:用 Python 复现「量价分析」策略,回测跑赢持有 91 个百分点

用 Python 揭秘均值回归策略:你的收益从何而来?

量化交易的生死线:用 Python 算出你的最优下注比例

2026年重磅升级已全面落地!欢迎加入专注财经数据与量化投研的【数据科学实战】知识星球!您将获取持续更新的《财经数据宝典》与《量化投研宝典》,双典协同提供系统化指引;星球内含 500 篇以上独有高质量文章,深度覆盖策略开发、因子分析、风险管理等核心领域,内容基本每日更新;同步推出的「量化因子专题教程」系列(含完整可运行代码与实战案例),系统详解因子构建、回测与优化全流程,并实现日更迭代。我们持续扩充独家内容资源,全方位赋能您的投研效率与专业成长。无论您是量化新手还是资深研究者,这里都是助您少走弯路、事半功倍的理想伙伴,携手共探数据驱动的投资未来!

引言

很多刚接触量化交易的 Python 学习者,往往从最简单的「双均线交叉」入手:短期均线上穿长期均线就买入,下穿就卖出。这个思路简单,但它只看价格方向,忽略了市场的另一半信息——成交量。

今天要拆解的是一个更进阶的思路:量价分析(Volume Spread Analysis,简称 VSA)。它的核心理念很朴素:同样一根上涨的 K 线,放巨量拉出的大阳线和缩量磨出的小阳线,含义完全不同;收在最高点附近和收在最低点附近,透露的信息也天差地别。

我们会结合一个真实回测案例来讲解:在日线上运行一年,该策略最终录得 43.25% 的收益,而同期买入并持有反而亏损 48.06%,两者相差 91.31 个百分点。下面就用 Python 和 Backtrader 一步步把它讲清楚。


一、VSA 到底在看什么

传统均线策略只盯着价格,而 VSA 策略在每根 K 线上会同时观察四类信息:

  • • 成交量:当前成交量相比近期平均成交量是放大还是萎缩。
  • • 价差(Spread):用 high - low 衡量 K 线的振幅,再和近期平均振幅对比,判断这根 K 线是「宽幅」还是「窄幅」。
  • • 收盘位置:收盘价落在整根 K 线区间的高位、中位还是低位。
  • • 趋势背景:价格在趋势均线之上还是之下。

把这四个维度组合起来,策略就能识别出一系列经典的量价形态,例如「停止量」「多头强势」「空头弱势」「高潮量」「测试支撑」「测试阻力」等。

它的目标不是抓住每一次波动,而是只在成交量、振幅、收盘位置、趋势方向四者达成一致时才出手。


二、策略参数:先把「旋钮」定义好

Backtrader 里习惯用 params 元组来集中管理可调参数。这个策略暴露出来的参数如下:

params = (    ('volume_period', 7),        # 计算平均成交量的窗口长度    ('volume_threshold', 1.2),   # 成交量放大到多少倍算「高量」    ('spread_period', 7),        # 计算平均振幅的窗口长度    ('spread_threshold', 1.2),   # 振幅超过多少倍算「宽幅」    ('trend_period', 30),        # 判断趋势用的均线周期    ('climax_volume_mult', 2.0), # 放量到多少倍算「高潮量」    ('test_volume_mult', 0.5),   # 成交量萎缩到多少倍算「低量」    ('trail_stop_pct', 0.05),    # 入场后的移动止损比例(5%))

把参数集中定义有两个好处:一是逻辑清晰、方便阅读;二是后续做参数优化(optimization)时,Backtrader 可以直接对这些参数做网格搜索。


三、代码走读:从原始数据到交易信号

1. 准备基础数据

策略先把 OHLCV(开高低收量)数据取出来,并计算两个核心派生量——价差和收盘位置:

self.high = self.data.highself.low = self.data.lowself.close = self.data.closeself.open = self.data.openself.volume = self.data.volume# 价差:最高价减最低价,衡量这根 K 线的振幅self.spread = self.high - self.low# 收盘位置:收盘价在整根 K 线区间中的相对高度,取值 0~1# 越接近 1 说明收得越高,越接近 0 说明收得越低self.close_position = (self.close - self.low) / (self.high - self.low)

小提示:(high - low) 有可能为 0(比如一字板行情),实盘代码里最好加上除零保护,否则会报错。

2. 构建三条移动平均线

# 成交量的移动平均,用来判断放量还是缩量self.volume_ma = bt.indicators.SMA(self.volume, period=self.params.volume_period)# 振幅的移动平均,用来判断宽幅还是窄幅self.spread_ma = bt.indicators.SMA(self.spread, period=self.params.spread_period)# 收盘价的移动平均,作为趋势判断的基准线self.trend_ma = bt.indicators.SMA(self.close, period=self.params.trend_period)

3. 对成交量分类

# 当前成交量相对近期平均量的比值volume_ratio = self.volume[0] / self.volume_ma[0]if volume_ratio >= self.params.climax_volume_mult:    return 'climax'   # 高潮量:放量到 2 倍以上elif volume_ratio >= self.params.volume_threshold:    return 'high'     # 高量:放量到 1.2 倍以上elif volume_ratio <= self.params.test_volume_mult:    return 'low'      # 低量:萎缩到 0.5 倍以下else:    return 'normal'   # 正常量

4. 对振幅分类

spread_ratio = self.spread[0] / self.spread_ma[0]if spread_ratio >= self.params.spread_threshold:    return 'wide'     # 宽幅 K 线elif spread_ratio <= (2 - self.params.spread_threshold):    return 'narrow'   # 窄幅 K 线else:    return 'normal'

这里 2 - spread_threshold 是个巧妙的对称写法:阈值取 1.2 时,宽幅门槛是 1.2 倍,窄幅门槛就是 0.8 倍,围绕「1 倍」上下对称。

5. 判断收盘位置和趋势方向

# 收盘位置分类close_pos = self.close_position[0]if close_pos >= 0.7:    return 'high'     # 收在高位elif close_pos <= 0.3:    return 'low'      # 收在低位else:    return 'middle'   # 收在中间
# 趋势方向判断if self.close[0] > self.trend_ma[0]:    return 'up'        # 价格在趋势均线之上,判定为上升趋势elif self.close[0] < self.trend_ma[0]:    return 'down'      # 价格在趋势均线之下,判定为下降趋势else:    return 'sideways'  # 横盘

四、形态识别:把分类结果拼成交易语言

有了上面几个分类标签,就可以拼装出具体的量价形态。举两个例子:

停止量(stopping volume):下跌趋势中突然放出高潮量,但 K 线并没有收弱,说明抛压可能被大资金接走:

if (    volume_class == 'climax' and   # 高潮量    trend == 'down' and            # 处于下降趋势    is_down_bar and                # 这是一根下跌 K 线    close_class in ['middle', 'high']  # 但收盘没有收在低位):    return 'stopping_volume', 4    # 返回形态名和强度分(满分 4)

高潮顶(bearish climax):上升趋势中放巨量拉出宽幅大阳线并收在高位,往往是多头力竭的信号:

if (    volume_class == 'climax' and   # 高潮量    spread_class == 'wide' and     # 宽幅 K 线    close_class == 'high' and      # 收在高位    is_up_bar and                  # 这是一根上涨 K 线    trend == 'up'                  # 处于上升趋势):    return 'climax', 4

策略还会回看最近 3 根 K 线作为「背景」加分,判断当前信号是否有连续放量的配合:

context_score = 0for i in range(1, 4):            # 回看前 1~3 根 K 线    if len(self.data) <= i:        continue    prev_volume = self.volume[-i]    if prev_volume > self.volume_ma[-i]:  # 若历史某根放量        context_score += 1                # 背景分加 1

五、下单逻辑:强度够高才出手

信号强度加上背景分,只有总分足够高才允许交易:

pattern, strength = self.detect_vsa_patterns()if pattern is None or strength < 2:   # 没有形态或强度太弱,直接跳过    returncontext = self.check_background_context()total_strength = strength + context   # 形态强度 + 背景分if total_strength < 3:                # 综合分不足,放弃    return

看多形态开多仓、平空仓;看空形态则相反:

# 看多形态:可以开多仓,或平掉已有空仓if pattern in ['no_demand', 'no_supply', 'stopping_volume',               'strength', 'test_support', 'effort_down']:    if self.position.size < 0:        # 当前持有空仓        self.order = self.close()     # 先平空    elif not self.position:           # 当前空仓(无持仓)        if total_strength >= 4 or pattern in ['stopping_volume', 'no_supply']:            self.order = self.buy()   # 开多仓

最后用移动止损控制风险:入场后自动挂一个比成交价低 5% 的止损单。

if order.isbuy() and self.position.size > 0:    self.entry_price = order.executed.price    # 止损价 = 成交价 × (1 - 5%)    self.trail_stop_price = order.executed.price * (1 - self.params.trail_stop_pct)    self.stop_order = self.sell(        exectype=bt.Order.Stop,        # 止损单类型        price=self.trail_stop_price,    )

至此一个完整的交易闭环就成型了:分类 K 线 → 识别形态 → 计算综合强度 → 达标才入场 → 移动止损管理。


六、回测结果

在 ETH-USD 日线、时间跨度一年的数据上运行,最终结果如下:

指标
数值
策略收益
43.25%
买入持有收益
-48.06%
超额收益
91.31%
夏普比率
1.39
最大回撤
11.98%
平仓交易数
12
未平仓交易数
0
胜率
66.67%

值得注意的是,这个成绩不是靠一笔运气好的持仓撑起来的:全程完成了 12 笔已平仓交易,收尾时没有留下任何未平仓头寸,胜率约三分之二。资金从 10000 美元增长到约 14324.86 美元,而同期直接持有 ETH 则大幅下跌,最大回撤也仅 11.98%,成功规避了单边下跌的大部分风险。

冷静提醒:单一品种、单一时间段、样本仅 12 笔交易的回测,统计意义有限。收益亮眼不代表可以直接实盘,务必再验证手续费、滑点、不同市场环境下的稳健性。


总结

这个 VSA 案例的价值,不在于它跑出了多高的收益,而在于它示范了一种比单纯看价格更立体的思路:把成交量、振幅、收盘位置、趋势背景当作交易的「上下文」来综合判断,而不是只盯着价格方向。

对 Python 量化学习者来说,可以带走三点:

  • • 多维度组合优于单一信号:与其只用一条均线,不如让「量、价、势」互相印证。
  • • 参数集中管理 + 强度打分:用 params 统一管理旋钮,用打分机制过滤弱信号,代码会更清晰、更易扩展。
  • • 风险控制不能省:移动止损把最大回撤压在了约 12%,这往往比多赚几个点更重要。

沿着这条路,你还可以继续尝试云图突破、ZigZag 枢轴、波动率突破、均值回归、动量过滤、趋势跟踪离场等更多思路,逐步搭建属于自己的策略库。

本文所有内容仅用于学习和研究,不构成任何投资建议。


参考文章

加入专注于财经数据与量化投研的知识星球【数据科学实战】,获取本文完整研究解析、代码实现细节。

财经数据与量化投研知识社区

2026年全面升级已落地!【数据科学实战】知识星球核心权益如下:

  1. 1. 双典系统赋能:获赠《财经数据宝典》与《量化投研宝典》完整文档,凝练多年实战经验,构建系统化知识框架;
  2. 2. 量化因子日更教程(2026重磅新增):每日更新「量化因子专题教程」,配套完整可运行代码与实战案例,深度拆解因子构建、回测与优化全流程;
  3. 3. 量化文章专题教程库:500+篇星球独有高质量教程式文章,系统覆盖策略开发、因子研究、风险管理等核心领域,内容基本每日更新,并配套精选学习资料与实战参考;
  4. 4. 量化投研实战课程:赠送《AKQuant-入门及实战》《PyBroker-入门及实战》视频课程,手把手教学,快速掌握量化策略开发技能;
  5. 5. 财经数据支持:定期更新国内外财经数据,为策略研发提供精准、可靠的数据基础;
  6. 6. 顶尖学者与行业专家分享:年度邀请学术界博士与业界资深专家开展前沿论文精讲与实战案例分享,不少于4场,直击研究前沿与产业实践;专家直连答疑:与核心开发者及领域专家实时互动,高效解决投研实战难题;
  7. 7. 专业社群与专属福利:加入高质量交流社群,获取课程折扣及更多独家资源。

星球已沉淀丰富内容生态——涵盖量化文章专题教程库、因子日更系列、高频数据集、PyBroker实战课程、专家深度分享与实时答疑服务。无论您是初探量化的学习者,还是深耕领域的从业者,这里都是助您少走弯路、高效成长的理想平台。诚邀加入,共探数据驱动的投资未来!

好文推荐

1. 用 Python 打造股票预测系统:Transformer 模型教程(一)

2. 用 Python 打造股票预测系统:Transformer 模型教程(二)

3. 用 Python 打造股票预测系统:Transformer 模型教程(三)

4. 用 Python 打造股票预测系统:Transformer 模型教程(完结)

5. 揭秘隐马尔可夫模型:因子投资的制胜武器

6. YOLO 也能预测股市涨跌?计算机视觉在股票市场预测中的应用

7. 金融 AI 助手:FinGPT 让你轻松掌握市场分析

8. 量化交易秘籍:为什么专业交易员都在用对数收益率?

9. Python 量化投资利器:Ridge、Lasso 和 Elastic Net 回归详解

10. 掌握金融波动率模型:完整 Python 实现指南

好书推荐

最新文章

随机文章