## Summary I've successfully implemented all the requested features to add BacktestId support to the strategies/bot system: ### 1. **Added BacktestId Column to BotEntity** ✅ - **File**: `src/Managing.Infrastructure.Database/PostgreSql/Entities/BotEntity.cs:47` - Added nullable `int? BacktestId` property with documentation - This allows bots to reference the backtest they were created from ### 2. **Updated Bot Domain Model** ✅ - **File**: `src/Managing.Domain/Bots/Bot.cs:37` - Added `BacktestId` property to the domain model - Maintains consistency between entity and domain layers ### 3. **Updated TradingBotConfig and TradingBotConfigRequest** ✅ - **File**: `src/Managing.Domain/Bots/TradingBotConfig.cs:131` - Added `[Id(24)] public int? BacktestId` with Orleans serialization attribute - **File**: `src/Managing.Domain/Bots/TradingBotConfigRequest.cs:119` - Added `BacktestId` property to the request model - These changes ensure BacktestId flows through the entire bot creation pipeline ### 4. **Updated Data Mappers** ✅ - **File**: `src/Managing.Infrastructure.Database/PostgreSql/PostgreSqlMappers.cs` - Updated `Map(Bot bot)` at line 833 to include BacktestId - Updated `Map(BotEntity entity)` at line 799 to include BacktestId - Ensures proper mapping between entity and domain models ### 5. **Updated LiveTradingBotGrain** ✅ - **File**: `src/Managing.Application/Bots/Grains/LiveTradingBotGrain.cs` - Added BacktestId to bot creation at line 1078 (for saved bots) - Added BacktestId to bot creation at line 1145 (for running bots) - The grain now properly persists BacktestId when saving bot statistics ### 6. **Created New Endpoint for Backtest Stats** ✅ - **File**: `src/Managing.Api/Controllers/BacktestController.cs:114` - **New Endpoint**: `GET /Backtest/{id}/stats` - Returns only statistical information without positions, signals, or candles: - Basic info: id, name, ticker, timeframe, tradingType, startDate, endDate - Performance: initialBalance, finalPnl, netPnl, growthPercentage, hodlPercentage, winRate - Risk metrics: sharpeRatio, maxDrawdown, maxDrawdownRecoveryTime - Other: fees, score, scoreMessage, positionCount ### 7. **Created Database Migration** ✅ - **Generated Migration**: `AddBacktestIdToBots` - The migration adds a nullable integer column `BacktestId` to the `Bots` table - Ready to be applied with `dotnet ef database update` ### 8. **Regenerated Frontend API Client** ✅ - Ran `dotnet build` in `src/Managing.Nswag` - The `ManagingApi.ts` file has been regenerated with: - `backtestId` field in bot-related DTOs - New `/Backtest/{id}/stats` endpoint ## How It Works ### Starting a Bot from a Backtest: 1. Frontend sends `StartBotRequest` with `TradingBotConfigRequest` containing `backtestId` 2. `BotController` validates and prepares the request 3. `StartBotCommandHandler` creates the bot configuration with BacktestId 4. `LiveTradingBotGrain.CreateAsync()` receives the config and saves it to state 5. When the bot is saved via `SaveBotAsync()`, BacktestId is persisted to the database 6. The Bot entity now has a reference to its originating backtest ### Retrieving Backtest Stats: 1. Frontend calls `GET /Backtest/{id}/stats` with the backtest ID 2. Backend retrieves the full backtest from the database 3. Returns only the statistical summary (without heavy data like positions/signals/candles) 4. Frontend can display backtest performance metrics when viewing a bot ## Database Schema ```sql ALTER TABLE "Bots" ADD COLUMN "BacktestId" integer NULL; ``` All changes follow the project's architecture patterns (Controller → Application → Repository) and maintain backward compatibility through nullable BacktestId fields.
120 lines
3.5 KiB
C#
120 lines
3.5 KiB
C#
using System.ComponentModel.DataAnnotations;
|
|
using Managing.Domain.Backtests;
|
|
using static Managing.Common.Enums;
|
|
|
|
namespace Managing.Domain.Bots;
|
|
|
|
/// <summary>
|
|
/// Simplified trading bot configuration request with only primary properties
|
|
/// </summary>
|
|
public class TradingBotConfigRequest
|
|
{
|
|
/// <summary>
|
|
/// The account name to use for trading
|
|
/// </summary>
|
|
public string AccountName { get; set; }
|
|
|
|
/// <summary>
|
|
/// The ticker/symbol to trade
|
|
/// </summary>
|
|
[Required]
|
|
public Ticker Ticker { get; set; }
|
|
|
|
/// <summary>
|
|
/// The timeframe for trading decisions
|
|
/// </summary>
|
|
[Required]
|
|
public Timeframe Timeframe { get; set; }
|
|
|
|
/// <summary>
|
|
/// Whether this bot is for watching only (no actual trading)
|
|
/// </summary>
|
|
[Required]
|
|
public bool IsForWatchingOnly { get; set; }
|
|
|
|
/// <summary>
|
|
/// The initial trading balance for the bot
|
|
/// </summary>
|
|
[Required]
|
|
public decimal BotTradingBalance { get; set; }
|
|
|
|
/// <summary>
|
|
/// The name/identifier for this bot
|
|
/// </summary>
|
|
[Required]
|
|
public string Name { get; set; }
|
|
|
|
[Required] public bool FlipPosition { get; set; }
|
|
|
|
/// <summary>
|
|
/// Cooldown period between trades (in candles)
|
|
/// </summary>
|
|
public int? CooldownPeriod { get; set; }
|
|
|
|
/// <summary>
|
|
/// Maximum consecutive losses before stopping the bot
|
|
/// </summary>
|
|
public int MaxLossStreak { get; set; }
|
|
|
|
/// <summary>
|
|
/// The scenario configuration (takes precedence over ScenarioName)
|
|
/// </summary>
|
|
public ScenarioRequest? Scenario { get; set; }
|
|
|
|
/// <summary>
|
|
/// The scenario name to load from database (only used when Scenario is not provided)
|
|
/// </summary>
|
|
public string? ScenarioName { get; set; }
|
|
|
|
/// <summary>
|
|
/// The money management name to load from database (only used when MoneyManagement is not provided)
|
|
/// </summary>
|
|
public string? MoneyManagementName { get; set; }
|
|
|
|
/// <summary>
|
|
/// The money management object to use for the bot
|
|
/// </summary>
|
|
public MoneyManagementRequest? MoneyManagement { get; set; }
|
|
|
|
/// <summary>
|
|
/// Maximum time in hours that a position can remain open before being automatically closed
|
|
/// </summary>
|
|
public decimal? MaxPositionTimeHours { get; set; }
|
|
|
|
/// <summary>
|
|
/// Whether to close positions early when they become profitable
|
|
/// </summary>
|
|
public bool CloseEarlyWhenProfitable { get; set; } = false;
|
|
|
|
/// <summary>
|
|
/// Whether to only flip positions when the current position is in profit
|
|
/// </summary>
|
|
public bool FlipOnlyWhenInProfit { get; set; } = true;
|
|
|
|
/// <summary>
|
|
/// Whether to use Synth API for predictions and risk assessment
|
|
/// </summary>
|
|
public bool UseSynthApi { get; set; } = false;
|
|
|
|
/// <summary>
|
|
/// Whether to use Synth predictions for position sizing adjustments
|
|
/// </summary>
|
|
public bool UseForPositionSizing { get; set; } = true;
|
|
|
|
/// <summary>
|
|
/// Whether to use Synth predictions for signal filtering
|
|
/// </summary>
|
|
public bool UseForSignalFiltering { get; set; } = true;
|
|
|
|
/// <summary>
|
|
/// Whether to use Synth predictions for dynamic stop-loss/take-profit adjustments
|
|
/// </summary>
|
|
public bool UseForDynamicStopLoss { get; set; } = true;
|
|
|
|
public TradingType TradingType { get; set; }
|
|
|
|
/// <summary>
|
|
/// The backtest ID associated with this bot configuration (nullable for bots not created from backtests)
|
|
/// </summary>
|
|
public int? BacktestId { get; set; }
|
|
} |