Enhance user settings management by adding new properties and updating related functionality
This commit introduces additional user settings properties, including TrendStrongAgreementThreshold, SignalAgreementThreshold, AllowSignalTrendOverride, and DefaultExchange, to the User entity and associated DTOs. The UserController and UserService are updated to handle these new settings, allowing users to customize their trading configurations more effectively. Database migrations are also included to ensure proper schema updates for the new fields.
This commit is contained in:
@@ -165,7 +165,11 @@ public class UserController : BaseController
|
||||
MaxWaitingTimeForPositionToGetFilledSeconds = settings.MaxWaitingTimeForPositionToGetFilledSeconds,
|
||||
MaxTxnGasFeePerPosition = settings.MaxTxnGasFeePerPosition,
|
||||
IsGmxEnabled = settings.IsGmxEnabled,
|
||||
MinimumConfidence = settings.MinimumConfidence
|
||||
MinimumConfidence = settings.MinimumConfidence,
|
||||
TrendStrongAgreementThreshold = settings.TrendStrongAgreementThreshold,
|
||||
SignalAgreementThreshold = settings.SignalAgreementThreshold,
|
||||
AllowSignalTrendOverride = settings.AllowSignalTrendOverride,
|
||||
DefaultExchange = settings.DefaultExchange
|
||||
};
|
||||
var updatedUser = await _userService.UpdateUserSettings(user, settingsDto);
|
||||
return Ok(updatedUser);
|
||||
|
||||
@@ -5,12 +5,19 @@ namespace Managing.Api.Models.Requests;
|
||||
|
||||
public class UpdateUserSettingsRequest
|
||||
{
|
||||
// Trading Configuration
|
||||
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; }
|
||||
|
||||
// Indicator Combo Configuration
|
||||
public Confidence? MinimumConfidence { get; set; }
|
||||
public decimal? TrendStrongAgreementThreshold { get; set; }
|
||||
public decimal? SignalAgreementThreshold { get; set; }
|
||||
public bool? AllowSignalTrendOverride { get; set; }
|
||||
public TradingExchanges? DefaultExchange { get; set; }
|
||||
}
|
||||
|
||||
|
||||
@@ -4,12 +4,19 @@ namespace Managing.Application.Abstractions.Models;
|
||||
|
||||
public class UserSettingsDto
|
||||
{
|
||||
// Trading Configuration
|
||||
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; }
|
||||
|
||||
// Indicator Combo Configuration
|
||||
public Confidence? MinimumConfidence { get; set; }
|
||||
public decimal? TrendStrongAgreementThreshold { get; set; }
|
||||
public decimal? SignalAgreementThreshold { get; set; }
|
||||
public bool? AllowSignalTrendOverride { get; set; }
|
||||
public TradingExchanges? DefaultExchange { get; set; }
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ using Managing.Common;
|
||||
using Managing.Domain.Bots;
|
||||
using Managing.Domain.Candles;
|
||||
using Managing.Domain.Indicators;
|
||||
using Managing.Domain.Shared.Helpers;
|
||||
|
||||
namespace Managing.Application.Abstractions.Grains;
|
||||
|
||||
@@ -17,8 +18,11 @@ public interface IScenarioRunnerGrain : IGrainWithGuidKey
|
||||
/// <param name="config">The trading bot configuration</param>
|
||||
/// <param name="previousSignals">Previous signals to consider</param>
|
||||
/// <param name="tradingExchange">Trading Exchange</param>
|
||||
/// <param name="lastCandle">The last candle</param>
|
||||
/// <param name="indicatorComboConfig">Optional indicator combo configuration (for user settings)</param>
|
||||
/// <returns>The generated signal or null if no signal</returns>
|
||||
Task<LightSignal> GetSignals(TradingBotConfig config, Dictionary<string, LightSignal> previousSignals,
|
||||
Enums.TradingExchanges tradingExchange,
|
||||
Candle lastCandle);
|
||||
Candle lastCandle,
|
||||
IndicatorComboConfig indicatorComboConfig = null);
|
||||
}
|
||||
@@ -714,7 +714,11 @@ public class FuturesBot : TradingBotBase
|
||||
await ServiceScopeHelpers.WithScopedService<IGrainFactory>(_scopeFactory, async grainFactory =>
|
||||
{
|
||||
var scenarioRunnerGrain = grainFactory.GetGrain<IScenarioRunnerGrain>(Guid.NewGuid());
|
||||
var signal = await scenarioRunnerGrain.GetSignals(Config, Signals, Account.Exchange, LastCandle);
|
||||
|
||||
// Create indicator combo config from user settings
|
||||
var indicatorComboConfig = TradingBox.CreateConfigFromUserSettings(Account.User);
|
||||
|
||||
var signal = await scenarioRunnerGrain.GetSignals(Config, Signals, Account.Exchange, LastCandle, indicatorComboConfig);
|
||||
if (signal == null) return;
|
||||
await AddSignal(signal);
|
||||
});
|
||||
|
||||
@@ -313,6 +313,10 @@ public class AgentGrain : Grain, IAgentGrain
|
||||
|
||||
public async Task<BalanceCheckResult> CheckAndEnsureEthBalanceAsync(Guid requestingBotId, string accountName)
|
||||
{
|
||||
// Get user settings
|
||||
var userId = (int)this.GetPrimaryKeyLong();
|
||||
var user = await _userService.GetUserByIdAsync(userId);
|
||||
|
||||
// Check if a swap is already in progress
|
||||
if (_state.State.IsSwapInProgress)
|
||||
{
|
||||
@@ -358,6 +362,15 @@ public class AgentGrain : Grain, IAgentGrain
|
||||
};
|
||||
}
|
||||
|
||||
// Check low ETH amount alert threshold
|
||||
var lowEthAlertThreshold = user.LowEthAmountAlert ?? Constants.GMX.Config.MinimumTradeEthBalanceUsd;
|
||||
if (balanceData.EthValueInUsd < lowEthAlertThreshold)
|
||||
{
|
||||
_logger.LogWarning(
|
||||
"ETH balance below alert threshold for user {UserId} - ETH: {EthValue:F2} USD (threshold: {Threshold:F2} USD)",
|
||||
userId, balanceData.EthValueInUsd, lowEthAlertThreshold);
|
||||
}
|
||||
|
||||
_logger.LogInformation(
|
||||
"Agent {UserId} balance check - ETH: {EthValue:F2} USD, USDC: {UsdcValue:F2} USD (cached: {IsCached})",
|
||||
this.GetPrimaryKeyLong(), balanceData.EthValueInUsd, balanceData.UsdcValue,
|
||||
@@ -402,18 +415,34 @@ public class AgentGrain : Grain, IAgentGrain
|
||||
};
|
||||
}
|
||||
|
||||
// Check if we have enough USDC for swap (need at least 5 USD for swap)
|
||||
if (balanceData.UsdcValue <
|
||||
(Constants.GMX.Config.MinimumPositionAmount + (decimal)Constants.GMX.Config.AutoSwapAmount))
|
||||
// Check if autoswap is enabled for this user
|
||||
if (!user.EnableAutoswap)
|
||||
{
|
||||
_logger.LogInformation("Autoswap is disabled for user {UserId}, skipping swap",
|
||||
userId);
|
||||
return new BalanceCheckResult
|
||||
{
|
||||
IsSuccessful = false,
|
||||
FailureReason = BalanceCheckFailureReason.None,
|
||||
Message = "Autoswap is disabled for this user",
|
||||
ShouldStopBot = false
|
||||
};
|
||||
}
|
||||
|
||||
// Get autoswap amount from user settings or use default
|
||||
var autoswapAmount = user.AutoswapAmount ?? (decimal)Constants.GMX.Config.AutoSwapAmount;
|
||||
|
||||
// Check if we have enough USDC for swap
|
||||
if (balanceData.UsdcValue < (Constants.GMX.Config.MinimumPositionAmount + autoswapAmount))
|
||||
{
|
||||
_logger.LogWarning(
|
||||
"Insufficient USDC balance for swap - ETH: {EthValue:F2} USD, USDC: {UsdcValue:F2} USD (need {AutoSwapAmount} USD for swap)",
|
||||
balanceData.EthValueInUsd, balanceData.UsdcValue, Constants.GMX.Config.AutoSwapAmount);
|
||||
balanceData.EthValueInUsd, balanceData.UsdcValue, autoswapAmount);
|
||||
return new BalanceCheckResult
|
||||
{
|
||||
IsSuccessful = false,
|
||||
FailureReason = BalanceCheckFailureReason.InsufficientUsdcForSwap,
|
||||
Message = $"Insufficient USDC balance for swap (need {Constants.GMX.Config.AutoSwapAmount} USD)",
|
||||
Message = $"Insufficient USDC balance for swap (need {autoswapAmount} USD)",
|
||||
ShouldStopBot = true
|
||||
};
|
||||
}
|
||||
@@ -440,22 +469,18 @@ public class AgentGrain : Grain, IAgentGrain
|
||||
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Initiating USDC to ETH swap for agent {UserId} - swapping 5 USDC",
|
||||
this.GetPrimaryKeyLong());
|
||||
_logger.LogInformation("Initiating USDC to ETH swap for agent {UserId} - swapping {Amount} USDC",
|
||||
this.GetPrimaryKeyLong(), autoswapAmount);
|
||||
|
||||
// Get user for the swap
|
||||
var userId = (int)this.GetPrimaryKeyLong();
|
||||
var user = await _userService.GetUserByIdAsync(userId);
|
||||
|
||||
// Perform the swap
|
||||
// Perform the swap using user's autoswap amount
|
||||
var swapInfo = await _tradingService.SwapGmxTokensAsync(user, accountName,
|
||||
Ticker.USDC, Ticker.ETH, Constants.GMX.Config.AutoSwapAmount);
|
||||
Ticker.USDC, Ticker.ETH, (double)autoswapAmount);
|
||||
|
||||
if (swapInfo.Success)
|
||||
{
|
||||
_logger.LogInformation(
|
||||
"Successfully swapped 5 USDC to ETH for agent {UserId}, transaction hash: {Hash}",
|
||||
userId, swapInfo.Hash);
|
||||
"Successfully swapped {Amount} USDC to ETH for agent {UserId}, transaction hash: {Hash}",
|
||||
autoswapAmount, userId, swapInfo.Hash);
|
||||
|
||||
// Update last swap time and invalidate cache
|
||||
_state.State.LastSwapTime = DateTime.UtcNow;
|
||||
|
||||
@@ -860,7 +860,11 @@ public class SpotBot : TradingBotBase
|
||||
await ServiceScopeHelpers.WithScopedService<IGrainFactory>(_scopeFactory, async grainFactory =>
|
||||
{
|
||||
var scenarioRunnerGrain = grainFactory.GetGrain<IScenarioRunnerGrain>(Guid.NewGuid());
|
||||
var signal = await scenarioRunnerGrain.GetSignals(Config, Signals, Account.Exchange, LastCandle);
|
||||
|
||||
// Create indicator combo config from user settings
|
||||
var indicatorComboConfig = TradingBox.CreateConfigFromUserSettings(Account.User);
|
||||
|
||||
var signal = await scenarioRunnerGrain.GetSignals(Config, Signals, Account.Exchange, LastCandle, indicatorComboConfig);
|
||||
if (signal == null) return;
|
||||
await AddSignal(signal);
|
||||
});
|
||||
|
||||
@@ -56,7 +56,7 @@ public class ScenarioRunnerGrain : Grain, IScenarioRunnerGrain
|
||||
}
|
||||
|
||||
public async Task<LightSignal> GetSignals(TradingBotConfig config, Dictionary<string, LightSignal> previousSignals,
|
||||
TradingExchanges tradingExchanges, Candle candle)
|
||||
TradingExchanges tradingExchanges, Candle candle, IndicatorComboConfig indicatorComboConfig = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -84,11 +84,16 @@ public class ScenarioRunnerGrain : Grain, IScenarioRunnerGrain
|
||||
|
||||
_logger.LogInformation($"Fetched {candlesList.Count} candles for {config.Ticker} for {config.Name}");
|
||||
|
||||
// Use provided config or default
|
||||
var comboConfig = indicatorComboConfig ?? new IndicatorComboConfig();
|
||||
|
||||
var signal = TradingBox.GetSignal(
|
||||
candlesList,
|
||||
config.Scenario,
|
||||
previousSignals,
|
||||
config.Scenario?.LookbackPeriod ?? 1);
|
||||
comboConfig,
|
||||
config.Scenario?.LookbackPeriod ?? 1,
|
||||
null);
|
||||
|
||||
if (signal != null && signal.Date > candle.Date)
|
||||
{
|
||||
|
||||
@@ -365,6 +365,18 @@ public class UserService : IUserService
|
||||
if (settings.MinimumConfidence.HasValue)
|
||||
user.MinimumConfidence = settings.MinimumConfidence.Value;
|
||||
|
||||
if (settings.TrendStrongAgreementThreshold.HasValue)
|
||||
user.TrendStrongAgreementThreshold = settings.TrendStrongAgreementThreshold.Value;
|
||||
|
||||
if (settings.SignalAgreementThreshold.HasValue)
|
||||
user.SignalAgreementThreshold = settings.SignalAgreementThreshold.Value;
|
||||
|
||||
if (settings.AllowSignalTrendOverride.HasValue)
|
||||
user.AllowSignalTrendOverride = settings.AllowSignalTrendOverride.Value;
|
||||
|
||||
if (settings.DefaultExchange.HasValue)
|
||||
user.DefaultExchange = settings.DefaultExchange.Value;
|
||||
|
||||
await _userRepository.SaveOrUpdateUserAsync(user);
|
||||
return user;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ using Managing.Domain.Statistics;
|
||||
using Managing.Domain.Strategies;
|
||||
using Managing.Domain.Strategies.Base;
|
||||
using Managing.Domain.Trades;
|
||||
using Managing.Domain.Users;
|
||||
using Orleans;
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
namespace Managing.Domain.Shared.Helpers;
|
||||
@@ -16,45 +18,72 @@ namespace Managing.Domain.Shared.Helpers;
|
||||
/// <summary>
|
||||
/// Configuration for strategy combination logic
|
||||
/// </summary>
|
||||
[GenerateSerializer]
|
||||
public class IndicatorComboConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// Minimum percentage of trend strategies that must agree for strong trend (default: 66%)
|
||||
/// </summary>
|
||||
[Id(0)]
|
||||
public decimal TrendStrongAgreementThreshold { get; set; } = 0.66m;
|
||||
|
||||
/// <summary>
|
||||
/// Minimum percentage of signal strategies that must agree (default: 50%)
|
||||
/// </summary>
|
||||
[Id(1)]
|
||||
public decimal SignalAgreementThreshold { get; set; } = 0.5m;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to allow signal strategies to override conflicting trends (default: true)
|
||||
/// This is useful for trend reversal signals
|
||||
/// </summary>
|
||||
[Id(2)]
|
||||
public bool AllowSignalTrendOverride { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Minimum confidence level to return a signal (default: Low)
|
||||
/// </summary>
|
||||
[Id(3)]
|
||||
public Confidence MinimumConfidence { get; set; } = Confidence.Low;
|
||||
|
||||
/// <summary>
|
||||
/// Minimum confidence level required from context strategies (default: Medium)
|
||||
/// Context strategies evaluate market conditions - higher requirements mean more conservative trading
|
||||
/// </summary>
|
||||
[Id(4)]
|
||||
public Confidence MinimumContextConfidence { get; set; } = Confidence.Medium;
|
||||
|
||||
/// <summary>
|
||||
/// Default exchange to use when signals don't specify one
|
||||
/// Default exchange to use when signals don't specify one (defaults to GMX)
|
||||
/// </summary>
|
||||
public TradingExchanges DefaultExchange { get; set; } = TradingExchanges.Binance;
|
||||
[Id(5)]
|
||||
public TradingExchanges DefaultExchange { get; set; } = TradingExchanges.GmxV2;
|
||||
}
|
||||
|
||||
public static class TradingBox
|
||||
{
|
||||
private static readonly IndicatorComboConfig _defaultConfig = new();
|
||||
|
||||
/// <summary>
|
||||
/// Creates an IndicatorComboConfig from user settings, using defaults for any null values
|
||||
/// </summary>
|
||||
/// <param name="user">The user with settings to apply</param>
|
||||
/// <returns>IndicatorComboConfig with user settings applied</returns>
|
||||
public static IndicatorComboConfig CreateConfigFromUserSettings(User user)
|
||||
{
|
||||
var config = new IndicatorComboConfig();
|
||||
|
||||
// Apply user's indicator combo settings, using defaults if not set
|
||||
config.MinimumContextConfidence = user.MinimumConfidence ?? Confidence.Medium;
|
||||
config.TrendStrongAgreementThreshold = user.TrendStrongAgreementThreshold ?? 0.66m;
|
||||
config.SignalAgreementThreshold = user.SignalAgreementThreshold ?? 0.5m;
|
||||
config.AllowSignalTrendOverride = user.AllowSignalTrendOverride ?? true;
|
||||
// DefaultExchange defaults to GMX if not set
|
||||
config.DefaultExchange = user.DefaultExchange ?? TradingExchanges.GmxV2;
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
public static LightSignal GetSignal(IReadOnlyList<Candle> newCandles, LightScenario scenario,
|
||||
Dictionary<string, LightSignal> previousSignal, int? loopbackPeriod = 1)
|
||||
{
|
||||
|
||||
@@ -25,12 +25,18 @@ public class User
|
||||
|
||||
[Id(8)] public DateTimeOffset? LastConnectionDate { get; set; }
|
||||
|
||||
// User Settings
|
||||
// User Settings - Trading Configuration
|
||||
[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;
|
||||
|
||||
// User Settings - Indicator Combo Configuration
|
||||
[Id(15)] public Confidence? MinimumConfidence { get; set; }
|
||||
[Id(16)] public decimal? TrendStrongAgreementThreshold { get; set; }
|
||||
[Id(17)] public decimal? SignalAgreementThreshold { get; set; }
|
||||
[Id(18)] public bool? AllowSignalTrendOverride { get; set; }
|
||||
[Id(19)] public TradingExchanges? DefaultExchange { get; set; }
|
||||
}
|
||||
@@ -14,7 +14,8 @@ namespace Managing.Infrastructure.Databases.Migrations
|
||||
name: "AutoswapAmount",
|
||||
table: "Users",
|
||||
type: "numeric(18,8)",
|
||||
nullable: true);
|
||||
nullable: true,
|
||||
defaultValue: 3m);
|
||||
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "EnableAutoswap",
|
||||
@@ -34,25 +35,29 @@ namespace Managing.Infrastructure.Databases.Migrations
|
||||
name: "LowEthAmountAlert",
|
||||
table: "Users",
|
||||
type: "numeric(18,8)",
|
||||
nullable: true);
|
||||
nullable: true,
|
||||
defaultValue: 1.5m);
|
||||
|
||||
migrationBuilder.AddColumn<decimal>(
|
||||
name: "MaxTxnGasFeePerPosition",
|
||||
table: "Users",
|
||||
type: "numeric(18,8)",
|
||||
nullable: true);
|
||||
nullable: true,
|
||||
defaultValue: 1.5m);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "MaxWaitingTimeForPositionToGetFilledSeconds",
|
||||
table: "Users",
|
||||
type: "integer",
|
||||
nullable: true);
|
||||
nullable: true,
|
||||
defaultValue: 600);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "MinimumConfidence",
|
||||
table: "Users",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
nullable: true,
|
||||
defaultValue: "Medium");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
1773
src/Managing.Infrastructure.Database/Migrations/20251229225934_SetUserSettingsDefaults.Designer.cs
generated
Normal file
1773
src/Managing.Infrastructure.Database/Migrations/20251229225934_SetUserSettingsDefaults.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,116 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Managing.Infrastructure.Databases.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class SetUserSettingsDefaults : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
// Set default values for existing NULL values
|
||||
migrationBuilder.Sql(@"
|
||||
UPDATE ""Users""
|
||||
SET ""LowEthAmountAlert"" = 1.5
|
||||
WHERE ""LowEthAmountAlert"" IS NULL;
|
||||
");
|
||||
|
||||
migrationBuilder.Sql(@"
|
||||
UPDATE ""Users""
|
||||
SET ""AutoswapAmount"" = 3
|
||||
WHERE ""AutoswapAmount"" IS NULL;
|
||||
");
|
||||
|
||||
migrationBuilder.Sql(@"
|
||||
UPDATE ""Users""
|
||||
SET ""MaxWaitingTimeForPositionToGetFilledSeconds"" = 600
|
||||
WHERE ""MaxWaitingTimeForPositionToGetFilledSeconds"" IS NULL;
|
||||
");
|
||||
|
||||
migrationBuilder.Sql(@"
|
||||
UPDATE ""Users""
|
||||
SET ""MaxTxnGasFeePerPosition"" = 1.5
|
||||
WHERE ""MaxTxnGasFeePerPosition"" IS NULL;
|
||||
");
|
||||
|
||||
migrationBuilder.Sql(@"
|
||||
UPDATE ""Users""
|
||||
SET ""MinimumConfidence"" = 'Medium'
|
||||
WHERE ""MinimumConfidence"" IS NULL;
|
||||
");
|
||||
|
||||
// Alter columns to set default values for future inserts
|
||||
migrationBuilder.AlterColumn<decimal>(
|
||||
name: "LowEthAmountAlert",
|
||||
table: "Users",
|
||||
type: "numeric(18,8)",
|
||||
nullable: true,
|
||||
defaultValue: 1.5m);
|
||||
|
||||
migrationBuilder.AlterColumn<decimal>(
|
||||
name: "AutoswapAmount",
|
||||
table: "Users",
|
||||
type: "numeric(18,8)",
|
||||
nullable: true,
|
||||
defaultValue: 3m);
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "MaxWaitingTimeForPositionToGetFilledSeconds",
|
||||
table: "Users",
|
||||
type: "integer",
|
||||
nullable: true,
|
||||
defaultValue: 600);
|
||||
|
||||
migrationBuilder.AlterColumn<decimal>(
|
||||
name: "MaxTxnGasFeePerPosition",
|
||||
table: "Users",
|
||||
type: "numeric(18,8)",
|
||||
nullable: true,
|
||||
defaultValue: 1.5m);
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "MinimumConfidence",
|
||||
table: "Users",
|
||||
type: "text",
|
||||
nullable: true,
|
||||
defaultValue: "Medium");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
// Remove default values (revert to nullable without defaults)
|
||||
migrationBuilder.AlterColumn<decimal>(
|
||||
name: "LowEthAmountAlert",
|
||||
table: "Users",
|
||||
type: "numeric(18,8)",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<decimal>(
|
||||
name: "AutoswapAmount",
|
||||
table: "Users",
|
||||
type: "numeric(18,8)",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "MaxWaitingTimeForPositionToGetFilledSeconds",
|
||||
table: "Users",
|
||||
type: "integer",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<decimal>(
|
||||
name: "MaxTxnGasFeePerPosition",
|
||||
table: "Users",
|
||||
type: "numeric(18,8)",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "MinimumConfidence",
|
||||
table: "Users",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
1785
src/Managing.Infrastructure.Database/Migrations/20251229231215_AddIndicatorComboConfigSettings.Designer.cs
generated
Normal file
1785
src/Managing.Infrastructure.Database/Migrations/20251229231215_AddIndicatorComboConfigSettings.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,88 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Managing.Infrastructure.Databases.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddIndicatorComboConfigSettings : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
// Add columns with defaults
|
||||
migrationBuilder.AddColumn<decimal>(
|
||||
name: "TrendStrongAgreementThreshold",
|
||||
table: "Users",
|
||||
type: "numeric(5,4)",
|
||||
nullable: true,
|
||||
defaultValue: 0.66m);
|
||||
|
||||
migrationBuilder.AddColumn<decimal>(
|
||||
name: "SignalAgreementThreshold",
|
||||
table: "Users",
|
||||
type: "numeric(5,4)",
|
||||
nullable: true,
|
||||
defaultValue: 0.5m);
|
||||
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "AllowSignalTrendOverride",
|
||||
table: "Users",
|
||||
type: "boolean",
|
||||
nullable: true,
|
||||
defaultValue: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "DefaultExchange",
|
||||
table: "Users",
|
||||
type: "text",
|
||||
nullable: true,
|
||||
defaultValue: "GmxV2");
|
||||
|
||||
// Update existing NULL values to defaults
|
||||
migrationBuilder.Sql(@"
|
||||
UPDATE ""Users""
|
||||
SET ""TrendStrongAgreementThreshold"" = 0.66
|
||||
WHERE ""TrendStrongAgreementThreshold"" IS NULL;
|
||||
");
|
||||
|
||||
migrationBuilder.Sql(@"
|
||||
UPDATE ""Users""
|
||||
SET ""SignalAgreementThreshold"" = 0.5
|
||||
WHERE ""SignalAgreementThreshold"" IS NULL;
|
||||
");
|
||||
|
||||
migrationBuilder.Sql(@"
|
||||
UPDATE ""Users""
|
||||
SET ""AllowSignalTrendOverride"" = true
|
||||
WHERE ""AllowSignalTrendOverride"" IS NULL;
|
||||
");
|
||||
|
||||
migrationBuilder.Sql(@"
|
||||
UPDATE ""Users""
|
||||
SET ""DefaultExchange"" = 'GmxV2'
|
||||
WHERE ""DefaultExchange"" IS NULL;
|
||||
");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "TrendStrongAgreementThreshold",
|
||||
table: "Users");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "SignalAgreementThreshold",
|
||||
table: "Users");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "AllowSignalTrendOverride",
|
||||
table: "Users");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "DefaultExchange",
|
||||
table: "Users");
|
||||
}
|
||||
}
|
||||
}
|
||||
1785
src/Managing.Infrastructure.Database/Migrations/20251229232332_UpdateDefaultExchangeToGmxV2.Designer.cs
generated
Normal file
1785
src/Managing.Infrastructure.Database/Migrations/20251229232332_UpdateDefaultExchangeToGmxV2.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,47 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Managing.Infrastructure.Databases.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class UpdateDefaultExchangeToGmxV2 : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
// Update existing Binance values to GmxV2
|
||||
migrationBuilder.Sql(@"
|
||||
UPDATE ""Users""
|
||||
SET ""DefaultExchange"" = 'GmxV2'
|
||||
WHERE ""DefaultExchange"" = 'Binance' OR ""DefaultExchange"" IS NULL;
|
||||
");
|
||||
|
||||
// Update the default value for future inserts
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "DefaultExchange",
|
||||
table: "Users",
|
||||
type: "text",
|
||||
nullable: true,
|
||||
defaultValue: "GmxV2");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
// Revert to Binance
|
||||
migrationBuilder.Sql(@"
|
||||
UPDATE ""Users""
|
||||
SET ""DefaultExchange"" = 'Binance'
|
||||
WHERE ""DefaultExchange"" = 'GmxV2';
|
||||
");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "DefaultExchange",
|
||||
table: "Users",
|
||||
type: "text",
|
||||
nullable: true,
|
||||
defaultValue: "Binance");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1425,6 +1425,9 @@ namespace Managing.Infrastructure.Databases.Migrations
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)");
|
||||
|
||||
b.Property<bool?>("AllowSignalTrendOverride")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<decimal?>("AutoswapAmount")
|
||||
.HasColumnType("decimal(18,8)");
|
||||
|
||||
@@ -1432,6 +1435,9 @@ namespace Managing.Infrastructure.Databases.Migrations
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("character varying(500)");
|
||||
|
||||
b.Property<string>("DefaultExchange")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<bool>("EnableAutoswap")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
@@ -1464,10 +1470,16 @@ namespace Managing.Infrastructure.Databases.Migrations
|
||||
b.Property<string>("OwnerWalletAddress")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<decimal?>("SignalAgreementThreshold")
|
||||
.HasColumnType("decimal(5,4)");
|
||||
|
||||
b.Property<string>("TelegramChannel")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)");
|
||||
|
||||
b.Property<decimal?>("TrendStrongAgreementThreshold")
|
||||
.HasColumnType("decimal(5,4)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AgentName");
|
||||
|
||||
@@ -19,14 +19,20 @@ public class UserEntity
|
||||
public DateTimeOffset? LastConnectionDate { get; set; }
|
||||
public bool IsAdmin { get; set; }
|
||||
|
||||
// User Settings
|
||||
[Column(TypeName = "decimal(18,8)")] public decimal? LowEthAmountAlert { get; set; }
|
||||
// User Settings - Trading Configuration
|
||||
[Column(TypeName = "decimal(18,8)")] public decimal? LowEthAmountAlert { get; set; } = 1.5m; // Default: MinimumTradeEthBalanceUsd
|
||||
public bool EnableAutoswap { get; set; } = false;
|
||||
[Column(TypeName = "decimal(18,8)")] public decimal? AutoswapAmount { get; set; }
|
||||
public int? MaxWaitingTimeForPositionToGetFilledSeconds { get; set; }
|
||||
[Column(TypeName = "decimal(18,8)")] public decimal? MaxTxnGasFeePerPosition { get; set; }
|
||||
[Column(TypeName = "decimal(18,8)")] public decimal? AutoswapAmount { get; set; } = 3m; // Default: AutoSwapAmount
|
||||
public int? MaxWaitingTimeForPositionToGetFilledSeconds { get; set; } = 600; // Default: 10 minutes (600 seconds)
|
||||
[Column(TypeName = "decimal(18,8)")] public decimal? MaxTxnGasFeePerPosition { get; set; } = 1.5m; // Default: MaximumGasFeeUsd
|
||||
public bool IsGmxEnabled { get; set; } = false;
|
||||
public Confidence? MinimumConfidence { get; set; }
|
||||
|
||||
// User Settings - Indicator Combo Configuration
|
||||
public Confidence? MinimumConfidence { get; set; } = Confidence.Medium; // Default: Medium confidence for context indicators
|
||||
[Column(TypeName = "decimal(5,4)")] public decimal? TrendStrongAgreementThreshold { get; set; } = 0.66m; // Default: 66% agreement required
|
||||
[Column(TypeName = "decimal(5,4)")] public decimal? SignalAgreementThreshold { get; set; } = 0.5m; // Default: 50% agreement required
|
||||
public bool? AllowSignalTrendOverride { get; set; } = true; // Default: Allow signal strategies to override trends
|
||||
public TradingExchanges? DefaultExchange { get; set; } = TradingExchanges.GmxV2; // Default exchange
|
||||
|
||||
// Navigation properties
|
||||
public virtual ICollection<AccountEntity> Accounts { get; set; } = new List<AccountEntity>();
|
||||
|
||||
@@ -103,6 +103,8 @@ public class ManagingDbContext : DbContext
|
||||
entity.Property(e => e.TelegramChannel).HasMaxLength(255);
|
||||
entity.Property(e => e.MinimumConfidence)
|
||||
.HasConversion<string>(); // Store enum as string
|
||||
entity.Property(e => e.DefaultExchange)
|
||||
.HasConversion<string>(); // Store enum as string
|
||||
|
||||
// Create indexes for performance
|
||||
entity.HasIndex(e => e.Name).IsUnique();
|
||||
|
||||
@@ -141,6 +141,10 @@ public static class PostgreSqlMappers
|
||||
MaxTxnGasFeePerPosition = entity.MaxTxnGasFeePerPosition,
|
||||
IsGmxEnabled = entity.IsGmxEnabled,
|
||||
MinimumConfidence = entity.MinimumConfidence,
|
||||
TrendStrongAgreementThreshold = entity.TrendStrongAgreementThreshold,
|
||||
SignalAgreementThreshold = entity.SignalAgreementThreshold,
|
||||
AllowSignalTrendOverride = entity.AllowSignalTrendOverride,
|
||||
DefaultExchange = entity.DefaultExchange,
|
||||
Accounts = entity.Accounts?.Select(MapAccountWithoutUser).ToList() ?? new List<Account>()
|
||||
};
|
||||
}
|
||||
@@ -183,7 +187,11 @@ public static class PostgreSqlMappers
|
||||
MaxWaitingTimeForPositionToGetFilledSeconds = user.MaxWaitingTimeForPositionToGetFilledSeconds,
|
||||
MaxTxnGasFeePerPosition = user.MaxTxnGasFeePerPosition,
|
||||
IsGmxEnabled = user.IsGmxEnabled,
|
||||
MinimumConfidence = user.MinimumConfidence
|
||||
MinimumConfidence = user.MinimumConfidence,
|
||||
TrendStrongAgreementThreshold = user.TrendStrongAgreementThreshold,
|
||||
SignalAgreementThreshold = user.SignalAgreementThreshold,
|
||||
AllowSignalTrendOverride = user.AllowSignalTrendOverride,
|
||||
DefaultExchange = user.DefaultExchange
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -264,6 +264,10 @@ public class PostgreSqlUserRepository : BaseRepositoryWithLogging, IUserReposito
|
||||
existingUser.MaxTxnGasFeePerPosition = user.MaxTxnGasFeePerPosition;
|
||||
existingUser.IsGmxEnabled = user.IsGmxEnabled;
|
||||
existingUser.MinimumConfidence = user.MinimumConfidence;
|
||||
existingUser.TrendStrongAgreementThreshold = user.TrendStrongAgreementThreshold;
|
||||
existingUser.SignalAgreementThreshold = user.SignalAgreementThreshold;
|
||||
existingUser.AllowSignalTrendOverride = user.AllowSignalTrendOverride;
|
||||
existingUser.DefaultExchange = user.DefaultExchange;
|
||||
|
||||
_context.Users.Update(existingUser);
|
||||
|
||||
|
||||
@@ -49,6 +49,24 @@ export interface User {
|
||||
ownerWalletAddress?: string | null;
|
||||
isAdmin?: boolean;
|
||||
lastConnectionDate?: Date | null;
|
||||
lowEthAmountAlert?: number | null;
|
||||
enableAutoswap?: boolean;
|
||||
autoswapAmount?: number | null;
|
||||
maxWaitingTimeForPositionToGetFilledSeconds?: number | null;
|
||||
maxTxnGasFeePerPosition?: number | null;
|
||||
isGmxEnabled?: boolean;
|
||||
minimumConfidence?: Confidence | null;
|
||||
trendStrongAgreementThreshold?: number | null;
|
||||
signalAgreementThreshold?: number | null;
|
||||
allowSignalTrendOverride?: boolean | null;
|
||||
defaultExchange?: TradingExchanges | null;
|
||||
}
|
||||
|
||||
export enum Confidence {
|
||||
Low = "Low",
|
||||
Medium = "Medium",
|
||||
High = "High",
|
||||
None = "None",
|
||||
}
|
||||
|
||||
export interface Balance {
|
||||
@@ -586,13 +604,6 @@ export enum SignalStatus {
|
||||
Expired = "Expired",
|
||||
}
|
||||
|
||||
export enum Confidence {
|
||||
Low = "Low",
|
||||
Medium = "Medium",
|
||||
High = "High",
|
||||
None = "None",
|
||||
}
|
||||
|
||||
export interface Candle {
|
||||
exchange: TradingExchanges;
|
||||
ticker: Ticker;
|
||||
@@ -1490,6 +1501,20 @@ export interface LoginRequest {
|
||||
ownerWalletAddress?: string | null;
|
||||
}
|
||||
|
||||
export interface UpdateUserSettingsRequest {
|
||||
lowEthAmountAlert?: number | null;
|
||||
enableAutoswap?: boolean | null;
|
||||
autoswapAmount?: number | null;
|
||||
maxWaitingTimeForPositionToGetFilledSeconds?: number | null;
|
||||
maxTxnGasFeePerPosition?: number | null;
|
||||
isGmxEnabled?: boolean | null;
|
||||
minimumConfidence?: Confidence | null;
|
||||
trendStrongAgreementThreshold?: number | null;
|
||||
signalAgreementThreshold?: number | null;
|
||||
allowSignalTrendOverride?: boolean | null;
|
||||
defaultExchange?: TradingExchanges | null;
|
||||
}
|
||||
|
||||
export interface PaginatedWhitelistAccountsResponse {
|
||||
accounts?: WhitelistAccount[] | null;
|
||||
totalCount?: number;
|
||||
|
||||
@@ -4414,6 +4414,45 @@ export class UserClient extends AuthorizedApiBase {
|
||||
}
|
||||
return Promise.resolve<string>(null as any);
|
||||
}
|
||||
|
||||
user_UpdateUserSettings(settings: UpdateUserSettingsRequest): Promise<User> {
|
||||
let url_ = this.baseUrl + "/User/settings";
|
||||
url_ = url_.replace(/[?&]$/, "");
|
||||
|
||||
const content_ = JSON.stringify(settings);
|
||||
|
||||
let options_: RequestInit = {
|
||||
body: content_,
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Accept": "application/json"
|
||||
}
|
||||
};
|
||||
|
||||
return this.transformOptions(options_).then(transformedOptions_ => {
|
||||
return this.http.fetch(url_, transformedOptions_);
|
||||
}).then((_response: Response) => {
|
||||
return this.processUser_UpdateUserSettings(_response);
|
||||
});
|
||||
}
|
||||
|
||||
protected processUser_UpdateUserSettings(response: Response): Promise<User> {
|
||||
const status = response.status;
|
||||
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||
if (status === 200) {
|
||||
return response.text().then((_responseText) => {
|
||||
let result200: any = null;
|
||||
result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as User;
|
||||
return result200;
|
||||
});
|
||||
} else if (status !== 200 && status !== 204) {
|
||||
return response.text().then((_responseText) => {
|
||||
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||
});
|
||||
}
|
||||
return Promise.resolve<User>(null as any);
|
||||
}
|
||||
}
|
||||
|
||||
export class WhitelistClient extends AuthorizedApiBase {
|
||||
@@ -4591,6 +4630,24 @@ export interface User {
|
||||
ownerWalletAddress?: string | null;
|
||||
isAdmin?: boolean;
|
||||
lastConnectionDate?: Date | null;
|
||||
lowEthAmountAlert?: number | null;
|
||||
enableAutoswap?: boolean;
|
||||
autoswapAmount?: number | null;
|
||||
maxWaitingTimeForPositionToGetFilledSeconds?: number | null;
|
||||
maxTxnGasFeePerPosition?: number | null;
|
||||
isGmxEnabled?: boolean;
|
||||
minimumConfidence?: Confidence | null;
|
||||
trendStrongAgreementThreshold?: number | null;
|
||||
signalAgreementThreshold?: number | null;
|
||||
allowSignalTrendOverride?: boolean | null;
|
||||
defaultExchange?: TradingExchanges | null;
|
||||
}
|
||||
|
||||
export enum Confidence {
|
||||
Low = "Low",
|
||||
Medium = "Medium",
|
||||
High = "High",
|
||||
None = "None",
|
||||
}
|
||||
|
||||
export interface Balance {
|
||||
@@ -5128,13 +5185,6 @@ export enum SignalStatus {
|
||||
Expired = "Expired",
|
||||
}
|
||||
|
||||
export enum Confidence {
|
||||
Low = "Low",
|
||||
Medium = "Medium",
|
||||
High = "High",
|
||||
None = "None",
|
||||
}
|
||||
|
||||
export interface Candle {
|
||||
exchange: TradingExchanges;
|
||||
ticker: Ticker;
|
||||
@@ -6032,6 +6082,20 @@ export interface LoginRequest {
|
||||
ownerWalletAddress?: string | null;
|
||||
}
|
||||
|
||||
export interface UpdateUserSettingsRequest {
|
||||
lowEthAmountAlert?: number | null;
|
||||
enableAutoswap?: boolean | null;
|
||||
autoswapAmount?: number | null;
|
||||
maxWaitingTimeForPositionToGetFilledSeconds?: number | null;
|
||||
maxTxnGasFeePerPosition?: number | null;
|
||||
isGmxEnabled?: boolean | null;
|
||||
minimumConfidence?: Confidence | null;
|
||||
trendStrongAgreementThreshold?: number | null;
|
||||
signalAgreementThreshold?: number | null;
|
||||
allowSignalTrendOverride?: boolean | null;
|
||||
defaultExchange?: TradingExchanges | null;
|
||||
}
|
||||
|
||||
export interface PaginatedWhitelistAccountsResponse {
|
||||
accounts?: WhitelistAccount[] | null;
|
||||
totalCount?: number;
|
||||
|
||||
@@ -49,6 +49,24 @@ export interface User {
|
||||
ownerWalletAddress?: string | null;
|
||||
isAdmin?: boolean;
|
||||
lastConnectionDate?: Date | null;
|
||||
lowEthAmountAlert?: number | null;
|
||||
enableAutoswap?: boolean;
|
||||
autoswapAmount?: number | null;
|
||||
maxWaitingTimeForPositionToGetFilledSeconds?: number | null;
|
||||
maxTxnGasFeePerPosition?: number | null;
|
||||
isGmxEnabled?: boolean;
|
||||
minimumConfidence?: Confidence | null;
|
||||
trendStrongAgreementThreshold?: number | null;
|
||||
signalAgreementThreshold?: number | null;
|
||||
allowSignalTrendOverride?: boolean | null;
|
||||
defaultExchange?: TradingExchanges | null;
|
||||
}
|
||||
|
||||
export enum Confidence {
|
||||
Low = "Low",
|
||||
Medium = "Medium",
|
||||
High = "High",
|
||||
None = "None",
|
||||
}
|
||||
|
||||
export interface Balance {
|
||||
@@ -586,13 +604,6 @@ export enum SignalStatus {
|
||||
Expired = "Expired",
|
||||
}
|
||||
|
||||
export enum Confidence {
|
||||
Low = "Low",
|
||||
Medium = "Medium",
|
||||
High = "High",
|
||||
None = "None",
|
||||
}
|
||||
|
||||
export interface Candle {
|
||||
exchange: TradingExchanges;
|
||||
ticker: Ticker;
|
||||
@@ -1490,6 +1501,20 @@ export interface LoginRequest {
|
||||
ownerWalletAddress?: string | null;
|
||||
}
|
||||
|
||||
export interface UpdateUserSettingsRequest {
|
||||
lowEthAmountAlert?: number | null;
|
||||
enableAutoswap?: boolean | null;
|
||||
autoswapAmount?: number | null;
|
||||
maxWaitingTimeForPositionToGetFilledSeconds?: number | null;
|
||||
maxTxnGasFeePerPosition?: number | null;
|
||||
isGmxEnabled?: boolean | null;
|
||||
minimumConfidence?: Confidence | null;
|
||||
trendStrongAgreementThreshold?: number | null;
|
||||
signalAgreementThreshold?: number | null;
|
||||
allowSignalTrendOverride?: boolean | null;
|
||||
defaultExchange?: TradingExchanges | null;
|
||||
}
|
||||
|
||||
export interface PaginatedWhitelistAccountsResponse {
|
||||
accounts?: WhitelistAccount[] | null;
|
||||
totalCount?: number;
|
||||
|
||||
Reference in New Issue
Block a user