In TradingView we can backtest our strategy in a specific currency to see how currency conversions affect our profits and losses. But TradingView performs these currency conversions with daily prices while brokers report with a real-time rate. Is this a big deal when evaluating our backtest results?

In this article:

Analysing a TradingView strategy’s performance in another currency

Programmatically configuring a TradingView strategy is done with the strategy() function, which we have to add to every TradingView strategy (Pine Script Language Tutorial, n.d.). This function has several arguments, like the required title argument that sets the strategy’s name and currency, which specifies the strategy’s currency setting (TradingView, n.d.).

With that currency argument our TradingView strategy can calculate with a different currency than the one used by the instrument it trades (Pine Script Language Tutorial, n.d.). This gives us an idea of how currency differences affect our strategy’s performance. For instance, when our strategy uses euros (currency=currency.EUR) but trades the E-mini S&P 500 Index future chart (which quotes in USD), then TradingView converts all profits and losses from US dollars to euros. And if we size orders based on an equity percentage, then TradingView converts a fraction of the euro capital to dollars when determining the order size.

Tip: A currency conversion happens when the instrument quotes in a different currency than the strategy uses. These conversions are use the daily closing price of the previous forex session (Pine Script Language Tutorial, n.d.). That means intra-day strategies use the same conversion rate throughout the whole trading day.

Because currency conversions happen with yesterday’s exchange rate, there are (small) differences between the backtest results and the profit/loss our broker reports in real time. TradingView’s currency conversion is a useful feature, though. But our backtest performance can be over- or underestimated depending on how volatile the exchange rate was during the backtest period. That is, the bigger the price change between the previous session’s close and the current forex rate, the more off TradingView’s backtest result will be.

The difference between backtest results and real-time results happens because brokers very likely use another exchange rate than the previous trading day’s close. How a broker converts profit/loss to the account’s base currency differs, though. FXCM, for instance, doesn’t list on its website how it performs that base currency conversion.

But LMAX uses the prevailing exchange rate when it reports the open and realised profits and losses (LMAX Exchange, 2016). But even here a small currency conversion difference can happen. That’s because LMAX performs the actual conversion the next business day, and the reported real-time trade balance is 98% of profits and 102% of losses (converted with the current exchange rate) to account for possible currency moves in the meantime (LMAX Exchange, 2016).

So depending on how your broker performs currency conversions and the volatility of the relevant forex exchange rate, the backtest results in TradingView are quite likely a bit different than those achieve in real-time trading. This is, however, just another reason why backtest reports only give a rough indication of possible performance.

For a better understanding of how TradingView performs currency conversion (and how this can impact backtest results), let’s look at an example strategy that shows the effect of currency conversion with daily forex rates and near real-time prices.

Example strategy: analysing currency conversion in TradingView

The example strategy below has its account currency set to euros while it trades FXCM’s EuroStoxx 50 Index CFD, which quotes in US dollars. On every bar, the script submits a buy order alongside a profit and stop-loss order of 1 tick. Since we trade 10 contracts at a time, each order has a profit or loss of $10. This means TradingView has to convert the same amount of US dollars to euros on each price bar, and that allows us to examine the effect of TradingView’s currency conversions.

We plot the $10 trade result in three ways. The first plot (blue) shows how TradingView converted this dollar amount to euros. The second plot (red dots) displays how we converted the $10 dollars to euros with daily forex closing prices. And the third and last plot (purple) converts $10 to euros using 1-minute EUR/USD prices. These different plots show how converting profit/loss with daily forex prices differs from near real-time conversion.

The chart below displays what the script looks like; after discussing the code we’ll take a closer look at its behaviour.

Example chart of the TradingView strategy with currency conversion
//@version=2
strategy(title="Example - Currency conversion in TradingView", 
     currency=currency.EUR)

// Submit orders
if year == 2016 and month > 3
    strategy.entry(id="Long Entry", long=true, qty=10)
    strategy.exit(id="Long Exit", from_entry="Long Entry", profit=1, loss=1)

// Plot the net profit of 10 dollar, as computed by TradingView
profitChange = abs(strategy.netprofit - strategy.netprofit[1])

plot(series=profitChange, color=blue, linewidth=2)

// Plot 10 dollar, converted with previous session EUR/USD prices
dailyEURUSD = security("EURUSD", "D", close[1])

plot(series=10 / dailyEURUSD, color=red, style=circles, linewidth=3)

// Plot 10 dollar, converted with 1 minute EUR/USD prices
eurUSDrate = security("EURUSD", "1", close[1])

tradeInEUR = 10 / eurUSDrate

plot(series=tradeInEUR, color=purple, linewidth=2)

We begin with the @version=2 comment. This specifies that the script should use the second version of TradingView Pine, and one thing made possible by that version are the if statements (Pine Script Language Tutorial, n.d.) which we use later on in the script.

Then we configure the strategy’s properties with strategy(). With the title argument we specify the strategy’s name and with currency we set the strategy’s currency to euros (currency.EUR). This way our strategy won’t report its results in the currency of the instrument it trades, but in euros (Pine Script Language Tutorial, n.d.).

Next we submit our entry and exit orders:

if year == 2016 and month > 3
    strategy.entry(id="Long Entry", long=true, qty=10)
    strategy.exit(id="Long Exit", from_entry="Long Entry", profit=1, loss=1)

We send off orders conditionally with an if statement. The if statement’s condition has two true/false expressions, which we combine with the and logical operator. That operator returns true when the value on its left and the value on its right are both true too – when one or both values are false, then and returns false too (Pine Script Language Tutorial, n.d.).

So before submitting our orders, both expressions have to be true. The first evaluates whether year, a built-in variable that returns the bar’s year in exchange time zone (TradingView, n.d.), equals (==) 2016. The second checks whether the month built-in variable (that returns the bar’s month in exchange time zone; TradingView, n.d.) is greater than (>) 3. Combined, these two expressions evaluate whether the current bar is in April 2016 or later.

This condition seems unnecessary: why add a filter based on date? Well, currently a TradingView strategy cannot generate more than 2,000 orders. Without this date filter, our script would generate too many orders. So we have to limit the backtest period by only generating trades in April 2016 and later. (Depending on when you run the above script, you might need to change the date filter to another month and/or year.)

Now when the script calculates on a bar that’s indeed in April 2016 or later, the code indented below the if statement executes. The first line below if submits a market order with the strategy.entry() function (TradingView, n.d.). We configure three of this function’s arguments. With id we set the order specifier, and this name displays on the chart and in the ‘Strategy Tester’ window – but is also used by other functions to reference this entry order. With the long argument set to a value of true strategy.entry() submits an enter long order (TradingView, n.d.). And with qty we set the order size to 10 contracts.

The next line below the if statement submits our exit order with strategy.exit(). With this function’s id argument we set the order name that displays on the chart and in the ‘Strategy Tester’ window. We use the from_entry argument to specify from which entry order this exit order should exit from (TradingView, n.d.), and here we have it exit our earlier entry (that is, from_entry="Long Entry").

With the profit and loss arguments of strategy.exit() we set the profit target and stop-loss with a number of ticks. TradingView will then submit these limit and stop orders with the correct price based on the entry price (TradingView, n.d.). We set these arguments both to 1; that way when the profit target or stop-loss hit, the trade generates a profit/loss of 10 dollars (since the entry order was for 10 contracts).

Now that we’ve submitted the orders, we plot the trade results in euros as computed by TradingView:

profitChange = abs(strategy.netprofit - strategy.netprofit[1])

plot(series=profitChange, color=blue, linewidth=2)

Here we create the profitChange variable and assign it the absolute difference between the strategy’s profit on this bar and the previous bar. We retrieve those profit values with strategy.netprofit, a built-in variable that returns the cumulative result all completed trades (TradingView, n.d.). That value is, by the way, in the strategy’s currency.

We get the previous bar value of that variable with the history referencing operator ([]) and a value of 1 between those square brackets (see Pine Script Language Tutorial, n.d.). Now to get the absolute value of how the net profit differs compared to the previous bar, we subtract the current and previous net profit values from each other in the abs() function, which returns the absolute value (TradingView, n.d.).

Then we plot the trade result in euros with plot(). This function plots the data of its series argument as a line by default (TradingView, n.d.). Here we set that argument to profitChange, and with the function’s color argument those values are in the blue standard TradingView colour. The linewidth argument, which sets the plot’s size starting from 1 as the default size (TradingView, n.d.), is set to 2 here to make a line slightly bigger than normal.

At this point in the programming example we plotted each bar’s absolute net profit change, and that value is converted from dollars to euros by TradingView. To replicate that currency conversion, we then convert $10 to euros ourselves:

dailyEURUSD = security("EURUSD", "D", close[1])

plot(series=10 / dailyEURUSD, color=red, style=circles, linewidth=3)

Since TradingView performs currency conversion with the closing price of the previous forex session (Pine Script Language Tutorial, n.d.), we have to retrieve those daily EUR/USD prices for our calculations. We do that with security(), a function that allows us to request data from additional symbols and/or resolutions other than the chart’s data that the script is currently added to (Pine Script Language Tutorial, n.d.).

We use the security() function with three arguments here. The first specifies the symbol to load, which we set to "EURUSD" for the Euro/US dollar exchange rate. The second argument is "D", and with that security() returns daily prices (Pine Script Language Tutorial, n.d.). The last argument specifies which value the function should return from that data (TradingView, n.d.), and for that we use close[1]. This way we don’t get the closing price of the current, still-developing trading day but the closing price of the previous day. That makes security() return the same prices as TradingView uses for currency conversions. We assign those prices in the dailyEURUSD variable for use next.

To convert the $10 of each trade ourselves, we divide 10 with the previous trading day’s EUR/USD price (dailyEURUSD) as the value for the series argument of the plot() function. So with an EUR/USD rate of 1.14638, our 10 dollar profit would plot as 8.72 euros.

We also set the color argument of this plot() function call to the red basic TradingView colour. With the style argument we specify the kind of plot (TradingView, n.d.), and with circles the plotted values display as dots on the chart. With linewidth=3 those filled circles appear several steps bigger than the default size.

At this point, we’ve plotted the euro amount of $10 as converted by TradingView and by ourselves. But both of those plots use the exchange rate of the previous forex session. To compare how a broker would report profits and losses of $10, we convert that dollar amount using near real-time EUR/USD prices:

eurUSDrate = security("EURUSD", "1", close[1])

tradeInEUR = 10 / eurUSDrate

plot(series=tradeInEUR, color=purple, linewidth=2)

Here we use security() again, but this time have it load EUR/USD prices from the previous 1-minute bar. With the function’s second argument set to "1" it loads one minute data, and with close[1] as the third argument we get the closing price of the previous 1-minute bar. With such a low resolution, the conversion of dollars to euros is much more accurate.

We store the values returned by security() in the eurUSDrate variable. Then we divide 10 with the EUR/USD rate (eurUSDrate) to get the euro equivalent of 10 dollars. We assign that value to the tradeInEUR variable.

Now to see how currency conversion with minute data looks, we call plot() again. This time we set series to tradeInEUR and have the plot display in the purple standard TradingView colour. With linewidth=2 our plotted line is a bit bigger than default.

Let’s examine some charts to see the difference between $10 converted with daily and 1-minute data, and get an idea of how big the impact of TradingView’s currency conversion with daily prices is.

Example charts: currency conversion with daily and minute data

When we add the above strategy to the chart, it trades and plot values like this:

Example chart of the TradingView strategy with currency conversion

Each plot value shows the absolute performance of that bar’s trade. The blue line is how TradingView converted the US dollar profit/loss to euros. The red dots are our own currency conversion with daily prices (and these match TradingView’s results exactly). And the purple line shows the euro value of $10 based on 1-minute EUR/USD prices. Since this latter line uses intra-day data, its values are updated repeatedly throughout the day while the other two lines use the same exchange rate for the whole day.

The good news is that there’s only a small difference between converting dollars to euros with daily or 1-minute prices. On the first two days shown in the above chart, the daily and 1-minute EUR/USD exchange rate didn’t differ much. Only in the right part of the chart do we see some difference (8.8120 versus 8.7318), which is just over an one percent difference.

While the difference between TradingView’s currency conversion and using 1-minute data remains small on other charts, the values are, however, nearly never the same:

Showing the difference between TradingView's currency conversion and near real-time conversion

When the EUR/USD exchange rate trends, sometimes real-time exchange rates give better results while at other times the previous day’s closing price gives more favourable conversion results:

Fluctuating currency conversion rates in TradingView

Looking at the small trade sample displayed on these charts, the difference between currency conversion with daily and almost real-time prices is quite modest. Furthermore, currency conversion with daily prices likely cancels out favourable with pessimistic conversions. So in terms of currency differences, TradingView’s backtest results when using currency conversion are likely a good estimate of real-time performance.

During periods of high forex volatility or when using another exchange rate than EUR/USD, there might be a bigger difference between how TradingView converts profit/loss to the strategy’s currency and how a broker reports this in real time. That being said, other factors like slippage (which currently cannot be backtested in TradingView) give a much bigger difference between real-time performance and backtest results than currency effects do.

Summary

The strategy() function configures a strategy’s properties and has to be added to every TradingView strategy. One argument of this function is currency, which sets the currency that’s used by the strategy and its performance reports. This optional argument defaults to currency.NONE, in which case the script uses the ‘Default’ currency and no currency conversion takes place. Now when a strategy uses a different currency than the instrument it trades, then TradingView performs currency conversion. TradingView performs that conversion with the closing price of the previous trading day of the applicable forex rate. That means backtest results will differ slightly from real-time performance since brokers use a much more recent exchange rate when reporting profits and losses. However, currency conversion with daily prices only has a minor impact since the percentage fluctuations of daily exchange rates are typically modest.

Learn more:


References

LMAX Exchange (March 2016). Trading Manual. Retrieved on July 16, 2016, from https://www.lmax.com/pdf/Trading-Manual.pdf

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