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,20 @@
using static Managing.Common.Enums;
namespace Managing.Infrastructure.Databases.PostgreSql.Entities;
public class AccountEntity
{
public int Id { get; set; }
public string Name { get; set; }
public TradingExchanges Exchange { get; set; }
public AccountType Type { get; set; }
public string? Key { get; set; }
public string? Secret { get; set; }
public int? UserId { get; set; }
// Navigation properties
public UserEntity? User { get; set; }
// Store balances as JSON if needed, or skip them entirely
// public string? BalancesJson { get; set; }
}

View File

@@ -0,0 +1,83 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Managing.Infrastructure.Databases.PostgreSql.Entities;
[Table("Backtests")]
public class BacktestEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
[MaxLength(255)]
public string Identifier { get; set; } = string.Empty;
[Required]
[MaxLength(255)]
public string RequestId { get; set; } = string.Empty;
[Required]
[Column(TypeName = "decimal(18,8)")]
public decimal FinalPnl { get; set; }
[Required]
public int WinRate { get; set; }
[Required]
[Column(TypeName = "decimal(18,8)")]
public decimal GrowthPercentage { get; set; }
[Required]
[Column(TypeName = "decimal(18,8)")]
public decimal HodlPercentage { get; set; }
[Required]
[Column(TypeName = "jsonb")]
public string ConfigJson { get; set; } = string.Empty;
[Required]
[Column(TypeName = "jsonb")]
public string PositionsJson { get; set; } = string.Empty;
[Required]
[Column(TypeName = "jsonb")]
public string SignalsJson { get; set; } = string.Empty;
[Required]
public DateTime StartDate { get; set; }
[Required]
public DateTime EndDate { get; set; }
[Required]
[Column(TypeName = "jsonb")]
public string MoneyManagementJson { get; set; } = string.Empty;
[Required]
[MaxLength(255)]
public string UserName { get; set; } = string.Empty;
[Column(TypeName = "jsonb")]
public string? StatisticsJson { get; set; }
[Required]
[Column(TypeName = "decimal(18,8)")]
public decimal Fees { get; set; }
[Required]
public double Score { get; set; }
[Column(TypeName = "text")]
public string ScoreMessage { get; set; } = string.Empty;
[Column(TypeName = "text")]
public string? Metadata { get; set; }
[Required]
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
[Required]
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}

View File

@@ -0,0 +1,36 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using static Managing.Common.Enums;
namespace Managing.Infrastructure.Databases.PostgreSql.Entities;
[Table("BotBackups")]
public class BotBackupEntity
{
[Key]
public int Id { get; set; }
[Required]
[MaxLength(255)]
public string Identifier { get; set; }
[MaxLength(255)]
public string? UserName { get; set; }
public int? UserId { get; set; }
// Navigation properties
[ForeignKey("UserId")]
public UserEntity? User { get; set; }
/// <summary>
/// Bot configuration and state data stored as JSON string
/// </summary>
[Column(TypeName = "text")]
public string Data { get; set; }
public BotStatus LastStatus { get; set; }
public DateTime CreateDate { get; set; } = DateTime.UtcNow;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}

View File

@@ -0,0 +1,70 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Managing.Domain.Backtests;
namespace Managing.Infrastructure.Databases.PostgreSql.Entities;
[Table("BundleBacktestRequests")]
public class BundleBacktestRequestEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
[MaxLength(255)]
public string RequestId { get; set; } = string.Empty;
[Required]
[MaxLength(255)]
public string UserName { get; set; } = string.Empty;
// Foreign key to User entity
public int? UserId { get; set; }
// Navigation property to User entity
public UserEntity? User { get; set; }
[Required]
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime? CompletedAt { get; set; }
[Required]
public BundleBacktestRequestStatus Status { get; set; }
[Required]
[Column(TypeName = "text")]
public string BacktestRequestsJson { get; set; } = string.Empty;
[Required]
public int TotalBacktests { get; set; }
[Required]
public int CompletedBacktests { get; set; }
[Required]
public int FailedBacktests { get; set; }
[Column(TypeName = "text")]
public string? ErrorMessage { get; set; }
[Column(TypeName = "text")]
public string? ProgressInfo { get; set; }
[MaxLength(500)]
public string? CurrentBacktest { get; set; }
public int? EstimatedTimeRemainingSeconds { get; set; }
[Required]
[MaxLength(255)]
public string Name { get; set; } = string.Empty;
[Required]
[Column(TypeName = "jsonb")]
public string ResultsJson { get; set; } = "[]";
[Required]
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}

View File

@@ -0,0 +1,27 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using static Managing.Common.Enums;
namespace Managing.Infrastructure.Databases.PostgreSql.Entities;
[Table("FundingRates")]
public class FundingRateEntity
{
[Key]
public int Id { get; set; }
public Ticker Ticker { get; set; }
public TradingExchanges Exchange { get; set; }
[Column(TypeName = "decimal(18,8)")]
public decimal Rate { get; set; }
[Column(TypeName = "decimal(18,8)")]
public decimal OpenInterest { get; set; }
public DateTime Date { get; set; }
public TradeDirection Direction { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}

View File

@@ -0,0 +1,38 @@
using static Managing.Common.Enums;
namespace Managing.Infrastructure.Databases.PostgreSql.Entities;
public class GeneticRequestEntity
{
public int Id { get; set; }
public string RequestId { get; set; }
public int? UserId { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime? CompletedAt { get; set; }
public DateTime? UpdatedAt { get; set; }
public string Status { get; set; } // GeneticRequestStatus as string
public Ticker Ticker { get; set; }
public Timeframe Timeframe { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public decimal Balance { get; set; }
public int PopulationSize { get; set; }
public int Generations { get; set; }
public double MutationRate { get; set; }
public GeneticSelectionMethod SelectionMethod { get; set; }
public GeneticCrossoverMethod CrossoverMethod { get; set; }
public GeneticMutationMethod MutationMethod { get; set; }
public int ElitismPercentage { get; set; }
public double MaxTakeProfit { get; set; }
public string? EligibleIndicatorsJson { get; set; } // Store List<IndicatorType> as JSON
public double? BestFitness { get; set; }
public string? BestIndividual { get; set; }
public string? ErrorMessage { get; set; }
public string? ProgressInfo { get; set; }
public string? BestChromosome { get; set; }
public double? BestFitnessSoFar { get; set; }
public int CurrentGeneration { get; set; }
// Navigation properties
public UserEntity? User { get; set; }
}

View File

@@ -0,0 +1,39 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using static Managing.Common.Enums;
namespace Managing.Infrastructure.Databases.PostgreSql.Entities;
[Table("Indicators")]
public class IndicatorEntity
{
[Key]
public int Id { get; set; }
[Required]
[MaxLength(255)]
public string Name { get; set; }
public IndicatorType Type { get; set; }
public Timeframe Timeframe { get; set; }
public SignalType SignalType { get; set; }
public int MinimumHistory { get; set; }
public int? Period { get; set; }
public int? FastPeriods { get; set; }
public int? SlowPeriods { get; set; }
public int? SignalPeriods { get; set; }
public double? Multiplier { get; set; }
public int? StochPeriods { get; set; }
public int? SmoothPeriods { get; set; }
public int? CyclePeriods { get; set; }
[MaxLength(255)]
public string? UserName { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
// Navigation property for the many-to-many relationship with scenarios
public virtual ICollection<ScenarioIndicatorEntity> ScenarioIndicators { get; set; } = new List<ScenarioIndicatorEntity>();
}

View File

@@ -0,0 +1,43 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using static Managing.Common.Enums;
namespace Managing.Infrastructure.Databases.PostgreSql.Entities;
[Table("MoneyManagements")]
public class MoneyManagementEntity
{
[Key]
public int Id { get; set; }
[Required]
[MaxLength(255)]
public string Name { get; set; }
[Required]
public Timeframe Timeframe { get; set; }
[Required]
[Column(TypeName = "decimal(18,8)")]
public decimal StopLoss { get; set; }
[Required]
[Column(TypeName = "decimal(18,8)")]
public decimal TakeProfit { get; set; }
[Required]
[Column(TypeName = "decimal(18,8)")]
public decimal Leverage { get; set; }
[MaxLength(255)]
public string? UserName { get; set; }
public int? UserId { get; set; }
// Navigation properties
[ForeignKey("UserId")]
public UserEntity? User { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}

View File

@@ -0,0 +1,61 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using static Managing.Common.Enums;
namespace Managing.Infrastructure.Databases.PostgreSql.Entities;
[Table("Positions")]
public class PositionEntity
{
[Key]
public int Id { get; set; }
[Required]
[MaxLength(255)]
public string Identifier { get; set; }
public DateTime Date { get; set; }
[Column(TypeName = "decimal(18,8)")]
public decimal ProfitAndLoss { get; set; }
public TradeDirection OriginDirection { get; set; }
public PositionStatus Status { get; set; }
public Ticker Ticker { get; set; }
public PositionInitiator Initiator { get; set; }
[MaxLength(255)]
public string SignalIdentifier { get; set; }
[MaxLength(255)]
public string AccountName { get; set; }
[MaxLength(255)]
public string? UserName { get; set; }
// Foreign keys to trades
public int? OpenTradeId { get; set; }
public int? StopLossTradeId { get; set; }
public int? TakeProfit1TradeId { get; set; }
public int? TakeProfit2TradeId { get; set; }
// Money management data stored as JSON
[Column(TypeName = "text")]
public string? MoneyManagementJson { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
// Navigation properties
[ForeignKey("OpenTradeId")]
public virtual TradeEntity? OpenTrade { get; set; }
[ForeignKey("StopLossTradeId")]
public virtual TradeEntity? StopLossTrade { get; set; }
[ForeignKey("TakeProfit1TradeId")]
public virtual TradeEntity? TakeProfit1Trade { get; set; }
[ForeignKey("TakeProfit2TradeId")]
public virtual TradeEntity? TakeProfit2Trade { get; set; }
}

View File

@@ -0,0 +1,26 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Managing.Infrastructure.Databases.PostgreSql.Entities;
[Table("Scenarios")]
public class ScenarioEntity
{
[Key]
public int Id { get; set; }
[Required]
[MaxLength(255)]
public string Name { get; set; }
public int LoopbackPeriod { get; set; }
[MaxLength(255)]
public string? UserName { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
// Navigation property for the many-to-many relationship with indicators
public virtual ICollection<ScenarioIndicatorEntity> ScenarioIndicators { get; set; } = new List<ScenarioIndicatorEntity>();
}

View File

@@ -0,0 +1,23 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Managing.Infrastructure.Databases.PostgreSql.Entities;
[Table("ScenarioIndicators")]
public class ScenarioIndicatorEntity
{
[Key]
public int Id { get; set; }
public int ScenarioId { get; set; }
public int IndicatorId { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
// Navigation properties
[ForeignKey("ScenarioId")]
public virtual ScenarioEntity Scenario { get; set; } = null!;
[ForeignKey("IndicatorId")]
public virtual IndicatorEntity Indicator { get; set; } = null!;
}

View File

@@ -0,0 +1,38 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using static Managing.Common.Enums;
namespace Managing.Infrastructure.Databases.PostgreSql.Entities;
[Table("Signals")]
public class SignalEntity
{
[Key]
public int Id { get; set; }
[Required]
[MaxLength(255)]
public string Identifier { get; set; }
public TradeDirection Direction { get; set; }
public Confidence Confidence { get; set; }
public DateTime Date { get; set; }
public Ticker Ticker { get; set; }
public SignalStatus Status { get; set; }
public Timeframe Timeframe { get; set; }
public IndicatorType Type { get; set; }
public SignalType SignalType { get; set; }
[MaxLength(255)]
public string IndicatorName { get; set; }
[MaxLength(255)]
public string? UserName { get; set; }
// Candle data stored as JSON
[Column(TypeName = "text")]
public string? CandleJson { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}

View File

@@ -0,0 +1,25 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Managing.Infrastructure.Databases.PostgreSql.Entities;
[Table("SpotlightOverviews")]
public class SpotlightOverviewEntity
{
[Key]
public int Id { get; set; }
public Guid Identifier { get; set; }
public DateTime DateTime { get; set; }
public int ScenarioCount { get; set; }
/// <summary>
/// JSON column containing the complex nested spotlights data
/// This stores the List<SpotlightDto> as JSON to avoid complex normalization
/// </summary>
[Column(TypeName = "jsonb")]
public string SpotlightsJson { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}

View File

@@ -0,0 +1,32 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Managing.Infrastructure.Databases.PostgreSql.Entities;
public class SynthMinersLeaderboardEntity
{
[Key]
public Guid Id { get; set; }
[Required]
[MaxLength(32)]
public string Asset { get; set; }
[Required]
public int TimeIncrement { get; set; }
public DateTime? SignalDate { get; set; }
[Required]
public bool IsBacktest { get; set; }
[Column(TypeName = "jsonb")]
public string MinersData { get; set; } // JSON serialized List<MinerInfo>
[Required]
[MaxLength(255)]
public string CacheKey { get; set; }
[Required]
public DateTime CreatedAt { get; set; }
}

View File

@@ -0,0 +1,38 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Managing.Infrastructure.Databases.PostgreSql.Entities;
public class SynthPredictionEntity
{
[Key]
public Guid Id { get; set; }
[Required]
[MaxLength(32)]
public string Asset { get; set; }
[Required]
public int MinerUid { get; set; }
[Required]
public int TimeIncrement { get; set; }
[Required]
public int TimeLength { get; set; }
public DateTime? SignalDate { get; set; }
[Required]
public bool IsBacktest { get; set; }
[Column(TypeName = "jsonb")]
public string PredictionData { get; set; } // JSON serialized MinerPrediction
[Required]
[MaxLength(255)]
public string CacheKey { get; set; }
[Required]
public DateTime CreatedAt { get; set; }
}

View File

@@ -0,0 +1,24 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using static Managing.Common.Enums;
namespace Managing.Infrastructure.Databases.PostgreSql.Entities;
[Table("TopVolumeTickers")]
public class TopVolumeTickerEntity
{
[Key]
public int Id { get; set; }
public Ticker Ticker { get; set; }
public DateTime Date { get; set; }
[Column(TypeName = "decimal(18,8)")]
public decimal Volume { get; set; }
public int Rank { get; set; }
public TradingExchanges Exchange { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}

View File

@@ -0,0 +1,39 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using static Managing.Common.Enums;
namespace Managing.Infrastructure.Databases.PostgreSql.Entities;
[Table("Trades")]
public class TradeEntity
{
[Key]
public int Id { get; set; }
public DateTime Date { get; set; }
public TradeDirection Direction { get; set; }
public TradeStatus Status { get; set; }
public TradeType TradeType { get; set; }
public Ticker Ticker { get; set; }
[Column(TypeName = "decimal(18,8)")]
public decimal Fee { get; set; }
[Column(TypeName = "decimal(18,8)")]
public decimal Quantity { get; set; }
[Column(TypeName = "decimal(18,8)")]
public decimal Price { get; set; }
[Column(TypeName = "decimal(18,8)")]
public decimal Leverage { get; set; }
[MaxLength(255)]
public string? ExchangeOrderId { get; set; }
[Column(TypeName = "text")]
public string? Message { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}

View File

@@ -0,0 +1,40 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Managing.Infrastructure.Databases.PostgreSql.Entities;
[Table("Traders")]
public class TraderEntity
{
[Key]
public int Id { get; set; }
[Required]
[MaxLength(255)]
public string Address { get; set; }
public int Winrate { get; set; }
[Column(TypeName = "decimal(18,8)")]
public decimal Pnl { get; set; }
public int TradeCount { get; set; }
[Column(TypeName = "decimal(18,8)")]
public decimal AverageWin { get; set; }
[Column(TypeName = "decimal(18,8)")]
public decimal AverageLoss { get; set; }
[Column(TypeName = "decimal(18,8)")]
public decimal Roi { get; set; }
/// <summary>
/// Indicates whether this is a best trader (true) or bad trader (false)
/// This allows us to use one table for both types
/// </summary>
public bool IsBestTrader { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}

View File

@@ -0,0 +1,10 @@
namespace Managing.Infrastructure.Databases.PostgreSql.Entities;
public class UserEntity
{
public int Id { get; set; }
public string Name { get; set; }
public string? AgentName { get; set; }
public string? AvatarUrl { get; set; }
public string? TelegramChannel { get; set; }
}

View File

@@ -0,0 +1,30 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using static Managing.Common.Enums;
namespace Managing.Infrastructure.Databases.PostgreSql.Entities;
[Table("Workers")]
public class WorkerEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public WorkerType WorkerType { get; set; }
[Required]
public DateTime StartTime { get; set; }
public DateTime? LastRunTime { get; set; }
[Required]
public int ExecutionCount { get; set; }
[Required]
public long DelayTicks { get; set; } // TimeSpan is not supported, store as ticks
[Required]
public bool IsActive { get; set; }
}