PROTECTED SOURCE SCRIPT
ELLIOT WAVE TP11OFC5

//version=6
indicator("TP11OFC5", overlay=true, scale=scale.right, max_lines_count=500, max_labels_count=500, max_boxes_count=500, max_bars_back=5000)
//──────────────────────────────── Inputs: Masked Names ───────────────────────────────
// yelow group (EMA200 + 5up/5down)
group200 = "yelow group"
emaLen200 = input.int(200, "yelow length", minval=1, group=group200)
show200Mid = input.bool(true, "show big brown", group=group200) // EMA200 mid
show200_5u = input.bool(true, "show yelow group up", group=group200) // 5up (EMA200)
show200_5d = input.bool(true, "show yelow group down",group=group200) // 5down (EMA200)
// Colors (masked)
groupClrMA = "Colors — lines"
colMid200 = input.color(color.rgb(100, 50, 0), "big brown", group=groupClrMA) // EMA200 mid
col5band = input.color(color.rgb(247, 212, 14), "yelow up/down", group=groupClrMA) // 5up/5down
col85_4 = input.color(color.rgb(9, 77, 202), "blue up/down (x4)",group=groupClrMA) // EMA85 4up/4down
col35 = input.color(color.rgb(7, 9, 155), "big blue", group=groupClrMA) // EMA35
colPNR = input.color(color.rgb(255,17,0), "pn", group=groupClrMA) // PNR
// blue group (EMA85 — 4 up/down)
group85 = "blue group"
emaLen85 = input.int(85, "blue length", minval=1, group=group85)
show85_4u = input.bool(true, "show blue group up", group=group85)
show85_4d = input.bool(true, "show blue group down", group=group85)
// big blue (EMA35)
group35 = "big blue"
emaLen35 = input.int(35, "big blue length", minval=1, group=group35)
useClose35 = input.bool(false, "big blue use close (else effClose)", group=group35)
showEMA35 = input.bool(true, "show big blue", group=group35)
// pn (PNR)
groupPNR = "pn"
pnrLen = input.int(15, "window size", minval=1, group=groupPNR)
pnrPerc = input.int(50, "percentile (0–100)", minval=0, maxval=100, group=groupPNR)
pnrSrc = input.source(close, "source", group=groupPNR)
showPNR = input.bool(true, "show pn", group=groupPNR)
// di (DSI)
groupDSI = "di"
showDSI = input.bool(true, "show di", group=groupDSI)
atrMovement= input.float(1.0, "movement required", step=0.5, group=groupDSI)
lookback = input.int(25, "high/low lookback", step=5, group=groupDSI)
maxZoneSize= input.float(2.5, "max zone size ", step=0.5, group=groupDSI)
newStructureReset = input.int(25, "zone update count before reset", step=5, group=groupDSI)
drawPreviousStructure = input.bool(true, "draw previous zones", group=groupDSI)
groupClrDSI = "Colors — zones"
dsiBullColor = input.color(color.rgb(178, 240, 180), "bull color", group=groupClrDSI)
dsiBearColor = input.color(color.rgb(240, 206, 206), "bear color", group=groupClrDSI)
//──────────────────────────────── FE (Trend-base Fibo) ───────────────────────────────
groupFE = "targets — FE"
feLenBars = input.int(35, "FE length (bars) from P3", minval=5, group=groupFE)
feLife = input.int(500, "FE lifespan (bars) before delete", minval=50, group=groupFE)
showFE = input.bool(true, "show FE", group=groupFE)
roundToTick = input.bool(true, "round FE to tick", group=groupFE)
// FE levels on/off
show95_105 = input.bool(true, "show band", group=groupFE)
show1618 = input.bool(true, "show 1", group=groupFE)
show2618 = input.bool(true, "show 2", group=groupFE)
show3618 = input.bool(true, "show 3", group=groupFE)
show4618 = input.bool(true, "show 4", group=groupFE)
// FE colors
colBand = input.color(color.rgb(79, 247, 46), "line", group=groupFE)
colBandFill = input.color(color.new(#8be95f, 85), "band", group=groupFE)
col1618 = input.color(color.orange, "1line", group=groupFE)
col2618 = input.color(color.fuchsia, "2line", group=groupFE)
col3618 = input.color(color.new(color.purple, 0), "3line", group=groupFE)
col4618 = input.color(color.new(color.maroon, 0), "4line", group=groupFE)
//──────────────────────────────── P-series (เดิม) ───────────────────────────────
groupP1P2P3 = "P-series options"
p1Lookback = input.int(200, "P1 max left scan", minval=20, group=groupP1P2P3)
rightWinBars = input.int(5, "P2 right confirm bars", minval=1, group=groupP1P2P3)
p3MaxWindowBars = input.int(600, "P3 max window (bars)", minval=50, maxval=5000, step=50, group=groupP1P2P3)
resetWithinBars = input.int(50, "reset old set if new within (bars)", minval=1, group=groupP1P2P3)
// >>> NEW: ระยะห่างขั้นต่ำ P1/P3 จาก P2 <<<
minGapBars = input.int(5, "Min gap bars: P1/P3 must be at least this far from P2", minval=1, group=groupP1P2P3)
// ── NEW: De-duplicate labels (no same-type within N bars; keep latest) ─────────────
groupDeDup = "Labels — de-dup"
dedupWinBars = input.int(50, "No same-type label within N bars", minval=1, group=groupDeDup)
// ──────────────────────────────── New: P2 window rule ───────────────────────────────
groupP2Win = "P2 window rule"
p2NewWithinBars = input.int(50, "Window N bars: new P2 within N must be better than last P2 (L: higher / S: lower)", minval=1, group=groupP2Win)
//──────────────────────────────── Visual options ───────────────────────────────
groupPviz = "Visual — Body highlights & labels"
showBodyBoxes = input.bool(true, "show body boxes", group=groupPviz)
P1BoxFullCandle = input.bool(false, "P1: full candle box", group=groupPviz)
P2BoxFullCandle = input.bool(false, "P2: full candle box", group=groupPviz)
P3BoxFullCandle = input.bool(false, "P3: full candle box", group=groupPviz)
P1BoxColor = input.color(color.black, "P1 box color", group=groupPviz)
P1BoxFillTransp = input.int(85, "P1 box fill transp", minval=0, maxval=100, group=groupPviz)
P2BoxColor = input.color(color.lime, "P2 box color", group=groupPviz)
P2BoxFillTransp = input.int(70, "P2 box fill transp", minval=0, maxval=100, group=groupPviz)
P3BoxColor = input.color(color.orange, "P3 box color", group=groupPviz)
P3BoxFillTransp = input.int(70, "P3 box fill transp", minval=0, maxval=100, group=groupPviz)
BoxBorderTransp = input.int(0, "box border transp", minval=0, maxval=100, group=groupPviz)
recolorBars = input.bool(true, "barcolor P1/P2/P3", group=groupPviz)
colP1Candle = input.color(color.black, "P1 candle", group=groupPviz)
colP2Candle = input.color(color.lime, "P2 candle", group=groupPviz)
colP3Candle = input.color(color.orange,"P3 candle", group=groupPviz)
showP1Label = input.bool(true, "show P1 label", group=groupPviz)
showP2Label = input.bool(true, "show P2 label", group=groupPviz)
showP3Label = input.bool(true, "show P3 label", group=groupPviz)
PLabelTextColor = input.color(color.white, "label text color", group=groupPviz)
PLabelBgColor = input.color(color.black, "label bg color", group=groupPviz)
// ── Label placement/offset (split LONG/SHORT) ───────────────────────────────
groupLbl = "Labels — placement"
LP_AUTO = "Auto"
LP_ABOVE = "Above"
LP_BELOW = "Below"
OM_TICKS = "Ticks"
OM_ATR = "ATR"
lblPlaceLong = input.string(LP_ABOVE, "Placement (LONG)", options=[LP_AUTO, LP_ABOVE, LP_BELOW], group=groupLbl)
lblPlaceShort = input.string(LP_BELOW, "Placement (SHORT)", options=[LP_AUTO, LP_ABOVE, LP_BELOW], group=groupLbl)
lblOffsetMet = input.string(OM_ATR, "Offset method", options=[OM_TICKS, OM_ATR], group=groupLbl)
lblTicks = input.int(5, "Ticks offset", minval=0, group=groupLbl)
lblAtrLen = input.int(14, "ATR length", minval=1, group=groupLbl)
lblAtrMult = input.float(0.25, "ATR multiple", minval=0.0, step=0.05, group=groupLbl)
lblSizeSel = input.string("small", "Label size", options=["tiny","small","normal","large"], group=groupLbl)
lblBgTransp = input.int(0, "Label BG transparency", minval=0, maxval=100, group=groupLbl)
//──────────────────────────────── Manual (แทน Override) ─────────────────────────
PM_OPEN = "Open"
PM_CLOSE = "Close"
PM_MID = "Mid"
PM_HIGH = "High"
PM_LOW = "Low"
PM_CUST = "Custom"
PK_TIME = "Time"
PK_OFF = "Offset"
// LONG
groupManL = "Manual (LONG)"
useManP1L = input.bool(false, "Use P1 manual (L)", group=groupManL)
pickP1L = input.string(PK_TIME, "P1 pick mode (L)", options=[PK_TIME, PK_OFF], group=groupManL)
manP1L_t = input.time(timestamp("01 Jan 2024 00:00 +0000"), "P1 time (L)", group=groupManL)
manP1L_of = input.int(-5, "P1 offset (bars, L)", group=groupManL)
pmP1L = input.string(PM_OPEN, "P1 price mode (L)", options=[PM_OPEN, PM_CLOSE, PM_MID, PM_HIGH, PM_LOW, PM_CUST], group=groupManL)
p1L_custom= input.float(0.0, "P1 custom price (L)", group=groupManL)
useManP2L = input.bool(false, "Use P2 manual (L)", group=groupManL)
pickP2L = input.string(PK_TIME, "P2 pick mode (L)", options=[PK_TIME, PK_OFF], group=groupManL)
manP2L_t = input.time(timestamp("01 Jan 2024 00:00 +0000"), "P2 time (L)", group=groupManL)
manP2L_of = input.int(-3, "P2 offset (bars, L)", group=groupManL)
pmP2L = input.string(PM_CLOSE, "P2 price mode (L)", options=[PM_OPEN, PM_CLOSE, PM_MID, PM_HIGH, PM_LOW, PM_CUST], group=groupManL)
p2L_custom= input.float(0.0, "P2 custom price (L)", group=groupManL)
useManP3L = input.bool(false, "Use P3 manual (L)", group=groupManL)
pickP3L = input.string(PK_TIME, "P3 pick mode (L)", options=[PK_TIME, PK_OFF], group=groupManL)
manP3L_t = input.time(timestamp("01 Jan 2024 00:00 +0000"), "P3 time (L)", group=groupManL)
manP3L_of = input.int(-1, "P3 offset (bars, L)", group=groupManL)
pmP3L = input.string(PM_OPEN, "P3 price mode (L)", options=[PM_OPEN, PM_CLOSE, PM_MID, PM_HIGH, PM_LOW, PM_CUST], group=groupManL)
p3L_custom= input.float(0.0, "P3 custom price (L)", group=groupManL)
// SHORT
groupManS = "Manual (SHORT)"
useManP1S = input.bool(false, "Use P1 manual (S)", group=groupManS)
pickP1S = input.string(PK_TIME, "P1 pick mode (S)", options=[PK_TIME, PK_OFF], group=groupManS)
manP1S_t = input.time(timestamp("01 Jan 2024 00:00 +0000"), "P1 time (S)", group=groupManS)
manP1S_of = input.int(-5, "P1 offset (bars, S)", group=groupManS)
pmP1S = input.string(PM_OPEN, "P1 price mode (S)", options=[PM_OPEN, PM_CLOSE, PM_MID, PM_HIGH, PM_LOW, PM_CUST], group=groupManS)
p1S_custom= input.float(0.0, "P1 custom price (S)", group=groupManS)
useManP2S = input.bool(false, "Use P2 manual (S)", group=groupManS)
pickP2S = input.string(PK_TIME, "P2 pick mode (S)", options=[PK_TIME, PK_OFF], group=groupManS)
manP2S_t = input.time(timestamp("01 Jan 2024 00:00 +0000"), "P2 time (S)", group=groupManS)
manP2S_of = input.int(-3, "P2 offset (bars, S)", group=groupManS)
pmP2S = input.string(PM_CLOSE, "P2 price mode (S)", options=[PM_OPEN, PM_CLOSE, PM_MID, PM_HIGH, PM_LOW, PM_CUST], group=groupManS)
p2S_custom= input.float(0.0, "P2 custom price (S)", group=groupManS)
useManP3S = input.bool(false, "Use P3 manual (S)", group=groupManS)
pickP3S = input.string(PK_TIME, "P3 pick mode (S)", options=[PK_TIME, PK_OFF], group=groupManS)
manP3S_t = input.time(timestamp("01 Jan 2024 00:00 +0000"), "P3 time (S)", group=groupManS)
manP3S_of = input.int(-1, "P3 offset (bars, S)", group=groupManS)
pmP3S = input.string(PM_OPEN, "P3 price mode (S)", options=[PM_OPEN, PM_CLOSE, PM_MID, PM_HIGH, PM_LOW, PM_CUST], group=groupManS)
p3S_custom= input.float(0.0, "P3 custom price (S)", group=groupManS)
// Buttons: Reset (UI switches)
groupBtnL = "Manual Controls — Buttons (LONG)"
btnResetAllL = input.bool(false, "Reset ALL manual (L)", group=groupBtnL)
btnResetP1L = input.bool(false, "Reset P1 manual (L)", group=groupBtnL)
btnResetP2L = input.bool(false, "Reset P2 manual (L)", group=groupBtnL)
btnResetP3L = input.bool(false, "Reset P3 manual (L)", group=groupBtnL)
groupBtnS = "Manual Controls — Buttons (SHORT)"
btnResetAllS = input.bool(false, "Reset ALL manual (S)", group=groupBtnS)
btnResetP1S = input.bool(false, "Reset P1 manual (S)", group=groupBtnS)
btnResetP2S = input.bool(false, "Reset P2 manual (S)", group=groupBtnS)
btnResetP3S = input.bool(false, "Reset P3 manual (S)", group=groupBtnS)
// ── Momentary Reset (edge-detect) ───────────────────────────────
var bool resetReqAllL = false
var bool resetReqP1L = false
var bool resetReqP2L = false
var bool resetReqP3L = false
var bool resetReqAllS = false
var bool resetReqP1S = false
var bool resetReqP2S = false
var bool resetReqP3S = false
bool fireAllL = ta.change(btnResetAllL) and btnResetAllL
bool fireP1L = ta.change(btnResetP1L) and btnResetP1L
bool fireP2L = ta.change(btnResetP2L) and btnResetP2L
bool fireP3L = ta.change(btnResetP3L) and btnResetP3L
bool fireAllS = ta.change(btnResetAllS) and btnResetAllS
bool fireP1S = ta.change(btnResetP1S) and btnResetP1S
bool fireP2S = ta.change(btnResetP2S) and btnResetP2S
bool fireP3S = ta.change(btnResetP3S) and btnResetP3S
if fireAllL
resetReqAllL := true
resetReqP1L := true
resetReqP2L := true
resetReqP3L := true
if fireP1L
resetReqP1L := true
if fireP2L
resetReqP2L := true
if fireP3L
resetReqP3L := true
if fireAllS
resetReqAllS := true
resetReqP1S := true
resetReqP2S := true
resetReqP3S := true
if fireP1S
resetReqP1S := true
if fireP2S
resetReqP2S := true
if fireP3S
resetReqP3S := true
//──────────────────────────────── Core helpers ───────────────────────────────
float effClose = close >= open ? math.max(open, close) : math.min(open, close)
f_bodyTop(_o, _c) => math.max(_o, _c)
f_bodyBot(_o, _c) => math.min(_o, _c)
f_midBody_at(_i) =>
float bt = f_bodyTop(open[_i], close[_i])
float bb = f_bodyBot(open[_i], close[_i])
(bt + bb) / 2.0
f_core(_len) =>
float mid = ta.ema(effClose, _len)
float _dev = ta.stdev(effClose, _len)
float devS = _dev == 0.0 ? na : _dev
float plus = na(mid) or na(devS) ? na : (close > mid ? (close - mid) / devS : 0.0)
float minus = na(mid) or na(devS) ? na : (close < mid ? (mid - close) / devS : 0.0)
float mmax = na(plus) or na(minus) ? na : math.max(plus, minus)
float lm = ta.ema(mmax, _len)
[mid, devS, lm]
f_core_src(_src, _len) =>
float mid = ta.ema(_src, _len)
float _dev = ta.stdev(_src, _len)
float devS = _dev == 0.0 ? na : _dev
float plus = na(mid) or na(devS) ? na : (_src > mid ? (_src - mid) / devS : 0.0)
float minus = na(mid) or na(devS) ? na : (_src < mid ? (mid - _src) / devS : 0.0)
float mmax = na(plus) or na(minus) ? na : math.max(plus, minus)
float lm = ta.ema(mmax, _len)
[mid, devS, lm]
// Price by mode
f_price_by_mode(off, mode, custom) =>
switch mode
PM_OPEN => open[off]
PM_CLOSE => close[off]
PM_MID => (math.max(open[off], close[off]) + math.min(open[off], close[off]))/2.0
PM_HIGH => high[off]
PM_LOW => low[off]
PM_CUST => custom > 0 ? (roundToTick ? math.round(custom / syminfo.mintick) * syminfo.mintick : custom) : na
=> na
// NEW: Gap helpers
f_gap_ok_left(p1Abs, p2Abs) =>
not na(p1Abs) and not na(p2Abs) and (p2Abs - p1Abs) >= minGapBars
f_gap_ok_right(p3Abs, p2Abs) =>
not na(p3Abs) and not na(p2Abs) and (p3Abs - p2Abs) >= minGapBars
//──────────────────────────────── yelow group (EMA200 + 5up/5down) ───────────────────
[mid200, dev200, lm200] = f_core_src(close, emaLen200)
phi_adj = 1.38196601
float fiveUp_200 = na(mid200) or na(dev200) or na(lm200) ? na : mid200 + (lm200 * phi_adj) * dev200
float fiveDown_200 = na(mid200) or na(dev200) or na(lm200) ? na : mid200 - (lm200 * phi_adj) * dev200
plot(show200_5d ? fiveDown_200 : na, title="yelow group down", color=col5band, linewidth=3)
plot(show200Mid ? mid200 : na, title="big brown", color=colMid200, linewidth=3)
plot(show200_5u ? fiveUp_200 : na, title="yelow group up", color=col5band, linewidth=3)
//──────────────────────────────── blue group (EMA85 — 4 up/down) ────────────────────
[mid85, dev85, lm85] = f_core(emaLen85)
float up4_85 = na(mid85) or na(dev85) or na(lm85) ? na : mid85 + lm85 * dev85
float down4_85 = na(mid85) or na(dev85) or na(lm85) ? na : mid85 - lm85 * dev85
float fiveUp_85 = na(mid85) or na(dev85) or na(lm85) ? na : mid85 + (lm85 * phi_adj) * dev85
float fiveDown_85 = na(mid85) or na(dev85) or na(lm85) ? na : mid85 - (lm85 * phi_adj) * dev85
plot(show85_4u ? up4_85 : na, title="blue group up", color=col85_4, linewidth=2)
plot(show85_4d ? down4_85 : na, title="blue group down", color=col85_4, linewidth=2)
// big blue (EMA35)
float ema35 = useClose35 ? ta.ema(close, emaLen35) : ta.ema(effClose, emaLen35)
plot(showEMA35 ? ema35 : na, title="big blue", color=col35, linewidth=2)
// pn (PNR)
float pnr = na
if bar_index >= pnrLen - 1
float[] win = array.new_float()
for i = 0 to pnrLen - 1
array.push(win, pnrSrc)
array.sort(win)
float rankF = (pnrPerc / 100.0) * (pnrLen - 1)
int idx = int(math.round(rankF))
idx := math.max(0, math.min(idx, pnrLen - 1))
pnr := array.get(win, idx)
plot(showPNR ? pnr : na, title="pn", color=colPNR, linewidth=2)
//──────────────────────────────── Masked EMA Clouds (line 1–5) ───────────────────────
groupCloud = "line clouds"
showClouds = input.bool(true, "show lines clouds", group=groupCloud)
l1Len = input.int(5, "line 1 length", minval=1, group=groupCloud)
l2Len = input.int(8, "line 2 length", minval=1, group=groupCloud)
l3Len = input.int(21, "line 3 length", minval=1, group=groupCloud)
l4Len = input.int(34, "line 4 length", minval=1, group=groupCloud)
l5Len = input.int(50, "line 5 length", minval=1, group=groupCloud)
cloudUpColor = input.color(color.green, "cloud up color", group=groupCloud)
cloudDnColor = input.color(color.red, "cloud down color", group=groupCloud)
cloudTransp = input.int(60, "cloud transparency (0–100)", minval=0, maxval=100, group=groupCloud)
l1 = ta.ema(close, l1Len)
l2 = ta.ema(close, l2Len)
l3 = ta.ema(close, l3Len)
l4 = ta.ema(close, l4Len)
l5 = ta.ema(close, l5Len)
// พล็อตเส้นพราง (transp=100) และใช้ชื่อ line 1..5
p1 = plot(showClouds ? l1 : na, color=color.new(color.gray, 100), style=plot.style_line, linewidth=1, title="line 1")
p2 = plot(showClouds ? l2 : na, color=color.new(color.gray, 100), style=plot.style_line, linewidth=1, title="line 2")
p3 = plot(showClouds ? l3 : na, color=color.new(color.gray, 100), style=plot.style_line, linewidth=1, title="line 3")
p4 = plot(showClouds ? l4 : na, color=color.new(color.gray, 100), style=plot.style_line, linewidth=1, title="line 4")
p5 = plot(showClouds ? l5 : na, color=color.new(color.gray, 100), style=plot.style_line, linewidth=1, title="line 5")
// เรียก fill ที่ "global scope" แล้วคุมการแสดงผลด้วยสี (ถ้าไม่โชว์ให้ทำเป็นโปร่งใส)
cloud23Color = showClouds ? (l2 > l3 ? color.new(cloudUpColor, cloudTransp) : color.new(cloudDnColor, cloudTransp)) : color.new(color.black, 100)
cloud45Color = showClouds ? (l4 > l5 ? color.new(cloudUpColor, cloudTransp) : color.new(cloudDnColor, cloudTransp)) : color.new(color.black, 100)
fill(p2, p3, color=cloud23Color, title="cloud 2–3")
fill(p4, p5, color=cloud45Color, title="cloud 4–5")
//──────────────────────────────── Utilities ───────────────────────────────
isGreen_at(i) => close > open
isRed_at(i) => close < open
bodyTop_at(i) => f_bodyTop(open, close)
f_frac_body_above_line(i, lineV) =>
float bt = bodyTop_at(i), bb = f_bodyBot(open, close)
float body = bt - bb
body <= 0 or na(lineV) ? 0.0 : math.max(0.0, bt - math.max(bb, lineV)) / body
f_frac_body_below_line(i, lineV) =>
float bt = bodyTop_at(i), bb = f_bodyBot(open, close)
float body = bt - bb
body <= 0 or na(lineV) ? 0.0 : math.max(0.0, math.min(bt, lineV) - bb) / body
// Draw helpers
var box[] PBOXES = array.new_box()
var label[] PLABELS = array.new_label()
f_delete_boxes(box[] arr) =>
int n = array.size(arr)
for k = 0 to n - 1
int i = n - 1 - k
box.delete(array.get(arr, i))
array.clear(arr)
f_delete_labels(label[] arr) =>
int n = array.size(arr)
for k = 0 to n - 1
int i = n - 1 - k
label.delete(array.get(arr, i))
array.clear(arr)
// size mapper
f_lbl_size(s) =>
s == "tiny" ? size.tiny : s == "large" ? size.large : s == "normal" ? size.normal : size.small
// helper: one-line label.new
f_make_label(_x, _y, _text, _placeAbove) =>
label.new(_x, _y, _text, xloc=xloc.bar_time, style=(_placeAbove ? label.style_label_down : label.style_label_up), textcolor=PLabelTextColor, color=color.new(PLabelBgColor, lblBgTransp), size=f_lbl_size(lblSizeSel))
// smarter label placement (split LONG/SHORT) → return handles
f_add_label_ret(_abs, _text, _isLong) =>
label lb = na
int off = bar_index - _abs
if off >= 0 and off <= 5000 and not na(time[off]) and not na(high[off]) and not na(low[off])
float pad = lblOffsetMet == OM_TICKS ? (syminfo.mintick * lblTicks) : (ta.atr(lblAtrLen)[off] * lblAtrMult)
string opt = _isLong ? lblPlaceLong : lblPlaceShort
bool placeAbove = (opt == LP_ABOVE) ? true : (opt == LP_BELOW) ? false : (close[off] >= open[off])
float yPos = placeAbove ? (high[off] + pad) : (low[off] - pad)
lb := f_make_label(time[off], yPos, _text, placeAbove)
array.push(PLABELS, lb)
if array.size(PLABELS) > 500
label.delete(array.get(PLABELS, 0))
array.remove(PLABELS, 0)
lb
// draw mark → return [box,label]
f_draw_mark_group(_abs, _full, _boxCol, _fillT, _borderT, _labelOn, _labelText, _isLong) =>
box nb = na
label lb = na
if not na(_abs)
int off = bar_index - _abs
if off >= 0 and off <= 5000
float top = _full ? high[off] : bodyTop_at(off)
float bot = _full ? low[off] : f_bodyBot(open[off], close[off])
if showBodyBoxes
nb := box.new(math.max(0, int(_abs) - 1), math.max(top, bot), int(_abs), math.min(top, bot), xloc=xloc.bar_index, bgcolor=color.new(_boxCol, _fillT), border_color=color.new(_boxCol, _borderT))
array.push(PBOXES, nb)
if array.size(PBOXES) > 500
box.delete(array.get(PBOXES, 0))
array.remove(PBOXES, 0)
if _labelOn
lb := f_add_label_ret(_abs, _labelText, _isLong)
[nb, lb]
//───────────────────── De-dup helpers (keep latest; delete older within window) ─────
f_del_if_exists(_bx, _lb) =>
if not na(_bx)
box.delete(_bx)
if not na(_lb)
label.delete(_lb)
// Strict int for last Abs to avoid NA-type errors
var int L_lastP1Abs = int(na)
var int L_lastP2Abs = int(na)
var int L_lastP3Abs = int(na)
var int S_lastP1Abs = int(na)
var int S_lastP2Abs = int(na)
var int S_lastP3Abs = int(na)
// IMPORTANT: declare one per line to keep type info on all variables
var box L_lastP1Box = na
var box L_lastP2Box = na
var box L_lastP3Box = na
var box S_lastP1Box = na
var box S_lastP2Box = na
var box S_lastP3Box = na
var label L_lastP1Lbl = na
var label L_lastP2Lbl = na
var label L_lastP3Lbl = na
var label S_lastP1Lbl = na
var label S_lastP2Lbl = na
var label S_lastP3Lbl = na
// >>> NEW: true-last P2 trackers (separate from de-dup) <<<
var int L_prevP2Abs = int(na)
var float L_prevP2Close = na
var int S_prevP2Abs = int(na)
var float S_prevP2Close = na
// enforce unique per type & side
f_enforce_and_set(_newAbs, _newBox, _newLbl, _lastAbs, _lastBox, _lastLbl) =>
bool keepNew = true
int lastAbsNew = _lastAbs
box lastBoxNew = _lastBox
label lastLblNew = _lastLbl
if not na(_lastAbs) and math.abs(_newAbs - _lastAbs) <= dedupWinBars
if _newAbs > _lastAbs
f_del_if_exists(_lastBox, _lastLbl)
lastAbsNew := _newAbs
lastBoxNew := _newBox
lastLblNew := _newLbl
else
f_del_if_exists(_newBox, _newLbl)
keepNew := false
else
lastAbsNew := _newAbs
lastBoxNew := _newBox
lastLblNew := _newLbl
[keepNew, lastAbsNew, lastBoxNew, lastLblNew]
//──────────────────────────────── FE helpers ───────────────────────────────
f_rt(v) => roundToTick ? math.round(v / syminfo.mintick) * syminfo.mintick : v
var line[] FE_l95 = array.new_line()
var line[] FE_l105 = array.new_line()
var line[] FE_l161 = array.new_line()
var line[] FE_l261 = array.new_line()
var line[] FE_l361 = array.new_line()
var line[] FE_l461 = array.new_line()
var linefill[] FE_fill = array.new_linefill()
var int[] FE_born = array.new_int()
f_delete_fe_index(idx) =>
int nAll = array.size(FE_born)
if idx >= 0 and idx < nAll
if idx < array.size(FE_fill)
linefill.delete(array.get(FE_fill, idx))
if idx < array.size(FE_l95)
line.delete(array.get(FE_l95, idx))
if idx < array.size(FE_l105)
line.delete(array.get(FE_l105, idx))
if idx < array.size(FE_l161)
line.delete(array.get(FE_l161, idx))
if idx < array.size(FE_l261)
line.delete(array.get(FE_l261, idx))
if idx < array.size(FE_l361)
line.delete(array.get(FE_l361, idx))
if idx < array.size(FE_l461)
line.delete(array.get(FE_l461, idx))
if idx < array.size(FE_l95)
array.remove(FE_l95, idx)
if idx < array.size(FE_l105)
array.remove(FE_l105, idx)
if idx < array.size(FE_l161)
array.remove(FE_l161, idx)
if idx < array.size(FE_l261)
array.remove(FE_l261, idx)
if idx < array.size(FE_l361)
array.remove(FE_l361, idx)
if idx < array.size(FE_l461)
array.remove(FE_l461, idx)
if idx < array.size(FE_fill)
array.remove(FE_fill, idx)
array.remove(FE_born, idx)
f_clear_all_fe() =>
int n = array.size(FE_born)
for k = 0 to n - 1
int i = n - 1 - k
f_delete_fe_index(i)
// ───────────── ADD: helper แปลง bar-abs → time (ms) ─────────────
f_abs_to_time(_abs) =>
if na(_abs)
na
else
int off = bar_index - _abs
if off < 0
na
else
int tfms = timeframe.in_seconds(timeframe.period) * 1000
off <= 5000 ? time[off] : (time - off * tfms)
// ───────────── REPLACE: f_add_fe_set เดิม ด้วยเวอร์ชันกัน error ─────────────
f_add_fe_set(p3Abs, y95, y105, y161, y261, y361, y461) =>
int off = bar_index - p3Abs
bool useTime = off > 4500
int tfms = timeframe.in_seconds(timeframe.period) * 1000
color c95 = show95_105 ? colBand : color.new(colBand, 100)
color c105 = show95_105 ? colBand : color.new(colBand, 100)
color c161 = show1618 ? col1618 : color.new(col1618, 100)
color c261 = show2618 ? col2618 : color.new(col2618, 100)
color c361 = show3618 ? col3618 : color.new(col3618, 100)
color c461 = show4618 ? col4618 : color.new(col4618, 100)
// <<< แก้ไขตรงนี้: ประกาศตัวแปร line ทีละบรรทัด >>>
line l95 = na
line l105 = na
line l161 = na
line l261 = na
line l361 = na
line l461 = na
linefill lf = na
if not useTime
int x1 = p3Abs
int x2 = p3Abs + feLenBars
l95 := line.new(x1, y95, x2, y95, xloc=xloc.bar_index, extend=extend.none, color=c95, width=3)
l105 := line.new(x1, y105, x2, y105, xloc=xloc.bar_index, extend=extend.none, color=c105, width=3)
l161 := line.new(x1, y161, x2, y161, xloc=xloc.bar_index, extend=extend.none, color=c161, width=2)
l261 := line.new(x1, y261, x2, y261, xloc=xloc.bar_index, extend=extend.none, color=c261, width=2)
l361 := line.new(x1, y361, x2, y361, xloc=xloc.bar_index, extend=extend.none, color=c361, width=2)
l461 := line.new(x1, y461, x2, y461, xloc=xloc.bar_index, extend=extend.none, color=c461, width=2)
lf := linefill.new(l95, l105, color= show95_105 ? colBandFill : color.new(color.black, 100))
else
int t1 = f_abs_to_time(p3Abs)
int t2 = int(na)
if not na(t1)
t2 := t1 + feLenBars * tfms
l95 := line.new(t1, y95, t2, y95, xloc=xloc.bar_time, extend=extend.none, color=c95, width=3)
l105 := line.new(t1, y105, t2, y105, xloc=xloc.bar_time, extend=extend.none, color=c105, width=3)
l161 := line.new(t1, y161, t2, y161, xloc=xloc.bar_time, extend=extend.none, color=c161, width=2)
l261 := line.new(t1, y261, t2, y261, xloc=xloc.bar_time, extend=extend.none, color=c261, width=2)
l361 := line.new(t1, y361, t2, y361, xloc=xloc.bar_time, extend=extend.none, color=c361, width=2)
l461 := line.new(t1, y461, t2, y461, xloc=xloc.bar_time, extend=extend.none, color=c461, width=2)
lf := linefill.new(l95, l105, color= show95_105 ? colBandFill : color.new(color.black, 100))
array.push(FE_l95, l95)
array.push(FE_l105, l105)
array.push(FE_l161, l161)
array.push(FE_l261, l261)
array.push(FE_l361, l361)
array.push(FE_l461, l461)
array.push(FE_fill, lf)
array.push(FE_born, bar_index)
f_find_abs_by_time(t) =>
int bestAbs = na
if na(t)
na
else
int maxBack = math.min(5000, bar_index)
int bestDiff = 1000000000
for i = 0 to maxBack
int ti = time
int diff = ti > t ? (ti - t) : (t - ti)
if diff < bestDiff
bestDiff := diff
bestAbs := bar_index - i
bestAbs
//──────────────────────────────── P3 picker (แบบเดิม/คลาสสิก) ─────────────────────
f_pickP3_abs(sAbs, eAbs, isLong) =>
if na(sAbs) or na(eAbs)
[na, na]
else
int eInit = math.min(eAbs, bar_index)
int sInit = sAbs
int s = math.max(sInit, bar_index - 10000)
int e = eInit
if s > e
[na, na]
else
float[] levels = array.new_float()
int[] counts = array.new_int()
int[] firstI = array.new_int()
int[] maxRun = array.new_int()
float prevBin = na
int curRun = 0
float minLowGreen = 1e100
int minLowGreenI = na
float minLowRed = 1e100
int minLowRedI = na
float minLowAll = 1e100
int minLowAllI = na
float maxHighRed = -1e100
int maxHighRedI = na
float maxHighGreen = -1e100
int maxHighGreenI= na
float maxHighAll = -1e100
int maxHighAllI = na
for t = s to e
int tOff = bar_index - t
if tOff < 0 or tOff > 10000
continue
float bin = math.round(open[tOff] / syminfo.mintick) * syminfo.mintick
int idx = array.indexof(levels, bin)
if idx == -1
array.push(levels, bin)
array.push(counts, 1)
array.push(firstI, t)
array.push(maxRun, 1)
curRun := 1
else
array.set(counts, idx, array.get(counts, idx) + 1)
if not na(prevBin) and bin == prevBin
curRun += 1
else
curRun := 1
int prevMax = array.get(maxRun, idx)
if curRun > prevMax
array.set(maxRun, idx, curRun)
prevBin := bin
// ... (ส่วนท้ายของ f_pickP3_abs เดิม)
int needCnt = 2
int best = -1, bestCnt = 0, bestRun = 0, bestFirst = 1000000000
int L = array.size(levels)
if L > 0
for m = 0 to L - 1
int c = array.get(counts, m)
if c >= needCnt
int r = array.get(maxRun, m)
int f = array.get(firstI, m)
if c > bestCnt or (c == bestCnt and (r > bestRun or (r == bestRun and f < bestFirst)))
best := m
bestCnt := c
bestRun := r
bestFirst := f
if best != -1
int pickAbs = array.get(firstI, best)
float pickPx = array.get(levels, best)
[pickPx, pickAbs]
else
if isLong
// เลือกจาก logic เดิม (ย่อ)
float minLowGreen = 1e100
int minLowGreenI = na
float minLowRed = 1e100
int minLowRedI = na
float minLowAll = 1e100
int minLowAllI = na
for t2 = s to e
int toff2 = bar_index - t2
if toff2 < 0 or toff2 > 10000
continue
bool g = close[toff2] > open[toff2]
bool r = close[toff2] < open[toff2]
if g and low[toff2] < minLowGreen
minLowGreen := low[toff2]
minLowGreenI := t2
if r and low[toff2] < minLowRed
minLowRed := low[toff2]
minLowRedI := t2
if low[toff2] < minLowAll
minLowAll := low[toff2]
minLowAllI := t2
bool redIsGlobalMin = not na(minLowRedI) and (minLowRed <= minLowAll + 0.0)
if redIsGlobalMin
int offR = bar_index - minLowRedI
[close[offR], minLowRedI]
else
int useAbs = na(minLowGreenI) ? minLowAllI : minLowGreenI
int offU = bar_index - useAbs
[open[offU], useAbs]
else
float maxHighRed = -1e100
int maxHighRedI = na
float maxHighGreen = -1e100
int maxHighGreenI= na
float maxHighAll = -1e100
int maxHighAllI = na
for t3 = s to e
int toff3 = bar_index - t3
if toff3 < 0 or toff3 > 10000
continue
bool g2 = close[toff3] > open[toff3]
bool r2 = close[toff3] < open[toff3]
if r2 and high[toff3] > maxHighRed
maxHighRed := high[toff3]
maxHighRedI := t3
if g2 and high[toff3] > maxHighGreen
maxHighGreen := high[toff3]
maxHighGreenI:= t3
if high[toff3] > maxHighAll
maxHighAll := high[toff3]
maxHighAllI := t3
bool greenIsGlobalMax = not na(maxHighGreenI) and (maxHighGreen >= maxHighAll - 0.0)
if greenIsGlobalMax
int offG = bar_index - maxHighGreenI
[close[offG], maxHighGreenI]
else
int useAbsS = na(maxHighRedI) ? maxHighAllI : maxHighRedI
int offS = bar_index - useAbsS
[open[offS], useAbsS]
//──────────────────────────────── P1/P2/P3 (Auto; state) ────────────────
// LONG state vars
var int L_P1Abs = int(na)
var int L_P2Abs = int(na)
var int L_P3Abs = int(na)
var int L_winOpenAbs = int(na)
var float L_P1Open = na
var float L_P2Close = na
var float L_P3Px = na
var float L_P2_bodyTop = na
var float L_P2_bodyBot = na
// SHORT state vars
var int S_P1Abs = int(na)
var int S_P2Abs = int(na)
var int S_P3Abs = int(na)
var int S_winOpenAbs = int(na)
var float S_P1Open = na
var float S_P2Close = na
var float S_P3Px = na
var float S_P2_bodyTop = na
var float S_P2_bodyBot = na
// draw-set containers
var box[] L_SET_BOX = array.new_box()
var label[] L_SET_LBL = array.new_label()
var box[] S_SET_BOX = array.new_box()
var label[] S_SET_LBL = array.new_label()
// scanners
var bool L_seek = false
var bool L_confirmActive = false
var int L_runMaxAbs = int(na)
var float L_runMaxClose = na
var int L_candAbs = int(na)
var float L_candClose = na
var bool S_seek = false
var bool S_confirmActive = false
var int S_runMinAbs = int(na)
var float S_runMinClose = na
var int S_candAbs = int(na)
var float S_candClose = na
// LONG: seed/confirm P2 (UPDATED: ต้องทั้งแท่งอยู่เหนือ fiveUp_200)
if not L_seek and not L_confirmActive
float __btL = math.max(open, close)
float __bbL = math.min(open, close)
float __fiveL = fiveUp_200
bool startLongSeed = close > open and not na(__fiveL) and (__bbL >= __fiveL)
if startLongSeed
L_seek := true
L_runMaxAbs := bar_index
L_runMaxClose := close
if L_confirmActive
if close > L_candClose and close > open
L_seek := true
L_confirmActive := false
L_candAbs := int(na)
L_candClose := na
L_runMaxAbs := bar_index
L_runMaxClose := close
else if bar_index >= L_candAbs + rightWinBars
bool acceptL = true
// ตรวจซ้ำที่แท่งผู้สมัคร (ทั้งแท่งต้องอยู่เหนือ fiveUp_200)
int offCandL = bar_index - L_candAbs
float _btL = math.max(open[offCandL], close[offCandL])
float _bbL = math.min(open[offCandL], close[offCandL])
float _fiveL = fiveUp_200[offCandL]
bool bodyAbove5 = not na(_fiveL) and (_bbL >= _fiveL)
acceptL := acceptL and bodyAbove5
if not na(L_prevP2Abs)
int dBarsL = L_candAbs - L_prevP2Abs
if dBarsL <= p2NewWithinBars
acceptL := acceptL and (L_candClose > L_prevP2Close)
if not acceptL
L_seek := true
L_confirmActive := false
L_runMaxAbs := bar_index
L_runMaxClose := close
L_candAbs := int(na)
L_candClose := na
else
array.clear(L_SET_BOX)
array.clear(L_SET_LBL)
L_P2Abs := L_candAbs
resetReqAllL := false
resetReqP1L := false
resetReqP2L := false
resetReqP3L := false
int offP2 = bar_index - L_P2Abs
L_P2Close := close[offP2]
L_P2_bodyTop := math.max(open[offP2], close[offP2])
L_P2_bodyBot := math.min(open[offP2], close[offP2])
L_prevP2Abs := L_P2Abs
L_prevP2Close := L_P2Close
[bxP2, lbP2] = f_draw_mark_group(L_P2Abs, false, P2BoxColor, P2BoxFillTransp, BoxBorderTransp, showP2Label, "P2", true)
[keepNewP2L, _newAbsP2L, _newBoxP2L, _newLblP2L] = f_enforce_and_set(L_P2Abs, bxP2, lbP2, L_lastP2Abs, L_lastP2Box, L_lastP2Lbl)
if keepNewP2L
L_lastP2Abs := _newAbsP2L
L_lastP2Box := _newBoxP2L
L_lastP2Lbl := _newLblP2L
f_del_if_exists(L_lastP3Box, L_lastP3Lbl)
L_lastP3Abs := int(na)
L_lastP3Box := na
L_lastP3Lbl := na
L_P3Abs := int(na)
L_P3Px := na
f_clear_all_fe()
L_winOpenAbs := L_P2Abs + 1
int bestAbs = int(na)
float bestDist = na
for k = 1 to 50
int a = L_P2Abs - k
if a < 0
break
int off = bar_index - a
if off < 0 or off > 5000
continue
if close[off] <= open[off]
continue
float ema5u85 = fiveUp_85[off]
if na(ema5u85)
continue
float bt = math.max(open[off], close[off])
float bb = math.min(open[off], close[off])
float body = bt - bb
float fracAbove = body <= 0 ? 0.0 : math.max(0.0, bt - math.max(bb, ema5u85))/body
if fracAbove >= 0.25
float d = math.abs(mid200[off] - (bt+bb)/2.0)
if na(bestDist) or d < bestDist or (d == bestDist and (na(bestAbs) or a < bestAbs))
bestDist := d
bestAbs := a
if not na(bestAbs) and f_gap_ok_left(bestAbs, L_P2Abs)
int offb = bar_index - bestAbs
L_P1Open := open[offb]
L_P1Abs := bestAbs
[bxP1, lbP1] = f_draw_mark_group(L_P1Abs, false, P1BoxColor, P1BoxFillTransp, BoxBorderTransp, showP1Label, "P1", true)
[keepNewP1L, _newAbsP1L, _newBoxP1L, _newLblP1L] = f_enforce_and_set(L_P1Abs, bxP1, lbP1, L_lastP1Abs, L_lastP1Box, L_lastP1Lbl)
if keepNewP1L
L_lastP1Abs := _newAbsP1L
L_lastP1Box := _newBoxP1L
L_lastP1Lbl := _newLblP1L
L_seek := false
L_confirmActive := false
L_candAbs := int(na)
L_candClose := na
L_runMaxAbs := int(na)
L_runMaxClose := na
if L_seek and not L_confirmActive
if close > open
if close > nz(L_runMaxClose, -1e100)
L_runMaxClose := close
L_runMaxAbs := bar_index
else if close < nz(L_runMaxClose, 1e100)
L_candAbs := L_runMaxAbs
L_candClose := L_runMaxClose
L_seek := false
L_confirmActive := true
else if open < nz(L_runMaxClose, 1e100)
L_candAbs := L_runMaxAbs
L_candClose := L_runMaxClose
L_seek := false
L_confirmActive := true
// SHORT: seed/confirm P2 (UPDATED: ต้องทั้งแท่งอยู่ใต้ fiveDown_200)
if not S_seek and not S_confirmActive
float __btS = math.max(open, close)
float __bbS = math.min(open, close)
float __fiveS = fiveDown_200
bool startShortSeed = close < open and not na(__fiveS) and (__btS <= __fiveS)
if startShortSeed
S_seek := true
S_runMinAbs := bar_index
S_runMinClose := close
if S_confirmActive
if close < S_candClose and close < open
S_seek := true
S_confirmActive := false
S_candAbs := int(na)
S_candClose := na
S_runMinAbs := bar_index
S_runMinClose := close
else if bar_index >= S_candAbs + rightWinBars
bool acceptS = true
// ตรวจซ้ำที่แท่งผู้สมัคร (ทั้งแท่งต้องอยู่ใต้ fiveDown_200)
int offCandS = bar_index - S_candAbs
float _btS = math.max(open[offCandS], close[offCandS])
float _bbS = math.min(open[offCandS], close[offCandS])
float _fiveS = fiveDown_200[offCandS]
bool bodyBelow5 = not na(_fiveS) and (_btS <= _fiveS)
acceptS := acceptS and bodyBelow5
if not na(S_prevP2Abs)
int dBarsS = S_candAbs - S_prevP2Abs
if dBarsS <= p2NewWithinBars
acceptS := acceptS and (S_candClose < S_prevP2Close)
if not acceptS
S_seek := true
S_confirmActive := false
S_runMinAbs := bar_index
S_runMinClose := close
S_candAbs := int(na)
S_candClose := na
else
array.clear(S_SET_BOX)
array.clear(S_SET_LBL)
S_P2Abs := S_candAbs
resetReqAllS := false
resetReqP1S := false
resetReqP2S := false
resetReqP3S := false
int offP2s = bar_index - S_P2Abs
S_P2Close := close[offP2s]
S_P2_bodyTop := math.max(open[offP2s], close[offP2s])
S_P2_bodyBot := math.min(open[offP2s], close[offP2s])
S_prevP2Abs := S_P2Abs
S_prevP2Close := S_P2Close
[bxP2s, lbP2s] = f_draw_mark_group(S_P2Abs, false, P2BoxColor, P2BoxFillTransp, BoxBorderTransp, showP2Label, "P2", false)
[keepNewP2S, _newAbsP2S, _newBoxP2S, _newLblP2S] = f_enforce_and_set(S_P2Abs, bxP2s, lbP2s, S_lastP2Abs, S_lastP2Box, S_lastP2Lbl)
if keepNewP2S
S_lastP2Abs := _newAbsP2S
S_lastP2Box := _newBoxP2S
S_lastP2Lbl := _newLblP2S
f_del_if_exists(S_lastP3Box, S_lastP3Lbl)
S_lastP3Abs := int(na)
S_lastP3Box := na
S_lastP3Lbl := na
S_P3Abs := int(na)
S_P3Px := na
f_clear_all_fe()
S_winOpenAbs := S_P2Abs + 1
int bestAbsS = int(na)
float bestDistS = na
for k = 1 to 50
int a = S_P2Abs - k
if a < 0
break
int off = bar_index - a
if off < 0 or off > 5000
continue
if close[off] >= open[off]
continue
float ema5d85 = fiveDown_85[off]
if na(ema5d85)
continue
float bt = math.max(open[off], close[off])
float bb = math.min(open[off], close[off])
float body = bt - bb
float fracBelow = body <= 0 ? 0.0 : math.max(0.0, math.min(bt, ema5d85) - bb)/body
if fracBelow >= 0.25
float d = math.abs(mid200[off] - (bt+bb)/2.0)
if na(bestDistS) or d < bestDistS or (d == bestDistS and (na(bestAbsS) or a < bestAbsS))
bestDistS := d
bestAbsS := a
if not na(bestAbsS) and f_gap_ok_left(bestAbsS, S_P2Abs)
int offb = bar_index - bestAbsS
S_P1Open := open[offb]
S_P1Abs := bestAbsS
[bxP1s, lbP1s] = f_draw_mark_group(S_P1Abs, false, P1BoxColor, P1BoxFillTransp, BoxBorderTransp, showP1Label, "P1", false)
[keepNewP1S, _newAbsP1S, _newBoxP1S, _newLblP1S] = f_enforce_and_set(S_P1Abs, bxP1s, lbP1s, S_lastP1Abs, S_lastP1Box, S_lastP1Lbl)
if keepNewP1S
S_lastP1Abs := _newAbsP1S
S_lastP1Box := _newBoxP1S
S_lastP1Lbl := _newLblP1S
S_seek := false
S_confirmActive := false
S_candAbs := int(na)
S_candClose := na
S_runMinAbs := int(na)
S_runMinClose := na
if S_seek and not S_confirmActive
if close < open
if close < nz(S_runMinClose, 1e100)
S_runMinClose := close
S_runMinAbs := bar_index
else if close > nz(S_runMinClose, -1e100)
S_candAbs := S_runMinAbs
S_candClose := S_runMinClose
S_seek := false
S_confirmActive := true
else if open > nz(S_runMinClose, -1e100)
S_candAbs := S_runMinAbs
S_candClose := S_runMinClose
S_seek := false
S_confirmActive := true
// ---------- LONG: close P3 window (classic picker) ----------
if not na(L_winOpenAbs)
int sAbs = L_winOpenAbs
int eAbs = bar_index
float rangeBody = L_P2_bodyTop - L_P2_bodyBot
float T33 = L_P2_bodyBot + rangeBody/3.0
float T75 = L_P2_bodyBot + rangeBody*0.75
int barsInWin = bar_index - L_winOpenAbs + 1
bool allowNormal = barsInWin >= 5 and close > open and close >= T33
bool allowEarly = barsInWin < 5 and close > open and close >= T75
if allowNormal or allowEarly
[p3PxL_tmp, p3AbsL] = f_pickP3_abs(sAbs, eAbs, true)
if not na(p3AbsL) and f_gap_ok_right(p3AbsL, L_P2Abs)
L_P3Abs := p3AbsL
L_P3Px := p3PxL_tmp
[bxP3, lbP3] = f_draw_mark_group(L_P3Abs, false, P3BoxColor, P3BoxFillTransp, BoxBorderTransp, showP3Label, "P3", true)
[keepNewP3L, _newAbsP3L, _newBoxP3L, _newLblP3L] = f_enforce_and_set(L_P3Abs, bxP3, lbP3, L_lastP3Abs, L_lastP3Box, L_lastP3Lbl)
if keepNewP3L
L_lastP3Abs := _newAbsP3L
L_lastP3Box := _newBoxP3L
L_lastP3Lbl := _newLblP3L
if showFE and not na(L_P1Open) and not na(L_P2Close)
float W = L_P2Close - L_P1Open
if W > 0
float y95 = f_rt(L_P3Px + 0.95 * W)
float y105 = f_rt(L_P3Px + 1.05 * W)
float y1618 = f_rt(L_P3Px + 1.618 * W)
float y2618 = f_rt(L_P3Px + 2.618 * W)
float y3618 = f_rt(L_P3Px + 3.618 * W)
float y4618 = f_rt(L_P3Px + 4.618 * W)
f_clear_all_fe()
f_add_fe_set(L_P3Abs, y95, y105, y1618, y2618, y3618, y4618)
L_winOpenAbs := int(na)
// ---------- SHORT: close P3 window (classic picker) ----------
if not na(S_winOpenAbs)
int sAbsS = S_winOpenAbs
int eAbsS = bar_index
float rangeBodyS = S_P2_bodyTop - S_P2_bodyBot
float T33d = S_P2_bodyTop - rangeBodyS/3.0
float T75d = S_P2_bodyTop - rangeBodyS*0.75
int barsInWinS = bar_index - S_winOpenAbs + 1
bool allowNormalS = barsInWinS >= 5 and close < open and close <= T33d
bool allowEarlyS = barsInWinS < 5 and close < open and close <= T75d
if allowNormalS or allowEarlyS
[p3PxS_tmp, p3AbsS] = f_pickP3_abs(sAbsS, eAbsS, false)
if not na(p3AbsS) and f_gap_ok_right(p3AbsS, S_P2Abs)
S_P3Abs := p3AbsS
S_P3Px := p3PxS_tmp
[bxP3s, lbP3s] = f_draw_mark_group(S_P3Abs, false, P3BoxColor, P3BoxFillTransp, BoxBorderTransp, showP3Label, "P3", false)
[keepNewP3S, _newAbsP3S, _newBoxP3S, _newLblP3S] = f_enforce_and_set(S_P3Abs, bxP3s, lbP3s, S_lastP3Abs, S_lastP3Box, S_lastP3Lbl)
if keepNewP3S
S_lastP3Abs := _newAbsP3S
S_lastP3Box := _newBoxP3S
S_lastP3Lbl := _newLblP3S
if showFE and not na(S_P1Open) and not na(S_P2Close)
float Ws = S_P2Close - S_P1Open
if Ws < 0
float y95s = f_rt(S_P3Px + 0.95 * Ws)
float y105s = f_rt(S_P3Px + 1.05 * Ws)
float y1618s = f_rt(S_P3Px + 1.618 * Ws)
float y2618s = f_rt(S_P3Px + 2.618 * Ws)
float y3618s = f_rt(S_P3Px + 3.618 * Ws)
float y4618s = f_rt(S_P3Px + 4.618 * Ws)
f_clear_all_fe()
f_add_fe_set(S_P3Abs, y95s, y105s, y1618s, y2618s, y3618s, y4618s)
S_winOpenAbs := int(na)
//──────────────────────────────── Manual Layer (+ Reset Latches) ─────────────────────
f_pick_abs_from_manual(_use, _pickMode, _time, _offset) =>
if not _use
na
else
_pickMode == PK_TIME ? f_find_abs_by_time(_time) : (bar_index + _offset)
f_pick_price_from_manual(_use, _abs, _pmode, _custom) =>
if not _use or na(_abs)
na
else
int off = bar_index - _abs
off < 0 or off > 5000 ? na : f_price_by_mode(off, _pmode, _custom)
useP1L_eff = useManP1L and not (resetReqAllL or resetReqP1L)
useP2L_eff = useManP2L and not (resetReqAllL or resetReqP2L)
useP3L_eff = useManP3L and not (resetReqAllL or resetReqP3L)
useP1S_eff = useManP1S and not (resetReqAllS or resetReqP1S)
useP2S_eff = useManP2S and not (resetReqAllS or resetReqP2S)
useP3S_eff = useManP3S and not (resetReqAllS or resetReqP3S)
// Effective ABS
int L_P1Abs_eff = useP1L_eff ? f_pick_abs_from_manual(useP1L_eff, pickP1L, manP1L_t, manP1L_of) : L_P1Abs
int L_P2Abs_eff = useP2L_eff ? f_pick_abs_from_manual(useP2L_eff, pickP2L, manP2L_t, manP2L_of) : L_P2Abs
int L_P3Abs_eff = useP3L_eff ? f_pick_abs_from_manual(useP3L_eff, pickP3L, manP3L_t, manP3L_of) : L_P3Abs
int S_P1Abs_eff = useP1S_eff ? f_pick_abs_from_manual(useP1S_eff, pickP1S, manP1S_t, manP1S_of) : S_P1Abs
int S_P2Abs_eff = useP2S_eff ? f_pick_abs_from_manual(useP2S_eff, pickP2S, manP2S_t, manP2S_of) : S_P2Abs
int S_P3Abs_eff = useP3S_eff ? f_pick_abs_from_manual(useP3S_eff, pickP3S, manP3S_t, manP3S_of) : S_P3Abs
// Effective Prices
float L_P1Open_eff = useP1L_eff ? f_pick_price_from_manual(useP1L_eff, L_P1Abs_eff, pmP1L, p1L_custom) : L_P1Open
float L_P2Close_eff = useP2L_eff ? f_pick_price_from_manual(useP2L_eff, L_P2Abs_eff, pmP2L, p2L_custom) : L_P2Close
float L_P3Px_eff = useP3L_eff ? f_pick_price_from_manual(useP3L_eff, L_P3Abs_eff, pmP3L, p3L_custom) : L_P3Px
float S_P1Open_eff = useP1S_eff ? f_pick_price_from_manual(useP1S_eff, S_P1Abs_eff, pmP1S, p1S_custom) : S_P1Open
float S_P2Close_eff = useP2S_eff ? f_pick_price_from_manual(useP2S_eff, S_P2Abs_eff, pmP2S, p2S_custom) : S_P2Close
float S_P3Px_eff = useP3S_eff ? f_pick_price_from_manual(useP3S_eff, S_P3Abs_eff, pmP3S, p3S_custom) : S_P3Px
// Redraw labels/boxes if manual in effect (apply de-dup too) — with GAP RULE
bool needRedrawL = useP1L_eff or useP2L_eff or useP3L_eff
bool needRedrawS = useP1S_eff or useP2S_eff or useP3S_eff
if needRedrawL
f_delete_boxes(L_SET_BOX)
f_delete_labels(L_SET_LBL)
if not na(L_P1Abs_eff) and not na(L_P2Abs_eff) and f_gap_ok_left(L_P1Abs_eff, L_P2Abs_eff) and showP1Label
[bx1, lb1] = f_draw_mark_group(L_P1Abs_eff, false, P1BoxColor, P1BoxFillTransp, BoxBorderTransp, true, "P1", true)
[keepP1L_m, nAbsP1L_m, nBoxP1L_m, nLblP1L_m] = f_enforce_and_set(L_P1Abs_eff, bx1, lb1, L_lastP1Abs, L_lastP1Box, L_lastP1Lbl)
if keepP1L_m
L_lastP1Abs := nAbsP1L_m
L_lastP1Box := nBoxP1L_m
L_lastP1Lbl := nLblP1L_m
if not na(L_P2Abs_eff) and showP2Label
[bx2, lb2] = f_draw_mark_group(L_P2Abs_eff, false, P2BoxColor, P2BoxFillTransp, BoxBorderTransp, true, "P2", true)
[keepP2L_m, nAbsP2L_m, nBoxP2L_m, nLblP2L_m] = f_enforce_and_set(L_P2Abs_eff, bx2, lb2, L_lastP2Abs, L_lastP2Box, L_lastP2Lbl)
if keepP2L_m
L_lastP2Abs := nAbsP2L_m
L_lastP2Box := nBoxP2L_m
L_lastP2Lbl := nLblP2L_m
if not na(L_P3Abs_eff) and not na(L_P2Abs_eff) and f_gap_ok_right(L_P3Abs_eff, L_P2Abs_eff) and showP3Label
[bx3, lb3] = f_draw_mark_group(L_P3Abs_eff, false, P3BoxColor, P3BoxFillTransp, BoxBorderTransp, true, "P3", true)
[keepP3L_m, nAbsP3L_m, nBoxP3L_m, nLblP3L_m] = f_enforce_and_set(L_P3Abs_eff, bx3, lb3, L_lastP3Abs, L_lastP3Box, L_lastP3Lbl)
if keepP3L_m
L_lastP3Abs := nAbsP3L_m
L_lastP3Box := nBoxP3L_m
L_lastP3Lbl := nLblP3L_m
if needRedrawS
f_delete_boxes(S_SET_BOX)
f_delete_labels(S_SET_LBL)
if not na(S_P1Abs_eff) and not na(S_P2Abs_eff) and f_gap_ok_left(S_P1Abs_eff, S_P2Abs_eff) and showP1Label
[bx1s, lb1s] = f_draw_mark_group(S_P1Abs_eff, false, P1BoxColor, P1BoxFillTransp, BoxBorderTransp, true, "P1", false)
[keepP1S_m, nAbsP1S_m, nBoxP1S_m, nLblP1S_m] = f_enforce_and_set(S_P1Abs_eff, bx1s, lb1s, S_lastP1Abs, S_lastP1Box, S_lastP1Lbl)
if keepP1S_m
S_lastP1Abs := nAbsP1S_m
S_lastP1Box := nBoxP1S_m
S_lastP1Lbl := nLblP1S_m
if not na(S_P2Abs_eff) and showP2Label
[bx2s, lb2s] = f_draw_mark_group(S_P2Abs_eff, false, P2BoxColor, P2BoxFillTransp, BoxBorderTransp, true, "P2", false)
[keepP2S_m, nAbsP2S_m, nBoxP2S_m, nLblP2S_m] = f_enforce_and_set(S_P2Abs_eff, bx2s, lb2s, S_lastP2Abs, S_lastP2Box, S_lastP2Lbl)
if keepP2S_m
S_lastP2Abs := nAbsP2S_m
S_lastP2Box := nBoxP2S_m
S_lastP2Lbl := nLblP2S_m
if not na(S_P3Abs_eff) and not na(S_P2Abs_eff) and f_gap_ok_right(S_P3Abs_eff, S_P2Abs_eff) and showP3Label
[bx3s, lb3s] = f_draw_mark_group(S_P3Abs_eff, false, P3BoxColor, P3BoxFillTransp, BoxBorderTransp, true, "P3", false)
[keepP3S_m, nAbsP3S_m, nBoxP3S_m, nLblP3S_m] = f_enforce_and_set(S_P3Abs_eff, bx3s, lb3s, S_lastP3Abs, S_lastP3Box, S_lastP3Lbl)
if keepP3S_m
S_lastP3Abs := nAbsP3S_m
S_lastP3Box := nBoxP3S_m
S_lastP3Lbl := nLblP3S_m
// FE from effective points (Manual precedence) — add GAP RULE
bool canFE_L = showFE and not na(L_P1Open_eff) and not na(L_P2Close_eff) and not na(L_P3Px_eff) and not na(L_P1Abs_eff) and not na(L_P2Abs_eff) and not na(L_P3Abs_eff) and f_gap_ok_left(L_P1Abs_eff, L_P2Abs_eff) and f_gap_ok_right(L_P3Abs_eff, L_P2Abs_eff)
bool canFE_S = showFE and not na(S_P1Open_eff) and not na(S_P2Close_eff) and not na(S_P3Px_eff) and not na(S_P1Abs_eff) and not na(S_P2Abs_eff) and not na(S_P3Abs_eff) and f_gap_ok_left(S_P1Abs_eff, S_P2Abs_eff) and f_gap_ok_right(S_P3Abs_eff, S_P2Abs_eff)
if canFE_L
float W = L_P2Close_eff - L_P1Open_eff
if W > 0
float y95 = f_rt(L_P3Px_eff + 0.95 * W)
float y105 = f_rt(L_P3Px_eff + 1.05 * W)
float y1618 = f_rt(L_P3Px_eff + 1.618 * W)
float y2618 = f_rt(L_P3Px_eff + 2.618 * W)
float y3618 = f_rt(L_P3Px_eff + 3.618 * W)
float y4618 = f_rt(L_P3Px_eff + 4.618 * W)
f_clear_all_fe()
f_add_fe_set(L_P3Abs_eff, y95, y105, y1618, y2618, y3618, y4618)
else if canFE_S
float Ws = S_P2Close_eff - S_P1Open_eff
if Ws < 0
float y95s = f_rt(S_P3Px_eff + 0.95 * Ws)
float y105s = f_rt(S_P3Px_eff + 1.05 * Ws)
float y1618s = f_rt(S_P3Px_eff + 1.618 * Ws)
float y2618s = f_rt(S_P3Px_eff + 2.618 * Ws)
float y3618s = f_rt(S_P3Px_eff + 3.618 * Ws)
float y4618s = f_rt(S_P3Px_eff + 4.618 * Ws)
f_clear_all_fe()
f_add_fe_set(S_P3Abs_eff, y95s, y105s, y1618s, y2618s, y3618s, y4618s)
// FE lifespan cleanup
int nBorn = array.size(FE_born)
if nBorn > 0
for k = 0 to nBorn - 1
int idx = nBorn - 1 - k
int born = array.get(FE_born, idx)
if bar_index - born > feLife
f_delete_fe_index(idx)
// Candle coloring
bool isP1_bar = (not na(L_P1Abs_eff) and bar_index == L_P1Abs_eff) or (not na(S_P1Abs_eff) and bar_index == S_P1Abs_eff)
bool isP2_bar = (not na(L_P2Abs_eff) and bar_index == L_P2Abs_eff) or (not na(S_P2Abs_eff) and bar_index == S_P2Abs_eff)
bool isP3_bar = (not na(L_P3Abs_eff) and bar_index == L_P3Abs_eff) or (not na(S_P3Abs_eff) and bar_index == S_P3Abs_eff)
color _candleCol = na
_candleCol := isP3_bar ? colP3Candle : (isP2_bar ? colP2Candle : (isP1_bar ? colP1Candle : na))
barcolor(recolorBars ? _candleCol : na)
// Reserve style slot
plot(showFE ? na : na, title="fe-slot")
//──────────────────────────────── di (DSI; masked) ───────────────────────────
float dsi_atr = ta.atr(14)
float dsi_highestBody = open > close ? open : close
float dsi_lowestBody = open > close ? close : open
var float dsi_res1 = na
var float dsi_res2 = na
var float dsi_sup1 = na
var float dsi_sup2 = na
var bool dsi_lookForNewResistance = true
var bool dsi_lookForNewSupport = true
var float dsi_prevRes1 = na
var float dsi_prevRes2 = na
var float dsi_prevSup1 = na
var float dsi_prevSup2 = na
var float dsi_atrSaved = na
var float dsi_potR1 = na
var float dsi_potR2 = na
var float dsi_potS1 = na
var float dsi_potS2 = na
if high[1] == ta.highest(high, lookback) and high < high[1] and dsi_lookForNewResistance
float r1 = high[1]
float hb2 = (open[2] > close[2] ? open[2] : close[2])
float hb1 = (open[1] > close[1] ? open[1] : close[1])
float hb0 = (open > close ? open : close)
float r2 = hb2 > hb1 ? hb2 : (hb0 > hb1 ? hb0 : hb1)
if (r1 - r2) / dsi_atr <= maxZoneSize
dsi_lookForNewResistance := false
dsi_potR1 := r1
dsi_potR2 := r2
dsi_atrSaved := dsi_atr
if low[1] == ta.lowest(low, lookback) and low > low[1] and dsi_lookForNewSupport
float s1 = low[1]
float lb2 = (open[2] > close[2] ? close[2] : open[2])
float lb1 = (open[1] > close[1] ? close[1] : open[1])
float lb0 = (open > close ? close : open)
float s2 = lb2 < lb1 ? lb2 : (lb0 < lb1 ? lb0 : lb1)
if (s2 - s1) / dsi_atr <= maxZoneSize
dsi_lookForNewSupport := false
dsi_potS1 := s1
dsi_potS2 := s2
dsi_atrSaved := dsi_atr
if close > dsi_potR1 and barstate.isconfirmed
dsi_potR1 := na
dsi_potR2 := na
if close < dsi_potS1 and barstate.isconfirmed
dsi_potS1 := na
dsi_potS2 := na
if not na(dsi_potR1) and dsi_potR1 - low >= (nz(dsi_atrSaved, dsi_atr) * atrMovement)
dsi_prevRes1 := na(dsi_prevRes1) ? dsi_potR1 : dsi_prevRes1
dsi_prevRes2 := na(dsi_prevRes2) ? dsi_potR2 : dsi_prevRes2
dsi_res1 := dsi_potR1
dsi_res2 := dsi_potR2
dsi_potR1 := na
dsi_potR2 := na
if not na(dsi_potS1) and high - dsi_potS1 >= (nz(dsi_atrSaved, dsi_atr) * atrMovement)
dsi_prevSup1 := na(dsi_prevSup1) ? dsi_potS1 : dsi_prevSup1
dsi_prevSup2 := na(dsi_prevSup2) ? dsi_potS2 : dsi_prevSup2
dsi_sup1 := dsi_potS1
dsi_sup2 := dsi_potS2
dsi_potS1 := na
dsi_potS2 := na
var int dsi_supCount = 0
var int dsi_resCount = 0
if close >= dsi_res1 and barstate.isconfirmed
dsi_lookForNewResistance := true
dsi_lookForNewSupport := true
dsi_resCount += 1
if close <= dsi_sup1 and barstate.isconfirmed
dsi_lookForNewSupport := true
dsi_lookForNewResistance := true
dsi_supCount += 1
if (close > dsi_res1 and na(dsi_prevRes1) and barstate.isconfirmed) or na(dsi_prevRes1) or dsi_resCount >= newStructureReset
dsi_prevRes1 := dsi_res1
dsi_prevRes2 := dsi_res2
dsi_resCount := 0
if (close < dsi_sup1 and na(dsi_prevSup1) and barstate.isconfirmed) or na(dsi_prevSup1) or dsi_supCount >= newStructureReset
dsi_prevSup1 := dsi_sup1
dsi_prevSup2 := dsi_sup2
dsi_supCount := 0
if close < dsi_prevRes2 and barstate.isconfirmed
dsi_prevRes1 := na
dsi_prevRes2 := na
if close > dsi_prevSup2 and barstate.isconfirmed
dsi_prevSup1 := na
dsi_prevSup2 := na
dsi_r1plot = plot(showDSI and (dsi_res1 == dsi_res1[1]) ? dsi_res1 : na, color=close >= dsi_res1 ? dsiBullColor : dsiBearColor, style=plot.style_linebr, title="di R1")
dsi_r2plot = plot(showDSI and (dsi_res1 == dsi_res1[1]) ? dsi_res2 : na, color=close >= dsi_res1 ? dsiBullColor : dsiBearColor, style=plot.style_linebr, title="di R2")
fill(dsi_r1plot, dsi_r2plot, color=showDSI ? (close > dsi_res1 ? dsiBullColor : color.new(dsiBearColor, 50)) : color.new(color.black, 100), title="di Resistance Zone")
dsi_s1plot = plot(showDSI and (dsi_sup1 == dsi_sup1[1]) ? dsi_sup1 : na, color=close < dsi_sup1 ? dsiBearColor : dsiBullColor, style=plot.style_linebr, title="di S1")
dsi_s2plot = plot(showDSI and (dsi_sup1 == dsi_sup1[1]) ? dsi_sup2 : na, color=close < dsi_sup1 ? dsiBearColor : dsiBullColor, style=plot.style_linebr, title="di S2")
fill(dsi_s1plot, dsi_s2plot, color=showDSI ? (close < dsi_sup1 ? dsiBearColor : color.new(dsiBullColor, 50)) : color.new(color.black, 100), title="di Support Zone")
dsi_ps1plot = plot(showDSI and drawPreviousStructure and (dsi_prevSup1 == dsi_prevSup1[1]) and (dsi_prevSup1 != dsi_sup1) ? dsi_prevSup1 : na, color=dsiBearColor, style=plot.style_linebr, title="di PS1")
dsi_ps2plot = plot(showDSI and drawPreviousStructure and (dsi_prevSup1 == dsi_prevSup1[1]) and (dsi_prevSup1 != dsi_sup1) ? dsi_prevSup2 : na, color=dsiBearColor, style=plot.style_linebr, title="di PS2")
fill(dsi_ps1plot, dsi_ps2plot, color=showDSI and drawPreviousStructure ? color.new(dsiBearColor, 10) : color.new(color.black, 100), title="di Previous Support Zone")
dsi_pr1plot = plot(showDSI and drawPreviousStructure and (dsi_prevRes1 == dsi_prevRes1[1]) and (dsi_prevRes1 != dsi_res1) ? dsi_prevRes1 : na, color=dsiBullColor, style=plot.style_linebr, title="di PR1")
dsi_pr2plot = plot(showDSI and drawPreviousStructure and (dsi_prevRes1 == dsi_prevRes1[1]) and (dsi_prevRes1 != dsi_res1) ? dsi_prevRes2 : na, color=dsiBullColor, style=plot.style_linebr, title="di Previous Resistance Zone")
//────────────────────────── Elliptic Bands (masked, locked) ──────────────────────────
groupEllipse = "es bands"
EB_show = input.bool(true, "show es bands", group=groupEllipse)
EB_midColor = input.color(color.rgb(229,236,241), "mid color", group=groupEllipse)
EB_upColor = input.color(color.green, "upper color", group=groupEllipse)
EB_dnColor = input.color(color.red, "lower color", group=groupEllipse)
EB_fillTransp = input.int(80, "band transparency (0–100)", minval=0, maxval=100, group=groupEllipse)
EB_showFill = input.bool(false, "fill es cloud", group=groupEllipse)
EB_showSignals = input.bool(true, "show es signals", group=groupEllipse)
EB_buyColor = input.color(color.green, "buy signal color", group=groupEllipse)
EB_sellColor = input.color(color.red, "sell signal color", group=groupEllipse)
// locked params
const int EB_MA_LEN = 50
const int EB_PERIOD = 50
const float EB_MULTI = 2.0
float EB_central_ma = ta.sma(close, EB_MA_LEN)
float EB_b = ta.stdev(close, EB_MA_LEN) * EB_MULTI
int EB_cycle_pos = bar_index % EB_PERIOD
float EB_x = 2.0 * (EB_cycle_pos / EB_PERIOD) - 1.0
float EB_offset = EB_b * math.sqrt(math.max(0.0, 1.0 - EB_x * EB_x))
float EB_band_upper = EB_central_ma + EB_offset
float EB_band_lower = EB_central_ma - EB_offset
// plot lines (upper/lower/mid)
EB_p_mid = plot(EB_show ? EB_central_ma : na, title="es mid", color=EB_midColor, linewidth=1)
EB_p_up = plot(EB_show ? EB_band_upper : na, title="es upper", color=EB_upColor)
EB_p_dn = plot(EB_show ? EB_band_lower : na, title="es lower", color=EB_dnColor)
// fill only if EB_showFill = true
EB_fillColor = (EB_show and EB_showFill) ? color.new(color.gray, EB_fillTransp) : color.new(color.gray, 100)
fill(EB_p_up, EB_p_dn, color=EB_fillColor, title="es cloud")
// signals
bool EB_buy = EB_show and close[1] < nz(EB_band_lower[1]) and close >= nz(EB_band_lower) and close <= nz(EB_band_upper) and barstate.isconfirmed
bool EB_sell = EB_show and close[1] > nz(EB_band_upper[1]) and close >= nz(EB_band_lower) and close <= nz(EB_band_upper) and barstate.isconfirmed
plotshape(EB_showSignals and EB_buy, title="es buy", location=location.belowbar, color=EB_buyColor, style=shape.triangleup, size=size.tiny)
plotshape(EB_showSignals and EB_sell, title="es sell", location=location.abovebar, color=EB_sellColor, style=shape.triangledown, size=size.tiny)
// Wave Labels (1–5) — minimal module for tp11ofc1 (Pine v6) — labels only
//──────────────────────────────────────────────────────────────────────────────
groupEW = "Wave labels (Elliott)"
srcHiSel = input.string("high", "High source", options=["high","close","max open/close"], group=groupEW)
srcLoSel = input.string("low", "Low source", options=["low","close","min open/close"], group=groupEW)
ew_hi = srcHiSel == "high" ? high : srcHiSel == "close" ? close : math.max(open, close)
ew_lo = srcLoSel == "low" ? low : srcLoSel == "close" ? close : math.min(open, close)
ewShowS1 = input.bool(true, "Show wave S", group=groupEW, inline="s1")
ewLen1 = input.int(4, "len", minval=1, group=groupEW, inline="s1")
ewCol1 = input.color(color.new(color.red,0), "", group=groupEW, inline="s1")
ewShowS2 = input.bool(true, "Show wave M", group=groupEW, inline="s2")
ewLen2 = input.int(8, "len", minval=1, group=groupEW, inline="s2")
ewCol2 = input.color(color.new(#0d86e9, 0), "", group=groupEW, inline="s2")
ewShowS3 = input.bool(true, "Show wave L", group=groupEW, inline="s3")
ewLen3 = input.int(16, "len", minval=1, group=groupEW, inline="s3")
ewCol3 = input.color(color.new(#470303, 0),"", group=groupEW, inline="s3")
ewSizeStr = input.string("small","Label size", options=["tiny","small","normal","large"], group=groupEW)
ew_lsize(s) => s=="tiny"?size.tiny:s=="normal"?size.normal:s=="large"?size.large:size.small
type _ZZ
int[] d
int[] x
float[] y
newZZ() => _ZZ.new(array.new_int(), array.new_int(), array.new_float())
f_push_pivot(_aZZ, _dir, _x1, _y1, _x2, _y2) =>
_aZZ.d.unshift(_dir)
_aZZ.x.unshift(_x2)
_aZZ.y.unshift(_y2)
if array.size(_aZZ.d) > 12
_ = array.pop(_aZZ.d)
_ = array.pop(_aZZ.x)
_ = array.pop(_aZZ.y)
var label[] EW_LABELS = array.new_label()
f_add_label(_x, _y, _txt, _col, _up) =>
label lb = label.new(_x, _y, text=_txt, style=_up?label.style_label_down:label.style_label_up, textcolor=_col, color=color.new(color.black, 100), size=ew_lsize(ewSizeStr), xloc=xloc.bar_index)
array.push(EW_LABELS, lb)
if array.size(EW_LABELS) > 500
label.delete(array.get(EW_LABELS, 0))
array.remove(EW_LABELS, 0)
f_check_motive_bull(_1y,_2y,_3y,_4y,_5y,_6y) =>
_W5 = _6y - _5y
_W3 = _4y - _3y
_W1 = _2y - _1y
_min = math.min(_W1,_W3,_W5)
(_W3 != _min) and (_6y > _4y) and (_3y > _1y) and (_5y > _2y)
f_check_motive_bear(_1y,_2y,_3y,_4y,_5y,_6y) =>
_W5 = _5y - _6y
_W3 = _3y - _4y
_W1 = _1y - _2y
_min = math.min(_W1,_W3,_W5)
(_W3 != _min) and (_4y > _6y) and (_1y > _3y) and (_2y > _5y)
f_wave_labels(_enabled, _len, _col, _rowSep) =>
if _enabled
var _ZZ zz = newZZ()
if barstate.isfirst
for _=0 to 10
array.unshift(zz.d, 0)
array.unshift(zz.x, 0)
array.unshift(zz.y, 0)
x2 = bar_index - 1
ph = ta.pivothigh(ew_hi, _len, 1)
pl = ta.pivotlow (ew_lo, _len, 1)
if not na(ph)
dir = array.get(zz.d, 0)
x1 = array.get(zz.x, 0)
y1 = array.get(zz.y, 0)
y2h = nz(ew_hi[1])
if dir < 1
f_push_pivot(zz, 1, x1, y1, x2, y2h)
else if ph > y1
array.set(zz.x, 0, x2)
array.set(zz.y, 0, y2h)
_6x = x2, _6y = y2h
_5x = array.get(zz.x,1), _5y = array.get(zz.y,1)
_4x = array.get(zz.x
indicator("TP11OFC5", overlay=true, scale=scale.right, max_lines_count=500, max_labels_count=500, max_boxes_count=500, max_bars_back=5000)
//──────────────────────────────── Inputs: Masked Names ───────────────────────────────
// yelow group (EMA200 + 5up/5down)
group200 = "yelow group"
emaLen200 = input.int(200, "yelow length", minval=1, group=group200)
show200Mid = input.bool(true, "show big brown", group=group200) // EMA200 mid
show200_5u = input.bool(true, "show yelow group up", group=group200) // 5up (EMA200)
show200_5d = input.bool(true, "show yelow group down",group=group200) // 5down (EMA200)
// Colors (masked)
groupClrMA = "Colors — lines"
colMid200 = input.color(color.rgb(100, 50, 0), "big brown", group=groupClrMA) // EMA200 mid
col5band = input.color(color.rgb(247, 212, 14), "yelow up/down", group=groupClrMA) // 5up/5down
col85_4 = input.color(color.rgb(9, 77, 202), "blue up/down (x4)",group=groupClrMA) // EMA85 4up/4down
col35 = input.color(color.rgb(7, 9, 155), "big blue", group=groupClrMA) // EMA35
colPNR = input.color(color.rgb(255,17,0), "pn", group=groupClrMA) // PNR
// blue group (EMA85 — 4 up/down)
group85 = "blue group"
emaLen85 = input.int(85, "blue length", minval=1, group=group85)
show85_4u = input.bool(true, "show blue group up", group=group85)
show85_4d = input.bool(true, "show blue group down", group=group85)
// big blue (EMA35)
group35 = "big blue"
emaLen35 = input.int(35, "big blue length", minval=1, group=group35)
useClose35 = input.bool(false, "big blue use close (else effClose)", group=group35)
showEMA35 = input.bool(true, "show big blue", group=group35)
// pn (PNR)
groupPNR = "pn"
pnrLen = input.int(15, "window size", minval=1, group=groupPNR)
pnrPerc = input.int(50, "percentile (0–100)", minval=0, maxval=100, group=groupPNR)
pnrSrc = input.source(close, "source", group=groupPNR)
showPNR = input.bool(true, "show pn", group=groupPNR)
// di (DSI)
groupDSI = "di"
showDSI = input.bool(true, "show di", group=groupDSI)
atrMovement= input.float(1.0, "movement required", step=0.5, group=groupDSI)
lookback = input.int(25, "high/low lookback", step=5, group=groupDSI)
maxZoneSize= input.float(2.5, "max zone size ", step=0.5, group=groupDSI)
newStructureReset = input.int(25, "zone update count before reset", step=5, group=groupDSI)
drawPreviousStructure = input.bool(true, "draw previous zones", group=groupDSI)
groupClrDSI = "Colors — zones"
dsiBullColor = input.color(color.rgb(178, 240, 180), "bull color", group=groupClrDSI)
dsiBearColor = input.color(color.rgb(240, 206, 206), "bear color", group=groupClrDSI)
//──────────────────────────────── FE (Trend-base Fibo) ───────────────────────────────
groupFE = "targets — FE"
feLenBars = input.int(35, "FE length (bars) from P3", minval=5, group=groupFE)
feLife = input.int(500, "FE lifespan (bars) before delete", minval=50, group=groupFE)
showFE = input.bool(true, "show FE", group=groupFE)
roundToTick = input.bool(true, "round FE to tick", group=groupFE)
// FE levels on/off
show95_105 = input.bool(true, "show band", group=groupFE)
show1618 = input.bool(true, "show 1", group=groupFE)
show2618 = input.bool(true, "show 2", group=groupFE)
show3618 = input.bool(true, "show 3", group=groupFE)
show4618 = input.bool(true, "show 4", group=groupFE)
// FE colors
colBand = input.color(color.rgb(79, 247, 46), "line", group=groupFE)
colBandFill = input.color(color.new(#8be95f, 85), "band", group=groupFE)
col1618 = input.color(color.orange, "1line", group=groupFE)
col2618 = input.color(color.fuchsia, "2line", group=groupFE)
col3618 = input.color(color.new(color.purple, 0), "3line", group=groupFE)
col4618 = input.color(color.new(color.maroon, 0), "4line", group=groupFE)
//──────────────────────────────── P-series (เดิม) ───────────────────────────────
groupP1P2P3 = "P-series options"
p1Lookback = input.int(200, "P1 max left scan", minval=20, group=groupP1P2P3)
rightWinBars = input.int(5, "P2 right confirm bars", minval=1, group=groupP1P2P3)
p3MaxWindowBars = input.int(600, "P3 max window (bars)", minval=50, maxval=5000, step=50, group=groupP1P2P3)
resetWithinBars = input.int(50, "reset old set if new within (bars)", minval=1, group=groupP1P2P3)
// >>> NEW: ระยะห่างขั้นต่ำ P1/P3 จาก P2 <<<
minGapBars = input.int(5, "Min gap bars: P1/P3 must be at least this far from P2", minval=1, group=groupP1P2P3)
// ── NEW: De-duplicate labels (no same-type within N bars; keep latest) ─────────────
groupDeDup = "Labels — de-dup"
dedupWinBars = input.int(50, "No same-type label within N bars", minval=1, group=groupDeDup)
// ──────────────────────────────── New: P2 window rule ───────────────────────────────
groupP2Win = "P2 window rule"
p2NewWithinBars = input.int(50, "Window N bars: new P2 within N must be better than last P2 (L: higher / S: lower)", minval=1, group=groupP2Win)
//──────────────────────────────── Visual options ───────────────────────────────
groupPviz = "Visual — Body highlights & labels"
showBodyBoxes = input.bool(true, "show body boxes", group=groupPviz)
P1BoxFullCandle = input.bool(false, "P1: full candle box", group=groupPviz)
P2BoxFullCandle = input.bool(false, "P2: full candle box", group=groupPviz)
P3BoxFullCandle = input.bool(false, "P3: full candle box", group=groupPviz)
P1BoxColor = input.color(color.black, "P1 box color", group=groupPviz)
P1BoxFillTransp = input.int(85, "P1 box fill transp", minval=0, maxval=100, group=groupPviz)
P2BoxColor = input.color(color.lime, "P2 box color", group=groupPviz)
P2BoxFillTransp = input.int(70, "P2 box fill transp", minval=0, maxval=100, group=groupPviz)
P3BoxColor = input.color(color.orange, "P3 box color", group=groupPviz)
P3BoxFillTransp = input.int(70, "P3 box fill transp", minval=0, maxval=100, group=groupPviz)
BoxBorderTransp = input.int(0, "box border transp", minval=0, maxval=100, group=groupPviz)
recolorBars = input.bool(true, "barcolor P1/P2/P3", group=groupPviz)
colP1Candle = input.color(color.black, "P1 candle", group=groupPviz)
colP2Candle = input.color(color.lime, "P2 candle", group=groupPviz)
colP3Candle = input.color(color.orange,"P3 candle", group=groupPviz)
showP1Label = input.bool(true, "show P1 label", group=groupPviz)
showP2Label = input.bool(true, "show P2 label", group=groupPviz)
showP3Label = input.bool(true, "show P3 label", group=groupPviz)
PLabelTextColor = input.color(color.white, "label text color", group=groupPviz)
PLabelBgColor = input.color(color.black, "label bg color", group=groupPviz)
// ── Label placement/offset (split LONG/SHORT) ───────────────────────────────
groupLbl = "Labels — placement"
LP_AUTO = "Auto"
LP_ABOVE = "Above"
LP_BELOW = "Below"
OM_TICKS = "Ticks"
OM_ATR = "ATR"
lblPlaceLong = input.string(LP_ABOVE, "Placement (LONG)", options=[LP_AUTO, LP_ABOVE, LP_BELOW], group=groupLbl)
lblPlaceShort = input.string(LP_BELOW, "Placement (SHORT)", options=[LP_AUTO, LP_ABOVE, LP_BELOW], group=groupLbl)
lblOffsetMet = input.string(OM_ATR, "Offset method", options=[OM_TICKS, OM_ATR], group=groupLbl)
lblTicks = input.int(5, "Ticks offset", minval=0, group=groupLbl)
lblAtrLen = input.int(14, "ATR length", minval=1, group=groupLbl)
lblAtrMult = input.float(0.25, "ATR multiple", minval=0.0, step=0.05, group=groupLbl)
lblSizeSel = input.string("small", "Label size", options=["tiny","small","normal","large"], group=groupLbl)
lblBgTransp = input.int(0, "Label BG transparency", minval=0, maxval=100, group=groupLbl)
//──────────────────────────────── Manual (แทน Override) ─────────────────────────
PM_OPEN = "Open"
PM_CLOSE = "Close"
PM_MID = "Mid"
PM_HIGH = "High"
PM_LOW = "Low"
PM_CUST = "Custom"
PK_TIME = "Time"
PK_OFF = "Offset"
// LONG
groupManL = "Manual (LONG)"
useManP1L = input.bool(false, "Use P1 manual (L)", group=groupManL)
pickP1L = input.string(PK_TIME, "P1 pick mode (L)", options=[PK_TIME, PK_OFF], group=groupManL)
manP1L_t = input.time(timestamp("01 Jan 2024 00:00 +0000"), "P1 time (L)", group=groupManL)
manP1L_of = input.int(-5, "P1 offset (bars, L)", group=groupManL)
pmP1L = input.string(PM_OPEN, "P1 price mode (L)", options=[PM_OPEN, PM_CLOSE, PM_MID, PM_HIGH, PM_LOW, PM_CUST], group=groupManL)
p1L_custom= input.float(0.0, "P1 custom price (L)", group=groupManL)
useManP2L = input.bool(false, "Use P2 manual (L)", group=groupManL)
pickP2L = input.string(PK_TIME, "P2 pick mode (L)", options=[PK_TIME, PK_OFF], group=groupManL)
manP2L_t = input.time(timestamp("01 Jan 2024 00:00 +0000"), "P2 time (L)", group=groupManL)
manP2L_of = input.int(-3, "P2 offset (bars, L)", group=groupManL)
pmP2L = input.string(PM_CLOSE, "P2 price mode (L)", options=[PM_OPEN, PM_CLOSE, PM_MID, PM_HIGH, PM_LOW, PM_CUST], group=groupManL)
p2L_custom= input.float(0.0, "P2 custom price (L)", group=groupManL)
useManP3L = input.bool(false, "Use P3 manual (L)", group=groupManL)
pickP3L = input.string(PK_TIME, "P3 pick mode (L)", options=[PK_TIME, PK_OFF], group=groupManL)
manP3L_t = input.time(timestamp("01 Jan 2024 00:00 +0000"), "P3 time (L)", group=groupManL)
manP3L_of = input.int(-1, "P3 offset (bars, L)", group=groupManL)
pmP3L = input.string(PM_OPEN, "P3 price mode (L)", options=[PM_OPEN, PM_CLOSE, PM_MID, PM_HIGH, PM_LOW, PM_CUST], group=groupManL)
p3L_custom= input.float(0.0, "P3 custom price (L)", group=groupManL)
// SHORT
groupManS = "Manual (SHORT)"
useManP1S = input.bool(false, "Use P1 manual (S)", group=groupManS)
pickP1S = input.string(PK_TIME, "P1 pick mode (S)", options=[PK_TIME, PK_OFF], group=groupManS)
manP1S_t = input.time(timestamp("01 Jan 2024 00:00 +0000"), "P1 time (S)", group=groupManS)
manP1S_of = input.int(-5, "P1 offset (bars, S)", group=groupManS)
pmP1S = input.string(PM_OPEN, "P1 price mode (S)", options=[PM_OPEN, PM_CLOSE, PM_MID, PM_HIGH, PM_LOW, PM_CUST], group=groupManS)
p1S_custom= input.float(0.0, "P1 custom price (S)", group=groupManS)
useManP2S = input.bool(false, "Use P2 manual (S)", group=groupManS)
pickP2S = input.string(PK_TIME, "P2 pick mode (S)", options=[PK_TIME, PK_OFF], group=groupManS)
manP2S_t = input.time(timestamp("01 Jan 2024 00:00 +0000"), "P2 time (S)", group=groupManS)
manP2S_of = input.int(-3, "P2 offset (bars, S)", group=groupManS)
pmP2S = input.string(PM_CLOSE, "P2 price mode (S)", options=[PM_OPEN, PM_CLOSE, PM_MID, PM_HIGH, PM_LOW, PM_CUST], group=groupManS)
p2S_custom= input.float(0.0, "P2 custom price (S)", group=groupManS)
useManP3S = input.bool(false, "Use P3 manual (S)", group=groupManS)
pickP3S = input.string(PK_TIME, "P3 pick mode (S)", options=[PK_TIME, PK_OFF], group=groupManS)
manP3S_t = input.time(timestamp("01 Jan 2024 00:00 +0000"), "P3 time (S)", group=groupManS)
manP3S_of = input.int(-1, "P3 offset (bars, S)", group=groupManS)
pmP3S = input.string(PM_OPEN, "P3 price mode (S)", options=[PM_OPEN, PM_CLOSE, PM_MID, PM_HIGH, PM_LOW, PM_CUST], group=groupManS)
p3S_custom= input.float(0.0, "P3 custom price (S)", group=groupManS)
// Buttons: Reset (UI switches)
groupBtnL = "Manual Controls — Buttons (LONG)"
btnResetAllL = input.bool(false, "Reset ALL manual (L)", group=groupBtnL)
btnResetP1L = input.bool(false, "Reset P1 manual (L)", group=groupBtnL)
btnResetP2L = input.bool(false, "Reset P2 manual (L)", group=groupBtnL)
btnResetP3L = input.bool(false, "Reset P3 manual (L)", group=groupBtnL)
groupBtnS = "Manual Controls — Buttons (SHORT)"
btnResetAllS = input.bool(false, "Reset ALL manual (S)", group=groupBtnS)
btnResetP1S = input.bool(false, "Reset P1 manual (S)", group=groupBtnS)
btnResetP2S = input.bool(false, "Reset P2 manual (S)", group=groupBtnS)
btnResetP3S = input.bool(false, "Reset P3 manual (S)", group=groupBtnS)
// ── Momentary Reset (edge-detect) ───────────────────────────────
var bool resetReqAllL = false
var bool resetReqP1L = false
var bool resetReqP2L = false
var bool resetReqP3L = false
var bool resetReqAllS = false
var bool resetReqP1S = false
var bool resetReqP2S = false
var bool resetReqP3S = false
bool fireAllL = ta.change(btnResetAllL) and btnResetAllL
bool fireP1L = ta.change(btnResetP1L) and btnResetP1L
bool fireP2L = ta.change(btnResetP2L) and btnResetP2L
bool fireP3L = ta.change(btnResetP3L) and btnResetP3L
bool fireAllS = ta.change(btnResetAllS) and btnResetAllS
bool fireP1S = ta.change(btnResetP1S) and btnResetP1S
bool fireP2S = ta.change(btnResetP2S) and btnResetP2S
bool fireP3S = ta.change(btnResetP3S) and btnResetP3S
if fireAllL
resetReqAllL := true
resetReqP1L := true
resetReqP2L := true
resetReqP3L := true
if fireP1L
resetReqP1L := true
if fireP2L
resetReqP2L := true
if fireP3L
resetReqP3L := true
if fireAllS
resetReqAllS := true
resetReqP1S := true
resetReqP2S := true
resetReqP3S := true
if fireP1S
resetReqP1S := true
if fireP2S
resetReqP2S := true
if fireP3S
resetReqP3S := true
//──────────────────────────────── Core helpers ───────────────────────────────
float effClose = close >= open ? math.max(open, close) : math.min(open, close)
f_bodyTop(_o, _c) => math.max(_o, _c)
f_bodyBot(_o, _c) => math.min(_o, _c)
f_midBody_at(_i) =>
float bt = f_bodyTop(open[_i], close[_i])
float bb = f_bodyBot(open[_i], close[_i])
(bt + bb) / 2.0
f_core(_len) =>
float mid = ta.ema(effClose, _len)
float _dev = ta.stdev(effClose, _len)
float devS = _dev == 0.0 ? na : _dev
float plus = na(mid) or na(devS) ? na : (close > mid ? (close - mid) / devS : 0.0)
float minus = na(mid) or na(devS) ? na : (close < mid ? (mid - close) / devS : 0.0)
float mmax = na(plus) or na(minus) ? na : math.max(plus, minus)
float lm = ta.ema(mmax, _len)
[mid, devS, lm]
f_core_src(_src, _len) =>
float mid = ta.ema(_src, _len)
float _dev = ta.stdev(_src, _len)
float devS = _dev == 0.0 ? na : _dev
float plus = na(mid) or na(devS) ? na : (_src > mid ? (_src - mid) / devS : 0.0)
float minus = na(mid) or na(devS) ? na : (_src < mid ? (mid - _src) / devS : 0.0)
float mmax = na(plus) or na(minus) ? na : math.max(plus, minus)
float lm = ta.ema(mmax, _len)
[mid, devS, lm]
// Price by mode
f_price_by_mode(off, mode, custom) =>
switch mode
PM_OPEN => open[off]
PM_CLOSE => close[off]
PM_MID => (math.max(open[off], close[off]) + math.min(open[off], close[off]))/2.0
PM_HIGH => high[off]
PM_LOW => low[off]
PM_CUST => custom > 0 ? (roundToTick ? math.round(custom / syminfo.mintick) * syminfo.mintick : custom) : na
=> na
// NEW: Gap helpers
f_gap_ok_left(p1Abs, p2Abs) =>
not na(p1Abs) and not na(p2Abs) and (p2Abs - p1Abs) >= minGapBars
f_gap_ok_right(p3Abs, p2Abs) =>
not na(p3Abs) and not na(p2Abs) and (p3Abs - p2Abs) >= minGapBars
//──────────────────────────────── yelow group (EMA200 + 5up/5down) ───────────────────
[mid200, dev200, lm200] = f_core_src(close, emaLen200)
phi_adj = 1.38196601
float fiveUp_200 = na(mid200) or na(dev200) or na(lm200) ? na : mid200 + (lm200 * phi_adj) * dev200
float fiveDown_200 = na(mid200) or na(dev200) or na(lm200) ? na : mid200 - (lm200 * phi_adj) * dev200
plot(show200_5d ? fiveDown_200 : na, title="yelow group down", color=col5band, linewidth=3)
plot(show200Mid ? mid200 : na, title="big brown", color=colMid200, linewidth=3)
plot(show200_5u ? fiveUp_200 : na, title="yelow group up", color=col5band, linewidth=3)
//──────────────────────────────── blue group (EMA85 — 4 up/down) ────────────────────
[mid85, dev85, lm85] = f_core(emaLen85)
float up4_85 = na(mid85) or na(dev85) or na(lm85) ? na : mid85 + lm85 * dev85
float down4_85 = na(mid85) or na(dev85) or na(lm85) ? na : mid85 - lm85 * dev85
float fiveUp_85 = na(mid85) or na(dev85) or na(lm85) ? na : mid85 + (lm85 * phi_adj) * dev85
float fiveDown_85 = na(mid85) or na(dev85) or na(lm85) ? na : mid85 - (lm85 * phi_adj) * dev85
plot(show85_4u ? up4_85 : na, title="blue group up", color=col85_4, linewidth=2)
plot(show85_4d ? down4_85 : na, title="blue group down", color=col85_4, linewidth=2)
// big blue (EMA35)
float ema35 = useClose35 ? ta.ema(close, emaLen35) : ta.ema(effClose, emaLen35)
plot(showEMA35 ? ema35 : na, title="big blue", color=col35, linewidth=2)
// pn (PNR)
float pnr = na
if bar_index >= pnrLen - 1
float[] win = array.new_float()
for i = 0 to pnrLen - 1
array.push(win, pnrSrc)
array.sort(win)
float rankF = (pnrPerc / 100.0) * (pnrLen - 1)
int idx = int(math.round(rankF))
idx := math.max(0, math.min(idx, pnrLen - 1))
pnr := array.get(win, idx)
plot(showPNR ? pnr : na, title="pn", color=colPNR, linewidth=2)
//──────────────────────────────── Masked EMA Clouds (line 1–5) ───────────────────────
groupCloud = "line clouds"
showClouds = input.bool(true, "show lines clouds", group=groupCloud)
l1Len = input.int(5, "line 1 length", minval=1, group=groupCloud)
l2Len = input.int(8, "line 2 length", minval=1, group=groupCloud)
l3Len = input.int(21, "line 3 length", minval=1, group=groupCloud)
l4Len = input.int(34, "line 4 length", minval=1, group=groupCloud)
l5Len = input.int(50, "line 5 length", minval=1, group=groupCloud)
cloudUpColor = input.color(color.green, "cloud up color", group=groupCloud)
cloudDnColor = input.color(color.red, "cloud down color", group=groupCloud)
cloudTransp = input.int(60, "cloud transparency (0–100)", minval=0, maxval=100, group=groupCloud)
l1 = ta.ema(close, l1Len)
l2 = ta.ema(close, l2Len)
l3 = ta.ema(close, l3Len)
l4 = ta.ema(close, l4Len)
l5 = ta.ema(close, l5Len)
// พล็อตเส้นพราง (transp=100) และใช้ชื่อ line 1..5
p1 = plot(showClouds ? l1 : na, color=color.new(color.gray, 100), style=plot.style_line, linewidth=1, title="line 1")
p2 = plot(showClouds ? l2 : na, color=color.new(color.gray, 100), style=plot.style_line, linewidth=1, title="line 2")
p3 = plot(showClouds ? l3 : na, color=color.new(color.gray, 100), style=plot.style_line, linewidth=1, title="line 3")
p4 = plot(showClouds ? l4 : na, color=color.new(color.gray, 100), style=plot.style_line, linewidth=1, title="line 4")
p5 = plot(showClouds ? l5 : na, color=color.new(color.gray, 100), style=plot.style_line, linewidth=1, title="line 5")
// เรียก fill ที่ "global scope" แล้วคุมการแสดงผลด้วยสี (ถ้าไม่โชว์ให้ทำเป็นโปร่งใส)
cloud23Color = showClouds ? (l2 > l3 ? color.new(cloudUpColor, cloudTransp) : color.new(cloudDnColor, cloudTransp)) : color.new(color.black, 100)
cloud45Color = showClouds ? (l4 > l5 ? color.new(cloudUpColor, cloudTransp) : color.new(cloudDnColor, cloudTransp)) : color.new(color.black, 100)
fill(p2, p3, color=cloud23Color, title="cloud 2–3")
fill(p4, p5, color=cloud45Color, title="cloud 4–5")
//──────────────────────────────── Utilities ───────────────────────────────
isGreen_at(i) => close > open
isRed_at(i) => close < open
bodyTop_at(i) => f_bodyTop(open, close)
f_frac_body_above_line(i, lineV) =>
float bt = bodyTop_at(i), bb = f_bodyBot(open, close)
float body = bt - bb
body <= 0 or na(lineV) ? 0.0 : math.max(0.0, bt - math.max(bb, lineV)) / body
f_frac_body_below_line(i, lineV) =>
float bt = bodyTop_at(i), bb = f_bodyBot(open, close)
float body = bt - bb
body <= 0 or na(lineV) ? 0.0 : math.max(0.0, math.min(bt, lineV) - bb) / body
// Draw helpers
var box[] PBOXES = array.new_box()
var label[] PLABELS = array.new_label()
f_delete_boxes(box[] arr) =>
int n = array.size(arr)
for k = 0 to n - 1
int i = n - 1 - k
box.delete(array.get(arr, i))
array.clear(arr)
f_delete_labels(label[] arr) =>
int n = array.size(arr)
for k = 0 to n - 1
int i = n - 1 - k
label.delete(array.get(arr, i))
array.clear(arr)
// size mapper
f_lbl_size(s) =>
s == "tiny" ? size.tiny : s == "large" ? size.large : s == "normal" ? size.normal : size.small
// helper: one-line label.new
f_make_label(_x, _y, _text, _placeAbove) =>
label.new(_x, _y, _text, xloc=xloc.bar_time, style=(_placeAbove ? label.style_label_down : label.style_label_up), textcolor=PLabelTextColor, color=color.new(PLabelBgColor, lblBgTransp), size=f_lbl_size(lblSizeSel))
// smarter label placement (split LONG/SHORT) → return handles
f_add_label_ret(_abs, _text, _isLong) =>
label lb = na
int off = bar_index - _abs
if off >= 0 and off <= 5000 and not na(time[off]) and not na(high[off]) and not na(low[off])
float pad = lblOffsetMet == OM_TICKS ? (syminfo.mintick * lblTicks) : (ta.atr(lblAtrLen)[off] * lblAtrMult)
string opt = _isLong ? lblPlaceLong : lblPlaceShort
bool placeAbove = (opt == LP_ABOVE) ? true : (opt == LP_BELOW) ? false : (close[off] >= open[off])
float yPos = placeAbove ? (high[off] + pad) : (low[off] - pad)
lb := f_make_label(time[off], yPos, _text, placeAbove)
array.push(PLABELS, lb)
if array.size(PLABELS) > 500
label.delete(array.get(PLABELS, 0))
array.remove(PLABELS, 0)
lb
// draw mark → return [box,label]
f_draw_mark_group(_abs, _full, _boxCol, _fillT, _borderT, _labelOn, _labelText, _isLong) =>
box nb = na
label lb = na
if not na(_abs)
int off = bar_index - _abs
if off >= 0 and off <= 5000
float top = _full ? high[off] : bodyTop_at(off)
float bot = _full ? low[off] : f_bodyBot(open[off], close[off])
if showBodyBoxes
nb := box.new(math.max(0, int(_abs) - 1), math.max(top, bot), int(_abs), math.min(top, bot), xloc=xloc.bar_index, bgcolor=color.new(_boxCol, _fillT), border_color=color.new(_boxCol, _borderT))
array.push(PBOXES, nb)
if array.size(PBOXES) > 500
box.delete(array.get(PBOXES, 0))
array.remove(PBOXES, 0)
if _labelOn
lb := f_add_label_ret(_abs, _labelText, _isLong)
[nb, lb]
//───────────────────── De-dup helpers (keep latest; delete older within window) ─────
f_del_if_exists(_bx, _lb) =>
if not na(_bx)
box.delete(_bx)
if not na(_lb)
label.delete(_lb)
// Strict int for last Abs to avoid NA-type errors
var int L_lastP1Abs = int(na)
var int L_lastP2Abs = int(na)
var int L_lastP3Abs = int(na)
var int S_lastP1Abs = int(na)
var int S_lastP2Abs = int(na)
var int S_lastP3Abs = int(na)
// IMPORTANT: declare one per line to keep type info on all variables
var box L_lastP1Box = na
var box L_lastP2Box = na
var box L_lastP3Box = na
var box S_lastP1Box = na
var box S_lastP2Box = na
var box S_lastP3Box = na
var label L_lastP1Lbl = na
var label L_lastP2Lbl = na
var label L_lastP3Lbl = na
var label S_lastP1Lbl = na
var label S_lastP2Lbl = na
var label S_lastP3Lbl = na
// >>> NEW: true-last P2 trackers (separate from de-dup) <<<
var int L_prevP2Abs = int(na)
var float L_prevP2Close = na
var int S_prevP2Abs = int(na)
var float S_prevP2Close = na
// enforce unique per type & side
f_enforce_and_set(_newAbs, _newBox, _newLbl, _lastAbs, _lastBox, _lastLbl) =>
bool keepNew = true
int lastAbsNew = _lastAbs
box lastBoxNew = _lastBox
label lastLblNew = _lastLbl
if not na(_lastAbs) and math.abs(_newAbs - _lastAbs) <= dedupWinBars
if _newAbs > _lastAbs
f_del_if_exists(_lastBox, _lastLbl)
lastAbsNew := _newAbs
lastBoxNew := _newBox
lastLblNew := _newLbl
else
f_del_if_exists(_newBox, _newLbl)
keepNew := false
else
lastAbsNew := _newAbs
lastBoxNew := _newBox
lastLblNew := _newLbl
[keepNew, lastAbsNew, lastBoxNew, lastLblNew]
//──────────────────────────────── FE helpers ───────────────────────────────
f_rt(v) => roundToTick ? math.round(v / syminfo.mintick) * syminfo.mintick : v
var line[] FE_l95 = array.new_line()
var line[] FE_l105 = array.new_line()
var line[] FE_l161 = array.new_line()
var line[] FE_l261 = array.new_line()
var line[] FE_l361 = array.new_line()
var line[] FE_l461 = array.new_line()
var linefill[] FE_fill = array.new_linefill()
var int[] FE_born = array.new_int()
f_delete_fe_index(idx) =>
int nAll = array.size(FE_born)
if idx >= 0 and idx < nAll
if idx < array.size(FE_fill)
linefill.delete(array.get(FE_fill, idx))
if idx < array.size(FE_l95)
line.delete(array.get(FE_l95, idx))
if idx < array.size(FE_l105)
line.delete(array.get(FE_l105, idx))
if idx < array.size(FE_l161)
line.delete(array.get(FE_l161, idx))
if idx < array.size(FE_l261)
line.delete(array.get(FE_l261, idx))
if idx < array.size(FE_l361)
line.delete(array.get(FE_l361, idx))
if idx < array.size(FE_l461)
line.delete(array.get(FE_l461, idx))
if idx < array.size(FE_l95)
array.remove(FE_l95, idx)
if idx < array.size(FE_l105)
array.remove(FE_l105, idx)
if idx < array.size(FE_l161)
array.remove(FE_l161, idx)
if idx < array.size(FE_l261)
array.remove(FE_l261, idx)
if idx < array.size(FE_l361)
array.remove(FE_l361, idx)
if idx < array.size(FE_l461)
array.remove(FE_l461, idx)
if idx < array.size(FE_fill)
array.remove(FE_fill, idx)
array.remove(FE_born, idx)
f_clear_all_fe() =>
int n = array.size(FE_born)
for k = 0 to n - 1
int i = n - 1 - k
f_delete_fe_index(i)
// ───────────── ADD: helper แปลง bar-abs → time (ms) ─────────────
f_abs_to_time(_abs) =>
if na(_abs)
na
else
int off = bar_index - _abs
if off < 0
na
else
int tfms = timeframe.in_seconds(timeframe.period) * 1000
off <= 5000 ? time[off] : (time - off * tfms)
// ───────────── REPLACE: f_add_fe_set เดิม ด้วยเวอร์ชันกัน error ─────────────
f_add_fe_set(p3Abs, y95, y105, y161, y261, y361, y461) =>
int off = bar_index - p3Abs
bool useTime = off > 4500
int tfms = timeframe.in_seconds(timeframe.period) * 1000
color c95 = show95_105 ? colBand : color.new(colBand, 100)
color c105 = show95_105 ? colBand : color.new(colBand, 100)
color c161 = show1618 ? col1618 : color.new(col1618, 100)
color c261 = show2618 ? col2618 : color.new(col2618, 100)
color c361 = show3618 ? col3618 : color.new(col3618, 100)
color c461 = show4618 ? col4618 : color.new(col4618, 100)
// <<< แก้ไขตรงนี้: ประกาศตัวแปร line ทีละบรรทัด >>>
line l95 = na
line l105 = na
line l161 = na
line l261 = na
line l361 = na
line l461 = na
linefill lf = na
if not useTime
int x1 = p3Abs
int x2 = p3Abs + feLenBars
l95 := line.new(x1, y95, x2, y95, xloc=xloc.bar_index, extend=extend.none, color=c95, width=3)
l105 := line.new(x1, y105, x2, y105, xloc=xloc.bar_index, extend=extend.none, color=c105, width=3)
l161 := line.new(x1, y161, x2, y161, xloc=xloc.bar_index, extend=extend.none, color=c161, width=2)
l261 := line.new(x1, y261, x2, y261, xloc=xloc.bar_index, extend=extend.none, color=c261, width=2)
l361 := line.new(x1, y361, x2, y361, xloc=xloc.bar_index, extend=extend.none, color=c361, width=2)
l461 := line.new(x1, y461, x2, y461, xloc=xloc.bar_index, extend=extend.none, color=c461, width=2)
lf := linefill.new(l95, l105, color= show95_105 ? colBandFill : color.new(color.black, 100))
else
int t1 = f_abs_to_time(p3Abs)
int t2 = int(na)
if not na(t1)
t2 := t1 + feLenBars * tfms
l95 := line.new(t1, y95, t2, y95, xloc=xloc.bar_time, extend=extend.none, color=c95, width=3)
l105 := line.new(t1, y105, t2, y105, xloc=xloc.bar_time, extend=extend.none, color=c105, width=3)
l161 := line.new(t1, y161, t2, y161, xloc=xloc.bar_time, extend=extend.none, color=c161, width=2)
l261 := line.new(t1, y261, t2, y261, xloc=xloc.bar_time, extend=extend.none, color=c261, width=2)
l361 := line.new(t1, y361, t2, y361, xloc=xloc.bar_time, extend=extend.none, color=c361, width=2)
l461 := line.new(t1, y461, t2, y461, xloc=xloc.bar_time, extend=extend.none, color=c461, width=2)
lf := linefill.new(l95, l105, color= show95_105 ? colBandFill : color.new(color.black, 100))
array.push(FE_l95, l95)
array.push(FE_l105, l105)
array.push(FE_l161, l161)
array.push(FE_l261, l261)
array.push(FE_l361, l361)
array.push(FE_l461, l461)
array.push(FE_fill, lf)
array.push(FE_born, bar_index)
f_find_abs_by_time(t) =>
int bestAbs = na
if na(t)
na
else
int maxBack = math.min(5000, bar_index)
int bestDiff = 1000000000
for i = 0 to maxBack
int ti = time
int diff = ti > t ? (ti - t) : (t - ti)
if diff < bestDiff
bestDiff := diff
bestAbs := bar_index - i
bestAbs
//──────────────────────────────── P3 picker (แบบเดิม/คลาสสิก) ─────────────────────
f_pickP3_abs(sAbs, eAbs, isLong) =>
if na(sAbs) or na(eAbs)
[na, na]
else
int eInit = math.min(eAbs, bar_index)
int sInit = sAbs
int s = math.max(sInit, bar_index - 10000)
int e = eInit
if s > e
[na, na]
else
float[] levels = array.new_float()
int[] counts = array.new_int()
int[] firstI = array.new_int()
int[] maxRun = array.new_int()
float prevBin = na
int curRun = 0
float minLowGreen = 1e100
int minLowGreenI = na
float minLowRed = 1e100
int minLowRedI = na
float minLowAll = 1e100
int minLowAllI = na
float maxHighRed = -1e100
int maxHighRedI = na
float maxHighGreen = -1e100
int maxHighGreenI= na
float maxHighAll = -1e100
int maxHighAllI = na
for t = s to e
int tOff = bar_index - t
if tOff < 0 or tOff > 10000
continue
float bin = math.round(open[tOff] / syminfo.mintick) * syminfo.mintick
int idx = array.indexof(levels, bin)
if idx == -1
array.push(levels, bin)
array.push(counts, 1)
array.push(firstI, t)
array.push(maxRun, 1)
curRun := 1
else
array.set(counts, idx, array.get(counts, idx) + 1)
if not na(prevBin) and bin == prevBin
curRun += 1
else
curRun := 1
int prevMax = array.get(maxRun, idx)
if curRun > prevMax
array.set(maxRun, idx, curRun)
prevBin := bin
// ... (ส่วนท้ายของ f_pickP3_abs เดิม)
int needCnt = 2
int best = -1, bestCnt = 0, bestRun = 0, bestFirst = 1000000000
int L = array.size(levels)
if L > 0
for m = 0 to L - 1
int c = array.get(counts, m)
if c >= needCnt
int r = array.get(maxRun, m)
int f = array.get(firstI, m)
if c > bestCnt or (c == bestCnt and (r > bestRun or (r == bestRun and f < bestFirst)))
best := m
bestCnt := c
bestRun := r
bestFirst := f
if best != -1
int pickAbs = array.get(firstI, best)
float pickPx = array.get(levels, best)
[pickPx, pickAbs]
else
if isLong
// เลือกจาก logic เดิม (ย่อ)
float minLowGreen = 1e100
int minLowGreenI = na
float minLowRed = 1e100
int minLowRedI = na
float minLowAll = 1e100
int minLowAllI = na
for t2 = s to e
int toff2 = bar_index - t2
if toff2 < 0 or toff2 > 10000
continue
bool g = close[toff2] > open[toff2]
bool r = close[toff2] < open[toff2]
if g and low[toff2] < minLowGreen
minLowGreen := low[toff2]
minLowGreenI := t2
if r and low[toff2] < minLowRed
minLowRed := low[toff2]
minLowRedI := t2
if low[toff2] < minLowAll
minLowAll := low[toff2]
minLowAllI := t2
bool redIsGlobalMin = not na(minLowRedI) and (minLowRed <= minLowAll + 0.0)
if redIsGlobalMin
int offR = bar_index - minLowRedI
[close[offR], minLowRedI]
else
int useAbs = na(minLowGreenI) ? minLowAllI : minLowGreenI
int offU = bar_index - useAbs
[open[offU], useAbs]
else
float maxHighRed = -1e100
int maxHighRedI = na
float maxHighGreen = -1e100
int maxHighGreenI= na
float maxHighAll = -1e100
int maxHighAllI = na
for t3 = s to e
int toff3 = bar_index - t3
if toff3 < 0 or toff3 > 10000
continue
bool g2 = close[toff3] > open[toff3]
bool r2 = close[toff3] < open[toff3]
if r2 and high[toff3] > maxHighRed
maxHighRed := high[toff3]
maxHighRedI := t3
if g2 and high[toff3] > maxHighGreen
maxHighGreen := high[toff3]
maxHighGreenI:= t3
if high[toff3] > maxHighAll
maxHighAll := high[toff3]
maxHighAllI := t3
bool greenIsGlobalMax = not na(maxHighGreenI) and (maxHighGreen >= maxHighAll - 0.0)
if greenIsGlobalMax
int offG = bar_index - maxHighGreenI
[close[offG], maxHighGreenI]
else
int useAbsS = na(maxHighRedI) ? maxHighAllI : maxHighRedI
int offS = bar_index - useAbsS
[open[offS], useAbsS]
//──────────────────────────────── P1/P2/P3 (Auto; state) ────────────────
// LONG state vars
var int L_P1Abs = int(na)
var int L_P2Abs = int(na)
var int L_P3Abs = int(na)
var int L_winOpenAbs = int(na)
var float L_P1Open = na
var float L_P2Close = na
var float L_P3Px = na
var float L_P2_bodyTop = na
var float L_P2_bodyBot = na
// SHORT state vars
var int S_P1Abs = int(na)
var int S_P2Abs = int(na)
var int S_P3Abs = int(na)
var int S_winOpenAbs = int(na)
var float S_P1Open = na
var float S_P2Close = na
var float S_P3Px = na
var float S_P2_bodyTop = na
var float S_P2_bodyBot = na
// draw-set containers
var box[] L_SET_BOX = array.new_box()
var label[] L_SET_LBL = array.new_label()
var box[] S_SET_BOX = array.new_box()
var label[] S_SET_LBL = array.new_label()
// scanners
var bool L_seek = false
var bool L_confirmActive = false
var int L_runMaxAbs = int(na)
var float L_runMaxClose = na
var int L_candAbs = int(na)
var float L_candClose = na
var bool S_seek = false
var bool S_confirmActive = false
var int S_runMinAbs = int(na)
var float S_runMinClose = na
var int S_candAbs = int(na)
var float S_candClose = na
// LONG: seed/confirm P2 (UPDATED: ต้องทั้งแท่งอยู่เหนือ fiveUp_200)
if not L_seek and not L_confirmActive
float __btL = math.max(open, close)
float __bbL = math.min(open, close)
float __fiveL = fiveUp_200
bool startLongSeed = close > open and not na(__fiveL) and (__bbL >= __fiveL)
if startLongSeed
L_seek := true
L_runMaxAbs := bar_index
L_runMaxClose := close
if L_confirmActive
if close > L_candClose and close > open
L_seek := true
L_confirmActive := false
L_candAbs := int(na)
L_candClose := na
L_runMaxAbs := bar_index
L_runMaxClose := close
else if bar_index >= L_candAbs + rightWinBars
bool acceptL = true
// ตรวจซ้ำที่แท่งผู้สมัคร (ทั้งแท่งต้องอยู่เหนือ fiveUp_200)
int offCandL = bar_index - L_candAbs
float _btL = math.max(open[offCandL], close[offCandL])
float _bbL = math.min(open[offCandL], close[offCandL])
float _fiveL = fiveUp_200[offCandL]
bool bodyAbove5 = not na(_fiveL) and (_bbL >= _fiveL)
acceptL := acceptL and bodyAbove5
if not na(L_prevP2Abs)
int dBarsL = L_candAbs - L_prevP2Abs
if dBarsL <= p2NewWithinBars
acceptL := acceptL and (L_candClose > L_prevP2Close)
if not acceptL
L_seek := true
L_confirmActive := false
L_runMaxAbs := bar_index
L_runMaxClose := close
L_candAbs := int(na)
L_candClose := na
else
array.clear(L_SET_BOX)
array.clear(L_SET_LBL)
L_P2Abs := L_candAbs
resetReqAllL := false
resetReqP1L := false
resetReqP2L := false
resetReqP3L := false
int offP2 = bar_index - L_P2Abs
L_P2Close := close[offP2]
L_P2_bodyTop := math.max(open[offP2], close[offP2])
L_P2_bodyBot := math.min(open[offP2], close[offP2])
L_prevP2Abs := L_P2Abs
L_prevP2Close := L_P2Close
[bxP2, lbP2] = f_draw_mark_group(L_P2Abs, false, P2BoxColor, P2BoxFillTransp, BoxBorderTransp, showP2Label, "P2", true)
[keepNewP2L, _newAbsP2L, _newBoxP2L, _newLblP2L] = f_enforce_and_set(L_P2Abs, bxP2, lbP2, L_lastP2Abs, L_lastP2Box, L_lastP2Lbl)
if keepNewP2L
L_lastP2Abs := _newAbsP2L
L_lastP2Box := _newBoxP2L
L_lastP2Lbl := _newLblP2L
f_del_if_exists(L_lastP3Box, L_lastP3Lbl)
L_lastP3Abs := int(na)
L_lastP3Box := na
L_lastP3Lbl := na
L_P3Abs := int(na)
L_P3Px := na
f_clear_all_fe()
L_winOpenAbs := L_P2Abs + 1
int bestAbs = int(na)
float bestDist = na
for k = 1 to 50
int a = L_P2Abs - k
if a < 0
break
int off = bar_index - a
if off < 0 or off > 5000
continue
if close[off] <= open[off]
continue
float ema5u85 = fiveUp_85[off]
if na(ema5u85)
continue
float bt = math.max(open[off], close[off])
float bb = math.min(open[off], close[off])
float body = bt - bb
float fracAbove = body <= 0 ? 0.0 : math.max(0.0, bt - math.max(bb, ema5u85))/body
if fracAbove >= 0.25
float d = math.abs(mid200[off] - (bt+bb)/2.0)
if na(bestDist) or d < bestDist or (d == bestDist and (na(bestAbs) or a < bestAbs))
bestDist := d
bestAbs := a
if not na(bestAbs) and f_gap_ok_left(bestAbs, L_P2Abs)
int offb = bar_index - bestAbs
L_P1Open := open[offb]
L_P1Abs := bestAbs
[bxP1, lbP1] = f_draw_mark_group(L_P1Abs, false, P1BoxColor, P1BoxFillTransp, BoxBorderTransp, showP1Label, "P1", true)
[keepNewP1L, _newAbsP1L, _newBoxP1L, _newLblP1L] = f_enforce_and_set(L_P1Abs, bxP1, lbP1, L_lastP1Abs, L_lastP1Box, L_lastP1Lbl)
if keepNewP1L
L_lastP1Abs := _newAbsP1L
L_lastP1Box := _newBoxP1L
L_lastP1Lbl := _newLblP1L
L_seek := false
L_confirmActive := false
L_candAbs := int(na)
L_candClose := na
L_runMaxAbs := int(na)
L_runMaxClose := na
if L_seek and not L_confirmActive
if close > open
if close > nz(L_runMaxClose, -1e100)
L_runMaxClose := close
L_runMaxAbs := bar_index
else if close < nz(L_runMaxClose, 1e100)
L_candAbs := L_runMaxAbs
L_candClose := L_runMaxClose
L_seek := false
L_confirmActive := true
else if open < nz(L_runMaxClose, 1e100)
L_candAbs := L_runMaxAbs
L_candClose := L_runMaxClose
L_seek := false
L_confirmActive := true
// SHORT: seed/confirm P2 (UPDATED: ต้องทั้งแท่งอยู่ใต้ fiveDown_200)
if not S_seek and not S_confirmActive
float __btS = math.max(open, close)
float __bbS = math.min(open, close)
float __fiveS = fiveDown_200
bool startShortSeed = close < open and not na(__fiveS) and (__btS <= __fiveS)
if startShortSeed
S_seek := true
S_runMinAbs := bar_index
S_runMinClose := close
if S_confirmActive
if close < S_candClose and close < open
S_seek := true
S_confirmActive := false
S_candAbs := int(na)
S_candClose := na
S_runMinAbs := bar_index
S_runMinClose := close
else if bar_index >= S_candAbs + rightWinBars
bool acceptS = true
// ตรวจซ้ำที่แท่งผู้สมัคร (ทั้งแท่งต้องอยู่ใต้ fiveDown_200)
int offCandS = bar_index - S_candAbs
float _btS = math.max(open[offCandS], close[offCandS])
float _bbS = math.min(open[offCandS], close[offCandS])
float _fiveS = fiveDown_200[offCandS]
bool bodyBelow5 = not na(_fiveS) and (_btS <= _fiveS)
acceptS := acceptS and bodyBelow5
if not na(S_prevP2Abs)
int dBarsS = S_candAbs - S_prevP2Abs
if dBarsS <= p2NewWithinBars
acceptS := acceptS and (S_candClose < S_prevP2Close)
if not acceptS
S_seek := true
S_confirmActive := false
S_runMinAbs := bar_index
S_runMinClose := close
S_candAbs := int(na)
S_candClose := na
else
array.clear(S_SET_BOX)
array.clear(S_SET_LBL)
S_P2Abs := S_candAbs
resetReqAllS := false
resetReqP1S := false
resetReqP2S := false
resetReqP3S := false
int offP2s = bar_index - S_P2Abs
S_P2Close := close[offP2s]
S_P2_bodyTop := math.max(open[offP2s], close[offP2s])
S_P2_bodyBot := math.min(open[offP2s], close[offP2s])
S_prevP2Abs := S_P2Abs
S_prevP2Close := S_P2Close
[bxP2s, lbP2s] = f_draw_mark_group(S_P2Abs, false, P2BoxColor, P2BoxFillTransp, BoxBorderTransp, showP2Label, "P2", false)
[keepNewP2S, _newAbsP2S, _newBoxP2S, _newLblP2S] = f_enforce_and_set(S_P2Abs, bxP2s, lbP2s, S_lastP2Abs, S_lastP2Box, S_lastP2Lbl)
if keepNewP2S
S_lastP2Abs := _newAbsP2S
S_lastP2Box := _newBoxP2S
S_lastP2Lbl := _newLblP2S
f_del_if_exists(S_lastP3Box, S_lastP3Lbl)
S_lastP3Abs := int(na)
S_lastP3Box := na
S_lastP3Lbl := na
S_P3Abs := int(na)
S_P3Px := na
f_clear_all_fe()
S_winOpenAbs := S_P2Abs + 1
int bestAbsS = int(na)
float bestDistS = na
for k = 1 to 50
int a = S_P2Abs - k
if a < 0
break
int off = bar_index - a
if off < 0 or off > 5000
continue
if close[off] >= open[off]
continue
float ema5d85 = fiveDown_85[off]
if na(ema5d85)
continue
float bt = math.max(open[off], close[off])
float bb = math.min(open[off], close[off])
float body = bt - bb
float fracBelow = body <= 0 ? 0.0 : math.max(0.0, math.min(bt, ema5d85) - bb)/body
if fracBelow >= 0.25
float d = math.abs(mid200[off] - (bt+bb)/2.0)
if na(bestDistS) or d < bestDistS or (d == bestDistS and (na(bestAbsS) or a < bestAbsS))
bestDistS := d
bestAbsS := a
if not na(bestAbsS) and f_gap_ok_left(bestAbsS, S_P2Abs)
int offb = bar_index - bestAbsS
S_P1Open := open[offb]
S_P1Abs := bestAbsS
[bxP1s, lbP1s] = f_draw_mark_group(S_P1Abs, false, P1BoxColor, P1BoxFillTransp, BoxBorderTransp, showP1Label, "P1", false)
[keepNewP1S, _newAbsP1S, _newBoxP1S, _newLblP1S] = f_enforce_and_set(S_P1Abs, bxP1s, lbP1s, S_lastP1Abs, S_lastP1Box, S_lastP1Lbl)
if keepNewP1S
S_lastP1Abs := _newAbsP1S
S_lastP1Box := _newBoxP1S
S_lastP1Lbl := _newLblP1S
S_seek := false
S_confirmActive := false
S_candAbs := int(na)
S_candClose := na
S_runMinAbs := int(na)
S_runMinClose := na
if S_seek and not S_confirmActive
if close < open
if close < nz(S_runMinClose, 1e100)
S_runMinClose := close
S_runMinAbs := bar_index
else if close > nz(S_runMinClose, -1e100)
S_candAbs := S_runMinAbs
S_candClose := S_runMinClose
S_seek := false
S_confirmActive := true
else if open > nz(S_runMinClose, -1e100)
S_candAbs := S_runMinAbs
S_candClose := S_runMinClose
S_seek := false
S_confirmActive := true
// ---------- LONG: close P3 window (classic picker) ----------
if not na(L_winOpenAbs)
int sAbs = L_winOpenAbs
int eAbs = bar_index
float rangeBody = L_P2_bodyTop - L_P2_bodyBot
float T33 = L_P2_bodyBot + rangeBody/3.0
float T75 = L_P2_bodyBot + rangeBody*0.75
int barsInWin = bar_index - L_winOpenAbs + 1
bool allowNormal = barsInWin >= 5 and close > open and close >= T33
bool allowEarly = barsInWin < 5 and close > open and close >= T75
if allowNormal or allowEarly
[p3PxL_tmp, p3AbsL] = f_pickP3_abs(sAbs, eAbs, true)
if not na(p3AbsL) and f_gap_ok_right(p3AbsL, L_P2Abs)
L_P3Abs := p3AbsL
L_P3Px := p3PxL_tmp
[bxP3, lbP3] = f_draw_mark_group(L_P3Abs, false, P3BoxColor, P3BoxFillTransp, BoxBorderTransp, showP3Label, "P3", true)
[keepNewP3L, _newAbsP3L, _newBoxP3L, _newLblP3L] = f_enforce_and_set(L_P3Abs, bxP3, lbP3, L_lastP3Abs, L_lastP3Box, L_lastP3Lbl)
if keepNewP3L
L_lastP3Abs := _newAbsP3L
L_lastP3Box := _newBoxP3L
L_lastP3Lbl := _newLblP3L
if showFE and not na(L_P1Open) and not na(L_P2Close)
float W = L_P2Close - L_P1Open
if W > 0
float y95 = f_rt(L_P3Px + 0.95 * W)
float y105 = f_rt(L_P3Px + 1.05 * W)
float y1618 = f_rt(L_P3Px + 1.618 * W)
float y2618 = f_rt(L_P3Px + 2.618 * W)
float y3618 = f_rt(L_P3Px + 3.618 * W)
float y4618 = f_rt(L_P3Px + 4.618 * W)
f_clear_all_fe()
f_add_fe_set(L_P3Abs, y95, y105, y1618, y2618, y3618, y4618)
L_winOpenAbs := int(na)
// ---------- SHORT: close P3 window (classic picker) ----------
if not na(S_winOpenAbs)
int sAbsS = S_winOpenAbs
int eAbsS = bar_index
float rangeBodyS = S_P2_bodyTop - S_P2_bodyBot
float T33d = S_P2_bodyTop - rangeBodyS/3.0
float T75d = S_P2_bodyTop - rangeBodyS*0.75
int barsInWinS = bar_index - S_winOpenAbs + 1
bool allowNormalS = barsInWinS >= 5 and close < open and close <= T33d
bool allowEarlyS = barsInWinS < 5 and close < open and close <= T75d
if allowNormalS or allowEarlyS
[p3PxS_tmp, p3AbsS] = f_pickP3_abs(sAbsS, eAbsS, false)
if not na(p3AbsS) and f_gap_ok_right(p3AbsS, S_P2Abs)
S_P3Abs := p3AbsS
S_P3Px := p3PxS_tmp
[bxP3s, lbP3s] = f_draw_mark_group(S_P3Abs, false, P3BoxColor, P3BoxFillTransp, BoxBorderTransp, showP3Label, "P3", false)
[keepNewP3S, _newAbsP3S, _newBoxP3S, _newLblP3S] = f_enforce_and_set(S_P3Abs, bxP3s, lbP3s, S_lastP3Abs, S_lastP3Box, S_lastP3Lbl)
if keepNewP3S
S_lastP3Abs := _newAbsP3S
S_lastP3Box := _newBoxP3S
S_lastP3Lbl := _newLblP3S
if showFE and not na(S_P1Open) and not na(S_P2Close)
float Ws = S_P2Close - S_P1Open
if Ws < 0
float y95s = f_rt(S_P3Px + 0.95 * Ws)
float y105s = f_rt(S_P3Px + 1.05 * Ws)
float y1618s = f_rt(S_P3Px + 1.618 * Ws)
float y2618s = f_rt(S_P3Px + 2.618 * Ws)
float y3618s = f_rt(S_P3Px + 3.618 * Ws)
float y4618s = f_rt(S_P3Px + 4.618 * Ws)
f_clear_all_fe()
f_add_fe_set(S_P3Abs, y95s, y105s, y1618s, y2618s, y3618s, y4618s)
S_winOpenAbs := int(na)
//──────────────────────────────── Manual Layer (+ Reset Latches) ─────────────────────
f_pick_abs_from_manual(_use, _pickMode, _time, _offset) =>
if not _use
na
else
_pickMode == PK_TIME ? f_find_abs_by_time(_time) : (bar_index + _offset)
f_pick_price_from_manual(_use, _abs, _pmode, _custom) =>
if not _use or na(_abs)
na
else
int off = bar_index - _abs
off < 0 or off > 5000 ? na : f_price_by_mode(off, _pmode, _custom)
useP1L_eff = useManP1L and not (resetReqAllL or resetReqP1L)
useP2L_eff = useManP2L and not (resetReqAllL or resetReqP2L)
useP3L_eff = useManP3L and not (resetReqAllL or resetReqP3L)
useP1S_eff = useManP1S and not (resetReqAllS or resetReqP1S)
useP2S_eff = useManP2S and not (resetReqAllS or resetReqP2S)
useP3S_eff = useManP3S and not (resetReqAllS or resetReqP3S)
// Effective ABS
int L_P1Abs_eff = useP1L_eff ? f_pick_abs_from_manual(useP1L_eff, pickP1L, manP1L_t, manP1L_of) : L_P1Abs
int L_P2Abs_eff = useP2L_eff ? f_pick_abs_from_manual(useP2L_eff, pickP2L, manP2L_t, manP2L_of) : L_P2Abs
int L_P3Abs_eff = useP3L_eff ? f_pick_abs_from_manual(useP3L_eff, pickP3L, manP3L_t, manP3L_of) : L_P3Abs
int S_P1Abs_eff = useP1S_eff ? f_pick_abs_from_manual(useP1S_eff, pickP1S, manP1S_t, manP1S_of) : S_P1Abs
int S_P2Abs_eff = useP2S_eff ? f_pick_abs_from_manual(useP2S_eff, pickP2S, manP2S_t, manP2S_of) : S_P2Abs
int S_P3Abs_eff = useP3S_eff ? f_pick_abs_from_manual(useP3S_eff, pickP3S, manP3S_t, manP3S_of) : S_P3Abs
// Effective Prices
float L_P1Open_eff = useP1L_eff ? f_pick_price_from_manual(useP1L_eff, L_P1Abs_eff, pmP1L, p1L_custom) : L_P1Open
float L_P2Close_eff = useP2L_eff ? f_pick_price_from_manual(useP2L_eff, L_P2Abs_eff, pmP2L, p2L_custom) : L_P2Close
float L_P3Px_eff = useP3L_eff ? f_pick_price_from_manual(useP3L_eff, L_P3Abs_eff, pmP3L, p3L_custom) : L_P3Px
float S_P1Open_eff = useP1S_eff ? f_pick_price_from_manual(useP1S_eff, S_P1Abs_eff, pmP1S, p1S_custom) : S_P1Open
float S_P2Close_eff = useP2S_eff ? f_pick_price_from_manual(useP2S_eff, S_P2Abs_eff, pmP2S, p2S_custom) : S_P2Close
float S_P3Px_eff = useP3S_eff ? f_pick_price_from_manual(useP3S_eff, S_P3Abs_eff, pmP3S, p3S_custom) : S_P3Px
// Redraw labels/boxes if manual in effect (apply de-dup too) — with GAP RULE
bool needRedrawL = useP1L_eff or useP2L_eff or useP3L_eff
bool needRedrawS = useP1S_eff or useP2S_eff or useP3S_eff
if needRedrawL
f_delete_boxes(L_SET_BOX)
f_delete_labels(L_SET_LBL)
if not na(L_P1Abs_eff) and not na(L_P2Abs_eff) and f_gap_ok_left(L_P1Abs_eff, L_P2Abs_eff) and showP1Label
[bx1, lb1] = f_draw_mark_group(L_P1Abs_eff, false, P1BoxColor, P1BoxFillTransp, BoxBorderTransp, true, "P1", true)
[keepP1L_m, nAbsP1L_m, nBoxP1L_m, nLblP1L_m] = f_enforce_and_set(L_P1Abs_eff, bx1, lb1, L_lastP1Abs, L_lastP1Box, L_lastP1Lbl)
if keepP1L_m
L_lastP1Abs := nAbsP1L_m
L_lastP1Box := nBoxP1L_m
L_lastP1Lbl := nLblP1L_m
if not na(L_P2Abs_eff) and showP2Label
[bx2, lb2] = f_draw_mark_group(L_P2Abs_eff, false, P2BoxColor, P2BoxFillTransp, BoxBorderTransp, true, "P2", true)
[keepP2L_m, nAbsP2L_m, nBoxP2L_m, nLblP2L_m] = f_enforce_and_set(L_P2Abs_eff, bx2, lb2, L_lastP2Abs, L_lastP2Box, L_lastP2Lbl)
if keepP2L_m
L_lastP2Abs := nAbsP2L_m
L_lastP2Box := nBoxP2L_m
L_lastP2Lbl := nLblP2L_m
if not na(L_P3Abs_eff) and not na(L_P2Abs_eff) and f_gap_ok_right(L_P3Abs_eff, L_P2Abs_eff) and showP3Label
[bx3, lb3] = f_draw_mark_group(L_P3Abs_eff, false, P3BoxColor, P3BoxFillTransp, BoxBorderTransp, true, "P3", true)
[keepP3L_m, nAbsP3L_m, nBoxP3L_m, nLblP3L_m] = f_enforce_and_set(L_P3Abs_eff, bx3, lb3, L_lastP3Abs, L_lastP3Box, L_lastP3Lbl)
if keepP3L_m
L_lastP3Abs := nAbsP3L_m
L_lastP3Box := nBoxP3L_m
L_lastP3Lbl := nLblP3L_m
if needRedrawS
f_delete_boxes(S_SET_BOX)
f_delete_labels(S_SET_LBL)
if not na(S_P1Abs_eff) and not na(S_P2Abs_eff) and f_gap_ok_left(S_P1Abs_eff, S_P2Abs_eff) and showP1Label
[bx1s, lb1s] = f_draw_mark_group(S_P1Abs_eff, false, P1BoxColor, P1BoxFillTransp, BoxBorderTransp, true, "P1", false)
[keepP1S_m, nAbsP1S_m, nBoxP1S_m, nLblP1S_m] = f_enforce_and_set(S_P1Abs_eff, bx1s, lb1s, S_lastP1Abs, S_lastP1Box, S_lastP1Lbl)
if keepP1S_m
S_lastP1Abs := nAbsP1S_m
S_lastP1Box := nBoxP1S_m
S_lastP1Lbl := nLblP1S_m
if not na(S_P2Abs_eff) and showP2Label
[bx2s, lb2s] = f_draw_mark_group(S_P2Abs_eff, false, P2BoxColor, P2BoxFillTransp, BoxBorderTransp, true, "P2", false)
[keepP2S_m, nAbsP2S_m, nBoxP2S_m, nLblP2S_m] = f_enforce_and_set(S_P2Abs_eff, bx2s, lb2s, S_lastP2Abs, S_lastP2Box, S_lastP2Lbl)
if keepP2S_m
S_lastP2Abs := nAbsP2S_m
S_lastP2Box := nBoxP2S_m
S_lastP2Lbl := nLblP2S_m
if not na(S_P3Abs_eff) and not na(S_P2Abs_eff) and f_gap_ok_right(S_P3Abs_eff, S_P2Abs_eff) and showP3Label
[bx3s, lb3s] = f_draw_mark_group(S_P3Abs_eff, false, P3BoxColor, P3BoxFillTransp, BoxBorderTransp, true, "P3", false)
[keepP3S_m, nAbsP3S_m, nBoxP3S_m, nLblP3S_m] = f_enforce_and_set(S_P3Abs_eff, bx3s, lb3s, S_lastP3Abs, S_lastP3Box, S_lastP3Lbl)
if keepP3S_m
S_lastP3Abs := nAbsP3S_m
S_lastP3Box := nBoxP3S_m
S_lastP3Lbl := nLblP3S_m
// FE from effective points (Manual precedence) — add GAP RULE
bool canFE_L = showFE and not na(L_P1Open_eff) and not na(L_P2Close_eff) and not na(L_P3Px_eff) and not na(L_P1Abs_eff) and not na(L_P2Abs_eff) and not na(L_P3Abs_eff) and f_gap_ok_left(L_P1Abs_eff, L_P2Abs_eff) and f_gap_ok_right(L_P3Abs_eff, L_P2Abs_eff)
bool canFE_S = showFE and not na(S_P1Open_eff) and not na(S_P2Close_eff) and not na(S_P3Px_eff) and not na(S_P1Abs_eff) and not na(S_P2Abs_eff) and not na(S_P3Abs_eff) and f_gap_ok_left(S_P1Abs_eff, S_P2Abs_eff) and f_gap_ok_right(S_P3Abs_eff, S_P2Abs_eff)
if canFE_L
float W = L_P2Close_eff - L_P1Open_eff
if W > 0
float y95 = f_rt(L_P3Px_eff + 0.95 * W)
float y105 = f_rt(L_P3Px_eff + 1.05 * W)
float y1618 = f_rt(L_P3Px_eff + 1.618 * W)
float y2618 = f_rt(L_P3Px_eff + 2.618 * W)
float y3618 = f_rt(L_P3Px_eff + 3.618 * W)
float y4618 = f_rt(L_P3Px_eff + 4.618 * W)
f_clear_all_fe()
f_add_fe_set(L_P3Abs_eff, y95, y105, y1618, y2618, y3618, y4618)
else if canFE_S
float Ws = S_P2Close_eff - S_P1Open_eff
if Ws < 0
float y95s = f_rt(S_P3Px_eff + 0.95 * Ws)
float y105s = f_rt(S_P3Px_eff + 1.05 * Ws)
float y1618s = f_rt(S_P3Px_eff + 1.618 * Ws)
float y2618s = f_rt(S_P3Px_eff + 2.618 * Ws)
float y3618s = f_rt(S_P3Px_eff + 3.618 * Ws)
float y4618s = f_rt(S_P3Px_eff + 4.618 * Ws)
f_clear_all_fe()
f_add_fe_set(S_P3Abs_eff, y95s, y105s, y1618s, y2618s, y3618s, y4618s)
// FE lifespan cleanup
int nBorn = array.size(FE_born)
if nBorn > 0
for k = 0 to nBorn - 1
int idx = nBorn - 1 - k
int born = array.get(FE_born, idx)
if bar_index - born > feLife
f_delete_fe_index(idx)
// Candle coloring
bool isP1_bar = (not na(L_P1Abs_eff) and bar_index == L_P1Abs_eff) or (not na(S_P1Abs_eff) and bar_index == S_P1Abs_eff)
bool isP2_bar = (not na(L_P2Abs_eff) and bar_index == L_P2Abs_eff) or (not na(S_P2Abs_eff) and bar_index == S_P2Abs_eff)
bool isP3_bar = (not na(L_P3Abs_eff) and bar_index == L_P3Abs_eff) or (not na(S_P3Abs_eff) and bar_index == S_P3Abs_eff)
color _candleCol = na
_candleCol := isP3_bar ? colP3Candle : (isP2_bar ? colP2Candle : (isP1_bar ? colP1Candle : na))
barcolor(recolorBars ? _candleCol : na)
// Reserve style slot
plot(showFE ? na : na, title="fe-slot")
//──────────────────────────────── di (DSI; masked) ───────────────────────────
float dsi_atr = ta.atr(14)
float dsi_highestBody = open > close ? open : close
float dsi_lowestBody = open > close ? close : open
var float dsi_res1 = na
var float dsi_res2 = na
var float dsi_sup1 = na
var float dsi_sup2 = na
var bool dsi_lookForNewResistance = true
var bool dsi_lookForNewSupport = true
var float dsi_prevRes1 = na
var float dsi_prevRes2 = na
var float dsi_prevSup1 = na
var float dsi_prevSup2 = na
var float dsi_atrSaved = na
var float dsi_potR1 = na
var float dsi_potR2 = na
var float dsi_potS1 = na
var float dsi_potS2 = na
if high[1] == ta.highest(high, lookback) and high < high[1] and dsi_lookForNewResistance
float r1 = high[1]
float hb2 = (open[2] > close[2] ? open[2] : close[2])
float hb1 = (open[1] > close[1] ? open[1] : close[1])
float hb0 = (open > close ? open : close)
float r2 = hb2 > hb1 ? hb2 : (hb0 > hb1 ? hb0 : hb1)
if (r1 - r2) / dsi_atr <= maxZoneSize
dsi_lookForNewResistance := false
dsi_potR1 := r1
dsi_potR2 := r2
dsi_atrSaved := dsi_atr
if low[1] == ta.lowest(low, lookback) and low > low[1] and dsi_lookForNewSupport
float s1 = low[1]
float lb2 = (open[2] > close[2] ? close[2] : open[2])
float lb1 = (open[1] > close[1] ? close[1] : open[1])
float lb0 = (open > close ? close : open)
float s2 = lb2 < lb1 ? lb2 : (lb0 < lb1 ? lb0 : lb1)
if (s2 - s1) / dsi_atr <= maxZoneSize
dsi_lookForNewSupport := false
dsi_potS1 := s1
dsi_potS2 := s2
dsi_atrSaved := dsi_atr
if close > dsi_potR1 and barstate.isconfirmed
dsi_potR1 := na
dsi_potR2 := na
if close < dsi_potS1 and barstate.isconfirmed
dsi_potS1 := na
dsi_potS2 := na
if not na(dsi_potR1) and dsi_potR1 - low >= (nz(dsi_atrSaved, dsi_atr) * atrMovement)
dsi_prevRes1 := na(dsi_prevRes1) ? dsi_potR1 : dsi_prevRes1
dsi_prevRes2 := na(dsi_prevRes2) ? dsi_potR2 : dsi_prevRes2
dsi_res1 := dsi_potR1
dsi_res2 := dsi_potR2
dsi_potR1 := na
dsi_potR2 := na
if not na(dsi_potS1) and high - dsi_potS1 >= (nz(dsi_atrSaved, dsi_atr) * atrMovement)
dsi_prevSup1 := na(dsi_prevSup1) ? dsi_potS1 : dsi_prevSup1
dsi_prevSup2 := na(dsi_prevSup2) ? dsi_potS2 : dsi_prevSup2
dsi_sup1 := dsi_potS1
dsi_sup2 := dsi_potS2
dsi_potS1 := na
dsi_potS2 := na
var int dsi_supCount = 0
var int dsi_resCount = 0
if close >= dsi_res1 and barstate.isconfirmed
dsi_lookForNewResistance := true
dsi_lookForNewSupport := true
dsi_resCount += 1
if close <= dsi_sup1 and barstate.isconfirmed
dsi_lookForNewSupport := true
dsi_lookForNewResistance := true
dsi_supCount += 1
if (close > dsi_res1 and na(dsi_prevRes1) and barstate.isconfirmed) or na(dsi_prevRes1) or dsi_resCount >= newStructureReset
dsi_prevRes1 := dsi_res1
dsi_prevRes2 := dsi_res2
dsi_resCount := 0
if (close < dsi_sup1 and na(dsi_prevSup1) and barstate.isconfirmed) or na(dsi_prevSup1) or dsi_supCount >= newStructureReset
dsi_prevSup1 := dsi_sup1
dsi_prevSup2 := dsi_sup2
dsi_supCount := 0
if close < dsi_prevRes2 and barstate.isconfirmed
dsi_prevRes1 := na
dsi_prevRes2 := na
if close > dsi_prevSup2 and barstate.isconfirmed
dsi_prevSup1 := na
dsi_prevSup2 := na
dsi_r1plot = plot(showDSI and (dsi_res1 == dsi_res1[1]) ? dsi_res1 : na, color=close >= dsi_res1 ? dsiBullColor : dsiBearColor, style=plot.style_linebr, title="di R1")
dsi_r2plot = plot(showDSI and (dsi_res1 == dsi_res1[1]) ? dsi_res2 : na, color=close >= dsi_res1 ? dsiBullColor : dsiBearColor, style=plot.style_linebr, title="di R2")
fill(dsi_r1plot, dsi_r2plot, color=showDSI ? (close > dsi_res1 ? dsiBullColor : color.new(dsiBearColor, 50)) : color.new(color.black, 100), title="di Resistance Zone")
dsi_s1plot = plot(showDSI and (dsi_sup1 == dsi_sup1[1]) ? dsi_sup1 : na, color=close < dsi_sup1 ? dsiBearColor : dsiBullColor, style=plot.style_linebr, title="di S1")
dsi_s2plot = plot(showDSI and (dsi_sup1 == dsi_sup1[1]) ? dsi_sup2 : na, color=close < dsi_sup1 ? dsiBearColor : dsiBullColor, style=plot.style_linebr, title="di S2")
fill(dsi_s1plot, dsi_s2plot, color=showDSI ? (close < dsi_sup1 ? dsiBearColor : color.new(dsiBullColor, 50)) : color.new(color.black, 100), title="di Support Zone")
dsi_ps1plot = plot(showDSI and drawPreviousStructure and (dsi_prevSup1 == dsi_prevSup1[1]) and (dsi_prevSup1 != dsi_sup1) ? dsi_prevSup1 : na, color=dsiBearColor, style=plot.style_linebr, title="di PS1")
dsi_ps2plot = plot(showDSI and drawPreviousStructure and (dsi_prevSup1 == dsi_prevSup1[1]) and (dsi_prevSup1 != dsi_sup1) ? dsi_prevSup2 : na, color=dsiBearColor, style=plot.style_linebr, title="di PS2")
fill(dsi_ps1plot, dsi_ps2plot, color=showDSI and drawPreviousStructure ? color.new(dsiBearColor, 10) : color.new(color.black, 100), title="di Previous Support Zone")
dsi_pr1plot = plot(showDSI and drawPreviousStructure and (dsi_prevRes1 == dsi_prevRes1[1]) and (dsi_prevRes1 != dsi_res1) ? dsi_prevRes1 : na, color=dsiBullColor, style=plot.style_linebr, title="di PR1")
dsi_pr2plot = plot(showDSI and drawPreviousStructure and (dsi_prevRes1 == dsi_prevRes1[1]) and (dsi_prevRes1 != dsi_res1) ? dsi_prevRes2 : na, color=dsiBullColor, style=plot.style_linebr, title="di Previous Resistance Zone")
//────────────────────────── Elliptic Bands (masked, locked) ──────────────────────────
groupEllipse = "es bands"
EB_show = input.bool(true, "show es bands", group=groupEllipse)
EB_midColor = input.color(color.rgb(229,236,241), "mid color", group=groupEllipse)
EB_upColor = input.color(color.green, "upper color", group=groupEllipse)
EB_dnColor = input.color(color.red, "lower color", group=groupEllipse)
EB_fillTransp = input.int(80, "band transparency (0–100)", minval=0, maxval=100, group=groupEllipse)
EB_showFill = input.bool(false, "fill es cloud", group=groupEllipse)
EB_showSignals = input.bool(true, "show es signals", group=groupEllipse)
EB_buyColor = input.color(color.green, "buy signal color", group=groupEllipse)
EB_sellColor = input.color(color.red, "sell signal color", group=groupEllipse)
// locked params
const int EB_MA_LEN = 50
const int EB_PERIOD = 50
const float EB_MULTI = 2.0
float EB_central_ma = ta.sma(close, EB_MA_LEN)
float EB_b = ta.stdev(close, EB_MA_LEN) * EB_MULTI
int EB_cycle_pos = bar_index % EB_PERIOD
float EB_x = 2.0 * (EB_cycle_pos / EB_PERIOD) - 1.0
float EB_offset = EB_b * math.sqrt(math.max(0.0, 1.0 - EB_x * EB_x))
float EB_band_upper = EB_central_ma + EB_offset
float EB_band_lower = EB_central_ma - EB_offset
// plot lines (upper/lower/mid)
EB_p_mid = plot(EB_show ? EB_central_ma : na, title="es mid", color=EB_midColor, linewidth=1)
EB_p_up = plot(EB_show ? EB_band_upper : na, title="es upper", color=EB_upColor)
EB_p_dn = plot(EB_show ? EB_band_lower : na, title="es lower", color=EB_dnColor)
// fill only if EB_showFill = true
EB_fillColor = (EB_show and EB_showFill) ? color.new(color.gray, EB_fillTransp) : color.new(color.gray, 100)
fill(EB_p_up, EB_p_dn, color=EB_fillColor, title="es cloud")
// signals
bool EB_buy = EB_show and close[1] < nz(EB_band_lower[1]) and close >= nz(EB_band_lower) and close <= nz(EB_band_upper) and barstate.isconfirmed
bool EB_sell = EB_show and close[1] > nz(EB_band_upper[1]) and close >= nz(EB_band_lower) and close <= nz(EB_band_upper) and barstate.isconfirmed
plotshape(EB_showSignals and EB_buy, title="es buy", location=location.belowbar, color=EB_buyColor, style=shape.triangleup, size=size.tiny)
plotshape(EB_showSignals and EB_sell, title="es sell", location=location.abovebar, color=EB_sellColor, style=shape.triangledown, size=size.tiny)
// Wave Labels (1–5) — minimal module for tp11ofc1 (Pine v6) — labels only
//──────────────────────────────────────────────────────────────────────────────
groupEW = "Wave labels (Elliott)"
srcHiSel = input.string("high", "High source", options=["high","close","max open/close"], group=groupEW)
srcLoSel = input.string("low", "Low source", options=["low","close","min open/close"], group=groupEW)
ew_hi = srcHiSel == "high" ? high : srcHiSel == "close" ? close : math.max(open, close)
ew_lo = srcLoSel == "low" ? low : srcLoSel == "close" ? close : math.min(open, close)
ewShowS1 = input.bool(true, "Show wave S", group=groupEW, inline="s1")
ewLen1 = input.int(4, "len", minval=1, group=groupEW, inline="s1")
ewCol1 = input.color(color.new(color.red,0), "", group=groupEW, inline="s1")
ewShowS2 = input.bool(true, "Show wave M", group=groupEW, inline="s2")
ewLen2 = input.int(8, "len", minval=1, group=groupEW, inline="s2")
ewCol2 = input.color(color.new(#0d86e9, 0), "", group=groupEW, inline="s2")
ewShowS3 = input.bool(true, "Show wave L", group=groupEW, inline="s3")
ewLen3 = input.int(16, "len", minval=1, group=groupEW, inline="s3")
ewCol3 = input.color(color.new(#470303, 0),"", group=groupEW, inline="s3")
ewSizeStr = input.string("small","Label size", options=["tiny","small","normal","large"], group=groupEW)
ew_lsize(s) => s=="tiny"?size.tiny:s=="normal"?size.normal:s=="large"?size.large:size.small
type _ZZ
int[] d
int[] x
float[] y
newZZ() => _ZZ.new(array.new_int(), array.new_int(), array.new_float())
f_push_pivot(_aZZ, _dir, _x1, _y1, _x2, _y2) =>
_aZZ.d.unshift(_dir)
_aZZ.x.unshift(_x2)
_aZZ.y.unshift(_y2)
if array.size(_aZZ.d) > 12
_ = array.pop(_aZZ.d)
_ = array.pop(_aZZ.x)
_ = array.pop(_aZZ.y)
var label[] EW_LABELS = array.new_label()
f_add_label(_x, _y, _txt, _col, _up) =>
label lb = label.new(_x, _y, text=_txt, style=_up?label.style_label_down:label.style_label_up, textcolor=_col, color=color.new(color.black, 100), size=ew_lsize(ewSizeStr), xloc=xloc.bar_index)
array.push(EW_LABELS, lb)
if array.size(EW_LABELS) > 500
label.delete(array.get(EW_LABELS, 0))
array.remove(EW_LABELS, 0)
f_check_motive_bull(_1y,_2y,_3y,_4y,_5y,_6y) =>
_W5 = _6y - _5y
_W3 = _4y - _3y
_W1 = _2y - _1y
_min = math.min(_W1,_W3,_W5)
(_W3 != _min) and (_6y > _4y) and (_3y > _1y) and (_5y > _2y)
f_check_motive_bear(_1y,_2y,_3y,_4y,_5y,_6y) =>
_W5 = _5y - _6y
_W3 = _3y - _4y
_W1 = _1y - _2y
_min = math.min(_W1,_W3,_W5)
(_W3 != _min) and (_4y > _6y) and (_1y > _3y) and (_2y > _5y)
f_wave_labels(_enabled, _len, _col, _rowSep) =>
if _enabled
var _ZZ zz = newZZ()
if barstate.isfirst
for _=0 to 10
array.unshift(zz.d, 0)
array.unshift(zz.x, 0)
array.unshift(zz.y, 0)
x2 = bar_index - 1
ph = ta.pivothigh(ew_hi, _len, 1)
pl = ta.pivotlow (ew_lo, _len, 1)
if not na(ph)
dir = array.get(zz.d, 0)
x1 = array.get(zz.x, 0)
y1 = array.get(zz.y, 0)
y2h = nz(ew_hi[1])
if dir < 1
f_push_pivot(zz, 1, x1, y1, x2, y2h)
else if ph > y1
array.set(zz.x, 0, x2)
array.set(zz.y, 0, y2h)
_6x = x2, _6y = y2h
_5x = array.get(zz.x,1), _5y = array.get(zz.y,1)
_4x = array.get(zz.x
Skrip dilindungi
Skrip ini diterbitkan sebagai sumber tertutup. Akan tetapi, anda boleh menggunakannya dengan percuma dan tanpa had – ketahui lebih lanjut di sini.
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.
Skrip dilindungi
Skrip ini diterbitkan sebagai sumber tertutup. Akan tetapi, anda boleh menggunakannya dengan percuma dan tanpa had – ketahui lebih lanjut di sini.
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.