Candle bodies · Full-width range · Chart data

Bollinger Bars Pine Script: inspect the whole candle range

Bollinger Bars draw the high-to-low range as a broad colored block, then distinguish the open-to-close body within it. This Pineify example uses blue for the range, green when close exceeds open, and red otherwise. It changes how existing chart values are displayed; it adds no volatility band or forecast.

Two drawing layers, one set of OHLC values

The first call passes high, high, low, low to plotcandle. Its synthetic open is the high and its synthetic close is the low, so its blue body fills the entire range. The second call uses the actual open, high, low and close, with native wicks hidden. Its green or red body covers the middle of that blue range. These remaining blue regions are broad blocks, not ordinary thin wick lines.

Hypothetical bars, each with high 105 and low 97
Open / closeBodyUpper / lower blue rangeBody / full range
100 / 103Green, 100–103103–105 / 97–1003 / 8 = 37.5%
103 / 100Red, 100–103103–105 / 97–1003 / 8 = 37.5%
100 / 100Red branch, zero-height body100–105 / 97–1000 / 8 = 0%

Upper remainder = high − max(open, close); lower remainder = min(open, close) − low. The full range is high − low. A zero-range bar has an undefined body-to-range ratio and should not be assigned a percentage by dividing by zero. The supplied indicator does not compute these ratios; they are independent checks of the geometry.

The helper function returns close, but its assigned output is not used to decide color. The actual rule is the strict comparison close > open. There is no previous-close comparison, volume test, moving average or standard deviation in that rule.

A green bar can still be a down day

Suppose the prior close is 110, the next open is 100, and the next close is 103. The body is green because 103 exceeds 100, while the close-to-close change is −7, or −6.36%. A gap is measured relative to the previous close; it is not included in the current bar's open-close color test.

Likewise, three green bars with open/close pairs 100/101, 98/99 and 96/97 have falling closes despite all three intrabar gains. A run of green bodies does not prove an upward trend, buyer-initiated volume or accumulation. Red includes equality in this code, so a red run can include unchanged open-close bars.

On an unfinished bar opening at 100, updates at 101, 99 and 100 give green, red and red respectively. The final color is only known when the bar closes. No closed-bar gate, alert condition or order logic is present in the retained source.

Standard chart values are used directly. On a Heikin-Ashi chart those values are synthetic, so this overlay does not recover traded OHLC prices. A line chart can still supply underlying bar OHLC; hiding candle graphics is not the same as removing those data. Verify the chart type and feed before interpreting the display.

The existing Pine Script example

The source below preserves the two plotting calls and framework helpers. The time-range helpers are not called by this candle display. There are no input declarations or custom signals. Compilation checks syntax; a chart comparison is still needed to inspect stacking and appearance.

Pine Script v6
// 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="Bollinger Bars", overlay=true, max_labels_count=500)

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
        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
        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
        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
        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, 7, 9)))
    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]

p_ta_bollinger_bars() =>
    close

p_ind_1 = p_ta_bollinger_bars()

plotcandle(high, high, low, low, title="Bollinger Bars - Wicks", color=color.rgb(13, 52, 158, 0), bordercolor=color.rgb(13, 52, 158, 0), wickcolor=na, display=display.pane)

col = close > open ? color.rgb(8, 153, 129, 0) : color.rgb(242, 54, 69, 0)
plotcandle(open, high, low, close, title="Bollinger Bars - Bodies", color=col, bordercolor=col, wickcolor=na)
Bollinger Bars chart preview with differently colored candle bodies and range blocks

Adding this indicator does not delete or replace the original chart series. If its colors are obscured, inspect Visual Order / Bring to Front or the original series visibility. The source does not explicitly request that it appear in front of chart candles.

Builder settings and copied-source settings differ

Pineify drawing settingDefaultEffect when generated
Show WicksEnabledIncludes the full-range blue plotcandle call
Wick Color#0D349EColors that full-range layer
Bull Color#089981Body when close > open
Bear Color#F23645Body when close <= open

These are builder drawing controls, not four Inputs in the copied script. Regenerating with Show Wicks disabled omits the first drawing call. That removes the high-low extensions from this overlay, so choosing it trades away range information; it is not a universally better intraday setting. TradingView Style controls and script input declarations are separate mechanisms.

What the name and comparison actually mean

TradingView's Bollinger Bars documentation credits John Bollinger and describes the equal-width body and range sections. This is not an unnamed Pineify invention. The retained example implements that visual convention; no claim of byte-for-byte identity with TradingView's built-in source is made.

Ordinary TradingView candles already support body, border and wick customization, including an option to color by the previous close. A separate indicator is useful for this broad-range presentation or custom logic, not because native candles lack color controls.

Bollinger Bands calculate an average and dispersion envelope. Bollinger Bars do not. Heikin-Ashi candles calculate synthetic OHLC values; applying this display to them preserves those synthetic inputs instead of converting them to market prices.

There is no measured scanning-time advantage, prediction accuracy or strategy win rate attached to these colors. Rendering still consumes resources, even though no rolling indicator calculation is involved. Prefer a color scheme that remains distinguishable against your actual background, and retain numeric OHLC values for checks.

A reproducible chart check before strategy work

  1. Use a recorded symbol, session, chart type and timeframe. Open the Pine Editor from the chart's Pine control, paste the complete source and add it to the chart.
  2. Compare a green, red, equal-open-close and zero-range bar against the Data Window. Check both the body and full range, then inspect an open bar separately.
  3. Compare against native candles with previous-close coloring disabled. If colors differ, check equality handling, chart type and visual order before changing the formula.
  4. If researching a pattern such as three green bars above EMA(50), define it on completed bars and evaluate the next eligible order execution. This illustrative condition is not present in the script and is not an optimized rule.
  5. Specify exits, position sizing, spread, commissions, slippage and gap handling. Compare the same condition calculated directly from OHLC; changing its display alone cannot change the underlying signal timestamps.

For example, a proposed long entry at 103 with a stop reference at 99 has planned price risk 4 per unit. A gap to an executable exit at 97 produces loss 6 per unit before costs. Green bodies and a visible stop reference do not cap the realized loss.

Use the official bar-plotting reference to check plotcandle parameters. For an adaptation, specify whether settings should be generated constants or editable inputs, how ties are colored and whether signals wait for the close.

Specify a candle-display adaptation

Pineify access and usage depend on the selected product and account. This builder indicator is marked as paid in its configuration. Generated adaptations require compilation and chart verification.

Bollinger Bars questions

TradingView attributes Bollinger Bars to John Bollinger. They display a candle body and its remaining high-low range at the same width, using different colors. The example here is Pineify code implementing that visual idea; it does not calculate Bollinger Bands.

Only that this bar's close is greater than its open. It does not compare with the prior close. A bar can be green after a gap down and still finish below the previous close. Equality takes the red branch in this example.

No. The first plotcandle call draws a blue candle body from high to low. The second draws the actual open-close body with wickcolor unavailable. The remaining blue regions are broad blocks, which is the defining visual difference from conventional thin wicks.

Pineify's builder has a Show Wicks drawing setting that determines whether the first plotting call is generated. This copied example has that call enabled and has no input declarations. It does not expose a custom Show Wicks switch in TradingView's Inputs tab.

It adds indicator candles. The original chart series remains present, and its visual order can obscure the overlay. Inspect the indicator's visual order or the original series visibility before assuming the colors are wrong.

On the open bar, the latest price can move above or below the open and change the body color. This example has no bar-close confirmation gate. A closed-bar pattern rule must explicitly wait for confirmation.

Yes. TradingView provides settings for body, border and wick colors, as well as a previous-close coloring option. A script is not required merely to change those colors. Bollinger Bars add the distinct full-width range display.

No. The script has no entries, exits, sizing, alert conditions or performance calculation. A run of green bars describes intrabar direction only. Any strategy built from that observation needs explicit timing, costs and testing.