kNN Market Architecture

Viewing 2 posts - 1 through 2 (of 2 total)
  • Author
    Posts
  • #261053 quote
    Maricarmen
    Participant
    Veteran

    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


    #261060 quote
    Iván González
    Moderator
    Legend

    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")
    



    robertogozzi thanked this post
Viewing 2 posts - 1 through 2 (of 2 total)
  • You must be logged in to reply to this topic.
ProRealAI ProRealAI New

Stuck on this ProBuilder code?

Describe what this topic is trying to build, in plain English, and ProRealAI writes the ProRealTime™ indicator, screener or system for you.

Available in 7 languages
Try ProRealAI

kNN Market Architecture


ProScreener: Buscadores de Mercado y Rastreo

New Reply
Author
author-avatar
Maricarmen @maricarmen Participant
Summary

This topic contains 1 reply,
has 2 voices, and was last updated by Iván González
4 months ago.

Topic Details
Forum: ProScreener: Buscadores de Mercado y Rastreo
Language: Spanish
Started: 05/13/2026
Status: Active
Attachments: No files
Logo Logo
Loading...