Skip to content
MarcoLombardoDevPublic

About

Strumento per l’analisi e la previsione del SuperEnalotto che verifica l’indipendenza delle estrazioni, valida i metodi predittivi con backtesting walk-forward e confronta le previsioni di TimesFM 3.0 con il caso.

Topics

Resources

Contributing

Stars

2 stars

Watchers

0 watching

Forks

Repository files navigation

🎲 Tyche — Analisi e previsione SuperEnalotto

Licenza: AGPL v3 Python 3.12+ CI

Un'applicazione desktop che scarica lo storico completo delle estrazioni del SuperEnalotto dal dicembre 1997, lo sottopone a test per cercarvi struttura sfruttabile, lo consegna al modello fondazionale per serie temporali TimesFM 3.0 di Google, e misura — onestamente — quanto valgano le previsioni che ne escono.

La versione breve di quella misura: niente. Le estrazioni sono indipendenti, i test lo dicono, e ogni metodo del programma ottiene 0,4 centri su sei, che è esattamente il caso. Tyche è costruito per dimostrarlo con cura, non per affermarlo.

🎲 Non può aiutarti a vincere, e non pretende di poterlo fare. Le probabilità sono esatte e immutabili: 1 su 622.614.630 per sei numeri — vedi Le probabilità, che nessun metodo cambia. ⚖️ AGPL-3.0-or-later e basta: nessuna licenza commerciale, nessun CLA. I pesi di TimesFM sono un'altra cosa dal codice — vedi Licenza.


Percorso

La scheda Percorso, che è quella su cui il programma si apre: le tre condizioni fra l'archivio vuoto e le sei cifre, ognuna con il suo stato.


Che cosa fa

Il programma si apre sulla scheda Percorso, che è una mappa: tre passi nell'ordine in cui vanno fatti, ognuno con il suo stato e con il pulsante per sistemarlo.

Passo La condizione
1 L'archivio C'è, ed è aggiornato? Scarica, importa e ispeziona lo storico, dice che cosa non va e lo mostra in cifre.
2 Il modello TimesFM I pesi sono su questo computer? Se no, il pulsante li scarica, con la percentuale nella barra in basso.
3 La previsione Il punto di arrivo: tutti e cinque i metodi insieme, con quanto costa la giocata e quanto vale.

Fuori percorso c'è Impostazioni: checkpoint, token Hugging Face, numeri per combinazione, SuperStar, esclusione dei numeri appena usciti e prezzi. Le frequenze, i ritardi, le decine e le coppie — ogni tabella con accanto il valore che produrrebbe il caso — stanno nella colonna destra della scheda Archivio, dove dalla 0.11.0 sono state portate: erano una scheda a sé, che si apriva una volta e mai più.

Nella Previsione non si sceglie il metodo: girano tutti e ognuno prende la stessa fetta di pagina. È l'argomento del programma, messo dove non si può saltare. Scegliere un metodo significava vederne uno, e vederne uno solo trasforma delle misure in una preferenza: prendi quello di cui ti fidi, ottieni i suoi numeri, e non scopri mai che gli altri — generatore casuale compreso — producono una schedina altrettanto convincente e che vale esattamente lo stesso.

Il primo riquadro è l'ensemble, ed è calcolato per ultimo. È la media pesata degli altri tre — TimesFM, ritardo, frequenza — con i pesi che un backtest ha assegnato loro; viene per primo perché è la risposta che il programma darebbe se gliene si chiedesse una sola, e per ultimo perché è fatto degli altri. Come vengono scelti quei pesi, e perché uno di loro è a zero, è più sotto.

Accanto a «Genera» c'è «Copia risultati», spento finché non c'è niente da copiare: mette negli appunti le combinazioni di tutti i metodi a schermo, ognuna col nome di chi l'ha prodotta e col SuperStar quando c'è. In fondo al testo copiato c'è la riga che li mette in proporzione — il punteggio atteso è lo stesso per tutti, compreso il metodo casuale — perché tutto il resto di quella schermata resta indietro.

Previsione

Il punto di arrivo. Le palline viola hanno lo stesso aspetto sicuro qualunque metodo le abbia prodotte, e il riquadro in basso a destra è un generatore casuale: è esattamente il punto. Sotto ci sono il costo della giocata e le probabilità che nessun metodo cambia.

La misura è rimasta, ma ha lasciato la finestra. Fino alla 0.9.1 c'erano due schede di prova — cinque test di indipendenza e un backtest walk-forward di ogni metodo contro il caso. Sono state tolte nella 0.10.0 perché erano incomprensibili a chi usa il programma, il che è un difetto della scheda e non della misura: --validate e --power fanno ancora esattamente le stesse cose dalla riga di comando, ed è così che le tabelle più sotto in questo file si rifanno.

C'è anche una riga di comando, per le parti che vale la pena automatizzare:

python main.py --check                  # i cinque test di indipendenza
python main.py --validate 500           # backtest walk-forward
python main.py --power                  # quanto piccolo un vantaggio deve essere
python main.py --ensemble               # ricalibra i pesi dell'ensemble e stampa tutto
python main.py --update                 # aggiorna da estrazioni.it — prova a vuoto
python main.py --update --yes           # ...e scrive
python main.py --import FILE --yes      # importa un file scaricato a mano
python main.py --forecast ritardo       # una giocata, senza scaricare il modello
python main.py --forecast ensemble      # la giocata combinata, con i pesi calibrati
python main.py --export-sqlite data/tyche.db

--update e --import mostrano che cosa cambierebbero e non scrivono nulla senza --yes, e rifiutano --yes quando l'import contraddice un'estrazione già registrata. L'archivio non ha un annulla e una delle due sorgenti di rete non è mai stata verificata: un lavoro pianificato che scrive tutto quello che ha analizzato è l'unica forma di questa funzione capace di distruggere lo storico in silenzio.


Installazione

pip install torch --index-url https://download.pytorch.org/whl/cpu
pip install -r requirements.txt
python main.py

Su Debian o Ubuntu tkinter è un pacchetto di sistema separato e deve corrispondere all'interprete con cui esegui Tyche:

sudo apt install python3-tk

La prima previsione con TimesFM scarica circa 1,3 GB di pesi da Hugging Face. Tutto il resto funziona senza — e finché quei pesi non sono sul computer, il passo 2 del Percorso e la scheda Previsione lo dicono e offrono il pulsante per scaricarli, invece di lasciartelo scoprire premendo «Genera».

Non serve un token Hugging Face, né un account. Il checkpoint predefinito è ad accesso libero: il token in Impostazioni esiste solo per un repository che il suo proprietario abbia messo ad accesso ristretto.

Se il download non arriva in fondo, si può fare a mano. Un gigabyte e mezzo su una linea domestica può interrompersi, e il modo di uscirne non è riprovare all'infinito: apri huggingface.co/google/timesfm-3.0-pytorch nel browser, scarica dalla scheda «Files» i due file config.json e model.safetensors, mettili in una cartella qualsiasi e indica quella cartella in Impostazioni → Cartella dei pesi TimesFM. Da lì in poi Tyche carica da quella cartella e non scarica più niente.

Bastano quei due file, e non è una semplificazione: timesfm3 passa una cartella a PyTorchModelHubMixin.from_pretrained, che apre config.json per costruire il modello e model.safetensors per riempirlo. Gli altri tre file del repository non vengono letti.

E dopo il download non c'è più rete. Il modello gira sul tuo computer, quindi il costo di una previsione è tempo di CPU e nient'altro: nessun consumo, nessuna chiamata a un servizio, nessun limite di quota. Quello che costa è il tempo: una previsione è una passata del modello sulla tua macchina, e --validate con TimesFM ne fa una per ogni estrazione valutata.

Per Windows c'è un pacchetto pronto allegato a ogni release: si scompatta in una sola cartella e si avvia con start.cmd, senza installare Python.

Il primo avvio richiede qualche secondo, e ogni avvio successivo anche. Da 1.3.0 Tyche è un unico eseguibile: tutto quello che gli serve — Python, Tk, PyTorch — sta dentro il file e viene scompattato in una cartella temporanea a ogni lancio. PyTorch da solo sono centinaia di megabyte, quindi qui l'attesa si vede più che in qualunque altro programma di questa famiglia. Non è un blocco e non è un errore: la finestra arriva. start.cmd aspetta che compaia e lo dice mentre aspetta, invece di lasciare la console muta.


Da dove vengono i dati

Quattro sorgenti, elencate per quanto meritano fiducia:

  • estrazioni.it — tutto l'archivio in una richiesta: 4.260 estrazioni dal 3 dicembre 1997 all'ultima, intestazione etichettata, zero problemi di integrità. È da qui che viene l'archivio di Tyche ed è la prima cosa che --update prova. Il suo indirizzo di download è dedotto e non documentato, quindi la CI lo ricontrolla e l'import viene sempre confermato prima di scrivere.
  • Import manuale — qualunque CSV, TXT o TSV scaricato a mano, compresa quella stessa esportazione. Il lettore riconosce il formato di Tyche, qualunque file con un'intestazione etichettata, il formato in blocco a dodici colonne e, come ultima risorsa, qualunque file con una data seguita da sei numeri per riga. Non può rompersi e non richiede rete.
  • Mirror storico — una richiesta, tutto lo storico, senza intestazione. Utile per partire, e si ferma a gennaio 2020: la sua stessa risposta HTTP dice last-modified: 24 Jan 2020. È anche sbagliato in alcuni punti — vedi sotto.
  • Scansione per anno — la sorgente che terrebbe aggiornato l'archivio senza scaricare a mano. I suoi indirizzi erano quattro tentativi fatti da un ambiente che non riusciva a raggiungere nessuno dei siti, e tutti e quattro hanno mancato. Uno è stato corretto sulla base di prove; gli altri restano tentativi. Controlla che cosa importa.

La scheda Archivio mostra un rapporto di integrità accanto all'elenco delle estrazioni, perché il mirror storico è sbagliato in un modo che nessun controllo riga per riga può vedere: le prime nove estrazioni del 1999 sono etichettate 1998, il che produce nove numeri di concorso duplicati e due coppie di estrazioni diverse che condividono una data. Tyche lo rileva e lo ripara all'import, sulla base di prove e non di un elenco scritto a mano — vedi core/archive.py::repair_year_offset.

Due conseguenze dell'avere una sorgente affidabile ma manuale e una automatica ma non verificata:

  • Gli import sono supervisionati. Prima di scrivere qualsiasi cosa, Tyche simula l'unione e mostra che cosa cambierebbe: righe aggiunte, righe che contraddicono un'estrazione registrata, e ogni errore di integrità che l'unione introdurrebbe. Un import pulito da una sorgente affidabile passa senza chiedere; tutto ciò che arriva da un indirizzo dedotto viene sempre confermato, perché un errore di analisi dall'aria sicura è esattamente quello che produce un lettore non verificato. C'è anche un interruttore per salvare le pagine scaricate: un parser non si corregge dalla descrizione di che cosa è andato storto, ma solo dalla pagina che è andata storta.
  • L'obsolescenza è sullo schermo, non nella documentazione. Il piè di pagina e la scheda Archivio dicono di quante estrazioni l'archivio è indietro, misurate sulla cadenza dell'archivio stesso e non su un calendario scritto nel codice.

Archivio


Che cosa hanno trovato i test

Su 4.260 estrazioni, dal 3 dicembre 1997 al 3 settembre 2026.

Test Esito
Uniformità dei 90 numeri χ² = 94,3 su 89 gdl, p = 0,33 — nessuno sbilanciamento
Distribuzione dei ritardi χ² = 45,7 su 50 gdl, p = 0,64 — i ritardi sono geometrici, nessun numero è mai «dovuto»
Indipendenza seriale, t → t+1 χ² = 0,95, p = 0,33 — l'ultima estrazione non dice nulla
Ripetizioni fra estrazioni consecutive χ² = 2,10 su 3 gdl, p = 0,55 — sovrapposizione media 0,391 contro 0,400 attesa
Somma dei sei numeri z = +3,73, p = 0,0002 — vedi sotto

Quattro test su cinque danno esattamente quello che produce un gioco equo. Il quinto no, ed è l'unico risultato reale qui — ma non quello che sembrava all'inizio.

La somma media dei sei numeri è 276,5 contro una attesa di 273,0. Era stata misurata la prima volta su un archivio diverso, e la spiegazione ovvia era che quel file fosse sbagliato. Non lo è: l'effetto si riproduce su una seconda fonte indipendente. Quello che fa, invece, è svanire.

Periodo Estrazioni Somma media
1997–1999 217 282,3
Anni 2000 1.287 278,5
Anni 2010 1.565 276,2
Anni 2020 1.191 273,8

Attesa: 273,0. Sulle ultime 1.191 estrazioni il test non trova più nulla — z = +0,42, e la correlazione fra un numero e quante volte è stato estratto scende da +0,37 sull'intero archivio a +0,05. Qualcosa spingeva l'estrazione verso i numeri alti, si è indebolito costantemente per venticinque anni, e da sei anni non c'è più niente da vedere. Che è grosso modo la forma che ci si aspetterebbe se fosse mai stato un fenomeno fisico.

Due cose che non è. Non è un motivo per giocare i numeri alti: lo sbilanciamento è sparito, e persino al suo massimo valeva meno del 2% per numero contro un montepremi che trattiene una quota fissa di ogni euro giocato. E non è un risultato acquisito: è una statistica su due fonti che potrebbero avere un antenato comune.

Il backtest walk-forward risolve la questione pratica. Ultime 1.000 estrazioni, sei numeri per volta:

Metodo Centri per estrazione Rispetto al caso p
casuale 0,3790 −21,0 0,26
frequenza 0,3930 −7,0 0,71
ritardo 0,3900 −10,0 0,59

Il caso vale 0,4000. Nessuno lo batte, modello da 330 milioni di parametri compreso.

Escludere i numeri appena usciti

Sembra la cosa più ovvia da fare, ed è l'impostazione «Escludi i numeri dell'ultima estrazione», attiva di default. Due righe della tabella qui sopra dicono già che non serve: l'estrazione precedente non dice nulla su quella dopo (p = 0,33), e due estrazioni consecutive hanno in comune 0,391 numeri dove il caso ne prevede 0,400. Un numero appena uscito vale quanto ogni altro.

Provata comunque, perché una misura vale più di un argomento. Ultime 1.000 estrazioni, 400 centri attesi dal caso, errore tipo 18,8:

Metodo Senza esclusione Con Colonne cambiate su 1.000
frequenza 369 375 499
ritardo 418 418 0
casuale 381 387 365

Si legga la terza riga per prima. L'esclusione fa guadagnare al generatore casuale esattamente quanto fa guadagnare al metodo frequenza: sei centri per ciascuno, un terzo di un errore tipo. È la dimostrazione più pulita che quei sei centri sono aritmetica e non bravura. Su 500 e su 2.000 estrazioni il quadro non cambia — la differenza più grande che si vede è di sei decimi di errore tipo. E il ritardo non si muove di un centro su nessuna delle tre: un numero appena uscito ha ritardo zero, quindi quel metodo lo teneva già per ultimo.

L'impostazione resta perché rinunciare a giocare sei numeri non costa niente — ogni colonna di sei vale quanto ogni altra, quali che siano i sei — e c'è chi preferisce non rigiocarli. È una preferenza sulla schedina, come quanti numeri giocare; non è un vantaggio, e il programma non la presenta come tale. Vale per tutti i metodi, compreso quello casuale: filtrarne quattro su cinque farebbe del controllo il controllo di un'altra cosa. Il SuperStar non è toccato, perché esce da un'altra urna e può ripetere uno dei sei — lo fa 247 volte contro le 223 attese.

Si rifà con python main.py --validate 1000 da entrambe le posizioni dell'impostazione: il backtest valuta la schedina che l'impostazione produce davvero.


«Non abbiamo trovato niente» oppure «non avremmo potuto trovarlo»

Sono due frasi diverse e producono lo stesso tabellone. Un esperimento che non trova nulla vale qualcosa solo se sappiamo che cosa sarebbe riuscito a trovare, quindi Tyche lo misura invece di lasciarlo intendere.

python main.py --power rifà la stessa prova contro previsori il cui vantaggio è noto, perché ce l'ha messo il programma. Ognuno legge di nascosto l'estrazione che gli si chiede di prevedere e ne rivela una parte, in una quantità che si può girare come una manopola: a zero è la linea di base casuale, alzandola diventa un oracolo. La frazione di ripetizioni in cui la validazione se ne accorge è la sua sensibilità.

Le forme del vantaggio sono tre, perché è la forma a decidere la risposta:

forma che cosa fa vista dai centri vista dal rango
concentrato rivela i sei numeri di netto, in cima da 0,020 mai all'80%
diffuso li fa salire di qualche posto da 0,020 da 0,020
nascosto li fa salire, ma mai oltre la metà mai da 0,050

La riga che conta è l'ultima. Il conteggio dei centri guarda solo i primi sei numeri di una graduatoria di novanta, quindi un vantaggio che esiste e non arriva fin lassù è invisibile per costruzione: il suo z resta lo stesso identico numero a ogni dimensione. La statistica sul rango medio lo vede a z = +11 sulle stesse prove.

Non è che il rango sia una misura migliore — sulla forma concentrato è nettamente peggiore. Sono due letture della stessa prova, cieche in punti diversi, e Tyche stampa entrambe.

La riga a dimensione zero è il controllo: non contiene alcun vantaggio, e segnala qualcosa nel 4% e nel 5% dei casi contro il 5% nominale. Se non fosse così, nessun'altra riga della stessa colonna vorrebbe dire niente.

E anche questa misura ha un limite dichiarato: tre forme non sono tutte le forme, quindi le soglie qui sopra sono il caso migliore. Un vantaggio reale di forma diversa sarebbe più difficile da vedere, non più facile.


L'ensemble e i pesi che nessuno ha scelto

La prima proposta della scheda Previsione non è un metodo nuovo: è i tre metodi di prima — TimesFM, ritardo, frequenza — mescolati.

Punteggio(n) = w_timesfm · TimesFM(n) + w_ritardo · Ritardo(n) + w_freq · Frequenza(n)

La domanda interessante non è la formula, è da dove vengono i tre pesi. Non sono scritti da nessuna parte nel codice, e non potrebbero esserlo: sceglierli a mano significherebbe affermare quale metodo ne sa di più, che è esattamente l'affermazione che tutto il resto di questo programma si rifiuta di fare.

Come vengono scelti

Un backtest walk-forward sulle ultime 120 estrazioni (si imposta):

  1. per ogni estrazione del backtest, ogni componente produce una graduatoria dei novanta numeri usando solo le estrazioni precedenti;
  2. le ultime 40 vengono messe da parte e non partecipano alla ricerca;
  3. tutte le 231 combinazioni di pesi a passi del 5% vengono provate sulle prime 80 e giudicate sulle 40 tenute da parte;
  4. e poi la procedura intera viene rimisurata come si comporterebbe davvero: ogni estrazione della seconda metà valutata con i pesi calcolati solo sulle precedenti, ricalibrati ogni dieci. È la riga «ensemble (ricalibrato)» del rapporto, ed è quella da leggere se se ne legge una sola.

Il criterio da minimizzare è il rango medio dei sei numeri usciti dentro la graduatoria dei novanta, non il conteggio dei centri: su poche decine di estrazioni i centri sono quasi tutti rumore, mentre il rango legge tutta la graduatoria — è la stessa differenza che la sezione sulla sensibilità misura per il backtest normale.

Tre regole che sembrano dettagli e non lo sono

I tre punteggi diventano distribuzioni, dividendo per la somma. Nient'altro. Una normalizzazione min-max, o una softmax con una temperatura, trasformerebbe la quarta cifra decimale di TimesFM in una graduatoria dall'aria sicura — e a quel punto a ordinare i numeri sarebbe la temperatura, non il modello. Se un componente è piatto resta piatto, e il rapporto stampa quanto lo è: entropia sulla distribuzione uniforme, «candidati efficaci», distanza dall'uniforme.

Fra i pesi che il backtest non sa distinguere viene preso il più equilibrato. Senza niente da trovare, il minimo del criterio su 231 combinazioni finisce in un angolo del simplesso più o meno come finisce altrove — e un angolo («frequenza 100%») non è un ensemble, è un'altra casella copiata nella prima. La colonna «compatibili» dice, per ogni componente, l'intervallo di pesi che il backtest non ha saputo distinguere dal migliore: dove è larga, il peso non è stato scelto, ed è giusto che si veda.

Un peso che non cambia la graduatoria non è una misura. Una miscela è lineare e tutte le distribuzioni hanno la stessa media, 1/90: quello che un componente aggiunge è il suo scostamento dall'uniforme moltiplicato per il suo peso. Un componente piatto non sposta niente a nessun peso, quindi il criterio lungo quell'asse è costante e la ricerca sta scegliendo fra candidati identici. Sotto il 2% di «influenza» il peso viene azzerato e ridistribuito.

Nessun minimo garantito, per nessuno

Non esiste nessuna regola del tipo «TimesFM almeno il 20%». Se la previsione del modello è piatta sui novanta numeri — ed è quello che fa su questi dati, vedi più sotto — il suo peso finisce a zero, e il rapporto distingue le due frasi che contano:

  • misurato e non ha guadagnato niente — il modello c'era, il backtest l'ha provato, il peso è zero;
  • non misurato — i pesi non sono su questo computer, quindi l'ensemble è fatto di due componenti e lo dice.

Il contrario vale allo stesso modo: messo alla prova contro un previsore con un vantaggio vero — uno di quelli di --power, che sbircia l'estrazione da prevedere — il backtest gli assegna il 75% del peso e registra che toglierlo costa venti posizioni di rango medio. Il meccanismo funziona in tutte e due le direzioni, ed è così che è stato verificato.

Che cosa stampa

python main.py --ensemble fa la calibrazione e stampa tutto: i pesi, la colonna «compatibili», l'influenza e l'entropia di ogni componente, che cosa ha segnato ogni componente da solo, che cosa ha segnato l'ensemble, che cosa ha segnato il controllo casuale sulle stesse estrazioni, quanto cambia togliendo ogni componente e ricalibrando senza, e la tabella numero per numero della prossima estrazione:

   n     Ritardo   Frequenza    ensemble  pos.
  69    0.058914    0.007212    0.033063     1
  27    0.055088    0.008814    0.031951     2
  24    0.049732    0.006410    0.028071     3

Le colonne sono distribuzioni: sommano a 1, quindi 1/90 = 0,011111 è il valore di un componente che non distingue niente. Non sono probabilità di uscita — di numeri ne escono sei su novanta, non uno — e infatti non vengono valutate come tali: log loss e Brier richiederebbero probabilità calibrate, e il numero che le calibrasse sarebbe un parametro libero deciso da chi lo sceglie.

E il risultato

Quello atteso. Sull'archivio l'intervallo compatibile copre l'intera gamma dei pesi — il backtest non sceglie, perché non c'è niente da cui scegliere — e l'ensemble segna un rango medio indistinguibile dal caso, esattamente come i tre metodi che lo compongono e come il generatore casuale che gli sta accanto. Quando succede, il rapporto lo scrive con queste parole: un ensemble che non migliora le sue componenti è una componente in più, non un metodo migliore.

I pesi calibrati restano in data/ensemble/, insieme ai risultati per estrazione del backtest: con TimesFM installato ogni estrazione costa una passata del modello, quindi si paga una volta e dopo un aggiornamento dell'archivio si ricalcolano solo le estrazioni nuove.


Sistemi e SuperStar

Nelle Impostazioni si scelgono due cose che cambiano la giocata.

Quanti numeri per combinazione. Sei è una colonna singola; da sette a dodici è un sistema integrale, che copre tutte le combinazioni di sei fra i numeri giocati. La previsione allora produce sistemi invece di colonne, e --validate misura quella stessa dimensione — nove numeri contro il caso a 0,600 centri per estrazione invece di 0,400, perché è un'altra scommessa.

Numeri Colonne coperte Il 6 è 1 su Per colonna
6 1 622.614.630 622.614.630
8 28 22.236.237 622.614.630
10 210 2.964.832 622.614.630
12 924 673.825 622.614.630

L'ultima colonna è il punto. Giocare più numeri accorcia davvero le probabilità del 6, e moltiplica il costo esattamente dello stesso fattore. La probabilità per euro giocato non si muove di una virgola: un sistema è un modo di spendere di più, non di ottenere di più. C'è un test che verifica che quel rapporto resti costante a ogni dimensione, così nessuna modifica futura può far sembrare un sistema un affare migliore di quello che è.

Quello che un sistema compra davvero sono le vincite minori che accompagnano quella grande: con dieci numeri, indovinandoli tutti e sei, la giocata non ha una colonna vincente ma un 6, ventiquattro 5 e novanta 4 — perché ogni colonna che contiene cinque dei sei è anch'essa sulla schedina. La scheda Previsione stampa quella tabella.

Perché una combinazione sola. La seconda combinazione è la settima scelta del metodo al posto della sesta, la terza l'ottava, e così via scendendo lungo la graduatoria. Su 1.000 estrazioni reali le cinque combinazioni segnano lo stesso punteggio — 0,393 contro 0,358, dentro un errore standard — perché un metodo che non sa niente non ha preferenze da rispettare. Ma contro un previsore a cui è stato dato un vantaggio vero, la prima combinazione segna 1,486 centri per estrazione e la quinta 0,304, appena sopra il caso.

Quindi più di una combinazione non vale mai di più per euro speso, e se il metodo sapesse qualcosa varrebbe di meno. Il valore predefinito è 1. Se si vuole comunque puntare più di una colonna, un sistema è il modo meglio argomentato per farlo: resta in cima alla graduatoria invece di scendere.

Quanto costa. La scheda Previsione stampa il costo della giocata che sta mostrando, ai prezzi che si impostano — un euro a colonna e cinquanta centesimi per il SuperStar, che si aggiunge a ogni colonna e non una volta sola. Sono prezzi decisi dal concessionario e non dalla matematica, quindi stanno nelle Impostazioni e si cambiano lì se cambiano.

Il conto rivela una cosa che non è ovvia. Le combinazioni proposte scorrono di un posto lungo la graduatoria, quindi si sovrappongono: cinque sistemi da dodici numeri fanno pagare 4.620 colonne e ne coprono 2.772 di diverse. Il 40% della spesa se ne va in colonne comprate due volte. Giocandone una sola non si spreca niente, e Tyche lo dice invece di limitarsi a stampare un totale.

Il SuperStar. Esce da un'urna separata, quindi è un numero da 1 a 90 indipendente dai sei che può ripeterne uno — sull'archivio reale lo fa 247 volte contro 223 attese. Tyche lo sceglie sulla storia della sua urna e non su quella dei sei, perché sono due domande diverse. Indovinarlo è 1 su 90, qualunque numero si giochi. L'archivio lo registra dal 28 marzo 2006, e le 914 estrazioni precedenti non vengono contate come se fosse uscito lo zero.


Le probabilità, che nessun metodo cambia

Combinatoria esatta su una ruota da 90 numeri, sei estratti:

Categoria Una su
6 622.614.630
5+1 103.769.105
5 1.250.230
4 11.907
3 327

Valgono qualunque numero si giochi. I premi sono a totalizzatore — una quota della raccolta, non un importo fisso — quindi il concessionario trattiene una parte fissa e il rendimento atteso di una colonna è sempre inferiore al suo prezzo.


Interrogare l'archivio

L'archivio è un CSV perché con 4.260 righe è la risposta giusta: 238 KB, 80 ms per caricarlo, e si può cercare con grep, confrontare dentro un commit e aprire in un foglio di calcolo. SQLite lo legge in 7 ms, undici volte più veloce, il che significa 73 millisecondi risparmiati una volta all'avvio per un file un terzo più grande — per confronto, costruire le matrici delle caratteristiche costa 63 ms.

Quindi a SQL tocca un'esportazione, non lo strato di memorizzazione:

python main.py --export-sqlite data/tyche.db

Tre tabelle: draws (una riga per estrazione, con la somma già calcolata), picks (una riga per numero per estrazione, indicizzata — è questa a rendere «quante volte è uscito il 37 nel 2024» un GROUP BY) e number_stats (la tabella delle frequenze, con accanto a ogni conteggio la sua attesa). Il database è un'istantanea usa e getta: nulla in Tyche lo rilegge.


Come viene usato TimesFM

core/features.py trasforma l'archivio in una matrice (90, T): una serie per numero, una colonna per estrazione. core/forecaster.py le consegna tutte e novanta a TimesFM 3.0 e ne chiede il valore successivo.

Due dettagli facili da sbagliare:

  • Usa TimesFM3Evaluator, non TimesFM3Forecaster. Il modello attende su al massimo 32 variate per passaggio. L'Evaluator è la sottoclasse che spezza un ingresso più ampio e ne ricompone il risultato, quindi novanta numeri diventano tre gruppi da trentadue. Non è un unico contesto congiunto su tutti e novanta, e chi ripete che «TimesFM 3.0 è multivariato, quindi li modella tutti insieme» dovrebbe saperlo.
  • Gli si danno le estrazioni grezze, e nient'altro. Una riga per numero, 1 se è uscito e 0 se no: l'archivio, senza perdere niente, nella forma che TimesFM legge. Fino alla 1.0.5 c'era un'impostazione per dargli invece una frequenza mobile, ed era quella predefinita — ed è il motivo per cui la classifica di TimesFM era una copia di quella del metodo «frequenza». Una media mobile di rumore bianco sembra avere uno slancio, e un buon previsore a cui la si dà prevede all'incirca l'ultimo valore: il modello stava riordinando il punteggio di un altro metodo. Due delle quattro caselle erano quasi lo stesso metodo, e questa pagina si regge sul fatto che siano quattro. Sul dato grezzo la previsione è più piatta e meno impressionante, ed è la verità su questi dati.

E che cosa ne fa, da un'esecuzione reale su una macchina che poteva scaricare i pesi:

frequenza  primi sei: 15 32 37 52 66 90    escursione 0,100000
timesfm    primi sei: 32 37 52 66 79 90    escursione 0,099857

Cinque numeri su sei coincidono e l'escursione corrisponde a quella della serie in ingresso fino alla quarta cifra. Date novanta serie senza segnale dentro, il modello prevede all'incirca l'ultimo valore di ciascuna — che è esattamente la cosa giusta, e che rende la sua classifica una copia di quella per frequenza. È tutto il risultato, in due righe.


Licenza

Tyche è AGPL-3.0-or-later. Vedi LICENSE per il testo completo e THIRD-PARTY-LICENSES.md per che cosa dipende da cosa.

In breve: puoi usarlo, studiarlo, modificarlo e ridistribuirlo per qualunque scopo. Se lo distribuisci — o se lo esponi come servizio di rete — devi consegnare il sorgente alle stesse condizioni, comprese le tue modifiche. Non c'è una licenza commerciale e non c'è un CLA: una contribuzione si offre sotto la stessa licenza, che è quello che l'AGPL prevede di suo.

I pesi del modello sono un'altra cosa dal codice del modello, ed è la distinzione che conta di più qui perché i due arrivano insieme. Il pacchetto timesfm è Apache-2.0. I pesi google/timesfm-3.0-pytorch, che Tyche scarica al primo uso, dichiarano timesfm-non-commercial-license-v1.0: uso non commerciale e non di produzione. Verificato sulla model card, e chiunque può rifare la verifica con il job checkpoint-licence della CI.

Quindi: l'AGPL ti permette di usare Tyche anche commercialmente, ed è un permesso che Tyche può darti. Non si estende ai pesi della 3.0, che non sono suoi da concedere. Il checkpoint 2.5 è Apache-2.0 e l'impostazione lo accetta già, ma core/forecaster.py è scritto sull'API della 3.0 e andrebbe adattato. Tutto il resto del programma — archivio, statistiche, test di indipendenza, validazione e i tre metodi che non sono TimesFM — funziona senza scaricare alcun peso.

Per qualsiasi cosa riguardi la licenza, o il programma in generale: marco.lombardo@gmail.com. È lo stesso indirizzo che core/version.py tiene come unica fonte, e che --version stampa.


Eseguire i test

python -m pytest tests/ -q                                    # 362 test core, 2 saltati
TYCHE_REQUIRE_GUI=1 xvfb-run -a python -m pytest tests/ -q     # 411, GUI compresa
python -m ruff check .

La suite GUI si salta da sola quando non c'è un display o manca tkinter, e un'esecuzione che riporta «130 passed, 1 skipped» significa che l'intera interfaccia non è stata provata. TYCHE_REQUIRE_GUI=1 trasforma quel salto in un errore: mettilo ogni volta che intendi aver verificato una modifica all'interfaccia. La CI lo mette.

Gli screenshot del README sono file versionati e invecchiano in silenzio. Dopo ogni modifica all'interfaccia:

SHOTDIR=docs/screenshots xvfb-run -a python docs/generate_screenshots.py

Release

Un tag pubblica una release. .github/workflows/release.yml fa il checkout del tag, esegue il linter, l'intera suite con l'interfaccia compresa, controlla che la versione riportata dal programma corrisponda al tag, e solo allora crea la release — con le note composte a partire da CHANGELOG.md e non dal registro dei commit.

Poi produce tre pacchetti — Windows, macOS e Linux — ognuno sul proprio runner, perché PyInstaller non compila per altre piattaforme. Prima che uno venga caricato deve avviare Tk davvero, presentarsi sul backend giusto per il suo sistema (win32, aqua, x11), eseguire l'analisi, superare un ciclo di scrittura e rilettura dell'archivio, dimostrare che TimesFM è realmente al suo interno, ed essere avviato dal proprio launcher — che viene a sua volta provato nel rifiutare un eseguibile il cui digest non corrisponde. Lo SHA-256 di ogni archivio finisce nelle note e non accanto al file, così arriva per una strada diversa da quella del download.

Dentro ogni archivio, in licenses/, viaggiano i testi di licenza di tutto quello che il pacchetto contiene, più l'inventario di quale binario appartiene a quale progetto, generato dalla macchina che lo ha costruito. Fino alla 0.3.3 gli archivi non contenevano nessun testo di licenza, nemmeno quello di Tyche; THIRD-PARTY-LICENSES.md racconta perché non era una formalità.

Resta una sola release online: finita la build, il workflow cancella la precedente e il suo tag. CHANGELOG.md conserva la storia di ogni versione.


Tyche porta il nome della dea greca della sorte. Non sta dalla parte di nessuno.

About

Strumento per l’analisi e la previsione del SuperEnalotto che verifica l’indipendenza delle estrazioni, valida i metodi predittivi con backtesting walk-forward e confronta le previsioni di TimesFM 3.0 con il caso.

Topics

Resources

Contributing

Stars

2 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages