Volatility, bands and ranges
True range, bands, channels and choppiness measures. See the indicator reference for how to read a signature, and Indicators for the construction and guarding rules.
BBW
Bollinger BandWidth as TradingView plots it: the distance between the bands in percent of their basis, (upper − lower) / basis × 100 (4.5 for bands 4.5% apart).
new BBW(sourceIndicator: Indicator<number>, period: number, stdDevMultiplier: number = 2)
| Parameter | Type | Default | Meaning |
|---|---|---|---|
sourceIndicator |
Indicator<number> |
required | The number stream. |
period |
number |
required | Bollinger length. |
stdDevMultiplier |
number |
2 |
Standard deviations between the basis and each band (2 by default). |
- Input: A number stream whose values are never
undefined. - Value (
getValue()afterhasValue()):number | undefined - Warm-up: First value on candle
period.
const symbol = 'BTC';
const candles = manager.getIntervalData(symbol, 60);
const indicator = new BBW(candles.close, 20);
manager.onIntervalCandle(symbol, 60, () => {
if (!indicator.hasValue()) return;
const value = indicator.getValue();
if (value === undefined) return;
manager.debugLog('BBW', value);
});
BBWP
Bollinger BandWidth Percentile, The_Caretaker's: the share, in percent, of the previous lookback BBW values (fewer at first) lower than or equal to the current one.
new BBWP(sourceIndicator: Indicator<number>, period: number, lookback: number)
| Parameter | Type | Default | Meaning |
|---|---|---|---|
sourceIndicator |
Indicator<number> |
required | The number stream. |
period |
number |
required | Bollinger length. |
lookback |
number |
required | How many BBW values to rank against. |
- Input: A number stream whose values are never
undefined. - Value (
getValue()afterhasValue()):number | undefined - Warm-up: First value on candle
period + 2.
const symbol = 'BTC';
const candles = manager.getIntervalData(symbol, 60);
const indicator = new BBWP(candles.close, 13, 252);
manager.onIntervalCandle(symbol, 60, () => {
if (!indicator.hasValue()) return;
const value = indicator.getValue();
if (value === undefined) return;
manager.debugLog('BBWP', value);
});
Bollinger
Bollinger bands: the maPeriod SMA (mean) plus and minus stdDevMultiplier standard deviations.
new Bollinger(sourceIndicator: Indicator<number>, maPeriod: number = 20, stdDevMultiplier: number = 2)
| Parameter | Type | Default | Meaning |
|---|---|---|---|
sourceIndicator |
Indicator<number> |
required | The number stream (usually closes). |
maPeriod |
number |
20 |
Window length. |
stdDevMultiplier |
number |
2 |
Band width in standard deviations. |
- Input: A number stream whose values are never
undefined(candles.close). - Value (
getValue()afterhasValue()):BollingerValueupper: number | undefinedmean: number | undefinedlower: number | undefined
- Warm-up: Fields are
undefineduntilmaPeriodcandles have been seen.
const symbol = 'BTC';
const candles = manager.getIntervalData(symbol, 60);
const indicator = new Bollinger(candles.close, 20, 2);
manager.onIntervalCandle(symbol, 60, () => {
if (!indicator.hasValue()) return;
const value = indicator.getValue();
if (value.upper === undefined || value.lower === undefined || value.mean === undefined) return;
manager.debugLog('upper', value.upper, 'mean', value.mean, 'lower', value.lower);
});
Chop
Choppiness index: 100 × log10(Σ TR / (highest high − lowest low)) / log10(period); high values mean a sideways market.
new Chop(highIndicator: Indicator<number | undefined>, lowIndicator: Indicator<number | undefined>, trIndicator: Indicator<number | undefined>, period: number)
| Parameter | Type | Default | Meaning |
|---|---|---|---|
highIndicator |
Indicator<number | undefined> |
required | The high stream (candles.high). |
lowIndicator |
Indicator<number | undefined> |
required | The low stream (candles.low). |
trIndicator |
Indicator<number | undefined> |
required | The true range (new TR(candles)). |
period |
number |
required | Window length. |
- Input: Three number streams: highs, lows and true range.
- Value (
getValue()afterhasValue()):number | undefined - Warm-up: First value on candle
period; not finite when the window's highest high equals its lowest low.
const symbol = 'BTC';
const candles = manager.getIntervalData(symbol, 60);
const indicator = new Chop(candles.high, candles.low, new TR(candles), 14);
manager.onIntervalCandle(symbol, 60, () => {
if (!indicator.hasValue()) return;
const value = indicator.getValue();
if (value === undefined || !Number.isFinite(value)) return;
manager.debugLog('chop', value);
});
Choppy
Counts monotonic runs among the last six closes: type rates the current run ('none', 'weak', 'medium', 'strong') and line counts trending candles among the last ten.
new Choppy(candleIndicator: Indicator<Candle>)
| Parameter | Type | Default | Meaning |
|---|---|---|---|
candleIndicator |
Indicator<Candle> |
required | The candle series. |
- Input: The candle series.
- Value (
getValue()afterhasValue()):ChoppyValuetype: ChoppyTypeline: number
ChoppyTypeis'none' | 'weak' | 'medium' | 'strong'.- Warm-up:
typeis'none'until six candles have been seen;linefills over ten candles.
const symbol = 'BTC';
const candles = manager.getIntervalData(symbol, 60);
const indicator = new Choppy(candles);
manager.onIntervalCandle(symbol, 60, () => {
if (!indicator.hasValue()) return;
const value = indicator.getValue();
manager.debugLog('run', value.type, 'trending candles out of 10', value.line);
});
DC
Donchian channel MIDLINE: (highest high + lowest low) / 2 over extremePeriod candles, current included. For the upper and lower channel lines use Extreme.
new DC(candleIndicator: Indicator<Candle>, extremePeriod: number)
| Parameter | Type | Default | Meaning |
|---|---|---|---|
candleIndicator |
Indicator<Candle> |
required | The candle series. |
extremePeriod |
number |
required | Window length, current candle included. |
- Input: The candle series.
- Value (
getValue()afterhasValue()):number - Warm-up: A number from the first candle (partial window until
extremePeriodcandles).
const symbol = 'BTC';
const candles = manager.getIntervalData(symbol, 60);
const indicator = new DC(candles, 20);
manager.onIntervalCandle(symbol, 60, () => {
if (!indicator.hasValue()) return;
const value = indicator.getValue();
manager.debugLog('Donchian midline', value);
});
Envelope
Percentage bands around an SMA or EMA basis.
new Envelope(sourceIndicator: Indicator<number | undefined>, length: number = 20, percent: number = 10, exponential: boolean = false)
| Parameter | Type | Default | Meaning |
|---|---|---|---|
sourceIndicator |
Indicator<number | undefined> |
required | Numeric input stream. |
length |
number |
20 |
Basis length, 1 to 5000. |
percent |
number |
10 |
Signed band percentage, divided by 100. |
exponential |
boolean |
false |
True for an EMA basis; false for an SMA. |
- Input: Numeric source stream.
- Value (
getValue()afterhasValue()):EnvelopeValuebasis: number | undefinedupper: number | undefinedlower: number | undefined
- Warm-up: All three values start at bar length - 1. EMA restart convergence measured up to 958 bars at length 100 across three markets. Chart preloads max(200, 30 * length); percent is not a lookback.
const symbol = 'BTC';
const candles = manager.getIntervalData(symbol, 60);
const indicator = new Envelope(candles.close, 20, 10, false);
manager.onIntervalCandle(symbol, 60, () => {
if (!indicator.hasValue()) return;
const value = indicator.getValue();
if (value.basis === undefined) return;
manager.debugLog('envelope', value.basis, value.upper, value.lower);
});
FindMarketBottom
Williams VIX Fix bottom finder: wvf = 100 × (highest close over 22 − low) / highest close, with Bollinger and percentile ranges; alert is true when wvf spikes above them.
new FindMarketBottom(candleIndicator: ICandleIndicator, bollingerLength: number = 20, bollingerMult: number = 2.0, percentileLookback: number = 50, highPercentile: number = 0.85, lowPercentile: number = 1.01)
| Parameter | Type | Default | Meaning |
|---|---|---|---|
candleIndicator |
ICandleIndicator |
required | The candle series. |
bollingerLength |
number |
20 |
Bollinger length on wvf. |
bollingerMult |
number |
2.0 |
Bollinger multiplier. |
percentileLookback |
number |
50 |
Look-back for the percentile range. |
highPercentile |
number |
0.85 |
Upper range factor (0.85 = 85% of the highest wvf). |
lowPercentile |
number |
1.01 |
Lower range factor. |
- Input: The candle series.
- Value (
getValue()afterhasValue()):FindMarketBottomValuewvf: number | undefinedupperBand: number | undefinedmidLine: number | undefinedlowerBand: number | undefinedrangeHigh: number | undefinedrangeLow: number | undefinedalert: boolean
- Warm-up:
alertis always a boolean; band fields areundefineduntilbollingerLengthandpercentileLookbackvalues exist (about 50 candles with the defaults).
const symbol = 'BTC';
const candles = manager.getIntervalData(symbol, 60);
const indicator = new FindMarketBottom(candles);
manager.onIntervalCandle(symbol, 60, () => {
if (!indicator.hasValue()) return;
const value = indicator.getValue();
if (value.alert) manager.debugLog('possible bottom, wvf', value.wvf);
});
KeltnerChannels
Keltner channels: an EMA of the close (middle) plus and minus multiplier ATRs.
new KeltnerChannels(candleIndicator: ICandleIndicator, period: number = 20, multiplier: number = 2, atrPeriod: number = 10)
| Parameter | Type | Default | Meaning |
|---|---|---|---|
candleIndicator |
ICandleIndicator |
required | The candle series. |
period |
number |
20 |
EMA length. |
multiplier |
number |
2 |
Channel width in ATRs. |
atrPeriod |
number |
10 |
ATR length. |
- Input: The candle series.
- Value (
getValue()afterhasValue()):{ upper: number | undefined; middle: number | undefined; lower: number | undefined; }upper: number | undefinedmiddle: number | undefinedlower: number | undefined
- Warm-up: Fields are
undefineduntil both the EMA (candleperiod) and the ATR (candleatrPeriod + 1) are ready.
const symbol = 'BTC';
const candles = manager.getIntervalData(symbol, 60);
const indicator = new KeltnerChannels(candles, 20, 2, 10);
manager.onIntervalCandle(symbol, 60, () => {
if (!indicator.hasValue()) return;
const value = indicator.getValue();
if (value.upper === undefined || value.lower === undefined) return;
manager.debugLog('upper', value.upper, 'lower', value.lower);
});
Median
Nearest-rank median with ATR bands and an EMA of the median.
new Median(candleIndicator: Indicator<Candle>, sourceIndicator: Indicator<number | undefined>, length: number = 3, atrLength: number = 14, atrMultiplier: number = 2)
| Parameter | Type | Default | Meaning |
|---|---|---|---|
candleIndicator |
Indicator<Candle> |
required | OHLC candle stream for true range. |
sourceIndicator |
Indicator<number | undefined> |
required | Numeric median source; the built-in defaults to hl2. |
length |
number |
3 |
Nearest-rank median and median EMA length, 1 to 5000. |
atrLength |
number |
14 |
SMA-seeded RMA true-range length, 1 to 5000. |
atrMultiplier |
number |
2 |
Signed integer ATR distance multiplier. |
- Input: Candle stream for ATR and a numeric stream for the median.
- Value (
getValue()afterhasValue()):MedianValuevalue: number | undefinedupper: number | undefinedlower: number | undefinedema: number | undefined
- Warm-up: Median begins at bar length - 1, its EMA at 2 * (length - 1), and bands at max(length, atrLength) - 1 on complete data. Measured restart convergence up to 1691 bars at length/ATR 100 across three markets. Chart preloads max(200, 30 * largest length); the multiplier is not a lookback.
- The nearest-rank median of [1, 2, 3, 4] is 2, rather than 2.5. Missing median observations are skipped.
const symbol = 'BTC';
const candles = manager.getIntervalData(symbol, 60);
const indicator = new Median(candles, candles.hl2, 3, 14, 2);
manager.onIntervalCandle(symbol, 60, () => {
if (!indicator.hasValue()) return;
const value = indicator.getValue();
if (value.value === undefined) return;
manager.debugLog('median', value.value, value.upper, value.lower, value.ema);
});
TR
True range: max(high − low, |high − previous close|, |low − previous close|). Smooth it with RMA for an ATR (TradingView's ta.atr).
new TR(candleIndicator: Indicator<Candle>, handleNa: boolean = true)
| Parameter | Type | Default | Meaning |
|---|---|---|---|
candleIndicator |
Indicator<Candle> |
required | The candle series. |
handleNa |
boolean |
true |
Count high − low on the first candle, which has no previous close (true by default, as TradingView's ATR does); false leaves that candle undefined, as its DMI does. |
- Input: The candle series.
- Value (
getValue()afterhasValue()):number | undefined - Warm-up: A value from the first candle; from the second with
handleNaset tofalse.
const symbol = 'BTC';
const candles = manager.getIntervalData(symbol, 60);
const indicator = new TR(candles);
manager.onIntervalCandle(symbol, 60, () => {
if (!indicator.hasValue()) return;
const value = indicator.getValue();
if (value === undefined) return;
manager.debugLog('true range', value);
});