TradingView indicator guides

Madrid Moving Average Ribbon: 18 Color Comparisons and a 100-MA Reference

The ribbon computes nineteen moving averages, but only eighteen shorter averages provide comparisons with the 100-period reference. Each color combines an average’s own change with its position relative to that reference. It does not count independent traders or establish a probability of a future move.

Inspect the Pine Script

The period list and attribution

The periods are 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90 and 100. There is no 95-period line. This reference plots all nineteen: eighteen dynamically colored averages plus a gray 100-period anchor. The 5 and 90 lines are thicker for identification.

The public Madrid author page identifies the publishing account as Madrid and dates the release to March 2015. It describes EMA/SMA ribbons and a separate companion Ribbon Bar study. This example does not implement that companion study or assert an unverified real-world identity for the author.

Read the ordered color conditions

Let A be a shorter average, R the current 100-period average, and ΔA = A − A[1]. Conditions are evaluated in this order:

PositionChangeColor
A > RΔA ≥ 0Lime
A > RΔA < 0Maroon
A < RΔA ≤ 0Red
A < RΔA > 0Green
A = R, or required comparison unavailableAnyGray

A flat average above R is lime. A flat average below R is red because the nonpositive-change branch is tested first. Gray does not mean merely flat or close to the anchor: equality is exact, with no tolerance band. Applying the same comparison to R itself would always give gray because R equals itself.

The slope is the average’s slope, not the current price change or the reference slope. “Lime” also does not require the shorter averages to be arranged in length order; each line is compared only with R.

A price step can make all eighteen comparisons lime

Start with a long constant price of 100 and all EMA states at 100. Move price to 110 for one bar. EMA(N) updates by 2/(N+1) times the ten-point change:

LengthFirst step valueState against EMA100
5103.333333Lime
10101.818182Lime
90100.219780Lime
100100.198020Reference

Every shorter EMA rises more than EMA100, so all eighteen colored lines are lime after one step. A large same-color count therefore does not by itself prove a long-established trend or independent agreement.

If the next close is 102, EMA5 becomes 102.888889 and falls, while EMA100 rises to about 100.233703. EMA5 is maroon even though the close remains above EMA100 and that reference is rising. This synthetic recurrence illustrates the specific comparisons; it is not a return estimate.

A count is not nineteen independent votes

The maximum number of lime or red shorter-line comparisons is eighteen. A count of fourteen means 14/18 of those comparisons, not fourteen independent observations of market participants. All averages consume the same source and heavily overlapping history. If you add a count threshold, specify which lines enter the denominator and how unavailable values are treated.

Ribbon width and line ordering can be defined separately from color count. Neither is calculated as a separate signal by this example. Adding more plotted averages does not average those outputs together, so the number of lines alone does not determine a single ribbon lag.

EMA and SMA are explicit choices in this reference

The input menu supports only EMA and SMA, both fully implemented. The periods remain fixed. An earlier incomplete helper listed other names while returning raw source for some of them; those placeholders are not presented as working average types here. This limited reference does not claim to reproduce every average option in Pineify’s broader MA module.

With valid uninterrupted data, SMA100 requires a full hundred observations; its first slope comparison would additionally need a prior valid value. EMA uses recursive state and depends on available history and its seed. When comparing charts, align the source, session, timeframe and history. Changing to SMA does not guarantee half as many color changes or a fixed delay.

The script plots current-bar values without a close-confirmation gate. Colors may change before close. A confirmed alert adaptation needs explicit event and timing rules; merely requiring several matching colors does not freeze an open bar.

Use the ribbon as a checkable display

To reproduce a condition, state the precise color count, reference-slope test, decision bar and any price-based entry or exit. Keep observed values separate from assumptions about future returns. The supplied indicator has no orders, alerts, RSI, volume filter or automated reversal classification.

GMMA groups a different set of averages, and Ichimoku uses rolling high/low midpoints and plot offsets. Those are distinct calculations, not evidence that a particular ribbon identifies trader types or universally confirms a reversal earlier.

Pine Script v6: implementation and limits

This complete reference computes all nineteen averages, restores the previously truncated final plot and adds a visible gray 100-period reference. It offers genuine EMA/SMA and source inputs; all dynamic color branches preserve their original ordering and tie behavior.

Pine Script v6
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Pineify

//@version=6
indicator(title="Madrid Moving Average Ribbon", overlay=true, max_labels_count=500)

sourceInput = input.source(close, "Source")
maType = input.string("EMA", "Average type", options=["EMA", "SMA"])

p_ta_ma(series float source, simple int length, simple string ma_type) =>
    emaValue = ta.ema(source, length)
    smaValue = ta.sma(source, length)
    ma_type == "SMA" ? smaValue : emaValue

p_ta_madrid_moving_average_ribbon(series float source, simple string ma_type) =>
    ma05 = p_ta_ma(source, 5, ma_type)
    ma10 = p_ta_ma(source, 10, ma_type)
    ma15 = p_ta_ma(source, 15, ma_type)
    ma20 = p_ta_ma(source, 20, ma_type)
    ma25 = p_ta_ma(source, 25, ma_type)
    ma30 = p_ta_ma(source, 30, ma_type)
    ma35 = p_ta_ma(source, 35, ma_type)
    ma40 = p_ta_ma(source, 40, ma_type)
    ma45 = p_ta_ma(source, 45, ma_type)
    ma50 = p_ta_ma(source, 50, ma_type)
    ma55 = p_ta_ma(source, 55, ma_type)
    ma60 = p_ta_ma(source, 60, ma_type)
    ma65 = p_ta_ma(source, 65, ma_type)
    ma70 = p_ta_ma(source, 70, ma_type)
    ma75 = p_ta_ma(source, 75, ma_type)
    ma80 = p_ta_ma(source, 80, ma_type)
    ma85 = p_ta_ma(source, 85, ma_type)
    ma90 = p_ta_ma(source, 90, ma_type)
    ma100 = p_ta_ma(source, 100, ma_type)

    [ma05, ma10, ma15, ma20, ma25, ma30, ma35, ma40, ma45, ma50, ma55, ma60, ma65, ma70, ma75, ma80, ma85, ma90, ma100]

// Madrid Ribbon color logic
maColor_p_ind_1(_ma, _maRef) =>
    diffMA = ta.change(_ma)
    diffMA >= 0 and _ma > _maRef ? color.rgb(0, 255, 0, 0) :
      diffMA < 0 and _ma > _maRef ? color.rgb(128, 0, 0, 0) :
      diffMA <= 0 and _ma < _maRef ? color.rgb(255, 0, 0, 0) :
      diffMA >= 0 and _ma < _maRef ? color.rgb(0, 128, 0, 0) :
      color.rgb(128, 128, 128, 0)

[ma05, ma10, ma15, ma20, ma25, ma30, ma35, ma40, ma45, ma50, ma55, ma60, ma65, ma70, ma75, ma80, ma85, ma90, ma100] =
  p_ta_madrid_moving_average_ribbon(sourceInput, maType)

plot(ma05, "Madrid Ribbon - MMA05", maColor_p_ind_1(ma05, ma100), 3)
plot(ma10, "Madrid Ribbon - MMA10", maColor_p_ind_1(ma10, ma100), 1)
plot(ma15, "Madrid Ribbon - MMA15", maColor_p_ind_1(ma15, ma100), 1)
plot(ma20, "Madrid Ribbon - MMA20", maColor_p_ind_1(ma20, ma100), 1)
plot(ma25, "Madrid Ribbon - MMA25", maColor_p_ind_1(ma25, ma100), 1)
plot(ma30, "Madrid Ribbon - MMA30", maColor_p_ind_1(ma30, ma100), 1)
plot(ma35, "Madrid Ribbon - MMA35", maColor_p_ind_1(ma35, ma100), 1)
plot(ma40, "Madrid Ribbon - MMA40", maColor_p_ind_1(ma40, ma100), 1)
plot(ma45, "Madrid Ribbon - MMA45", maColor_p_ind_1(ma45, ma100), 1)
plot(ma50, "Madrid Ribbon - MMA50", maColor_p_ind_1(ma50, ma100), 1)
plot(ma55, "Madrid Ribbon - MMA55", maColor_p_ind_1(ma55, ma100), 1)
plot(ma60, "Madrid Ribbon - MMA60", maColor_p_ind_1(ma60, ma100), 1)
plot(ma65, "Madrid Ribbon - MMA65", maColor_p_ind_1(ma65, ma100), 1)
plot(ma70, "Madrid Ribbon - MMA70", maColor_p_ind_1(ma70, ma100), 1)
plot(ma75, "Madrid Ribbon - MMA75", maColor_p_ind_1(ma75, ma100), 1)
plot(ma80, "Madrid Ribbon - MMA80", maColor_p_ind_1(ma80, ma100), 1)
plot(ma85, "Madrid Ribbon - MMA85", maColor_p_ind_1(ma85, ma100), 1)
plot(ma90, "Madrid Ribbon - MMA90", maColor_p_ind_1(ma90, ma100), 3)
plot(ma100, "Madrid Ribbon - MMA100 reference", color.gray, 2)
Existing indicator chart preview
Existing visual preview. Verify exact values against the source; the image is not a performance result.

Specify a checkable adaptation in Pineify

Ask Pine Script AI Coding Agent for a defined extension, such as an eighteen-line color count and a confirmed-bar alert when that count first crosses a chosen threshold. Inspect the denominator, unavailable-value handling and timing, then compare the calculation with the synthetic step before evaluating any trading rule.

Open Pine Script AI Coding Agent

Educational indicator analysis. No measured trading performance is established here. Syntax validation does not prove formula equivalence, execution assumptions or profitability.

Implementation questions

No. It uses 5 through 90 in steps of five, followed by 100, for nineteen calculations.

Eighteen shorter lines. The 100-period anchor compares with itself and is shown in gray.

Not necessarily. A flat average above the reference is lime and a flat one below is red. Gray follows exact equality or unavailable comparisons.

It means that average is nondecreasing and strictly above the current reference. The condition does not compare the current price with its previous value.

The complete example exposes EMA and SMA inputs. It does not include placeholder implementations for other names.

No. They are live comparisons. The example has no bar-close event gate, alerts or strategy orders.