OPEN-SOURCE SCRIPT

엘리어트 파동 3의 3파

153
//version=5
indicator("Elliott Wave — 3 of 3 Detector (v5)", overlay=true, timeframe_gaps=true)

// === Inputs ===
pivotLen = input.int(5, "Pivot length (bars each side)", minval=2)
subPivotLen = input.int(3, "Sub-pivot length (internal waves)", minval=2)
retrMin = input.float(0.382, "Wave 2 retracement min", minval=0.1, maxval=0.9, step=0.001)
retrMax = input.float(0.786, "Wave 2 retracement max", minval=0.1, maxval=0.95, step=0.001)
subRetrMin = input.float(0.382, "Subwave 2 retracement min", minval=0.1, maxval=0.9, step=0.001)
subRetrMax = input.float(0.618, "Subwave 2 retracement max", minval=0.1, maxval=0.95, step=0.001)

useRSI = input.bool(true, "Require RSI > threshold")
rsiPeriod = input.int(14, "RSI period", minval=2)
rsiThresh = input.float(55.0, "RSI threshold", minval=40, maxval=70)

useMACD = input.bool(true, "Require MACD histogram > 0")
fastLen = input.int(12, "MACD fast EMA", minval=2)
slowLen = input.int(26, "MACD slow EMA", minval=2)
signalLen = input.int(9, "MACD signal", minval=1)

useEMAFilter = input.bool(true, "Require trend filter (EMA50 > EMA200)")

useVolFilter = input.bool(false, "Require volume > volume MA")
volMaLen = input.int(20, "Volume MA length", minval=1)

plotZigs = input.bool(true, "Plot swing lines")
showLabels = input.bool(true, "Show wave labels")

// === Helpers ===
rsi = ta.rsi(close, rsiPeriod)
macdLine = ta.ema(close, fastLen) - ta.ema(close, slowLen)
signal = ta.ema(macdLine, signalLen)
hist = macdLine - signal
ema50 = ta.ema(close, 50)
ema200 = ta.ema(close, 200)
volMa = ta.sma(volume, volMaLen)

bool momentumOK = (not useRSI or rsi > rsiThresh) and (not useMACD or hist > 0)
bool trendOK = (not useEMAFilter or ema50 > ema200)
bool volOK = (not useVolFilter or volume > volMa)

// === Swing detection (basic pivot-based zigzag) ===
var float[] pivPrice = array.new_float()
var int[] pivIndex = array.new_int()
var int[] pivType = array.new_int() // +1 = swing high, -1 = swing low

ph = ta.pivothigh(high, pivotLen, pivotLen)
pl = ta.pivotlow(low, pivotLen, pivotLen)

f_addPivot(_price, _index, _type) =>
// avoid duplicate consecutive types
if array.size(pivType) > 0 and array.get(pivType, array.size(pivType)-1) == _type
// replace last pivot if same type and is more extreme in same direction
lastPrice = array.get(pivPrice, array.size(pivPrice)-1)
replace = (_type == 1 and _price > lastPrice) or (_type == -1 and _price < lastPrice)
if replace
array.set(pivPrice, array.size(pivPrice)-1, _price)
array.set(pivIndex, array.size(pivIndex)-1, _index)
else
array.push(pivPrice, _price)
array.push(pivIndex, _index)
array.push(pivType, _type)

if not na(ph)
f_addPivot(ph, bar_index - pivotLen, 1)
if not na(pl)
f_addPivot(pl, bar_index - pivotLen, -1)

// Keep arrays from growing unbounded
maxKeep = 200
if array.size(pivPrice) > maxKeep
for _i = 0 to array.size(pivPrice) - maxKeep - 1
array.shift(pivPrice)
array.shift(pivIndex)
array.shift(pivType)

// === Utility to get recent Nth pivot from the end ===
getPrice(n) => array.get(pivPrice, array.size(pivPrice) - 1 - n)
getIndex(n) => array.get(pivIndex, array.size(pivIndex) - 1 - n)
getType(n) => array.get(pivType, array.size(pivType) - 1 - n)

haveAtLeast(n) => array.size(pivPrice) >= n

// === Identify bullish 1-2 structure ===
bool has12 = false
float L0 = na, H1 = na, L2 = na
int L0i = na, H1i = na, L2i = na

if haveAtLeast(3)
// We want last three alternating pivots to be: low (L0), high (H1), low (L2)
t0 = getType(2)
t1 = getType(1)
t2 = getType(0)
if t0 == -1 and t1 == 1 and t2 == -1
L0 := getPrice(2)
H1 := getPrice(1)
L2 := getPrice(0)
L0i := getIndex(2)
H1i := getIndex(1)
L2i := getIndex(0)
// Retracement check for wave 2
wave1 = H1 - L0
retr = wave1 != 0 ? (H1 - L2) / wave1 : na
has12 := wave1 > 0 and not na(retr) and retr >= retrMin and retr <= retrMax

// === Wave 3 start (break above H1) ===
bool wave3Start = has12 and close > H1 and bar_index > H1i

// === Internal subwave 1-2 inside wave 3 using tighter sub-pivots ===
// We'll compute a separate list of sub-pivots since L2 to now, using smaller length
var float[] spPrice = array.new_float()
var int[] spIndex = array.new_int()
var int[] spType = array.new_int()

sph = ta.pivothigh(high, subPivotLen, subPivotLen)
spl = ta.pivotlow(low, subPivotLen, subPivotLen)

f_addSubPivot(_price, _index, _type) =>
if array.size(spType) > 0 and array.get(spType, array.size(spType)-1) == _type
lastPrice = array.get(spPrice, array.size(spPrice)-1)
replace = (_type == 1 and _price > lastPrice) or (_type == -1 and _price < lastPrice)
if replace
array.set(spPrice, array.size(spPrice)-1, _price)
array.set(spIndex, array.size(spIndex)-1, _index)
else
array.push(spPrice, _price)
array.push(spIndex, _index)
array.push(spType, _type)

// Reset sub-pivots after L2 to only track internal wave structure of current move
var int lastL2iTracked = na
if not na(L2i)
if na(lastL2iTracked) or L2i != lastL2iTracked
array.clear(spPrice)
array.clear(spIndex)
array.clear(spType)
lastL2iTracked := L2i

if not na(sph) and (na(L2i) or (bar_index - subPivotLen) >= L2i)
f_addSubPivot(sph, bar_index - subPivotLen, 1)
if not na(spl) and (na(L2i) or (bar_index - subPivotLen) >= L2i)
f_addSubPivot(spl, bar_index - subPivotLen, -1)

// Find subwave 1-2 (sL0 -> sH1 -> sL2) after L2
bool hasSub12 = false
float sL0 = na, sH1 = na, sL2 = na
int sL0i = na, sH1i = na, sL2i = na

if array.size(spPrice) >= 3
st0 = array.get(spType, array.size(spType) - 3)
st1 = array.get(spType, array.size(spType) - 2)
st2 = array.get(spType, array.size(spType) - 1)
if st0 == -1 and st1 == 1 and st2 == -1
sL0 := array.get(spPrice, array.size(spPrice) - 3)
sH1 := array.get(spPrice, array.size(spPrice) - 2)
sL2 := array.get(spPrice, array.size(spPrice) - 1)
sL0i := array.get(spIndex, array.size(spIndex) - 3)
sH1i := array.get(spIndex, array.size(spIndex) - 2)
sL2i := array.get(spIndex, array.size(spIndex) - 1)
// Sub retracement check
sw1 = sH1 - sL0
sRetr = sw1 != 0 ? (sH1 - sL2) / sw1 : na
hasSub12 := sw1 > 0 and not na(sRetr) and sRetr >= subRetrMin and sRetr <= subRetrMax

// === 3 of 3 trigger ===
bool threeOfThree = wave3Start and hasSub12 and close > sH1 and bar_index > sH1i and momentumOK and trendOK and volOK

// === Plotting ===
color upCol = color.new(color.lime, 0)
color dnCol = color.new(color.red, 0)
color neutCol = color.new(color.gray, 60)

plotshape(threeOfThree, title="3 of 3 Buy Signal", style=shape.triangleup, location=location.belowbar, size=size.large, color=upCol, text="3/3")

// Mark the 1-2 and sub 1-2 swings
if showLabels and has12
label.new(H1i, H1, text="1", style=label.style_label_up, color=color.new(color.green, 0))
label.new(L2i, L2, text="2", style=label.style_label_down, color=color.new(color.orange, 0))
if showLabels and hasSub12
label.new(sH1i, sH1, text="(i)", style=label.style_label_up, color=color.new(color.green, 60))
label.new(sL2i, sL2, text="(ii)", style=label.style_label_down, color=color.new(color.orange, 60))

// Draw swing lines
f_plotZigzag() =>
if array.size(pivPrice) >= 2 and plotZigs
for i = 1 to 1
x1 = array.get(pivIndex, array.size(pivIndex) - 2)
y1 = array.get(pivPrice, array.size(pivPrice) - 2)
x2 = array.get(pivIndex, array.size(pivIndex) - 1)
y2 = array.get(pivPrice, array.size(pivPrice) - 1)
line.new(x1, y1, x2, y2, extend=extend.none, color=neutCol, width=1)

f_plotZigzag()

// Visual filters
plot(ema50, color=color.new(color.teal, 0), title="EMA50")
plot(ema200, color=color.new(color.blue, 0), title="EMA200")

bgcolor(threeOfThree ? color.new(color.lime, 85) : na)

// === Alerts ===
alertcondition(threeOfThree, title="3 of 3 long", message="3 of 3 long setup on {{ticker}} {{interval}} — price has broken above subwave (i) high with momentum.")

// === Notes ===
// Heuristic detector:
// 1) Find L0-H1-L2 with L2 retracing 38.2%–78.6% of wave 1.
// 2) Confirm wave 3 start when price breaks above H1.
// 3) Inside wave 3, find sub L0-H1-L2 using tighter sub-pivots with 38.2%–61.8% retracement.
// 4) Trigger 3 of 3 when price breaks above subwave (i) high with momentum/trend/volume filters.
// Tune pivotLen/subPivotLen and thresholds to match your instrument and timeframe.

Penafian

Maklumat dan penerbitan adalah tidak dimaksudkan untuk menjadi, dan tidak membentuk, nasihat untuk kewangan, pelaburan, perdagangan dan jenis-jenis lain atau cadangan yang dibekalkan atau disahkan oleh TradingView. Baca dengan lebih lanjut di Terma Penggunaan.