Update the ProExecutionFilter to listen for closed positions and capture the TradeResult from ExecuteMarketOrder. Because cTrader executes market orders synchronously, you get the Position.Id immediately upon a successful fill.
Code: Select all
public class ProExecutionFilter : Robot
{
// ... (existing parameters and properties) ...
protected override void OnStart()
{
// ... (existing init logic) ...
_logger = new SqlServerLogger(DbConnectionString);
_validator = new ExecutionValidator(this, _cpiStart, _cpiEnd);
_hud = new ChartHud(this);
Chart.KeyDown += OnChartKeyDown;
Positions.Closed += OnPositionsClosed; // Subscribe to closure events
UpdateHud();
}
private void TryExecute(TradeType tradeType)
{
ValidationResult result = _validator.Validate();
if (!result.IsValid)
{
Print($"🔴 REJECTED: {result.Reason} | Spread: {result.CurrentSpread:F1}");
_logger.LogExecutionAsync(result, SymbolName, tradeType, VolumeInUnits, false);
return;
}
// Await the synchronous broker execution
TradeResult tradeResult = ExecuteMarketOrder(tradeType, SymbolName, VolumeInUnits, "ExecutionFilter", 0, 0);
if (tradeResult.IsSuccessful)
{
Print($"🟢 ACCEPTED | Spread: {result.CurrentSpread:F1}");
// Log the accepted trade and map it to the generated Position ID
_logger.LogExecutionAsync(result, SymbolName, tradeType, VolumeInUnits, true, tradeResult.Position.Id);
}
}
private void OnPositionsClosed(PositionClosedEventArgs args)
{
// Only update database for positions opened by this specific bot
if (args.Position.Label == "ExecutionFilter")
{
_logger.UpdateOutcomeAsync(args.Position.Id, args.Position.NetProfit);
}
}
}