Quant500 Academy

5. Osciladores: EMA y estocástico para detectar rebotes

Nivel 4: Screening de Acciones

El Trend Template de Minervini busca tendencias ya establecidas. El segundo screener que vas a construir busca algo distinto: el momento concreto en el que una acción, dentro de una tendencia alcista, rebota tras una pequeña corrección — una oportunidad de entrada, no solo una confirmación de tendencia.

Para esto se combinan dos herramientas: tres medias móviles exponenciales de distinta longitud, que definen la tendencia de fondo, y el oscilador estocástico, que mide si el precio está en zona de sobreventa a corto plazo.

def añadir_ema(precio, dias):
    return precio.ewm(span=dias).mean()

def añadir_estocastico(cierre, minimo, maximo, periodo, k, d=0):
    k_bruto = ((cierre - minimo.rolling(window=periodo).min()) /
               (maximo.rolling(window=periodo).max() - minimo.rolling(window=periodo).min())) * 100
    stoch_k = k_bruto.rolling(window=k).mean()
    if d == 0:
        return stoch_k
    return stoch_k.rolling(window=d).mean()

El oscilador estocástico compara el precio de cierre actual con el rango (mínimo-máximo) de los últimos periodo días, expresado en una escala de 0 a 100. Un valor cercano a 0 significa que el precio está cerca del mínimo reciente (posible sobreventa); un valor cercano a 100, que está cerca del máximo reciente (posible sobrecompra). Las variables k y d suavizan ese cálculo con una media móvil adicional, para reducir el ruido día a día.

Con las tres EMA (18, 50 y 100 días) y el estocástico ya calculados, la función que detecta el rebote comprueba tres condiciones sobre las dos últimas velas del precio:

def detectar_rebote(df):
    vela_actual = df.iloc[-1]
    vela_anterior = df.iloc[-2]

    tendencia_alcista = vela_actual["EMA18"] > vela_actual["EMA50"] > vela_actual["EMA100"]
    zona_sobreventa = vela_actual["STOCH_K"] <= 30 or vela_actual["STOCH_D"] <= 30
    rebote_confirmado = (vela_anterior["Low"] < vela_anterior["EMA50"]
                          and vela_anterior["Close"] > vela_anterior["EMA50"])

    return tendencia_alcista and zona_sobreventa and rebote_confirmado

La primera condición (tendencia_alcista) exige que las tres EMA estén alineadas de la más corta a la más larga — la misma lógica de alineación de medias que ya viste en el Trend Template, aplicada aquí con medias exponenciales en vez de simples. La segunda (zona_sobreventa) exige que el oscilador estocástico esté bajo, señal de que el precio se ha enfriado a corto plazo dentro de esa tendencia alcista de fondo. La tercera (rebote_confirmado) es la más específica: mira la vela anterior, no la actual, y comprueba que el precio mínimo de ese día tocó por debajo de la EMA de 50 pero el cierre terminó por encima — es decir, que el precio "pinchó" la media y se recuperó en el mismo día, el patrón visual clásico de un rebote sobre un soporte dinámico.

Este screener es más exigente en el tiempo que el de Minervini porque, al usar la vela anterior además de la actual, solo detecta la señal el día exacto en que ocurre — si no revisas el screener con frecuencia, te puedes perder la ventana de entrada que está buscando.

Para ampliar esta lección

El resto de Quant500

Lo que estás aprendiendo, aplicado al índice todos los días:

La cartera del modelo, cada semana en tu correo

Cada sábado, su semana en un minuto: cómo fue, lo mejor y lo peor, y qué directivos compraron con su dinero. Y el día que el modelo se rehace, qué entra y qué sale. Es una simulación, no un consejo. Como mucho un correo a la semana, sin publicidad y sin cuenta; te das de baja con un clic. Lo hace una persona: Pol Gracia.

Cartera modelo con resultados simulados, no una recomendación personalizada. Tu correo se usa solo para esto: privacidad.

Detrás de la Academia y del resto de Quant500 hay una sola persona: Pol Gracia Serrahima.