Building MACD-Based Support & Resistance Levels

Building MACD-Based Support & Resistance Levels

19 September 2026, 18:44
Jose Rodrgues Chaves
0
21

Building MACD-Based Support & Resistance Levels in MQL5 — A Concept Walkthrough

How I turned MACD crossovers into horizontal price levels — and the design decisions that keep the chart from turning into noise.

The Idea Behind MACD S/R

MACD is one of the oldest momentum indicators in technical analysis. Traders use it for crossovers, divergences, and histogram shifts. But there is a lesser-known use: the price at the moment of a MACD cross often marks a level that matters later.

When MACD crosses above its signal line, the bar that produced the cross tends to sit near a local low. When MACD crosses below its signal, the bar sits near a local high. If we mark those prices and hold them on the chart, we get a support/resistance map that updates automatically as MACD generates new crosses.

That is the entire idea behind this indicator. It draws a small arrow at each cross and — optionally — extends a horizontal line from that bar to the present, with a price label pinned to the right edge. Over time, the levels form a picture of where price has historically reacted to momentum shifts.

This blog walks through how it works and the design decisions behind it. I will not be posting the source — the indicator is on the MQL5 Market — but the concepts are worth sharing.


The Core Inputs

The indicator uses the standard MACD parameters plus two colors and a display toggle:

Fast Length       — EMA/SMA period for the fast moving average
Slow Length       — EMA/SMA period for the slow moving average
Signal Length     — EMA/SMA period for the signal line
Source            — which price to use (close, open, high, low, median, etc.)
Oscillator MA     — SMA or EMA for the fast/slow lines
Signal MA         — SMA or EMA for the signal line
Support Color     — color for bullish (support) levels
Resistance Color  — color for bearish (resistance) levels
Show S/R Lines    — toggle horizontal lines and price labels on/off

Three design choices stand out:

  • Source is configurable. Most MACD implementations hardcode close. Some traders prefer median or typical price. Making it an input costs nothing and adds flexibility.
  • MA types are configurable. Classic MACD uses EMA. Some traders use SMA. Neither is wrong — so both are supported.
  • Lines are optional. The arrows alone are enough for some traders. Others want the full horizontal lines and price tags. The toggle exists because both are legitimate workflows.

How the MACD Series Is Built

The indicator computes MACD from scratch rather than calling the built-in iMACD handle. This is deliberate — it gives full control over the seeding behavior, which matters when matching crossovers exactly.

The conceptual pipeline is:

Step 1 — Compute fast_ma and slow_ma on the chosen source.
         For SMA, wait until `length` bars are available.
         For EMA, seed with the source value on the first bar,
         then apply alpha = 2 / (length + 1).

Step 2 — MACD = fast_ma - slow_ma.
         The value is undefined until both averages are ready.

Step 3 — Signal = SMA or EMA of MACD.
         For SMA, wait until `signal_length` MACD values exist.
         For EMA, seed with the first defined MACD value.

The seeding rules matter more than most people realize. An EMA that seeds with a zero produces a distorted signal line for the first few dozen bars. Seeding with the source value — the standard Wilder-style approach — avoids that distortion entirely.

The same logic applies to the signal line's EMA: it seeds with the first available MACD value, not zero. This is why custom-computed MACD often produces cleaner crossovers than the built-in handle on the first few hundred bars of a chart.


Detecting the Crosses

Once the MACD and signal series exist, detecting a cross is straightforward — compare two adjacent bars:

For each bar i (starting from i = 1):

    If MACD on bar i-1 was above Signal, and MACD on bar i is below:
        Register a bearish cross (Resistance level candidate).

    If MACD on bar i-1 was below Signal, and MACD on bar i is above:
        Register a bullish cross (Support level candidate).

    Skip if either bar's MACD or Signal is undefined.

The undefined check is important. Early bars in the chart do not have enough data to compute MACD or the signal line. Without the check, the code would treat those bars as zeros and produce a false cross against them.


From Cross to Price Level

A MACD cross happens on a specific bar. The price level for the level comes from that bar and its immediate neighbors:

For a bullish cross (Support level):
    Look at the last 6 bars ending at the cross bar.
    Find the minimum low among them.
    Register that minimum as a support level.

For a bearish cross (Resistance level):
    Look at the last 6 bars ending at the cross bar.
    Find the maximum high among them.
    Register that maximum as a resistance level.

The 6-bar lookback is a small but important detail. Using only the cross bar's own high/low would produce levels that sit slightly above or below the actual reaction point. Extending the search backward catches the local extreme that produced the crossover in the first place.


Keeping the Level List Tidy

MACD crosses happen frequently — especially on lower timeframes. Without limits, the indicator would quickly accumulate hundreds of levels and the chart would become unreadable.

Two rules keep the list manageable:

Rule 1 — Cap the list at 20 levels.
         When a new level pushes the count above 20,
         remove the oldest one.

Rule 2 — Remove levels that price has already crossed.
         For a support level, remove it when a later bar's low
         drops below the level.
         For a resistance level, remove it when a later bar's high
         rises above the level.

Rule 2 is the important one. A support level that price has already broken is no longer support — it is history. Removing it automatically keeps the chart focused on the levels that are still in play.

The combination of the two rules means the chart always shows at most 20 active levels, and every level is one that price has not yet violated. That is what makes the indicator readable after hours of running.


How the Levels Are Drawn

Each level is drawn as three chart objects:

1. An arrow marker at the cross bar.
   Support uses an up arrow, offset slightly below the level.
   Resistance uses a down arrow, offset slightly above the level.
   The offset keeps the arrow from overlapping the candle body.

2. A horizontal trendline from the cross bar to the current bar.
   This shows the level extending forward in time.

3. A price label anchored at the right edge of the line.
   The label shows the level's exact price.
   Because the label anchors to the last bar, it follows new bars
   as they form — the label always sits at the leading edge of price.

Three implementation principles guide the drawing routine:

  • Reuse existing objects by name. Each level gets a deterministic object name like SR_Line_SUP_0 or SR_Arrow_RES_3 . On the next update, the code finds the object and moves it rather than creating a new one.
  • Delete stale objects. Any object whose corresponding level no longer exists is removed. This keeps the object count in sync with the level count.
  • Anchor labels to the right edge. Using the last bar as the label anchor means the price tag naturally slides forward as the chart advances, without any per-tick repositioning logic.

Previous Day / Week / Month Levels

The indicator also draws PDH/PDL, PWH/PWL, and PMH/PML lines from the previous period. The implementation is simple:

For each enabled period (day, week, month):
    Read the previous bar's high, low, and time from that timeframe.
    Draw a horizontal line from that time to the right edge of the chart.
    Draw a text label ("PDH", "PDL", etc.) at the right edge.

Use a common prefix ("DWM_") for all of them.
This lets the entire group be cleaned up in one call on removal.

These lines give higher-timeframe context alongside the MACD levels. A bullish MACD cross near the previous week's low is very different from the same cross near the previous week's high — having the D/W/M levels visible makes that distinction obvious.


Update Throttling

MACD crosses are not tick-level events. They happen on closed bars. Recomputing the entire level list on every tick would waste CPU and produce unnecessary chart redraws.

The indicator throttles heavy work to at most once every few seconds:

On every calculation pass:
    If this is the first pass:
        Run the full computation and draw.

    Otherwise:
        Compare the current time to the time of the last full pass.
        If less than N seconds have elapsed, return immediately.
        If N seconds have passed, run the full pass and record the time.

The interval is short enough that new crosses appear promptly, but long enough that a fast-moving market does not trigger a redraw on every tick. On a liquid symbol during active hours, the visual result is identical to a per-tick update — but the CPU cost is a fraction.


What the Indicator Does Not Do

To be clear about what this is:

  • It does not generate buy or sell signals on its own.
  • It does not predict where price will go next.
  • It does not use any repainting logic — every level is derived from closed bars and stays at its original price once placed.

It is a context tool. The levels mark prices where MACD momentum shifts occurred. Whether those prices continue to act as support or resistance is a market question, not an indicator question.

Macd Support and Resistance


What I Learned Building It

  1. Seeding rules for EMA matter more than most people think. Seeding with the source value instead of zero produces a cleaner signal line on the first few hundred bars — which is exactly where most backtests start.
  2. Automatic level removal is essential for readability. Without it, the chart becomes a wall of horizontal lines within an hour. Removing crossed levels keeps the display focused on what is still relevant.
  3. Right-edge anchoring is a small trick with a big payoff. Labels that follow the last bar never need repositioning logic. They just work as the chart advances.
  4. Throttling is invisible when done right. When the update interval is tuned correctly, the user cannot tell whether the indicator is updating per-tick or per-second. The CPU cost, however, is very different.

Wrapping Up

MACD S/R is a small indicator with a clear purpose: turn MACD crossovers into price levels that stay on the chart until price invalidates them. The result is a support/resistance map that grows organically from the momentum indicator traders already watch.

The full version is available on the MQL5 Market — the link is in my profile. If you find any of the design principles here useful — EMA seeding rules, automatic level removal, right-edge anchoring, or update throttling — feel free to apply them in your own indicators. Those patterns are not unique to this tool; they are worth knowing regardless of what you build.

Trade safely.

— Jose Rodrigues Chaves


About the author: Independent MQL5 developer. Interested in clean indicator design and momentum-based context tools. All opinions are my own.