Fix config update + remove messages + Summary fix for not open position
This commit is contained in:
@@ -10,6 +10,7 @@ using Managing.Core;
|
|||||||
using Managing.Domain.Accounts;
|
using Managing.Domain.Accounts;
|
||||||
using Managing.Domain.Backtests;
|
using Managing.Domain.Backtests;
|
||||||
using Managing.Domain.Bots;
|
using Managing.Domain.Bots;
|
||||||
|
using Managing.Domain.Indicators;
|
||||||
using Managing.Domain.MoneyManagements;
|
using Managing.Domain.MoneyManagements;
|
||||||
using Managing.Domain.Scenarios;
|
using Managing.Domain.Scenarios;
|
||||||
using Managing.Domain.Strategies;
|
using Managing.Domain.Strategies;
|
||||||
@@ -479,13 +480,13 @@ public class BotController : BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Manually opens a position for a specified bot with the given parameters.
|
/// Manually create a signal for a specified bot with the given parameters.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="request">The request containing position parameters.</param>
|
/// <param name="request">The request containing position parameters.</param>
|
||||||
/// <returns>A response indicating the result of the operation.</returns>
|
/// <returns>A response indicating the result of the operation.</returns>
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[Route("OpenPosition")]
|
[Route("CreateManualSignal")]
|
||||||
public async Task<ActionResult<Position>> OpenPositionManually([FromBody] OpenPositionManuallyRequest request)
|
public async Task<ActionResult<LightSignal>> CreateManualSignalAsync([FromBody] CreateManualSignalRequest request)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -507,16 +508,15 @@ public class BotController : BaseController
|
|||||||
return BadRequest($"Bot with identifier {request.Identifier} is not running");
|
return BadRequest($"Bot with identifier {request.Identifier} is not running");
|
||||||
}
|
}
|
||||||
|
|
||||||
var position = await _botService.OpenPositionManuallyAsync(request.Identifier, request.Direction);
|
var signal = await _botService.CreateManualSignalAsync(request.Identifier, request.Direction);
|
||||||
|
|
||||||
await NotifyBotSubscriberAsync();
|
return Ok(signal);
|
||||||
return Ok(position);
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "Error opening position manually");
|
_logger.LogError(ex, "Error creating signal manually");
|
||||||
return StatusCode(500,
|
return StatusCode(500,
|
||||||
$"Error opening position: {ex.Message}, {ex.InnerException?.Message} or {ex.StackTrace}");
|
$"Error creating signal: {ex.Message}, {ex.InnerException?.Message} or {ex.StackTrace}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -664,17 +664,17 @@ public class BotController : BaseController
|
|||||||
Leverage = fullMoneyManagement.Leverage
|
Leverage = fullMoneyManagement.Leverage
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else if (request.MoneyManagement != null)
|
else if (request.Config.MoneyManagement != null)
|
||||||
{
|
{
|
||||||
// Use provided money management object
|
// Use provided money management object
|
||||||
moneyManagement = request.MoneyManagement;
|
moneyManagement = new LightMoneyManagement
|
||||||
// Format percentage values if using custom money management
|
|
||||||
moneyManagement.FormatPercentage();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// Use existing bot's money management if no new one is provided
|
Name = request.Config.Name,
|
||||||
moneyManagement = config.MoneyManagement;
|
Timeframe = request.Config.Timeframe,
|
||||||
|
StopLoss = request.Config.MoneyManagement.StopLoss,
|
||||||
|
TakeProfit = request.Config.MoneyManagement.TakeProfit,
|
||||||
|
Leverage = request.Config.MoneyManagement.Leverage
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate CloseEarlyWhenProfitable requires MaxPositionTimeHours
|
// Validate CloseEarlyWhenProfitable requires MaxPositionTimeHours
|
||||||
@@ -921,7 +921,7 @@ public class BotController : BaseController
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Request model for opening a position manually
|
/// Request model for opening a position manually
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class OpenPositionManuallyRequest
|
public class CreateManualSignalRequest
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The identifier of the bot
|
/// The identifier of the bot
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Managing.Domain.Accounts;
|
using Managing.Domain.Accounts;
|
||||||
using Managing.Domain.Bots;
|
using Managing.Domain.Bots;
|
||||||
|
using Managing.Domain.Indicators;
|
||||||
using Managing.Domain.Trades;
|
using Managing.Domain.Trades;
|
||||||
using Managing.Domain.Users;
|
using Managing.Domain.Users;
|
||||||
using Orleans;
|
using Orleans;
|
||||||
@@ -18,7 +19,7 @@ public interface ILiveTradingBotGrain : IGrainWithGuidKey
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="direction">The direction of the trade (Long/Short)</param>
|
/// <param name="direction">The direction of the trade (Long/Short)</param>
|
||||||
/// <returns>The created Position object</returns>
|
/// <returns>The created Position object</returns>
|
||||||
Task<Position> OpenPositionManuallyAsync(TradeDirection direction);
|
Task<LightSignal> CreateManualSignalAsync(TradeDirection direction);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets comprehensive bot data including positions, signals, and performance metrics
|
/// Gets comprehensive bot data including positions, signals, and performance metrics
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using Managing.Application.Bots.Models;
|
using Managing.Application.Bots.Models;
|
||||||
using Managing.Domain.Accounts;
|
using Managing.Domain.Accounts;
|
||||||
using Managing.Domain.Bots;
|
using Managing.Domain.Bots;
|
||||||
|
using Managing.Domain.Indicators;
|
||||||
using Managing.Domain.Trades;
|
using Managing.Domain.Trades;
|
||||||
using static Managing.Common.Enums;
|
using static Managing.Common.Enums;
|
||||||
|
|
||||||
@@ -19,7 +20,7 @@ public interface IBotService
|
|||||||
Task<IEnumerable<Bot>> GetBotsByIdsAsync(IEnumerable<Guid> botIds);
|
Task<IEnumerable<Bot>> GetBotsByIdsAsync(IEnumerable<Guid> botIds);
|
||||||
Task<Bot> GetBotByName(string name);
|
Task<Bot> GetBotByName(string name);
|
||||||
Task<Bot> GetBotByIdentifier(Guid identifier);
|
Task<Bot> GetBotByIdentifier(Guid identifier);
|
||||||
Task<Position> OpenPositionManuallyAsync(Guid identifier, TradeDirection direction);
|
Task<LightSignal> CreateManualSignalAsync(Guid identifier, TradeDirection direction);
|
||||||
Task<Position> ClosePositionAsync(Guid identifier, Guid positionId);
|
Task<Position> ClosePositionAsync(Guid identifier, Guid positionId);
|
||||||
Task<TradingBotConfig> GetBotConfig(Guid identifier);
|
Task<TradingBotConfig> GetBotConfig(Guid identifier);
|
||||||
Task<IEnumerable<TradingBotConfig>> GetBotConfigsByIdsAsync(IEnumerable<Guid> botIds);
|
Task<IEnumerable<TradingBotConfig>> GetBotConfigsByIdsAsync(IEnumerable<Guid> botIds);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ namespace Managing.Application.Abstractions
|
|||||||
decimal GetTotalFees();
|
decimal GetTotalFees();
|
||||||
Task LoadAccount();
|
Task LoadAccount();
|
||||||
Task LoadLastCandle();
|
Task LoadLastCandle();
|
||||||
Task<Position> OpenPositionManually(TradeDirection direction);
|
Task<LightSignal> CreateManualSignal(TradeDirection direction);
|
||||||
|
|
||||||
Task CloseTrade(LightSignal signal, Position position, Trade tradeToClose, decimal lastPrice,
|
Task CloseTrade(LightSignal signal, Position position, Trade tradeToClose, decimal lastPrice,
|
||||||
bool tradeClosingPosition = false);
|
bool tradeClosingPosition = false);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using Managing.Application.Shared;
|
|||||||
using Managing.Core;
|
using Managing.Core;
|
||||||
using Managing.Domain.Accounts;
|
using Managing.Domain.Accounts;
|
||||||
using Managing.Domain.Bots;
|
using Managing.Domain.Bots;
|
||||||
|
using Managing.Domain.Indicators;
|
||||||
using Managing.Domain.Shared.Helpers;
|
using Managing.Domain.Shared.Helpers;
|
||||||
using Managing.Domain.Trades;
|
using Managing.Domain.Trades;
|
||||||
using Managing.Domain.Users;
|
using Managing.Domain.Users;
|
||||||
@@ -277,7 +278,8 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
|
|||||||
var hasOpenPositions = await HasOpenPositionsInDatabaseAsync();
|
var hasOpenPositions = await HasOpenPositionsInDatabaseAsync();
|
||||||
if (hasOpenPositions)
|
if (hasOpenPositions)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Stopping bot {Name} while it still has open positions in database. Trading loop will stop but positions remain managed by system.",
|
_logger.LogWarning(
|
||||||
|
"Stopping bot {Name} while it still has open positions in database. Trading loop will stop but positions remain managed by system.",
|
||||||
_tradingBot?.Config.Name);
|
_tradingBot?.Config.Name);
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
"Cannot stop bot while it has open positions. Please close all positions first.");
|
"Cannot stop bot while it has open positions. Please close all positions first.");
|
||||||
@@ -442,7 +444,7 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task<Position> OpenPositionManuallyAsync(TradeDirection direction)
|
public async Task<LightSignal> CreateManualSignalAsync(TradeDirection direction)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -462,7 +464,7 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
|
|||||||
await _state.WriteStateAsync();
|
await _state.WriteStateAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
return await _tradingBot.OpenPositionManually(direction);
|
return await _tradingBot.CreateManualSignal(direction);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -339,11 +339,6 @@ public class TradingBotBase : ITradingBot
|
|||||||
{
|
{
|
||||||
Positions[newlyCreatedPosition.Identifier] = newlyCreatedPosition;
|
Positions[newlyCreatedPosition.Identifier] = newlyCreatedPosition;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
await LogWarning(
|
|
||||||
$"⚠️ Position Creation Failed\nSignal: `{signal.Identifier}`\nPosition creation returned null");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -486,7 +481,7 @@ public class TradingBotBase : ITradingBot
|
|||||||
if (timeSinceRequest.TotalMinutes >= waitTimeMinutes)
|
if (timeSinceRequest.TotalMinutes >= waitTimeMinutes)
|
||||||
{
|
{
|
||||||
await LogWarning(
|
await LogWarning(
|
||||||
$"⚠️ Order Cleanup\nToo many open orders: `{orders.Count()}`\nPosition: `{positionForSignal.Identifier}`\nTime elapsed: `{waitTimeMinutes}min`\nCanceling all orders...");
|
$"⚠️ Orders Cleanup\nTime elapsed: {waitTimeMinutes}min\nCanceling all orders...");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await ServiceScopeHelpers.WithScopedService<IExchangeService>(_scopeFactory,
|
await ServiceScopeHelpers.WithScopedService<IExchangeService>(_scopeFactory,
|
||||||
@@ -495,7 +490,7 @@ public class TradingBotBase : ITradingBot
|
|||||||
await exchangeService.CancelOrder(Account, Config.Ticker);
|
await exchangeService.CancelOrder(Account, Config.Ticker);
|
||||||
});
|
});
|
||||||
await LogInformation(
|
await LogInformation(
|
||||||
$"✅ Orders Canceled\nSuccessfully canceled all orders for: `{Config.Ticker}`");
|
$"✅ Orders for {internalPosition.OriginDirection} {Config.Ticker} successfully canceled");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -504,6 +499,13 @@ public class TradingBotBase : ITradingBot
|
|||||||
|
|
||||||
await SetPositionStatus(signal.Identifier, PositionStatus.Canceled);
|
await SetPositionStatus(signal.Identifier, PositionStatus.Canceled);
|
||||||
SetSignalStatus(signal.Identifier, SignalStatus.Expired);
|
SetSignalStatus(signal.Identifier, SignalStatus.Expired);
|
||||||
|
|
||||||
|
positionForSignal.Status = PositionStatus.Canceled;
|
||||||
|
positionForSignal.Open.SetStatus(TradeStatus.Cancelled);
|
||||||
|
positionForSignal.StopLoss.SetStatus(TradeStatus.Cancelled);
|
||||||
|
positionForSignal.TakeProfit1.SetStatus(TradeStatus.Cancelled);
|
||||||
|
|
||||||
|
await UpdatePositionDatabase(positionForSignal);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -762,16 +764,16 @@ public class TradingBotBase : ITradingBot
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (internalPosition.Status == PositionStatus.Rejected ||
|
// else if (internalPosition.Status == PositionStatus.Rejected ||
|
||||||
internalPosition.Status == PositionStatus.Canceled)
|
// internalPosition.Status == PositionStatus.Canceled)
|
||||||
{
|
// {
|
||||||
await LogWarning($"Open position trade is rejected for signal {signal.Identifier}");
|
// await LogWarning($"Open position trade is rejected for signal {signal.Identifier}");
|
||||||
if (signal.Status == SignalStatus.PositionOpen)
|
// if (signal.Status == SignalStatus.PositionOpen)
|
||||||
{
|
// {
|
||||||
Logger.LogInformation($"Try to re-open position");
|
// Logger.LogInformation($"Try to re-open position");
|
||||||
await OpenPosition(signal);
|
// await OpenPosition(signal);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (Config.UseSynthApi && !Config.IsForBacktest &&
|
if (Config.UseSynthApi && !Config.IsForBacktest &&
|
||||||
positionForSignal.Status == PositionStatus.Filled)
|
positionForSignal.Status == PositionStatus.Filled)
|
||||||
@@ -926,24 +928,26 @@ public class TradingBotBase : ITradingBot
|
|||||||
|
|
||||||
if (position != null)
|
if (position != null)
|
||||||
{
|
{
|
||||||
if (position.Open.Status != TradeStatus.Cancelled)
|
if (position.Open.Status != TradeStatus.Cancelled && position.Status != PositionStatus.Rejected)
|
||||||
{
|
{
|
||||||
SetSignalStatus(signal.Identifier, SignalStatus.PositionOpen);
|
SetSignalStatus(signal.Identifier, SignalStatus.PositionOpen);
|
||||||
|
|
||||||
if (!Config.IsForBacktest)
|
if (!Config.IsForBacktest)
|
||||||
{
|
{
|
||||||
await ServiceScopeHelpers.WithScopedService<IMessengerService>(_scopeFactory,
|
await ServiceScopeHelpers.WithScopedService<IMessengerService>(_scopeFactory,
|
||||||
async messengerService => { await messengerService.SendClosedPosition(position, Account.User); });
|
async messengerService => { await messengerService.SendPosition(position); });
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.LogInformation($"Position requested");
|
Logger.LogInformation($"Position requested");
|
||||||
return position; // Return the created position without adding to list
|
return position;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await SetPositionStatus(signal.Identifier, PositionStatus.Rejected);
|
await SetPositionStatus(signal.Identifier, PositionStatus.Rejected);
|
||||||
|
position.Status = PositionStatus.Rejected;
|
||||||
|
await UpdatePositionDatabase(position);
|
||||||
SetSignalStatus(signal.Identifier, SignalStatus.Expired);
|
SetSignalStatus(signal.Identifier, SignalStatus.Expired);
|
||||||
return null;
|
return position;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -964,7 +968,7 @@ public class TradingBotBase : ITradingBot
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
SetSignalStatus(signal.Identifier, SignalStatus.Expired);
|
SetSignalStatus(signal.Identifier, SignalStatus.Expired);
|
||||||
await LogWarning($"Cannot open trade : {ex.Message}, stackTrace : {ex.StackTrace}");
|
SentrySdk.CaptureException(ex);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1586,10 +1590,7 @@ public class TradingBotBase : ITradingBot
|
|||||||
if (!Config.IsForBacktest)
|
if (!Config.IsForBacktest)
|
||||||
{
|
{
|
||||||
await ServiceScopeHelpers.WithScopedService<IMessengerService>(_scopeFactory,
|
await ServiceScopeHelpers.WithScopedService<IMessengerService>(_scopeFactory,
|
||||||
async messengerService =>
|
async messengerService => { await messengerService.SendClosedPosition(position, Account.User); });
|
||||||
{
|
|
||||||
await messengerService.SendClosedPosition(position, Account.User);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await CancelAllOrders();
|
await CancelAllOrders();
|
||||||
@@ -1810,7 +1811,7 @@ public class TradingBotBase : ITradingBot
|
|||||||
/// <param name="direction">The direction of the trade (Long/Short).</param>
|
/// <param name="direction">The direction of the trade (Long/Short).</param>
|
||||||
/// <returns>The created Position object.</returns>
|
/// <returns>The created Position object.</returns>
|
||||||
/// <exception cref="Exception">Throws if no candles are available or position opening fails.</exception>
|
/// <exception cref="Exception">Throws if no candles are available or position opening fails.</exception>
|
||||||
public async Task<Position> OpenPositionManually(TradeDirection direction)
|
public async Task<LightSignal> CreateManualSignal(TradeDirection direction)
|
||||||
{
|
{
|
||||||
if (LastCandle == null)
|
if (LastCandle == null)
|
||||||
{
|
{
|
||||||
@@ -1828,22 +1829,7 @@ public class TradingBotBase : ITradingBot
|
|||||||
// Add the signal to our collection
|
// Add the signal to our collection
|
||||||
await AddSignal(signal);
|
await AddSignal(signal);
|
||||||
|
|
||||||
// Open the position using the generated signal (SL/TP handled by MoneyManagement)
|
return signal;
|
||||||
var position = await OpenPosition(signal);
|
|
||||||
|
|
||||||
if (position == null)
|
|
||||||
{
|
|
||||||
// Clean up the signal if position creation failed
|
|
||||||
SetSignalStatus(signal.Identifier, SignalStatus.Expired);
|
|
||||||
throw new Exception("Failed to open position");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the position to the list after successful creation
|
|
||||||
Positions[position.Identifier] = position;
|
|
||||||
|
|
||||||
Logger.LogInformation(
|
|
||||||
$"👤 Manual Position Opened\nPosition: `{position.Identifier}`\nSignal: `{signal.Identifier}`\nAdded to positions list");
|
|
||||||
return position;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task AddSignal(LightSignal signal)
|
public async Task AddSignal(LightSignal signal)
|
||||||
@@ -1866,7 +1852,7 @@ public class TradingBotBase : ITradingBot
|
|||||||
$"🆔 Signal ID: `{signal.Identifier}`";
|
$"🆔 Signal ID: `{signal.Identifier}`";
|
||||||
|
|
||||||
// Apply Synth-based signal filtering if enabled
|
// Apply Synth-based signal filtering if enabled
|
||||||
if ((Config.UseSynthApi || !Config.IsForBacktest) && ExecutionCount > 0)
|
if (Config.UseSynthApi && !Config.IsForBacktest && ExecutionCount > 0)
|
||||||
{
|
{
|
||||||
await ServiceScopeHelpers.WithScopedServices<ITradingService, IExchangeService>(_scopeFactory,
|
await ServiceScopeHelpers.WithScopedServices<ITradingService, IExchangeService>(_scopeFactory,
|
||||||
async (tradingService, exchangeService) =>
|
async (tradingService, exchangeService) =>
|
||||||
@@ -2052,11 +2038,26 @@ public class TradingBotBase : ITradingBot
|
|||||||
changes.Add($"👀 Watch Only: {oldWatch} → {newWatch}");
|
changes.Add($"👀 Watch Only: {oldWatch} → {newWatch}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Config.MoneyManagement?.GetType().Name != newConfig.MoneyManagement?.GetType().Name)
|
// Check for changes in individual MoneyManagement properties
|
||||||
|
if (Config.MoneyManagement?.StopLoss != newConfig.MoneyManagement?.StopLoss)
|
||||||
{
|
{
|
||||||
var oldMM = Config.MoneyManagement?.GetType().Name ?? "None";
|
var oldStopLoss = Config.MoneyManagement?.StopLoss.ToString("P2") ?? "None";
|
||||||
var newMM = newConfig.MoneyManagement?.GetType().Name ?? "None";
|
var newStopLoss = newConfig.MoneyManagement?.StopLoss.ToString("P2") ?? "None";
|
||||||
changes.Add($"💰 Money Management: {oldMM} → {newMM}");
|
changes.Add($"🛑 Stop Loss: {oldStopLoss} → {newStopLoss}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Config.MoneyManagement?.TakeProfit != newConfig.MoneyManagement?.TakeProfit)
|
||||||
|
{
|
||||||
|
var oldTakeProfit = Config.MoneyManagement?.TakeProfit.ToString("P2") ?? "None";
|
||||||
|
var newTakeProfit = newConfig.MoneyManagement?.TakeProfit.ToString("P2") ?? "None";
|
||||||
|
changes.Add($"🎯 Take Profit: {oldTakeProfit} → {newTakeProfit}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Config.MoneyManagement?.Leverage != newConfig.MoneyManagement?.Leverage)
|
||||||
|
{
|
||||||
|
var oldLeverage = Config.MoneyManagement?.Leverage.ToString("F1") + "x" ?? "None";
|
||||||
|
var newLeverage = newConfig.MoneyManagement?.Leverage.ToString("F1") + "x" ?? "None";
|
||||||
|
changes.Add($"⚡ Leverage: {oldLeverage} → {newLeverage}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Config.RiskManagement != newConfig.RiskManagement)
|
if (Config.RiskManagement != newConfig.RiskManagement)
|
||||||
|
|||||||
@@ -136,12 +136,14 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable
|
|||||||
|
|
||||||
foreach (var position in positions)
|
foreach (var position in positions)
|
||||||
{
|
{
|
||||||
|
if (!position.IsValidForMetrics()) continue;
|
||||||
|
|
||||||
// Calculate volume using the dedicated method
|
// Calculate volume using the dedicated method
|
||||||
var positionVolume = TradingHelpers.GetVolumeForPosition(position);
|
var positionVolume = TradingHelpers.GetVolumeForPosition(position);
|
||||||
totalVolume += positionVolume;
|
totalVolume += positionVolume;
|
||||||
|
|
||||||
// Add to open interest for active positions only (only opening volume)
|
// Add to open interest for active positions only (only opening volume)
|
||||||
if (!position.IsFinished())
|
if (position.Status.Equals(PositionStatus.Filled))
|
||||||
{
|
{
|
||||||
var openingVolume = position.Open.Price * position.Open.Quantity * position.Open.Leverage;
|
var openingVolume = position.Open.Price * position.Open.Quantity * position.Open.Leverage;
|
||||||
totalOpenInterest += openingVolume;
|
totalOpenInterest += openingVolume;
|
||||||
@@ -175,7 +177,7 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable
|
|||||||
_state.State.PositionCountByAsset[ticker]++;
|
_state.State.PositionCountByAsset[ticker]++;
|
||||||
|
|
||||||
// Position count breakdown by direction - only count finished positions
|
// Position count breakdown by direction - only count finished positions
|
||||||
if (!position.IsFinished())
|
if (position.IsValidForMetrics())
|
||||||
{
|
{
|
||||||
if (!_state.State.PositionCountByDirection.ContainsKey(direction))
|
if (!_state.State.PositionCountByDirection.ContainsKey(direction))
|
||||||
{
|
{
|
||||||
@@ -201,6 +203,7 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable
|
|||||||
_state.State.PositionCountByDirection.GetValueOrDefault(TradeDirection.Short, 0));
|
_state.State.PositionCountByDirection.GetValueOrDefault(TradeDirection.Short, 0));
|
||||||
|
|
||||||
_state.State.LastUpdated = DateTime.UtcNow;
|
_state.State.LastUpdated = DateTime.UtcNow;
|
||||||
|
await RefreshAgentCountAsync();
|
||||||
await _state.WriteStateAsync();
|
await _state.WriteStateAsync();
|
||||||
|
|
||||||
_logger.LogInformation("Platform summary data refreshed successfully");
|
_logger.LogInformation("Platform summary data refreshed successfully");
|
||||||
@@ -420,7 +423,8 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable
|
|||||||
var snapshot = await CalculateDailySnapshotFromPositionsAsync(positions.ToList(), missingDate);
|
var snapshot = await CalculateDailySnapshotFromPositionsAsync(positions.ToList(), missingDate);
|
||||||
_state.State.DailySnapshots.Add(snapshot);
|
_state.State.DailySnapshots.Add(snapshot);
|
||||||
|
|
||||||
_logger.LogInformation("Created missing daily snapshot for {Date}: Volume={Volume}, PnL={PnL}, Positions={Positions}",
|
_logger.LogInformation(
|
||||||
|
"Created missing daily snapshot for {Date}: Volume={Volume}, PnL={PnL}, Positions={Positions}",
|
||||||
missingDate, snapshot.TotalVolume, snapshot.TotalPnL, snapshot.TotalLifetimePositionCount);
|
missingDate, snapshot.TotalVolume, snapshot.TotalPnL, snapshot.TotalLifetimePositionCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -448,7 +452,8 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable
|
|||||||
/// <param name="positions">All positions to analyze</param>
|
/// <param name="positions">All positions to analyze</param>
|
||||||
/// <param name="targetDate">The date to calculate the snapshot up to</param>
|
/// <param name="targetDate">The date to calculate the snapshot up to</param>
|
||||||
/// <returns>A cumulative daily snapshot for the specified date</returns>
|
/// <returns>A cumulative daily snapshot for the specified date</returns>
|
||||||
private async Task<DailySnapshot> CalculateDailySnapshotFromPositionsAsync(List<Position> positions, DateTime targetDate)
|
private async Task<DailySnapshot> CalculateDailySnapshotFromPositionsAsync(List<Position> positions,
|
||||||
|
DateTime targetDate)
|
||||||
{
|
{
|
||||||
var dayStart = targetDate;
|
var dayStart = targetDate;
|
||||||
var dayEnd = targetDate.AddDays(1);
|
var dayEnd = targetDate.AddDays(1);
|
||||||
@@ -480,9 +485,13 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable
|
|||||||
// Check if position was active at this hour
|
// Check if position was active at this hour
|
||||||
var wasActiveAtThisHour = position.Date <= hourDateTime &&
|
var wasActiveAtThisHour = position.Date <= hourDateTime &&
|
||||||
(!position.IsFinished() ||
|
(!position.IsFinished() ||
|
||||||
(position.StopLoss.Status == TradeStatus.Filled && position.StopLoss.Date > hourDateTime) ||
|
(position.StopLoss.Status == TradeStatus.Filled &&
|
||||||
(position.TakeProfit1.Status == TradeStatus.Filled && position.TakeProfit1.Date > hourDateTime) ||
|
position.StopLoss.Date > hourDateTime) ||
|
||||||
(position.TakeProfit2 != null && position.TakeProfit2.Status == TradeStatus.Filled && position.TakeProfit2.Date > hourDateTime));
|
(position.TakeProfit1.Status == TradeStatus.Filled &&
|
||||||
|
position.TakeProfit1.Date > hourDateTime) ||
|
||||||
|
(position.TakeProfit2 != null &&
|
||||||
|
position.TakeProfit2.Status == TradeStatus.Filled &&
|
||||||
|
position.TakeProfit2.Date > hourDateTime));
|
||||||
|
|
||||||
if (wasActiveAtThisHour)
|
if (wasActiveAtThisHour)
|
||||||
{
|
{
|
||||||
@@ -502,7 +511,8 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable
|
|||||||
{
|
{
|
||||||
// Calculate CUMULATIVE volume up to this point in time
|
// Calculate CUMULATIVE volume up to this point in time
|
||||||
// Include all positions that were opened on or before the target date
|
// Include all positions that were opened on or before the target date
|
||||||
_logger.LogDebug("Checking position {PositionId}: Position.Date={PositionDate}, TargetDate={TargetDate}, Position.Date.Date={PositionDateOnly}",
|
_logger.LogDebug(
|
||||||
|
"Checking position {PositionId}: Position.Date={PositionDate}, TargetDate={TargetDate}, Position.Date.Date={PositionDateOnly}",
|
||||||
position.Identifier, position.Date, targetDate, position.Date.Date);
|
position.Identifier, position.Date, targetDate, position.Date.Date);
|
||||||
|
|
||||||
// Add opening volume if position was opened on or before this day
|
// Add opening volume if position was opened on or before this day
|
||||||
@@ -511,7 +521,8 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable
|
|||||||
{
|
{
|
||||||
var openingVolume = position.Open.Price * position.Open.Quantity * position.Open.Leverage;
|
var openingVolume = position.Open.Price * position.Open.Quantity * position.Open.Leverage;
|
||||||
totalVolume += openingVolume;
|
totalVolume += openingVolume;
|
||||||
_logger.LogDebug("Position {PositionId} opened on/before {TargetDate}: Opening volume = {OpeningVolume}",
|
_logger.LogDebug(
|
||||||
|
"Position {PositionId} opened on/before {TargetDate}: Opening volume = {OpeningVolume}",
|
||||||
position.Identifier, targetDate, openingVolume);
|
position.Identifier, targetDate, openingVolume);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -520,21 +531,29 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable
|
|||||||
{
|
{
|
||||||
if (position.StopLoss.Status == TradeStatus.Filled && position.StopLoss.Date.Date <= targetDate)
|
if (position.StopLoss.Status == TradeStatus.Filled && position.StopLoss.Date.Date <= targetDate)
|
||||||
{
|
{
|
||||||
var closingVolume = position.StopLoss.Price * position.StopLoss.Quantity * position.StopLoss.Leverage;
|
var closingVolume = position.StopLoss.Price * position.StopLoss.Quantity *
|
||||||
|
position.StopLoss.Leverage;
|
||||||
totalVolume += closingVolume;
|
totalVolume += closingVolume;
|
||||||
_logger.LogDebug("Position {PositionId} closed on/before {TargetDate} via StopLoss: Closing volume = {ClosingVolume}",
|
_logger.LogDebug(
|
||||||
|
"Position {PositionId} closed on/before {TargetDate} via StopLoss: Closing volume = {ClosingVolume}",
|
||||||
position.Identifier, targetDate, closingVolume);
|
position.Identifier, targetDate, closingVolume);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (position.TakeProfit1.Status == TradeStatus.Filled && position.TakeProfit1.Date.Date <= targetDate)
|
if (position.TakeProfit1.Status == TradeStatus.Filled && position.TakeProfit1.Date.Date <= targetDate)
|
||||||
{
|
{
|
||||||
var closingVolume = position.TakeProfit1.Price * position.TakeProfit1.Quantity * position.TakeProfit1.Leverage;
|
var closingVolume = position.TakeProfit1.Price * position.TakeProfit1.Quantity *
|
||||||
|
position.TakeProfit1.Leverage;
|
||||||
totalVolume += closingVolume;
|
totalVolume += closingVolume;
|
||||||
_logger.LogDebug("Position {PositionId} closed on/before {TargetDate} via TakeProfit1: Closing volume = {ClosingVolume}",
|
_logger.LogDebug(
|
||||||
|
"Position {PositionId} closed on/before {TargetDate} via TakeProfit1: Closing volume = {ClosingVolume}",
|
||||||
position.Identifier, targetDate, closingVolume);
|
position.Identifier, targetDate, closingVolume);
|
||||||
}
|
}
|
||||||
if (position.TakeProfit2 != null && position.TakeProfit2.Status == TradeStatus.Filled && position.TakeProfit2.Date.Date <= targetDate)
|
|
||||||
|
if (position.TakeProfit2 != null && position.TakeProfit2.Status == TradeStatus.Filled &&
|
||||||
|
position.TakeProfit2.Date.Date <= targetDate)
|
||||||
{
|
{
|
||||||
var closingVolume = position.TakeProfit2.Price * position.TakeProfit2.Quantity * position.TakeProfit2.Leverage;
|
var closingVolume = position.TakeProfit2.Price * position.TakeProfit2.Quantity *
|
||||||
|
position.TakeProfit2.Leverage;
|
||||||
totalVolume += closingVolume;
|
totalVolume += closingVolume;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -543,7 +562,8 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable
|
|||||||
var wasClosedOnOrBeforeThisDay = position.IsFinished() && (
|
var wasClosedOnOrBeforeThisDay = position.IsFinished() && (
|
||||||
(position.StopLoss.Status == TradeStatus.Filled && position.StopLoss.Date.Date <= targetDate) ||
|
(position.StopLoss.Status == TradeStatus.Filled && position.StopLoss.Date.Date <= targetDate) ||
|
||||||
(position.TakeProfit1.Status == TradeStatus.Filled && position.TakeProfit1.Date.Date <= targetDate) ||
|
(position.TakeProfit1.Status == TradeStatus.Filled && position.TakeProfit1.Date.Date <= targetDate) ||
|
||||||
(position.TakeProfit2 != null && position.TakeProfit2.Status == TradeStatus.Filled && position.TakeProfit2.Date.Date <= targetDate)
|
(position.TakeProfit2 != null && position.TakeProfit2.Status == TradeStatus.Filled &&
|
||||||
|
position.TakeProfit2.Date.Date <= targetDate)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (wasClosedOnOrBeforeThisDay)
|
if (wasClosedOnOrBeforeThisDay)
|
||||||
@@ -563,7 +583,8 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable
|
|||||||
var totalAgents = await _agentService.GetTotalAgentCount();
|
var totalAgents = await _agentService.GetTotalAgentCount();
|
||||||
var totalStrategies = _state.State.TotalActiveStrategies;
|
var totalStrategies = _state.State.TotalActiveStrategies;
|
||||||
|
|
||||||
_logger.LogInformation("Calculated CUMULATIVE daily snapshot for {TargetDate}: CumVolume={TotalVolume}, MaxOpenInterest={MaxOpenInterest}, CumPositionCount={TotalPositionCount}",
|
_logger.LogInformation(
|
||||||
|
"Calculated CUMULATIVE daily snapshot for {TargetDate}: CumVolume={TotalVolume}, MaxOpenInterest={MaxOpenInterest}, CumPositionCount={TotalPositionCount}",
|
||||||
targetDate, totalVolume, maxOpenInterest, totalPositionCount);
|
targetDate, totalVolume, maxOpenInterest, totalPositionCount);
|
||||||
|
|
||||||
return new DailySnapshot
|
return new DailySnapshot
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using Managing.Common;
|
|||||||
using Managing.Core;
|
using Managing.Core;
|
||||||
using Managing.Domain.Accounts;
|
using Managing.Domain.Accounts;
|
||||||
using Managing.Domain.Bots;
|
using Managing.Domain.Bots;
|
||||||
|
using Managing.Domain.Indicators;
|
||||||
using Managing.Domain.Scenarios;
|
using Managing.Domain.Scenarios;
|
||||||
using Managing.Domain.Shared.Helpers;
|
using Managing.Domain.Shared.Helpers;
|
||||||
using Managing.Domain.Trades;
|
using Managing.Domain.Trades;
|
||||||
@@ -264,10 +265,10 @@ namespace Managing.Application.ManageBot
|
|||||||
return await _botRepository.GetBotByIdentifierAsync(identifier);
|
return await _botRepository.GetBotByIdentifierAsync(identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Position> OpenPositionManuallyAsync(Guid identifier, TradeDirection direction)
|
public async Task<LightSignal> CreateManualSignalAsync(Guid identifier, TradeDirection direction)
|
||||||
{
|
{
|
||||||
var grain = _grainFactory.GetGrain<ILiveTradingBotGrain>(identifier);
|
var grain = _grainFactory.GetGrain<ILiveTradingBotGrain>(identifier);
|
||||||
return await grain.OpenPositionManuallyAsync(direction);
|
return await grain.CreateManualSignalAsync(direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Position> ClosePositionAsync(Guid identifier, Guid positionId)
|
public async Task<Position> ClosePositionAsync(Guid identifier, Guid positionId)
|
||||||
|
|||||||
@@ -73,7 +73,9 @@ namespace Managing.Domain.Trades
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Identifier of the bot or entity that initiated this position
|
/// Identifier of the bot or entity that initiated this position
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Id(17)] [Required] public Guid InitiatorIdentifier { get; set; }
|
[Id(17)]
|
||||||
|
[Required]
|
||||||
|
public Guid InitiatorIdentifier { get; set; }
|
||||||
|
|
||||||
public bool IsFinished()
|
public bool IsFinished()
|
||||||
{
|
{
|
||||||
@@ -85,6 +87,18 @@ namespace Managing.Domain.Trades
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsValidForMetrics()
|
||||||
|
{
|
||||||
|
return Status switch
|
||||||
|
{
|
||||||
|
PositionStatus.Filled => true,
|
||||||
|
PositionStatus.Finished => true,
|
||||||
|
PositionStatus.Flipped => true,
|
||||||
|
PositionStatus.Updating => true,
|
||||||
|
_ => false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Calculates the total fees for this position based on GMX V2 fee structure
|
/// Calculates the total fees for this position based on GMX V2 fee structure
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -671,7 +671,7 @@ public class EvmManager : IEvmManager
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Console.WriteLine(e);
|
SentrySdk.CaptureException(e);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ test('GMX Position Closing', async (t) => {
|
|||||||
|
|
||||||
const result = await closeGmxPositionImpl(
|
const result = await closeGmxPositionImpl(
|
||||||
sdk,
|
sdk,
|
||||||
"DOGE",
|
"ADA",
|
||||||
TradeDirection.Short
|
TradeDirection.Long
|
||||||
)
|
)
|
||||||
console.log('Position closing result:', result)
|
console.log('Position closing result:', result)
|
||||||
assert.ok(result, 'Position closing result should be defined')
|
assert.ok(result, 'Position closing result should be defined')
|
||||||
|
|||||||
@@ -30,17 +30,17 @@ function ManualPositionModal({ showModal, botName, onClose }: ManualPositionModa
|
|||||||
const onSubmit = async (data: ManualPositionFormValues) => {
|
const onSubmit = async (data: ManualPositionFormValues) => {
|
||||||
if (!botName) return
|
if (!botName) return
|
||||||
|
|
||||||
const t = new Toast('Opening position...')
|
const t = new Toast('Creating signal...')
|
||||||
try {
|
try {
|
||||||
await client.bot_OpenPositionManually({
|
await client.bot_CreateManualSignal({
|
||||||
identifier: botName,
|
identifier: botName,
|
||||||
direction: data.direction,
|
direction: data.direction,
|
||||||
})
|
})
|
||||||
t.update('success', 'Position opened successfully')
|
t.update('success', 'Signal created successfully')
|
||||||
reset()
|
reset()
|
||||||
onClose()
|
onClose()
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
t.update('error', `Failed to open position: ${error.message || error}`)
|
t.update('error', `Failed to create signal: ${error.message || error}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ function ManualPositionModal({ showModal, botName, onClose }: ManualPositionModa
|
|||||||
return (
|
return (
|
||||||
<dialog open={showModal} className="modal modal-bottom sm:modal-middle modal-open">
|
<dialog open={showModal} className="modal modal-bottom sm:modal-middle modal-open">
|
||||||
<div className="modal-box">
|
<div className="modal-box">
|
||||||
<h3 className="font-bold text-lg">Open Position Manually for {botName}</h3>
|
<h3 className="font-bold text-lg">Create Signal Manually</h3>
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
<div className="form-control w-full max-w-xs py-2">
|
<div className="form-control w-full max-w-xs py-2">
|
||||||
<label className="label">
|
<label className="label">
|
||||||
@@ -63,7 +63,7 @@ function ManualPositionModal({ showModal, botName, onClose }: ManualPositionModa
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="modal-action">
|
<div className="modal-action">
|
||||||
<button type="submit" className="btn btn-primary">Open Position</button>
|
<button type="submit" className="btn btn-primary">Create Signal</button>
|
||||||
<button type="button" className="btn" onClick={() => { reset(); onClose(); }}>Cancel</button>
|
<button type="button" className="btn" onClick={() => { reset(); onClose(); }}>Cancel</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -18,15 +18,15 @@ const CustomMoneyManagement: React.FC<ICustomMoneyManagement> = ({
|
|||||||
const { moneyManagement, setCustomMoneyManagement } = useCustomMoneyManagement()
|
const { moneyManagement, setCustomMoneyManagement } = useCustomMoneyManagement()
|
||||||
|
|
||||||
const [leverage, setLeverage] = useState<number>(moneyManagement?.leverage || 1)
|
const [leverage, setLeverage] = useState<number>(moneyManagement?.leverage || 1)
|
||||||
const [takeProfit, setTakeProfit] = useState<number>(moneyManagement?.takeProfit || 2)
|
const [takeProfit, setTakeProfit] = useState<number>((moneyManagement?.takeProfit || 0.02) * 100) // Convert decimal to percentage
|
||||||
const [stopLoss, setStopLoss] = useState<number>(moneyManagement?.stopLoss || 1)
|
const [stopLoss, setStopLoss] = useState<number>((moneyManagement?.stopLoss || 0.01) * 100) // Convert decimal to percentage
|
||||||
|
|
||||||
const handleCreateMoneyManagement = () => {
|
const handleCreateMoneyManagement = () => {
|
||||||
const moneyManagement: MoneyManagement = {
|
const moneyManagement: MoneyManagement = {
|
||||||
leverage,
|
leverage,
|
||||||
name: 'custom',
|
name: 'custom',
|
||||||
stopLoss,
|
stopLoss: stopLoss / 100, // Convert percentage to decimal
|
||||||
takeProfit,
|
takeProfit: takeProfit / 100, // Convert percentage to decimal
|
||||||
timeframe,
|
timeframe,
|
||||||
}
|
}
|
||||||
onCreateMoneyManagement(moneyManagement)
|
onCreateMoneyManagement(moneyManagement)
|
||||||
@@ -37,6 +37,15 @@ const CustomMoneyManagement: React.FC<ICustomMoneyManagement> = ({
|
|||||||
handleCreateMoneyManagement()
|
handleCreateMoneyManagement()
|
||||||
}, [leverage, takeProfit, stopLoss])
|
}, [leverage, takeProfit, stopLoss])
|
||||||
|
|
||||||
|
// Update local state when global moneyManagement changes
|
||||||
|
useEffect(() => {
|
||||||
|
if (moneyManagement) {
|
||||||
|
setLeverage(moneyManagement.leverage)
|
||||||
|
setTakeProfit(moneyManagement.takeProfit * 100) // Convert decimal to percentage
|
||||||
|
setStopLoss(moneyManagement.stopLoss * 100) // Convert decimal to percentage
|
||||||
|
}
|
||||||
|
}, [moneyManagement])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{showCustomMoneyManagement ? (
|
{showCustomMoneyManagement ? (
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ const UnifiedTradingModal: React.FC<UnifiedTradingModalProps> = ({
|
|||||||
|
|
||||||
const { apiUrl } = useApiUrlStore();
|
const { apiUrl } = useApiUrlStore();
|
||||||
const { addBacktest } = useBacktestStore();
|
const { addBacktest } = useBacktestStore();
|
||||||
const { setCustomMoneyManagement: setGlobalCustomMoneyManagement } = useCustomMoneyManagement();
|
const { moneyManagement: globalCustomMoneyManagement, setCustomMoneyManagement: setGlobalCustomMoneyManagement } = useCustomMoneyManagement();
|
||||||
const { setCustomScenario: setGlobalCustomScenario } = useCustomScenario();
|
const { setCustomScenario: setGlobalCustomScenario } = useCustomScenario();
|
||||||
|
|
||||||
// API clients
|
// API clients
|
||||||
@@ -620,7 +620,7 @@ const UnifiedTradingModal: React.FC<UnifiedTradingModalProps> = ({
|
|||||||
let moneyManagement: MoneyManagement | undefined = undefined;
|
let moneyManagement: MoneyManagement | undefined = undefined;
|
||||||
|
|
||||||
if (showCustomMoneyManagement || (mode === 'createBot' && backtest)) {
|
if (showCustomMoneyManagement || (mode === 'createBot' && backtest)) {
|
||||||
moneyManagement = customMoneyManagement;
|
moneyManagement = globalCustomMoneyManagement || customMoneyManagement;
|
||||||
} else {
|
} else {
|
||||||
const selectedMM = moneyManagements?.find(mm => mm.name === selectedMoneyManagement);
|
const selectedMM = moneyManagements?.find(mm => mm.name === selectedMoneyManagement);
|
||||||
if (selectedMM) {
|
if (selectedMM) {
|
||||||
@@ -712,7 +712,7 @@ const UnifiedTradingModal: React.FC<UnifiedTradingModalProps> = ({
|
|||||||
useForSignalFiltering: form.useForSignalFiltering ?? true,
|
useForSignalFiltering: form.useForSignalFiltering ?? true,
|
||||||
useForDynamicStopLoss: form.useForDynamicStopLoss ?? true,
|
useForDynamicStopLoss: form.useForDynamicStopLoss ?? true,
|
||||||
moneyManagementName: showCustomMoneyManagement ? undefined : selectedMoneyManagement,
|
moneyManagementName: showCustomMoneyManagement ? undefined : selectedMoneyManagement,
|
||||||
moneyManagement: customMoneyManagement,
|
moneyManagement: globalCustomMoneyManagement || customMoneyManagement,
|
||||||
flipPosition: form.flipPosition || false,
|
flipPosition: form.flipPosition || false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1591,8 +1591,8 @@ export class BotClient extends AuthorizedApiBase {
|
|||||||
return Promise.resolve<PaginatedResponseOfTradingBotResponse>(null as any);
|
return Promise.resolve<PaginatedResponseOfTradingBotResponse>(null as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
bot_OpenPositionManually(request: OpenPositionManuallyRequest): Promise<Position> {
|
bot_CreateManualSignal(request: CreateManualSignalRequest): Promise<LightSignal> {
|
||||||
let url_ = this.baseUrl + "/Bot/OpenPosition";
|
let url_ = this.baseUrl + "/Bot/CreateManualSignal";
|
||||||
url_ = url_.replace(/[?&]$/, "");
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
const content_ = JSON.stringify(request);
|
const content_ = JSON.stringify(request);
|
||||||
@@ -1609,17 +1609,17 @@ export class BotClient extends AuthorizedApiBase {
|
|||||||
return this.transformOptions(options_).then(transformedOptions_ => {
|
return this.transformOptions(options_).then(transformedOptions_ => {
|
||||||
return this.http.fetch(url_, transformedOptions_);
|
return this.http.fetch(url_, transformedOptions_);
|
||||||
}).then((_response: Response) => {
|
}).then((_response: Response) => {
|
||||||
return this.processBot_OpenPositionManually(_response);
|
return this.processBot_CreateManualSignal(_response);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected processBot_OpenPositionManually(response: Response): Promise<Position> {
|
protected processBot_CreateManualSignal(response: Response): Promise<LightSignal> {
|
||||||
const status = response.status;
|
const status = response.status;
|
||||||
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
if (status === 200) {
|
if (status === 200) {
|
||||||
return response.text().then((_responseText) => {
|
return response.text().then((_responseText) => {
|
||||||
let result200: any = null;
|
let result200: any = null;
|
||||||
result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as Position;
|
result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as LightSignal;
|
||||||
return result200;
|
return result200;
|
||||||
});
|
});
|
||||||
} else if (status !== 200 && status !== 204) {
|
} else if (status !== 200 && status !== 204) {
|
||||||
@@ -1627,7 +1627,7 @@ export class BotClient extends AuthorizedApiBase {
|
|||||||
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return Promise.resolve<Position>(null as any);
|
return Promise.resolve<LightSignal>(null as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
bot_ClosePosition(request: ClosePositionRequest): Promise<Position> {
|
bot_ClosePosition(request: ClosePositionRequest): Promise<Position> {
|
||||||
@@ -4309,7 +4309,7 @@ export enum BotSortableColumn {
|
|||||||
AgentName = "AgentName",
|
AgentName = "AgentName",
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OpenPositionManuallyRequest {
|
export interface CreateManualSignalRequest {
|
||||||
identifier?: string;
|
identifier?: string;
|
||||||
direction?: TradeDirection;
|
direction?: TradeDirection;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -784,7 +784,7 @@ export enum BotSortableColumn {
|
|||||||
AgentName = "AgentName",
|
AgentName = "AgentName",
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OpenPositionManuallyRequest {
|
export interface CreateManualSignalRequest {
|
||||||
identifier?: string;
|
identifier?: string;
|
||||||
direction?: TradeDirection;
|
direction?: TradeDirection;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user