Finish copy trading
This commit is contained in:
@@ -407,7 +407,8 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
|
||||
_copyTradingStreamHandle = await streamProvider.GetStream<Position>(streamId)
|
||||
.SubscribeAsync(OnCopyTradingPositionReceivedAsync);
|
||||
|
||||
_logger.LogInformation("LiveTradingBotGrain {GrainId} subscribed to copy trading stream for master bot {MasterBotId}",
|
||||
_logger.LogInformation(
|
||||
"LiveTradingBotGrain {GrainId} subscribed to copy trading stream for master bot {MasterBotId}",
|
||||
this.GetPrimaryKey(), _state.State.Config.MasterBotIdentifier.Value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -425,7 +426,8 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
|
||||
{
|
||||
await _copyTradingStreamHandle.UnsubscribeAsync();
|
||||
_copyTradingStreamHandle = null;
|
||||
_logger.LogInformation("LiveTradingBotGrain {GrainId} unsubscribed from copy trading stream", this.GetPrimaryKey());
|
||||
_logger.LogInformation("LiveTradingBotGrain {GrainId} unsubscribed from copy trading stream",
|
||||
this.GetPrimaryKey());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -438,7 +440,8 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
|
||||
{
|
||||
if (_tradingBot == null)
|
||||
{
|
||||
_logger.LogWarning("Received copy trading position {PositionId} but trading bot is not running for bot {GrainId}",
|
||||
_logger.LogWarning(
|
||||
"Received copy trading position {PositionId} but trading bot is not running for bot {GrainId}",
|
||||
masterPosition.Identifier, this.GetPrimaryKey());
|
||||
return;
|
||||
}
|
||||
@@ -511,41 +514,52 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
|
||||
// Check if copy trading authorization is still valid
|
||||
if (_state.State.Config.IsForCopyTrading && _state.State.Config.MasterBotIdentifier.HasValue)
|
||||
{
|
||||
try
|
||||
// Check if copy trading validation should be bypassed (for testing)
|
||||
var enableValidation = Environment.GetEnvironmentVariable("ENABLE_COPY_TRADING_VALIDATION")?
|
||||
.Equals("true", StringComparison.OrdinalIgnoreCase) ?? true;
|
||||
|
||||
if (enableValidation)
|
||||
{
|
||||
var ownedKeys = await _kaigenService.GetOwnedKeysAsync(_state.State.User);
|
||||
|
||||
var masterStrategy = await ServiceScopeHelpers.WithScopedService<IBotService, Bot>(
|
||||
_scopeFactory,
|
||||
async botService => await botService.GetBotByIdentifier(_state.State.Config.MasterBotIdentifier.Value));
|
||||
|
||||
if (masterStrategy == null)
|
||||
try
|
||||
{
|
||||
_logger.LogWarning("Master strategy {MasterBotId} not found", _state.State.Config.MasterBotIdentifier.Value);
|
||||
return;
|
||||
var ownedKeys = await _kaigenService.GetOwnedKeysAsync(_state.State.User);
|
||||
|
||||
var masterStrategy = await ServiceScopeHelpers.WithScopedService<IBotService, Bot>(
|
||||
_scopeFactory,
|
||||
async botService =>
|
||||
await botService.GetBotByIdentifier(_state.State.Config.MasterBotIdentifier.Value));
|
||||
|
||||
if (masterStrategy == null)
|
||||
{
|
||||
_logger.LogWarning("Master strategy {MasterBotId} not found",
|
||||
_state.State.Config.MasterBotIdentifier.Value);
|
||||
return;
|
||||
}
|
||||
|
||||
var hasMasterStrategyKey = ownedKeys.Items.Any(key =>
|
||||
string.Equals(key.AgentName, masterStrategy.User.AgentName,
|
||||
StringComparison.OrdinalIgnoreCase) &&
|
||||
key.Owned >= 1);
|
||||
|
||||
if (!hasMasterStrategyKey)
|
||||
{
|
||||
_logger.LogWarning(
|
||||
"Copy trading bot {GrainId} no longer has authorization for master strategy {MasterBotId}. Stopping bot.",
|
||||
this.GetPrimaryKey(), _state.State.Config.MasterBotIdentifier.Value);
|
||||
|
||||
await StopAsync(
|
||||
"Copy trading authorization revoked - user no longer owns keys for master strategy");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var hasMasterStrategyKey = ownedKeys.Items.Any(key =>
|
||||
string.Equals(key.AgentName, masterStrategy.User.AgentName, StringComparison.OrdinalIgnoreCase) &&
|
||||
key.Owned >= 1);
|
||||
|
||||
if (!hasMasterStrategyKey)
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(
|
||||
"Copy trading bot {GrainId} no longer has authorization for master strategy {MasterBotId}. Stopping bot.",
|
||||
_logger.LogError(ex,
|
||||
"Failed to verify copy trading authorization for bot {GrainId} with master strategy {MasterBotId}. Continuing execution.",
|
||||
this.GetPrimaryKey(), _state.State.Config.MasterBotIdentifier.Value);
|
||||
|
||||
await StopAsync("Copy trading authorization revoked - user no longer owns keys for master strategy");
|
||||
return;
|
||||
SentrySdk.CaptureException(ex);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex,
|
||||
"Failed to verify copy trading authorization for bot {GrainId} with master strategy {MasterBotId}. Continuing execution.",
|
||||
this.GetPrimaryKey(), _state.State.Config.MasterBotIdentifier.Value);
|
||||
SentrySdk.CaptureException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (_tradingBot.Positions.Any(p => p.Value.IsOpen() || p.Value.Status.Equals(PositionStatus.New)))
|
||||
@@ -1128,7 +1142,8 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
|
||||
_scopeFactory,
|
||||
async tradingService => await tradingService.GetPositionsByInitiatorIdentifierAsync(botId));
|
||||
|
||||
var openPositions = positions?.Where(p => p.IsOpen() || p.Status.Equals(PositionStatus.New)).ToList() ?? new List<Position>();
|
||||
var openPositions = positions?.Where(p => p.IsOpen() || p.Status.Equals(PositionStatus.New)).ToList() ??
|
||||
new List<Position>();
|
||||
|
||||
if (openPositions.Any())
|
||||
{
|
||||
@@ -1140,13 +1155,16 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Closing position {PositionId} for bot {GrainId}", position.Identifier, botId);
|
||||
_logger.LogInformation("Closing position {PositionId} for bot {GrainId}", position.Identifier,
|
||||
botId);
|
||||
await ClosePositionAsync(position.Identifier);
|
||||
_logger.LogInformation("Successfully closed position {PositionId} for bot {GrainId}", position.Identifier, botId);
|
||||
_logger.LogInformation("Successfully closed position {PositionId} for bot {GrainId}",
|
||||
position.Identifier, botId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to close position {PositionId} for bot {GrainId}", position.Identifier, botId);
|
||||
_logger.LogError(ex, "Failed to close position {PositionId} for bot {GrainId}",
|
||||
position.Identifier, botId);
|
||||
// Continue with other positions even if one fails
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,13 +93,16 @@ public class TradingBotBase : ITradingBot
|
||||
{
|
||||
case BotStatus.Saved:
|
||||
var indicatorNames = Config.Scenario.Indicators.Select(i => i.Type.ToString()).ToList();
|
||||
var modeText = Config.IsForWatchingOnly ? "Watch Only" :
|
||||
Config.IsForCopyTrading ? "Copy Trading" : "Live Trading";
|
||||
|
||||
var startupMessage = $"🚀 Bot Started Successfully\n\n" +
|
||||
$"📊 Trading Setup:\n" +
|
||||
$"🎯 Ticker: `{Config.Ticker}`\n" +
|
||||
$"⏰ Timeframe: `{Config.Timeframe}`\n" +
|
||||
$"🎮 Scenario: `{Config.Scenario?.Name ?? "Unknown"}`\n" +
|
||||
$"💰 Balance: `${Config.BotTradingBalance:F2}`\n" +
|
||||
$"👀 Mode: `{(Config.IsForWatchingOnly ? "Watch Only" : "Live Trading")}`\n\n" +
|
||||
$"👀 Mode: `{modeText}`\n\n" +
|
||||
$"📈 Active Indicators: `{string.Join(", ", indicatorNames)}`\n\n" +
|
||||
$"✅ Ready to monitor signals and execute trades\n" +
|
||||
$"📢 Notifications will be sent when positions are triggered";
|
||||
|
||||
@@ -71,7 +71,9 @@ namespace Managing.Application.ManageBot
|
||||
try
|
||||
{
|
||||
var config = await grain.GetConfiguration();
|
||||
var account = await grain.GetAccount();
|
||||
var account = await ServiceScopeHelpers.WithScopedService<IAccountService, Account>(
|
||||
_scopeFactory,
|
||||
async accountService => await accountService.GetAccount(config.AccountName, true, false));
|
||||
await grain.StopAsync("Deleting bot");
|
||||
await _botRepository.DeleteBot(identifier);
|
||||
await grain.DeleteAsync();
|
||||
|
||||
@@ -8,7 +8,6 @@ using Managing.Domain.Accounts;
|
||||
using Managing.Domain.Bots;
|
||||
using Managing.Domain.Users;
|
||||
using MediatR;
|
||||
using System;
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
namespace Managing.Application.ManageBot
|
||||
@@ -50,7 +49,7 @@ namespace Managing.Application.ManageBot
|
||||
|
||||
// Check if copy trading validation should be bypassed (for testing)
|
||||
var enableValidation = Environment.GetEnvironmentVariable("ENABLE_COPY_TRADING_VALIDATION")?
|
||||
.Equals("true", StringComparison.OrdinalIgnoreCase) == true;
|
||||
.Equals("true", StringComparison.OrdinalIgnoreCase) ?? true;
|
||||
|
||||
if (enableValidation)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user