Machine Learning RSI

Category: Indicators By: Iván González Created: June 8, 2026, 8:47 AM
June 8, 2026, 8:47 AM
Indicators
0 Comments

Zeiierman’s Machine Learning RSI | AI Classification & Ranking is one of the most downloaded “AI” oscillators on TradingView, and unlike many indicators that wear the machine-learning label as marketing, this one earns it. It does not read the RSI through fixed 70/30 levels. Instead it turns every bar into an 8-dimensional fingerprint of momentum behaviour, stores those fingerprints in a memory bank together with what the market did next, and then — for the current bar — searches that bank for the closest historical analogues and lets them vote on the directional bias. The vote drives an adaptive RSI line, a rank/confidence quality score, long/short signals, and a Supertrend whose band width tightens or loosens with the model’s conviction.

 

Theory Behind the Indicator

1. Eight RSI features — momentum as a fingerprint

The engine never looks at “RSI = 63”. It builds eight normalised features from a base RSI (length 14 by default), each describing a different facet of momentum behaviour:

1. value     = RSI / 100
2. slope     = scale01( RSI - RSI[3] )
3. accel     = scale01( (RSI - RSI[3]) - (RSI[3] - RSI[6]) )
4. mid       = |RSI - 50| / 50
5. percentile= percentrank(RSI, 100) / 100
6. churn     = scale01( stdev(RSI, 14) )       // RSI's own volatility
7. spread    = scale01( RSI(7) - RSI(28) )      // fast vs slow RSI
8. regime    = scale01( EMA(RSI, 20) - 50 )

 

scale01(x) is a rolling min-max normalisation over a 100-bar window: (x – lowest) / (highest – lowest), mapping every feature into [0, 1] so they are directly comparable in distance space. The result is that each bar becomes a point in an 8-dimensional momentum space rather than a single oscillator value.

2. The memory bank and supervised labelling

Every bar (subsampled to decorrelate neighbours) is stored with its fingerprint and the outcome that followed it. The outcome is the forward price move over a fixed horizon, bucketed by ATR into seven classes:

moveFwd = close - close[horizon]
band    = atrFactor × ATR[horizon]
outcome = +3 if moveFwd > 2·band ... down to -3 if moveFwd < -2·band   (0 if flat)

 

The fingerprint stored is the one from horizon bars ago, paired with the outcome measured up to now — i.e. “given this momentum state, here is what happened next”. That is the labelled training set, built continuously as the chart prints.

3. KNN with a Lorentzian distance

For the current bar, the engine scans the bank and computes a weighted distance to every stored fingerprint:

dist = Σ  w_i × log(1 + |feature_i_now − feature_i_stored|)

 

The log(1 + |d|) compression (a Lorentzian-style metric) is the key idea: it stops any single feature with a huge mismatch from dominating the comparison, which makes analogue matching robust to outliers. The k nearest fingerprints (k = 8 by default) are retained via a manual top-K — there is no array.sort in ProBuilder, so a parallel array of distances is kept and the worst of the current k is replaced whenever a closer one appears.

4. Distance-weighted voting

The k neighbours vote, weighted by closeness:

weight   = 1 / (1 + dist)
score   += class × weight          // class is the stored outcome, -3..+3

 

The aggregate produces analogScore (the normalised directional bias), agreeFrac (how unanimous the neighbours are), and gapTight (how close, on average, the matches were). Together these answer not just “which way?” but “how well-supported is this read?”.

5. Rank and confidence — quality gating

A flip of bias is not enough to fire a signal. Each setup is scored twice, on a 0–100 scale:

  • Rank blends neighbour agreement (25), match tightness (15), trend alignment, volatility health, regime fit, slope fit, smoothness and stance persistence, minus penalties for chop, over-extension, early flips and a shortage of neighbours.
  • Confidence focuses on agreement, tightness, persistence and slope fit, penalised by early flips.

 

A long or short only prints when the bias flips and rank ≥ 60 and confidence ≥ 50 and the volatility/trend/chop gates pass and a cooldown of 5 bars has elapsed. This is what turns a noisy classifier into a selective one.

6. The ML-adaptive Supertrend

A trailing stop whose ATR multiplier is modulated by the model’s conviction:

mlDrive  = |convSmoothed|·0.5 + gapTight·0.3 + agreeFrac·0.2     (×0.35 in chop)
adaptMult= baseMult × (1 + responsiveness × (1 − mlDrive))

 

High conviction tightens the bands (faster trailing); low conviction or chop widens them (fewer whipsaws). It is a Supertrend that listens to the classifier instead of to volatility alone.

Key Features at a Glance

| Feature | Behaviour |
|---|---|
| 8-feature RSI fingerprint | Value, slope, accel, midpoint distance, percentile, churn, fast/slow spread, regime |
| Memory bank | Circular buffer of past fingerprints + ATR-bucketed forward outcome |
| KNN classifier | k nearest analogues by weighted Lorentzian distance, manual top-K |
| Distance-weighted vote | Closer analogues count more; yields bias, agreement, tightness |
| Rank & confidence | Two independent 0–100 quality scores gating the signals |
| Adaptive Supertrend | ATR band width modulated by model conviction |
| ML RSI oscillator | RSI tilted by conviction × rank, coloured by a bull/bear gradient |
| Signal line + BB | Switchable MA (SMA/EMA/SMMA/WMA/VWMA) with optional Bollinger Bands |

 

How to Read the Indicator

  1. The ML RSI (0–100) reads like an RSI, but it is tilted by the engine: above 50 = bullish momentum context dominates, below 50 = bearish. Readings above 70 / below 30 mark strong conditions. The colour gradient (bullish above ≈72, bearish below ≈28) gives the regime at a glance.
  2. The signal line is a moving average of the ML RSI — crosses can anticipate a shift before a full bias flip. Switch it to SMA + Bollinger Bands to see momentum extremes.
  3. The ML Supertrend (companion overlay) is both a trend filter and a trailing stop. When it flips, the engine considers the regime changed. Its band width is not constant — it breathes with the model’s conviction.
  4. The L / S arrows are not “every flip”. They are the flips that survived the rank, confidence, trend, volatility and chop gates plus the cooldown. Few arrows is by design; loosen gateRank / gateConf if you want more.

Practical Applications

  1. Context-aware momentum. Use the ML RSI in place of a plain RSI: its 50-cross and OB/OS reads are conditioned on how similar momentum states resolved historically, not on a fixed threshold.
  2. Trend-with-quality entries. Take the Supertrend as the regime filter and the gated L/S arrows as triggers. Because the arrows already require rank + confidence + trend alignment, they are inherently selective.
  3. Conviction-scaled risk. The Supertrend tightening under high conviction and widening in chop gives a natural, model-driven trailing stop — tighter when the engine is sure, looser when it is not.
  4. Confluence. Trade only when the ML RSI bias, the Supertrend direction and a signal-line cross all agree.

Indicator Configuration

// Indicator 1/2 — ML RSI Oscillator (panel)
| Parameter | Default | Description |
|---|---|---|
| `rsiBase` | 14 | Base RSI length; the whole feature set is seeded from it |
| `memoryDepth` | 400 | Span of bars the bank covers |
| `kNeighbors` | 8 | Number of analogues that vote |
| `maType` | 1 | Signal line: 0=None,1=SMA,2=SMA+BB,3=EMA,4=SMMA,5=WMA,6=VWMA |
| `maLen` / `bbMult` | 14 / 2.0 | Signal line length / Bollinger width |

 

// Indicator 2/2 — ML Supertrend + Signals (overlay)
| Parameter | Default | Description |
|---|---|---|
| `stMultBase` | 1.5 | Base ATR multiplier of the Supertrend |
| `stMlResp` | 1.0 | How strongly conviction reshapes the band (0 = fixed Supertrend) |
| `gateRank` / `gateConf` | 60 / 50 | Minimum rank / confidence for a signal |
| `coolBars` | 5 | Minimum bars between signals |
| `atrFactor` | 0.5 | Learning sensitivity: how big a move counts as an outcome |

 

Code

The indicator ships as two scripts. Load the first in a separate panel and the second on the price chart, with matching key inputs (rsiBase, memoryDepth, kNeighbors).

Indicator 1/2 — ML RSI Oscillator (panel)

// ============================================================
// PRC_Machine Learning RSI (Zeiierman)
// version = 0
// 05.06.2026
// Iván González @ www.prorealcode.com
// Sharing ProRealTime knowledge
// ============================================================

rsiBase     = 14
memoryDepth = 400
kNeighbors  = 8
winLen      = 100
spacingBars = 4
horizonBars = 4
atrFactor   = 0.5

wVal = 1.0
wSlp = 1.0
wAcc = 1.0
wMid = 1.0
wPct = 1.0
wChn = 1.0
wSpr = 1.0
wReg = 1.0

stMultBase = 1.5
stMlResp   = 1.0
stAtrLen   = 10
trendLen   = 50
chopCut    = 0.5
useChop    = 1
smoothLen  = 10

useTrendGate = 1
useVolBand   = 1
volBandLo    = 20
volBandHi    = 85

maType = 1     // 0=None, 1=SMA, 2=SMA+BB, 3=EMA, 4=SMMA, 5=WMA, 6=VWMA
maLen  = 14
bbMult = 2.0

bullR = 41
bullG = 98
bullB = 255
bearR = 255
bearG = 93
bearB = 0

bankCap = round(memoryDepth / spacingBars)
src     = close
stSrc   = (high + low) / 2

rOsc   = rsi[rsiBase](src)
rfastL = max(2, round(rsiBase / 2))
rOscF  = rsi[rfastL](src)
rOscS  = rsi[rsiBase * 2](src)
atrVal = averagetruerange[14]
stepLen = 3

fVal = rOsc / 100.0

slopeRaw = rOsc - rOsc[stepLen]
slLo = lowest[winLen](slopeRaw)
slHi = highest[winLen](slopeRaw)
if slHi = slLo then
   fSlp = 0.5
else
   fSlp = (slopeRaw - slLo) / (slHi - slLo)
endif

accRaw = rOsc - rOsc[stepLen] - (rOsc[stepLen] - rOsc[2 * stepLen])
acLo = lowest[winLen](accRaw)
acHi = highest[winLen](accRaw)
if acHi = acLo then
   fAcc = 0.5
else
   fAcc = (accRaw - acLo) / (acHi - acLo)
endif

fMid = abs(rOsc - 50.0) / 50.0

prCnt = 0
for p = 1 to winLen do
   if rOsc[p] <= rOsc then
      prCnt = prCnt + 1
   endif
next
fPct = prCnt / winLen

churnRaw = std[14](rOsc)
chLo = lowest[winLen](churnRaw)
chHi = highest[winLen](churnRaw)
if chHi = chLo then
   fChn = 0.5
else
   fChn = (churnRaw - chLo) / (chHi - chLo)
endif

spreadRaw = rOscF - rOscS
spLo = lowest[winLen](spreadRaw)
spHi = highest[winLen](spreadRaw)
if spHi = spLo then
   fSpr = 0.5
else
   fSpr = (spreadRaw - spLo) / (spHi - spLo)
endif

emaR20 = average[20, 1](rOsc)
regRaw = emaR20 - 50.0
rgLo = lowest[winLen](regRaw)
rgHi = highest[winLen](regRaw)
if rgHi = rgLo then
   fReg = 0.5
else
   fReg = (regRaw - rgLo) / (rgHi - rgLo)
endif

moveFwd = src - src[horizonBars]
bandFwd = atrFactor * atrVal[horizonBars]
if moveFwd > 2 * bandFwd then
   outcome = 3
elsif moveFwd > bandFwd then
   outcome = 2
elsif moveFwd > 0 then
   outcome = 1
elsif moveFwd < -2 * bandFwd then
   outcome = -3
elsif moveFwd < -bandFwd then
   outcome = -2
elsif moveFwd < 0 then
   outcome = -1
else
   outcome = 0
endif

once bankPtr = 0
once bankRows = 0
once writeCnt = 0

if barindex > horizonBars + winLen then
   writeCnt = writeCnt + 1
   if writeCnt >= spacingBars then
      writeCnt = 0
      $bVal[bankPtr] = fVal[horizonBars]
      $bSlp[bankPtr] = fSlp[horizonBars]
      $bAcc[bankPtr] = fAcc[horizonBars]
      $bMid[bankPtr] = fMid[horizonBars]
      $bPct[bankPtr] = fPct[horizonBars]
      $bChn[bankPtr] = fChn[horizonBars]
      $bSpr[bankPtr] = fSpr[horizonBars]
      $bReg[bankPtr] = fReg[horizonBars]
      $bOut[bankPtr] = outcome
      bankPtr = bankPtr + 1
      if bankPtr >= bankCap then
         bankPtr = 0
      endif
      if bankRows < bankCap then
         bankRows = bankRows + 1
      endif
   endif
endif

for n = 0 to kNeighbors - 1 do
   $kgap[n] = 10000000000
   $kcls[n] = 0
next

if bankRows > 1 then
   for idx = 0 to bankRows - 1 do
      dist = wVal * log(1 + abs(fVal - $bVal[idx])) + wSlp * log(1 + abs(fSlp - $bSlp[idx])) + wAcc * log(1 + abs(fAcc - $bAcc[idx])) + wMid * log(1 + abs(fMid - $bMid[idx])) + wPct * log(1 + abs(fPct - $bPct[idx])) + wChn * log(1 + abs(fChn - $bChn[idx])) + wSpr * log(1 + abs(fSpr - $bSpr[idx])) + wReg * log(1 + abs(fReg - $bReg[idx]))
      worst = 0
      worstGap = $kgap[0]
      for j = 1 to kNeighbors - 1 do
         if $kgap[j] > worstGap then
            worstGap = $kgap[j]
            worst = j
         endif
      next
      if dist < worstGap then
         $kgap[worst] = dist
         $kcls[worst] = $bOut[idx]
      endif
   next
endif

voteTotal = 0.0
voteScore = 0.0
voteBull  = 0.0
voteBear  = 0.0
kCount    = 0
gapSum    = 0.0
for n = 0 to kNeighbors - 1 do
   if $kgap[n] < 10000000000 then
      wgt = 1.0 / (1.0 + $kgap[n])
      voteTotal = voteTotal + wgt
      voteScore = voteScore + $kcls[n] * wgt
      if $kcls[n] > 0 then
         voteBull = voteBull + wgt
      elsif $kcls[n] < 0 then
         voteBear = voteBear + wgt
      endif
      gapSum = gapSum + $kgap[n]
      kCount = kCount + 1
   endif
next

if voteTotal > 0 then
   analogScore = voteScore / voteTotal
else
   analogScore = 0.0
endif

if voteTotal > 0 and analogScore > 0.15 then
   biasDir = 1
elsif voteTotal > 0 and analogScore < -0.15 then
   biasDir = -1
else
   biasDir = 0
endif

if voteTotal > 0 and biasDir = 1 then
   agreeFrac = voteBull / voteTotal
elsif voteTotal > 0 and biasDir = -1 then
   agreeFrac = voteBear / voteTotal
else
   agreeFrac = 0.0
endif

if kCount > 0 then
   avgGap = gapSum / kCount
else
   avgGap = 0.0
endif
wSum = wVal + wSlp + wAcc + wMid + wPct + wChn + wSpr + wReg
gapScale = wSum * 0.45 + 0.000000001
gapTight = max(0.0, min(1.0, 1.0 - avgGap / gapScale))

emaTrend = average[trendLen, 1](src)
emaQuick = average[5, 1](src)
if atrVal > 0 then
   trendForce = abs(emaQuick - emaTrend) / atrVal
else
   trendForce = 0
endif
chopRaw = trendForce < chopCut
if useChop then
   chopNow = chopRaw
else
   chopNow = 0
endif

convInst = max(-1.0, min(1.0, analogScore / 1.5))
convSmoothed = average[smoothLen, 1](convInst)
mlDriveBase = abs(convSmoothed) * 0.5 + gapTight * 0.3 + agreeFrac * 0.2
mlDrive = max(0.0, min(1.0, mlDriveBase))
if chopNow then
   mlDrive = mlDrive * 0.35
endif

adaptMult = stMultBase * (1.0 + stMlResp * (1.0 - mlDrive))
stAtr  = averagetruerange[stAtrLen]
upBand = stSrc - adaptMult * stAtr
dnBand = stSrc + adaptMult * stAtr

if barindex <= 1 then
   stLong = upBand
   stShort = dnBand
   stDir = 1
else
   if close[1] > stLong[1] then
      stLong = max(upBand, stLong[1])
   else
      stLong = upBand
   endif
   if close[1] < stShort[1] then
      stShort = min(dnBand, stShort[1])
   else
      stShort = dnBand
   endif
   if stDir[1] = -1 and close > stShort[1] then
      stDir = 1
   elsif stDir[1] = 1 and close < stLong[1] then
      stDir = -1
   else
      stDir = stDir[1]
   endif
endif

atrPctCnt = 0
for q = 1 to 100 do
   if atrVal[q] <= atrVal then
      atrPctCnt = atrPctCnt + 1
   endif
next
atrPct = atrPctCnt

slopeUp = rOsc > rOsc[stepLen]
oscReg  = emaR20
volHealthy = atrPct >= volBandLo and atrPct <= volBandHi
slopeFit = (biasDir = 1 and slopeUp) or (biasDir = -1 and slopeUp = 0)
stretched = (biasDir = 1 and rOsc > 70) or (biasDir = -1 and rOsc < 30)
emaR5 = average[5, 1](rOsc)
oscSmoothUp = emaR5 > emaR5[1]
trendAligned = (biasDir = 1 and stDir = 1) or (biasDir = -1 and stDir = -1)

once stanceState = 0
once stanceAge   = 0

if useTrendGate then
   gateTrend = trendAligned
else
   gateTrend = 1
endif
if useVolBand then
   gateVol = volHealthy
else
   gateVol = 1
endif
gatesPass = gateTrend and gateVol and (chopNow = 0)

if biasDir = 1 and gatesPass then
   stanceState = 1
elsif biasDir = -1 and gatesPass then
   stanceState = -1
else
   stanceState = stanceState[1]
endif

stanceChanged = stanceState <> stanceState[1]
if stanceChanged then
   stanceAge = 0
else
   stanceAge = stanceAge[1] + 1
endif
earlyFlip = stanceChanged and (stanceChanged[1] or stanceChanged[2] or stanceChanged[3])

pAgree = 25.0 * agreeFrac
pGap   = 15.0 * gapTight

if slopeFit then
   pStructA = 10.0
else
   pStructA = 0.0
endif
if stretched then
   pStructB = 0.0
else
   pStructB = 5.0
endif
pStruct = pStructA + pStructB

if trendAligned then
   pTrend = 10.0
else
   pTrend = 0.0
endif

if volHealthy then
   pVol = 10.0
elsif atrPct < volBandLo then
   pVol = 5.0
else
   pVol = 3.0
endif

regFit = (biasDir = 1 and oscReg > 55) or (biasDir = -1 and oscReg < 45)
if regFit then
   pReg = 10.0
elsif oscReg >= 45 and oscReg <= 55 then
   pReg = 4.0
else
   pReg = 6.0
endif

if (biasDir = 1 and oscSmoothUp) or (biasDir = -1 and oscSmoothUp = 0) then
   pSmooth = 5.0
else
   pSmooth = 0.0
endif

pHold = min(5.0, stanceAge)

penChop = 0.0
if chopRaw then
   penChop = 8.0
endif
penStr = 0.0
if stretched then
   penStr = 6.0
endif
penFlip = 0.0
if earlyFlip then
   penFlip = 6.0
endif
penK = 0.0
if kCount < kNeighbors then
   penK = 5.0 * (kNeighbors - kCount) / kNeighbors
endif
pPen = min(20.0, penChop + penStr + penFlip + penK)

rawRank = pAgree + pGap + pStruct + pTrend + pVol + pReg + pSmooth + pHold - pPen
if biasDir = 0 then
   rankVal = 0.0
else
   rankVal = max(0.0, min(100.0, rawRank))
endif

intensity = max(0.0, min(1.0, average[3, 1](rankVal) / 100.0))
mlTilt = max(-1.0, min(1.0, convSmoothed)) * intensity * 18.0
mlRSI = average[3, 1](max(0.0, min(100.0, rOsc + mlTilt)))

gradPos = max(0.0, min(1.0, (mlRSI - 28.0) / 44.0))
rCol = round(bearR + (bullR - bearR) * gradPos)
gCol = round(bearG + (bullG - bearG) * gradPos)
bCol = round(bearB + (bullB - bearB) * gradPos)

if maType = 1 or maType = 2 then
   sigLine = average[maLen](mlRSI)
elsif maType = 3 then
   sigLine = average[maLen, 1](mlRSI)
elsif maType = 4 then
   sigLine = average[maLen, 3](mlRSI)
elsif maType = 5 then
   sigLine = average[maLen, 2](mlRSI)
elsif maType = 6 then
   volSum = summation[maLen](volume)
   if volSum > 0 then
      sigLine = summation[maLen](mlRSI * volume) / volSum
   else
      sigLine = undefined
   endif
else
   sigLine = undefined
endif

if maType = 2 then
   bbDev = std[maLen](mlRSI) * bbMult
   bbUp = sigLine + bbDev
   bbDn = sigLine - bbDev
else
   bbUp = undefined
   bbDn = undefined
endif

return mlRSI as "ML RSI" coloured(rCol, gCol, bCol) style(line, 2), sigLine as "Signal" coloured(227, 177, 58), bbUp as "BB Up" coloured(150, 150, 150), bbDn as "BB Dn" coloured(150, 150, 150), 70 as "OB", 50 as "Mid", 30 as "OS"

Indicator 2/2 — ML Supertrend + Signals (overlay)

Load on the price chart with matching rsiBase, memoryDepth, kNeighbors.

// ============================================================
// PRC_Machine Learning RSI (Zeiierman) 
// version = 0
// 05.06.2026
// Iván González @ www.prorealcode.com
// Sharing ProRealTime knowledge
// ============================================================

rsiBase     = 14
memoryDepth = 400
kNeighbors  = 8
winLen      = 100
spacingBars = 4
horizonBars = 4
atrFactor   = 0.5

wVal = 1.0
wSlp = 1.0
wAcc = 1.0
wMid = 1.0
wPct = 1.0
wChn = 1.0
wSpr = 1.0
wReg = 1.0

stMultBase = 1.5
stMlResp   = 1.0
stAtrLen   = 10
trendLen   = 50
chopCut    = 0.5
useChop    = 1
smoothLen  = 10

gateRank     = 60
gateConf     = 50
useTrendGate = 1
useVolBand   = 1
volBandLo    = 20
volBandHi    = 85
coolBars     = 5

bankCap = round(memoryDepth / spacingBars)
src     = close
stSrc   = (high + low) / 2

rOsc   = rsi[rsiBase](src)
rfastL = max(2, round(rsiBase / 2))
rOscF  = rsi[rfastL](src)
rOscS  = rsi[rsiBase * 2](src)
atrVal = averagetruerange[14]
stepLen = 3

fVal = rOsc / 100.0

slopeRaw = rOsc - rOsc[stepLen]
slLo = lowest[winLen](slopeRaw)
slHi = highest[winLen](slopeRaw)
if slHi = slLo then
   fSlp = 0.5
else
   fSlp = (slopeRaw - slLo) / (slHi - slLo)
endif

accRaw = rOsc - rOsc[stepLen] - (rOsc[stepLen] - rOsc[2 * stepLen])
acLo = lowest[winLen](accRaw)
acHi = highest[winLen](accRaw)
if acHi = acLo then
   fAcc = 0.5
else
   fAcc = (accRaw - acLo) / (acHi - acLo)
endif

fMid = abs(rOsc - 50.0) / 50.0

prCnt = 0
for p = 1 to winLen do
   if rOsc[p] <= rOsc then
      prCnt = prCnt + 1
   endif
next
fPct = prCnt / winLen

churnRaw = std[14](rOsc)
chLo = lowest[winLen](churnRaw)
chHi = highest[winLen](churnRaw)
if chHi = chLo then
   fChn = 0.5
else
   fChn = (churnRaw - chLo) / (chHi - chLo)
endif

spreadRaw = rOscF - rOscS
spLo = lowest[winLen](spreadRaw)
spHi = highest[winLen](spreadRaw)
if spHi = spLo then
   fSpr = 0.5
else
   fSpr = (spreadRaw - spLo) / (spHi - spLo)
endif

emaR20 = average[20, 1](rOsc)
regRaw = emaR20 - 50.0
rgLo = lowest[winLen](regRaw)
rgHi = highest[winLen](regRaw)
if rgHi = rgLo then
   fReg = 0.5
else
   fReg = (regRaw - rgLo) / (rgHi - rgLo)
endif

moveFwd = src - src[horizonBars]
bandFwd = atrFactor * atrVal[horizonBars]
if moveFwd > 2 * bandFwd then
   outcome = 3
elsif moveFwd > bandFwd then
   outcome = 2
elsif moveFwd > 0 then
   outcome = 1
elsif moveFwd < -2 * bandFwd then
   outcome = -3
elsif moveFwd < -bandFwd then
   outcome = -2
elsif moveFwd < 0 then
   outcome = -1
else
   outcome = 0
endif

once bankPtr = 0
once bankRows = 0
once writeCnt = 0

if barindex > horizonBars + winLen then
   writeCnt = writeCnt + 1
   if writeCnt >= spacingBars then
      writeCnt = 0
      $bVal[bankPtr] = fVal[horizonBars]
      $bSlp[bankPtr] = fSlp[horizonBars]
      $bAcc[bankPtr] = fAcc[horizonBars]
      $bMid[bankPtr] = fMid[horizonBars]
      $bPct[bankPtr] = fPct[horizonBars]
      $bChn[bankPtr] = fChn[horizonBars]
      $bSpr[bankPtr] = fSpr[horizonBars]
      $bReg[bankPtr] = fReg[horizonBars]
      $bOut[bankPtr] = outcome
      bankPtr = bankPtr + 1
      if bankPtr >= bankCap then
         bankPtr = 0
      endif
      if bankRows < bankCap then
         bankRows = bankRows + 1
      endif
   endif
endif

for n = 0 to kNeighbors - 1 do
   $kgap[n] = 10000000000
   $kcls[n] = 0
next

if bankRows > 1 then
   for idx = 0 to bankRows - 1 do
      dist = wVal * log(1 + abs(fVal - $bVal[idx])) + wSlp * log(1 + abs(fSlp - $bSlp[idx])) + wAcc * log(1 + abs(fAcc - $bAcc[idx])) + wMid * log(1 + abs(fMid - $bMid[idx])) + wPct * log(1 + abs(fPct - $bPct[idx])) + wChn * log(1 + abs(fChn - $bChn[idx])) + wSpr * log(1 + abs(fSpr - $bSpr[idx])) + wReg * log(1 + abs(fReg - $bReg[idx]))
      worst = 0
      worstGap = $kgap[0]
      for j = 1 to kNeighbors - 1 do
         if $kgap[j] > worstGap then
            worstGap = $kgap[j]
            worst = j
         endif
      next
      if dist < worstGap then
         $kgap[worst] = dist
         $kcls[worst] = $bOut[idx]
      endif
   next
endif

voteTotal = 0.0
voteScore = 0.0
voteBull  = 0.0
voteBear  = 0.0
kCount    = 0
gapSum    = 0.0
for n = 0 to kNeighbors - 1 do
   if $kgap[n] < 10000000000 then
      wgt = 1.0 / (1.0 + $kgap[n])
      voteTotal = voteTotal + wgt
      voteScore = voteScore + $kcls[n] * wgt
      if $kcls[n] > 0 then
         voteBull = voteBull + wgt
      elsif $kcls[n] < 0 then
         voteBear = voteBear + wgt
      endif
      gapSum = gapSum + $kgap[n]
      kCount = kCount + 1
   endif
next

if voteTotal > 0 then
   analogScore = voteScore / voteTotal
else
   analogScore = 0.0
endif

if voteTotal > 0 and analogScore > 0.15 then
   biasDir = 1
elsif voteTotal > 0 and analogScore < -0.15 then
   biasDir = -1
else
   biasDir = 0
endif

if voteTotal > 0 and biasDir = 1 then
   agreeFrac = voteBull / voteTotal
elsif voteTotal > 0 and biasDir = -1 then
   agreeFrac = voteBear / voteTotal
else
   agreeFrac = 0.0
endif

if kCount > 0 then
   avgGap = gapSum / kCount
else
   avgGap = 0.0
endif
wSum = wVal + wSlp + wAcc + wMid + wPct + wChn + wSpr + wReg
gapScale = wSum * 0.45 + 0.000000001
gapTight = max(0.0, min(1.0, 1.0 - avgGap / gapScale))

emaTrend = average[trendLen, 1](src)
emaQuick = average[5, 1](src)
if atrVal > 0 then
   trendForce = abs(emaQuick - emaTrend) / atrVal
else
   trendForce = 0
endif
chopRaw = trendForce < chopCut
if useChop then
   chopNow = chopRaw
else
   chopNow = 0
endif

convInst = max(-1.0, min(1.0, analogScore / 1.5))
convSmoothed = average[smoothLen, 1](convInst)
mlDriveBase = abs(convSmoothed) * 0.5 + gapTight * 0.3 + agreeFrac * 0.2
mlDrive = max(0.0, min(1.0, mlDriveBase))
if chopNow then
   mlDrive = mlDrive * 0.35
endif

adaptMult = stMultBase * (1.0 + stMlResp * (1.0 - mlDrive))
stAtr  = averagetruerange[stAtrLen]
upBand = stSrc - adaptMult * stAtr
dnBand = stSrc + adaptMult * stAtr

if barindex <= 1 then
   stLong = upBand
   stShort = dnBand
   stDir = 1
else
   if close[1] > stLong[1] then
      stLong = max(upBand, stLong[1])
   else
      stLong = upBand
   endif
   if close[1] < stShort[1] then
      stShort = min(dnBand, stShort[1])
   else
      stShort = dnBand
   endif
   if stDir[1] = -1 and close > stShort[1] then
      stDir = 1
   elsif stDir[1] = 1 and close < stLong[1] then
      stDir = -1
   else
      stDir = stDir[1]
   endif
endif

if stDir = 1 then
   stLine = stLong
   r = 33
   g = 87
   b = 243
else
   stLine = stShort
   r = 242
   g = 54
   b = 69
endif

atrPctCnt = 0
for q = 1 to 100 do
   if atrVal[q] <= atrVal then
      atrPctCnt = atrPctCnt + 1
   endif
next
atrPct = atrPctCnt

slopeUp = rOsc > rOsc[stepLen]
oscReg  = emaR20
volHealthy = atrPct >= volBandLo and atrPct <= volBandHi
slopeFit = (biasDir = 1 and slopeUp) or (biasDir = -1 and slopeUp = 0)
stretched = (biasDir = 1 and rOsc > 70) or (biasDir = -1 and rOsc < 30)
emaR5 = average[5, 1](rOsc)
oscSmoothUp = emaR5 > emaR5[1]
trendAligned = (biasDir = 1 and stDir = 1) or (biasDir = -1 and stDir = -1)

once stanceState = 0
once stanceAge   = 0
once lastEntryBar = -1000

if useTrendGate then
   gateTrend = trendAligned
else
   gateTrend = 1
endif
if useVolBand then
   gateVol = volHealthy
else
   gateVol = 1
endif
gatesPass = gateTrend and gateVol and (chopNow = 0)

if biasDir = 1 and gatesPass then
   stanceState = 1
elsif biasDir = -1 and gatesPass then
   stanceState = -1
else
   stanceState = stanceState[1]
endif

stanceChanged = stanceState <> stanceState[1]
if stanceChanged then
   stanceAge = 0
else
   stanceAge = stanceAge[1] + 1
endif
earlyFlip = stanceChanged and (stanceChanged[1] or stanceChanged[2] or stanceChanged[3])

pAgree = 25.0 * agreeFrac
pGap   = 15.0 * gapTight

if slopeFit then
   pStructA = 10.0
else
   pStructA = 0.0
endif
if stretched then
   pStructB = 0.0
else
   pStructB = 5.0
endif
pStruct = pStructA + pStructB

if trendAligned then
   pTrend = 10.0
else
   pTrend = 0.0
endif

if volHealthy then
   pVol = 10.0
elsif atrPct < volBandLo then
   pVol = 5.0
else
   pVol = 3.0
endif

regFit = (biasDir = 1 and oscReg > 55) or (biasDir = -1 and oscReg < 45)
if regFit then
   pReg = 10.0
elsif oscReg >= 45 and oscReg <= 55 then
   pReg = 4.0
else
   pReg = 6.0
endif

if (biasDir = 1 and oscSmoothUp) or (biasDir = -1 and oscSmoothUp = 0) then
   pSmooth = 5.0
else
   pSmooth = 0.0
endif

pHold = min(5.0, stanceAge)

penChop = 0.0
if chopRaw then
   penChop = 8.0
endif
penStr = 0.0
if stretched then
   penStr = 6.0
endif
penFlip = 0.0
if earlyFlip then
   penFlip = 6.0
endif
penK = 0.0
if kCount < kNeighbors then
   penK = 5.0 * (kNeighbors - kCount) / kNeighbors
endif
pPen = min(20.0, penChop + penStr + penFlip + penK)

rawRank = pAgree + pGap + pStruct + pTrend + pVol + pReg + pSmooth + pHold - pPen
if biasDir = 0 then
   rankVal = 0.0
else
   rankVal = max(0.0, min(100.0, rawRank))
endif

if slopeFit then
   confSlope = 10.0
else
   confSlope = 0.0
endif
confFlipPen = 0.0
if earlyFlip then
   confFlipPen = 15.0
endif
confKPen = 0.0
if kCount < kNeighbors then
   confKPen = 10.0 * (kNeighbors - kCount) / kNeighbors
endif
confRaw = 40.0 * agreeFrac + 25.0 * gapTight + 15.0 * min(1.0, stanceAge / 5.0) + confSlope - confFlipPen - confKPen
if biasDir = 0 then
   confVal = 0.0
else
   confVal = max(0.0, min(100.0, confRaw))
endif

flipLong  = stanceState = 1 and stanceState[1] <> 1
flipShort = stanceState = -1 and stanceState[1] <> -1
qualifies = rankVal >= gateRank and confVal >= gateConf
coolOK    = barindex - lastEntryBar >= coolBars
triggerLong  = flipLong and qualifies and coolOK
triggerShort = flipShort and qualifies and coolOK
if triggerLong or triggerShort then
   lastEntryBar = barindex
endif

placebuy  = lowest[5](low) - 0.25 * atrVal
placesell = highest[5](high) + 0.25 * atrVal
if triggerLong then
   drawtext("▲", barindex, placebuy) coloured(50, 205, 50)
endif
if triggerShort then
   drawtext("▼", barindex, placesell) coloured(242, 54, 69)
endif

return stLine as "ML Supertrend" coloured(r, g, b)

Download
Filename: PRC_Machine-Learning-RSI_price.itf
Downloads: 22
Download
Filename: PRC_Machine-Learning-RSI.itf
Downloads: 18
Iván González Legend
Currently debugging life, so my bio is on hold. Check back after the next commit for an update.
Author’s Profile

Comments

Logo Logo
Loading...