* Start building with orlean * Add missing file * Serialize grain state * Remove grain and proxies * update and add plan * Update a bit * Fix backtest grain * Fix backtest grain * Clean a bit
255 lines
8.9 KiB
Markdown
255 lines
8.9 KiB
Markdown
# 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<BotStatus> GetStatusAsync();
|
|
Task<TradingBotConfig> GetConfigurationAsync();
|
|
Task<bool> UpdateConfigurationAsync(TradingBotConfig newConfig);
|
|
Task<Position> OpenPositionManuallyAsync(TradeDirection direction);
|
|
Task ToggleIsForWatchOnlyAsync();
|
|
Task<TradingBotResponse> 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<IExchangeService, ExchangeService>();
|
|
services.AddSingleton<IAccountService, AccountService>();
|
|
services.AddSingleton<ITradingService, TradingService>();
|
|
services.AddSingleton<IMessengerService, MessengerService>();
|
|
services.AddSingleton<IBackupBotService, BackupBotService>();
|
|
});
|
|
|
|
// 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<ITradingBot> CreateTradingBotAsync(TradingBotConfig config, bool useGrain = true)
|
|
{
|
|
if (config.IsForBacktest || !useGrain)
|
|
{
|
|
// For backtesting: Create regular class instance
|
|
return new TradingBot(
|
|
_serviceProvider.GetService<ILogger<TradingBot>>(),
|
|
_serviceProvider.GetService<IServiceScopeFactory>(),
|
|
config
|
|
);
|
|
}
|
|
else
|
|
{
|
|
// For live trading: Use Orleans grain
|
|
var grain = _clusterClient.GetGrain<ITradingBotGrain>(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<LightSignal> Signals { get; set; }
|
|
[Id(2)] public List<Position> Positions { get; set; }
|
|
[Id(3)] public Dictionary<DateTime, decimal> 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<TradingBotGrainState>, 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<TradingBotGrainState>`
|
|
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 |