Fix status for position and SLTP

This commit is contained in:
2025-09-24 12:55:12 +07:00
parent d2a4bd4426
commit 38a58abc5f

View File

@@ -402,6 +402,12 @@ public class TradingBotBase : ITradingBot
internalPosition.ProfitAndLoss = brokerPosition.ProfitAndLoss; internalPosition.ProfitAndLoss = brokerPosition.ProfitAndLoss;
internalPosition.Status = PositionStatus.Filled; internalPosition.Status = PositionStatus.Filled;
// Update Open trade status when position is found on broker
if (internalPosition.Open != null)
{
internalPosition.Open.SetStatus(TradeStatus.Filled);
}
if (internalPosition.Status.Equals(PositionStatus.New)) if (internalPosition.Status.Equals(PositionStatus.New))
{ {
await SetPositionStatus(internalPosition.SignalIdentifier, PositionStatus.Filled); await SetPositionStatus(internalPosition.SignalIdentifier, PositionStatus.Filled);
@@ -493,6 +499,13 @@ public class TradingBotBase : ITradingBot
$"✅ **Position Found on Broker**\nPosition is already open on broker\nUpdating position status to Filled"); $"✅ **Position Found on Broker**\nPosition is already open on broker\nUpdating position status to Filled");
UpdatePositionPnl(positionForSignal.Identifier, brokerPosition.ProfitAndLoss.Realized); UpdatePositionPnl(positionForSignal.Identifier, brokerPosition.ProfitAndLoss.Realized);
// Update Open trade status when position is found on broker with 2 orders
if (internalPosition.Open != null)
{
internalPosition.Open.SetStatus(TradeStatus.Filled);
}
await SetPositionStatus(signal.Identifier, PositionStatus.Filled); await SetPositionStatus(signal.Identifier, PositionStatus.Filled);
// Notify platform summary about the executed trade // Notify platform summary about the executed trade
@@ -568,56 +581,130 @@ public class TradingBotBase : ITradingBot
{ {
if (positionForSignal.StopLoss.Price >= lastCandle.Low) if (positionForSignal.StopLoss.Price >= lastCandle.Low)
{ {
await LogInformation( // Use actual execution price (lastCandle.Low for SL hit)
$"🛑 **Stop Loss Hit**\nClosing LONG position\nPrice: `${positionForSignal.StopLoss.Price}`"); var executionPrice = lastCandle.Low;
await CloseTrade(signal, positionForSignal, positionForSignal.StopLoss, positionForSignal.StopLoss.SetPrice(executionPrice, 2);
positionForSignal.StopLoss.Price, true); positionForSignal.StopLoss.SetDate(lastCandle.Date);
positionForSignal.StopLoss.SetStatus(TradeStatus.Filled); positionForSignal.StopLoss.SetStatus(TradeStatus.Filled);
// Cancel TP trades when SL is hit
if (positionForSignal.TakeProfit1 != null)
{
positionForSignal.TakeProfit1.SetStatus(TradeStatus.Cancelled);
}
if (positionForSignal.TakeProfit2 != null)
{
positionForSignal.TakeProfit2.SetStatus(TradeStatus.Cancelled);
}
await LogInformation(
$"🛑 **Stop Loss Hit**\nClosing LONG position\nPrice: `${executionPrice:F2}` (was `${positionForSignal.StopLoss.Price:F2}`)");
await CloseTrade(signal, positionForSignal, positionForSignal.StopLoss,
executionPrice, true);
} }
else if (positionForSignal.TakeProfit1.Price <= lastCandle.High && else if (positionForSignal.TakeProfit1.Price <= lastCandle.High &&
positionForSignal.TakeProfit1.Status != TradeStatus.Filled) positionForSignal.TakeProfit1.Status != TradeStatus.Filled)
{ {
await LogInformation( // Use actual execution price (lastCandle.High for TP hit)
$"🎯 **Take Profit 1 Hit**\nClosing LONG position\nPrice: `${positionForSignal.TakeProfit1.Price}`"); var executionPrice = lastCandle.High;
await CloseTrade(signal, positionForSignal, positionForSignal.TakeProfit1, positionForSignal.TakeProfit1.SetPrice(executionPrice, 2);
positionForSignal.TakeProfit1.Price, positionForSignal.TakeProfit2 == null); positionForSignal.TakeProfit1.SetDate(lastCandle.Date);
positionForSignal.TakeProfit1.SetStatus(TradeStatus.Filled); positionForSignal.TakeProfit1.SetStatus(TradeStatus.Filled);
// Cancel SL trade when TP is hit
if (positionForSignal.StopLoss != null)
{
positionForSignal.StopLoss.SetStatus(TradeStatus.Cancelled);
}
await LogInformation(
$"🎯 **Take Profit 1 Hit**\nClosing LONG position\nPrice: `${executionPrice:F2}` (was `${positionForSignal.TakeProfit1.Price:F2}`)");
await CloseTrade(signal, positionForSignal, positionForSignal.TakeProfit1,
executionPrice, positionForSignal.TakeProfit2 == null);
} }
else if (positionForSignal.TakeProfit2?.Price <= lastCandle.High) else if (positionForSignal.TakeProfit2?.Price <= lastCandle.High)
{ {
await LogInformation( // Use actual execution price (lastCandle.High for TP hit)
$"🎯 **Take Profit 2 Hit**\nClosing LONG position\nPrice: `${positionForSignal.TakeProfit2.Price}`"); var executionPrice = lastCandle.High;
await CloseTrade(signal, positionForSignal, positionForSignal.TakeProfit2, positionForSignal.TakeProfit2.SetPrice(executionPrice, 2);
positionForSignal.TakeProfit2.Price, true); positionForSignal.TakeProfit2.SetDate(lastCandle.Date);
positionForSignal.TakeProfit2.SetStatus(TradeStatus.Filled); positionForSignal.TakeProfit2.SetStatus(TradeStatus.Filled);
// Cancel SL trade when TP is hit
if (positionForSignal.StopLoss != null)
{
positionForSignal.StopLoss.SetStatus(TradeStatus.Cancelled);
}
await LogInformation(
$"🎯 **Take Profit 2 Hit**\nClosing LONG position\nPrice: `${executionPrice:F2}` (was `${positionForSignal.TakeProfit2.Price:F2}`)");
await CloseTrade(signal, positionForSignal, positionForSignal.TakeProfit2,
executionPrice, true);
} }
} }
else if (positionForSignal.OriginDirection == TradeDirection.Short) else if (positionForSignal.OriginDirection == TradeDirection.Short)
{ {
if (positionForSignal.StopLoss.Price <= lastCandle.High) if (positionForSignal.StopLoss.Price <= lastCandle.High)
{ {
await LogInformation( // Use actual execution price (lastCandle.High for SL hit on SHORT)
$"🛑 **Stop Loss Hit**\nClosing SHORT position\nPrice: `${positionForSignal.StopLoss.Price}`"); var executionPrice = lastCandle.High;
await CloseTrade(signal, positionForSignal, positionForSignal.StopLoss, positionForSignal.StopLoss.SetPrice(executionPrice, 2);
positionForSignal.StopLoss.Price, true); positionForSignal.StopLoss.SetDate(lastCandle.Date);
positionForSignal.StopLoss.SetStatus(TradeStatus.Filled); positionForSignal.StopLoss.SetStatus(TradeStatus.Filled);
// Cancel TP trades when SL is hit
if (positionForSignal.TakeProfit1 != null)
{
positionForSignal.TakeProfit1.SetStatus(TradeStatus.Cancelled);
}
if (positionForSignal.TakeProfit2 != null)
{
positionForSignal.TakeProfit2.SetStatus(TradeStatus.Cancelled);
}
await LogInformation(
$"🛑 **Stop Loss Hit**\nClosing SHORT position\nPrice: `${executionPrice:F2}` (was `${positionForSignal.StopLoss.Price:F2}`)");
await CloseTrade(signal, positionForSignal, positionForSignal.StopLoss,
executionPrice, true);
} }
else if (positionForSignal.TakeProfit1.Price >= lastCandle.Low && else if (positionForSignal.TakeProfit1.Price >= lastCandle.Low &&
positionForSignal.TakeProfit1.Status != TradeStatus.Filled) positionForSignal.TakeProfit1.Status != TradeStatus.Filled)
{ {
await LogInformation( // Use actual execution price (lastCandle.Low for TP hit on SHORT)
$"🎯 **Take Profit 1 Hit**\nClosing SHORT position\nPrice: `${positionForSignal.TakeProfit1.Price}`"); var executionPrice = lastCandle.Low;
await CloseTrade(signal, positionForSignal, positionForSignal.TakeProfit1, positionForSignal.TakeProfit1.SetPrice(executionPrice, 2);
positionForSignal.TakeProfit1.Price, positionForSignal.TakeProfit2 == null); positionForSignal.TakeProfit1.SetDate(lastCandle.Date);
positionForSignal.TakeProfit1.SetStatus(TradeStatus.Filled); positionForSignal.TakeProfit1.SetStatus(TradeStatus.Filled);
// Cancel SL trade when TP is hit
if (positionForSignal.StopLoss != null)
{
positionForSignal.StopLoss.SetStatus(TradeStatus.Cancelled);
}
await LogInformation(
$"🎯 **Take Profit 1 Hit**\nClosing SHORT position\nPrice: `${executionPrice:F2}` (was `${positionForSignal.TakeProfit1.Price:F2}`)");
await CloseTrade(signal, positionForSignal, positionForSignal.TakeProfit1,
executionPrice, positionForSignal.TakeProfit2 == null);
} }
else if (positionForSignal.TakeProfit2?.Price >= lastCandle.Low) else if (positionForSignal.TakeProfit2?.Price >= lastCandle.Low)
{ {
await LogInformation( // Use actual execution price (lastCandle.Low for TP hit on SHORT)
$"🎯 **Take Profit 2 Hit**\nClosing SHORT position\nPrice: `${positionForSignal.TakeProfit2.Price}`"); var executionPrice = lastCandle.Low;
await CloseTrade(signal, positionForSignal, positionForSignal.TakeProfit2, positionForSignal.TakeProfit2.SetPrice(executionPrice, 2);
positionForSignal.TakeProfit2.Price, true); positionForSignal.TakeProfit2.SetDate(lastCandle.Date);
positionForSignal.TakeProfit2.SetStatus(TradeStatus.Filled); positionForSignal.TakeProfit2.SetStatus(TradeStatus.Filled);
// Cancel SL trade when TP is hit
if (positionForSignal.StopLoss != null)
{
positionForSignal.StopLoss.SetStatus(TradeStatus.Cancelled);
}
await LogInformation(
$"🎯 **Take Profit 2 Hit**\nClosing SHORT position\nPrice: `${executionPrice:F2}` (was `${positionForSignal.TakeProfit2.Price:F2}`)");
await CloseTrade(signal, positionForSignal, positionForSignal.TakeProfit2,
executionPrice, true);
} }
} }
} }
@@ -676,6 +763,12 @@ public class TradingBotBase : ITradingBot
internalPosition.Status = PositionStatus.Filled; internalPosition.Status = PositionStatus.Filled;
internalPosition.ProfitAndLoss = internalPosition.ProfitAndLoss; internalPosition.ProfitAndLoss = internalPosition.ProfitAndLoss;
// Update Open trade status when position is updated to Filled
if (internalPosition.Open != null)
{
internalPosition.Open.SetStatus(TradeStatus.Filled);
}
// Save updated position to database // Save updated position to database
await tradingService.UpdatePositionAsync(internalPosition); await tradingService.UpdatePositionAsync(internalPosition);
}); });
@@ -1137,26 +1230,52 @@ public class TradingBotBase : ITradingBot
if (wasStopLossHit) if (wasStopLossHit)
{ {
closingPrice = position.StopLoss.Price; // Use actual execution price based on direction
closingPrice = position.OriginDirection == TradeDirection.Long
? minPriceRecent // For LONG, SL hits at the low
: maxPriceRecent; // For SHORT, SL hits at the high
position.StopLoss.SetPrice(closingPrice, 2);
position.StopLoss.SetDate(currentCandle.Date); position.StopLoss.SetDate(currentCandle.Date);
position.StopLoss.SetStatus(TradeStatus.Filled); position.StopLoss.SetStatus(TradeStatus.Filled);
// Cancel TP trades when SL is hit
if (position.TakeProfit1 != null)
{
position.TakeProfit1.SetStatus(TradeStatus.Cancelled);
}
if (position.TakeProfit2 != null)
{
position.TakeProfit2.SetStatus(TradeStatus.Cancelled);
}
Logger.LogInformation( Logger.LogInformation(
$"🛑 **Stop Loss Execution Confirmed**\n" + $"🛑 **Stop Loss Execution Confirmed**\n" +
$"Position: `{position.Identifier}`\n" + $"Position: `{position.Identifier}`\n" +
$"SL Price: `${position.StopLoss.Price:F2}` was hit\n" + $"SL Price: `${closingPrice:F2}` was hit (was `${position.StopLoss.Price:F2}`)\n" +
$"Recent Low: `${minPriceRecent:F2}` | Recent High: `${maxPriceRecent:F2}`"); $"Recent Low: `${minPriceRecent:F2}` | Recent High: `${maxPriceRecent:F2}`");
} }
else if (wasTakeProfitHit) else if (wasTakeProfitHit)
{ {
closingPrice = position.TakeProfit1.Price; // Use actual execution price based on direction
closingPrice = position.OriginDirection == TradeDirection.Long
? maxPriceRecent // For LONG, TP hits at the high
: minPriceRecent; // For SHORT, TP hits at the low
position.TakeProfit1.SetPrice(closingPrice, 2);
position.TakeProfit1.SetDate(currentCandle.Date); position.TakeProfit1.SetDate(currentCandle.Date);
position.TakeProfit1.SetStatus(TradeStatus.Filled); position.TakeProfit1.SetStatus(TradeStatus.Filled);
// Cancel SL trade when TP is hit
if (position.StopLoss != null)
{
position.StopLoss.SetStatus(TradeStatus.Cancelled);
}
Logger.LogInformation( Logger.LogInformation(
$"🎯 **Take Profit Execution Confirmed**\n" + $"🎯 **Take Profit Execution Confirmed**\n" +
$"Position: `{position.Identifier}`\n" + $"Position: `{position.Identifier}`\n" +
$"TP Price: `${position.TakeProfit1.Price:F2}` was hit\n" + $"TP Price: `${closingPrice:F2}` was hit (was `${position.TakeProfit1.Price:F2}`)\n" +
$"Recent Low: `${minPriceRecent:F2}` | Recent High: `${maxPriceRecent:F2}`"); $"Recent Low: `${minPriceRecent:F2}` | Recent High: `${maxPriceRecent:F2}`");
} }
else else
@@ -1176,13 +1295,31 @@ public class TradingBotBase : ITradingBot
if (isManualCloseProfitable) if (isManualCloseProfitable)
{ {
position.TakeProfit1.SetPrice(closingPrice, 2);
position.TakeProfit1.SetDate(currentCandle.Date); position.TakeProfit1.SetDate(currentCandle.Date);
position.TakeProfit1.SetStatus(TradeStatus.Filled); position.TakeProfit1.SetStatus(TradeStatus.Filled);
// Cancel SL trade when TP is used for manual close
if (position.StopLoss != null)
{
position.StopLoss.SetStatus(TradeStatus.Cancelled);
}
} }
else else
{ {
position.StopLoss.SetPrice(closingPrice, 2);
position.StopLoss.SetDate(currentCandle.Date); position.StopLoss.SetDate(currentCandle.Date);
position.StopLoss.SetStatus(TradeStatus.Filled); position.StopLoss.SetStatus(TradeStatus.Filled);
// Cancel TP trades when SL is used for manual close
if (position.TakeProfit1 != null)
{
position.TakeProfit1.SetStatus(TradeStatus.Cancelled);
}
if (position.TakeProfit2 != null)
{
position.TakeProfit2.SetStatus(TradeStatus.Cancelled);
}
} }
Logger.LogInformation( Logger.LogInformation(