Files
PolyTraderSharp/Program.cs
T
RichardandClaude Opus 4.8 3503bbb5d4 Phase 5-UI (Proof-of-Pattern): Launcher-Shell + erste extrahierte View (Terminal)
- Ui/LauncherForm: schlanke Startleiste, rendert Buttons dynamisch aus den
  registrierten Views (gruppiert) + Legacy-Button fuer das alte Tab-frm_main.
- Ui/ViewHostForm: generisches Host-Fenster fuer eine View (Control docked fill).
- Ui/ShellUiHost : IModuleUiHost: sammelt Views, oeffnet Einzelinstanz-Fenster.
- Ui/Views/TerminalView: erste designbare View (UserControl + Designer.cs);
  Terminal-Logik aus frm_main extrahiert; DI via Initialize(TerminalLogger)
  -> parameterloser Ctor bleibt fuer den VS-Designer nutzbar.
- Program.cs: startet jetzt LauncherForm (statt frm_main), registriert die
  Terminal-View; App bleibt via Legacy-Button voll bedienbar.
- Build 0 Fehler.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 10:47:14 +02:00

153 lines
6.4 KiB
C#

using System;
using MongoDB.Driver;
using PolyTraderSharp.Extensions;
using System.Net.Http;
using System.Threading.Channels;
using System.Windows.Forms;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using PolyTrader.Core.Configuration;
using PolyTrader.Core.DependencyInjection;
using PolyTrader.Core.Streaming;
using PolyTrader.Modules.CopyTrading.Persistence;
using PolyTraderSharp.Models;
using PolyTraderSharp.Services;
namespace PolyTraderSharp;
internal static class Program
{
public static IHost? AppHost { get; private set; }
[STAThread]
private static void Main()
{
ApplicationConfiguration.Initialize();
Channel<CopySignal> copySignalChannel = Channel.CreateUnbounded<CopySignal>();
Channel<ClosedTrade> closedTradeChannel = Channel.CreateUnbounded<ClosedTrade>();
AppHost = Host.CreateDefaultBuilder().ConfigureServices(delegate(HostBuilderContext context, IServiceCollection services)
{
services.Configure<DatabaseOptions>(context.Configuration.GetSection(DatabaseOptions.SectionName));
services.AddSingleton<IMongoDatabase>((IServiceProvider sp) =>
{
var dbOptions = sp.GetRequiredService<IOptions<DatabaseOptions>>().Value;
var client = new MongoClient(dbOptions.ConnectionString);
return client.GetDatabase(dbOptions.DatabaseName);
});
services.AddCorePersistence();
services.AddSingleton<ICopyTradeLogRepository, MongoCopyTradeLogRepository>();
services.AddSingleton<IBlockchainWssClientFactory, AlchemyWssClientFactory>();
services.AddSingleton((IServiceProvider sp) => ServerSettings.Load("server_settings.xml"));
services.AddSingleton<TradingState>();
services.AddSingleton<CopyTradingState>();
services.AddSingleton(copySignalChannel.Writer);
services.AddSingleton(copySignalChannel.Reader);
services.AddSingleton(closedTradeChannel.Writer);
services.AddSingleton(closedTradeChannel.Reader);
services.AddSingleton(delegate(IServiceProvider sp)
{
TerminalLogger requiredService2 = sp.GetRequiredService<TerminalLogger>();
var httpHandler = new SocketsHttpHandler { PooledConnectionLifetime = TimeSpan.FromMinutes(2), MaxConnectionsPerServer = 100 };
return new PolymarketApiService(requiredService2, new HttpClient(httpHandler)
{
DefaultRequestHeaders =
{
{ "User-Agent", "py_clob_client" },
{ "Accept", "*/*" }
}
});
});
services.AddSingleton(delegate(IServiceProvider sp)
{
TerminalLogger requiredService2 = sp.GetRequiredService<TerminalLogger>();
var httpHandler = new SocketsHttpHandler { PooledConnectionLifetime = TimeSpan.FromMinutes(2), MaxConnectionsPerServer = 100 };
return new PolymarketClobClient(requiredService2, new HttpClient(httpHandler)
{
DefaultRequestHeaders =
{
{ "User-Agent", "py_clob_client" },
{ "Accept", "*/*" }
}
});
});
services.AddSingleton<TerminalLogger>();
services.AddSingleton<MullvadVpnService>();
services.AddSingleton<ThreemaService>();
services.AddSingleton<JobManager>();
services.AddSingleton<TraderMonitorService>();
// MUSS als erster HostedService laufen: hydriert den State, bevor die
// Trading-Services (unten) gegen einen leeren State anlaufen.
services.AddHostedService<StartupHydrationService>();
services.AddHostedService((IServiceProvider sp) => sp.GetRequiredService<TraderMonitorService>());
services.AddHostedService<CopyTradingEngine>();
services.AddHostedService<AlchemyWebsocketService>();
services.AddHostedService<PersistenceService>();
services.AddHostedService<MarketSyncService>();
services.AddHostedService<TraderAnalyticsJob>();
services.AddHostedService<MasterTraderAnalyticsJob>();
services.AddHostedService<PolymarketWssClient>();
services.AddHostedService((IServiceProvider sp) => sp.GetRequiredService<MullvadVpnService>());
services.AddHostedService((IServiceProvider sp) => sp.GetRequiredService<ThreemaService>());
services.AddTransient<frm_main>();
services.AddSingleton<PolyTraderSharp.Ui.ShellUiHost>();
services.AddTransient<PolyTraderSharp.Ui.LauncherForm>();
}).Build();
try
{
var db = AppHost.Services.GetRequiredService<IMongoDatabase>();
// Einmal-Bereinigung (Alt-Bug): entferne closed_trades mit ObjectId-_id.
// Das _id muss die int-TradeId sein; fehlerhafte Auto-ObjectIds werden verworfen.
// Läuft jetzt über die konfigurierte DB statt über einen hart codierten Client.
try
{
var cleanupCol = db.GetCollection<MongoDB.Bson.BsonDocument>("closed_trades");
cleanupCol.DeleteMany(Builders<MongoDB.Bson.BsonDocument>.Filter.Type("_id", MongoDB.Bson.BsonType.ObjectId));
}
catch { }
var copyState = AppHost.Services.GetRequiredService<CopyTradingState>();
var maxTradeDoc = db.GetCollection<MongoDB.Bson.BsonDocument>("closed_trades")
.Find(Builders<MongoDB.Bson.BsonDocument>.Filter.Empty)
.SortByDescending(d => d["_id"])
.Limit(1)
.FirstOrDefault();
if (maxTradeDoc != null && maxTradeDoc.Contains("_id"))
{
copyState.TotalCopyTrades = maxTradeDoc["_id"].AsInt32;
}
}
catch { }
AppHost.Start();
// Shell-Views registrieren (Core-App-Views; Module folgen via module.RegisterUi).
var uiHost = AppHost.Services.GetRequiredService<PolyTraderSharp.Ui.ShellUiHost>();
var viewServices = AppHost.Services;
uiHost.RegisterView(new PolyTrader.Core.Modularity.ModuleView
{
Id = "core.terminal",
Title = "Terminal",
Group = "Core",
Order = 10,
PreferredWidth = 1000,
PreferredHeight = 650,
CreateControl = () =>
{
var view = new PolyTraderSharp.Ui.Views.TerminalView();
view.Initialize(viewServices.GetRequiredService<TerminalLogger>());
return view;
}
});
// TODO Phase 5-UI: registrierte IPolyTraderModule durchlaufen und module.RegisterUi(uiHost) aufrufen.
var launcher = AppHost.Services.GetRequiredService<PolyTraderSharp.Ui.LauncherForm>();
Application.Run(launcher);
AppHost.StopAsync().GetAwaiter().GetResult();
}
}