Tradingview has a few handy time-based variables and functions which allow you to manually keep track of time, events, sessions and detect time changes. These come in handy if you want to limit back tests to trade only during in-session hours or have indicators reset at certain intervals.
First things first, the Tradingview wiki actually has some good examples and tutorials showing how to use some of the variables and functions. Instead of reinventing the wheel, this post will try to add some value by showing the output of variables that do not have examples in the wiki and by providing a real-world example strategy.
You can take a look at Tradingview’s wiki tutorial here:
For those that are just following along in the series or have not read over the Tradingview wiki, a quick primer will help with digesting the rest of the post.
Regarding time, Pine Script has both special variables and a set of functions that use the same name. This means to avoid unintended syntax errors or behavior, you need to pay special attention to whether the code has brackets
()at the end of the name.
An example straight from the Wiki shows:
- time: A variable – Which returns a timestamp of the current date/time in a UNIX format.
- time(): A function – Which also returns a timestamp but for a specified resolution or session. This is useful for mixing time frames.
The Wikipedia description for UNIX time is an integer that represents the number of seconds that have elapsed since 00:00:00 Coordinated Universal Time (UTC), Thursday, 1 January 1970. However, it is important to note that Pine Script works with timestamps in millisecond format rather than seconds since 1970. If you are interested in why the 1st of January 1970 is used, take a look at this post on stack exchange which does a good job of explaining it:
Next up if
plot(na(t) ? 0 : 1)does not make any sense to you, it might be an idea to first take a look at another tutorial in the series: https://backtest-rookies.com/2017/09/04/tradingview-ternary-conditional-operators/ then come back here.
As mentioned above, Pine script has a number of built-in variables for tracking the time. In order to know how to use them, it is worth to plot each of them so you can see their expected output. Not all variables plot like
time where the output is always increasing. Some variables such as
hour cycle in a range. Let’s take a look.
Notice how this one does not step up as nicely as the
weekofyear variables. This is because we are often missing trading days due to the weekend and national holidays.
The range of
dayofweek already assumes weekends are not included. On the chart below we can clearly see the national holidays.
hour variable holds the current bar hour in the exchange timezone.
minute variable holds the current bar minute in the exchange time zone.
second variable holds the current bar second in the exchange timezone.
time vs timenow
Time provides the current time of the bar on the chart. Therefore it steps up in the same resolution as the timeframe you are working on. Using
timenow on the other hand, gives you the current time right now. This results in historical bars all showing the time now. When live data kicks in, you will see the two lines converge to an extent.
If you want to know about the differences between historical bars of data and real-time bars, see my post here: Tradingview: Understanding lookahead, historical and realtime data
Exploring time functions:
time() function itself is well covered in Tradingview’s wiki. However, there are a couple of points that can be expanded upon for the beginner. First, let’s take a look at the code:
t = time(period, "0930-1600")
plot(na(t) ? 0 : 1)
The explanation as noted in the wiki is:
timereturns the time of the bar in milliseconds UNIX time or NaN value if the bar is located outside the given trade session (09:30-16:00 in our example).
Some extra notes for the beginner are:
periodvariable in the Tradingview wiki example contains the resolution to be displayed.
- The session string is given in the exchange timezone and not the timezone on your chart! See below for more details.
NaNmeans “not a number”, it is this which allows us the easily differentiate between open and closed sessions bars. When the session is open, the variable which contains the series data will hold a UNIX timestamp for that bar. Conversely, if it is closed, the series will contain a
NaNvalue for the bar.
na()function checks a number/value in a series. In this case, we are passing it the
tseries variable. If
True. If a valid number is found, it will return
- Finally, the
plotline is using a ternary condition to check the returned value from
na(). If it returns a
Truevalue (because we are NOT in session) then 0 will be plotted on the indicators. If it returns
False, then 1 is plotted on the indicator.
Session vs chart time zones
As noted above, the session value that you enter is for the exchange timezone. This may seem confusing at first but using the session time zone instead of the chart time zone simplifies deployment of the code. It ensures that the code can be copied and pasted for any user around the world. Different users will have different chart time preferences and as such, they would potentially be out of sync with the session open / close if they are not located in the same timezone as the code developer. Using the exchange timezone ensures that the code will open and close and the same time regardless of a users preference.
year(), month(), second() etc….
The rest of the time-based functions all do pretty much the same thing. They all accept a UTC timestamp in milliseconds and they return either a year, month, second etc for the timestamp given.
All the theory is good and well but it is useless unless you put it into practice. A real-world example is provided below to get you moving on your way.
This example will create a simple stochastic strategy to buy and sell only when we are in the Asian trading session and ADR (average directional index) is showing that we are not heavily trending. The strategy will also close open positions at the end of the session.
The code shown below was setup to trade GBPUSD. The chart was set to Tokyo time zone so I could verify trades were being opened correctly at the right local times. You will see the exchange times used in the codes are not the same as the local times.
strategy("Asian Stoch", overlay=true)
//########### Inputs #################\\
adxlen = input(14, title="ADX Smoothing")
dilen = input(14, title="DI Length")
maxADX = input(26, title="Maximum ADX value allowed to trade")
stPeriod = input(14, title="The lookback period for the stochastic")
stBuy = input(30, title="Buy below this stochastic value")
stSell = input(70, title="Sell above this stochastic value")
//########### ADR CODE #################\\
up = change(high)
down = -change(low)
truerange = rma(tr, len)
plus = fixnan(100 * rma(up > down and up > 0 ? up : 0, len) / truerange)
minus = fixnan(100 * rma(down > up and down > 0 ? down : 0, len) / truerange)
adx(dilen, adxlen) =>
[plus, minus] = dirmov(dilen)
sum = plus + minus
adx = 100 * rma(abs(plus - minus) / (sum == 0 ? 1 : sum), adxlen)
sig = adx(dilen, adxlen)
not_trending = sig < maxADX
//########### Asian Session CODE #################\\
t = time(period, "1900-0315")
session_open = na(t) ? false : true
//########### Stochastic CODE #################\\
stoch = stoch(close, high, low, stPeriod)
long = stoch < stBuy
short = stoch > stSell
//########### STRATEGY CODE #################\\
if (long and session_open and not_trending)
// strategy.close("Short 1")
strategy.entry("Long 1", strategy.long)
if (short and session_open and not_trending)
// strategy.close("Long 1")
strategy.entry("Short 1", strategy.short)
//Close out position before the end of the session.
if not (session_open)
On the charts, it looks something like this.
You can see the end of day closes in purple. Otherwise, it alternates between long and short positions.
What about the profitability? Don’t get too excited! It is nothing to write home about:
The results above used an order size of 5% of equity on a 100,000 USD account and did not take commissions into account. However, that was not the point of the exercise!