ProRealCode - Trading & Coding with ProRealTime™
Hola: Se podría hacer el Screener de este indicador.
Gracias,
//———————————————-
//PRC_kNN Market Architecture [LuxAlgo]
//Indicador 1/2 — estructura, BOS, profile, delta tank, kNN filter (opt-in)
//version = 2
//27.04.2026
//Iván González @ http://www.prorealcode.com
//Sharing ProRealTime knowledge
//———————————————-
defparam drawonlastbaronly = true
defparam calculateonlastbars = 1500
// === INPUTS ===
sensitivityInput = 5
autoSensitivity = 1
showST = 1
showMT = 1
showLT = 1
biasSource = 3
showSTBOS = 1
showMTBOS = 0
showLTBOS = 1
showDeltaTank = 1
showVP = 1
vpRows = 30
vpWidth = 50
vpOffset = 10
stOffsetMult = 0.5
mtOffsetMult = 1.5
ltOffsetMult = 2.5
// Optional kNN filter (applied to LT term only).
// Replaces the placebo “kNN classifier” of the Pine original (score=1.0 hardcoded)
// with a real score: percentile rank of pivot bar volume, autocalibrated per asset.
useKnn = 0 // 0=off (default), 1=filter LT pivots with kNN
knnK = 5
knnThreshold = 0.7 // minimum percentile (0.7 = top 30% of volume)
pctWindow = 100 // percentile rank window (bars before pivot)
// === COLOURS (RGB) ===
bullR = 8
bullG = 153
bullB = 129
bearR = 242
bearG = 54
bearB = 69
neuR = 120
neuG = 123
neuB = 134
// === DYNAMIC ENGINE ===
atrLong = averagetruerange[200]
avgAtrL = average[200](atrLong)
if avgAtrL > 0 then
volRatio = atrLong / avgAtrL
else
volRatio = 1.0
endif
smoothedRatio = exponentialaverage[50](volRatio)
if autoSensitivity = 1 and smoothedRatio > 0 then
dynMult = exp(1.5 * log(smoothedRatio))
else
dynMult = 1.0
endif
baseLen = max(3, round((11 – sensitivityInput) * dynMult))
mtLen = baseLen * 3
ltLen = mtLen * 3
atr14 = averagetruerange[14]
stOffset = atr14 * stOffsetMult
mtOffset = atr14 * mtOffsetMult
ltOffset = atr14 * ltOffsetMult
// Features for the kNN scoring (relAtr and relVol of current bar)
avgAtr14 = average[100](atr14)
if avgAtr14 > 0 then
relAtr = atr14 / avgAtr14
else
relAtr = 1.0
endif
avg100Vol = average[100](volume)
if avg100Vol > 0 then
relVol = volume / avg100Vol
else
relVol = 1.0
endif
// === PERSISTENT STATE ===
once stB = 0
once mtB = 0
once ltB = 0
once stHactive = 0
once stLactive = 0
once mtHactive = 0
once mtLactive = 0
once ltHactive = 0
once ltLactive = 0
once stHy = 0
once stHx = 0
once stLy = 0
once stLx = 0
once mtHy = 0
once mtHx = 0
once mtLy = 0
once mtLx = 0
once ltHy = 0
once ltHx = 0
once ltLy = 0
once ltLx = 0
once lastSTHigh = 0
once lastSTLow = 0
once lastMTHigh = 0
once lastMTLow = 0
once lastLTHigh = 0
once lastLTLow = 0
// kNN history for the LT filter
once ltHistCount = 0
// === ST: pivots + BOS ===
stPHfound = 0
stPLfound = 0
if barindex > 2*baseLen + 1 then
if high[baseLen] = highest[2*baseLen+1](high) and high[baseLen] > high[baseLen+1] and high[baseLen] >= high[baseLen-1] then
stPHfound = 1
endif
if low[baseLen] = lowest[2*baseLen+1](low) and low[baseLen] < low[baseLen+1] and low[baseLen] <= low[baseLen-1] then
stPLfound = 1
endif
endif
if stPHfound = 1 then
stHy = high[baseLen]
stHx = barindex – baseLen
stHactive = 1
lastSTHigh = stHy
endif
if stPLfound = 1 then
stLy = low[baseLen]
stLx = barindex – baseLen
stLactive = 1
lastSTLow = stLy
endif
if stHactive = 1 and close > stHy then
$stBosX1[stB] = stHx
$stBosX2[stB] = barindex
$stBosY[stB] = stHy
$stBosDir[stB] = 1
stB = stB + 1
stHactive = 0
endif
if stLactive = 1 and close < stLy then
$stBosX1[stB] = stLx
$stBosX2[stB] = barindex
$stBosY[stB] = stLy
$stBosDir[stB] = -1
stB = stB + 1
stLactive = 0
endif
// === MT ===
mtPHfound = 0
mtPLfound = 0
if barindex > 2*mtLen + 1 then
if high[mtLen] = highest[2*mtLen+1](high) and high[mtLen] > high[mtLen+1] and high[mtLen] >= high[mtLen-1] then
mtPHfound = 1
endif
if low[mtLen] = lowest[2*mtLen+1](low) and low[mtLen] < low[mtLen+1] and low[mtLen] <= low[mtLen-1] then
mtPLfound = 1
endif
endif
if mtPHfound = 1 then
mtHy = high[mtLen]
mtHx = barindex – mtLen
mtHactive = 1
lastMTHigh = mtHy
endif
if mtPLfound = 1 then
mtLy = low[mtLen]
mtLx = barindex – mtLen
mtLactive = 1
lastMTLow = mtLy
endif
if mtHactive = 1 and close > mtHy then
$mtBosX1[mtB] = mtHx
$mtBosX2[mtB] = barindex
$mtBosY[mtB] = mtHy
$mtBosDir[mtB] = 1
mtB = mtB + 1
mtHactive = 0
endif
if mtLactive = 1 and close < mtLy then
$mtBosX1[mtB] = mtLx
$mtBosX2[mtB] = barindex
$mtBosY[mtB] = mtLy
$mtBosDir[mtB] = -1
mtB = mtB + 1
mtLactive = 0
endif
// === LT ===
ltPHfound = 0
ltPLfound = 0
if barindex > 2*ltLen + 1 then
if high[ltLen] = highest[2*ltLen+1](high) and high[ltLen] > high[ltLen+1] and high[ltLen] >= high[ltLen-1] then
ltPHfound = 1
endif
if low[ltLen] = lowest[2*ltLen+1](low) and low[ltLen] < low[ltLen+1] and low[ltLen] <= low[ltLen-1] then
ltPLfound = 1
endif
endif
// === Optional kNN filter for LT (see Appendix) ===
// Replaces the placebo “kNN classifier” of the Pine original with a real score:
// percentile rank of the pivot bar’s volume over the previous pctWindow bars.
// If the kNN score is below threshold, the pivot is suppressed (no active line).
if useKnn = 1 and (ltPHfound = 1 or ltPLfound = 1) then
curFeat1 = relAtr[ltLen]
curFeat2 = relVol[ltLen]
volPivot = volume[ltLen]
// 1) Score = percentile rank of pivot bar volume in previous pctWindow bars
maxBack = barindex – ltLen
if maxBack > pctWindow then
maxBack = pctWindow
endif
if maxBack >= 20 then
pctCount = 0
for jPct = 0 to maxBack – 1 do
if volume[ltLen + jPct] <= volPivot then
pctCount = pctCount + 1
endif
next
curScore = pctCount / maxBack
else
curScore = relVol[ltLen]
endif
// 2) kNN score = average of K nearest neighbours’ scores in feature-space
if ltHistCount < knnK then
knnScoreLT = 0.5
else
for iKnn = 0 to ltHistCount – 1 do
$ltDist[iKnn] = abs(curFeat1 – $ltHF1[iKnn]) + abs(curFeat2 – $ltHF2[iKnn])
$ltSortIdx[iKnn] = iKnn
next
for iiKnn = 0 to knnK – 1 do
for jjKnn = iiKnn + 1 to ltHistCount – 1 do
idxI = $ltSortIdx[iiKnn]
idxJ = $ltSortIdx[jjKnn]
if $ltDist[idxJ] < $ltDist[idxI] then
$ltSortIdx[iiKnn] = idxJ
$ltSortIdx[jjKnn] = idxI
endif
next
next
sumKnn = 0
for kKnn = 0 to knnK – 1 do
kIdx = $ltSortIdx[kKnn]
sumKnn = sumKnn + $ltHSc[kIdx]
next
knnScoreLT = sumKnn / knnK
endif
// 3) Push to history (always, FIFO 100)
if ltHistCount >= 100 then
for shKnn = 0 to 98 do
$ltHF1[shKnn] = $ltHF1[shKnn+1]
$ltHF2[shKnn] = $ltHF2[shKnn+1]
$ltHSc[shKnn] = $ltHSc[shKnn+1]
next
$ltHF1[99] = curFeat1
$ltHF2[99] = curFeat2
$ltHSc[99] = curScore
else
$ltHF1[ltHistCount] = curFeat1
$ltHF2[ltHistCount] = curFeat2
$ltHSc[ltHistCount] = curScore
ltHistCount = ltHistCount + 1
endif
// 4) Apply filter: suppress pivot if score < threshold
if knnScoreLT < knnThreshold then
ltPHfound = 0
ltPLfound = 0
endif
endif
if ltPHfound = 1 then
ltHy = high[ltLen]
ltHx = barindex – ltLen
ltHactive = 1
lastLTHigh = ltHy
endif
if ltPLfound = 1 then
ltLy = low[ltLen]
ltLx = barindex – ltLen
ltLactive = 1
lastLTLow = ltLy
endif
if ltHactive = 1 and close > ltHy then
$ltBosX1[ltB] = ltHx
$ltBosX2[ltB] = barindex
$ltBosY[ltB] = ltHy
$ltBosDir[ltB] = 1
ltB = ltB + 1
ltHactive = 0
endif
if ltLactive = 1 and close < ltLy then
$ltBosX1[ltB] = ltLx
$ltBosX2[ltB] = barindex
$ltBosY[ltB] = ltLy
$ltBosDir[ltB] = -1
ltB = ltB + 1
ltLactive = 0
endif
// === BIAS ===
if biasSource = 1 then
selectedHigh = lastSTHigh
selectedLow = lastSTLow
elsif biasSource = 2 then
selectedHigh = lastMTHigh
selectedLow = lastMTLow
elsif biasSource = 3 then
selectedHigh = lastLTHigh
selectedLow = lastLTLow
else
selectedHigh = 0
selectedLow = 0
endif
biasState = 0
if selectedHigh > 0 and selectedLow > 0 then
if close > selectedHigh then
biasState = 1
elsif close < selectedLow then
biasState = -1
endif
endif
// === RENDERING (last bar only) ===
if islastbarupdate then
// ST: active line + BOS
if showST = 1 then
if stHactive = 1 then
drawsegment(stHx, stHy, barindex, stHy) coloured(bullR, bullG, bullB) style(dottedline, 1)
endif
if stLactive = 1 then
drawsegment(stLx, stLy, barindex, stLy) coloured(bearR, bearG, bearB) style(dottedline, 1)
endif
for i = 0 to stB – 1 do
if $stBosDir[i] = 1 then
drawsegment($stBosX1[i], $stBosY[i], $stBosX2[i], $stBosY[i]) coloured(bullR, bullG, bullB) style(dottedline, 1)
if showSTBOS = 1 then
midX = round(($stBosX1[i] + $stBosX2[i]) / 2)
drawtext(“ST BOS”, midX, $stBosY[i] + stOffset) coloured(bullR, bullG, bullB)
endif
else
drawsegment($stBosX1[i], $stBosY[i], $stBosX2[i], $stBosY[i]) coloured(bearR, bearG, bearB) style(dottedline, 1)
if showSTBOS = 1 then
midX = round(($stBosX1[i] + $stBosX2[i]) / 2)
drawtext(“ST BOS”, midX, $stBosY[i] – stOffset) coloured(bearR, bearG, bearB)
endif
endif
next
endif
// MT: active line + BOS
if showMT = 1 then
if mtHactive = 1 then
drawsegment(mtHx, mtHy, barindex, mtHy) coloured(bullR, bullG, bullB) style(dottedline2, 1)
endif
if mtLactive = 1 then
drawsegment(mtLx, mtLy, barindex, mtLy) coloured(bearR, bearG, bearB) style(dottedline2, 1)
endif
for i = 0 to mtB – 1 do
if $mtBosDir[i] = 1 then
drawsegment($mtBosX1[i], $mtBosY[i], $mtBosX2[i], $mtBosY[i]) coloured(bullR, bullG, bullB) style(dottedline2, 1)
if showMTBOS = 1 then
midX = round(($mtBosX1[i] + $mtBosX2[i]) / 2)
drawtext(“MT BOS”, midX, $mtBosY[i] + mtOffset) coloured(bullR, bullG, bullB)
endif
else
drawsegment($mtBosX1[i], $mtBosY[i], $mtBosX2[i], $mtBosY[i]) coloured(bearR, bearG, bearB) style(dottedline2, 1)
if showMTBOS = 1 then
midX = round(($mtBosX1[i] + $mtBosX2[i]) / 2)
drawtext(“MT BOS”, midX, $mtBosY[i] – mtOffset) coloured(bearR, bearG, bearB)
endif
endif
next
endif
// LT: active line + BOS
if showLT = 1 then
if ltHactive = 1 then
drawsegment(ltHx, ltHy, barindex, ltHy) coloured(bullR, bullG, bullB) style(line, 2)
endif
if ltLactive = 1 then
drawsegment(ltLx, ltLy, barindex, ltLy) coloured(bearR, bearG, bearB) style(line, 2)
endif
for i = 0 to ltB – 1 do
if $ltBosDir[i] = 1 then
drawsegment($ltBosX1[i], $ltBosY[i], $ltBosX2[i], $ltBosY[i]) coloured(bullR, bullG, bullB) style(line, 2)
if showLTBOS = 1 then
midX = round(($ltBosX1[i] + $ltBosX2[i]) / 2)
drawtext(“LT BOS”, midX, $ltBosY[i] + ltOffset) coloured(bullR, bullG, bullB)
endif
else
drawsegment($ltBosX1[i], $ltBosY[i], $ltBosX2[i], $ltBosY[i]) coloured(bearR, bearG, bearB) style(line, 2)
if showLTBOS = 1 then
midX = round(($ltBosX1[i] + $ltBosX2[i]) / 2)
drawtext(“LT BOS”, midX, $ltBosY[i] – ltOffset) coloured(bearR, bearG, bearB)
endif
endif
next
endif
// VOLUME PROFILE (anchored to selected term)
if showVP = 1 and selectedHigh > 0 and selectedLow > 0 and selectedHigh > selectedLow then
if biasSource = 1 then
vpFirstBar = stHx
if stLx < vpFirstBar then
vpFirstBar = stLx
endif
elsif biasSource = 2 then
vpFirstBar = mtHx
if mtLx < vpFirstBar then
vpFirstBar = mtLx
endif
else
vpFirstBar = ltHx
if ltLx < vpFirstBar then
vpFirstBar = ltLx
endif
endif
vpLook = barindex – vpFirstBar
if vpLook > 499 then
vpLook = 499
endif
if vpLook < 30 then
vpLook = 30
endif
vpRange = selectedHigh – selectedLow
vpStep = vpRange / vpRows
for i = 0 to vpRows – 1 do
$vpBin[i] = 0
next
for i = 0 to vpLook do
priceI = close[i]
if priceI >= selectedLow and priceI <= selectedHigh then
binIdx = floor((priceI – selectedLow) / vpStep)
if binIdx > vpRows – 1 then
binIdx = vpRows – 1
endif
if binIdx < 0 then
binIdx = 0
endif
$vpBin[binIdx] = $vpBin[binIdx] + volume[i]
endif
next
maxV = 0
pocIdx = 0
for i = 0 to vpRows – 1 do
if $vpBin[i] > maxV then
maxV = $vpBin[i]
pocIdx = i
endif
next
if maxV > 0 then
vpRight = barindex + vpOffset
for i = 0 to vpRows – 1 do
v = $vpBin[i]
if v > 0 then
binBot = selectedLow + i * vpStep
binTop = binBot + vpStep
binW = round((v / maxV) * vpWidth)
vpLeft = vpRight – binW
if i = pocIdx then
bcR = neuR
bcG = neuG
bcB = neuB
elsif i > pocIdx then
bcR = bullR
bcG = bullG
bcB = bullB
else
bcR = bearR
bcG = bearG
bcB = bearB
endif
drawrectangle(vpLeft, binTop, vpRight, binBot) coloured(bcR, bcG, bcB, 0) fillcolor(bcR, bcG, bcB, 80)
endif
next
endif
endif
// DELTA TANK
if showDeltaTank = 1 and biasSource <> 0 then
if biasSource = 1 then
dtHact = stHactive
dtHx = stHx
dtHy = stHy
dtLact = stLactive
dtLx = stLx
dtLy = stLy
elsif biasSource = 2 then
dtHact = mtHactive
dtHx = mtHx
dtHy = mtHy
dtLact = mtLactive
dtLx = mtLx
dtLy = mtLy
else
dtHact = ltHactive
dtHx = ltHx
dtHy = ltHy
dtLact = ltLactive
dtLx = ltLx
dtLy = ltLy
endif
if dtHact = 1 then
barsBackH = barindex – dtHx
if barsBackH > 0 and barsBackH < 500 then
cumVolH = 0
cumDeltaH = 0
for i = 0 to barsBackH do
cumVolH = cumVolH + volume[i]
if close[i] > open[i] then
cumDeltaH = cumDeltaH + volume[i]
elsif close[i] < open[i] then
cumDeltaH = cumDeltaH – volume[i]
endif
next
if cumVolH > 0 then
deltaPctH = round(abs(cumDeltaH) / cumVolH * 100)
if cumDeltaH >= 0 then
drawtext(“Delta H +#deltaPctH#%”, barindex + 8, dtHy) coloured(bullR, bullG, bullB)
else
drawtext(“Delta H -#deltaPctH#%”, barindex + 8, dtHy) coloured(bearR, bearG, bearB)
endif
endif
endif
endif
if dtLact = 1 then
barsBackL = barindex – dtLx
if barsBackL > 0 and barsBackL < 500 then
cumVolL = 0
cumDeltaL = 0
for i = 0 to barsBackL do
cumVolL = cumVolL + volume[i]
if close[i] > open[i] then
cumDeltaL = cumDeltaL + volume[i]
elsif close[i] < open[i] then
cumDeltaL = cumDeltaL – volume[i]
endif
next
if cumVolL > 0 then
deltaPctL = round(abs(cumDeltaL) / cumVolL * 100)
if cumDeltaL >= 0 then
drawtext(“Delta L +#deltaPctL#%”, barindex + 8, dtLy) coloured(bullR, bullG, bullB)
else
drawtext(“Delta L -#deltaPctL#%”, barindex + 8, dtLy) coloured(bearR, bearG, bearB)
endif
endif
endif
endif
endif
// BIAS LABEL
if biasSource <> 0 then
if biasState = 1 then
drawtext(“Bias: Bullish”, barindex + 5, high + 3*atr14) coloured(bullR, bullG, bullB)
elsif biasState = -1 then
drawtext(“Bias: Bearish”, barindex + 5, high + 3*atr14) coloured(bearR, bearG, bearB)
else
drawtext(“Bias: Neutral”, barindex + 5, high + 3*atr14) coloured(neuR, neuG, neuB)
endif
endif
endif
return
Aquí tienes un screener que detecta las roturas de las BOS long term. A partir de aquí te lo dejo a ti para que modifiques lo que necesites.
//----------------------------------------------
//PRC_kNN Market Architecture [LuxAlgo] — Screener LT BOS
//version = 1
//13.05.2026
//Ivan Gonzalez @ www.prorealcode.com
//Sharing ProRealTime knowledge
//----------------------------------------------
// === INPUTS ===
sensitivityInput = 5 // 1..10 (mayor = pivots más grandes)
autoSensitivity = 1 // 1=on, 0=off (longitud por volatilidad)
lookbackBOS = 5 // BOS confirmado hace ≤ N barras
// === MOTOR DINÁMICO (idéntico al indicador) ===
atrLong = averagetruerange[200]
avgAtrL = average[200](atrLong)
if avgAtrL > 0 then
volRatio = atrLong / avgAtrL
else
volRatio = 1.0
endif
smoothedRatio = exponentialaverage[50](volRatio)
if autoSensitivity = 1 and smoothedRatio > 0 then
dynMult = exp(1.5 * log(smoothedRatio))
else
dynMult = 1.0
endif
baseLen = max(3, round((11 - sensitivityInput) * dynMult))
ltLen = baseLen * 9 // término LT = baseLen × 3 × 3
// === LT PIVOTS + BOS ===
once ltHy = 0
once ltLy = 0
once ltHactive = 0
once ltLactive = 0
once lastBOSbarBull = -1
once lastBOSbarBear = -1
if barindex > 2*ltLen + 1 then
if high[ltLen] = highest[2*ltLen+1](high) and high[ltLen] > high[ltLen+1] and high[ltLen] >= high[ltLen-1] then
ltHy = high[ltLen]
ltHactive = 1
endif
if low[ltLen] = lowest[2*ltLen+1](low) and low[ltLen] < low[ltLen+1] and low[ltLen] <= low[ltLen-1] then
ltLy = low[ltLen]
ltLactive = 1
endif
endif
if ltHactive = 1 and close > ltHy then
lastBOSbarBull = barindex
ltHactive = 0
endif
if ltLactive = 1 and close < ltLy then
lastBOSbarBear = barindex
ltLactive = 0
endif
// Selecciona el BOS más reciente (en cualquier dirección)
if lastBOSbarBull >= lastBOSbarBear then
lastBOSbar = lastBOSbarBull
bosDir = 1
else
lastBOSbar = lastBOSbarBear
bosDir = 0
endif
barsSinceBOS = barindex - lastBOSbar
SCREENER[lastBOSbar > 0 AND barsSinceBOS <= lookbackBOS](barsSinceBOS AS "Bars since BOS", bosDir AS "Bullish/Bearish")
kNN Market Architecture
This topic contains 1 reply,
has 2 voices, and was last updated by
Iván González
2 weeks, 2 days ago.
| Forum: | ProScreener: Buscadores de Mercado y Rastreo |
| Language: | Spanish |
| Started: | 05/13/2026 |
| Status: | Active |
| Attachments: | No files |
The information collected on this form is stored in a computer file by ProRealCode to create and access your ProRealCode profile. This data is kept in a secure database for the duration of the member's membership. They will be kept as long as you use our services and will be automatically deleted after 3 years of inactivity. Your personal data is used to create your private profile on ProRealCode. This data is maintained by SAS ProRealCode, 407 rue Freycinet, 59151 Arleux, France. If you subscribe to our newsletters, your email address is provided to our service provider "MailChimp" located in the United States, with whom we have signed a confidentiality agreement. This company is also compliant with the EU/Swiss Privacy Shield, and the GDPR. For any request for correction or deletion concerning your data, you can directly contact the ProRealCode team by email at privacy@prorealcode.com If you would like to lodge a complaint regarding the use of your personal data, you can contact your data protection supervisory authority.