Files
Mimante/Mimante/Ml/LEGGIMI.md
T
Alby96andClaude Fable 5.1 9177b31bd5 Due database, interruttore dell'apprendimento, barre a icone; via kill-switch, esportazioni e voci deprecate
Tutto ciò che l'applicazione registra sta ora in due file SQLite in
%LocalAppData%\AutoBidder\Database: autobidder.sqlite per le osservazioni e
esercizio.sqlite per i documenti d'esercizio (aste nel monitor, prodotti, promozioni,
modelli appresi con prefisso ml/) e per i registri applicativo e del riscatto puntate.
Il motore comune è SqliteDatabase; i file JSON e la cartella Apprendimento delle
versioni precedenti vengono importati la prima volta e lasciati dove sono. La cartella
si cambia dalle Impostazioni: al salvataggio si chiede se spostare i file, e si riavvia.
Le cartelle Dati/Statistiche/Registri, i registri su file, le misure dell'anticipo e
le impostazioni morte (LogBids, AutoApplyProductDefaults, NewAuctionLimitsPriority…)
non esistono più.

Il kill-switch se ne va: al suo posto un solo interruttore in barra, accanto ad
Avvia/Osserva/Ferma, che spegne l'apprendimento. Spento, il motore punta solo entro i
limiti dell'utente (prezzo, puntate, budget, fascia oraria, rischio) con l'anticipo
fisso: niente valore atteso, regime, duello, bandit, anticipo adattivo. Le aste vengono
comunque registrate e studiate.

Tre difetti visti osservando il motore dal vivo per un'ora, in Osserva:
- la copertura «Compralo Ora» con V lasciato al listino azzerava la perdita coperta e
  il motore diceva BID a ogni scadenza con P dell'1%: ora vale solo per i prodotti con
  «Valore reale €» scritto, altrimenti la puntata si conta persa e P decide;
- la chiusura di un'asta arrivava due volte (fine, poi rimozione dal monitor) e di
  nuovo al riavvio: modello, profilo, bandit e statistiche per prodotto contavano ogni
  asta due volte. Il monitor la comunica una volta sola, l'apprendimento salta le aste
  già apprese, e le schede prodotto vengono ricostruite una volta dallo storico;
- la pagina delle ricompense veniva scambiata per la pagina di accesso perché porta un
  collegamento a /login.php: prima si guarda se è la pagina delle ricompense.

Interfaccia: la scheda Esporta e tutto il suo codice sono tolti; le esportazioni
chiedono sempre dove salvare. Prodotti, Storico e Apprendimento hanno barre a sole
icone con tooltip che dicono esattamente cosa succede, colorate come il monitor, con
i nuovi pulsanti di pulizia (spegni tutte le stelline, togli i non seguiti, pulizia
completa; seleziona tutte / elimina le selezionate / svuota lo storico). Impostazioni:
sezione Database, Manutenzione con «Elimina tutti i dati (tranne la login)» e
«Impostazioni di fabbrica», esportazione dei registri in testo. Modifiche.txt, il
prompt ormai realizzato, esce dal repository.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-08 13:58:08 +02:00

15 KiB
Raw Blame History

AutoBidder — il sistema di decisione e apprendimento

Questo documento descrive come AutoBidder osserva, impara e decide. Vale come specifica: il codice in Data/, Ml/, Services/BidStrategyService.cs, Services/RiskManager.cs e Engine/AuctionRunner.cs la implementa, i test in Tests/ la verificano. Nessuna libreria esterna: SQLite arriva da winsqlite3.dll di Windows, rete neurale, bandit, simulatore e agente di rinforzo sono C# puro.


0. Avvertenze, prima di tutto

Termini e condizioni di Bidoo. I termini (it.bidoo.com/terms.php) vietano «l'uso di software di monitoraggio dell'offerta» e la creazione di account multipli, e consentono un solo account per persona. Questo programma è software di monitoraggio e puntata: il suo uso può comportare il blocco o la chiusura dell'account e la perdita delle puntate acquistate. Non implementa e non implementerà la creazione di account multipli.

Quadro legale. In Italia le aste al centesimo sono in una zona grigia: non classificate come gioco d'azzardo (art. 721 c.p. richiede aleatorietà pressoché totale; qui c'è un elemento di abilità), ma trattate dall'AGCM come pratica commerciale ai sensi del Codice del Consumo. Nel 2015 (provvedimenti PS8243 e PS9030) l'AGCM ha sanzionato due operatori del settore per un milione di euro complessivo. Non risulta alcuna azione contro Bidoo, ma ciò non è una garanzia.

Realtà economica. Augenblick (2016, Review of Economic Studies 83(1)), su 166.000 aste: il margine medio del banco supera il 50% del valore del bene; il 75% dei puntatori abbandona prima di 50 puntate, l'86% prima di 100. Platt, Price e Tappen (2013) e Hinnosaar (2016): in ogni equilibrio che non finisce subito, il profitto atteso di ogni puntata è zero. Un vantaggio, se esiste, viene solo dall'irrazionalità altrui (costo affondato, gusto per il rischio), non dalla struttura del gioco.

Il sistema è quindi scettico per costruzione: ogni stima di profittabilità si confronta con il null-model (ROI per puntata = 0), e l'esito atteso onesto è astenersi dalla grande maggioranza delle aste. Lo stato Osserva è la modalità shadow: registra ogni decisione che avrebbe preso senza puntare. L'utente ha scelto di non avere una shadow globale obbligatoria; le aste in Attiva puntano davvero, dentro i paletti del gestore del rischio.


1. Cosa si registra: il database

Due file SQLite in %LocalAppData%\AutoBidder\Database (cartella cambiabile dalle Impostazioni, con spostamento dei file e riavvio; mai una cartella sincronizzata):

  • autobidder.sqlite — le osservazioni: le tabelle qui sotto.
  • esercizio.sqlite — l'esercizio: i documenti JSON dell'applicazione (aste nel monitor, prodotti seguiti, statistiche per prodotto, promozioni riscattate, modelli appresi con prefisso ml/) e i registri applicativo e del riscatto puntate. I file JSON delle versioni precedenti vengono importati la prima volta e lasciati dove sono.

Le scritture vanno in coda e un thread dedicato per database le svuota a blocchi in transazioni: nulla sul percorso della puntata aspetta il disco. Le letture usano una seconda connessione con giornale WAL. Il motore comune è SqliteDatabase.

tabella cosa contiene
items il prodotto: chiave, titolo, «Compralo Ora», valore reale V scelto dall'utente, spedizione
auctions una riga per asta, aggiornata dall'apertura alla chiusura: esito, prezzo finale, vincitore, puntate mie e del vincitore, copertura dell'osservazione, rete, motore, serie dei prezzi, puntate per utente, configurazione
bids ogni puntata di ogni utente: prezzo dopo, tipo (Auto/Manuale), ora del server, secondi residui quando è arrivata, mia/altrui
polls le interrogazioni, coalescenti (quando cambia qualcosa, e almeno una al secondo): prezzo, timer, ultimo puntatore, ping, scarto dell'orologio
resets ogni azzeramento del timer con la profondità del ciclo (fin dove era sceso) e la sua durata
my_bids le nostre puntate: anticipo voluto ed effettivo, ping, andata e ritorno, esito, id della decisione
bot_decisions ogni decisione del motore, in shadow e dal vivo: azione, P(vittoria), EV, policy, regime, reason_detail, e l'esito scritto alla chiusura
network_metrics una riga ogni dieci secondi: mediana e p95 del ping, jitter, scarto dell'orologio
bidders chi punta: aste, puntate, quota di automatiche, vittorie
sessions, risk_ledger, meta sessioni dell'applicazione; uscite ed entrate in euro per il gestore del rischio; stato HALT

Lo storico compatto (CompletedAuctionsStore), le schede dettagliate (AuctionDetailStore), l'apprendimento, la rigiocata e le esportazioni leggono tutti da qui. I vecchi dossier JSON Lines restano leggibili (DossierReader.Read, DossierTrainingReader.Read) per un'eventuale importazione, ma non vengono più scritti.

Esiti delle decisioni. Alla chiusura dell'asta ogni decisione riceve un esito: se il prezzo non è più salito dopo quell'istante, una puntata lì sarebbe stata l'ultima (won/would_win; missed se non si è puntato), altrimenti sarebbe stata coperta (answered/would_be_answered; right_skip). È quello che permette di giudicare le policy sugli stessi istanti (§5).


2. Il modello matematico — Ml/Theory.cs

Valore atteso di una puntata (§3.1 del documento di progetto, nella forma corretta: la puntata si paga in entrambi i rami):

EV = P · (V  (p + Δ)  fee  spedizione  c)  (1  P) · c_perdita

con V il valore reale del bene (colonna «Valore reale €» nella scheda Prodotti; se vuota, il «Compralo Ora»), Δ = 0,01 €, fee ≈ 1 €, c il costo della puntata.

Copertura «Compralo Ora». Chi perde può comprare al listino L recuperando le puntate spese come credito: la perdita finale, se si esercita, è L V qualunque sia il numero di puntate. Quindi c_perdita = c finché spese + c ≤ L V, zero dopo. Con V = L la copertura è totale dal primo centesimo e si punterebbe sempre, a qualunque probabilità: in shadow è successo (BID con P dell'1%). Per questo la copertura è un'impostazione (Copertura «Compralo Ora») e vale solo per i prodotti con «Valore reale €» scritto: con V lasciato al listino la puntata si conta persa, come senza copertura.

Null-model. Profitto atteso per puntata = 0; numero critico di puntatori V/c (Hinnosaar). Sopravvivenza empirica: dalla tabella resets, P(vittoria) a un dato anticipo = quota dei cicli scesi almeno fin lì che hanno chiuso l'asta; curva di Kaplan-Meier della profondità dei cicli. Arrivi di Poisson: P(nessuna puntata in τ) = exp(−λτ) con λ dagli intervalli recenti.


3. La pipeline di decisione — Services/BidStrategyService.cs

Cinque passi, sempre nello stesso ordine, una volta per ciclo del timer, ~60 ms prima dell'istante di fuoco:

 RISCHIO ──▶ PALETTI ──▶ DUELLO ──▶ VALORE ATTESO ──▶ REGIME ──▶ punta?
 (solo dal    (utente)   (sessione)  (storico +          (sessione)
  vivo)                               sessione)                │
                                                    QUANDO: anticipo adattivo
  1. RischioRiskManager.Authorize: HALT persistente, stop-loss del giorno, drawdown dal picco, tetto di spesa del giorno, aste in gioco insieme. Lo stop-loss e il drawdown mettono in HALT, che sopravvive al riavvio e si toglie a mano. La contabilità è in risk_ledger: ogni puntata riuscita un'uscita, ogni vincita un'entrata al valore reale meno prezzo, fee e spedizione.

  2. Paletti — fascia oraria sospesa (globale, per prodotto, per asta), tetti di puntate.

    L'interruttore dell'apprendimento (il robot nella barra del monitor, accanto ad Avvia/Osserva/Ferma; LearningEnabled) taglia qui la pipeline: spento, i passi 35 non girano e l'anticipo è quello fisso delle impostazioni. Si punta solo entro i limiti dell'utente — prezzo minimo e massimo, puntate, budget, fascia oraria, rischio — come un cecchino senza cervello. Le aste vengono comunque registrate e studiate: quando lo si riaccende il modello non ha perso niente.

  3. Duello — cinque risposte di fila con la firma dell'autopuntata (6 ± 2,5 s) = macchina armata dall'altra parte; si smette e si informa il regime.

  4. Valore atteso — il modello dà P(senza risposta); Theory la trasforma in euro. Il modello parla sempre, decide dopo LearningMinAuctions aste apprese.

  5. RegimeCompetitionRegime: Calmo / Sfogo / Sondaggio con isteresi e pazienza che raddoppia a ogni sondaggio coperto. Uscire è facile, rientrare è difficile.

QuandoLatencyModel: anticipo = margine + p99 della latenza di sessione, fra LeadMinMs e LeadMaxMs; una puntata tardiva alza il margine subito, venti in tempo lo abbassano piano. Un anticipo scritto a mano su un'asta vince sempre.

Shadow. In Osserva il cecchino arriva allo stesso istante e chiama la stessa pipeline (saltando il gestore del rischio, che riguarda solo i soldi veri), registra la decisione e non punta. Ogni decisione porta anche il parere del bandit (§4.3) sullo stesso istante.


4. Cosa impara, e come — Ml/

4.1 P(senza risposta): campione e sfidante

Due modelli imparano dagli stessi esempi — ogni puntata di ogni asta chiusa, etichettata «è rimasta l'ultima?» — con le stesse variabili a fasce (BidFeatures: durata del ciclo, quota di autopuntate, puntatori distinti, prezzo sul valore, ora, giorno, ora di apertura, tipo di puntata, profondità, prodotto in 32 cassetti):

  • campione: regressione logistica online (OnlineLogit, SGD, L2, calibrazione in linea);
  • sfidante: rete neurale 70→32→16→1 (NeuralNet, ReLU, Adam, L2, stessa calibrazione).

A ogni esempio, prima di imparare, entrambi prevedono; il quadrato dell'errore va in una media mobile (20.000 esempi): è il punteggio di Brier prequenziale di ciascuno. Risponde al motore chi ce l'ha più basso; la rete non comanda prima di 5.000 esempi. La scheda Apprendimento mostra chi risponde e i due punteggi.

Perché non le nostre vittorie come etichetta: sono troppo poche (l'utente non ne ha ancora). Il comportamento avversario non dipende da chi ha puntato: questo rende utilizzabili i milioni di puntate altrui.

4.2 Profilo per prodotto e ora

AuctionProfileStats: puntate del vincitore e prezzo di chiusura in frazione del valore, per prodotto × fascia oraria × feriale/festivo, con restringimento gerarchico dove i dati scarseggiano. Alimentato asta per asta.

4.3 Bandit contestuale (Thompson)

ThompsonBandit: per ogni contesto (ciclo, prezzo/valore, fascia, puntatori, autopuntate) una Beta(α, β) su P(senza risposta). Decide estraendo p dalla Beta e applicando la regola del valore atteso: esplora dove ha visto poco, si stringe con i dati. Impara dagli esiti delle decisioni — informazione completa, anche dove non si è puntato. È la seconda policy, sempre in shadow, confrontata con la prima sugli stessi istanti.

4.4 Regime e latenza

Sessione in corso, non storico: CompetitionRegime per asta, LatencyModel per la rete. Vedi §3.

4.5 Simulatore e agente di rinforzo

PennyAuctionEnv: aste sintetiche con quattro profili di avversario (aggressivo, cecchino, autopuntata a 2 s, principiante), ognuno con credito e persistenza crescente con lo speso (costo affondato, Augenblick). Taratura dal database: puntatori per asta, istogramma della profondità dei cicli, quota di autopuntate, chiusura mediana in frazione del valore.

QLearningAgent: funzione Q su rete neurale, replay delle esperienze, ε-greedy decrescente, penalità conservativa sulle azioni poco viste (nello spirito di CQL). Si addestra solo nel simulatore: non si esplora con denaro vero.

SimulationLab mette a confronto su aste identiche (stessi semi): non punta mai, punta sempre, valore atteso con P empirica, bandit che impara giocando, agente Q. Il simulatore non è Bidoo: i numeri assoluti non contano, il confronto sì. È l'unico posto dove si vede come reagirebbero gli altri a una nostra puntata.


5. Come si giudica — ShadowReport, LearningEvaluator, rigiocata

  • Shadow (ShadowReport): sugli istanti di decisione con esito noto, per ogni policy: puntate, vincenti, spesi, incassati al valore reale, ROI per puntata con estremo inferiore dell'intervallo al 95%. Il null-model è battuto solo se l'estremo inferiore è sopra zero, su abbastanza puntate.
  • Prequenziale (LearningEvaluator, «Valuta ora»): addestra sulle aste più vecchie, giudica sulle più recenti, poi ogni asta prima prevista e poi appresa; sollevamento, calibrazione per fasce, punteggio di Brier, cosa avrebbe fatto il cancello sulle nostre puntate vere.
  • Rigiocata (BacktestReport): cosa avrebbe fatto il motore su ogni asta registrata, anticipo per anticipo; misura i costi, non l'esito.
  • Esportazione: «Esporta decisioni (CSV)» — punto e virgola, colonna reason_detail.

Criteri di promozione e di stop (dal documento di progetto): una policy passa dal shadow al vivo solo con ROI per puntata > 0 ed estremo inferiore > 0 su almeno quattro settimane, calibrazione buona, drawdown simulato entro il limite. Se dopo un periodo di vita reale il ROI cumulato non batte il null-model, il sistema resta strumento analitico e si spegne il vivo. La posizione di default è che un vantaggio consistente sia improbabile.


6. Dove si vede

Scheda Apprendimento: stato e pesi del modello, ultime decisioni, profilo per prodotto, valutazione, autonomia sul momento (latenza e regime per asta), shadow (policy a confronto, campione/sfidante, bandit), simulatore. Barra del monitor: l'interruttore dell'apprendimento. Scheda Impostazioni Gestione del rischio: paletti, HALT e contabilità; Impostazioni Database e Manutenzione: cartella dei database, «Elimina tutti i dati (tranne la login)», «Impostazioni di fabbrica». Scheda Prodotti: colonna «Valore reale €».

Nel registro di ogni asta: [SHADOW] Avrei puntato…, [REGIME] Calmo → Sfogo…, [TIMING] … anticipo adattivo…, ⛔ Strategia blocca: ….


7. Cosa non c'è, e perché

  • Feed DOM (Playwright): gli endpoint HTTP di Bidoo (data.php, get_auction_updates) sono verificati e usati da mesi; un browser sarebbe più lento e più fragile.
  • Dataset Swoopo (2008-09): sito e anni diversi; il database si riempie da solo.
  • Modelli sequenziali (LSTM/Transformer): rimandati; le variabili a fasce con la rete MLP coprono le interazioni che contano, e i dati per una sequenza profonda non ci sono.
  • Account multipli: mai.

8. Milestone

stato
M1 rischio, HALT, interruttore dell'apprendimento, shadow per asta fatto
M2 database SQLite (osservazioni + esercizio), registrazione, sessioni, misure di rete fatto (si parte da zero)
M3 teoria, simulatore con avversari tarati, rigiocata fatto
M4 modelli: logistico, rete neurale, profilo, hazard/Kaplan-Meier, Brier fatto
M5 policy: valore atteso + regime, bandit Thompson, agente Q conservativo fatto (Q solo nel simulatore)
M6 valutazione shadow ≥ 4 settimane, confronto fra policy strumenti pronti; servono le settimane
M7 esecuzione e latenza fatto (anticipo adattivo)
M8 monitoraggio e riaddestramento scheda pronta; riaddestramento a ogni asta chiusa; deriva: da fare