Trading bot grain (#33)

* Trading bot Grain

* Fix a bit more of the trading bot

* Advance on the tradingbot grain

* Fix build

* Fix db script

* Fix user login

* Fix a bit backtest

* Fix cooldown and backtest

* start fixing bot start

* Fix startup

* Setup local db

* Fix build and update candles and scenario

* Add bot registry

* Add reminder

* Updateing the grains

* fix bootstraping

* Save stats on tick

* Save bot data every tick

* Fix serialization

* fix save bot stats

* Fix get candles

* use dict instead of list for position

* Switch hashset to dict

* Fix a bit

* Fix bot launch and bot view

* add migrations

* Remove the tolist

* Add agent grain

* Save agent summary

* clean

* Add save bot

* Update get bots

* Add get bots

* Fix stop/restart

* fix Update config

* Update scanner table on new backtest saved

* Fix backtestRowDetails.tsx

* Fix agentIndex

* Update agentIndex

* Fix more things

* Update user cache

* Fix

* Fix account load/start/restart/run
This commit is contained in:
Oda
2025-08-04 23:07:06 +02:00
committed by GitHub
parent cd378587aa
commit 082ae8714b
215 changed files with 9562 additions and 14028 deletions

View File

@@ -0,0 +1,55 @@
using Orleans;
using static Managing.Common.Enums;
namespace Managing.Application.Abstractions.Grains;
/// <summary>
/// A small serializable class to store bot metadata.
/// This is a very lean object, perfect for fast storage and retrieval.
/// </summary>
[GenerateSerializer]
public class BotRegistryEntry
{
/// <summary>
/// The unique identifier of the bot
/// </summary>
[Id(0)]
public Guid Identifier { get; set; }
/// <summary>
/// The unique identifier of the user who owns the bot
/// </summary>
[Id(1)]
public int UserId { get; set; }
/// <summary>
/// The current operational status of the bot
/// </summary>
[Id(2)]
public BotStatus Status { get; set; }
/// <summary>
/// When the bot was registered in the registry
/// </summary>
[Id(3)]
public DateTime RegisteredAt { get; set; } = DateTime.UtcNow;
/// <summary>
/// When the bot status was last updated
/// </summary>
[Id(4)]
public DateTime LastStatusUpdate { get; set; } = DateTime.UtcNow;
public BotRegistryEntry()
{
}
public BotRegistryEntry(Guid identifier, int userId, BotStatus status = BotStatus.None)
{
Identifier = identifier;
UserId = userId;
Status = status;
RegisteredAt = DateTime.UtcNow;
LastStatusUpdate = DateTime.UtcNow;
}
}

View File

@@ -0,0 +1,36 @@
using Orleans;
namespace Managing.Application.Abstractions.Grains;
/// <summary>
/// Orleans grain state for BotRegistry.
/// This class represents the persistent state of the bot registry grain.
/// All properties must be serializable for Orleans state management.
/// </summary>
[GenerateSerializer]
public class BotRegistryState
{
/// <summary>
/// Dictionary containing all registered bots. The key is the identifier.
/// </summary>
[Id(0)]
public Dictionary<Guid, BotRegistryEntry> Bots { get; set; } = new();
/// <summary>
/// When the registry was last updated
/// </summary>
[Id(1)]
public DateTime LastUpdated { get; set; } = DateTime.UtcNow;
/// <summary>
/// Total number of bots currently registered
/// </summary>
[Id(2)]
public int TotalBotsCount { get; set; }
/// <summary>
/// Number of active bots (status = Up)
/// </summary>
[Id(3)]
public int ActiveBotsCount { get; set; }
}

View File

@@ -23,23 +23,5 @@ public interface IBacktestTradingBotGrain : IGrainWithGuidKey
/// <param name="requestId">The request ID to associate with this backtest</param>
/// <param name="metadata">Additional metadata to associate with this backtest</param>
/// <returns>The complete backtest result</returns>
Task<LightBacktest> RunBacktestAsync(TradingBotConfig config, List<Candle> candles, User user = null, bool save = false, bool withCandles = false, string requestId = null, object metadata = null);
/// <summary>
/// Gets the current backtest progress
/// </summary>
/// <returns>Backtest progress information</returns>
Task<BacktestProgress> GetBacktestProgressAsync();
Task<LightBacktest> RunBacktestAsync(TradingBotConfig config, HashSet<Candle> candles, User user = null, bool save = false, bool withCandles = false, string requestId = null, object metadata = null);
}
/// <summary>
/// Represents the progress of a backtest
/// </summary>
public class BacktestProgress
{
public bool IsInitialized { get; set; }
public int TotalCandles { get; set; }
public int ProcessedCandles { get; set; }
public double ProgressPercentage { get; set; }
public bool IsComplete { get; set; }
}

View File

@@ -0,0 +1,51 @@
using Orleans;
using static Managing.Common.Enums;
namespace Managing.Application.Abstractions.Grains;
/// <summary>
/// Orleans grain interface for LiveBotRegistry operations.
/// This interface defines the distributed, async operations available for the bot registry.
/// The registry acts as a central, durable directory for all LiveTradingBot grains.
/// </summary>
public interface ILiveBotRegistryGrain : IGrainWithIntegerKey
{
/// <summary>
/// Registers a new bot with its user ID. This should be called by the LiveTradingBotGrain when it is first initialized.
/// The initial status will be BotStatus.Up.
/// </summary>
/// <param name="identifier">The unique identifier of the bot</param>
/// <param name="userId">The unique identifier of the user who owns the bot</param>
/// <returns>A task that represents the asynchronous operation</returns>
Task RegisterBot(Guid identifier, int userId);
/// <summary>
/// Removes a bot from the registry. This should be a full removal, perhaps called when a user permanently deletes a bot.
/// </summary>
/// <param name="identifier">The unique identifier of the bot to unregister</param>
/// <returns>A task that represents the asynchronous operation</returns>
Task UnregisterBot(Guid identifier);
/// <summary>
/// Returns a list of all bots in the registry. This is for a management dashboard to see all bots in the system.
/// </summary>
/// <returns>A list of all BotRegistryEntry objects in the registry</returns>
Task<List<BotRegistryEntry>> GetAllBots();
/// <summary>
/// Returns a list of all bots associated with a specific user. This is the primary method for a user's watchlist.
/// </summary>
/// <param name="userId">The unique identifier of the user</param>
/// <returns>A list of BotRegistryEntry objects for the specified user</returns>
Task<List<BotRegistryEntry>> GetBotsForUser(int userId);
/// <summary>
/// A dedicated method for updating only the bot's Status field (Up/Down).
/// This will be called by LiveTradingBot's StartAsync and StopAsync methods.
/// </summary>
/// <param name="identifier">The unique identifier of the bot</param>
/// <param name="status">The new status to set for the bot</param>
/// <returns>A task that represents the asynchronous operation</returns>
Task UpdateBotStatus(Guid identifier, BotStatus status);
Task<BotStatus> GetBotStatus(Guid identifier);
}

View File

@@ -0,0 +1,43 @@
using Managing.Application.Abstractions.Models;
using Managing.Domain.Accounts;
using Managing.Domain.Bots;
using Managing.Domain.Trades;
using Managing.Domain.Users;
using Orleans;
using static Managing.Common.Enums;
namespace Managing.Application.Abstractions.Grains;
/// <summary>
/// Orleans grain interface for TradingBot operations.
/// This interface defines the distributed, async operations available for trading bots.
/// </summary>
public interface ILiveTradingBotGrain : IGrainWithGuidKey
{
/// <summary>
/// Manually opens a position in the specified direction
/// </summary>
/// <param name="direction">The direction of the trade (Long/Short)</param>
/// <returns>The created Position object</returns>
Task<Position> OpenPositionManuallyAsync(TradeDirection direction);
/// <summary>
/// Gets comprehensive bot data including positions, signals, and performance metrics
/// </summary>
Task<TradingBotResponse> GetBotDataAsync();
Task CreateAsync(TradingBotConfig config, User user);
Task StartAsync();
Task StopAsync();
Task<bool> UpdateConfiguration(TradingBotConfig newConfig);
Task<Account> GetAccount();
Task<TradingBotConfig> GetConfiguration();
Task<Position> ClosePositionAsync(Guid positionId);
Task RestartAsync();
/// <summary>
/// Deletes the bot and cleans up all associated resources
/// </summary>
Task DeleteAsync();
}

View File

@@ -1,94 +0,0 @@
using Managing.Application.Abstractions.Models;
using Managing.Domain.Bots;
using Managing.Domain.Trades;
using Orleans;
using static Managing.Common.Enums;
namespace Managing.Application.Abstractions.Grains;
/// <summary>
/// Orleans grain interface for TradingBot operations.
/// This interface defines the distributed, async operations available for trading bots.
/// </summary>
public interface ITradingBotGrain : IGrainWithGuidKey
{
/// <summary>
/// Starts the trading bot asynchronously
/// </summary>
Task StartAsync();
/// <summary>
/// Stops the trading bot asynchronously
/// </summary>
Task StopAsync();
/// <summary>
/// Gets the current status of the trading bot
/// </summary>
Task<BotStatus> GetStatusAsync();
/// <summary>
/// Gets the current configuration of the trading bot
/// </summary>
Task<TradingBotConfig> GetConfigurationAsync();
/// <summary>
/// Updates the trading bot configuration
/// </summary>
/// <param name="newConfig">The new configuration to apply</param>
/// <returns>True if the configuration was successfully updated</returns>
Task<bool> UpdateConfigurationAsync(TradingBotConfig newConfig);
/// <summary>
/// Manually opens a position in the specified direction
/// </summary>
/// <param name="direction">The direction of the trade (Long/Short)</param>
/// <returns>The created Position object</returns>
Task<Position> OpenPositionManuallyAsync(TradeDirection direction);
/// <summary>
/// Toggles the bot between watch-only and trading mode
/// </summary>
Task ToggleIsForWatchOnlyAsync();
/// <summary>
/// Gets comprehensive bot data including positions, signals, and performance metrics
/// </summary>
Task<TradingBotResponse> GetBotDataAsync();
/// <summary>
/// Loads a bot backup into the grain state
/// </summary>
/// <param name="backup">The bot backup to load</param>
Task LoadBackupAsync(BotBackup backup);
/// <summary>
/// Forces a backup save of the current bot state
/// </summary>
Task SaveBackupAsync();
/// <summary>
/// Gets the current profit and loss for the bot
/// </summary>
Task<decimal> GetProfitAndLossAsync();
/// <summary>
/// Gets the current win rate percentage for the bot
/// </summary>
Task<int> GetWinRateAsync();
/// <summary>
/// Gets the bot's execution count (number of Run cycles completed)
/// </summary>
Task<long> GetExecutionCountAsync();
/// <summary>
/// Gets the bot's startup time
/// </summary>
Task<DateTime> GetStartupTimeAsync();
/// <summary>
/// Gets the bot's creation date
/// </summary>
Task<DateTime> GetCreateDateAsync();
}