Lesson 2 of 58 min readUpdated Oct 2026

Your First EA: MA Crossover

Line by line through the platform’s example EA — including the warm-up bug.

Written and reviewed by the Fundezy team · how we produce this

The platform ships a complete example: a Simple MA Crossover EA. It buys when a fast moving average crosses above a slow one, and sells on the opposite cross — the purest trend-following starter. Let's read it the way a reviewer would.

The logic in words

  1. Each tick, read the fast MA (period 10) and slow MA (period 30) on the current bar (shift 0) and the previous bar (shift 1).
  2. Bullish cross: fast was ≤ slow on the previous bar, and is > slow now → buy.
  3. Bearish cross: the mirror condition → sell.
  4. Trade one position at a time, fixed lot size from an input.

The code that matters

input int    FastMAPeriod = 10;
input int    SlowMAPeriod = 30;
input double LotSize      = 0.01;

void OnTick()
{
   string symbol = Symbol();
   int    tf     = Period();

   double fastMA_current = iMA(symbol, tf, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE);
   double fastMA_prev    = iMA(symbol, tf, FastMAPeriod, 1, MODE_SMA, PRICE_CLOSE);
   double slowMA_current = iMA(symbol, tf, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE);
   double slowMA_prev    = iMA(symbol, tf, SlowMAPeriod, 1, MODE_SMA, PRICE_CLOSE);

   // Guard: indicators return 0 until enough bars exist
   if (fastMA_current <= 0 || slowMA_current <= 0)
      return;

   bool bullishCross = (fastMA_prev <= slowMA_prev) && (fastMA_current > slowMA_current);
   bool bearishCross = (fastMA_prev >= slowMA_prev) && (fastMA_current < slowMA_current);

   if (bullishCross)  OrderSend(symbol, OP_BUY,  LotSize, Ask, 10, 0, 0, "MA cross up");
   if (bearishCross)  OrderSend(symbol, OP_SELL, LotSize, Bid, 10, 0, 0, "MA cross down");
}

The bug that teaches the most

That innocent-looking guard line — if (fastMA_current <= 0 || slowMA_current <= 0) return; — is the difference between a valid backtest and garbage. Here's why it exists on this platform:

Indicators return 0 until their period's worth of bars exists. An SMA(30) can't be computed until 30 bars have passed. On bar one, iMA returns 0. Without the guard, fastMA_prev (0) ≤ slowMA_prev (0) is true, and any positive current reading looks like a bullish cross — the EA fires a phantom trade on the very first bars. This exact bug was found and fixed in the platform's own test suite.

The lesson generalizes: always check indicator validity during warm-up. Every indicator here has this behavior (RSI returns a neutral 50 during warm-up — same problem, sneakier).

Weaknesses you should already see

You've done Course 03 — spot the flaws:

  • No stop loss, no take profit (zeros passed to OrderSend). A cross-strategy without stops is one trend away from margin trouble.
  • Fixed lot size — the 1% rule should size orders from AccountEquity() and stop distance.
  • Whipsaw exposure — MAs lag; choppy ranges generate serial false crosses.

Each weakness is a hypothesis: "adding a stop at structure improves net P/L." The Strategy Tester is where hypotheses go to be confirmed or destroyed — next lesson.

By the numbers

The bug every first EA hits: iMA() returns 0 — not an error — until its period of bars exists, so an SMA(30) signal computed on the chart's first bar is undefined, not zero. The lesson's example uses periods 10/30 plus a warm-up guard that simply refuses to trade until the slow average has data — two lines that eliminate the entire class of bug.

Practice in the simulator

Open the Strategy Tester with the example EA — apply what you just read with simulated money.

Check your understanding

4 questions · answer all, then submit.

1. Why does the example EA check `fastMA_current <= 0` before trading?
2. What does OrderSend’s 5th argument (10 in the example) represent?
3. From a risk-management view, the biggest flaw in the example EA is…
4. A bullish cross is defined as…