.NET WinForms-Anwendung (Core, Modules/CongressTrading, UI). Enthaelt .gitignore und settings.example.json als Konfigurationsvorlage. Echte settings.json mit Zugangsdaten ist bewusst ausgeschlossen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
83 lines
2.8 KiB
C#
83 lines
2.8 KiB
C#
using IBKRTrader.Core.Database;
|
|
using IBKRTrader.Core.Logging;
|
|
using IBKRTrader.Core.Settings;
|
|
using IBKRTrader.Modules.CongressTrading.Database;
|
|
using IBKRTrader.Modules.CongressTrading.Scraper;
|
|
using IBKRTrader.Core.Workers;
|
|
|
|
namespace IBKRTrader.Modules.CongressTrading.Workers;
|
|
|
|
/// <summary>
|
|
/// Periodischer Scrape-Worker: alle 30 Minuten.
|
|
/// Lädt nur Seite 1 (neueste 96 Trades) und prüft auf neue Einträge.
|
|
/// Alle Daten (Datum, Typ, Value, Ticker, Mitglied) kommen direkt aus dem RSC-JSON.
|
|
/// </summary>
|
|
public class CongressScrapeWorker : WorkerBase
|
|
{
|
|
private readonly CapitolTradesScraper _scraper;
|
|
private readonly CongressRepository _repo;
|
|
|
|
public override string Name => "CT-ScrapeWorker";
|
|
public override string Module => "CT";
|
|
public override WorkerType Type => WorkerType.Worker;
|
|
|
|
protected override TimeSpan? Interval => TimeSpan.FromMinutes(30);
|
|
|
|
public CongressScrapeWorker(
|
|
LoggingService logger,
|
|
DatabaseService db,
|
|
CapitolTradesScraper scraper,
|
|
CongressRepository repo,
|
|
SettingsService settings)
|
|
: base(logger, db)
|
|
{
|
|
_scraper = scraper;
|
|
_repo = repo;
|
|
}
|
|
|
|
protected override async Task ExecuteAsync(CancellationToken ct)
|
|
{
|
|
Logger.Info(Module, "Suche neue Kongress-Trades (Seite 1)...");
|
|
|
|
var knownMembers = await _repo.GetAllMemberBioIdsAsync();
|
|
var (trades, _) = await _scraper.ScrapeTradesPageAsync(1, ct);
|
|
|
|
if (trades.Count == 0)
|
|
{
|
|
Logger.Warn(Module, "Scrape: Keine Trades auf Seite 1 gefunden.");
|
|
Info.Info = $"Letzter Lauf {DateTime.Now:HH:mm}: 0 Trades";
|
|
return;
|
|
}
|
|
|
|
// Neue Kongressmitglieder
|
|
var newMembers = 0;
|
|
foreach (var trade in trades.Where(t => t.MemberSnapshot != null))
|
|
{
|
|
var snapshot = trade.MemberSnapshot!;
|
|
if (knownMembers.Contains(snapshot.BioId)) continue;
|
|
|
|
await _repo.UpsertMemberAsync(snapshot);
|
|
knownMembers.Add(snapshot.BioId);
|
|
Logger.Info(Module, $"Neues Mitglied: {snapshot.Name} ({snapshot.BioId})");
|
|
newMembers++;
|
|
}
|
|
|
|
// Neue Trades
|
|
var newTrades = 0;
|
|
foreach (var trade in trades)
|
|
{
|
|
ct.ThrowIfCancellationRequested();
|
|
if (await _repo.TradeExistsAsync(trade.TradeId)) continue;
|
|
|
|
await _repo.InsertTradeAsync(trade, detailsFetched: true);
|
|
Logger.Info(Module,
|
|
$" + {trade.IssuerName} ({trade.TradeType}) [{trade.Ticker}] von {trade.MemberBioId}");
|
|
newTrades++;
|
|
}
|
|
|
|
var summary = $"{newTrades} neue Trades, {newMembers} neue Mitglieder";
|
|
Logger.Info(Module, $"Scrape abgeschlossen: {summary}");
|
|
Info.Info = $"Letzter Lauf {DateTime.Now:HH:mm}: {summary}";
|
|
}
|
|
}
|