The Relative Volatility Index. Deriving Trading Signals from Fluctuations.
Creating and Back-testing a Contrarian Indicator Using Pure Volatility.
Every aspiring or professional trader knows about the Relative Strength Index — RSI. A contrarian momentum indicator that is trapped between 0 and 100 which is used in a lot of discretionary and systematic strategies. But what about using volatility within the same reasoning of the RSI? This should give us another view that can confirm our views. By this, we are talking about the Relative Volatility Index — RVI. An indicator that we will present in detail below and back-test it through a simple strategy.
If you are interested in contrarian strategies, feel free to read this article as well:
Calculating Volatility
Volatility is the magnitude of fluctuations of a variable around its mean. In time series, a volatile data is one that moves swiftly from one level to another and is generally away from its mean while a stable or low-volatility data is one that looks closer to its moving average (mean).

There are many ways to measure volatility such as the Average True Range, the Mean Absolute Deviation, and the Standard Deviation. We will use Standard Deviation to create the Relative Volatility Index.
The most basic type of volatility is the Standard Deviation. It is one of the pillars of descriptive statistics and an important element in some technical indicators such as the famous Bollinger Bands. But first let us define what Variance is before we find the Standard Deviation.
Variance is the squared deviations from the mean (a dispersion measure), we take the square deviations so as to force the distance from the mean to be non-negative, finally we take the square root to make the measure have the same units as the mean, in a way we are comparing apples to apples (mean to standard deviation standard deviation). Variance is calculated through this formula:

Following what we have said, standard deviation is therefore:

The result of the above functions on the daily values of the EURUSD pair with a Standard Deviation period of 10 can be seen in the below chart:

def volatility(Data, lookback, what, where):
for i in range(len(Data)):
try:
Data[i, where] = (Data[i - lookback + 1:i + 1, what].std()) except IndexError:
pass
return Data
Creating the Relative Volatility Index
The exciting job now is to turn the historical volatility otherwise known as the historical Standard Deviation into a tradeable indicator that gives us buy and sell signals. The first part of creating the RVI is to calculate the Standard Deviation of a certain period. Let us choose the common default period of 14. We can use the below code on an OHLC data array to do so:
my_ohlc_array = volatility(my_ohlc_array, 14, 3, 4)# We are saying that we want to apply the volatility function seen above onto our OHLC array using a lookback period of 14 and applying the calculation on the closing price (hence, the fourth column which is indexed at 3). Then, we want to output the result in the fifth empty column which is indexed at 4

The next step is to create two columns to contain the values of when volatility increases or decreases from the last period. Thus, we can define the following conditions:
- If the current Standard Deviation is greater than the previous Standard Deviation, then, input in a new column the current value of the Standard Deviation. Otherwise, input zero. Let us call this column the Positive Change.
- If the current Standard Deviation is lower than the previous Standard Deviation, then, input in a new column the current value of the Standard Deviation. Otherwise, input zero. Let us call this column the Negative Change.
Now that we have two columns where one contains the positive changes in volatility and the other contains the negative changes in volatility, we can proceed by coding them in this way:
for i in range(len(my_ohlc_array)):
if my_ohlc_array[i, std_col] > my_ohlc_array[i - 1, std_col]:
my_ohlc_array[i, positive_ch] = my_ohlc_array[i, std_col]
else:
my_ohlc_array[i, positive_ch] = 0
for i in range(len(my_ohlc_array)):
if my_ohlc_array[i, std_col] < my_ohlc_array[i - 1, std_col]:
my_ohlc_array[i, negative_ch] = my_ohlc_array[i, std_col]
else:
my_ohlc_array[i, negative_ch] = 0# The variable std_col refers to the column where the Standard Deviation is stored
# The variable positive_ch refers to the Positive Change column that will be populated
# The variable negative_ch refers to the Negative Change column that will be populated
Next, we can calculate a simple moving average of the Positive Change and the Negative Change columns. We can also compute a smoothed moving average instead if we want to be exactly in line with the RSI formula, but I like to keep it simple from time to time. Here is how to do so:
def ma(Data, lookback, what, where):
for i in range(len(Data)):
try:
Data[i, where] = (Data[i - lookback + 1:i + 1, what].mean())
except IndexError:
pass
return Datamy_ohlc_array = ma(my_ohlc_array, lookback, positive_ch, up_ma)
my_ohlc_array= ma(my_ohlc_array, lookback, negative_ch, down_ma)# The variable up_ma refers to where we want to store the averaged values of the positive change while the down_ma refers to where we want to store the averaged values of the negative change
All the above work can be combined into one function that defines the Relative Volatility Index:

def relative_volatility_index(Data, lookback, what, where):Data = volatility(Data, lookback, what, where)
for i in range(len(Data)):
if Data[i, where] > Data[i - 1, where]:
Data[i, where + 1] = Data[i, where]
else:
Data[i, where + 1] = 0
for i in range(len(Data)):
if Data[i, where] < Data[i - 1, where]:
Data[i, where + 2] = Data[i, where]
else:
Data[i, where + 2] = 0
Data = ma(Data, lookback, where + 1, where + 3)
Data = ma(Data, lookback, where + 2, where + 4)# RVI
for i in range(len(Data)):
Data[i, where + 5] = 100 * Data[i, where + 3] / (Data[i, where + 3] + Data[i, where + 4])
return Data

Back-testing a Contrarian Strategy
As we know, the general idea is that when volatility goes up, it is generally accompanied with a sell-off following a form of panic and when volatility is going down, this is usually accompanied by a steady rise in the market. This is of course not very accurate as a stable bearish downtrend can also have low volatility and sudden upside spikes can have high volatility.
However, we will stick to this consensus for the sake of back-testing this indicator purely. We can discuss in a future article how to use the RVI as a volatility confirming indicator in a strategy that relies on a directional indicator, but for now, let us derive the following trading rules using a 3-period RVI:
- Go long (Buy) whenever the RVI reaches 90 level with the previous two values less than 90. Hold this position until getting a contrarian signal.
- Go short (Sell) whenever the RVI reaches 10 level with the previous two values above 10. Hold this position until getting a contrarian signal.
- Using an Average True Range risk management system detailed later in the article.
- The back-tested data is hourly from January 2010 until January 2021. The spread is 0.2 pips.

Now, let us see how did this strategy perform. We will use a risk management system of 0.25 which is targeting 1x ATR and stopping at 4x ATR. While we are discussing performance and risk elements, we can introduce the other ones rapidly:
- The hit ratio is the number of profitably closed trades on the total number of trades taken and closed.
- The expectancy is a weighted measure of the expected gain. It uses the average gain, the average loss, and the historical hit ratio to determine a probability-weighted metric of the next result.
- The profit factor is simply the total gross profit over the total gross loss. A value more than one means that our profits were greater than our losses.
- The realized risk-reward ratio is a quick glance at the risk management performance. It is the average gain per trade divided by the average loss per trade.
- The break-even hit ratio is the minimum ratio for the system to be profitable given a realized risk-reward ratio.


It is clear that the RVI on its own underperforms using the above parameters and therefore, it may be more suited to be a confirming indicator.
Risk Management Snapshot
When I say I use ATR-based risk management system (Average True Range), it means that the algorithm will do the following steps with regards to the position it takes.
A long (Buy) position:
- The algorithm initiates a buy order after a signal has been generated following a certain strategy.
- Then, the algorithm will monitor the ticks and whenever the high equals a certain constant multiplied by ATR value at the time of the trade inception, an exit (at profit) order is initiated. Simultaneously, if a low equals a certain constant multiplied by ATR value at the time of the trade inception is seen, an exit (at loss) is initiated. The exit encountered first is naturally the taken event.
A short (Sell) position:
- The algorithm initiates a short sell order after a signal has been generated following a certain strategy.
- Then, the algorithm will monitor the ticks and whenever the low equals a certain constant multiplied by ATR value at the time of the trade inception, an exit (at profit) order is initiated. Simultaneously, if a high equals a certain constant multiplied by ATR value at the time of the trade inception is seen, an exit (at loss) is initiated. The exit encountered first is naturally the taken event.

The plot above shows the Average True Range I generally use. It is based on an exponential moving average as opposed to the original smoothed moving average.
Take a look at the latest value on the ATR. It is around 0.0014 (14 pips). If we initiate a buy order following a simple 2.00 risk-reward ratio (risking half of what we expect to gain), we can place an order this way:
- Buy at current market price.
- Take profit at current market price + (2 x 14 pips).
- Stop the position at current market price — (1 x 14 pips).
Conclusion
If you regularly follow my articles, you will find that many of the indicators I develop or optimize have a high hit ratio and on average are profitable. This is mostly due to the risk management method I use. But what about market randomness and the fact that many underperformers blaming Technical Analysis for their failure?
First of all, I constantly publish my trading logs on Twitter before initiation and after initiation to show the results. This ensures transparency. I also publish a track record on Twitter every 1–3 months. However, I never guarantee a return nor superior skill whatsoever. As for the indicators that I develop, I constantly use them in my personal trading. Hence, I have no motive to publish biased research. My goal is to share back what I have learnt from the online community.
Remember to always do your back-tests. Even though I supply the indicator’s function (as opposed to just brag about it and say it is the holy grail and its function is a secret), you should always believe that other people are wrong. My indicators and style of trading works for me but maybe not for everybody. I rely on this rule:
The market price cannot be predicted or is very hard to be predicted more than 50% of the time. But market reactions can fairly be predicted.
What the above quote means is that we can form a small zone around an area and say with some degree of confidence that the market price will show a reaction around that area. But we cannot really say that it will go down 4% from there, then test it again, and breakout on the third attempt to go to $103.85. The error term becomes exponentially higher because we are predicting over predictions.
While we are discussing this topic, I should point out a few things about my back-tests and articles:
- The spread I use is based on institutional quotes of a small pip fraction. Generally, retail traders are given a whopping spread of 1–2 pips per trade. This is huge. I use 0.2 spread. However, most of the strategies that use the hourly time frame still work with 1 pip spread. For the ones that use M15 or M5 time frames, they cannot be profitable with a spread of 1 pip.
- The holding period calculation I use is close-to-close in case there is no risk management process.
- Although I discourage trading based on just one indicator, the numbers do not lie. What I am presenting is what could have happened when taking into account a low spread.
- Some of the back-tests I provide are losers and they are published either to demystify a trading myth or to present interesting functions to be coded by readers.
- Finally, I am a firm believer of not spoon-feeding the learners. I have learnt by doing and not by copying. You should get the idea, the function, the intuition, the conditions of the strategy, and then elaborate (an even better) one yourself so that you back-test it and improve it before deciding to take it live or to eliminate it.
To sum up, are the strategies I provide realistic? Yes, but with optimizing the environment (robust algorithm, low costs, honest broker, risk management). Are the strategies provided only for the sole use of trading? No, it is to stimulate brainstorming and getting more trading ideas as we are all sick of hearing about an oversold RSI as a reason to go short.