Every serious algorithmic trader eventually needs their Expert Advisor or indicator to remember something between runs — trade history, market regime data, custom symbol lists, or optimization results. The built-in MQL4/MQL5 file operations give you that persistence. This guide walks you through reading from and writing to files in both MQL4 and MQL5, covering the exact function calls, the file sandbox rules, CSV handling, and the gotchas that trip up even experienced developers.
What You Will Learn
By the end of this guide you will be able to:
- Open and close files safely using
FileOpenandFileClose - Write structured trade data to CSV files from your EA
- Read back that data and parse it into usable variables
- Handle the MetaTrader file sandbox (the
Filesfolder) correctly - Avoid common pitfalls like unclosed handles and wrong file flags
Prerequisites
Before you begin, ensure you have:
- MetaTrader 4 or 5 (build 600+ for MT4; MT5 is fine as-is)
- MetaEditor installed (comes with the terminal)
- An MQL4 or MQL5 project open (EA, script, or indicator)
- Basic familiarity with MQL syntax — variables, functions,
ifstatements
Understanding the File Sandbox
MetaTrader restricts file access to a specific sandbox folder to protect your system. In MT4, the default path is \MQL4\Files\; in MT5, it is \MQL5\Files\. You can verify this by navigating in MetaEditor to File > Open Data Folder, then looking for the Files subdirectory. Any file operation using a relative filename (e.g., "trades.csv") will resolve inside this sandbox. To access a shared folder across multiple terminal instances (useful for multi-chart EAs), use the FILE_COMMON flag, which places files in \AppData\Roaming\MetaQuotes\Terminal\Common\Files\ (Windows) or the equivalent on other OSes.
Sandbox Limitations and Workarounds
- No absolute paths: You cannot use paths like
C:\Users\...\trades.csv. MQL will reject them. - File size limits: While not enforced by MQL, large files (over 100 MB) can slow down terminal performance. Keep files lean.
- Concurrent access: Multiple EAs on the same chart share the same sandbox. Use unique filenames or the
FILE_COMMONflag to avoid conflicts.
Step-by-Step Instructions: Writing to a File
Step 1: Choose the Right File Flags
Every file operation in MQL begins with FileOpen. You must supply the correct combination of flags. The most common ones are:
| Flag | Value | Purpose |
|---|---|---|
| FILE_TXT | 0 | Opens file in text mode (CR+LF line endings) |
| FILE_CSV | 0 | Opens file in CSV mode (comma-delimited, same as FILE_TXT in MQL4) |
| FILE_BIN | 0 | Opens file in binary mode (no line-ending conversion) |
| FILE_READ | 1 | Allows reading from the file |
| FILE_WRITE | 2 | Allows writing to the file |
| FILE_COMMON | 4096 | Uses the common Files folder shared between terminals |
Combine flags with the bitwise OR operator |. For example, to open a CSV file for both reading and writing: FILE_CSV|FILE_READ|FILE_WRITE.
Step 2: Write Data with FileWrite
Here is a complete MQL4 snippet that writes trade data to a CSV file. The same code works in MQL5 with one difference: in MQL5 you must include #include .
// MQL4 example — writes a trade record to "trades.csv"
int fileHandle = FileOpen("trades.csv", FILE_CSV|FILE_WRITE|FILE_READ, ",");
if(fileHandle != INVALID_HANDLE)
{
FileSeek(fileHandle, 0, SEEK_END); // append to end
FileWrite(fileHandle, TimeToString(TimeCurrent()), Symbol(),
DoubleToString(OrderProfit(), 2), "EURUSD");
FileClose(fileHandle);
Print("Trade recorded successfully.");
}
else
Print("Failed to open file. Error: ", GetLastError());
Key points:
FileOpenreturnsINVALID_HANDLE(-1) on failure — always check this.- The third parameter to
FileOpenis the separator character (comma in this case). FileSeekwithSEEK_ENDpositions the write cursor at the end so you append, not overwrite.FileWriteautomatically adds a newline after each call.
Step 3: Write Binary Data for Efficiency
For high-frequency trading or large datasets, binary mode is faster and more compact. Here is an example writing integer and double values:
// MQL4 example — writes binary trade data
int fileHandle = FileOpen("trades.bin", FILE_BIN|FILE_WRITE|FILE_READ);
if(fileHandle != INVALID_HANDLE)
{
FileSeek(fileHandle, 0, SEEK_END);
FileWriteInteger(fileHandle, (int)TimeCurrent(), INT_VALUE);
FileWriteDouble(fileHandle, OrderProfit());
FileWriteInteger(fileHandle, OrderType(), SHORT_VALUE);
FileClose(fileHandle);
}
When reading binary data, you must read in the exact same order and with matching types. Use FileReadInteger, FileReadDouble, etc. Binary files are not human-readable but are ideal for internal EA state storage.
Step 4: Read Data with FileReadString and FileIsEnding
To read back the data, open the file with FILE_READ and loop until you hit the end:
// MQL4 example — reads all lines from "trades.csv"
int fileHandle = FileOpen("trades.csv", FILE_CSV|FILE_READ, ",");
if(fileHandle != INVALID_HANDLE)
{
while(!FileIsEnding(fileHandle))
{
string timestamp = FileReadString(fileHandle);
string symbol = FileReadString(fileHandle);
string profit = FileReadString(fileHandle);
string pair = FileReadString(fileHandle);
Print("Trade: ", timestamp, " | ", symbol, " | ", profit, " | ", pair);
}
FileClose(fileHandle);
}
else
Print("Failed to open file. Error: ", GetLastError());
Notice that FileReadString reads one field at a time, delimited by the separator you specified in FileOpen. For numeric fields, use FileReadNumber instead.
Advanced Techniques
Handling Large Files with FileTell and FileSize
When dealing with files that may grow large (e.g., logging every tick), use FileSize to check the file size before opening, and FileTell to track your position. This prevents accidental overwrites and helps with partial reads:
int fileHandle = FileOpen("biglog.txt", FILE_TXT|FILE_READ);
if(fileHandle != INVALID_HANDLE)
{
ulong fileSize = FileSize(fileHandle);
if(fileSize > 1048576) // 1 MB limit
{
Print("File too large, truncating...");
FileClose(fileHandle);
FileDelete("biglog.txt");
fileHandle = FileOpen("biglog.txt", FILE_TXT|FILE_WRITE);
}
FileClose(fileHandle);
}
Using FileWriteStruct for Complex Data
MQL5 supports writing entire structures to binary files using FileWriteStruct. This is powerful for saving EA state (e.g., open orders, indicators). Define a struct and write it atomically:
// MQL5 example
struct TradeRecord
{
long ticket;
double price;
int type;
string symbol;
};
// In EA
TradeRecord rec;
rec.ticket = OrderTicket();
rec.price = OrderOpenPrice();
rec.type = OrderType();
rec.symbol = OrderSymbol();
int fileHandle = FileOpen("state.bin", FILE_BIN|FILE_WRITE);
if(fileHandle != INVALID_HANDLE)
{
FileWriteStruct(fileHandle, rec);
FileClose(fileHandle);
}
To read back, use FileReadStruct with the same struct definition.
Tips and Best Practices from Experience
- Always close file handles. Every
FileOpenmust have a matchingFileClose. Use atry-finallypattern in MQL4 by putting the close insideOnDeinitor a cleanup function. - Use FILE_COMMON for multi-instance sharing. If you run the same EA on multiple charts and want them to share one file, add the
FILE_COMMONflag. Otherwise each chart gets its own sandboxedFilesfolder. - Check the file sandbox path. In MT4, files go to
\MQL4\Files\. In MT5, it is\MQL5\Files\. You cannot access files outside this folder unless you useFILE_COMMON. - Handle errors gracefully.
GetLastError()returns the error code after a failed operation. Common codes: 5003 (file not found), 5004 (file already open), 5006 (disk full). - Use FILE_TXT for human-readable logs. CSV mode is fine, but if you only need plain text,
FILE_TXTworks identically and makes the file easier to open in Notepad. - Backup your files regularly. MetaTrader does not automatically backup the
Filesfolder. Copy important CSVs to an external location periodically.
Common Mistakes and Troubleshooting
Mistake 1: Forgetting to Close the File
If your EA crashes or you forget FileClose, the file handle remains locked. The next call to FileOpen will fail with error 5004. Fix: Always call FileClose in a cleanup section, and consider using a global variable to track the handle. For example:
int fileHandle = INVALID_HANDLE;
void OnTick()
{
if(fileHandle == INVALID_HANDLE)
fileHandle = FileOpen("data.csv", FILE_CSV|FILE_WRITE|FILE_READ, ",");
// ... use fileHandle ...
}
void OnDeinit(const int reason)
{
if(fileHandle != INVALID_HANDLE)
FileClose(fileHandle);
}
Mistake 2: Wrong File Flags
Opening a file with FILE_WRITEFrequently Asked Questions
Can I write to a file in the Experts folder instead of Files?
No. MetaTrader restricts file writes to the Files subdirectory of your MQL4/MQL5 folder. Use FILE_COMMON to access a shared folder that all terminals can see.
Why does my file keep getting overwritten instead of appended?
You likely opened the file with FILE_WRITE only. Add FILE_READ to the flags and call FileSeek(fileHandle, 0, SEEK_END) before writing.
How do I read a CSV file with a semicolon delimiter?
Pass the semicolon as the separator in FileOpen: FileOpen("data.csv", FILE_CSV|FILE_READ, ";"). MQL treats the separator literally.
What is the maximum file size MQL can handle?
MQL4/MQL5 can handle files up to 2 GB in practice, but performance degrades with very large files. For logging, consider rotating files daily or weekly.






