Sostituisci le euristiche a soglia con regime e anticipo adattivi; un solo archivio per asta

Le strategie a numero fisso (calore, ritiro morbido, anti-bot, avversari aggressivi,
puntata probabilistica, velocità del prezzo, esaurimento, concorrenza) e le impostazioni
morte (cadenze di polling, finestra critica, database, log avanzati, suggerimenti
sull'anticipo, schede dettagliate) non ci sono più: rigiocate sui dossier non fermavano
una puntata sbagliata senza fermarne anche di giuste, e i loro numeri andavano tarati a
mano. Restano i paletti dell'utente (tetti, budget, fascia oraria) e il duello.

Al loro posto due componenti che imparano dalla sessione in corso, dentro i paletti:
- CompetitionRegime per asta (Calmo / Sfogo / Sondaggio) guidato dal valore atteso
  appreso: tre negativi di fila e si lascia sfogare gli altri, si rientra con una
  puntata di prova dopo abbastanza cicli buoni, e se viene coperta subito la pazienza
  raddoppia. È il "capire da soli quando tornare a puntare".
- LatencyModel per l'anticipo: margine + p99 della latenza misurata adesso, tenuto 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 (BidLeadIsManual).

Archiviazione: l'archivio mensile aste-AAAA-MM.jsonl (95 MB) duplicava il riepilogo che
ogni dossier ha già in coda. AuctionDetailStore ora legge testa e coda dei dossier, con
cache: 6349 file in 6 s la prima volta. Pulsanti per svuotare le esportazioni e per
azzerare le statistiche voce per voce (lo storico passa dalla copia di sicurezza).

Scheda Apprendimento: sezione "Autonomia sul momento" con il modello di latenza e il
regime di ogni asta seguita. Ml/LEGGIMI.md descrive l'algoritmo per intero.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-09-08 00:11:49 +02:00
co-authored by Claude Fable 5.1
parent afb778ea26
commit 8b7c39c9e3
36 changed files with 2111 additions and 1155 deletions
+27 -45
View File
@@ -140,20 +140,32 @@
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Anticipo Puntata (millisecondi)" Foreground="{DynamicResource Brush.Text}" Margin="0,10" VerticalAlignment="Center" ToolTip="Quanti millisecondi prima della scadenza parte la puntata. È il parametro che decide quanto costa vincere: il motore punta solo nei cicli che arrivano fin qui senza che nessun altro abbia puntato.&#10;&#10;Dalla rigiocata di 2.095 aste concluse: sotto il secondo basta in mediana 1 puntata per asta, sotto i 2 s ne servono 15, sotto i 3 s 46. Ma sotto i 600 ms un picco di rete fa arrivare la puntata a giochi chiusi (il ping tocca 444 ms nel p99,9).&#10;&#10;Fascia consigliata: 6002000 ms. Predefinito 1000."/>
<TextBox Grid.Row="0" Grid.Column="1" x:Name="DefaultBidBeforeDeadlineMsTextBox" Text="200" Margin="10,10"/>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Anticipo deciso dalla rete" Foreground="{DynamicResource Brush.Text}" Margin="0,10" VerticalAlignment="Center" ToolTip="Acceso: l'anticipo lo sceglie il modello di latenza — margine di sicurezza più la coda alta del ping di questa sessione — e si corregge da solo a ogni puntata tardiva. Si muove solo fra il minimo e il massimo qui sotto.&#10;&#10;Spento: vale l'anticipo fisso della riga seguente.&#10;&#10;In entrambi i casi un anticipo scritto a mano su una singola asta vince sempre."/>
<CheckBox Grid.Row="0" Grid.Column="1" x:Name="AdaptiveLeadCheckBox" Margin="10,10" VerticalAlignment="Center" IsChecked="True"/>
<TextBlock Grid.Row="1" Grid.Column="0" Text="Anticipo minimo (ms)" Foreground="{DynamicResource Brush.Text}" Margin="0,10" VerticalAlignment="Center" ToolTip="Il modello non scende mai sotto questo valore. Sotto i 300 ms un picco di rete fa arrivare la puntata a giochi chiusi: il ping tocca 444 ms nel p99,9."/>
<TextBox Grid.Row="1" Grid.Column="1" x:Name="LeadMinMsTextBox" Text="300" Margin="10,10"/>
<TextBlock Grid.Row="2" Grid.Column="0" Text="Anticipo massimo (ms)" Foreground="{DynamicResource Brush.Text}" Margin="0,10" VerticalAlignment="Center" ToolTip="Il modello non sale mai sopra questo valore. Ogni millisecondo in più è tempo regalato agli avversari: dalla rigiocata di 2.095 aste, sotto il secondo basta in mediana 1 puntata per asta, sotto i 2 s ne servono 15."/>
<TextBox Grid.Row="2" Grid.Column="1" x:Name="LeadMaxMsTextBox" Text="1500" Margin="10,10"/>
<TextBlock Grid.Row="3" Grid.Column="0" Text="Anticipo fisso (millisecondi)" Foreground="{DynamicResource Brush.Text}" Margin="0,10" VerticalAlignment="Center" ToolTip="Usato quando l'anticipo deciso dalla rete è spento, e come punto di partenza finché il modello non ha misurato abbastanza ping. Quanti millisecondi prima della scadenza parte la puntata: il motore punta solo nei cicli che arrivano fin qui senza che nessun altro abbia puntato."/>
<TextBox Grid.Row="3" Grid.Column="1" x:Name="DefaultBidBeforeDeadlineMsTextBox" Text="500" Margin="10,10"/>
<TextBlock Grid.Row="2" Grid.Column="0" Text="Prezzo Minimo (€)" Foreground="{DynamicResource Brush.Text}" Margin="0,10" VerticalAlignment="Center"/>
<TextBox Grid.Row="2" Grid.Column="1" x:Name="DefaultMinPriceTextBox" Text="0" Margin="10,10"/>
<TextBlock Grid.Row="5" Grid.Column="0" Text="Prezzo Minimo (€)" Foreground="{DynamicResource Brush.Text}" Margin="0,10" VerticalAlignment="Center"/>
<TextBox Grid.Row="5" Grid.Column="1" x:Name="DefaultMinPriceTextBox" Text="0" Margin="10,10"/>
<TextBlock Grid.Row="3" Grid.Column="0" Text="Prezzo Massimo (€)" Foreground="{DynamicResource Brush.Text}" Margin="0,10" VerticalAlignment="Center"/>
<TextBox Grid.Row="3" Grid.Column="1" x:Name="DefaultMaxPriceTextBox" Text="0" Margin="10,10"/>
<TextBlock Grid.Row="6" Grid.Column="0" Text="Prezzo Massimo (€)" Foreground="{DynamicResource Brush.Text}" Margin="0,10" VerticalAlignment="Center"/>
<TextBox Grid.Row="6" Grid.Column="1" x:Name="DefaultMaxPriceTextBox" Text="0" Margin="10,10"/>
<TextBlock Grid.Row="4" Grid.Column="0" Text="Max Click" Foreground="{DynamicResource Brush.Text}" Margin="0,10" VerticalAlignment="Center" ToolTip="Quante puntate al massimo spendere su una singola asta. Entra anche nel calcolo dei limiti consigliati per prodotto: ogni puntata in più è denaro che non si può mettere sul prezzo. 0 = illimitate."/>
<TextBox Grid.Row="4" Grid.Column="1" x:Name="DefaultMaxClicksTextBox" Text="0" Margin="10,10"/>
<TextBlock Grid.Row="7" Grid.Column="0" Text="Max Click" Foreground="{DynamicResource Brush.Text}" Margin="0,10" VerticalAlignment="Center" ToolTip="Quante puntate al massimo spendere su una singola asta. Entra anche nel calcolo dei limiti consigliati per prodotto: ogni puntata in più è denaro che non si può mettere sul prezzo. 0 = illimitate."/>
<TextBox Grid.Row="7" Grid.Column="1" x:Name="DefaultMaxClicksTextBox" Text="0" Margin="10,10"/>
</Grid>
</StackPanel>
</Border>
@@ -257,7 +269,7 @@ Consiglio: usa Fermata per caricare senza avviare, poi avvia a mano quelle che v
<StackPanel>
<ctl:HelpHeader Title="Motore di Precisione"
Margin="0,0,0,14"
Help="Ogni asta ha il proprio motore indipendente. Il polling si infittisce solo avvicinandosi alla scadenza: un'asta lontana non consuma richieste inutili, una vicina sì."/>
Help="Ogni asta ha il proprio motore indipendente e interroga Bidoo al massimo che la rete concede: nessuna cadenza da impostare. Se il server chiede di rallentare (429/503) il motore frena da solo e riparte appena può."/>
<Grid>
<Grid.ColumnDefinitions>
@@ -267,33 +279,13 @@ Consiglio: usa Fermata per caricare senza avviare, poi avvia a mano quelle che v
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Polling oltre 60s (ms)" Foreground="{DynamicResource Brush.Text}" Margin="0,10" VerticalAlignment="Center" ToolTip="Cadenza quando la scadenza è lontana"/>
<TextBox Grid.Row="0" Grid.Column="1" x:Name="PollIntervalFarMsTextBox" Text="2000" Margin="10,10"/>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Limite richieste al secondo" Foreground="{DynamicResource Brush.Text}" Margin="0,10" VerticalAlignment="Center" ToolTip="0 = nessun tetto (consigliato: si va al massimo che la rete concede). Le puntate hanno corsia preferenziale e non sono mai soggette a questo limite."/>
<TextBox Grid.Row="0" Grid.Column="1" x:Name="MaxRequestsPerSecondTextBox" Text="0" Margin="10,10"/>
<TextBlock Grid.Row="1" Grid.Column="0" Text="Polling 10-60s (ms)" Foreground="{DynamicResource Brush.Text}" Margin="0,10" VerticalAlignment="Center"/>
<TextBox Grid.Row="1" Grid.Column="1" x:Name="PollIntervalMidMsTextBox" Text="900" Margin="10,10"/>
<TextBlock Grid.Row="2" Grid.Column="0" Text="Polling sotto 10s (ms)" Foreground="{DynamicResource Brush.Text}" Margin="0,10" VerticalAlignment="Center"/>
<TextBox Grid.Row="2" Grid.Column="1" x:Name="PollIntervalNearMsTextBox" Text="400" Margin="10,10"/>
<TextBlock Grid.Row="3" Grid.Column="0" Text="Polling in finestra critica (ms)" Foreground="{DynamicResource Brush.Text}" Margin="0,10" VerticalAlignment="Center" ToolTip="Usato solo dalle aste in stato Attiva: in Osserva non c'è puntata da azzeccare"/>
<TextBox Grid.Row="3" Grid.Column="1" x:Name="PollIntervalCriticalMsTextBox" Text="220" Margin="10,10"/>
<TextBlock Grid.Row="4" Grid.Column="0" Text="Ampiezza finestra critica (ms)" Foreground="{DynamicResource Brush.Text}" Margin="0,10" VerticalAlignment="Center"/>
<TextBox Grid.Row="4" Grid.Column="1" x:Name="CriticalWindowMsTextBox" Text="4000" Margin="10,10"/>
<TextBlock Grid.Row="5" Grid.Column="0" Text="Limite richieste al secondo" Foreground="{DynamicResource Brush.Text}" Margin="0,10" VerticalAlignment="Center" ToolTip="Le puntate hanno corsia preferenziale e non sono soggette a questo limite"/>
<TextBox Grid.Row="5" Grid.Column="1" x:Name="MaxRequestsPerSecondTextBox" Text="40" Margin="10,10"/>
<TextBlock Grid.Row="6" Grid.Column="0" Text="Timer di sistema a 1 ms" Foreground="{DynamicResource Brush.Text}" Margin="0,10" VerticalAlignment="Center" ToolTip="Senza, ogni attesa può sforare di ~15 ms e l'anticipo perde significato"/>
<CheckBox Grid.Row="6" Grid.Column="1" x:Name="PrecisionTimerCheckBox" Margin="10,10" VerticalAlignment="Center" IsChecked="True"/>
<TextBlock Grid.Row="1" Grid.Column="0" Text="Timer di sistema a 1 ms" Foreground="{DynamicResource Brush.Text}" Margin="0,10" VerticalAlignment="Center" ToolTip="Senza, ogni attesa può sforare di ~15 ms e l'anticipo perde significato"/>
<CheckBox Grid.Row="1" Grid.Column="1" x:Name="PrecisionTimerCheckBox" Margin="10,10" VerticalAlignment="Center" IsChecked="True"/>
</Grid>
<Border Style="{StaticResource InfoBox}" Margin="0,15,0,0">
@@ -405,7 +397,6 @@ Dalla rigiocata di 2.095 aste concluse: con anticipo sotto il secondo serve in m
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Misura l'anticipo effettivo"
@@ -413,15 +404,9 @@ Dalla rigiocata di 2.095 aste concluse: con anticipo sotto il secondo serve in m
<CheckBox Grid.Row="0" Grid.Column="1" x:Name="BidLeadTrackingCheckBox"
Margin="10,10" VerticalAlignment="Center" IsChecked="True"/>
<TextBlock Grid.Row="1" Grid.Column="0" Text="Proponi correzioni"
Foreground="{DynamicResource Brush.Text}" Margin="0,10" VerticalAlignment="Center"
ToolTip="Il consiglio non viene mai applicato da solo"/>
<CheckBox Grid.Row="1" Grid.Column="1" x:Name="BidLeadSuggestionsCheckBox"
Margin="10,10" VerticalAlignment="Center" IsChecked="True"/>
<TextBlock Grid.Row="2" Grid.Column="0" Text="Puntate minime per un consiglio"
<TextBlock Grid.Row="1" Grid.Column="0" Text="Puntate minime per un consiglio"
Foreground="{DynamicResource Brush.Text}" Margin="0,10" VerticalAlignment="Center"/>
<TextBox Grid.Row="2" Grid.Column="1" x:Name="BidLeadMinSamplesTextBox"
<TextBox Grid.Row="1" Grid.Column="1" x:Name="BidLeadMinSamplesTextBox"
Text="15" Margin="10,10"/>
</Grid>
@@ -577,9 +562,6 @@ Dalla rigiocata di 2.095 aste concluse: con anticipo sotto il secondo serve in m
<TextBlock FontFamily="Segoe MDL2 Assets" Text="&#xE838;"/>
</Button>
</Grid>
<CheckBox x:Name="DetailedStatsCheckBox" IsChecked="True" Margin="0,0,0,6"
Content="Registra una scheda dettagliata per ogni asta conclusa (serie prezzi, puntate per utente, durata)"/>
</StackPanel>
</Border>