Trading bot grain (#33)
* Trading bot Grain * Fix a bit more of the trading bot * Advance on the tradingbot grain * Fix build * Fix db script * Fix user login * Fix a bit backtest * Fix cooldown and backtest * start fixing bot start * Fix startup * Setup local db * Fix build and update candles and scenario * Add bot registry * Add reminder * Updateing the grains * fix bootstraping * Save stats on tick * Save bot data every tick * Fix serialization * fix save bot stats * Fix get candles * use dict instead of list for position * Switch hashset to dict * Fix a bit * Fix bot launch and bot view * add migrations * Remove the tolist * Add agent grain * Save agent summary * clean * Add save bot * Update get bots * Add get bots * Fix stop/restart * fix Update config * Update scanner table on new backtest saved * Fix backtestRowDetails.tsx * Fix agentIndex * Update agentIndex * Fix more things * Update user cache * Fix * Fix account load/start/restart/run
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using Managing.Application.Abstractions.Repositories;
|
||||
using Managing.Domain.Bots;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
namespace Managing.Infrastructure.Databases.PostgreSql;
|
||||
|
||||
@@ -13,7 +14,7 @@ public class PostgreSqlBotRepository : IBotRepository
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task InsertBotAsync(BotBackup bot)
|
||||
public async Task InsertBotAsync(Bot bot)
|
||||
{
|
||||
bot.CreateDate = DateTime.UtcNow;
|
||||
var entity = PostgreSqlMappers.Map(bot);
|
||||
@@ -22,18 +23,24 @@ public class PostgreSqlBotRepository : IBotRepository
|
||||
{
|
||||
var userEntity = await _context.Users
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(u => u.Name == bot.User.Name)
|
||||
.FirstOrDefaultAsync(u => u.Id == bot.User.Id)
|
||||
.ConfigureAwait(false);
|
||||
entity.UserId = userEntity?.Id;
|
||||
|
||||
if (userEntity == null)
|
||||
{
|
||||
throw new InvalidOperationException($"User with id '{bot.User.Id}' not found");
|
||||
}
|
||||
|
||||
entity.UserId = userEntity.Id;
|
||||
}
|
||||
|
||||
await _context.BotBackups.AddAsync(entity).ConfigureAwait(false);
|
||||
await _context.Bots.AddAsync(entity).ConfigureAwait(false);
|
||||
await _context.SaveChangesAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<BotBackup>> GetBotsAsync()
|
||||
public async Task<IEnumerable<Bot>> GetBotsAsync()
|
||||
{
|
||||
var entities = await _context.BotBackups
|
||||
var entities = await _context.Bots
|
||||
.AsNoTracking()
|
||||
.Include(m => m.User)
|
||||
.ToListAsync()
|
||||
@@ -42,9 +49,9 @@ public class PostgreSqlBotRepository : IBotRepository
|
||||
return PostgreSqlMappers.Map(entities);
|
||||
}
|
||||
|
||||
public async Task UpdateBackupBot(BotBackup bot)
|
||||
public async Task UpdateBot(Bot bot)
|
||||
{
|
||||
var existingEntity = await _context.BotBackups
|
||||
var existingEntity = await _context.Bots
|
||||
.AsTracking()
|
||||
.FirstOrDefaultAsync(b => b.Identifier == bot.Identifier)
|
||||
.ConfigureAwait(false);
|
||||
@@ -54,18 +61,25 @@ public class PostgreSqlBotRepository : IBotRepository
|
||||
throw new InvalidOperationException($"Bot backup with identifier '{bot.Identifier}' not found");
|
||||
}
|
||||
|
||||
// Update the entity properties
|
||||
existingEntity.Data = bot.SerializeData(); // Use the serialized data string
|
||||
existingEntity.LastStatus = bot.LastStatus;
|
||||
// Update the existing entity properties directly instead of creating a new one
|
||||
existingEntity.Name = bot.Name;
|
||||
existingEntity.Ticker = bot.Ticker;
|
||||
existingEntity.Status = bot.Status;
|
||||
existingEntity.StartupTime = bot.StartupTime;
|
||||
existingEntity.TradeWins = bot.TradeWins;
|
||||
existingEntity.TradeLosses = bot.TradeLosses;
|
||||
existingEntity.Pnl = bot.Pnl;
|
||||
existingEntity.Roi = bot.Roi;
|
||||
existingEntity.Volume = bot.Volume;
|
||||
existingEntity.Fees = bot.Fees;
|
||||
existingEntity.UpdatedAt = DateTime.UtcNow;
|
||||
existingEntity.UserName = bot.User?.Name;
|
||||
|
||||
await _context.SaveChangesAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task DeleteBotBackup(string identifier)
|
||||
public async Task DeleteBot(Guid identifier)
|
||||
{
|
||||
var entity = await _context.BotBackups
|
||||
var entity = await _context.Bots
|
||||
.AsTracking()
|
||||
.FirstOrDefaultAsync(b => b.Identifier == identifier)
|
||||
.ConfigureAwait(false);
|
||||
@@ -75,17 +89,142 @@ public class PostgreSqlBotRepository : IBotRepository
|
||||
throw new InvalidOperationException($"Bot backup with identifier '{identifier}' not found");
|
||||
}
|
||||
|
||||
_context.BotBackups.Remove(entity);
|
||||
_context.Bots.Remove(entity);
|
||||
await _context.SaveChangesAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<BotBackup?> GetBotByIdentifierAsync(string identifier)
|
||||
public async Task<Bot> GetBotByIdentifierAsync(Guid identifier)
|
||||
{
|
||||
var entity = await _context.BotBackups
|
||||
var entity = await _context.Bots
|
||||
.AsNoTracking()
|
||||
.Include(m => m.User)
|
||||
.FirstOrDefaultAsync(b => b.Identifier == identifier)
|
||||
.ConfigureAwait(false);
|
||||
return PostgreSqlMappers.Map(entity);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Bot>> GetBotsByUserIdAsync(int id)
|
||||
{
|
||||
var entities = await _context.Bots
|
||||
.AsNoTracking()
|
||||
.Include(m => m.User)
|
||||
.Where(b => b.UserId == id)
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
return PostgreSqlMappers.Map(entities);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Bot>> GetBotsByStatusAsync(BotStatus status)
|
||||
{
|
||||
var entities = await _context.Bots
|
||||
.AsNoTracking()
|
||||
.Include(m => m.User)
|
||||
.Where(b => b.Status == status)
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
return PostgreSqlMappers.Map(entities);
|
||||
}
|
||||
|
||||
public async Task<Bot> GetBotByNameAsync(string name)
|
||||
{
|
||||
var entity = await _context.Bots
|
||||
.AsNoTracking()
|
||||
.Include(m => m.User)
|
||||
.FirstOrDefaultAsync(b => b.Name == name)
|
||||
.ConfigureAwait(false);
|
||||
return PostgreSqlMappers.Map(entity);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Bot>> GetBotsByIdsAsync(IEnumerable<Guid> identifiers)
|
||||
{
|
||||
var entities = await _context.Bots
|
||||
.AsNoTracking()
|
||||
.Include(m => m.User)
|
||||
.Where(b => identifiers.Contains(b.Identifier))
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return PostgreSqlMappers.Map(entities);
|
||||
}
|
||||
|
||||
public async Task<(IEnumerable<Bot> Bots, int TotalCount)> GetBotsPaginatedAsync(
|
||||
int pageNumber,
|
||||
int pageSize,
|
||||
BotStatus? status = null,
|
||||
string? name = null,
|
||||
string? ticker = null,
|
||||
string? agentName = null,
|
||||
string sortBy = "CreateDate",
|
||||
string sortDirection = "Desc")
|
||||
{
|
||||
// Build the query with filters
|
||||
var query = _context.Bots
|
||||
.AsNoTracking()
|
||||
.Include(m => m.User)
|
||||
.AsQueryable();
|
||||
|
||||
// Apply filters
|
||||
if (status.HasValue)
|
||||
{
|
||||
query = query.Where(b => b.Status == status.Value);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
query = query.Where(b => EF.Functions.ILike(b.Name, $"%{name}%"));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(ticker))
|
||||
{
|
||||
query = query.Where(b => EF.Functions.ILike(b.Ticker.ToString(), $"%{ticker}%"));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(agentName))
|
||||
{
|
||||
query = query.Where(b => b.User != null && EF.Functions.ILike(b.User.AgentName, $"%{agentName}%"));
|
||||
}
|
||||
|
||||
// Get total count before applying pagination
|
||||
var totalCount = await query.CountAsync().ConfigureAwait(false);
|
||||
|
||||
// Apply sorting
|
||||
query = sortBy.ToLower() switch
|
||||
{
|
||||
"name" => sortDirection.ToLower() == "asc"
|
||||
? query.OrderBy(b => b.Name)
|
||||
: query.OrderByDescending(b => b.Name),
|
||||
"ticker" => sortDirection.ToLower() == "asc"
|
||||
? query.OrderBy(b => b.Ticker)
|
||||
: query.OrderByDescending(b => b.Ticker),
|
||||
"status" => sortDirection.ToLower() == "asc"
|
||||
? query.OrderBy(b => b.Status)
|
||||
: query.OrderByDescending(b => b.Status),
|
||||
"startuptime" => sortDirection.ToLower() == "asc"
|
||||
? query.OrderBy(b => b.StartupTime)
|
||||
: query.OrderByDescending(b => b.StartupTime),
|
||||
"pnl" => sortDirection.ToLower() == "asc"
|
||||
? query.OrderBy(b => b.Pnl)
|
||||
: query.OrderByDescending(b => b.Pnl),
|
||||
"winrate" => sortDirection.ToLower() == "asc"
|
||||
? query.OrderBy(b => b.TradeWins / (b.TradeWins + b.TradeLosses))
|
||||
: query.OrderByDescending(b => b.TradeWins / (b.TradeWins + b.TradeLosses)),
|
||||
"agentname" => sortDirection.ToLower() == "asc"
|
||||
? query.OrderBy(b => b.User.AgentName)
|
||||
: query.OrderByDescending(b => b.User.AgentName),
|
||||
_ => sortDirection.ToLower() == "asc"
|
||||
? query.OrderBy(b => b.CreateDate)
|
||||
: query.OrderByDescending(b => b.CreateDate) // Default to CreateDate
|
||||
};
|
||||
|
||||
// Apply pagination
|
||||
var skip = (pageNumber - 1) * pageSize;
|
||||
var entities = await query
|
||||
.Skip(skip)
|
||||
.Take(pageSize)
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
var bots = PostgreSqlMappers.Map(entities);
|
||||
return (bots, totalCount);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user