动量指标-SMI(Squeeze Momentum Indicator)


算法流程

  1. 动量:对连续几日的最高最低值取平均值,然后与 sma 取平均值
  2. 取离合程度:用 close 减去这个值
  3. 拟合这个值:取线性回归(或ma)

pine 源码

最后取线性回归

study(shorttitle = "SQZMOM_LB", title="Squeeze Momentum Indicator", overlay=false)

length = input(20, title="BB Length")
mult = input(2.0,title="BB MultFactor")
lengthKC=input(20, title="KC Length")
multKC = input(1.5, title="KC MultFactor")

useTrueRange = input(true, title="Use TrueRange (KC)", type=bool)

// Calculate BB
source = close
basis = sma(source, length)
dev = multKC * stdev(source, length)
upperBB = basis + dev
lowerBB = basis - dev

// Calculate KC
ma = sma(source, lengthKC)
range = useTrueRange ? tr : (high - low)
rangema = sma(range, lengthKC)
upperKC = ma + rangema * multKC
lowerKC = ma - rangema * multKC

sqzOn  = (lowerBB > lowerKC) and (upperBB < upperKC)
sqzOff = (lowerBB < lowerKC) and (upperBB > upperKC)
noSqz  = (sqzOn == false) and (sqzOff == false)

val = linreg(source  -  avg(avg(highest(high, lengthKC), lowest(low, lengthKC)),sma(close,lengthKC)), 
            lengthKC,0)

bcolor = iff( val > 0, 
            iff( val > nz(val[1]), lime, green),
            iff( val < nz(val[1]), red, maroon))
scolor = noSqz ? blue : sqzOn ? black : gray 
plot(val, color=bcolor, style=histogram, linewidth=4)
plot(0, color=scolor, style=cross, linewidth=2)

python 源码

最后取 sma

class SqueezeMomentumIndicator(object):
    _length = 20
    _mult = 2.0
    _lengthKC = 20
    _lengthVal = 3
    _multKC = 1.5
    _useTrueRange = True

    def __init__(self, length, mult, lengthKC, lengthVal, multKC, useTrueRange, df):
        self._length = length
        self._mult = mult
        self._lengthKC = lengthKC
        self._lengthVal = lengthVal
        self._multKC = multKC
        self._useTrueRange = useTrueRange
        self._df = df

    def index(self):
        df = self._df.copy()
        df['source'] = df['Close']
        df['sma'] = df['source'].rolling(window=self._length).mean()
        df['basis'] = df['sma'].fillna(value=0)
        df['stdev'] = df['source'].rolling(window=self._length).std()
        df['dev'] = self._multKC * df['stdev']
        df['upperBB'] = df['basis'] + df['dev']
        df['lowerBB'] = df['basis'] - df['dev']

        df['ma'] = df['source'].rolling(window=self._lengthKC).mean()
        df['DailyRange'] = df['High'] - df['Low']
        df['HC'] = df['High'] - df['Close'].shift(1)
        df['CL'] = df['Close'].shift(1) - df['Low']
        df['HC'] = df['HC'].abs()
        df['CL'] = df['CL'].abs()
        df['tr'] = df[['DailyRange', 'HC', 'CL']].max(axis=1)
        df['range'] = df['tr'] if self._useTrueRange else df['DailyRange']

        df['rangema'] = df['range'].rolling(window=self._lengthKC).mean()
        df['upperKC'] = df['ma'] + df['rangema'] * self._multKC
        df['lowerKC'] = df['ma'] - df['rangema'] * self._multKC

        df['sqzOn'] = df.apply(
            lambda item: item["lowerBB"] > item["lowerKC"] and item["upperBB"] < item["upperKC"], axis=1)
        df['sqzOff'] = df.apply(
            lambda item: item["lowerBB"] < item["lowerKC"] and item["upperBB"] > item["upperKC"], axis=1)

        df['highest'] = df['High'].rolling(window=self._lengthKC).max()
        df['lowest'] = df['Low'].rolling(window=self._lengthKC).min()
        df['avg_hl'] = df.apply(lambda item: (item['highest'] + item['lowest']) / 2, axis=1)
        df['sma_kc'] = df['Close'].rolling(window=self._lengthKC).mean()
        df['avg_hl_c'] = df.apply(lambda item: (item['avg_hl'] + item['sma_kc']) / 2, axis=1)
        df['s_avg_hl_c'] = df['source'] - df['avg_hl_c']
        df['val'] = df['s_avg_hl_c'].rolling(window=self._lengthVal).mean()

        df['val_1'] = df['val'].shift(1)
        df['val'] = df['val'].fillna(value=0)
        df['val_1'] = df['val_1'].fillna(value=0)

        df['color'] = df.apply(lambda item: 'lime' if item['val'] > 0 and item['val'] > item['val_1']
        else ('green' if item['val'] > 0 else ('red' if item['val'] < item['val_1'] else 'maroon')), axis=1)

        self._df['val'] = df['val']
        self._df['color'] = df['color']

        return self._df

文章作者: 钱不寒
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 钱不寒 !
  目录