While we can set the indicator’s number of decimals programmatically, that setting is not always respected by TradingView. When does that happen and what can we do about that?

In this article:

Setting the number of decimals with code in TradingView

In TradingView we set an indicator’s characteristics, like its name and how it displays on the chart, with the study() function (Pine Script Language Tutorial, n.d.). This function needs to be present in the code of every indicator (Pine Script Language Tutorial, n.d.) and its title argument, which specifies the indicator name, also always needs to be set (TradingView, n.d.).

Another argument of study() is precision. This argument defines the indicator’s number of decimals after the floating point (TradingView, n.d.). We do that by setting this optional argument, which defaults to 4, to a non-negative integer (TradingView, n.d.). Alternatively, precision set to 0 makes indicator values in the thousands and millions display with the ‘K’ and ’M’ suffixes.

However, TradingView doesn’t always respect the value of the precision argument. While indicators plotted in a separate chart panel always plot with the number of decimals set by precision, indicators overlaid on the chart’s instrument don’t do this. In that case, the indicator uses the number of decimals from the instrument.

Let’s look at a programming example showing this behaviour and how we can work around it.

Precision and an indicator’s price scale: a TradingView discrepancy

To see how an instrument’s price scale affects the decimals of an indicator, we create an indicator that plots two smoothed Exponential Moving Averages (EMAs). Since these plot on the chart’s instrument, the indicator ‘inherits’ the number of decimals used by that symbol – even though we’ll set the precision argument. After discussing the code shown below, we look at charts displaying the indicator and its values.

study(title="Double EMAs - smoothed", overlay=true, precision=3)

// Inputs
priceData = input(title="Price Data", type=source, defval=hl2)
quickLen  = input(title="Quick EMA", type=integer, defval=10)
slowLen   = input(title="Slow EMA", type=integer, defval=25)
smoothLen = input(title="Smooth Length", type=integer, 
    defval=3, minval=1, maxval=10)

// Compute values
quickEMA = ema(ema(priceData, quickLen), smoothLen)
slowEMA  = ema(ema(priceData, slowLen), smoothLen)

// Plot values
plot(series=quickEMA, color=teal, linewidth=2)
plot(series=slowEMA, color=navy, linewidth=2)

We first define the indicator properties with the study() function. With this function’s title argument we set the indicator’s name and, by setting overlay to true, we overlay the indicator on the chart’s data series. With precision given a value of 3 we intend to display the indicator’s values with 3 numbers after the floating point.

Then we create several input options:

priceData = input(title="Price Data", type=source, defval=hl2)
quickLen  = input(title="Quick EMA", type=integer, defval=10)
slowLen   = input(title="Slow EMA", type=integer, defval=25)
smoothLen = input(title="Smooth Length", type=integer, 
    defval=3, minval=1, maxval=10)

User-configurable inputs are added to a script with the input() function, and this function also returns the input’s value (TradingView, n.d.). Here we store each returned value in a variable with the assignment operator (=). That way we can use the variable later on to refer to the input’s value.

The first input that we make is a ‘source’ data input (type=source). Such an input creates a pull-down menu with several types of price data from the chart’s instrument (Pine Script Language Tutorial, n.d.), like its high, low, and close prices. Here the input is set to a starting value (defval) of hl2, which are the bar’s midpoint prices (that is, [High + Low] / 2).

With the title argument of the input() function we name this input “Price Data”, and that name is what’s placed before the option in the script’s settings. We store its current value in the priceData variable to use later on when computing the EMAs.

The three other inputs are numerical integer inputs. These inputs only accept whole numbers and are made by setting the type argument of the input() function to integer (Pine Script Language Tutorial, n.d.). The first is named “Quick EMA” and starts with a value of 10 (defval=10), and has its current value stored in the quickLen variable.

The second integer input is titled “Slow EMA” and has a default value of 25. This input’s value is tracked in the slowLen variable. We’ll use both quickLen and slowLen variables later on when computing the EMAs.

The last input, named “Smooth Length”, begins with a value of 3. Its value is assigned to the smoothLen variable, which we use later on when smoothing both EMAs. The minval and maxval arguments of the input() function, which set the minimum and maximum value of a numerical input (TradingView, n.d.), we ensure that this variable’s value is at least 1 and not more than 10.

Next we compute the indicator’s values:

quickEMA = ema(ema(priceData, quickLen), smoothLen)
slowEMA  = ema(ema(priceData, slowLen), smoothLen)

The two variables created here (quickEMA and slowEMA) are both assigned a value returned by ema(). That function calculates an Exponential Moving Average with two arguments: a series of values to process alongside an integer that specifies the number of bars to calculate the EMA on (TradingView, n.d.).

For both variables we use ema() twice. The first, inner ema() function call computes the EMA on price data with a length of either 10 or 25 bars. That EMA value is subsequently smoothed by the second, outer ema() function call that has a length of 3 bars. With these functions placed inside each other, TradingView Pine evaluates them from the inside out, starting with the inner function.

And so for the value of the quickEMA variable Pine first processes the ema() function with the priceData and quickLen arguments. This computes an EMA based on the values held by the priceData input variable, which we set to a default of hl2 (a bar’s midpoint). The length of this EMA is set with quickLen, the input variable with a standard value of 10.

With that 10-bar EMA computed, we use ema() again to perform the smoothing. This second ema() function call processes the price data that’s returned by the first ema() function call, and calculates this for the smoothLen number of bars. That input variable, which holds the “Smooth Length” input option, has an initial value of 3. After this second ema() function is processed, the value returned by this function is stored in the quickEMA variable.

The other variable, slowEMA, is computed similarly. We again use the ema() function twice here, but this time the inner ema() function computes on the priceData values for a length of slowLen bars. That latter input variable defaults to 25 bars. The other ema() function then smooths that 25-bar EMA with the smoothLen number of bars, after which the value returned by this ema() function is assigned to the slowEMA variable.

Now that we have both EMAs computed, we plot them on the chart:

plot(series=quickEMA, color=teal, linewidth=2)
plot(series=slowEMA, color=navy, linewidth=2)

The plot() function displays data on the chart that’s set by its series argument (TradingView, n.d.). In the first plot() statement we set that argument to the quickEMA variable, which holds the 10-bar moving average smoothed by a 3-bar EMA. The plot() function creates a line by default (TradingView, n.d.), and here that line is displayed in the teal basic TradingView colour. With the linewidth argument set to 2, the line’s width is slightly thicker than default (TradingView, n.d.).

The second plot() statement is much like the first, but this time we use plot() to display the slowEMA values on the chart. This 25-bar EMA smoothed with a 3-bar EMA is coloured navy blue with a line width that’s one step greater than the default line size.

When we save the indicator and add it to the chart, it has these input options:

Input options of our TradingView example indicator

Example: discrepancy between price scale and precision in TradingView

Now let’s look at how the indicator values display on the chart. As you recall, we set the precision argument to 3. When we add our example script to a S&P 500 Index CFD chart (which uses one decimal), the indicator looks like:

Plotting our TradingView EMAs on the chart

As we can see here, our EMA values only display with 1 decimal (1980.4 and 1980.0). So instead of using the decimals set by the precision argument, our indicator ‘inherits’ the number of decimals from the chart’s instrument. This happens with other instruments too: our EMAs display with 5 decimals when plotted on a GBP/USD forex chart, for instance.

However, the indicator values do display correctly with 3 decimals in the ‘Data Window’ of the S&P 500 Index CFD chart:

Example of the indicator's values in the Data Window

Let’s look at how the indicator’s precision behaves when we plot the EMAs in a separate chart panel. For that we make one change to our script’s code: setting the overlay argument of the study() function to false.

study(title="Double EMAs - smoothed", overlay=false, precision=3)

Now with overlay set to false the indicator displays in a subchart. We don’t make other code changes but just save the script. To see the effect of changing the overlay argument, we first need to remove and then re-add the script to the chart. Then our EMAs display as follows:

Precision of the TradingView indicator in a separate chart panel

The indicator’s plots are now displayed with the correct number of decimals. However, this isn’t much of a solution since we intended the EMAs to plot on the chart’s instrument and not below it.

Luckily, there are two ways in which an indicator can plot on the chart’s instrument with the correct amount of decimals:

  • By changing the number of decimals of the instrument’s price scale.
  • Or by plotting the indicator on a different price scale.

We take a look at both approaches below.

Workaround 1: Changing the precision of the chart’s price scale

The first approach is to change the number of decimals that are shown on the instrument’s price scale. That also changes the precision of our indicator that’s overlaid on that instrument.

If we look at our S&P 500 Index CFD chart, then the instrument’s values are displayed with 1 decimal on the chart’s price axis and ‘Data Window’:

Number of decimals used by the chart's instrument

We change the precision of an instrument’s values with the ‘Override Min Tick’ setting. To change that setting we first open the instrument’s settings by clicking on the star sign ( ) that’s displayed to the right of the instrument’s name:

Formatting an indicator in TradingView

This brings us to a window with several settings. Here we select the ‘Style’ tab and there we can set the ‘Override Min Tick’ option to several values:

Changing the 'Override Min Tick' option in TradingView

This ‘Override Min Tick’ setting changes the instrument’s default tick size (as in, the minimum price change). That allows us to see the instrument’s values with more (or less) decimals. For instance, the precision of the S&P 500 Index CFD can be changed from the default 1/10 to 1/1000:

Changed the 'Override Min Tick' setting in TradingView

Since an indicator that’s overlaid on the instrument uses the same precision as the instrument has, an ‘Override Min Tick’ setting of 1/1000 not only changes the instrument’s but the indicator’s precision too:

TradingView indicator changes with the chart's precision

And this change is also visible in the ‘Data Window’:

Instrument and indicator precision changed in the TradingView 'Data Window'

Now when we set the ‘Override Min Tick’ setting to a low value like 1/1000000, we immediately see a drawback of this approach: the chart’s right price scale takes up a lot of room.

Adjusted the precision of a TradingView chart

So let’s look at the second workaround, one that doesn’t intervene with the right price axis.

Workaround 2: Plotting the indicator on a different price scale

As we saw above, one workaround that displays an overlaid indicator’s values with more decimals is to change the precision of the chart’s instrument. Another approach is to make the indicator use the left price axis. That enables the indicator to use the number of decimals that are specified by the precision argument of the study() function instead of ‘inheriting’ that number of decimals from the instrument on which the indicator is placed.

So if we consider our programming example that has precision set to 3, then plotting the indicator on the chart’s instrument didn’t show the EMAs with 3 decimals:

Precision of the TradingView indicator added to a chart

To have the indicator display on the left price scale with its own precision, we right-click on one of the indicator’s plots and select ‘Scale Left’:

Setting a TradingView indicator to use the left price scale

With the indicator using the left price scale, we can already see its higher precision in the plot’s labels when the indicator is selected:

TradingView indicator plots with a different precision than the chart

Now to display the indicator’s price axis, we right-click on the right price scale and select ‘Left Axis’:

Enabling the left price axis in TradingView

This shows the left axis, and on that axis the indicator values are now plotted with the number of decimals set by the precision argument:

TradingView indicator plotting its values on the left price scale

Besides manually selecting an indicator’s price scale, we can also programmatically specify an indicator’s price scale with the help of the study() function.

Our EMAs keep their 3 decimals on the left price axis when we change the chart to an instrument that has a different number of decimals, like the GBP/USD symbol:

Indicator values showing up in the TradingView chart's left axis

To learn more about the study() function’s precision argument, see setting an indicator’s precision programmatically. Other arguments of study() are discussed in overlaying an indicator on the chart’s instrument and setting an indicator’s price scale programmatically.

Summary

study() is the only function that needs to be added to the code of every TradingView indicator. This function sets the indicator’s properties with several arguments, including precision. That optional argument specifies how many digits are displayed after the floating point of the indicator’s values. This argument defaults to 4 when not added to study(). But when precision is added, its value is ignored whenever the indicator displays on the chart’s instrument. In that case, TradingView gives the script the same number of decimals that the instrument has. To work around this, we can either change the instrument’s precision with the ‘Override Min Tick’ setting or plot the indicator’s values on the left price scale. Both approaches make the indicator plot with the number of decimals set by precision, regardless of how many decimals the chart’s instrument has.


References

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

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