PROTECTED SOURCE SCRIPT

Marcus Donchian + Volume Divergence — Indicator v2

13
//version=5
indicator("Marcus Donchian + Volume Divergence — Indicator v2", shorttitle="Marcus DV-Ind v2", overlay=true)

// ── Inputs
trendTF = input.timeframe("60", "Trend TF for EMA (상위TF)")
emaLen = input.int(200, "Trend EMA Length", minval=1)
emaSlopeBars = input.int(3, "EMA slope bars (HTF)", minval=1)

breakLen = input.int(50, "Donchian Lookback", minval=2)
sweepLen = input.int(30, "Sweep lookback (Reversal)", minval=3)
atrLen = input.int(14, "ATR Length", minval=1)
breakBufATR = input.float(0.30, "ATR buffer for channel (+/−)", step=0.05)

useADX = input.bool(true, "Use ADX filter?")
adxLen = input.int(14, "ADX Length", minval=1)
adxTrendThr = input.int(28, "Trend ADX ≥", minval=1, maxval=100)
adxRangeMax = input.int(22, "Range ADX ≤", minval=1, maxval=100)

useVolFilter = input.bool(true, "Use volatility filter (ATR%)")
atrMinPct = input.float(0.18, "Min ATR% of price", step=0.01)

useDivFilter = input.bool(true, "Use Volume Divergence filter/confirm?")
pvLen = input.int(5, "Pivot L/R bars (divergence)", minval=2)
divConfirmBars = input.int(30, "Divergence confirm window (bars)", minval=5)
volLen = input.int(20, "Volume MA length")
volExpMult = input.float(1.5, "Volume expansion ×MA", step=0.1)

distZLimitBO = input.float(1.5, "Max |Z| for Trend breakout (ATR)", step=0.1) // 과열 돌파 금지
distZRev = input.float(2.0, "Min |Z| for Reversal (ATR)", step=0.1) // 충분한 할인/프리미엄

allowLongs = input.bool(true, "Enable Longs", inline="SIDE")
allowShorts = input.bool(true, "Enable Shorts", inline="SIDE")
enableTrend = input.bool(true, "Enable Trend (breakout)")
enableRev = input.bool(true, "Enable Reversal (sweep+reclaim)")

// ── Wilder ADX (ta.adx 미탑재 방어)
adxWilder(len) =>
up = ta.change(high)
down = -ta.change(low)
plusDM = (up > down and up > 0) ? up : 0.0
minusDM = (down > up and down > 0) ? down : 0.0
tr_ = math.max(high - low, math.max(math.abs(high - close[1]), math.abs(low - close[1])))
smTR = ta.rma(tr_, len)
smPDM = ta.rma(plusDM, len)
smMDM = ta.rma(minusDM, len)
plusDI = 100 * smPDM / smTR
minusDI = 100 * smMDM / smTR
dx = 100 * math.abs(plusDI - minusDI) / math.max(plusDI + minusDI, 1e-10)
ta.rma(dx, len)

// ── Calculations
trendEMA = request.security(syminfo.tickerid, trendTF, ta.ema(close, emaLen))
emaSlope = trendEMA - trendEMA[emaSlopeBars]
upper = ta.highest(high, breakLen)
lower = ta.lowest(low, breakLen)
atr = ta.atr(atrLen)
buf = atr * breakBufATR
atrPct = (atr / close) * 100.0
adxVal = adxWilder(adxLen)
Z = (close - trendEMA) / math.max(atr, 1e-10)

// ── OBV & Volume expansion
obvStep = close > close[1] ? volume : close < close[1] ? -volume : 0.0
obv = ta.cum(obvStep)
volMA = ta.sma(volume, volLen)
volExp = volume >= volExpMult * volMA

// ── Pivot-based divergence (모든 상태변수 단일 선언: 재발 방지)
ph = ta.pivothigh(high, pvLen, pvLen) // 확정되면 pvLen 바 전에 찍힘
pl = ta.pivotlow(low, pvLen, pvLen)

var float ph_price_last = na
var float ph_price_prev = na
var float ph_obv_last = na
var float ph_obv_prev = na

var float pl_price_last = na
var float pl_price_prev = na
var float pl_obv_last = na
var float pl_obv_prev = na

if not na(ph)
ph_price_prev := ph_price_last
ph_obv_prev := ph_obv_last
ph_price_last := ph
ph_obv_last := obv[pvLen] // 피벗 바의 OBV

if not na(pl)
pl_price_prev := pl_price_last
pl_obv_prev := pl_obv_last
pl_price_last := pl
pl_obv_last := obv[pvLen]

// 다이버전스 정의
bearDiv = not na(ph_price_prev) and not na(ph_price_last) and (ph_price_last > ph_price_prev) and (ph_obv_last < ph_obv_prev)
bullDiv = not na(pl_price_prev) and not na(pl_price_last) and (pl_price_last < pl_price_prev) and (pl_obv_last > pl_obv_prev)

// 최근 N봉 내 다이버전스 존재?
bearDivRecent = not useDivFilter ? true : (nz(ta.barssince(bearDiv), 1e9) <= divConfirmBars)
bullDivRecent = not useDivFilter ? true : (nz(ta.barssince(bullDiv), 1e9) <= divConfirmBars)

// ── Regime predicates (원자 변수화)
trendStrong = (not useADX) or (adxVal >= adxTrendThr)
rangeLike = (not useADX) or (adxVal <= adxRangeMax)
volOK = (not useVolFilter) or (atrPct >= atrMinPct)
slopeUp = emaSlope > 0
slopeDn = emaSlope < 0

// ── Donchian Breakout (Trend) + 과열(Z) + 거래량 확장 + 역다이버전스 차단
boLong_raw = enableTrend and allowLongs and trendStrong and slopeUp and (Z < distZLimitBO) and ta.crossover(close, upper[1] + buf)
boShort_raw = enableTrend and allowShorts and trendStrong and slopeDn and (Z > -distZLimitBO) and ta.crossunder(close, lower[1] - buf)
boLong = boLong_raw and (not useDivFilter or (volExp and not bearDivRecent))
boShort = boShort_raw and (not useDivFilter or (volExp and not bullDivRecent))

// ── Reversal: sweep & reclaim + Z 임계 + 저 ADX + 다이버전스 확증
sweptLow = low < ta.lowest(low, sweepLen)[1]
sweptHigh = high > ta.highest(high, sweepLen)[1]
reclaimL = close > (lower[1] + buf)
reclaimS = close < (upper[1] - buf)
discOK = Z <= -distZRev
premOK = Z >= distZRev
revLong = enableRev and allowLongs and rangeLike and discOK and sweptLow and reclaimL and (not useDivFilter or bullDivRecent)
revShort = enableRev and allowShorts and rangeLike and premOK and sweptHigh and reclaimS and (not useDivFilter or bearDivRecent)

// ── Final Signals + 변동성 필터
openLongTrend = volOK and boLong
openShortTrend = volOK and boShort
openLongRev = volOK and revLong
openShortRev = volOK and revShort

// ── Alert conditions (웹훅 없음)
alertcondition(openLongTrend, "Open Long (Trend)", "Open Long (Trend breakout)")
alertcondition(openShortTrend, "Open Short (Trend)", "Open Short (Trend breakout)")
alertcondition(openLongRev, "Open Long (Reversal)", "Open Long (Reversal reclaim)")
alertcondition(openShortRev, "Open Short (Reversal)","Open Short (Reversal reject)")

// ── Plots
plot(trendEMA, "Trend EMA (HTF)", color=color.new(color.orange, 0), linewidth=2)
plot(upper, "Donchian Upper", color=color.new(color.blue, 0))
plot(lower, "Donchian Lower", color=color.new(color.blue, 0))
plotshape(boLong, title="BO Long", style=shape.triangleup, location=location.belowbar, color=color.new(color.lime,0), size=size.tiny, text="BO L")
plotshape(boShort, title="BO Short", style=shape.triangledown, location=location.abovebar, color=color.new(color.red ,0), size=size.tiny, text="BO S")
plotshape(revLong, title="REV Long", style=shape.circle, location=location.belowbar, color=color.new(color.teal,0), size=size.tiny, text="REV L")
plotshape(revShort, title="REV Short",style=shape.circle, location=location.abovebar, color=color.new(color.purple,0), size=size.tiny, text="REV S")
plotshape(bullDiv, title="Bull Div", style=shape.labelup, location=location.belowbar, color=color.new(color.green,70), size=size.tiny, text="▲Div")
plotshape(bearDiv, title="Bear Div", style=shape.labeldown, location=location.abovebar, color=color.new(color.red, 70), size=size.tiny, text="▼Div")

Feragatname

Bilgiler ve yayınlar, TradingView tarafından sağlanan veya onaylanan finansal, yatırım, işlem veya diğer türden tavsiye veya tavsiyeler anlamına gelmez ve teşkil etmez. Kullanım Şartları'nda daha fazlasını okuyun.