Files
PolyTraderSharp/src/PolyTrader.Modules.ResolutionFarming/ResolutionFarmingModule.cs
T
RichardandClaude Opus 4.8 ad6c676e60 RF-Slice 3: Read-only-Scanner (Bewertungs-Pipeline + Persistenz)
Phase RF-1 (read-only): Scanner holt bald aufloesende Favoriten von einer
IFarmingMarketSource, bewertet sie und schreibt JEDEN Kandidaten (akzeptiert wie
abgelehnt inkl. Grund) nach rf_candidates. Platziert keine Orders.

- MarketScannerService.Evaluate (pur/statisch, voll getestet): Filterkette mit
  Reject-Grund = erster Fehlschlag (Preisband -> Kategorie -> Blacklist ->
  Aufloesungsfenster -> Netto-Edge nach Fees). Cluster-Key + Score immer berechnet.
- ScanAccountAsync: Beschaffung -> Bewertung -> Persistenz. BackgroundService-Loop
  (12min) ueber Accounts mit Settings; fehlertolerant.
- IFarmingMarketSource + ScannedMarket-DTO trennen die (live-/API-gebundene)
  Beschaffung von der Bewertung -> Pipeline ohne echte Gamma/CLOB-API testbar.
- NullFarmingMarketSource als Default: Modul laeuft ohne Live-Anbindung (die im
  Zielland registriert wird) und produziert dann korrekt keine Kandidaten.

Hinweis: Zur Laufzeit fragt der Scanner rf_settings ab; bis die Migration angewendet
ist, faengt der try/catch den fehlenden-Tabelle-Fehler ab (nur Log). Migration bewusst
separat anzuwenden.

7 neue Tests (Evaluate-Faelle + Orchestrierung). Build 0 Fehler, 296 Tests gruen, --smoke-ui ok.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 22:11:11 +02:00

58 lines
2.9 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.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using PolyTrader.Core.Configuration;
using PolyTrader.Core.Modularity;
using PolyTrader.Modules.ResolutionFarming.Persistence;
using PolyTrader.Modules.ResolutionFarming.Persistence.Ef;
namespace PolyTrader.Modules.ResolutionFarming
{
/// <summary>
/// Strategiemodul „ResolutionFarming": kauft systematisch unterbewertete Favoriten (~0.900.98)
/// in bald auflösenden Märkten, hält bis zur Resolution und löst ein (Favorite-Longshot-Reversal).
/// Erstes neues Strategiemodul über Copytrading hinaus geringster Infrastrukturbedarf.
///
/// Aufbau (inkrementell): geldkritische Entscheidungslogik liegt pur und unit-getestet in
/// <c>Logic/</c> (FarmingRiskEngine, FarmingScanner, FarmingFillModel); Persistenz, Scanner-Job,
/// Execution und UI folgen in eigenen Slices. Live-CLOB/On-Chain-Redeem sind Zielland-Arbeit.
/// </summary>
public class ResolutionFarmingModule : IPolyTraderModule
{
public string Name => "ResolutionFarming";
public string DbPrefix => "rf_";
public void RegisterServices(IServiceCollection services, IConfiguration configuration)
{
// Modul-Persistenz: EF Core / Pomelo / MySQL (thread-safer DbContextFactory), eigene rf_-Tabellen.
var conn = configuration["Database:MySqlConnectionString"] ?? string.Empty;
services.AddDbContextFactory<ResolutionFarmingDbContext>(o => o.UseMySql(conn, DatabaseServerVersion.Value));
services.AddSingleton<IRfSettingsRepository, EfRfSettingsRepository>();
services.AddSingleton<IRfCandidateRepository, EfRfCandidateRepository>();
services.AddSingleton<IRfPositionRepository, EfRfPositionRepository>();
services.AddSingleton<IRfClosedTradeRepository, EfRfClosedTradeRepository>();
// Read-only-Scanner (Phase RF-1). Marktquelle vorerst NullFarmingMarketSource: das Modul
// läuft ohne Live-Gamma/CLOB-Anbindung (die im Zielland registriert wird) und produziert
// dann korrekt keine Kandidaten.
services.AddSingleton<Services.IFarmingMarketSource, Services.NullFarmingMarketSource>();
services.AddSingleton<Services.MarketScannerService>();
services.AddHostedService(sp => sp.GetRequiredService<Services.MarketScannerService>());
// Execution, Resolution-Monitor, Auto-Redeem und UI folgen in den nächsten Slices.
}
public void RegisterUi(IModuleUiHost host, System.IServiceProvider services)
{
// Slice 1: noch keine UI-Tabs. Folgen mit Persistenz/Scanner.
}
public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
}