Implementate strategie avanzate e tracking aste v1.3.0
- Aggiunto BidStrategyService: adaptive latency, jitter, offset dinamico, heat metric, soft retreat, probabilistic bidding, profiling avversari, bankroll manager. - Esteso AuctionInfo con metriche avanzate: latenze, collisioni, heat, duello, tracking sessione, override strategie. - Nuova sezione "Strategie Avanzate" in Settings (UI) con opzioni dettagliate e bulk update. - Miglioramenti UX: auto-scroll log, filtri e dettagli avanzati in Statistics, gestione nomi prodotti, pulsanti sempre attivi. - Fix bug Blazor (layout, redirect, log, conteggio puntate, entità HTML). - Aggiornata documentazione, changelog, guide Docker/Gitea. - Versione incrementata a 1.3.0. Migrazione database per nuove metriche e tracking completo.
This commit is contained in:
@@ -148,6 +148,175 @@ namespace AutoBidder.Models
|
||||
}
|
||||
|
||||
public int PollingLatencyMs { get; set; } = 0; // Ultima latenza polling ms
|
||||
|
||||
// ???????????????????????????????????????????????????????????????
|
||||
// TRACKING AVANZATO PER STRATEGIE
|
||||
// ???????????????????????????????????????????????????????????????
|
||||
|
||||
/// <summary>
|
||||
/// Storico latenze ultime N misurazioni (per media mobile)
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public List<int> LatencyHistory { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Numero massimo di latenze da memorizzare
|
||||
/// </summary>
|
||||
private const int MAX_LATENCY_HISTORY = 20;
|
||||
|
||||
/// <summary>
|
||||
/// Aggiunge una misurazione di latenza allo storico
|
||||
/// </summary>
|
||||
public void AddLatencyMeasurement(int latencyMs)
|
||||
{
|
||||
LatencyHistory.Add(latencyMs);
|
||||
if (LatencyHistory.Count > MAX_LATENCY_HISTORY)
|
||||
LatencyHistory.RemoveAt(0);
|
||||
PollingLatencyMs = latencyMs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Latenza media calcolata sullo storico
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public double AverageLatencyMs => LatencyHistory.Count > 0
|
||||
? LatencyHistory.Average()
|
||||
: PollingLatencyMs > 0 ? PollingLatencyMs : 60;
|
||||
|
||||
/// <summary>
|
||||
/// Heat metric (0-100) che indica quanto è "calda" l'asta
|
||||
/// Calcolato in base a: bidder attivi, frequenza puntate, collisioni
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public int HeatMetric { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Numero di bidder unici attivi negli ultimi N secondi
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public int ActiveBiddersCount { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Numero di collisioni rilevate (puntate nello stesso secondo)
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public int CollisionCount { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Collisioni consecutive senza puntata vincente
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public int ConsecutiveCollisions { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp dell'ultimo soft retreat
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public DateTime? LastSoftRetreatAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Se true, l'asta è in soft retreat temporaneo
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public bool IsInSoftRetreat { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Contatore puntate effettuate in questa sessione su questa asta
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public int SessionBidCount { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Numero di volte che il timer è scaduto prima della puntata
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public int TimerExpiredCount { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Numero di puntate riuscite
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public int SuccessfulBidCount { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Numero di puntate fallite
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public int FailedBidCount { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Lista utenti identificati come aggressivi in questa asta
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public HashSet<string> AggressiveBidders { get; set; } = new(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// Offset dinamico calcolato per questa asta (ms)
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public int DynamicOffsetMs { get; set; } = 150;
|
||||
|
||||
/// <summary>
|
||||
/// Offset effettivo usato nell'ultima puntata (include jitter)
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public int LastUsedOffsetMs { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Indica se questa asta è stata seguita dall'inizio (per salvare storia completa)
|
||||
/// </summary>
|
||||
public bool IsTrackedFromStart { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp di inizio tracking
|
||||
/// </summary>
|
||||
public DateTime? TrackingStartedAt { get; set; }
|
||||
|
||||
// ???????????????????????????????????????????????????????????????
|
||||
// IMPOSTAZIONI PER-ASTA (override globali)
|
||||
// ???????????????????????????????????????????????????????????????
|
||||
|
||||
/// <summary>
|
||||
/// Override: abilita/disabilita strategie avanzate per questa asta
|
||||
/// null = usa impostazione globale
|
||||
/// </summary>
|
||||
public bool? AdvancedStrategiesEnabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Override: abilita/disabilita jitter per questa asta
|
||||
/// </summary>
|
||||
public bool? JitterEnabledOverride { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Override: abilita/disabilita soft retreat per questa asta
|
||||
/// </summary>
|
||||
public bool? SoftRetreatEnabledOverride { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Override: limite puntate per questa asta
|
||||
/// </summary>
|
||||
public int? MaxBidsOverride { get; set; }
|
||||
|
||||
// ?? NUOVO: Rilevamento situazione di duello
|
||||
|
||||
/// <summary>
|
||||
/// True se rilevata situazione di duello (solo 2 bidder dominanti)
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public bool IsDuelSituation { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Username dell'avversario in caso di duello
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public string? DuelOpponent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Vantaggio/svantaggio nel duello (% puntate mie - % puntate avversario)
|
||||
/// Positivo = sto dominando, Negativo = sto perdendo
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public double DuelAdvantage { get; set; } = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -117,4 +117,62 @@ namespace AutoBidder.Models
|
||||
|
||||
public double WinRate => TotalAuctions > 0 ? (double)WonAuctions / TotalAuctions * 100 : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Record completo storia asta con tutte le metriche avanzate
|
||||
/// </summary>
|
||||
public class CompleteAuctionHistoryRecord
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string AuctionId { get; set; } = "";
|
||||
public string AuctionName { get; set; } = "";
|
||||
public string? ProductKey { get; set; }
|
||||
public string? OriginalUrl { get; set; }
|
||||
|
||||
// Dati finali
|
||||
public double FinalPrice { get; set; }
|
||||
public double? BuyNowPrice { get; set; }
|
||||
public double? ShippingCost { get; set; }
|
||||
public double? TotalCost { get; set; }
|
||||
public double? Savings { get; set; }
|
||||
public double? SavingsPercentage { get; set; }
|
||||
|
||||
// Risultato
|
||||
public bool Won { get; set; }
|
||||
public string? WinnerUsername { get; set; }
|
||||
public int? WinnerBidsUsed { get; set; }
|
||||
|
||||
// Metriche competizione
|
||||
public int TotalResets { get; set; }
|
||||
public int TotalUniqueBidders { get; set; }
|
||||
public int MaxHeatMetric { get; set; }
|
||||
public double AvgHeatMetric { get; set; }
|
||||
public int TotalCollisions { get; set; }
|
||||
|
||||
// Mie statistiche
|
||||
public int MyBidsUsed { get; set; }
|
||||
public int MySuccessfulBids { get; set; }
|
||||
public int MyFailedBids { get; set; }
|
||||
public int MyTimerExpired { get; set; }
|
||||
public double? MyAvgLatencyMs { get; set; }
|
||||
|
||||
// Timestamps
|
||||
public DateTime ClosedAt { get; set; }
|
||||
public int ClosedAtHour { get; set; }
|
||||
public int? DurationSeconds { get; set; }
|
||||
public bool IsCompleteTracking { get; set; }
|
||||
|
||||
// JSON
|
||||
public string? AggressiveBiddersJson { get; set; }
|
||||
public string? BiddersSummaryJson { get; set; }
|
||||
|
||||
// Proprietà calcolate
|
||||
public string DurationFormatted => DurationSeconds.HasValue
|
||||
? TimeSpan.FromSeconds(DurationSeconds.Value).ToString(@"hh\:mm\:ss")
|
||||
: "-";
|
||||
|
||||
public double SuccessRate => (MySuccessfulBids + MyFailedBids) > 0
|
||||
? (double)MySuccessfulBids / (MySuccessfulBids + MyFailedBids) * 100
|
||||
: 0;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user