ta-lib-python 算 ATR/NATR:5 分钟画好波动率止损线
【免费下载链接】ta-lib-pythonPython wrapper for TA-Lib (http://ta-lib.org/).项目地址: https://gitcode.com/gh_mirrors/ta/ta-lib-python
止损线为什么总被扫:先让波动率说话
上周复盘时你发现:止损线设得近,一根普通阴烛就把你扫出去;设得远,又扛着浮亏过夜。病根在于固定百分比止损没考虑每天的波动差异。用 ta-lib-python 算 ATR(平均真实波幅)来动态定止损线,波动大的日子自动放宽、波动小的日子自动收紧,5 分钟就能跑通。
读完你能独立做完这几件事
- 用 3 条命令装好 ta-lib-python 环境
- 对任意 high/low/close 序列算出 ATR 和 NATR(归一化平均真实波幅),并解释前面那些 NaN
- 画出"收盘价 + 2 倍 ATR 止损线"的组合图,再改出一个追踪止损变体
ATR 和 NATR 到底怎么算的
一句话:ATR 就是"最近 N 天每天颠簸程度的加权平均",NATR 把它换算成相对收盘价的百分比。
TR = max(high - low, |high - 昨close|, |low - 昨close|) # 当日真实波幅 ATR[14] = mean(TR[1..14]) # 第 14 根K线:算术平均 ATR[t] = (ATR[t-1] * 13 + TR[t]) / 14 # 之后:加权滚动平滑 NATR = ATR / close * 100 # 转成百分比相当于给最近 14 天的颠簸程度做个"昨天的分量略大"的均值,所以它对最近几天的异动特别敏感。周期怎么选,看这张小表:
| 周期 | 特点 | 适合 |
|---|---|---|
| 5~10 | 反应快、噪音多 | 日内 / 超短 |
| 14(默认) | 敏感与平滑平衡 | 日线短线 |
| 50+ | 很稳、反应慢 | 趋势跟踪 |
函数签名一行就能看全,仓库里 docs/func_groups/volatility_indicators.md 就是波动率指标(含 ATR、NATR、TRANGE)的签名一览:real = ATR(high, low, close, timeperiod=14)。
跟着做:ta-lib-python 从零算出 ATR 止损线
装环境只需 3 条命令
ta-lib-python 0.6.5+ 的 PyPI 轮子自带 TA-Lib C 库,不用自己编译:
python -m pip install -U TA-Lib python -m pip install pandas matplotlib python -c "import talib; print(talib.__version__)"第三条会打印版本号,能打印出来就算装好了 ✅
造 120 根模拟 K 线
真实数据源随便接,这里用随机游走模拟 120 根日 K 线,并保证 high ≥ close ≥ low:
import numpy as np, pandas as pd rng = np.random.default_rng(42) close = 100 + np.cumsum(rng.normal(0, 1, 120)) # 收盘价:随机游走 df = pd.DataFrame({'high': close + np.abs(rng.normal(0, .8, 120)), 'low': close - np.abs(rng.normal(0, .8, 120)), 'close': close})核心计算:两行指标 + 一条止损线
Function API 直接吃 pandas.Series,不用转.values。前 13 个 NaN 是回看期,第 14 根 K 线才开始出值:
import talib df['atr'] = talib.ATR(df['high'], df['low'], df['close'], timeperiod=14) # 平均真实波幅 df['natr'] = talib.NATR(df['high'], df['low'], df['close'], timeperiod=14) # ATR/收盘*100 df['stop'] = df['close'] - df['atr'] * 2 # 2 倍 ATR 止损线 df[['atr', 'natr', 'stop']].dropna().head()画出来:价格、止损线、波动率一张图
上下两个子图:上面看"价格 vs 止损线"的相对关系,下面看波动率什么时候被放大:
import matplotlib.pyplot as plt fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 6), sharex=True) ax1.plot(df['close'], label='收盘价') ax1.plot(df['stop'], '--', label='2倍ATR止损') ax1.legend() ax2.plot(df['atr'], label='ATR(14)') ax2.plot(df['natr'], '--', label='NATR(14)') ax2.set_title('ta-lib-python ATR 波动率曲线') ax2.legend() fig.tight_layout(); plt.show()你会看到:价格走得猛的区段 ATR 同步抬升,止损线自动离收盘价远一点;平静区段止损线又贴回来。这就是"动态"的含义。
换个场景试试 ATR
追踪止损:只抬升、不回落
持有趋势单时不能每根 K 线重算止损,要让"累计最高价减 2 倍 ATR"只向上走:
trail = df['close'].cummax() - df['atr'] * 2 # 累计最高价 - 2 倍 ATR exit_sig = (df['close'] < trail).diff().fillna(0) == 1 # 首次跌破追踪止损的位置 print(df.loc[exit_sig].index.tolist())适合持有趋势单的场景:止损线随价格新高不断上移,只在价格真正回头时才离场。
波动率过滤:先判断"能不能打"
有些策略只在低波动环境成立,用 NATR 当闸门最直接:
can_trade = df['natr'] < 3 # NATR 低于 3% 视为低波动,允许入场 too_hot = df['natr'] > 6 # 高于 6% 先观望 print(can_trade.mean()) # 低波动窗口占全部时间的比例回测前先用它过滤入场K线,免得策略表现被少数极端波动日稀释。
跨品种对比:谁的 NATR 高谁更颠簸
ATR 带绝对量纲,100 元的股票和 5 元的股票没法直接比;NATR 是百分比,横排就出来了(df2 是另一品种的同样结构):
a = df['natr'].rolling(20).mean() # 品种 A:20 日 NATR 均值 b = df2['natr'].rolling(20).mean() # 品种 B pd.DataFrame({'A': a, 'B': b}).dropna().tail()做多品种组合时用它比较相对波动,把仓位往"颠簸程度"匹配的品种上分。
踩坑 & 自检清单
Q: 前 13 个值全是 NaN,是不是算错了?
不是,ATR 需要 14 根 K 线的回看期,第 14 根才出第一个值:
df['atr'].head(13).isna().all() # 返回 True 就是正常行为Q: 行情数据中间缺了一根,ATR 会怎样?
TA-Lib 会把 NaN 一直传导到序列末尾,所以先清洗再算,别带着空洞进函数:
df[['high', 'low', 'close']] = df[['high', 'low', 'close']].ffill()Q: 几十万根 K 线算一次太慢?
一次性全量算本身就是 C 实现,很快;真正慢的是"每来一根 K 线就重算全量",这时换 Streaming API,每根 O(1) 更新:
from talib import stream s = stream.ATR(df['high'], df['low'], df['close'], timeperiod=14)Q: 止损倍数固定 2 倍够用吗?
不固定。高波动品种(期货、成长股)可以试 3 倍,或者先用 NATR 阈值滤掉极端波动段,再回到 2 倍。
上线前自检:
- high / low / close 等长、无 NaN
- ATR 前 13 个 NaN 没被强行填 0
- 止损倍数在自己的品种上回测过
- timeperiod 与交易周期匹配(日线常用 14)
- 图上看一眼:波动放大段止损线确实放宽了
速查卡:ATR / NATR 参数一览
| 参数 | 类型 | 默认值 | 一句话说明 |
|---|---|---|---|
| high / low / close | ndarray 或 pandas.Series | 必填 | 高、低、收盘价,三者长度必须一致 |
| timeperiod | int | 14 | 平滑周期,NaN 回看期约为 timeperiod - 1 |
| 返回值 | ndarray | — | 与输入等长,NATR 已是百分比不用再乘 100 |
| 变体 | — | — | 只要原始真实波幅用talib.TRANGE(high, low, close) |
下一步:把 mock 数据换成你的真实行情源,或者给入场信号加上 RSI 过滤,让 ATR 只管"止在哪"、RSI 管"何时进"。
【免费下载链接】ta-lib-pythonPython wrapper for TA-Lib (http://ta-lib.org/).项目地址: https://gitcode.com/gh_mirrors/ta/ta-lib-python
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考