// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © SAMANYFX / © LuxAlgo
//@version=6
indicator("TRINITY 2.0", overlay=true, max_lines_count=500, max_boxes_count=500, max_labels_count=500, max_bars_back=3000)
o = 'Options'
sp1 = ' '
sp2 = ' '
ny_ = 'New York' + sp1
lo_ = 'London Open'
lc_ = 'London Close'
as_ = 'Asian'
i_mode = input.string('Present', title='Mode', options=['Present', 'Historical'])
showMS = input.bool(true, title='', group='Market Structures', inline='MS')
len = input.int (5, title=' Length ' +sp2, group='Market Structures', inline='MS', minval=3, maxval=10)
iMSS = input.bool(true, title=' MSS' +sp1, group='Market Structures', inline='M1')
cMSSbl = input.color(color.new(#00e6a1, 0), title='bullish', group='Market Structures', inline='M1')
cMSSbr = input.color(color.new(#e60400, 0), title='bearish', group='Market Structures', inline='M1')
iBOS = input.bool(true, title=' BOS'+sp1, group='Market Structures', inline='BS')
cBOSbl = input.color(color.new(#00e6a1, 0), title='bullish', group='Market Structures', inline='BS')
cBOSbr = input.color(color.new(#e60400, 0), title='bearish', group='Market Structures', inline='BS')
sDispl = input.bool(false, title='Show Displacement', group='Displacement')
perc_Body = 0.36
bxBack = 10
sVimbl = input.bool(true, title='', group='Volume Imbalance', inline='VI')
visVim = input.int (2, title=" # Visible VI's "+sp1, group='Volume Imbalance', inline='VI', minval=2, maxval=100)
cVimbl = input.color(color.new(#06b2d0, 0), title='', group='Volume Imbalance', inline='VI')
showOB = input.bool(true, title='Show Order Blocks', group='Order Blocks')
ob_length = input.int (10, title='Swing Lookback', group='Order Blocks', minval=3)
showBull = input.int (1, title='Show Last Bullish OB', group='Order Blocks', minval=0)
showBear = input.int (1, title='Show Last Bearish OB', group='Order Blocks', minval=0)
useBody = input.bool(false, title='Use Candle Body')
bullCss = input.color(color.new(#3e89fa, 0), title='Bullish OB', group='Order Blocks', inline='bullcss')
bullBrkCss = input.color(color.new(#4785f9, 85), title='Bullish Break', group='Order Blocks', inline='bullcss')
bearCss = input.color(color.new(#FF3131, 0), title='Bearish OB', group='Order Blocks', inline='bearcss')
bearBrkCss = input.color(color.new(#f9ff57, 85), title='Bearish Break', group='Order Blocks', inline='bearcss')
showLabels = input.bool(false, title='Show Historical Polarity Changes', group='Order Blocks')
showLq = input.bool(true, title='Show Liquidity', group='Liquidity')
a = 10 / input.float(4, title='margin', group='Liquidity', step=0.1, minval=2, maxval=7)
visLiq = input.int (2, title='# Visible Liq. boxes', group='Liquidity', minval=1, maxval=50)
cLIQ_B = input.color(color.new(#fa451c, 0), title='Buyside Liquidity ', group='Liquidity')
cLIQ_S = input.color(color.new(#1ce4fa, 0), title='Sellside Liquidity', group='Liquidity')
shwFVG = input.bool(true, title='Show FVGs', group='Fair Value Gaps')
i_BPR = input.bool(false, title='Balance Price Range', group='Fair Value Gaps')
i_FVG = input.string('FVG', title=o, group='Fair Value Gaps', options=['FVG', 'IFVG'])
visBxs = input.int (2, title="# Visible FVG's", group='Fair Value Gaps', minval=1, maxval=20)
cFVGbl = input.color(color.new(#00e676, 0), title='Bullish FVG ', group='Fair Value Gaps', inline='FVGbl')
cFVGblBR = input.color(color.new(#808000, 0), title='Break', group='Fair Value Gaps', inline='FVGbl')
cFVGbr = input.color(color.new(#ff5252, 0), title='Bearish FVG ', group='Fair Value Gaps', inline='FVGbr')
cFVGbrBR = input.color(color.new(#FF0000, 0), title='Break', group='Fair Value Gaps', inline='FVGbr')
iNWOG = input.bool(true, title='', inline='NWOG', group='NWOG/NDOG')
cNWOG1 = input.color(color.new(#ff5252, 28), title='NWOG ', inline='NWOG', group='NWOG/NDOG')
cNWOG2 = input.color(color.new(#b2b5be, 50), title='', inline='NWOG', group='NWOG/NDOG')
maxNWOG = input.int (3, title='Show max', inline='NWOG', group='NWOG/NDOG', minval=0, maxval=50)
iNDOG = input.bool(false, title='', inline='NDOG', group='NWOG/NDOG')
cNDOG1 = input.color(color.new(#ff9800, 20), title='NDOG ', inline='NDOG', group='NWOG/NDOG')
cNDOG2 = input.color(color.new(#4dd0e1, 65), title='', inline='NDOG', group='NWOG/NDOG')
maxNDOG = input.int (1, title='Show max', inline='NDOG', group='NWOG/NDOG', minval=0, maxval=50)
iFib = input.string('NONE', title='Fibonacci between last: ', group='Fibonacci', options=['FVG', 'BPR', 'OB', 'Liq', 'VI', 'NWOG', 'NONE'])
iExt = input.bool(false, title='Extend lines', group='Fibonacci')
showKZ = input.bool(false, title='Show Killzones', group='Killzones')
showNy = input.bool(true, title=ny_, inline='ny', group='Killzones') and showKZ
nyCss = input.color(color.new(#ff5d00, 93), title='', inline='ny', group='Killzones')
showLdno = input.bool(true, title=lo_, inline='lo', group='Killzones') and showKZ
ldnoCss = input.color(color.new(#00bcd4, 93), title='', inline='lo', group='Killzones')
showLdnc = input.bool(true, title=lc_, inline='lc', group='Killzones') and showKZ
ldncCss = input.color(color.new(#2157f3, 93), title='', inline='lc', group='Killzones')
showAsia = input.bool(true, title=as_+sp2, inline='as', group='Killzones') and showKZ
asiaCss = input.color(color.new(#e91e63, 93), title='', inline='as', group='Killzones')
g_ote = "OTE Zone"
ote_fib1 = input.float(0.618, "Fib 0.618", group=g_ote, step=0.001)
ote_fib2 = input.float(0.786, "Fib 0.786", group=g_ote, step=0.001)
cOTEbull = input.color(color.new(#00e676, 85), "OTE Long", group=g_ote)
cOTEbear = input.color(color.new(#ff5252, 85), "OTE Short", group=g_ote)
g_tri = "TRINITY Setup"
tri_close = input.bool(true, "Alertes sur cloture seulement", group=g_tri)
// tri_strictZone supprimé : le signal se déclenche sans attendre le prix dans l'OTE
//-----------------------------------------------------------------------------}
// GENERAL
//-----------------------------------------------------------------------------{
n = bar_index
hi = high
lo = low
tf_msec = timeframe.in_seconds(timeframe.period) * 1000
maxSize = 50
atr = ta.atr(10)
per = i_mode == 'Present' ? last_bar_index - bar_index <= 500 : true
xloc = iFib == 'OB' ? xloc.bar_time : xloc.bar_index
ext = iExt ? extend.right : extend.none
plus = iFib == 'OB' ? tf_msec * 50 : 50
mx = math.max(close, open)
mn = math.min(close, open)
body = math.abs(close - open)
meanBody = ta.sma(body, len)
max = useBody ? mx : high
min = useBody ? mn : low
blBrkConf = 0
brBrkConf = 0
//-----------------------------------------------------------------------------}
// TYPES
//-----------------------------------------------------------------------------{
type ZZ
int [] d
int [] x
float [] y
bool [] b
type _2ln_lb
line l1
line l2
label lb
type bx_ln
box b
line l
type bx_ln_lb
box bx
line ln
label lb
type mss
int dir
line [] l_mssBl
line [] l_mssBr
line [] l_bosBl
line [] l_bosBr
label[] lbMssBl
label[] lbMssBr
label[] lbBosBl
label[] lbBosBr
type liq
box bx
bool broken
bool brokenTop
bool brokenBtm
line ln
type ob
float top = na
float btm = na
int loc = bar_index
bool breaker = false
int break_loc = na
type swing
float y = na
int x = na
bool crossed = false
type FVG
box box
bool active
int pos
var mss MSS = mss.new(0, array.new<line>(), array.new<line>(), array.new<line>(), array.new<line>(), array.new<label>(), array.new<label>(), array.new<label>(), array.new<label>())
//-----------------------------------------------------------------------------}
// VARIABLES
//-----------------------------------------------------------------------------{
var _2ln_lb[] Vimbal = array.new<_2ln_lb>()
var liq[] b_liq_B = array.new<liq>(1, liq.new(box(na), false, false, false, line(na)))
var liq[] b_liq_S = array.new<liq>(1, liq.new(box(na), false, false, false, line(na)))
var ob[] bullish_ob = array.new<ob>()
var ob[] bearish_ob = array.new<ob>()
var bx_ln[] bl_NWOG = array.new<bx_ln>()
var bx_ln[] bl_NDOG = array.new<bx_ln>()
var bx_ln_lb[] a_bx_ln_lb = array.new<bx_ln_lb>()
var FVG[] bFVG_UP = array.new<FVG>()
var FVG[] bFVG_DN = array.new<FVG>()
var FVG[] bBPR_UP = array.new<FVG>()
var FVG[] bBPR_DN = array.new<FVG>()
var ZZ aZZ = ZZ.new(array.new<int>(maxSize, 0), array.new<int>(maxSize, 0), array.new<float>(maxSize, na), array.new<bool>(maxSize, false))
var float friCp = na, var int friCi = na
var float monOp = na, var int monOi = na
var float prDCp = na, var int prDCi = na
var float cuDOp = na, var int cuDOi = na
var line _diag = line.new(na, na, na, na, color=color.new(color.silver, 50), style=line.style_dashed, xloc=xloc)
var line _vert = line.new(na, na, na, na, color=color.new(color.silver, 50), style=line.style_dotted, xloc=xloc)
var line _zero = line.new(na, na, na, na, color=color.new(color.silver, 5), style=line.style_solid, xloc=xloc, extend=ext)
var line _0236 = line.new(na, na, na, na, color=color.new(color.orange, 25), style=line.style_solid, xloc=xloc, extend=ext)
var line _0382 = line.new(na, na, na, na, color=color.new(color.yellow, 25), style=line.style_solid, xloc=xloc, extend=ext)
var line _0500 = line.new(na, na, na, na, color=color.new(color.green, 25), style=line.style_solid, xloc=xloc, extend=ext)
var line _0618 = line.new(na, na, na, na, color=color.new(color.yellow, 25), style=line.style_solid, xloc=xloc, extend=ext)
var line _0786 = line.new(na, na, na, na, color=color.new(color.orange, 25), style=line.style_solid, xloc=xloc, extend=ext)
var line _one_ = line.new(na, na, na, na, color=color.new(color.silver, 5), style=line.style_solid, xloc=xloc, extend=ext)
var line _1618 = line.new(na, na, na, na, color=color.new(color.yellow, 25), style=line.style_solid, xloc=xloc, extend=ext)
// OTE variables
var float tl_obBtm = na
var float tl_obTop = na
var int tl_obLoc = na
var float tl_swingHi = na
var bool tl_mssOk = false
var box tl_oteBox = na
var float ts_obBtm = na
var float ts_obTop = na
var int ts_obLoc = na
var float ts_swingLo = na
var bool ts_mssOk = false
var box ts_oteBox = na
var float ote_buy_lo = na
var float ote_buy_hi = na
var float ote_sel_lo = na
var float ote_sel_hi = na
var int prevMSSdir = 0
var int tl_ob_bar = 0 // bar_index quand le TL OB a été détecté
var int ts_ob_bar = 0 // bar_index quand le TS OB a été détecté
//-----------------------------------------------------------------------------}
// METHODS
//-----------------------------------------------------------------------------{
method in_out(ZZ aZZ, int d, int x2, float y2) =>
aZZ.d.unshift(d), aZZ.x.unshift(x2), aZZ.y.unshift(y2), aZZ.b.unshift(false), aZZ.d.pop(), aZZ.x.pop(), aZZ.y.pop(), aZZ.b.pop()
method setLine(line ln, int x1, float y1, int x2, float y2) => ln.set_xy1(x1, y1), ln.set_xy2(x2, y2)
method clear_aLabLin(label[] l) =>
if l.size() > 0
for i = l.size() - 1 to 0
l.pop().delete()
method clear_aLabLin(line[] l) =>
if l.size() > 0
for i = l.size() - 1 to 0
l.pop().delete()
method notransp(color css) => color.rgb(color.r(css), color.g(css), color.b(css))
method display(ob id, css, break_css, str) =>
if showOB
if id.breaker
a_bx_ln_lb.unshift(bx_ln_lb.new(box.new(id.loc, id.top, timenow + (tf_msec * 10), id.btm, na, bgcolor=break_css, extend=extend.none, xloc=xloc.bar_time), line(na), label(na)))
else
y = str == 'bl' ? id.btm : id.top
s = str == 'bl' ? label.style_label_up : label.style_label_down
a_bx_ln_lb.unshift(bx_ln_lb.new(box(na), line.new(id.loc, y, id.loc + (tf_msec * 10), y, xloc=xloc.bar_time, color=css, width=2), label.new(id.loc + (tf_msec * 10), y, text=str == 'bl' ? '+OB' : '-OB', xloc=xloc.bar_time, style=s, color=color(na), textcolor=css, size=size.small)))
// FIX #1 : swings() utilise le paramètre correctement
swings(swingLen) =>
var os = 0
var swing top = swing.new(na, na)
var swing btm = swing.new(na, na)
upper = ta.highest(swingLen)
lower = ta.lowest(swingLen)
os := high[swingLen] > upper ? 0 : low[swingLen] < lower ? 1 : os
if os == 0 and os[1] != 0
top := swing.new(high[swingLen], bar_index[swingLen])
if os == 1 and os[1] != 1
btm := swing.new(low[swingLen], bar_index[swingLen])
[top, btm]
set_lab(i, str) =>
style = str == 'Bl' ? label.style_label_down : label.style_label_up
txcol = str == 'Bl' ? color.lime : color.red
label.new(math.round(math.avg(aZZ.x.get(i), n)), aZZ.y.get(i), text='BOS', style=style, color=color(na), textcolor=txcol, size=size.tiny)
set_lin(i, str) =>
col = str == 'Bl' ? color.lime : color.red
line.new(aZZ.x.get(i), aZZ.y.get(i), n, aZZ.y.get(i), color=col, style=line.style_dotted)
// FIX #2 : MSS/BOS logic extraite dans une fonction dédiée
detect_mss() =>
if showMS
iH = aZZ.d.get(2) == 1 ? 2 : 1
iL = aZZ.d.get(2) == -1 ? 2 : 1
switch
close > aZZ.y.get(iH) and aZZ.d.get(iH) == 1 and MSS.dir < 1 =>
MSS.dir := 1
if i_mode == 'Present'
MSS.l_bosBl.clear_aLabLin(), MSS.l_bosBr.clear_aLabLin()
MSS.lbBosBl.clear_aLabLin(), MSS.lbBosBr.clear_aLabLin()
MSS.l_mssBl.clear_aLabLin(), MSS.l_mssBr.clear_aLabLin()
MSS.lbMssBl.clear_aLabLin(), MSS.lbMssBr.clear_aLabLin()
MSS.l_mssBl.unshift(line.new(aZZ.x.get(iH), aZZ.y.get(iH), n, aZZ.y.get(iH), color=cMSSbl))
MSS.lbMssBl.unshift(label.new(math.round(math.avg(aZZ.x.get(iH), n)), aZZ.y.get(iH), text='MSS', style=label.style_label_down, size=size.tiny, color=color(na), textcolor=cMSSbl))
close < aZZ.y.get(iL) and aZZ.d.get(iL) == -1 and MSS.dir > -1 =>
MSS.dir := -1
if i_mode == 'Present'
MSS.l_bosBl.clear_aLabLin(), MSS.l_bosBr.clear_aLabLin()
MSS.lbBosBl.clear_aLabLin(), MSS.lbBosBr.clear_aLabLin()
MSS.l_mssBl.clear_aLabLin(), MSS.l_mssBr.clear_aLabLin()
MSS.lbMssBl.clear_aLabLin(), MSS.lbMssBr.clear_aLabLin()
MSS.l_mssBr.unshift(line.new(aZZ.x.get(iL), aZZ.y.get(iL), n, aZZ.y.get(iL), color=cMSSbr))
MSS.lbMssBr.unshift(label.new(math.round(math.avg(aZZ.x.get(iL), n)), aZZ.y.get(iL), text='MSS', style=label.style_label_up, size=size.tiny, color=color(na), textcolor=cMSSbr))
MSS.dir == 1 and close > aZZ.y.get(iH) and iBOS =>
if MSS.l_bosBl.size() > 0
if aZZ.y.get(iH) != MSS.l_bosBl.get(0).get_y2() and aZZ.y.get(iH) != MSS.l_mssBl.get(0).get_y2()
MSS.l_bosBl.unshift(set_lin(iH, 'Bl')), MSS.lbBosBl.unshift(set_lab(iH, 'Bl'))
else
if aZZ.y.get(iH) != MSS.l_mssBl.get(0).get_y2()
MSS.l_bosBl.unshift(set_lin(iH, 'Bl')), MSS.lbBosBl.unshift(set_lab(iH, 'Bl'))
MSS.dir == -1 and close < aZZ.y.get(iL) and iBOS =>
if MSS.l_bosBr.size() > 0
if aZZ.y.get(iL) != MSS.l_bosBr.get(0).get_y2() and aZZ.y.get(iL) != MSS.l_mssBr.get(0).get_y2()
MSS.l_bosBr.unshift(set_lin(iL, 'Br')), MSS.lbBosBr.unshift(set_lab(iL, 'Br'))
else
if aZZ.y.get(iL) != MSS.l_mssBr.get(0).get_y2()
MSS.l_bosBr.unshift(set_lin(iL, 'Br')), MSS.lbBosBr.unshift(set_lab(iL, 'Br'))
if not iMSS
MSS.l_mssBl.get(0).set_color(color(na)), MSS.lbMssBl.get(0).set_textcolor(color(na))
MSS.l_mssBr.get(0).set_color(color(na)), MSS.lbMssBr.get(0).set_textcolor(color(na))
draw(left, col) =>
max_bars_back(time, 1000)
var int dir = na, var int x1 = na, var float y1 = na, var int x2 = na, var float y2 = na
sz = aZZ.d.size()
x2 := bar_index - 1
ph = ta.pivothigh(hi, left, 1)
pl = ta.pivotlow (lo, left, 1)
if not na(ph)
dir := aZZ.d.get(0), x1 := aZZ.x.get(0), y1 := aZZ.y.get(0), y2 := nz(hi[1])
if dir < 1
aZZ.in_out(1, x2, y2)
else
if dir == 1 and ph > y1
aZZ.x.set(0, x2), aZZ.y.set(0, y2)
if showLq and per and sz > 0
count = 0, st_P = 0., st_B = 0, minP = 0., maxP = 10e6
for i = 0 to math.min(sz, 50) - 1
if aZZ.d.get(i) == 1
if aZZ.y.get(i) > ph + (atr/a)
break
else
if aZZ.y.get(i) > ph - (atr/a) and aZZ.y.get(i) < ph + (atr/a)
count += 1, st_B := aZZ.x.get(i), st_P := aZZ.y.get(i)
if aZZ.y.get(i) > minP
minP := aZZ.y.get(i)
if aZZ.y.get(i) < maxP
maxP := aZZ.y.get(i)
if count > 2
getB = b_liq_B.get(0)
if st_B == getB.bx.get_left()
getB.bx.set_top(math.avg(minP, maxP) + (atr/a))
getB.bx.set_rightbottom(n + 10, math.avg(minP, maxP) - (atr/a))
else
b_liq_B.unshift(liq.new(box.new(st_B, math.avg(minP, maxP) + (atr/a), n + 10, math.avg(minP, maxP) - (atr/a), text='Buyside liquidity', text_size=size.tiny, text_halign=text.align_left, text_valign=text.align_bottom, text_color=color.new(cLIQ_B, 25), bgcolor=color(na), border_color=color(na)), false, false, false, line.new(st_B, st_P, n - 1, st_P, color=color.new(cLIQ_B, 0))))
if b_liq_B.size() > visLiq
getLast = b_liq_B.pop()
getLast.bx.delete()
getLast.ln.delete()
if not na(pl)
dir := aZZ.d.get(0), x1 := aZZ.x.get(0), y1 := aZZ.y.get(0), y2 := nz(lo[1])
if dir > -1
aZZ.in_out(-1, x2, y2)
else
if dir == -1 and pl < y1
aZZ.x.set(0, x2), aZZ.y.set(0, y2)
if showLq and per and sz > 0
count = 0, st_P = 0., st_B = 0, minP = 0., maxP = 10e6
for i = 0 to math.min(sz, 50) - 1
if aZZ.d.get(i) == -1
if aZZ.y.get(i) < pl - (atr/a)
break
else
if aZZ.y.get(i) > pl - (atr/a) and aZZ.y.get(i) < pl + (atr/a)
count += 1, st_B := aZZ.x.get(i), st_P := aZZ.y.get(i)
if aZZ.y.get(i) > minP
minP := aZZ.y.get(i)
if aZZ.y.get(i) < maxP
maxP := aZZ.y.get(i)
if count > 2
getB = b_liq_S.get(0)
if st_B == getB.bx.get_left()
getB.bx.set_top(math.avg(minP, maxP) + (atr/a))
getB.bx.set_rightbottom(n + 10, math.avg(minP, maxP) - (atr/a))
else
b_liq_S.unshift(liq.new(box.new(st_B, math.avg(minP, maxP) + (atr/a), n + 10, math.avg(minP, maxP) - (atr/a), text='Sellside liquidity', text_size=size.tiny, text_halign=text.align_left, text_valign=text.align_bottom, text_color=color.new(cLIQ_S, 25), bgcolor=color(na), border_color=color(na)), false, false, false, line.new(st_B, st_P, n - 1, st_P, color=color.new(cLIQ_S, 0))))
if b_liq_S.size() > visLiq
getLast = b_liq_S.pop()
getLast.bx.delete()
getLast.ln.delete()
// FIX #2 : MSS appelé UNE SEULE FOIS au lieu d'être dupliqué
detect_mss()
draw(len, color.yellow)
if MSS.l_bosBl.size() > 200
MSS.l_bosBl.pop().delete()
MSS.lbBosBl.pop().delete()
if MSS.l_bosBr.size() > 200
MSS.l_bosBr.pop().delete()
MSS.lbBosBr.pop().delete()
ny = (not na(time(timeframe.period, input.session('0700-0900', '', inline='ny', group='Killzones'), 'America/New_York'))) and showNy
ldn_open = (not na(time(timeframe.period, input.session('0700-1000', '', inline='lo', group='Killzones'), 'Europe/London'))) and showLdno
ldn_close = (not na(time(timeframe.period, input.session('1500-1700', '', inline='lc', group='Killzones'), 'Europe/London'))) and showLdnc
asian = (not na(time(timeframe.period, input.session('1000-1400', '', inline='as', group='Killzones'), 'Asia/Tokyo'))) and showAsia
ph2 = ta.pivothigh(3, 1), lPh = fixnan(ph2)
pl2 = ta.pivotlow (3, 1), lPl = fixnan(pl2)
L_body = high - mx < body * perc_Body and mn - low < body * perc_Body
L_bodyUP = body > meanBody and L_body and close > open
L_bodyDN = body > meanBody and L_body and close < open
bsNOTbodyUP = ta.barssince(not L_bodyUP)
bsNOTbodyDN = ta.barssince(not L_bodyDN)
lwst = math.min(lPh[bsNOTbodyUP[1]], low[bsNOTbodyUP[1]])
hgst = math.max(high[bsNOTbodyDN[1]], lPl[bsNOTbodyDN[1]])
imbalanceUP = L_bodyUP[1] and (i_FVG == 'FVG' ? low > high[2] : low < high[2])
imbalanceDN = L_bodyDN[1] and (i_FVG == 'FVG' ? high < low[2] : high > low[2])
vImb_Bl = open > close[1] and high[1] > low and close > close[1] and open > open[1] and high[1] < mn
vImb_Br = open < close[1] and low[1] < high and close < close[1] and open < open[1] and low[1] > mx
if sVimbl
if vImb_Bl
Vimbal.unshift(_2ln_lb.new(line.new(n-1, mx[1], n+3, mx[1], color=cVimbl), line.new(n, mn, n+3, mn, color=cVimbl), label.new(n+3, math.avg(mx[1], mn), text='VI', color=color(na), textcolor=cVimbl, style=label.style_label_left)))
if vImb_Br
Vimbal.unshift(_2ln_lb.new(line.new(n-1, mn[1], n+3, mn[1], color=cVimbl), line.new(n, mx, n+3, mx, color=cVimbl), label.new(n+3, math.avg(mn[1], mx), text='VI', color=color(na), textcolor=cVimbl, style=label.style_label_left)))
if Vimbal.size() > visVim
pop = Vimbal.pop()
pop.l1.delete()
pop.l2.delete()
pop.lb.delete()
if barstate.isfirst
for i = 0 to visBxs - 1
bFVG_UP.unshift(FVG.new(box(na), false))
bFVG_DN.unshift(FVG.new(box(na), false))
if i_BPR
bBPR_UP.unshift(FVG.new(box(na), false))
bBPR_DN.unshift(FVG.new(box(na), false))
if imbalanceUP and per and shwFVG
if imbalanceUP[1]
bFVG_UP.get(0).box.set_lefttop(n-2, low)
bFVG_UP.get(0).box.set_rightbottom(n+8, high[2])
else
bFVG_UP.unshift(FVG.new(box.new(n-2, i_FVG=='FVG'?low:high[2], n, i_FVG=='FVG'?high[2]:low, bgcolor=i_BPR?color(na):color.new(cFVGbl,90), border_color=i_BPR?color(na):color.new(cFVGbl,65), text_color=i_BPR?color(na):color.new(cFVGbl,65), text_size=size.small, text=i_FVG), true, n))
bFVG_UP.pop().box.delete()
if imbalanceDN and per and shwFVG
if imbalanceDN[1]
bFVG_DN.get(0).box.set_lefttop(n-2, low[2])
bFVG_DN.get(0).box.set_rightbottom(n+8, high)
else
bFVG_DN.unshift(FVG.new(box.new(n-2, i_FVG=='FVG'?low[2]:high, n, i_FVG=='FVG'?high:low[2], bgcolor=i_BPR?color(na):color.new(cFVGbr,90), border_color=i_BPR?color(na):color.new(cFVGbr,65), text_color=i_BPR?color(na):color.new(cFVGbr,65), text_size=size.small, text=i_FVG), true, n))
bFVG_DN.pop().box.delete()
for i = 0 to math.min(bxBack, bFVG_UP.size()-1)
getUPi = bFVG_UP.get(i)
if getUPi.active
getUPi.box.set_right(bar_index+8)
if low < getUPi.box.get_top() and not i_BPR
getUPi.box.set_border_style(line.style_dashed)
if low < getUPi.box.get_bottom()
if not i_BPR
getUPi.box.set_bgcolor(color.new(cFVGblBR,95))
getUPi.box.set_border_style(line.style_dotted)
getUPi.box.set_right(bar_index)
getUPi.active := false
for i = 0 to math.min(bxBack, bFVG_DN.size()-1)
getDNi = bFVG_DN.get(i)
if getDNi.active
getDNi.box.set_right(bar_index+8)
if high > getDNi.box.get_bottom() and not i_BPR
getDNi.box.set_border_style(line.style_dashed)
if high > getDNi.box.get_top()
if not i_BPR
getDNi.box.set_bgcolor(color.new(cFVGbrBR,95))
getDNi.box.set_border_style(line.style_dotted)
getDNi.box.set_right(bar_index)
getDNi.active := false
if barstate.isfirst
for i = 0 to maxNWOG - 1
bl_NWOG.unshift(bx_ln.new(box(na), line(na)))
for i = 0 to maxNDOG - 1
bl_NDOG.unshift(bx_ln.new(box(na), line(na)))
if dayofweek == dayofweek.friday
friCp := close, friCi := n
newDay = ta.change(time("D")) != 0
if newDay
if dayofweek == dayofweek.monday and iNWOG
monOp := open, monOi := n
bl_NWOG.unshift(bx_ln.new(box.new(friCi, math.max(friCp,monOp), monOi, math.min(friCp,monOp), bgcolor=color(na), border_color=cNWOG2, extend=extend.right), line.new(monOi, math.avg(friCp,monOp), monOi+1, math.avg(friCp,monOp), color=cNWOG1, style=line.style_dotted, extend=extend.right)))
bl = bl_NWOG.pop()
bl.b.delete()
bl.l.delete()
if iNDOG
cuDOp := open, cuDOi := n, prDCp := close[1], prDCi := n-1
bl_NDOG.unshift(bx_ln.new(box.new(prDCi, math.max(prDCp,cuDOp), cuDOi, math.min(prDCp,cuDOp), bgcolor=color(na), border_color=cNDOG2, extend=extend.right), line.new(cuDOi, math.avg(prDCp,cuDOp), cuDOi+1, math.avg(prDCp,cuDOp), color=cNDOG1, style=line.style_dotted, extend=extend.right)))
bl = bl_NDOG.pop()
bl.b.delete()
bl.l.delete()
for i = 0 to b_liq_B.size()-1
x = b_liq_B.get(i)
if not x.broken
x.bx.set_right(n+3), x.ln.set_x2(n+3)
if not x.brokenTop
if close > x.bx.get_top()
x.brokenTop := true
if not x.brokenBtm
if close > x.bx.get_bottom()
x.brokenBtm := true
if x.brokenBtm
x.bx.set_bgcolor(color.new(cLIQ_B,90)), x.ln.delete()
if x.brokenTop
x.broken := true, x.bx.set_right(n)
for i = 0 to b_liq_S.size()-1
x = b_liq_S.get(i)
if not x.broken
x.bx.set_right(n+3), x.ln.set_x2(n+3)
if not x.brokenTop
if close < x.bx.get_top()
x.brokenTop := true
if not x.brokenBtm
if close < x.bx.get_bottom()
x.brokenBtm := true
if x.brokenTop
x.bx.set_bgcolor(color.new(cLIQ_S,90)), x.ln.delete()
if x.brokenBtm
x.broken := true, x.bx.set_right(n)
[top, btm] = swings(ob_length)
if showOB and per
if close > top.y and not top.crossed
top.crossed := true
minima = max[1], maxima = min[1], loc = time[1]
for i = 1 to (n - top.x)-1
minima := math.min(min[i], minima)
maxima := minima == min[i] ? max[i] : maxima
loc := minima == min[i] ? time[i] : loc
bullish_ob.unshift(ob.new(maxima, minima, loc))
if bullish_ob.size() > 0
for i = bullish_ob.size()-1 to 0
element = bullish_ob.get(i)
if not element.breaker
if math.min(close, open) < element.btm
element.breaker := true, element.break_loc := time
else
if close > element.top
bullish_ob.remove(i)
else if i < showBull and top.y < element.top and top.y > element.btm
blBrkConf := 1
if blBrkConf > blBrkConf[1] and showLabels
label.new(top.x, top.y, '▼', color=na, textcolor=bearCss.notransp(), style=label.style_label_down, size=size.tiny)
if showOB and per
if close < btm.y and not btm.crossed
btm.crossed := true
minima = min[1], maxima = max[1], loc = time[1]
for i = 1 to (n - btm.x)-1
maxima := math.max(max[i], maxima)
minima := maxima == max[i] ? min[i] : minima
loc := maxima == max[i] ? time[i] : loc
bearish_ob.unshift(ob.new(maxima, minima, loc))
if bearish_ob.size() > 0
for i = bearish_ob.size()-1 to 0
element = bearish_ob.get(i)
if not element.breaker
if math.max(close, open) > element.top
element.breaker := true, element.break_loc := time
else
if close < element.btm
bearish_ob.remove(i)
else if i < showBear and btm.y > element.btm and btm.y < element.top
brBrkConf := 1
if brBrkConf > brBrkConf[1] and showLabels
label.new(btm.x, btm.y, '▲', color=na, textcolor=bullCss.notransp(), style=label.style_label_up, size=size.tiny)
if barstate.islast and showOB
if a_bx_ln_lb.size() > 0
for i = a_bx_ln_lb.size()-1 to 0
item = a_bx_ln_lb.remove(i)
item.bx.delete()
item.ln.delete()
item.lb.delete()
if showBull > 0 and bullish_ob.size() > 0
for i = 0 to math.min(showBull, bullish_ob.size())-1
bullish_ob.get(i).display(bullCss, bullBrkCss, 'bl')
if showBear > 0 and bearish_ob.size() > 0
for i = 0 to math.min(showBear, bearish_ob.size())-1
bearish_ob.get(i).display(bearCss, bearBrkCss, 'br')
if barstate.islast
x1 = 0, y1 = 0., x2 = 0, y2 = 0., box up = na, box dn = na
switch iFib
'FVG' =>
if bFVG_UP.size() > 0 and bFVG_DN.size() > 0
up := bFVG_UP.get(0).box, dn := bFVG_DN.get(0).box
dnFirst = up.get_left() > dn.get_left()
dnBottm = up.get_top() > dn.get_top()
x1 := dnFirst ? dn.get_left() : up.get_left()
x2 := dnFirst ? up.get_right() : dn.get_right()
y1 := dnFirst ? dnBottm ? dn.get_bottom() : dn.get_top() : dnBottm ? up.get_top() : up.get_bottom()
y2 := dnFirst ? dnBottm ? up.get_top() : up.get_bottom() : dnBottm ? dn.get_bottom() : dn.get_top()
'OB' =>
oSz = a_bx_ln_lb.size()
if oSz > 1
xA = nz(a_bx_ln_lb.get(oSz-1).ln.get_x1(), a_bx_ln_lb.get(oSz-1).bx.get_left())
xB = nz(a_bx_ln_lb.get(oSz-2).ln.get_x1(), a_bx_ln_lb.get(oSz-2).bx.get_left())
AFirst = xB > xA
yAT = nz(a_bx_ln_lb.get(oSz-1).ln.get_y1(), a_bx_ln_lb.get(oSz-1).bx.get_top())
yAB = nz(a_bx_ln_lb.get(oSz-1).ln.get_y1(), a_bx_ln_lb.get(oSz-1).bx.get_bottom())
yBT = nz(a_bx_ln_lb.get(oSz-2).ln.get_y1(), a_bx_ln_lb.get(oSz-2).bx.get_top())
yBB = nz(a_bx_ln_lb.get(oSz-2).ln.get_y1(), a_bx_ln_lb.get(oSz-2).bx.get_bottom())
ABottom = yAB < yBB
x1 := AFirst ? xA : xB
x2 := AFirst ? xB : xA
y1 := AFirst ? ABottom ? yAB : yAT : ABottom ? yBT : yBB
y2 := AFirst ? ABottom ? yBT : yBB : ABottom ? yAB : yAT
if iFib != 'NONE'
rt = math.max(x1,x2), _0 = rt==x1?y1:y2, _1 = rt==x1?y2:y1
df = _1 - _0
_diag.setLine(x1,y1,x2,y2)
_zero.setLine(rt,_0,rt+plus,_0)
_0236.setLine(rt,_0+df*0.236,rt+plus,_0+df*0.236)
_0382.setLine(rt,_0+df*0.382,rt+plus,_0+df*0.382)
_0500.setLine(rt,_0+df*0.500,rt+plus,_0+df*0.500)
_0618.setLine(rt,_0+df*0.618,rt+plus,_0+df*0.618)
_0786.setLine(rt,_0+df*0.786,rt+plus,_0+df*0.786)
_one_.setLine(rt,_1,rt+plus,_1)
_1618.setLine(rt,_0+df*1.618,rt+plus,_0+df*1.618)
plotshape(sDispl?per?L_bodyUP?low:na:na:na, title='Displacement UP', style=shape.labelup, color=color.lime, location=location.belowbar)
plotshape(sDispl?per?L_bodyDN?high:na:na:na, title='Displacement DN', style=shape.labeldown, color=color.red, location=location.abovebar)
bgcolor(per?ny?nyCss:na:na, editable=false)
bgcolor(per?ldn_open?ldnoCss:na:na, editable=false)
bgcolor(per?ldn_close?ldncCss:na:na,editable=false)
bgcolor(per?asian?asiaCss:na:na, editable=false)
//-----------------------------------------------------------------------------}
// TRINITY — Active OB selection + OTE live logic
//-----------------------------------------------------------------------------{
inRange(_v, _a, _b) => _v >= math.min(_a,_b) and _v <= math.max(_a,_b)
// _min_bar : seuls les FVGs créés APRÈS la détection de l'OB sont pris en compte
fvgInOTE(_arr, _lo, _hi, _min_bar) =>
result = false
if _arr.size() > 0
for i = 0 to _arr.size()-1
f = _arr.get(i)
if f.active and f.pos >= _min_bar
if f.box.get_bottom() <= _hi and f.box.get_top() >= _lo
result := true
break
result
bool mssFlippedBull = MSS.dir == 1 and prevMSSdir != 1
bool mssFlippedBear = MSS.dir == -1 and prevMSSdir != -1
if mssFlippedBull
ote_sel_lo := na
ote_sel_hi := na
ts_obLoc := na
ts_obBtm := na
ts_obTop := na
ts_swingLo := na
ts_mssOk := false
if not na(ts_oteBox)
ts_oteBox.delete()
ts_oteBox := na
if mssFlippedBear
ote_buy_lo := na
ote_buy_hi := na
tl_obLoc := na
tl_obBtm := na
tl_obTop := na
tl_swingHi := na
tl_mssOk := false
if not na(tl_oteBox)
tl_oteBox.delete()
tl_oteBox := na
prevMSSdir := MSS.dir
float activeBullOB_btm = na
float activeBullOB_top = na
int activeBullOB_loc = na
if MSS.dir == 1 and bullish_ob.size() > 0
for i = 0 to bullish_ob.size()-1
ob_item = bullish_ob.get(i)
if not ob_item.breaker
activeBullOB_btm := ob_item.btm
activeBullOB_top := ob_item.top
activeBullOB_loc := ob_item.loc
break
float activeBearOB_btm = na
float activeBearOB_top = na
int activeBearOB_loc = na
if MSS.dir == -1 and bearish_ob.size() > 0
for i = 0 to bearish_ob.size()-1
ob_item = bearish_ob.get(i)
if not ob_item.breaker
activeBearOB_btm := ob_item.btm
activeBearOB_top := ob_item.top
activeBearOB_loc := ob_item.loc
break
if not na(activeBullOB_loc) and (na(tl_obLoc) or activeBullOB_loc != tl_obLoc)
tl_obLoc := activeBullOB_loc
tl_obBtm := activeBullOB_btm
tl_obTop := activeBullOB_top
tl_swingHi := high
tl_mssOk := true
tl_ob_bar := bar_index
ote_buy_lo := na
ote_buy_hi := na
if not na(tl_oteBox)
tl_oteBox.delete()
tl_oteBox := na
if na(activeBullOB_loc) and not na(tl_obLoc)
tl_obLoc := na
tl_obBtm := na
tl_obTop := na
tl_swingHi := na
tl_mssOk := false
ote_buy_lo := na
ote_buy_hi := na
if not na(tl_oteBox)
tl_oteBox.delete()
tl_oteBox := na
if not na(activeBearOB_loc) and (na(ts_obLoc) or activeBearOB_loc != ts_obLoc)
ts_obLoc := activeBearOB_loc
ts_obBtm := activeBearOB_btm
ts_obTop := activeBearOB_top
ts_swingLo := low
ts_mssOk := true
ts_ob_bar := bar_index
ote_sel_lo := na
ote_sel_hi := na
if not na(ts_oteBox)
ts_oteBox.delete()
ts_oteBox := na
if na(activeBearOB_loc) and not na(ts_obLoc)
ts_obLoc := na
ts_obBtm := na
ts_obTop := na
ts_swingLo := na
ts_mssOk := false
ote_sel_lo := na
ote_sel_hi := na
if not na(ts_oteBox)
ts_oteBox.delete()
ts_oteBox := na
if not na(tl_obLoc)
tl_swingHi := na(tl_swingHi) ? high : math.max(tl_swingHi, high)
if not na(ts_obLoc)
ts_swingLo := na(ts_swingLo) ? low : math.min(ts_swingLo, low)
if not na(tl_obBtm) and not na(tl_swingHi) and tl_swingHi > tl_obBtm
_rng = tl_swingHi - tl_obBtm
ote_buy_lo := tl_swingHi - _rng * ote_fib2
ote_buy_hi := tl_swingHi - _rng * ote_fib1
if not na(ts_obTop) and not na(ts_swingLo) and ts_swingLo < ts_obTop
_rng = ts_obTop - ts_swingLo
ote_sel_lo := ts_swingLo + _rng * ote_fib1
ote_sel_hi := ts_swingLo + _rng * ote_fib2
//-----------------------------------------------------------------------------}
// OTE BOX DISPLAY
//-----------------------------------------------------------------------------{
if not na(ote_buy_lo) and not na(ote_buy_hi) and per and MSS.dir == 1
_left = na(tl_obLoc) ? time : tl_obLoc
_right = timenow + tf_msec * 20
if na(tl_oteBox)
tl_oteBox := box.new(_left, ote_buy_hi, _right, ote_buy_lo, bgcolor=cOTEbull, border_color=color.new(#00e676,40), text='OTE', text_size=size.tiny, xloc=xloc.bar_time)
else
tl_oteBox.set_left(_left)
tl_oteBox.set_top(ote_buy_hi)
tl_oteBox.set_bottom(ote_buy_lo)
tl_oteBox.set_right(_right)
else if not na(tl_oteBox)
tl_oteBox.delete()
tl_oteBox := na
if not na(ote_sel_lo) and not na(ote_sel_hi) and per and MSS.dir == -1
_left = na(ts_obLoc) ? time : ts_obLoc
_right = timenow + tf_msec * 20
if na(ts_oteBox)
ts_oteBox := box.new(_left, ote_sel_hi, _right, ote_sel_lo, bgcolor=cOTEbear, border_color=color.new(#ff5252,40), text='OTE', text_size=size.tiny, xloc=xloc.bar_time)
else
ts_oteBox.set_left(_left)
ts_oteBox.set_top(ote_sel_hi)
ts_oteBox.set_bottom(ote_sel_lo)
ts_oteBox.set_right(_right)
else if not na(ts_oteBox)
ts_oteBox.delete()
ts_oteBox := na
//-----------------------------------------------------------------------------}
// TRINITY SIGNAL
//-----------------------------------------------------------------------------{
var bool tl_fired = false
var bool ts_fired = false
var int tl_signal_ob = na // OB qui a déclenché le dernier TL
var int ts_signal_ob = na // OB qui a déclenché le dernier TS
var label tl_lbl = na // label unique TL (1 seul sur le chart)
var label ts_lbl = na // label unique TS (1 seul sur le chart)
// Reset sur flip MSS + effacement du label de l'autre côté
if mssFlippedBear
tl_fired := false
tl_signal_ob := na
if not na(ts_lbl)
ts_lbl.delete()
ts_lbl := na
if mssFlippedBull
ts_fired := false
ts_signal_ob := na
if not na(tl_lbl)
tl_lbl.delete()
tl_lbl := na
// Reset si l'OB actif a changé depuis le dernier signal (nouveau setup)
if tl_fired and not na(tl_signal_ob) and tl_obLoc != tl_signal_ob
tl_fired := false
if ts_fired and not na(ts_signal_ob) and ts_obLoc != ts_signal_ob
ts_fired := false
// Signal : OB détecté + MSS aligné + FVG dans la zone OTE calculée
// Le prix N'A PAS besoin d'entrer dans l'OTE
fvgInOTE_buy = not na(ote_buy_lo) and fvgInOTE(bFVG_UP, ote_buy_lo, ote_buy_hi, tl_ob_bar)
fvgInOTE_sell = not na(ote_sel_lo) and fvgInOTE(bFVG_DN, ote_sel_lo, ote_sel_hi, ts_ob_bar)
bool tri_long_raw = tl_mssOk and not na(tl_obLoc) and fvgInOTE_buy and not tl_fired
bool tri_short_raw = ts_mssOk and not na(ts_obLoc) and fvgInOTE_sell and not ts_fired
bool tri_long = tri_close ? (tri_long_raw and barstate.isconfirmed) : tri_long_raw
bool tri_short = tri_close ? (tri_short_raw and barstate.isconfirmed) : tri_short_raw
if tri_long
tl_fired := true
tl_signal_ob := tl_obLoc
if not na(tl_lbl)
tl_lbl.delete()
tl_lbl := label.new(tl_obLoc, tl_obBtm, 'TL', xloc=xloc.bar_time, style=label.style_label_up, color=color.new(color.lime,0), textcolor=color.white, size=size.small)
alert('TRINITY LONG SETUP | ' + syminfo.ticker + ' | ' + timeframe.period + 'min | OB+MSS+FVG alignés | Prix: ' + str.tostring(close), alert.freq_once_per_bar)
if tri_short
ts_fired := true
ts_signal_ob := ts_obLoc
if not na(ts_lbl)
ts_lbl.delete()
ts_lbl := label.new(ts_obLoc, ts_obTop, 'TS', xloc=xloc.bar_time, style=label.style_label_down, color=color.new(color.red,0), textcolor=color.white, size=size.small)
alert('TRINITY SHORT SETUP | ' + syminfo.ticker + ' | ' + timeframe.period + 'min | OB+MSS+FVG alignés | Prix: ' + str.tostring(close), alert.freq_once_per_bar)
alertcondition(tri_long or tri_short, 'TRINITY Signal', message='TRINITY SIGNAL')
Show all 786 lines