kNN Market Architecture

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

    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.

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
2 weeks, 2 days ago.

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