TradingView indicators

Tom DeMark Sequential indicator: rules and code limits

TD Sequential uses Setup and Countdown phases to study possible trend exhaustion. A 9 or 13 is a count, not a guaranteed turning point. The Pine Script on this page is a simplified, repeating nine-count example. It does not implement the complete Sequential methodology.

What the supplied code actually checks

Nine consecutive bars with close < close[4] produce a green 9; the reverse comparison produces a red 9. It plots completion labels only. There are no Countdown labels, configurable inputs or trade orders.

Setup and Countdown use different rules

DeMARK's public documentation distinguishes consecutive Setup comparisons from nonconsecutive Countdown comparisons. The following is a scope comparison, not a complete implementation specification.

StagePublic rule overviewThis code
Setup9 consecutive closes below or above the close four bars earlier.Core comparison only; no price-flip prerequisite or perfection test.
CountdownAfter Setup, seeks 13 qualifying comparisons of closes with highs/lows two bars earlier; counts need not be consecutive.Absent. Counting 13 consecutive closes is not Countdown.
QualificationPerfection, deferral, TDST and risk rules add conditions beyond a number.Absent.

In the official overview, an unfinished Countdown can be cancelled by an opposing Setup or a qualifying TDST violation. Recycling handles a later same-direction Setup under separate conditions. Neither is implemented here. This script simply resets or loops its two counters.

Version matters when comparing results. DeMARK describes its official 9-13 product for TradingView as a simplified version of Sequential and Combo that includes both phases. This page's Pine Script v6 counter is a different implementation with no Countdown at all.

Rule reference: DeMARK Sequential documentation, checked October 17, 2026. The educational Pineify snippet is not presented as an authorized DeMARK product or a complete reproduction. For the official indicator, use the services or licensed partners listed by DeMARK.

A bar-by-bar example, including failure and restart

These are invented closing prices, not market data or a backtest. Seed bars 1 to 4 close at 104, 103, 102 and 101. Start the buy counter at zero. For each later bar, compare its close with the close exactly four bars earlier.

Demonstration of the existing nine-count loop
BarCloseClose[4]Buy countResult
51001041Qualifying close
6991032Qualifying close
7981023Qualifying close
8971014Qualifying close
9961005Qualifying close
1095996Qualifying close
1194987Qualifying close
1293978Qualifying close
1392969Green 9 label
1491951Loop restarts at 1
1594940Equality: reset to 0
1690931New count starts at 1

Bar 13 completes the count at 92, yet bar 14 closes lower at 91. The completed label does not prevent further decline. Bar 15 closes at 94, equal to bar 11: both strict comparisons fail, so both counters become zero. Bar 16 starts a new buy count because 90 is below bar 12's 93.

To check interruption before completion, change only bar 10's close from 95 to 99. It then equals bar 6 and resets the buy count from 5 to 0. With all other closes unchanged, bar 13 has count 3, so the green 9 disappears. This is a reproducible change to the input sequence, not a claim about a historical trade.

Existing Pine Script v6: setup-style labels only

Paste this existing example into TradingView's Pine Editor and add it to a chart. Its title is retained from the original example; read the scope notes before comparing it with an official indicator. The complete source is preserved, including generated helper functions that the counter does not use.

Existing Pine Script v6 example
// 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="TD Sequential", overlay=true, max_labels_count=500)

//#region —————————————————————————————————————————————————— Custom Code

//#endregion ————————————————————————————————————————————————————————————


//#region —————————————————————————————————————————————————— Common Dependence

p_comm_time_range_to_unix_time(string time_range, int date_time = time, string timezone = syminfo.timezone) =>
    int start_unix_time = na
    int end_unix_time = na
    int start_time_hour = na
    int start_time_minute = na
    int end_time_hour = na
    int end_time_minute = na
    if str.length(time_range) == 11
        // Format: hh:mm-hh:mm
        start_time_hour := math.floor(str.tonumber(str.substring(time_range, 0, 2)))
        start_time_minute := math.floor(str.tonumber(str.substring(time_range, 3, 5)))
        end_time_hour := math.floor(str.tonumber(str.substring(time_range, 6, 8)))
        end_time_minute := math.floor(str.tonumber(str.substring(time_range, 9, 11)))
    else if str.length(time_range) == 9
        // Format: hhmm-hhmm
        start_time_hour := math.floor(str.tonumber(str.substring(time_range, 0, 2)))
        start_time_minute := math.floor(str.tonumber(str.substring(time_range, 2, 4)))
        end_time_hour := math.floor(str.tonumber(str.substring(time_range, 5, 7)))
        end_time_minute := math.floor(str.tonumber(str.substring(time_range, 7, 9)))
    start_unix_time := timestamp(timezone, year(date_time, timezone), month(date_time, timezone), dayofmonth(date_time, timezone), start_time_hour, start_time_minute, 0)
    end_unix_time := timestamp(timezone, year(date_time, timezone), month(date_time, timezone), dayofmonth(date_time, timezone), end_time_hour, end_time_minute, 0)
    [start_unix_time, end_unix_time]

p_comm_time_range_to_start_unix_time(string time_range, int date_time = time, string timezone = syminfo.timezone) =>
    int start_time_hour = na
    int start_time_minute = na
    if str.length(time_range) == 11
        // Format: hh:mm-hh:mm
        start_time_hour := math.floor(str.tonumber(str.substring(time_range, 0, 2)))
        start_time_minute := math.floor(str.tonumber(str.substring(time_range, 3, 5)))
    else if str.length(time_range) == 9
        // Format: hhmm-hhmm
        start_time_hour := math.floor(str.tonumber(str.substring(time_range, 0, 2)))
        start_time_minute := math.floor(str.tonumber(str.substring(time_range, 2, 4)))
    timestamp(timezone, year(date_time, timezone), month(date_time, timezone), dayofmonth(date_time, timezone), start_time_hour, start_time_minute, 0)

p_comm_time_range_to_end_unix_time(string time_range, int date_time = time, string timezone = syminfo.timezone) =>
    int end_time_hour = na
    int end_time_minute = na
    if str.length(time_range) == 11
        end_time_hour := math.floor(str.tonumber(str.substring(time_range, 6, 8)))
        end_time_minute := math.floor(str.tonumber(str.substring(time_range, 9, 11)))
    else if str.length(time_range) == 9
        end_time_hour := math.floor(str.tonumber(str.substring(time_range, 5, 7)))
        end_time_minute := math.floor(str.tonumber(str.substring(time_range, 7, 9)))
    timestamp(timezone, year(date_time, timezone), month(date_time, timezone), dayofmonth(date_time, timezone), end_time_hour, end_time_minute, 0)

p_comm_timeframe_to_seconds(simple string tf) =>
    float seconds = 0
    tf_lower = str.lower(tf)
    value = str.tonumber(str.substring(tf_lower, 0, str.length(tf_lower) - 1))
    if str.endswith(tf_lower, 's')
        seconds := value
    else if str.endswith(tf_lower, 'd')
        seconds := value * 86400
    else if str.endswith(tf_lower, 'w')
        seconds := value * 604800
    else if str.endswith(tf_lower, 'm')
        seconds := value * 2592000
    else
        seconds := str.tonumber(tf_lower) * 60
    seconds

p_custom_sources() =>
    [open, high, low, close, volume]

//#endregion


//#region —————————————————————————————————————————————————— Ta Dependence

p_ta_sequential_candles(simple int counting) =>
    buy_setup = 0
    buy_setup := close < close[4] ? buy_setup[1] == counting ? 1 : buy_setup[1] + 1 : 0
    sell_setup = 0
    sell_setup := close > close[4] ? sell_setup[1] == counting ? 1 : sell_setup[1] + 1 : 0
    buySignal = buy_setup == counting
    sellSignal = sell_setup == counting
    [buySignal, sellSignal]

//#endregion


//#region —————————————————————————————————————————————————— Constants

// Input Groups
string P_GP_1      =      ""

//#endregion


//#region —————————————————————————————————————————————————— Inputs

//#endregion


//#region —————————————————————————————————————————————————— Price Data

//#endregion


//#region —————————————————————————————————————————————————— Indicators

[p_ind_1_buySignal, p_ind_1_sellSignal]      =      p_ta_sequential_candles(9) // TD Sequential

//#endregion


//#region —————————————————————————————————————————————————— Conditions

//#endregion


//#region —————————————————————————————————————————————————— Indicator Plots

// TD Sequential
if p_ind_1_buySignal
    label.new(x=bar_index, y=0, yloc=yloc.belowbar, style=label.style_label_up, text=str.tostring(9), textcolor=color.rgb(255, 255, 255, 0), color=color.rgb(56, 142, 60, 20), size=size.tiny, text_font_family=font.family_monospace)
if p_ind_1_sellSignal
    label.new(x=bar_index, y=0, yloc=yloc.abovebar, style=label.style_label_down, text=str.tostring(9), textcolor=color.rgb(255, 255, 255, 0), color=color.rgb(247, 82, 95, 20), size=size.tiny, text_font_family=font.family_monospace)

//#endregion


//#region —————————————————————————————————————————————————— Custom Plots

//#endregion


//#region —————————————————————————————————————————————————— Alert

//#endregion

Parameters, labels and confirmation

  • The call to p_ta_sequential_candles(9) fixes the count at 9. There are no settings-panel inputs.
  • The four-bar lookback is hard-coded. Bars without that history cannot satisfy either comparison.
  • Green 9 appears below a completed buy count; red 9 appears above a completed sell count. Intermediate counts are not displayed.
  • The next qualifying bar after 9 restarts at 1. Equality or a failed comparison resets that direction to 0.
  • There is no barstate.isconfirmed condition. An open bar can lose its label before closing. TradingView documents confirmation in its bar-state reference.
  • The script defines no alert conditions or orders. Its 500-label limit also means a long chart will not retain every historical label.

Specify the state machine before adding trades

A matching label on one chart does not prove two implementations are equivalent. Compare the same symbol, feed, session, timeframe and completed bars. Then test equality, an interrupted count, a continuing trend after 9 and the first bars of the data set.

  1. Choose the intended scope: this repeating close-comparison counter, or a separately specified methodology with an identified rule source and version.
  2. Describe the start condition, strict comparisons, reset rule and behavior after 9 to the Pine Script AI Coding Agent.
  3. Specify whether signals use completed bars and whether intermediate count values must be visible for auditing.
  4. Compare generated values with the demonstration table and additional edge cases. Syntax validation alone does not verify the trading rules.
  5. Define entry timing, exits, sizing, commission and slippage separately before converting labels into a strategy.
Draft a counting specification

Educational implementation reference. No count or completed sequence guarantees a reversal or a profitable trade.

TD Sequential questions

No. It implements a repeating nine-count comparison with the close four bars earlier. It does not implement a price-flip prerequisite, Setup perfection, Countdown, deferral, TDST, recycling or risk levels. The script title does not establish equivalence to an official DeMARK implementation.

The function is called with a fixed count of 9 and returns only two completion booleans. The plot code prints a 9 when either boolean is true. There is no Countdown state or plotting logic for 13. Changing the function argument to 13 would still count consecutive close comparisons; it would not add Countdown.

A buy count resets to zero when the close is not strictly below the close four bars earlier. A sell count resets when it is not strictly above that reference. Equality resets both counts. After a count reaches 9, the next qualifying bar starts again at 1. This loop is separate from official Countdown recycling.

Yes. This code compares the current close without a barstate.isconfirmed gate. An open-bar label can appear and disappear as price crosses its four-bar reference. Audit completed bars first; if you need close-only signals, specify that behavior before adding alerts or order logic.

This example declares no input controls. The function call fixes the count at 9 and uses the active chart timeframe. The lookback is hard-coded at four bars. A different chart timeframe changes the input bars; it does not establish a better trading setting.

No. It records nine qualifying comparisons. Price can continue lower, and another count can begin immediately. This indicator has no entry, exit, position sizing or trading-cost rules, so its labels are not a backtest or evidence of a profitable strategy.

Sources and further reading