fix backtest below 10usdc + update trade
This commit is contained in:
@@ -33,4 +33,5 @@ public interface ITradingRepository
|
|||||||
Task UpdateStrategyAsync(IndicatorBase indicatorBase);
|
Task UpdateStrategyAsync(IndicatorBase indicatorBase);
|
||||||
Task<IndicatorBase> GetStrategyByNameUserAsync(string name, User user);
|
Task<IndicatorBase> GetStrategyByNameUserAsync(string name, User user);
|
||||||
Task<Scenario> GetScenarioByNameUserAsync(string scenarioName, User user);
|
Task<Scenario> GetScenarioByNameUserAsync(string scenarioName, User user);
|
||||||
|
Task UpdateTradeAsync(Trade trade);
|
||||||
}
|
}
|
||||||
@@ -19,6 +19,7 @@ public interface ITradingService
|
|||||||
Task<Scenario> GetScenarioByNameAsync(string scenario);
|
Task<Scenario> GetScenarioByNameAsync(string scenario);
|
||||||
Task InsertPositionAsync(Position position);
|
Task InsertPositionAsync(Position position);
|
||||||
Task UpdatePositionAsync(Position position);
|
Task UpdatePositionAsync(Position position);
|
||||||
|
Task UpdateTradeAsync(Trade trade);
|
||||||
Task<IndicatorBase> GetIndicatorByNameAsync(string strategy);
|
Task<IndicatorBase> GetIndicatorByNameAsync(string strategy);
|
||||||
Task InsertScenarioAsync(Scenario scenario);
|
Task InsertScenarioAsync(Scenario scenario);
|
||||||
Task InsertIndicatorAsync(IndicatorBase indicatorBase);
|
Task InsertIndicatorAsync(IndicatorBase indicatorBase);
|
||||||
|
|||||||
@@ -98,8 +98,8 @@ public class BacktestTradingBotGrain : Grain, IBacktestTradingBotGrain
|
|||||||
if (currentWalletBalance < Constants.GMX.Config.MinimumPositionAmount)
|
if (currentWalletBalance < Constants.GMX.Config.MinimumPositionAmount)
|
||||||
{
|
{
|
||||||
_logger.LogWarning(
|
_logger.LogWarning(
|
||||||
"Backtest stopped early: Wallet balance fell below 10 USDC (Current: {CurrentBalance:F2} USDC) at candle {CurrentCandle}/{TotalCandles} from {CandleDate}",
|
"Backtest stopped early: Wallet balance fell below {MinimumPositionAmount} USDC (Current: {CurrentBalance:F2} USDC) at candle {CurrentCandle}/{TotalCandles} from {CandleDate}",
|
||||||
currentWalletBalance, currentCandle, totalCandles, candle.Date.ToString("yyyy-MM-dd HH:mm"));
|
Constants.GMX.Config.MinimumPositionAmount, currentWalletBalance, currentCandle, totalCandles, candle.Date.ToString("yyyy-MM-dd HH:mm"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -420,6 +420,12 @@ public class TradingBotBase : ITradingBot
|
|||||||
if (!internalPosition.Status.Equals(PositionStatus.New))
|
if (!internalPosition.Status.Equals(PositionStatus.New))
|
||||||
{
|
{
|
||||||
internalPosition.Status = PositionStatus.Filled;
|
internalPosition.Status = PositionStatus.Filled;
|
||||||
|
|
||||||
|
// Update Open trade status when position becomes Filled
|
||||||
|
if (internalPosition.Open != null)
|
||||||
|
{
|
||||||
|
internalPosition.Open.SetStatus(TradeStatus.Filled);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -431,7 +437,8 @@ public class TradingBotBase : ITradingBot
|
|||||||
|
|
||||||
if (orders.Any())
|
if (orders.Any())
|
||||||
{
|
{
|
||||||
if (orders.Count() >= 3)
|
var ordersCount = orders.Count();
|
||||||
|
if (ordersCount >= 3)
|
||||||
{
|
{
|
||||||
var currentTime = Config.IsForBacktest ? LastCandle?.Date ?? DateTime.UtcNow : DateTime.UtcNow;
|
var currentTime = Config.IsForBacktest ? LastCandle?.Date ?? DateTime.UtcNow : DateTime.UtcNow;
|
||||||
var timeSinceRequest = currentTime - positionForSignal.Open.Date;
|
var timeSinceRequest = currentTime - positionForSignal.Open.Date;
|
||||||
@@ -467,7 +474,7 @@ public class TradingBotBase : ITradingBot
|
|||||||
$"⏳ **Waiting for Orders**\nPosition has `{orders.Count()}` open orders\nElapsed: `{timeSinceRequest.TotalMinutes:F1}min`\nWaiting `{remainingMinutes:F1}min` more before canceling");
|
$"⏳ **Waiting for Orders**\nPosition has `{orders.Count()}` open orders\nElapsed: `{timeSinceRequest.TotalMinutes:F1}min`\nWaiting `{remainingMinutes:F1}min` more before canceling");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (orders.Count() == 2 && Positions[internalPosition.Identifier].Status == PositionStatus.New)
|
else if (ordersCount == 2)
|
||||||
{
|
{
|
||||||
// Check if position is already open on broker with 2 orders
|
// Check if position is already open on broker with 2 orders
|
||||||
await LogInformation(
|
await LogInformation(
|
||||||
@@ -488,7 +495,6 @@ public class TradingBotBase : ITradingBot
|
|||||||
UpdatePositionPnl(positionForSignal.Identifier, brokerPosition.ProfitAndLoss.Realized);
|
UpdatePositionPnl(positionForSignal.Identifier, brokerPosition.ProfitAndLoss.Realized);
|
||||||
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
|
||||||
await NotifyAgentAndPlatformGrainAsync(AgentSummaryEventType.PositionOpened,
|
await NotifyAgentAndPlatformGrainAsync(AgentSummaryEventType.PositionOpened,
|
||||||
$"Position found on broker with 2 orders: {internalPosition.Identifier}", internalPosition);
|
$"Position found on broker with 2 orders: {internalPosition.Identifier}", internalPosition);
|
||||||
@@ -1118,6 +1124,7 @@ public class TradingBotBase : ITradingBot
|
|||||||
{
|
{
|
||||||
closingPrice = position.StopLoss.Price;
|
closingPrice = position.StopLoss.Price;
|
||||||
position.StopLoss.SetDate(currentCandle.Date);
|
position.StopLoss.SetDate(currentCandle.Date);
|
||||||
|
position.StopLoss.SetStatus(TradeStatus.Filled);
|
||||||
|
|
||||||
Logger.LogInformation(
|
Logger.LogInformation(
|
||||||
$"🛑 **Stop Loss Execution Confirmed**\n" +
|
$"🛑 **Stop Loss Execution Confirmed**\n" +
|
||||||
@@ -1129,6 +1136,7 @@ public class TradingBotBase : ITradingBot
|
|||||||
{
|
{
|
||||||
closingPrice = position.TakeProfit1.Price;
|
closingPrice = position.TakeProfit1.Price;
|
||||||
position.TakeProfit1.SetDate(currentCandle.Date);
|
position.TakeProfit1.SetDate(currentCandle.Date);
|
||||||
|
position.TakeProfit1.SetStatus(TradeStatus.Filled);
|
||||||
|
|
||||||
Logger.LogInformation(
|
Logger.LogInformation(
|
||||||
$"🎯 **Take Profit Execution Confirmed**\n" +
|
$"🎯 **Take Profit Execution Confirmed**\n" +
|
||||||
@@ -1154,10 +1162,12 @@ public class TradingBotBase : ITradingBot
|
|||||||
if (isManualCloseProfitable)
|
if (isManualCloseProfitable)
|
||||||
{
|
{
|
||||||
position.TakeProfit1.SetDate(currentCandle.Date);
|
position.TakeProfit1.SetDate(currentCandle.Date);
|
||||||
|
position.TakeProfit1.SetStatus(TradeStatus.Filled);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
position.StopLoss.SetDate(currentCandle.Date);
|
position.StopLoss.SetDate(currentCandle.Date);
|
||||||
|
position.StopLoss.SetStatus(TradeStatus.Filled);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.LogInformation(
|
Logger.LogInformation(
|
||||||
@@ -1193,6 +1203,15 @@ public class TradingBotBase : ITradingBot
|
|||||||
|
|
||||||
await SetPositionStatus(position.SignalIdentifier, PositionStatus.Finished);
|
await SetPositionStatus(position.SignalIdentifier, PositionStatus.Finished);
|
||||||
|
|
||||||
|
// Update position in database with all trade changes
|
||||||
|
if (!Config.IsForBacktest)
|
||||||
|
{
|
||||||
|
await ServiceScopeHelpers.WithScopedService<ITradingService>(_scopeFactory, async tradingService =>
|
||||||
|
{
|
||||||
|
await tradingService.UpdatePositionAsync(position);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Update the last position closing time for cooldown period tracking
|
// Update the last position closing time for cooldown period tracking
|
||||||
LastPositionClosingTime = Config.IsForBacktest ? currentCandle.Date : DateTime.UtcNow;
|
LastPositionClosingTime = Config.IsForBacktest ? currentCandle.Date : DateTime.UtcNow;
|
||||||
|
|
||||||
@@ -1299,6 +1318,12 @@ public class TradingBotBase : ITradingBot
|
|||||||
Positions.Values.First(p => p.SignalIdentifier == signalIdentifier).Status = positionStatus;
|
Positions.Values.First(p => p.SignalIdentifier == signalIdentifier).Status = positionStatus;
|
||||||
await LogInformation(
|
await LogInformation(
|
||||||
$"📊 **Position Status Change**\nPosition: `{signalIdentifier}`\nStatus: `{position.Status}` → `{positionStatus}`");
|
$"📊 **Position Status Change**\nPosition: `{signalIdentifier}`\nStatus: `{position.Status}` → `{positionStatus}`");
|
||||||
|
|
||||||
|
// Update Open trade status when position becomes Filled
|
||||||
|
if (positionStatus == PositionStatus.Filled && position.Open != null)
|
||||||
|
{
|
||||||
|
position.Open.SetStatus(TradeStatus.Filled);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SetSignalStatus(signalIdentifier,
|
SetSignalStatus(signalIdentifier,
|
||||||
|
|||||||
@@ -184,6 +184,11 @@ public class TradingService : ITradingService
|
|||||||
await _tradingRepository.UpdatePositionAsync(position);
|
await _tradingRepository.UpdatePositionAsync(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task UpdateTradeAsync(Trade trade)
|
||||||
|
{
|
||||||
|
await _tradingRepository.UpdateTradeAsync(trade);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<Position>> GetPositionsAsync()
|
public async Task<IEnumerable<Position>> GetPositionsAsync()
|
||||||
{
|
{
|
||||||
var positions = new List<Position>();
|
var positions = new List<Position>();
|
||||||
|
|||||||
@@ -402,6 +402,52 @@ public class PostgreSqlTradingRepository : ITradingRepository
|
|||||||
: null;
|
: null;
|
||||||
entity.UpdatedAt = DateTime.UtcNow;
|
entity.UpdatedAt = DateTime.UtcNow;
|
||||||
|
|
||||||
|
// Update related trades
|
||||||
|
if (position.Open != null)
|
||||||
|
{
|
||||||
|
await UpdateTradeAsync(position.Open);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (position.StopLoss != null)
|
||||||
|
{
|
||||||
|
await UpdateTradeAsync(position.StopLoss);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (position.TakeProfit1 != null)
|
||||||
|
{
|
||||||
|
await UpdateTradeAsync(position.TakeProfit1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (position.TakeProfit2 != null)
|
||||||
|
{
|
||||||
|
await UpdateTradeAsync(position.TakeProfit2);
|
||||||
|
}
|
||||||
|
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateTradeAsync(Trade trade)
|
||||||
|
{
|
||||||
|
var entity = _context.Trades
|
||||||
|
.AsTracking()
|
||||||
|
.FirstOrDefault(t => t.ExchangeOrderId == trade.ExchangeOrderId);
|
||||||
|
|
||||||
|
if (entity != null)
|
||||||
|
{
|
||||||
|
entity.Date = trade.Date;
|
||||||
|
entity.Direction = trade.Direction;
|
||||||
|
entity.Status = trade.Status;
|
||||||
|
entity.TradeType = trade.TradeType;
|
||||||
|
entity.Ticker = trade.Ticker;
|
||||||
|
entity.Fee = trade.Fee;
|
||||||
|
entity.Quantity = trade.Quantity;
|
||||||
|
entity.Price = trade.Price;
|
||||||
|
entity.Leverage = trade.Leverage;
|
||||||
|
entity.ExchangeOrderId = trade.ExchangeOrderId;
|
||||||
|
entity.Message = trade.Message;
|
||||||
|
entity.UpdatedAt = DateTime.UtcNow;
|
||||||
|
|
||||||
await _context.SaveChangesAsync();
|
await _context.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user