Files
PolyTraderSharp/src/PolyTrader.Core/Services/CoreStateHydrationService.cs
T
RichardandClaude Opus 5 cd59e5c0a5 Avalonia-Grundgeruest: plattformneutrale App laeuft (Shell + erstes Fenster)
Neues Projekt src/PolyTrader.App.Avalonia (net10.0, Avalonia 12.1.1, LiveCharts2 2.0.5)
- laeuft unter Windows und Linux aus derselben Quelle.

Enthalten:
- Program.cs mit bewusst getrenntem Aufbau: BuildHost() stellt Persistenz, Dienste und
  Module ohne jeden UI-Bezug zusammen, erst Main haengt Avalonia daran. Damit ist der
  kopflose Linux-Betrieb (--headless, Stufe L2) ohne Umbau erreichbar - der Schalter ist
  bereits drin.
- AvaloniaUiHost als IModuleUiHost: gleiche Semantik wie die WinForms-Shell (ein Fenster
  je View, offene nach vorn holen, alles maximiert).
- Fenster-Menueleiste vollstaendig DEKLARATIV (Controls/WindowMenuBar.axaml + ItemsSource
  auf WindowMenuModel.Entries). Loest die alte Fassung ab, die menu.Items zur Laufzeit
  leerte und neu befuellte - genau der Punkt, den die neue Layout-Regel verbietet.
- ViewIcons fuer Avalonia: dieselben Schluessel und dieselben PNGs wie zuvor, Core und
  Module bleiben unveraendert.
- LauncherWindow, JobsWindow, ShutdownConfirmWindow (inkl. der 10-Sekunden-Sperre).
- --smoke-ui als Nachfolger der WinForms-Konstruktionspruefung; startet den Host bewusst
  NICHT, damit ein reiner UI-Test nicht die Trading-Engine gegen echte Endpunkte anwirft.

Dabei aufgeraeumt:
- JobManager.Jobs: BindingList -> ObservableCollection. BindingList implementiert kein
  INotifyCollectionChanged; neu registrierte Jobs waeren in Avalonia unsichtbar geblieben.
- StartupHydrationService aufgeteilt in CoreStateHydrationService (Core: Accounts +
  Demo-Positionen) und CopyTradingHydrationService (Modul: Settings + Trader). Behebt einen
  latenten Fehler: bei deaktiviertem Copytrading-Modul waeren die Accounts gar nicht mehr
  hydriert worden, obwohl sie zum Core gehoeren.

Verifiziert: Solution baut, 442 Tests gruen, --smoke-ui gruen, die App laeuft real mit
Fenster und allen Trading-Diensten (Market-Sync, Master-Trader-Analyse, RF-Scanner),
und publisht fuer linux-x64.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 17:55:05 +02:00

62 lines
2.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using PolyTrader.Core.Persistence;
using PolyTraderSharp.Models;
namespace PolyTraderSharp.Services
{
/// <summary>
/// Hydriert den Core-<see cref="TradingState"/> EINMALIG beim Start: Accounts und bei
/// Demo-Konten deren offene Positionen. Muss als ERSTER IHostedService laufen, damit die
/// Trading-BackgroundServices nicht gegen einen leeren State anlaufen (Startup-Race).
///
/// <para>Zuvor erledigte das der modulübergreifende <c>StartupHydrationService</c> der WinForms-App.
/// Der ist mit der Linux-Portierung aufgeteilt worden: Der Core-Anteil steht jetzt hier, der
/// Copytrading-Anteil im Modul (<c>CopyTradingHydrationService</c>). Das behebt nebenbei einen
/// latenten Fehler bei deaktiviertem Copytrading-Modul wären die Accounts vorher gar nicht
/// mehr hydriert worden, obwohl sie zum Core gehören.</para>
/// </summary>
public sealed class CoreStateHydrationService : IHostedService
{
private readonly TradingState _state;
private readonly IAccountRepository _accountRepo;
private readonly IPositionRepository _positionRepo;
private readonly TerminalLogger _logger;
public CoreStateHydrationService(TradingState state, IAccountRepository accountRepo,
IPositionRepository positionRepo, TerminalLogger logger)
{
_state = state;
_accountRepo = accountRepo;
_positionRepo = positionRepo;
_logger = logger;
}
public Task StartAsync(CancellationToken cancellationToken)
{
try
{
foreach (var acc in _accountRepo.GetAll())
{
if (acc.IsDemo)
foreach (var pos in _positionRepo.GetDemo(acc.AccountId))
acc.OpenPositions.TryAdd(pos.TokenId, pos);
_state.Accounts[acc.AccountId] = acc;
}
_logger.Info($"Core-Hydration abgeschlossen: {_state.Accounts.Count} Accounts geladen.");
}
catch (System.Exception ex)
{
_logger.Error($"Core-Hydration fehlgeschlagen: {ex.Message}");
}
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
}