Equalhigh - Pettitt Structural Break DetectorEqualhigh — Pettitt Structural Break Detector
User Manual
Overview
The Equalhigh Pettitt Structural Break Detector is a statistical regime-change indicator for PulseWire. It is designed to identify a recent change in the distribution of price returns rather than a conventional overbought, oversold, or moving-average condition.
The indicator applies a rolling version of Pettitt's non-parametric change-point test to logarithmic price returns. It estimates the most likely break location inside the active window, evaluates its statistical significance, measures the direction and size of the median shift, and filters out changes that are too old or too small to be considered actionable.
This is a diagnostic indicator, not an automatic trading system. Its purpose is to answer:
Has the recent return regime changed materially, in which direction, and with what level of statistical evidence?
Core calculation
The observation tested on each bar is the multi-bar logarithmic return:
100 × ln(Source / Source )
Inside the selected Pettitt window, the indicator:
Orders the observations chronologically.
Assigns non-parametric ranks, using average ranks for equal values.
Tests every admissible split while preserving the minimum segment size on both sides.
Selects the split with the largest absolute Pettitt statistic.
Calculates the approximate two-sided p-value:
p ≈ min(1, 2 × exp(-6K² / (n³ + n²)))
Compares the median return before and after the estimated break.
Standardizes the median shift by the rolling standard deviation.
Rejects breaks that are too old or have an insufficient effect size.
The test is non-parametric: it relies on ranks and does not require returns to follow a normal distribution.
Reading the indicator
The main line is a signed statistical-confidence display ranging from approximately -100 to +100.
Display
Meaning
Green
Recent, statistically confirmed upward shift in the return distribution
Red
Recent, statistically confirmed downward shift in the return distribution
Orange
Possible break; evidence is developing but does not yet meet the confirmed threshold
Gray
No currently actionable structural break
BULL label
A new confirmed upward structural-break event
BEAR label
A new confirmed downward structural-break event
Orange ?
A new possible upward or downward break
A positive reading means that the post-break median return is higher than the pre-break median. A negative reading means it is lower.
Important: a bullish break does not necessarily mean that returns are already positive. A change from strongly negative returns to mildly negative returns is an upward structural shift and can therefore be classified as bullish. Price structure should still be checked separately.
The displayed confidence is calculated as 100 × (1 − p-value). It is not the probability that a trade will be profitable, the probability that price will rise, or a forecast accuracy score.
Confirmation rules
A confirmed break requires all of the following:
The approximate p-value is less than or equal to the Confirmed p-value setting.
The estimated break age does not exceed the Maximum actionable break age.
The absolute median-shift effect reaches the Minimum median-shift effect.
The post-break median is different from the pre-break median.
A possible break requires:
A p-value above the confirmed threshold but no higher than the Possible-break p-value.
A recent estimated break.
At least half of the selected minimum effect size.
Dashboard
The statistical dashboard provides five fields:
Field
Interpretation
Pettitt State
Current classification: stable, possible break, confirmed break, or old break
P Value Approx
Approximate probability of observing a Pettitt statistic at least this extreme under the no-change hypothesis
Break Age
Estimated number of bars since the detected split
Median Shift
Post-break median return minus pre-break median return, in percentage points
Effect Size
Median shift divided by the rolling standard deviation of the tested returns
An OLD BREAK state means that statistically significant evidence remains inside the window, but the estimated change point is older than the selected actionable-age limit.
Inputs
1. Observations
Price sourceSelects the series used in the logarithmic-return calculation. Close is the standard choice.
Log-return horizonDefines the number of bars used for each return observation. A higher value focuses on slower moves but creates more overlap between consecutive observations.
Pettitt windowDefines the number of observations included in each rolling test. Short windows react faster but are noisier. Long windows are more stable but detect changes later.
Minimum segment sizePrevents the estimated split from being placed too close to either edge of the window. Larger values reduce unstable edge detections but also delay recognition of very recent changes.
2. Validation
Confirmed p-valueMaximum approximate p-value for a confirmed break. 0.05 is the default. Lower values are more selective.
Possible-break p-valueMaximum p-value for the orange early-warning state. 0.15 is the default.
Maximum actionable break ageMaximum number of bars allowed between the estimated break and the current bar. This prevents an old statistical event from being treated as a fresh signal.
Minimum median-shift effectMinimum absolute standardized median shift required for confirmation. 0.25 means that the shift must represent at least one quarter of the rolling return standard deviation.
Confirm signals at bar closeWhen enabled, new labels and alert events are confirmed only after the current bar closes. This is the recommended setting.
3. Display
These controls independently enable the regime background, confirmed labels, possible-break markers, and statistical dashboard.
Suggested starting profiles
Use case
Return horizon
Window
Minimum segment
Maximum age
Minimum effect
General swing trading
5
60
10
10
0.25
Faster market monitoring
3
50
8
7
0.30
Slower regime analysis
10
90
15
15
0.35
These are starting points, not optimized trading parameters. Settings should be tested across different symbols and market regimes without selecting them solely from the best historical result.
Practical workflow
Use a liquid instrument and ordinary candlestick data.
Keep bar-close confirmation enabled.
Treat orange as an observation state, not an entry instruction.
When a confirmed label appears, check whether price structure, volume, volatility, and the higher-timeframe context support the same interpretation.
Use the p-value, effect size, and break age together. A small p-value alone does not guarantee a useful trade.
Define entry, invalidation, position size, and exit rules independently.
For example, a green event with p = 0.02, a break age of 6 bars, and an effect size of +0.60 sigma represents a recent and statistically meaningful upward shift. It becomes more useful if price has also reclaimed an important level or broken a declining structure.
Alerts
Four alert conditions are available:
Pettitt — Possible bullish break
Pettitt — Possible bearish break
Pettitt — Bullish structural break
Pettitt — Bearish structural break
Alerts fire when a qualifying state first appears or when the estimated break resets to a more recent point while the same directional condition remains active. With bar-close confirmation enabled, alerts should be configured Once Per Bar Close.
Repainting and timing
The script does not use future data, lookahead, or a negative plot offset. A signal is displayed on the bar where the break is detected; it is not placed retrospectively on the estimated historical change point.
However, this is a rolling estimator. As new bars enter the window, the most likely split, p-value, break age, and state can change. On a live unclosed bar, values can also move with price. Enabling Confirm signals at bar close prevents provisional intrabar labels from being treated as confirmed events.
Limitations
Pettitt's test identifies the dominant single change point inside the active window. Multiple rapid regime changes can interfere with one another.
The p-value is an approximation, not an exact posterior probability.
Consecutive multi-bar returns overlap and are therefore not independent. This makes the p-value best treated as comparative statistical evidence rather than a perfectly calibrated probability.
A statistically significant distribution shift does not guarantee trend continuation or trading profitability.
Outliers are less influential than in many mean-based tests, but they can still affect the detected split and the rolling volatility denominator.
Very short windows are noisy; very long windows can react too slowly.
Logarithmic returns require positive source values. The test remains unavailable when the selected source contains invalid or non-positive observations inside the active window.
Results on Heikin Ashi, Renko, Range, Kagi, or other synthetic chart types describe the transformed data rather than standard traded prices.
Always evaluate the indicator on unseen data and combine it with independent risk controls.
Data Window outputs
The script exposes the following values for inspection and alert integration:
State code: +2 confirmed bullish, +1 possible bullish, 0 stable, −1 possible bearish, −2 confirmed bearish.
Approximate p-value.
Estimated break age.
Median shift in percentage points.
Median-shift effect size.
Pettitt K statistic.
Reference
A. N. Pettitt, “A Non-Parametric Approach to the Change-Point Problem,” Journal of the Royal Statistical Society: Series C (Applied Statistics), Vol. 28, No. 2, 1979, pp. 126–135. DOI: 10.2307/2346729.
Disclaimer
This indicator is provided for research and educational purposes. It does not constitute investment advice, a recommendation, or a guarantee of future performance. Trading involves risk, including the possible loss of capital. Indicator

Indicator

Equalhigh - GAPO Easy ModeEQUALHIGH - GAPO EASY MODE
OVERVIEW
GAPO Easy Mode is a volatility-regime indicator based on the Gopalakrishnan Range Index developed by Jayanthi Gopalakrishnan.
Its purpose is not to predict market direction. It identifies:
• Volatility compression
• Volatility expansion
• Possible bullish or bearish releases
• Donchian breakouts occurring shortly after compression
The original GAPO value is converted into a rolling percentile from 0 to 100. This makes the indicator easier to interpret across different market periods.
CALCULATION
The original Gopalakrishnan Range Index is:
GAPO = ln(Highest High − Lowest Low) / ln(Period)
The highest high and lowest low are calculated over the selected GAPO period.
Because the original GAPO depends on the asset’s price scale, this script calculates its percentile rank over a user-defined historical window.
• A low percentile indicates an unusually narrow price range.
• A rising percentile indicates that the range is expanding.
• A high percentile indicates unusually elevated variability.
DEFAULT SETTINGS
• GAPO period: 14 bars
• Percentile lookback: 252 bars
• Compression threshold: 20
• High variability threshold: 80
• Expansion confirmation: 2 rising bars
• Donchian breakout period: 20 bars
• Activation window: 15 bars
• Direction filter: EMA 50
• Signal confirmation: Bar close
COLOR INTERPRETATION
BLUE — COMPRESSION
The GAPO percentile is at or below the compression threshold.
The market’s recent price range is unusually narrow compared with its own history. This does not provide a directional signal. It indicates that traders should prepare for a possible volatility release.
GRAY — NEUTRAL
No meaningful compression or confirmed expansion is currently detected.
GREEN — BULLISH RELEASE
The following conditions are present:
• A compression occurred recently
• The GAPO percentile is rising
• The percentile is above the compression threshold
• Price is above the direction-filter EMA
This indicates expanding volatility with a bullish directional bias. It is not necessarily a confirmed breakout.
RED — BEARISH RELEASE
The following conditions are present:
• A compression occurred recently
• The GAPO percentile is rising
• The percentile is above the compression threshold
• Price is below the direction-filter EMA
This indicates expanding volatility with a bearish directional bias.
ORANGE — HIGH VARIABILITY
The GAPO percentile is at or above the high-variability threshold.
The current range is unusually wide compared with the historical reference period. This can occur during a strong trend or an erratic market.
A high percentile is not automatically a reversal signal.
DASHBOARD
The dashboard displays three items.
GAPO STATE
Possible states include:
• COMPRESSION
• NEUTRAL
• BULLISH RELEASE
• BEARISH RELEASE
• BULL BREAKOUT
• BEAR BREAKOUT
• HIGH VARIABILITY
PERCENTILE
Shows the current GAPO percentile between 0 and 100.
BREAKOUT ARMED
• YES: A compression occurred within the activation window.
• NO: No sufficiently recent compression is available to validate a breakout signal.
BREAKOUT SIGNALS
BUY SIGNAL
A BUY label appears when:
1. A GAPO compression occurred within the activation window.
2. The GAPO percentile has moved above the compression threshold.
3. The percentile has risen for the required number of bars.
4. Price closes above the previous Donchian high.
The current bar is excluded from the Donchian boundary calculation. This ensures that the current close genuinely breaks the previous price range.
SELL SIGNAL
A SELL label appears when:
1. A recent GAPO compression is available.
2. The GAPO percentile is expanding.
3. Price closes below the previous Donchian low.
The EMA determines the directional color of a volatility release. It is not required for the BUY or SELL breakout calculation itself.
PRACTICAL WORKFLOW
1. WAIT FOR BLUE
A blue GAPO line identifies volatility compression. Do not assume the next move will be bullish.
2. CHECK “BREAKOUT ARMED”
The dashboard should display YES. This confirms that a qualifying compression occurred recently.
3. WATCH FOR VOLATILITY RELEASE
The GAPO percentile should leave the compression zone and begin rising.
• Green indicates bullish expansion.
• Red indicates bearish expansion.
4. REQUIRE PRICE CONFIRMATION
For stronger confirmation, wait for a BUY or SELL label generated by the Donchian breakout.
5. CONTROL RISK
Use price structure, ATR or another risk-management method to determine the stop.
The indicator does not calculate position size or guarantee that a breakout will continue.
EXAMPLE OF A BULLISH SETUP
• GAPO percentile falls below 20
• Dashboard displays COMPRESSION
• Breakout Armed displays YES
• GAPO begins rising above 20
• Price remains above EMA 50
• The line becomes green
• Price closes above the previous 20-bar high
• A BUY label appears
EXAMPLE OF A BEARISH SETUP
• GAPO enters compression
• The percentile subsequently begins rising
• Price is below EMA 50
• The line becomes red
• Price closes below the previous 20-bar low
• A SELL label appears
ALERTS
Five PulseWire alert conditions are included:
• GAPO - New compression
• GAPO - Bullish release
• GAPO - Bearish release
• GAPO - Bullish breakout
• GAPO - Bearish breakout
For more stable signals, configure PulseWire alerts as “Once Per Bar Close.”
SETTINGS
GAPO PERIOD
Controls the number of bars used to calculate the highest high and lowest low.
A shorter period reacts faster but produces more noise. The default value is 14.
PERCENTILE LOOKBACK
Defines the historical window used to determine whether the current GAPO is relatively low or high.
The default value of 252 corresponds approximately to one trading year on a daily chart.
COMPRESSION THRESHOLD
Determines when the market is classified as compressed.
The default value is the 20th percentile.
HIGH VARIABILITY THRESHOLD
Determines when the market’s range is considered historically elevated.
The default value is the 80th percentile.
RISING BARS REQUIRED
Defines how many consecutive rising percentile readings are required to confirm volatility expansion.
A higher value reduces noise but delays detection.
DONCHIAN BREAKOUT PERIOD
Defines the price range that must be broken to generate a BUY or SELL signal.
The default setting is 20 bars.
MAXIMUM BARS AFTER COMPRESSION
Defines how long a compression can remain valid for a subsequent breakout.
After this window expires, Breakout Armed returns to NO.
DIRECTION FILTER EMA
Determines whether an expansion is classified as bullish or bearish.
• Price above the EMA: bullish bias
• Price below the EMA: bearish bias
CONFIRM SIGNALS AT BAR CLOSE
When enabled, signals are confirmed only after the current candle closes. This reduces temporary intrabar signals.
SUGGESTED TIMEFRAMES
For swing trading:
• Daily chart: use the default settings
• Four-hour chart: defaults can be used as a starting point
• Weekly chart: consider increasing the activation window
The periods always represent chart bars, not calendar days.
DATA REQUIREMENTS
The percentile requires sufficient historical data.
With a 14-bar GAPO and a 252-bar percentile lookback, approximately 265 chart bars may be required before the normalized indicator becomes available.
Newly listed securities may therefore show no value until enough history exists. Reducing the percentile lookback can produce earlier readings, but the statistical reference will be less robust.
NON-REPAINTING BEHAVIOR
The indicator uses only current and historical price data. It does not use future bars.
The GAPO line and dashboard can change while the current candle is forming. When bar-close confirmation is enabled, completed BUY and SELL signals remain fixed after the candle closes.
LIMITATIONS
GAPO measures range variability, not market direction.
It does not directly account for:
• Trading volume
• Fundamental information
• Earnings announcements
• Market liquidity
• Transaction costs
• Position sizing
• Broader market conditions
Corporate actions, large gaps and exceptional price events can temporarily distort the rolling range.
Compression does not guarantee a breakout, and a breakout can still fail. GAPO Easy Mode should be combined with price structure and disciplined risk management.
DISCLAIMER
This indicator is provided for educational and analytical purposes only. It does not constitute financial advice or a recommendation to buy or sell any financial instrument. Past performance does not guarantee future results.
Indicator

VSA No Supply No Demand
VSA No Supply & No Demand
The **VSA No Supply & No Demand** indicator is a Volume Spread Analysis (VSA) tool designed to identify potential **No Supply (NS)** and **No Demand (ND)** conditions by analyzing price direction, relative volume, candle structure, and recent price behavior.
### 🟢 No Supply (NS)
A **No Supply** signal identifies a potential reduction in selling pressure.
The indicator looks for:
* A bearish candle
* Lower volume compared with the previous two bars
* Specific wick/pin-bar structure
* Confirmation from recent price behavior
**Interpretation:**
No Supply may indicate that sellers are becoming less aggressive. When it appears near support, after a selling climax, or following a downward move, it can provide an early indication that the market may be preparing for a bullish reaction.
### 🔴 No Demand (ND)
A **No Demand** signal identifies potential weakness in buying pressure.
The indicator looks for:
* A bullish candle
* Lower volume compared with the previous two bars
* Specific wick/pin-bar structure
* Confirmation from recent price behavior
**Interpretation:**
No Demand may indicate that buyers are not showing enough strength to continue pushing price higher. When it appears near resistance, after an extended rally, or following a buying climax, it can provide an early warning of potential bearish weakness.
### 📊 VSA Logic
The indicator is designed around the relationship between **Price, Volume and Market Context**.
Typical VSA interpretation:
**Selling Climax → Stopping Volume → No Supply → Bullish Confirmation**
**Buying Climax → Distribution → No Demand → Bearish Confirmation**
### ⚙️ NSND Count
The **NSND Count** setting controls how many recent bars are evaluated when checking the price-behavior conditions surrounding an NS or ND setup.
This allows traders to adjust the sensitivity of the indicator according to their timeframe and trading style.
### 🔔 Alerts
The indicator includes separate PulseWire alerts for:
* **No Supply Alert**
* **No Demand Alert**
### ⚠️ Important
NS and ND signals should **not be treated as standalone trade entries**. VSA signals are most effective when combined with:
* Support & Resistance
* Market Structure
* Trend
* Volume Climax
* Stopping Volume
* Absorption
* Breakouts
* Higher-Timeframe Context
Use the indicator as a **confirmation and market-reading tool**, not as a guaranteed buy or sell system.
Indicator

Indicator

TRADLEWARE-HODL
Buy and Hold Benchmark
This is a passive reference strategy, not a signal-based trading system. It exists to give an honest baseline: buy once, hold through everything, and see what an active strategy actually needs to beat.
How it works
Buy-and-hold ("HODL") is the simplest possible approach to markets: put the money in once and do nothing else, regardless of what price does afterward. There is no attempt to time entries or exits, no reaction to drawdowns, and no risk management of any kind. Any active strategy that cannot beat this, risk-adjusted, over the same period has not demonstrated an edge.
Entry
The entire starting capital is deployed in a single buy, on the first bar at or after the start date.
Exit
The position is held until the end date, or the end of the chart's available history, whichever comes first — at which point it is closed once so the backtest can report a final equity figure. This is bookkeeping, not a trading decision; the whole point of the strategy is that it does not exit early.
Parameters
Start Date / End Date: the single buy fires on the first bar at or after the start date; the position is held until the end date
Position sizing is set to 99.95% of equity rather than a full 100%. That small gap avoids a PulseWire position-sizing rounding artifact that can otherwise show up as an extra "Margin call" row even on a strategy with only one real trade; the effect on the actual result is negligible.
Costs modelled
0.1% commission per side, 3 ticks slippage.
Intended assets and timeframe
Works on any asset or timeframe — there is no technical logic to adapt, just a buy date and a hold period.
Known limitations
Full exposure to every drawdown the asset experiences, for the entire holding period, by design. This is not a flaw to fix — it is the deliberate point of comparison for any strategy that claims to manage risk better than doing nothing.
Strategy

TRADLEWARE-DCA
Dollar-Cost Averaging Benchmark
This is a passive reference strategy, not a signal-based trading system. It exists to give an honest, apples-to-apples comparison for active strategies: instead of trying to time entries, it buys a fixed amount of the asset on a regular schedule until a set capital budget is fully deployed.
How it works
Dollar-cost averaging (DCA) means investing a fixed amount of money at regular intervals, regardless of price. Some buys land at high prices, some at low prices, and over time the average purchase price smooths out. There is no attempt to predict direction — the schedule is the whole strategy.
This script buys on either a fixed day of the week (e.g. every Monday) or every fixed number of bars (e.g. every 30 daily bars, roughly monthly), and keeps buying until the total amount invested reaches the strategy's starting capital. After that, no more buys are placed — the same total capital pool as whatever active strategy this is being compared against, with no extra money added along the way.
Entry
A buy is placed each time the schedule fires, as long as the running total invested plus the next buy amount does not exceed the starting capital. If a scheduled buy would push the total over budget, it is skipped, but the schedule keeps advancing rather than getting stuck retrying.
Exit
There is no exit signal in the usual sense — the strategy only ever adds to its position. The full position is closed out once, on the final bar of the chart's history, purely so the backtest can report a final equity figure. This is bookkeeping, not a trading decision.
Parameters
Start Date / End Date: window during which buys are allowed
Use Day of Week Mode: switch between "buy on a specific weekday" and "buy every N bars"
Day of Week: which weekday to buy on, when day-of-week mode is on
Every X Bars: how many bars between buys, when day-of-week mode is off (30 on a daily chart is roughly monthly)
Amount per buy: fixed amount invested at each scheduled buy
The strategy allows up to 500 stacked buy layers to accumulate into a single overall position — that number just needs to be large enough to never run out before the capital budget is spent; it is not a trading parameter to tune.
Costs modelled
0.1% commission per side, 3 ticks slippage, fills at the same bar's close (this benchmark intentionally fills immediately rather than waiting for the next bar's open, since there is no signal timing to protect).
Intended assets and timeframe
Works on any asset or timeframe — the frequency inputs just need to be set to match (e.g. 30 bars on a daily chart for roughly monthly buys, 7 for weekly). For higher-priced assets, check that the per-buy amount converts to at least a fraction PulseWire will actually simulate.
Known limitations
The starting capital, buy amount, and buy frequency together decide how long full deployment actually takes — and depending on the chart's date range, that can run out in either direction. With the default settings (10,000 starting capital, 100 per buy, roughly monthly), full deployment takes 100 buys — about 8 years of monthly investing. Starting from 2018-01-01, that budget is exhausted by roughly mid-2026, so on a chart that runs through mid-2026 or later, this script will have already placed its last scheduled buy weeks or months before the present: it simply holds the fully-invested position afterward and stops buying, exactly as designed by the "never invest more than the starting capital" rule, not because of an error. On a shorter chart window relative to the amount and frequency chosen, the opposite can happen instead — the window ends before the full budget is spent, leaving some capital undeployed. Either way, check the strategy's equity and invested-capital tracking rather than assuming full deployment by the end of the chart. This script also has no risk management of any kind by design: it never sells until the very end, so it carries full exposure to any drawdown the asset experiences. That is the intended comparison point for an active strategy, not a flaw to fix.
Strategy

MW WINDOWS TIME🇫🇷 Français
MW WINDOWS TIME est un indicateur PulseWire simple et visuel conçu pour cadrer les principales fenêtres horaires de trading sur MGC et MNQ.
Il affiche automatiquement deux zones directement sur le graphique :
08h45 → 11h00 : fenêtre Europe, priorité MGC
14h15 → 17h30 : fenêtre US, priorité MNQ + MGC
Pendant chaque fenêtre, l’indicateur crée une boîte qui s’adapte automatiquement au plus haut et au plus bas des bougies de la période. À la fin de la fenêtre, la boîte reste figée afin de conserver un repère visuel clair.
Le nom de l’actif à privilégier est affiché sous chaque boîte :
MGC le matin, puis MNQ • MGC l’après-midi.
L’utilisateur peut personnaliser les couleurs, l’opacité, les bordures, la taille du texte et la position des labels.
Le fuseau horaire peut être réglé manuellement entre UTC+2 et UTC+1 afin de s’adapter au passage heure d’été / heure d’hiver.
L’objectif du script est simple : savoir immédiatement quand chercher un setup et éviter de trader en dehors des fenêtres prévues.
🇬🇧 English
MW WINDOWS TIME is a simple and visual PulseWire indicator designed to highlight the main trading windows for MGC and MNQ.
It automatically displays two trading windows directly on the chart:
08:45 → 11:00: European session, priority MGC
14:15 → 17:30: US session, priority MNQ + MGC
During each window, the indicator creates a box that automatically adjusts to the highest and lowest price reached during the session. Once the time window is over, the box remains fixed on the chart for clear historical reference.
The preferred trading instrument is displayed below each box:
MGC during the morning session and MNQ • MGC during the US session.
Users can customize the box colors, opacity, border colors and thickness, text colors, label size, and label position.
The timezone can be manually switched between UTC+2 and UTC+1 to adapt to summer and winter time changes.
The purpose of the script is simple: clearly identify when to look for trading opportunities and avoid trading outside the planned windows. Indicator

Indicator

Indicator

Indicator

Strategy

Indicator

Custom ORB, Premarket & EMAs// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at mozilla.org
//@version=6
indicator("Custom ORB, Premarket & EMAs", overlay = true, max_lines_count = 100, max_labels_count = 100, max_bars_back = 5000)
// --- Groups ---
var string G_PRE = "Premarket Settings"
var string G_PD = "Previous Day Levels"
var string G_2OR = "2m Opening Range Settings"
var string G_5OR = "5m Opening Range Settings"
var string G_15OR = "15m Opening Range Settings"
var string G_EMA = "EMA Settings"
var string G_VWAP = "VWAP Settings"
var string G_SIG = "Signal Visuals"
// --- Inputs ---
pmColor = input.color(color.gray, "Premarket Color", group = G_PRE, tooltip = "Color used for the premarket high and low levels.")
pmStyle = input.string("Dashed", "Premarket Style", options = , group = G_PRE, tooltip = "Line style used for the premarket levels.")
pmWidth = input.int(1, "Premarket Line Width", minval = 1, maxval = 10, group = G_PRE, tooltip = "Width of the premarket high and low lines.")
pmSession = input.session("0400-0930", "Premarket Session", group = G_PRE, tooltip = "Exchange-time session used to calculate the premarket range.")
showPd = input.bool(true, "Show PDH/PDL", group = G_PD, tooltip = "Display the confirmed previous trading day's high and low.")
pdhColor = input.color(#5b9cf6, "PDH Color", group = G_PD, tooltip = "Color used for the previous day high level.")
pdlColor = input.color(#f23645, "PDL Color", group = G_PD, tooltip = "Color used for the previous day low level.")
pdStyle = input.string("Dotted", "PDH/PDL Style", options = , group = G_PD, tooltip = "Line style used for the previous day high and low levels.")
pdWidth = input.int(1, "PDH/PDL Line Width", minval = 1, maxval = 10, group = G_PD, tooltip = "Width of the previous day high and low lines.")
showOr2 = input.bool(true, "Show 2m ORB", group = G_2OR, tooltip = "Display the 2-minute opening range high and low.")
or2Color = input.color(#5b9cf6, "2m OR Color", group = G_2OR, tooltip = "Color used for the 2-minute opening range.")
or2Style = input.string("Solid", "2m OR Style", options = , group = G_2OR, tooltip = "Line style used for the 2-minute opening range.")
or2Width = input.int(1, "2m OR Line Width", minval = 1, maxval = 10, group = G_2OR, tooltip = "Width of the 2-minute opening range lines.")
or2Time = input.string("0930-0932", "2m OR Time", group = G_2OR, tooltip = "Exchange-time session used to calculate the 2-minute opening range.")
showOr5 = input.bool(true, "Show 5m ORB", group = G_5OR, tooltip = "Display the 5-minute opening range high and low.")
or5Color = input.color(#089981, "5m OR Color", group = G_5OR, tooltip = "Color used for the 5-minute opening range.")
or5Style = input.string("Solid", "5m OR Style", options = , group = G_5OR, tooltip = "Line style used for the 5-minute opening range.")
or5Width = input.int(1, "5m OR Line Width", minval = 1, maxval = 10, group = G_5OR, tooltip = "Width of the 5-minute opening range lines.")
or5Time = input.string("0930-0935", "5m OR Time", group = G_5OR, tooltip = "Exchange-time session used to calculate the 5-minute opening range.")
showOr15 = input.bool(true, "Show 15m ORB", group = G_15OR, tooltip = "Display the 15-minute opening range high and low.")
or15Color = input.color(#f23645, "15m OR Color", group = G_15OR, tooltip = "Color used for the 15-minute opening range.")
or15Style = input.string("Solid", "15m OR Style", options = , group = G_15OR, tooltip = "Line style used for the 15-minute opening range.")
or15Width = input.int(1, "15m OR Line Width", minval = 1, maxval = 10, group = G_15OR, tooltip = "Width of the 15-minute opening range lines.")
or15Time = input.string("0930-0945", "15m OR Time", group = G_15OR, tooltip = "Exchange-time session used to calculate the 15-minute opening range.")
emaFastLength = input.int(9, "Fast EMA Length", minval = 1, group = G_EMA, tooltip = "Period used to calculate the fast EMA.")
emaSlowLength = input.int(20, "Slow EMA Length", minval = 1, group = G_EMA, tooltip = "Period used to calculate the slow EMA.")
ema9Color = input.color(#5b9cf6, "Fast EMA Color", group = G_EMA, tooltip = "Color used for the fast EMA.")
ema20Color = input.color(#f23645, "Slow EMA Color", group = G_EMA, tooltip = "Color used for the slow EMA.")
showVwap = input.bool(true, "Show VWAP", group = G_VWAP, tooltip = "Display the volume-weighted average price.")
vwapColor = input.color(color.orange, "VWAP Color", group = G_VWAP, tooltip = "Color used for VWAP.")
showShapes = input.bool(true, "Show Buy/Sell Triangles", group = G_SIG, tooltip = "Display triangles when tracked levels break during regular session.")
// --- Helper: Get Line Style ---
getLineStyle(styleStr) =>
switch styleStr
"Solid" => line.style_solid
"Dotted" => line.style_dotted
"Dashed" => line.style_dashed
=> line.style_solid
// --- Logic ---
inSession(sess) => not na(time(timeframe.period, sess))
isNewDay = ta.change(time("D")) != 0
// EMAs, VWAP & Previous Day Levels
ema9 = ta.ema(close, emaFastLength)
ema20 = ta.ema(close, emaSlowLength)
vwapVal = ta.vwap(hlc3)
pdhVal = request.security(syminfo.tickerid, "D", high , lookahead = barmerge.lookahead_on)
pdlVal = request.security(syminfo.tickerid, "D", low , lookahead = barmerge.lookahead_on)
plot(ema9, "Fast EMA", color = ema9Color, linewidth = 1)
plot(ema20, "Slow EMA", color = ema20Color, linewidth = 1)
plot(showVwap ? vwapVal : na, "VWAP", color = vwapColor, linewidth = 2)
// --- Trackers ---
var float pmH = na
var float pmL = na
var int pmStartIdx = na
var float or2H = na
var float or2L = na
var int or2StartIdx = na
var float or5H = na
var float or5L = na
var int or5StartIdx = na
var float or15H = na
var float or15L = na
var int or15StartIdx = na
var int dayStartIdx = na
// --- Reset & Start Index Capture ---
if na(dayStartIdx) or isNewDay
dayStartIdx := bar_index
if isNewDay
pmH := na
pmL := na
pmStartIdx := na
or2H := na
or2L := na
or2StartIdx := na
or5H := na
or5L := na
or5StartIdx := na
or15H := na
or15L := na
or15StartIdx := na
if inSession(pmSession)
if na(pmStartIdx)
pmStartIdx := bar_index
pmH := math.max(high, nz(pmH, high))
pmL := math.min(low, nz(pmL, low))
if inSession(or2Time)
if na(or2StartIdx)
or2StartIdx := bar_index
or2H := math.max(high, nz(or2H, high))
or2L := math.min(low, nz(or2L, low))
if inSession(or5Time)
if na(or5StartIdx)
or5StartIdx := bar_index
or5H := math.max(high, nz(or5H, high))
or5L := math.min(low, nz(or5L, low))
if inSession(or15Time)
if na(or15StartIdx)
or15StartIdx := bar_index
or15H := math.max(high, nz(or15H, high))
or15L := math.min(low, nz(or15L, low))
// --- Visuals: Current Session Only Redraw ---
var line lines = array.new_line()
var label labels = array.new_label()
if barstate.islast
for l in lines
line.delete(l)
for lb in labels
label.delete(lb)
array.clear(lines)
array.clear(labels)
// Stagger the label x-positions to prevent overlapping if levels share the same price.
int pdIdx = bar_index + 2
int pmIdx = bar_index + 6
int or2Idx = bar_index + 10
int or5Idx = bar_index + 14
int or15Idx = bar_index + 18
// Previous day high and low.
if showPd and not na(pdhVal) and not na(pdlVal) and not na(dayStartIdx)
array.push(lines, line.new(dayStartIdx, pdhVal, bar_index, pdhVal, color = pdhColor, style = getLineStyle(pdStyle), width = pdWidth))
array.push(lines, line.new(dayStartIdx, pdlVal, bar_index, pdlVal, color = pdlColor, style = getLineStyle(pdStyle), width = pdWidth))
array.push(labels, label.new(pdIdx, pdhVal, "PDH", color = #00000000, textcolor = pdhColor, style = label.style_label_left, size = size.small))
array.push(labels, label.new(pdIdx, pdlVal, "PDL", color = #00000000, textcolor = pdlColor, style = label.style_label_left, size = size.small))
// Premarket.
if not na(pmH) and not na(pmStartIdx)
array.push(lines, line.new(pmStartIdx, pmH, bar_index, pmH, color = pmColor, style = getLineStyle(pmStyle), width = pmWidth))
array.push(lines, line.new(pmStartIdx, pmL, bar_index, pmL, color = pmColor, style = getLineStyle(pmStyle), width = pmWidth))
array.push(labels, label.new(pmIdx, pmH, "PM High", color = #00000000, textcolor = pmColor, style = label.style_label_left, size = size.small))
array.push(labels, label.new(pmIdx, pmL, "PM Low", color = #00000000, textcolor = pmColor, style = label.style_label_left, size = size.small))
// 2m ORB.
if showOr2 and not na(or2H) and not na(or2StartIdx) and not inSession(or2Time)
array.push(lines, line.new(or2StartIdx, or2H, bar_index, or2H, color = or2Color, style = getLineStyle(or2Style), width = or2Width))
array.push(lines, line.new(or2StartIdx, or2L, bar_index, or2L, color = or2Color, style = getLineStyle(or2Style), width = or2Width))
array.push(labels, label.new(or2Idx, or2H, "2m OR High", color = #00000000, textcolor = or2Color, style = label.style_label_left, size = size.small))
array.push(labels, label.new(or2Idx, or2L, "2m OR Low", color = #00000000, textcolor = or2Color, style = label.style_label_left, size = size.small))
// 5m ORB.
if showOr5 and not na(or5H) and not na(or5StartIdx) and not inSession(or5Time)
array.push(lines, line.new(or5StartIdx, or5H, bar_index, or5H, color = or5Color, style = getLineStyle(or5Style), width = or5Width))
array.push(lines, line.new(or5StartIdx, or5L, bar_index, or5L, color = or5Color, style = getLineStyle(or5Style), width = or5Width))
array.push(labels, label.new(or5Idx, or5H, "5m OR High", color = #00000000, textcolor = or5Color, style = label.style_label_left, size = size.small))
array.push(labels, label.new(or5Idx, or5L, "5m OR Low", color = #00000000, textcolor = or5Color, style = label.style_label_left, size = size.small))
// 15m ORB.
if showOr15 and not na(or15H) and not na(or15StartIdx) and not inSession(or15Time)
array.push(lines, line.new(or15StartIdx, or15H, bar_index, or15H, color = or15Color, style = getLineStyle(or15Style), width = or15Width))
array.push(lines, line.new(or15StartIdx, or15L, bar_index, or15L, color = or15Color, style = getLineStyle(or15Style), width = or15Width))
array.push(labels, label.new(or15Idx, or15H, "15m OR High", color = #00000000, textcolor = or15Color, style = label.style_label_left, size = size.small))
array.push(labels, label.new(or15Idx, or15L, "15m OR Low", color = #00000000, textcolor = or15Color, style = label.style_label_left, size = size.small))
// --- Signal Logic & Alerts ---
isRegularSession = inSession("0930-1600")
// Track crossovers on all bars to avoid conditional evaluation warnings.
crossUpPM = ta.crossover(close, pmH)
crossDnPM = ta.crossunder(close, pmL)
crossUpOR2 = ta.crossover(close, or2H)
crossDnOR2 = ta.crossunder(close, or2L)
crossUpOR5 = ta.crossover(close, or5H)
crossDnOR5 = ta.crossunder(close, or5L)
crossUpOR15 = ta.crossover(close, or15H)
crossDnOR15 = ta.crossunder(close, or15L)
// Individual breakout booleans.
pmBreakUp = isRegularSession and not inSession(pmSession) and crossUpPM
pmBreakDn = isRegularSession and not inSession(pmSession) and crossDnPM
or2BreakUp = showOr2 and isRegularSession and not inSession(or2Time) and crossUpOR2
or2BreakDn = showOr2 and isRegularSession and not inSession(or2Time) and crossDnOR2
or5BreakUp = showOr5 and isRegularSession and not inSession(or5Time) and crossUpOR5
or5BreakDn = showOr5 and isRegularSession and not inSession(or5Time) and crossDnOR5
or15BreakUp = showOr15 and isRegularSession and not inSession(or15Time) and crossUpOR15
or15BreakDn = showOr15 and isRegularSession and not inSession(or15Time) and crossDnOR15
// Master buy/sell signal.
buySignal = pmBreakUp or or2BreakUp or or5BreakUp or or15BreakUp
sellSignal = pmBreakDn or or2BreakDn or or5BreakDn or or15BreakDn
// Visual signals.
plotshape(showShapes and buySignal, "Buy Breakout", shape.triangleup, location.belowbar, #089981, size = size.small)
plotshape(showShapes and sellSignal, "Sell Breakdown", shape.triangledown, location.abovebar, #f23645, size = size.small)
// Alert triggers.
if buySignal
alert("Level Breakout: Buy Signal", alert.freq_once_per_bar)
if sellSignal
alert("Level Breakdown: Sell Signal", alert.freq_once_per_bar)
Indicator

Indicator

Volume Ignition OscillatorVolume Ignition Oscillator (VIO)
Volume Ignition Oscillator flags potential exhaustion points after a sharp price move by combining three conditions: a recent large price swing, price sitting at a range extreme, and volume running hot relative to its recent average. When all three line up, the oscillator "ignites" — hence the name.
How it works
Big Move Detection — the script measures the price change over a lookback window (default 5 bars) against a multiple of ATR (default 2x, 14-period ATR). A move that clears this threshold opens a "watch window" of N bars (default 8) during which the indicator is active — up-moves open a top watch, down-moves open a bottom watch.
Range Position — price's position within the recent high/low range (default 20 bars) is calculated as a 0–1 value. The oscillator only engages when price is in the top zone (default ≥75%) during a top watch, or the bottom zone (default ≤25%) during a bottom watch.
Volume Surge — current volume is compared to its moving average (default 20-period SMA). The excess volume above that average scales the signal — the more volume expands beyond normal, the stronger the reading.
These three factors combine into a raw oscillator value, which is then EMA-smoothed. A slower EMA of the oscillator acts as a signal line.
Reading the indicator
Columns above zero (shaded toward red) = potential topping pressure: a big up-move, price near the highs, and volume ignition.
Columns below zero (shaded toward teal/green) = potential bottoming pressure: a big down-move, price near the lows, and volume ignition.
Column brightness/gradient scales with the strength of the current reading relative to the last 100 bars.
Background shading shows when a watch window is active and fades out as the window expires.
Triangle markers print when the oscillator crosses the signal threshold (default ±0.15): a down-triangle at the top signals possible short/exhaustion, an up-triangle at the bottom signals possible long/exhaustion.
Info panel (top-right, optional) shows the live oscillator value, volume ratio, range position %, and current watch zone.
Suggested use
VIO is designed as a mean-reversion / exhaustion tool, not a trend-following signal. It's best used to:
Spot potential climax moves after an extended impulsive swing on rising volume
Time partial profit-taking or tightened stops on existing trend positions
Screen for reversal candidates that can then be confirmed with price action, support/resistance, or another momentum tool
It is not intended as a standalone entry system — combine it with your own risk management and confirmation criteria. Like any exhaustion/reversal tool, it can trigger repeatedly during strong sustained trends, so treat signals as alerts to watch price action rather than automatic trade triggers.
Inputs
Big Move Detection — lookback bars, ATR length, move threshold (x ATR), post-move watch window length
Volume — volume moving average length
Range Position — range lookback, top/bottom zone thresholds
Signal — oscillator smoothing length, signal trigger level
Appearance — top/bottom colors, toggle for the info panel
Alerts
Two alert conditions are built in:
VIO Short Signal — fires on a top exhaustion cross
VIO Long Signal — fires on a bottom exhaustion cross Indicator

Strategy

Indicator

Indicator

Indicator

Strategy

Indicator

Indicator
