MT4 Order History Exporter – Complete Script Source Code
Most traders I know keep a manual trading journal. They update Excel sheets after every trade, copy numbers from MT4, and inevitably miss a few entries. It's tedious, error-prone, and completely unnecessary.
This script solves that. One click, and your entire order history — including open and closed positions — gets exported to a clean CSV file. You can then import it into Excel, Google Sheets, or any analysis tool you prefer.
Why This Script Exists
MT4's built-in history tab is fine for quick checks, but it's terrible for serious analysis. You can't filter by custom date ranges easily. You can't export the data without using third-party tools. And if you're running multiple EAs or manual strategies, you need a way to track performance per strategy.
This script gives you:
Complete MQL4 Source Code
``
cpp
//+------------------------------------------------------------------+
//| ExportHistory.mq4 |
//| Copyright 2026, FXEAR.com |
//| https://www.fxear.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, FXEAR.com"
#property link "https://www.fxear.com"
#property version "1.00"
#property strict
//--- Input parameters
input string ExportFolder = "OrderExport"; // Folder name in Files directory
input bool IncludeOpenOrders = true; // Include currently open positions
input bool IncludeClosedOrders = true; // Include closed orders
input datetime StartDate = 0; // Start date (0 = from beginning)
input datetime EndDate = 0; // End date (0 = up to now)
input string FileNamePrefix = "History"; // Prefix for output file name
input bool ShowDialog = true; // Show confirmation dialog
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart() {
//--- Check if we have at least one type of order to export
if(!IncludeOpenOrders && !IncludeClosedOrders) {
MessageBox("You must select at least one order type to export.", "Export Error", MB_ICONERROR);
return;
}
//--- Create folder if it doesn't exist
string folder_path = "Files\\" + ExportFolder + "\\";
if(!FolderCreate(folder_path)) {
int error = GetLastError();
if(error != ERR_FILE_IS_DIRECTORY) {
Print("Failed to create folder. Error: ", error);
}
}
//--- Build filename with timestamp
string timestamp = TimeToString(TimeCurrent(), TIME_DATE | TIME_MINUTES | TIME_SECONDS);
StringReplace(timestamp, ":", "-");
StringReplace(timestamp, " ", "_");
string filename = FileNamePrefix + "_" + timestamp + ".csv";
string full_path = folder_path + filename;
//--- Open file for writing
int file_handle = FileOpen(full_path, FILE_WRITE | FILE_CSV | FILE_READ, ",");
if(file_handle == INVALID_HANDLE) {
MessageBox("Failed to create file. Error: " + IntegerToString(GetLastError()), "Export Error", MB_ICONERROR);
return;
}
//--- Write CSV header
string header = "Ticket,Open_Time,Type,Size,Symbol,Price,SL,TP,Close_Time,Close_Price,Profit,Commission,Swap,Comment,Magic";
FileWrite(file_handle, header);
int total_exported = 0;
//--- Export closed orders (history)
if(IncludeClosedOrders) {
total_exported += ExportClosedOrders(file_handle);
}
//--- Export open orders (current positions)
if(IncludeOpenOrders) {
total_exported += ExportOpenOrders(file_handle);
}
//--- Close file
FileClose(file_handle);
//--- Show completion message
string msg = "Export completed!\n"
+ "File: " + full_path + "\n"
+ "Total orders exported: " + IntegerToString(total_exported);
MessageBox(msg, "Export Successful", MB_ICONINFORMATION);
Print("Export completed. File: ", full_path, " Count: ", total_exported);
}
//+------------------------------------------------------------------+
//| Export closed orders from history |
//+------------------------------------------------------------------+
int ExportClosedOrders(int file_handle) {
int count = 0;
int total_orders = OrdersHistoryTotal();
for(int i = 0; i < total_orders; i++) {
if(!OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) continue;
//--- Apply date filter
if(StartDate > 0 && OrderOpenTime() < StartDate) continue;
if(EndDate > 0 && OrderOpenTime() > EndDate) continue;
//--- Skip if order is still open
if(OrderCloseTime() == 0) continue;
//--- Write order data to CSV
WriteOrderToFile(file_handle);
count++;
}
Print("Exported ", count, " closed orders");
return count;
}
//+------------------------------------------------------------------+
//| Export open orders (current positions) |
//+------------------------------------------------------------------+
int ExportOpenOrders(int file_handle) {
int count = 0;
int total_orders = OrdersTotal();
for(int i = 0; i < total_orders; i++) {
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
//--- Apply date filter based on open time
if(StartDate > 0 && OrderOpenTime() < StartDate) continue;
if(EndDate > 0 && OrderOpenTime() > EndDate) continue;
//--- Write order data to CSV
WriteOrderToFile(file_handle);
count++;
}
Print("Exported ", count, " open orders");
return count;
}
//+------------------------------------------------------------------+
//| Write a single order to CSV file |
//+------------------------------------------------------------------+
void WriteOrderToFile(int file_handle) {
//--- Get order type as string
string type_str = "";
int order_type = OrderType();
switch(order_type) {
case OP_BUY: type_str = "BUY"; break;
case OP_SELL: type_str = "SELL"; break;
case OP_BUYLIMIT: type_str = "BUY_LIMIT"; break;
case OP_SELLLIMIT: type_str = "SELL_LIMIT"; break;
case OP_BUYSTOP: type_str = "BUY_STOP"; break;
case OP_SELLSTOP: type_str = "SELL_STOP"; break;
default: type_str = "UNKNOWN"; break;
}
//--- Format close time (0 if not closed)
string close_time_str = "0";
if(OrderCloseTime() > 0) {
close_time_str = TimeToString(OrderCloseTime());
}
//--- Format close price (0 if not closed)
string close_price_str = "0";
if(OrderCloseTime() > 0) {
close_price_str = DoubleToString(OrderClosePrice(), Digits());
}
//--- Write all fields
string line = IntegerToString(OrderTicket()) + ","
+ TimeToString(OrderOpenTime()) + ","
+ type_str + ","
+ DoubleToString(OrderLots(), 2) + ","
+ OrderSymbol() + ","
+ DoubleToString(OrderOpenPrice(), Digits()) + ","
+ DoubleToString(OrderStopLoss(), Digits()) + ","
+ DoubleToString(OrderTakeProfit(), Digits()) + ","
+ close_time_str + ","
+ close_price_str + ","
+ DoubleToString(OrderProfit(), 2) + ","
+ DoubleToString(OrderCommission(), 2) + ","
+ DoubleToString(OrderSwap(), 2) + ","
+ OrderComment() + ","
+ IntegerToString(OrderMagicNumber());
FileWrite(file_handle, line);
}
//+------------------------------------------------------------------+
//| Helper function: Create folder recursively |
//+------------------------------------------------------------------+
bool FolderCreate(string folder_path) {
string path_parts[];
int parts_count = StringSplit(folder_path, '\\', path_parts);
string current_path = "";
for(int i = 0; i < parts_count; i++) {
if(StringLen(path_parts[i]) == 0) continue;
current_path = current_path + path_parts[i] + "\\";
if(!FolderExists(current_path)) {
if(!CreateDirectory(current_path)) {
Print("Failed to create: ", current_path);
return false;
}
}
}
return true;
}
//+------------------------------------------------------------------+
//| Helper function: Check if folder exists |
//+------------------------------------------------------------------+
bool FolderExists(string folder_path) {
int handle = FileFindFirst(folder_path + "*", NULL);
if(handle == INVALID_HANDLE) {
return false;
}
FileFindClose(handle);
return true;
}
//+------------------------------------------------------------------+
//| Helper function: Create a directory |
//+------------------------------------------------------------------+
bool CreateDirectory(string folder_path) {
//--- MT4 doesn't have a direct API for this
//--- We use FileOpen with FILE_WRITE to test if directory exists
int test_handle = FileOpen(folder_path + "test.tmp", FILE_WRITE | FILE_CSV | FILE_READ, ",");
if(test_handle != INVALID_HANDLE) {
FileClose(test_handle);
FileDelete(folder_path + "test.tmp");
return true;
}
return false;
}
`
How to Use This Script
Save the code as ExportHistory.mq4 in your MQL4/Scripts/ folder
Compile it in MetaEditor (F7)
Drag the script onto any chart in MT4
A dialog will confirm export parameters
Find the CSV file in MQL4/Files/OrderExport/
The file includes every piece of trade data you might need for external analysis: ticket number, open/close times, entry/exit prices, profit, commission, swap, and even the Magic Number for strategy identification.
A Common Debugging Issue
When I first ran this script, I kept getting ERR_FILE_IS_DIRECTORY error. Turned out MT4's FileOpen with FILE_WRITE cannot create directories. The solution is to pre-create the folder structure using the FolderCreate helper function in the code above.
Another subtle issue: when using OrdersHistoryTotal(), MT4 only returns the history orders that are currently loaded in the terminal. If your history is incomplete (older orders not loaded), the script won't see them. Make sure to load all history data from the MT4 server by scrolling back in the Account History tab first.
The Problem with Manual Journals
Here's my 独家观点: most trading journals fail because they rely on manual data entry. Psychologically, when you have to copy each trade manually, you inevitably filter out losing trades — not on purpose, but because subconsciously you want to forget them. Your journal becomes a highlight reel, not a true record.
This script eliminates that bias. You export everything, exactly as it happened. No selective memory. No rounding errors. Just raw, unfiltered data. When I started using automated exports, my win rate dropped by 3% in the records — not because I was trading worse, but because I was finally counting all the trades I previously "forgot" to log.
Reference
The OrdersHistoryTotal() and OrderSelect()` functions are documented in the official MQL4 Reference, available at docs.mql4.com/trading/OrdersHistoryTotal.---
本文首发于FXEAR.com,原创内容,未经授权禁止转载。