Behebt die April-Verlustquelle: SELLs wurden als Market-Order mit 0.01-Limit ins
oft leergeraeumte Orderbuch geworfen -> wir wurden zur Exit-Liquidity. Jetzt:
GTC-Limit nahe am Master-Exit, stufenweises Nachpreisen bis zum Floor.
- Position.ExitPending (runtime-only, EF-ignoriert): Position wird bei SELL NICHT
mehr optimistisch entfernt, sondern als ExitPending zurueckgestellt (kein
Doppel-SELL, Limits rechnen korrekt; Sync schliesst nach bestaetigtem Fill).
- CopyTradingState.ExitLadders + ExitLadderState (transienter Leiter-Zustand).
- SellLogic (pure, getestet): FirstLimit (HF-fest/prozentual), Floor (SellFloorPct),
NextPrice (relative Stufe, auf Floor geclamped), IsAtFloor, LadderStepPct (3%),
LadderIntervalSeconds (HF 20s / sonst 120s).
- SellLadderService (BackgroundService): senkt offene Exit-Limits stufenweise
(cancel via CancelConflictingOrdersAsync -> tiefer neu platzieren), am Floor ohne
Fill Position halten + Threema-Benachrichtigung. Fills erkennt der bestehende Sync.
- CopyTradingEngine SELL-Live-Pfad ruft die Leiter; Demo-Pfad unveraendert.
Doppel-SELL-Guard ueber ExitPending. Umfangreiches Logging (kein Live-Test moeglich).
163 Tests gruen. Build/Smoke gruen. Backup-Rollback: Commit 1dffc9e.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
98 lines
4.4 KiB
C#
98 lines
4.4 KiB
C#
using System;
|
||
using System.Threading;
|
||
using System.Threading.Tasks;
|
||
using System.Threading.Channels;
|
||
using Microsoft.EntityFrameworkCore;
|
||
using Microsoft.Extensions.Configuration;
|
||
using Microsoft.Extensions.DependencyInjection;
|
||
using PolyTrader.Core.Configuration;
|
||
using PolyTrader.Core.Modularity;
|
||
using PolyTrader.Core.Streaming;
|
||
using PolyTrader.Modules.CopyTrading.Persistence;
|
||
using PolyTrader.Modules.CopyTrading.Persistence.Ef;
|
||
using PolyTrader.Modules.CopyTrading.Ui;
|
||
using PolyTraderSharp;
|
||
using PolyTraderSharp.Models;
|
||
using PolyTraderSharp.Services;
|
||
|
||
namespace PolyTrader.Modules.CopyTrading
|
||
{
|
||
/// <summary>
|
||
/// Das Copytrading-Modul: registriert seinen eigenen State, seine Channels, sein
|
||
/// Trade-Log-Repository und seine Services selbst. Die App kennt nur den Contract.
|
||
/// </summary>
|
||
public class CopyTradingModule : IPolyTraderModule
|
||
{
|
||
public string Name => "CopyTrading";
|
||
public string DbPrefix => "ct_";
|
||
|
||
public void RegisterServices(IServiceCollection services, IConfiguration configuration)
|
||
{
|
||
// Copytrading-Hot-Path-State
|
||
services.AddSingleton<CopyTradingState>();
|
||
|
||
// Signal-/Trade-Channels des Moduls
|
||
var copySignalChannel = Channel.CreateUnbounded<CopySignal>();
|
||
var closedTradeChannel = Channel.CreateUnbounded<ClosedTrade>();
|
||
services.AddSingleton(copySignalChannel.Writer);
|
||
services.AddSingleton(copySignalChannel.Reader);
|
||
services.AddSingleton(closedTradeChannel.Writer);
|
||
services.AddSingleton(closedTradeChannel.Reader);
|
||
|
||
// Modul-Persistenz: EF Core / Pomelo / MySQL (thread-safer DbContextFactory).
|
||
var conn = configuration["Database:MySqlConnectionString"] ?? string.Empty;
|
||
services.AddDbContextFactory<CopyTradingDbContext>(o => o.UseMySql(conn, DatabaseServerVersion.Value));
|
||
|
||
services.AddSingleton<ICopyTradeLogRepository, EfCopyTradeLogRepository>();
|
||
services.AddSingleton<ICopyTradingAccountSettingsRepository, EfCopyTradingAccountSettingsRepository>();
|
||
services.AddSingleton<ITrackedTraderRepository, EfTrackedTraderRepository>();
|
||
services.AddSingleton<IMasterTraderHistoryRepository, EfMasterTraderHistoryRepository>();
|
||
|
||
// WSS-Infrastruktur (Core) wird nur vom Copytrading-Blockchain-Listener genutzt.
|
||
services.AddSingleton<IBlockchainWssClientFactory, AlchemyWssClientFactory>();
|
||
|
||
// Modul-Services (Signalquelle, Ausführung, Analytics)
|
||
services.AddSingleton<TraderMonitorService>();
|
||
services.AddHostedService(sp => sp.GetRequiredService<TraderMonitorService>());
|
||
services.AddHostedService<CopyTradingEngine>();
|
||
services.AddHostedService<TraderAnalyticsJob>();
|
||
services.AddHostedService<MasterTraderAnalyticsJob>();
|
||
|
||
// Persistiert die geschlossenen Copytrades (Modul-Channel -> Modul-Log + Core-Log).
|
||
services.AddHostedService<PersistenceService>();
|
||
|
||
// WSS-Listener des Moduls: Blockchain (Alchemy → Master-Trader-Wallets) und
|
||
// Polymarket-Markt-WSS (Auto-Redeem nach Copytrading-Settings).
|
||
services.AddHostedService<AlchemyWebsocketService>();
|
||
services.AddHostedService<PolymarketWssClient>();
|
||
|
||
// Phase 0.1: SELL-Eskalationsleiter (preist offene Exit-Limits stufenweise nach).
|
||
services.AddHostedService<SellLadderService>();
|
||
}
|
||
|
||
public void RegisterUi(IModuleUiHost host, IServiceProvider services)
|
||
{
|
||
// EIN Fenster fürs ganze Modul: die einzelnen Ansichten sind Tabs im
|
||
// CopyTradingMainForm (Master-Trader / geschlossene Trades / Account-Einstellungen).
|
||
// So bleibt der Launcher schlank – ein Button je Modul statt je View.
|
||
host.RegisterView(new ModuleView
|
||
{
|
||
Id = "copytrading.main",
|
||
Title = "Copytrading",
|
||
Group = "CopyTrading",
|
||
Order = 100,
|
||
CreateForm = () =>
|
||
{
|
||
var form = new CopyTradingMainForm();
|
||
form.Initialize(services);
|
||
return form;
|
||
}
|
||
});
|
||
}
|
||
|
||
public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||
|
||
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||
}
|
||
}
|