Update pricing timing
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using Managing.Application.Abstractions;
|
||||
using Managing.Application.Abstractions.Grains;
|
||||
using Managing.Application.Abstractions.Services;
|
||||
using Managing.Application.Shared;
|
||||
using Managing.Common;
|
||||
using Managing.Core;
|
||||
using Managing.Domain.Accounts;
|
||||
@@ -120,15 +121,15 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
|
||||
// Set startup time when bot actually starts running
|
||||
_state.State.StartupTime = DateTime.UtcNow;
|
||||
await _state.WriteStateAsync();
|
||||
|
||||
|
||||
// Start the in-memory timer and persistent reminder
|
||||
RegisterAndStartTimer();
|
||||
await RegisterReminder();
|
||||
|
||||
|
||||
// Update both database and registry status
|
||||
await SaveBotAsync(BotStatus.Running);
|
||||
await UpdateBotRegistryStatus(BotStatus.Running);
|
||||
|
||||
|
||||
_logger.LogInformation("LiveTradingBotGrain {GrainId} resumed successfully", this.GetPrimaryKey());
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -184,12 +185,14 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
|
||||
|
||||
if (_timer != null) return;
|
||||
|
||||
var botOptions = GrainHelpers.GetDynamicRandomizedTimerOptions(TimeSpan.FromMinutes(1), 20);
|
||||
|
||||
_timer = this.RegisterGrainTimer(
|
||||
async _ => await ExecuteBotCycle(),
|
||||
new GrainTimerCreationOptions
|
||||
{
|
||||
Period = TimeSpan.FromMinutes(1),
|
||||
DueTime = TimeSpan.FromMinutes(1),
|
||||
Period = botOptions.period,
|
||||
DueTime = botOptions.dueTime,
|
||||
KeepAlive = true
|
||||
});
|
||||
}
|
||||
@@ -294,21 +297,18 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
|
||||
}
|
||||
|
||||
// Check broker balance before running
|
||||
var balances = await ServiceScopeHelpers.WithScopedService<IExchangeService, List<Balance>>(_scopeFactory, async exchangeService =>
|
||||
{
|
||||
return await exchangeService.GetBalances(_tradingBot.Account, false);
|
||||
|
||||
});
|
||||
var balances = await ServiceScopeHelpers.WithScopedService<IExchangeService, List<Balance>>(_scopeFactory,
|
||||
async exchangeService => { return await exchangeService.GetBalances(_tradingBot.Account, false); });
|
||||
|
||||
var usdcBalance = balances.FirstOrDefault(b => b.TokenName == Ticker.USDC.ToString());
|
||||
var ethBalance = balances.FirstOrDefault(b => b.TokenName == Ticker.ETH.ToString());
|
||||
|
||||
|
||||
// Check USDC balance first
|
||||
if (usdcBalance?.Value < Constants.GMX.Config.MinimumPositionAmount)
|
||||
{
|
||||
await _tradingBot.LogWarning(
|
||||
$"USDC balance is below {Constants.GMX.Config.MinimumPositionAmount} USD (actual: {usdcBalance?.Value:F2}). Stopping bot {_tradingBot.Identifier}.");
|
||||
|
||||
|
||||
await StopAsync();
|
||||
return;
|
||||
}
|
||||
@@ -319,16 +319,19 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
|
||||
{
|
||||
await _tradingBot.LogWarning(
|
||||
$"ETH balance is below 2 USD (actual: {ethValueInUsd:F2}). Attempting to swap USDC to ETH.");
|
||||
|
||||
|
||||
// Check if we have enough USDC for the swap
|
||||
if (usdcBalance?.Value >= 5) // Need at least 5 USD for swap
|
||||
{
|
||||
try
|
||||
{
|
||||
var swapInfo = await ServiceScopeHelpers.WithScopedService<IAccountService, SwapInfos>(_scopeFactory, async accountService =>
|
||||
{
|
||||
return await accountService.SwapGmxTokensAsync(_state.State.User, _tradingBot.Account.Name, Ticker.USDC, Ticker.ETH, 5);
|
||||
});
|
||||
var swapInfo = await ServiceScopeHelpers.WithScopedService<IAccountService, SwapInfos>(
|
||||
_scopeFactory,
|
||||
async accountService =>
|
||||
{
|
||||
return await accountService.SwapGmxTokensAsync(_state.State.User,
|
||||
_tradingBot.Account.Name, Ticker.USDC, Ticker.ETH, 5);
|
||||
});
|
||||
|
||||
if (swapInfo.Success)
|
||||
{
|
||||
@@ -351,7 +354,7 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
|
||||
// Both USDC and ETH are low - stop the strategy
|
||||
await _tradingBot.LogWarning(
|
||||
$"Both USDC ({usdcBalance?.Value:F2}) and ETH ({ethValueInUsd:F2}) balances are low. Stopping bot {_tradingBot.Identifier}.");
|
||||
|
||||
|
||||
await StopAsync();
|
||||
return;
|
||||
}
|
||||
@@ -395,7 +398,7 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
|
||||
{
|
||||
_logger.LogInformation("LastCandle is null, loading latest candle data for manual position opening");
|
||||
await _tradingBot.LoadLastCandle();
|
||||
|
||||
|
||||
// Sync the loaded candle to grain state
|
||||
SyncStateFromBase();
|
||||
await _state.WriteStateAsync();
|
||||
@@ -480,7 +483,7 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
|
||||
// For non-running bots, just update the configuration
|
||||
_state.State.Config = newConfig;
|
||||
await _state.WriteStateAsync();
|
||||
|
||||
|
||||
var botRegistry = GrainFactory.GetGrain<ILiveBotRegistryGrain>(0);
|
||||
var status = await botRegistry.GetBotStatus(this.GetPrimaryKey());
|
||||
await SaveBotAsync(status);
|
||||
@@ -507,6 +510,7 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
|
||||
{
|
||||
throw new InvalidOperationException("Bot is not running - cannot get account information");
|
||||
}
|
||||
|
||||
return Task.FromResult(_tradingBot.Account);
|
||||
}
|
||||
|
||||
@@ -543,21 +547,21 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
|
||||
public async Task RestartAsync()
|
||||
{
|
||||
_logger.LogInformation("Restarting LiveTradingBotGrain {GrainId}", this.GetPrimaryKey());
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
await StopAsync();
|
||||
|
||||
|
||||
// Add a small delay to ensure stop operations complete
|
||||
await Task.Delay(100);
|
||||
|
||||
|
||||
await StartAsync();
|
||||
|
||||
|
||||
// Verify the restart was successful
|
||||
var botRegistry = GrainFactory.GetGrain<ILiveBotRegistryGrain>(0);
|
||||
var finalStatus = await botRegistry.GetBotStatus(this.GetPrimaryKey());
|
||||
|
||||
_logger.LogInformation("LiveTradingBotGrain {GrainId} restart completed with final status: {Status}",
|
||||
|
||||
_logger.LogInformation("LiveTradingBotGrain {GrainId} restart completed with final status: {Status}",
|
||||
this.GetPrimaryKey(), finalStatus);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -605,39 +609,42 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
|
||||
{
|
||||
const int maxRetries = 3;
|
||||
var botId = this.GetPrimaryKey();
|
||||
|
||||
|
||||
for (int attempt = 1; attempt <= maxRetries; attempt++)
|
||||
{
|
||||
try
|
||||
{
|
||||
var botRegistry = GrainFactory.GetGrain<ILiveBotRegistryGrain>(0);
|
||||
await botRegistry.UpdateBotStatus(botId, status);
|
||||
|
||||
|
||||
// Verify the update was successful
|
||||
var actualStatus = await botRegistry.GetBotStatus(botId);
|
||||
if (actualStatus == status)
|
||||
{
|
||||
_logger.LogDebug("Bot {BotId} status successfully updated to {Status} in BotRegistry (attempt {Attempt})",
|
||||
_logger.LogDebug(
|
||||
"Bot {BotId} status successfully updated to {Status} in BotRegistry (attempt {Attempt})",
|
||||
botId, status, attempt);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("Bot {BotId} status update verification failed. Expected: {Expected}, Actual: {Actual} (attempt {Attempt})",
|
||||
_logger.LogWarning(
|
||||
"Bot {BotId} status update verification failed. Expected: {Expected}, Actual: {Actual} (attempt {Attempt})",
|
||||
botId, status, actualStatus, attempt);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to update bot {BotId} status to {Status} in BotRegistry (attempt {Attempt})",
|
||||
_logger.LogError(ex,
|
||||
"Failed to update bot {BotId} status to {Status} in BotRegistry (attempt {Attempt})",
|
||||
botId, status, attempt);
|
||||
|
||||
|
||||
if (attempt == maxRetries)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Wait before retry
|
||||
if (attempt < maxRetries)
|
||||
{
|
||||
@@ -734,7 +741,8 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
|
||||
{
|
||||
_logger.LogDebug(
|
||||
"Successfully saved bot statistics for bot {BotId}: Wins={Wins}, Losses={Losses}, PnL={PnL}, ROI={ROI}%, Volume={Volume}, Fees={Fees}, Long={LongPositions}, Short={ShortPositions}",
|
||||
_state.State.Identifier, bot.TradeWins, bot.TradeLosses, bot.Pnl, bot.Roi, bot.Volume, bot.Fees, bot.LongPositionCount, bot.ShortPositionCount);
|
||||
_state.State.Identifier, bot.TradeWins, bot.TradeLosses, bot.Pnl, bot.Roi, bot.Volume, bot.Fees,
|
||||
bot.LongPositionCount, bot.ShortPositionCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -750,7 +758,8 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
|
||||
/// <summary>
|
||||
/// Notifies the user about swap operations via webhook/telegram
|
||||
/// </summary>
|
||||
private async Task NotifyUserAboutSwap(bool isSuccess, decimal amount, string? transactionHash, string? errorMessage = null)
|
||||
private async Task NotifyUserAboutSwap(bool isSuccess, decimal amount, string? transactionHash,
|
||||
string? errorMessage = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -769,10 +778,11 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
|
||||
$"⏰ **Time:** {DateTime.UtcNow:yyyy-MM-dd HH:mm:ss} UTC";
|
||||
|
||||
// Send notification via webhook service
|
||||
await ServiceScopeHelpers.WithScopedService<IWebhookService>(_scopeFactory, async webhookService =>
|
||||
{
|
||||
await webhookService.SendMessage(message, _state.State.User?.TelegramChannel);
|
||||
});
|
||||
await ServiceScopeHelpers.WithScopedService<IWebhookService>(_scopeFactory,
|
||||
async webhookService =>
|
||||
{
|
||||
await webhookService.SendMessage(message, _state.State.User?.TelegramChannel);
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user