Range Bars — SPY

Range and volume bars are constructed from 1-minute OHLCV data by accumulating source bars until the selected event threshold is met. Range bars wait for the aggregated high-low span; volume bars wait for cumulative volume. Unlike time-based bars, event bars adapt to volatility — quiet periods collapse into fewer bars, busy periods produce more. Toggle between standard timeframes and the three range-bar methods below.

Mode
Bars: —
Period: —
Price: —
Detail: —
Move cursor over chart for OHLC
Calculation check
First completed range candle for each method. Source rows are consecutive 1-minute bars accumulated into the emitted candle.

How Range Bars Work

We aggregate consecutive 1 minute OHLCV bars into a pending bucket. Nothing is drawn while the selected event condition remains false. Once the condition is satisfied, that whole OHLCV bucket is emitted as one candle and the next source bar starts a new bucket. The chart spacing is compressed to one slot per emitted event candle; tick labels show the source timestamp for the corresponding emitted candle.

Range Candle OHLCV

Let the source 1 minute bars inside one pending bucket be i = s, …, e. The emitted range candle is:

Open   = O_s
High   = max(H_i) for i = s..e
Low    = min(L_i) for i = s..e
Close  = C_e
Volume = sum(V_i) for i = s..e

The candle wick is not a separate calculation. It is simply the part of this emitted High/Low range that lies outside the candle body formed by Open and Close.

Absolute Price Range

High − Low ≥ Δ

A bar forms whenever the aggregated candle's high-low span reaches at least Δ points. Simple but ticker-dependent: a Δ that works for SPY will be too large for a low-priced stock.

Percentage Range

100 × (High − Low) / P_ref ≥ r

Expresses the high-low span as a percentage of a reference price. This demo uses the bucket open as the reference: P_ref = Open = O_s.

Percentage Break Range

H_1 = high of the first source bar in the bucket
L_1 = low of the first source bar in the bucket

100 × (High / H_1 - 1) ≥ r
or
100 × (L_1 / Low - 1) ≥ r

This alternative uses the first source bar as the seed range. The bucket keeps accumulating until later highs break above that seed high by r, or later lows break below that seed low by r. Once the first break occurs, the completed candle is printed and the next source bar starts the next bucket.

Log Range

log(High) − log(Low) ≥ ℓ
log(High / Low) ≥ ℓ

Measures the high-low span in log-price units. For fixed-size completed range bars this span is approximately , modulo source-bar granularity, tick-size rounding, and gaps.

Volume Bars

Volume = sum(V_i) for i = s..e
Volume ≥ V_min

A volume bar ignores elapsed clock time and emits once the pending bucket's cumulative volume reaches the minimum volume threshold. The emitted candle still uses the same OHLCV aggregation above: first source open, max high, min low, last source close, and summed volume.

Manual Calculation Example

Here are concrete calculations from the SPY data used in the chart.

Absolute range, Δ = $0.50

The first source bar is 2025-05-01 09:30 ET:

O = 560.37
H = 561.00
L = 559.81
C = 560.32
V = 692,295

High - Low = 561.00 - 559.81 = 1.19
1.19 ≥ 0.50, so emit immediately.

The emitted range candle is:

Open   = 560.37
High   = 561.00
Low    = 559.81
Close  = 560.32
Volume = 692,295

Percent range, r = 0.50%

For percent range, this demo uses the first bucket open as the reference price: P_ref = Open = 560.37. At 09:30:

High = 561.00
Low  = 559.81

100 × (High - Low) / Open
= 100 × (561.00 - 559.81) / 560.37
= 0.212%

0.212% < 0.50%, so keep accumulating.

By 10:00, the accumulated bucket is:

High = 561.36
Low  = 558.65

100 × (561.36 - 558.65) / 560.37
= 0.484%

0.484% < 0.50%, so keep accumulating.

By 10:23, the bucket finally crosses the threshold:

High = 561.71
Low  = 558.65
Close = 561.61
Volume = 11,706,166

100 × (561.71 - 558.65) / 560.37
= 100 × 3.06 / 560.37
= 0.546%

0.546% ≥ 0.50%, so emit.

The emitted percent-range candle is:

Open   = 560.37
High   = 561.71
Low    = 558.65
Close  = 561.61
Volume = 11,706,166
Source = 09:30 through 10:23 ET

Percent break range, r = 0.50%

The first source bar seeds the range with H_1 = 561.00 and L_1 = 559.81. The bucket keeps accumulating until either side breaks the seed by 0.50%.

At 11:15 ET:
High = 564.07
Low  = 558.65

Upside break:
100 × (High / H_1 - 1)
= 100 × (564.07 / 561.00 - 1)
= 0.547%

Downside break:
100 × (L_1 / Low - 1)
= 100 × (559.81 / 558.65 - 1)
= 0.208%

max(0.547%, 0.208%) ≥ 0.50%, so emit.

The emitted percent-break candle is:

Open   = 560.37
High   = 564.07
Low    = 558.65
Close  = 563.52
Volume = 19,062,621
Source = 09:30 through 11:15 ET

Log range, ℓ = 0.002

Using the same first 09:30 source bar:

High = 561.00
Low  = 559.81

log(High / Low)
= log(561.00 / 559.81)
= log(1.002125)
= 0.002123

0.002123 ≥ 0.002, so emit immediately.

The emitted log-range candle is:

Open   = 560.37
High   = 561.00
Low    = 559.81
Close  = 560.32
Volume = 692,295

Volume bar, V_min = 5,000,000 shares

Volume bars accumulate source volume until the threshold is reached. Using the first bucket of the same SPY data:

Start = 2025-05-01 09:30 ET
End   = 2025-05-01 09:46 ET

Volume = sum(V_i)
       = 5,351,243

5,351,243 ≥ 5,000,000, so emit.

The emitted volume candle is:

Open   = 560.37
High   = 561.00
Low    = 559.05
Close  = 560.38
Volume = 5,351,243
Source = 09:30 through 09:46 ET

Standard Timeframes

1 min uses the raw data directly. 1 day, 1 week, and 1 month aggregate the 1-minute bars in the browser by calendar period (open = first open, high = max high, low = min low, close = last close, volume = sum of volume).