Phase 1: Modul-System formalisiert (IModule + ModuleRegistry) - Core/Modules/IModule.cs: Vertrag (Key, DisplayName, Description, Version, RegisterServices, InitializeAsync, GetWorkers, CreateWindow) - Core/Modules/ModuleRegistry.cs - CongressTradingModule auf IModule umgestellt (instanzbasiert, Platzhalter-Fenster) - Program.cs iteriert ueber IModule[] + Registry; Form1 initialisiert Module ueber Registry - Testbarkeit: WorkerBase DB-Log-Seam (virtuell); CapitolTradesScraper.ParseTradesFromHtml extrahiert (offline gegen ct_raw.html testbar) - Tests: ModuleRegistry, CongressTradingModule, WorkerBase, CapitolTradesScraper -> 15/15 gruen Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> @
82 lines
2.9 KiB
C#
82 lines
2.9 KiB
C#
using System.Drawing;
|
||
using IBKRTrader.Core.Modules;
|
||
using IBKRTrader.Core.Workers;
|
||
using IBKRTrader.Modules.CongressTrading.Database;
|
||
using IBKRTrader.Modules.CongressTrading.Scraper;
|
||
using IBKRTrader.Modules.CongressTrading.Workers;
|
||
using Microsoft.Extensions.DependencyInjection;
|
||
|
||
namespace IBKRTrader.Modules.CongressTrading;
|
||
|
||
/// <summary>
|
||
/// CongressTrading-Modul: kopiert Aktien-Trades von US-Kongressmitgliedern
|
||
/// (Quelle: capitoltrades.com).
|
||
///
|
||
/// Architektur-Regel: Dieses Modul hängt sich ausschließlich über den
|
||
/// <see cref="IModule"/>-Vertrag ein. Der Core kennt dieses Modul NICHT –
|
||
/// die Abhängigkeit geht nur von Modul → Core.
|
||
/// </summary>
|
||
public sealed class CongressTradingModule : IModule
|
||
{
|
||
public const string ModuleKey = "CT";
|
||
|
||
public string Key => ModuleKey;
|
||
public string DisplayName => "Congress Trading";
|
||
public string Description => "Kopiert Aktien-Trades von US-Kongressmitgliedern (capitoltrades.com).";
|
||
public string Version => "1.0.0";
|
||
|
||
/// <summary>Registriert alle Modul-Services im DI-Container.</summary>
|
||
public void RegisterServices(IServiceCollection services)
|
||
{
|
||
// Datenbank
|
||
services.AddSingleton<CongressMigrations>();
|
||
services.AddSingleton<CongressRepository>();
|
||
|
||
// Scraper
|
||
services.AddSingleton<CapitolTradesScraper>();
|
||
|
||
// Worker
|
||
services.AddSingleton<CongressHistoryImportWorker>();
|
||
services.AddSingleton<CongressScrapeWorker>();
|
||
}
|
||
|
||
/// <summary>Führt die Modul-Migrationen aus.</summary>
|
||
public async Task InitializeAsync(IServiceProvider provider)
|
||
{
|
||
var migrations = provider.GetRequiredService<CongressMigrations>();
|
||
await migrations.RunAsync();
|
||
|
||
// Einmaliger Reset (deaktiviert): löscht alten Fortschritt für sauberen Neustart.
|
||
// var repo = provider.GetRequiredService<CongressRepository>();
|
||
// await repo.ResetHistoryImportAsync();
|
||
}
|
||
|
||
/// <summary>Gibt die Modul-Worker für die WorkerEngine zurück.</summary>
|
||
public IEnumerable<IWorker> GetWorkers(IServiceProvider provider) =>
|
||
[
|
||
provider.GetRequiredService<CongressHistoryImportWorker>(),
|
||
provider.GetRequiredService<CongressScrapeWorker>()
|
||
];
|
||
|
||
/// <summary>
|
||
/// Erzeugt das Modul-Fenster. Platzhalter – die vollständige UI folgt in Phase 2.
|
||
/// </summary>
|
||
public Form CreateWindow(IServiceProvider provider)
|
||
{
|
||
var form = new Form
|
||
{
|
||
Text = $"{DisplayName} ({Key})",
|
||
Width = 800,
|
||
Height = 500,
|
||
StartPosition = FormStartPosition.CenterParent
|
||
};
|
||
form.Controls.Add(new Label
|
||
{
|
||
Dock = DockStyle.Fill,
|
||
TextAlign = ContentAlignment.MiddleCenter,
|
||
Text = $"{DisplayName}\n\nModul-UI folgt in Phase 2."
|
||
});
|
||
return form;
|
||
}
|
||
}
|