When coding trading strategies in TradingView, no function is used more often than strategy(). What does this function do and what are the ways to use it programmatically?

In this article:

Setting strategy properties programmatically in TradingView

In TradingView we programmatically configure the characteristics of a trading strategy, like its default order size and pyramiding settings, with the strategy() function (TradingView, n.d.). This function has to be added to every strategy (Pine Script Language Tutorial, n.d.) and its title argument (which specifies the strategy’s name) always needs to be set (TradingView, n.d.).

The strategy() function doesn’t return a value, but configures the strategy’s settings. The arguments that it can use are (TradingView, n.d.):

strategy(title, shorttitle, overlay, precision, scale, max_bars_back,
    pyramiding, calc_on_order_fills, calc_on_every_tick,
    backtest_fill_limits_assumption, default_qty_type, default_qty_value,
    initial_capital, currency)

These arguments mean the following (Pine Script Language Tutorial, n.d.; TradingView, n.d.):

Argument Description
title Required string argument that sets the name of the trading strategy. This name is used in several TradingView windows, and can be different from the filename that the script is saved under in the Pine Editor. For more on title, see setting the name of a TradingView strategy.
shorttitle Optional string argument that also names the strategy. This argument overrides the value set by title and, as we discuss in naming a TradingView strategy, doesn’t provide capabilities beyond what title already does.
overlay Optional true/false argument that, when set to true, displays the strategy in the chart area of the chart’s instrument. With overlay=false the strategy instead appears in a separate chart panel below the chart’s instrument. For more, see overlaying a strategy on the chart’s instrument.
precision Optional integer argument that specifies how many digits to show after the decimal point of the plotted strategy values. This argument defaults to 4 and has a minimum of 0. With that latter large numbers are formatted with the ‘K’ (for thousands) and ’M’ (for millions) suffixes. See setting the displayed precision of a trading strategy for more.
scale Optional argument that defines which price scale the strategy attaches to. Possible values are scale.right (the default value when we don’t set the scale argument), scale.left, and scale.none. With that latter the strategy uses the full chart area when plotting, and this requires that overlay is set to true. For more on the scale argument, see configuring the scale of a TradingView strategy programmatically.
pyramiding Optional integer argument that specifies how many entries are allowed in the same direction. This argument defaults to 0, and with that value only one long or short entry order can be filled and additional entries will be rejected. We take a closer look at this argument in setting pyramiding settings programmatically in TradingView.
calc_on_order_fills Optional Boolean argument that, when set to true, makes the strategy perform an additional intra-bar order calculation immediately after an order fills. That extra calculation happens on both historical and real-time price bars. When omitted, calc_on_order_fills defaults to false and then the strategy calculates on the close of each bar. See calculating a TradingView strategy immediately after an order fills for more.
calc_on_every_tick Optional true/false value that, when set to true, makes the strategy calculate with every real-time tick rather than only on bar close. On historical bars, however, the strategy will keep calculating on the close of each price bar. The default value of calc_on_every_tick is false. We examine this argument closely in calculating a TradingView strategy with every real-time price update.
max_bars_back Optional integer argument that specifies the maximum number of historical bars that the strategy references to perform its calculations. That number of bars is automatically calculated by TradingView, but can be changed with this argument. For more on max_bars_back see setting the number of historical bars a strategy uses programmatically.
backtest_fill_limits_assumption Optional integer argument that configures how strict TradingView deals with limit orders when backtesting. Before TradingView considers a limit order filled, the bar’s price has to exceed the limit order price with the number of ticks set by backtest_fill_limits_assumption. We take a closer look at this argument in specifying TradingView’s backtest assumptions of limit orders.
default_qty_type Optional argument that specifies the default order size (that is, the order size used when we submit an order without specifying its quantity). This argument can be set to three values: strategy.fixed (order sizing with a fixed quantity; the default setting), strategy.cash (sizing orders based on a cash amount), and strategy.percent_of_equity (sizing orders based on an equity percentage).
default_qty_value Optional float argument that specifies the quantity of the default order size. Whereas the default_qty_type argument specifies how the default order size is calculated, default_qty_value sets the standard order size. And so the default_qty_value argument specifies the number of contracts or shares, the cash amount of each order, or the equity percentage to invest with each order.
initial_capital Optional argument that sets the strategy’s starting funds, and this value defaults to 100,000. See setting a strategy’s initial capital programmatically for more.
currency Optional argument that specifies the account currency. Whenever the strategy’s currency differs from the currency used by the chart’s instrument, TradingView performs currency conversion of things like the strategy’s net profit and equity. This argument defaults to currency.NONE, and with that no currency conversion takes place. Other values for currency are currency.AUD (Australian dollar), currency.CAD (Canadian dollar), currency.CHF (Swiss franc), currency.EUR (euro), currency.GBP (pound sterling), currency.HKD (Hong Kong dollar), currency.JPY (Japanese yen), currency.NOK (Norwegian krone), currency.NZD (New Zealand dollar), currency.RUB (Russian ruble), currency.SEK (Swedish krona), currency.SGD (Singapore dollar), currency.TRY (Turkish lira), currency.USD (US dollar), and currency.ZAR (South African rand). See setting the currency of a TradingView strategy programmatically for more.
Note: A TradingView strategy always has to use the strategy() function whereas an indicator always needs to implement the study() function (TradingView, n.d.). This also means we can tell by looking at a script’s code whether we’re dealing with a strategy or an indicator.

Before exploring the strategy() function in the context of an example strategy, let’s first look at its requirements and error messages.

Working with the strategy() function in TradingView Pine

The strategy() function has several requirements. The first is that every strategy script should use this function (TradingView, n.d.). And so when we don’t properly format the strategy() function or when it isn’t in the script’s code, TradingView generates the ‘the script must have one study() or strategy() function call’ error message:

Example of TradingView's strategy() function missing
Note: The strategy() function can be placed anywhere in the script, but its common place is at the top of the strategy’s code (see Pine Script Language Tutorial, n.d.).

Another requirement of strategy() is that it should only be added once to the script. For instance, this isn’t allowed:

strategy(title="My Strategy", overlay=true)
strategy(precision=3, initial_capital=10000)

This generates the ‘cannot call ‘strategy’ with arguments …’ error message. The same error, by the way, also triggers when we don’t specify the title argument of this function.

Example of using strategy() in TradingView with the wrong arguments

Furthermore, the arguments of the strategy() function need to be named correctly (with the exact name from the table above). This means we may not use an unrecognised argument or mistype one. For example, using initialcapital (instead of the correct initial_capital) like this:

strategy(title="My Strategy", overlay=true, initialcapital=10000)

Generates the ‘unknown argument’ error message:

Using TradingView's strategy() function with an incorrect argument name

Another requirement is that each argument has to be set to its appropriate value. For instance, the calc_on_order_fills argument requires a true/false value but here we’ve set it to an integer:

strategy(title="My Strategy", overlay=true, calc_on_order_fills=1)

These kind of errors trigger the ‘mismatched input’ error message:

Mismatched input error message in TradingView Pine

Now let’s see how to use strategy() in a full, practical programming example.

Example: trading the MACD and configuring the strategy programmatically

The example below is a basic MACD trading strategy. The Moving Average Convergence Divergence (MACD) indicates trend deviations by using two moving averages: a short average that’s subtracted from the longer one (Pring, 2002). One approach to trading the MACD values is with its signal line, which often is the 9-period EMA (Exponential Moving Average) of MACD values. In our example strategy we go long whenever the MACD line crosses over the signal line, and go short when the MACD drops below its signal line.

The image below gives a quick view of what the finished strategy script looks like. We’ll take a closer look at the strategy’s behaviour and performance after discussing the code.

Example chart of the TradingView strategy
strategy(title="MACD example strategy", overlay=false, default_qty_value=3, 
    initial_capital=10000, currency=currency.EUR)

// Create inputs
fastLen = input(title="Fast Length", type=integer, defval=12)
slowLen = input(title="Slow Length", type=integer, defval=26)
sigLen  = input(title="Signal Length", type=integer, defval=9)

// Get MACD values
[macdLine, signalLine, _] = macd(close, fastLen, slowLen, sigLen)

// Plot MACD values and line
plot(series=macdLine, color=#6495ED, linewidth=2)
plot(series=signalLine, color=orange, linewidth=2)

hline(price=0)

// Determine long and short conditions
longCondition  = crossover(macdLine, signalLine)
shortCondition = crossunder(macdLine, signalLine)

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

We first configure the strategy’s settings with strategy(). With the title argument we name the strategy and with overlay set to false the strategy displays in a separate chart panel (TradingView, n.d.). We set the default order size with default_qty_value to 3 contracts, and initial_capital=10000 sets the strategy’s initial funds to 10,000. The fifth and last argument specifies the strategy’s currency to euros (currency=currency.EUR) to make the script report its results in that currency.

Then we create several input options:

fastLen = input(title="Fast Length", type=integer, defval=12)
slowLen = input(title="Slow Length", type=integer, defval=26)
sigLen  = input(title="Signal Length", type=integer, defval=9)

Input options are added to a script with input(), and this function also returns the input’s current value (Pine Script Language Tutorial, n.d.). Here we store those values in variables with the assignment operator (=). That makes it possible to refer to the input’s value later on by using the variable.

All three inputs are numerical integer inputs. These accept whole numbers only and are made by setting the type argument of the input() function to integer (Pine Script Language Tutorial, n.d.). Other arguments that these input() function calls have in common are title (which specifies the name that’s displayed before the option) and defval that sets the input’s default value (TradingView, n.d.).

We name the first input “Fast Length” and set its standard value to 12. The current value of this input is tracked with the fastLen input variable. The next input option is named “Slow Length” and this one starts with a value of 26, while its current value is tracked in slowLen. The third and last input is named “Signal Length”, stored in the signLen variable, and begins with a value of 9.

We use the input options when calculating the MACD values next:

[macdLine, signalLine, _] = macd(close, fastLen, slowLen, sigLen)

One way to compute the MACD is with the macd() function that works on four arguments: the series of price data to calculate on alongside three integers that set the fast, slow, and signal MACD parameters (TradingView, n.d.). Here we set those arguments to the instrument closing prices (close) and the fastLen, slowLen, and sigLen input variables that we defined earlier with default values of 12, 26, and 9.

Unlike most other TradingView functions, macd() doesn’t return a single value but an array with three values instead: the MACD line, the signal line, and the histogram values (TradingView, n.d.). In our case, we’re interested in the MACD line and signal line, and so place the new macdLine and signalLine variables inside the square brackets ([ and ]). With those square brackets we accompany the array values that macd() returns. Since we have no use for the histogram values, we place an underscore (_) at the array location of those returned values instead of a variable name.

With the MACD computed, we plot its values on the chart:

plot(series=macdLine, color=#6495ED, linewidth=2)
plot(series=signalLine, color=orange, linewidth=2)

hline(price=0)

The plot() function displays the values of its series argument as a line by default on the chart (TradingView, n.d.). Other arguments of plot() that we use are the plot’s colour (color) and size. That latter is set with linewidth, an argument that accepts values starting from 1 as the default plot size (TradingView, n.d.).

With the first plot() statement we display the MACD line (macdLine) on the chart in the #6495ED hexadecimal colour of cornflower blue. The next plot() statement shows the signal line (signalLine) with the orange basic TradingView colour. Both plots are made a bit bigger than default (linewidth=2).

We also plot a horizontal line to easily see when MACD values turn positive or negative. We do that with hline(), a function that creates a horizontal line at a fixed price level (TradingView, n.d.). With that function’s price argument set to 0 that line becomes a zero line.

Then we determine the strategy’s long and short conditions:

longCondition  = crossover(macdLine, signalLine)
shortCondition = crossunder(macdLine, signalLine)

The first of these two true/false variables, longCondition, is assigned its value based on what’s returned by crossover(). That function requires two arguments and returns true when the first argument’s value is greater than that of the second on the current bar, while on the previous bar the first argument had a value that was less than that of the second (TradingView, n.d.).

Since we use crossover() with the macdLine and signalLine variables, this means the function returns true when the MACD line crosses above its signal line and returns false when that crossover didn’t happen.

The value of the shortCondition variable is set likewise, although here we use crossunder(). This function returns true when, on the current bar, the value of its first argument is less than that of the second argument while, on the previous bar, the first argument’s value was still above that of the second (TradingView, n.d.). With the macdLine and signalLine variables passed into this function, this makes crossunder() return true whenever the MACD values drop below their signal line and false in all other cases. That returned value is assigned to the shortCondition variable.

We end the programming example by submitting our long and short orders:

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

We generate those orders with strategy.entry(), a function that opens a position with a market order by default. And when there’s already a position in the other direction, strategy.entry() reverses that open position (TradingView, n.d.).

We use strategy.entry() twice here, and both times we specify three arguments. With id we provide the order name, and this identifier appears on the chart and in the ‘Strategy Tester’ window. The long argument sets the direction of the order: with long=true the function creates an enter long order while long=false has it submit an enter short order (TradingView, n.d.). And the when argument defines when the order is submitted: whenever this argument is true during a script calculation, strategy.entry() sends off the order while with a value of false the order isn’t submitted (TradingView, n.d.).

The first strategy.entry() function call submits a long order (long=true) named “Long Entry” whenever the longCondition variable holds a value of true (so when the MACD line crossed above its signal line). And with the second strategy.entry() statement we generate the “Short Entry” enter short (long=false) each time the MACD values drop below their signal values (that is, when=shortCondition).

Example: a MACD trading strategy in TradingView

Our above example strategy has the following input options:

Input options of our TradingView example strategy

When we add the script to the chart, it looks like:

Example chart of the TradingView strategy

As we can see here, the strategy goes long whenever the MACD (blue line) crosses above its signal line (orange line). Likewise, the script initiates short positions whenever the MACD falls below its signal line. Since we didn’t submit other orders in the script besides the enter long and enter short orders, our strategy is always in the market and goes from long to short and vice versa.

When we add our example strategy to the Crude Oil (Brent) CFD, the performance report shows that the short side shows a little promise while the long orders heavily underperformed:

Backtest results of our TradingView example strategy

Summary

We programmatically configure a TradingView strategy with strategy(). This function has to be included in the code of every strategy, and its title argument (which names the strategy) always needs to be set. Another argument that sets the script’s name is shorttitle. With the overlay argument we configure where the strategy should display, and precision sets how many decimals the strategy uses for its plotted values. The scale argument sets the price scale that the script attaches to. The number of entries in the same direction are configured with pyramiding while the default_qty_type and default_qty_value arguments sets the default order size. Whether a strategy should perform intra-bar calculations after an order fills or with every real-time price update is specified with calc_on_order_fills and calc_on_every_tick. The backtest_fill_limits_assumption argument defines how strict TradingView should backtest our limit orders, while max_bars_back specifies how many historical bars our strategy needs for its calculations. And with the currency argument of strategy() we set the strategy’s currency, which affects the results in the performance reports and enables currency conversion whenever the chart’s instrument quotes in a different currency.

Learn more:


References

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

Pring, M.J. (2002). Technical Analysis Explained (4th edition). New York, NY: McGraw-Hill.

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