Onder de motorkap

Hoe LotteryCortex werkt

LotteryCortex combineert vier technieken die normaal alleen door quants en data-scientists worden gebruikt. We maken ze toegankelijk voor iedereen die een lot koopt.

Deze pagina beschrijft elk algoritme dat LotteryCortex draait — van data-ingest tot ticket-selectie. Alles is open documenteerbaar: voor elke stap noemen we de bronfile in de codebase. Geen wondermiddel, wél de meest complete publiek gedocumenteerde stack voor loterij-analyse die we konden bouwen.

De pipeline in 7 stappen

Elke trekking doorloopt deze keten. Onderaan vind je per algoritme de details.

  1. 01

    Data-ingest & anomaly-detection

    Per loterij scrapen we de officiële archieven (direct HTML-fetch met Firecrawl-fallback). Elke nieuwe trekking gaat door detectDrawAnomaly(): shape-check, range-check, duplicate-detect en een chi-kwadraat-vergelijking tegen de laatste 200 trekkingen. Verdachte trekkingen worden geblokkeerd voordat ze de historie raken.

  2. 02

    Engine-core: zes basissignalen

    engine-core.ts berekent per nummer zes onafhankelijke scores (Bayes, EMA × 3 half-lifes, PMI, Markov), normaliseert ze naar ranks en combineert ze met getuneede gewichten tot één ensemble-score.

  3. 03

    Meta-learner & GBM stacking

    De zes engine-scores + 6 afgeleide features (interacties, recency, hot/cold streaks) gaan in een per-loterij logistic regression (meta-learner.ts) en een gradient boosted stumps model (gbm.ts). De stacked blender combineert beide out-of-fold zonder leakage.

  4. 04

    Ticket-generatie met anti-clustering

    We samplen duizenden kandidaat-tickets uit de top-scorende nummers, maar verwerpen alles met te veel clustering: max 3 uit dezelfde decade, pariteit binnen historische band, som binnen IQR-band van werkelijke trekkingen.

  5. 05

    Portfolio-optimalisatie

    Greedy submodulaire selectie (portfolio-optimizer.ts) + Markowitz min-variance selector (markowitz.ts) kiezen K tickets die samen de meeste waarschijnlijkheidsmassa dekken met minimale overlap.

  6. 06

    Popularity-correctie & EV-gating

    popularity.ts straft 'mooie' combinaties (verjaardagen ≤ 31, opeenvolgende reeksen, lage helft) want bij een hit moet je delen. ev-gating berekent jackpot-bewuste EV per €1 inzet en geeft 'speel' of 'sla over' advies.

  7. 07

    Walk-forward backtest & auto-tuning

    Elke zondag draait een nested k-fold cross-validation (nested-cv.ts) plus grid-search over engine-gewichten en half-life-presets. Een Thompson-sampling bandit (bandit.ts) selecteert online de best presterende preset op basis van gerealiseerde ROI.

Index — 20 algoritmes

Algoritmes in detail

1. Bayesiaanse frequentie-shrinkage

Hoe vaak een nummer is getrokken, gecorrigeerd voor de hoeveelheid data die we hebben.

  • Pure ruwe frequentie overschat 'hot' nummers wanneer de geschiedenis kort is. We leggen er een Dirichlet-prior overheen met automatische alpha-schatting (dirichletAlphaAuto, method-of-moments op de empirische variantie).
  • Het resultaat is een posterior-kans per nummer die naar 1/N (uniform) krimpt zolang de geschiedenis klein is, en de echte frequentie gaat volgen zodra we genoeg trekkingen hebben.
p̂(n) = (count(n) + α) / (totalDraws · k + α · N)

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

2-4. Tijd-gewogen EMA met meerdere half-lifes

Recente trekkingen tellen zwaarder dan oude — drie horizonnen tegelijk.

  • Voor elke trekking i vanaf het einde geeft we gewicht w_i = 0.5^(i / H). We draaien drie EMA's parallel met H = 8, 26 en 78 trekkingen (kort/middel/lang).
  • Korte half-life vangt 'hot streaks' op. Lange half-life voorkomt over-reageren op één rare trekking. De ensemble-blender kiest hoeveel gewicht elke horizon krijgt per loterij — getuneed met 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. PMI co-occurrence boost

Welke nummers samen verschijnen vaker dan het toeval zou voorspellen?

  • We berekenen Pointwise Mutual Information: PMI(a,b) = log [P(a,b) / (P(a)·P(b))]. Positieve PMI = paar verschijnt vaker samen dan onafhankelijk verwacht.
  • Per kandidaat-nummer sommeren we de PMI met alle nummers van de meest recente trekking. Dat geeft een 'follow-the-pattern' signaal zonder over-fitten: PMI is bounded en wordt geclipt op ±3.
score_PMI(n) = Σ_{m ∈ lastDraw}  clip(log[P(n,m) / (P(n)P(m))], ±3)

src/lib/engine-core.ts

6. Markov-overgangskansen

Vanuit de laatste trekking schatten we de transitie-kans naar het volgende nummer.

  • We bouwen een N×N transitiematrix T waarin T[a,b] = P(b in trekking_t+1 | a in trekking_t), geschat met Laplace-smoothing.
  • Voor de live-score nemen we het gemiddelde van T[a, n] over alle a in de laatste trekking. Cold nummers blijven niet altijd cold; deze stap modelleert eindige geheugen.

src/lib/engine-core.ts

7. Ensemble & getuneede gewichten

De zes signalen worden via gewogen rank-aggregatie samengevoegd.

  • Elk signaal wordt naar rank-percentielen [0, 1] omgezet. Daarna lineair gecombineerd met gewichten w = (w_bayes, w_ema1, w_ema2, w_ema3, w_pmi, w_markov). Default uniform; per loterij getuneed via grid-search + ROI-validatie.
  • Rank-aggregatie is robuust tegen scale-verschillen tussen signalen en voorkomt dat één outlier-score het ensemble domineert.
score(n) = Σ_s  w_s · rank_s(n) / N

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

8. Meta-learner (logistic regression, 12 features)

Een per-loterij logreg leert de optimale non-lineaire combinatie van engine-signalen.

  • Feature-vector (12 dims): de 6 engine-ranks + interacties (EMA1·PMI, Bayes·Markov, EMA3·Bayes) + recency + hot streak (verschijningen laatste 10) + cold streak (consecutive absences).
  • Training: L2-geregulariseerde logreg met SGD over de hele historie. Verlies = log-loss op label '1 als nummer in de volgende trekking voorkwam'. Backward-compatible: oude 9-dim modellen blijven werken.
P(n in volgende trekking) = σ(w · features(n) + b)

src/lib/meta-learner.ts

9. Gradient Boosted Decision Stumps

Tweede meta-learner die non-lineaire interacties opvangt zonder neuraal net.

  • Mini-LightGBM clone: itereratief decision stumps op de residuen. Elke stump kiest 1 feature + threshold die de loss maximaal reduceert; we voegen lr · stump.output toe aan de huidige predictie.
  • Output is JSON-serializable en wordt naast de logreg gestored in engine_config.meta_weights.gbm. De stacked blender combineert beide.

src/lib/gbm.ts

10. Out-of-fold stacking blender

Logreg + GBM worden gecombineerd zonder data-leakage.

  • We splitsen de historie in 5 stratified folds. Per fold trainen we logreg + GBM op 4 folds en voorspellen op de overgebleven fold. Die OOF-predicties worden de inputs voor een tweede-laag logreg-meta die de optimale weging leert.
  • Resultaat: kalibreerbare kansen zonder dat de meta-learner zichzelf zijn eigen trainingsdata terug ziet.

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

11. Isotonische & Platt-kalibratie

Ruwe model-kansen worden gemonotoniseerd zodat ze écht kansen zijn.

  • Platt scaling fit een 1-parameter sigmoid over de raw scores op validatiedata. Isotonische regressie (Pool-Adjacent-Violators) is een non-parametrische versie die alleen monotonie afdwingt.
  • We meten Expected Calibration Error (ECE) op out-of-fold predicties; de calibrator met laagste ECE wordt productie.

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

12. Anti-clustering ticket-generator

Kandidaat-tickets worden gesampled, slechte structuren afgewezen.

  • We trekken nummers proportioneel aan ensemble-score (softmax met temperatuur τ getuneed per loterij). Elke kandidaat wordt gevalideerd:
  • • max 3 uit dezelfde decade (anti-clustering),
  • • som binnen historische IQR-band (geen alleen-laag of alleen-hoog tickets),
  • • pariteits-split binnen empirische distributie,
  • • geen rekenkundige reeks van ≥4 opeenvolgende getallen.
  • Afgewezen kandidaten worden hergesampled tot we N geldige tickets hebben.

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

13. Greedy submodular portfolio selection

Uit duizenden kandidaten kiezen we K tickets die samen maximaal dekken.

  • Probleem: kies K tickets die de som van P(nummer komt) over de geselecteerde tickets maximaliseren, met diminishing returns voor overlap.
  • Submodulaire functies hebben een 1 − 1/e ≈ 63% optimaliteits-garantie voor de greedy oplossing. Per iteratie kiezen we het ticket met de grootste marginal gain en discounten gedekte nummers met factor 0.4.
f(S ∪ {t}) − f(S) = Σ_{n ∈ t}  remain[n] · (½ als bonus)

src/lib/portfolio-optimizer.ts

14. Markowitz min-variance portfolio

Naast dekking minimaliseren we onderlinge correlatie tussen tickets.

  • Correlatie tussen ticket i en j ≈ |overlap| / √(|t_i|·|t_j|). Greedy: kies steeds het ticket met hoogste EV minus λ · Σ corr(huidig, gekozenen).
  • Risico-aversie λ is een tuneable parameter (default 1.2). Hogere λ = meer diversificatie, lagere verwachte score per ticket maar lagere variantie van de totale portfolio-uitbetaling.
util(t) = EV(t) − λ · Σ_{j ∈ picked}  overlap(t, j)

src/lib/markowitz.ts

15. Shared-jackpot popularity correctie

Een hit op een 'populaire' combinatie wordt met meer winnaars gedeeld.

  • popularityScore() telt: % nummers ≤ 31 (verjaardagen), % in onderste helft, opeenvolgende reeksen ≥3, rekenkundige progressies, allemaal-zelfde-eindcijfer, kruisjes/diagonalen op de speelkaart.
  • Op basis daarvan schatten we het aantal mede-winnaars en passen we adjustJackpotForSharing() toe: de EV in de gating-stap gebruikt de verwachte uitbetaling ná deling, niet de bruto jackpot.

src/lib/popularity.ts

16. Jackpot-aware EV-gating

Adviseer 'spelen' alleen als de verwachte waarde positief is.

  • EV = Σ_tier P(tier) · payout(tier) − ticketCost. P(tier) is exact uit combinatorische kansen (binomial coefficients per loterij-formule). Payout(tier) komt uit PRIZE_TIERS — voor de jackpot-klasse vervangen door de huidige jackpot (na popularity-deling).
  • We berekenen ook de break-even jackpot: het bedrag waarvoor EV = 0. Onder dat bedrag toont de UI '⏸ overslaan'.
  • Kelly-criterion bepaalt optionele bet-sizing voor abonnees die meerdere weken plannen.
EV = Σ_t  P(t) · payout(t) − cost   |   break-even = (cost − Σ_{t≠jp} P(t)·payout(t)) / P(jp)

src/lib/ev-gating.ts

17. Regime-detectie (CUSUM + 2-state HMM + particle filter)

Detecteren of de generator van trekkingen zelf is verschoven.

  • CUSUM houdt per nummer een cumulatieve afwijking van de verwachte frequentie bij en alarmeert bij overschrijding van de drempel h.
  • Een 2-state HMM (hot/cold) wordt met Baum-Welch op de frequentie-tijdreeks getraind; transities worden Viterbi-gedecodeerd.
  • Een Sequential Monte-Carlo particle filter onderhoudt 200 deeltjes over de verborgen regime-state en geeft een soft probability per draw.
  • Bij regime-shift krijgt de korte-EMA tijdelijk meer gewicht (online adaptatie).

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

18. Niveau-3 statistische uitbreidingen

Conformal prediction, Negative-Binomial gap-model, copulas, Shapley, en meer.

  • • Split-conformal prediction → bandbreedte op meta-probs met gegarandeerde coverage.
  • • Dirichlet-Multinomial posterior over de volledige trekking (niet alleen per nummer).
  • • Negative-Binomial gap-model voor over-dispersie tussen verschijningen.
  • • Gaussian-copula voor pair-dependencies die PMI mist.
  • • Permutatie-test per signaal (label-shuffle) → p-waarde voor 'beter dan random'.
  • • SHAP-attributie per ticket (lineaire benadering) → uitleg waarom dit ticket gekozen is.
  • • CVaR / Expected Shortfall over portfolio-uitbetalingen.
  • • Anderson-Darling goodness-of-fit op uniformiteit.

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

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

Wekelijkse pg_cron herziet engine-gewichten en meta-modellen per loterij.

  • Outer 5-fold stratified CV → out-of-sample ROI-schatting. Inner CV → preset selectie.
  • Grid-search over 6-dim weight-simplex (BMA-weighted) + half-life presets (HALF_LIFE_GRID). Voor elke configuratie: simuleer K tickets per fold, scoor met prize-tiers, aggregeer ROI met 95% bootstrap CI.
  • Een nieuwe preset wordt alleen geaccepteerd als CI-low > baseline-ROI (geen geluksshot).
  • Resultaten gaan in engine_config (DB) en zijn meteen live voor alle abonnees.

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

20. Thompson-sampling bandit (online preset-selectie)

Tussen auto-tunes door schakelt een bandit live tussen presets op basis van actuele ROI.

  • Per preset houden we een Beta(α, β) posterior: α = winnen (ROI > 0), β = verliezen. Bij elke productie-pick samplen we uit elke Beta en kiezen de hoogste sample.
  • Updates komen uit de tracker: zodra een trekking afgelopen is, krijgen de gekozen presets hun α of β +1.
  • Resultaat: zelfs zonder volledige her-tuning convergeert het systeem online naar de beste preset.
pick = argmax_p  Beta(α_p, β_p).sample()

src/lib/bandit.ts

21. Walk-forward backtest

Iedere strategie wordt getoetst zonder toekomstkennis (geen leakage).

  • Vanaf MIN_HISTORY itereren we trekking voor trekking. Per trekking bouwen we het model op uit ENKEL trekkingen daarvoor, genereren N tickets, en scoren tegen de werkelijke trekking.
  • We aggregeren hits per tier, gemiddelde ROI, cumulatieve P&L én een random-baseline ter controle. Een strategie 'wint' alleen als het CI-band boven random ligt.

src/lib/backtest.functions.ts

22. Wheeling-systemen (covering designs)

Wiskundige garantie: bij M juiste nummers in de pool altijd een Y-uit-X win.

  • We implementeren full wheels, key wheels en abbreviated covering designs. Voor elke (pool-size, ticket-size, garantie) kiezen we de combinatorisch optimale set.
  • De wheel-generator combineert met de portfolio-optimizer: kandidaten worden eerst gewheel'd, daarna submodulair gekozen.

src/lib/wheel.functions.ts

Eerlijk gezegd

Loterijen zijn en blijven kansspelen. Geen enkele analyse kan een trekking voorspellen. Wat LotteryCortex wel doet: je helpen betere beslissingen te nemen over welke combinaties je speelt, wanneer je meer inzet en wanneer je een week overslaat.

Loterij-trekkingen zijn ontworpen om willekeurig te zijn. Geen enkel algoritme — hier of elders — kan de uitkomst voorspellen. Wat we wél meetbaar doen: betere nummer-spreiding kiezen, populaire combinaties vermijden (zodat je minder hoeft te delen bij een hit), en eerlijk advies geven om over te slaan wanneer de verwachte waarde negatief is. De auto-tuner valideert wekelijks dat onze ROI-curve significant boven random ligt — als dat ooit niet meer zo is, lees je dat hier eerst.

Waarom LotteryCortex?

LotteryCortex combineert historische statistieken, backtests en tracking in één webapp. Analyse voorspelt geen trekkingen en verhoogt je winkans niet.

The information on this website is created in part with the help of artificial intelligence and may contain errors or omissions. It is provided for general informational purposes only and does not constitute professional advice. Independently verify important details and consult a qualified professional when necessary. To the extent permitted by applicable law, we accept no liability for loss or damage arising from the use of, or reliance on, this information. This does not affect statutory rights or liabilities that cannot legally be excluded.