作者:老余捞鱼
原创不易,转载请标明出处及原作者。

本文约 4900 字 | 预计阅读 8 – 11 分钟
深夜刷 TradingView 社区指标库,大概是我们特有的”深夜放毒”。在这种漫无目的的浏览中,我挖到了一个叫 RMA ATR Bands 的指标,作者SchizoQuant,描述里没有夸大其词的吹嘘,就是由一段干净利落的Pine Script代码组成。
一、这个指标凭什么让我停下来
TradingView上的通道类指标,十个有八个是布林带的换皮版本。但RMA ATR Bands不太一样。

TradingView上的 RMA ATR Bands 指标
先说核心区别。普通通道指标用EMA或SMA做中轨,用收盘价做基准。这个指标用 Wilder RMA 做中轨,而且锚定的不是收盘价,是最高价。
而这个设计选择不是随意的。Wilder RMA是RSI和经典ADX背后用的同一种平滑算法,特点是衰减比EMA更慢,对短期噪音不那么敏感。把中轨锚定在最高价而不是收盘价,意味着均线自然贴近K线实体上沿,上轨就处在比典型收盘区间更高的位置。
更有意思的是不对称乘数:上轨乘数0.4倍ATR,下轨乘数1.6倍ATR。这个偏置是刻意设计的,对做多策略来说,慢一点确认下行、快一点确认上行,是合理的默认设置。

不对称乘数:上轨0.4倍ATR窄通道,下轨1.6倍ATR宽通道
| 特征 | 常规布林带 | RMA ATR Bands |
|---|---|---|
| 中轨算法 | SMA / EMA | Wilder RMA |
| 锚定价格 | 收盘价 | 最高价 |
| 波动率基础 | 标准差 | ATR(真实波动幅度) |
| 上下轨乘数 | 对称(如2倍) | 不对称(0.4 / 1.6) |
| 设计倾向 | 中性 | 偏多头(适合做多策略) |
进出场逻辑也极简。收盘价突破上轨,趋势翻多,发出信号。收盘价跌破下轨,趋势翻空,退出信号。没有RSI背离叠加,没有多周期确认,没有满屏仪表盘。价格相对自身波动通道的位置,就是全部信息。
简单到五分钟能审计完逻辑。但也鲁棒到真的能跑。
二、从Pine Script搬到Python
我的习惯是:TradingView上发现的任何值得测的指标,一律移植到Python用vectorbt跑回测。原因很实际,TradingView内置的策略测试器有已知的前视偏差问题,而且没法批量跑几百个标的。
移植过程很顺畅。两个核心函数 wilder_rma() 和 wilder_atr(),各不到十行代码。有状态的循环用NumPy数组迭代实现,精确对应Pine Script里 var int trend = 0 的模式。
关键的防偏步骤:信号在进入组合引擎之前做了 .shift(1) 处理。意思是,第N根K线收盘确认的信号,只能在第N+1根K线开盘时执行。不看未来数据,回测可信度的底线就在这里。

信号位移:第N根K线确认,第N+1根K线开盘执行
# ─────────────────────────────────────────────────────────────────# 入场 / 出场信号# ─────────────────────────────────────────────────────────────────# 向后移动1根K线 — Pine在确认的K线上触发信号,我们在下一根K线的开盘价执行entries = long_sig_s.shift(1).astype(bool).fillna(False).to_numpy()exits = short_sig_s.shift(1).astype(bool).fillna(False).to_numpy()# ──────────────────────────────────────────────────────────────────# 回测(仅做多,匹配Pine的多空信号结构)# ──────────────────────────────────────────────────────────────────pf = vbt.Portfolio.from_signals( close = open_, # 以下一根K线开盘价执行 entries = entries, exits = exits, init_cash= 100_000, fees = 0.001, slippage = 0.002, freq = "1d",)print("\n" + "=" * 60)print(f" {SYMBOL} | RMA ATR 带状策略 | {INTERVAL}")print("=" * 60)print(pf.stats())# ──────────────────────────────────────────────────────────────────# 绘图# ──────────────────────────────────────────────────────────────────fig = pf.plot( subplots=[ "value", "underwater", "orders", "trade_pnl", ], title=f"{SYMBOL}", make_subplots_kwargs=dict( row_heights=[0.30, 0.20, 0.20, 0.30], vertical_spacing=0.03, ),)fig.update_layout(height=1200)fig.show()测试标的选了MTG(MGIC投资公司),这一家按揭保险商。选它不是因为我有什么观点,纯粹因为它在我的观察列表里躺了很久,历史数据足够长,能给统计测试提供足够的样本量。
三、35年回测结果
回测区间从1991年8月到2026年5月,将近35年日线数据,8754根K线。
先看核心数字:
| 指标 | 数值 |
|---|---|
| 初始资金 | $100,000 |
| 期末价值 | $1,400,971 |
| 策略总收益 | 1,301% |
| 被动持有同期收益 | 374.7% |
| 超额收益 | +926个百分点 |
| 总交易次数 | 128笔(35年) |
| 年均交易频率 | 约3-4笔/年 |
| 胜率 | 45.3% |
| 盈亏比 | 1.55 |
| 单笔最大盈利 | +199% |
| 单笔最大亏损 | -52.9% |
| 最大回撤 | 90.9% |
| Calmar比率 | 0.13 |

几个值得拆开说的点。
低频交易,高频复利。35年128笔交易,年均不到4笔。这不是一个每天进出场磨手续费的策略。每笔盈利交易平均持仓69天,让趋势跑足。每笔亏损交易平均只持仓17天,迅速认错。趋势跟踪系统最想要的”截断亏损、让利润奔跑”的不对称性,这里自然出现了。
2008年活下来了。MTG是按揭保险公司,2008年次贷危机股价跌了95%以上。策略在崩跌前已经退出,保持空仓或平坦度过最惨烈的阶段。一家按揭保险公司的股票,用趋势跟踪策略在2008年活下来了,这本身就有说明力。

2008年:策略在崩跌前退出,被动持有者跌了95%
胜率不到一半,但盈亏比兜底。45.3%的胜率意味着亏的比赢的多。但平均盈利+19.9%,平均亏损-8.5%,盈利笔的规模是亏损笔的两倍多。盈亏比1.55,靠的是赢的时候赢得够多,而不是赢的次数够多。

低胜率高盈亏比:亏损笔多但单笔小,盈利笔少但单笔大
最大回撤90.9%怎么看。这个数字乍看吓人。但回撤主要集中在2008-2012年,MTG本身差点破产。对于单标的的策略来说,在这种极端冲击下还能产出13倍回报,是说得过去的。Calmar比率0.13老实反映了这段艰难时期,这不是一个风险调整后收益的优等生,是一个raw趋势捕获引擎。
四、需要理性看待这个结果
我们需要说清楚这个回测是什么和不是什么。
是:单标的、单参数组、无前视偏差、无过拟合的干净回测。核心逻辑(RMA锚定通道、不对称ATR乘数、有状态趋势、无重绘)在MTG的价格历史上捕获了主要趋势,有真实的机械性价值。
不是:不是策略验证。没有样本外测试,没有walk-forward分析,没有跨标的稳健性检验。一次好结果不等于一个策略。MTG也是特殊案例,从低价股到30多美元、波动巨大,恰好是趋势跟踪策略的理想环境。
这个结果说明的是:这个指标的底层逻辑值得进一步检验。下一步该做的,是把它跑到更广泛的标的池上,看看边际收益在哪里稳定存在、在哪里消失。
提醒:回测结果不代表未来收益。单标的回测尤其容易产生幸存者偏差式的乐观。任何策略在投入实盘前,都需要跨标的、跨周期的样本外验证。
聊聊你的想法
你有没有在TradingView社区库里挖到过看起来不起眼、但实测效果不错的小众指标?或者你对这种”单标的回测”的可信度怎么看?
欢迎在评论区聊聊,我会逐条看。如果觉得这篇有用,转发给你身边还在只用布林带的朋友。
#TradingView #RMA #ATR #量化策略 #趋势跟踪 #vectorbt #回测 #技术指标 #Python量化 #波动率通道
Be First to Comment