Add user to position + fix few things

This commit is contained in:
2025-04-24 19:46:21 +07:00
parent 76b8b7ebb6
commit c22c925087
17 changed files with 357 additions and 238 deletions

View File

@@ -331,7 +331,7 @@ public class TradingBot : Bot, ITradingBot
: TradingService.GetPositionByIdentifier(positionForSignal.Identifier);
var positionsExchange = IsForBacktest
? new List<Position>{position}
? new List<Position> { position }
: await TradingService.GetBrokerPositions(Account);
if (!IsForBacktest)
@@ -344,11 +344,13 @@ public class TradingBot : Bot, ITradingBot
var orders = await ExchangeService.GetOpenOrders(Account, Ticker);
if (orders.Any())
{
await LogInformation($"Cannot update Position. Position is still waiting for opening. There is {orders.Count()} open orders.");
await LogInformation(
$"Cannot update Position. Position is still waiting for opening. There is {orders.Count()} open orders.");
}
else
{
await LogWarning($"Cannot update Position. No position on exchange and no orders. Position {signal.Identifier} might be closed already.");
await LogWarning(
$"Cannot update Position. No position on exchange and no orders. Position {signal.Identifier} might be closed already.");
await HandleClosedPosition(positionForSignal);
}
}
@@ -446,7 +448,7 @@ public class TradingBot : Bot, ITradingBot
Logger.LogInformation($"Try to re-open position");
await OpenPosition(signal);
}
}
}
}
catch (Exception ex)
{
@@ -525,15 +527,16 @@ public class TradingBot : Bot, ITradingBot
Ticker,
IsForBacktest ? PositionInitiator.PaperTrading : PositionInitiator.Bot,
signal.Date,
User,
IsForBacktest,
lastPrice,
balance: WalletBalances.LastOrDefault().Value,
fee: Fee);
fee: Fee,
signalIdentifier: signal.Identifier);
var position = await new OpenPositionCommandHandler(ExchangeService, AccountService, TradingService)
.Handle(command);
if (position != null)
{
position.SignalIdentifier = signal.Identifier;
@@ -691,7 +694,7 @@ public class TradingBot : Bot, ITradingBot
await ExchangeService.CancelOrder(Account, Ticker);
var closePendingOrderStatus = await ExchangeService.CancelOrder(Account, Ticker);
Logger.LogInformation($"Closing all {Ticker} orders status : {closePendingOrderStatus}");
}
}
}
else
{
@@ -839,7 +842,7 @@ public class TradingBot : Bot, ITradingBot
// Create a fake signal for manual position opening
var signal = new Signal(Ticker, direction, Confidence.Low, lastCandle, lastCandle.Date, TradingExchanges.GmxV2,
StrategyType.Stc, SignalType.Signal);
StrategyType.Stc, SignalType.Signal);
signal.Status = SignalStatus.WaitingForPosition; // Ensure status is correct
signal.User = Account.User; // Assign user
@@ -854,7 +857,7 @@ public class TradingBot : Bot, ITradingBot
if (position == null)
{
// Clean up the signal if position creation failed
SetSignalStatus(signal.Identifier, SignalStatus.Expired);
SetSignalStatus(signal.Identifier, SignalStatus.Expired);
throw new Exception("Failed to open position");
}

View File

@@ -1,5 +1,6 @@
using Managing.Domain.MoneyManagements;
using Managing.Domain.Trades;
using Managing.Domain.Users;
using MediatR;
using static Managing.Common.Enums;
@@ -14,11 +15,13 @@ namespace Managing.Application.Trading.Commands
Ticker ticker,
PositionInitiator initiator,
DateTime date,
User user,
bool isForPaperTrading = false,
decimal? price = null,
decimal? balance = 1000,
decimal? fee = null,
bool? ignoreSLTP = false)
decimal? fee = null,
bool? ignoreSLTP = false,
string signalIdentifier = null)
{
AccountName = accountName;
MoneyManagement = moneyManagement;
@@ -31,8 +34,11 @@ namespace Managing.Application.Trading.Commands
Initiator = initiator;
Fee = fee;
IgnoreSLTP = ignoreSLTP;
User = user;
SignalIdentifier = signalIdentifier;
}
public string SignalIdentifier { get; set; }
public string AccountName { get; }
public MoneyManagement MoneyManagement { get; }
public TradeDirection Direction { get; }
@@ -44,5 +50,6 @@ namespace Managing.Application.Trading.Commands
public decimal? Balance { get; }
public DateTime Date { get; set; }
public PositionInitiator Initiator { get; internal set; }
public User User { get; internal set; }
}
}
}

View File

@@ -26,8 +26,15 @@ namespace Managing.Application.Trading
}
var initiator = request.IsForPaperTrading ? PositionInitiator.PaperTrading : request.Initiator;
var position = new Position(request.AccountName, request.Direction, request.Ticker, request.MoneyManagement,
initiator, request.Date);
var position = new Position(new Guid().ToString(), request.AccountName, request.Direction, request.Ticker,
request.MoneyManagement,
initiator, request.Date, request.User);
if (!string.IsNullOrEmpty(request.SignalIdentifier))
{
position.SignalIdentifier = request.SignalIdentifier;
}
var balance = request.IsForPaperTrading
? request.Balance.GetValueOrDefault()
: exchangeService.GetBalance(account, request.IsForPaperTrading).Result;
@@ -63,12 +70,12 @@ namespace Managing.Application.Trading
TradeType.Limit,
isForPaperTrading: request.IsForPaperTrading,
currentDate: request.Date,
stopLossPrice: stopLossPrice, // Pass determined SL price
stopLossPrice: stopLossPrice, // Pass determined SL price
takeProfitPrice: takeProfitPrice); // Pass determined TP price
//trade.Fee = TradingHelpers.GetFeeAmount(fee, openPrice * quantity, account.Exchange);
position.Open = trade;
var closeDirection = request.Direction == TradeDirection.Long
? TradeDirection.Short
: TradeDirection.Long;

View File

@@ -1,4 +1,5 @@
using Managing.Application.Abstractions;
using InfluxDB.Client.Api.Domain;
using Managing.Application.Abstractions;
using Managing.Application.Abstractions.Services;
using Managing.Application.Trading.Commands;
using Managing.Application.Trading;
@@ -63,13 +64,12 @@ public class OpenPosition : FlowBase
var Positions = JsonConvert.DeserializeObject<List<Position>>(_cacheService.GetValue(POSITIONS_KEY));
var Signals = JsonConvert.DeserializeObject<HashSet<Signal>>(_cacheService.GetValue(POSITIONS_KEY));
Fee = _cacheService.GetOrSave(FEE_KEY, () =>
{
return _tradingService.GetFee(Account, OpenPositionParameters.IsForBacktest);
}, TimeSpan.FromDays(1));
Fee = _cacheService.GetOrSave(FEE_KEY,
() => { return _tradingService.GetFee(Account, OpenPositionParameters.IsForBacktest); },
TimeSpan.FromDays(1));
await ExecuteOpenPosition(signal, Positions, Signals, Candles, Account);
_cacheService.SaveValue(POSITIONS_KEY, JsonConvert.SerializeObject(Positions));
_cacheService.SaveValue(SIGNALS_KEY, JsonConvert.SerializeObject(Signals));
@@ -82,13 +82,16 @@ public class OpenPosition : FlowBase
}
}
private async Task ExecuteOpenPosition(Signal signal, List<Position> positions, HashSet<Signal> signals, HashSet<Candle> candles, Account account)
private async Task ExecuteOpenPosition(Signal signal, List<Position> positions, HashSet<Signal> signals,
HashSet<Candle> candles, Account account)
{
// Check if a position is already open
var openedPosition = positions.FirstOrDefault(p => p.Status == PositionStatus.Filled
&& p.SignalIdentifier != signal.Identifier);
&& p.SignalIdentifier != signal.Identifier);
var lastPrice = OpenPositionParameters.IsForBacktest ? candles.Last().Close : _exchangeService.GetPrice(account, signal.Ticker, DateTime.UtcNow);
var lastPrice = OpenPositionParameters.IsForBacktest
? candles.Last().Close
: _exchangeService.GetPrice(account, signal.Ticker, DateTime.UtcNow);
// If position open
if (openedPosition != null)
@@ -110,7 +113,8 @@ public class OpenPosition : FlowBase
{
//await LogInformation("Try to flip the position because of an opposite direction signal");
//await CloseTrade(previousSignal, openedPosition, openedPosition.Open, lastPrice, true);
positions.FirstOrDefault(s => s.Identifier == previousSignal.Identifier).Status = PositionStatus.Flipped;
positions.FirstOrDefault(s => s.Identifier == previousSignal.Identifier).Status =
PositionStatus.Flipped;
await ExecuteOpenPosition(signal, positions, signals, candles, account);
//await LogInformation($"Position {previousSignal.Identifier} flipped by {signal.Identifier} at {lastPrice}$");
@@ -134,23 +138,27 @@ public class OpenPosition : FlowBase
try
{
var moneyManagement = await _settingsRepository.GetMoneyManagement(OpenPositionParameters.MoneyManagementName);
var WalletBalances = JsonConvert.DeserializeObject<Dictionary<DateTime, decimal>>(_cacheService.GetValue(WALLET_BALANCES));
var moneyManagement =
await _settingsRepository.GetMoneyManagement(OpenPositionParameters.MoneyManagementName);
var WalletBalances =
JsonConvert.DeserializeObject<Dictionary<DateTime, decimal>>(
_cacheService.GetValue(WALLET_BALANCES));
var command = new OpenPositionRequest(
OpenPositionParameters.AccountName,
moneyManagement,
moneyManagement,
signal.Direction,
signal.Ticker,
signal.Ticker,
PositionInitiator.Bot,
signal.Date,
account.User,
OpenPositionParameters.IsForBacktest,
lastPrice,
balance: WalletBalances.LastOrDefault().Value,
fee: Fee);
var position = await new OpenPositionCommandHandler(_exchangeService, _accountService, _tradingService)
.Handle(command);
.Handle(command);
if (position != null)
{
@@ -158,18 +166,21 @@ public class OpenPosition : FlowBase
{
position.SignalIdentifier = signal.Identifier;
positions.Add(position);
signals.FirstOrDefault(s => s.Identifier == signal.Identifier).Status = SignalStatus.PositionOpen;
signals.FirstOrDefault(s => s.Identifier == signal.Identifier).Status =
SignalStatus.PositionOpen;
if (!OpenPositionParameters.IsForBacktest)
{
await _messengerService.SendPosition(position);
}
Output = JsonConvert.SerializeObject(position);
//Logger.LogInformation($"Position requested");
}
else
{
positions.FirstOrDefault(s => s.Identifier == signal.Identifier).Status = PositionStatus.Rejected;
positions.FirstOrDefault(s => s.Identifier == signal.Identifier).Status =
PositionStatus.Rejected;
signals.FirstOrDefault(s => s.Identifier == signal.Identifier).Status = SignalStatus.Expired;
}
}
@@ -180,18 +191,18 @@ public class OpenPosition : FlowBase
//await LogWarning($"Cannot open trade : {ex.Message}");
}
}
}
private bool CanOpenPosition(Signal signal, List<Position> positions, HashSet<Signal> signals, HashSet<Candle> candles)
private bool CanOpenPosition(Signal signal, List<Position> positions, HashSet<Signal> signals,
HashSet<Candle> candles)
{
if (positions.Count == 0)
return true;
var lastPosition = positions.LastOrDefault(p => p.IsFinished()
&& p.SignalIdentifier != signal.Identifier
&& p.ProfitAndLoss.Realized < 0
&& p.OriginDirection == signal.Direction);
&& p.SignalIdentifier != signal.Identifier
&& p.ProfitAndLoss.Realized < 0
&& p.OriginDirection == signal.Direction);
if (lastPosition == null)
return true;
@@ -224,4 +235,4 @@ public class OpenPositionParameters
public string AccountName { get; set; }
public bool IsForBacktest { get; set; }
public bool FlipPosition { get; set; }
}
}