Hoy he han hecho referencia en el foro a este indicador así que aquí va una actualización. He incluido filtros de tendencia adicionales.
// ============================================================
// PRC_Machine Learning: Lorentzian Classification [@jdehorty]
// version = 1
// 09.02.2026
// Iván González @ www.prorealcode.com
// Sharing ProRealTime knowledge
// ============================================================
defparam calculateonlastbars = 1000
// ============================================================
// ==== PARÁMETROS GENERALES ====
// ============================================================
neighborsCount = 8 // Número de vecinos K
maxBarsBack = 700 // Ventana histórica
featureCount = 5 // Features para distancia
// Filtros EMA/SMA (0=desactivado, 1=activado)
useEmaFilter = 0
emaPeriod = 200
useSmaFilter = 0
smaPeriod = 200
// Filtros ML (0=desactivado, 1=activado)
useVolatilityFilter = 1 // ATR reciente > ATR histórico
useRegimeFilter = 1 // Detección trending/ranging con KLMF
regimeThreshold = -0.1 // Umbral régimen (-10 a 10, default -0.1)
useAdxFilter = 0 // ADX > umbral
adxThreshold = 20 // Umbral ADX (0-100)
// Kernel Regression
useKernelFilter = 1
useKernelSmoothing = 0 // 0=rate of change, 1=crossover yhat2/yhat1
lookbackWindow = 8
relWeight = 8
regLevel = 25
kLag = 2
// ============================================================
// ==== CÁLCULO DE FEATURES (NORMALIZADAS) ====
// ============================================================
// Feature 1: RSI(14) normalizado
f1raw = RSI[14](close)
f1lo = lowest[maxBarsBack](f1raw)
f1hi = highest[maxBarsBack](f1raw)
f1 = (f1raw - f1lo) / max(0.0001, f1hi - f1lo)
// Feature 2: Wave Trend(10,11) normalizado
ap = (high + low + close) / 3
esa = average[10,1](ap)
d1 = average[10,1](abs(ap - esa))
ci = (ap - esa) / (0.015 * d1)
f2raw = average[11,1](ci)
f2lo = lowest[maxBarsBack](f2raw)
f2hi = highest[maxBarsBack](f2raw)
f2 = (f2raw - f2lo) / max(0.0001, f2hi - f2lo)
// Feature 3: CCI(20) normalizado
f3raw = CCI[20](close)
f3lo = lowest[maxBarsBack](f3raw)
f3hi = highest[maxBarsBack](f3raw)
f3 = (f3raw - f3lo) / max(0.0001, f3hi - f3lo)
// Feature 4: ADX(20) normalizado
f4raw = ADX[20]
f4lo = lowest[maxBarsBack](f4raw)
f4hi = highest[maxBarsBack](f4raw)
f4 = (f4raw - f4lo) / max(0.0001, f4hi - f4lo)
// Feature 5: RSI(9) normalizado
f5raw = RSI[9](close)
f5lo = lowest[maxBarsBack](f5raw)
f5hi = highest[maxBarsBack](f5raw)
f5 = (f5raw - f5lo) / max(0.0001, f5hi - f5lo)
// ============================================================
// ==== NEXT BAR CLASSIFICATION (Training Labels) ====
// ============================================================
src = close
IF src[4] < src[0] THEN
yTrainSeries = -1
ELSIF src[4] > src[0] THEN
yTrainSeries = 1
ELSE
yTrainSeries = 0
ENDIF
// ============================================================
// ==== CORE ML LOGIC: KNN con Distancia Lorentziana ====
// ============================================================
lastDistance = -1.0
mySize = min(maxBarsBack - 1, barindex - 1)
sizeLoop = min(maxBarsBack - 1, mySize)
IF barindex >= maxBarsBack THEN
nn = 0
FOR i = 0 TO sizeLoop DO
d = LOG(1 + ABS(f1 - f1[i])) + LOG(1 + ABS(f2 - f2[i])) + LOG(1 + ABS(f3 - f3[i])) + LOG(1 + ABS(f4 - f4[i])) + LOG(1 + ABS(f5 - f5[i]))
IF d >= lastDistance AND (i MOD 4) <> 0 THEN
lastDistance = d
nn = nn + 1
$distances[nn] = d
$predictions[nn] = round(yTrainSeries[i])
IF nn > neighborsCount THEN
lastDistance = $distances[round(neighborsCount * 3 / 4)]
FOR k = 1 TO nn - 1 DO
$distances[k] = $distances[k + 1]
$predictions[k] = $predictions[k + 1]
NEXT
$distances[nn] = 0
$predictions[nn] = 0
nn = nn - 1
ENDIF
ENDIF
NEXT
prediction = 0
FOR j = 1 TO nn DO
prediction = prediction + $predictions[j]
NEXT
ENDIF
// ============================================================
// ==== FILTROS ML ====
// ============================================================
// --- 1. Filtro de Volatilidad ---
IF useVolatilityFilter THEN
recentAtr = averagetruerange[1]
historicalAtr = averagetruerange[10]
filterVolatility = (recentAtr > historicalAtr)
ELSE
filterVolatility = 1
ENDIF
// --- 2. Filtro de Régimen (KLMF - Kaufman Adaptive) ---
ohlc4src = (open + high + low + close) / 4
IF (high - low) <> 0 THEN
value1 = 0.2 * (ohlc4src - ohlc4src[1]) + 0.8 * value1[1]
value2 = 0.1 * (high - low) + 0.8 * value2[1]
ENDIF
IF value2 <> 0 THEN
omega = abs(value1 / value2)
ELSE
omega = 0
ENDIF
alphaK = (-1 * POW(omega, 2) + SQRT(POW(omega, 4) + 16 * POW(omega, 2))) / 8
klmf = alphaK * ohlc4src + (1 - alphaK) * klmf[1]
curveSlope = abs(klmf - klmf[1])
avgSlope = average[200,1](curveSlope)
IF useRegimeFilter THEN
IF avgSlope <> 0 THEN
normalizedSlope = (curveSlope - avgSlope) / avgSlope
filterRegime = (normalizedSlope >= regimeThreshold)
ELSE
filterRegime = 1
ENDIF
ELSE
filterRegime = 1
ENDIF
// --- 3. Filtro ADX ---
IF useAdxFilter THEN
adxVal = ADX[14]
filterAdx = (adxVal > adxThreshold)
ELSE
filterAdx = 1
ENDIF
// --- Combinación de todos los filtros ---
filterAll = filterVolatility AND filterRegime AND filterAdx
// ============================================================
// ==== FILTROS DE PREDICCIÓN ====
// ============================================================
// --- EMA Trend Filter ---
IF useEmaFilter THEN
isEmaUptrend = (close > average[emaPeriod,1](close))
isEmaDowntrend = (close < average[emaPeriod,1](close))
ELSE
isEmaUptrend = 1
isEmaDowntrend = 1
ENDIF
// --- SMA Trend Filter ---
IF useSmaFilter THEN
isSmaUptrend = (close > average[smaPeriod](close))
isSmaDowntrend = (close < average[smaPeriod](close))
ELSE
isSmaUptrend = 1
isSmaDowntrend = 1
ENDIF
// --- Signal GATED por filterAll ---
IF prediction > 0 AND filterAll THEN
signal = 1
ELSIF prediction < 0 AND filterAll THEN
signal = -1
ENDIF
// --- Bar-Count Filter ---
IF signal <> signal[1] THEN
barsHeld = 0
ELSE
barsHeld = barsHeld + 1
ENDIF
isHeldFourBars = (barsHeld = 4)
isHeldLessThanFourBars = (barsHeld > 0 AND barsHeld < 4)
// --- Fractal Filters ---
isDifferentSignalType = (signal <> signal[1])
isEarlySignalFlip = isDifferentSignalType AND ((signal[1] <> signal[2]) OR (signal[2] <> signal[3]) OR (signal[3] <> signal[4]))
isBuySignal = (signal = 1) AND isEmaUptrend AND isSmaUptrend
isSellSignal = (signal = -1) AND isEmaDowntrend AND isSmaDowntrend
isNewBuySignal = isDifferentSignalType AND isBuySignal
isNewSellSignal = isDifferentSignalType AND isSellSignal
// ============================================================
// ==== KERNEL REGRESSION (Nadaraya-Watson) ====
// ============================================================
// --- Rational Quadratic Kernel (yhat1) ---
currentWeight1 = 0
cumulativeWeight1 = 0
FOR i = 0 TO lookbackWindow + regLevel DO
y = src[i]
w1 = POW(1 + (POW(i, 2) / (POW(lookbackWindow, 2) * 2 * relWeight)), -relWeight)
currentWeight1 = currentWeight1 + y * w1
cumulativeWeight1 = cumulativeWeight1 + w1
NEXT
yhat1 = currentWeight1 / cumulativeWeight1
// --- Gaussian Kernel (yhat2) ---
currentWeight2 = 0
cumulativeWeight2 = 0
gaussWindow = max(1, lookbackWindow - kLag)
FOR i = 0 TO gaussWindow + regLevel DO
y = src[i]
w2 = EXP(-POW(i, 2) / (2 * POW(gaussWindow, 2)))
currentWeight2 = currentWeight2 + y * w2
cumulativeWeight2 = cumulativeWeight2 + w2
NEXT
yhat2 = currentWeight2 / cumulativeWeight2
// --- Kernel Rates of Change ---
wasBearishRate = (yhat1[2] > yhat1[1])
wasBullishRate = (yhat1[2] < yhat1[1])
isBearishRate = (yhat1[1] > yhat1)
isBullishRate = (yhat1[1] < yhat1)
isBearishChange = isBearishRate AND wasBullishRate
isBullishChange = isBullishRate AND wasBearishRate
// --- Kernel Crossovers ---
isBullishSmooth = (yhat2 >= yhat1)
isBearishSmooth = (yhat2 <= yhat1)
// --- Aplicar filtro kernel según modo ---
IF useKernelFilter THEN
IF useKernelSmoothing THEN
isBullish = isBullishSmooth
isBearish = isBearishSmooth
ELSE
isBullish = isBullishRate
isBearish = isBearishRate
ENDIF
ELSE
isBullish = 1
isBearish = 1
ENDIF
// --- Kernel color ---
IF useKernelSmoothing THEN
IF isBullishSmooth THEN
cr = 0
cg = 153
cb = 136
ELSE
cr = 204
cg = 51
cb = 17
ENDIF
ELSE
IF isBullishRate THEN
cr = 0
cg = 153
cb = 136
ELSE
cr = 204
cg = 51
cb = 17
ENDIF
ENDIF
// ============================================================
// ==== ENTRY CONDITIONS ====
// ============================================================
startLongTrade = isNewBuySignal AND isBullish AND isEmaUptrend AND isSmaUptrend
startShortTrade = isNewSellSignal AND isBearish AND isEmaDowntrend AND isSmaDowntrend
// ============================================================
// ==== DISPLAY ====
// ============================================================
myRange = high - low
// Transparencia basada en fuerza de predicción (clamped 30-255)
IF prediction <> 0 THEN
maxPred = max(1, highest[300](abs(prediction)))
alphaVal = min(255, max(30, round(abs(prediction) / maxPred * 255)))
ELSE
alphaVal = 80
ENDIF
IF startLongTrade THEN
drawarrowup(barindex, low - myRange) coloured(0, 153, 136, alphaVal)
drawtext("#prediction#", barindex, low - 1.5 * myRange) coloured(0, 153, 136)
ELSIF startShortTrade THEN
drawarrowdown(barindex, high + myRange) coloured(204, 51, 17, alphaVal)
drawtext("#prediction#", barindex, high + 1.5 * myRange) coloured(204, 51, 17)
ENDIF
// ============================================================
RETURN yhat1 AS "Kernel Estimate" style(line, 2) coloured(cr, cg, cb)