refactor(bot): update paper trading models, broker integration, background services, and test project

This commit is contained in:
2026-08-24 21:37:10 +02:00
parent 5c95dd182c
commit 7060f0f7b1
32 changed files with 1904 additions and 1477 deletions
+49 -16
View File
@@ -1,45 +1,78 @@
using System;
using FinlyticBot.Entities;
using System.Collections.Generic;
using System.Text.Json;
using FinlyticCore.Database;
using FinlyticCore.Dtos.TechnicalAnalysis;
using FinlyticCore.Entities.Settings;
using FinlyticBot.Database.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace FinlyticBot.Database;
public class BotDbContext : DbContext, ISettingsDbContext
{
public BotDbContext(DbContextOptions<BotDbContext> options) : base(options) { }
private static readonly JsonSerializerOptions JsonOptions = new()
{
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = false
};
public BotDbContext(DbContextOptions<BotDbContext> options) : base(options)
{
}
public DbSet<SettingEntity> DynamicSettings => Set<SettingEntity>();
public DbSet<ExecutedPaperTradeEntity> ExecutedPaperTrades => Set<ExecutedPaperTradeEntity>();
public DbSet<BotAuditLogEntity> BotAuditLogs => Set<BotAuditLogEntity>();
public DbSet<BotPositionEntity> Positions => Set<BotPositionEntity>();
public DbSet<BotPortfolioSnapshotEntity> PortfolioSnapshots => Set<BotPortfolioSnapshotEntity>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// 1. Settings Table
modelBuilder.Entity<SettingEntity>(entity =>
{
entity.HasKey(e => e.Id);
entity.HasIndex(e => e.Key).IsUnique();
});
modelBuilder.Entity<ExecutedPaperTradeEntity>(entity =>
// 2. ExitPlan JSONB Converter
var exitPlanConverter = new ValueConverter<ExitPlan, string>(
v => JsonSerializer.Serialize(v, JsonOptions),
v => JsonSerializer.Deserialize<ExitPlan>(v, JsonOptions) ?? new ExitPlan(ExitStrategyType.FixedSingleTarget, 0m, new List<TakeProfitStage>(), null, null, null, null)
);
// 3. Bot Positions Table
modelBuilder.Entity<BotPositionEntity>(entity =>
{
entity.HasIndex(e => e.TradeId).IsUnique();
entity.HasIndex(e => e.Symbol);
entity.HasIndex(e => e.Isin);
entity.HasIndex(e => e.AlpacaOrderId);
entity.HasIndex(e => e.Status);
entity.HasIndex(e => e.PlacedAt);
entity.HasKey(e => e.Id);
entity.HasIndex(e => new { e.Status, e.Venue });
entity.HasIndex(e => e.OpenedAtUtc);
entity.HasIndex(e => e.ProposalId);
entity.Property(e => e.ExitPlan)
.HasColumnType("jsonb")
.HasConversion(exitPlanConverter);
});
modelBuilder.Entity<BotAuditLogEntity>(entity =>
// 4. Portfolio Snapshots Table
modelBuilder.Entity<BotPortfolioSnapshotEntity>(entity =>
{
entity.HasIndex(e => e.TradeId);
entity.HasIndex(e => e.Symbol);
entity.HasIndex(e => e.Action);
entity.HasIndex(e => e.Timestamp);
entity.HasKey(e => e.Id);
entity.HasIndex(e => e.SnapshotDateUtc);
});
}
}
public class BotDbContextFactory : IDesignTimeDbContextFactory<BotDbContext>
{
public BotDbContext CreateDbContext(string[] args)
{
var optionsBuilder = new DbContextOptionsBuilder<BotDbContext>();
optionsBuilder.UseNpgsql("Host=localhost;Database=finlytic_bot;Username=postgres;Password=postgres");
return new BotDbContext(optionsBuilder.Options);
}
}