The post this week comes courtesy of one the readers who got in touch with an interesting problem. He said:
“When I open a position I want to store the value of an indicator at that time to use with later candles.”
It is easy to see why he would want to do this. Accessing values later is useful for a number of applications. You can use it to monitor key levels and detect when the break. You can use it to implement some sophisticated trailing stops where the stop level only updates under certain conditions.
I sense that he may not be the only one who has faced this challenge. The most basic pine script tutorials teach you how to save a value to a variable in the script but what they do not teach is how to access it again 10 bars later. One option is to use indexing to retrieve the value. However, that only works if you know exactly when you want to access. In this post, we will look at storing, retrieving and working with key values of interest any time within the script.
How to Save a variable
There are two ways we can approach this. The method you choose will depend on how sophisticated your conditions for saving/discarding the variable needs to be:
- If your variable value comes from a fixed condition (like entering a position), we can simply use the
valuewhen()
built-in function. - If you want to have finer control over when to start and stop tracking a variable, a ternary conditional operator is the tool of choice.
We will use cover both of these methods in a set of examples below culminating in a final example that uses both methods together.
Examples
The following examples rely on entering a position. As such, we use some very basic entry criteria. The entry criteria are not important to understanding the concept and can safely be ignored or replaced with your own criteria.
Example 1 – valuewhen()
In this first example, we will just simply monitor the open value of a trade. We will keep track of this value until the trade is closed. This can be useful if you have multiple positions open and cannot rely on printing the built-in variablestrategy.average_price
.
valuewhen() Primer
The built-in function valuewhen()
looks at any condition we give it and returns the value of a line (which we also give it) when the condition was last true
. Using this function actually means we don’t have to save a variable at all! Instead, we just recall the correct value.
Here is a snippet from the docs:
valuewhen
Source series value when the condition was true on the n-th most recent occurrence.valuewhen(condition, source, occurrence) → series
To break it down further:
- condition: This can be anything that returns a Boolean value (
true
orfalse
). E.gclose > open
. - source: This is the line you want to take the value from. It can be anything.
open
,high
,rsi
,macd
whatever you want to pass it. - occurrence: This allows us to access not only the most recent value but other occurrences too. If we want the most recent value, we place a
0
here. If we want the second most recent, a1
and so on…
Code
//@version=3 strategy("Store Value Post - Open", overlay=true) // In the first example we will just simply store the open value of a trade. // We will keep track of this value until the trade is closed. This can be useful // if you have multiple positions open and cannot rely on printing the built // in variablestrategy.average_price. // SIMPLE ENTRY LOGIC sma = sma(close, 200) strategy.entry("Long", strategy.long, when=close > sma) // Close after 10 bars bought = strategy.position_size[0] > strategy.position_size[1] since_entry = barssince(bought) strategy.close("Long", when=since_entry >=10) // Get the entry price entry_price = valuewhen(bought, open, 0) plot(sma, color=orange, title='SMA') plot(entry_price, title='Entry Price', linewidth=2)
In the example code, the condition given to valuewhen()
checks whether the position size has increased. If it has, that means we have bought. Since we want the opening price of the trade and we know that Tradingview will always fill our orders at the open of the bar, we pass the open
variable as the source
.
When it is all put together valuewhen()
will keep returning the same value until we buy again! We can see this when we place the code on the charts!
Example 2 – Ternary Conditional Operator
In the next example, we will store to RSI value at the time we open a LONG trade and track it until the trade is closed. If the RSI breaks below this open value at any time, we will close the position. To help visualize this, we will plot the saved RSI value.
The code in this example will actually use the same technique described in the opening a window post. Since Pine script is a series based programming language, we just need to ensure we keep saving the previous value in a line/series until conditions change and we want to update it.
Note: If you are wondering what the heck a series based programming language is, it just means that we build lines of data every time a new candle is received. A series is just a line on the chart and we can access previous values in the series at any time. For more information on this see the pine script indexing tutorial.
Ternary Conditional Operator Primer
If you have not noticed the links yet, there is a full article on this site discussing ternary conditional operators in more detail. Although the name is a little scary, they are actually quite simple in nature. For more see here:
https://backtest-rookies.com/2017/09/04/tradingview-ternary-conditional-operators/
Code
//@version=3 strategy("Store Value Post - RSI", overlay=false) // In the next example, we will store to RSI value at the time we open a LONG trade // and track it until the trade is closed. If the RSI breaks below this open value // at anytime, we will close the position. To help visualise this, we will plot // the saved RSI value. // SIMPLE ENTRY LOGIC sma = sma(close, 14) strategy.entry("Long", strategy.long, when=close > sma) rsi = rsi(close, 14) // Track the Entry RSI Value entry_rsi = na rsi_close = na entry_rsi := rsi_close[1] ? na : strategy.position_size[0] > strategy.position_size[1] ? rsi : entry_rsi[1] // See if we need to close rsi_close := rsi < entry_rsi strategy.close("Long", when=rsi_close) plot(rsi, color=purple, title='RSI') plot(entry_rsi, style=linebr, title='Entry Value', linewidth=2, color=red)
This example turns the complexity up a notch. The code uses the ternary conditional operator in much the same way as valuewhen()
. However, in this example, we will also alter the entry_rsi
level when other conditions are met. To be more specific, we will stop updating the entry_rsi
level when we close the position so it looks a little neater on the charts.
In the code, you will see that before the ternary conditional operator, we first need to declare a couple of variables. We need to reference entry_rsi
in the same line we want to calculate it and rsi_close
before we have even created it! If these have not been declared, then we will receive an error.
rsi_close
is a little more interesting of the two. It presents a chicken and an egg scenario that can often be tricky to figure out. The problem is that we want to want to use rsi_close
to stop updating a line when our close conditions are met. However, at the same time we can only calculate whether to close condition after calculating the entry_rsi
line!
To tackle this problem, we check the previous value using rsi_close[1] ? na
. This is the key. We need to look at the last bar and see if that was signaling for us to close the position. In practice, this lines up nicely with the close marker on the chart as we always close at the open of the following bar when we send a strategy.close()
order.
After this, the logic is more straightforward. We check if we opened a position, if we did we track the RSI value at the open.
As an overview, the complete logic of the ternary conditional operator in this example goes something like this:
- Did we just close a position?
- YES: set
entry_rsi
tona
– We don’t need to track anything anymore. - NO: then did we open a position?
- YES: save the
rsi
value toentry_rsi
- NO: save the last
entry_rsi
value toentry_rsi
.
- YES: save the
- YES: set
Placing this code on the charts should result in something that looks like this:
Example 3 – Both
In the final example, we will use both methods to implement a sophisticated trailing stop! We will create a trailing stop that only moves whenever a new swing low occurs.
The reason we will use both valuewhen()
and a ternary conditional operator is again for plotting aesthetics but you may wish to have a number of conditions that cause the stop to trail up. Using a ternary conditional operator in conjunction with valuewhen()
will allow you to do this.
//@version=3 strategy("Store Value Post - Trailing Stop", overlay=true) // In the final example, we will store the value of the most recent swing low. // We will then use this to create a trailing stop that only moves whenever there // is a new swing low. // SIMPLE ENTRY LOGIC sma = sma(close, 14) strategy.entry("Long", strategy.long, when=close > sma) // Detect Swing Lows // ----------------------- leftbars = 5 rightbars = 2 last_pivot_low = pivotlow(low,leftbars,rightbars) // Get the stop price stop_price = na stop_price := strategy.position_size == 0 ? na : valuewhen(last_pivot_low, low[rightbars], 0) strategy.exit("SL","Long", stop=stop_price) plot(sma, color=orange, title='SMA') plot(stop_price, style=linebr, title='Stop Price', linewidth=1, color=red) //plot(last_pivot_low_value)
In the code above we have a simpler ternary conditional operator. We reset the stop level if our position size is zero. (This means our stop was hit). If not, we just use the most recent swing low as our stop level. Finally, we then use this stop level in strategy.exit()
and when a new swing occurs, the stop is updated automatically.
O,n the charts we can expect the price to trail behind the swings. Note that due to a lag in how swings are detected the line only updates after the number of rightbars
used in the code. In this case, it is two bars after the swing.
Here we can see that the trailing stop (in red) jumps up at each swing until it is taken out.
Find This Post Useful?
If this post saved you time and effort, please consider support the site! There are many ways to support us and some won’t even cost you a penny.
Backtest Rookies is a registered with Brave publisher!
Brave users can drop us a tip.
Alternatively, support us by switching to Brave using this referral link and we will receive some BAT!
Referral Link
Enjoying the content and thinking of subscribing to Tradingview? Support this site by clicking the referral link before you sign up!
3HxNVyh5729ieTfPnTybrtK7J7QxJD9gjD
0x9a2f88198224d59e5749bacfc23d79507da3d431
M8iUBnb8KamHR18gpgi2sSG7jopddFJi8S
Do you know how to get the value of the close candle at a specific date and security? e.g. Trying to compare the movement of EURUSD and GBPUSD from a year ago until now. I know TV has the compare option but I’m looking to create more of a static indicator.
Thank you
Hi Andrew – You could use the
security()
function to import theclose
data from another asset (like GBPUSD) and then use similar techniques as above.One option would to count the
barssince()
thedayofweek == 1 and month ==1 and year == 2018
etc…Or if you want 1 year ago from the current date, you could import
close[52]
in thesecurity()
function (making sure you are importing weekly data).Love your blog! Its extremely helpful!
Can you please give an example where the condition for saving a value is not a buy (not having an active trade)? I would like to use this for a Tradingview alert only for as long as another condition is active.
Rollin,
The easiest way is to think of it in these terms
your_indicator = valuewhen(another_condition, value_to_display, occurrence)
plot(your_indicator)
This will plot the value when the condition was true on the n-th most recent occurrence.
EXAMPLE
slow = sma(close, 7)
fast = sma(close, 14)
// get value of close on second cross occurrence
valuewhen(cross(slow, fast), close, 1)
BTR, keep up the good work! Love the blog!
Hi guys, I tried this earlier but to no avail:
//@version=2
strategy(title=”Engulfing”, shorttitle=”Lng_Eng”, overlay=false)
t_close = close
t_open = open
y_close = close[1]
y_open = open[1]
if (t_close > y_open) and (t_open = 2018) and (t_close > t_open) and (y_open > y_close)
strategy.entry(“Buy”, strategy.long)
bought = strategy.position_size[0] > strategy.position_size[1]
since_entry = barssince(bought)
entry_price = open[since_entry]
strategy.close(“Buy”, when = high > (entry_price*1.05))
I thought this would close the open position when the high was 5% above the entry price based on counting back the number of bars since bought and taking that open price which is the same as the entry price for that particular bar. Any ideas where I am going wrong?
Thanks
Hello, thanks for this website, it s pretty the only documentation/examples we have for Pine scripts. I have an issue with your example, what about if we can simultaneously have one long (and only one long) and one short (and only one short) at the same time ? How to distinguish the position if one is already opened ? Example:
—-
goLong() => crossunder(emaRSI, rsi)
killLong() => crossover(emaRSI, rsi)
if(startTime and endTime)
strategy.entry(“Buy”, strategy.long, when = goLong())
bought = strategy.position_size[0] > strategy.position_size[1]
strategy.close(“Buy”, when = killLong() and strategy.position_avg_price > valuewhen(bought,close,0) and rsi >= valuewhen(bought,rsi,0) + 5)
// Shorting if using
goShort() => killLong()
killShort() => goLong()
if(startTime and endTime)
strategy.entry(“Sell”, strategy.short, when = goShort())
sell = strategy.position_size[0] < strategy.position_size[1]
strategy.close("Sell", when = killShort() and strategy.position_avg_price < valuewhen(sell,close,0) and rsi <= valuewhen(sell,rsi,0) – 5)
—–
I want to exit only if indicators are crossing and i want to keep the closing price entry and rsi value entry and compare them to their values when indicators are crossing (in order to meet the whole condition). And another thing how do you specify you want only one long trade and only one short trade (default pyramiding is enough ?)?
Thanks in advance for your help, we reallyyyy need it!
Is it possible to replace “strategy” with “plot”?
Trying to apply this method differently and getting confused.
For example,
SMA = sma(close, 1)
x = (high > SMA) ? high : na
plot(x)
Can you spot the highest point of the plot(x) in (high > SMA) condition?
I want to plot a line of that highest point.
Would it be possible by using “valuewhen”?
Most helpful. Thank you. Great work !!