Coding your first Expert Advisor (EA) in MQL5 can feel intimidating if you’re not a programmer. The good news: you don’t need a computer science degree to build a simple, working Forex robot for MetaTrader 5 (MT5).
In this tutorial you’ll go from zero to a complete EA that:
- Trades a Moving Average crossover strategy
- Uses stop loss and take profit
- Trades automatically using the CTrade class
- Can be backtested in the MT5 Strategy Tester
You’ll also get the full source code, tables of parameters, and explanations of how everything works.
1. What You’ll Build (and How We’ll Do It)
We’ll create a simple trend-following Moving Average crossover EA:
- When a fast MA crosses above a slow MA → open a BUY
- When a fast MA crosses below a slow MA → open a SELL
- Only one position at a time per symbol
- Stop Loss and Take Profit in pips
- Runs on any symbol/timeframe you attach it to
1.1. High-Level Roadmap
| Step | What You Do | Result |
|---|---|---|
| 1 | Install / open MetaTrader 5 and MetaEditor | Environment ready |
| 2 | Create a new EA template | Basic skeleton with OnInit() and OnTick() |
| 3 | Define input parameters | User-configurable settings (MA periods, risk) |
| 4 | Write a simple signal function | Detect BUY/SELL based on MA crossover |
| 5 | Use CTrade to open and close positions | EA can place trades automatically |
| 6 | Compile, attach to chart, and backtest | You see your EA in action |
2. Prerequisites
You need:
- MetaTrader 5 installed (desktop version)
- Basic comfort with:
- Opening a chart
- Switching timeframes
- Using Tabs in MT5 (Terminal, Strategy Tester, etc.)
No prior coding experience is required. We’ll explain the important pieces of MQL5 as we go.
3. EA Lifecycle in MQL5: OnInit, OnDeinit, OnTick
Every Expert Advisor in MQL5 is basically a program with event handlers. You don’t call these functions; MT5 calls them for you.
The key ones:
| Function | When It Runs | Typical Use |
|---|---|---|
OnInit() | When EA is attached to chart or recompiled | Initialize variables, check inputs, set handles |
OnDeinit() | When EA is removed / chart closed / terminal exit | Release resources, close files, etc. |
OnTick() | On every new tick (price change) | Main trading logic (signals, orders, updates) |
In this tutorial, we’ll focus mainly on OnInit() and OnTick().

4. The Strategy: Simple Moving Average Crossover
Let’s formalize what the EA should do. This is critical before you write a single line of code.
4.1. Entry Rules
We’ll use two Simple Moving Averages (SMA):
- Fast MA (e.g. 20-period)
- Slow MA (e.g. 50-period)
We detect crossovers using previous bar vs current bar:
- BUY signal:
- On previous bar:
FastMA_prev < SlowMA_prev - On current bar:
FastMA_curr > SlowMA_curr
- On previous bar:
- SELL signal:
- On previous bar:
FastMA_prev > SlowMA_prev - On current bar:
FastMA_curr < SlowMA_curr
- On previous bar:
This avoids reacting to random one-tick noise and ensures a clean crossover.
4.2. Position Management Rules
- Only one open position at a time on the symbol (either BUY or SELL).
- If a BUY signal appears while there is an open SELL, we close the SELL and open a BUY.
- If a SELL signal appears while there is an open BUY, we close the BUY and open a SELL.
- Each trade has:
- Fixed Stop Loss in pips (e.g. 100)
- Fixed Take Profit in pips (e.g. 200)
4.3. EA Input Parameters
We’ll make these user-configurable, so you can tweak them in MT5 without changing code.
| Input Name | Type | Default | Description |
|---|---|---|---|
InpFastMAPeriod | int | 20 | Period of the fast Moving Average |
InpSlowMAPeriod | int | 50 | Period of the slow Moving Average |
InpLots | double | 0.10 | Lot size per trade |
InpStopLossPips | int | 100 | Stop Loss distance in pips |
InpTakeProfitPips | int | 200 | Take Profit distance in pips |
InpSlippage | int | 10 | Max slippage in points (Broker-dependent) |
InpMagicNumber | int | 123456 | Unique ID for this EA’s trades |
InpTradeComment | string | “MA_EA” | Comment attached to trades |
5. Creating the Expert Advisor in MetaEditor
- Open MetaTrader 5.
- Press F4 or click Tools → MetaQuotes Language Editor to open MetaEditor.
- In MetaEditor, click:
- File → New → Expert Advisor (template).
- Name it, e.g.
MA_Crossover_EA. - Choose the folder (usually
MQL5\Experts). - Click Next → Finish.
MetaEditor will generate a basic EA template with empty OnInit(), OnDeinit(), and OnTick() functions.
6. Designing the Code Structure
We’ll structure our EA into three main parts:
- Inputs and Globals
- Signal Detection (function that returns BUY/SELL/NO_SIGNAL)
- Trading Logic (function that manages orders based on the signal)
6.1. Enumerations for Signal Types
We’ll define a small enum to make code more readable:
enum TradeSignal
{
SIGNAL_NONE = 0,
SIGNAL_BUY = 1,
SIGNAL_SELL = -1
};
This is clearer than using raw integers.
7. Coding the EA Step by Step
Let’s build the EA piece by piece, then we’ll show the full source code.

7.1. Includes, Inputs, and Global Variables
We’ll use the standard CTrade class (from Trade.mqh) to simplify order execution.
#include <Trade\Trade.mqh>
CTrade trade; // trading object
//--- input parameters
input int InpFastMAPeriod = 20; // Fast MA Period
input int InpSlowMAPeriod = 50; // Slow MA Period
input double InpLots = 0.10; // Lots
input int InpStopLossPips = 100; // Stop Loss (pips)
input int InpTakeProfitPips = 200; // Take Profit (pips)
input int InpSlippage = 10; // Slippage (points)
input int InpMagicNumber = 123456; // Magic Number
input string InpTradeComment = "MA_EA"; // Trade Comment
//--- enum for signals
enum TradeSignal
{
SIGNAL_NONE = 0,
SIGNAL_BUY = 1,
SIGNAL_SELL = -1
};
//--- global variables
int fast_ma_handle;
int slow_ma_handle;
The handles will refer to the indicator instances created in OnInit().
7.2. Initializing the Moving Averages in OnInit()
We will create two SMA indicators using iMA() and store their handles.
int OnInit()
{
//--- create fast MA
fast_ma_handle = iMA(_Symbol, _Period, InpFastMAPeriod,
0, MODE_SMA, PRICE_CLOSE);
if(fast_ma_handle == INVALID_HANDLE)
{
Print("Failed to create fast MA handle. Error: ", GetLastError());
return(INIT_FAILED);
}
//--- create slow MA
slow_ma_handle = iMA(_Symbol, _Period, InpSlowMAPeriod,
0, MODE_SMA, PRICE_CLOSE);
if(slow_ma_handle == INVALID_HANDLE)
{
Print("Failed to create slow MA handle. Error: ", GetLastError());
return(INIT_FAILED);
}
//--- set magic number for trade object
trade.SetExpertMagicNumber(InpMagicNumber);
Print("MA_Crossover_EA initialized successfully.");
return(INIT_SUCCEEDED);
}
We return INIT_FAILED if indicator creation fails. This prevents the EA from running in an invalid state.
7.3. Cleaning Up in OnDeinit()
void OnDeinit(const int reason)
{
if(fast_ma_handle != INVALID_HANDLE)
IndicatorRelease(fast_ma_handle);
if(slow_ma_handle != INVALID_HANDLE)
IndicatorRelease(slow_ma_handle);
Print("MA_Crossover_EA deinitialized. Reason: ", reason);
}
This releases indicator resources when EA is removed.
7.4. Helper: Getting the Moving Average Values
We need current and previous bar values for each MA. We’ll use CopyBuffer().
bool GetMAs(double &fast_prev, double &fast_curr,
double &slow_prev, double &slow_curr)
{
double fast_ma[2];
double slow_ma[2];
// Copy last 2 values of each MA (index 0 = current bar)
if(CopyBuffer(fast_ma_handle, 0, 0, 2, fast_ma) != 2)
{
Print("Failed to copy fast MA buffer. Error: ", GetLastError());
return(false);
}
if(CopyBuffer(slow_ma_handle, 0, 0, 2, slow_ma) != 2)
{
Print("Failed to copy slow MA buffer. Error: ", GetLastError());
return(false);
}
fast_curr = fast_ma[0];
fast_prev = fast_ma[1];
slow_curr = slow_ma[0];
slow_prev = slow_ma[1];
return(true);
}
7.5. Signal Detection Function
Now we use those values to generate a BUY/SELL/NO_SIGNAL.
TradeSignal GetSignal()
{
double fast_prev, fast_curr;
double slow_prev, slow_curr;
if(!GetMAs(fast_prev, fast_curr, slow_prev, slow_curr))
return(SIGNAL_NONE);
//--- BUY crossover
if(fast_prev < slow_prev && fast_curr > slow_curr)
return(SIGNAL_BUY);
//--- SELL crossover
if(fast_prev > slow_prev && fast_curr < slow_curr)
return(SIGNAL_SELL);
return(SIGNAL_NONE);
}
7.6. Helper: Check Existing Position
We want only one position per symbol and magic number. Let’s create a helper.
int GetCurrentPositionDirection()
{
// returns 1 for BUY, -1 for SELL, 0 for none
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket))
{
string symbol = PositionGetString(POSITION_SYMBOL);
long magic = PositionGetInteger(POSITION_MAGIC);
if(symbol == _Symbol && magic == InpMagicNumber)
{
long type = PositionGetInteger(POSITION_TYPE);
if(type == POSITION_TYPE_BUY)
return(1);
if(type == POSITION_TYPE_SELL)
return(-1);
}
}
}
return(0);
}
7.7. Calculating Stop Loss and Take Profit Prices
We’ll convert pips to price using SymbolInfoDouble and the tick size.
bool CalculateSLTP(double &sl, double &tp, int direction)
{
double price = (direction > 0) ? SymbolInfoDouble(_Symbol, SYMBOL_ASK)
: SymbolInfoDouble(_Symbol, SYMBOL_BID);
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
double pip_value = (digits == 3 || digits == 5) ? (10 * point) : point;
double sl_distance = InpStopLossPips * pip_value;
double tp_distance = InpTakeProfitPips * pip_value;
if(direction > 0) // BUY
{
sl = price - sl_distance;
tp = price + tp_distance;
}
else if(direction < 0) // SELL
{
sl = price + sl_distance;
tp = price - tp_distance;
}
else
return(false);
return(true);
}
7.8. Main Trading Logic in OnTick()
Now we combine everything:
- Get signal
- Check existing position
- If needed, close opposite and open new trade
void OnTick()
{
//--- ignore if not enough bars
if(Bars(_Symbol, _Period) < MathMax(InpFastMAPeriod, InpSlowMAPeriod) + 10)
return;
//--- get signal
TradeSignal signal = GetSignal();
if(signal == SIGNAL_NONE)
return;
int current_dir = GetCurrentPositionDirection();
//--- no existing position
if(current_dir == 0)
{
OpenPosition(signal);
}
else
{
// we have a position
if((current_dir == 1 && signal == SIGNAL_SELL) ||
(current_dir == -1 && signal == SIGNAL_BUY))
{
// opposite signal -> close and reverse
CloseCurrentPosition();
OpenPosition(signal);
}
// if signal same direction as current position, do nothing
}
}
We’ll implement OpenPosition() and CloseCurrentPosition() next.
7.9. Opening a Position
void OpenPosition(TradeSignal signal)
{
int direction = (signal == SIGNAL_BUY) ? 1 : -1;
double sl, tp;
if(!CalculateSLTP(sl, tp, direction))
{
Print("Failed to calculate SL/TP");
return;
}
trade.SetDeviationInPoints(InpSlippage);
bool result = false;
if(direction > 0)
{
result = trade.Buy(InpLots, _Symbol, 0.0, sl, tp, InpTradeComment);
}
else
{
result = trade.Sell(InpLots, _Symbol, 0.0, sl, tp, InpTradeComment);
}
if(!result)
{
Print("Order failed. Error: ", GetLastError());
}
else
{
Print("Opened ", (direction > 0 ? "BUY" : "SELL"),
" ", DoubleToString(InpLots, 2),
" lot(s) at ", DoubleToString(trade.ResultPrice(), _Digits),
", SL=", DoubleToString(sl, _Digits),
", TP=", DoubleToString(tp, _Digits));
}
}
7.10. Closing the Current Position
void CloseCurrentPosition()
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket))
{
string symbol = PositionGetString(POSITION_SYMBOL);
long magic = PositionGetInteger(POSITION_MAGIC);
if(symbol == _Symbol && magic == InpMagicNumber)
{
long type = PositionGetInteger(POSITION_TYPE);
bool result = false;
if(type == POSITION_TYPE_BUY)
result = trade.PositionClose(ticket, InpSlippage);
else if(type == POSITION_TYPE_SELL)
result = trade.PositionClose(ticket, InpSlippage);
if(!result)
Print("Failed to close position #", ticket,
". Error: ", GetLastError());
else
Print("Closed position #", ticket);
}
}
}
}
8. Full Source Code: MA_Crossover_EA.mq5
Here is the complete EA in one piece.
You can copy–paste it into your MQL5\Experts folder in MetaEditor.
//+------------------------------------------------------------------+
//| MA_Crossover_EA |
//| Simple Moving Average Crossover Expert Advisor |
//+------------------------------------------------------------------+
#property strict
#include <Trade\Trade.mqh>
CTrade trade;
//--- inputs
input int InpFastMAPeriod = 20; // Fast MA Period
input int InpSlowMAPeriod = 50; // Slow MA Period
input double InpLots = 0.10; // Lots
input int InpStopLossPips = 100; // Stop Loss (pips)
input int InpTakeProfitPips = 200; // Take Profit (pips)
input int InpSlippage = 10; // Slippage (points)
input int InpMagicNumber = 123456; // Magic Number
input string InpTradeComment = "MA_EA"; // Trade Comment
//--- signal enum
enum TradeSignal
{
SIGNAL_NONE = 0,
SIGNAL_BUY = 1,
SIGNAL_SELL = -1
};
//--- global indicator handles
int fast_ma_handle;
int slow_ma_handle;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- create fast MA handle
fast_ma_handle = iMA(_Symbol, _Period, InpFastMAPeriod,
0, MODE_SMA, PRICE_CLOSE);
if(fast_ma_handle == INVALID_HANDLE)
{
Print("Failed to create fast MA handle. Error: ", GetLastError());
return(INIT_FAILED);
}
//--- create slow MA handle
slow_ma_handle = iMA(_Symbol, _Period, InpSlowMAPeriod,
0, MODE_SMA, PRICE_CLOSE);
if(slow_ma_handle == INVALID_HANDLE)
{
Print("Failed to create slow MA handle. Error: ", GetLastError());
return(INIT_FAILED);
}
//--- set magic number
trade.SetExpertMagicNumber(InpMagicNumber);
Print("MA_Crossover_EA initialized on ", _Symbol,
" timeframe ", EnumToString(_Period));
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(fast_ma_handle != INVALID_HANDLE)
IndicatorRelease(fast_ma_handle);
if(slow_ma_handle != INVALID_HANDLE)
IndicatorRelease(slow_ma_handle);
Print("MA_Crossover_EA deinitialized. Reason: ", reason);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- ensure enough bars for MAs
if(Bars(_Symbol, _Period) < MathMax(InpFastMAPeriod, InpSlowMAPeriod) + 10)
return;
//--- get signal
TradeSignal signal = GetSignal();
if(signal == SIGNAL_NONE)
return;
//--- check current position direction
int current_dir = GetCurrentPositionDirection();
//--- no position yet
if(current_dir == 0)
{
OpenPosition(signal);
}
else
{
// if opposite signal -> close and reverse
if((current_dir == 1 && signal == SIGNAL_SELL) ||
(current_dir == -1 && signal == SIGNAL_BUY))
{
CloseCurrentPosition();
OpenPosition(signal);
}
// if same direction -> do nothing
}
}
//+------------------------------------------------------------------+
//| Get Moving Averages values |
//+------------------------------------------------------------------+
bool GetMAs(double &fast_prev, double &fast_curr,
double &slow_prev, double &slow_curr)
{
double fast_ma[2];
double slow_ma[2];
if(CopyBuffer(fast_ma_handle, 0, 0, 2, fast_ma) != 2)
{
Print("Failed to copy fast MA buffer. Error: ", GetLastError());
return(false);
}
if(CopyBuffer(slow_ma_handle, 0, 0, 2, slow_ma) != 2)
{
Print("Failed to copy slow MA buffer. Error: ", GetLastError());
return(false);
}
fast_curr = fast_ma[0];
fast_prev = fast_ma[1];
slow_curr = slow_ma[0];
slow_prev = slow_ma[1];
return(true);
}
//+------------------------------------------------------------------+
//| Determine trading signal |
//+------------------------------------------------------------------+
TradeSignal GetSignal()
{
double fast_prev, fast_curr;
double slow_prev, slow_curr;
if(!GetMAs(fast_prev, fast_curr, slow_prev, slow_curr))
return(SIGNAL_NONE);
//--- BUY crossover
if(fast_prev < slow_prev && fast_curr > slow_curr)
return(SIGNAL_BUY);
//--- SELL crossover
if(fast_prev > slow_prev && fast_curr < slow_curr)
return(SIGNAL_SELL);
return(SIGNAL_NONE);
}
//+------------------------------------------------------------------+
//| Get current position direction for this EA |
//+------------------------------------------------------------------+
int GetCurrentPositionDirection()
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket))
{
string symbol = PositionGetString(POSITION_SYMBOL);
long magic = PositionGetInteger(POSITION_MAGIC);
if(symbol == _Symbol && magic == InpMagicNumber)
{
long type = PositionGetInteger(POSITION_TYPE);
if(type == POSITION_TYPE_BUY)
return(1);
if(type == POSITION_TYPE_SELL)
return(-1);
}
}
}
return(0);
}
//+------------------------------------------------------------------+
//| Calculate SL and TP prices |
//+------------------------------------------------------------------+
bool CalculateSLTP(double &sl, double &tp, int direction)
{
double price = (direction > 0) ? SymbolInfoDouble(_Symbol, SYMBOL_ASK)
: SymbolInfoDouble(_Symbol, SYMBOL_BID);
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
double pip_value = (digits == 3 || digits == 5) ? (10 * point) : point;
double sl_distance = InpStopLossPips * pip_value;
double tp_distance = InpTakeProfitPips * pip_value;
if(direction > 0) // BUY
{
sl = price - sl_distance;
tp = price + tp_distance;
}
else if(direction < 0) // SELL
{
sl = price + sl_distance;
tp = price - tp_distance;
}
else
return(false);
return(true);
}
//+------------------------------------------------------------------+
//| Open a new position |
//+------------------------------------------------------------------+
void OpenPosition(TradeSignal signal)
{
int direction = (signal == SIGNAL_BUY) ? 1 : -1;
double sl, tp;
if(!CalculateSLTP(sl, tp, direction))
{
Print("Failed to calculate SL/TP.");
return;
}
trade.SetDeviationInPoints(InpSlippage);
bool result = false;
if(direction > 0)
{
result = trade.Buy(InpLots, _Symbol, 0.0, sl, tp, InpTradeComment);
}
else
{
result = trade.Sell(InpLots, _Symbol, 0.0, sl, tp, InpTradeComment);
}
if(!result)
{
Print("Order failed. Error: ", GetLastError());
}
else
{
Print("Opened ", (direction > 0 ? "BUY" : "SELL"),
" ", DoubleToString(InpLots, 2),
" lots at ", DoubleToString(trade.ResultPrice(), _Digits),
", SL=", DoubleToString(sl, _Digits),
", TP=", DoubleToString(tp, _Digits));
}
}
//+------------------------------------------------------------------+
//| Close current position |
//+------------------------------------------------------------------+
void CloseCurrentPosition()
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket))
{
string symbol = PositionGetString(POSITION_SYMBOL);
long magic = PositionGetInteger(POSITION_MAGIC);
if(symbol == _Symbol && magic == InpMagicNumber)
{
long type = PositionGetInteger(POSITION_TYPE);
bool result = trade.PositionClose(ticket, InpSlippage);
if(!result)
Print("Failed to close position #", ticket,
". Error: ", GetLastError());
else
Print("Closed position #", ticket);
}
}
}
}
//+------------------------------------------------------------------+
9. Compiling and Attaching the EA
- Compile:
- In MetaEditor, click Compile or press F7.
- Check the Errors and Warnings panel.
- If there are no errors, your EA is ready.
- Attach to Chart in MT5:
- Go back to MetaTrader 5.
- In the Navigator window → Expert Advisors.
- Find
MA_Crossover_EA. - Drag it onto a chart (e.g., EURUSD H1).
- In the Inputs tab, you can tweak:
- MA periods
- Lots
- Stop Loss / Take Profit, etc.
- Make sure AutoTrading is enabled (green button).
10. Quick Backtest in Strategy Tester
You should never trust a robot until you’ve at least backtested it.

10.1. Running a Basic Backtest
- Press Ctrl+R or open View → Strategy Tester.
- Select:
- Expert:
MA_Crossover_EA - Symbol: e.g.,
EURUSD - Period: e.g.,
H1 - Model: “Every tick” (for better accuracy)
- Date range: pick last 6–12 months
- Expert:
- Click Start.
10.2. Example Backtest Settings Table
| Setting | Value |
|---|---|
| Symbol | EURUSD |
| Timeframe | H1 |
| Period | Last 1 year |
| Fast MA Period | 20 |
| Slow MA Period | 50 |
| Lots | 0.10 |
| SL / TP (pips) | 100 / 200 |
10.3. Sample Interpretation of Results
Look at:
| Metric | What It Tells You |
|---|---|
| Net profit | Overall profit or loss |
| Maximal drawdown | Risk and worst-case drop in equity |
| Profit factor | Gross profit / gross loss (>1 is good) |
| Number of trades | Whether sample size is meaningful |
If you see very few trades, try lowering MA periods or testing a longer date range.
11. Common Pitfalls and How to Avoid Them
11.1. EA Not Trading at All
Checklist:
| Possible Issue | Fix |
|---|---|
| AutoTrading disabled | Enable the AutoTrading button |
| “Algo Trading” not allowed in EA | Check EA settings → Common → Allow live trading |
| Initialization failed (INIT_FAILED) | Look in Experts log for MA handle creation errors |
| Symbol or timeframe too small bars | Lower MA periods or use longer history |
11.2. Wrong SL / TP Values
If your broker uses 5-digit quotes (e.g. 1.12345), a “pip” is often 10 points.
Our CalculateSLTP() function already tries to account for 3/5-digit pricing using:
double pip_value = (digits == 3 || digits == 5) ? (10 * point) : point;
If SL/TP still look off:
- Check Digits for the symbol (
Market Watch → Symbol properties). - Print debug info:
Print("Point=", point, " Digits=", digits, " PipValue=", pip_value);
11.3. EA Opens Too Many Trades
In this EA we restrict to one position per symbol. If you clone the EA with different magic numbers or attach it to several charts, you might unintentionally create multiple active copies.
Mitigation:
- Use a unique MagicNumber per EA instance.
- Optionally add a time filter, so EA only checks once per bar instead of every tick (advanced improvement: use
static datetime last_bar_time;).
12. Where to Go Next: Improving the EA
You now have a fully working MQL5 Expert Advisor that:
- Creates and uses indicators
- Generates signals from MA crossovers
- Opens and closes trades with SL/TP
- Can be optimized and backtested in MT5
Some ideas for your second generation:
- Trade only during specific sessions (e.g., London/NY overlap).
- Add spread filter – don’t trade when the spread is too wide.
- Replace SMA with EMA or other indicators.
- Use multi-timeframe confirmation (e.g., H4 trend, M15 entries).
- Add trailing stop or break-even functions.
