
Esta estrategia es un sistema de negociación que combina la señal de cruce de la línea media con un filtro de estado de mercado. Captura la tendencia del mercado mediante la cruce de una media móvil simple de 9 y 21 períodos (SMA) y utiliza el índice de dirección promedio (ADX) y el índice de caos (Choppiness Index, CI) para filtrar el entorno del mercado y garantizar que se negocie solo en mercados con una tendencia clara y con buenas características de volatilidad. Este método combina eficazmente las estrategias tradicionales de seguimiento de tendencias con los indicadores tecnológicos modernos y ofrece un marco de negociación más sólido.
La lógica central de la estrategia incluye tres componentes clave:
La estrategia utiliza un método optimizado de cálculo de indicadores técnicos, que incluye una función de suma, un cálculo de valores máximos y mínimos personalizados, y un cálculo estandarizado de la amplitud de onda real (TR), lo que garantiza la precisión de la señal y la eficiencia del cálculo.
La estrategia combina la clásica estrategia de cruce de línea uniforme con los indicadores tecnológicos modernos para construir un sistema de negociación completo. No solo se centra en la captura de tendencias, sino también en la adecuación al entorno del mercado, aumentando la estabilidad de las operaciones mediante un mecanismo de filtración múltiple. Aunque hay ciertos problemas de sensibilidad a los parámetros y atraso, la estrategia aún tiene un gran espacio para mejorar con la dirección de optimización propuesta.
/*backtest
start: 2024-02-22 00:00:00
end: 2024-12-06 00:00:00
period: 1d
basePeriod: 1d
exchanges: [{"eid":"Binance","currency":"ETH_USDT"}]
*/
//@version=6
strategy("MA9/MA21 Cross with ADX & CHOP Filter", overlay=true, initial_capital=10000, currency=currency.USD)
// ─── CUSTOM FUNCTIONS ──────────────────────────────────────────────────────
// Custom function to compute the sum over the last 'len' bars.
f_sum(src, len) =>
s = 0.0
for i = 0 to len - 1
s += src[i]
s
// Custom function to compute the highest value over the last 'len' bars.
f_highest(src, len) =>
h = src[0]
for i = 1 to len - 1
h := math.max(h, src[i])
h
// Custom function to compute the lowest value over the last 'len' bars.
f_lowest(src, len) =>
l = src[0]
for i = 1 to len - 1
l := math.min(l, src[i])
l
// ─── INPUTS ──────────────────────────────────────────────────────────────
ma9Period = input.int(9, title="MA 9 Period", minval=1)
ma21Period = input.int(21, title="MA 21 Period", minval=1)
adxLength = input.int(7, title="ADX Smoothing / DI Length", minval=1)
adxThresh = input.float(20.0, title="ADX Threshold", step=0.1)
chopLen = input.int(7, title="CHOP Length", minval=1)
chopOff = input.int(0, title="CHOP Offset", minval=0) // Not applied in calculation
chopThresh = input.float(50.0, title="CHOP Maximum (do not trade if above)", step=0.1)
// ─── CALCULATE INDICATORS ────────────────────────────────────────────────────
// Moving Averages
ma9 = ta.sma(close, ma9Period)
ma21 = ta.sma(close, ma21Period)
// --- True Range Calculation ---
// Manual implementation of true range (tr)
tr = math.max(math.max(high - low, math.abs(high - nz(close[1]))), math.abs(low - nz(close[1])))
// --- ADX Calculation (Manual Implementation) ---
// Calculate directional movements
upMove = high - nz(high[1])
downMove = nz(low[1]) - low
plusDM = (upMove > downMove and upMove > 0) ? upMove : 0.0
minusDM = (downMove > upMove and downMove > 0) ? downMove : 0.0
// Smooth the values using the built-in rma function
atr = ta.rma(tr, adxLength)
plusDI = 100 * ta.rma(plusDM, adxLength) / atr
minusDI = 100 * ta.rma(minusDM, adxLength) / atr
dx = 100 * math.abs(plusDI - minusDI) / (plusDI + minusDI)
adxValue = ta.rma(dx, adxLength)
// --- Choppiness Index Calculation ---
// Compute the sum of true range over chopLen periods
atrSum = f_sum(tr, chopLen)
// Compute highest high and lowest low over chopLen periods using custom functions
highestHigh = f_highest(high, chopLen)
lowestLow = f_lowest(low, chopLen)
priceRange = highestHigh - lowestLow
chop = priceRange != 0 ? 100 * math.log(atrSum / priceRange) / math.log(chopLen) : 0
// ─── STRATEGY CONDITIONS ─────────────────────────────────────────────────────
// MA Crossover Signals
longCond = ta.crossover(ma9, ma21)
shortCond = ta.crossunder(ma9, ma21)
// Filter: Only trade if ADX > threshold and CHOP ≤ threshold.
filterCond = (adxValue > adxThresh) and (chop <= chopThresh)
// Entries and Exits
if longCond and filterCond
strategy.entry("Long", strategy.long)
if shortCond and filterCond
strategy.entry("Short", strategy.short)
if shortCond
strategy.close("Long")
if longCond
strategy.close("Short")
// ─── PLOTTING ──────────────────────────────────────────────────────────────
plot(ma9, color=color.red, title="MA 9")
plot(ma21, color=color.blue, title="MA 21")
plot(adxValue, title="ADX", color=color.purple)
hline(adxThresh, title="ADX Threshold", color=color.purple, linestyle=hline.style_dotted)
plot(chop, title="CHOP", color=color.orange)
hline(chopThresh, title="CHOP Threshold", color=color.orange, linestyle=hline.style_dotted)