Study ›
[Course] [Build an EA 4] First EA: moving-average cross (copy & use)
Let's turn the rules from part 3 into code. In MetaEditor, delete everything in the `MyFirstEA` file from part 2, paste the code below and press F7 (compile).
#include <Trade/Trade.mqh> // helper that makes placing orders easy
input int FastMA = 20; // fast moving average period
input int SlowMA = 50; // slow moving average period
input double Lots = 0.01; // order size
input int StopPts = 3000; // stop loss in points (gold, 2 decimals: 3000 = $30)
input int TakePts = 6000; // take profit in points
input long Magic = 20261103; // tag attached to this EA's orders
CTrade trade;
int hFast, hSlow; // moving average handles
datetime lastBar = 0; // time of the last candle we checked
int OnInit()
{
hFast = iMA(_Symbol, _Period, FastMA, 0, MODE_EMA, PRICE_CLOSE);
hSlow = iMA(_Symbol, _Period, SlowMA, 0, MODE_EMA, PRICE_CLOSE);
if(hFast == INVALID_HANDLE || hSlow == INVALID_HANDLE) return INIT_FAILED;
trade.SetExpertMagicNumber(Magic);
return INIT_SUCCEEDED;
}
void OnDeinit(const int reason)
{
IndicatorRelease(hFast);
IndicatorRelease(hSlow);
}
// does this EA have an open position right now?
bool HasPosition()
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong t = PositionGetTicket(i);
if(PositionSelectByTicket(t)
&& PositionGetString(POSITION_SYMBOL) == _Symbol
&& PositionGetInteger(POSITION_MAGIC) == Magic) return true;
}
return false;
}
void OnTick()
{
// 1) decide only when a new candle opens
datetime bar = iTime(_Symbol, _Period, 0);
if(bar == lastBar) return;
lastBar = bar;
// 2) moving averages of the candle that just closed (1) and the one before (2)
double f[], s[];
ArraySetAsSeries(f, true);
ArraySetAsSeries(s, true);
if(CopyBuffer(hFast, 0, 1, 2, f) < 2 || CopyBuffer(hSlow, 0, 1, 2, s) < 2) return;
bool goldenCross = f[1] <= s[1] && f[0] > s[0]; // crossed from below to above
bool deadCross = f[1] >= s[1] && f[0] < s[0]; // crossed from above to below
// 3) already in a position? sit out (one at a time)
if(HasPosition()) return;
// 4) place the order
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
if(goldenCross)
trade.Buy(Lots, _Symbol, ask,
NormalizeDouble(ask - StopPts * _Point, _Digits),
NormalizeDouble(ask + TakePts * _Point, _Digits), "MA cross");
else if(deadCross)
trade.Sell(Lots, _Symbol, bid,
NormalizeDouble(bid + StopPts * _Point, _Digits),
NormalizeDouble(bid - TakePts * _Point, _Digits), "MA cross");
}What each part means
- input: settings you can change when attaching the EA. Experiment with numbers without touching the code.
- iMA: creates a moving average calculator. Create it once in OnInit and reuse it.
- CopyBuffer(…, 1, 2, …): gets 2 values starting from candle 1 (the one that just closed). `f[0]` is the just-closed candle, `f[1]` the one before.
- Magic: a tag on this EA's orders, so they don't mix with other EAs or manual trades.
- _Point: the symbol's smallest price step. Gold (2 decimals) is 0.01, so 3000 points = $30.
Try it
- F7 → check for `0 errors`
- Attach it to an XAUUSD M15 chart in MT5 (on demo!)
- Check the Toolbox → Experts tab for errors
- When a cross happens, an order goes in. On M15 that may take a few hours.
Want results right away? The Strategy Tester in the next posts runs years of data in seconds. First, part 5 shows how to size positions properly.
