- Neu in PolyTrader.Core.Streaming: IBlockchainWssClient + AlchemyWssClient (+ Factory) und Modelle (BlockchainWssSubscription/LogSubscriptionFilter/ BlockchainLogEvent). Domänen-agnostisch: Connect, eth_subscribe, Receive-Loop, Decode; Reconnect/Gating/Filter bleiben beim Aufrufer. - AlchemyWebsocketService (weiter in App) nutzt jetzt den Core-Client via Factory: baut Filter aus getrackten Trader-Wallets, konsumiert OnLog, triggert Poll. ExecuteAsync-Reconnect/Backoff/Gating unverändert. Verhaltensneutral. - Factory in DI registriert. - Build 0 Fehler. Naechster Teil: Modul-Listener (eigener Key+Filter) nach Modul-Umzug. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
128 lines
5.4 KiB
C#
128 lines
5.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 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<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>();
|
|
}).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();
|
|
frm_main requiredService = AppHost.Services.GetRequiredService<frm_main>();
|
|
Application.Run(requiredService);
|
|
AppHost.StopAsync().GetAwaiter().GetResult();
|
|
}
|
|
}
|