Slice 6 (Fable-Fixes): Totcode/Demo-Balance/Settings-Validierung + Plan-Abschluss

- Totcode: services/SnapshotService.cs entfernt (nirgends registriert).
- Demo-Balance/PnL-Reconciliation: Demo-BUY zieht jetzt die Entry-Fee ab, Demo-Close
  schreibt netto (exitUsd - Exit-Fee) gut -> Summe(Balance-Aenderungen) = Summe(PnL)
  statt um die Fees zu driften (Demo als Validierung konsistent).
- Settings-Validierung: SellLogic.IsLadderConfigInverted (Max-Preisabstand >= SELL-Floor
  -> Leiter startet am Floor) + Warnung beim Settings-Laden (StartupHydration).

Bewusst als Follow-up dokumentiert (Live-Verifikation/Risiko): M3-Autoincrement-Migration,
PersistenceService-Dedup-Zeitfenster, Perf (UpsertLive-Dirty-Check, Leiter-Parallelitaet).

Tests: +3 (IsLadderConfigInverted). Build 0 Fehler, 236 gruen, --smoke-ui ok.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-07-09 18:45:52 +02:00
co-authored by Claude Opus 4.8
parent 84b2b276d9
commit 782c08a860
6 changed files with 50 additions and 158 deletions
@@ -539,7 +539,12 @@ namespace PolyTraderSharp.Services
_positionRepo.UpsertDemo(account.AccountId, finalPos);
account.UpdateBalance(account.AvailableBalance - exactUsdc);
// Entry-Fee auch im Demo abziehen, damit Balance und PnL konsistent bleiben (siehe Close).
int demoBuyFeeBps = _state.MarketCache.TryGetValue(signal.TokenId, out var demoBuyMd)
? FeeModel.ResolveBps(demoBuyMd.TakerFeeBps, demoBuyMd.Category)
: FeeModel.FallbackBps(null);
decimal demoEntryFee = FeeModel.FeeUsd(exactUsdc, demoBuyFeeBps);
account.UpdateBalance(account.AvailableBalance - exactUsdc - demoEntryFee);
_accountRepo.Upsert(account);
_logger.Trade($"✅ [DEMO AUSGEFÜHRT]\n" +
$" Konto: {account.Name}\n" +
@@ -678,7 +683,10 @@ namespace PolyTraderSharp.Services
decimal demoExitPrice = DemoModel.ExitFillPrice(signal.Price, DemoModel.FallbackHalfSpread);
_state.GlobalPnl += realizedPnl;
account.UpdateBalance(account.AvailableBalance + exitUsd);
// Balance netto gutschreiben (exitUsd Exit-Fee), damit Σ(Balance-Änderungen) = Σ(PnL)
// statt um die Fees zu driften (Entry-Fee wurde beim BUY abgezogen).
decimal demoExitFee = FeeModel.FeeUsd(exitUsd, demoFeeBps);
account.UpdateBalance(account.AvailableBalance + exitUsd - demoExitFee);
_accountRepo.Upsert(account);
var ct = new ClosedTrade