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.
| Stage | Public rule overview | This code |
|---|---|---|
| Setup | 9 consecutive closes below or above the close four bars earlier. | Core comparison only; no price-flip prerequisite or perfection test. |
| Countdown | After 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. |
| Qualification | Perfection, 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.
| Bar | Close | Close[4] | Buy count | Result |
|---|---|---|---|---|
| 5 | 100 | 104 | 1 | Qualifying close |
| 6 | 99 | 103 | 2 | Qualifying close |
| 7 | 98 | 102 | 3 | Qualifying close |
| 8 | 97 | 101 | 4 | Qualifying close |
| 9 | 96 | 100 | 5 | Qualifying close |
| 10 | 95 | 99 | 6 | Qualifying close |
| 11 | 94 | 98 | 7 | Qualifying close |
| 12 | 93 | 97 | 8 | Qualifying close |
| 13 | 92 | 96 | 9 | Green 9 label |
| 14 | 91 | 95 | 1 | Loop restarts at 1 |
| 15 | 94 | 94 | 0 | Equality: reset to 0 |
| 16 | 90 | 93 | 1 | New 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.
// 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
//#endregionParameters, 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.isconfirmedcondition. 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.
- Choose the intended scope: this repeating close-comparison counter, or a separately specified methodology with an identified rule source and version.
- Describe the start condition, strict comparisons, reset rule and behavior after 9 to the Pine Script AI Coding Agent.
- Specify whether signals use completed bars and whether intermediate count values must be visible for auditing.
- Compare generated values with the demonstration table and additional edge cases. Syntax validation alone does not verify the trading rules.
- Define entry timing, exits, sizing, commission and slippage separately before converting labels into a strategy.
Educational implementation reference. No count or completed sequence guarantees a reversal or a profitable trade.