When a strategy plots its data in TradingView, we often look up its values on the chart. How do we programmatically change the number of decimals that those strategy values use?

In this article:

Setting the precision of a TradingView strategy with code

Several TradingView strategy properties, like its backtest fill assumptions and initial capital, can be set programmatically with the strategy() function (TradingView, n.d.). We need to include this function in the code of every strategy (Pine Script Language Tutorial, n.d.), and its title argument (which sets the strategy’s name) always needs to be set (TradingView, n.d.).

Another argument of strategy() is precision. This optional argument accepts values of 0 or greater to specify how many digits to display after the floating point of the strategy’s values (TradingView, n.d.). We can use this argument like this:

strategy(name="My example strategy", precision=3)

When we set precision to 0, large values of the strategy display with special formatting (TradingView, n.d.). That is, thousands show with the ‘K’ and millions with the ’M’ suffix. This way we can prevent that a strategy’s values take up a lot of chart space.

If the precision argument isn’t set, it defaults to 4 (TradingView, n.d.) – and so strategy values are plotted with 4 decimals by default.

The precision argument of the strategy() function has these noteworthy characteristics:

  • precision only affects how the strategy’s values are displayed (like on the price axis or in the ‘Data Window’). It doesn’t affect the script’s calculations nor the price at which orders are submitted.
  • precision can only be set to a literal integer (like precision=6). It doesn’t accept built-in or user-defined variables (like precision=myVariable) nor does precision accept a numerical input variable.
  • All of the strategy’s plotted values are affected by precision. It’s not possible to, for example, have one plot display with 3 decimals while another one uses 5 decimals.
  • When we overlay a strategy on the price chart, the script uses the same precision as the chart’s instrument. This means that TradingView doesn’t always respect our precision argument setting. For more information and workarounds, see ‘why does a TradingView strategy display with another precision than specified?’.

Now, let’s look at how we can programmatically set how many decimals our strategy’s values use.

Setting the precision of a TradingView RSI strategy programmatically

The example strategy below uses the RSI (Relative Strength Index) to generate trades. When that oscillator is oversold and above its 5-bar moving average, we go long. And when the RSI is overbought and below its average, we initiate a short position. The strategy’s positions are closed when the RSI crosses above or below the exit level, which we initially set at 50.

The image below gives a quick view of how the finished strategy script looks like (with the number of decimals highlighted). After discussing the code we look at more charts showing the strategy and how changing the precision argument affects how the script’s values display on the chart.

Example of the TradingView strategy with 3 decimals plotted
strategy(title="RSI example strategy", overlay=false, precision=3)

// Inputs
priceData = input(title="Price Data", type=source, defval=close)
rsiLen    = input(title="RSI Length", type=integer, defval=14)
maLen     = input(title="Average Length", type=integer, defval=5)
obLevel   = input(title="Overbought", type=integer, defval=70)
exitLevel = input(title="Exit Level", type=integer, defval=50)
osLevel   = input(title="Oversold", type=integer, defval=30)

// Compute
rsiValue = rsi(priceData, rsiLen)
rsiAvg   = sma(rsiValue, maLen)

// Plot values
plot(series=rsiValue, color=purple, linewidth=2, title="RSI")
plot(series=rsiAvg, color=orange, title="Average")

hline(price=obLevel, linestyle=solid, color=#87CEFA)
hline(price=osLevel, linestyle=solid, color=#87CEFA)
hline(price=exitLevel, color=#87CEFA)

// Determine trading conditions
longCondition  = (rsiValue < osLevel) and (rsiValue > rsiAvg)
shortCondition = (rsiValue > obLevel) and (rsiValue < rsiAvg)
exitPosition   = crossunder(rsiValue, exitLevel) or 
     crossover(rsiValue, exitLevel)

// Submit orders
strategy.entry(id="Enter Long", long=true, when=longCondition)
strategy.entry(id="Enter Short", long=false, when=shortCondition)

strategy.close_all(when=exitPosition)

We start with the required strategy() function, and use three of this function’s arguments here. With title we specify the strategy’s name whereas overlay set to false displays the strategy in a separate subchart. And precision set to 3 makes the strategy’s values display with three decimals after the floating point.

Next we create several input options:

priceData = input(title="Price Data", type=source, defval=close)
rsiLen    = input(title="RSI Length", type=integer, defval=14)
maLen     = input(title="Average Length", type=integer, defval=5)
obLevel   = input(title="Overbought", type=integer, defval=70)
exitLevel = input(title="Exit Level", type=integer, defval=50)
osLevel   = input(title="Oversold", type=integer, defval=30)

Input options are made with input() (Pine Script Language Tutorial, n.d.), and this function also returns the setting’s current value (TradingView, n.d.). Here each of those returned values is stored in a variable with the assignment operator (=). That way we can use the variable later on in the code to refer to the input’s current value.

The first input that we make is a so-called ‘source’ data type input. This input option is made by setting the type argument of the input() function to source (Pine Script Language Tutorial, n.d.). This input creates a pull-down menu with different kinds of price data from the instrument that the script is applied to (like its high, low, or closing prices). That way we can manually configure the type of price data that our script should use by selecting a value from this option’s pull-down menu.

We use the title argument to set this input’s name to “Price Data”, and that name is what’s displayed before the input option in the scripts settings (see image further down below). And with the defval argument set to close our input is set to the instrument’s closing prices by default. The value that’s returned by input() here is stored in the priceData variable, and we use that variable in our script as the price data to compute the RSI on.

The other 5 inputs that we make are all numerical integer inputs. These inputs accept whole numbers only, and are made by setting the type argument of the input() function to integer (Pine Script Language Tutorial, n.d.).

The first of these integer inputs is named “RSI Length”. This input begins with a value of 14 (defval=14), has its value stored in the rsiLen variable, and is subsequently used in the script when we compute the RSI. The next input is named “Average Length” and starts with a value of 5, with its current value tracked in the maLen variable. We use that variable when we calculate the RSI’s moving average.

The names of the last three inputs are “Overbought”, “Exit Level”, and “Oversold”. We use these inputs when plotting the horizontal lines in the RSI’s chart panel, and we give them standard values of 70, 50, and 30. Their current values are tracked in the obLevel, exitLevel, and osLevel variables.

With the input options made, we calculate the RSI and its average:

rsiValue = rsi(priceData, rsiLen)
rsiAvg   = sma(rsiValue, maLen)

We calculate the Relative Strength Index with rsi(), a function that accepts two arguments: a series of values to calculate on and an integer that sets the RSI length (TradingView, n.d.). Here we have the function compute on priceData (our input variable that’s set to the instrument’s closing prices by default) and rsiLen (the input variable with a standard value of 14). We assign the RSI value that’s returned by rsi() to the rsiValue variable for use later on.

Then we use sma() to determine the average RSI. That function calculates a Simple Moving Average (SMA) with two arguments: a series of values to process besides an integer that sets the SMA length (TradingView, n.d.). Here we have the function calculate on the RSI value that we’ve just stored in the rsiValue variable, and we set the average’s length to the maLen input variable (which we gave a default value of 5). The moving average value that’s returned here by sma() is stored in the rsiAvg variable.

Next up is plotting the strategy’s data:

plot(series=rsiValue, color=purple, linewidth=2, title="RSI")
plot(series=rsiAvg, color=orange, title="Average")

hline(price=obLevel, linestyle=solid, color=#87CEFA)
hline(price=osLevel, linestyle=solid, color=#87CEFA)
hline(price=exitLevel, color=#87CEFA)

We plot data on the chart with plot(), and this function’s series argument specifies which data to plot (TradingView, n.d.).

In the first plot() statement we set that argument to rsiValue, our 14-bar RSI variable. plot() displays data as a line by default (TradingView, n.d.), and here we colour that line purple by setting the color argument to the purple basic TradingView colour. We give the linewidth argument a value of 2 so that the line is a bit thicker than default. And we use the title argument to give the plot a descriptive name, which shows up in the chart’s ‘Data Window’ and when changing a script’s colours by hand.

The second plot() function call displays the RSI’s moving average on the chart. We do that by setting the series argument to the rsiAvg variable. We name this plot “Average” and display it in the orange basic TradingView colour.

Then we plot horizontal lines on the chart with hline(), which renders such a line at a specified price level (TradingView, n.d.). The first two hline() function calls plot the obLevel and osLevel input variables on the chart by setting the function’s price argument to those variables. With the function’s linestyle argument, which sets the line’s formatting (TradingView, n.d.), we make these two lines display as a solid line. The color argument of these lines is set to #87CEFA, the hexadecimal colour value of light sky blue.

The last hline() statement displays the exitLevel variable as a light sky blue line on the chart. That variable has a default value of 50, and we use this line as a visual confirmation of when the strategy should exit its position.

After the plotting we determine the trading conditions:

longCondition  = (rsiValue < osLevel) and (rsiValue > rsiAvg)
shortCondition = (rsiValue > obLevel) and (rsiValue < rsiAvg)
exitPosition   = crossunder(rsiValue, exitLevel) or 
     crossover(rsiValue, exitLevel)

We create three true/false variables here: longCondition, shortCondition, and exitPosition. These variables are used later on in the code when submitting the strategy’s orders.

The first variable, longCondition, is assigned true or false based on two true/false expressions. The first is whether the RSI (rsiValue) is less than (<) the oversold level (stored in the osLevel input variable); the second is whether the RSI is greater than (>) the 5-bar moving average of the RSI (rsiAvg). These two things happen when the RSI is in the oversold area and moving below its average.

We combine the two expressions with the and logical operator. This means both need to be true before the entire condition is also true, and when one or both expressions are false, then their combination is false too (Pine Script Language Tutorial, n.d.).

The second variable, shortCondition, is also given a true/false value based on two expressions. The first is whether the RSI is greater than the overbought level (which we set with the obLevel input variable); the second expression checks if the RSI is less than its 5-bar average. Since we combine both expressions with and, both need to be true before shortCondition is assigned true. And so the RSI has to reach the overbought area and drop below its average before there’s a short condition.

exitPosition is the third variable, and we use this true/false variable when closing a position. This variable is assigned true or false depending on a condition with two expressions. Those expressions are joined together with the or logical operator, meaning that one or both of them need to be true before the entire condition is true, and the condition is only false when both expressions are false too (Pine Script Language Tutorial, n.d.).

The first expression uses crossunder(). That function returns true when the value of its first argument is below the value of its second argument on the current bar, while on the previous bar the first argument’s value was above that of the second argument (TradingView, n.d.). The arguments that we use are the rsiValue and exitLevel variables, and so crossunder() returns true when the RSI drops below 50 on the current bar and returns false in all other cases.

The crossover() function is used in the other expression. This function works similar, and returns true when the value of the first argument is above that of the second argument on the current bar while, on the previous bar, that wasn’t the case (TradingView, n.d.). We use the function here with rsiValue and exitLevel; this way it returns true whenever the RSI rises above 50 on the current bar and returns false otherwise.

What the use of the or logical operator means when combining the crossunder() and crossover() functions means is that our exitPosition variable is true when the RSI either rises above or drops below the 50 level. This way that RSI level acts as the ‘exit position level’ for both long and short positions.

After determining the trading conditions we submit the orders themselves:

strategy.entry(id="Enter Long", long=true, when=longCondition)
strategy.entry(id="Enter Short", long=false, when=shortCondition)

strategy.close_all(when=exitPosition)

The strategy.entry() function opens a position with a market order by default and, when there’s already a position in the other direction, reverses that position (TradingView, n.d.). We use three arguments of this function here.

The first argument is id to specify the order identifier (TradingView, n.d.). That identifier is used by other functions when referring to this order, but also acts as the order name on the chart and in the ‘Strategy Tester’ window. The second argument is long that, when set to true, opens a long position while a value of false makes strategy.entry() open a short position (TradingView, n.d.). The third argument, when, specifies the order’s condition: when that argument is true on the current bar, then strategy.entry() submits that order (TradingView, n.d.).

In the first strategy.entry() function call we use “Enter Long” as the order name and, with long set to true, make the function submit an enter long market order. when is set to the longCondition variable, and so our order is submitted whenever the RSI is below its oversold level but above its 5-bar average.

The second strategy.entry() statement creates a short order (long=false) that’s named “Enter Short” and submitted whenever the shortCondition variable holds a value of true. This means our strategy goes short when the RSI is overbought and below its moving average.

We end the example with strategy.close_all(). That function closes the strategy’s open market position and has no effect when the strategy is already flat (TradingView, n.d.). With its when argument we specify when the strategy’s position should be closed, and here we set that argument to exitPosition. That true/false variable holds true whenever the RSI crossed above or below 50 on the current bar. Because strategy.close_all() submits the right order to close the position for us, we don’t have to use separate exit orders for long and short positions.

Plotting a TradingView strategy with a precision that’s set with code

When we add the above example strategy to a chart (like the German DAX Index CFD that’s displayed below), we see the strategy values display with 3 decimals after the floating point:

Example of the TradingView trading strategy

The strategy’s values show with the same precision in the chart’s ‘Data Window’:

TradingView's 'Data Window' with 3-decimal precision

The input options that we made in the code look like this:

The input options of the TradingView example strategy

When we set the RSI length to 8 and the overbought and oversold levels to 85 and 15, the previous chart changes to:

Example chart of with the TradingView trading strategy

Here the strategy’s values also display with 3 decimals, so let’s see how we can change the amount of decimals programmatically.

Changing the precision of a TradingView strategy with code

In the above programming example, the first line was:

strategy(title="RSI example strategy", overlay=false, precision=3)

By setting precision to 3, we made the strategy values display with 3 decimals after the floating point. If we, for example, change that argument to 6, the first line of the example script becomes:

strategy(title="RSI example strategy", overlay=false, precision=6)

Now when we save the script, the strategy reloads and displays as follows:

Example of the TradingView strategy with changed decimal precision

Likewise, the ‘Data Window’ also differs and shows 6 decimals now:

TradingView's 'Data Window' with 3 decimal precision

Besides changing the number of decimals with the precision argument of the strategy() function, we can also manually configure how many decimals a TradingView strategy uses.

Configuring the precision of a TradingView strategy by hand

Setting strategy properties with code is helpful because it makes sure that, when we add the strategy to the chart, it’s applied with the right settings. However, by setting a strategy’s precision by hand we can give multiple instances of the same strategy a different number of digits after the floating point.

To set the precision of a TradingView strategy by hand, we first click on the ‘Format’ icon ( ) that’s to the right of the strategy’s name:

Changing the precision of a TradingView strategy by hand

This brings up the strategy’s settings. Here we go to the ‘Style’ tab, where we set the number of decimals used by the script with the ‘Precision’ setting:

The 'Style' settings window of TradingView trading strategies

When we, for example, set ‘Precision’ to 1 and click ‘OK’, then our example strategy plots like this:

Changed the precision of the TradingView strategy by hand

Summary

The strategy() function is the only function that we need to add to every TradingView strategy. Several strategy properties are set with this function, including the script’s name with the required title argument. Another argument is precision, and this optional one specifies how many numbers display after the decimal point of the strategy’s values. While this changes how the strategy’s values display on the price axis and in the ‘Data Window’, precision doesn’t affect the script’s calculations. When we don’t set this argument, the strategy’s values display with 4 decimals by default. And when we set precision to 0, thousands and millions are displayed with the ‘K’ and ’M’ suffixes. Note that the value set to precision isn’t always respected: when a strategy is overlaid on the chart’s instrument, it inherits the number of decimals that are used by that instrument’s values.

Learn more:


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 29, 2016, from https://www.tradingview.com/study-script-reference/