//@version=6
indicator("RM'S JADU TONA", overlay=true, max_lines_count=500, max_labels_count=500, max_boxes_count=500)
// ==================================================================
// INPUTS
// ==================================================================
grpMain = "Main"
inpStartTime = input.time(timestamp("2026-01-01T00:00:00"), "Start Time", group=grpMain)
inpMaxBars = input.int(12000, "Max Bars", minval=20, group=grpMain)
grpDisp = "Structure Display"
inpShowSwings = input.bool(true, "Show Swings", group=grpDisp)
inpShowBOS = input.bool(true, "Show BOS", group=grpDisp)
inpShowCHOCH = input.bool(true, "Show CHOCH", group=grpDisp)
inpShowLevels = input.bool(true, "Show Levels", group=grpDisp)
inpShowTJL = input.bool(true, "Show TJL", group=grpDisp)
inpShowISS = input.bool(true, "Show ISS", group=grpDisp)
inpKeepOnlyLastCHOCH = input.bool(false, "Keep Only Last CHOCH", group=grpDisp)
grpIndiv = "Individual Level Visibility"
inpShowTJL1 = input.bool(true, "Show TJL 1", group=grpIndiv)
inpShowTJL2 = input.bool(true, "Show TJL 2", group=grpIndiv)
inpShowQML = input.bool(true, "Show QML", group=grpIndiv)
inpShowSBR = input.bool(true, "Show SBR", group=grpIndiv)
inpShowRBS = input.bool(true, "Show RBS", group=grpIndiv)
inpShowDB = input.bool(true, "Show DB", group=grpIndiv)
inpShowDT = input.bool(true, "Show DT", group=grpIndiv)
inpShowBestQML = input.bool(true, "Show Best Levels", group=grpIndiv)
inpShowISS1 = input.bool(false, "Show ISS 1", group=grpIndiv)
inpShowISS3 = input.bool(true, "Show ISS 3", group=grpIndiv)
inpShowISS4 = input.bool(true, "Show ISS 4", group=grpIndiv)
grpISS = "ISS Controls"
inpEnableISS = input.bool(true, "Enable ISS Logic", group=grpISS)
inpShowISSLabel = input.bool(true, "Show ISS Label", group=grpISS)
inpShowISSBOS = input.bool(true, "Show ISS BOS", group=grpISS)
inpStopISS34ByWickTap = input.bool(true, "Stop ISS 3/4 on Wick Tap", group=grpISS)
grpCol = "Level Colors"
inpCHColor = input.color(color.white, "CH Color", group=grpCol)
inpCLColor = input.color(color.orange, "CL Color", group=grpCol)
inpBullBOSColor = input.color(color.green, "Bull BOS Color", group=grpCol)
inpBearBOSColor = input.color(color.red, "Bear BOS Color", group=grpCol)
inpBullTJLColor = input.color(color.green, "Bull TJL Color", group=grpCol)
inpBearTJLColor = input.color(color.orange, "Bear TJL Color", group=grpCol)
inpSBRColor = input.color(color.red, "SBR Color", group=grpCol)
inpRBSColor = input.color(color.green, "RBS Color", group=grpCol)
inpQMLColor = input.color(color.rgb(186, 85, 211), "QML Color", group=grpCol)
inpDTDBColor = input.color(color.blue, "DT/DB Color", group=grpCol)
inpISSColor = input.color(color.yellow, "ISS Color", group=grpCol)
inpBestQMLColor = input.color(color.rgb(255, 215, 0), "Best QML Color", group=grpCol)
grpSt = "Style"
inpLineWidth = input.int(2, "Line Width", minval=1, group=grpSt)
inpMaxLiveLevels = input.int(140, "Max Live Levels", minval=1, group=grpSt)
inpMaxLabels = input.int(180, "Max Labels", minval=1, group=grpSt)
inpMaxLines = input.int(180, "Max Lines", minval=1, group=grpSt)
inpZoneBodyPct = input.float(1.0, "Zone Body %", minval=0.0, maxval=100.0, step=0.1, group=grpSt)
tapByWick = "TapByWick"
tapByClose = "TapByClose"
inpStopOnTap = input.bool(true, "Stop On Tap", group=grpSt)
inpTapSource = input.string(tapByWick, "Tap Source", options=[tapByWick, tapByClose], group=grpSt)
inpLevelTextVPos = input.string("Inside", "Level Text Vertical", options=["Top", "Inside", "Bottom"], group=grpSt)
inpLevelTextHPos = input.string("Right", "Level Text Horizontal", options=["Left", "Center", "Right"], group=grpSt)
grpSMC = "Smart Money Concepts (SMC)"
inpShowFVG = input.bool(false, "Show FVG (Fair Value Gap / IPDA)", group=grpSMC)
inpFVGDeleteOnTap = input.bool(true, "Delete FVG on Tap", group=grpSMC)
inpMaxFVG = input.int(30, "Max FVG Levels", minval=1, maxval=50, group=grpSMC)
inpShowOB = input.bool(false, "Show Order Blocks (Opposite Candle Before Move)",group=grpSMC)
inpOBDeleteOnTap = input.bool(true, "Delete OB on Tap", group=grpSMC)
inpMaxOB = input.int(20, "Max Order Block Levels", minval=1, maxval=30, group=grpSMC)
inpShowKZ = input.bool(false, "Show Kill Zones (IST)", group=grpSMC)
inpBullFVGColor = input.color(color.new(color.teal, 70), "Bull FVG Color", group=grpSMC)
inpBearFVGColor = input.color(color.new(color.maroon, 70), "Bear FVG Color", group=grpSMC)
inpBullOBColor = input.color(color.new(color.lime, 75), "Demand OB Color", group=grpSMC)
inpBearOBColor = input.color(color.new(color.red, 75), "Supply OB Color", group=grpSMC)
inpLondonColor = input.color(color.new(color.blue, 92), "London KZ Color", group=grpSMC)
inpNYColor = input.color(color.new(color.purple, 92), "NY KZ Color", group=grpSMC)
grpDash = "Trend Dashboard"
inpShowTrendDash = input.bool(false, "Show MTF Trend Dashboard", group=grpDash)
inpDashShowTf1 = input.bool(true, "Show Timeframe 1", group=grpDash)
inpDashTf1 = input.timeframe("1", "Timeframe 1", group=grpDash)
inpDashShowTf2 = input.bool(true, "Show Timeframe 2", group=grpDash)
inpDashTf2 = input.timeframe("3", "Timeframe 2", group=grpDash)
inpDashShowTf3 = input.bool(true, "Show Timeframe 3", group=grpDash)
inpDashTf3 = input.timeframe("5", "Timeframe 3", group=grpDash)
inpDashShowTf4 = input.bool(true, "Show Timeframe 4", group=grpDash)
inpDashTf4 = input.timeframe("15", "Timeframe 4", group=grpDash)
inpDashShowTf5 = input.bool(true, "Show Timeframe 5", group=grpDash)
inpDashTf5 = input.timeframe("30", "Timeframe 5", group=grpDash)
inpDashShowTf6 = input.bool(true, "Show Timeframe 6", group=grpDash)
inpDashTf6 = input.timeframe("45", "Timeframe 6", group=grpDash)
inpDashShowTf7 = input.bool(true, "Show Timeframe 7", group=grpDash)
inpDashTf7 = input.timeframe("60", "Timeframe 7", group=grpDash)
inpDashShowTf8 = input.bool(true, "Show Timeframe 8", group=grpDash)
inpDashTf8 = input.timeframe("120", "Timeframe 8", group=grpDash)
inpDashShowTf9 = input.bool(true, "Show Timeframe 9", group=grpDash)
inpDashTf9 = input.timeframe("180", "Timeframe 9", group=grpDash)
inpDashShowTf10 = input.bool(true, "Show Timeframe 10", group=grpDash)
inpDashTf10 = input.timeframe("240", "Timeframe 10", group=grpDash)
inpDashShowTf11 = input.bool(true, "Show Timeframe 11", group=grpDash)
inpDashTf11 = input.timeframe("D", "Timeframe 11", group=grpDash)
inpDashShowTf12 = input.bool(true, "Show Timeframe 12", group=grpDash)
inpDashTf12 = input.timeframe("W", "Timeframe 12", group=grpDash)
inpDashShowTf13 = input.bool(true, "Show Timeframe 13", group=grpDash)
inpDashTf13 = input.timeframe("M", "Timeframe 13", group=grpDash)
grpAnalyzer = "Level Analyzer"
inpShowLevelAnalyzer = input.bool(false, "Show Level Accuracy Analyzer", group=grpAnalyzer)
inpAnalyzerTargetPips = input.float(100.0, "Win Target (Pips)", minval=0.1, step=0.1, group=grpAnalyzer)
inpAnalyzerLossPips = input.float(50.0, "Loss Target (Pips)", minval=0.1, step=0.1, group=grpAnalyzer)
inpAnalyzerPipMode = input.string("Auto", "Pip Size Mode", options=["Auto", "Custom"], group=grpAnalyzer)
inpAnalyzerCustomPipSize = input.float(0.0001, "Custom Pip Size", minval=0.00000001, step=0.00000001, group=grpAnalyzer)
inpAnalyzerMinDone = input.int(3, "Min Finished Tests To Rank", minval=1, group=grpAnalyzer)
inpAnalyzerShowBuyTJL1 = input.bool(true, "Table: BUY TJL1", group=grpAnalyzer)
inpAnalyzerShowBuyTJL2 = input.bool(true, "Table: BUY TJL2", group=grpAnalyzer)
inpAnalyzerShowSellTJL1 = input.bool(true, "Table: SELL TJL1", group=grpAnalyzer)
inpAnalyzerShowSellTJL2 = input.bool(true, "Table: SELL TJL2", group=grpAnalyzer)
inpAnalyzerShowSBR = input.bool(true, "Table: SBR", group=grpAnalyzer)
inpAnalyzerShowRBS = input.bool(true, "Table: RBS", group=grpAnalyzer)
inpAnalyzerShowDT = input.bool(true, "Table: DT", group=grpAnalyzer)
inpAnalyzerShowDB = input.bool(true, "Table: DB", group=grpAnalyzer)
inpAnalyzerShowBuyQML = input.bool(true, "Table: BUY QML", group=grpAnalyzer)
inpAnalyzerShowSellQML = input.bool(true, "Table: SELL QML", group=grpAnalyzer)
inpAnalyzerShowISS4 = input.bool(true, "Table: ISS 4", group=grpAnalyzer)
inpAnalyzerShowBestSBR = input.bool(true, "Table: BEST SBR", group=grpAnalyzer)
inpAnalyzerShowBestRBS = input.bool(true, "Table: BEST RBS", group=grpAnalyzer)
inpAnalyzerShowBestDT = input.bool(true, "Table: BEST DT", group=grpAnalyzer)
inpAnalyzerShowBestDB = input.bool(true, "Table: BEST DB", group=grpAnalyzer)
inpAnalyzerShowBestBuyQML = input.bool(true, "Table: BEST BUY QML", group=grpAnalyzer)
inpAnalyzerShowBestSellQML = input.bool(true, "Table: BEST SELL QML", group=grpAnalyzer)
// ==================================================================
// EMA (Merged from Code 2)
// ==================================================================
grpEMA = "EMA"
emaLen = input.int(132, minval=1, title="EMA Length", group=grpEMA)
emaSrc = input.source(close, title="EMA Source", group=grpEMA)
emaOffset = input.int(title="EMA Offset", defval=0, minval=-500, maxval=500, group=grpEMA)
emaColor = input.color(color.blue, "EMA Color", group=grpEMA)
emaOut = ta.ema(emaSrc, emaLen)
plot(emaOut, title="EMA", color=emaColor, offset=emaOffset)
// Smoothing MA inputs
emaSmoothGrp = "EMA Smoothing"
emaTTBB = "Only applies when 'SMA + Bollinger Bands' is selected. Determines the distance between the SMA and the bands."
emaMaTypeInput = input.string("None", "Type", options=["None", "SMA", "SMA + Bollinger Bands", "EMA", "SMMA (RMA)", "WMA", "VWMA"], group=emaSmoothGrp)
emaIsBB = emaMaTypeInput == "SMA + Bollinger Bands"
emaMaLengthInput = input.int(14, "Length", group=emaSmoothGrp, active=emaMaTypeInput != "None")
emaBbMultInput = input.float(2.0, "BB StdDev", minval=0.001, maxval=50, step=0.5, tooltip=emaTTBB, group=emaSmoothGrp, active=emaIsBB)
emaEnableMA = emaMaTypeInput != "None"
// Smoothing MA Calculation
f_emaMa(source, length, maType) =>
switch maType
"SMA" => ta.sma(source, length)
"SMA + Bollinger Bands" => ta.sma(source, length)
"EMA" => ta.ema(source, length)
"SMMA (RMA)" => ta.rma(source, length)
"WMA" => ta.wma(source, length)
"VWMA" => ta.vwma(source, length)
emaSmoothingMA = emaEnableMA ? f_emaMa(emaOut, emaMaLengthInput, emaMaTypeInput) : na
emaSmoothingStDev = emaIsBB ? ta.stdev(emaOut, emaMaLengthInput) * emaBbMultInput : na
plot(emaSmoothingMA, "EMA-based MA", color=color.yellow, display=emaEnableMA ? display.all : display.none, editable=emaEnableMA)
emaBbUpperBand = plot(emaSmoothingMA + emaSmoothingStDev, title="Upper Bollinger Band", color=color.green, display=emaIsBB ? display.all : display.none, editable=emaIsBB)
emaBbLowerBand = plot(emaSmoothingMA - emaSmoothingStDev, title="Lower Bollinger Band", color=color.green, display=emaIsBB ? display.all : display.none, editable=emaIsBB)
fill(emaBbUpperBand, emaBbLowerBand, color=emaIsBB ? color.new(color.green, 90) : na, title="Bollinger Bands Background Fill", display=emaIsBB ? display.all : display.none, editable=emaIsBB)
// ==================================================================
// TYPES
// ==================================================================
type Snap
int t
int bar
float o
float c
float h
float l
float lvl
type Level
int left
int right
float top
float bot
color col
string txt
int kind
int dir
bool active
bool deleted
bool stopReady
int stopReadyBar
int bornBar
box bx
label lb
bool anaStarted
bool anaActive
int anaStartBar
type FVGLevel
int left
int right
float top
float bot
bool bull
bool active
bool deleted
box bx
type OBLevel
int left
int right
float top
float bot
bool bull
bool active
bool deleted
box bx
// ==================================================================
// HELPERS
// ==================================================================
f_initSnap() =>
Snap.new(0, 0, 0.0, 0.0, 0.0, 0.0, 0.0)
f_makeSnapCurrent(float level) =>
Snap.new(time, bar_index, open, close, high, low, level)
f_makeSnapAtBar(int srcBar, float level) =>
off = bar_index - srcBar
off >= 0 ? Snap.new(time[off], srcBar, open[off], close[off], high[off], low[off], level) : f_initSnap()
f_candleZone(float o, float c, float h, float l, bool isHigh) =>
bodyTop = math.max(o, c)
bodyBot = math.min(o, c)
pad = math.max(bodyTop - bodyBot, 0.0) * inpZoneBodyPct * 0.01
top_ = isHigh ? h : bodyBot + pad
bot_ = isHigh ? bodyTop - pad : l
[top_, bot_]
f_isTapped(float rClose, float rHigh, float rLow, float top_, float bot_) =>
if inpTapSource == tapByClose
rClose <= top_ and rClose >= bot_
else
rHigh >= bot_ and rLow <= top_
f_levelDir(int kind, bool isHigh) =>
if kind == 1 or kind == 2
isHigh ? -1 : 1
else if kind == 4 or kind == 6
1
else if kind == 3 or kind == 5
-1
else if kind == 7
isHigh ? -1 : 1
else if kind == 30 or kind == 31
1
else if kind == 32 or kind == 33
-1
else
0
f_levelDisplayText(int kind, int dir, string txt) =>
if kind == 1
dir == 1 ? "SELL TJL1" : "BUY TJL1"
else if kind == 2
dir == 1 ? "BUY TJL2" : "SELL TJL2"
else
txt
f_analyzerSlot(string txt) =>
if txt == "BUY TJL1"
0
else if txt == "BUY TJL2"
1
else if txt == "SELL TJL1"
2
else if txt == "SELL TJL2"
3
else if txt == "SBR"
4
else if txt == "RBS"
5
else if txt == "DT"
6
else if txt == "DB"
7
else if txt == "BUY QML"
8
else if txt == "SELL QML"
9
else if txt == "ISS 4"
10
else if txt == "BEST SBR"
11
else if txt == "BEST RBS"
12
else if txt == "BEST DT"
13
else if txt == "BEST DB"
14
else if txt == "BEST BUY QML"
15
else if txt == "BEST SELL QML"
16
else
-1
f_analyzerLabel(int slot) =>
switch slot
0 => "BUY TJL1"
1 => "BUY TJL2"
2 => "SELL TJL1"
3 => "SELL TJL2"
4 => "SBR"
5 => "RBS"
6 => "DT"
7 => "DB"
8 => "BUY QML"
9 => "SELL QML"
10 => "ISS 4"
11 => "BEST SBR"
12 => "BEST RBS"
13 => "BEST DT"
14 => "BEST DB"
15 => "BEST BUY QML"
16 => "BEST SELL QML"
=> ""
f_analyzerShowSlot(int slot) =>
switch slot
0 => inpAnalyzerShowBuyTJL1
1 => inpAnalyzerShowBuyTJL2
2 => inpAnalyzerShowSellTJL1
3 => inpAnalyzerShowSellTJL2
4 => inpAnalyzerShowSBR
5 => inpAnalyzerShowRBS
6 => inpAnalyzerShowDT
7 => inpAnalyzerShowDB
8 => inpAnalyzerShowBuyQML
9 => inpAnalyzerShowSellQML
10 => inpAnalyzerShowISS4
11 => inpAnalyzerShowBestSBR
12 => inpAnalyzerShowBestRBS
13 => inpAnalyzerShowBestDT
14 => inpAnalyzerShowBestDB
15 => inpAnalyzerShowBestBuyQML
16 => inpAnalyzerShowBestSellQML
=> false
f_analyzerRateText(int wins, int losses) =>
done = wins + losses
done > 0 ? str.tostring((wins * 100.0) / done, "#.##") + "%" : "n/a"
f_analyzerPipSize() =>
inpAnalyzerPipMode == "Custom" ? inpAnalyzerCustomPipSize : syminfo.type == "forex" ? syminfo.mintick * 10.0 : syminfo.mintick
// FIX 1: Loop extended from 14 → 16 to cover all 17 slots (0–16).
// Previously only evaluated slots 0–14, so BEST BUY QML (15) and
// BEST SELL QML (16) were never considered for the best-slot highlight.
f_bestAnalyzerSlot(array<int> wins, array<int> losses) =>
int bestSlot = -1
float bestRate = na
for i = 0 to 16
w = array.get(wins, i)
l = array.get(losses, i)
done = w + l
if f_analyzerShowSlot(i) and done >= inpAnalyzerMinDone
rate = (w * 1.0) / done
if na(bestRate) or rate > bestRate
bestRate := rate
bestSlot := i
bestSlot
f_updateLevelAnalyzer(Level lv, float rClose, float rHigh, float rLow, int barNum, array<int> tests, array<int> wins, array<int> losses) =>
slot = f_analyzerSlot(lv.txt)
if inpShowLevelAnalyzer and slot >= 0 and lv.dir != 0
targetMove = inpAnalyzerTargetPips * f_analyzerPipSize()
lossMove = inpAnalyzerLossPips * f_analyzerPipSize()
tapped = f_isTapped(rClose, rHigh, rLow, lv.top, lv.bot)
if not lv.anaStarted and barNum > lv.bornBar and tapped
lv.anaStarted := true
lv.anaActive := true
lv.anaStartBar := barNum
array.set(tests, slot, array.get(tests, slot) + 1)
if lv.anaActive and barNum > lv.anaStartBar
win = lv.dir == 1 ? rHigh >= lv.top + targetMove : rLow <= lv.bot - targetMove
loss = lv.dir == 1 ? rLow <= lv.bot - lossMove : rHigh >= lv.top + lossMove
if win
array.set(wins, slot, array.get(wins, slot) + 1)
lv.anaActive := false
else if loss
array.set(losses, slot, array.get(losses, slot) + 1)
lv.anaActive := false
lv
f_levelTextHAlign() =>
if inpLevelTextHPos == "Left"
text.align_left
else if inpLevelTextHPos == "Right"
text.align_right
else
text.align_center
f_levelTextVAlign() =>
if inpLevelTextVPos == "Top"
text.align_top
else if inpLevelTextVPos == "Bottom"
text.align_bottom
else
text.align_center
f_applyLevelText(box bx, string txt, color col) =>
box.set_text(bx, txt)
box.set_text_color(bx, col)
box.set_text_size(bx, size.small)
box.set_text_halign(bx, f_levelTextHAlign())
box.set_text_valign(bx, f_levelTextVAlign())
f_bestLevelText(int kind, int dir) =>
if kind == 3
"BEST SBR"
else if kind == 4
"BEST RBS"
else if kind == 5
"BEST DT"
else if kind == 6
"BEST DB"
else if kind == 7 and dir == 1
"BEST BUY QML"
else if kind == 7 and dir == -1
"BEST SELL QML"
else
"BEST QML"
f_bestLevelColor(int kind, color srcCol) =>
kind == 7 ? inpBestQMLColor : srcCol
f_promoteLastChochLevelsToBest(array<Level> lvs, int qmlLeft) =>
if not na(qmlLeft) and array.size(lvs) > 0
int srcBornBar = na
for i = array.size(lvs) - 1 to 0
lv = array.get(lvs, i)
if lv.kind == 7 and not lv.deleted and lv.left == qmlLeft
srcBornBar := lv.bornBar
break
if not na(srcBornBar)
for i = array.size(lvs) - 1 to 0
srcLv = array.get(lvs, i)
if srcLv.kind >= 3 and srcLv.kind <= 7 and not srcLv.deleted and srcLv.bornBar == srcBornBar
bestTxt = f_bestLevelText(srcLv.kind, srcLv.dir)
bestCol = f_bestLevelColor(srcLv.kind, srcLv.col)
srcLv.active := true
srcLv.right := bar_index
srcLv.bornBar := bar_index
srcLv.stopReady := false
srcLv.stopReadyBar := 0
if not na(srcLv.bx)
f_applyLevelText(srcLv.bx, srcLv.txt, srcLv.col)
box.set_border_color(srcLv.bx, srcLv.col)
box.set_bgcolor(srcLv.bx, color.new(srcLv.col, 75))
box.set_right(srcLv.bx, bar_index)
if not na(srcLv.lb)
label.delete(srcLv.lb)
srcLv.lb := na
array.set(lvs, i, srcLv)
bool bestFound = false
for j = array.size(lvs) - 1 to 0
foundBestLv = array.get(lvs, j)
if foundBestLv.kind == 8 and not foundBestLv.deleted and foundBestLv.left == srcLv.left and foundBestLv.top == srcLv.top and foundBestLv.bot == srcLv.bot and foundBestLv.txt == bestTxt
foundBestLv.active := true
foundBestLv.right := bar_index
foundBestLv.bornBar := bar_index
foundBestLv.stopReady := false
foundBestLv.stopReadyBar := 0
foundBestLv.col := bestCol
foundBestLv.txt := bestTxt
if not na(foundBestLv.bx)
f_applyLevelText(foundBestLv.bx, bestTxt, bestCol)
box.set_border_color(foundBestLv.bx, bestCol)
box.set_bgcolor(foundBestLv.bx, color.new(bestCol, 80))
box.set_right(foundBestLv.bx, bar_index)
if not na(foundBestLv.lb)
label.delete(foundBestLv.lb)
foundBestLv.lb := na
array.set(lvs, j, foundBestLv)
bestFound := true
break
if not bestFound
newBestLv = Level.new(srcLv.left, bar_index, srcLv.top, srcLv.bot, bestCol, bestTxt, 8, srcLv.dir, true, false, false, 0, bar_index, na, na, false, false, 0)
array.push(lvs, newBestLv)
f_addLevel(array<Level> lvs, int left_, float o, float c, float h, float l,
bool isHigh, color col, string txt, int kind, int bornBar, int right_) =>
[top_, bot_] = f_candleZone(o, c, h, l, isHigh)
dir_ = f_levelDir(kind, isHigh)
lv = Level.new(left_, right_, top_, bot_, col, f_levelDisplayText(kind, dir_, txt), kind, dir_, true, false, false, 0, bornBar, na, na, false, false, 0)
array.push(lvs, lv)
f_addLevelFromBar(array<Level> lvs, int leftBar, int srcBar, bool isHigh, color col, string txt, int kind, int bornBar, int rightBar) =>
off = bar_index - srcBar
if off >= 0
[top_, bot_] = f_candleZone(open[off], close[off], high[off], low[off], isHigh)
dir_ = f_levelDir(kind, isHigh)
lv = Level.new(leftBar, rightBar, top_, bot_, col, f_levelDisplayText(kind, dir_, txt), kind, dir_, true, false, false, 0, bornBar, na, na, false, false, 0)
array.push(lvs, lv)
f_addLevelFromBarReady(array<Level> lvs, int leftBar, int srcBar, bool isHigh, color col, string txt, int kind, int bornBar, int rightBar, int readyBar) =>
off = bar_index - srcBar
if off >= 0
[top_, bot_] = f_candleZone(open[off], close[off], high[off], low[off], isHigh)
dir_ = f_levelDir(kind, isHigh)
lv = Level.new(leftBar, rightBar, top_, bot_, col, f_levelDisplayText(kind, dir_, txt), kind, dir_, true, false, true, readyBar, bornBar, na, na, false, false, 0)
array.push(lvs, lv)
f_deleteLatestTJL1ByLeft(array<Level> lvs, int srcLeftBar) =>
if array.size(lvs) > 0
for i = array.size(lvs) - 1 to 0
lv = array.get(lvs, i)
if not lv.deleted and lv.active and lv.kind == 1 and lv.left == srcLeftBar
lv.deleted := true
lv.active := false
if not na(lv.bx)
box.delete(lv.bx)
if not na(lv.lb)
label.delete(lv.lb)
array.set(lvs, i, lv)
break
f_freezePreviousCHOCHLevels(array<Level> lvs) =>
if array.size(lvs) > 0
for i = 0 to array.size(lvs) - 1
lv = array.get(lvs, i)
if not lv.deleted and lv.active and lv.kind >= 3 and lv.kind <= 7
lv.active := false
array.set(lvs, i, lv)
f_updateLevels(array<Level> lvs, float rClose, float rHigh, float rLow, int barNum, array<int> anaTests, array<int> anaWins, array<int> anaLosses) =>
if array.size(lvs) > 0
for i = 0 to array.size(lvs) - 1
lv = array.get(lvs, i)
if lv.deleted
continue
lv := f_updateLevelAnalyzer(lv, rClose, rHigh, rLow, barNum, anaTests, anaWins, anaLosses)
if not lv.active
array.set(lvs, i, lv)
continue
lv.right := barNum
issWickLevel = lv.kind == 30 or lv.kind == 31 or lv.kind == 32 or lv.kind == 33
if issWickLevel
if inpStopISS34ByWickTap and barNum > lv.bornBar
crossed = lv.dir == 1 ? rClose > lv.top : rClose < lv.bot
if not lv.stopReady and crossed
lv.stopReady := true
lv.stopReadyBar := barNum
if lv.stopReady and barNum > lv.stopReadyBar
issTapped = rHigh >= lv.bot and rLow <= lv.top
if issTapped
lv.active := false
lv.right := barNum
else
if inpStopOnTap and barNum > lv.bornBar
stdTapped = f_isTapped(rClose, rHigh, rLow, lv.top, lv.bot)
if stdTapped
lv.active := false
lv.right := barNum
array.set(lvs, i, lv)
f_trimLevels(array<Level> lvs) =>
if array.size(lvs) > 0
kept = 0
for i = array.size(lvs) - 1 to 0
lv = array.get(lvs, i)
if lv.deleted
continue
kept += 1
if kept > inpMaxLiveLevels
lv.deleted := true
if not na(lv.bx)
box.delete(lv.bx)
if not na(lv.lb)
label.delete(lv.lb)
array.set(lvs, i, lv)
f_pushLine(array<line> arr, line ln) =>
array.push(arr, ln)
if array.size(arr) > inpMaxLines
old = array.shift(arr)
line.delete(old)
f_pushLabel(array<label> arr, label lb) =>
array.push(arr, lb)
if array.size(arr) > inpMaxLabels
old = array.shift(arr)
label.delete(old)
f_shouldShowLevel(int kind) =>
if kind == 1
inpShowTJL1
else if kind == 2
inpShowTJL2
else if kind == 3
inpShowSBR
else if kind == 4
inpShowRBS
else if kind == 5
inpShowDT
else if kind == 6
inpShowDB
else if kind == 7
inpShowQML
else if kind == 8
inpShowBestQML
else if kind == 29
inpShowISS1
else if kind == 30 or kind == 32
inpShowISS3
else if kind == 31 or kind == 33
inpShowISS4
else
true
f_mtfTrendCalc() =>
var int mtfTrend = 0
var int mtfStructureTrend = 0
var int mtfPhase = 1
var int mtfStartBarIndex = na
var float mtfRunHigh = na
var int mtfRunHighBar = na
var float mtfRunLow = na
var int mtfRunLowBar = na
var float mtfLastCH = na
var bool mtfLastCHSet = false
var float mtfLastCL = na
var bool mtfLastCLSet = false
var int mtfBullIssState = 0
var bool mtfBullIssBaseConfirmed = false
var float mtfBullIssBaseLow = na
var int mtfBullIssBaseLowBar = na
var float mtfBullIssRunHigh = na
var int mtfBullIssRunHighBar = na
var float mtfBullIss1Level = na
var int mtfBullIss1Bar = na
var float mtfBullIssAfterBreakRunHigh = na
var int mtfBullIssAfterBreakRunHighBar = na
var float mtfBullIssAfterBreakRunLow = na
var int mtfBullIssAfterBreakRunLowBar = na
var int mtfBearIssState = 0
var bool mtfBearIssBaseConfirmed = false
var float mtfBearIssBaseHigh = na
var int mtfBearIssBaseHighBar = na
var float mtfBearIssRunLow = na
var int mtfBearIssRunLowBar = na
var float mtfBearIss1Level = na
var int mtfBearIss1Bar = na
var float mtfBearIssAfterBreakRunLow = na
var int mtfBearIssAfterBreakRunLowBar = na
var float mtfBearIssAfterBreakRunHigh = na
var int mtfBearIssAfterBreakRunHighBar = na
if na(mtfStartBarIndex) and time >= inpStartTime
mtfStartBarIndex := bar_index
mtfInWindow = not na(mtfStartBarIndex) and bar_index >= mtfStartBarIndex and (bar_index - mtfStartBarIndex) <= inpMaxBars
mtfEnoughBars = bar_index >= 2
if mtfInWindow and mtfEnoughBars
if na(mtfRunHigh) or high > mtfRunHigh
mtfRunHigh := high
mtfRunHighBar := bar_index
if na(mtfRunLow) or low < mtfRunLow
mtfRunLow := low
mtfRunLowBar := bar_index
mtfRedP = close[1] < open[1]
mtfGreenP = close[1] > open[1]
mtfRedC = close < open
mtfGreenC = close > open
mtfBearishIssShift = mtfRedP and mtfRedC and close < low[1]
mtfBullishIssShift = mtfGreenP and mtfGreenC and close > high[1]
mtfBullRetracement = mtfBearishIssShift
mtfBearRetracement = mtfBullishIssShift
mtfBearChoch = mtfTrend == 1 and mtfLastCLSet and mtfRedP and close[1] < mtfLastCL and close < mtfLastCL
mtfBullChoch = mtfTrend == -1 and mtfLastCHSet and mtfGreenP and close[1] > mtfLastCH and close > mtfLastCH
if mtfBearChoch
mtfTrend := -1
mtfStructureTrend := -1
mtfPhase := 1
mtfLastCH := mtfRunHigh
mtfLastCHSet := true
mtfRunHigh := high
mtfRunHighBar := bar_index
mtfRunLow := low
mtfRunLowBar := bar_index
mtfBullIssState := 1
mtfBullIssBaseConfirmed := false
mtfBullIssBaseLow := low
mtfBullIssBaseLowBar := bar_index
mtfBullIssRunHigh := high
mtfBullIssRunHighBar := bar_index
mtfBullIss1Level := na
mtfBullIss1Bar := na
mtfBullIssAfterBreakRunHigh := na
mtfBullIssAfterBreakRunHighBar := na
mtfBullIssAfterBreakRunLow := na
mtfBullIssAfterBreakRunLowBar := na
mtfBearIssState := 0
mtfBearIssBaseConfirmed := false
mtfBearIssBaseHigh := na
mtfBearIssBaseHighBar := na
mtfBearIssRunLow := na
mtfBearIssRunLowBar := na
mtfBearIss1Level := na
mtfBearIss1Bar := na
mtfBearIssAfterBreakRunLow := na
mtfBearIssAfterBreakRunLowBar := na
mtfBearIssAfterBreakRunHigh := na
mtfBearIssAfterBreakRunHighBar := na
else if mtfBullChoch
mtfTrend := 1
mtfStructureTrend := 1
mtfPhase := 1
mtfLastCL := mtfRunLow
mtfLastCLSet := true
mtfRunHigh := high
mtfRunHighBar := bar_index
mtfRunLow := low
mtfRunLowBar := bar_index
mtfBearIssState := 1
mtfBearIssBaseConfirmed := false
mtfBearIssBaseHigh := high
mtfBearIssBaseHighBar := bar_index
mtfBearIssRunLow := low
mtfBearIssRunLowBar := bar_index
mtfBearIss1Level := na
mtfBearIss1Bar := na
mtfBearIssAfterBreakRunLow := na
mtfBearIssAfterBreakRunLowBar := na
mtfBearIssAfterBreakRunHigh := na
mtfBearIssAfterBreakRunHighBar := na
mtfBullIssState := 0
mtfBullIssBaseConfirmed := false
mtfBullIssBaseLow := na
mtfBullIssBaseLowBar := na
mtfBullIssRunHigh := na
mtfBullIssRunHighBar := na
mtfBullIss1Level := na
mtfBullIss1Bar := na
mtfBullIssAfterBreakRunHigh := na
mtfBullIssAfterBreakRunHighBar := na
mtfBullIssAfterBreakRunLow := na
mtfBullIssAfterBreakRunLowBar := na
else
if mtfTrend == 1 and mtfPhase == 2 and mtfLastCHSet and close > mtfLastCH
mtfLastCL := mtfRunLow
mtfLastCLSet := true
mtfStructureTrend := 1
mtfPhase := 1
mtfRunHigh := high
mtfRunHighBar := bar_index
mtfRunLow := low
mtfRunLowBar := bar_index
mtfBearIssState := 1
mtfBearIssBaseConfirmed := false
mtfBearIssBaseHigh := high
mtfBearIssBaseHighBar := bar_index
mtfBearIssRunLow := low
mtfBearIssRunLowBar := bar_index
mtfBearIss1Level := na
mtfBearIss1Bar := na
mtfBearIssAfterBreakRunLow := na
mtfBearIssAfterBreakRunLowBar := na
mtfBearIssAfterBreakRunHigh := na
mtfBearIssAfterBreakRunHighBar := na
mtfBullIssState := 0
mtfBullIssBaseConfirmed := false
mtfBullIssBaseLow := na
mtfBullIssBaseLowBar := na
mtfBullIssRunHigh := na
mtfBullIssRunHighBar := na
mtfBullIss1Level := na
mtfBullIss1Bar := na
mtfBullIssAfterBreakRunHigh := na
mtfBullIssAfterBreakRunHighBar := na
mtfBullIssAfterBreakRunLow := na
mtfBullIssAfterBreakRunLowBar := na
else if mtfTrend == -1 and mtfPhase == 2 and mtfLastCLSet and close < mtfLastCL
mtfLastCH := mtfRunHigh
mtfLastCHSet := true
mtfStructureTrend := -1
mtfPhase := 1
mtfRunHigh := high
mtfRunHighBar := bar_index
mtfRunLow := low
mtfRunLowBar := bar_index
mtfBullIssState := 1
mtfBullIssBaseConfirmed := false
mtfBullIssBaseLow := low
mtfBullIssBaseLowBar := bar_index
mtfBullIssRunHigh := high
mtfBullIssRunHighBar := bar_index
mtfBullIss1Level := na
mtfBullIss1Bar := na
mtfBullIssAfterBreakRunHigh := na
mtfBullIssAfterBreakRunHighBar := na
mtfBullIssAfterBreakRunLow := na
mtfBullIssAfterBreakRunLowBar := na
mtfBearIssState := 0
mtfBearIssBaseConfirmed := false
mtfBearIssBaseHigh := na
mtfBearIssBaseHighBar := na
mtfBearIssRunLow := na
mtfBearIssRunLowBar := na
mtfBearIss1Level := na
mtfBearIss1Bar := na
mtfBearIssAfterBreakRunLow := na
mtfBearIssAfterBreakRunLowBar := na
mtfBearIssAfterBreakRunHigh := na
mtfBearIssAfterBreakRunHighBar := na
else if mtfPhase == 1
if mtfTrend != -1 and mtfBullRetracement
mtfLastCH := mtfRunHigh
mtfLastCHSet := true
mtfTrend := 1
mtfPhase := 2
if low < low[1]
mtfRunLow := low
mtfRunLowBar := bar_index
else
mtfRunLow := low[1]
mtfRunLowBar := bar_index - 1
else if mtfTrend != 1 and mtfBearRetracement
mtfLastCL := mtfRunLow
mtfLastCLSet := true
mtfTrend := -1
mtfPhase := 2
if high > high[1]
mtfRunHigh := high
mtfRunHighBar := bar_index
else
mtfRunHigh := high[1]
mtfRunHighBar := bar_index - 1
if inpEnableISS
mtfBullIssInvalidated = mtfBullIssState >= 2 and not na(mtfBullIssBaseLow) and close < mtfBullIssBaseLow
mtfBearIssInvalidated = mtfBearIssState >= 2 and not na(mtfBearIssBaseHigh) and close > mtfBearIssBaseHigh
if mtfBullIssInvalidated
mtfBullIssState := 0
mtfBullIssBaseConfirmed := false
mtfBullIssBaseLow := na
mtfBullIssBaseLowBar := na
mtfBullIssRunHigh := na
mtfBullIssRunHighBar := na
mtfBullIss1Level := na
mtfBullIss1Bar := na
mtfBullIssAfterBreakRunHigh := na
mtfBullIssAfterBreakRunHighBar := na
mtfBullIssAfterBreakRunLow := na
mtfBullIssAfterBreakRunLowBar := na
else if mtfBullIssState == 1
if na(mtfBullIssBaseLow) or low < mtfBullIssBaseLow
mtfBullIssBaseLow := low
mtfBullIssBaseLowBar := bar_index
mtfBullIssRunHigh := high
mtfBullIssRunHighBar := bar_index
mtfBullIssBaseConfirmed := false
if not mtfBullIssBaseConfirmed
if mtfBullishIssShift
mtfBullIssBaseConfirmed := true
mtfBullIssRunHigh := high
mtfBullIssRunHighBar := bar_index
else
if na(mtfBullIssRunHigh) or high > mtfBullIssRunHigh
mtfBullIssRunHigh := high
mtfBullIssRunHighBar := bar_index
if mtfBearishIssShift and not na(mtfBullIssRunHighBar) and mtfBullIssRunHighBar < bar_index
mtfBullIss1Level := mtfBullIssRunHigh
mtfBullIss1Bar := mtfBullIssRunHighBar
mtfBullIssState := 2
else if mtfBullIssState == 2
if not na(mtfBullIss1Level) and close > mtfBullIss1Level
mtfBullIssAfterBreakRunHigh := high
mtfBullIssAfterBreakRunHighBar := bar_index
mtfBullIssAfterBreakRunLow := low
mtfBullIssAfterBreakRunLowBar := bar_index
mtfBullIssState := 3
else if mtfBullIssState == 3
if na(mtfBullIssAfterBreakRunHigh) or high > mtfBullIssAfterBreakRunHigh
mtfBullIssAfterBreakRunHigh := high
mtfBullIssAfterBreakRunHighBar := bar_index
mtfBullIssAfterBreakRunLow := low
mtfBullIssAfterBreakRunLowBar := bar_index
else if na(mtfBullIssAfterBreakRunLow) or low < mtfBullIssAfterBreakRunLow
mtfBullIssAfterBreakRunLow := low
mtfBullIssAfterBreakRunLowBar := bar_index
if mtfBearishIssShift and not na(mtfBullIssAfterBreakRunHighBar) and not na(mtfBullIssAfterBreakRunLowBar)
mtfBullIssState := 4
else if mtfBullIssState == 4
if na(mtfBullIssAfterBreakRunLow) or low < mtfBullIssAfterBreakRunLow
mtfBullIssAfterBreakRunLow := low
mtfBullIssAfterBreakRunLowBar := bar_index
if not na(mtfBullIssAfterBreakRunHigh) and not na(mtfBullIssAfterBreakRunLowBar) and close > mtfBullIssAfterBreakRunHigh
mtfTrend := 1
mtfStructureTrend := 1
mtfPhase := 1
mtfBullIssState := 0
mtfBullIssBaseConfirmed := false
mtfBullIssBaseLow := na
mtfBullIssBaseLowBar := na
mtfBullIssRunHigh := na
mtfBullIssRunHighBar := na
mtfBullIss1Level := na
mtfBullIss1Bar := na
mtfBullIssAfterBreakRunHigh := na
mtfBullIssAfterBreakRunHighBar := na
mtfBullIssAfterBreakRunLow := na
mtfBullIssAfterBreakRunLowBar := na
mtfBearIssState := 0
mtfBearIssBaseConfirmed := false
mtfBearIssBaseHigh := na
mtfBearIssBaseHighBar := na
mtfBearIssRunLow := na
mtfBearIssRunLowBar := na
mtfBearIss1Level := na
mtfBearIss1Bar := na
mtfBearIssAfterBreakRunLow := na
mtfBearIssAfterBreakRunLowBar := na
mtfBearIssAfterBreakRunHigh := na
mtfBearIssAfterBreakRunHighBar := na
if mtfBearIssInvalidated
mtfBearIssState := 0
mtfBearIssBaseConfirmed := false
mtfBearIssBaseHigh := na
mtfBearIssBaseHighBar := na
mtfBearIssRunLow := na
mtfBearIssRunLowBar := na
mtfBearIss1Level := na
mtfBearIss1Bar := na
mtfBearIssAfterBreakRunLow := na
mtfBearIssAfterBreakRunLowBar := na
mtfBearIssAfterBreakRunHigh := na
mtfBearIssAfterBreakRunHighBar := na
else if mtfBearIssState == 1
if na(mtfBearIssBaseHigh) or high > mtfBearIssBaseHigh
mtfBearIssBaseHigh := high
mtfBearIssBaseHighBar := bar_index
mtfBearIssRunLow := low
mtfBearIssRunLowBar := bar_index
mtfBearIssBaseConfirmed := false
if not mtfBearIssBaseConfirmed
if mtfBearishIssShift
mtfBearIssBaseConfirmed := true
mtfBearIssRunLow := low
mtfBearIssRunLowBar := bar_index
else
if na(mtfBearIssRunLow) or low < mtfBearIssRunLow
mtfBearIssRunLow := low
mtfBearIssRunLowBar := bar_index
if mtfBullishIssShift and not na(mtfBearIssRunLowBar) and mtfBearIssRunLowBar < bar_index
mtfBearIss1Level := mtfBearIssRunLow
mtfBearIss1Bar := mtfBearIssRunLowBar
mtfBearIssState := 2
else if mtfBearIssState == 2
if not na(mtfBearIss1Level) and close < mtfBearIss1Level
mtfBearIssAfterBreakRunLow := low
mtfBearIssAfterBreakRunLowBar := bar_index
mtfBearIssAfterBreakRunHigh := high
mtfBearIssAfterBreakRunHighBar := bar_index
mtfBearIssState := 3
else if mtfBearIssState == 3
if na(mtfBearIssAfterBreakRunLow) or low < mtfBearIssAfterBreakRunLow
mtfBearIssAfterBreakRunLow := low
mtfBearIssAfterBreakRunLowBar := bar_index
mtfBearIssAfterBreakRunHigh := high
mtfBearIssAfterBreakRunHighBar := bar_index
else if na(mtfBearIssAfterBreakRunHigh) or high > mtfBearIssAfterBreakRunHigh
mtfBearIssAfterBreakRunHigh := high
mtfBearIssAfterBreakRunHighBar := bar_index
if mtfBullishIssShift and not na(mtfBearIssAfterBreakRunLowBar) and not na(mtfBearIssAfterBreakRunHighBar)
mtfBearIssState := 4
else if mtfBearIssState == 4
if na(mtfBearIssAfterBreakRunHigh) or high > mtfBearIssAfterBreakRunHigh
mtfBearIssAfterBreakRunHigh := high
mtfBearIssAfterBreakRunHighBar := bar_index
if not na(mtfBearIssAfterBreakRunLow) and not na(mtfBearIssAfterBreakRunHighBar) and close < mtfBearIssAfterBreakRunLow
mtfTrend := -1
mtfStructureTrend := -1
mtfPhase := 1
mtfBearIssState := 0
mtfBearIssBaseConfirmed := false
mtfBearIssBaseHigh := na
mtfBearIssBaseHighBar := na
mtfBearIssRunLow := na
mtfBearIssRunLowBar := na
mtfBearIss1Level := na
mtfBearIss1Bar := na
mtfBearIssAfterBreakRunLow := na
mtfBearIssAfterBreakRunLowBar := na
mtfBearIssAfterBreakRunHigh := na
mtfBearIssAfterBreakRunHighBar := na
mtfBullIssState := 0
mtfBullIssBaseConfirmed := false
mtfBullIssBaseLow := na
mtfBullIssBaseLowBar := na
mtfBullIssRunHigh := na
mtfBullIssRunHighBar := na
mtfBullIss1Level := na
mtfBullIss1Bar := na
mtfBullIssAfterBreakRunHigh := na
mtfBullIssAfterBreakRunHighBar := na
mtfBullIssAfterBreakRunLow := na
mtfBullIssAfterBreakRunLowBar := na
mtfStructureTrend
f_dashEmaTrendCalc() =>
dashEma = ta.ema(emaSrc, emaLen)
close > dashEma ? 1 : close < dashEma ? -1 : 0
f_dashTfLabel(string tf) =>
switch tf
"1" => "1m"
"3" => "3m"
"5" => "5m"
"15" => "15m"
"30" => "30m"
"45" => "45m"
"60" => "1H"
"120" => "2H"
"180" => "3H"
"240" => "4H"
"D" => "1D"
"1D" => "1D"
"W" => "1W"
"1W" => "1W"
"M" => "1M"
"1M" => "1M"
=> tf
f_dashTrendText(int dir) =>
dir == 1 ? "BULLISH" : dir == -1 ? "BEARISH" : "NEUTRAL"
f_dashTrendColor(int dir) =>
dir == 1 ? color.green : dir == -1 ? color.red : color.gray
// ==================================================================
// PERSISTENT STATE
// ==================================================================
var array<Level> levels = array.new<Level>()
var array<line> drawnLines = array.new<line>()
var array<label> drawnLabels = array.new<label>()
var array<FVGLevel> fvgLevels = array.new<FVGLevel>()
var array<OBLevel> obLevels = array.new<OBLevel>()
var line bullIssBos1Line = na
var line bearIssBos1Line = na
var int trend = 0
var int phase = 1
var table tfDashboard = table.new(position.top_right, 2, 14, border_width=1)
// FIX 2 & 3: Table rows increased from 16 → 19 (1 header + 17 data slots + 1 spare).
// Previously only 16 rows were allocated, but slots 0–16 need up to 18 rows.
var table levelAnalyzerTable = table.new(position.bottom_right, 5, 19, border_width=1)
// FIX 4, 5, 6: Arrays resized from 15 → 17 elements to cover all slots 0–16.
// Slots 15 ("BEST BUY QML") and 16 ("BEST SELL QML") previously caused
// "Index N is out of bounds, array size is 15" at runtime.
var array<int> levelAnalyzerTests = array.new<int>(17, 0)
var array<int> levelAnalyzerWins = array.new<int>(17, 0)
var array<int> levelAnalyzerLosses = array.new<int>(17, 0)
var Snap runHigh = f_initSnap()
var Snap runLow = f_initSnap()
var Snap lastCH = f_initSnap()
var Snap lastCL = f_initSnap()
var Snap tjl1 = f_initSnap()
var Snap tjl2 = f_initSnap()
var bool runHighSet = false
var bool runLowSet = false
var bool lastCHSet = false
var bool lastCLSet = false
var bool tjl1Set = false
var int bullIssState = 0
var bool bullIssBaseConfirmed = false
var float bullIssBaseLow = na
var int bullIssBaseLowBar = na
var float bullIssRunHigh = na
var int bullIssRunHighBar = na
var float bullIss1Level = na
var int bullIss1Bar = na
var float bullIssAfterBreakRunHigh = na
var int bullIssAfterBreakRunHighBar = na
var float bullIssAfterBreakRunLow = na
var int bullIssAfterBreakRunLowBar = na
var array<int> bullIssBosBars = array.new<int>()
var array<float> bullIssBosLvls = array.new<float>()
var int bearIssState = 0
var bool bearIssBaseConfirmed = false
var float bearIssBaseHigh = na
var int bearIssBaseHighBar = na
var float bearIssRunLow = na
var int bearIssRunLowBar = na
var float bearIss1Level = na
var int bearIss1Bar = na
var float bearIssAfterBreakRunLow = na
var int bearIssAfterBreakRunLowBar = na
var float bearIssAfterBreakRunHigh = na
var int bearIssAfterBreakRunHighBar = na
var array<int> bearIssBosBars = array.new<int>()
var array<float> bearIssBosLvls = array.new<float>()
var int lastChochSide = 0
var bool issOrTjlSinceChoch = false
var int lastQmlLeft = na
var float lastQmlTop = na
var float lastQmlBot = na
var color lastQmlCol = na
var int startBarIndex = na
if na(startBarIndex) and time >= inpStartTime
startBarIndex := bar_index
inWindow = not na(startBarIndex) and bar_index >= startBarIndex and (bar_index - startBarIndex) <= inpMaxBars
enoughBars = bar_index >= 2
// ==================================================================
// KILL ZONES
// ==================================================================
utcH = hour(time, "UTC")
utcM = minute(time, "UTC")
utcTot = utcH * 60 + utcM
isLondonKZ = utcTot >= 390 and utcTot < 480
isNYKZ = utcTot >= 750 and utcTot < 870
bgcolor(inpShowKZ and isLondonKZ ? inpLondonColor : na, title="London Kill Zone")
bgcolor(inpShowKZ and isNYKZ ? inpNYColor : na, title="New York Kill Zone")
// ==================================================================
// MAIN LOGIC
// ==================================================================
if inWindow and enoughBars
f_updateLevels(levels, close, high, low, bar_index, levelAnalyzerTests, levelAnalyzerWins, levelAnalyzerLosses)
if inpShowFVG and array.size(fvgLevels) > 0
for i = 0 to array.size(fvgLevels) - 1
fv = array.get(fvgLevels, i)
if fv.deleted
continue
fv.right := bar_index
if inpFVGDeleteOnTap and bar_index > fv.left
fvTapped = inpTapSource == tapByClose ? (close >= fv.bot and close <= fv.top) : (low <= fv.top and high >= fv.bot)
if fvTapped
fv.active := false
fv.deleted := true
if not na(fv.bx)
box.delete(fv.bx)
array.set(fvgLevels, i, fv)
continue
if not na(fv.bx)
box.set_right(fv.bx, bar_index)
array.set(fvgLevels, i, fv)
if inpShowOB and array.size(obLevels) > 0
for i = 0 to array.size(obLevels) - 1
ob = array.get(obLevels, i)
if ob.deleted
continue
ob.right := bar_index
if inpOBDeleteOnTap and bar_index > ob.left
obTapped = inpTapSource == tapByClose ? (close >= ob.bot and close <= ob.top) : (low <= ob.top and high >= ob.bot)
if obTapped
ob.active := false
ob.deleted := true
if not na(ob.bx)
box.delete(ob.bx)
array.set(obLevels, i, ob)
continue
if not na(ob.bx)
box.set_right(ob.bx, bar_index)
array.set(obLevels, i, ob)
if not runHighSet or high > runHigh.lvl
runHigh := f_makeSnapCurrent(high)
runHighSet := true
if not runLowSet or low < runLow.lvl
runLow := f_makeSnapCurrent(low)
runLowSet := true
redP = close[1] < open[1]
greenP = close[1] > open[1]
redC = close < open
greenC = close > open
// ISS confirmation uses two same-direction candles. The second candle must
// close through the first candle's wick.
bearishIssShift = redP and redC and close < low[1]
bullishIssShift = greenP and greenC and close > high[1]
bullRetracement = bearishIssShift
bearRetracement = bullishIssShift
bearChoch = trend == 1 and lastCLSet and redP and close[1] < lastCL.lvl and close < lastCL.lvl
bullChoch = trend == -1 and lastCHSet and greenP and close[1] > lastCH.lvl and close > lastCH.lvl
if bearChoch
dualChochHit = lastChochSide == -1 and not issOrTjlSinceChoch
if inpShowCHOCH
ln = line.new(lastCL.bar, lastCL.lvl, bar_index, lastCL.lvl, xloc=xloc.bar_index, extend=extend.none, color=inpCHColor, style=line.style_dashed, width=inpLineWidth)
f_pushLine(drawnLines, ln)
if tjl1Set
f_deleteLatestTJL1ByLeft(levels, tjl1.bar)
if dualChochHit
f_promoteLastChochLevelsToBest(levels, lastQmlLeft)
else
if inpKeepOnlyLastCHOCH
f_freezePreviousCHOCHLevels(levels)
if inpShowLevels
clOffset = bar_index - lastCL.bar
rhOffset = bar_index - runHigh.bar
f_addLevel(levels, lastCL.bar, open[clOffset], close[clOffset], high[clOffset], low[clOffset], false, inpSBRColor, "SBR", 3, bar_index, bar_index)
if runHigh.bar != tjl1.bar
f_addLevel(levels, runHigh.bar, open[rhOffset], close[rhOffset], high[rhOffset], low[rhOffset], true, inpDTDBColor, "DT", 5, bar_index, bar_index)
if tjl1Set
tjOffset = bar_index - tjl1.bar
[tjTop, tjBot] = f_candleZone(open[tjOffset], close[tjOffset], high[tjOffset], low[tjOffset], true)
f_addLevel(levels, tjl1.bar, open[tjOffset], close[tjOffset], high[tjOffset], low[tjOffset], true, inpQMLColor, "SELL QML", 7, bar_index, bar_index)
lastQmlLeft := tjl1.bar
lastQmlTop := tjTop
lastQmlBot := tjBot
lastQmlCol := inpQMLColor
if inpShowOB
obOff = -1
for i = 1 to 10
if close[i] > open[i]
obOff := i
break
if obOff != -1
obBar = bar_index - obOff
obTop = high[obOff]
obBot = open[obOff]
if obTop > obBot
bx = box.new(obBar, obTop, bar_index, obBot, xloc=xloc.bar_index, border_color=inpBearOBColor, bgcolor=inpBearOBColor, text="S.OB", text_color=color.white, text_size=size.tiny, text_halign=text.align_right, text_valign=text.align_center)
ob = OBLevel.new(obBar, bar_index, obTop, obBot, false, true, false, bx)
array.push(obLevels, ob)
trend := -1
phase := 1
lastCH := f_makeSnapAtBar(runHigh.bar, runHigh.lvl)
lastCHSet := true
runHigh := f_makeSnapCurrent(high)
runLow := f_makeSnapCurrent(low)
lastChochSide := 1
issOrTjlSinceChoch := false
// Bearish external structure: arm bullish ISS from a candidate low.
if not na(bullIssBos1Line)
line.delete(bullIssBos1Line)
bullIssBos1Line := na
if not na(bearIssBos1Line)
line.delete(bearIssBos1Line)
bearIssBos1Line := na
bullIssState := 1
bullIssBaseConfirmed := false
bullIssBaseLow := low
bullIssBaseLowBar := bar_index
bullIssRunHigh := high
bullIssRunHighBar := bar_index
bullIss1Level := na
bullIss1Bar := na
bullIssAfterBreakRunHigh := na
bullIssAfterBreakRunHighBar := na
bullIssAfterBreakRunLow := na
bullIssAfterBreakRunLowBar := na
array.clear(bullIssBosBars)
array.clear(bullIssBosLvls)
bearIssState := 0
bearIssBaseConfirmed := false
bearIssBaseHigh := na
bearIssBaseHighBar := na
bearIssRunLow := na
bearIssRunLowBar := na
bearIss1Level := na
bearIss1Bar := na
bearIssAfterBreakRunLow := na
bearIssAfterBreakRunLowBar := na
bearIssAfterBreakRunHigh := na
bearIssAfterBreakRunHighBar := na
array.clear(bearIssBosBars)
array.clear(bearIssBosLvls)
else if bullChoch
dualChochHit = lastChochSide == 1 and not issOrTjlSinceChoch
if inpShowCHOCH
ln = line.new(lastCH.bar, lastCH.lvl, bar_index, lastCH.lvl, xloc=xloc.bar_index, extend=extend.none, color=inpCHColor, style=line.style_dashed, width=inpLineWidth)
f_pushLine(drawnLines, ln)
if tjl1Set
f_deleteLatestTJL1ByLeft(levels, tjl1.bar)
if dualChochHit
f_promoteLastChochLevelsToBest(levels, lastQmlLeft)
else
if inpKeepOnlyLastCHOCH
f_freezePreviousCHOCHLevels(levels)
if inpShowLevels
chOffset = bar_index - lastCH.bar
rlOffset = bar_index - runLow.bar
f_addLevel(levels, lastCH.bar, open[chOffset], close[chOffset], high[chOffset], low[chOffset], true, inpRBSColor, "RBS", 4, bar_index, bar_index)
if runLow.bar != tjl1.bar
f_addLevel(levels, runLow.bar, open[rlOffset], close[rlOffset], high[rlOffset], low[rlOffset], false, inpDTDBColor, "DB", 6, bar_index, bar_index)
if tjl1Set
tjOffset = bar_index - tjl1.bar
[tjTop, tjBot] = f_candleZone(open[tjOffset], close[tjOffset], high[tjOffset], low[tjOffset], false)
f_addLevel(levels, tjl1.bar, open[tjOffset], close[tjOffset], high[tjOffset], low[tjOffset], false, inpQMLColor, "BUY QML", 7, bar_index, bar_index)
lastQmlLeft := tjl1.bar
lastQmlTop := tjTop
lastQmlBot := tjBot
lastQmlCol := inpQMLColor
if inpShowOB
obOff = -1
for i = 1 to 10
if close[i] < open[i]
obOff := i
break
if obOff != -1
obBar = bar_index - obOff
obTop = open[obOff]
obBot = low[obOff]
if obTop > obBot
bx = box.new(obBar, obTop, bar_index, obBot, xloc=xloc.bar_index, border_color=inpBullOBColor, bgcolor=inpBullOBColor, text="D.OB", text_color=color.white, text_size=size.tiny, text_halign=text.align_right, text_valign=text.align_center)
ob = OBLevel.new(obBar, bar_index, obTop, obBot, true, true, false, bx)
array.push(obLevels, ob)
trend := 1
phase := 1
lastCL := f_makeSnapAtBar(runLow.bar, runLow.lvl)
lastCLSet := true
runHigh := f_makeSnapCurrent(high)
runLow := f_makeSnapCurrent(low)
lastChochSide := -1
issOrTjlSinceChoch := false
// Bullish external structure: arm bearish ISS from a candidate high.
if not na(bullIssBos1Line)
line.delete(bullIssBos1Line)
bullIssBos1Line := na
if not na(bearIssBos1Line)
line.delete(bearIssBos1Line)
bearIssBos1Line := na
bearIssState := 1
bearIssBaseConfirmed := false
bearIssBaseHigh := high
bearIssBaseHighBar := bar_index
bearIssRunLow := low
bearIssRunLowBar := bar_index
bearIss1Level := na
bearIss1Bar := na
bearIssAfterBreakRunLow := na
bearIssAfterBreakRunLowBar := na
bearIssAfterBreakRunHigh := na
bearIssAfterBreakRunHighBar := na
array.clear(bearIssBosBars)
array.clear(bearIssBosLvls)
bullIssState := 0
bullIssBaseConfirmed := false
bullIssBaseLow := na
bullIssBaseLowBar := na
bullIssRunHigh := na
bullIssRunHighBar := na
bullIss1Level := na
bullIss1Bar := na
bullIssAfterBreakRunHigh := na
bullIssAfterBreakRunHighBar := na
bullIssAfterBreakRunLow := na
bullIssAfterBreakRunLowBar := na
array.clear(bullIssBosBars)
array.clear(bullIssBosLvls)
else
if trend == 1 and phase == 2 and lastCHSet and close > lastCH.lvl
if inpShowBOS
ln = line.new(lastCH.bar, lastCH.lvl, bar_index, lastCH.lvl, xloc=xloc.bar_index, extend=extend.none, color=inpBullBOSColor, style=line.style_solid, width=inpLineWidth)
f_pushLine(drawnLines, ln)
lastCL := f_makeSnapAtBar(runLow.bar, runLow.lvl)
lastCLSet := true
chOff2 = bar_index - lastCH.bar
tjl1 := f_makeSnapAtBar(lastCH.bar, lastCH.lvl)
tjl2 := f_makeSnapAtBar(lastCL.bar, lastCL.lvl)
tjl1Set := true
if inpShowTJL
f_addLevel(levels, tjl1.bar, open[chOff2], close[chOff2], high[chOff2], low[chOff2], true, inpBullTJLColor, "TJL1", 1, bar_index, bar_index)
clOff2 = bar_index - lastCL.bar
f_addLevel(levels, tjl2.bar, open[clOff2], close[clOff2], high[clOff2], low[clOff2], false, inpBullTJLColor, "TJL2", 2, bar_index, bar_index)
issOrTjlSinceChoch := true
if inpShowOB
obOff = -1
for i = 1 to 10
if close[i] < open[i]
obOff := i
break
if obOff != -1
obBar = bar_index - obOff
obTop = open[obOff]
obBot = low[obOff]
if obTop > obBot
bx = box.new(obBar, obTop, bar_index, obBot, xloc=xloc.bar_index, border_color=inpBullOBColor, bgcolor=inpBullOBColor, text="D.OB", text_color=color.white, text_size=size.tiny, text_halign=text.align_right, text_valign=text.align_center)
ob = OBLevel.new(obBar, bar_index, obTop, obBot, true, true, false, bx)
array.push(obLevels, ob)
phase := 1
runHigh := f_makeSnapCurrent(high)
runLow := f_makeSnapCurrent(low)
if not na(bullIssBos1Line)
line.delete(bullIssBos1Line)
bullIssBos1Line := na
if not na(bearIssBos1Line)
line.delete(bearIssBos1Line)
bearIssBos1Line := na
bearIssState := 1
bearIssBaseConfirmed := false
bearIssBaseHigh := high
bearIssBaseHighBar := bar_index
bearIssRunLow := low
bearIssRunLowBar := bar_index
bearIss1Level := na
bearIss1Bar := na
bearIssAfterBreakRunLow := na
bearIssAfterBreakRunLowBar := na
bearIssAfterBreakRunHigh := na
bearIssAfterBreakRunHighBar := na
array.clear(bearIssBosBars)
array.clear(bearIssBosLvls)
bullIssState := 0
bullIssBaseConfirmed := false
bullIssBaseLow := na
bullIssBaseLowBar := na
bullIssRunHigh := na
bullIssRunHighBar := na
bullIss1Level := na
bullIss1Bar := na
bullIssAfterBreakRunHigh := na
bullIssAfterBreakRunHighBar := na
bullIssAfterBreakRunLow := na
bullIssAfterBreakRunLowBar := na
array.clear(bullIssBosBars)
array.clear(bullIssBosLvls)
else if trend == -1 and phase == 2 and lastCLSet and close < lastCL.lvl
if inpShowBOS
ln = line.new(lastCL.bar, lastCL.lvl, bar_index, lastCL.lvl, xloc=xloc.bar_index, extend=extend.none, color=inpBearBOSColor, style=line.style_solid, width=inpLineWidth)
f_pushLine(drawnLines, ln)
lastCH := f_makeSnapAtBar(runHigh.bar, runHigh.lvl)
lastCHSet := true
clOff2 = bar_index - lastCL.bar
tjl1 := f_makeSnapAtBar(lastCL.bar, lastCL.lvl)
tjl2 := f_makeSnapAtBar(lastCH.bar, lastCH.lvl)
tjl1Set := true
if inpShowTJL
f_addLevel(levels, tjl1.bar, open[clOff2], close[clOff2], high[clOff2], low[clOff2], false, inpBearTJLColor, "TJL1", 1, bar_index, bar_index)
chOff2 = bar_index - lastCH.bar
f_addLevel(levels, tjl2.bar, open[chOff2], close[chOff2], high[chOff2], low[chOff2], true, inpBearTJLColor, "TJL2", 2, bar_index, bar_index)
issOrTjlSinceChoch := true
if inpShowOB
obOff = -1
for i = 1 to 10
if close[i] > open[i]
obOff := i
break
if obOff != -1
obBar = bar_index - obOff
obTop = high[obOff]
obBot = open[obOff]
if obTop > obBot
bx = box.new(obBar, obTop, bar_index, obBot, xloc=xloc.bar_index, border_color=inpBearOBColor, bgcolor=inpBearOBColor, text="S.OB", text_color=color.white, text_size=size.tiny, text_halign=text.align_right, text_valign=text.align_center)
ob = OBLevel.new(obBar, bar_index, obTop, obBot, false, true, false, bx)
array.push(obLevels, ob)
phase := 1
runHigh := f_makeSnapCurrent(high)
runLow := f_makeSnapCurrent(low)
if not na(bullIssBos1Line)
line.delete(bullIssBos1Line)
bullIssBos1Line := na
if not na(bearIssBos1Line)
line.delete(bearIssBos1Line)
bearIssBos1Line := na
bullIssState := 1
bullIssBaseConfirmed := false
bullIssBaseLow := low
bullIssBaseLowBar := bar_index
bullIssRunHigh := high
bullIssRunHighBar := bar_index
bullIss1Level := na
bullIss1Bar := na
bullIssAfterBreakRunHigh := na
bullIssAfterBreakRunHighBar := na
bullIssAfterBreakRunLow := na
bullIssAfterBreakRunLowBar := na
array.clear(bullIssBosBars)
array.clear(bullIssBosLvls)
bearIssState := 0
bearIssBaseConfirmed := false
bearIssBaseHigh := na
bearIssBaseHighBar := na
bearIssRunLow := na
bearIssRunLowBar := na
bearIss1Level := na
bearIss1Bar := na
bearIssAfterBreakRunLow := na
bearIssAfterBreakRunLowBar := na
bearIssAfterBreakRunHigh := na
bearIssAfterBreakRunHighBar := na
array.clear(bearIssBosBars)
array.clear(bearIssBosLvls)
else if phase == 1
if trend != -1 and bullRetracement
lastCH := f_makeSnapAtBar(runHigh.bar, runHigh.lvl)
lastCHSet := true
trend := 1
phase := 2
if inpShowSwings
lb = label.new(lastCH.bar, lastCH.lvl, "CH", xloc=xloc.bar_index, style=label.style_none, textcolor=inpCHColor, size=size.small)
f_pushLabel(drawnLabels, lb)
runLow := low < low[1] ? f_makeSnapCurrent(low) : f_makeSnapAtBar(bar_index - 1, low[1])
else if trend != 1 and bearRetracement
lastCL := f_makeSnapAtBar(runLow.bar, runLow.lvl)
lastCLSet := true
trend := -1
phase := 2
if inpShowSwings
lb = label.new(lastCL.bar, lastCL.lvl, "CL", xloc=xloc.bar_index, style=label.style_none, textcolor=inpCLColor, size=size.small)
f_pushLabel(drawnLabels, lb)
runHigh := high > high[1] ? f_makeSnapCurrent(high) : f_makeSnapAtBar(bar_index - 1, high[1])
// ==================================================================
// ISS STATE MACHINE
// ==================================================================
if inpEnableISS
bullIssInvalidated = bullIssState >= 2 and not na(bullIssBaseLow) and close < bullIssBaseLow
bearIssInvalidated = bearIssState >= 2 and not na(bearIssBaseHigh) and close > bearIssBaseHigh
if bullIssInvalidated
if not na(bullIssBos1Line)
line.delete(bullIssBos1Line)
bullIssBos1Line := na
bullIssState := 0
bullIssBaseConfirmed := false
bullIssBaseLow := na
bullIssBaseLowBar := na
bullIssRunHigh := na
bullIssRunHighBar := na
bullIss1Level := na
bullIss1Bar := na
bullIssAfterBreakRunHigh := na
bullIssAfterBreakRunHighBar := na
bullIssAfterBreakRunLow := na
bullIssAfterBreakRunLowBar := na
array.clear(bullIssBosBars)
array.clear(bullIssBosLvls)
else if bullIssState == 1
if na(bullIssBaseLow) or low < bullIssBaseLow
bullIssBaseLow := low
bullIssBaseLowBar := bar_index
bullIssRunHigh := high
bullIssRunHighBar := bar_index
bullIssBaseConfirmed := false
if not bullIssBaseConfirmed
if bullishIssShift
bullIssBaseConfirmed := true
bullIssRunHigh := high
bullIssRunHighBar := bar_index
else
if na(bullIssRunHigh) or high > bullIssRunHigh
bullIssRunHigh := high
bullIssRunHighBar := bar_index
if bearishIssShift and not na(bullIssRunHighBar) and bullIssRunHighBar < bar_index
bullIss1Level := bullIssRunHigh
bullIss1Bar := bullIssRunHighBar
bullIssState := 2
else if bullIssState == 2
if not na(bullIss1Level) and close > bullIss1Level
array.push(bullIssBosBars, bullIss1Bar)
array.push(bullIssBosLvls, bullIss1Level)
if inpShowISSBOS
bullIssBos1Line := line.new(bullIss1Bar, bullIss1Level, bar_index, bullIss1Level, xloc=xloc.bar_index, extend=extend.none, color=inpISSColor, style=line.style_solid, width=inpLineWidth)
f_pushLine(drawnLines, bullIssBos1Line)
bullIssAfterBreakRunHigh := high
bullIssAfterBreakRunHighBar := bar_index
bullIssAfterBreakRunLow := low
bullIssAfterBreakRunLowBar := bar_index
bullIssState := 3
else if bullIssState == 3
if na(bullIssAfterBreakRunHigh) or high > bullIssAfterBreakRunHigh
bullIssAfterBreakRunHigh := high
bullIssAfterBreakRunHighBar := bar_index
bullIssAfterBreakRunLow := low
bullIssAfterBreakRunLowBar := bar_index
else if na(bullIssAfterBreakRunLow) or low < bullIssAfterBreakRunLow
bullIssAfterBreakRunLow := low
bullIssAfterBreakRunLowBar := bar_index
if bearishIssShift and not na(bullIssAfterBreakRunHighBar) and not na(bullIssAfterBreakRunLowBar)
bullIssState := 4
else if bullIssState == 4
if na(bullIssAfterBreakRunLow) or low < bullIssAfterBreakRunLow
bullIssAfterBreakRunLow := low
bullIssAfterBreakRunLowBar := bar_index
if not na(bullIssAfterBreakRunHigh) and not na(bullIssAfterBreakRunLowBar) and close > bullIssAfterBreakRunHigh
array.push(bullIssBosBars, bullIssAfterBreakRunHighBar)
array.push(bullIssBosLvls, bullIssAfterBreakRunHigh)
if inpShowISSBOS
ln = line.new(bullIssAfterBreakRunHighBar, bullIssAfterBreakRunHigh, bar_index, bullIssAfterBreakRunHigh, xloc=xloc.bar_index, extend=extend.none, color=inpISSColor, style=line.style_solid, width=inpLineWidth)
f_pushLine(drawnLines, ln)
if inpShowISS and inpShowISSLabel
lb = label.new(bullIssBaseLowBar, bullIssBaseLow, "ISS", xloc=xloc.bar_index, style=label.style_none, textcolor=inpISSColor, size=size.normal)
f_pushLabel(drawnLabels, lb)
issOrTjlSinceChoch := true
if inpShowLevels and inpShowISS1
f_addLevelFromBarReady(levels, bullIss1Bar, bullIss1Bar, true, inpISSColor, "ISS 1", 29, bar_index, bar_index, bar_index)
if inpShowLevels and inpShowISS3
f_addLevelFromBarReady(levels, bullIssAfterBreakRunHighBar, bullIssAfterBreakRunHighBar, true, inpISSColor, "ISS 3", 30, bar_index, bar_index, bar_index)
if inpShowLevels and inpShowISS4
f_addLevelFromBarReady(levels, bullIssAfterBreakRunLowBar, bullIssAfterBreakRunLowBar, false, inpISSColor, "ISS 4", 31, bar_index, bar_index, bar_index)
// Promote the confirmed bullish ISS swing into the main structure.
// This makes the next CHOCH use the ISS internal pivots for QML.
trend := 1
phase := 1
lastCH := f_makeSnapAtBar(bullIssAfterBreakRunHighBar, bullIssAfterBreakRunHigh)
lastCL := f_makeSnapAtBar(bullIssAfterBreakRunLowBar, bullIssAfterBreakRunLow)
lastCHSet := true
lastCLSet := true
tjl1 := f_makeSnapAtBar(bullIssAfterBreakRunHighBar, bullIssAfterBreakRunHigh)
tjl2 := f_makeSnapAtBar(bullIssAfterBreakRunLowBar, bullIssAfterBreakRunLow)
tjl1Set := true
runHigh := f_makeSnapCurrent(high)
runLow := f_makeSnapCurrent(low)
issOrTjlSinceChoch := true
bullIssState := 0
bullIssBaseConfirmed := false
bullIssBaseLow := na
bullIssBaseLowBar := na
bullIssRunHigh := na
bullIssRunHighBar := na
bullIss1Level := na
bullIss1Bar := na
bullIssAfterBreakRunHigh := na
bullIssAfterBreakRunHighBar := na
bullIssAfterBreakRunLow := na
bullIssAfterBreakRunLowBar := na
array.clear(bullIssBosBars)
array.clear(bullIssBosLvls)
bullIssBos1Line := na
bearIssState := 0
bearIssBaseConfirmed := false
bearIssBaseHigh := na
bearIssBaseHighBar := na
bearIssRunLow := na
bearIssRunLowBar := na
bearIss1Level := na
bearIss1Bar := na
bearIssAfterBreakRunLow := na
bearIssAfterBreakRunLowBar := na
bearIssAfterBreakRunHigh := na
bearIssAfterBreakRunHighBar := na
array.clear(bearIssBosBars)
array.clear(bearIssBosLvls)
if bearIssInvalidated
if not na(bearIssBos1Line)
line.delete(bearIssBos1Line)
bearIssBos1Line := na
bearIssState := 0
bearIssBaseConfirmed := false
bearIssBaseHigh := na
bearIssBaseHighBar := na
bearIssRunLow := na
bearIssRunLowBar := na
bearIss1Level := na
bearIss1Bar := na
bearIssAfterBreakRunLow := na
bearIssAfterBreakRunLowBar := na
bearIssAfterBreakRunHigh := na
bearIssAfterBreakRunHighBar := na
array.clear(bearIssBosBars)
array.clear(bearIssBosLvls)
else if bearIssState == 1
if na(bearIssBaseHigh) or high > bearIssBaseHigh
bearIssBaseHigh := high
bearIssBaseHighBar := bar_index
bearIssRunLow := low
bearIssRunLowBar := bar_index
bearIssBaseConfirmed := false
if not bearIssBaseConfirmed
if bearishIssShift
bearIssBaseConfirmed := true
bearIssRunLow := low
bearIssRunLowBar := bar_index
else
if na(bearIssRunLow) or low < bearIssRunLow
bearIssRunLow := low
bearIssRunLowBar := bar_index
if bullishIssShift and not na(bearIssRunLowBar) and bearIssRunLowBar < bar_index
bearIss1Level := bearIssRunLow
bearIss1Bar := bearIssRunLowBar
bearIssState := 2
else if bearIssState == 2
if not na(bearIss1Level) and close < bearIss1Level
array.push(bearIssBosBars, bearIss1Bar)
array.push(bearIssBosLvls, bearIss1Level)
if inpShowISSBOS
bearIssBos1Line := line.new(bearIss1Bar, bearIss1Level, bar_index, bearIss1Level, xloc=xloc.bar_index, extend=extend.none, color=inpISSColor, style=line.style_solid, width=inpLineWidth)
f_pushLine(drawnLines, bearIssBos1Line)
bearIssAfterBreakRunLow := low
bearIssAfterBreakRunLowBar := bar_index
bearIssAfterBreakRunHigh := high
bearIssAfterBreakRunHighBar := bar_index
bearIssState := 3
else if bearIssState == 3
if na(bearIssAfterBreakRunLow) or low < bearIssAfterBreakRunLow
bearIssAfterBreakRunLow := low
bearIssAfterBreakRunLowBar := bar_index
bearIssAfterBreakRunHigh := high
bearIssAfterBreakRunHighBar := bar_index
else if na(bearIssAfterBreakRunHigh) or high > bearIssAfterBreakRunHigh
bearIssAfterBreakRunHigh := high
bearIssAfterBreakRunHighBar := bar_index
if bullishIssShift and not na(bearIssAfterBreakRunLowBar) and not na(bearIssAfterBreakRunHighBar)
bearIssState := 4
else if bearIssState == 4
if na(bearIssAfterBreakRunHigh) or high > bearIssAfterBreakRunHigh
bearIssAfterBreakRunHigh := high
bearIssAfterBreakRunHighBar := bar_index
if not na(bearIssAfterBreakRunLow) and not na(bearIssAfterBreakRunHighBar) and close < bearIssAfterBreakRunLow
array.push(bearIssBosBars, bearIssAfterBreakRunLowBar)
array.push(bearIssBosLvls, bearIssAfterBreakRunLow)
if inpShowISSBOS
ln = line.new(bearIssAfterBreakRunLowBar, bearIssAfterBreakRunLow, bar_index, bearIssAfterBreakRunLow, xloc=xloc.bar_index, extend=extend.none, color=inpISSColor, style=line.style_solid, width=inpLineWidth)
f_pushLine(drawnLines, ln)
if inpShowISS and inpShowISSLabel
lb = label.new(bearIssBaseHighBar, bearIssBaseHigh, "ISS", xloc=xloc.bar_index, style=label.style_none, textcolor=inpISSColor, size=size.normal)
f_pushLabel(drawnLabels, lb)
issOrTjlSinceChoch := true
if inpShowLevels and inpShowISS1
f_addLevelFromBarReady(levels, bearIss1Bar, bearIss1Bar, false, inpISSColor, "ISS 1", 29, bar_index, bar_index, bar_index)
if inpShowLevels and inpShowISS3
f_addLevelFromBarReady(levels, bearIssAfterBreakRunLowBar, bearIssAfterBreakRunLowBar, false, inpISSColor, "ISS 3", 32, bar_index, bar_index, bar_index)
if inpShowLevels and inpShowISS4
f_addLevelFromBarReady(levels, bearIssAfterBreakRunHighBar, bearIssAfterBreakRunHighBar, true, inpISSColor, "ISS 4", 33, bar_index, bar_index, bar_index)
// Promote the confirmed bearish ISS swing into the main structure.
// This makes the next CHOCH use the ISS internal pivots for QML.
trend := -1
phase := 1
lastCH := f_makeSnapAtBar(bearIssAfterBreakRunHighBar, bearIssAfterBreakRunHigh)
lastCL := f_makeSnapAtBar(bearIssAfterBreakRunLowBar, bearIssAfterBreakRunLow)
lastCHSet := true
lastCLSet := true
tjl1 := f_makeSnapAtBar(bearIssAfterBreakRunLowBar, bearIssAfterBreakRunLow)
tjl2 := f_makeSnapAtBar(bearIssAfterBreakRunHighBar, bearIssAfterBreakRunHigh)
tjl1Set := true
runHigh := f_makeSnapCurrent(high)
runLow := f_makeSnapCurrent(low)
issOrTjlSinceChoch := true
bearIssState := 0
bearIssBaseConfirmed := false
bearIssBaseHigh := na
bearIssBaseHighBar := na
bearIssRunLow := na
bearIssRunLowBar := na
bearIss1Level := na
bearIss1Bar := na
bearIssAfterBreakRunLow := na
bearIssAfterBreakRunLowBar := na
bearIssAfterBreakRunHigh := na
bearIssAfterBreakRunHighBar := na
array.clear(bearIssBosBars)
array.clear(bearIssBosLvls)
bearIssBos1Line := na
bullIssState := 0
bullIssBaseConfirmed := false
bullIssBaseLow := na
bullIssBaseLowBar := na
bullIssRunHigh := na
bullIssRunHighBar := na
bullIss1Level := na
bullIss1Bar := na
bullIssAfterBreakRunHigh := na
bullIssAfterBreakRunHighBar := na
bullIssAfterBreakRunLow := na
bullIssAfterBreakRunLowBar := na
array.clear(bullIssBosBars)
array.clear(bullIssBosLvls)
if inpShowFVG
bullFVGForm = low > high[2]
bearFVGForm = high < low[2]
if bullFVGForm
fvgTop = low
fvgBot = high[2]
if fvgTop > fvgBot
bx = box.new(bar_index - 2, fvgTop, bar_index, fvgBot, xloc=xloc.bar_index, border_color=inpBullFVGColor, bgcolor=inpBullFVGColor, text="FVG", text_color=color.white, text_size=size.tiny, text_halign=text.align_right, text_valign=text.align_center)
fv = FVGLevel.new(bar_index - 2, bar_index, fvgTop, fvgBot, true, true, false, bx)
array.push(fvgLevels, fv)
if bearFVGForm
fvgTop = low[2]
fvgBot = high
if fvgTop > fvgBot
bx = box.new(bar_index - 2, fvgTop, bar_index, fvgBot, xloc=xloc.bar_index, border_color=inpBearFVGColor, bgcolor=inpBearFVGColor, text="FVG", text_color=color.white, text_size=size.tiny, text_halign=text.align_right, text_valign=text.align_center)
fv = FVGLevel.new(bar_index - 2, bar_index, fvgTop, fvgBot, false, true, false, bx)
array.push(fvgLevels, fv)
f_trimLevels(levels)
if inpShowFVG and array.size(fvgLevels) > 0
kept = 0
for i = array.size(fvgLevels) - 1 to 0
fv = array.get(fvgLevels, i)
if fv.deleted
continue
kept += 1
if kept > inpMaxFVG
fv.deleted := true
fv.active := false
if not na(fv.bx)
box.delete(fv.bx)
array.set(fvgLevels, i, fv)
if inpShowOB and array.size(obLevels) > 0
kept = 0
for i = array.size(obLevels) - 1 to 0
ob = array.get(obLevels, i)
if ob.deleted
continue
kept += 1
if kept > inpMaxOB
ob.deleted := true
ob.active := false
if not na(ob.bx)
box.delete(ob.bx)
array.set(obLevels, i, ob)
drawn = 0
if array.size(levels) > 0
for j = array.size(levels) - 1 to 0
if drawn >= inpMaxLiveLevels
break
lv = array.get(levels, j)
if lv.deleted
continue
if not f_shouldShowLevel(lv.kind)
continue
if na(lv.bx)
lv.bx := box.new(lv.left, lv.top, lv.right, lv.bot, xloc=xloc.bar_index, border_color=lv.col, bgcolor=color.new(lv.col, 75), text=lv.txt, text_color=lv.col, text_size=size.small, text_halign=f_levelTextHAlign(), text_valign=f_levelTextVAlign())
else
box.set_lefttop(lv.bx, lv.left, lv.top)
box.set_rightbottom(lv.bx, lv.right, lv.bot)
box.set_border_color(lv.bx, lv.col)
box.set_bgcolor(lv.bx, color.new(lv.col, 75))
f_applyLevelText(lv.bx, lv.txt, lv.col)
if not na(lv.lb)
label.delete(lv.lb)
lv.lb := na
array.set(levels, j, lv)
drawn += 1
dashTrend1 = request.security(syminfo.tickerid, inpDashTf1, f_dashEmaTrendCalc(), lookahead=barmerge.lookahead_off)
dashTrend2 = request.security(syminfo.tickerid, inpDashTf2, f_dashEmaTrendCalc(), lookahead=barmerge.lookahead_off)
dashTrend3 = request.security(syminfo.tickerid, inpDashTf3, f_dashEmaTrendCalc(), lookahead=barmerge.lookahead_off)
dashTrend4 = request.security(syminfo.tickerid, inpDashTf4, f_dashEmaTrendCalc(), lookahead=barmerge.lookahead_off)
dashTrend5 = request.security(syminfo.tickerid, inpDashTf5, f_dashEmaTrendCalc(), lookahead=barmerge.lookahead_off)
dashTrend6 = request.security(syminfo.tickerid, inpDashTf6, f_dashEmaTrendCalc(), lookahead=barmerge.lookahead_off)
dashTrend7 = request.security(syminfo.tickerid, inpDashTf7, f_dashEmaTrendCalc(), lookahead=barmerge.lookahead_off)
dashTrend8 = request.security(syminfo.tickerid, inpDashTf8, f_dashEmaTrendCalc(), lookahead=barmerge.lookahead_off)
dashTrend9 = request.security(syminfo.tickerid, inpDashTf9, f_dashEmaTrendCalc(), lookahead=barmerge.lookahead_off)
dashTrend10 = request.security(syminfo.tickerid, inpDashTf10, f_dashEmaTrendCalc(), lookahead=barmerge.lookahead_off)
dashTrend11 = request.security(syminfo.tickerid, inpDashTf11, f_dashEmaTrendCalc(), lookahead=barmerge.lookahead_off)
dashTrend12 = request.security(syminfo.tickerid, inpDashTf12, f_dashEmaTrendCalc(), lookahead=barmerge.lookahead_off)
dashTrend13 = request.security(syminfo.tickerid, inpDashTf13, f_dashEmaTrendCalc(), lookahead=barmerge.lookahead_off)
if barstate.islast
table.clear(tfDashboard, 0, 0, 1, 13)
if inpShowTrendDash
headerBg = color.rgb(30, 30, 30)
tfCellBg = color.rgb(18, 18, 18)
table.cell(tfDashboard, 0, 0, "TIMEFRAME", text_color=color.white, bgcolor=headerBg, text_size=size.small)
table.cell(tfDashboard, 1, 0, "TREND", text_color=color.white, bgcolor=headerBg, text_size=size.small)
dashRow = 1
if inpDashShowTf1
table.cell(tfDashboard, 0, dashRow, f_dashTfLabel(inpDashTf1), text_color=color.white, bgcolor=tfCellBg, text_size=size.small)
table.cell(tfDashboard, 1, dashRow, f_dashTrendText(dashTrend1), text_color=color.white, bgcolor=f_dashTrendColor(dashTrend1), text_size=size.small)
dashRow += 1
if inpDashShowTf2
table.cell(tfDashboard, 0, dashRow, f_dashTfLabel(inpDashTf2), text_color=color.white, bgcolor=tfCellBg, text_size=size.small)
table.cell(tfDashboard, 1, dashRow, f_dashTrendText(dashTrend2), text_color=color.white, bgcolor=f_dashTrendColor(dashTrend2), text_size=size.small)
dashRow += 1
if inpDashShowTf3
table.cell(tfDashboard, 0, dashRow, f_dashTfLabel(inpDashTf3), text_color=color.white, bgcolor=tfCellBg, text_size=size.small)
table.cell(tfDashboard, 1, dashRow, f_dashTrendText(dashTrend3), text_color=color.white, bgcolor=f_dashTrendColor(dashTrend3), text_size=size.small)
dashRow += 1
if inpDashShowTf4
table.cell(tfDashboard, 0, dashRow, f_dashTfLabel(inpDashTf4), text_color=color.white, bgcolor=tfCellBg, text_size=size.small)
table.cell(tfDashboard, 1, dashRow, f_dashTrendText(dashTrend4), text_color=color.white, bgcolor=f_dashTrendColor(dashTrend4), text_size=size.small)
dashRow += 1
if inpDashShowTf5
table.cell(tfDashboard, 0, dashRow, f_dashTfLabel(inpDashTf5), text_color=color.white, bgcolor=tfCellBg, text_size=size.small)
table.cell(tfDashboard, 1, dashRow, f_dashTrendText(dashTrend5), text_color=color.white, bgcolor=f_dashTrendColor(dashTrend5), text_size=size.small)
dashRow += 1
if inpDashShowTf6
table.cell(tfDashboard, 0, dashRow, f_dashTfLabel(inpDashTf6), text_color=color.white, bgcolor=tfCellBg, text_size=size.small)
table.cell(tfDashboard, 1, dashRow, f_dashTrendText(dashTrend6), text_color=color.white, bgcolor=f_dashTrendColor(dashTrend6), text_size=size.small)
dashRow += 1
if inpDashShowTf7
table.cell(tfDashboard, 0, dashRow, f_dashTfLabel(inpDashTf7), text_color=color.white, bgcolor=tfCellBg, text_size=size.small)
table.cell(tfDashboard, 1, dashRow, f_dashTrendText(dashTrend7), text_color=color.white, bgcolor=f_dashTrendColor(dashTrend7), text_size=size.small)
dashRow += 1
if inpDashShowTf8
table.cell(tfDashboard, 0, dashRow, f_dashTfLabel(inpDashTf8), text_color=color.white, bgcolor=tfCellBg, text_size=size.small)
table.cell(tfDashboard, 1, dashRow, f_dashTrendText(dashTrend8), text_color=color.white, bgcolor=f_dashTrendColor(dashTrend8), text_size=size.small)
dashRow += 1
if inpDashShowTf9
table.cell(tfDashboard, 0, dashRow, f_dashTfLabel(inpDashTf9), text_color=color.white, bgcolor=tfCellBg, text_size=size.small)
table.cell(tfDashboard, 1, dashRow, f_dashTrendText(dashTrend9), text_color=color.white, bgcolor=f_dashTrendColor(dashTrend9), text_size=size.small)
dashRow += 1
if inpDashShowTf10
table.cell(tfDashboard, 0, dashRow, f_dashTfLabel(inpDashTf10), text_color=color.white, bgcolor=tfCellBg, text_size=size.small)
table.cell(tfDashboard, 1, dashRow, f_dashTrendText(dashTrend10), text_color=color.white, bgcolor=f_dashTrendColor(dashTrend10), text_size=size.small)
dashRow += 1
if inpDashShowTf11
table.cell(tfDashboard, 0, dashRow, f_dashTfLabel(inpDashTf11), text_color=color.white, bgcolor=tfCellBg, text_size=size.small)
table.cell(tfDashboard, 1, dashRow, f_dashTrendText(dashTrend11), text_color=color.white, bgcolor=f_dashTrendColor(dashTrend11), text_size=size.small)
dashRow += 1
if inpDashShowTf12
table.cell(tfDashboard, 0, dashRow, f_dashTfLabel(inpDashTf12), text_color=color.white, bgcolor=tfCellBg, text_size=size.small)
table.cell(tfDashboard, 1, dashRow, f_dashTrendText(dashTrend12), text_color=color.white, bgcolor=f_dashTrendColor(dashTrend12), text_size=size.small)
dashRow += 1
if inpDashShowTf13
table.cell(tfDashboard, 0, dashRow, f_dashTfLabel(inpDashTf13), text_color=color.white, bgcolor=tfCellBg, text_size=size.small)
table.cell(tfDashboard, 1, dashRow, f_dashTrendText(dashTrend13), text_color=color.white, bgcolor=f_dashTrendColor(dashTrend13), text_size=size.small)
// FIX 7: table.clear end row updated from 15 → 18 to match the expanded table (19 rows, 0-indexed 0–18).
table.clear(levelAnalyzerTable, 0, 0, 1, 13)
if inpShowLevelAnalyzer
anaHeaderBg = color.rgb(30, 30, 30)
anaCellBg = color.rgb(18, 18, 18)
anaBestBg = color.rgb(0, 100, 0)
bestSlot = f_bestAnalyzerSlot(levelAnalyzerWins, levelAnalyzerLosses)
table.cell(levelAnalyzerTable, 0, 0, "LEVEL", text_color=color.white, bgcolor=anaHeaderBg, text_size=size.small)
table.cell(levelAnalyzerTable, 1, 0, "TESTS", text_color=color.white, bgcolor=anaHeaderBg, text_size=size.small)
table.cell(levelAnalyzerTable, 2, 0, "WINS", text_color=color.white, bgcolor=anaHeaderBg, text_size=size.small)
table.cell(levelAnalyzerTable, 3, 0, "LOSS", text_color=color.white, bgcolor=anaHeaderBg, text_size=size.small)
table.cell(levelAnalyzerTable, 4, 0, "ACC", text_color=color.white, bgcolor=anaHeaderBg, text_size=size.small)
anaRow = 1
// FIX 8: Loop extended from 14 → 16 so all 17 slots (0–16) are rendered in the table.
for anaSlot = 0 to 16
if f_analyzerShowSlot(anaSlot)
tests = array.get(levelAnalyzerTests, anaSlot)
wins = array.get(levelAnalyzerWins, anaSlot)
losses = array.get(levelAnalyzerLosses, anaSlot)
rowBg = anaSlot == bestSlot ? anaBestBg : anaCellBg
table.cell(levelAnalyzerTable, 0, anaRow, f_analyzerLabel(anaSlot), text_color=color.white, bgcolor=rowBg, text_size=size.small)
table.cell(levelAnalyzerTable, 1, anaRow, str.tostring(tests), text_color=color.white, bgcolor=rowBg, text_size=size.small)
table.cell(levelAnalyzerTable, 2, anaRow, str.tostring(wins), text_color=color.white, bgcolor=rowBg, text_size=size.small)
table.cell(levelAnalyzerTable, 3, anaRow, str.tostring(losses), text_color=color.white, bgcolor=rowBg, text_size=size.small)
table.cell(levelAnalyzerTable, 4, anaRow, f_analyzerRateText(wins, losses), text_color=color.white, bgcolor=rowBg, text_size=size.small)
anaRow += 1