<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Ehlers &#8211; The Financial Hacker</title>
	<atom:link href="https://financial-hacker.com/tag/ehlers/feed/" rel="self" type="application/rss+xml" />
	<link>https://financial-hacker.com</link>
	<description>A new view on algorithmic trading</description>
	<lastBuildDate>Mon, 30 Mar 2026 12:26:00 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://financial-hacker.com/wp-content/uploads/2017/07/cropped-mask-32x32.jpg</url>
	<title>Ehlers &#8211; The Financial Hacker</title>
	<link>https://financial-hacker.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>The One Euro Filter</title>
		<link>https://financial-hacker.com/the-one-euro-filter/</link>
					<comments>https://financial-hacker.com/the-one-euro-filter/#comments</comments>
		
		<dc:creator><![CDATA[Petra Volkova]]></dc:creator>
		<pubDate>Mon, 16 Mar 2026 10:07:33 +0000</pubDate>
				<category><![CDATA[Indicators]]></category>
		<category><![CDATA[Petra on Programming]]></category>
		<category><![CDATA[Ehlers]]></category>
		<category><![CDATA[Indicator]]></category>
		<category><![CDATA[Low-Lag]]></category>
		<guid isPermaLink="false">https://financial-hacker.com/?p=4925</guid>

					<description><![CDATA[Whenever John Ehlers writes about a new indicator, I crack it open and wire it straight into C for the Zorro platform. Or rather, I let ChatGPT do most of the work. The One Euro Filter is a minimalistic, yet surprisingly effective low-latency smoother that reacts instantly to volatility with less lag of the usual &#8230; <a href="https://financial-hacker.com/the-one-euro-filter/" class="more-link">Continue reading<span class="screen-reader-text"> "The One Euro Filter"</span></a>]]></description>
										<content:encoded><![CDATA[<p><em>Whenever <strong>John Ehlers</strong> writes about a new indicator, I crack it open and wire it straight into C for the Zorro platform. Or rather, I let ChatGPT do most of the work. The <strong>One Euro Filter</strong> is a minimalistic, yet surprisingly effective low-latency smoother that reacts instantly to volatility with less lag of the usual adaptive averages. This is achieved by dynamically adapting its time period.</em><span id="more-4925"></span></p>
<p>This is the <strong>OneEurFilter</strong> function in C, converted straight from Ehlers’ EasyLanguage code, the comments left in place:</p>
<pre class="prettyprint">var OneEurFilter(vars Data, int PeriodMin, var Factor)
{
  vars SmoothedDX = series(Data[0],2), 
    Smoothed = series(Data[0],2);
  var Alpha = 2*PI/(4*PI + 10);
//EMA the Delta Price
  SmoothedDX[0] = Alpha*(Data[0]-Data[1]) + (1.-Alpha)*SmoothedDX[1];
//Adjust cutoff period based on a fraction of the rate of change
  var Cutoff = PeriodMin + Factor*abs(SmoothedDX[0]);
//Compute adaptive alpha
  Alpha = 2*PI/(4*PI + Cutoff);
//Adaptive smoothing
  return Smoothed[0] = Alpha*Data[0] + (1.-Alpha)*Smoothed[1];
}</pre>
<p>This is how the OneEurFilter (blue line) looks when applied on a ES chart:</p>
<p><img fetchpriority="high" decoding="async" width="1112" height="571" class="wp-image-4926" src="https://financial-hacker.com/wp-content/uploads/2026/03/word-image-4925-1.png" srcset="https://financial-hacker.com/wp-content/uploads/2026/03/word-image-4925-1.png 1112w, https://financial-hacker.com/wp-content/uploads/2026/03/word-image-4925-1-300x154.png 300w, https://financial-hacker.com/wp-content/uploads/2026/03/word-image-4925-1-1024x526.png 1024w, https://financial-hacker.com/wp-content/uploads/2026/03/word-image-4925-1-768x394.png 768w" sizes="(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px" /></p>
<p>The price curve is well reproduced with almost no lag. Cheap, efficient, low-latency — 1 Euro well spent. The code can be downloaded from the 2026 script repository.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://financial-hacker.com/the-one-euro-filter/feed/</wfw:commentRss>
			<slash:comments>7</slash:comments>
		
		
			</item>
		<item>
		<title>The Cybernetic Oscillator</title>
		<link>https://financial-hacker.com/the-cybernetic-oscillator/</link>
					<comments>https://financial-hacker.com/the-cybernetic-oscillator/#comments</comments>
		
		<dc:creator><![CDATA[Petra Volkova]]></dc:creator>
		<pubDate>Sun, 18 May 2025 16:30:05 +0000</pubDate>
				<category><![CDATA[Indicators]]></category>
		<category><![CDATA[Petra on Programming]]></category>
		<category><![CDATA[Ehlers]]></category>
		<category><![CDATA[Indicator]]></category>
		<guid isPermaLink="false">https://financial-hacker.com/?p=4847</guid>

					<description><![CDATA[Oscillator-type indicators swing around the zero line. They are often used for opening positions when oscillator exceeds a positive or negative threshold. In his article series about no-lag indicators, John Ehlers presents in the TASC June issue the Cybernetic Oscillator. It is built by applying a highpass and afterwards a lowpass filter to the price &#8230; <a href="https://financial-hacker.com/the-cybernetic-oscillator/" class="more-link">Continue reading<span class="screen-reader-text"> "The Cybernetic Oscillator"</span></a>]]></description>
										<content:encoded><![CDATA[<p><em>Oscillator-type indicators swing around the zero line. They are often used for opening positions when oscillator exceeds a positive or negative threshold. In his article series about no-lag indicators, <strong>John Ehlers</strong> presents in the TASC June issue the Cybernetic Oscillator. It is built by applying a highpass and afterwards a lowpass filter to the price curve, then normalizing the result.</em></p>
<p><span id="more-4847"></span></p>
<p>We already know Ehlers’ highpass filter from previous articles. It’s in the Zorro indicator library under the name <strong>HighPass3</strong>. The lowpass filter, Ehlers’ ‘SuperSmoother’, is also in the library, as well as the Sum of Sqares function for normalizing. This makes the Cybernetic Oscillator easy to code in C:</p>
<pre class="prettyprint">var CyberOsc(vars Data,int HPLength,int LPLength)
{
  vars HP = series(HighPass3(Data,HPLength));
  vars LP = series(Smooth(HP,LPLength));
  var RMS = sqrt(SumSq(LP,100)/100);
  return LP[0]/fix0(RMS);
}</pre>
<p>We apply two Cybernetic Oscillators, one with a short and one with a long highpass cutoff, to an S&amp;P500 chart from 2024:</p>
<pre class="prettyprint">void run()
{
  BarPeriod = 1440;
  LookBack = 250;
  StartDate = 20240301;
  EndDate = 20250407;
  asset("SPX500");
  plot("CyberOsc1",CyberOsc(seriesC(),30,20),NEW|LINE,RED);
  plot("CyberOsc2",CyberOsc(seriesC(),250,20),NEW|LINE,BLUE);
}</pre>
<p>The resulting chart replicates Ehler’s chart in the article. The red line reproduces the swings of the price curve, the blue line the long-term trend:</p>
<p><img decoding="async" width="701" height="410" class="wp-image-4848" src="https://financial-hacker.com/wp-content/uploads/2025/05/word-image-4847-1.png" srcset="https://financial-hacker.com/wp-content/uploads/2025/05/word-image-4847-1.png 701w, https://financial-hacker.com/wp-content/uploads/2025/05/word-image-4847-1-300x175.png 300w" sizes="(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px" /></p>
<p>Now we test the Cybernetic Oscillator by using it for a swing trading system. We open positions in the direction of the trend. The code, replicated from Ehlers&#8217; EasyLanguage script:</p>
<pre class="prettyprint">void run()
{
  BarPeriod = 1440;
  LookBack = 250;
  StartDate = 2009;
  EndDate = 2025;
  Fill = 2; // enter at next open
  assetList("AssetsIB"); // simulate IBKR
  asset("SPY");
  vars LP = series(Smooth(seriesC(),20));
  vars BP1 = series(HighPass3(LP,55));
  var ROC1 = BP1[0] - BP1[2];
  vars BP2 = series(HighPass3(LP,156));
  var ROC2 = BP2[0] - BP2[2];

  if(!NumOpenLong &amp;&amp; ROC1 &gt; 0 &amp;&amp; ROC2 &gt; 0)
    enterLong();
  if(NumOpenLong &amp;&amp; (ROC1 &lt; 0 || ROC2 &lt; 0))
    exitLong();
}</pre>
<p>The system is opening a 1-share SPY position without reinvestment. We’re using commission, leverage and other trading parameters from a popular US broker for the simulation. Ehlers had produced his filter parameters with in-sample optimization, so take the result with a grain of salt. This is the equity curve:</p>
<p><img decoding="async" width="701" height="405" class="wp-image-4849" src="https://financial-hacker.com/wp-content/uploads/2025/05/word-image-4847-2.png" srcset="https://financial-hacker.com/wp-content/uploads/2025/05/word-image-4847-2.png 701w, https://financial-hacker.com/wp-content/uploads/2025/05/word-image-4847-2-300x173.png 300w" sizes="(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px" /></p>
<p>Backtesting the same system with walk-forward optimization, for getting a more accurate result, is left as an exercise to the reader. Hint: you need to enter 4 extra lines. Ehlers’ system generates about 180 trades with 60% win rate and profit factor 2. The code can be downloaded from the 2025 script repository on <a href="https://financial-hacker.com">https://financial-hacker.com</a>.</p>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://financial-hacker.com/the-cybernetic-oscillator/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
			</item>
		<item>
		<title>Ehlers&#8217; Ultimate Oscillator</title>
		<link>https://financial-hacker.com/ehlers-ultimate-oscillator/</link>
					<comments>https://financial-hacker.com/ehlers-ultimate-oscillator/#comments</comments>
		
		<dc:creator><![CDATA[Petra Volkova]]></dc:creator>
		<pubDate>Mon, 17 Mar 2025 11:26:37 +0000</pubDate>
				<category><![CDATA[Indicators]]></category>
		<category><![CDATA[Petra on Programming]]></category>
		<category><![CDATA[Ehlers]]></category>
		<category><![CDATA[Indicator]]></category>
		<guid isPermaLink="false">https://financial-hacker.com/?p=4823</guid>

					<description><![CDATA[In his TASC article series about no-lag indicators, John Ehlers presented last month the Ultimate Oscillator.  What&#8217;s so ultimate about it? Unlike other oscillators, it is supposed to indicate the current market direction with almost no lag. The Ultimate Oscillator is built from the difference of two highpass filters. The highpass function below is a &#8230; <a href="https://financial-hacker.com/ehlers-ultimate-oscillator/" class="more-link">Continue reading<span class="screen-reader-text"> "Ehlers&#8217; Ultimate Oscillator"</span></a>]]></description>
										<content:encoded><![CDATA[<p><em>In his TASC article series about no-lag indicators, <strong>John Ehlers</strong> presented last month the <strong>Ultimate Oscillator</strong>.  What&#8217;s so ultimate about it? Unlike other oscillators, it is supposed to indicate the current market direction with almost no lag.</em><span id="more-4823"></span></p>
<p>The Ultimate Oscillator is built from the difference of two highpass filters. The highpass function below is a straightforward conversion of Ehlers&#8217; EasyLanguage code to C:</p>
<pre class="prettyprint">var HighPass3(vars Data,int Period)
{
  var a1 = exp(-1.414*PI / Period);
  var c2 = 2*a1*cos(1.414*PI / Period);
  var c3 = -a1*a1;
  var c1 = (1.+c2-c3) / 4;
  vars HP = series(0,3);
  return HP[0] = c1*(Data[0]-2*Data[1]+Data[2])+c2*HP[1]+c3*HP[2];
}</pre>
<p>The function is named <strong>HighPass3</strong> because we have already 3 other highpass filters in the Zorro indicator library, all with different code. The Ultimate Oscillator is the difference of two highpass filters with different periods, and scaled by its root mean square for converting the output to standard deviations. Fortunately Zorro has already a sum of squares function, which makes the code shorter and simpler than Ehlers’ original:</p>
<pre class="prettyprint">var UltimateOsc(vars Data,int Edge,int Width)
{
  vars Signals = series(HighPass3(Data,Width*Edge)-HighPass3(Data,Edge));
  var RMS = sqrt(SumSq(Signals,100)/100);
  return Signals[0]/fix0(RMS);
}</pre>
<p>For checking its lag and smoothing power, we apply the Ultimate Oscillator to an S&amp;P500 chart from 2024:</p>
<pre class="prettyprint">void run()
{
  BarPeriod = 1440;
  StartDate = 20240101;
  EndDate = 20241231;
  asset("SPX500");
  plot("UltOsc", UltimateOsc(seriesC(),20,2),LINE,RED);
}</pre>
<p>The resulting chart replicates Ehler’s chart in the article. The Oscillator output is the red line:</p>
<p><img loading="lazy" decoding="async" width="701" height="408" class="wp-image-4824" src="https://financial-hacker.com/wp-content/uploads/2025/03/word-image-4823-1.png" srcset="https://financial-hacker.com/wp-content/uploads/2025/03/word-image-4823-1.png 701w, https://financial-hacker.com/wp-content/uploads/2025/03/word-image-4823-1-300x175.png 300w" sizes="auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px" /></p>
<p>We can see that the ultimate oscillator reproduces the market trend remarkably well and with no visible lag. The code can be downloaded from the 2025 script repository.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://financial-hacker.com/ehlers-ultimate-oscillator/feed/</wfw:commentRss>
			<slash:comments>7</slash:comments>
		
		
			</item>
		<item>
		<title>The Ultimate Strength Index</title>
		<link>https://financial-hacker.com/the-ultimate-strength-index/</link>
					<comments>https://financial-hacker.com/the-ultimate-strength-index/#comments</comments>
		
		<dc:creator><![CDATA[Petra Volkova]]></dc:creator>
		<pubDate>Fri, 13 Dec 2024 09:47:55 +0000</pubDate>
				<category><![CDATA[Indicators]]></category>
		<category><![CDATA[Petra on Programming]]></category>
		<category><![CDATA[Ehlers]]></category>
		<category><![CDATA[RSI]]></category>
		<guid isPermaLink="false">https://financial-hacker.com/?p=4776</guid>

					<description><![CDATA[The RSI (Relative Strength Index) is a popular indicator used in many trading systems for filters or triggers. In TASC 12/2024 John Ehlers proposed a replacement for this indicator. His USI (Ultimate Strength Index) has the advantage of symmetry – the range is -1 to 1 – and, especially important, less lag. So it can &#8230; <a href="https://financial-hacker.com/the-ultimate-strength-index/" class="more-link">Continue reading<span class="screen-reader-text"> "The Ultimate Strength Index"</span></a>]]></description>
										<content:encoded><![CDATA[<p><em>The <strong>RSI</strong> (Relative Strength Index) is a popular indicator used in many trading systems for filters or triggers. In TASC 12/2024 John Ehlers proposed a replacement for this indicator. His <strong>USI</strong> (Ultimate Strength Index) has the advantage of symmetry – the range is -1 to 1 – and, especially important, less lag. So it can trigger trades earlier. Like the RSI, it enhances cycles and trends in the data, which makes it well suited for various sorts of trading systems. Let’s look how to realize it in code.</em><span id="more-4776"></span></p>
<p>The USI is based on another indicator by John Ehlers, the <strong>Ultimate Smoother</strong>. It was covered in a previous article. Here’s again its code in C:</p>
<pre class="prettyprint">var UltimateSmoother (var *Data, int Length)
{
  var f = (1.414*PI) / Length;
  var a1 = exp(-f);
  var c2 = 2*a1*cos(f);
  var c3 = -a1*a1;
  var c1 = (1+c2-c3)/4;
  vars US = series(*Data,4);
  return US[0] = (1-c1)*Data[0] + (2*c1-c2)*Data[1] - (c1+c3)*Data[2] + c2*US[1] + c3*US[2];
}</pre>
<p>Similar to the RSI, the Ultimate Strength Index calculates the normalized differences of the ups and downs in the price curve, after no-lag smoothing. Here’s Ehlers’ EasyLanguage code converted to C:</p>
<pre class="prettyprint">var UltimateStrength (int Length)
{
  vars SU = series(max(0,priceC(0) - priceC(1)));
  var USU = UltimateSmooth(series(SMA(SU,4)),Length);
  vars SD = series(max(0,priceC(1) - priceC(0)));
  var USD = UltimateSmooth(series(SMA(SD,4)),Length);
  return (USU-USD)/fix0(USU+USD);
}</pre>
<p>The <strong>fix0</strong> function is a convenience function that corrects possible divisions by zero. For checking the correctness of our conversion, we’re plotting the USI with two different time periods on a SPX chart. The code:</p>
<pre class="prettyprint">void run()
{
  BarPeriod = 1440;
  StartDate = 20230801;
  EndDate = 20240801;
  assetAdd("SPX","STOOQ:^SPX");
  asset("SPX");
  plot("USI(112)",UltimateStrength(112),NEW|LINE,BLUE);
  plot("USI(28)",UltimateStrength(28),NEW|LINE,BLUE);
}</pre>
<p>The resulting chart replicates the ES chart in Ehlers’ article:</p>
<p><img loading="lazy" decoding="async" width="774" height="537" class="wp-image-4777" src="https://financial-hacker.com/wp-content/uploads/2024/12/word-image-4776-1.png" srcset="https://financial-hacker.com/wp-content/uploads/2024/12/word-image-4776-1.png 774w, https://financial-hacker.com/wp-content/uploads/2024/12/word-image-4776-1-300x208.png 300w, https://financial-hacker.com/wp-content/uploads/2024/12/word-image-4776-1-768x533.png 768w" sizes="auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px" /></p>
<p>We can see that the long time frame USI enhances the begin and end of trends, the short time frame USI makes the cycles visible. The code can be downloaded from the 2024 script repository.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://financial-hacker.com/the-ultimate-strength-index/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Ehlers’ Precision Trend Analysis</title>
		<link>https://financial-hacker.com/ehlers-precision-trend-analysis/</link>
					<comments>https://financial-hacker.com/ehlers-precision-trend-analysis/#comments</comments>
		
		<dc:creator><![CDATA[Petra Volkova]]></dc:creator>
		<pubDate>Mon, 19 Aug 2024 08:49:55 +0000</pubDate>
				<category><![CDATA[Indicators]]></category>
		<category><![CDATA[Petra on Programming]]></category>
		<category><![CDATA[Ehlers]]></category>
		<guid isPermaLink="false">https://financial-hacker.com/?p=4735</guid>

					<description><![CDATA[In TASC 8/24, John Ehlers presented a new algorithm for separating the trend line from a price curve, using spectral analysis functions. Trend lines are only useful for trading when they have little lag, so that trend changes can immediately trigger trade signals. The usual suspects like SMA, WMA, EMA are too laggy for this. &#8230; <a href="https://financial-hacker.com/ehlers-precision-trend-analysis/" class="more-link">Continue reading<span class="screen-reader-text"> "Ehlers’ Precision Trend Analysis"</span></a>]]></description>
										<content:encoded><![CDATA[<p><em>In TASC 8/24, <strong>John Ehlers</strong> presented a new algorithm for separating the trend line from a price curve, using spectral analysis functions. Trend lines are only useful for trading when they have little lag, so that trend changes can immediately trigger trade signals. The usual suspects like SMA, WMA, EMA are too laggy for this. Let&#8217;s see how good this new algorithm works. The functions below are a 1:1 conversion from Ehlers&#8217; TradeStation code to C.</em><span id="more-4735"></span></p>
<pre class="prettyprint">var HighPass3(vars Data, int Length)
{
  var f = 1.414*PI/Length;
  var a1 = exp(-f);
  var c2 = 2*a1*cos(f/2);
  var c3 = -a1*a1;
  var c1 = (1+c2-c3)/4;
  vars HP = series(0,4);
  return HP[0] = c1*(Data[0] - 2*Data[1] + Data[2]) + c2*HP[1] + c3*HP[2];
}

var TROC;
var Trend(vars Data,int Length1,int Length2)
{
  var HP1 = HighPass3(Data,Length1);
  var HP2 = HighPass3(Data,Length2);
  vars Trends = series(HP1-HP2,2);
  TROC = (Length2/6.28)*(Trends[0]-Trends[1]);
  return Trends[0];
}</pre>
<p>The filter name is <strong>HighPass3</strong> because Zorro got already threee other highpass filters in its library. We apply the <strong>trend</strong> function to an ES chart from 2022-2024, and plot also the highpass filter and the intermediate TROC variable:</p>
<pre class="prettyprint">void run()
{
  BarPeriod = 1440;
  StartDate = 20221001;
  EndDate = 20240401;
  LookBack = 250;
  assetAdd("ES","YAHOO:ES=F");
  asset("ES");
  plot("HP",HighPass3(seriesC(),250),NEW,RED);
  plot("Trend",Trend(seriesC(),250,40),NEW,RED);
  plot("ROC",TROC,0,BLUE);
}</pre>
<p>The resulting chart:</p>
<p><img loading="lazy" decoding="async" width="873" height="656" class="wp-image-4736" src="https://financial-hacker.com/wp-content/uploads/2024/08/word-image-4735-1.png" srcset="https://financial-hacker.com/wp-content/uploads/2024/08/word-image-4735-1.png 873w, https://financial-hacker.com/wp-content/uploads/2024/08/word-image-4735-1-300x225.png 300w, https://financial-hacker.com/wp-content/uploads/2024/08/word-image-4735-1-768x577.png 768w" sizes="auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px" /></p>
<p>We can see that the red trend line in the bottom chart gives a pretty good approximation of the price curve trend with no noticable lag. The code can be downloaded from the 2024 script repository.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://financial-hacker.com/ehlers-precision-trend-analysis/feed/</wfw:commentRss>
			<slash:comments>6</slash:comments>
		
		
			</item>
		<item>
		<title>Ehlers’ Ultimate Smoother</title>
		<link>https://financial-hacker.com/ehlers-ultimate-smoother/</link>
					<comments>https://financial-hacker.com/ehlers-ultimate-smoother/#comments</comments>
		
		<dc:creator><![CDATA[Petra Volkova]]></dc:creator>
		<pubDate>Fri, 17 May 2024 10:10:01 +0000</pubDate>
				<category><![CDATA[Indicators]]></category>
		<category><![CDATA[Petra on Programming]]></category>
		<category><![CDATA[Ehlers]]></category>
		<category><![CDATA[Smoothing]]></category>
		<guid isPermaLink="false">https://financial-hacker.com/?p=4717</guid>

					<description><![CDATA[In TASC 3/24, John Ehlers presented several functions for smoothing a price curve without lag, smoothing it even more, and applying a highpass and bandpass filter. No-lag smoothing, highpass, and bandpass filters are already available in the indicator library of the Zorro platform, but not Ehlers&#8217; latest invention, the Ultimate Smoother. It achieves its tremendous &#8230; <a href="https://financial-hacker.com/ehlers-ultimate-smoother/" class="more-link">Continue reading<span class="screen-reader-text"> "Ehlers’ Ultimate Smoother"</span></a>]]></description>
										<content:encoded><![CDATA[<p><em>In TASC 3/24, John Ehlers presented several functions for smoothing a price curve without lag, smoothing it even more, and applying a highpass and bandpass filter. No-lag smoothing, highpass, and bandpass filters are already available in the indicator library of the Zorro platform, but not Ehlers&#8217; latest invention, the Ultimate Smoother. It achieves its tremendous smoothing power by subtracting the high frequency components from the price curve, using a highpass filter.</em><span id="more-4717"></span></p>
<p>The function below is a straightforward conversion of Ehlers&#8217; EasyLanguage code to C:</p>
<pre class="prettyprint">var UltimateSmoother (var *Data, int Length)
{
  var f = (1.414*PI) / Length;
  var a1 = exp(-f);
  var c2 = 2*a1*cos(f);
  var c3 = -a1*a1;
  var c1 = (1+c2-c3)/4;
  vars US = series(*Data,4);
  return US[0] = (1-c1)*Data[0] + (2*c1-c2)*Data[1] - (c1+c3)*Data[2]
+ c2*US[1] + c3*US[2];
}</pre>
<p>For comparing lag and smoothing power, we apply the ultimate smoother, the super smoother from Zorro&#8217;s indicator library, and a standard EMA to an ES chart from 2023:</p>
<pre class="prettyprint">void run()
{
  BarPeriod = 1440;
  StartDate = 20230201;
  EndDate = 20231201;
  assetAdd("ES","YAHOO:ES=F");
  asset("ES");
  int Length = 30;
  plot("UltSmooth", UltimateSmoother(seriesC(),Length),LINE,MAGENTA);
  plot("Smooth",Smooth(seriesC(),Length),LINE,RED);
  plot("EMA",EMA(seriesC(),3./Length),LINE,BLUE);}
}</pre>
<p>The resulting chart replicates the ES chart in the article. The EMA is shown in blue, the super smoothing filter in red, and the ultimate smoother in magenta:</p>
<p><img loading="lazy" decoding="async" width="917" height="560" class="wp-image-4718" src="https://financial-hacker.com/wp-content/uploads/2024/05/word-image-4717-1.png" srcset="https://financial-hacker.com/wp-content/uploads/2024/05/word-image-4717-1.png 917w, https://financial-hacker.com/wp-content/uploads/2024/05/word-image-4717-1-300x183.png 300w, https://financial-hacker.com/wp-content/uploads/2024/05/word-image-4717-1-768x469.png 768w" sizes="auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px" /></p>
<p>We can see that the ultimate smoother produces indeed the best, albeit smoothed, representation of the price curve.</p>
<p>In TASC 4/24, Ehlers also presented two band indicators based on his Ultimate Smoother. Band indicators can be used to trigger long or short positions when the price hits the upper or lower band. The first band indicator, the <strong>Ultimate Channel</strong>, is again a straightforward conversion to the C language from Ehlers’ TradeStation code:</p>
<pre class="prettyprint">var UltimateChannel(int Length,int STRLength,int NumSTRs)
{
  var TH = max(priceC(1),priceH());
  var TL = min(priceC(1),priceL());
  var STR = UltimateSmoother(series(TH-TL),STRLength);
  var Center = UltimateSmoother(seriesC(),Length);
  rRealUpperBand = Center + NumSTRs*STR;
  rRealLowerBand = Center - NumSTRs*STR;
  return Center;
}</pre>
<p><strong>rRealUpperBand</strong> and <strong>rRealLowerBand</strong> are pre-defined global variables that are used by band indicators in the indicator library of the Zorro platform. For testing the new indicator, we apply it to an ES chart:</p>
<pre class="prettyprint">void run()
{
  BarPeriod = 1440;
  StartDate = 20230301;
  EndDate = 20240201;
  assetAdd("ES","YAHOO:ES=F");
  asset("ES");
  UltimateChannel(20,20,1);
  plot("UltChannel1",rRealUpperBand,BAND1,BLUE);
  plot("UltChannel2",rRealLowerBand,BAND2,BLUE|TRANSP);
}</pre>
<p>The resulting chart replicates the ES chart in Ehlers’ article:</p>
<p><img loading="lazy" decoding="async" width="1060" height="620" class="wp-image-4721" src="https://financial-hacker.com/wp-content/uploads/2024/05/word-image-4717-1-1.png" srcset="https://financial-hacker.com/wp-content/uploads/2024/05/word-image-4717-1-1.png 1060w, https://financial-hacker.com/wp-content/uploads/2024/05/word-image-4717-1-1-300x175.png 300w, https://financial-hacker.com/wp-content/uploads/2024/05/word-image-4717-1-1-1024x599.png 1024w, https://financial-hacker.com/wp-content/uploads/2024/05/word-image-4717-1-1-768x449.png 768w" sizes="auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px" /></p>
<p>The second band indicator, <strong>Ultimate Bands</strong>, requires less code than Ehlers’ implementation, since lite-C can apply functions to a whole data series:</p>
<pre class="prettyprint">var UltimateBands(int Length,int NumSDs)
{
  var Center = UltimateSmoother(seriesC(),Length);
  vars Diffs = series(priceC()-Center);
  var SD = sqrt(SumSq(Diffs,Length)/Length);
  rRealUpperBand = Center + NumSDs*SD;
  rRealLowerBand = Center - NumSDs*SD; return Center;
}</pre>
<p>Again applied to the ES chart:</p>
<pre class="prettyprint">void run()
{
  BarPeriod = 1440;
  StartDate = 20230301;
  EndDate = 20240201;
  assetAdd("ES","YAHOO:ES=F");
  asset("ES");
  UltimateBands(20,1);
  plot("UltBands1",rRealUpperBand,BAND1,BLUE);
  plot("UltBands2",rRealLowerBand,BAND2,BLUE|TRANSP);
}</pre>
<p><img loading="lazy" decoding="async" width="1060" height="620" class="wp-image-4722" src="https://financial-hacker.com/wp-content/uploads/2024/05/word-image-4717-2.png" srcset="https://financial-hacker.com/wp-content/uploads/2024/05/word-image-4717-2.png 1060w, https://financial-hacker.com/wp-content/uploads/2024/05/word-image-4717-2-300x175.png 300w, https://financial-hacker.com/wp-content/uploads/2024/05/word-image-4717-2-1024x599.png 1024w, https://financial-hacker.com/wp-content/uploads/2024/05/word-image-4717-2-768x449.png 768w" sizes="auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px" /></p>
<p>We can see that both indicators produce relatively similar bands with low lag. The code of the Ultimate Smoother and the bands can be downloaded from the 2024 script repository.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://financial-hacker.com/ehlers-ultimate-smoother/feed/</wfw:commentRss>
			<slash:comments>7</slash:comments>
		
		
			</item>
		<item>
		<title>Undersampling</title>
		<link>https://financial-hacker.com/undersampling/</link>
					<comments>https://financial-hacker.com/undersampling/#comments</comments>
		
		<dc:creator><![CDATA[Petra Volkova]]></dc:creator>
		<pubDate>Sat, 08 Apr 2023 13:09:31 +0000</pubDate>
				<category><![CDATA[Indicators]]></category>
		<category><![CDATA[Petra on Programming]]></category>
		<category><![CDATA[Ehlers]]></category>
		<category><![CDATA[SPY]]></category>
		<guid isPermaLink="false">https://financial-hacker.com/?p=4673</guid>

					<description><![CDATA[All the popular &#8216;smoothing&#8217; indicators, like SMA or lowpass filters, exchange more lag for more smoothing. In TASC 4/2023, John Ehlers suggested the undersampling of price curves for achieving a better compromise between smoothness and lag. We will check that by applying a Hann filter to the original price curve and to a 5-fold undersampled &#8230; <a href="https://financial-hacker.com/undersampling/" class="more-link">Continue reading<span class="screen-reader-text"> "Undersampling"</span></a>]]></description>
										<content:encoded><![CDATA[<p><em>All the popular &#8216;smoothing&#8217; indicators, like SMA or lowpass filters, exchange more lag for more smoothing. In TASC 4/2023, John Ehlers suggested the undersampling of price curves for achieving a better compromise between smoothness and lag. We will check that by applying a Hann filter to the original price curve and to a 5-fold undersampled curve.</em><span id="more-4673"></span></p>
<p>The C code of the used Hann filter, straight from Ehler&#8217;s article:</p>
<pre class="prettyprint">var Hann(vars Data,int Length)
{
  var Filt = 0, Coeff = 0;
  int i; for(i=1; i&lt;=Length; i++) {
    Filt += (1-cos(2*PI*i/(Length+1)))*Data[i-1];
    Coeff += 1-cos(2*PI*i/(Length+1));
  }
  return Filt/fix0(Coeff);
}
</pre>
<p>The <strong>fix0</strong> function in the denominator is a convenience function for fixing division by zero issues.</p>
<p>We will now apply this Hann filter to the undersampled SPY price curve. Undersampling means: Take only every n-th price, and throw the rest away. We use the modulo operator to detect every 5th bar:</p>
<pre class="prettyprint">void run()
{
 StartDate = 20220101;
 EndDate = 20221231;
 BarPeriod = 1440;
 set(PLOTNOW);
 asset("SPY");
 vars Samples = series();
 if(Init || Bar%5 == 0) // sample only every 5th bar
   Samples[0] = priceC(0);
 else
   Samples[0] = Samples[1];
 plot("Hann6",Hann(Samples,6),LINE,MAGENTA);
 plot("Hann12",Hann(Samples,12),LINE,BLUE);
 plot("Hann",Hann(seriesC(),12),0,DARKGREEN);
}
</pre>
<p>The resulting chart:</p>
<p><img decoding="async" src="https://financial-hacker.com/wp-content/uploads/2023/04/040823_1254_Undersampli1.png" alt="" /></p>
<p>The blue line is the Hann filter of the undersampled curve with period 12, the magenta line with period 6. For comparison I&#8217;ve added the Hann filter output from the original curve (thin green line). We can see that the green line has less lag, but is also less smooth. Will using undersampled data improve a trading system? Well&#8230; I guess it depends on the system.</p>
<p>The Hann indicator and undersampling test script can be downloaded from the 2022 script repository.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://financial-hacker.com/undersampling/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>Open or Close? Why Not Both?</title>
		<link>https://financial-hacker.com/open-or-close-why-not-both/</link>
					<comments>https://financial-hacker.com/open-or-close-why-not-both/#comments</comments>
		
		<dc:creator><![CDATA[Petra Volkova]]></dc:creator>
		<pubDate>Mon, 13 Feb 2023 14:25:13 +0000</pubDate>
				<category><![CDATA[Indicators]]></category>
		<category><![CDATA[Petra on Programming]]></category>
		<category><![CDATA[Ehlers]]></category>
		<guid isPermaLink="false">https://financial-hacker.com/?p=4663</guid>

					<description><![CDATA[In his TASC February 2023 article, John Ehlers proposed to use the average of open and close, rather than the close price, for technical indicators. The advantage is a certain amount of noise reduction. On intraday bars the open-close average is similar to an SMA(2). It makes the data a bit smoother, but at cost &#8230; <a href="https://financial-hacker.com/open-or-close-why-not-both/" class="more-link">Continue reading<span class="screen-reader-text"> "Open or Close? Why Not Both?"</span></a>]]></description>
										<content:encoded><![CDATA[<p><em>In his TASC February 2023 article, <strong>John Ehlers</strong> proposed to use the average of open and close, rather than the close price, for technical indicators. The advantage is a certain amount of noise reduction. On intraday bars the open-close average is similar to an SMA(2). It makes the data a bit smoother, but at cost of additional lag by half a bar.</em><span id="more-4663"></span></p>
<p>The script below, in C for the Zorro platform, compares the standard RSI with the open-close average RSI on the S&amp;P 500 index with 15-minute bars:</p>
<pre class="prettyprint">void run()
{
  BarPeriod = 15;
  StartDate = 20220629;
  EndDate = 20220712;
  asset("SPX500");
  vars OC = series((priceO()+priceC())/2);
  plot("RSI(Close)",RSI(seriesC(),14),NEW,RED);
  plot("RSI(OC)",RSI(OC,14),0,BLUE);
}</pre>
<p>We can indeed see some noise reduction in the resulting chart:</p>
<p><img decoding="async" src="https://financial-hacker.com/wp-content/uploads/2023/02/021323_1417_OpenorClose1.png" alt="" /></p>
<p>The obvious question: Will the smoother curve compensate for the additional lag in a trading system? For testing this, I added the following 5 lines to the script:</p>
<pre class="prettyprint">vars RSIs = series(RSI(OC,14));
if(crossUnder(RSIs,70))
  enterShort();
if(crossOver(RSIs,30))
  enterLong();</pre>
<p>That&#8217;s a simple RSI trading system: Enter a short position when the RSI crosses below 70, and enter a long position when it crosses above 30. Any position is closed when an opposite position is opened. I found indeed that that using the open-close average produced a better result with some instruments and time periods, but a worse result with others. There was no clear tendency. However, it&#8217;s certainly worth a try when you&#8217;re anyway developing an indicator based trading system.</p>
<p>The script can be downloaded from the 2023 script repository.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://financial-hacker.com/open-or-close-why-not-both/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
			</item>
		<item>
		<title>Ehlers Loops</title>
		<link>https://financial-hacker.com/ehlers-loops/</link>
					<comments>https://financial-hacker.com/ehlers-loops/#comments</comments>
		
		<dc:creator><![CDATA[Petra Volkova]]></dc:creator>
		<pubDate>Fri, 10 Jun 2022 17:08:46 +0000</pubDate>
				<category><![CDATA[Petra on Programming]]></category>
		<category><![CDATA[System Development]]></category>
		<category><![CDATA[Ehlers]]></category>
		<category><![CDATA[Pairs rotation]]></category>
		<category><![CDATA[SPY]]></category>
		<guid isPermaLink="false">https://financial-hacker.com/?p=4448</guid>

					<description><![CDATA[Price charts normally display price over time. Or in some special cases price over ranges or momentum. In his TASC articles in June and July 2022, John Ehlers proposed a different way of charting. The relation of two parameters, like price over momentum, or price A over price B, is displayed as a 2D curve &#8230; <a href="https://financial-hacker.com/ehlers-loops/" class="more-link">Continue reading<span class="screen-reader-text"> "Ehlers Loops"</span></a>]]></description>
										<content:encoded><![CDATA[<p><em>Price charts normally display price over time. Or in some special cases price over ranges or momentum. In his TASC articles in June and July 2022, John Ehlers proposed a different way of charting. The relation of two parameters, like price over momentum, or price A over price B, is displayed as a 2D curve in a scatter plot. The resulting closed or open loop is supposed to predict the future price development. Of course only if interpreted in the right way.</em></p>
<p><span id="more-4448"></span></p>
<p>For his loop chart, Ehlers filtered the low and high frequencies out of the two data series with a roofing filter. Its code in C for Zorro:</p>
<pre class="prettyprint">var Roofing(var *Data,int HPeriod,int LPeriod)
{
  var f = 1.414*PI/HPeriod;
  var hpa1 = exp(-f);
  var hpc2 = 2*hpa1*cos(f/2);
  var hpc3 = -hpa1*hpa1;
  var hpc1 = (1 + hpc2 - hpc3) / 4;
  f = 1.414*PI/LPeriod;
  var ssa1 = exp(-f);
  var ssc2 = 2*ssa1*cos(f/2);
  var ssc3 = -ssa1*ssa1;
  var ssc1 = 1 - ssc2 - ssc3;

  vars HP = series(0,3);
  HP[0] = hpc1*(Data[0] - 2*Data[1] + Data[2]) + hpc2*HP[1] + hpc3*HP[2];
  vars SS = series(HP[0],3);
  SS[0] = ssc1*(HP[0] + HP[1])/2 + ssc2*SS[1] + ssc3*SS[2];
  var Scaled = EMA(SS[0]*SS[0],.0242);
  return SS[0]/sqrt(Scaled);
}</pre>
<p>For demonstration purposes we apply that filter to the FDX price and volume series. The filtered data points serve as XY coordinates for our curve – the &#8220;Ehlers Loop&#8221;. The following script reads 3 months stock data from an online source and displays it in a scatter plot where the XY points are connected with splines:</p>
<pre class="prettyprint">function run()
{
  StartDate = ymd(wdate(NOW)-90); // 90 days before today
  BarPeriod = 1440;
  asset("FDX");
  var PriceRMS = Roofing(seriesC(),125,20);
  var VolRMS = Roofing(series(marketVol()),125,20);

  if(is(LOOKBACK)) return; // don't plot the lookback period
  plotGraph("Loop",VolRMS,PriceRMS,DOT|GRAPH,BLUE);
  plotGraph("Loops",VolRMS,PriceRMS,SPLINE|GRAPH,TRANSP|GREY);
  if(is(EXITRUN))
    plotGraph("Last",VolRMS,PriceRMS,SQUARE|GRAPH,RED);
}</pre>
<p>The plotGraph function is used to display each coordinate with a blue dot. The last day is marked with a red square.</p>
<p><img decoding="async" src="https://financial-hacker.com/wp-content/uploads/2022/06/061022_1641_EhlersLoops1.png" alt="" /></p>
<p>Ehlers intended his loops for discretionary trading, but it can of course also be automated. For instance, the last N coordinates could be used as inputs for Zorro&#8217;s neural net, which can then be trained to predict tomorrow&#8217;s price. Or even simpler, the slope of a polynomial regression through the last points could trigger a buy order when positive, or a sell order when negative. You can use Zorro&#8217;s polyfit function and filter with the regression error. I leave this trading system as an exercise to the reader.</p>
<p>The same method can be used to compare a stock with an index for a pairs rotation strategy. We&#8217;re using RTX and SPY:</p>
<pre class="prettyprint">function run()
{
  BarPeriod = 1440;
  LookBack = 300;
  StartDate = 20210801;
  EndDate = 20211130;

  assetAdd("RTX","YAHOO:*");
  asset("RTX");
  var Y = Roofing(seriesC(),125,20);
  assetAdd("SPY","YAHOO:*");
  asset("SPY");
  var X = Roofing(seriesC(),125,20);

  if(is(LOOKBACK)) return;
  plotGraph("Loop",X,Y,DOT|GRAPH,BLUE);
  plotGraph("Loops",X,Y,SPLINE|GRAPH,TRANSP|GREY);
  if(is(EXITRUN))
    plotGraph("Last",X,Y,SQUARE|GRAPH,RED);
}</pre>
<p>The resulting chart for the period from August to November 2021:</p>
<p><img decoding="async" src="https://financial-hacker.com/wp-content/uploads/2022/06/061022_1641_EhlersLoops2.png" alt="" /></p>
<p>I found that Ehlers&#8217; roofing filter is sensitive to the lookback period. It needs some time to &#8216;swing in&#8217;. A too short lookback period, like Zorro&#8217;s default 80 bars, produces a visibly different loop. With 300 bars we&#8217;re on the safe side.</p>
<p>What can you now do with this loop chart? Ehlers proposed to switch between stock and index depending on the loop rotation and angle quadrant. Our example above, with the SPY index on the Y axis and the stock on the X axis, has a clockwise rotating loop. On clockwise rotations, buy the stock and sell the index from 5 to 10 on the clock face. Sell the stock and buy the index from 11 to 4. Be out of the market between 4 and 5, and have both positions between 10 and 11.<img loading="lazy" decoding="async" class="aligncenter" src="https://financial-hacker.com/wp-content/uploads/2022/06/Clock.png" alt="" width="211" height="198" /></p>
<p>On a counter clockwise rotation, do just the opposite. This was intended for discretionary trading, but can of course be automated with a script. Which I also gracefully leave to the reader.</p>
<p>The Roofing indicator and the Ehlers Loop scripts can be downloaded from the 2022 script repository. The Zorro software can be downloaded from <a href="https://zorro-project.com/download.php">https://zorro-project.com</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://financial-hacker.com/ehlers-loops/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>The Inverse Fisher Transform</title>
		<link>https://financial-hacker.com/the-inverse-fisher-transform/</link>
					<comments>https://financial-hacker.com/the-inverse-fisher-transform/#comments</comments>
		
		<dc:creator><![CDATA[Petra Volkova]]></dc:creator>
		<pubDate>Sun, 13 Feb 2022 12:28:13 +0000</pubDate>
				<category><![CDATA[Indicators]]></category>
		<category><![CDATA[Petra on Programming]]></category>
		<category><![CDATA[Ehlers]]></category>
		<category><![CDATA[Fisher transformation]]></category>
		<guid isPermaLink="false">https://financial-hacker.com/?p=4288</guid>

					<description><![CDATA[The Fisher Transform converts data to or from a Gaussian distribution. It was first used in algorithmic trading by John Ehlers (1) , and became a common part of indicators since then. In a TASC February 2022 article, Ehlers described a new indicator, the Elegant Oscillator, based on the Inverse Fisher Transform. Let&#8217;s have a &#8230; <a href="https://financial-hacker.com/the-inverse-fisher-transform/" class="more-link">Continue reading<span class="screen-reader-text"> "The Inverse Fisher Transform"</span></a>]]></description>
										<content:encoded><![CDATA[<p><em>The Fisher Transform converts data to or from a Gaussian distribution. It was first used in algorithmic trading by John Ehlers (1) , and became a common part of indicators since then. In a TASC February 2022 article, Ehlers described a new indicator, the <strong>Elegant Oscillator</strong>, based on the Inverse Fisher Transform. Let&#8217;s have a look at this indicator and how it&#8217;s used in a trading system.</em></p>
<p><span id="more-4288"></span></p>
<p>First, the Fisher Transform and its inverse in code:</p>
<pre class="prettyprint">var Fisher(vars Data)
{
  var V = clamp(Data[0],-0.999,0.999);
  return 0.5*log((1.+V)/(1.-V));
}

var FisherInv(vars Data)
{
  var V = exp(2.*Data[0]);
  return (V-1.)/(V+1.);
}</pre>
<p>The Inverse Fisher Transform (IFT) is used in the Elegant Oscillator to convert a normalized derivative of a price series to the +/-1 range. The normalization is done by dividing by the square root of the sum of squares, a sort of N-dimensional distance. Using the IFT is supposedly a better method than simply clipping the data. The result is smoothed by Ehlers&#8217; &#8216;SuperSmoother&#8217;, a low-lag lowpass filter. The Elegant Oscillator code in C for Zorro:</p>
<pre class="prettyprint">var EO(vars Data,int Length)
{
  vars Derivs = series(Data[0]-Data[2]);
  var RMS = sqrt(SumSq(Derivs,Length)/Length);
  var NDeriv = Derivs[0]/RMS;
  vars IFishs = series(FisherInv(&amp;NDeriv));
  return Smooth(IFishs,20);
}
</pre>
<p><strong>SumSq()</strong> is a helper function for summing up the squares of a data series, and <strong>Smooth()</strong> is Ehlers&#8217; &#8216;SuperSmoother&#8217; that&#8217;s already in the Zorro library. Since the <strong>FisherInv</strong> function needs only a data series of length 1, I could simply pass a pointer to the <strong>NDeriv</strong> variable instead of a series of it. For comparison, here&#8217;s the simple code for hard clipping the data:</p>
<pre class="prettyprint">var HardClip(vars Data)
{
  var Deriv = Data[0]-Data[2];
  vars Clips = series(clamp(Deriv,-1,1));
  return FIR6(Clips);
}</pre>
<p>The clipped data is this time smoothed with a finite response filter (FIR6). Here&#8217;s a SPY chart with the Elegant Oscillator (upper red line), the Inverse Fisher Transform smoothed with a finite response filter (lower red line), and the hard clipped variant (blue line).</p>
<p><img decoding="async" src="https://financial-hacker.com/wp-content/uploads/2022/02/021322_1208_TheInverseF1.png" alt="" /></p>
<p>Of the 3, the super smoothed Elegant Oscillator makes the best impression and appears to generate the best signals. According to Ehlers, its peaks and valleys that exceed a threshold can be used for mean reversion trading. Let&#8217;s put that to the test. The code:</p>
<pre class="prettyprint">void run()
{
  StartDate = 20200301;
  EndDate = 20210501;
  BarPeriod = 1440;
  asset("SPY");
  vars Signals = series(EO(seriesC(),50));
  var Threshold = 0.5;
  if(Signals[0] &gt; Threshold &amp;&amp; peak(Signals))
    enterShort();
  else if(Signals[0] &lt; -Threshold &amp;&amp; valley(Signals))
    enterLong();
}</pre>
<p>The resulting chart:</p>
<p><img decoding="async" src="https://financial-hacker.com/wp-content/uploads/2022/02/021322_1208_TheInverseF2.png" alt="" /></p>
<p>Indeed, 5 of 7 trades in that time period were winning, producing an overall positive result with a profit factor above 6.  Of course, 7 trades won&#8217;t tell much, so I encorage anyone to experiment with different instruments and different time periods for determining the real value of the EO oscillator for mean reversion trading.</p>
<p>The oscillator and trading strategy can be downloaded from the 2021 script repository.</p>
<p>(1) John Ehlers, Cybernetic Analysis of Stocks and Futures, Wiley 2004</p>
]]></content:encoded>
					
					<wfw:commentRss>https://financial-hacker.com/the-inverse-fisher-transform/feed/</wfw:commentRss>
			<slash:comments>16</slash:comments>
		
		
			</item>
	</channel>
</rss>
