I’ve structured the file I/O to use the FILE_COMMON flag. This saves the CSV to your shared Terminal Common/Files directory, making it immediately accessible for data analysis without having to dig through isolated instance folders.
Code: Select all
//+------------------------------------------------------------------+
//| Background_Execution_Logger.mq5 |
//+------------------------------------------------------------------+
#property copyright "Execution Logger"
#property version "1.10"
input string InpFileName = "Liquidity_Sweeps_Log.csv";
int fileHandle = INVALID_HANDLE;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Open file in common folder so it's easily accessible and shared
// FILE_COMMON saves to: %APPDATA%\MetaQuotes\Terminal\Common\Files
fileHandle = FileOpen(InpFileName, FILE_READ | FILE_WRITE | FILE_CSV | FILE_ANSI | FILE_COMMON, ',');
if(fileHandle != INVALID_HANDLE)
{
if(FileSize(fileHandle) == 0)
{
// Write headers if file is new
FileWrite(fileHandle, "GMT_Time", "Local_Ms_Tick", "Symbol", "Action", "Requested_Price", "Fill_Price", "Slippage_Points", "Volume", "Deal_Ticket");
}
// Move pointer to the end of the file for rolling append
FileSeek(fileHandle, 0, SEEK_END);
Print("Background Execution Logger Initialized. Writing to Common/Files/", InpFileName);
}
else
{
Print("Error opening file: ", GetLastError());
return(INIT_FAILED);
}
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(fileHandle != INVALID_HANDLE)
{
FileClose(fileHandle);
Print("Execution Logger file closed.");
}
}
//+------------------------------------------------------------------+
//| TradeTransaction function |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction &trans,
const MqlTradeRequest &request,
const MqlTradeResult &result)
{
if(trans.type != TRADE_TRANSACTION_DEAL_ADD)
return;
ulong dealTicket = trans.deal;
if(HistoryDealSelect(dealTicket))
{
ulong orderTicket = HistoryDealGetInteger(dealTicket, DEAL_ORDER);
if(HistoryOrderSelect(orderTicket))
{
string symbol = HistoryDealGetString(dealTicket, DEAL_SYMBOL);
double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
if(point == 0) return;
ENUM_ORDER_TYPE orderType = (ENUM_ORDER_TYPE)HistoryOrderGetInteger(orderTicket, ORDER_TYPE);
long orderReason = HistoryOrderGetInteger(orderTicket, ORDER_REASON);
double requestedPrice = HistoryOrderGetDouble(orderTicket, ORDER_PRICE_OPEN);
double fillPrice = HistoryDealGetDouble(dealTicket, DEAL_PRICE);
double volume = HistoryDealGetDouble(dealTicket, DEAL_VOLUME);
double slippagePoints = 0;
if(orderType == ORDER_TYPE_BUY || orderType == ORDER_TYPE_BUY_STOP || orderType == ORDER_TYPE_BUY_LIMIT || orderType == ORDER_TYPE_BUY_STOP_LIMIT)
{
slippagePoints = (fillPrice - requestedPrice) / point;
}
else if(orderType == ORDER_TYPE_SELL || orderType == ORDER_TYPE_SELL_STOP || orderType == ORDER_TYPE_SELL_LIMIT || orderType == ORDER_TYPE_SELL_STOP_LIMIT)
{
slippagePoints = (requestedPrice - fillPrice) / point;
}
string orderTypeStr = EnumToString(orderType);
if(orderReason == ORDER_REASON_SL) orderTypeStr = "STOP_LOSS";
else if(orderReason == ORDER_REASON_TP) orderTypeStr = "TAKE_PROFIT";
// Format timestamp for London hour alignment (GMT baseline)
datetime timeGMT = TimeGMT();
string timeStr = TimeToString(timeGMT, TIME_DATE | TIME_SECONDS);
ulong localMs = GetMicrosecondCount() / 1000; // Track millisecond pacing
// Append row to CSV
if(fileHandle != INVALID_HANDLE)
{
FileWrite(fileHandle, timeStr, localMs, symbol, orderTypeStr, requestedPrice, fillPrice, slippagePoints, volume, dealTicket);
// Force write to disk immediately. Prevents data loss if the terminal crashes
// or connection is lost during high-frequency liquidity events.
FileFlush(fileHandle);
}
PrintFormat("LOGGED -> %s | Vol: %.2f | Slippage: %.1f pts", symbol, volume, slippagePoints);
}
}
}