Warning: Declaration of ElementorPro\Modules\Posts\Skins\Skin_Content_Base::register_controls(Elementor\Widget_Base $widget) should be compatible with Elementor\Controls_Stack::register_controls() in /home/customer/www/backtest-rookies.com/public_html/wp-content/plugins/elementor-pro/modules/theme-builder/widgets/post-content.php on line 17
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
- 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.
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 variable
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:
valuewhenSource 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 (
close > open.
- source: This is the line you want to take the value from. It can be anything.
macdwhatever 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
0here. If we want the second most recent, a
1and so on…
//@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 > strategy.position_size 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
openvariable as the
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:
//@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 ? na : strategy.position_size > strategy.position_size ? rsi : entry_rsi // 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_rsiin the same line we want to calculate it and
rsi_closebefore 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
To tackle this problem, we check the previous value using
rsi_close ? 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
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
na– We don’t need to track anything anymore.
- NO: then did we open a position?
- YES: save the
- NO: save the last
- 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
rightbarsused 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.