本文是《量化指标解码》系列的第8篇,我们将深入解码SuperTrend超级趋势指标,从ATR自适应机制到趋势状态判断,从参数优化到可视化实现,让你掌握这个最简洁但威力强大的趋势跟踪工具。
上一篇我们讲了成交量分析,很多读者私信留言说:"成交量配合趋势指标用起来效果更好"。说得对,量价配合本来就是技术分析的核心思路。
最初接触到SuperTrend,第一眼就被它的简洁吸引了。整个指标就两条线、两种状态:上涨趋势和下跌趋势。没有像MACD一样的金叉死叉,没有像RSI一样的超买超卖,就是这么直接。
更关键的是,SuperTrend是基于ATR(平均真实波幅)计算的,天然就考虑了市场波动。在高波动环境下自动放宽止损距离,低波动时自动收紧。这种自适应特性,是很多传统指标做不到的。
这篇文章,我们就来深入解码SuperTrend。不会讲得太复杂,就讲它的核心原理、计算方法、使用技巧,以及如何把它做成一个既美观又实用的可视化指标。
SuperTrend,中文叫"超级趋势",是由Olivier Seban开发的趋势跟踪指标。它的核心思想非常简单:用ATR来动态设置止损位,形成一条自适应的趋势线。
你可以把SuperTrend理解成一个"会移动的止损线":
很多人会问:这不就是移动均线吗?
其实不是。均线是基于历史价格的平均值,反应总是滞后的。而SuperTrend是基于波动率(ATR)计算的,它考虑的是市场的波动特征,而不仅仅是价格本身。
举个例子:
这种自适应的特性,是SuperTrend最大的优势。
SuperTrend天生就是为趋势交易设计的:
所以SuperTrend适合做中长线的趋势跟踪,不太适合短线高频交易。
SuperTrend的计算分两步:先算基础带,再算最终趋势线。
ATR是SuperTrend的基础,它衡量市场的波动性。
# ATR计算很简单
def calculate_atr(bars, period=14):
"""
计算ATR
真实波幅 = max(最高价-最低价, abs(最高价-昨收), abs(最低价-昨收))
ATR = 真实波幅的移动平均
"""
high = [bar.high_price for bar in bars]
low = [bar.low_price for bar in bars]
close = [bar.close_price for bar in bars]
atr = talib.ATR(high, low, close, timeperiod=period)
return atr
ATR的意义:
SuperTrend有上轨和下轨两条带:
def calculate_supertrend_bands(bars, atr, multiplier=3.0):
"""
计算SuperTrend的基础带
基本带 = (最高价 + 最低价) / 2
上轨 = 基本带 - (ATR × 乘数)
下轨 = 基本带 + (ATR × 乘数)
"""
basic_band = [(bar.high_price + bar.low_price) / 2 for bar in bars]
upper_band = [basic_band[i] - (atr[i] * multiplier)
for i in range(len(bars))]
lower_band = [basic_band[i] + (atr[i] * multiplier)
for i in range(len(bars))]
return upper_band, lower_band
这里的**乘数(multiplier)**通常设为3.0,这是个经验值:
有了上下轨,还需要判断当前是上涨趋势还是下跌趋势:
def calculate_supertrend(bars, upper_band, lower_band):
"""
计算最终的SuperTrend线和趋势方向
逻辑:
1. 收盘价突破上轨 → 转为上涨趋势,跟踪下轨
2. 收盘价跌破下轨 → 转为下跌趋势,跟踪上轨
3. 趋势不变时,趋势线只能向趋势方向移动,不能回头
"""
supertrend = []
direction = []
current_trend = "Down Trend"# 初始假设为下跌
for i, bar in enumerate(bars):
close = bar.close_price
# 第一根K线
if i == 0:
supertrend.append(upper_band[i])
direction.append(current_trend)
continue
# 判断趋势转换
if current_trend == "Down Trend":
# 如果收盘价突破上轨,转为上涨趋势
if close > supertrend[i-1]:
current_trend = "Up Trend"
supertrend.append(lower_band[i])
else:
# 继续下跌趋势,上轨只能向下,不能向上
supertrend.append(min(upper_band[i], supertrend[i-1]))
else: # Up Trend
# 如果收盘价跌破下轨,转为下跌趋势
if close < supertrend[i-1]:
current_trend = "Down Trend"
supertrend.append(upper_band[i])
else:
# 继续上涨趋势,下轨只能向上,不能向下
supertrend.append(max(lower_band[i], supertrend[i-1]))
direction.append(current_trend)
return supertrend, direction
关键点:
理解了计算原理,使用起来就很简单了。
SuperTrend最直接的用法就是判断趋势方向:
上涨趋势(Up Trend):价格在SuperTrend上方
下跌趋势(Down Trend):价格在SuperTrend下方
def generate_signal(close_price, supertrend_value, trend_direction):
"""
生成交易信号
"""
if trend_direction == "Up Trend":
return "做多", f"止损位: {supertrend_value:.2f}"
else:
return "做空", f"止损位: {supertrend_value:.2f}"
当趋势发生转换时,就是入场信号:
def detect_trend_change(prev_direction, current_direction,
close_price, supertrend_value):
"""
检测趋势反转信号
"""
signal = None
# 从下跌转为上涨 = 买入信号
if prev_direction == "Down Trend"and current_direction == "Up Trend":
signal = {
'type': 'BUY',
'price': close_price,
'stop_loss': supertrend_value,
'description': '趋势反转向上,买入信号'
}
# 从上涨转为下跌 = 卖出信号
elif prev_direction == "Up Trend"and current_direction == "Down Trend":
signal = {
'type': 'SELL',
'price': close_price,
'stop_loss': supertrend_value,
'description': '趋势反转向下,卖出信号'
}
return signal
在我们的实现中,还加入了波动率分析:
def analyze_volatility(current_atr, atr_ma, threshold=1.5):
"""
分析波动率状态
通过当前ATR与ATR均值的比较,判断波动状态
"""
ratio = current_atr / atr_ma
if ratio >= threshold:
return "High Volatility", "市场波动剧烈,谨慎交易"
elif ratio <= 0.7:
return "Low Volatility", "市场波动平缓,可能突破"
else:
return "Normal Volatility", "正常波动"
实战意义:
在ATMQuant系统中,我们对SuperTrend做了精心的可视化设计。
颜色区分趋势:
填充区域:
信息提示:
def _draw_bar_picture(self, ix: int, bar: BarData) -> QtGui.QPicture:
"""绘制SuperTrend指标"""
picture = QtGui.QPicture()
painter = QtGui.QPainter(picture)
# 获取数据
supertrend_direction = getattr(bar, 'supertrend_direction', None)
supertrend_high = getattr(bar, 'supertrend_high', None)
supertrend_low = getattr(bar, 'supertrend_low', None)
# 获取下一根K线数据(用于画线)
next_bar = self._manager.get_bar(ix + 1)
if next_bar isNone:
painter.end()
return picture
# 下跌趋势:绘制红色上轨和填充区
if supertrend_direction == "Down Trend"and supertrend_high isnotNone:
next_high = getattr(next_bar, 'supertrend_high', None)
if next_high isnotNone:
# 绘制红色虚线
pen = pg.mkPen(color="red", width=2, style=QtCore.Qt.DotLine)
painter.setPen(pen)
painter.drawLine(
QtCore.QPointF(ix, float(supertrend_high)),
QtCore.QPointF(ix + 1, float(next_high))
)
# 填充K线低点到上轨的区域(浅红色)
if ix > 0:
prev_bar = self._manager.get_bar(ix - 1)
if prev_bar:
prev_high = getattr(prev_bar, 'supertrend_high', None)
prev_low = prev_bar.low_price
if prev_high isnotNone:
# 绘制填充区域
path = QtGui.QPainterPath()
path.moveTo(ix - 1, float(prev_low))
path.lineTo(ix, float(bar.low_price))
path.lineTo(ix, float(supertrend_high))
path.lineTo(ix - 1, float(prev_high))
path.closeSubpath()
painter.setPen(pg.mkPen(None))
painter.setBrush(QtGui.QColor(255, 9, 7, 50)) # 浅红色
painter.drawPath(path)
# 上涨趋势:绘制绿色下轨和填充区
elif supertrend_direction == "Up Trend"and supertrend_low isnotNone:
next_low = getattr(next_bar, 'supertrend_low', None)
if next_low isnotNone:
# 绘制绿色虚线
pen = pg.mkPen(color="green", width=2, style=QtCore.Qt.DotLine)
painter.setPen(pen)
painter.drawLine(
QtCore.QPointF(ix, float(supertrend_low)),
QtCore.QPointF(ix + 1, float(next_low))
)
# 填充下轨到K线高点的区域(浅绿色)
if ix > 0:
prev_bar = self._manager.get_bar(ix - 1)
if prev_bar:
prev_low = getattr(prev_bar, 'supertrend_low', None)
prev_high = prev_bar.high_price
if prev_low isnotNone:
# 绘制填充区域
path = QtGui.QPainterPath()
path.moveTo(ix - 1, float(prev_low))
path.lineTo(ix, float(supertrend_low))
path.lineTo(ix, float(bar.high_price))
path.lineTo(ix - 1, float(prev_high))
path.closeSubpath()
painter.setPen(pg.mkPen(None))
painter.setBrush(QtGui.QColor(44, 238, 44, 50)) # 浅绿色
painter.drawPath(path)
painter.end()
return picture
设计要点:
def get_info_text(self, ix: int) -> str:
"""获取SuperTrend信息文本"""
bar = self._manager.get_bar(ix)
ifnot bar:
return"SuperTrend - 数据不足"
supertrend_high = getattr(bar, 'supertrend_high', 0)
supertrend_low = getattr(bar, 'supertrend_low', 0)
direction = getattr(bar, 'supertrend_direction', '')
volatility = getattr(bar, 'volatility_state', '')
atr = getattr(bar, 'current_atr', 0)
ifnot supertrend_high:
return"SuperTrend - 数据不足"
text = f"SuperTrend High: {supertrend_high:.2f}\n"
text += f"SuperTrend Low: {supertrend_low:.2f}\n"
text += f"Direction: {direction}\n"
text += f"Volatility: {volatility}\n"
text += f"ATR: {atr:.2f}"
return text
这样,鼠标悬停在任何一根K线上,都能看到完整的SuperTrend信息。
说几个实际用的时候遇到的坑和经验。
首先是参数选择的问题。SuperTrend有两个关键参数:ATR周期和乘数。
默认参数是ATR周期14、乘数3.0。这是Olivier Seban原始设定,也是用得最广的参数。刚开始我想优化一下参数,测试了十几组不同的组合。结果发现,改来改去,还是默认参数最稳定。
不过话说回来,不同品种确实需要微调。活跃品种像螺纹钢、铁矿石,可以考虑用较大的乘数(3.5-4.0),因为日内波动大,太小的乘数容易被假突破欺骗。而一些冷门品种,波动本来就小,可以用较小的乘数(2.5-3.0),让信号更灵敏。
第二个坑是震荡市场的问题。SuperTrend在趋势市场中表现优秀,但在震荡市场里就比较难受了。
我回测过一段横盘整理的数据,SuperTrend的表现惨不忍睹。趋势反转信号频繁出现,但每次都是假突破,连续止损好几次。后来想明白了,SuperTrend本来就是趋势跟踪工具,不适合震荡市。
怎么办?最好的办法是结合其他指标判断市场状态。比如用ADX判断趋势强度,ADX大于25才考虑用SuperTrend;或者用布林带宽度,带宽收窄说明在震荡,这时候就少交易或不交易。
第三个是止损执行的问题。SuperTrend给出的止损位是动态的,会跟随价格移动。这就带来一个问题:止损位一直在变,到底该在哪里设置止损单?
我的做法是:入场时固定止损,持仓后用移动止损。
举个例子:趋势反转向上时买入,入场价是100,当时的SuperTrend在95。我会在95设置止损单。但持仓后,如果价格涨到110,SuperTrend也跟着涨到105,这时候我会把止损单移到105。止损只能向有利方向移动,不能向不利方向移动。
这种做法的好处是,既保护了利润,又不会因为短期回调被止损出场。
第四个经验是多周期验证。单一周期的SuperTrend信号不够可靠,最好看两个周期。
我现在的习惯是:5分钟图看入场时机,15分钟图看大趋势。只有15分钟的SuperTrend也是同向趋势时,才考虑在5分钟图上入场。这样做虽然机会少了,但胜率明显提高。
还有个细节。ATR周期的选择也很重要。默认是14,这是根据自然周期设定的(两周交易日)。但如果你做日内短线,14根5分钟K线只代表70分钟,可能太短了。这时候可以考虑用更长的ATR周期,比如20或30。
反过来,如果做日线级别,14日ATR可能反应太慢,可以考虑用7日或10日ATR,让指标更灵敏。
最后说个使用技巧:结合成交量使用效果更好。
当SuperTrend发出趋势反转信号时,如果同时伴随放量,这个信号的可靠性就大大提高了。反之,如果缩量突破,很可能是假信号。这也是为什么上一篇我要专门讲成交量分析,因为量价配合真的很重要。
到这里,SuperTrend的核心内容基本讲完了。从ATR波动率到自适应止损,从趋势判断到可视化设计,最重要的是理解SuperTrend的本质:它不是预测工具,而是趋势跟踪工具。
不要指望SuperTrend能提前告诉你趋势什么时候来,它只能告诉你趋势已经开始了,该上车了。也不要指望每次信号都能赚钱,趋势跟踪的精髓就是"小亏大赚":大部分时间在震荡中小亏,但抓住一次大趋势就能覆盖所有亏损还有盈利。
下一篇准备讲ZLEMA(零延迟趋势信号)。说实话,传统的EMA虽然好用,但总是有延迟。趋势已经走了一半,指标才开始反应。ZLEMA就是为了解决这个问题而生的,通过一套巧妙的算法,能把延迟降到接近于零。配合SuperTrend一起用,效果会更好。
先写到这,有问题欢迎留言交流。
本文是《量化指标解码》系列的第八篇,ATMQuant量化交易系统已开源至GitHub:https://github.com/seasonstar/atmquant
SuperTrend增强版指标为付费会员专享功能,加入知识星球即可获取完整源码和配置教程。
本文内容仅供学习交流,不构成任何投资建议。交易有风险,投资需谨慎。
想系统性掌握策略研发、指标可视化与回测优化?加入我的知识星球,获得持续、体系化的成长支持:
《量化指标解码》系列
《以AI量化为生》系列