Creating a Trading Strategy Using the RSI & the Bollinger Bands. New Ideas Using Python.
By: Sofien Kaabar
Tags: Trading, Finance, Machine Learning, Data Science, Investing

An overwhelming number of traders use the famous Relative Strength Index to help with their decisions, and although it can only serve as a confirming indicator, it nevertheless, has its weight in many trading decisions or at the very least timing the decisions. The RSI has been created by J. Welles Wilder in 1978 as a momentum indicator with an optimal look-back period of 14 bars. It is bounded between 0 and 100 with 30 and 70 as the agreed-upon oversold and overbought zones respectively. The RSI can be used through 3 known techniques:

Oversold and overbought zones as indicators of possible short-term corrections or reversals.

Divergence from prices as an indication of trend exhaustion (I’ve written about it here in Medium: Back-testing the RSI divergence strategy on FX in Python. Should it be used as a stand-alone strategy?)

Drawing normal supports/resistances on the indicator just as we would do with prices.

In this small study, we will be back-testing the first RSI technique and see whether touching the 30 or 70 level can provide a reversal or correction point. In other words, should we develop a system that trades when the RSI touches these levels? We will try to optimize the signals based on the holding period and the RSI period.

The first line in the function below is a correction/transformation from the exponential moving average in pandas to the original smoother version that is commonly used in the RSI packages. I recommend using an older version of pandas as the below ewma function is deprecated in the newer versions.

def rsi(Data, rsi_lookback, which = 1): #OHLC Data



rsi_lookback = (rsi_lookback * 2) - 1 # From exp to smoothed # Get the difference in price from previous step

Data = pd.DataFrame(Data)

delta = Data.iloc[:, 3].diff()

delta = delta[1:]



# Make the positive gains (up) and negative gains (down) Series

up, down = delta.copy(), delta.copy()

up[up < 0] = 0

down[down > 0] = 0



roll_up = pd.stats.moments.ewma(up, rsi_lookback)

roll_down = pd.stats.moments.ewma(down.abs(), rsi_lookback)



roll_up = roll_up[rsi_lookback:]

roll_down = roll_down[rsi_lookback:]

Data = Data.iloc[rsi_lookback + 1:,].values



# Calculate the RSI

RS = roll_up / roll_down

RSI = (100.0 - (100.0 / (1.0 + RS)))

RSI = np.array(RSI)

RSI = np.reshape(RSI, (-1, 1))



Data = np.concatenate((Data, RSI), axis = 1)

We will try to optimize the signals here by tuning the parameters. The back-tested pairs will as usual be the six major pairs, on the 3H time frame, using a 1 pip transaction cost for every trade (indicative), holding the positions for 10 periods (3 x 10 = 30 hours), and with an RSI(14, 25, 75). The historical data analyzed span since 2005-to date.

Visibly, the pure RSI method does not work. What if we optimize the holding period and the RSI period. You can do it for all of the pairs, but to not make the article longer than it should be, we will only optimize the EURUSD (that is, if it is optimizable).

Equity curves after holding period optimization attempt (i.e. looping through different holding periods)

Optimization attempt with varying holding periods.

Optimization attempt with varying RSI periods using an upper barrier of 70 and a lower barrier of 30.

Optimization attempt with varying RSI periods using an upper barrier of 75 and a lower barrier of 25.

It can be seen that there’s not much we can do regarding a pure RSI strategy (which was already the idea before writing the article). Key takeways before we move on to a more advanced strategy below:

Do not believe posts from people claiming good results from only using the RSI. It is either an anomaly or cherry-picking. An indicator this simple from a subjective field can never yield abnormal returns. If it did, it would have been artbitraged away.

The RSI can only be used as a confirming factor inside a ranging market. I will soon post another article to show that it really adds value to an already existing trading framework.

Always mass back-test and try not to tweak too much the parameters. Only working with one security through one timeframe screams of overfitting and pure coincidence.

The RSI depends on the current market state. If it’s ranging, then it will likely provide good signals. If it’s trending, then it’s better to use other tools.

A quick glance at a signal chart from the above strategy:

What if we now try something new?

What if we try to know whether the market is trending or ranging and through that information we decide if we trade the RSI signals or not. By using the Bollinger bands we should calculate the widening variable that tells us if prices are about to trend and if the RSI signals will not be that good.

The idea remains simple:

Buy conditions : If the widening variable remain within the Bollinger and the widening of the bands is less than a pre-specified margin as well as the RSI reaching the oversold zone, then we initiate a buy order.

: If the widening variable remain within the Bollinger and the widening of the bands is less than a pre-specified margin as well as the RSI reaching the oversold zone, then we initiate a buy order. Sell conditions: If the widening variable remain within the Bollinger and the widening of the bands is less than a pre-specified margin as well as the RSI reaching the overbought zone, then we initiate a sell (short) order.

What is the widening variable? It is simply the moving spread between the upper and the lower Bollinger band. If we calculate that spread, we can calculate the standard deviation of its movements. If it’s moving well above or below the deviations, then it’s clearly we’re not ranging and we’re not in the normality phase. This serves as a filter to any signals given by the RSI. Sometimes, it reaches the overbought level just at the beginning of the trend, thus, making the outcome very bad.

Here’s an example below on the EURNOK showing that when the Bollinger bands widen by much, then, the RSI signals should not be taken into account.

The back-testing conditions will be the same as the above on the 3H time frame on the six major FX pairs. Let’s see the new signal chart and understand how it works:

The first panel is the price chart with the red arrows as sell signals and the green arrows as buy signals.

The second panel is the RSI indicator. Remember, we buy at 30 and sell at 70.

The third panel is the Bollinger spread with 2.00 standard deviation of the spread. This is to measure the approximate state of the market. Hence, if the spread is greater than its upper deviation or lower than its lower deviation while having a signal from the RSI, we do not take it. This is shown by the two vertical black lines on the graph where we had a signal from the RSI but the spread (in the third panel) was bigger than its deviation. Now, we’re off to compare our initial RSI results with the new modified range-bound strategy results:

Visibly, the results are much better. They are still not worthy of the “great strategy” title, but the Bollinger spread filter improved the results, proving that getting closer to detect the market state will enhance your trading results.

Unlike many other posts and articles that will give you the holy grail strategy and promise you great wealth, I’m in the business of demystifying and finding consistent risk-adjusted profitable strategies that actually work. And to do that, we must build the strategy block by block, not expect a machine learning code that will trade for us and make us rich overnight, that’s just clickbait. I advise you to try them out to see the disappointing results yourself. Ever wondered why they post them to the public? Is it because they work or because they don’t? I’ll let you reflect on that.