用代码动态选择移动平均线类型
Pine Script提供了多种类型的移动平均线。通常,我们会选择某一种特定的平均线,并让指标或策略围绕它来构建。但实际上,我们完全可以编写一个能够自主选择移动平均线类型的脚本。接下来,就让我们在Pine Script中实现这一功能。
自定义函数
要让Pine Script能够根据我们的指令选择移动平均线,最简单的方法是使用一个字符串来指定要使用的平均线类型。然后,Pine Script会解析这个字符串,并计算出相应的移动平均线。
如果我们将这套逻辑封装在一个自定义函数中,未来就可以方便地在其他脚本中复用。这样一个自定义函数如下所示:
// MovAvgType() 函数根据给定的类型、数据源和周期,
// 返回计算出的移动平均线。
// 如果给定的类型未知,它会在图表上显示一条错误信息。
MovAvgType(averageType, averageSource, averageLength) =>
switch str.upper(averageType)
"SMA" => ta.sma(averageSource, averageLength)
"EMA" => ta.ema(averageSource, averageLength)
"WMA" => ta.wma(averageSource, averageLength)
"HMA" => ta.hma(averageSource, averageLength)
"RMA" => ta.rma(averageSource, averageLength)
"SWMA" => ta.swma(averageSource)
"ALMA" => ta.alma(averageSource, averageLength, 0.85, 6)
"VWMA" => ta.vwma(averageSource, averageLength)
"VWAP" => ta.vwap(averageSource)
=> runtime.error("Moving average type '" + averageType +
"' not found!"), na
这个自定义的 MovAvgType() 函数有三个必需的参数。averageType 是一个文本值(字符串),用于指定移动平均线的种类。averageSource 定义了平均线计算所依据的数据源。averageLength 则定义了平均线的计算周期。
在函数内部,一个 switch 语句会解析 averageType 参数的值,并根据该值决定要计算哪种移动平均线。不同的选项如下:
"SMA":使用ta.sma()函数计算简单移动平均线 (Simple Moving Average)。"EMA":使用ta.ema()函数计算指数移动平均线 (Exponential Moving Average)。"WMA":使用ta.wma()函数计算加权移动平均线 (Weighted Moving Average)。"HMA":使用ta.hma()函数计算赫尔移动平均线 (Hull Moving Average)。"RMA":使用ta.rma()函数计算相对移动平均线 (Relative Moving Average)。"SWMA":使用ta.swma()函数计算对称加权移动平均线 (Symmetrically-Weighted Moving Average)。"ALMA":使用ta.alma()函数计算Arnaud Legoux移动平均线。(为了避免自定义函数的参数过于复杂,我们在这里将偏移量和sigma值硬编码为0.85和6。)"VWMA":使用ta.vwma()函数计算成交量加权移动平均线 (Volume-Weighted Moving Average)。"VWAP":使用ta.vwap()计算成交量加权平均价 (Volume-Weighted Average Price)。
函数在计算出其中一种平均线后,会返回其计算结果。调用 MovAvgType() 函数的脚本代码就可以像处理普通移动平均线一样来使用这个返回的数据。
值得注意的是,switch 语句首先使用了 str.upper() 函数将 averageType 参数转换为大写。这样一来,无论我们使用小写(”sma”)、混合大小写(”Sma”)还是大写(”SMA”)来指定类型,函数都能正确识别,使其更易于使用。
另外两个参数 averageSource 和 averageLength,则被函数用于计算所选定的移动平均线。
switch 语句的最后是一个默认分支。当 averageType 参数与任何预定义的类型都不匹配时,该分支就会执行。如果出现这种情况,就意味着我们使用了一个不被支持的移动平均线选项来调用 MovAvgType() 函数。
与其计算一个默认的平均线并假装它是我们想要的类型,我们选择调用 runtime.error() 函数来生成一条明确的错误信息。这会通知我们使用了不被支持的移动平均线类型。
现在,让我们看看脚本该如何使用这个自定义函数。
使用函数
在脚本中复制/粘贴了上述函数后,我们可以通过多种方式来使用它。
一种基本用法是直接使用一个字面量字符串来指定要计算哪种移动平均线。例如,如果我们想要一条指数移动平均线,可以这么写:
// 计算一条20周期的指数移动平均线
emaValue = MovAvgType("EMA", close, 20)
由于该函数返回的是一个序列值,因此其输出可以被另一个函数(包括 MovAvgType() 函数自身)再次处理。我们可以利用这一点来平滑一条移动平均线:
// 使用3周期的简单移动平均线来平滑15周期的相对移动平均线
smoothedMA = MovAvgType("SMA", MovAvgType("RMA", close, 15), 3)
当代码可以根据特定条件来决定使用哪种移动平均线时,这个自定义函数的真正威力就显现出来了。例如,假设我们想根据交易品种所在的交易所来选择均线类型,可以这么做:
// 对于在纳斯达克上市的交易品种,使用成交量加权移动平均线,
// 对于所有其他交易所的品种,则使用加权移动平均线
weightedMA = MovAvgType(syminfo.prefix == "NASDAQ" ? "vwma" : "wma", close, 80)
指标示例
接下来,让我们通过一个完整的脚本来看看如何使用这个自定义的 MovAvgType() 函数。下方的指标会在图表上绘制两条移动平均线。
第一条移动平均线的类型由交易品种的资产类别决定。对于加密货币,我们使用指数移动平均线;对于指数,使用相对移动平均线;而对于期货,则显示赫尔移动平均线。
第二条移动平均线的类型则取决于其所在的交易所。在纳斯达克(NASDAQ)交易的品种会使用成交量加权移动平均线,而在任何其他交易所上市的品种则使用加权移动平均线。
完整的指标代码如下:
//@version=5
indicator(title="Moving average type example", overlay=true)
// MovAvgType() 函数根据给定的类型、数据源和周期,
// 返回计算出的移动平均线。
// 如果给定的类型未知,它会在图表上显示一条错误信息。
MovAvgType(averageType, averageSource, averageLength) =>
switch str.upper(averageType)
"SMA" => ta.sma(averageSource, averageLength)
"EMA" => ta.ema(averageSource, averageLength)
"WMA" => ta.wma(averageSource, averageLength)
"HMA" => ta.hma(averageSource, averageLength)
"RMA" => ta.rma(averageSource, averageLength)
"SWMA" => ta.swma(averageSource)
"ALMA" => ta.alma(averageSource, averageLength, 0.85, 6)
"VWMA" => ta.vwma(averageSource, averageLength)
"VWAP" => ta.vwap(averageSource)
=> runtime.error("Moving average type '" + averageType +
"' not found!"), na
// 根据资产类别(加密货币、指数、期货)计算移动平均线
fastAverage = if syminfo.type == "crypto"
MovAvgType("EMA", close, 20)
else if syminfo.type == "index"
MovAvgType("RMA", close, 40)
else if syminfo.type == "futures"
MovAvgType("HMA", hlc3, 30)
// 对于纳斯达克市场的品种使用VWMA,其他市场则使用WMA
slowAverage = MovAvgType(syminfo.prefix == "NASDAQ" ? "vwma" : "wma",
close, 80)
// 在图表上绘制移动平均线
plot(fastAverage, color=color.blue, title="Fast Average")
plot(slowAverage, color=color.orange, title="Slow Average")
我们首先调用 indicator() 函数,它负责为脚本命名,并通过 overlay=true 将指标叠加到主图表的交易品种上。
然后,我们包含了上文讨论过的自定义函数 MovAvgType()。
接下来,我们获取第一条移动平均线:
// 根据资产类别(加密货币、指数、期货)计算移动平均线
fastAverage = if syminfo.type == "crypto"
MovAvgType("EMA", close, 20)
else if syminfo.type == "index"
MovAvgType("RMA", close, 40)
else if syminfo.type == "futures"
MovAvgType("HMA", hlc3, 30)
这个级联 if 语句会根据 syminfo.type 变量返回的交易品种资产类别,来选择三种移动平均线中的一种。
当资产类别为加密货币(“crypto”)时,我们让 MovAvgType() 计算一条20周期的指数移动平均线。如果交易品种是指数,则使用40周期的相对移动平均线。如果图上的品种既不是加密货币也不是指数,而是期货,那么 MovAvgType() 会返回一条30周期的赫尔移动平均线。
这个级联 if 语句还隐含了第四种情况:当交易品种不属于加密货币、指数或期货中的任何一种时,将不会计算任何移动平均线,此时我们创建的 fastAverage 变量会得到一个 na(不可用)值。
之后,我们选择第二条移动平均线:
// 对于纳斯达克市场的品种使用VWMA,其他市场则使用WMA
slowAverage = MovAvgType(syminfo.prefix == "NASDAQ" ? "vwma" : "wma",
close, 80)
slowAverage 变量的值可能是两种移动平均线之一,具体由条件运算符(?:) 来决定。该运算符会判断当前交易品种的数据源(即交易所)是否等于 “NASDAQ”。如果是,代码会选择计算成交量加权移动平均线 (“vwma”)。否则,对于任何不在纳斯达克交易的品种,条件运算符会选择使用加权移动平均线 (“wma”)。
请注意,这两种可能的平均线都使用相同的价格数据和周期;代码只决定均线的类型。我们使用小写字符串来指定均线类型,这完全没问题,因为我们已经让自定义的 MovAvgType() 函数不区分字母的大小写。
指标的最后一部分代码通过 plot() 函数将两条平均线显示在图表上。快周期均线显示为蓝色(color.blue),慢周期均线则使用 color.orange。由于我们没有设置绘图类型,Pine Script默认将它们绘制成常规的线图。
让我们看看它在图表上的样子。当我们将该指标添加到在CME交易的期货合约上时,它会显示一条30周期的赫尔移动平均线和一条80周期的加权移动平均线:
如果我们将图表切换到在NASDAQ交易的QQQ,这种交易所和交易品种的组合则只会让我们看到那条成交量加权移动平均线:
总结
Pine Script提供了多种移动平均线类型。switch 语句可以帮助我们决定使用哪种平均线。
这使得指标或策略能够基于某个真/假条件来动态选择移动平均线。




