Forex trading on the MetaTrader 4 (MT4) platform offers traders the flexibility to automate strategies and customize technical analysis tools. Two popular ways to extend MT4’s functionality are Expert Advisors (EAs) and custom indicators. EAs are essentially trading robots – programs that can analyze market data and execute trades automatically based on predefined rules. Custom indicators, on the other hand, allow traders to visualize market data or signals in unique ways beyond the standard indicators. This article will explain how to code a simple EA and a custom indicator in MQL4 (MetaQuotes Language 4), using a moving average crossover strategy for the EA and a color-coded Relative Strength Index (RSI) for the indicator. The tone is casual yet informative, targeting intermediate forex traders who have some familiarity with MT4 and basic programming concepts.
Many beginners start by learning trading basics – for example, looking up how to forex trade for beginners on phone apps or simple platforms. As you progress to an intermediate level, you may want more sophisticated tools or even consider automating your strategies. Coding your own EA or indicator can bridge that gap by allowing you to tailor trading strategies and signals to your specific needs. In the sections below, we’ll walk through practical examples with clean, commented code to help you understand how both EAs and custom indicators are created in MQL4.
What is an Expert Advisor (EA) in MT4?
An Expert Advisor is an automated trading system script that runs on MT4 and can execute trades on behalf of the trader based on a coded strategy Unlike manual trading, where you place orders yourself, an EA continuously monitors price ticks and makes decisions instantly according to its algorithm. EAs are especially useful for removing emotion from trading and for acting on strategies 24/7. They are written in MQL4, which is a C++-like programming language designed for MT4. When you attach an EA to a chart, MT4 will initialize it and then call its code on every new tick (price update) in the market. This means your EA’s core logic (written in the OnTick() function) will run repeatedly, evaluating conditions and executing trades as coded.
Key characteristics of an EA:
-
Runs in real-time on the chart it’s attached to, reacting to each price change (tick).
-
Can open, modify, and close orders automatically via trading functions.
-
Often includes input parameters (extern variables) so you can adjust things like lot size, stop-loss, or indicator periods without altering code.
-
Must be tested (e.g., using MT4’s Strategy Tester) to ensure it behaves as expected under various market conditions before live use.
Building a Simple Moving Average Crossover EA
One common strategy for algorithmic trading is the moving average crossover. In this strategy, you use two moving averages (MAs) – a fast (short-period) MA and a slow (long-period) MA. A buy signal is generated when the fast MA crosses above the slow MA (often called a “golden cross”), indicating upward momentum. Conversely, a sell signal occurs when the fast MA crosses below the slow MA (“dead cross”), indicating downward momentum. In terms of coding logic, a crossover is detected by comparing the relationship of the two MAs on the current bar and the previous bar. For example, a fast MA crossing above a slow MA can be defined as: on the previous candle the fast MA was below the slow MA, and on the current candle the fast MA is above the slow MA. This ensures we catch the moment of crossover rather than every time one MA is simply greater than the other.
Steps to create the Moving Average Crossover EA:
1) Define Input Parameters: Set up external variables for things like the fast MA period, slow MA period, lot size, stop-loss, take-profit, etc. These allow easy tweaking of strategy parameters without editing the code.
2) Initialize the EA (OnInit): Perform any one-time setup if needed. In this simple EA, initialization can be minimal (e.g., just returning success).
3) Calculate Indicators on Each Tick (OnTick): On every tick, use MQL4’s built-in iMA function to get the latest values of the fast and slow moving averages. We retrieve both the current bar’s MA values and the previous bar’s values. The iMA function allows us to specify the symbol, timeframe, MA period, MA method (SMA, EMA, etc.), applied price, and shift (0 for current bar, 1 for previous bar).
4) Detect Crossover Conditions: Compare the current and previous MA values to determine if a crossover just happened. If fast MA crossed above slow MA, that’s a buy signal; if fast crossed below slow, that’s a sell signal.
5) Execute Trade Actions: If a buy signal is detected, and no buy trade is currently open, the EA should send a buy order. Similarly, send a sell order on a sell signal if no sell trade is open. For simplicity, our example EA will only hold one position at a time – it will close any opposite trade when a new signal occurs. We use OrderSend() to place orders and OrderClose() to close any existing trade in the opposite direction.
6) Cleanup (OnDeinit): Not much is needed here for our simple EA, but MT4 will call OnDeinit when the EA is removed or the platform closes, where you could release resources or print a log message.
Below is a MQL4 code example of a simple Moving Average Crossover EA. The strategy uses a fast SMA (e.g., 50-period) and a slow SMA (e.g., 100-period) on the current chart and symbol. It will open a buy when a golden cross occurs, or a sell on a dead cross. For brevity, we assume only one trade at a time and we manage basic stop-loss and take-profit for each order:
//— Expert Advisor: Moving Average Crossover
#property strict
// Input parameters for the strategy
extern int FastMAPeriod = 50;
extern int SlowMAPeriod = 100;
extern double LotSize = 0.1;
extern int StopLoss = 50; // in pips
extern int TakeProfit = 100; // in pips
int OnInit() {
// Nothing special to initialize in this simple EA
return(INIT_SUCCEEDED);
}
void OnTick() {
// Calculate current and previous values of the fast and slow MAs
double fastCurr = iMA(NULL, 0, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 0);
double fastPrev = iMA(NULL, 0, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
double slowCurr = iMA(NULL, 0, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 0);
double slowPrev = iMA(NULL, 0, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
// Check for a Buy signal (fast MA crosses above slow MA)
if (fastCurr > slowCurr && fastPrev <= slowPrev) {
// If there is an open sell, close it before buying
if (OrdersTotal() > 0) {
if (OrderSelect(0, SELECT_BY_POS) && OrderType() == OP_SELL && OrderSymbol() == Symbol()) {
OrderClose(OrderTicket(), OrderLots(), Ask, 3, clrBlue);
}
}
// Open a new Buy order if no orders are open
if (OrdersTotal() == 0) {
