avatarSofien Kaabar, CFA

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

8205

Abstract

an class="hljs-built_in">range</span>(lookback + <span class="hljs-number">2</span>, len(<span class="hljs-keyword">Data</span>)): try: <span class="hljs-keyword">Data</span>[i, <span class="hljs-keyword">where</span>] = (<span class="hljs-keyword">Data</span>[i, what] * alpha) + (<span class="hljs-keyword">Data</span>[i - <span class="hljs-number">1</span>, <span class="hljs-keyword">where</span>] * beta)

        except IndexError:
            <span class="hljs-keyword">pass</span>
        
<span class="hljs-keyword">return</span> <span class="hljs-keyword">Data</span></pre></div><div id="0f96"><pre>def macd(<span class="hljs-keyword">Data</span>, what, long_ema, short_ema, signal_ema, <span class="hljs-keyword">where</span>):

<span class="hljs-keyword">Data</span> = adder(<span class="hljs-keyword">Data</span>, <span class="hljs-number">1</span>)

<span class="hljs-keyword">Data</span> = ema(<span class="hljs-keyword">Data</span>, <span class="hljs-number">2</span>, long_ema,  what, <span class="hljs-keyword">where</span>)
<span class="hljs-keyword">Data</span> = ema(<span class="hljs-keyword">Data</span>, <span class="hljs-number">2</span>, short_ema, what, <span class="hljs-keyword">where</span> + <span class="hljs-number">1</span>)

<span class="hljs-keyword">Data</span>[:, <span class="hljs-keyword">where</span> + <span class="hljs-number">2</span>] = <span class="hljs-keyword">Data</span>[:, <span class="hljs-keyword">where</span> + <span class="hljs-number">1</span>] - <span class="hljs-keyword">Data</span>[:, <span class="hljs-keyword">where</span>]</pre></div><div id="d213"><pre><span class="hljs-keyword">Data</span> = jump(<span class="hljs-keyword">Data</span>, long_ema)
<span class="hljs-keyword">Data</span> = ema(<span class="hljs-keyword">Data</span>, <span class="hljs-number">2</span>, signal_ema, <span class="hljs-keyword">where</span> + <span class="hljs-number">2</span>, <span class="hljs-keyword">where</span> + <span class="hljs-number">3</span>)

<span class="hljs-keyword">Data</span> = deleter(<span class="hljs-keyword">Data</span>, <span class="hljs-keyword">where</span>, <span class="hljs-number">2</span>)   
<span class="hljs-keyword">Data</span> = jump(<span class="hljs-keyword">Data</span>, signal_ema)

<span class="hljs-keyword">return</span> <span class="hljs-keyword">Data</span></pre></div><p id="0347">As a reminder, the MACD line is the difference between the two exponential moving averages which is plotted as histograms in green and red. The MACD signal is simply the 9-period exponential moving average of the MACD line.</p><h1 id="c32c">The Stochastic Oscillator</h1><p id="c94f">The first concept to understand with the Stochastic Oscillator is normalization. This technique allows us to trap values between 0 and 1 (or 0 and 100 if we wish to multiply by 100). The concept revolves around subtracting the minimum value in a certain lookback period from the current value and dividing by the maximum value in the same lookback period minus the minimum value (the same in the nominator).</p><figure id="e77c"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/0*PhCSlaERyAU-nSKq.png"><figcaption></figcaption></figure><p id="e15b">The Stochastic Oscillator<b> </b>seeks to find oversold and overbought zones by incorporating the highs and lows using the normalization formula as shown below:</p><figure id="2381"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/0*YF4JWXSzgQ0qiFNs.png"><figcaption></figcaption></figure><p id="2422">An <b>overbought </b>level is an area where the market is perceived to be extremely bullish and is bound to consolidate. An <b>oversold </b>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 will create the below function that calculates the Stochastic on an OHLC data:</p><div id="e3e2"><pre>def stochastic(Data, lookback, high, low, <span class="hljs-keyword">close</span>, <span class="hljs-keyword">where</span>, genre <span class="hljs-operator">=</span> <span class="hljs-string">'High-Low'</span>):
    
# Adding a <span class="hljs-keyword">column</span>
Data <span class="hljs-operator">=</span> adder(Data, <span class="hljs-number">1</span>)

if genre <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-string">'High-Low'</span>:
    
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-keyword">range</span>(len(Data)):
        
        try:
            Data[i, <span class="hljs-keyword">where</span>] <span class="hljs-operator">=</span> (Data[i, <span class="hljs-keyword">close</span>] <span class="hljs-operator">-</span> <span class="hljs-built_in">min</span>(Data[i <span class="hljs-operator">-</span> lookback <span class="hljs-operator">+</span> <span class="hljs-number">1</span>:i <span class="hljs-operator">+</span> <span class="hljs-number">1</span>, low])) <span class="hljs-operator">/</span> (<span class="hljs-built_in">max</span>(Data[i <span class="hljs-operator">-</span> lookback <span class="hljs-operator">+</span> <span class="hljs-number">1</span>:i <span class="hljs-operator">+</span> <span class="hljs-number">1</span>, high]) <span class="hljs-operator">-</span> <span class="hljs-built_in">min</span>(Data[i <span class="hljs-operator">-</span> lookback <span class="hljs-operator">+</span> <span class="hljs-number">1</span>:i <span class="hljs-operator">+</span> <span class="hljs-number">1</span>, low]))
        
        <span class="hljs-keyword">except</span> ValueError:
            pass
        
if genre <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-string">'Normalization'</span>:
    
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-keyword">range</span>(len(Data)):
        
        try:
            Data[i, <span class="hljs-keyword">where</span>] <span class="hljs-operator">=</span> (Data[i, <span class="hljs-keyword">close</span>] <span class="hljs-operator">-</span> <span class="hljs-built_in">min</span>(Data[i <span class="hljs-operator">-</span> lookback <span class="hljs-operator">+</span> <span class="hljs-number">1</span>:i <span class="hljs-operator">+</span> <span class="hljs-number">1</span>, <span class="hljs-keyword">close</span>])) <span class="hljs-operator">/</span> (<span class="hljs-built_in">max</span>(Data[i <span class="hljs-operator">-</span> lookback <span class="hljs-operator">+</span> <span class="hljs-number">1</span>:i <span class="hljs-operator">+</span> <span class="hljs-number">1</span>, <span class="hljs-keyword">close</span>]) <span class="hljs-operator">-</span> <span class="hljs-built_in">min</span>(Data[i <span class="hljs-operator">-</span> lookback <span class="hljs-operator">+</span> <span class="hljs-number">1</span>:i <span class="hljs-operator">+</span> <span class="hljs-number">1</span>, <span class="hljs-keyword">close</span>]))
        
        <span class="hljs-keyword">except</span> ValueError:
            pass
        
Data[:, <span class="hljs-keyword">where</span>] <span class="hljs-operator">=</span> Data[:, <span class="hljs-keyword">where</span>] <span class="hljs-operator">*</span> <span class="hljs-number">100</span>  
Data <span class="hljs-operator">=</span> jump(Data, lookback)</pre></div><div id="9b94"><pre><span class="hljs-keyword">return</span> <span class="hljs-keyword">Data</span></pre></div><figure id="6a48"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*gC0umy_vYkwsV8cl_76pOQ.png"><figcaption>EURUSD in the first panel with the 70-period Stochastic oscillator.</figcaption></figure><p id="5c94">The above plot shows the EURUSD values plotted with a 70-period Stochastic Oscillator. Notice that the indicator will always be bounded between 0 and 10

Options

0 due to the nature of its normalization function that traps values between the minimum and the maximum.</p><p id="d065">If you are also interested by trend following strategies and indicators, then my other book might interest you:</p><div id="a91e" class="link-block"> <a href="https://www.amazon.com/gp/product/B09KNGG1CC/ref=as_li_tl?ie=UTF8&amp;camp=1789&amp;creative=9325&amp;creativeASIN=B09KNGG1CC&amp;linkCode=as2&amp;tag=sofien-20&amp;linkId=e1bce47813016a38e5d95faf2978a26b"> <div> <div> <h2>Trend Following Strategies in Python: How to Use Indicators to Follow the Trend.</h2> <div><h3>Amazon.com: Trend Following Strategies in Python: How to Use Indicators to Follow the Trend.: 9798756939620: Kaabar…</h3></div> <div><p>www.amazon.com</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*1f_9hczBPtuIGIwT)"></div> </div> </div> </a> </div><h1 id="a706">Creating the Rob Booker Reversal Indicator</h1><p id="ed56">The reversal indicator is an overlay indicator based on arrows created following some rules on the MACD and the Stochastic oscillators:</p><ul><li><b>For a long (Buy) reversal signal, the MACD oscillator with its default parameters must surpass the zero line while the 10-period simple moving average of the 70-period Stochastic oscillator is below the lower barrier 30.</b></li><li><b>For a short (Sell) reversal signal, the MACD oscillator with its default parameters must break the zero line while the 10-period simple moving average of the 70-period Stochastic oscillator is above the upper barrier 70.</b></li></ul><figure id="ce2b"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*RkFRUH4bYUqYNELsEFm1jw.png"><figcaption>USDCHF hourly values with the Rob Booker’s Reversal indicator.</figcaption></figure><div id="1470"><pre><span class="hljs-comment"># Setting parameters</span> <span class="hljs-attr">stoch_lookback</span> = <span class="hljs-number">70</span> <span class="hljs-attr">lower_barrier</span> = <span class="hljs-number">30</span> <span class="hljs-attr">upper_barrier</span> = <span class="hljs-number">70</span></pre></div><div id="ba7c"><pre><span class="hljs-comment"># Calling the 70-period Stochastic oscillator</span> <span class="hljs-attribute">my_data</span> = stochastic(my_data, stoch_lookback, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>)</pre></div><div id="79f3"><pre><span class="hljs-comment"># Calling the 10-period moving average on the Stochastic values</span> <span class="hljs-attribute">my_data</span> = ma(my_data, <span class="hljs-number">10</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>)</pre></div><div id="c9e0"><pre><span class="hljs-comment"># Calling the MACD function</span> <span class="hljs-attribute">my_data</span> = macd(my_data, <span class="hljs-number">3</span>, <span class="hljs-number">26</span>, <span class="hljs-number">12</span>, <span class="hljs-number">9</span>, <span class="hljs-number">6</span>)</pre></div><figure id="8e85"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*Ij1TgtO51hA1t5KMIA7ToQ.png"><figcaption>USDJPY hourly values with the Rob Booker’s Reversal indicator.</figcaption></figure><div id="22d4"><pre><span class="hljs-symbol">def</span> signal(<span class="hljs-meta">Data</span>, stoch_col, macd_col, buy, sell):

<span class="hljs-meta">Data</span> = adder(<span class="hljs-meta">Data</span>, <span class="hljs-number">10</span>)
    
for i in range(len(<span class="hljs-meta">Data</span>)):
        
    <span class="hljs-meta">if</span> <span class="hljs-meta">Data</span>[i, macd_col] &gt; <span class="hljs-number">0</span> <span class="hljs-keyword">and</span> <span class="hljs-meta">Data</span>[i - <span class="hljs-number">1</span>, macd_col] &lt; <span class="hljs-number">0</span> <span class="hljs-keyword">and</span> <span class="hljs-meta">Data</span>[i, stoch_col] &lt; lower_barrier:
           
           <span class="hljs-meta">Data</span>[i, buy] = <span class="hljs-number">1</span>
        
    <span class="hljs-meta">elif</span> <span class="hljs-meta">Data</span>[i, macd_col] &lt; <span class="hljs-number">0</span> <span class="hljs-keyword">and</span> <span class="hljs-meta">Data</span>[i - <span class="hljs-number">1</span>, macd_col] &gt; <span class="hljs-number">0</span> <span class="hljs-keyword">and</span> <span class="hljs-meta">Data</span>[i, stoch_col] &gt; upper_barrier:
                          
           <span class="hljs-meta">Data</span>[i, sell] = -<span class="hljs-number">1</span>
            
return <span class="hljs-meta">Data</span></pre></div><p id="1e4c">The indicator can be found in some charting platforms which is already a recognition that it is accepted among the trading community. However, it is not recommended to use it alone due to its lagging nature.</p><figure id="ac7b"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*9hq1uic83hfRPOwSs0TKiA.png"><figcaption>EURNZD hourly values with the Rob Booker’s Reversal indicator.</figcaption></figure><h1 id="502e">Summary</h1><p id="eca2">To summarize up, what I am trying to do is to simply contribute to the world of objective technical analysis which is promoting more transparent techniques and strategies that need to be back-tested before being implemented. This way, technical analysis will get rid of the bad reputation of being a subjective and scientifically unfounded.</p><p id="f372">Medium is a hub to many interesting reads. I read a lot of articles before I decided to start writing. Consider joining Medium using my referral link!</p><div id="8d75" class="link-block">
      <a href="https://kaabar-sofien.medium.com/membership">
        <div>
          <div>
            <h2>Join Medium with my referral link — Sofien Kaabar</h2>
            <div><h3>As a Medium member, a portion of your membership fee goes to writers you read, and you get full access to every story…</h3></div>
            <div><p>kaabar-sofien.medium.com</p></div>
          </div>
          <div>
            <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*wTy7jI6m2yjI2yho)"></div>
          </div>
        </div>
      </a>
    </div><p id="fac9">I recommend you always follow the the below steps whenever you come across a trading technique or strategy:</p><ul><li>Have a critical mindset and get rid of any emotions.</li><li>Back-test it using real life simulation and conditions.</li><li>If you find potential, try optimizing it and running a forward test.</li><li>Always include transaction costs and any slippage simulation in your tests.</li><li>Always include risk management and position sizing in your tests.</li></ul><p id="9509">Finally, even after making sure of the above, stay careful and monitor the strategy because market dynamics shift and make the strategy unprofitable.</p><p id="1173">For the PDF alternative, the price of the book is <b>9.99 EUR</b>. Please include your email in the note before paying so that you receive it on the right address. Also, once you receive it, make sure to download it through google drive.</p><div id="77c9" class="link-block">
      <a href="https://www.paypal.com/paypalme/sofienkaabar?country.x=FR&amp;locale.x=en_US">
        <div>
          <div>
            <h2>Pay Kaabar using PayPal.Me</h2>
            <div><h3>If you accept cookies, we’ll use them to improve and customize your experience and enable our partners to show you…</h3></div>
            <div><p>www.paypal.com</p></div>
          </div>
          <div>
            <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*bqRtxbPeOt9U97Pn)"></div>
          </div>
        </div>
      </a>
    </div></article></body>

The Reversal Indicator — Coding in Python.

Coding the Rob Booker Reversal Indicator in Python.

www.pxfuel.com

Some less-known indicator actually function pretty well. Among those indicator is Rob Booker’s Reversal Indicator which uses a special combination between the MACD oscillator and the Stochastic oscillator. This article discusses creating the indicator in Python. All credits go to Rob Booker.

I have just released a new book after the success of my previous one “Trend Following Strategies in Python”. It features advanced contrarian indicators and strategies with a GitHub page dedicated to the continuously updated code. Also, this book features the original colors after having optimized for printing costs. If you feel that this interests you, feel free to visit the below Amazon link, or if you prefer to buy the PDF version, you could check the link at the end of the article.

The MACD Oscillator

The MACD is probably the second most known oscillator after the RSI. One that is heavily followed by traders. It stands for Moving Average Convergence Divergence and it is used mainly for divergences and flips. Many people also consider it a trend-following indicator but others use graphical analysis on it to find reversal points, making the MACD a versatile indicator.

USDCHF in the first panel with the MACD in the second panel.

How is the MACD calculated? It is the difference between the 26-period Exponential Moving Average applied to the closing price and the 12-period Exponential Moving Average also applied to the closing price. The value found after taking the difference is called the MACD line. The 9-period Exponential Moving Average of that calculation is called the MACD signal.

EURUSD in the first panel with the MACD in the second panel.
# The function to add a number of columns inside an array
def adder(Data, times):
    
    for i in range(1, times + 1):
    
        new_col = np.zeros((len(Data), 1), dtype = float)
        Data = np.append(Data, new_col, axis = 1)
        
    return Data
# The function to delete a number of columns starting from an index
def deleter(Data, index, times):
    
    for i in range(1, times + 1):
    
        Data = np.delete(Data, index, axis = 1)
        
    return Data
    
# The function to delete a number of rows from the beginning
def jump(Data, jump):
    
    Data = Data[jump:, ]
    
    return Data
# Example of adding 3 empty columns to an array
my_ohlc_array = adder(my_ohlc_array, 3)
# Example of deleting the 2 columns after the column indexed at 3
my_ohlc_array = deleter(my_ohlc_array, 3, 2)
# Example of deleting the first 20 rows
my_ohlc_array = jump(my_ohlc_array, 20)
# Remember, OHLC is an abbreviation of Open, High, Low, and Close and it refers to the standard historical data file
def ma(Data, lookback, close, where): 
    
    Data = adder(Data, 1)
    
    for i in range(len(Data)):
           
            try:
                Data[i, where] = (Data[i - lookback + 1:i + 1, close].mean())
            
            except IndexError:
                pass
            
    # Cleaning
    Data = jump(Data, lookback)
    
    return Data
def ema(Data, alpha, lookback, what, where):
    
    alpha = alpha / (lookback + 1.0)
    beta  = 1 - alpha
    
    # First value is a simple SMA
    Data = ma(Data, lookback, what, where)
    
    # Calculating first EMA
    Data[lookback + 1, where] = (Data[lookback + 1, what] * alpha) + (Data[lookback, where] * beta)
# Calculating the rest of EMA
    for i in range(lookback + 2, len(Data)):
            try:
                Data[i, where] = (Data[i, what] * alpha) + (Data[i - 1, where] * beta)
        
            except IndexError:
                pass
            
    return Data
def macd(Data, what, long_ema, short_ema, signal_ema, where):
    
    Data = adder(Data, 1)
    
    Data = ema(Data, 2, long_ema,  what, where)
    Data = ema(Data, 2, short_ema, what, where + 1)
    
    Data[:, where + 2] = Data[:, where + 1] - Data[:, where]
Data = jump(Data, long_ema)
    Data = ema(Data, 2, signal_ema, where + 2, where + 3)
    
    Data = deleter(Data, where, 2)   
    Data = jump(Data, signal_ema)
    
    return Data

As a reminder, the MACD line is the difference between the two exponential moving averages which is plotted as histograms in green and red. The MACD signal is simply the 9-period exponential moving average of the MACD line.

The Stochastic Oscillator

The first concept to understand with the Stochastic Oscillator is normalization. This technique allows us to trap values between 0 and 1 (or 0 and 100 if we wish to multiply by 100). The concept revolves around subtracting the minimum value in a certain lookback period from the current value and dividing by the maximum value in the same lookback period minus the minimum value (the same in the nominator).

The Stochastic Oscillator seeks to find oversold and overbought zones by incorporating the highs and lows using the normalization formula as shown below:

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 will create the below function that calculates the Stochastic on an OHLC data:

def stochastic(Data, lookback, high, low, close, where, genre = 'High-Low'):
        
    # Adding a column
    Data = adder(Data, 1)
    
    if genre == 'High-Low':
        
        for i in range(len(Data)):
            
            try:
                Data[i, where] = (Data[i, close] - min(Data[i - lookback + 1:i + 1, low])) / (max(Data[i - lookback + 1:i + 1, high]) - min(Data[i - lookback + 1:i + 1, low]))
            
            except ValueError:
                pass
            
    if genre == 'Normalization':
        
        for i in range(len(Data)):
            
            try:
                Data[i, where] = (Data[i, close] - min(Data[i - lookback + 1:i + 1, close])) / (max(Data[i - lookback + 1:i + 1, close]) - min(Data[i - lookback + 1:i + 1, close]))
            
            except ValueError:
                pass
            
    Data[:, where] = Data[:, where] * 100  
    Data = jump(Data, lookback)
return Data
EURUSD in the first panel with the 70-period Stochastic oscillator.

The above plot shows the EURUSD values plotted with a 70-period Stochastic Oscillator. 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.

If you are also interested by trend following strategies and indicators, then my other book might interest you:

Creating the Rob Booker Reversal Indicator

The reversal indicator is an overlay indicator based on arrows created following some rules on the MACD and the Stochastic oscillators:

  • For a long (Buy) reversal signal, the MACD oscillator with its default parameters must surpass the zero line while the 10-period simple moving average of the 70-period Stochastic oscillator is below the lower barrier 30.
  • For a short (Sell) reversal signal, the MACD oscillator with its default parameters must break the zero line while the 10-period simple moving average of the 70-period Stochastic oscillator is above the upper barrier 70.
USDCHF hourly values with the Rob Booker’s Reversal indicator.
# Setting parameters
stoch_lookback = 70
lower_barrier  = 30
upper_barrier  = 70
# Calling the 70-period Stochastic oscillator
my_data = stochastic(my_data, stoch_lookback, 1, 2, 3, 4)
# Calling the 10-period moving average on the Stochastic values
my_data = ma(my_data, 10, 4, 5)
# Calling the MACD function
my_data = macd(my_data, 3, 26, 12, 9, 6)
USDJPY hourly values with the Rob Booker’s Reversal indicator.
def signal(Data, stoch_col, macd_col, buy, sell):
    
    Data = adder(Data, 10)
        
    for i in range(len(Data)):
            
        if Data[i, macd_col] > 0 and Data[i - 1, macd_col] < 0 and Data[i, stoch_col] < lower_barrier:
               
               Data[i, buy] = 1
            
        elif Data[i, macd_col] < 0 and Data[i - 1, macd_col] > 0 and Data[i, stoch_col] > upper_barrier:
                              
               Data[i, sell] = -1
                
    return Data

The indicator can be found in some charting platforms which is already a recognition that it is accepted among the trading community. However, it is not recommended to use it alone due to its lagging nature.

EURNZD hourly values with the Rob Booker’s Reversal indicator.

Summary

To summarize up, what I am trying to do is to simply contribute to the world of objective technical analysis which is promoting more transparent techniques and strategies that need to be back-tested before being implemented. This way, technical analysis will get rid of the bad reputation of being a subjective and scientifically unfounded.

Medium is a hub to many interesting reads. I read a lot of articles before I decided to start writing. Consider joining Medium using my referral link!

I recommend you always follow the the below steps whenever you come across a trading technique or strategy:

  • Have a critical mindset and get rid of any emotions.
  • Back-test it using real life simulation and conditions.
  • If you find potential, try optimizing it and running a forward test.
  • Always include transaction costs and any slippage simulation in your tests.
  • Always include risk management and position sizing in your tests.

Finally, even after making sure of the above, stay careful and monitor the strategy because market dynamics shift and make the strategy unprofitable.

For the PDF alternative, the price of the book is 9.99 EUR. Please include your email in the note before paying so that you receive it on the right address. Also, once you receive it, make sure to download it through google drive.

Data Science
Investing
Finance
Trading
Cryptocurrency
Recommended from ReadMedium