Every swing high leaves a cluster of buy stops just above it, and every swing low a cluster of sell stops just below it. Traders call these clusters liquidity pools: levels that price is often drawn to, and that tend to produce a reaction once they are taken. Most liquidity tools mark them with a line or a box. Liquidity Contour Map by AlgoNorth draws them as a topographic map.
Each pool becomes a zone centred on its price, shaped like a stadium with a rounded nose at the swing candle, and filled with up to 14 contour rings. The height of the zone, and the colour of its inner rings, show how much liquidity the pool is likely to hold: heavy swing volume, repeated touches (equal highs and equal lows) and age make a zone taller. Pools that price has already crossed stay on the map, lower and in grey. On top of that, every live pool gets a tag with the share of comparable pools that price actually reached within the next 48 bars in the recent past.
Pools. A swing high is a bar whose high is the highest of the 5 bars on each side (the later of two equal highs counts as the swing); a swing low, the same with the lows. It is confirmed 5 bars later, and from then on it is a live pool. A new swing within 0.25 ATR(100) of a live pool on the same side merges into the nearest one instead of starting its own: the pool keeps its first price and candle and counts one more touch (EQH, EQL).
Score. Each pool gets a unitless score:
Score = volume x touches x age, from 0 to 6.25. When price crosses the pool (a high above a swing high, a low below a swing low, gaps included) the pool is swept: its score freezes at the value of the sweep bar and is multiplied by 0.35.
Zones and contours. Each pool is drawn from its swing candle (or the left edge of the 150-bar map) to 8 bars past the last closed bar; a swept pool ends 8 bars after its sweep, with a second rounded nose. Its maximum half-height is 9% of the price range of the map, scaled down for short zones. Zones that share bars are trimmed to half the distance between them, so they never touch; when two pools that share bars are closer than half of that maximum half-height, only the taller one is drawn. The contour levels are spread evenly from 5% to 90% of the tallest zone inside the map’s high-low range: a zone shows as many rings as its score reaches, and each ring is narrower and shorter than the one outside it, like the contour lines of a hill. The colours follow the same scale, from pale teal on the outer ring to deep amber at the top.
Crossing statistics. Every live pool is watched in back-to-back windows of 48 bars. A window opens only while the pool is within the relevance band (3 ATR beyond the map’s high and low), less than 8 ATR from the close and young enough to finish before 1,000 bars of age. It is filed by side (highs or lows) and by the pool’s distance from the close in ATR when it opened: under 0.5, 0.5 to 1, 1 to 2, 2 to 3, 3 to 5 and 5 to 8. It counts as crossed if price went through the pool before the window ended. Only the windows that ended in the last 3,000 bars are counted, and a band needs 30 windows before it shows a rate. The rate is a past frequency for that distance band, not a forecast for one particular level: one pool opens many windows, and a pool changes band when price moves.
Pools
Score
Map
Look
Callouts and statistics
Style
The map is built from the last closed bar, so it changes only when a bar closes. The indicator needs at least 150 bars (the map width) and 100 bars for the ATR before it draws anything; until then the panel says WARMING UP. The crossing rates need a few thousand bars of history to be meaningful.
//---------------------------------------------------------------
//PRC_Liquidity Contour Map
//version = 0
//22.10.2026
//Iván González @ www.prorealcode.com
//Author: AlgoNorth
//Sharing ProRealTime knowledge
//--------------------------------------------------------------------//
// Original work: "Liquidity Contour Map [AlgoNorth]" by AlgoNorth, licensed under CC BY-NC-SA 4.0
// (https://creativecommons.org/licenses/by-nc-sa/4.0/). This code is shared under the same licence.
defparam drawonlastbaronly = true
// ===================== POOLS =====================
pivLen = 5 // swing length: bars on each side that confirm a swing high / low (2 to 30)
eqTol = 0.25 // equal high / low tolerance in ATR: a new swing this close to a live pool on its side merges into it (0 to 2)
maxPools = 60 // pools held in memory (10 to 120)
relBand = 3.0 // relevance band: pools further than this many ATR beyond the map's high / low are ignored (0 to 10)
// ===================== SCORE =====================
riseLen = 14 // bars from the swing candle to full height (2 to 200)
erode = 0.35 // height multiplier once price has crossed the pool (0 = swept zones hidden)
sweptGrey = 1 // 1 = swept zones in grey
capLen = 8 // bars a swept zone runs on past the sweep (1 to 60)
useVol = 1 // 1 = scale each pool by its swing candle's volume against the 50 bars before it (0.5x to 2.5x)
// ===================== MAP =====================
mapW = 150 // map width in bars (50 to 480)
hPct = 9.0 // max zone half-height, % of the map's price range (2 to 30)
gapK = 0.5 // min gap between zones, in half-heights (0.25 to 3)
nLevels = 14 // contour levels, max (4 to 14)
lowPct = 5.0 // lowest contour, % of the tallest zone (1 to 40)
topPct = 90.0 // top contour, % of the tallest zone (50 to 99)
extR = 8 // zones run up to this many bars past the last closed candle (0 to 50)
roundK = 1.0 // nose roundness (0.3 to 3)
// ===================== LOOK =====================
look3D = 0 // 0 = flat contours, 1 = 3D contours (lit ring edges and slope shadows)
edgeOn = 1 // 3D: lit ring edges
edgeW = 0.35 // 3D: edge width, share of the gap between rings (0.05 to 1)
shadeOn = 1 // 3D: slope shading
shadeK = 1.0 // 3D: shading strength (0.05 to 1.5)
groundOn = 1 // 3D: soft shadow under the lowest ring
// ===================== CALLOUTS =====================
showCall = 1 // 1 = tag the tallest zones
nCall = 6 // max callouts (1 to 12)
tagSize = 2 // tag text size: 1 = small, 2 = normal, 3 = large
// ===================== HISTORY STATS =====================
horizon = 48 // each live pool is watched in back-to-back windows of this many bars (5 to 500)
winW = 3000 // only windows that ended within this many bars are counted (500 to 10000)
retireN = 1000 // a pool opens no window that would end past this age, in bars (100 to 4400)
minN = 30 // windows a band needs before it shows a rate (10 to 500)
// ===================== STYLE =====================
fillT = 40 // contour transparency in % (0 = solid colours, up to 60): 40 keeps the candles visible through the map
showLeg = 1 // 1 = score legend (middle right)
showPanel = 1 // 1 = stats panel (top right)
txtSize = 2 // panel text size: 1 = tiny, 2 = small, 3 = normal
darkChart = 0 // 0 = palette for a light chart background, 1 = for a dark one
polyCap = 100 // shape budget: at most this many filled shapes per map, one per tag stem first. It sets how many contours fit; raise it to draw them all
// ===================== SETTINGS CHECK =====================
pLen = max(2, min(30, round(pivLen)))
eqT = max(0, min(2, eqTol))
mxP = max(10, min(120, round(maxPools)))
rBand = max(0, min(10, relBand))
rise = max(2, min(200, round(riseLen)))
ero = max(0, min(1, erode))
capB = max(1, min(60, round(capLen)))
mW = max(50, min(480, round(mapW)))
hP = max(2, min(30, hPct))
gK = max(0.25, min(3, gapK))
nLev = max(4, min(14, round(nLevels)))
loP = max(1, min(40, lowPct))
topP = max(50, min(99, topPct))
eR = max(0, min(50, round(extR)))
rndK = max(0.3, min(3, roundK))
eW = max(0.05, min(1, edgeW))
shK = max(0.05, min(1.5, shadeK))
nCl = max(1, min(12, round(nCall)))
hor = max(5, min(500, round(horizon)))
wW = max(500, min(10000, round(winW)))
retN = max(100, min(4400, round(retireN)))
mnN = max(10, min(500, round(minN)))
fT = max(0, min(60, round(fillT)))
pCap = max(1, round(polyCap))
// A pool is at least pLen bars old, so a longer horizon could never open a window
hzOK = 0
IF hor <= retN - pLen THEN
hzOK = 1
ENDIF
// Flat look: rings share one nose centre, like contour lines. 3D: each inner nose sits further back
IF look3D = 1 THEN
stagK = 1.5
ELSE
stagK = 1
ENDIF
// Nose length of a full-width ring, in bars
noseR0 = rndK * hP / 100 * mW * 1.2
// ===================== SERIES =====================
// True range and ATR(100): Wilder's average seeded with a simple average
IF barindex = 0 THEN
trv = high - low
ELSE
trv = max(high - low, max(abs(high - close[1]), abs(low - close[1])))
ENDIF
IF barindex = 99 THEN
atrv = summation[100](trv) / 100
ELSIF barindex > 99 THEN
atrv = 0.01 * trv + 0.99 * atrv[1]
ELSE
atrv = 0
ENDIF
volMA = average[50](volume)
winLo = lowest[mW](low)
winHi = highest[mW](high)
// ===================== POOL TRACKING (closed bars only) =====================
// All the state lives in arrays and each closed bar is processed exactly once: historical
// bars on themselves, and the bar that has just closed on the first tick of the next one.
// Arrays are NOT rewound between ticks the way scalars are, so nothing here may run twice.
IF barindex = 0 THEN
$gS[0] = 0 - 1 // last bar processed
$gS[1] = 0 // pools held
$gS[2] = 0 // oldest window of the rolling sample (ring buffer)
$gS[3] = 0 // windows held in the rolling sample
$gS[4] = 0 // open windows of dropped pools
FOR c = 0 TO 11 DO
$rN[c] = 0 // windows per cell: highs 0-5, lows 6-11 (one cell per ATR band)
$rH[c] = 0 // of those, crossed
NEXT
ENDIF
FOR pss = 1 DOWNTO 0 DO
ofs = pss
doIt = 0
// the previous bar was the live one and has just closed
IF ofs = 1 AND barindex >= 1 AND $gS[0] < barindex - 1 THEN
doIt = 1
ENDIF
// a historical bar is already closed
IF ofs = 0 AND NOT islastbarupdate AND $gS[0] < barindex THEN
doIt = 1
ENDIF
IF doIt = 1 THEN
bb = barindex - ofs
$gS[0] = bb
nP = $gS[1]
nO = $gS[4]
nF = 0
x0b = max(0, bb - mW + 1)
atrOKb = bb >= 99
bandOKb = 0
IF atrOKb AND bb >= mW - 1 THEN
bandOKb = 1
ENDIF
atrE = atrv[ofs]
bLoE = winLo[ofs] - rBand * atrE
bHiE = winHi[ofs] + rBand * atrE
hiE = high[ofs]
loE = low[ofs]
clE = close[ofs]
// 1. Forget swept pools whose zone has left the map, and pools older than 4,900 bars
IF nP > 0 THEN
FOR i = nP - 1 DOWNTO 0 DO
dropIt = 0
IF $pTk[i] >= 0 THEN
IF $pTk[i] + capB < x0b THEN
dropIt = 1
ENDIF
ENDIF
IF bb - $pSt[i] > 4900 THEN
dropIt = 1
ENDIF
IF dropIt = 1 THEN
IF i < nP - 1 THEN
FOR k = i TO nP - 2 DO
$pPx[k] = $pPx[k + 1]
$pSt[k] = $pSt[k + 1]
$pSd[k] = $pSd[k + 1]
$pTo[k] = $pTo[k + 1]
$pVo[k] = $pVo[k + 1]
$pTk[k] = $pTk[k + 1]
$pWs[k] = $pWs[k + 1]
$pWc[k] = $pWc[k + 1]
NEXT
ENDIF
nP = nP - 1
ENDIF
NEXT
ENDIF
// 2. New swings, confirmed pLen bars after the swing candle. The swing candle may tie
// the bars before it, not the ones after it (the later of two equal highs is the swing)
co = ofs + pLen
isPH = 0
isPL = 0
cH = 0
cL = 0
IF bb >= 2 * pLen THEN
cH = high[co]
cL = low[co]
isPH = 1
isPL = 1
FOR k = 1 TO pLen DO
IF high[co + k] > cH OR high[co - k] >= cH THEN
isPH = 0
ENDIF
IF low[co + k] < cL OR low[co - k] <= cL THEN
isPL = 0
ENDIF
NEXT
ENDIF
// Swing candle volume against the average of the 50 bars before it, clamped to 0.5-2.5
vFa = 1
IF useVol = 1 AND bb >= pLen + 50 THEN
vMa = volMA[co + 1]
IF vMa > 0 THEN
vFa = max(0.5, min(2.5, volume[co] / vMa))
ENDIF
ENDIF
FOR q = 0 TO 1 DO
addIt = 0
aPx = 0
aSd = 0
IF q = 0 AND isPH = 1 THEN
addIt = 1
aPx = cH
aSd = 1
ENDIF
IF q = 1 AND isPL = 1 THEN
addIt = 1
aPx = cL
aSd = -1
ENDIF
IF addIt = 1 THEN
// An equal high / low merges into the nearest live pool on its side within the tolerance
best = -1
bd = 0
IF atrOKb AND nP > 0 THEN
tolB = eqT * atrE
FOR i = 0 TO nP - 1 DO
IF $pTk[i] < 0 AND $pSd[i] = aSd THEN
dd = abs($pPx[i] - aPx)
IF dd <= tolB THEN
IF best < 0 OR dd < bd THEN
best = i
bd = dd
ENDIF
ENDIF
ENDIF
NEXT
ENDIF
IF best >= 0 THEN
$pTo[best] = $pTo[best] + 1
IF vFa > $pVo[best] THEN
$pVo[best] = vFa
ENDIF
ELSE
$pPx[nP] = aPx
$pSt[nP] = bb - pLen
$pSd[nP] = aSd
$pTo[nP] = 1
$pVo[nP] = vFa
$pTk[nP] = -1 // bar price crossed it, -1 while live
$pWs[nP] = -1 // bar its open stats window started, -1 when none is open
$pWc[nP] = 0 // stats cell of that window
nP = nP + 1
// List full: drop the live pool furthest beyond the relevance band, else the oldest
// live pool, else the oldest swept one. The pool just added is never dropped
IF nP > mxP THEN
iOut = -1
dOut = 0
iOld = -1
iSw = -1
FOR i = 0 TO nP - 2 DO
IF $pTk[i] < 0 THEN
IF bandOKb = 1 THEN
dB = max($pPx[i] - bHiE, bLoE - $pPx[i])
IF dB > dOut THEN
iOut = i
dOut = dB
ENDIF
ENDIF
IF iOld < 0 THEN
iOld = i
ELSIF $pSt[i] < $pSt[iOld] THEN
iOld = i
ENDIF
ELSE
IF iSw < 0 THEN
iSw = i
ELSIF $pTk[i] < $pTk[iSw] THEN
iSw = i
ENDIF
ENDIF
NEXT
IF iOut >= 0 THEN
iRem = iOut
ELSIF iOld >= 0 THEN
iRem = iOld
ELSE
iRem = iSw
ENDIF
// A dropped pool's open window still runs to its end and is counted
IF $pWs[iRem] >= 0 THEN
$oPx[nO] = $pPx[iRem]
$oSd[nO] = $pSd[iRem]
$oSt[nO] = $pWs[iRem]
$oCe[nO] = $pWc[iRem]
nO = nO + 1
ENDIF
FOR k = iRem TO nP - 2 DO
$pPx[k] = $pPx[k + 1]
$pSt[k] = $pSt[k + 1]
$pSd[k] = $pSd[k + 1]
$pTo[k] = $pTo[k + 1]
$pVo[k] = $pVo[k + 1]
$pTk[k] = $pTk[k + 1]
$pWs[k] = $pWs[k + 1]
$pWc[k] = $pWc[k + 1]
NEXT
nP = nP - 1
ENDIF
ENDIF
ENDIF
NEXT
// 3. Sweeps, and the windows behind the history stats. A live pool is watched in
// back-to-back windows of hor bars, each filed by side and by its ATR band when it opened.
// Finished windows are queued in $fCe / $fHt and filed below, in the same order.
IF nP > 0 THEN
FOR i = 0 TO nP - 1 DO
IF $pTk[i] < 0 THEN
pxI = $pPx[i]
hitI = 0
IF $pSd[i] = 1 AND hiE > pxI THEN
hitI = 1
ENDIF
IF $pSd[i] = -1 AND loE < pxI THEN
hitI = 1
ENDIF
IF hitI = 1 THEN
$pTk[i] = bb
IF $pWs[i] >= 0 THEN
$fCe[nF] = $pWc[i]
$fHt[nF] = 1
nF = nF + 1
$pWs[i] = -1
ENDIF
ELSE
IF $pWs[i] >= 0 THEN
IF bb - $pWs[i] >= hor THEN
$fCe[nF] = $pWc[i]
$fHt[nF] = 0
nF = nF + 1
$pWs[i] = -1
ENDIF
ENDIF
// A window opens only inside the relevance band, within 8 ATR, and young enough
// to finish before the retire age
IF $pWs[i] < 0 AND bandOKb = 1 AND atrE > 0 THEN
IF bb - $pSt[i] + hor <= retN AND pxI >= bLoE AND pxI <= bHiE THEN
dA = abs(pxI - clE) / atrE
bk = -1
IF dA < 0.5 THEN
bk = 0
ELSIF dA < 1 THEN
bk = 1
ELSIF dA < 2 THEN
bk = 2
ELSIF dA < 3 THEN
bk = 3
ELSIF dA < 5 THEN
bk = 4
ELSIF dA < 8 THEN
bk = 5
ENDIF
IF bk >= 0 THEN
$pWs[i] = bb
IF $pSd[i] = 1 THEN
$pWc[i] = bk
ELSE
$pWc[i] = bk + 6
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
NEXT
ENDIF
// Windows handed over by dropped pools: same crossing rule, same end
IF nO > 0 THEN
FOR i = nO - 1 DOWNTO 0 DO
hitO = 0
IF $oSd[i] = 1 AND hiE > $oPx[i] THEN
hitO = 1
ENDIF
IF $oSd[i] = -1 AND loE < $oPx[i] THEN
hitO = 1
ENDIF
IF hitO = 1 OR bb - $oSt[i] >= hor THEN
$fCe[nF] = $oCe[i]
$fHt[nF] = hitO
nF = nF + 1
IF i < nO - 1 THEN
FOR k = i TO nO - 2 DO
$oPx[k] = $oPx[k + 1]
$oSd[k] = $oSd[k + 1]
$oSt[k] = $oSt[k + 1]
$oCe[k] = $oCe[k + 1]
NEXT
ENDIF
nO = nO - 1
ENDIF
NEXT
ENDIF
// File the finished windows into the rolling sample (at most 50,000 held)
IF nF > 0 THEN
FOR fi = 0 TO nF - 1 DO
IF $gS[3] = 50000 THEN
h0 = $gS[2]
cq = $qCe[h0]
IF cq >= 12 THEN
cq = cq - 12
$rH[cq] = $rH[cq] - 1
ENDIF
$rN[cq] = $rN[cq] - 1
$gS[2] = (h0 + 1) MOD 50000
$gS[3] = $gS[3] - 1
ENDIF
ce = $fCe[fi]
$rN[ce] = $rN[ce] + 1
IF $fHt[fi] = 1 THEN
$rH[ce] = $rH[ce] + 1
ENDIF
iq = ($gS[2] + $gS[3]) MOD 50000
$qBar[iq] = bb
$qCe[iq] = ce + 12 * $fHt[fi]
$gS[3] = $gS[3] + 1
NEXT
ENDIF
// Keep only the windows that ended within the last wW bars
popOn = 1
WHILE popOn = 1 DO
popOn = 0
IF $gS[3] > 0 THEN
h0 = $gS[2]
IF $qBar[h0] <= bb - wW THEN
popOn = 1
cq = $qCe[h0]
IF cq >= 12 THEN
cq = cq - 12
$rH[cq] = $rH[cq] - 1
ENDIF
$rN[cq] = $rN[cq] - 1
$gS[2] = (h0 + 1) MOD 50000
$gS[3] = $gS[3] - 1
ENDIF
ENDIF
WEND
$gS[1] = nP
$gS[4] = nO
ENDIF
NEXT
// ===================== MAP BUILD (from the last closed bar) =====================
IF islastbarupdate AND $gS[0] >= 0 THEN
// Palettes, packed as r * 65536 + g * 256 + b: contour ramp, 3D lit edges and greys of swept zones
IF darkChart = 1 THEN
$rmp[0] = 730416 // #0B2530
$rmp[1] = 930880 // #0E3440
$rmp[2] = 1131596 // #11444C
$rmp[3] = 1332563 // #145553
$rmp[4] = 1533526 // #176656
$rmp[5] = 2062935 // #1F7A57
$rmp[6] = 3051093 // #2E8E55
$rmp[7] = 4891474 // #4AA352
$rmp[8] = 7583308 // #73B64C
$rmp[9] = 10732615 // #A3C447
$rmp[10] = 13617989 // #CFCB45
$rmp[11] = 15780159 // #F0C93F
$rmp[12] = 16767334 // #FFD966
$rmp[13] = 16773570 // #FFF1C2
$edg[0] = 2774374 // #2A5566
$edg[1] = 3105651 // #2F6373
$edg[2] = 3502973 // #35737D
$edg[3] = 3966594 // #3C8682
$edg[4] = 4561540 // #459A84
$edg[5] = 5549957 // #54AF85
$edg[6] = 6865797 // #68C385
$edg[7] = 9098628 // #8AD584
$edg[8] = 11723391 // #B2E27F
$edg[9] = 14281599 // #D9EB7F
$edg[10] = 16117643 // #F5EF8B
$edg[11] = 16771476 // #FFE994
$edg[12] = 16773565 // #FFF1BD
$edg[13] = 16776695 // #FFFDF7
$gry[0] = 1974566 // #1E2126
$gry[1] = 2632753 // #282C31
$gry[2] = 3356220 // #33363C
$gry[3] = 4014406 // #3D4146
$gry[4] = 4672337 // #474B51
$gry[5] = 5396060 // #52565C
$gry[6] = 6053991 // #5C6067
$gry[7] = 6712177 // #666B71
$gry[8] = 7370108 // #70757C
$gry[9] = 8093831 // #7B8087
$gry[10] = 8751762 // #858A92
$gry[11] = 9409948 // #8F959C
$gry[12] = 10133415 // #9A9FA7
$gry[13] = 10791602 // #A4AAB2
txR = 215
txG = 220
txB = 228
dmR = 142
dmG = 151
dmB = 166
bgR = 10
bgG = 13
bgB = 19
bgA = 235
acR = 255
acG = 197
acB = 61
hbR = 255
hbG = 241
hbB = 194
htR = 18
htG = 12
htB = 0
ELSE
$rmp[0] = 14873071 // #E2F1EF
$rmp[1] = 12903904 // #C4E5E0
$rmp[2] = 10934737 // #A6D9D1
$rmp[3] = 8570813 // #82C7BD
$rmp[4] = 6141353 // #5DB5A9
$rmp[5] = 4630162 // #46A692
$rmp[6] = 3118715 // #2F967B
$rmp[7] = 4102741 // #3E9A55
$rmp[8] = 6202440 // #5EA448
$rmp[9] = 8367676 // #7FAE3C
$rmp[10] = 10531379 // #A0B233
$rmp[11] = 12760362 // #C2B52A
$rmp[12] = 14786068 // #E19E14
$rmp[13] = 12152842 // #B9700A
$edg[0] = 15726582 // #EFF7F6
$edg[1] = 14676462 // #DFF1EE
$edg[2] = 13560550 // #CEEAE6
$edg[3] = 12247259 // #BAE0DB
$edg[4] = 10933968 // #A6D6D0
$edg[5] = 10079939 // #99CEC3
$edg[6] = 9291190 // #8DC5B6
$edg[7] = 9815970 // #95C7A2
$edg[8] = 10931610 // #A6CD9A
$edg[9] = 12178068 // #B9D294
$edg[10] = 13358479 // #CBD58F
$edg[11] = 14538378 // #DDD68A
$edg[12] = 15649406 // #EECA7E
$edg[13] = 14200952 // #D8B078
$gry[0] = 12830926 // #C3C8CE
$gry[1] = 12107204 // #B8BDC4
$gry[2] = 11449273 // #AEB3B9
$gry[3] = 10725551 // #A3A8AF
$gry[4] = 10067620 // #999EA4
$gry[5] = 9343898 // #8E939A
$gry[6] = 8685967 // #84898F
$gry[7] = 7962245 // #797E85
$gry[8] = 7304314 // #6F747A
$gry[9] = 6580592 // #646970
$gry[10] = 5922661 // #5A5F65
$gry[11] = 5198939 // #4F545B
$gry[12] = 4541008 // #454A50
$gry[13] = 3817286 // #3A3F46
txR = 26
txG = 31
txB = 41
dmR = 90
dmG = 98
dmB = 112
bgR = 255
bgG = 255
bgB = 255
bgA = 242
acR = 122
acG = 79
acB = 0
hbR = 122
hbG = 79
hbB = 0
htR = 255
htG = 241
htB = 194
ENDIF
aFill = round(255 * (100 - fT) / 100)
bC = $gS[0]
oB = barindex - bC
clC = close[oB]
atrC = atrv[oB]
atrOK = bC >= 99
winOK = bC >= mW - 1
wLo = winLo[oB]
wHi = winHi[oB]
bandOK = 0
IF atrOK AND winOK THEN
bandOK = 1
ENDIF
bLoC = wLo - rBand * atrC
bHiC = wHi + rBand * atrC
x0 = max(0, bC - mW + 1) // map's left edge
xEnd = bC + eR // zones run to here (swept ones end earlier)
rng = wHi - wLo
sg = hP / 100 * rng // max zone half-height
dG = (topP - loP) / 100 / (nLev - 1) // contour spacing, share of the peak
nP = $gS[1]
IF look3D = 1 THEN
nLay0 = groundOn + edgeOn + 1
nCol = edgeOn + 1
ELSE
nLay0 = 1
nCol = 1
ENDIF
// Pools in view: everything inside the relevance band
nV = 0
nSwept = 0
IF bandOK = 1 AND nP > 0 THEN
FOR i = 0 TO nP - 1 DO
IF $pPx[i] >= bLoC AND $pPx[i] <= bHiC THEN
$vP[nV] = i
nV = nV + 1
IF $pTk[i] >= 0 THEN
nSwept = nSwept + 1
ENDIF
ENDIF
NEXT
ENDIF
// Each pool is its own zone. Pools claim their space in order of pre-sweep height; a pool is
// hidden only when it sits within the min zone gap of a taller one sharing bars, its peak is
// below the lowest contour, or its outer ring has too few bars for a smooth outline
nZ = 0
nZS = 0
fTop = 0
IF winOK AND sg > 0 AND nV > 0 THEN
pkAll = 0
pkMap = 0
FOR v = 0 TO nV - 1 DO
i = $vP[v]
zs = max($pSt[i], x0)
IF $pTk[i] < 0 THEN
ze = xEnd
xq = bC
ELSE
ze = min(xEnd, $pTk[i] + capB)
xq = $pTk[i]
ENDIF
// Age envelope: a straight build-up from the swing candle that bends into full height
// at rise bars (a live pool peaks now, a swept one keeps the height of its sweep bar)
uu = 1.25 * (xq - $pSt[i]) / rise
tt = 1.25 - uu
IF uu <= 0 THEN
env = 0
ELSIF tt >= 0.5 THEN
env = uu
ELSIF tt <= 0 THEN
env = 1
ELSE
env = 1 - tt * tt / 1
ENDIF
// Score: swing volume x touches (up to 2.5 at the 4th touch) x age envelope
rkV = $pVo[i] * min(2.5, 1 + 0.5 * ($pTo[i] - 1)) * env
$vS[v] = zs
$vE[v] = ze
$vRk[v] = rkV
IF $pTk[i] < 0 THEN
pkV = rkV
ELSE
pkV = rkV * ero
ENDIF
$vPk[v] = pkV
pkAll = max(pkAll, pkV)
IF $pPx[i] >= wLo AND $pPx[i] <= wHi THEN
pkMap = max(pkMap, pkV)
ENDIF
NEXT
// Colours and contours scale to the tallest zone inside the map's high-low range
IF pkMap > 0 THEN
gate = max(0.01, pkMap * loP / 100)
ELSE
gate = max(0.01, pkAll * loP / 100)
ENDIF
// Order by pre-sweep score, tallest first (stable: ties keep the list order)
FOR v = 0 TO nV - 1 DO
$ord[v] = v
NEXT
IF nV > 1 THEN
FOR v = 1 TO nV - 1 DO
cur = $ord[v]
rkCur = $vRk[cur]
w = v - 1
moving = 1
WHILE moving = 1 DO
IF w < 0 THEN
moving = 0
ELSE
ow = $ord[w]
IF $vRk[ow] < rkCur THEN
$ord[w + 1] = ow
w = w - 1
ELSE
moving = 0
ENDIF
ENDIF
WEND
$ord[w + 1] = cur
NEXT
ENDIF
nK = 0
ptAcc = 0
fMap = 0
FOR oo = 0 TO nV - 1 DO
k = $ord[oo]
i = $vP[k]
zs = $vS[k]
ze = $vE[k]
pkV = $vPk[k]
pt = (2 * (ze - zs) + 5) * nLay0
ok = 0
IF pkV > gate AND ptAcc + pt <= 150000 THEN
IF look3D = 1 OR nK < pCap - showCall * nCl THEN
ok = 1
ENDIF
ENDIF
IF ok = 1 THEN
// its outer ring needs room for a smooth outline, checked at the gate
heK = 0
IF $pTk[i] >= 0 AND ze < xEnd THEN
heK = 1
ENDIF
ff = 1 - gate / pkV
IF heK = 1 THEN
rz0 = min(noseR0, (ze - zs) / 2 / stagK)
ELSE
rz0 = min(noseR0, (ze - zs) / stagK)
ENDIF
ld = stagK * rz0 * (1 - ff)
xa = floor(zs + ld + 0.5)
IF heK = 1 THEN
xl = floor(ze - ld + 0.5) - 1
ELSE
xl = ze
ENDIF
IF xl < xa + 4 THEN
ok = 0
ENDIF
ENDIF
IF ok = 1 AND nK > 0 THEN
pxK = $pPx[i]
FOR mm = 0 TO nK - 1 DO
m = $kp[mm]
im = $vP[m]
IF $vS[m] <= ze AND zs <= $vE[m] AND abs($pPx[im] - pxK) < gK * sg THEN
ok = 0
ENDIF
NEXT
ENDIF
IF ok = 1 THEN
$kp[nK] = k
nK = nK + 1
ptAcc = ptAcc + pt
fTop = max(fTop, pkV)
IF $pPx[i] >= wLo AND $pPx[i] <= wHi THEN
fMap = max(fMap, pkV)
ENDIF
ENDIF
NEXT
IF fMap > 0 THEN
fTop = fMap
ENDIF
// Zones that share bars are trimmed to half the gap between them, so no two touch.
// A zone too short for full noses is scaled down whole, so it keeps the same shape
IF nK > 0 THEN
FOR kk = 0 TO nK - 1 DO
k = $kp[kk]
i = $vP[k]
pxK = $pPx[i]
gg = 1000000000000
FOR mm = 0 TO nK - 1 DO
m = $kp[mm]
IF m <> k AND $vS[m] <= $vE[k] AND $vS[k] <= $vE[m] THEN
im = $vP[m]
gg = min(gg, abs($pPx[im] - pxK))
ENDIF
NEXT
zs = $vS[k]
ze = $vE[k]
heK = 0
IF $pTk[i] >= 0 AND ze < xEnd THEN
heK = 1
ENDIF
IF heK = 1 THEN
rz0 = min(noseR0, (ze - zs) / 2 / stagK)
ELSE
rz0 = min(noseR0, (ze - zs) / stagK)
ENDIF
sI = min(sg * rz0 / noseR0, 0.5 * gg - 0.06 * sg)
$zPl[nZ] = i
$zSg[nZ] = sI
$zAm[nZ] = $vPk[k]
$zXs[nZ] = zs
$zXe[nZ] = ze
$zHe[nZ] = heK
$zGp[nZ] = sI * fTop / $vPk[k] * dG
$zGr[nZ] = 0
IF sweptGrey = 1 AND $pTk[i] >= 0 THEN
$zGr[nZ] = 1
nZS = nZS + 1
ENDIF
nZ = nZ + 1
NEXT
ENDIF
ENDIF
// Contours: geometry of every ring, then the most contours that fit the shape budget
// (the original draws at most 100 polylines, one per tag stem first)
nTagOK = 0
IF nZ > 0 THEN
FOR z = 0 TO nZ - 1 DO
pl = $zPl[z]
IF $pSt[pl] >= x0 THEN
nTagOK = nTagOK + 1
ENDIF
NEXT
ENDIF
nTag = 0
IF showCall = 1 THEN
nTag = min(nCl, nTagOK)
ENDIF
budget = pCap - nTag
nSel = 0
need = 0
nPoly = 0
dropped = 0
IF nZ > 0 THEN
FOR i = 0 TO nLev - 1 DO
lvI = fTop * (loP / 100 + i * dG)
$lv[i] = lvI
$cix[i] = floor(13 * i / (nLev - 1) + 0.5)
cntP = 0
cntQ = 0
FOR z = 0 TO nZ - 1 DO
gi = i * 120 + z
am = $zAm[z]
zs = $zXs[z]
ze = $zXe[z]
heZ = $zHe[z]
ff = 1 - lvI / am
IF heZ = 1 THEN
rz0 = min(noseR0, (ze - zs) / 2 / stagK)
ELSE
rz0 = min(noseR0, (ze - zs) / stagK)
ENDIF
ld = stagK * rz0 * (1 - ff)
rr = max(2, rz0 * ff)
xa = floor(zs + ld + 0.5)
IF heZ = 1 THEN
xb = floor(ze - ld + 0.5)
xl = xb - 1
ELSE
xb = ze
xl = ze
ENDIF
nn = 0
IF lvI < am AND xl >= xa + 4 THEN
nn = 1 + 2 * (xl - xa) + heZ
ENDIF
$gN[gi] = nn
$gXa[gi] = xa
$gXb[gi] = xb
$gXl[gi] = xl
$gRl[gi] = zs + ld + rr - xa
$gRr[gi] = xb - (ze - ld - rr)
$gF[gi] = ff
IF nn > 0 THEN
cntP = cntP + 1
cntQ = cntQ + nn
ENDIF
NEXT
IF look3D = 0 THEN
// flat: one polyline per ring
$cP[i] = cntP
$cPt[i] = cntQ
ELSE
// 3D: each layer joins every zone into one polyline, cut every 9,500 points
FOR sb = 0 TO 2 DO
lcP = 0
lcQ = 0
acc = 0
nA = 0
FOR z = 0 TO nZ - 1 DO
inSb = 0
IF sb = 0 THEN
inSb = 1
ELSIF sb = 1 AND $zGr[z] = 0 THEN
inSb = 1
ELSIF sb = 2 AND $zGr[z] = 1 THEN
inSb = 1
ENDIF
IF inSb = 1 THEN
IF acc > 0 AND acc + 2 * ($zXe[z] - $zXs[z]) + 8 > 9500 THEN
lcP = lcP + 1
lcQ = lcQ + acc + nA - 1
acc = 0
nA = 0
ENDIF
nn = $gN[i * 120 + z]
IF nn > 0 THEN
acc = acc + nn + 1
nA = nA + 1
ENDIF
ENDIF
NEXT
IF acc > 0 THEN
lcP = lcP + 1
lcQ = lcQ + acc + nA - 1
ENDIF
$lyP[sb] = lcP
$lyQ[sb] = lcQ
NEXT
IF i = 0 THEN
nSh = groundOn
ELSIF shadeOn = 1 THEN
nSh = 2
ELSE
nSh = 0
ENDIF
$cP[i] = nSh * $lyP[0] + nCol * ($lyP[1] + $lyP[2])
$cPt[i] = nSh * $lyQ[0] + nCol * ($lyQ[1] + $lyQ[2])
ENDIF
need = need + $cP[i]
NEXT
// The most contours that fit: evenly spaced, the lowest and the top kept whenever two fit
kS = nLev
WHILE nSel = 0 AND kS >= 1 DO
sumP = 0
sumQ = 0
FOR j = 0 TO kS - 1 DO
IF kS = 1 THEN
ii = 0
ELSE
ii = floor(j * (nLev - 1) / (kS - 1) + 0.5)
ENDIF
$sTry[j] = ii
sumP = sumP + $cP[ii]
sumQ = sumQ + $cPt[ii]
NEXT
IF sumP <= budget AND sumQ <= 150000 THEN
nSel = kS
FOR j = 0 TO kS - 1 DO
$sel[j] = $sTry[j]
nPoly = nPoly + $cP[$sel[j] + 0]
NEXT
ENDIF
kS = kS - 1
WEND
dropped = need - nPoly
// 3D on a thinned ladder: edges, cores and ground shadows scale with the ring spacing drawn
IF look3D = 1 AND nSel > 1 AND nSel < nLev THEN
FOR z = 0 TO nZ - 1 DO
$zGp[z] = $zGp[z] * (nLev - 1) / (nSel - 1)
NEXT
ENDIF
// ===================== DRAW THE MAP =====================
// Every ring is a closed outline: a pointed nose at the swing candle (and at the end of a
// swept zone) and a flat run in between, filled column by column with triangles (a flat run
// is one block). Flat look: each ring is drawn as the band between it and the next contour
// of its zone, so colours never pile up and the candles show through evenly; with no
// transparency it is exactly the stacked picture of the original. 3D look: every layer is
// drawn whole and on top of the previous one, as in the original.
op = 1 - fT / 100
IF darkChart = 1 THEN
grT = round(100 - 45 * op)
ELSE
grT = round(100 - 15 * op)
ENDIF
aGround = round(255 * (100 - grT) / 100)
coreT = round(100 - 100 * shK * 0.32 * op)
aCore = round(255 * (100 - coreT) / 100)
IF nSel > 0 THEN
FOR jj = 0 TO nSel - 1 DO
i = $sel[jj]
lvI = $lv[i]
ci = $cix[i]
iNx = -1
IF look3D = 0 AND jj < nSel - 1 THEN
iNx = $sel[jj + 1]
ENDIF
FOR ps = 0 TO 4 DO
psOn = 0
IF look3D = 0 THEN
IF ps = 4 THEN
psOn = 1
ENDIF
ELSE
IF ps = 0 AND i = 0 AND groundOn = 1 THEN
psOn = 1
ENDIF
IF (ps = 1 OR ps = 2) AND i > 0 AND shadeOn = 1 THEN
psOn = 1
ENDIF
IF ps = 3 AND edgeOn = 1 THEN
psOn = 1
ENDIF
IF ps = 4 THEN
psOn = 1
ENDIF
ENDIF
IF psOn = 1 THEN
// Layer: 0 ground shadow, 1 shadow cast down to the ring outside, 2 dark core
// under the ring, 3 lit edge (ring widened), 4 face
kd = 0
eT = 0
eB = 0
lvP = lvI
aSh = 255
IF ps = 0 THEN
kd = 3
aSh = aGround
ELSIF ps = 1 THEN
kd = 1
jp = $sel[jj - 1]
lvP = $lv[jp]
aL = shK * (0.62 - 0.48 * (i - 1) / (nLev - 2)) * op
shT = round(100 - 100 * aL)
aSh = round(255 * (100 - shT) / 100)
ELSIF ps = 2 THEN
kd = 2
aSh = aCore
ELSIF ps = 3 THEN
eT = eW
eB = eW * 0.5
ENDIF
FOR z = 0 TO nZ - 1 DO
gi = i * 120 + z
IF $gN[gi] > 0 THEN
// colour of this zone on this layer
IF ps <= 2 THEN
cR = 0
cG = 0
cB = 0
cA = aSh
ELSE
IF ps = 3 THEN
IF $zGr[z] = 1 THEN
IF darkChart = 1 THEN
cv = $gry[min(13, ci + 2)]
ELSE
cv = $gry[max(0, ci - 2)]
ENDIF
ELSE
cv = $edg[ci]
ENDIF
ELSE
IF $zGr[z] = 1 THEN
cv = $gry[ci]
ELSE
cv = $rmp[ci]
ENDIF
ENDIF
cR = floor(cv / 65536)
cG = floor(cv / 256) - cR * 256
cB = cv - floor(cv / 256) * 256
cA = aFill
ENDIF
// no outline: an outline in the fill colour shows every seam between triangles
oA = 0
pl = $zPl[z]
pr = $pPx[pl]
sz = $zSg[z]
am = $zAm[z]
gp = $zGp[z]
heZ = $zHe[z]
wRing = sz * $gF[gi]
dW = 0
IF kd = 1 THEN
dW = sz * (lvI - lvP) / am
ELSIF kd = 2 THEN
dW = 0.6 * gp
ELSIF kd = 3 THEN
dW = 1.2 * gp
ENDIF
wT = min(sz, wRing + eT * gp)
IF kd = 0 THEN
wB = min(sz, wRing + eB * gp)
ELSE
wB = min(sz, wRing + dW)
ENDIF
xa = $gXa[gi]
xb = $gXb[gi]
xl = $gXl[gi]
rlN = $gRl[gi]
rrN = $gRr[gi]
IF heZ = 1 THEN
xEo = xb
ELSE
xEo = xl
ENDIF
// the next contour of this zone is cut out of this ring (flat look)
inOn = 0
wI = 0
IF iNx >= 0 THEN
gn = iNx * 120 + z
IF $gN[gn] > 0 THEN
inOn = 1
xaI = $gXa[gn]
xbI = $gXb[gn]
xlI = $gXl[gn]
rlI = $gRl[gn]
rrI = $gRr[gn]
wI = sz * $gF[gn]
IF heZ = 1 THEN
xEi = xbI
ELSE
xEi = xlI
ENDIF
ENDIF
ENDIF
x1 = xa
fo1 = 0
fn1 = 0
runOn = 0
xRun = xa
runIn = 0
// one column per step; the extra last step only closes a pending flat block
FOR xx = xa + 1 TO xEo + 1 DO
drawNow = 0
flushNow = 0
newRun = 0
fo2 = 0
fn2 = 0
inCol = 0
IF xx <= xEo THEN
// ring profile at xx: 0 at the tips, 1 on the flat run
IF xx <= xl THEN
cc = min(1, (xx - xa) / rlN)
fo2 = POW(cc * (2 - cc), 0.7)
IF heZ = 1 THEN
cc = min(1, (xb - xx) / rrN)
fo2 = fo2 * POW(cc * (2 - cc), 0.7)
ENDIF
ENDIF
IF inOn = 1 THEN
IF x1 >= xaI AND xx <= xEi THEN
inCol = 1
IF xx <= xlI THEN
cc = min(1, (xx - xaI) / rlI)
fn2 = POW(cc * (2 - cc), 0.7)
IF heZ = 1 THEN
cc = min(1, (xbI - xx) / rrI)
fn2 = fn2 * POW(cc * (2 - cc), 0.7)
ENDIF
ENDIF
ENDIF
ENDIF
flatC = 0
IF fo1 = 1 AND fo2 = 1 THEN
IF inCol = 0 THEN
flatC = 1
ELSIF fn1 = 1 AND fn2 = 1 THEN
flatC = 1
ENDIF
ENDIF
IF flatC = 1 AND runOn = 1 AND runIn = inCol THEN
drawNow = 0
ELSE
IF runOn = 1 THEN
flushNow = 1
ENDIF
IF flatC = 1 THEN
newRun = 1
ELSE
drawNow = 1
ENDIF
ENDIF
ELSIF runOn = 1 THEN
flushNow = 1
ENDIF
// emit the pending flat block, then this column
FOR em = 0 TO 1 DO
doEm = 0
IF em = 0 AND flushNow = 1 THEN
doEm = 1
exL = xRun
exR = x1
uTa = pr + wT
uTb = uTa
uBa = pr - wB
uBb = uBa
hasIn = runIn
vTa = pr + wI
vTb = vTa
vBa = pr - wI
vBb = vBa
runOn = 0
ENDIF
IF em = 1 AND drawNow = 1 THEN
doEm = 1
exL = x1
exR = xx
uTa = pr + wT * fo1
uTb = pr + wT * fo2
uBa = pr - wB * fo1
uBb = pr - wB * fo2
hasIn = inCol
vTa = pr + wI * fn1
vTb = pr + wI * fn2
vBa = pr - wI * fn1
vBb = pr - wI * fn2
ENDIF
IF doEm = 1 THEN
FOR pc = 0 TO hasIn DO
IF hasIn = 0 THEN
pa1 = uTa
pa2 = uTb
pb1 = uBa
pb2 = uBb
ELSIF pc = 0 THEN
pa1 = uTa
pa2 = uTb
pb1 = vTa
pb2 = vTb
ELSE
pa1 = vBa
pa2 = vBb
pb1 = uBa
pb2 = uBb
ENDIF
// a vertical-sided quad as two triangles (a tip leaves one)
IF pa2 <> pb2 THEN
DRAWTRIANGLE(exL, pa1, exR, pa2, exR, pb2) COLOURED(cR, cG, cB, oA) FILLCOLOR(cR, cG, cB, cA)
ENDIF
IF pa1 <> pb1 THEN
DRAWTRIANGLE(exL, pa1, exR, pb2, exL, pb1) COLOURED(cR, cG, cB, oA) FILLCOLOR(cR, cG, cB, cA)
ENDIF
NEXT
ENDIF
NEXT
IF newRun = 1 THEN
runOn = 1
xRun = x1
runIn = inCol
ENDIF
x1 = xx
fo1 = fo2
fn1 = fn2
NEXT
ENDIF
NEXT
ENDIF
NEXT
NEXT
ENDIF
ENDIF
// ===================== CALLOUTS =====================
// Live zones first, then swept ones, each tallest first. A tag sits beyond its own zone and is
// pushed past any zone or earlier tag in its way; a dotted stem joins it to the swing candle
IF nTag > 0 THEN
IF tagSize = 1 THEN
tgK = 0.8
tz = 10
ELSIF tagSize = 3 THEN
tgK = 1.3
tz = 15
ELSE
tgK = 1
tz = 12
ENDIF
tagH = 0.075 * tgK * rng
tagW = 0.13 * tgK * mW
mg = 0.3 * sg
nT = 0
FOR pz = 0 TO 1 DO
FOR z = 0 TO nZ - 1 DO
pl = $zPl[z]
isLive = 0
IF $pTk[pl] < 0 THEN
isLive = 1
ENDIF
okT = 0
IF nT < nTag AND $pSt[pl] >= x0 THEN
IF (pz = 0 AND isLive = 1) OR (pz = 1 AND isLive = 0) THEN
okT = 1
ENDIF
ENDIF
IF okT = 1 THEN
xT = $pSt[pl]
prT = $pPx[pl]
upT = 0
IF $pSd[pl] = 1 THEN
upT = 1
yT = prT + $zSg[z] + mg
ELSE
yT = prT - $zSg[z] - mg
ENDIF
// obstacles: every zone and earlier tag in the tag's columns
nOb = 0
FOR o = 0 TO nZ - 1 DO
IF $zXs[o] <= xT + tagW / 2 AND xT - tagW / 2 <= $zXe[o] THEN
po = $zPl[o]
$obL[nOb] = $pPx[po] - $zSg[o] - mg
$obH[nOb] = $pPx[po] + $zSg[o] + mg
nOb = nOb + 1
ENDIF
NEXT
IF nT > 0 THEN
FOR tq = 0 TO nT - 1 DO
IF abs($tX[tq] - xT) < tagW THEN
$obL[nOb] = $tLo[tq] - mg
$obH[nOb] = $tHi[tq] + mg
nOb = nOb + 1
ENDIF
NEXT
ENDIF
// one sweep outwards in price order clears them all
IF nOb > 0 THEN
FOR v = 0 TO nOb - 1 DO
IF upT = 1 THEN
$obK[v] = $obL[v]
ELSE
$obK[v] = 0 - $obH[v]
ENDIF
$obO[v] = v
NEXT
IF nOb > 1 THEN
FOR v = 1 TO nOb - 1 DO
cur = $obO[v]
kCur = $obK[cur]
w = v - 1
moving = 1
WHILE moving = 1 DO
IF w < 0 THEN
moving = 0
ELSE
ow = $obO[w]
IF $obK[ow] > kCur THEN
$obO[w + 1] = ow
w = w - 1
ELSE
moving = 0
ENDIF
ENDIF
WEND
$obO[w + 1] = cur
NEXT
ENDIF
FOR v = 0 TO nOb - 1 DO
jo = $obO[v]
IF upT = 1 THEN
IF yT < $obH[jo] AND yT + tagH > $obL[jo] THEN
yT = $obH[jo]
ENDIF
ELSE
IF yT > $obL[jo] AND yT - tagH < $obH[jo] THEN
yT = $obL[jo]
ENDIF
ENDIF
NEXT
ENDIF
$tX[nT] = xT
IF upT = 1 THEN
$tLo[nT] = yT
$tHi[nT] = yT + tagH
y1 = yT + 0.68 * tagH
y2 = yT + 0.32 * tagH
ELSE
$tLo[nT] = yT - tagH
$tHi[nT] = yT
y1 = yT - 0.32 * tagH
y2 = yT - 0.68 * tagH
ENDIF
nT = nT + 1
// Tag colour: live tags in the text colour (light chart) or the lit edge of their height (dark chart)
IF isLive = 1 THEN
IF darkChart = 1 THEN
ce2 = max(6, min(13, floor(13 * $zAm[z] / fTop + 0.5)))
cv = $edg[ce2]
tcR = floor(cv / 65536)
tcG = floor(cv / 256) - tcR * 256
tcB = cv - floor(cv / 256) * 256
ELSE
tcR = txR
tcG = txG
tcB = txB
ENDIF
ELSE
tcR = dmR
tcG = dmG
tcB = dmB
ENDIF
IF darkChart = 1 THEN
skR = tcR
skG = tcG
skB = tcB
ELSE
skR = txR
skG = txG
skB = txB
ENDIF
DRAWSEGMENT(xT, prT, xT, yT) COLOURED(skR, skG, skB, 217) STYLE(dottedline, 1)
// Line 1: pool type and price
tch = $pTo[pl]
IF upT = 1 THEN
IF tch > 1 THEN
DRAWTEXT("EQH×#tch# #prT#", xT, y1, monospaced, bold, tz) COLOURED(tcR, tcG, tcB, 255)
ELSE
DRAWTEXT("HIGH #prT#", xT, y1, monospaced, bold, tz) COLOURED(tcR, tcG, tcB, 255)
ENDIF
ELSE
IF tch > 1 THEN
DRAWTEXT("EQL×#tch# #prT#", xT, y1, monospaced, bold, tz) COLOURED(tcR, tcG, tcB, 255)
ELSE
DRAWTEXT("LOW #prT#", xT, y1, monospaced, bold, tz) COLOURED(tcR, tcG, tcB, 255)
ENDIF
ENDIF
// Line 2, live pool: share of past windows in this pool's band (same side) that price
// crossed within the horizon. Swept pool: when it was swept
IF isLive = 1 THEN
ageT = bC - $pSt[pl]
bkT = -1
IF atrC > 0 THEN
dAt = abs(prT - clC) / atrC
IF dAt < 0.5 THEN
bkT = 0
ELSIF dAt < 1 THEN
bkT = 1
ELSIF dAt < 2 THEN
bkT = 2
ELSIF dAt < 3 THEN
bkT = 3
ELSIF dAt < 5 THEN
bkT = 4
ELSIF dAt < 8 THEN
bkT = 5
ENDIF
ENDIF
IF hzOK = 0 THEN
DRAWTEXT("no rate · horizon too long", xT, y2, monospaced, bold, tz) COLOURED(tcR, tcG, tcB, 255)
ELSIF ageT > retN THEN
DRAWTEXT("no rate · >#retN#b", xT, y2, monospaced, bold, tz) COLOURED(tcR, tcG, tcB, 255)
ELSIF bkT < 0 THEN
DRAWTEXT("beyond 8 ATR", xT, y2, monospaced, bold, tz) COLOURED(tcR, tcG, tcB, 255)
ELSE
cT = bkT
IF upT = 0 THEN
cT = bkT + 6
ENDIF
nW = $rN[cT]
hW = $rH[cT]
IF nW = 0 THEN
DRAWTEXT("no windows yet", xT, y2, monospaced, bold, tz) COLOURED(tcR, tcG, tcB, 255)
ELSIF nW < mnN THEN
DRAWTEXT("n #nW# · too few", xT, y2, monospaced, bold, tz) COLOURED(tcR, tcG, tcB, 255)
ELSE
pI = floor(100 * hW / nW + 0.5)
IF pI <= 0 THEN
nFill = 0
ELSIF pI >= 100 THEN
nFill = 10
ELSE
nFill = max(1, min(9, floor(pI / 10 + 0.5)))
ENDIF
// 10-block meter: 0% shows no block, a full meter needs 99.5% or more
IF nFill = 0 THEN
IF hW > 0 THEN
DRAWTEXT("▱▱▱▱▱▱▱▱▱▱ <1%", xT, y2, monospaced, bold, tz) COLOURED(tcR, tcG, tcB, 255)
ELSE
DRAWTEXT("▱▱▱▱▱▱▱▱▱▱ 0%", xT, y2, monospaced, bold, tz) COLOURED(tcR, tcG, tcB, 255)
ENDIF
ELSIF nFill = 1 THEN
DRAWTEXT("▰▱▱▱▱▱▱▱▱▱ #pI#%", xT, y2, monospaced, bold, tz) COLOURED(tcR, tcG, tcB, 255)
ELSIF nFill = 2 THEN
DRAWTEXT("▰▰▱▱▱▱▱▱▱▱ #pI#%", xT, y2, monospaced, bold, tz) COLOURED(tcR, tcG, tcB, 255)
ELSIF nFill = 3 THEN
DRAWTEXT("▰▰▰▱▱▱▱▱▱▱ #pI#%", xT, y2, monospaced, bold, tz) COLOURED(tcR, tcG, tcB, 255)
ELSIF nFill = 4 THEN
DRAWTEXT("▰▰▰▰▱▱▱▱▱▱ #pI#%", xT, y2, monospaced, bold, tz) COLOURED(tcR, tcG, tcB, 255)
ELSIF nFill = 5 THEN
DRAWTEXT("▰▰▰▰▰▱▱▱▱▱ #pI#%", xT, y2, monospaced, bold, tz) COLOURED(tcR, tcG, tcB, 255)
ELSIF nFill = 6 THEN
DRAWTEXT("▰▰▰▰▰▰▱▱▱▱ #pI#%", xT, y2, monospaced, bold, tz) COLOURED(tcR, tcG, tcB, 255)
ELSIF nFill = 7 THEN
DRAWTEXT("▰▰▰▰▰▰▰▱▱▱ #pI#%", xT, y2, monospaced, bold, tz) COLOURED(tcR, tcG, tcB, 255)
ELSIF nFill = 8 THEN
DRAWTEXT("▰▰▰▰▰▰▰▰▱▱ #pI#%", xT, y2, monospaced, bold, tz) COLOURED(tcR, tcG, tcB, 255)
ELSIF nFill = 9 THEN
DRAWTEXT("▰▰▰▰▰▰▰▰▰▱ #pI#%", xT, y2, monospaced, bold, tz) COLOURED(tcR, tcG, tcB, 255)
ELSE
IF hW < nW THEN
DRAWTEXT("▰▰▰▰▰▰▰▰▰▰ >99%", xT, y2, monospaced, bold, tz) COLOURED(tcR, tcG, tcB, 255)
ELSE
DRAWTEXT("▰▰▰▰▰▰▰▰▰▰ 100%", xT, y2, monospaced, bold, tz) COLOURED(tcR, tcG, tcB, 255)
ENDIF
ENDIF
ENDIF
ENDIF
ELSE
agoT = bC - $pTk[pl]
IF agoT = 0 THEN
DRAWTEXT("SWEPT this bar", xT, y2, monospaced, bold, tz) COLOURED(tcR, tcG, tcB, 255)
ELSIF agoT = 1 THEN
DRAWTEXT("SWEPT 1 bar ago", xT, y2, monospaced, bold, tz) COLOURED(tcR, tcG, tcB, 255)
ELSE
DRAWTEXT("SWEPT #agoT# bars ago", xT, y2, monospaced, bold, tz) COLOURED(tcR, tcG, tcB, 255)
ENDIF
ENDIF
ENDIF
NEXT
NEXT
ENDIF
// ===================== LEGEND (middle right) =====================
// Drawn contours only, top contour first, as % of the tallest zone; a grey row for swept zones
IF showLeg = 1 THEN
nRow = 0
IF nSel > 0 THEN
FOR jj = nSel - 1 DOWNTO 0 DO
i = $sel[jj]
IF $cP[i] > 0 THEN
$lgI[nRow] = i
nRow = nRow + 1
ENDIF
NEXT
ENDIF
nLg = nRow
IF nZS > 0 THEN
nLg = nLg + 1
ENDIF
IF nLg > 0 THEN
lgH = 18
lgTop = nLg * lgH / 2
lgR = 0 - 90
lgL = 0 - 160
DRAWRECTANGLE(lgL, lgTop + 3, lgR, lgTop - nLg * lgH - 3) ANCHOR(RIGHT, XSHIFT, YSHIFT) COLOURED(bgR, bgG, bgB, bgA) FILLCOLOR(bgR, bgG, bgB, bgA)
IF nRow > 0 THEN
FOR rw = 0 TO nRow - 1 DO
i = $lgI[rw]
ci = $cix[i]
cv = $rmp[ci]
cR = floor(cv / 65536)
cG = floor(cv / 256) - cR * 256
cB = cv - floor(cv / 256) * 256
yC = lgTop - (rw + 0.5) * lgH
DRAWRECTANGLE(lgL + 6, yC + 7, lgL + 30, yC - 7) ANCHOR(RIGHT, XSHIFT, YSHIFT) COLOURED(cR, cG, cB, aFill) FILLCOLOR(cR, cG, cB, aFill)
pcL = round(loP + i * (topP - loP) / (nLev - 1))
DRAWTEXT("#pcL#%", lgL + 50, yC, monospaced, bold, 10) ANCHOR(RIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
NEXT
ENDIF
IF nZS > 0 THEN
cv = $gry[5]
cR = floor(cv / 65536)
cG = floor(cv / 256) - cR * 256
cB = cv - floor(cv / 256) * 256
yC = lgTop - (nRow + 0.5) * lgH
DRAWRECTANGLE(lgL + 6, yC + 7, lgL + 30, yC - 7) ANCHOR(RIGHT, XSHIFT, YSHIFT) COLOURED(cR, cG, cB, aFill) FILLCOLOR(cR, cG, cB, aFill)
DRAWTEXT("swept", lgL + 50, yC, monospaced, bold, 10) ANCHOR(RIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ENDIF
ENDIF
ENDIF
// ===================== PANEL (top right) =====================
// Live settings, past crossing rates by band and side, the tallest live zone, pool counts and
// the last bar used. Texts are centred in their column
IF showPanel = 1 THEN
IF txtSize = 1 THEN
fz = 8
fzs = 8
ELSIF txtSize = 3 THEN
fz = 12
fzs = 10
ELSE
fz = 10
fzs = 10
ENDIF
cw = 0.62 * fz
rhM = fz + 8
rhS = fzs + 6
w0 = 32 * cw
w1 = 16 * cw
w2 = 16 * cw
pnR = 0 - 90
pnL = pnR - w0 - w1 - w2
c0 = pnL + w0 / 2
c1 = pnL + w0 + w1 / 2
c2 = pnR - w2 / 2
c01 = pnL + (w0 + w1) / 2
c12 = pnL + w0 + (w1 + w2) / 2
cMid = (pnL + pnR) / 2
nSet = 5 + look3D
pTop = 0 - 8
pH = 8 * rhM + (nSet + 1) * rhS
DRAWRECTANGLE(pnL, pTop, pnR, pTop - pH) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(125, 125, 125, 255) FILLCOLOR(bgR, bgG, bgB, bgA)
DRAWRECTANGLE(pnL, pTop, pnR, pTop - rhM) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(hbR, hbG, hbB, 255) FILLCOLOR(hbR, hbG, hbB, 255)
// Header
yy = pTop - rhM / 2
DRAWTEXT("LIQUIDITY CONTOUR MAP", c01, yy, monospaced, bold, fz) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(htR, htG, htB, 255)
IF atrOK = 0 OR winOK = 0 THEN
wu1 = bC + 1
wu2 = max(100, mW)
DRAWTEXT("WARMING UP #wu1#/#wu2#", c2, yy, monospaced, bold, fz) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(htR, htG, htB, 255)
ELSIF nZ = 1 THEN
DRAWTEXT("1 ZONE", c2, yy, monospaced, bold, fz) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(htR, htG, htB, 255)
ELSE
DRAWTEXT("#nZ# ZONES", c2, yy, monospaced, bold, fz) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(htR, htG, htB, 255)
ENDIF
// Settings
yy = pTop - rhM - rhS / 2
loPi = round(loP)
toPi = round(topP)
DRAWTEXT("swing #pLen# · map #mW#b +#eR# · contours #nSel# of #nLev# (#loPi#–#toPi#%)", cMid, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
yy = yy - rhS
hPr = round(hP * 10) / 10
gKr = round(gK * 100) / 100
rKr = round(rndK * 10) / 10
IF look3D = 0 THEN
DRAWTEXT("height #hPr#% · gap #gKr# · rise #rise#b · nose #rKr# · flat", cMid, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ELSE
DRAWTEXT("height #hPr#% · gap #gKr# · rise #rise#b · nose #rKr# · 3D", cMid, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
yy = yy - rhS
eWr = round(eW * 100) / 100
shKr = round(shK * 100) / 100
IF edgeOn = 1 AND shadeOn = 1 AND groundOn = 1 THEN
DRAWTEXT("edges #eWr# · shade #shKr# · ground on", cMid, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ELSIF edgeOn = 1 AND shadeOn = 1 THEN
DRAWTEXT("edges #eWr# · shade #shKr# · ground off", cMid, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ELSIF edgeOn = 1 AND groundOn = 1 THEN
DRAWTEXT("edges #eWr# · shade off · ground on", cMid, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ELSIF edgeOn = 1 THEN
DRAWTEXT("edges #eWr# · shade off · ground off", cMid, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ELSIF shadeOn = 1 AND groundOn = 1 THEN
DRAWTEXT("edges off · shade #shKr# · ground on", cMid, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ELSIF shadeOn = 1 THEN
DRAWTEXT("edges off · shade #shKr# · ground off", cMid, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ELSIF groundOn = 1 THEN
DRAWTEXT("edges off · shade off · ground on", cMid, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ELSE
DRAWTEXT("edges off · shade off · ground off", cMid, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ENDIF
ENDIF
yy = yy - rhS
eqr = round(eqT * 100) / 100
IF useVol = 0 THEN
DRAWTEXT("eq #eqr# ATR · pools #mxP# · vol off", cMid, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ELSIF bC < 49 OR volMA[oB] <= 0 THEN
DRAWTEXT("eq #eqr# ATR · pools #mxP# · vol on · no data", cMid, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ELSE
DRAWTEXT("eq #eqr# ATR · pools #mxP# · vol on", cMid, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ENDIF
yy = yy - rhS
DRAWTEXT("horizon #hor#b · window #wW#b · retire #retN#b · min n #mnN#", cMid, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
yy = yy - rhS
rBr = round(rBand * 10) / 10
eror = round(ero * 100) / 100
IF sweptGrey = 1 THEN
DRAWTEXT("band #rBr# ATR · swept ×#eror# / #capB#b grey", cMid, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ELSE
DRAWTEXT("band #rBr# ATR · swept ×#eror# / #capB#b", cMid, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ENDIF
// Crossing rates by distance band and side
yy = yy - rhS / 2 - rhM / 2
IF hzOK = 1 THEN
DRAWTEXT("Crossed ≤#hor# bars", c0, yy, monospaced, bold, fz) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
DRAWTEXT("HIGHS", c1, yy, monospaced, bold, fz) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
DRAWTEXT("LOWS", c2, yy, monospaced, bold, fz) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ELSE
DRAWTEXT("STATS OFF · horizon > retire - swing", c01, yy, monospaced, bold, fz) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(acR, acG, acB, 255)
ENDIF
FOR rr = 0 TO 3 DO
yy = yy - rhM
IF rr = 0 THEN
b0 = 0
b1 = 1
DRAWTEXT("< 1 ATR", c0, yy, monospaced, bold, fz) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ELSIF rr = 1 THEN
b0 = 2
b1 = 3
DRAWTEXT("1–3 ATR", c0, yy, monospaced, bold, fz) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ELSIF rr = 2 THEN
b0 = 4
b1 = 4
DRAWTEXT("3–5 ATR", c0, yy, monospaced, bold, fz) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ELSE
b0 = 5
b1 = 5
DRAWTEXT("5–8 ATR", c0, yy, monospaced, bold, fz) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ENDIF
FOR sdI = 0 TO 1 DO
nS = 0
hS = 0
FOR bq = b0 TO b1 DO
cq = bq + 6 * sdI
nS = nS + $rN[cq]
hS = hS + $rH[cq]
NEXT
IF sdI = 0 THEN
xC = c1
ELSE
xC = c2
ENDIF
IF nS = 0 THEN
DRAWTEXT("-", xC, yy, monospaced, bold, fz) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(txR, txG, txB, 255)
ELSIF nS < mnN THEN
DRAWTEXT("- · n #nS#", xC, yy, monospaced, bold, fz) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(txR, txG, txB, 255)
ELSE
pcS = floor(100 * hS / nS + 0.5)
IF pcS = 0 AND hS > 0 THEN
DRAWTEXT("<1% · n #nS#", xC, yy, monospaced, bold, fz) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(txR, txG, txB, 255)
ELSIF pcS = 100 AND hS < nS THEN
DRAWTEXT(">99% · n #nS#", xC, yy, monospaced, bold, fz) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(txR, txG, txB, 255)
ELSE
DRAWTEXT("#pcS#% · n #nS#", xC, yy, monospaced, bold, fz) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(txR, txG, txB, 255)
ENDIF
ENDIF
NEXT
NEXT
// Tallest live zone (zones are ordered by height)
yy = yy - rhM
DRAWTEXT("Tallest live zone", c0, yy, monospaced, bold, fz) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
tl = -1
IF nZ > 0 THEN
FOR z = nZ - 1 DOWNTO 0 DO
pl = $zPl[z]
IF $pTk[pl] < 0 THEN
tl = z
ENDIF
NEXT
ENDIF
IF tl < 0 THEN
DRAWTEXT("-", c12, yy, monospaced, bold, fz) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(txR, txG, txB, 255)
ELSE
pl = $zPl[tl]
tpx = $pPx[pl]
tsc = round($zAm[tl] * 100) / 100
dz = 0
IF atrC > 0 THEN
dz = (tpx - clC) / atrC
ENDIF
dzr = round(abs(dz) * 10) / 10
IF dz > 0 THEN
DRAWTEXT("#tpx# · score #tsc# · ▲ #dzr# ATR", c12, yy, monospaced, bold, fz) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(txR, txG, txB, 255)
ELSIF dz < 0 THEN
DRAWTEXT("#tpx# · score #tsc# · ▼ #dzr# ATR", c12, yy, monospaced, bold, fz) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(txR, txG, txB, 255)
ELSE
DRAWTEXT("#tpx# · score #tsc# · = 0.0 ATR", c12, yy, monospaced, bold, fz) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(txR, txG, txB, 255)
ENDIF
ENDIF
// Pool counts and shapes drawn against the budget
yy = yy - rhM
nLive = nV - nSwept
DRAWTEXT("Pools live · swept · polylines", c0, yy, monospaced, bold, fz) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
IF dropped > 0 THEN
DRAWTEXT("#nLive# · #nSwept# · #nPoly#/#budget# · #dropped# short", c12, yy, monospaced, bold, fz) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(acR, acG, acB, 255)
ELSE
DRAWTEXT("#nLive# · #nSwept# · #nPoly#/#budget#", c12, yy, monospaced, bold, fz) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(txR, txG, txB, 255)
ENDIF
// Last bar used (close time, the instrument's time zone)
yy = yy - rhM / 2 - rhS / 2
dtC = date[oB]
tmC = time[oB]
yr2 = floor(dtC / 10000) - 2000
mo = floor(dtC / 100) - floor(dtC / 10000) * 100
dy = dtC - floor(dtC / 100) * 100
hh = floor(tmC / 10000)
mi = floor(tmC / 100) - hh * 100
IF mo = 1 THEN
IF mi < 10 THEN
DRAWTEXT("Last bar #dy# Jan 20#yr2# · #hh#h0#mi#", c01, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ELSE
DRAWTEXT("Last bar #dy# Jan 20#yr2# · #hh#h#mi#", c01, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ENDIF
ELSIF mo = 2 THEN
IF mi < 10 THEN
DRAWTEXT("Last bar #dy# Feb 20#yr2# · #hh#h0#mi#", c01, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ELSE
DRAWTEXT("Last bar #dy# Feb 20#yr2# · #hh#h#mi#", c01, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ENDIF
ELSIF mo = 3 THEN
IF mi < 10 THEN
DRAWTEXT("Last bar #dy# Mar 20#yr2# · #hh#h0#mi#", c01, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ELSE
DRAWTEXT("Last bar #dy# Mar 20#yr2# · #hh#h#mi#", c01, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ENDIF
ELSIF mo = 4 THEN
IF mi < 10 THEN
DRAWTEXT("Last bar #dy# Apr 20#yr2# · #hh#h0#mi#", c01, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ELSE
DRAWTEXT("Last bar #dy# Apr 20#yr2# · #hh#h#mi#", c01, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ENDIF
ELSIF mo = 5 THEN
IF mi < 10 THEN
DRAWTEXT("Last bar #dy# May 20#yr2# · #hh#h0#mi#", c01, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ELSE
DRAWTEXT("Last bar #dy# May 20#yr2# · #hh#h#mi#", c01, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ENDIF
ELSIF mo = 6 THEN
IF mi < 10 THEN
DRAWTEXT("Last bar #dy# Jun 20#yr2# · #hh#h0#mi#", c01, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ELSE
DRAWTEXT("Last bar #dy# Jun 20#yr2# · #hh#h#mi#", c01, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ENDIF
ELSIF mo = 7 THEN
IF mi < 10 THEN
DRAWTEXT("Last bar #dy# Jul 20#yr2# · #hh#h0#mi#", c01, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ELSE
DRAWTEXT("Last bar #dy# Jul 20#yr2# · #hh#h#mi#", c01, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ENDIF
ELSIF mo = 8 THEN
IF mi < 10 THEN
DRAWTEXT("Last bar #dy# Aug 20#yr2# · #hh#h0#mi#", c01, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ELSE
DRAWTEXT("Last bar #dy# Aug 20#yr2# · #hh#h#mi#", c01, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ENDIF
ELSIF mo = 9 THEN
IF mi < 10 THEN
DRAWTEXT("Last bar #dy# Sep 20#yr2# · #hh#h0#mi#", c01, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ELSE
DRAWTEXT("Last bar #dy# Sep 20#yr2# · #hh#h#mi#", c01, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ENDIF
ELSIF mo = 10 THEN
IF mi < 10 THEN
DRAWTEXT("Last bar #dy# Oct 20#yr2# · #hh#h0#mi#", c01, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ELSE
DRAWTEXT("Last bar #dy# Oct 20#yr2# · #hh#h#mi#", c01, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ENDIF
ELSIF mo = 11 THEN
IF mi < 10 THEN
DRAWTEXT("Last bar #dy# Nov 20#yr2# · #hh#h0#mi#", c01, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ELSE
DRAWTEXT("Last bar #dy# Nov 20#yr2# · #hh#h#mi#", c01, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ENDIF
ELSIF mo = 12 THEN
IF mi < 10 THEN
DRAWTEXT("Last bar #dy# Dec 20#yr2# · #hh#h0#mi#", c01, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ELSE
DRAWTEXT("Last bar #dy# Dec 20#yr2# · #hh#h#mi#", c01, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ENDIF
ENDIF
nBar = bC + 1
IF nBar = 1 THEN
DRAWTEXT("1 bar", c2, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ELSE
DRAWTEXT("#nBar# bars", c2, yy, monospaced, bold, fzs) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT) COLOURED(dmR, dmG, dmB, 255)
ENDIF
ENDIF
ENDIF
RETURN