Bajo el capó

Cómo funciona LotteryCortex

LotteryCortex combina cuatro técnicas normalmente usadas solo por quants y data scientists. Las hacemos accesibles para cualquiera que compre un boleto.

Esta página describe cada algoritmo que ejecuta LotteryCortex — desde la ingesta de datos hasta la selección de tickets. Todo está abiertamente documentado: para cada paso nombramos el archivo fuente en el código. No es una solución milagrosa, sino la pila de análisis de lotería más completamente documentada públicamente que pudimos construir.

El pipeline en 7 pasos

Cada sorteo recorre esta cadena. Detalles por algoritmo más abajo.

  1. 01

    Ingesta de datos y detección de anomalías

    Por lotería raspamos los archivos oficiales (fetch HTML directo con fallback Firecrawl). Cada nuevo sorteo pasa por detectDrawAnomaly(): comprobación de forma, rango, duplicados y comparación chi-cuadrado contra los últimos 200 sorteos. Los sorteos sospechosos se bloquean antes de tocar el historial.

  2. 02

    Engine-core: seis señales base

    engine-core.ts calcula seis puntuaciones independientes por número (Bayes, EMA × 3 semividas, PMI, Markov), las normaliza a rangos y las combina con pesos ajustados en una puntuación de ensemble.

  3. 03

    Meta-learner y stacking GBM

    Las seis puntuaciones del motor + 6 features derivadas (interacciones, recencia, hot/cold streaks) alimentan una regresión logística por lotería (meta-learner.ts) y un modelo gradient boosted stumps (gbm.ts). El blender apilado combina ambos out-of-fold sin filtración.

  4. 04

    Generación de tickets con anti-clustering

    Muestreamos miles de tickets candidatos entre los números mejor puntuados, pero rechazamos todo lo que tenga demasiado clustering: máx 3 de la misma década, paridad dentro de la banda histórica, suma dentro de la banda IQR de sorteos reales.

  5. 05

    Optimización de cartera

    Selección greedy submodular (portfolio-optimizer.ts) + selector Markowitz de mínima varianza (markowitz.ts) eligen K tickets que juntos cubren la mayor masa de probabilidad con mínimo solape.

  6. 06

    Corrección de popularidad y EV gating

    popularity.ts penaliza combinaciones 'bonitas' (cumpleaños ≤ 31, secuencias consecutivas, mitad baja) porque al acertar hay que compartir. ev-gating calcula el EV consciente del jackpot por 1 € apostado y emite consejo de 'jugar' o 'saltarse'.

  7. 07

    Backtest walk-forward y auto-tuning

    Cada domingo se ejecuta una validación cruzada k-fold anidada (nested-cv.ts) más una grid-search sobre los pesos del motor y los presets de semividas. Un bandido Thompson-sampling (bandit.ts) selecciona en línea el preset con mejor rendimiento según el ROI realizado.

Índice — 20 algoritmos

Algoritmos en detalle

1. Encogimiento bayesiano de frecuencias

Cuántas veces se ha sorteado un número, corregido por la cantidad de datos disponibles.

  • La frecuencia bruta sobreestima los números 'calientes' cuando el historial es corto. Le superponemos una a priori de Dirichlet con estimación automática de alpha (dirichletAlphaAuto, método de los momentos sobre la varianza empírica).
  • El resultado es una probabilidad a posteriori por número que se encoge hacia 1/N (uniforme) mientras el historial es pequeño y sigue la verdadera frecuencia cuando hay suficientes sorteos.
p̂(n) = (count(n) + α) / (totalDraws · k + α · N)

src/lib/engine-core.ts · src/lib/advanced-stats.ts

2-4. EMA ponderado en el tiempo con múltiples semividas

Los sorteos recientes pesan más que los antiguos — tres horizontes en paralelo.

  • Para cada sorteo i desde el final asignamos peso w_i = 0.5^(i / H). Corremos tres EMAs en paralelo con H = 8, 26 y 78 sorteos (corto/medio/largo).
  • La semivida corta capta 'hot streaks'. La larga evita reaccionar exageradamente a un sorteo extraño. El blender de ensemble elige cuánto peso lleva cada horizonte por lotería — ajustado por grid-search.
EMA_H(n) = Σ_i  0.5^(i/H) · 1[n ∈ draw_i]

src/lib/engine-core.ts (HALF_LIVES = [8, 26, 78])

5. Boost de co-ocurrencia PMI

¿Qué números aparecen juntos más a menudo de lo que predeciría el azar?

  • Calculamos Pointwise Mutual Information: PMI(a,b) = log [P(a,b) / (P(a)·P(b))]. PMI positivo = el par aparece junto más de lo esperado bajo independencia.
  • Por número candidato sumamos el PMI con todos los números del sorteo más reciente. Eso da una señal 'sigue el patrón' sin sobreajustar: PMI está acotado y se recorta a ±3.
score_PMI(n) = Σ_{m ∈ lastDraw}  clip(log[P(n,m) / (P(n)P(m))], ±3)

src/lib/engine-core.ts

6. Probabilidades de transición de Markov

Desde el último sorteo estimamos la probabilidad de transición al siguiente número.

  • Construimos una matriz de transición N×N T con T[a,b] = P(b en draw_t+1 | a en draw_t), estimada con suavizado de Laplace.
  • Para la puntuación en vivo tomamos la media de T[a, n] sobre todos los a del último sorteo. Los números fríos no se mantienen fríos para siempre; este paso modela memoria finita.

src/lib/engine-core.ts

7. Ensemble y pesos ajustados

Las seis señales se fusionan vía agregación ponderada de rangos.

  • Cada señal se convierte a percentiles de rango [0, 1]. Luego se combinan linealmente con pesos w = (w_bayes, w_ema1, w_ema2, w_ema3, w_pmi, w_markov). Uniforme por defecto; ajustado por lotería vía grid-search + validación de ROI.
  • La agregación de rangos es robusta a diferencias de escala entre señales y evita que una puntuación atípica domine el ensemble.
score(n) = Σ_s  w_s · rank_s(n) / N

src/lib/engine-core.ts · src/lib/engine-tuning.functions.ts

8. Meta-learner (regresión logística, 12 features)

Una logreg por lotería aprende la combinación no lineal óptima de las señales del motor.

  • Vector de features (12 dim): los 6 rangos del motor + interacciones (EMA1·PMI, Bayes·Markov, EMA3·Bayes) + recencia + hot streak (apariciones en los últimos 10) + cold streak (ausencias consecutivas).
  • Entrenamiento: logreg regularizada L2 con SGD sobre todo el historial. Pérdida = log-loss sobre la etiqueta '1 si el número apareció en el siguiente sorteo'. Retrocompatible: los modelos antiguos de 9 dim siguen funcionando.
P(n en próximo sorteo) = σ(w · features(n) + b)

src/lib/meta-learner.ts

9. Gradient Boosted Decision Stumps

Segundo meta-learner que capta interacciones no lineales sin red neuronal.

  • Mini-clon de LightGBM: decision stumps iterativos sobre los residuos. Cada stump elige 1 feature + umbral que reduce al máximo la pérdida; añadimos lr · stump.output a la predicción actual.
  • La salida es serializable en JSON y se almacena junto a la logreg en engine_config.meta_weights.gbm. El blender apilado combina ambos.

src/lib/gbm.ts

10. Blender de stacking out-of-fold

Logreg + GBM se combinan sin filtración de datos.

  • Dividimos el historial en 5 folds estratificados. Por fold entrenamos logreg + GBM en 4 folds y predecimos en el fold retenido. Esas predicciones OOF se vuelven las entradas de una segunda capa meta-logreg que aprende la ponderación óptima.
  • Resultado: probabilidades calibrables sin que el meta-learner vuelva a ver sus propios datos de entrenamiento.

src/lib/advanced-stats-v3.ts · src/lib/nested-cv.ts

11. Calibración isotónica y de Platt

Las probabilidades brutas del modelo se monotonizan para que de verdad sean probabilidades.

  • Platt scaling ajusta una sigmoide de 1 parámetro sobre las puntuaciones brutas en datos de validación. La regresión isotónica (Pool-Adjacent-Violators) es una versión no paramétrica que solo impone monotonía.
  • Medimos el Expected Calibration Error (ECE) en predicciones out-of-fold; el calibrador con menor ECE pasa a producción.

src/lib/advanced-stats-v2.ts · src/lib/advanced-stats-v3.ts

12. Generador de tickets anti-clustering

Los tickets candidatos se muestrean, las malas estructuras se rechazan.

  • Extraemos números proporcionalmente a la puntuación del ensemble (softmax con temperatura τ ajustada por lotería). Cada candidato se valida:
  • • máx 3 de la misma década (anti-clustering),
  • • suma dentro de la banda IQR histórica (sin tickets todos bajos o todos altos),
  • • reparto de paridad dentro de la distribución empírica,
  • • sin secuencia aritmética de ≥4 números consecutivos.
  • Los candidatos rechazados se vuelven a muestrear hasta tener N tickets válidos.

src/lib/engine-core.ts (generateAntiClusterTickets)

13. Selección greedy submodular de cartera

Entre miles de candidatos elegimos K tickets que juntos cubren el máximo.

  • Problema: elegir K tickets que maximicen la suma de P(número sorteado) entre los tickets seleccionados, con retornos decrecientes por solape.
  • Las funciones submodulares aportan una garantía de optimalidad de 1 − 1/e ≈ 63 % para la solución greedy. Por iteración tomamos el ticket con la mayor ganancia marginal y aplicamos factor 0.4 a los números ya cubiertos.
f(S ∪ {t}) − f(S) = Σ_{n ∈ t}  remain[n] · (½ si bonus)

src/lib/portfolio-optimizer.ts

14. Cartera Markowitz de mínima varianza

Más allá de la cobertura minimizamos la correlación mutua entre tickets.

  • Correlación entre tickets i y j ≈ |overlap| / √(|t_i|·|t_j|). Greedy: tomar siempre el ticket con mayor EV menos λ · Σ corr(actual, elegidos).
  • La aversión al riesgo λ es un parámetro ajustable (defecto 1.2). λ más alto = más diversificación, menor puntuación esperada por ticket pero menor varianza del pago total de la cartera.
util(t) = EV(t) − λ · Σ_{j ∈ picked}  overlap(t, j)

src/lib/markowitz.ts

15. Corrección de popularidad de jackpot compartido

Un acierto en una combinación 'popular' se comparte con más ganadores.

  • popularityScore() cuenta: % de números ≤ 31 (cumpleaños), % en la mitad baja, secuencias consecutivas ≥3, progresiones aritméticas, todos con la misma última cifra, cruces/diagonales en el boleto.
  • En base a eso estimamos el número de co-ganadores y aplicamos adjustJackpotForSharing(): el EV en el paso de gating usa el pago esperado tras compartir, no el jackpot bruto.

src/lib/popularity.ts

16. EV gating consciente del jackpot

Aconsejar 'jugar' solo cuando el valor esperado es positivo.

  • EV = Σ_tier P(tier) · payout(tier) − ticketCost. P(tier) es exacto a partir de cuotas combinatorias (coeficientes binomiales según la fórmula de la lotería). Payout(tier) viene de PRIZE_TIERS — para la clase jackpot se sustituye por el jackpot actual (tras compartir por popularidad).
  • También calculamos el break-even jackpot: la cifra donde EV = 0. Por debajo, la UI muestra '⏸ saltarse'.
  • El criterio de Kelly determina el tamaño opcional de la apuesta para suscriptores que planifican varias semanas.
EV = Σ_t  P(t) · payout(t) − cost   |   break-even = (cost − Σ_{t≠jp} P(t)·payout(t)) / P(jp)

src/lib/ev-gating.ts

17. Detección de régimen (CUSUM + HMM 2 estados + filtro de partículas)

Detectar si el generador de sorteos en sí ha cambiado.

  • CUSUM sigue por número una desviación acumulada de la frecuencia esperada y alarma al superar el umbral h.
  • Un HMM de 2 estados (hot/cold) se entrena con Baum-Welch sobre la serie temporal de frecuencia; las transiciones se decodifican con Viterbi.
  • Un filtro de partículas Sequential Monte Carlo mantiene 200 partículas sobre el estado oculto de régimen y da una probabilidad blanda por sorteo.
  • En cambio de régimen la EMA corta recibe temporalmente más peso (adaptación en línea).

src/lib/advanced-stats-v2.ts · src/lib/advanced-stats-v3.ts

18. Extensiones estadísticas de nivel 3

Conformal prediction, modelo de gap binomial negativo, cópulas, Shapley y más.

  • • Split-conformal prediction → banda sobre meta-probs con cobertura garantizada.
  • • A posteriori Dirichlet-Multinomial sobre el sorteo completo (no solo por número).
  • • Modelo de gap binomial negativo para sobredispersión entre apariciones.
  • • Cópula gaussiana para dependencias de pares que PMI se pierde.
  • • Test de permutación por señal (label-shuffle) → p-valor de 'mejor que el azar'.
  • • Atribución SHAP por ticket (aproximación lineal) → explica por qué se eligió este ticket.
  • • CVaR / Expected Shortfall sobre los pagos de la cartera.
  • • Bondad de ajuste Anderson-Darling sobre uniformidad.

src/lib/advanced-stats-v2.ts · src/lib/advanced-stats-v3.ts

19. Auto-tuner: CV anidada + grid-search

Un pg_cron semanal revisa pesos del motor y meta-modelos por lotería.

  • CV estratificada 5-fold externa → estimación de ROI fuera de muestra. CV interna → selección de preset.
  • Grid-search sobre simplex de pesos 6-dim (ponderado BMA) + presets de semividas (HALF_LIFE_GRID). Para cada config: simular K tickets por fold, puntuar con tiers de premios, agregar ROI con CI bootstrap del 95 %.
  • Un preset nuevo solo se acepta si CI-low > ROI baseline (no un golpe de suerte).
  • Los resultados van a engine_config (DB) y están inmediatamente activos para todos los suscriptores.

src/lib/engine-tuning.functions.ts · src/routes/api/public/hooks/auto-tune.ts

20. Bandido Thompson-sampling (selección de preset en línea)

Entre auto-tunes, un bandido conmuta en vivo entre presets según el ROI actual.

  • Por preset mantenemos un a posteriori Beta(α, β): α = victorias (ROI > 0), β = derrotas. En cada elección de producción muestreamos de cada Beta y elegimos la muestra más alta.
  • Las actualizaciones vienen del tracker: en cuanto termina un sorteo, los presets elegidos suman +1 en α o β.
  • Resultado: incluso sin re-tuning completo el sistema converge en línea al mejor preset.
pick = argmax_p  Beta(α_p, β_p).sample()

src/lib/bandit.ts

21. Backtest walk-forward

Cada estrategia se prueba sin conocimiento del futuro (sin filtración).

  • Desde MIN_HISTORY iteramos sorteo a sorteo. Por sorteo construimos el modelo SOLO con sorteos anteriores, generamos N tickets y puntuamos contra el sorteo real.
  • Agregamos aciertos por tier, ROI medio, P&L acumulado y una baseline aleatoria de control. Una estrategia solo 'gana' si su banda CI está por encima del azar.

src/lib/backtest.functions.ts

22. Sistemas de wheeling (covering designs)

Garantía matemática: con M números correctos en el pool, siempre un premio Y-de-X.

  • Implementamos full wheels, key wheels y covering designs abreviados. Para cada (tamaño de pool, tamaño de ticket, garantía) tomamos el conjunto combinatoriamente óptimo.
  • El generador de wheels se combina con el optimizador de cartera: los candidatos primero se wheelean y luego se eligen de forma submodular.

src/lib/wheel.functions.ts

Honestamente

Las loterías son y seguirán siendo juegos de azar. Ningún análisis puede predecir un sorteo. Lo que hace LotteryCortex: ayudarte a tomar mejores decisiones sobre qué combinaciones jugar, cuándo apostar más y cuándo saltar una semana.

Los sorteos de lotería están diseñados para ser aleatorios. Ningún algoritmo — aquí ni en ningún otro sitio — puede predecir el resultado. Lo que sí hacemos de forma medible: elegir mejores reparticiones de números, evitar combinaciones populares (para compartir menos al acertar) y aconsejar honestamente saltarse el sorteo cuando el valor esperado es negativo. El auto-tuner valida cada semana que nuestra curva de ROI esté significativamente por encima del azar — si dejara de ser así, lo leerás aquí primero.

¿Por qué LotteryCortex?

La mayoría de las herramientas de lotería tienen más de 10 años, solo están en inglés y son desktop-first. LotteryCortex es moderno, mobile-first y orientado a la UE — con un motor de IA que aprende continuamente de nuevos sorteos.