Problem Description
Solution
To save the state of your Expert Advisor (EA) so that data persists across terminal restarts, timeframe changes, or re-initializations, the most efficient method in MQL4 is using Global Variables of the Client Terminal.
These variables are stored on your hard drive by the MetaTrader 4 terminal and remain available until they are explicitly deleted or expire (after 4 weeks of no access).
Method 1: Using Global Variables (Recommended for Simple Data)
This method is best for saving integers or floating-point numbers, such as a "Strategy Step", "Trade Counter", or "Last Order Ticket".
Here is a complete, robust implementation. It generates a unique name for the variable based on the Symbol and Magic Number to prevent conflicts if you run the EA on multiple charts.
//+------------------------------------------------------------------+
//| StatePreservation.mq4 |
//| Copyright 2023, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
//--- Input Parameters
input int MagicNumber = 12345;
//--- Global scope variables (internal to the EA)
int currentStep = 0;
int tradeCounter = 0;
//--- Helper variable to store the unique name
string gv_StepName;
string gv_CountName;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// 1. Create unique names for the Global Variables
// Format: EA_Name + Symbol + MagicNumber + VariableName
string prefix = "MyEA_" + Symbol() + "_" + IntegerToString(MagicNumber) + "_";
gv_StepName = prefix + "Step";
gv_CountName = prefix + "Counter";
// 2. Load the state from the terminal
LoadState();
Print("EA Initialized. Current Step: ", currentStep, " | Counter: ", tradeCounter);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Optional: Save state on exit (though we usually save immediately on change)
SaveState();
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// --- SIMULATION OF STRATEGY LOGIC ---
// Example: Advance step logic
if(currentStep == 0)
{
// Do logic for step 0...
Print("Processing Step 0...");
// Move to next step and increment counter
currentStep = 1;
tradeCounter++;
// CRITICAL: Save state immediately after changing it
SaveState();
}
else if(currentStep == 1)
{
// Do logic for step 1...
Print("Processing Step 1...");
// Reset for demo purposes
currentStep = 0;
tradeCounter++;
SaveState();
}
}
//+------------------------------------------------------------------+
//| Custom Function: Save State to Terminal Global Variables |
//+------------------------------------------------------------------+
void SaveState()
{
// GlobalVariableSet creates the variable if it doesn't exist,
// or updates it if it does.
// Note: Global Variables only store type 'double'.
GlobalVariableSet(gv_StepName, (double)currentStep);
GlobalVariableSet(gv_CountName, (double)tradeCounter);
// Optional: Force flush to disk immediately (good for crash safety)
GlobalVariablesFlush();
}
//+------------------------------------------------------------------+
//| Custom Function: Load State from Terminal Global Variables |
//+------------------------------------------------------------------+
void LoadState()
{
// Check if the variable exists in the terminal
if(GlobalVariableCheck(gv_StepName))
{
// Retrieve and cast back to int
currentStep = (int)GlobalVariableGet(gv_StepName);
}
else
{
// If it doesn't exist (first run), initialize it
currentStep = 0;
GlobalVariableSet(gv_StepName, 0);
}
if(GlobalVariableCheck(gv_CountName))
{
tradeCounter = (int)GlobalVariableGet(gv_CountName);
}
else
{
tradeCounter = 0;
GlobalVariableSet(gv_CountName, 0);
}
}
//+------------------------------------------------------------------+
Method 2: Using Files (For Complex Data)
If you need to save arrays, strings, or complex structures (which Global Variables cannot handle), you should use binary files.
Here is how to save and load a custom structure containing your strategy state:
//+------------------------------------------------------------------+
//| Define a structure to hold your data |
//+------------------------------------------------------------------+
struct StrategyState
{
int currentStep;
int counter;
double lastPrice;
datetime lastTradeTime;
};
StrategyState myState;
string fileName = "MyEA_State_" + Symbol() + ".bin";
//+------------------------------------------------------------------+
//| Save State to File |
//+------------------------------------------------------------------+
void SaveStateToFile()
{
// Open file for writing (Binary mode)
int handle = FileOpen(fileName, FILE_WRITE|FILE_BIN);
if(handle != INVALID_HANDLE)
{
// Write the structure directly to the file
FileWriteStruct(handle, myState);
FileClose(handle);
}
else
{
Print("Error saving state: ", GetLastError());
}
}
//+------------------------------------------------------------------+
//| Load State from File |
//+------------------------------------------------------------------+
void LoadStateFromFile()
{
// Check if file exists
if(FileIsExist(fileName))
{
int handle = FileOpen(fileName, FILE_READ|FILE_BIN);
if(handle != INVALID_HANDLE)
{
// Read the data back into the structure
FileReadStruct(handle, myState);
FileClose(handle);
Print("State loaded. Step: ", myState.currentStep);
}
}
else
{
// Initialize defaults if file doesn't exist
myState.currentStep = 0;
myState.counter = 0;
}
}
Key Differences
-
Global Variables (Method 1):
- Pros: Easiest to implement, viewable in MT4 (Tools -> Global Variables), fast.
- Cons: Only stores numbers (
double), limited to 63 characters for the name.
-
File Operations (Method 2):
- Pros: Can store anything (Structures, Arrays, Strings, History).
- Cons: Slightly more code, data is hidden in the
MQL4/Filesfolder.
Q&A
Q: Where can I see the Global Variables in the terminal?
A: Press F3 in MetaTrader 4, or go to Tools -> Global Variables. You will see your variables listed there with their current values.
Q: What happens if I change the Magic Number?
A: In the code provided in Method 1, the variable name includes the Magic Number. If you change it, the EA will treat it as a fresh instance and create new variables (starting from 0), preserving the state of the previous Magic Number separately.
Q: Do Global Variables survive a computer reboot?
A: Yes. MetaTrader 4 saves these variables to a file on your hard drive. They persist even if the computer is turned off.