2024.05.11 - [주가 분석/기술적 분석] - [기술적 분석] 지표/전략 : 스토캐스틱 슬로우(Stochastic Slow)
SMI (Stochastics Momentum Index, 스토캐스틱 모멘텀 지수)는 기본적인 개념은 스토캐스틱 오실레이터와 동일하다. 스토캐스틱 오실레이터는 관찰 기간 내의 최대값과 최소값 사이 현재 주가의 위치를 표시한다. 스토캐스틱 오실레이터는 최저가 대비 현재 가격의 위치를 표현하므로 항상 0 혹은 양의 값이 나오는데 SMI는 최대값과 최소값을 각각 100, -100으로 표현하고 이 사이 현재 주가를 표현하여 약세일 경우, 음수, 강세일 경우, 양수로 표현한다. 이때, 관찰 기간 내의 현재 현재 가격의 위치를 두 번 지수 이동 평균(Exponential Moving Average), 즉 DEMA(Double Exponential Moving Average)하고 이 값을 역시 두 번 지수 이동 평균한 최대값과 최소값의 범위로 나눈다. 이 값은 SMI로 사용하고 이것을 다시 지수 이동 평균하여 시그널 라인을 만들어 사용한다.
SMI는 스토캐스틱 오실레이터와 기본적으로 동일한 방식으로 계산되고, 표현하는 형식 역시 유사하기 때문에 스토캐스틱 오실레이터와 모양이 거의 유사하다. 하지만 별도의 지표로 존재하는 이유와 차이가 미비한 이 지표를 소개하는 이유는, 스토캐스틱 오실레이터는 가격 변화에 민감하여 허위시그널이 자주 발생하는데 비해 SMI는 그런 단점을 일부 보완한 지표이기 때문이다. 추가로 값을 양수와 음수로 표현하여 50을 기준으로 판단하던 스토캐스틱에 비해 좀 더 직관적이라는 것도 소소한 개선점이라고 할 수 있겠다.
매매 전략은 스토캐스틱 오실레이터와 동일하다. 단, 과매수, 과매도 구간을 판단할 때 40, -40을 기준으로 판단하는 것이 일반적이다. -40을 상향 돌파할 경우, 과매도로 보고 매수, 40을 하향 돌파할 경우 과매수로 보고 매도하는 전략이다.
SMI와 SMI의 이동평균선이 교차하는 시점을 추세전환으로 보고 매매에 임할 수도 있다. SMI가 SMI 이동 평균을 상향 돌파하면 매수, 반대로 SMI가 SMI 이동 평균을 하향 돌파하는 경우 매도를 하는 방식이다. 단 SMI의 경우, SMI와 SMI의 이동 평균이 스토캐스틱의 그것보다 좀 더 가깝게 붙어서 움직이다. 따라서 허위시그널이 스토캐스틱 오실레이터에 비해 훨씬 많이 발생할 수 있다.
이 외에, 다이버전스(Divergence)라고 해서 가격은 상승하나 SMI는 상승하지 못하고 하락하는 경우, 가격은 하락하나 SMI는 완만하게 상승하는 경우, 추세전환의 신호로 인식하기도 한다. 단, 다이버전스는 고점, 저점의 갱신을 사람이 눈으로 파악하는 방법 외에 시스템에 적용할 경우 정확히 파악하기 어려우며, 다이버전스 발생 후 얼마간의 시차를 두고 추세전환이 발생하는데, 이 지점을 특정하기 어려워 시스템 트레이딩에는 적용하기 어렵다는 단점이 있다.
마지막으로 트레이딩 뷰 파인 스크립트 소스를 공유하며 마친다.
- 스토캐스틱 모멘텀 지수 (SMI, Stochastics Momentum Index) 트레이딩 뷰 파인 스크립트 지표 소스
//@version=5
indicator(title="Stochastic Momentum Index", shorttitle="SMI", format=format.price, precision=2, timeframe="", timeframe_gaps=true)
import TradingView/ta/7 as ta7
import blackcat1402/pandas_ta/7 as pta
ma(source, length, _type) =>
switch _type
"SMA" => ta.sma(source, length)
"EMA" => ta.ema(source, length)
"DEMA" => ta7.dema(source,length)
"TEMA" => ta7.tema(source,length)
"FRAMA" => ta7.frama(source,length)
"T3" => ta7.t3(source,length)
"TRIMA" => ta7.trima(source,length)
"RMA" => ta.rma(source, length)
"WMA" => ta.wma(source, length)
"HMA" => ta.hma(source, length)
"VWMA" => ta.vwma(source * volume, length)
"ALMA" => pta.alma(source, length)
"JMA" => pta.jma(source, length)
"SINWMA" => pta.sinwma(source, length)
"FWMA" => pta.fwma(source, length)
"LINREG" => pta.linreg(source, length)
"SWMA" => pta.swma(source)
"YIDYA" => pta.vidya(source, length)
"VWAP" => pta.vwap(source)
"ZLMA" => pta.zlma(source, length)
srcInput = input(close, "Source")
periodKInput = input.int(10, title="%K Period", group="%K Settings", minval = 1)
smoothKInput = input.int(3, title="%K Smooth", group="%K Settings", minval = 1)
kmaTypeInput = input.string("DEMA", title="%K MA Type", options = ["SMA", "EMA", "DEMA", "TEMA", "FRAMA", "T3", "TRIMA", "RMA", "WMA", "HMA", "VWMA", "ALMA", "JMA", "SINWMA", "FWMA", "LINREG", "SWMA", "VIDYA", "VWAP", "ZLMA"], group="%K Settings", display = display.data_window)
smoothDInput = input.int(3, title="%D Smooth", group="%D Settings", minval = 1)
dmaTypeInput = input.string("DEMA", title="%D MA Type", options = ["SMA", "EMA", "DEMA", "TEMA", "FRAMA", "T3", "TRIMA", "RMA", "WMA", "HMA", "VWMA", "ALMA", "JMA", "SINWMA", "FWMA", "LINREG", "SWMA", "VIDYA", "VWAP", "ZLMA"], group="%D Settings", display = display.data_window)
upperInput = input.int(40, title="Upper", group="Band Settings")
lowerInput = input.int(-40, title="Lower", group="Band Settings")
highestHigh = ta.highest(periodKInput)
lowestLow = ta.lowest(periodKInput)
highestLowestRange = highestHigh - lowestLow
relativeRange = srcInput - (highestHigh + lowestLow) / 2
smi = 200 * (ma(relativeRange, smoothKInput, kmaTypeInput) / ma(highestLowestRange, smoothKInput, kmaTypeInput))
smiPlot = plot(smi, "SMI", color = color.blue)
plot(ma(smi, smoothDInput, dmaTypeInput), "SMI-based MA", color = color.orange)
upperBand = hline(upperInput, "Upper Band", color=color.gray)
hline(0, "Middle Band", linestyle=hline.style_dotted, color=color.gray)
lowerBand = hline(lowerInput, "Lower Band", color=color.gray)
fill(upperBand, lowerBand, title="Background", color=color.new(color.gray, 90))
midLinePlot = plot(0, color = na, editable = false, display = display.none)
fill(smiPlot, midLinePlot, 100, upperInput, top_color = color.green, bottom_color = color.new(color.green, 100), title = "Overbought Gradient Fill")
fill(smiPlot, midLinePlot, lowerInput, -100, top_color = color.new(color.red, 100), bottom_color = color.red, title = "Oversold Gradient Fill")
- 스토캐스틱 모멘텀 지수 (SMI, Stochastics Momentum Index) 트레이딩 뷰 파인 스크립트 전략 소스
//@version=5
strategy(title="Stochastic Momentum Index", shorttitle="SMI", margin_long=100, margin_short=100, default_qty_type=strategy.percent_of_equity, default_qty_value=50, commission_type=strategy.commission.percent, commission_value=0.2, pyramiding=0)
import TradingView/ta/7 as ta7
import blackcat1402/pandas_ta/7 as pta
ma(source, length, _type) =>
switch _type
"SMA" => ta.sma(source, length)
"EMA" => ta.ema(source, length)
"DEMA" => ta7.dema(source,length)
"TEMA" => ta7.tema(source,length)
"FRAMA" => ta7.frama(source,length)
"T3" => ta7.t3(source,length)
"TRIMA" => ta7.trima(source,length)
"RMA" => ta.rma(source, length)
"WMA" => ta.wma(source, length)
"HMA" => ta.hma(source, length)
"VWMA" => ta.vwma(source * volume, length)
"ALMA" => pta.alma(source, length)
"JMA" => pta.jma(source, length)
"SINWMA" => pta.sinwma(source, length)
"FWMA" => pta.fwma(source, length)
"LINREG" => pta.linreg(source, length)
"SWMA" => pta.swma(source)
"YIDYA" => pta.vidya(source, length)
"VWAP" => pta.vwap(source)
"ZLMA" => pta.zlma(source, length)
srcInput = input(close, "Source")
periodKInput = input.int(10, title="%K Period", group="%K Settings", minval = 1)
smoothKInput = input.int(3, title="%K Smooth", group="%K Settings", minval = 1)
kmaTypeInput = input.string("DEMA", title="%K MA Type", options = ["SMA", "EMA", "DEMA", "TEMA", "FRAMA", "T3", "TRIMA", "RMA", "WMA", "HMA", "VWMA", "ALMA", "JMA", "SINWMA", "FWMA", "LINREG", "SWMA", "VIDYA", "VWAP", "ZLMA"], group="%K Settings", display = display.data_window)
smoothDInput = input.int(3, title="%D Smooth", group="%D Settings", minval = 1)
dmaTypeInput = input.string("DEMA", title="%D MA Type", options = ["SMA", "EMA", "DEMA", "TEMA", "FRAMA", "T3", "TRIMA", "RMA", "WMA", "HMA", "VWMA", "ALMA", "JMA", "SINWMA", "FWMA", "LINREG", "SWMA", "VIDYA", "VWAP", "ZLMA"], group="%D Settings", display = display.data_window)
upperInput = input.int(40, title="Upper", group="Band Settings")
lowerInput = input.int(-40, title="Lower", group="Band Settings")
strategySignal = input.string("SMI-Band", title="Strategy Indicator", options = ["SMI-Band", "SMI MA-Band", "SMI-SMI MA"])
highestHigh = ta.highest(periodKInput)
lowestLow = ta.lowest(periodKInput)
highestLowestRange = highestHigh - lowestLow
relativeRange = srcInput - (highestHigh + lowestLow) / 2
smi = 200 * (ma(relativeRange, smoothKInput, kmaTypeInput) / ma(highestLowestRange, smoothKInput, kmaTypeInput))
smiMA = ma(smi, smoothDInput, dmaTypeInput)
smiPlot = plot(smi, "SMI", color = color.blue)
plot(smiMA, "SMI-based MA", color = color.orange)
upperBand = hline(upperInput, "Upper Band", color=color.gray)
hline(0, "Middle Band", linestyle=hline.style_dotted, color=color.gray)
lowerBand = hline(lowerInput, "Lower Band", color=color.gray)
fill(upperBand, lowerBand, title="Background", color=color.new(color.gray, 90))
midLinePlot = plot(0, color = na, editable = false, display = display.none)
fill(smiPlot, midLinePlot, 100, upperInput, top_color = color.green, bottom_color = color.new(color.green, 100), title = "Overbought Gradient Fill")
fill(smiPlot, midLinePlot, lowerInput, -100, top_color = color.new(color.red, 100), bottom_color = color.red, title = "Oversold Gradient Fill")
startDate = input.time(defval=timestamp("01 Jan 1970 00:00 +0000"), group = "Test Range")
finishDate = input.time(defval=timestamp("31 Dec 2025 24:00 +0000"), group = "Test Range")
time_condition = time >= startDate and time <= finishDate
if(time_condition)
if (strategySignal == "SMI-Band")
if ta.crossover(smi, lowerInput)
strategy.entry("매수", strategy.long, oca_type=strategy.oca.cancel, comment="매수")
if ta.crossunder(smi, upperInput)
strategy.close_all('매도')
if (strategySignal == "SMI MA-Band")
if ta.crossover(smiMA, lowerInput)
strategy.entry("매수", strategy.long, oca_type=strategy.oca.cancel, comment="매수")
if ta.crossunder(smiMA, upperInput)
strategy.close_all('매도')
if (strategySignal == "SMI-SMI MA")
if ta.crossover(smi, smiMA)
strategy.entry("매수", strategy.long, oca_type=strategy.oca.cancel, comment="매수")
if ta.crossunder(smi, smiMA)
strategy.close_all('매도')
bgcolor(strategy.position_size > 0 ? color.new(color.yellow,90) : na)