130 lines
5.3 KiB
C#
130 lines
5.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text.Json;
|
|
using FinlyticCore.Database;
|
|
using FinlyticCore.Dtos.TechnicalAnalysis;
|
|
using FinlyticCore.Entities.Settings;
|
|
using FinlyticTechnicals.Entities;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.EntityFrameworkCore.Design;
|
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
|
|
namespace FinlyticTechnicals.Database;
|
|
|
|
public class TechnicalAnalysisDbContext : DbContext, ISettingsDbContext
|
|
{
|
|
private static readonly JsonSerializerOptions JsonOptions = new()
|
|
{
|
|
PropertyNameCaseInsensitive = true,
|
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
|
WriteIndented = false
|
|
};
|
|
|
|
public TechnicalAnalysisDbContext(DbContextOptions<TechnicalAnalysisDbContext> options) : base(options)
|
|
{
|
|
}
|
|
|
|
public DbSet<SettingEntity> DynamicSettings => Set<SettingEntity>();
|
|
public DbSet<FtaCandleEntity> FtaCandles => Set<FtaCandleEntity>();
|
|
public DbSet<FtaTechnicalSetupEntity> FtaTechnicalSetups => Set<FtaTechnicalSetupEntity>();
|
|
public DbSet<FtaDetectedPatternEntity> FtaDetectedPatterns => Set<FtaDetectedPatternEntity>();
|
|
public DbSet<FtaMonitoredUniverseAssetEntity> MonitoredUniverseAssets => Set<FtaMonitoredUniverseAssetEntity>();
|
|
|
|
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();
|
|
});
|
|
|
|
// 2. FTA Candles Table & Composite Time-Series Index
|
|
modelBuilder.Entity<FtaCandleEntity>(entity =>
|
|
{
|
|
entity.HasKey(e => e.Id);
|
|
entity.HasIndex(e => new { e.Isin, e.Timeframe, e.TimestampUtc });
|
|
entity.HasIndex(e => e.TimestampUtc);
|
|
});
|
|
|
|
// 3. JSONB Value Converters for Complex Types
|
|
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)
|
|
);
|
|
|
|
var patternsConverter = new ValueConverter<List<PatternResultDto>, string>(
|
|
v => JsonSerializer.Serialize(v, JsonOptions),
|
|
v => JsonSerializer.Deserialize<List<PatternResultDto>>(v, JsonOptions) ?? new List<PatternResultDto>()
|
|
);
|
|
|
|
var indicatorSnapshotConverter = new ValueConverter<Dictionary<string, decimal>, string>(
|
|
v => JsonSerializer.Serialize(v, JsonOptions),
|
|
v => JsonSerializer.Deserialize<Dictionary<string, decimal>>(v, JsonOptions) ?? new Dictionary<string, decimal>()
|
|
);
|
|
|
|
var extraDataConverter = new ValueConverter<Dictionary<string, object>?, string>(
|
|
v => v == null ? "{}" : JsonSerializer.Serialize(v, JsonOptions),
|
|
v => string.IsNullOrWhiteSpace(v) ? null : JsonSerializer.Deserialize<Dictionary<string, object>>(v, JsonOptions)
|
|
);
|
|
|
|
// 4. FTA Technical Setups Table & JSONB mappings
|
|
modelBuilder.Entity<FtaTechnicalSetupEntity>(entity =>
|
|
{
|
|
entity.HasKey(e => e.SetupId);
|
|
entity.HasIndex(e => new { e.Isin, e.IsActive, e.ExpiresAtUtc });
|
|
entity.HasIndex(e => e.CreatedAtUtc);
|
|
entity.HasIndex(e => e.QualityScore);
|
|
entity.HasIndex(e => e.IsTopPick);
|
|
entity.HasIndex(e => new { e.IsActive, e.IsTopPick, e.QualityScore });
|
|
|
|
|
|
entity.Property(e => e.ExitPlan)
|
|
.HasColumnType("jsonb")
|
|
.HasConversion(exitPlanConverter);
|
|
|
|
entity.Property(e => e.TriggeringPatterns)
|
|
.HasColumnType("jsonb")
|
|
.HasConversion(patternsConverter);
|
|
|
|
entity.Property(e => e.IndicatorSnapshot)
|
|
.HasColumnType("jsonb")
|
|
.HasConversion(indicatorSnapshotConverter);
|
|
});
|
|
|
|
// 5. FTA Detected Patterns Table & JSONB mappings
|
|
modelBuilder.Entity<FtaDetectedPatternEntity>(entity =>
|
|
{
|
|
entity.HasKey(e => e.Id);
|
|
entity.HasIndex(e => new { e.Isin, e.DetectedAtUtc });
|
|
entity.HasIndex(e => e.PatternType);
|
|
entity.HasIndex(e => e.QualityScore);
|
|
|
|
entity.Property(e => e.ExtraData)
|
|
.HasColumnType("jsonb")
|
|
.HasConversion(extraDataConverter);
|
|
});
|
|
|
|
// 6. Monitored Universe Assets Table (persisted backing store for TechnicalUniverseManager, cleared on
|
|
// every service startup - see FtaMonitoredUniverseAssetEntity's doc comment)
|
|
modelBuilder.Entity<FtaMonitoredUniverseAssetEntity>(entity =>
|
|
{
|
|
entity.HasKey(e => e.Isin);
|
|
entity.HasIndex(e => e.Source);
|
|
entity.HasIndex(e => e.ExpiresAtUtc);
|
|
});
|
|
}
|
|
}
|
|
|
|
public class TechnicalAnalysisDbContextFactory : IDesignTimeDbContextFactory<TechnicalAnalysisDbContext>
|
|
{
|
|
public TechnicalAnalysisDbContext CreateDbContext(string[] args)
|
|
{
|
|
var optionsBuilder = new DbContextOptionsBuilder<TechnicalAnalysisDbContext>();
|
|
optionsBuilder.UseNpgsql("Host=localhost;Database=finlytic_ta;Username=postgres;Password=postgres");
|
|
return new TechnicalAnalysisDbContext(optionsBuilder.Options);
|
|
}
|
|
}
|