LotteryCortex łączy cztery techniki normalnie używane tylko przez quantów i data scientistów. Udostępniamy je każdemu, kto kupuje los.
Ta strona opisuje każdy algorytm uruchamiany przez LotteryCortex — od pozyskiwania danych po wybór kuponów. Wszystko jest otwarcie udokumentowane: dla każdego kroku podajemy plik źródłowy w kodzie. To nie cudowny środek, ale najbardziej kompletnie publicznie udokumentowany stos do analizy loterii, jaki udało nam się zbudować.
Algorytmy szczegółowo
1. Bayesowskie ściąganie częstości
Jak często liczba była losowana, skorygowane o ilość posiadanych danych.
- Surowa częstość przeszacowuje 'gorące' liczby przy krótkiej historii. Nakładamy a priori Dirichleta z automatyczną estymacją alfa (dirichletAlphaAuto, metoda momentów na wariancji empirycznej).
- Wynikiem jest a posteriori prawdopodobieństwo na liczbę, które przy małej historii kurczy się do 1/N (jednostajne), a przy wystarczającej liczbie losowań podąża za prawdziwą częstością.
p̂(n) = (count(n) + α) / (totalDraws · k + α · N)
src/lib/engine-core.ts · src/lib/advanced-stats.ts
2-4. EMA ważone czasem z wieloma okresami półtrwania
Świeże losowania ważą więcej niż stare — trzy horyzonty równolegle.
- Dla każdego losowania i od końca przypisujemy wagę w_i = 0.5^(i / H). Uruchamiamy trzy EMA równolegle z H = 8, 26 i 78 losowań (krótki/średni/długi).
- Krótki okres półtrwania chwyta 'hot streaki'. Długi zapobiega przereagowaniu na jedno dziwne losowanie. Blender ensemble wybiera, ile wagi dostaje każdy horyzont na loterię — dostrojony przez 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. Wzmocnienie współwystępowania PMI
Które liczby pojawiają się razem częściej, niż przewidziałby przypadek?
- Liczymy Pointwise Mutual Information: PMI(a,b) = log [P(a,b) / (P(a)·P(b))]. Dodatnie PMI = para pojawia się razem częściej niż przy niezależności.
- Dla każdej liczby kandydującej sumujemy PMI ze wszystkimi liczbami z najnowszego losowania. Daje to sygnał 'idź za wzorcem' bez przeuczenia: PMI jest ograniczone i przycinane do ±3.
score_PMI(n) = Σ_{m ∈ lastDraw} clip(log[P(n,m) / (P(n)P(m))], ±3)
src/lib/engine-core.ts
6. Prawdopodobieństwa przejść Markowa
Z ostatniego losowania szacujemy prawdopodobieństwo przejścia do następnej liczby.
- Budujemy macierz przejść N×N T, gdzie T[a,b] = P(b w draw_t+1 | a w draw_t), estymowaną z wygładzaniem Laplace'a.
- Dla wyniku live bierzemy średnią T[a, n] po wszystkich a z ostatniego losowania. Zimne liczby nie zostają zimne na zawsze; ten krok modeluje skończoną pamięć.
src/lib/engine-core.ts
7. Ensemble i dostrojone wagi
Sześć sygnałów łączy się przez ważoną agregację rang.
- Każdy sygnał konwertujemy na percentyle rangowe [0, 1]. Następnie liniowo łączymy z wagami w = (w_bayes, w_ema1, w_ema2, w_ema3, w_pmi, w_markov). Domyślnie jednostajnie; na loterię dostrojone przez grid-search + walidację ROI.
- Agregacja rang jest odporna na różnice skali między sygnałami i zapobiega dominacji ensemble przez jeden odstający wynik.
score(n) = Σ_s w_s · rank_s(n) / N
src/lib/engine-core.ts · src/lib/engine-tuning.functions.ts
8. Meta-learner (regresja logistyczna, 12 cech)
Logreg na loterię uczy się optymalnej nieliniowej kombinacji sygnałów silnika.
- Wektor cech (12 wymiarów): 6 rang silnika + interakcje (EMA1·PMI, Bayes·Markov, EMA3·Bayes) + świeżość + hot streak (wystąpienia w 10 ostatnich) + cold streak (kolejne nieobecności).
- Trenowanie: logreg z regularyzacją L2 i SGD na całej historii. Strata = log-loss dla etykiety '1, jeśli liczba pojawiła się w kolejnym losowaniu'. Wstecznie kompatybilne: stare modele 9-wymiarowe nadal działają.
P(n w następnym losowaniu) = σ(w · features(n) + b)
src/lib/meta-learner.ts
9. Gradient Boosted Decision Stumps
Drugi meta-learner łapiący nieliniowe interakcje bez sieci neuronowej.
- Mini-klon LightGBM: iteracyjne decision stumps na rezyduach. Każdy stump wybiera 1 cechę + próg maksymalnie redukujący stratę; dodajemy lr · stump.output do bieżącej predykcji.
- Wynik jest serializowalny do JSON i zapisywany obok logreg w engine_config.meta_weights.gbm. Stacked blender łączy oba.
src/lib/gbm.ts
10. Blender stackingu out-of-fold
Logreg + GBM łączone bez wycieku danych.
- Historię dzielimy na 5 stratyfikowanych foldów. Na fold trenujemy logreg + GBM na 4 foldach i przewidujemy na zatrzymanym. Te predykcje OOF stają się wejściami drugiej warstwy meta-logreg, która uczy się optymalnej wagi.
- Wynik: kalibrowalne prawdopodobieństwa bez tego, że meta-learner widzi własne dane treningowe.
src/lib/advanced-stats-v3.ts · src/lib/nested-cv.ts
11. Kalibracja izotoniczna i Platta
Surowe prawdopodobieństwa modelu są monotonizowane, by faktycznie były prawdopodobieństwami.
- Skalowanie Platta dopasowuje 1-parametrową sigmoidę do surowych wyników na danych walidacyjnych. Regresja izotoniczna (Pool-Adjacent-Violators) to wersja nieparametryczna wymuszająca jedynie monotoniczność.
- Mierzymy Expected Calibration Error (ECE) na predykcjach out-of-fold; do produkcji idzie kalibrator z najniższym ECE.
src/lib/advanced-stats-v2.ts · src/lib/advanced-stats-v3.ts
12. Generator kuponów anti-clustering
Kandydujące kupony są próbkowane, złe struktury odrzucane.
- Liczby losujemy proporcjonalnie do wyniku ensemble (softmax z temperaturą τ dostrojoną na loterię). Każdy kandydat jest walidowany:
- • maks 3 z tej samej dekady (anti-clustering),
- • suma w paśmie IQR historii (bez kuponów wyłącznie niskich lub wysokich),
- • podział parzystości w rozkładzie empirycznym,
- • brak ciągu arytmetycznego ≥4 kolejnych liczb.
- Odrzucone kupony są ponownie próbkowane, aż mamy N poprawnych.
src/lib/engine-core.ts (generateAntiClusterTickets)
13. Zachłanna submodularna selekcja portfela
Spośród tysięcy kandydatów wybieramy K kuponów, które łącznie pokrywają najwięcej.
- Problem: wybrać K kuponów maksymalizujących sumę P(liczba wylosowana) po wybranych kuponach, z malejącymi przychodami za nakładanie się.
- Funkcje submodularne mają gwarancję optymalności 1 − 1/e ≈ 63 % dla rozwiązania zachłannego. W każdej iteracji bierzemy kupon o największym marginalnym zysku i dyskontujemy pokryte liczby współczynnikiem 0.4.
f(S ∪ {t}) − f(S) = Σ_{n ∈ t} remain[n] · (½ przy bonusie)
src/lib/portfolio-optimizer.ts
14. Portfel Markowitza o minimalnej wariancji
Poza pokryciem minimalizujemy wzajemną korelację między kuponami.
- Korelacja między kuponami i a j ≈ |overlap| / √(|t_i|·|t_j|). Zachłannie: zawsze brać kupon z najwyższym EV minus λ · Σ corr(bieżący, wybrane).
- Awersja do ryzyka λ to strojeny parametr (domyślnie 1.2). Wyższe λ = większa dywersyfikacja, niższy oczekiwany wynik na kupon, ale niższa wariancja sumarycznej wypłaty portfela.
util(t) = EV(t) − λ · Σ_{j ∈ picked} overlap(t, j)
src/lib/markowitz.ts
15. Korekta popularności dzielonego jackpota
Trafienie 'popularnej' kombinacji jest dzielone z większą liczbą zwycięzców.
- popularityScore() liczy: % liczb ≤ 31 (urodziny), % w dolnej połowie, ciągi kolejnych ≥3, postępy arytmetyczne, same takie same ostatnie cyfry, krzyżyki/przekątne na kuponie.
- Na tej podstawie szacujemy liczbę współ-zwycięzców i stosujemy adjustJackpotForSharing(): EV w kroku gating używa oczekiwanej wypłaty po podziale, nie brutto jackpota.
src/lib/popularity.ts
16. EV-gating świadome jackpota
Doradzaj 'graj' tylko, gdy wartość oczekiwana jest dodatnia.
- EV = Σ_tier P(tier) · payout(tier) − ticketCost. P(tier) jest dokładne z kombinatorycznych szans (współczynniki dwumianowe zgodnie ze wzorem loterii). Payout(tier) pochodzi z PRIZE_TIERS — dla klasy jackpota podmienione na bieżący jackpot (po podziale z popularności).
- Liczymy też break-even jackpot: kwotę, dla której EV = 0. Poniżej tej wartości UI pokazuje '⏸ odpuść'.
- Kryterium Kelly'ego wyznacza opcjonalny rozmiar zakładu dla subskrybentów planujących wiele tygodni.
EV = Σ_t P(t) · payout(t) − cost | break-even = (cost − Σ_{t≠jp} P(t)·payout(t)) / P(jp)
src/lib/ev-gating.ts
17. Wykrywanie reżimu (CUSUM + HMM 2-stanowy + filtr cząsteczkowy)
Wykryj, czy sam generator losowań się przesunął.
- CUSUM śledzi dla każdej liczby skumulowane odchylenie od oczekiwanej częstości i alarmuje przy przekroczeniu progu h.
- HMM o 2 stanach (hot/cold) jest trenowany Baum-Welchem na szeregu czasowym częstości; przejścia są dekodowane Viterbim.
- Filtr cząsteczkowy Sequential Monte Carlo utrzymuje 200 cząsteczek nad ukrytym stanem reżimu i daje miękkie prawdopodobieństwo na losowanie.
- Przy zmianie reżimu krótka EMA czasowo dostaje więcej wagi (adaptacja online).
src/lib/advanced-stats-v2.ts · src/lib/advanced-stats-v3.ts
18. Rozszerzenia statystyczne poziomu 3
Conformal prediction, model luki ujemny-dwumianowy, kopuły, Shapley i więcej.
- • Split-conformal prediction → pasmo na meta-prob z gwarantowanym pokryciem.
- • A posteriori Dirichlet-Multinomial nad pełnym losowaniem (nie tylko na liczbę).
- • Model luki ujemny-dwumianowy dla nadmiernej dyspersji między wystąpieniami.
- • Kopuła Gaussa dla zależności par, które omija PMI.
- • Test permutacyjny na sygnał (label-shuffle) → p-wartość dla 'lepiej niż losowo'.
- • Atrybucja SHAP na kupon (przybliżenie liniowe) → wyjaśnia, dlaczego ten kupon wybrano.
- • CVaR / Expected Shortfall nad wypłatami portfela.
- • Test zgodności Andersona-Darlinga na jednostajność.
src/lib/advanced-stats-v2.ts · src/lib/advanced-stats-v3.ts
19. Auto-tuner: zagnieżdżona CV + grid-search
Tygodniowy pg_cron rewiduje wagi silnika i meta-modele na loterię.
- Zewnętrzna 5-foldowa stratyfikowana CV → estymata ROI poza próbą. Wewnętrzna CV → wybór presetu.
- Grid-search po 6-wymiarowym sympleksie wag (ważony BMA) + presety okresów półtrwania (HALF_LIFE_GRID). Dla każdej konfiguracji: symuluj K kuponów na fold, oceń tierami wygranych, agreguj ROI z 95 % bootstrapowym CI.
- Nowy preset jest akceptowany tylko, gdy CI-low > bazowe ROI (nie szczęśliwy strzał).
- Wyniki trafiają do engine_config (DB) i są natychmiast live dla wszystkich subskrybentów.
src/lib/engine-tuning.functions.ts · src/routes/api/public/hooks/auto-tune.ts
20. Bandita Thompson-sampling (online wybór presetu)
Pomiędzy auto-tune'ami bandita na żywo przełącza presety w oparciu o bieżące ROI.
- Na preset trzymamy a posteriori Beta(α, β): α = wygrane (ROI > 0), β = straty. Przy każdym wyborze produkcyjnym próbkujemy z każdej Bety i bierzemy największą próbkę.
- Aktualizacje przychodzą z trackera: gdy tylko losowanie się kończy, wybrane presety dostają +1 do α lub β.
- Wynik: nawet bez pełnego re-tuningu system zbiega online do najlepszego presetu.
pick = argmax_p Beta(α_p, β_p).sample()
src/lib/bandit.ts
21. Backtest walk-forward
Każda strategia jest testowana bez znajomości przyszłości (bez wycieku).
- Od MIN_HISTORY iterujemy losowanie po losowaniu. Dla każdego losowania budujemy model TYLKO z losowań wcześniejszych, generujemy N kuponów i oceniamy względem prawdziwego losowania.
- Agregujemy trafienia per tier, średnie ROI, skumulowany P&L oraz losową baseline jako kontrolę. Strategia 'wygrywa' tylko wtedy, gdy jej pasmo CI jest powyżej losowości.
src/lib/backtest.functions.ts
22. Systemy wheelingowe (covering designs)
Gwarancja matematyczna: przy M poprawnych liczbach w puli zawsze wygrana Y-z-X.
- Implementujemy full wheels, key wheels i skrócone covering designs. Dla każdej (wielkość puli, wielkość kuponu, gwarancja) bierzemy kombinatorycznie optymalny zbiór.
- Generator wheelingu łączy się z optymalizatorem portfela: kandydaci są najpierw wheelowani, a potem wybierani submodularnie.
src/lib/wheel.functions.ts
Szczerze mówiąc
Loterie są i pozostaną grami losowymi. Żadna analiza nie może przewidzieć losowania. To, co LotteryCortex robi: pomaga podejmować lepsze decyzje — które kombinacje grać, kiedy stawiać więcej, a kiedy lepiej odpuścić tydzień.
Losowania loterii są zaprojektowane jako losowe. Żaden algorytm — ani tu, ani gdzie indziej — nie potrafi przewidzieć wyniku. Co robimy w sposób mierzalny: wybieramy lepsze rozkłady liczb, unikamy popularnych kombinacji (by mniej dzielić przy trafieniu) i uczciwie radzimy odpuścić, gdy wartość oczekiwana jest ujemna. Auto-tuner co tydzień sprawdza, czy nasza krzywa ROI jest istotnie powyżej losowości — jeśli kiedyś przestanie, dowiesz się o tym tu pierwszy.