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,223 @@
using System.Text.Json;
using Managing.Application.Abstractions.Repositories;
using Managing.Domain.Synth.Models;
using Managing.Infrastructure.Databases.PostgreSql.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace Managing.Infrastructure.Databases.PostgreSql;
public class PostgreSqlSynthRepository : ISynthRepository
{
private readonly ManagingDbContext _context;
private readonly ILogger<PostgreSqlSynthRepository> _logger;
public PostgreSqlSynthRepository(ManagingDbContext context, ILogger<PostgreSqlSynthRepository> logger)
{
_context = context;
_logger = logger;
}
public async Task<SynthMinersLeaderboard?> GetLeaderboardAsync(string cacheKey)
{
try
{
var entity = await _context.SynthMinersLeaderboards.AsNoTracking().FirstOrDefaultAsync(x => x.CacheKey == cacheKey);
if (entity == null)
{
_logger.LogDebug($"[PG Synth] No leaderboard cache found for key: {cacheKey}");
return null;
}
var miners = JsonSerializer.Deserialize<List<MinerInfo>>(entity.MinersData);
return new SynthMinersLeaderboard
{
Id = entity.Id.ToString(),
Asset = entity.Asset,
TimeIncrement = entity.TimeIncrement,
SignalDate = entity.SignalDate,
IsBacktest = entity.IsBacktest,
Miners = miners ?? new List<MinerInfo>(),
CreatedAt = entity.CreatedAt
};
}
catch (Exception ex)
{
_logger.LogError(ex, $"Error retrieving leaderboard cache for key: {cacheKey}");
return null;
}
}
public async Task SaveLeaderboardAsync(SynthMinersLeaderboard leaderboard)
{
try
{
leaderboard.CreatedAt = DateTime.UtcNow;
var cacheKey = leaderboard.GetCacheKey();
var minersData = JsonSerializer.Serialize(leaderboard.Miners);
var existing = await _context.SynthMinersLeaderboards.FirstOrDefaultAsync(x => x.CacheKey == cacheKey);
if (existing != null)
{
existing.Asset = leaderboard.Asset;
existing.TimeIncrement = leaderboard.TimeIncrement;
existing.SignalDate = leaderboard.SignalDate;
existing.IsBacktest = leaderboard.IsBacktest;
existing.MinersData = minersData;
existing.CreatedAt = leaderboard.CreatedAt;
_context.SynthMinersLeaderboards.Update(existing);
_logger.LogDebug($"[PG Synth] Updated leaderboard in DB for key: {cacheKey}");
}
else
{
var entity = new SynthMinersLeaderboardEntity
{
Id = Guid.NewGuid(),
Asset = leaderboard.Asset,
TimeIncrement = leaderboard.TimeIncrement,
SignalDate = leaderboard.SignalDate,
IsBacktest = leaderboard.IsBacktest,
MinersData = minersData,
CacheKey = cacheKey,
CreatedAt = leaderboard.CreatedAt
};
await _context.SynthMinersLeaderboards.AddAsync(entity);
_logger.LogDebug($"[PG Synth] Saved new leaderboard to DB for key: {cacheKey}");
}
await _context.SaveChangesAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, $"Error saving leaderboard cache for key: {leaderboard.GetCacheKey()}");
}
}
public async Task<List<SynthPrediction>> GetIndividualPredictionsAsync(string asset, int timeIncrement, int timeLength, List<int> minerUids, bool isBacktest, DateTime? signalDate)
{
try
{
var results = new List<SynthPrediction>();
foreach (var minerUid in minerUids)
{
var cacheKey = $"{asset}_{timeIncrement}_{timeLength}_{minerUid}";
if (isBacktest && signalDate.HasValue)
{
cacheKey += $"_backtest_{signalDate.Value:yyyy-MM-dd-HH}";
}
var entity = await _context.SynthPredictions.AsNoTracking().FirstOrDefaultAsync(x => x.CacheKey == cacheKey);
if (entity != null)
{
var prediction = JsonSerializer.Deserialize<MinerPrediction>(entity.PredictionData);
if (prediction != null)
{
results.Add(new SynthPrediction
{
Id = entity.Id.ToString(),
Asset = entity.Asset,
MinerUid = entity.MinerUid,
TimeIncrement = entity.TimeIncrement,
TimeLength = entity.TimeLength,
SignalDate = entity.SignalDate,
IsBacktest = entity.IsBacktest,
Prediction = prediction,
CreatedAt = entity.CreatedAt
});
}
}
}
if (results.Any())
{
_logger.LogDebug($"[PG Synth] Retrieved {results.Count}/{minerUids.Count} individual predictions for {asset}");
}
else
{
_logger.LogDebug($"[PG Synth] No individual predictions found for {asset}");
}
return results;
}
catch (Exception ex)
{
_logger.LogError(ex, $"Error retrieving individual predictions cache for asset: {asset}");
return new List<SynthPrediction>();
}
}
public async Task SaveIndividualPredictionAsync(SynthPrediction prediction)
{
try
{
prediction.CreatedAt = DateTime.UtcNow;
var cacheKey = prediction.GetCacheKey();
var predictionData = JsonSerializer.Serialize(prediction.Prediction);
var existing = await _context.SynthPredictions.FirstOrDefaultAsync(x => x.CacheKey == cacheKey).ConfigureAwait(false);
if (existing != null)
{
existing.Asset = prediction.Asset;
existing.MinerUid = prediction.MinerUid;
existing.TimeIncrement = prediction.TimeIncrement;
existing.TimeLength = prediction.TimeLength;
existing.SignalDate = prediction.SignalDate;
existing.IsBacktest = prediction.IsBacktest;
existing.PredictionData = predictionData;
existing.CreatedAt = prediction.CreatedAt;
_context.SynthPredictions.Update(existing);
_logger.LogDebug($"[PG Synth] Updated individual prediction for miner {prediction.MinerUid}");
}
else
{
var entity = new SynthPredictionEntity
{
Id = Guid.NewGuid(),
Asset = prediction.Asset,
MinerUid = prediction.MinerUid,
TimeIncrement = prediction.TimeIncrement,
TimeLength = prediction.TimeLength,
SignalDate = prediction.SignalDate,
IsBacktest = prediction.IsBacktest,
PredictionData = predictionData,
CacheKey = cacheKey,
CreatedAt = prediction.CreatedAt
};
await _context.SynthPredictions.AddAsync(entity).ConfigureAwait(false);
_logger.LogDebug($"[PG Synth] Saved new individual prediction for miner {prediction.MinerUid}");
}
await _context.SaveChangesAsync().ConfigureAwait(false);
}
catch (Exception ex)
{
_logger.LogError(ex, $"Error saving individual prediction cache for miner {prediction.MinerUid}: {ex.Message}");
}
}
public async Task SaveIndividualPredictionsAsync(List<SynthPrediction> predictions)
{
if (!predictions.Any())
return;
try
{
var saveTasks = predictions.Select(SaveIndividualPredictionAsync);
await Task.WhenAll(saveTasks);
_logger.LogInformation($"[PG Synth] Successfully saved {predictions.Count} individual predictions to DB");
}
catch (Exception ex)
{
_logger.LogError(ex, $"Error saving batch of {predictions.Count} individual predictions");
}
}
public async Task CleanupOldDataAsync(int retentionDays = 30)
{
try
{
var cutoffDate = DateTime.UtcNow.AddDays(-retentionDays);
var oldLeaderboards = _context.SynthMinersLeaderboards.Where(x => x.CreatedAt < cutoffDate);
_context.SynthMinersLeaderboards.RemoveRange(oldLeaderboards);
var oldPredictions = _context.SynthPredictions.Where(x => x.CreatedAt < cutoffDate);
_context.SynthPredictions.RemoveRange(oldPredictions);
await _context.SaveChangesAsync();
_logger.LogInformation($"[PG Synth] Cleaned up old Synth cache data older than {retentionDays} days");
}
catch (Exception ex)
{
_logger.LogError(ex, $"Error during cleanup of old Synth cache data");
}
}
}