diff --git a/Program.cs b/Program.cs index e0a6de4..f5ca3b5 100644 --- a/Program.cs +++ b/Program.cs @@ -10,6 +10,8 @@ using Microsoft.Extensions.Options; using PolyTrader.Core.Configuration; using PolyTrader.Core.DependencyInjection; using PolyTrader.Core.Streaming; +using PolyTrader.Core.Modularity; +using PolyTrader.Modules.CopyTrading; using PolyTrader.Modules.CopyTrading.Persistence; using PolyTraderSharp.Models; using PolyTraderSharp.Services; @@ -25,8 +27,11 @@ internal static class Program { ApplicationConfiguration.Initialize(); - Channel copySignalChannel = Channel.CreateUnbounded(); - Channel closedTradeChannel = Channel.CreateUnbounded(); + var modules = new System.Collections.Generic.List + { + new CopyTradingModule() + }; + AppHost = Host.CreateDefaultBuilder().ConfigureServices(delegate(HostBuilderContext context, IServiceCollection services) { services.Configure(context.Configuration.GetSection(DatabaseOptions.SectionName)); @@ -37,15 +42,9 @@ internal static class Program return client.GetDatabase(dbOptions.DatabaseName); }); services.AddCorePersistence(); - services.AddSingleton(); services.AddSingleton(); services.AddSingleton((IServiceProvider sp) => ServerSettings.Load("server_settings.xml")); services.AddSingleton(); - services.AddSingleton(); - 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(); @@ -76,16 +75,21 @@ internal static class Program services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + // MUSS als erster HostedService laufen: hydriert den State, bevor die - // Trading-Services (unten) gegen einen leeren State anlaufen. + // Trading-Services gegen einen leeren State anlaufen. services.AddHostedService(); - services.AddHostedService((IServiceProvider sp) => sp.GetRequiredService()); - services.AddHostedService(); + + // Module registrieren ihre eigenen Services/Channels/State selbst. + foreach (var module in modules) + { + services.AddSingleton(module); + module.RegisterServices(services, context.Configuration); + } + services.AddHostedService(); services.AddHostedService(); services.AddHostedService(); - services.AddHostedService(); services.AddHostedService(); services.AddHostedService(); services.AddHostedService((IServiceProvider sp) => sp.GetRequiredService()); @@ -193,7 +197,11 @@ internal static class Program return view; } }); - // TODO Phase 5-UI: registrierte IPolyTraderModule durchlaufen und module.RegisterUi(uiHost) aufrufen. + // Modul-UI registrieren (Module steuern ihre Views selbst bei). + foreach (var module in modules) + { + module.RegisterUi(uiHost); + } var launcher = AppHost.Services.GetRequiredService(); Application.Run(launcher); diff --git a/src/PolyTrader.Modules.CopyTrading/CopyTradingModule.cs b/src/PolyTrader.Modules.CopyTrading/CopyTradingModule.cs new file mode 100644 index 0000000..18da1b2 --- /dev/null +++ b/src/PolyTrader.Modules.CopyTrading/CopyTradingModule.cs @@ -0,0 +1,55 @@ +using System.Threading; +using System.Threading.Tasks; +using System.Threading.Channels; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using PolyTrader.Core.Modularity; +using PolyTrader.Modules.CopyTrading.Persistence; +using PolyTraderSharp; +using PolyTraderSharp.Models; +using PolyTraderSharp.Services; + +namespace PolyTrader.Modules.CopyTrading +{ + /// + /// Das Copytrading-Modul: registriert seinen eigenen State, seine Channels, sein + /// Trade-Log-Repository und seine Services selbst. Die App kennt nur den Contract. + /// + 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(); + + // Signal-/Trade-Channels des Moduls + var copySignalChannel = Channel.CreateUnbounded(); + var closedTradeChannel = Channel.CreateUnbounded(); + services.AddSingleton(copySignalChannel.Writer); + services.AddSingleton(copySignalChannel.Reader); + services.AddSingleton(closedTradeChannel.Writer); + services.AddSingleton(closedTradeChannel.Reader); + + // Modul-eigener Trade-Log + services.AddSingleton(); + + // Modul-Services (Signalquelle, Ausführung, Analytics) + services.AddSingleton(); + services.AddHostedService(sp => sp.GetRequiredService()); + services.AddHostedService(); + services.AddHostedService(); + } + + public void RegisterUi(IModuleUiHost host) + { + // TODO: Master-Traders- und Geschlossene-Trades-Views als Modul-UI beisteuern. + } + + public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask; + + public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; + } +} diff --git a/services/CopyTradingEngine.cs b/src/PolyTrader.Modules.CopyTrading/Services/CopyTradingEngine.cs similarity index 99% rename from services/CopyTradingEngine.cs rename to src/PolyTrader.Modules.CopyTrading/Services/CopyTradingEngine.cs index f338c75..11464a3 100644 --- a/services/CopyTradingEngine.cs +++ b/src/PolyTrader.Modules.CopyTrading/Services/CopyTradingEngine.cs @@ -1,7 +1,5 @@ using System; -using MongoDB.Driver; using PolyTrader.Core.Persistence; -using PolyTraderSharp.Extensions; using System.Threading; using System.Threading.Channels; using System.Threading.Tasks; diff --git a/services/TraderAnalyticsJob.cs b/src/PolyTrader.Modules.CopyTrading/Services/TraderAnalyticsJob.cs similarity index 100% rename from services/TraderAnalyticsJob.cs rename to src/PolyTrader.Modules.CopyTrading/Services/TraderAnalyticsJob.cs diff --git a/services/TraderMonitorService.cs b/src/PolyTrader.Modules.CopyTrading/Services/TraderMonitorService.cs similarity index 100% rename from services/TraderMonitorService.cs rename to src/PolyTrader.Modules.CopyTrading/Services/TraderMonitorService.cs