python - 计算 smma(平滑移动平均线)

python - calculating smma (smoothed moving average)

我正在尝试在 Python 中编写 smma(平滑移动平均线)。我从 tradingview 中的 pine 脚本中获取公式。

smma =  0.0
smma := na(smma[1]) ? ta.sma(src, length) : (smma[1] * (length - 1) + src) / length

因此,当没有先前的 smma 值时,我们应该采用 (src,length) 的简单移动平均线。接下来的计算是根据 (smma[1] * (length - 1) + src) / length。 smmma[1] 是之前的 smma 值。

这是我的代码:

def smma(src, length):
    smma = 0.0
    dataLength = len(src)
    lookbackPeriod = dataLength - length

    #first value of smma is the sma of src and length
    #Convert list to dataframe
    df = pd.DataFrame(src, columns = ['hl2'])
    smma = df.rolling(window=length).mean()
    smma = float(smma.iloc[-1])
    log.info(f"First smma value = {smma}")

    lookbackPeriod = dataLength - length + 1 #calculate smma for the other values
    while (lookbackPeriod < dataLength):
        smma = (smma * (length - 1) + float(src[lookbackPeriod])) / length
        log.info(f"lookback = {lookbackPeriod} src[lookbackPeriod] = {src[lookbackPeriod]} smma = {smma}")
        lookbackPeriod = lookbackPeriod + 1
    return smma

周期长度为 5 的输出如下所示:

[2021-11-07 12:26:21,701] First smma value = 61842.0
[2021-11-07 12:26:21,701] lookback = 196 src[lookbackPeriod] = 61817.25 smma = 61837.05
[2021-11-07 12:26:21,701] lookback = 197 src[lookbackPeriod] = 61883.5 smma = 61846.340000000004
[2021-11-07 12:26:21,701] lookback = 198 src[lookbackPeriod] = 61867.75 smma = 61850.621999999996
[2021-11-07 12:26:21,702] lookback = 199 src[lookbackPeriod] = 61838.0 smma = 61848.0976

src 在我的例子中是一个包含 200 个值的列表。 当我将第一个 smma 的值与 sma 进行比较时,它与 Tradingview 上的值相比是正确的。与我在 Tradingview 上看到的相比,smma 的最终值不正确。 (我在这种情况下将其作为源 (high+low)/2 而不是收盘价,但是当我将其作为 Tradingview 中的源时它仍然无法正确显示)

有人能看出我做错了什么吗?

非常感谢!

最近我一直在为同样的问题而苦苦挣扎 - 通过我的代码计算的 SMMA 值与图表上的 TradingView 值。

问题是您可以找到各种计算 SMMA 的公式,例如:
chartmill.com
fxcorporate.com

老实说,到目前为止我无法获得准确的 TradingView 结果,但我发现 chartmill 结果最接近 TradingView 的结果。

我尝试在 Java 中实施 SMMA 作为 ta4j library 的扩展。请在下面找到我最近的结果。希望您觉得它有帮助,我们将一起找到正确的实施方式:

public class SMMAIndicator extends RecursiveCachedIndicator<Num> {

/**
 * N - Number of periods, over which the indicator is calculated.
 */
private final int barCount;
private final Num n;

/**
 * Usually ClosePriceIndicator
 */
private final Indicator<Num> indicator;

/**
 * SMA to calculate 1st SMMA period per index
 */
private final SMAIndicator smaIndicator;

public SMMAIndicator(Indicator<Num> indicator, int barCount) {
    super(indicator.getBarSeries());
    this.barCount = barCount;
    this.n = numOf(barCount);
    this.indicator = indicator;
    this.smaIndicator = new SMAIndicator(indicator, barCount);
}

@Override
public Num calculate(int index) {
    var i = max(0, index - barCount + 1);

    if (i == 0) {
        return smaIndicator.getValue(index);
    }

    if (i == 1) {
        var nMinus1 = n.minus(numOf(1));
        var smma0 = getValue(index - 1);
        var input = indicator.getValue(index);
        return smma0.multipliedBy(nMinus1).plus(input).dividedBy(n);
    }

    var prevSmma = getValue(index - 1);
    var prevSum = prevSmma.multipliedBy(n);
    return prevSum.minus(prevSmma).plus(indicator.getValue(index)).dividedBy(n);
}

}

我找到了解决办法。您只需要在足够大的样本量上进行计算。在我的例子中,计算周期为 5 的 smma 不应在 5 个数据点上 运行,但在 200 的大小上我有正确的值。 因此,计算前 5 个数据点的简单移动平均值,然后开始对剩余 195 个数据点进行 smma 计算。 smma 的最后一个值是与 Tradingview 中的值匹配的正确值。