Postgres (#30)

* Add postgres

* Migrate users

* Migrate geneticRequest

* Try to fix Concurrent call

* Fix asyncawait

* Fix async and concurrent

* Migrate backtests

* Add cache for user by address

* Fix backtest migration

* Fix not open connection

* Fix backtest command error

* Fix concurrent

* Fix all concurrency

* Migrate TradingRepo

* Fix scenarios

* Migrate statistic repo

* Save botbackup

* Add settings et moneymanagement

* Add bot postgres

* fix a bit more backups

* Fix bot model

* Fix loading backup

* Remove cache market for read positions

* Add workers to postgre

* Fix workers api

* Reduce get Accounts for workers

* Migrate synth to postgre

* Fix backtest saved

* Remove mongodb

* botservice decorrelation

* Fix tradingbot scope call

* fix tradingbot

* fix concurrent

* Fix scope for genetics

* Fix account over requesting

* Fix bundle backtest worker

* fix a lot of things

* fix tab backtest

* Remove optimized moneymanagement

* Add light signal to not use User and too much property

* Make money management lighter

* insert indicators to awaitable

* Migrate add strategies to await

* Refactor scenario and indicator retrieval to use asynchronous methods throughout the application

* add more async await

* Add services

* Fix and clean

* Fix bot a bit

* Fix bot and add message for cooldown

* Remove fees

* Add script to deploy db

* Update dfeeploy script

* fix script

* Add idempotent script and backup

* finish script migration

* Fix did user and agent name on start bot
This commit is contained in:
Oda
2025-07-27 15:42:17 +02:00
committed by GitHub
parent 361bfbf6e8
commit 422fecea7b
294 changed files with 23953 additions and 7272 deletions

View File

@@ -0,0 +1,521 @@
using Managing.Infrastructure.Databases.PostgreSql.Entities;
using Microsoft.EntityFrameworkCore;
namespace Managing.Infrastructure.Databases.PostgreSql;
public class ManagingDbContext : DbContext
{
public ManagingDbContext(DbContextOptions<ManagingDbContext> options) : base(options)
{
}
public DbSet<AccountEntity> Accounts { get; set; }
public DbSet<UserEntity> Users { get; set; }
public DbSet<GeneticRequestEntity> GeneticRequests { get; set; }
public DbSet<BacktestEntity> Backtests { get; set; }
public DbSet<BundleBacktestRequestEntity> BundleBacktestRequests { get; set; }
// Trading entities
public DbSet<ScenarioEntity> Scenarios { get; set; }
public DbSet<IndicatorEntity> Indicators { get; set; }
public DbSet<ScenarioIndicatorEntity> ScenarioIndicators { get; set; }
public DbSet<SignalEntity> Signals { get; set; }
public DbSet<PositionEntity> Positions { get; set; }
public DbSet<TradeEntity> Trades { get; set; }
// Statistics entities
public DbSet<TopVolumeTickerEntity> TopVolumeTickers { get; set; }
public DbSet<SpotlightOverviewEntity> SpotlightOverviews { get; set; }
public DbSet<TraderEntity> Traders { get; set; }
public DbSet<FundingRateEntity> FundingRates { get; set; }
// Bot entities
public DbSet<BotBackupEntity> BotBackups { get; set; }
// Settings entities
public DbSet<MoneyManagementEntity> MoneyManagements { get; set; }
// Worker entities
public DbSet<WorkerEntity> Workers { get; set; }
public DbSet<SynthMinersLeaderboardEntity> SynthMinersLeaderboards { get; set; }
public DbSet<SynthPredictionEntity> SynthPredictions { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Configure Account entity
modelBuilder.Entity<AccountEntity>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.Name).IsRequired().HasMaxLength(255);
entity.Property(e => e.Key).HasMaxLength(500);
entity.Property(e => e.Secret).HasMaxLength(500);
entity.Property(e => e.Exchange)
.IsRequired()
.HasConversion<string>(); // Store enum as string
entity.Property(e => e.Type)
.IsRequired()
.HasConversion<string>(); // Store enum as string
// Create unique index on account name
entity.HasIndex(e => e.Name).IsUnique();
entity.HasIndex(e => e.Key);
// Configure relationship with User
entity.HasOne(e => e.User)
.WithMany()
.HasForeignKey(e => e.UserId)
.OnDelete(DeleteBehavior.SetNull);
});
// Configure User entity
modelBuilder.Entity<UserEntity>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.Name).IsRequired().HasMaxLength(255);
entity.Property(e => e.AgentName).HasMaxLength(255);
entity.Property(e => e.AvatarUrl).HasMaxLength(500);
entity.Property(e => e.TelegramChannel).HasMaxLength(255);
});
// Configure GeneticRequest entity
modelBuilder.Entity<GeneticRequestEntity>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.RequestId).IsRequired().HasMaxLength(255);
entity.Property(e => e.Status).IsRequired().HasMaxLength(50);
entity.Property(e => e.Ticker)
.IsRequired()
.HasConversion<string>(); // Store enum as string
entity.Property(e => e.Timeframe)
.IsRequired()
.HasConversion<string>(); // Store enum as string
entity.Property(e => e.SelectionMethod)
.IsRequired()
.HasConversion<string>(); // Store enum as string
entity.Property(e => e.CrossoverMethod)
.IsRequired()
.HasConversion<string>(); // Store enum as string
entity.Property(e => e.MutationMethod)
.IsRequired()
.HasConversion<string>(); // Store enum as string
entity.Property(e => e.Balance).HasColumnType("decimal(18,8)");
entity.Property(e => e.BestIndividual).HasMaxLength(4000);
entity.Property(e => e.ErrorMessage).HasMaxLength(2000);
entity.Property(e => e.ProgressInfo).HasMaxLength(4000);
entity.Property(e => e.BestChromosome).HasMaxLength(4000);
entity.Property(e => e.EligibleIndicatorsJson).HasMaxLength(2000);
// Create indexes
entity.HasIndex(e => e.RequestId).IsUnique();
entity.HasIndex(e => e.Status);
entity.HasIndex(e => e.CreatedAt);
// Configure relationship with User
entity.HasOne(e => e.User)
.WithMany()
.HasForeignKey(e => e.UserId)
.OnDelete(DeleteBehavior.SetNull);
});
// Configure Backtest entity
modelBuilder.Entity<BacktestEntity>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.Identifier).IsRequired().HasMaxLength(255);
entity.Property(e => e.RequestId).IsRequired().HasMaxLength(255);
entity.Property(e => e.UserName).IsRequired().HasMaxLength(255);
entity.Property(e => e.FinalPnl).HasColumnType("decimal(18,8)");
entity.Property(e => e.GrowthPercentage).HasColumnType("decimal(18,8)");
entity.Property(e => e.HodlPercentage).HasColumnType("decimal(18,8)");
entity.Property(e => e.Fees).HasColumnType("decimal(18,8)");
entity.Property(e => e.ConfigJson).HasColumnType("jsonb");
entity.Property(e => e.PositionsJson).HasColumnType("jsonb");
entity.Property(e => e.SignalsJson).HasColumnType("jsonb");
entity.Property(e => e.MoneyManagementJson).HasColumnType("jsonb");
entity.Property(e => e.StatisticsJson).HasColumnType("jsonb");
entity.Property(e => e.ScoreMessage).HasMaxLength(1000);
entity.Property(e => e.Metadata).HasColumnType("text");
// Create indexes for common queries
entity.HasIndex(e => e.Identifier).IsUnique();
entity.HasIndex(e => e.RequestId);
entity.HasIndex(e => e.UserName);
entity.HasIndex(e => e.Score);
entity.HasIndex(e => e.FinalPnl);
entity.HasIndex(e => e.WinRate);
entity.HasIndex(e => e.StartDate);
entity.HasIndex(e => e.EndDate);
entity.HasIndex(e => e.CreatedAt);
// Composite indexes for efficient pagination and filtering
entity.HasIndex(e => new { e.UserName, e.Score });
entity.HasIndex(e => new { e.RequestId, e.Score });
});
// Configure BundleBacktestRequest entity
modelBuilder.Entity<BundleBacktestRequestEntity>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.RequestId).IsRequired().HasMaxLength(255);
entity.Property(e => e.UserName).IsRequired().HasMaxLength(255);
entity.Property(e => e.Name).IsRequired().HasMaxLength(255);
entity.Property(e => e.Status)
.IsRequired()
.HasConversion<string>(); // Store enum as string
entity.Property(e => e.BacktestRequestsJson).HasColumnType("text");
entity.Property(e => e.ErrorMessage).HasColumnType("text");
entity.Property(e => e.ProgressInfo).HasColumnType("text");
entity.Property(e => e.CurrentBacktest).HasMaxLength(500);
entity.Property(e => e.ResultsJson).HasColumnType("jsonb");
// Configure relationship with User
entity.HasOne(e => e.User)
.WithMany()
.HasForeignKey(e => e.UserId)
.OnDelete(DeleteBehavior.SetNull);
// Create indexes for common queries
entity.HasIndex(e => e.RequestId).IsUnique();
entity.HasIndex(e => e.UserName);
entity.HasIndex(e => e.Status);
entity.HasIndex(e => e.CreatedAt);
entity.HasIndex(e => e.CompletedAt);
entity.HasIndex(e => e.UserId);
// Composite index for user queries ordered by creation date
entity.HasIndex(e => new { e.UserName, e.CreatedAt });
});
// Configure Scenario entity
modelBuilder.Entity<ScenarioEntity>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.Name).IsRequired().HasMaxLength(255);
entity.Property(e => e.UserName).HasMaxLength(255);
// Create indexes
entity.HasIndex(e => e.Name);
entity.HasIndex(e => e.UserName);
entity.HasIndex(e => e.CreatedAt);
// Composite index for user scenarios
entity.HasIndex(e => new { e.UserName, e.Name });
});
// Configure Indicator entity
modelBuilder.Entity<IndicatorEntity>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.Name).IsRequired().HasMaxLength(255);
entity.Property(e => e.Type).IsRequired().HasConversion<string>();
entity.Property(e => e.Timeframe).IsRequired().HasConversion<string>();
entity.Property(e => e.SignalType).IsRequired().HasConversion<string>();
entity.Property(e => e.UserName).HasMaxLength(255);
// Create indexes
entity.HasIndex(e => e.Name);
entity.HasIndex(e => e.Type);
entity.HasIndex(e => e.UserName);
entity.HasIndex(e => e.CreatedAt);
// Composite index for user indicators
entity.HasIndex(e => new { e.UserName, e.Name });
});
// Configure ScenarioIndicator junction table
modelBuilder.Entity<ScenarioIndicatorEntity>(entity =>
{
entity.HasKey(e => e.Id);
// Configure relationships
entity.HasOne(e => e.Scenario)
.WithMany(s => s.ScenarioIndicators)
.HasForeignKey(e => e.ScenarioId)
.OnDelete(DeleteBehavior.Cascade);
entity.HasOne(e => e.Indicator)
.WithMany(i => i.ScenarioIndicators)
.HasForeignKey(e => e.IndicatorId)
.OnDelete(DeleteBehavior.Cascade);
// Create indexes
entity.HasIndex(e => e.ScenarioId);
entity.HasIndex(e => e.IndicatorId);
entity.HasIndex(e => new { e.ScenarioId, e.IndicatorId }).IsUnique();
});
// Configure Signal entity
modelBuilder.Entity<SignalEntity>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.Identifier).IsRequired().HasMaxLength(255);
entity.Property(e => e.Direction).IsRequired().HasConversion<string>();
entity.Property(e => e.Confidence).IsRequired().HasConversion<string>();
entity.Property(e => e.Ticker).IsRequired().HasConversion<string>();
entity.Property(e => e.Status).IsRequired().HasConversion<string>();
entity.Property(e => e.Timeframe).IsRequired().HasConversion<string>();
entity.Property(e => e.Type).IsRequired().HasConversion<string>();
entity.Property(e => e.SignalType).IsRequired().HasConversion<string>();
entity.Property(e => e.IndicatorName).IsRequired().HasMaxLength(255);
entity.Property(e => e.UserName).HasMaxLength(255);
entity.Property(e => e.CandleJson).HasColumnType("text");
// Create indexes
entity.HasIndex(e => e.Identifier);
entity.HasIndex(e => e.UserName);
entity.HasIndex(e => e.Date);
entity.HasIndex(e => e.Ticker);
entity.HasIndex(e => e.Status);
entity.HasIndex(e => e.CreatedAt);
// Composite indexes for common queries
entity.HasIndex(e => new { e.UserName, e.Date });
entity.HasIndex(e => new { e.Identifier, e.Date, e.UserName }).IsUnique();
});
// Configure Position entity
modelBuilder.Entity<PositionEntity>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.Identifier).IsRequired().HasMaxLength(255);
entity.Property(e => e.ProfitAndLoss).HasColumnType("decimal(18,8)");
entity.Property(e => e.OriginDirection).IsRequired().HasConversion<string>();
entity.Property(e => e.Status).IsRequired().HasConversion<string>();
entity.Property(e => e.Ticker).IsRequired().HasConversion<string>();
entity.Property(e => e.Initiator).IsRequired().HasConversion<string>();
entity.Property(e => e.SignalIdentifier).IsRequired().HasMaxLength(255);
entity.Property(e => e.AccountName).IsRequired().HasMaxLength(255);
entity.Property(e => e.UserName).HasMaxLength(255);
entity.Property(e => e.MoneyManagementJson).HasColumnType("text");
// Configure relationships with trades
entity.HasOne(e => e.OpenTrade)
.WithMany()
.HasForeignKey(e => e.OpenTradeId)
.OnDelete(DeleteBehavior.SetNull);
entity.HasOne(e => e.StopLossTrade)
.WithMany()
.HasForeignKey(e => e.StopLossTradeId)
.OnDelete(DeleteBehavior.SetNull);
entity.HasOne(e => e.TakeProfit1Trade)
.WithMany()
.HasForeignKey(e => e.TakeProfit1TradeId)
.OnDelete(DeleteBehavior.SetNull);
entity.HasOne(e => e.TakeProfit2Trade)
.WithMany()
.HasForeignKey(e => e.TakeProfit2TradeId)
.OnDelete(DeleteBehavior.SetNull);
// Create indexes
entity.HasIndex(e => e.Identifier).IsUnique();
entity.HasIndex(e => e.UserName);
entity.HasIndex(e => e.Status);
entity.HasIndex(e => e.Initiator);
entity.HasIndex(e => e.Date);
entity.HasIndex(e => e.CreatedAt);
// Composite indexes
entity.HasIndex(e => new { e.UserName, e.Identifier });
});
// Configure Trade entity
modelBuilder.Entity<TradeEntity>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.Direction).IsRequired().HasConversion<string>();
entity.Property(e => e.Status).IsRequired().HasConversion<string>();
entity.Property(e => e.TradeType).IsRequired().HasConversion<string>();
entity.Property(e => e.Ticker).IsRequired().HasConversion<string>();
entity.Property(e => e.Fee).HasColumnType("decimal(18,8)");
entity.Property(e => e.Quantity).HasColumnType("decimal(18,8)");
entity.Property(e => e.Price).HasColumnType("decimal(18,8)");
entity.Property(e => e.Leverage).HasColumnType("decimal(18,8)");
entity.Property(e => e.ExchangeOrderId).HasMaxLength(255);
entity.Property(e => e.Message).HasColumnType("text");
// Create indexes
entity.HasIndex(e => e.Date);
entity.HasIndex(e => e.Status);
entity.HasIndex(e => e.ExchangeOrderId);
entity.HasIndex(e => e.CreatedAt);
});
// Configure TopVolumeTicker entity
modelBuilder.Entity<TopVolumeTickerEntity>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.Volume).HasPrecision(18, 8);
// Create indexes
entity.HasIndex(e => e.Ticker);
entity.HasIndex(e => e.Date);
entity.HasIndex(e => e.Exchange);
entity.HasIndex(e => e.Rank);
// Composite indexes for efficient queries
entity.HasIndex(e => new { e.Exchange, e.Date });
entity.HasIndex(e => new { e.Date, e.Rank });
});
// Configure SpotlightOverview entity
modelBuilder.Entity<SpotlightOverviewEntity>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.Identifier).IsRequired();
entity.Property(e => e.SpotlightsJson).HasColumnType("jsonb");
// Create indexes
entity.HasIndex(e => e.Identifier).IsUnique();
entity.HasIndex(e => e.DateTime);
entity.HasIndex(e => e.ScenarioCount);
// Composite index for efficient queries
entity.HasIndex(e => new { e.DateTime, e.ScenarioCount });
});
// Configure Trader entity
modelBuilder.Entity<TraderEntity>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.Address).IsRequired().HasMaxLength(255);
entity.Property(e => e.Pnl).HasPrecision(18, 8);
entity.Property(e => e.AverageWin).HasPrecision(18, 8);
entity.Property(e => e.AverageLoss).HasPrecision(18, 8);
entity.Property(e => e.Roi).HasPrecision(18, 8);
// Create indexes
entity.HasIndex(e => e.Address);
entity.HasIndex(e => e.IsBestTrader);
entity.HasIndex(e => e.Winrate);
entity.HasIndex(e => e.Pnl);
entity.HasIndex(e => e.Roi);
// Composite indexes for efficient queries
entity.HasIndex(e => new { e.IsBestTrader, e.Winrate });
entity.HasIndex(e => new { e.IsBestTrader, e.Roi });
entity.HasIndex(e => new { e.Address, e.IsBestTrader }).IsUnique();
});
// Configure FundingRate entity
modelBuilder.Entity<FundingRateEntity>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.Rate).HasPrecision(18, 8);
entity.Property(e => e.OpenInterest).HasPrecision(18, 8);
// Create indexes
entity.HasIndex(e => e.Ticker);
entity.HasIndex(e => e.Exchange);
entity.HasIndex(e => e.Date);
entity.HasIndex(e => e.Direction);
// Composite indexes for efficient queries
entity.HasIndex(e => new { e.Ticker, e.Exchange });
entity.HasIndex(e => new { e.Exchange, e.Date });
entity.HasIndex(e => new { e.Ticker, e.Exchange, e.Date }).IsUnique();
});
// Configure BotBackup entity
modelBuilder.Entity<BotBackupEntity>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.Identifier).IsRequired().HasMaxLength(255);
entity.Property(e => e.UserName).HasMaxLength(255);
entity.Property(e => e.Data).IsRequired().HasColumnType("text");
// Create indexes
entity.HasIndex(e => e.Identifier).IsUnique();
entity.HasIndex(e => e.UserName);
entity.HasIndex(e => e.LastStatus);
entity.HasIndex(e => e.CreateDate);
// Composite index for user bots
entity.HasIndex(e => new { e.UserName, e.CreateDate });
// Configure relationship with User
entity.HasOne(e => e.User)
.WithMany()
.HasForeignKey(e => e.UserId)
.OnDelete(DeleteBehavior.SetNull);
});
// Configure MoneyManagement entity
modelBuilder.Entity<MoneyManagementEntity>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.Name).IsRequired().HasMaxLength(255);
entity.Property(e => e.Timeframe).IsRequired().HasConversion<string>();
entity.Property(e => e.StopLoss).HasColumnType("decimal(18,8)");
entity.Property(e => e.TakeProfit).HasColumnType("decimal(18,8)");
entity.Property(e => e.Leverage).HasColumnType("decimal(18,8)");
entity.Property(e => e.UserName).HasMaxLength(255);
// Create indexes
entity.HasIndex(e => e.Name);
entity.HasIndex(e => e.UserName);
// Composite index for user money managements
entity.HasIndex(e => new { e.UserName, e.Name });
// Configure relationship with User
entity.HasOne(e => e.User)
.WithMany()
.HasForeignKey(e => e.UserId)
.OnDelete(DeleteBehavior.SetNull);
});
// Configure Worker entity
modelBuilder.Entity<WorkerEntity>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.WorkerType).IsRequired().HasConversion<string>();
entity.Property(e => e.StartTime).IsRequired();
entity.Property(e => e.LastRunTime);
entity.Property(e => e.ExecutionCount).IsRequired();
entity.Property(e => e.DelayTicks).IsRequired();
entity.Property(e => e.IsActive).IsRequired();
entity.HasIndex(e => e.WorkerType).IsUnique();
});
// Configure SynthMinersLeaderboard entity
modelBuilder.Entity<SynthMinersLeaderboardEntity>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.Asset).IsRequired().HasMaxLength(32);
entity.Property(e => e.TimeIncrement).IsRequired();
entity.Property(e => e.SignalDate);
entity.Property(e => e.IsBacktest).IsRequired();
entity.Property(e => e.MinersData).HasColumnType("jsonb");
entity.Property(e => e.CacheKey).IsRequired().HasMaxLength(255);
entity.Property(e => e.CreatedAt).IsRequired();
entity.HasIndex(e => e.CacheKey).IsUnique();
entity.HasIndex(e => e.CreatedAt);
});
// Configure SynthPrediction entity
modelBuilder.Entity<SynthPredictionEntity>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.Asset).IsRequired().HasMaxLength(32);
entity.Property(e => e.MinerUid).IsRequired();
entity.Property(e => e.TimeIncrement).IsRequired();
entity.Property(e => e.TimeLength).IsRequired();
entity.Property(e => e.SignalDate);
entity.Property(e => e.IsBacktest).IsRequired();
entity.Property(e => e.PredictionData).HasColumnType("jsonb");
entity.Property(e => e.CacheKey).IsRequired().HasMaxLength(255);
entity.Property(e => e.CreatedAt).IsRequired();
entity.HasIndex(e => e.CacheKey).IsUnique();
entity.HasIndex(e => e.CreatedAt);
});
}
}