In TradingView Pine we can programmatically colour the chart’s background and use that feature to do things like colouring the background conditionally and offsetting a coloured background. But those backgrounds can also be overlaid on top of each other. So how do we do that?

In this article:

Programmatically colouring a TradingView background repeatedly

When using colours programmatically in TradingView, we choose from the basic TradingView colours and hexadecimal colour values. Once a script uses a colour, we can change that colour manually too.

One function that works with colours is bgcolor(), which colours the chart’s background from top to bottom (Pine Script Language Tutorial, n.d.). What chart area that’s affected by this function depends on where the script displays: if the script overlays on the instrument’s data series, then bgcolor() colours the background of price bars. And when the script plots in its own subchart, then the function colours the background of that chart area. See colouring the chart’s background in TradingView for more on bgcolor() and its arguments.

Typically, bgcolor() is used once in a script (as we did in offsetting a coloured background), and this still allows for more elaborate things like colouring a TradingView background conditionally. But we can add this function as many times as we want to our script. Such a multiple use of bgcolor() can make our code easier to read and, more interestingly, allows us to place coloured backgrounds on top of each other. Let’s take a closer look at how this works.

Combining coloured backgrounds: the impact of function call order

When we use bgcolor() several times in one script, their order matters: the first bgcolor() function call creates the main background that additional coloured backgrounds are placed on. In other words, the background colour of the last bgcolor() function is the uppermost background.

An example of that is the following:

study(title="Overlaying coloured backgrounds", overlay=false)

bgcolor(color=blue, transp=25)
bgcolor(color=close > open ? lime : na, transp=25)

First we set the indicator’s properties with study(). With this function’s overlay argument set to false the script displays in a separate subchart (TradingView, n.d.).

The first bgcolor() statement then sets the chart’s background to the blue standard TradingView colour. The transp argument, which sets the background’s transparency from 0 (not transparent) to 100 (fully transparent) (TradingView, n.d.), is given a value of 25 here.

The second bgcolor() function call sets the chart’s background conditionally. For that we use the conditional (ternary) operator (?:). That operator evaluates a condition and, should the condition be true, returns the operator’s second value. When the condition is false, the operator returns its third value (Pine Script Language Tutorial, n.d.).

The condition that we check here is whether the bar’s closing price (close) is greater than (>) the bar’s open (open). When that’s the case, the conditional operator returns the lime colour and we use that colour subsequently with the color argument of the bgcolor() function. Should the bar close lower or unchanged, the conditional operator returns na. That built-in variable represents a “not a number” value (TradingView, n.d.) which, in turn, has the effect of making a coloured background invisible (see Pine Script Language Tutorial, n.d.). This means that we colour the background of bars that are closed higher lime green, while we leave the background of other price bars untouched.

This example script looks like this when added to a chart:

Example of overlaid coloured backgrounds in TradingView

The main background is blue here since every bar that closed lower or unchanged has a background with that colour. This happens because those bars weren’t coloured by the second bgcolor() statement, and so they still have the background colour from the first bgcolor() function call.

We can see the effect that the order of bgcolor() statements has more clearly when the two bgcolor() function calls switch places. The code then becomes:

study(title="Overlaying coloured backgrounds", overlay=false)

bgcolor(color=close > open ? lime : na, transp=25)
bgcolor(color=blue, transp=25)

The only change that we’ve made here is that now we first set the chart’s background to lime or na (that is, transparent), and then the second bgcolor() statement sets the background to blue. This changes our EUR/USD chart to:

Changed the order of the coloured TradingView backgrounds

Now all bars have a blue background. Some price bars, however, have a blue-like shade. That’s caused by the green background ‘shining through’ the blue background. This effect of the blue background colouring over the lime green one is even more pronounced when we turn off the backgrounds’ transparency:

study(title="Overlaying coloured backgrounds", overlay=false)

bgcolor(color=close > open ? lime : na, transp=0)
bgcolor(color=blue, transp=0)

Here the last statement still unconditionally colours the background blue, but now the transp argument of both bgcolor() statements is set to 0 to make the background fully solid (TradingView, n.d.). This changes the chart to:

Solid TradingView backgrounds overlaid on top of each other

The green background that’s made with the first bgcolor() statement isn’t visible anymore now since the blue background (that’s made with the second bgcolor() function call) overlays it completely. Now let’s look at a more practical example of overlaying backgrounds in TradingView.

Highlighting trading signals with superimposed TradingView backgrounds

In the next example we colour the background twice: first based on a moving average and then again with the Relative Strength Index (RSI). The idea is that the first coloured background show the instrument’s general trend, while the second, overlaid background displays the actual buy and sell signals. We’ll also look at how the indicator and its input options look, but first the code:

study(title="Colouring the background repeatedly", overlay=false)

// Inputs
srcData    = input(title="Source Data", type=source, defval=close)
rsiLength  = input(title="RSI Length", type=integer, defval=14)
overbought = input(title="RSI Overbought", type=integer, defval=70)
oversold   = input(title="RSI Oversold", type=integer, defval=30)
smaLength  = input(title="SMA Length", type=integer, defval=5)

// Compute values
rsiValue = rsi(srcData, rsiLength)
smaValue = sma(srcData, smaLength)

// Display values
plot(series=rsiValue, color=purple, linewidth=2)
hline(price=overbought, color=black)
hline(price=oversold, color=black)

// Colour the background based on the SMA
backgroundColour = (close > smaValue) ? green : red

bgcolor(color=backgroundColour, transp=85)

// Colour the background when the RSI signals happen
buySignal  = (rsiValue > oversold) and (rsiValue[1] <= oversold) and 
     (close > smaValue)
sellSignal = (rsiValue < overbought) and (rsiValue[1] >= overbought) and 
     (close < smaValue)

bgcolor(color=buySignal ? lime : na, transp=50)
bgcolor(color=sellSignal ? red : na, transp=50)

We begin with study(), a function that needs to be included in every indicator’s code (TradingView, n.d.). With this function’s overlay argument set to false the indicator plots in a separate chart pane below the main chart (Pine Script Language Tutorial, n.d.).

Then we add several input options to the script:

srcData    = input(title="Source Data", type=source, defval=close)
rsiLength  = input(title="RSI Length", type=integer, defval=14)
overbought = input(title="RSI Overbought", type=integer, defval=70)
oversold   = input(title="RSI Oversold", type=integer, defval=30)
smaLength  = input(title="SMA Length", type=integer, defval=5)

These five input options are made with the input() function, which not only creates a manual option in the script’s settings but also returns the input’s current value (TradingView, n.d.). Here we store those current values in variables with the assignment operator (=). That allows us to use the input’s current value later on in the script by referring to the variable.

The first input is a so-called ‘source’ input option, which we make by setting the type argument of the input() function to source. This creates a pull-down menu in the script’s options for selecting different price data from the instrument that the script is added to (Pine Script Language Tutorial, n.d.), such as high, low, or close prices. This input’s current value is stored in the srcData input variable, and it holds the instrument’s closing prices by default (defval=close). We name the input “Source Data” with the input() function’s title argument, and this text is placed before the input option in the script’s setting (see image further down below).

The other four input options are all numerical integer input options. These inputs only accept whole numbers, and we make these by setting the input() function’s type argument to integer (Pine Script Language Tutorial, n.d.). The first integer input is named “RSI Length” and set to a default value of 14 (defval=14). Its current value is stored in the rsiLength variable and we’ll use this variable later on when computing the RSI.

Then the next two inputs are named “RSI Overbought” and “RSI Oversold” with default values of 70 and 30. We use these to set the overbought and oversold levels for the RSI, and keep their values in the overbought and oversold input variables. The last integer input option is titled “SMA Length” and has a default value of 5 with its current value stored in the smaLength variable.

Next we compute the RSI and SMA values:

rsiValue = rsi(srcData, rsiLength)
smaValue = sma(srcData, smaLength)

We calculate the oscillator’s value by passing two arguments in the rsi() function: a series of values plus an integer that sets the RSI length as the number of bars (TradingView, n.d.). These arguments are set to the srcData and rsiLength input variables, which hold closing prices and a value of 14 by default. We store the value that’s returned by rsi() in the rsiValue variable.

Then we determine the SMA with sma(). That function also has a series of values alongside an integer that sets the length in bars as arguments (TradingView, n.d.), and we set these to srcData and smaLength. This calculates the 5-bar SMA on closing prices when these two input variables are set to their standard values. We assign the moving average value in the smaValue variable.

Now we plot some values on the chart:

plot(series=rsiValue, color=purple, linewidth=2)
hline(price=overbought, color=black)
hline(price=oversold, color=black)

Our RSI values are used with plot() here, a function that displays a series of values on the chart (TradingView, n.d.). For that we set this function’s series argument to the rsiValue variable. This function defaults to a line plot, and we colour that line purple here with a linewidth of 2, which is one step above the standard size for plots (TradingView, n.d.).

We then create the overbought and oversold lines in the black standard TradingView colour with hline(). That function renders a horizontal line at a fixed price level that’s set by its price argument (TradingView, n.d.), which we set to the overbought and oversold input variables here. This way these lines also change their location whenever we adjust the “RSI Overbought” and “RSI Oversold” input options.

Note that we don’t plot our SMA. That’s because it has a different price scale than the RSI, and so will skew the indicator’s subchart. Instead, we’ll use that moving average later on when determining the buy and sell signals. But we first apply the first background layer:

backgroundColour = (close > smaValue) ? green : red

bgcolor(color=backgroundColour, transp=85)

We first figure out the background colour with the conditional ternary operator (?:). This operator requires a true/false condition as its first value and, when that condition is true, returns its second value. Should the condition evaluate to false, then this operator returns its third value (Pine Script Language Tutorial, n.d.).

The condition that’s evaluated here is whether the bar’s closing price (close) is greater than (>) the SMA (smaValue). When the price bar indeed closed above that moving average, the conditional operator returns the green colour; otherwise, it returns the red standard TradingView colour. That returned value is then assigned to the backgroundColour variable.

That variable is subsequently used with the color argument of the bgcolor() function to colour the indicator’s background green or red. The transp argument, which sets the background’s transparency ranging from 0 (no transparency) to 100 for fully invisible (TradingView, n.d.), is set to 85 here for a reasonably transparent background.

With the first background layer added, we’re going to colour the background again whenever a RSI signal happens. But for that we first need to implement our buy and sell logic:

buySignal  = (rsiValue > oversold) and (rsiValue[1] <= oversold) and 
     (close > smaValue)
sellSignal = (rsiValue < overbought) and (rsiValue[1] >= overbought) and 
     (close < smaValue)

The two variables that we create here (buySignal and sellSignal) are given a true/false value, which we arrive at by joining several conditions together with the and logical operator. Because of that operator, the variables only hold true when all three of their conditions are true also (Pine Script Language Tutorial, n.d.).

That means that three things need to happen before our buySignal variable is true. First, the RSI (rsiValue) needs to be greater than (>) the oversold input variable that has a default value of 30. Second, the RSI value of the previous bar (rsiValue[1]), retrieved with the history referencing operator ([]), needs to be less than or equal to (<=) the oversold value.

With those first two conditions we check if the RSI value has left the oversold area on the current bar. The last condition requires that the bar closed above the SMA (close > smaValue). When all three conditions occurred on the current bar (that is, when they’re all true), then our buySignal variable is true also. But when one, two, or three conditions are false, then buySignal is false too.

We determine the value of the sellSignal variable in much the same way: now the RSI needs to be below the overbought area (rsiValue < overbought) while still in that area on the previous bar (rsiValue[1] >= overbought), and we also require that the bar closed below the SMA (close < smaValue). When all three of these conditions are true, sellSignal is true also; otherwise, this true/false variable is false.

Now that we have the buy and sell signals figured out, we conditionally colour the background using the two variables:

bgcolor(color=buySignal ? lime : na, transp=50)
bgcolor(color=sellSignal ? red : na, transp=50)

Here we first colour the background of any bar on which a buy signal occurs. For that we set the bgcolor() function’s color argument to either the lime standard TradingView colour or the na value with the conditional ternary operator (?:). Given how this operator works, the bar’s background is coloured lime green when the buySignal variable is true. And when that variable is false, the color argument of the bgcolor() function is set to na. That built-in variable represent a “not a number” value (TradingView, n.d.) that, when used as a colour, behaves as a transparent colour (Pine Script Language Tutorial, n.d.).

We end the example with another bgcolor() statement. This time we set this function’s color argument with the conditional ternary operator to red or na, depending on the value of the sellSignal variable. This way we colour the background for bars on which the sell signal occurred from top to bottom red.

Since the transp argument of these two bgcolor() function calls is set to 50, the lime green and red backgrounds are less transparent than the background we place them on. That makes the buy and sell signals stand out more clearly on the chart.

Using the background colour to highlight conditions and signals

The above example indicator looks like this when added to a S&P 500 index CFD chart:

Example of overlaying backgrounds in TradingView Pine

And, when added to an EuroStoxx 50 index CFD chart, looks as follows:

Example of TradingView backgrounds overlaid on each other

The indicator creates the following inputs:

Example of the script's input options

When we change the ‘Source Data’ option to ‘hl2’ (a bar’s midpoint; [high + low] / 2) and set the ‘RSI Overbought’ and ‘RSI Oversold’ levels to 65 and 35, then the previous EuroStoxx 50 chart becomes:

Example of programmatically placing coloured TradingView backgrounds on top of each other

See colouring a background from top to bottom to learn more about the bgcolor() function. Applications of this function include offsetting a coloured background and colouring a TradingView background conditionally. While bgcolor() colours the chart’s full background, the fill() function colours a background section and can, for instance, fill the background between circles and crosses. Both functions can use the basic TradingView colours in addition to the hexadecimal colour values.

Summary

The bgcolor() function colours the chart’s background from top to bottom, and this can be the main chart area (when the script overlays on the chart’s instrument) or the script’s own subchart. When we use the bgcolor() function repeatedly in our script, their call order matters: the first bgcolor() statement creates the main coloured background, and the following bgcolor() function(s) create a background that’s overlaid on the previous. These additional bgcolor() function calls need to colour the background conditionally; otherwise, they colour the background of all bars which would prevents us from seeing the first coloured background.


References

Pine Script Language Tutorial (n.d.). Retrieved on October 23, 2015, from https://docs.google.com/document/d/1sCfC873xJEMV7MGzt1L70JTStTE9kcG2q-LDuWWkBeY/

TradingView (n.d.). Script Language Reference Manual. Retrieved on December 18, 2015, from https://www.tradingview.com/study-script-reference/