TD Sequential EA MQL5: Code Setup & Countdown Logic

Build a working TD Sequential EA in MQL5 with correct setup and countdown logic, practical filters, and honest backtesting advice.

td-sequential-ea-mql5-code-setup-countdown-logic

Most traders who discover Tom DeMark's TD Sequential do the same thing I did: stare at the chart, watch it call a bottom perfectly, and immediately think "I need this in an EA." Then they open MetaEditor, stare at the blank file, and realize the logic is deceptively messy. It's not a crossover or a moving average — it's a state machine with two distinct phases, and getting it wrong means your EA fires signals three bars late or not at all.

This post is for developers who've coded a few MQL5 EAs and want a genuinely working TD Sequential implementation. I'll walk through the exact logic, give you the core functions, and — more importantly — show you where this indicator fails so you don't blow up your account learning the hard way.

What TD Sequential Actually Measures

Tom DeMark's system has two parts: the setup and the countdown. Most articles blur them together, which is why so many "TD Sequential" indicators you download from forums are just the setup phase with a counter painted on the chart. That's not the full system.

The setup phase looks for a specific sequence of closing prices. For a buy setup, you need nine consecutive closes where each close is lower than the close four bars earlier. That's it — close[1] < close[5], close[2] < close[6], and so on through nine bars. The sell setup is the mirror: nine closes higher than four bars prior.

The countdown phase is where the real exhaustion signal lives. Once a setup completes, you start counting from the setup's final bar (bar 13 in DeMark's original numbering, but let's not get pedantic). A countdown bar qualifies when its close is lower than the low two bars earlier — again, for buys. You need thirteen of these qualifying bars. Sell countdowns use closes higher than the high two bars back.

Here's the nuance most coders miss: the countdown doesn't restart when the setup restarts. If a new buy setup completes while an old countdown is still running, you don't discard the countdown — you keep it and add the new setup's completion as a second candidate. DeMark's original rules also include a "relaxed" countdown variant that allows a countdown bar to qualify if the close is lower than the close two bars earlier, but I'd skip that for your first version. It adds ambiguity without much benefit.

The Original Numbering vs. What You'll Actually Code

DeMark numbers bars starting at 1, so the setup's ninth bar is also bar 13 in his full sequence (1-9 setup, then 10-13 countdown). In MQL5, bar indexing starts at 0 for the current bar, and shift 1 is the last completed bar. This off-by-one confusion is the single most common bug I see in forum-posted TD Sequential code. When you're testing your setup detection, verify it against a manually counted chart before trusting any signal.

Why This Is Harder to Code Than It Looks

The core challenge in MQL5 is bar state management. You can't just check the current bar and fire a signal — the setup takes nine bars to build, and the countdown takes up to thirteen after that. Your EA needs to track which phase it's in, remember the setup's completion bar, and handle the case where price gaps through your entry while you're waiting.

There's also the repainting question. I've seen TD Sequential indicators that repaint because they use the current forming bar's close. For an EA, you absolutely must wait for the bar to close before confirming a signal. If you don't, your backtest results will be fiction — the indicator will "know" the close before it happens. My rule: only evaluate completed bars. The current bar is for entry execution, never for signal generation.

Let me show you the core setup detection function. This is the skeleton you'll build on:

// Returns 1 for buy setup, -1 for sell setup, 0 for none
int DetectSetup(const string symbol, const ENUM_TIMEFRAMES tf)
{
    // We need at least 14 completed bars for a 9-bar setup
    // with the 4-bar lookback
    if(Bars(symbol, tf) < 14) return 0;

    bool buySetup = true;
    bool sellSetup = true;

    for(int i = 1; i <= 9; i++)
    {
        double closeI = iClose(symbol, tf, i);
        double closeI4 = iClose(symbol, tf, i + 4);

        if(closeI >= closeI4) buySetup = false;
        if(closeI <= closeI4) sellSetup = false;
    }

    if(buySetup) return 1;
    if(sellSetup) return -1;
    return 0;
}

Notice I'm using iClose() with explicit shift values rather than the CopyClose() array approach. For a single-bar check this is cleaner and less error-prone. If you're doing this inside OnTick() on every tick, you'll want to cache the result and only recompute when a new bar opens — checking for NewBar() is a standard pattern.

The countdown phase is where the state tracking gets real. You need a struct or a set of global variables that persist across ticks:

struct TDState
{
    int   setupDirection;    // 1=buy, -1=sell
    int   setupCompleteBar;  // bar index when setup finished
    int   countdownCount;    // qualifying bars so far
    bool  countdownActive;
    bool  signalFired;
};

TDState g_state;

When a setup completes, you initialize the countdown. Then on each new bar, you check whether the current bar qualifies for the countdown. For a buy countdown, bar i qualifies if Close[i] < Low[i+2]. You increment the counter, and when it hits 13, you have a TD Buy Countdown 13 — the exhaustion signal.

Why the Countdown Is Not Sequential

A common beginner mistake is assuming the countdown bars must be consecutive. They don't. You might get three qualifying bars in a row, then a non-qualifying bar, then two more qualifying bars. The counter only increments on qualifying bars, and it doesn't reset on non-qualifying ones. This is why a simple loop over the last N bars won't work — you need persistent state that tracks how many qualifying bars you've accumulated since the setup completed.

There's also a subtle rule about countdown cancellation. DeMark specifies that if price makes a new low (for a buy countdown) below the setup's low, the countdown is cancelled and you start over. I've seen implementations that skip this rule, and it makes a meaningful difference in trending markets. A new price extreme invalidates the exhaustion thesis — the market isn't exhausted, it's accelerating.

Building the Counter-Trend EA Entry Logic

So you've got the signal. Now what? The naive approach — "buy at countdown 13, sell at countdown 13" — will lose money in a trending market. TD Sequential is a mean-reversion tool. It works beautifully in ranging markets and gets destroyed in strong trends. The 2020 COVID crash and the 2021 crypto bull run both produced countdown 13 signals that kept going.

You need filters. Here's what I've found actually helps, in rough order of importance:

  1. Trend filter: Only take buy signals when price is above the 200-period moving average, or sell signals below it. This sounds counterintuitive for a counter-trend system, but it prevents you from catching a falling knife in a genuine crash.
  2. Volatility filter: Skip signals when ATR is above a threshold. High volatility means the "exhaustion" is just noise.
  3. Time filter: Some sessions produce better mean reversion than others. For forex, London and New York overlap is where I see the best setups.
  4. Multiple timeframe confirmation: A countdown 13 on H1 that aligns with a setup on H4 is far stronger than one that conflicts.

Here's a realistic input block for your EA:

ParameterTypeDefaultDescription
InpUseTrendFilterbooltrueOnly take buys above / sells below the trend MA.
InpTrendMAPeriodint200Period for the trend filter MA.
InpUseATRFilterbooltrueSkip signals when ATR exceeds the threshold.
InpATRThresholddouble2.5ATR value in price units above which signals are skipped.
InpStopLossPipsint150Stop loss in points (10x pips for 5-digit brokers).
InpTakeProfitPipsint100Take profit in points.
InpMaxSpreadint30Skip entries if spread exceeds this many points.

Notice the stop loss is wider than the take profit. That's deliberate — mean reversion trades need room to breathe. If you use a tight stop on a countdown 13 signal, you'll get stopped out on the very volatility spike that often precedes the reversal. I've seen this kill more TD Sequential EAs than any other single mistake.

Position Sizing for Mean Reversion

Because you're trading against the prevailing move, your win rate will be lower than a trend-following system. You need to size positions so that a string of 5-6 losses doesn't cripple the account. I use a fixed fractional approach: risk 0.5% per trade, computed from the stop distance in points. That means smaller lots on high-ATR pairs like GBPJPY and larger on EURUSD. The PositionSize calculation in MQL5 uses NormalizeDouble() to respect the broker's lot step, and you'll want to check SYMBOL_VOLUME_MIN and SYMBOL_VOLUME_MAX before placing orders.

The Countdown Signal in Practice

Let's walk through a realistic scenario. Say you're on EURUSD H1, and you get a completed buy setup — nine bars closing lower than four bars prior. You mark that bar. Over the next several hours, you watch for countdown qualifying bars: closes below the low two bars back. Some bars qualify, some don't. It's not sequential — bar 5 might qualify, bar 6 might not, bar 7 qualifies again. The counter only increments on qualifying bars.

When the counter hits 13, you have your signal. But here's the thing — that signal might come 20 bars after the setup

Want to build your own version?

Recreate similar entry logic, risk rules, and filters in TradingBotMaker—no MQL coding. Start free.

Community

Clap for the article and open comments only when you want to read them.

0 claps0 comments

Related articles