An Oscillator of Moving Average is an interesting transformation that can be used as confirmation in trading. It is very versatile and can be used with the majority of technical indicators. In this article, we will apply the Oscillator of Moving Average transformation on two known indicators and then see how it should be used properly.
If you are interested by contrarian strategies, be sure to check out the below article I have recently published:
The Relative Strength Index
The RSI is without a doubt the most famous momentum indicator out there, and this is to be expected as it has many strengths especially in ranging markets. It is also bounded between 0 and 100 which makes it easier to interpret. Also, the fact that it is famous, contributes to its potential.
This is because, the more traders and portfolio managers look at the RSI, the more people will react based on its signals and this in turn can push market prices. Of course, we cannot prove this idea, but it is intuitive as one of the basis of Technical Analysis is that it is self-fulfilling.
The RSI is calculated using a rather simple way. We first start by taking price differences of one period. This means that we have to subtract every closing price from the one before it. Then, we will calculate the smoothed average of the positive differences and divide it by the smoothed average of the negative differences. The last calculation gives us the Relative Strength which is then used in the RSI formula to be transformed into a measure between 0 and 100.
def rsi(Data, rsi_lookback, what1, what2):
rsi_lookback = (rsi_lookback * 2) - 1 # From exponential to smoothed
# Get the difference in price from previous step
delta = 
for i in range(len(Data)):
diff = Data[i, what1] - Data[i - 1, what1]
delta = np.append(delta, diff)
delta = np.insert(delta, 0, 0, axis = 0)
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
up = np.array(up)
down = np.array(down)
roll_up = up
roll_down = down
roll_up = np.reshape(roll_up, (-1, 1))
roll_down = np.reshape(roll_down, (-1, 1))
roll_up = adder(roll_up, 3)
roll_down = adder(roll_down, 3)
roll_up = ema(roll_up, 2, rsi_lookback, what2, 1)
roll_down = ema(abs(roll_down), 2, rsi_lookback, what2, 1)
roll_up = roll_up[rsi_lookback:, 1:2]
roll_down = roll_down[rsi_lookback:, 1:2]
Data = Data[rsi_lookback + 1:,]
# Calculate the RSI based on SMA
RS = roll_up / roll_down
RSI = (100.0 - (100.0 / (1.0 + RS)))
RSI = np.array(RSI)
RSI = np.reshape(RSI, (-1, 1))
RSI = RSI[1:,]
Data = np.concatenate((Data, RSI), axis = 1)return Data
The Oscillator of Moving Average — The RSI Case
The Oscillator of Moving Average — OsMA is the distance between the Indicator such as the RSI and its moving average. Hence, it is a measure of normality and can be used in many ways in trading. Let us check out the mathematical formula of the OsMA:
For a 9-period moving average on the standard 14-period Relative Strength Indicator, we can use the following code snippet:
osma = 9def ma(Data, lookback, what, where):
for i in range(len(Data)):
Data[i, where] = (Data[i - lookback + 1:i + 1, what].mean())
return Datamy_ohlc_data = ma(my_ohlc_data, osma, rsi_column, where_to_put_ma)
And now to transform it into the Oscillator of Moving Average, we can simply write a line of code that subtracts the 9-period moving average from the 14-period Relative Strength Index.
my_ohlc_data[:, new] = my_ohlc_data[:, rsi] - my_ohlc_data[:, sma]# The code inputs in the new column, the rsi column values minus its simple moving average
Hence, we can brief the steps needed to calculate the OsMA on the RSI as follows:
- Calculate a 14-period RSI on the market price.
- Calculate a 9-period simple moving average on the RSI.
- Subtract the RSI column from its moving average column.
- Plot the results as the Oscillator of Moving Average.
It is worth-mentioning that the most famous OsMA is simply the MACD as it is simply a difference between exponential moving averages.
Now, for the question on how to use this oscillator. We can use it in three ways similar to any momentum indicator:
- Using extreme levels that we can find in many ways. Among those ways is a plain subjective method. For example, we use a boundary of 10 and -10 on the above OsMA.
- Detecting divergences from the market price in a signal of trend exhaustion.
- Surpassing the zero level to confirm a new trend direction. When the OsMA flips from negative to positive, we can say that the RSI has surpassed its descending moving average and is showing that the momentum may be strengthening to the upside. When the OsMA flips from positive to negative, we can say that the RSI has broken its ascending moving average and is showing that the momentum may be accelerating to the downside.
A strategy relying on the subjective 10 and -10 extreme levels can have the signal chart when used on the EURUSD hourly data:
However, I do not recommend trading based on these conditions. This is because the OsMA can only be used as a confirmation indicator which is confirmed by the disappointing back-testing results I have gotten from using this strategy. Let us proceed to applying the same idea on another indicator.
The Stochastic Oscillator
The Stochastic Oscillator seeks to find oversold and overbought zones by incorporating the highs and lows in its calculation. It uses the below formula to calculate its values:
We will create the below function that calculates the Stochastic on an OHLC data:
def stochastic(Data, lookback, what, high, low, where):
for i in range(len(Data)):
Data[i, where] = (Data[i, what] - min(Data[i - lookback + 1:i + 1, low])) / (max(Data[i - lookback + 1:i + 1, high]) - min(Data[i - lookback + 1:i + 1, low]))
Data[:, where] = Data[:, where] * 100
return Data# The Data variable refers to the OHLC array
# The lookback variable refers to the period (5, 14, 21, etc.)
# The what variable refers to the closing price
# The high variable refers to the high price
# The low variable refers to the low price
# The where variable refers to where to put the Oscillator
The above plot shows the GBPUSD values plotted with a 14-period Stochastics. Notice that the indicator will always be bounded between 0 and 100 due to the nature of its normalization function that traps values between the minimum and the maximum. The default parameters that are generally found in trading softwares are of a 14-period Stochastics with some form of smoothing (i.e. applying a moving average on it). It generally has overbought levels at 20 and oversold levels at 80. Some softwares use other parameters.
An overbought level is an area where the market is perceived to be extremely bullish and is bound to consolidate. An oversold level is an area where market is perceived to be extremely bearish and is bound to bounce. Hence, the Stochastic Oscillator is a contrarian indicator that seeks to signal reactions of extreme movements. We should be careful from taking trades based solely on its signals.
The Oscillator of Moving Average — The Stochastic Case
As previously mentioned, the Oscillator of Moving Average — OsMA is the distance between the Indicator and its moving average. In our case, we will be calculating the moving average on the Stochastic Oscillator and then doing the subtraction in order to get the OsMA. Let us use the same lookback periods as before.
When we use the transformation, we can get the following plot:
def indicator_plot_double(Data, first, second, name = '', name_ind = '', window = 250):fig, ax = plt.subplots(2, figsize = (10, 5))
ax.plot(Data[-window:, first], color = 'black', label = name)
ax.plot(Data[-window:, second], color = 'blue', label = name_ind)
ax.legend()indicator_plot_double(my_ohlc_data, closing_price, osma_column, name = 'EURNZD', name_ind = '9-period OsMA', window = 500)
Again, the same conditions apply to trade this oscillator from extreme levels to divergences and flip strategies.
Why was this article written? It is certainly not a spoon-feeding method or the way to a profitable strategy. If you follow my articles, you will notice that I place more emphasize on how to do it instead of here it is and that I also provide functions not full replicable code. In the financial industry, you should combine the pieces yourself from other exogenous information and data, only then, will you master the art of research and trading.