avatarSofien Kaabar, CFA

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

9377

Abstract

hmHiIjmfRTkzr3mKkYg.png"><figcaption></figcaption></figure><figure id="9321"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*ROxyYTBN_DLkyxGzulFj2g.png"><figcaption>EURUSD in the first panel with the Fractal Dimension Index in the second panel.</figcaption></figure><p id="c4fe">Therefore, the code can be adjusted to the following:</p><div id="a51a"><pre><span class="hljs-keyword">def</span> <span class="hljs-title function_">fractal_dimension_index</span>(<span class="hljs-params"><span class="hljs-title class_">Data</span>, lookback, what, where</span>)<span class="hljs-symbol">:</span></pre></div><div id="c52f"><pre>for i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(len(<span class="hljs-keyword">Data</span>)): try: new = <span class="hljs-keyword">Data</span>[i - lookback:i, what]

        <span class="hljs-keyword">Data</span>[i, <span class="hljs-keyword">where</span>] = compute_Hc(<span class="hljs-keyword">Data</span>[i - lookback:i + <span class="hljs-number">1</span>, what])[<span class="hljs-number">0</span>]
        <span class="hljs-keyword">Data</span>[i, <span class="hljs-keyword">where</span>] = <span class="hljs-number">2</span> - <span class="hljs-keyword">Data</span>[i, <span class="hljs-keyword">where</span>]
        
    except ValueError:
        <span class="hljs-keyword">pass</span></pre></div><div id="8b5e"><pre>    <span class="hljs-keyword">return</span> <span class="hljs-keyword">Data</span></pre></div><figure id="ad14"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*hLWrkpClQ_qVSEqv7-2y6Q.png"><figcaption>GBPUSD in the first panel with the Fractal Dimension Index in the second panel.</figcaption></figure><p id="516e">If you are also interested by more technical indicators and using Python to create strategies, then my best-selling book on Technical Indicators may interest you:</p><div id="22e9" class="link-block">
      <a href="https://www.amazon.com/gp/product/B08WZL1PNL/ref=as_li_tl?ie=UTF8&amp;camp=1789&amp;creative=9325&amp;creativeASIN=B08WZL1PNL&amp;linkCode=as2&amp;tag=sofien-20&amp;linkId=e3cb9716bb6a07cf6c8b9fb585412b07">
        <div>
          <div>
            <h2>New Technical Indicators in Python</h2>
            <div><h3>Amazon.com: New Technical Indicators in Python: 9798711128861: Kaabar, Mr Sofien: Books</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*-gKRLKFy98DlWItP)"></div>
          </div>
        </div>
      </a>
    </div><h1 id="56da">Using the Fractal Dimension Index</h1><p id="7986">There is not really a clear trading strategy that can be formed around the Fractal Dimension Index. The best way is to check for extreme lows around 1.25/1.20 to see whether the current move will be broken or not. To put it in clear terms:</p><ul><li><b>Whenever the market is trending down and the Fractal Dimension Index reaches 1.25/1.20, we should be careful as we are probably entering a bottoming phase.</b></li><li><b>Whenever the market is trending up and the Fractal Dimension Index reaches 1.25/1.20, we should be careful as we are probably entering a toppish phase.</b></li></ul><figure id="c665"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*8FrWmXrT139a8xCIj87s4w.png"><figcaption>Signal chart on the EURUSD generated following the signals from the Fractal Dimension Index.</figcaption></figure><figure id="9040"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*vt74dhKeNAqukkCiL0j1sg.png"><figcaption>Signal chart on the GBPUSD generated following the signals from the Fractal Dimension Index.</figcaption></figure><p id="e0f7">Obviously, the index must be tweaked so that it delivers more signals. The main tweaks are the barriers and the addition of other technical indicators.</p><div id="f48b"><pre><span class="hljs-symbol">def</span> signal(<span class="hljs-meta">Data</span>, fdi, trend, buy, sell):

for i in range(len(<span class="hljs-meta">Data</span>)):

 <span class="hljs-meta">if</span> <span class="hljs-meta">Data</span>[i, fdi] &lt; lower_barrier <span class="hljs-keyword">and</span> <span class="hljs-meta">Data</span>[i, what] &lt; <span class="hljs-meta">Data</span>[i - trend, what] <span class="hljs-keyword">and</span> <span class="hljs-meta">Data</span>[i - <span class="hljs-number">1</span>, fdi] &gt; lower_barrier:
        <span class="hljs-meta">Data</span>[i, buy] = <span class="hljs-number">1</span>
        
 <span class="hljs-meta">if</span> <span class="hljs-meta">Data</span>[i, fdi] &lt; lower_barrier <span class="hljs-keyword">and</span> <span class="hljs-meta">Data</span>[i, what] &gt; <span class="hljs-meta">Data</span>[i - trend, what] <span class="hljs-keyword">and</span> <span class="hljs-meta">Data</span>[i - <span class="hljs-number">1</span>, fdi] &gt; lower_barrier:
        <span class="hljs-meta">Data</span>[i, sell] = -<span class="hljs-number">1</span></pre></div><div id="03b0"><pre><span class="hljs-comment"># The trend variable is to help the algorithm know whether the market has been trending up or down</span></pre></div><h1 id="4fd4">A Throwback to the Hurst Exponent</h1><p id="b688">How can we use the Hurst Exponent in trading, considering it does not have predictive properties?</p><p id="cdc7">Assume you have a performance period to assess after having used a strategy or model that comes from the family of trend-following systems and then you look at the Hurst of the performance period of the asset only to notice that is around 0.389 making it a mean-reverting time period. You can conclude that you cannot say the strategy used is bad, but that the market structure of the performance period was not convenient to the model and thus it is better to test it on a a trending market in order to fully know its profitability. What you know for sure is that the strategy you have is not adapted to all types of markets and that is already a useful information extracted from the Hurst.</p><h1 id="b7ce">A Similar Tool: The Fractal Indicator</h1><p id="000d">In a previous article, we have discussed the Fractal Indicator which is different from the one discussed above. British hydrologist Harold Edwin Hurst introduced a measure of variability of time series across the period of time analyzed. This measure is called the Rescaled Range Analysis which is the basis of our Fractal Indicator. Here is how to calculate Rescaled Range:</p><figure id="8d29"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/0*sDTT-tYDWgbYTuoQ.jpg"><figcaption></figcaption></figure><p id="b24e">The Rescaled Range formula is very interesting as it takes into account the volatility (<i>S</i>), the mean (<i>X-bar</i>), and the range of the data to analyze its properties. What the above formula says is that, we have to calculate the range between the mini ranges of the maximum and minimum values and then divide them by the Standard Deviation, which in this case is the proxy for volatility.</p><p id="bfef">As I am a perpetual fan of do-it-yourself and tweak-it-yourself, I have modified the formula to have the following sense which we will later see together in a step-by-step method:</p><p id="4a72" type="7">Incorporating the highs and the lows could give us a clearer picture on volatility, which is why we will first calculate an exponential moving average on both the lows and highs for the previous X period and then calculate their respective standard deviation i.e. volatility. Next, we will calculate the first range where we will subtract the current high from the average high measured by the exponential moving average in the first step and then do the same thing with the low. After that, we will calculate a rolling maximum for the first range (the high minus its average) and a rolling minimum for the second range (the low minus its average). Then, we subtract the the high rolling maximum from the low rolling minimum before rescaling by dividing the result by the average between the two standard deviations calculated above for the highs and lows.</p><p id="3867">This is all done using the following function that requires an OHLC array with a few columns to spare:</p><div id="705d"><pre><span class="hljs-attribute">def</span> fractal_indicator(Data, high, low, ema_lookback, min_max_lookback, where):

<span class="hljs-attribute">Data</span> = ema(Data, <span class="hljs-number">2</span>, ema_lookback, high, where)
<span class="hljs-attribute">Data</span> = ema(Data, <span class="hljs-number">2</span>, ema_lookback, low, where + <span class="hljs-number">1</span>)

<span class="hljs-attribute">Data</span> = volatility(Data, ema_lookback, high, where + <span class="hljs-number">2</span>)
<span class="hljs-attribute">Data</span> = volatility(Data, ema_lookback, low, where + <span class="hljs-number">3</span>)

<span class="hljs-attribute">Data</span>[:, where + <span class="hljs-number">4</span>] = Data[:, high] - Data[:, where]
<span class="hljs-attribute">Data</span>[:, where + <span class="hljs-number">5</span>] = Data[:, low]  - Data[:, where + <sp

Options

an class="hljs-number">1</span>]for i in range(len(Data)): <span class="hljs-attribute">try</span>: <span class="hljs-attribute">Data</span>[i, where + <span class="hljs-number">6</span>] = max(Data[i - min_max_lookback + <span class="hljs-number">1</span>:i + <span class="hljs-number">1</span>, where + <span class="hljs-number">4</span>])

    <span class="hljs-attribute">except</span> ValueError:
        <span class="hljs-attribute">pass</span>              
    
<span class="hljs-attribute">for</span> i in range(len(Data)):
    <span class="hljs-attribute">try</span>:
        <span class="hljs-attribute">Data</span>[i, where + <span class="hljs-number">7</span>] = min(Data[i - min_max_lookback + <span class="hljs-number">1</span>:i + <span class="hljs-number">1</span>, where + <span class="hljs-number">5</span>])
    
    <span class="hljs-attribute">except</span> ValueError:
        <span class="hljs-attribute">pass</span>  
     
<span class="hljs-attribute">Data</span>[:, where + <span class="hljs-number">8</span>] =  (Data[:, where +  <span class="hljs-number">2</span>] + Data[:, where +  <span class="hljs-number">3</span>]) / <span class="hljs-number">2</span>
<span class="hljs-attribute">Data</span>[:, where + <span class="hljs-number">9</span>] = (Data[:, where + <span class="hljs-number">6</span>] - Data[:, where + <span class="hljs-number">7</span>]) / Data[:, where + <span class="hljs-number">8</span>]

<span class="hljs-attribute">return</span> Data</pre></div><blockquote id="dd16"><p><i>So, it becomes clear, the Fractal Indicator is simply a reformed version of the Rescaled Range formula created by Harold Hurst.</i></p></blockquote><p id="649e">If you want to add columns to your array, you can use the below function:</p><div id="dae5"><pre>def adder(<span class="hljs-keyword">Data</span>, times):

for i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">1</span>, times + <span class="hljs-number">1</span>):

    z = np.zeros((len(<span class="hljs-keyword">Data</span>), <span class="hljs-number">1</span>), dtype = <span class="hljs-built_in">float</span>)
    <span class="hljs-keyword">Data</span> = np.append(<span class="hljs-keyword">Data</span>, z, axis = <span class="hljs-number">1</span>)<span class="hljs-keyword">return</span> <span class="hljs-keyword">Data</span></pre></div><figure id="f23b"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/0*smNAM4IiCsCDf3Br.png"><figcaption>EURUSD Hourly Data in the first panel and the Fractal Indicator(20, 14) in the second panel.</figcaption></figure><p id="02ec">We have to understand how to use the Fractal Indicator. From charting, it is clear that we can find extreme values around the lower extremity which is 1.00 (or slightly lower depending on the parameters used below). We can call this, <i>the</i> <i>Fractal Threshold.</i></p><p id="d8f1">Hence, a reasonable trading strategy can have the following conditions:</p><ul><li><b>Every time the Fractal Indicator reaches the 1.00 threshold while the market price has been trending downwards, we can expect that there will be a structural break in the market price, i.e. a short-term reversal to the upside. We should initiate a long position.</b></li><li><b>Every time the Fractal Indicator reaches the 1.00 threshold while the market price has been trending upwards, we can expect that there will be a structural break in the market price, i.e. a short-term reversal to the downside. We should initiate a short position.</b></li></ul><div id="0f43"><pre>trend = <span class="hljs-number">10</span>

def signal(Data, what, <span class="hljs-keyword">closing, </span><span class="hljs-keyword">buy, </span>sell):

for i in range(len(Data)):
        
 if Data[i, what] &lt; <span class="hljs-keyword">barrier </span><span class="hljs-keyword">and </span>Data[i, <span class="hljs-keyword">closing] </span>&lt; Data[i - trend, <span class="hljs-keyword">closing]:

</span> Data[i, <span class="hljs-keyword">buy] </span>= <span class="hljs-number">1</span>

 if Data[i, what] &lt; <span class="hljs-keyword">barrier </span><span class="hljs-keyword">and </span>Data[i, <span class="hljs-keyword">closing] </span>&gt; Data[i - trend, <span class="hljs-keyword">closing]: </span> 
    Data[i, sell] = -<span class="hljs-number">1</span></pre></div><div id="37d6"><pre><span class="hljs-comment"># The trend variable is the algorithm's way to see whether the market price has been trending down or up. This is to known what position to initiate (long/short) as the Fractal Indicator only shows a uniform signal which is the event of reaching 1.00</span>

<span class="hljs-comment"># The Data variable refers to the OHLC array</span> <span class="hljs-comment"># The what variable refers to the Fractal Indicator</span> <span class="hljs-comment"># The closing variable refers to the closing price</span> <span class="hljs-comment"># The buy variable refers to where we should place long orders</span> <span class="hljs-comment"># The sell variable refers to where we should place short orders</span></pre></div><p id="5b7f">It is worth noting that we can develop a miniature nomenclature to describe the Fractal Indicator. Notice how we have two variables, the lookback period on the exponential moving average and the lookback period on the normalization range period:</p><ul><li><b>The first variable is simply the moving average’s calculation period.</b></li><li><b>The second variable is simply the range’s observation period.</b></li></ul><p id="b146">Hence, a Fractal Indicator with an exponential moving average period of 20 and a normalization lookback period of 14 can be written as <b>FI(20, 14)</b>.</p><figure id="7766"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/0*SVp-_ZWBpeYUx6Fk.png"><figcaption>USDCHF M15 Data in the first panel and the Fractal Indicator(20, 14) in the second panel.</figcaption></figure><p id="1cb4">We need the Exponential Moving Average function for the above indicator to work. It can be found here:</p><div id="b422"><pre>def ma(<span class="hljs-keyword">Data</span>, lookback, what, <span class="hljs-keyword">where</span>):

for i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</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 - lookback + <span class="hljs-number">1</span>:i + <span class="hljs-number">1</span>, what].mean())
    
        except IndexError:
            <span class="hljs-keyword">pass</span>
<span class="hljs-keyword">return</span> <span class="hljs-keyword">Data</span></pre></div><div id="4989"><pre>def ema(<span class="hljs-type">Data</span>, alpha, lookback, what, where):

<span class="hljs-comment"># alpha is the smoothing factor</span>
<span class="hljs-comment"># window is the lookback period</span>
<span class="hljs-comment"># what is the column that needs to have its average calculated</span>
<span class="hljs-comment"># where is where to put the exponential moving average</span>

alpha = alpha / (lookback + <span class="hljs-number">1.0</span>)
beta  = <span class="hljs-number">1</span> - alpha

<span class="hljs-comment"># First value is a simple SMA</span>
<span class="hljs-type">Data</span> = ma(<span class="hljs-type">Data</span>, lookback, what, where)

<span class="hljs-comment"># Calculating first EMA</span>
<span class="hljs-type">Data</span>[lookback + <span class="hljs-number">1</span>, where] = (<span class="hljs-type">Data</span>[lookback + <span class="hljs-number">1</span>, what] * alpha) + (<span class="hljs-type">Data</span>[lookback, where] * beta)</pre></div><div id="2360"><pre>    # Calculating the rest of EMA
for i <span class="hljs-keyword">in</span> <span 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><h1 id="0987">Conclusion</h1><p id="1eea">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 <b>how to do it</b> instead of <b>here it is </b>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.</p><p id="8118">I always advise you to do the proper back-tests and understand any risks relating to trading.</p></article></body>

The Fractal Dimension Index on Predicting Market Tops & Bottoms

Coding a Variation of the Fractal Dimension Index.

www.pxfuel.com

Markets are fractal in nature meaning they possess certain properties such as self-similarity that allows them to be modelled using tools from this field. Of course, this is easier said than done. In this article, we will try to develop the Fractal Dimension Index from the Hurst Exponent function in order to see how we can predict when market trends are about to break. We will first start by introducing and coding the Hurst Exponent before moving on to the Fractal Dimension Index.

I have just published a new book after the success of New Technical Indicators in Python. It features a more complete description and addition of complex trading strategies with a Github page dedicated to the continuously updated code. If you feel that this interests you, feel free to visit the below link, or if you prefer to buy the PDF version, you could contact me on Linkedin.

The Hurst Exponent

Financial assets alternate between momentum and mean-reversion as regimes and business cycles change. One way to know whether markets are mean-reverting or trending (thus momentum is prevailing) is to use the Hurst Exponent.

The three general types of financial data that can be observed are; trending, mean-reverting, and random walk.

  • A Trending time series is one that increases or decreases over time. The main characteristic is positive autocorrelation.
  • A Mean-reverting time series is one that fluctuates around its long-term equilibrium. The main characteristic is negative autocorrelation.
  • A Random Walk time series is one that moves randomly over time. The main characteristic is zero autocorrelation.

The Random Walk theory is the foundation of quantitative finance and is one of the first things a practitioner should understand. Financial data are assumed to follow a random walk and that implies that price movements are random and cannot be forecasted using their past values. Our aim here is to understand which of the three types is the main characteristic of our analyzed data and that question can be answered through the Hurst exponent.

To briefly define this metric, it has been created by British hydrologist, Edwin Hurst during a study on the Nile river in Egypt. We can interpret it in the following three ways:

  • Whenever H < 0.5, then we can say that our data is mean-reverting.
  • Whenever H =0.5, then we can say that our data is random.
  • Whenever H >0.5, then we can say that our data is trending in nature.
Hurst = 0.4978.
Hurst = 0.0016.
Hurst = 0.9488.

If we calculate the Hurst Exponent on real world data, for example the S&P500 index between 2007 and 2019, we find that it is around 0.43. Does this mean that the index is mean-reverting?

Not necessarily, the calculated value is from the 2007–2019 period and has a range of 30 values which may not capture the whole story. The true value should lie between 0.49 and 0.51 which is closer to a random walk with a pinch of determinism. We cannot negate the possibility that the S&P500 follows no specific pattern whatsoever and although we know that it does from time to time (mostly trending), we merely want to learn how to use the Hurst exponent for quick statistical tests granted we use quality data and optimal parameters such as taking relevant time periods. Another real example is the US M2 money supply. Naturally, it is always upwards sloping.

Hurst = 0.7445.

It is apparent that it is trending overtime, but what does the exponent say? According to the results shown, the Hurst exponent is around 0.744 which is an indication of a highly trending series. Mathematically speaking, the Hurst exponent revolves around the idea of using the variance of a log price series to determine the diffusion. What the function does is compare the diffusion of a time series to that of a geometric Brownian motion, in other words, if the data possesses autocorrelation then the below relationship will not hold and can be modified to include a value of 2H, which is actually the Hurst exponent:

If H = 0.5, then the equation would reduce to the below:

That is the rate of diffusion of a geometric Brownian motion. Tau (𝛕) denotes time and it is equal to the variance at a longer time horizon. The geometric Brownian motion dictates that the variance is equal to the time horizon when it is large enough. It becomes clear now why we say that when the Hurst exponent equals 0.5, we have a random time series.

To calculate a rolling measure of the Hurst Exponent, we need to first install the library:

pip install hurst

Next, we can create the function as below:

from hurst import compute_Hc
def hurst(Data, lookback, what, where):
for i in range(len(Data)):
        try:
            new = Data[i - lookback:i, what]
            
            Data[i, where] = compute_Hc(Data[i - lookback:i + 1, what])[0]
        except ValueError:
            pass
        
    return Data
# Using the Function
my_data = hurst(my_data, 100, 3, 4)
EURUSD in the first panel with the Hurst Exponent in the second panel.

Whenever the market starts to trend, its Hurst Exponent starts to rise due to persistency until markets start to consolidate which is when the Hurst starts dropping. The idea of detecting tops in the Hurst to detect market turning points seems reasonable but in practice, it is not very useful as the Hurst does not really follow a clear stationary pattern. Yesterday’s 0.60 barrier is today’s meaningless level.

The Fractal Dimension Index

The index measures how irregular the time series is. When there is a strong trend going on, naturally, the market price is approaching a one-dimensional line and the Fractal Dimension Index approaches 1.0. When the market is choppy and moving sideways, the Fractal Dimension Index approaches 2.0.

The Fractal Dimension can be easily calculated from the Hurst Exponent using the following formula:

EURUSD in the first panel with the Fractal Dimension Index in the second panel.

Therefore, the code can be adjusted to the following:

def fractal_dimension_index(Data, lookback, what, where):
for i in range(len(Data)):
        try:
            new = Data[i - lookback:i, what]
            
            Data[i, where] = compute_Hc(Data[i - lookback:i + 1, what])[0]
            Data[i, where] = 2 - Data[i, where]
            
        except ValueError:
            pass
    return Data
GBPUSD in the first panel with the Fractal Dimension Index in the second panel.

If you are also interested by more technical indicators and using Python to create strategies, then my best-selling book on Technical Indicators may interest you:

Using the Fractal Dimension Index

There is not really a clear trading strategy that can be formed around the Fractal Dimension Index. The best way is to check for extreme lows around 1.25/1.20 to see whether the current move will be broken or not. To put it in clear terms:

  • Whenever the market is trending down and the Fractal Dimension Index reaches 1.25/1.20, we should be careful as we are probably entering a bottoming phase.
  • Whenever the market is trending up and the Fractal Dimension Index reaches 1.25/1.20, we should be careful as we are probably entering a toppish phase.
Signal chart on the EURUSD generated following the signals from the Fractal Dimension Index.
Signal chart on the GBPUSD generated following the signals from the Fractal Dimension Index.

Obviously, the index must be tweaked so that it delivers more signals. The main tweaks are the barriers and the addition of other technical indicators.

def signal(Data, fdi, trend, buy, sell):
    
  for i in range(len(Data)):
            
     if Data[i, fdi] < lower_barrier and Data[i, what] < Data[i - trend, what] and Data[i - 1, fdi] > lower_barrier:
            Data[i, buy] = 1
            
     if Data[i, fdi] < lower_barrier and Data[i, what] > Data[i - trend, what] and Data[i - 1, fdi] > lower_barrier:
            Data[i, sell] = -1
# The trend variable is to help the algorithm know whether the market has been trending up or down

A Throwback to the Hurst Exponent

How can we use the Hurst Exponent in trading, considering it does not have predictive properties?

Assume you have a performance period to assess after having used a strategy or model that comes from the family of trend-following systems and then you look at the Hurst of the performance period of the asset only to notice that is around 0.389 making it a mean-reverting time period. You can conclude that you cannot say the strategy used is bad, but that the market structure of the performance period was not convenient to the model and thus it is better to test it on a a trending market in order to fully know its profitability. What you know for sure is that the strategy you have is not adapted to all types of markets and that is already a useful information extracted from the Hurst.

A Similar Tool: The Fractal Indicator

In a previous article, we have discussed the Fractal Indicator which is different from the one discussed above. British hydrologist Harold Edwin Hurst introduced a measure of variability of time series across the period of time analyzed. This measure is called the Rescaled Range Analysis which is the basis of our Fractal Indicator. Here is how to calculate Rescaled Range:

The Rescaled Range formula is very interesting as it takes into account the volatility (S), the mean (X-bar), and the range of the data to analyze its properties. What the above formula says is that, we have to calculate the range between the mini ranges of the maximum and minimum values and then divide them by the Standard Deviation, which in this case is the proxy for volatility.

As I am a perpetual fan of do-it-yourself and tweak-it-yourself, I have modified the formula to have the following sense which we will later see together in a step-by-step method:

Incorporating the highs and the lows could give us a clearer picture on volatility, which is why we will first calculate an exponential moving average on both the lows and highs for the previous X period and then calculate their respective standard deviation i.e. volatility. Next, we will calculate the first range where we will subtract the current high from the average high measured by the exponential moving average in the first step and then do the same thing with the low. After that, we will calculate a rolling maximum for the first range (the high minus its average) and a rolling minimum for the second range (the low minus its average). Then, we subtract the the high rolling maximum from the low rolling minimum before rescaling by dividing the result by the average between the two standard deviations calculated above for the highs and lows.

This is all done using the following function that requires an OHLC array with a few columns to spare:

def fractal_indicator(Data, high, low, ema_lookback, min_max_lookback, where):
    
    Data = ema(Data, 2, ema_lookback, high, where)
    Data = ema(Data, 2, ema_lookback, low, where + 1)
    
    Data = volatility(Data, ema_lookback, high, where + 2)
    Data = volatility(Data, ema_lookback, low, where + 3)
    
    Data[:, where + 4] = Data[:, high] - Data[:, where]
    Data[:, where + 5] = Data[:, low]  - Data[:, where + 1]for i in range(len(Data)):
        try:
            Data[i, where + 6] = max(Data[i - min_max_lookback + 1:i + 1, where + 4])
        
        except ValueError:
            pass              
        
    for i in range(len(Data)):
        try:
            Data[i, where + 7] = min(Data[i - min_max_lookback + 1:i + 1, where + 5])
        
        except ValueError:
            pass  
         
    Data[:, where + 8] =  (Data[:, where +  2] + Data[:, where +  3]) / 2
    Data[:, where + 9] = (Data[:, where + 6] - Data[:, where + 7]) / Data[:, where + 8]
    
    return Data

So, it becomes clear, the Fractal Indicator is simply a reformed version of the Rescaled Range formula created by Harold Hurst.

If you want to add columns to your array, you can use the below function:

def adder(Data, times):
    
    for i in range(1, times + 1):
    
        z = np.zeros((len(Data), 1), dtype = float)
        Data = np.append(Data, z, axis = 1)return Data
EURUSD Hourly Data in the first panel and the Fractal Indicator(20, 14) in the second panel.

We have to understand how to use the Fractal Indicator. From charting, it is clear that we can find extreme values around the lower extremity which is 1.00 (or slightly lower depending on the parameters used below). We can call this, the Fractal Threshold.

Hence, a reasonable trading strategy can have the following conditions:

  • Every time the Fractal Indicator reaches the 1.00 threshold while the market price has been trending downwards, we can expect that there will be a structural break in the market price, i.e. a short-term reversal to the upside. We should initiate a long position.
  • Every time the Fractal Indicator reaches the 1.00 threshold while the market price has been trending upwards, we can expect that there will be a structural break in the market price, i.e. a short-term reversal to the downside. We should initiate a short position.
trend = 10
def signal(Data, what, closing, buy, sell):
    
    for i in range(len(Data)):
            
     if Data[i, what] < barrier and Data[i, closing] < Data[i - trend, closing]:
        Data[i, buy] = 1
            
     if Data[i, what] < barrier and Data[i, closing] > Data[i - trend, closing]:  
        Data[i, sell] = -1
# The trend variable is the algorithm's way to see whether the market price has been trending down or up. This is to known what position to initiate (long/short) as the Fractal Indicator only shows a uniform signal which is the event of reaching 1.00
# The Data variable refers to the OHLC array
# The what variable refers to the Fractal Indicator
# The closing variable refers to the closing price
# The buy variable refers to where we should place long orders
# The sell variable refers to where we should place short orders

It is worth noting that we can develop a miniature nomenclature to describe the Fractal Indicator. Notice how we have two variables, the lookback period on the exponential moving average and the lookback period on the normalization range period:

  • The first variable is simply the moving average’s calculation period.
  • The second variable is simply the range’s observation period.

Hence, a Fractal Indicator with an exponential moving average period of 20 and a normalization lookback period of 14 can be written as FI(20, 14).

USDCHF M15 Data in the first panel and the Fractal Indicator(20, 14) in the second panel.

We need the Exponential Moving Average function for the above indicator to work. It can be found here:

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 Data
def ema(Data, alpha, lookback, what, where):
    
    # alpha is the smoothing factor
    # window is the lookback period
    # what is the column that needs to have its average calculated
    # where is where to put the exponential moving average
    
    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

Conclusion

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.

I always advise you to do the proper back-tests and understand any risks relating to trading.

Data Science
Machine Learning
Artificial Intelligence
Trading
Finance
Recommended from ReadMedium