One of the most helpful TradingView settings for international traders is the currency that a TradingView strategy reports in. How does a strategy’s currency conversion work and how do we configure it programmatically?

In this article:

Specifying a TradingView strategy’s currency with code

We configure the settings of a TradingView strategy either by hand or with code, and with that latter we can be sure our script is always added to the chart with the right settings. Configuring a strategy programmatically is done with strategy(). Every strategy needs to use that function (Pine Script Language Tutorial, n.d.) and its title argument, which specifies the strategy’s name, always needs to be set (TradingView, n.d.).

Another argument of strategy() is currency, and with that argument we specify the account currency of the strategy (TradingView, n.d.). This way our strategy can calculate in a different currency than the currency of the instrument we added the script to (Pine Script Language Tutorial, n.d.).

For example, having a strategy behave like it’s trading an euro account is done like:

strategy(title="Example - strategy currency", currency=currency.EUR)

When a strategy is set to a specific currency (like euros, currency.EUR, here), its net profit, open profit, equity, initial capital, drawdowns, and all other performance measures from the ‘Strategy Tester’ window are reported in that specific currency. This makes it easy to evaluate how our strategy would perform when using the same currency as our broker account.

The different values for the currency argument are (TradingView, n.d.):

currency value Currency used by the strategy
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.NONE Unspecified currency. With this setting, the strategy always uses the same currency as the instrument it trades and no currency conversion happens.
currency.NZD New Zealand dollar
currency.RUB Russian ruble
currency.SEK Swedish krona
currency.SGD Singapore dollar
currency.TRY Turkish lira
currency.USD United States dollar
currency.ZAR South African rand
Note: When we don’t specify the currency argument in the strategy() function, it defaults to currency.NONE (which is called the ‘Default’ currency in the strategy’s settings). With that value the strategy always uses the same currency as the instrument it trades, and no currency conversion takes place.

Below we’ll look at setting a strategy’s currency by hand, but first let’s examine currency conversion in more depth.

How does currency conversion in TradingView work?

Depending on the value of the currency argument and the actual currency our instrument trades in, one of three things can happen:

  • Without setting currency, no currency conversion happens. That means the strategy’s results are reported in euros when we backtest an European stock and reported in US dollars when backtesting a US future. We use this approach when there isn’t a currency difference between our broker account and the instrument we’re backtesting, or when we want to evaluate the strategy’s performance without ‘noise’ from currency effects.
  • When the currency argument is set to the same currency as the instrument, then currency conversion also doesn’t happen. So with currency=currency.GBP and applying the strategy to a stock listed at the London Stock Exchange, there’s no need for currency conversion. This approach can be valuable though, since setting a strategy to a specific currency ensures its results are always in that currency, regardless of which instrument is currently charted.
  • Now when currency is set to a different currency than the instrument, then currency conversion does happen. So when trading Tesla shares with currency=currency.EUR, the strategy’s performance report is in euros and TradingView converts the profit/loss from US dollars to euros. Such backtests give a more accurate reflection of how the strategy would perform in the currency of our trading capital.
Tip: Currency conversion is performed with the foreign exchange closing price of the previous trading day (Pine Script Language Tutorial, n.d.). And so currency conversion isn’t done in real-time but with the recent forex closing price instead (and, consequently, the same conversion rate is used for the whole day of trading). This causes small differences in results due to currency conversion when comparing backtest results with real-time performance, since in the latter case the broker performs currency conversion with a much more recent rate.

Besides influencing the reported results of a strategy’s performance, the currency argument of the strategy() function affects other strategy settings too. We discuss those in the following articles:

Let’s continue our discussion of a strategy’s currency and see how we can configure this option by hand.

Manually configuring a TradingView strategy’s currency setting

While the strategy() function configures several strategy properties, we can override those settings with the accompanying manual option in the script’s settings. That makes it possible to configure multiple instances of the same strategy differently.

To change a strategy’s currency by hand, we click on the gear icon ( ) that’s displayed to the right of the strategy’s name on the chart:

Opening the strategy settings window in TradingView

This brings up a window with the different strategy settings. Here we select the ‘Properties’ tab and there we specify the strategy’s currency with the ‘Base Currency’ option:

The manual currency settings of trading strategies in TradingView

Tip: look up the currency of a TradingView instrument

A quick tip for looking up the currency used by the chart’s instrument is the following. In the same ‘Properties’ tab as were we configure the currency setting, there’s also an ‘Order Size’ option. Now the second item that’s inside this option’s pull-down menu specifies which currency is used by the chart’s instrument.

For example, we can see when charting AUD/CAD, that this forex pair quotes in Canadian dollars:

Looking up the currency of a TradingView instrument that quotes in Canadian Dollars

On the other hand, the German DAX Index CFD from FXCM quotes in US dollars:

Viewing the currency of a TradingView instrument

Example: trading moving averages with momentum filtering

Now let’s see how a strategy’s currency setting works in the context of a full example strategy. In the script below we trade a 12-bar and 24-bar EMA (Exponential Moving Average). We generate a long signal when the quick average crosses above the slower one, and a short signal triggers when the quick average drops below the slow moving average. We filter these signals with the 14-bar momentum of closing prices. That is, long signals are only traded when the momentum is rising and above its 5-bar EMA. Likewise, before we open a short position based on an EMA cross, the 14-bar momentum has to be falling and below its EMA.

The chart displayed below gives a quick view of the strategy. After discussing the code, we’ll explore the strategy and how it’s affected by the currency setting in depth.

Example chart of the TradingView momentum trading strategy
//@version=2
strategy(title="Example - strategy currency", overlay=false, 
     currency=currency.NONE)

// Inputs
quickMALen = input(title="Quick MA Length", type=integer, defval=12)
slowMALen  = input(title="Slow MA Length", type=integer, defval=24)
momLen     = input(title="Momentum Length", type=integer, defval=14)
momAvgLen  = input(title="Momentum Average Length", type=integer, defval=5)

// Compute values
quickMA   = ema(close, quickMALen)
slowMA    = ema(close, slowMALen)
momentum  = mom(close, momLen)
momSmooth = ema(momentum, momAvgLen)

// Plot values
plot(series=momentum, linewidth=2, color=#4169E1)
plot(series=momSmooth, color=#FF4500)

hline(price=0)

// Determine trading conditions
enterLong  = crossover(quickMA, slowMA) and rising(momentum, 1) 
     and (momentum > momSmooth)
enterShort = crossunder(quickMA, slowMA) and falling(momentum, 1) 
     and (momentum < momSmooth)

exitLong   = (strategy.position_size > 0) and crossunder(momSmooth, 0)
exitShort  = (strategy.position_size < 0) and crossover(momSmooth, 0)

// Submit orders
if (enterLong)
    strategy.entry(id="Enter Long", long=true)

if (enterShort)
    strategy.entry(id="Enter Short", long=false)
    
if (exitLong or exitShort)
    strategy.close_all()

We start with a comment saying @version=2. This specifies that the script should use the second version of Pine Script, and that way we can use if statements later on in the code (Pine Script Language Tutorial, n.d.).

Then we set the strategy’s properties programmatically with strategy(). With this function’s title argument we specify the strategy name and we display the script in a separate subchart with the overlay argument set to false (TradingView, n.d.). By giving the currency argument a value of currency.NONE we explicitly make the strategy use the default currency (that is, the same currency as the chart’s currency).

Next we add several input options to the script:

quickMALen = input(title="Quick MA Length", type=integer, defval=12)
slowMALen  = input(title="Slow MA Length", type=integer, defval=24)
momLen     = input(title="Momentum Length", type=integer, defval=14)
momAvgLen  = input(title="Momentum Average Length", type=integer, defval=5)

Input options are added to a TradingView script with input(), and that function also returns the input’s current setting (TradingView, n.d.). Here we store those returned values in variables with the assignment operator (=); that way we can refer to the input’s value later on by using the variable.

All 4 inputs are numerical integer inputs. These only accept whole numbers and are made by setting the type argument of the input() function to integer (Pine Script Language Tutorial, n.d.). Other similarities of these four input() function calls is the title argument (which specifies the name placed before the input option in the script’s settings) and defval, which sets the input’s standard value (TradingView, n.d.).

The first two inputs are named “Quick MA Length” and “Slow MA Length”, and have default values of 12 and 24. We store their values in the quickMALen and slowMALen input variables, and we’ll use those variables when computing the EMAs.

The other two inputs are for calculating the momentum. The first is named “Momentum Length” with the other called “Momentum Average Length”. Their default values are 14 and 5, and we can access their current values with the momLen and momAvgLen input variable.

Then we calculate the values the strategy uses:

quickMA   = ema(close, quickMALen)
slowMA    = ema(close, slowMALen)
momentum  = mom(close, momLen)
momSmooth = ema(momentum, momAvgLen)

We compute the moving averages with ema(), a function that calculates an Exponential Moving Average with two arguments: a series of values to process and the number of bars to calculate on (TradingView, n.d.).

The fast moving average is calculated here with closing prices (close) and for its length we use the value of the quickMALen input variable. We assign that 12-bar moving average to the quickMA variable. The slower average is computed on closing prices too, but now for a length of slowMALen bars. That average’s value is stored in the slowMA variable.

Next we calculate the momentum with mom(), a function that requires two arguments: a series of values to process and an integer with the offset of the current bar to a previous bar (TradingView, n.d.). We use the function with closing prices (close) and momLen, the input variable we set to a standard value of 14. The difference between the current close and the closing price of 14 bars ago is what we store in the momentum variable.

Then we calculate the smoothed momentum with ema(). This time we have the function calculate on the momentum values stored in the momentum variable, and we set the average’s length with the momAvgLen input variable (which defaults to 5). We assign that 5-bar EMA of th 14-period momentum to the momSmooth variable.

Next we plot those momentum values on the chart:

plot(series=momentum, linewidth=2, color=#4169E1)
plot(series=momSmooth, color=#FF4500)

hline(price=0)

The plot() function plots the values of its series argument, and that data displays as a line by default (TradingView, n.d.). In the first plot() function call that argument is set to momentum, and with the function’s color argument we display those 14-bar momentum values with the #4169E1 hexadecimal colour value of royal blue.

The linewidth argument sets the plot’s size and has a default value of 1 when not specified (TradingView, n.d.). Since we set it to 2 here, our momentum line is bit thicker than default. The next plot() statement shows the momSmooth values on the chart. This 5-bar EMA momentum has a default size (since we didn’t set linewidth) and displays in orange red with the #FF4500 hexadecimal colour.

We also plot a horizontal line at 0 to easily spot when the momentum becomes positive and when it crosses into negative territory. We do that with hline(), a function that renders a horizontal line at a given fixed price (TradingView, n.d.). With that function’s price argument set to 0 we have the line plot at that level.

Then we figure out the strategy’s conditions for opening long and short positions:

enterLong  = crossover(quickMA, slowMA) and rising(momentum, 1) 
     and (momentum > momSmooth)
enterShort = crossunder(quickMA, slowMA) and falling(momentum, 1) 
     and (momentum < momSmooth)

We make two true/false variables here: enterLong and enterShort. Both have their value set with three expressions joined together with the and logical operator. This operator returns true when the expression on its left and the one on its right are both true also. Otherwise, when one or both expressions are false, then the result combined by and is false too (Pine Script Language Tutorial, n.d.). This means enterLong and enterShort will only be true when each situation checked by the three true/false expressions happened.

The first of three expressions that influences the enterLong variable uses the crossover() function. That function returns true when, on the current bar, the value of its first argument is above that of the second while, on the previous bar, the first argument’s value was less than the second (TradingView, n.d.). Since we use crossover() with the quickMA and slowMA variables, it returns true when the 12-bar EMA crossed above the 24-bar EMA on the current bar and false in all other cases.

The second expression uses the rising() function, which returns true when the values of its first argument are rising for the number of bars set by its second argument (TradingView, n.d.). We use rising() here with the momentum variable and 1, and this makes it return true when the 14-bar momentum has risen for 1 bar (so is higher on the current bar compared to the previous bar). Now when the momentum has been flat or declining, rising(momentum, 1) returns false.

The third and last expression checks whether the 14-bar momentum (stored in the momentum variable) is greater than (>) the 5-bar EMA of momentum values (which we put into the momSmooth variable). When the momentum is indeed above its average, this last expression returns true (and false otherwise).

To recap the above in normal English, our enterLong variable only holds a value of true when the quick moving average crossed above the slow one, and when the momentum rose compared to the previous bar, and when the momentum is above its moving average. When any of these three situations didn’t happen on the current bar, enterLong is false and then we won’t submit the enter long order later on in the script.

We set the value of the enterShort variable in an opposite manner as we did with enterLong. Now we use three expressions to check for three bearish situations. The first expression uses the crossunder() function to see whether the 12-bar EMA dropped below the 24-bar EMA. In the second expression we use the falling() function to check if the 14-bar momentum (momentum) has fallen compared to the previous bar. And the last expression evaluates whether the momentum is less than (<) its 5-bar moving average. When all three expressions return true, our enterShort variable holds true too. And due to using the and logical operator here: when one of the three expressions returns false, then enterShort becomes false too.

But before we submit orders with the enterLong and enterShort variables, we first specify the conditions for closing open long and short positions:

exitLong   = (strategy.position_size > 0) and crossunder(momSmooth, 0)
exitShort  = (strategy.position_size < 0) and crossover(momSmooth, 0)

Here we create two additional true/false variables: exitLong and exitShort. Each has its value set with two true/false expressions that we combine with the and logical operator. And so each expressions needs to be true before the variable is assigned a true value also (Pine Script Language Tutorial, n.d.).

The first of the two expressions that sets the value of the exitLong variable evaluate whether the strategy is currently long. We use strategy.position_size for that, a variable that returns both the size and direction of the strategy’s open position: a positive value indicates the number of open long contracts, a negative value signals the open short contracts, and the strategy is flat when this variable returns 0 (TradingView, n.d.). And so whenever strategy.position_size returns a value greater than (>) 0, our strategy is long.

The second expression uses the crossunder() function to check whether the 5-bar EMA of momentum values (momSmooth) dropped below 0. Combined, these two expressions mean that exitLong holds true whenever the strategy is long and when the moving average of the momentum fell into negative territory. When both situations don’t happen at the same time, our sell signal doesn’t generate.

In a similar way we assign the cover short signal to the exitShort variable. Here the first expression evaluates whether the strategy is short, which it is when strategy.position_size is less than (<) 0. For the second expression we use the crossover() function to see whether the 5-bar EMA of momentum (momSmoothed) rose above 0. Together these two expressions mean we exit open short positions whenever the smoothed momentum is positive on the current bar while being negative on the previous bar.

After determining both the enter and exit market conditions, we submit the actual orders:

if (enterLong)
    strategy.entry(id="Enter Long", long=true)

if (enterShort)
    strategy.entry(id="Enter Short", long=false)
    
if (exitLong or exitShort)
    strategy.close_all()

We submit the strategy’s orders conditionally with three if statements that all use the true/false variables we’ve defined just a moment ago.

The first if statement evaluates the enterLong variable and, when that variable returns true, calls strategy.entry(). That function enters a position with a market order by default and, when there’s already a position in the other direction, reverses that open position (TradingView, n.d.).

We use that function with two arguments: id specifies the order identifier, and that name displays on the chart and in the ‘Strategy Tester’ window. With the long argument we define whether strategy.entry() should open a long position (long=true) or a short position (long=false) (TradingView, n.d.). Here we set those arguments to “Enter Long” and true to have the function submit an enter long order.

The second if statement checks the enterShort variable. When that variable holds true on the current bar, we again call the strategy.entry() function. This time we specify it should open a short position (long=false) that’s named “Enter Short”.

The condition of the third and last if statement consists out of two true/false variables: exitLong and exitShort. Those variables are joined together with the or logical operator that returns true when the value on its left, the value on its right, or both values are true too. Only when the value on its left and right are false will or return false too (Pine Script Language Tutorial, n.d.).

The code that’s indented below the if statement calls strategy.close_all(). That function flattens the strategy’s current position, regardless of whether the strategy is currently long or short (TradingView, n.d.). And without an open position, strategy.close_all() doesn’t do anything.

This concludes the discussion of our programming example. Now let’s look at the strategy’s behaviour and then we’ll see how the currency argument of the strategy() function influences the script’s performance results.

Example charts: a momentum TradingView trading strategy

Our above example script has these input options:

Input options of our TradingView example strategy

When we add the strategy to the chart, it generates trades like the following:

Example chart of the TradingView momentum trading strategy Example chart of the TradingView example trading strategy

Example strategy: backtesting with a currency effect in TradingView

We started our programming example with the strategy() function configured like this:

strategy(title="Example - strategy currency", overlay=false, 
     currency=currency.NONE)

With the currency argument set to currency.NONE, we didn’t specify the strategy’s currency but instead had the script use the ‘Default’ currency. Since the Crude Oil (Brent) CFD of FXCM that we added the strategy to in the previous charts quotes in US dollars, the strategy’s results are reported in dollars too.

We see that for example happening in the ‘Overview’ tab of the ‘Strategy Tester’ window:

Backtest performance of a TradingView strategy that quotes in US Dollars

And in the ‘Performance Summary’ tab the results are denominated in dollars too:

Performance summary of our TradingView strategy that uses US Dollars

Likewise, the ‘List of Trades’ tab also uses US dollars:

TradingView's list of trades with profit/loss in US Dollars

Now let’s see how changing the currency argument affects these reports. For that we set the argument to currency.EUR like this:

strategy(title="Example - strategy currency", overlay=false, 
     currency=currency.EUR)

After making that change we save the strategy, and then TradingView reloads our strategy with the updated setting. Now all performance statistics are reported in euros instead of US dollars. We see that, for instance, happening in the ‘Overview’ tab of the ‘Strategy Tester’ window:

Performance overview of our TradingView strategy when trading in euros

Here we can already see that the net profit of $79.00 is 38.02 euros now. Euros are also used in the ‘Performance Summary’ now:

Performance summary of our TradingView strategy when using euros

And they also pop up in the ‘List of Trades’ tab:

TradingView's list of trades with the profit and loss in euros

Summary

We need to use the strategy() function in every TradingView strategy. That function configures several strategy settings with arguments, including currency. That optional argument specifies which currency the strategy uses and, when we don’t set it, defaults to currency.NONE. With that value the strategy uses the ‘Default’ currency and no currency conversion will take place. Instead, TradingView reports the strategy’s results in the same currency as the instrument it trades. However, when we set currency to a specific value (like currency.EUR for euros, currency.USD for US dollars, or currency.GBP for British pounds), then TradingView performs currency conversion whenever the instrument trades in a different currency than the one used by the strategy. The strategy’s initial capital, net profit, equity, drawdowns, and other statistics are then all converted to the currency we’ve specified with the currency argument or the equivalent manual option in the script’s settings. Note that TradingView performs currency conversion with daily closing prices from the applicable foreign exchange rate. That gives small differences between backtest and live results since broker accounts use a more recent exchange rate.

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