diff --git a/src/Managing.Api/Controllers/UserController.cs b/src/Managing.Api/Controllers/UserController.cs
index 9ac7739a..f61a96a7 100644
--- a/src/Managing.Api/Controllers/UserController.cs
+++ b/src/Managing.Api/Controllers/UserController.cs
@@ -145,4 +145,29 @@ public class UserController : BaseController
return StatusCode(500, $"Failed to send test message: {ex.Message}");
}
}
+
+ ///
+ /// Updates the user settings for the current user.
+ ///
+ /// The user settings to update.
+ /// The updated user with the new settings.
+ [Authorize]
+ [HttpPut("settings")]
+ public async Task> UpdateUserSettings([FromBody] UpdateUserSettingsRequest settings)
+ {
+ var user = await GetUser();
+ // Map API request to DTO
+ var settingsDto = new Managing.Application.Abstractions.Models.UserSettingsDto
+ {
+ LowEthAmountAlert = settings.LowEthAmountAlert,
+ EnableAutoswap = settings.EnableAutoswap,
+ AutoswapAmount = settings.AutoswapAmount,
+ MaxWaitingTimeForPositionToGetFilledSeconds = settings.MaxWaitingTimeForPositionToGetFilledSeconds,
+ MaxTxnGasFeePerPosition = settings.MaxTxnGasFeePerPosition,
+ IsGmxEnabled = settings.IsGmxEnabled,
+ MinimumConfidence = settings.MinimumConfidence
+ };
+ var updatedUser = await _userService.UpdateUserSettings(user, settingsDto);
+ return Ok(updatedUser);
+ }
}
\ No newline at end of file
diff --git a/src/Managing.Api/Models/Requests/UpdateUserSettingsRequest.cs b/src/Managing.Api/Models/Requests/UpdateUserSettingsRequest.cs
new file mode 100644
index 00000000..77d0819d
--- /dev/null
+++ b/src/Managing.Api/Models/Requests/UpdateUserSettingsRequest.cs
@@ -0,0 +1,16 @@
+using Managing.Common;
+using static Managing.Common.Enums;
+
+namespace Managing.Api.Models.Requests;
+
+public class UpdateUserSettingsRequest
+{
+ public decimal? LowEthAmountAlert { get; set; }
+ public bool? EnableAutoswap { get; set; }
+ public decimal? AutoswapAmount { get; set; }
+ public int? MaxWaitingTimeForPositionToGetFilledSeconds { get; set; }
+ public decimal? MaxTxnGasFeePerPosition { get; set; }
+ public bool? IsGmxEnabled { get; set; }
+ public Confidence? MinimumConfidence { get; set; }
+}
+
diff --git a/src/Managing.Application.Abstractions/Models/UserSettingsDto.cs b/src/Managing.Application.Abstractions/Models/UserSettingsDto.cs
new file mode 100644
index 00000000..9e9d92b0
--- /dev/null
+++ b/src/Managing.Application.Abstractions/Models/UserSettingsDto.cs
@@ -0,0 +1,15 @@
+using static Managing.Common.Enums;
+
+namespace Managing.Application.Abstractions.Models;
+
+public class UserSettingsDto
+{
+ public decimal? LowEthAmountAlert { get; set; }
+ public bool? EnableAutoswap { get; set; }
+ public decimal? AutoswapAmount { get; set; }
+ public int? MaxWaitingTimeForPositionToGetFilledSeconds { get; set; }
+ public decimal? MaxTxnGasFeePerPosition { get; set; }
+ public bool? IsGmxEnabled { get; set; }
+ public Confidence? MinimumConfidence { get; set; }
+}
+
diff --git a/src/Managing.Application.Abstractions/Services/IUserService.cs b/src/Managing.Application.Abstractions/Services/IUserService.cs
index a11a8f27..6a46433d 100644
--- a/src/Managing.Application.Abstractions/Services/IUserService.cs
+++ b/src/Managing.Application.Abstractions/Services/IUserService.cs
@@ -1,4 +1,5 @@
-using Managing.Application.Abstractions.Shared;
+using Managing.Application.Abstractions.Models;
+using Managing.Application.Abstractions.Shared;
using Managing.Domain.Users;
using static Managing.Common.Enums;
@@ -11,6 +12,7 @@ public interface IUserService
Task UpdateAgentName(User user, string agentName);
Task UpdateAvatarUrl(User user, string avatarUrl);
Task UpdateTelegramChannel(User user, string telegramChannel);
+ Task UpdateUserSettings(User user, UserSettingsDto settings);
Task GetUserByName(string name);
Task GetUserByAgentName(string agentName);
Task GetUserByIdAsync(int userId);
diff --git a/src/Managing.Application/Users/UserService.cs b/src/Managing.Application/Users/UserService.cs
index 3c0bdeaf..ba5261d5 100644
--- a/src/Managing.Application/Users/UserService.cs
+++ b/src/Managing.Application/Users/UserService.cs
@@ -1,5 +1,6 @@
using System.Text.RegularExpressions;
using Managing.Application.Abstractions.Grains;
+using Managing.Application.Abstractions.Models;
using Managing.Application.Abstractions.Repositories;
using Managing.Application.Abstractions.Services;
using Managing.Application.Abstractions.Shared;
@@ -338,6 +339,36 @@ public class UserService : IUserService
return user;
}
+ public async Task UpdateUserSettings(User user, UserSettingsDto settings)
+ {
+ user = await GetUserByName(user.Name);
+
+ // Update settings only if values are provided (partial update support)
+ if (settings.LowEthAmountAlert.HasValue)
+ user.LowEthAmountAlert = settings.LowEthAmountAlert.Value;
+
+ if (settings.EnableAutoswap.HasValue)
+ user.EnableAutoswap = settings.EnableAutoswap.Value;
+
+ if (settings.AutoswapAmount.HasValue)
+ user.AutoswapAmount = settings.AutoswapAmount.Value;
+
+ if (settings.MaxWaitingTimeForPositionToGetFilledSeconds.HasValue)
+ user.MaxWaitingTimeForPositionToGetFilledSeconds = settings.MaxWaitingTimeForPositionToGetFilledSeconds.Value;
+
+ if (settings.MaxTxnGasFeePerPosition.HasValue)
+ user.MaxTxnGasFeePerPosition = settings.MaxTxnGasFeePerPosition.Value;
+
+ if (settings.IsGmxEnabled.HasValue)
+ user.IsGmxEnabled = settings.IsGmxEnabled.Value;
+
+ if (settings.MinimumConfidence.HasValue)
+ user.MinimumConfidence = settings.MinimumConfidence.Value;
+
+ await _userRepository.SaveOrUpdateUserAsync(user);
+ return user;
+ }
+
public async Task GetUserByName(string name)
{
return await _userRepository.GetUserByNameAsync(name);
diff --git a/src/Managing.Domain/Users/User.cs b/src/Managing.Domain/Users/User.cs
index e301f7c7..b93706f5 100644
--- a/src/Managing.Domain/Users/User.cs
+++ b/src/Managing.Domain/Users/User.cs
@@ -1,5 +1,6 @@
using Managing.Domain.Accounts;
using Orleans;
+using static Managing.Common.Enums;
namespace Managing.Domain.Users;
@@ -23,4 +24,13 @@ public class User
[Id(7)] public bool IsAdmin { get; set; } = false;
[Id(8)] public DateTimeOffset? LastConnectionDate { get; set; }
+
+ // User Settings
+ [Id(9)] public decimal? LowEthAmountAlert { get; set; }
+ [Id(10)] public bool EnableAutoswap { get; set; } = false;
+ [Id(11)] public decimal? AutoswapAmount { get; set; }
+ [Id(12)] public int? MaxWaitingTimeForPositionToGetFilledSeconds { get; set; }
+ [Id(13)] public decimal? MaxTxnGasFeePerPosition { get; set; }
+ [Id(14)] public bool IsGmxEnabled { get; set; } = false;
+ [Id(15)] public Confidence? MinimumConfidence { get; set; }
}
\ No newline at end of file
diff --git a/src/Managing.Infrastructure.Database/Migrations/20251229224000_AddUserSettings.Designer.cs b/src/Managing.Infrastructure.Database/Migrations/20251229224000_AddUserSettings.Designer.cs
new file mode 100644
index 00000000..669d3671
--- /dev/null
+++ b/src/Managing.Infrastructure.Database/Migrations/20251229224000_AddUserSettings.Designer.cs
@@ -0,0 +1,1773 @@
+//
+using System;
+using Managing.Infrastructure.Databases.PostgreSql;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace Managing.Infrastructure.Databases.Migrations
+{
+ [DbContext(typeof(ManagingDbContext))]
+ [Migration("20251229224000_AddUserSettings")]
+ partial class AddUserSettings
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "8.0.11")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Managing.Infrastructure.Databases.PostgreSql.Entities.AccountEntity", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Exchange")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("IsGmxInitialized")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("boolean")
+ .HasDefaultValue(false);
+
+ b.Property("Key")
+ .IsRequired()
+ .HasMaxLength(500)
+ .HasColumnType("character varying(500)");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.Property("Secret")
+ .HasMaxLength(500)
+ .HasColumnType("character varying(500)");
+
+ b.Property("Type")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UserId")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Name")
+ .IsUnique();
+
+ b.HasIndex("UserId");
+
+ b.ToTable("Accounts");
+ });
+
+ modelBuilder.Entity("Managing.Infrastructure.Databases.PostgreSql.Entities.AgentSummaryEntity", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("ActiveStrategiesCount")
+ .HasColumnType("integer");
+
+ b.Property("AgentName")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.Property("BacktestCount")
+ .HasColumnType("integer");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Losses")
+ .HasColumnType("integer");
+
+ b.Property("NetPnL")
+ .HasPrecision(18, 8)
+ .HasColumnType("numeric(18,8)");
+
+ b.Property("Runtime")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("TotalBalance")
+ .HasPrecision(18, 8)
+ .HasColumnType("numeric(18,8)");
+
+ b.Property("TotalFees")
+ .HasPrecision(18, 8)
+ .HasColumnType("numeric(18,8)");
+
+ b.Property("TotalPnL")
+ .HasColumnType("decimal(18,8)");
+
+ b.Property("TotalROI")
+ .HasColumnType("decimal(18,8)");
+
+ b.Property("TotalVolume")
+ .HasPrecision(18, 8)
+ .HasColumnType("numeric(18,8)");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("UserId")
+ .HasColumnType("integer");
+
+ b.Property("Wins")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AgentName")
+ .IsUnique();
+
+ b.HasIndex("TotalPnL");
+
+ b.HasIndex("UserId")
+ .IsUnique();
+
+ b.ToTable("AgentSummaries");
+ });
+
+ modelBuilder.Entity("Managing.Infrastructure.Databases.PostgreSql.Entities.BacktestEntity", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("ConfigJson")
+ .IsRequired()
+ .HasColumnType("jsonb");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Duration")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("interval")
+ .HasDefaultValue(new TimeSpan(0, 0, 0, 0, 0));
+
+ b.Property("EndDate")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Fees")
+ .HasColumnType("decimal(18,8)");
+
+ b.Property("FinalPnl")
+ .HasColumnType("decimal(18,8)");
+
+ b.Property("GrowthPercentage")
+ .HasColumnType("decimal(18,8)");
+
+ b.Property("HodlPercentage")
+ .HasColumnType("decimal(18,8)");
+
+ b.Property("Identifier")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.Property("IndicatorsCount")
+ .HasColumnType("integer");
+
+ b.Property("IndicatorsCsv")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("InitialBalance")
+ .HasColumnType("decimal(18,8)");
+
+ b.Property("MaxDrawdown")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("decimal(18,8)")
+ .HasDefaultValue(0m);
+
+ b.Property("MaxDrawdownRecoveryTime")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("interval")
+ .HasDefaultValue(new TimeSpan(0, 0, 0, 0, 0));
+
+ b.Property("Metadata")
+ .HasColumnType("text");
+
+ b.Property("MoneyManagementJson")
+ .IsRequired()
+ .HasColumnType("jsonb");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.Property("NetPnl")
+ .HasColumnType("decimal(18,8)");
+
+ b.Property("PositionCount")
+ .HasColumnType("integer");
+
+ b.Property("PositionsJson")
+ .IsRequired()
+ .HasColumnType("jsonb");
+
+ b.Property("RequestId")
+ .HasMaxLength(255)
+ .HasColumnType("uuid");
+
+ b.Property("Score")
+ .HasColumnType("double precision");
+
+ b.Property("ScoreMessage")
+ .IsRequired()
+ .HasMaxLength(1000)
+ .HasColumnType("text");
+
+ b.Property("SharpeRatio")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("decimal(18,8)")
+ .HasDefaultValue(0m);
+
+ b.Property("SignalsJson")
+ .IsRequired()
+ .HasColumnType("jsonb");
+
+ b.Property("StartDate")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("StatisticsJson")
+ .HasColumnType("jsonb");
+
+ b.Property("Ticker")
+ .IsRequired()
+ .HasMaxLength(32)
+ .HasColumnType("character varying(32)");
+
+ b.Property("Timeframe")
+ .HasColumnType("integer");
+
+ b.Property("TradingType")
+ .HasColumnType("integer");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("UserId")
+ .HasColumnType("integer");
+
+ b.Property("WinRate")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Identifier")
+ .IsUnique();
+
+ b.HasIndex("RequestId");
+
+ b.HasIndex("Score");
+
+ b.HasIndex("UserId");
+
+ b.HasIndex("RequestId", "Score");
+
+ b.HasIndex("UserId", "Name");
+
+ b.HasIndex("UserId", "Score");
+
+ b.HasIndex("UserId", "Ticker");
+
+ b.HasIndex("UserId", "Timeframe");
+
+ b.ToTable("Backtests");
+ });
+
+ modelBuilder.Entity("Managing.Infrastructure.Databases.PostgreSql.Entities.BotEntity", b =>
+ {
+ b.Property("Identifier")
+ .ValueGeneratedOnAdd()
+ .HasMaxLength(255)
+ .HasColumnType("uuid");
+
+ b.Property("AccumulatedRunTimeSeconds")
+ .HasColumnType("bigint");
+
+ b.Property("CreateDate")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Fees")
+ .HasPrecision(18, 8)
+ .HasColumnType("numeric(18,8)");
+
+ b.Property("LastStartTime")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("LastStopTime")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("LongPositionCount")
+ .HasColumnType("integer");
+
+ b.Property("MasterBotUserId")
+ .HasColumnType("integer");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.Property("NetPnL")
+ .HasPrecision(18, 8)
+ .HasColumnType("numeric(18,8)");
+
+ b.Property("Pnl")
+ .HasPrecision(18, 8)
+ .HasColumnType("numeric(18,8)");
+
+ b.Property("Roi")
+ .HasPrecision(18, 8)
+ .HasColumnType("numeric(18,8)");
+
+ b.Property("ShortPositionCount")
+ .HasColumnType("integer");
+
+ b.Property("StartupTime")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Ticker")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("TradeLosses")
+ .HasColumnType("integer");
+
+ b.Property("TradeWins")
+ .HasColumnType("integer");
+
+ b.Property("TradingType")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("UserId")
+ .HasColumnType("integer");
+
+ b.Property("Volume")
+ .HasPrecision(18, 8)
+ .HasColumnType("numeric(18,8)");
+
+ b.HasKey("Identifier");
+
+ b.HasIndex("Identifier")
+ .IsUnique();
+
+ b.HasIndex("MasterBotUserId");
+
+ b.HasIndex("Status");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("Bots");
+ });
+
+ modelBuilder.Entity("Managing.Infrastructure.Databases.PostgreSql.Entities.BundleBacktestRequestEntity", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("CompletedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CompletedBacktests")
+ .HasColumnType("integer");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CurrentBacktest")
+ .HasMaxLength(500)
+ .HasColumnType("character varying(500)");
+
+ b.Property("DateTimeRangesJson")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ErrorMessage")
+ .HasColumnType("text");
+
+ b.Property("EstimatedTimeRemainingSeconds")
+ .HasColumnType("integer");
+
+ b.Property("FailedBacktests")
+ .HasColumnType("integer");
+
+ b.Property("MoneyManagementVariantsJson")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.Property("ProgressInfo")
+ .HasColumnType("text");
+
+ b.Property("RequestId")
+ .HasMaxLength(255)
+ .HasColumnType("uuid");
+
+ b.Property("ResultsJson")
+ .IsRequired()
+ .HasColumnType("jsonb");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("TickerVariantsJson")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("TotalBacktests")
+ .HasColumnType("integer");
+
+ b.Property("UniversalConfigJson")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("UserId")
+ .HasColumnType("integer");
+
+ b.Property("Version")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasDefaultValue(1);
+
+ b.HasKey("Id");
+
+ b.HasIndex("RequestId")
+ .IsUnique();
+
+ b.HasIndex("Status");
+
+ b.HasIndex("UserId");
+
+ b.HasIndex("UserId", "CreatedAt");
+
+ b.HasIndex("UserId", "Name", "Version");
+
+ b.ToTable("BundleBacktestRequests");
+ });
+
+ modelBuilder.Entity("Managing.Infrastructure.Databases.PostgreSql.Entities.FundingRateEntity", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Date")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Direction")
+ .HasColumnType("integer");
+
+ b.Property("Exchange")
+ .HasColumnType("integer");
+
+ b.Property("OpenInterest")
+ .HasPrecision(18, 8)
+ .HasColumnType("decimal(18,8)");
+
+ b.Property("Rate")
+ .HasPrecision(18, 8)
+ .HasColumnType("decimal(18,8)");
+
+ b.Property("Ticker")
+ .HasColumnType("integer");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Date");
+
+ b.HasIndex("Exchange");
+
+ b.HasIndex("Ticker");
+
+ b.HasIndex("Exchange", "Date");
+
+ b.HasIndex("Ticker", "Exchange");
+
+ b.HasIndex("Ticker", "Exchange", "Date")
+ .IsUnique();
+
+ b.ToTable("FundingRates");
+ });
+
+ modelBuilder.Entity("Managing.Infrastructure.Databases.PostgreSql.Entities.GeneticRequestEntity", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Balance")
+ .HasColumnType("decimal(18,8)");
+
+ b.Property("BestChromosome")
+ .HasMaxLength(4000)
+ .HasColumnType("character varying(4000)");
+
+ b.Property("BestFitness")
+ .HasColumnType("double precision");
+
+ b.Property("BestFitnessSoFar")
+ .HasColumnType("double precision");
+
+ b.Property("BestIndividual")
+ .HasMaxLength(4000)
+ .HasColumnType("character varying(4000)");
+
+ b.Property("CompletedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CrossoverMethod")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("CurrentGeneration")
+ .HasColumnType("integer");
+
+ b.Property("EligibleIndicatorsJson")
+ .HasMaxLength(2000)
+ .HasColumnType("character varying(2000)");
+
+ b.Property("ElitismPercentage")
+ .HasColumnType("integer");
+
+ b.Property("EndDate")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ErrorMessage")
+ .HasMaxLength(2000)
+ .HasColumnType("character varying(2000)");
+
+ b.Property("Generations")
+ .HasColumnType("integer");
+
+ b.Property("MaxTakeProfit")
+ .HasColumnType("double precision");
+
+ b.Property("MutationMethod")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("MutationRate")
+ .HasColumnType("double precision");
+
+ b.Property("PopulationSize")
+ .HasColumnType("integer");
+
+ b.Property("ProgressInfo")
+ .HasMaxLength(4000)
+ .HasColumnType("character varying(4000)");
+
+ b.Property("RequestId")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.Property("SelectionMethod")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("StartDate")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("Ticker")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Timeframe")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("UserId")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.HasIndex("RequestId")
+ .IsUnique();
+
+ b.HasIndex("Status");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("GeneticRequests");
+ });
+
+ modelBuilder.Entity("Managing.Infrastructure.Databases.PostgreSql.Entities.IndicatorEntity", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CyclePeriods")
+ .HasColumnType("integer");
+
+ b.Property("FastPeriods")
+ .HasColumnType("integer");
+
+ b.Property("MinimumHistory")
+ .HasColumnType("integer");
+
+ b.Property("Multiplier")
+ .HasColumnType("double precision");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.Property("Period")
+ .HasColumnType("integer");
+
+ b.Property("SignalPeriods")
+ .HasColumnType("integer");
+
+ b.Property("SignalType")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("SlowPeriods")
+ .HasColumnType("integer");
+
+ b.Property("SmoothPeriods")
+ .HasColumnType("integer");
+
+ b.Property("StochPeriods")
+ .HasColumnType("integer");
+
+ b.Property("Timeframe")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Type")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("UserId")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.HasIndex("UserId", "Name");
+
+ b.ToTable("Indicators");
+ });
+
+ modelBuilder.Entity("Managing.Infrastructure.Databases.PostgreSql.Entities.JobEntity", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("uuid");
+
+ b.Property("AssignedWorkerId")
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.Property("BundleRequestId")
+ .HasColumnType("uuid");
+
+ b.Property("CompletedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ConfigJson")
+ .IsRequired()
+ .HasColumnType("jsonb");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("EndDate")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ErrorMessage")
+ .HasColumnType("text");
+
+ b.Property("FailureCategory")
+ .HasColumnType("integer");
+
+ b.Property("GeneticRequestId")
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.Property("IsRetryable")
+ .HasColumnType("boolean");
+
+ b.Property("JobType")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasDefaultValue(0);
+
+ b.Property("LastHeartbeat")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("MaxRetries")
+ .HasColumnType("integer");
+
+ b.Property("Priority")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasDefaultValue(0);
+
+ b.Property("ProgressPercentage")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasDefaultValue(0);
+
+ b.Property("RequestId")
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.Property("ResultJson")
+ .HasColumnType("jsonb");
+
+ b.Property("RetryAfter")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("RetryCount")
+ .HasColumnType("integer");
+
+ b.Property("StartDate")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("StartedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Status")
+ .HasColumnType("integer");
+
+ b.Property("UserId")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.HasIndex("BundleRequestId")
+ .HasDatabaseName("idx_bundle_request");
+
+ b.HasIndex("GeneticRequestId")
+ .HasDatabaseName("idx_genetic_request");
+
+ b.HasIndex("AssignedWorkerId", "Status")
+ .HasDatabaseName("idx_assigned_worker");
+
+ b.HasIndex("UserId", "Status")
+ .HasDatabaseName("idx_user_status");
+
+ b.HasIndex("Status", "JobType", "Priority", "CreatedAt")
+ .HasDatabaseName("idx_status_jobtype_priority_created");
+
+ b.ToTable("Jobs", (string)null);
+ });
+
+ modelBuilder.Entity("Managing.Infrastructure.Databases.PostgreSql.Entities.MoneyManagementEntity", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Leverage")
+ .HasColumnType("decimal(18,8)");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.Property("StopLoss")
+ .HasColumnType("decimal(18,8)");
+
+ b.Property("TakeProfit")
+ .HasColumnType("decimal(18,8)");
+
+ b.Property("Timeframe")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("UserId")
+ .HasColumnType("integer");
+
+ b.Property("UserName")
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.HasIndex("UserName");
+
+ b.HasIndex("UserName", "Name");
+
+ b.ToTable("MoneyManagements");
+ });
+
+ modelBuilder.Entity("Managing.Infrastructure.Databases.PostgreSql.Entities.PositionEntity", b =>
+ {
+ b.Property("Identifier")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("AccountId")
+ .HasColumnType("integer");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Date")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("GasFees")
+ .HasColumnType("decimal(18,8)");
+
+ b.Property("Initiator")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("InitiatorIdentifier")
+ .HasColumnType("uuid");
+
+ b.Property("MoneyManagementJson")
+ .HasColumnType("text");
+
+ b.Property("NetPnL")
+ .HasColumnType("decimal(18,8)");
+
+ b.Property("OpenTradeId")
+ .HasColumnType("integer");
+
+ b.Property("OriginDirection")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ProfitAndLoss")
+ .HasColumnType("decimal(18,8)");
+
+ b.Property("SignalIdentifier")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("StopLossTradeId")
+ .HasColumnType("integer");
+
+ b.Property("TakeProfit1TradeId")
+ .HasColumnType("integer");
+
+ b.Property("TakeProfit2TradeId")
+ .HasColumnType("integer");
+
+ b.Property("Ticker")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("TradingType")
+ .HasColumnType("integer");
+
+ b.Property("UiFees")
+ .HasColumnType("decimal(18,8)");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("UserId")
+ .HasColumnType("integer");
+
+ b.HasKey("Identifier");
+
+ b.HasIndex("Identifier")
+ .IsUnique();
+
+ b.HasIndex("InitiatorIdentifier");
+
+ b.HasIndex("OpenTradeId");
+
+ b.HasIndex("Status");
+
+ b.HasIndex("StopLossTradeId");
+
+ b.HasIndex("TakeProfit1TradeId");
+
+ b.HasIndex("TakeProfit2TradeId");
+
+ b.HasIndex("UserId");
+
+ b.HasIndex("UserId", "Identifier");
+
+ b.ToTable("Positions");
+ });
+
+ modelBuilder.Entity("Managing.Infrastructure.Databases.PostgreSql.Entities.ScenarioEntity", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("LoopbackPeriod")
+ .HasColumnType("integer");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("UserId")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.HasIndex("UserId", "Name");
+
+ b.ToTable("Scenarios");
+ });
+
+ modelBuilder.Entity("Managing.Infrastructure.Databases.PostgreSql.Entities.ScenarioIndicatorEntity", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("IndicatorId")
+ .HasColumnType("integer");
+
+ b.Property("ScenarioId")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.HasIndex("IndicatorId");
+
+ b.HasIndex("ScenarioId", "IndicatorId")
+ .IsUnique();
+
+ b.ToTable("ScenarioIndicators");
+ });
+
+ modelBuilder.Entity("Managing.Infrastructure.Databases.PostgreSql.Entities.SignalEntity", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("CandleJson")
+ .HasColumnType("text");
+
+ b.Property("Confidence")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Date")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Direction")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Identifier")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.Property("IndicatorName")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.Property("SignalType")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Ticker")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Timeframe")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property