# Orleans Migration Plan for Managing Apps Trading Bot ## Overview Migrate the `TradingBot` class to Microsoft Orleans grains for improved performance, scalability, and high availability while maintaining backward compatibility with the `Backtester` class. ## Current Architecture Analysis ### TradingBot Key Characteristics - Long-running stateful service with complex state (positions, signals, candles, indicators) - Timer-based execution via `InitWorker(Run)` - Dependency injection via `IServiceScopeFactory` - Persistence via `SaveBackup()` and `LoadBackup()` - SignalR integration for real-time updates ### Backtester Requirements - Creates TradingBot instances as regular classes (line 198: `_botFactory.CreateBacktestTradingBot`) - Runs synchronous backtesting without Orleans overhead - Needs direct object manipulation for performance ## 1. Orleans Grain Design ### A. Create ITradingBotGrain Interface ```csharp // src/Managing.Application.Abstractions/Grains/ITradingBotGrain.cs public interface ITradingBotGrain : IGrainWithStringKey { Task StartAsync(); Task StopAsync(); Task GetStatusAsync(); Task GetConfigurationAsync(); Task UpdateConfigurationAsync(TradingBotConfig newConfig); Task OpenPositionManuallyAsync(TradeDirection direction); Task ToggleIsForWatchOnlyAsync(); Task GetBotDataAsync(); Task LoadBackupAsync(BotBackup backup); } ``` ### B. Modify TradingBot Class ```csharp // src/Managing.Application/Bots/TradingBot.cs public class TradingBot : Grain, ITradingBotGrain, ITradingBot { // Keep existing implementation but add Orleans-specific methods // Add grain lifecycle management // Replace IServiceScopeFactory with Orleans DI } ``` ## 2. Program.cs Orleans Configuration Add to `src/Managing.Api/Program.cs` after line 188: ```csharp // Orleans Configuration builder.Host.UseOrleans(siloBuilder => { siloBuilder .UseLocalhostClustering() // For local development .ConfigureLogging(logging => logging.AddConsole()) .UseDashboard(options => { options.Port = 8080; }) .AddMemoryGrainStorageAsDefault() .ConfigureServices(services => { // Register existing services for Orleans DI services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); }); // Production clustering configuration if (builder.Environment.IsProduction()) { siloBuilder .UseAdoNetClustering(options => { options.ConnectionString = postgreSqlConnectionString; options.Invariant = "Npgsql"; }) .UseAdoNetReminderService(options => { options.ConnectionString = postgreSqlConnectionString; options.Invariant = "Npgsql"; }); } }); // Orleans Client Configuration (for accessing grains from controllers) builder.Services.AddOrleansClient(clientBuilder => { clientBuilder.UseLocalhostClustering(); if (builder.Environment.IsProduction()) { clientBuilder.UseAdoNetClustering(options => { options.ConnectionString = postgreSqlConnectionString; options.Invariant = "Npgsql"; }); } }); ``` ## 3. Conditional Bot Instantiation Strategy ### A. Enhanced BotFactory Pattern ```csharp // src/Managing.Application/Bots/Base/BotFactory.cs public class BotFactory : IBotFactory { private readonly IClusterClient _clusterClient; private readonly IServiceProvider _serviceProvider; public async Task CreateTradingBotAsync(TradingBotConfig config, bool useGrain = true) { if (config.IsForBacktest || !useGrain) { // For backtesting: Create regular class instance return new TradingBot( _serviceProvider.GetService>(), _serviceProvider.GetService(), config ); } else { // For live trading: Use Orleans grain var grain = _clusterClient.GetGrain(config.Name); return new TradingBotGrainProxy(grain, config); } } } ``` ### B. TradingBotGrainProxy (Adapter Pattern) ```csharp // src/Managing.Application/Bots/TradingBotGrainProxy.cs public class TradingBotGrainProxy : ITradingBot { private readonly ITradingBotGrain _grain; private TradingBotConfig _config; public TradingBotGrainProxy(ITradingBotGrain grain, TradingBotConfig config) { _grain = grain; _config = config; } public async Task Start() => await _grain.StartAsync(); public async Task Stop() => await _grain.StopAsync(); // Implement all ITradingBot methods by delegating to grain // This maintains compatibility with existing bot management code } ``` ### C. Backtester Compatibility In `Backtester.cs` (line 198), the factory call remains unchanged: ```csharp // This will automatically create a regular class instance due to IsForBacktest = true var tradingBot = await _botFactory.CreateBacktestTradingBot(config); ``` ## 4. Orleans Grain State Management ```csharp // src/Managing.Application/Bots/TradingBotGrainState.cs [GenerateSerializer] public class TradingBotGrainState { [Id(0)] public TradingBotConfig Config { get; set; } [Id(1)] public HashSet Signals { get; set; } [Id(2)] public List Positions { get; set; } [Id(3)] public Dictionary WalletBalances { get; set; } [Id(4)] public BotStatus Status { get; set; } [Id(5)] public DateTime StartupTime { get; set; } [Id(6)] public DateTime CreateDate { get; set; } } // Updated TradingBot grain public class TradingBot : Grain, ITradingBotGrain { private IDisposable _timer; public override async Task OnActivateAsync(CancellationToken cancellationToken) { // Initialize grain state and start timer-based execution if (State.Config != null && State.Status == BotStatus.Running) { await StartTimerAsync(); } } private async Task StartTimerAsync() { var interval = CandleExtensions.GetIntervalFromTimeframe(State.Config.Timeframe); _timer = RegisterTimer(async _ => await Run(), null, TimeSpan.Zero, TimeSpan.FromMilliseconds(interval)); } } ``` ## 5. Implementation Roadmap ### Phase 1: Infrastructure Setup 1. **Add Orleans packages** (already done in Managing.Api.csproj) 2. **Configure Orleans in Program.cs** with clustering and persistence 3. **Create grain interfaces and state classes** ### Phase 2: Core Migration 1. **Create ITradingBotGrain interface** with async methods 2. **Modify TradingBot class** to inherit from `Grain` 3. **Implement TradingBotGrainProxy** for compatibility 4. **Update BotFactory** with conditional instantiation logic ### Phase 3: Service Integration 1. **Replace IServiceScopeFactory** with Orleans dependency injection 2. **Update timer management** to use Orleans grain timers 3. **Migrate state persistence** from SaveBackup/LoadBackup to Orleans state 4. **Update bot management services** to work with grains ### Phase 4: Testing & Optimization 1. **Test backtesting compatibility** (should remain unchanged) 2. **Performance testing** with multiple concurrent bots 3. **High availability testing** with node failures 4. **Memory and resource optimization** ## Key Benefits 1. **High Availability**: Orleans automatic failover and grain migration 2. **Scalability**: Distributed bot execution across multiple nodes 3. **Performance**: Reduced serialization overhead, efficient state management 4. **Backward Compatibility**: Backtester continues using regular classes 5. **Simplified State Management**: Orleans handles persistence automatically ## Migration Considerations 1. **Async Conversion**: All bot operations become async 2. **State Serialization**: Ensure all state classes are serializable 3. **Timer Management**: Replace custom timers with Orleans grain timers 4. **Dependency Injection**: Adapt from ASP.NET Core DI to Orleans DI 5. **SignalR Integration**: Update to work with distributed grains ## Current Status - ✅ Orleans package added to Managing.Api.csproj - ✅ Orleans configuration implemented in Program.cs - ✅ ITradingBotGrain interface created - ✅ TradingBotGrainState class created - ✅ TradingBotGrain implementation completed - ✅ TradingBotResponse model created - ✅ TradingBotProxy adapter pattern implemented - ✅ Original TradingBot class preserved for backtesting - ✅ BotService conditional logic implemented for all creation methods - ⏳ Testing Orleans integration