保持敬畏之心
交易是一场持久战

Pine Script(141):三重指数移动平均线指标TEMA

#Pine Script入门教学

三重指数移动平均线指标(TEMA)

在一个明确的趋势中,几乎没有哪个指标能比移动平均线表现得更好。但有些均线存在严重的市场滞后问题,这导致我们在开仓或平掉亏损仓位时浪费宝贵的时间。接下来,让我们看看三重指数移动平均线(Triple Exponential Moving Average, TEMA)是如何旨在完全消除价格滞后的。

使用三重指数移动平均线(TEMA)消除滞后

移动平均线是一种广受欢迎的交易工具,用于识别趋势的开始和结束。它们是市场的“追随者”而非“预测者”的趋势跟踪指标。

由于移动平均线是对历史数值进行平均,它不可避免地会滞后于最新的价格。当价格突然飙升或新趋势启动时,移动平均线总是会延迟发出这种动量变化的信号。当趋势持续时间不长时,这种滞后尤其令人沮丧,因为此时快速行动就显得更为重要。

多年来,人们开发了多种响应更快的移动平均线。三重指数移动平均线(TEMA)就是其中之一。该指标建立在指数移动平均线的基础上,但其构建方式极大地减少了滞后性。这使得TEMA的响应速度比其他旨在减少滞后的均线(如双指数移动平均线(DEMA))更快。

理论上,更少的均线滞后能让我们更快地入市和离市,从而获得更多利润(或更小的亏损)。但消除滞后并不总是一件好事,因为价格滞后同时也过滤掉了市场的噪音。

因此,虽然滞后会导致交易信号变慢,但滞后性均线产生的信号质量可能更高。所以,使用三重指数移动平均线的挑战在于,既要让它足够快以产生及时的信号,又要让它足够慢以避免我们交易市场噪音。

让我们更深入地了解TEMA指标。之后,我们将在TradingView Pine中对其进行编程。

计算三重指数移动平均线(TEMA)

如上所述,TEMA基于指数移动平均线,但它并非简单的对EMA进行EMA计算,因为那仍会引入价格滞后。相反,TEMA使用了一个更复杂的公式,它实际上减去了一部分滞后。

下面是我们如何计算TEMA的公式:

  • EMA1 是一个常规的指数移动平均线 (EMA)。
  • EMA2 是对 EMA1 进行一次EMA计算。
  • EMA3 是对 EMA2 进行一次EMA计算。(即对EMA进行EMA再进行EMA计算。)

用通俗的话来说,我们首先将一条常规的EMA乘以3。然后,我们对一条EMA再进行一次平滑处理(即EMA of EMA),并将结果也乘以3。接着,我们将前两个值相减,最后再加上一个三重EMA的值(即EMA of EMA of EMA)。

如何使用三重指数移动平均线进行交易

我们使用三重指数移动平均线(TEMA)指标的方法与使用常规移动平均线类似,这为我们提供了多种使用方式。

第一种方法是用TEMA来确认趋势。当价格位于该均线上方时,我们可以将其视为上升趋势的确认;而当价格移动到TEMA下方时,则是市场疲软的信号。

价格穿越TEMA线是趋势变化的信号。因此,当价格向上穿越均线时,会产生一个看涨信号;当它们收盘于均线下方时,则是看跌的迹象。

第三种交易方法是在图表上绘制两条TEMA线。然后我们观察均线的交叉情况。这样,当快周期TEMA向上穿越慢周期TEMA时,产生买入信号,反之亦然。

第四种选择是将TEMA用作动态的支撑和阻力区域。这之所以有效,是因为移动平均线是趋势的平滑版本。所以在上涨市场中,我们可以预期价格回调会在移动平均线区域找到支撑;而在下跌市场中,短期反弹则会在均线附近遇到阻力。此外,价格触及移动平均线的次数越多,当该均线最终被突破时,其意义就越大。

将TEMA指标编写为TradingView Pine脚本

现在,让我们把注意力转向为TradingView编写三重指数移动平均线的代码。以下是我们准备在脚本中实现的功能:

  • 我们将使用输入选项来设置TEMA的周期。但图表上的多条均线有时只会增加噪音,所以当周期被设为零时,脚本会自动关闭该线条的显示。
  • 为了观察市场趋势,我们会将均线涂成绿色(上升趋势)、红色(下降趋势)或黄色(盘整市场)。我们用TEMA的值来确定趋势方向,并提供一个设置来启用或禁用这些趋势颜色。
  • 我们将用一个绘制的图形来高亮显示金叉和死叉,以便能轻松看到信号发生的确切K线。(同样会有一个输入选项来禁用这些信号。)
  • 我们还会为这些交叉生成警报。这样,即使我们不在市场旁边,也能收到交易机会的通知。

用于编写TradingView指标的模板

要将上述功能转化为实际的TradingView代码,一个有效的方法是使用模板。这能提供一些结构,并将任务分解成更小的部分。

这是我们将用于TEMA指标的模板:

//@version=5
// 步骤一:脚本设置
// 步骤二:计算指标数值
// 步骤三:确定指标信号
// 步骤四:输出指标数据
// 步骤五:创建指标警报

如果你想跟着本文一起操作,请在TradingView的Pine编辑器中创建一个新的指标脚本,并粘贴以上模板。(如果你只想要完整的代码,可以直接滚动到本文末尾。)

为了让你对我们即将编写的代码有个直观的印象,下图是最终完成的TEMA指标在图表上的样子:

现在,就让我们开始吧!

步骤一:设置指标参数与输入选项

我们首先来定义指标的各项属性。为此,我们调用 indicator() 函数:

//@version=5
// 步骤一:脚本设置
indicator(title="Triple Exponential Moving Average (TEMA)",
     shorttitle="TEMA", overlay=true)

这里,我们让该函数定义脚本的名称(title)及其缩写名称(shorttitle),后者会显示在图表上。overlay 参数则让指标能够直接叠加显示在主图表的交易品种上。

接着,我们创建几个输入选项,以便能够方便地配置指标的参数。第一个设置用于定义我们使用的价格数据:

// 输入选项
// 用于计算TEMA的数据源
srcData = input.source(close, title="Source Data")

我们使用 input.source() 函数创建了一个数据源输入选项。该输入会生成一个下拉菜单,其中包含多种价格数据,如收盘价、最高价和开盘价。

我们将其默认值设为收盘价(close),并使用 srcData 变量来追踪其当前值。

然后,我们为TEMA的周期创建选项:

// TEMA周期
temaLen1 = input.int(20, title="Length TEMA #1")
temaLen2 = input.int(0, title="Length TEMA #2", minval=0)

我们在这里创建的两个设置都是整数输入选项(input.int())。第一个,“Length TEMA #1”,指定了第一条TEMA线所使用的周期数,其默认值为20。

第二个长度选项,“Length TEMA #2”,初始值为零。根据我们稍后将要编写的代码,这个值会禁用第二条线。该输入的最小值(minval)也为零,这样用户就不必尝试输入负值来禁用这条均线了。

在脚本的后续部分,我们将通过 temaLen1temaLen2 这两个变量来引用这些输入的值。

最后两个设置影响指标的视觉外观:

// 外观设置
showArrows  = input.bool(true, title="Show Arrows?")
colourLines = input.bool(true, title="Colour Lines?")

这两个设置都是使用 input.bool() 函数创建的布尔型(真/假)输入选项。第一个,“Show Arrows?”(显示箭头?),默认开启(true)。当它被启用时,我们的指标将绘制箭头来高亮显示移动平均线的交叉。

另一个输入,“Colour Lines?”(为线条着色?),也默认开启(true)。它定义了指标是否应该根据趋势为TEMA线进行着色。

我们使用 showArrowscolourLines 变量来追踪这些输入项的当前值。

步骤二:计算指标数值

在第二步中,我们计算三重指数移动平均线的值。由于我们需要计算两次(每条TEMA线各一次),因此先创建一个自定义函数会更方便,这能避免我们重复编写相同的代码。

首先,我们创建一个计算TEMA的函数:

// 步骤二:计算指标数值
TEMA(series, length) =>
    if length > 0
        ema1 = ta.ema(series, length)
        ema2 = ta.ema(ema1, length)
        ema3 = ta.ema(ema2, length)
        (3 * ema1) - (3 * ema2) + ema3
    else
        na

我们创建的 TEMA() 函数有两个参数:serieslength。前者指定了函数处理的数据,后者则是计算TEMA所用的K线数量。

在函数内部,我们有一个 if/else 语句。if 部分会检查 length 是否大于0。当TEMA线被配置为需要显示在图表上时,就会满足此条件。(回想一下,根据我们的输入选项,周期为0会禁用该线条。)

当我们得到一个非零的周期时,我们首先使用 ta.ema() 函数计算一个指数移动平均线(EMA)。该函数基于 series 数据和 length 周期进行计算,我们将结果存储在 ema1 变量中。

然后,我们计算第二个EMA。这次计算是基于第一个EMA的结果(ema1),并使用相同的周期(length)。我们用这个均线来计算第三个EMA,它则基于 ema2 变量的值进行计算。

完成这些计算后,我们就有足够的数据来确定三重指数移动平均线了。为此,我们首先将 ema1 变量乘以3,然后对 ema2 做同样的操作。我们将这两个结果相减,最后再加上双重平滑后的均线(ema3)。这就得到了TEMA,其值由 TEMA() 自定义函数返回。

函数的 else 代码块在均线周期为0或更小时执行。当我们通过将输入选项设为零来禁用某条TEMA线时,就会发生这种情况。此时,我们不必计算移动平均线,而是直接返回 na

na 值只是一个缺失值的占位符。na 的一个好处是它不会在图表上显示任何内容。因此,当指标接下来绘图时,被禁用的TEMA线就不会出现在图表上。通过这种方式,将输入选项设为0实际上就关闭了该线条的绘制。

但首先,我们使用这个自定义函数来计算TEMA的值:

// 计算TEMA值
temaVal1 = TEMA(srcData, temaLen1)
temaVal2 = TEMA(srcData, temaLen2)

我们在这里创建的两个变量 temaVal1temaVal2,从我们刚刚编写的 TEMA() 自定义函数中获取它们的值。

我们对两者使用相同的价格数据:srcData,即我们早先默认设置为收盘价的输入选项变量。对于TEMA的周期,我们使用 temaLen1temaLen2 这两个输入变量。其中第一个的默认值为20,另一个则从零开始。

步骤三:确定指标的买卖交易信号

有了TEMA值,我们现在就可以判断是否发生了交易信号。在第三步中,我们将编写四种信号的逻辑:

  • 价格上穿TEMA时的看涨信号。
  • 价格下穿TEMA时的看跌信号。
  • 价格或均线处于上升趋势时的上升趋势信号。
  • 价格或均线显现弱势时的下降趋势信号。

首先,我们来寻找看涨信号:

// 步骤三:确定指标信号
// 检查看涨信号
temaCrossover = if temaLen2 > 0
    ta.crossover(temaVal1, temaVal2)
else
    ta.crossover(srcData, temaVal1)

我们在这里创建的 temaCrossover 变量通过一个 if/else 语句来获取其布尔值(true/false)。if 条件会检查 temaLen2 输入变量是否大于0。如果是,我们就假定两条TEMA线都显示在图表上。(毕竟,第一条线的周期默认已经是20。)

在这种情况下,我们将两条TEMA线的交叉视为一个买入信号。为了判断交叉是否发生,我们执行 ta.crossover() 函数,并将 temaVal1temaVal2 变量作为其参数。当第一条TEMA线上穿第二条时,该函数返回 true,否则返回 false。这个返回值随后被存入 temaCrossover 变量,供脚本后续使用。

如果第二条TEMA不显示,if/else 语句的 else 代码块就会执行。在那里,我们也使用 ta.crossover(),但这次我们判断的是用户配置的价格数据(srcData)是否上穿了第一条TEMA线。如果是,temaCrossover 变量的值就为 true(否则为 false)。

接下来,我们编写寻找看跌信号的TradingView代码:

// 判断TEMA是否触发了看跌信号
temaCrossunder = if temaLen2 > 0
    ta.crossunder(temaVal1, temaVal2)
else
    ta.crossunder(srcData, temaVal1)

这段代码与看涨信号的逻辑非常相似。我们通过一个 if/else 语句首先判断 temaLen2 输入变量是否大于0。

如果是,我们就让 ta.crossunder() 函数判断第一条TEMA线是否下穿了第二条。如果交叉发生,我们创建的 temaCrossunder 变量就变为 true(否则为 false)。

如果第二条TEMA线未在图表上显示,else 代码块同样会使用 ta.crossunder(),但这次我们判断的是价格(srcData)是否跌破了第一条均线(temaVal1)。在这种情况下,temaCrossunder 变量的值为 true,否则为 false

第三个信号是判断TEMA是否处于上升趋势。下面是我们的判断方法:

// 确定TEMA的趋势
// 价格(及慢速均线)位于TEMA上方的上升趋势
uptrend = if temaLen2 > 0
    close > temaVal1 and temaVal1 > temaVal2
else
    close > temaVal1 and temaVal1 > temaVal1[1]

我们判断上升趋势的方式取决于图表上显示的是一条还是两条TEMA线。因此,if/else 语句首先会检查 temaLen2 是否大于0。如果是,我们就假定两条线都处于激活状态。

在这种情况下,要定义为上升趋势,我们要求K线收盘于第一条TEMA线上方(close > temaVal1),并且第一条TEMA线也位于第二条线上方(temaVal1 > temaVal2)。当这两个条件同时满足时(and),我们创建的 uptrend 变量的值为 true(否则为 false)。

如果第二条TEMA未在图表上显示,else 代码块就会执行。在那里,我们判断收盘价是否高于第一条TEMA线,并且要求TEMA的值相比前一根K线有所上升(temaVal1 > temaVal1[1])。当这些条件都满足时,uptrend 变量的值为 true(否则为 false)。

第四个也是最后一个信号是下降趋势。下面是我们的判断方法:

// 价格(及慢速均线)位于TEMA下方的下降趋势
downtrend = if temaLen2 > 0
    close < temaVal1 and temaVal1 < temaVal2
else
    close < temaVal1 and temaVal1 < temaVal1[1]

这段代码与前一个片段非常相似。downtrend 变量通过一个 if/else 语句获取其布尔值。

if 条件判断第二条TEMA线是否显示在图表上(temaLen2 > 0)。在这种情况下,需要满足两个要求我们才称之为下降趋势:第一,K线收盘于第一条TEMA线下方(close < temaVal1);第二,第一条TEMA线位于第二条线下方(temaVal1 < temaVal2)。这两个条件结合起来使得 downtrend 变量为 true(否则其值为 false)。

当第二条TEMA线未激活时,else 代码块会执行。该场景下,我们判断价格K线是否收盘于第一条TEMA线下方,并且该线的值是否相比上一根K线有所下降(temaVal1 < temaVal1[1])。如果是,downtrend 的值为 true,否则为 false

步骤四:绘制指标的数据与信号

接下来,我们输出指标的数据。这一步包含几项任务:确定线条颜色、绘制TEMA线,以及在图表上显示交易信号。

首先,我们来确定要使用哪种线条颜色:

// 步骤四:输出指标数据
// 确定线条颜色
lineColour = uptrend ? color.green :
     downtrend ? color.red :
     color.yellow

我们在这里创建的 lineColour 变量会被设为绿色、红色或黄色之一。具体得到哪种颜色取决于我们用两个条件运算符(?:)所评估的条件。

第一个运算符判断 uptrend 变量是否为 true。如果根据TEMA的判断确实处于上升趋势,我们就返回绿色(color.green)作为 lineColour 的值。否则,第二个条件运算符会执行。

那一个则判断 downtrend。如果该变量为 true,我们为线条颜色变量选择红色(color.red)。当既不是上升趋势也不是下降趋势时,我们使用黄色(color.yellow)来高亮显示盘整市场。

接下来,我们在图表上绘制三重指数移动平均线时使用这个线条颜色:

// 在图表上绘制TEMA线
plot(temaVal1, color=colourLines ? lineColour : color.orange,
     linewidth=2, title="TEMA #1")
plot(temaVal2, color=colourLines ? lineColour : color.teal,
     linewidth=2, title="TEMA #2")

第一个 plot() 语句显示第一条TEMA线(temaVal1)。这些值以常规线图的形式显示,并且通过 linewidth 设为2,使线条比默认的更粗一些。

对于线条的颜色,我们首先评估一个条件。这次,条件运算符(?:)会检查 colourLines 是否为 true。该输入变量的值对应于“Colour Lines?”(为线条着色?)输入选项。如果该选项被启用,我们就使用刚才确定的 lineColour 变量作为颜色。

当该输入被关闭时,我们默认使用橙色(color.orange)。通过这种方式,我们使用该输入选项来启用或禁用带有趋势颜色的TEMA线。

第二个 plot() 语句与第一个非常相似。这次我们同样绘制一条线图,但对象是第二条TEMA线(temaVal2)。如果这条线的周期为零,temaVal2 变量的值就会是 na。这样的值会禁用绘图,所以我们不需要在这里实现额外的代码逻辑。

除了TEMA线,我们还在图表上显示它们的信号。我们使用 plotshape() 函数来编写该逻辑:

// 用上/下箭头高亮TEMA信号
plotshape(showArrows and temaCrossover,
     style=shape.arrowup, location=location.belowbar,
     size=size.normal, color=color.green)
plotshape(showArrows and temaCrossunder,
     style=shape.arrowdown, location=location.abovebar,
     size=size.normal, color=color.red)

第一个 plotshape() 语句负责在价格K线下方(location.belowbar)显示绿色(color.green)的向上箭头(shape.arrowup)。当然,我们不希望在每根K线上都显示这些形状,因此我们使用该函数的第一个参数来设置一个显示条件。

向上箭头显示之前需要满足两个要求:

  1. showArrows:这是一个输入变量,其值来自“Show Arrows?”输入选项。当该选项被启用时,showArrowstrue(否则为 false)。
  2. temaCrossover:我们之前创建的变量,当价格或快周期TEMA上穿慢周期TEMA时,其值为 true

因为我们使用 and 运算符连接这两个变量,所以它们必须同时为 true,绘制的形状才会出现在图表上。

第二个 plotshape() 语句与第一个非常相似。它在 showArrows 输入变量被启用(true并且 temaCrossunder 变量也为 true 时绘制。当价格或快周期TEMA跌破慢周期TEMA时,后一个条件会满足。

当这两个条件都成立时,我们在价格K线上方(location.abovebar)显示一个红色(color.red)的向下箭头(shape.arrowdown)。

步骤五:为指标添加警报条件

在最后一步中,我们来编写警报条件。这样,即使我们没有盯着市场,三重指数移动平均线指标也能通知我们。

为了添加该功能,我们使用 alertcondition() 函数,如下所示:

// 步骤五:创建指标警报
alertcondition(condition=temaCrossover,
     title="Crossover",
     message="Close (or fast TEMA) crossed over TEMA")

alertcondition(condition=temaCrossunder,
     title="Crossunder",
     message="Close (or fast TEMA) crossed under TEMA")

第一个语句基于 temaCrossover 变量创建了一个警报条件。之前我们设定,当价格或一条TEMA线上穿另一条(更慢的)TEMA线时,该变量的值为 true。当这种情况发生时,这个标题为Crossover(金叉)的警报就会激活。我们通过 message 参数为该情况提供了一条标准的描述信息。

第二个 alertcondition() 语句与第一个非常相似,但它是基于 temaCrossunder 变量来触发的。当价格或一条TEMA线下穿另一条(更慢的)TEMA线时,该变量为 true。如果发生这种情况,这个Crossunder(死叉)警报就会激活,并通过标准文本(message)告知发生了这样的下穿。

请注意,即使我们编写了这些警报条件,它们也不会自动触发。相反,我们需要在将指标添加到图表后,在TradingView的“创建警报”窗口中手动激活并配置它们。没有这个额外的步骤,TEMA指标是无法生成警报的。

在图表上绘制TEMA指标

现在我们完成了三重指数移动平均线指标的编码,让我们看看它在图表上的表现。与其他移动平均线一样,TEMA在市场趋势明显时表现得尤为出色。

下面的英国原油(UKOIL)日内图就是一个例子。在第二根K线上,TEMA产生了一个卖出信号。几小时后,这个原油差价合约的价格大幅下跌,每桶获利$3:

在下面的亚马逊股票图表上,两条TEMA线成功地识别出了一波强劲的上升趋势。第三根K线上的买入信号恰好在趋势启动后不久发生。倒数第二根K线上的卖出信号(事后看来)则接近这波上涨的顶部。更值得一提的是,价格曾多次在75周期的TEMA值附近找到支撑:

TEMA忠于其趋势跟踪的本性,在价格横盘整理时表现不佳。下面的以太坊图表就是一个例子。在这里,指标产生了数个买卖信号,但价格并没有真正朝任何方向发展。当我们遇到这样的市场状况时,最好将TEMA与其他指标结合使用,以减少假信号。

双指数移动平均线(DEMA) 是对流行的指数移动平均线的另一种改良。后者使用两条而非三条移动平均线,这使得它比TEMA稍慢一些,但同时也过滤掉了更多的市场噪音。

完整代码:适用于TradingView的三重指数移动平均线(TEMA)指标

三重指数移动平均线指标的完整代码如下。更多信息和细节,请参阅上文的代码讨论。

//@version=5
// 步骤一:脚本设置
indicator(title="Triple Exponential Moving Average (TEMA)",
     shorttitle="TEMA", overlay=true)

// 输入选项
// 用于计算TEMA的数据源
srcData = input.source(close, title="Source Data")

// TEMA周期
temaLen1 = input.int(20, title="Length TEMA #1")
temaLen2 = input.int(0, title="Length TEMA #2", minval=0)

// 外观设置
showArrows  = input.bool(true, title="Show Arrows?")
colourLines = input.bool(true, title="Colour Lines?")

// 步骤二:计算指标数值
TEMA(series, length) =>
    if length > 0
        ema1 = ta.ema(series, length)
        ema2 = ta.ema(ema1, length)
        ema3 = ta.ema(ema2, length)
        (3 * ema1) - (3 * ema2) + ema3
    else
        na

// 计算TEMA值
temaVal1 = TEMA(srcData, temaLen1)
temaVal2 = TEMA(srcData, temaLen2)

// 步骤三:确定指标信号
// 检查看涨信号
temaCrossover = if temaLen2 > 0
    ta.crossover(temaVal1, temaVal2)
else
    ta.crossover(srcData, temaVal1)

// 判断TEMA是否触发了看跌信号
temaCrossunder = if temaLen2 > 0
    ta.crossunder(temaVal1, temaVal2)
else
    ta.crossunder(srcData, temaVal1)

// 确定TEMA的趋势
// 价格(及慢速均线)位于TEMA上方的上升趋势
uptrend = if temaLen2 > 0
    close > temaVal1 and temaVal1 > temaVal2
else
    close > temaVal1 and temaVal1 > temaVal1[1]

// 价格(及慢速均线)位于TEMA下方的下降趋势
downtrend = if temaLen2 > 0
    close < temaVal1 and temaVal1 < temaVal2
else
    close < temaVal1 and temaVal1 < temaVal1[1]

// 步骤四:输出指标数据
// 确定线条颜色
lineColour = uptrend ? color.green :
     downtrend ? color.red :
     color.yellow

// 在图表上绘制TEMA线
plot(temaVal1, color=colourLines ? lineColour : color.orange,
     linewidth=2, title="TEMA #1")
plot(temaVal2, color=colourLines ? lineColour : color.teal,
     linewidth=2, title="TEMA #2")

// 用上/下箭头高亮TEMA信号
plotshape(showArrows and temaCrossover,
     style=shape.arrowup, location=location.belowbar,
     size=size.normal, color=color.green)
plotshape(showArrows and temaCrossunder,
     style=shape.arrowdown, location=location.abovebar,
     size=size.normal, color=color.red)

// 步骤五:创建指标警报
alertcondition(condition=temaCrossover,
     title="Crossover",
     message="Close (or fast TEMA) crossed over TEMA")
alertcondition(condition=temaCrossunder,
     title="Crossunder",
     message="Close (or fast TEMA) crossed under TEMA")
赞(0)
未经允许不得转载:图道交易 » Pine Script(141):三重指数移动平均线指标TEMA
分享到

评论 抢沙发

登录

找回密码

注册