<?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>Indicators &#8211; The Financial Hacker</title>
	<atom:link href="https://financial-hacker.com/category/indicators/feed/" rel="self" type="application/rss+xml" />
	<link>https://financial-hacker.com</link>
	<description>A new view on algorithmic trading</description>
	<lastBuildDate>Fri, 17 Apr 2026 14:55:25 +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>Indicators &#8211; The Financial Hacker</title>
	<link>https://financial-hacker.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>The AutoTune filter</title>
		<link>https://financial-hacker.com/the-autotune-filter/</link>
					<comments>https://financial-hacker.com/the-autotune-filter/#comments</comments>
		
		<dc:creator><![CDATA[Petra Volkova]]></dc:creator>
		<pubDate>Fri, 17 Apr 2026 14:53:29 +0000</pubDate>
				<category><![CDATA[Indicators]]></category>
		<category><![CDATA[Petra on Programming]]></category>
		<category><![CDATA[System Development]]></category>
		<category><![CDATA[Dominant Cycle]]></category>
		<category><![CDATA[Ehlers]]></category>
		<guid isPermaLink="false">https://financial-hacker.com/?p=4989</guid>

					<description><![CDATA[By the Fourier theorem, any price curve is a mix of many long-term and short-term cycles. Once in a while a dominant market cycle emerges and can be exploited for trading. In his TASC 5/2026 article, John Ehlers described an algorithm for detecting such dominant cycles, using them to tune a bandpass filter, and creating &#8230; <a href="https://financial-hacker.com/the-autotune-filter/" class="more-link">Continue reading<span class="screen-reader-text"> "The AutoTune filter"</span></a>]]></description>
										<content:encoded><![CDATA[<p><em>By the Fourier theorem, any price curve is a mix of many long-term and short-term cycles. Once in a while a <strong>dominant market cycle</strong> emerges and can be exploited for trading. In his TASC 5/2026 article, <strong>John Ehlers</strong> described an algorithm for detecting such dominant cycles, using them to tune a bandpass filter, and creating a profitable trading system. Here&#8217;s how to do it.</em></p>
<p><span id="more-4989"></span></p>
<p>Ehlers&#8217; Easylanguage code from the TASC article can be directly converted to C for Zorro.  ChatGPT does the job in a few seconds. First, the cycle detector:</p>
<pre class="prettyprint">var MinCorr, Filt;
var AutoTune(vars Data,int Window)
{
  Filt = HighPass3(Data,Window);
  vars HP = series(Filt);
  var Corr[256];
  int Lag, J;
  for(Lag = 1; Lag &lt;= Window; Lag++)
  {
    var Sx = 0., Sy = 0.;
    var Sxx = 0., Sxy = 0., Syy = 0.;
    for(J = 0; J &lt; Window; J++)
    {
      var X = HP[J];
      var Y = HP[Lag + J];
      Sx += X; Sy += Y;
      Sxx += X*X; Sxy += X*Y; Syy += Y*Y;
    }
    var Den1 = Window*Sxx - Sx*Sx;
    var Den2 = Window*Syy - Sy*Sy;
    Corr[Lag] = (Window*Sxy - Sx*Sy) / sqrt(fix0(Den1*Den2));
  }

  MinCorr = 1.;
  var DC = Window;
  for(Lag = 1; Lag &lt;= Window; Lag++)
    if(Corr[Lag] &lt; MinCorr) {
      MinCorr = Corr[Lag];
      DC = 2*Lag;
    }

  vars DCs = series(DC,2);
  return DCs[0] = clamp(DC,DCs[1]-2.,DCs[1]+2.);
}</pre>
<p>The output of the <strong>AutoTune</strong> function is supposed to be the dominant price cycle in units of bars. It is then used to set the center frequency of a bandpass filter. Since Zorro has already a bandpass filter in its arsenal, I named Ehlers&#8217; new version <strong>BandPass2</strong>:</p>
<pre class="prettyprint">var BandPass2(vars Data, int Period, var Bandwidth)
{
  var L1 = cos(2.*PI/Period);
  var G1 = cos(Bandwidth*2.*PI/Period);
  var S1 = 1./G1 - sqrt(1./(G1*G1) - 1.);
  vars BP = series(0,3);
  return BP[0] = 0.5*(1.-S1)*(Data[0]-Data[2]) 
    + L1*(1.+S1)*BP[1] - S1*BP[2];
}</pre>
<p>Here&#8217;s some code for reproducing Ehlers’ ES chart in the article:</p>
<pre class="prettyprint">function run()
{
  BarPeriod = 1440;
  StartDate = 2024;
  EndDate = 2025;
  asset("ES");
  var DC = AutoTune(seriesC(),20);
  var BP = BandPass2(seriesC(),DC,0.25);
  plot("Zero",0,NEW,BLACK);
  plot("BP",BP,LINE,BLUE);
}</pre>
<p>The resulting chart:</p>
<p><img fetchpriority="high" decoding="async" width="877" height="514" class="wp-image-4990" src="https://financial-hacker.com/wp-content/uploads/2026/04/word-image-4989-1.png" srcset="https://financial-hacker.com/wp-content/uploads/2026/04/word-image-4989-1.png 877w, https://financial-hacker.com/wp-content/uploads/2026/04/word-image-4989-1-300x176.png 300w, https://financial-hacker.com/wp-content/uploads/2026/04/word-image-4989-1-768x450.png 768w" sizes="(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px" /></p>
<p>How can we use this bandpass output for a trade signal? Ehlers used the zero crossovers of its rate-of-change (ROC). In this way he generated an impressive equity curve in his article, unfortunately with in-sample optimization. For a more realistic result, we’re using <strong>walk-forward analysis</strong> and reinvest profits by the <strong>square root rule</strong>:</p>
<pre class="prettyprint">function run()
{
  BarPeriod = 1440;
  StartDate = 2010;
  EndDate = 2025;
  Capital = 100000;

  asset("ES");
  set(TESTNOW,PARAMETERS);
  NumWFOCycles = 10;

  int Window = optimize("Window",26,10,30,2);
  var BW = optimize("BW",0.22,0.10,0.30,0.01);
  var Thresh = -optimize("Thresh",0.22,0.1,0.3,0.01);
  var DC = AutoTune(seriesC(),Window);
  var BP = BandPass2(seriesC(),DC,BW);
  vars ROCs = series(BP-ref(BP,2));
  
  Lots = 0.5*(Capital+sqrt(1.+ProfitTotal/Capital))/MarginCost;
  MaxLong = MaxShort = 1;
  if(crossOver(ROCs,0) &amp;&amp; MinCorr &lt; Thresh)
    enterLong();
  if(crossUnder(ROCs,0) &amp;&amp; MinCorr &lt; Thresh &amp;&amp; Filt &gt; 0)
    enterShort();
}</pre>
<p>The signals are filtered by a threshold that determines whether we&#8217;re in a cyclic market condition or not. The system is not fully symmetrical in long and short positions. Training and testing produced this equity curve:</p>
<p><img decoding="async" width="701" height="405" class="wp-image-4991" src="https://financial-hacker.com/wp-content/uploads/2026/04/word-image-4989-2.png" srcset="https://financial-hacker.com/wp-content/uploads/2026/04/word-image-4989-2.png 701w, https://financial-hacker.com/wp-content/uploads/2026/04/word-image-4989-2-300x173.png 300w" sizes="(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px" /></p>
<p>This curve does not look as impressive as Ehler’s one, but the CAGR is in the 25% area, much better than a buy-and-hold strategy. The code can be downloaded from the 2026 script repository.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://financial-hacker.com/the-autotune-filter/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<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 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 Points-and-Line Chart</title>
		<link>https://financial-hacker.com/the-points-and-line-chart/</link>
					<comments>https://financial-hacker.com/the-points-and-line-chart/#comments</comments>
		
		<dc:creator><![CDATA[Petra Volkova]]></dc:creator>
		<pubDate>Tue, 14 Oct 2025 13:45:25 +0000</pubDate>
				<category><![CDATA[Indicators]]></category>
		<category><![CDATA[Petra on Programming]]></category>
		<category><![CDATA[Amibroker]]></category>
		<category><![CDATA[Bars]]></category>
		<category><![CDATA[MACD]]></category>
		<guid isPermaLink="false">https://financial-hacker.com/?p=4869</guid>

					<description><![CDATA[Traders like charts with special bars, since they let the price curve appear smoother and more predictable as it really is. Some types of bars, such as Renko bars, even use fake prices for generating curves that appear to move straight upwards or downwards. In the TASC November issue, Mohamed Ashraf and Mohamed Meregy presented &#8230; <a href="https://financial-hacker.com/the-points-and-line-chart/" class="more-link">Continue reading<span class="screen-reader-text"> "The Points-and-Line Chart"</span></a>]]></description>
										<content:encoded><![CDATA[<p><em>Traders like charts with special bars, since they let the price curve appear smoother and more predictable as it really is. Some types of bars, such as <strong>Renko bars</strong>, even use fake prices for generating curves that appear to move straight upwards or downwards. In the TASC November issue, Mohamed Ashraf and Mohamed Meregy presented the <strong>Points and Line Chart</strong> that avoids this problem. At least in the standard variant, the prices in the chart are real, and can be used with indicators. In this article I&#8217;ll explain the usage of special bars with Zorro, and how ChatGPT can help with generating code.</em><span id="more-4869"></span></p>
<p>As far as I know, there is only one trading platform that supports custom bars natively. All other platforms require complicated workarounds. The author&#8217;s Amibroker code for the points-and-line chart filled six pages and looked a bit&#8230; awful. I did not want to touch it. Fortunately, my new friend Chad offered his help. The prompt:</p>
<p><strong>Dear Chad, please convert the AmiBroker code in this PDF to C for Zorro. Use the bar function for user-defined bars on </strong><a href="https://zorro-project.com/manual/en/bar.htm"><strong>https://zorro-project.com/manual/en/bar.htm</strong></a><strong>. Generate a DJIA chart with MACD and MACDSignal. For good code I’ll give you $100.</strong></p>
<p>(The $100 reward, in my experience, often improves Chad’s code. In the past, <em>“write good code or I break all your bones”</em> used to work even better, but not anymore since Chad 5.0 came out).</p>
<p>After about 3 minutes, Chad produced a lite-C script. It does still look a bit awful, but far better than the original code. I have cleaned it up at a few places, used different colors for the MACD, and added a ‘g’ to the names of global and static variables since this is my custom. This is the code of the <strong>bar</strong> function to generate Points-and-Line bars:</p>
<pre class="prettyprint">//////////////////////////////////////////////////////////
// PointsLine.c — Zorro C port of "Points &amp; Line" chart
// Ashraf &amp; Meregy, TASC Traders' Tips
// Conversion P. Volkova &amp; ChatGPT 5.0
//////////////////////////////////////////////////////////
// Modes
#define SCALE_DEFAULT 0
#define SCALE_ATR 1
#define SCALE_PERCENT 2
#define M_POINTSIZE 0
#define M_HIGHLOW 1
#define M_CLOSE 2

// User parameters
int gReverse = 3; // boxes needed to reverse
int gScale = SCALE_DEFAULT; // 0=Default, 1=ATR(14), 2=Percent
int gMethod = M_CLOSE; // 0=PointSize, 1=HighLow, 2=Close
var gPercent = 1.0; // % for SCALE_PERCENT

// Compute "box size"
var box(var Price)
{
  if(gScale == SCALE_DEFAULT) {
#define RNG(X,Y) if(Price &lt; X) return Y
    RNG(0.25,0.025);
    RNG(0.5,0.05);
    RNG(1,0.1);
    RNG(5,0.25);
    RNG(20,0.5);
    RNG(100,1);
    RNG(200,2);
    RNG(500,5);
    RNG(1000,10);
    RNG(2000,20);
    RNG(5000,50);
    RNG(10000,100);
    RNG(20000,200);
    return 500;
  }
  if(gScale = SCALE_ATR)
    return ATR(14);
  else // SCALE_PERCENT
    return Price*gPercent/100;
}
 
// User-defined bars
function bar(var *Open, var *High, var *Low, var *Close)
{
  var C = Close[0], H = High[0], L = Low[0];
  static int gDir = -1; // initially down
  static var gCF = C, gCR = C, gLF = C, gHR = C;
// box size
  var Box = fix0(box(C));
  var CF = ceil(C/Box)*Box,
  CR = floor(C/Box)*Box,
  LF = ceil(L/Box)*Box,
  HR = floor(H/Box)*Box;
   
  Switch (gMethod)
  {
  case M_POINTSIZE:
    if(CF &lt; gCF &amp;&amp; gDir &lt; 0) { // continue down, new box
      gCR = CF - Box; gCF = CF;
      Close[0] = CF; return 1;
    }
    if(gCF + Box*gReverse &lt;= CR &amp;&amp; gDir &lt; 0) {
      gCR = CR; gCF = CR + Box;
      Close[0] = CR; gDir = 1; return 1; // swap direction
    }
    if(gCR &lt; CR &amp;&amp; gDir &gt; 0) { // continue up
      gCR = CR; gCF = CR + Box; Close[0] = CR; return 1;
    }
    if(gCR - Box*gReverse &gt;= CF &amp;&amp; gDir &gt; 0) {
      gCF = CF; gCR = CF - Box; Close[0] = CF;
      gDir = -1; return 1;
    }
    break;
     
  case M_HIGHLOW:
    if(LF &lt; gLF &amp;&amp; gDir &lt; 0) {
      gHR = LF - Box; gLF = LF;
      Close[0] = L; return 1;
    }
    if(gLF + Box*gReverse &lt;= HR &amp;&amp; gDir &lt; 0) {
      gHR = HR; gLF = HR + Box;
      Close[0] = H; gDir = 1; return 1;
    }
    if(gHR &lt; HR &amp;&amp; gDir &gt; 0) {
      gHR = HR; gLF = HR + Box;
      Close[0] = H; return 1;
    }
    if(gHR - Box*gReverse &gt;= LF &amp;&amp; gDir &gt; 0) {
      gLF = LF; gHR = LF - Box;
      Close[0] = L; gDir = -1; return 1;
    }
    break;
     
  case M_CLOSE:
    if(CF &lt; gCF &amp;&amp; gDir &lt; 0) { // continue down
      gCR = CF-Box; gCF = CF;
    return 1;
    }
    if(gCF+Box*gReverse &lt;= CR &amp;&amp; gDir &lt; 0) { // go up
      gCR = CR; gCF = CR+Box;
      gDir = 1; return 1;
    }
    if(gCR &lt; CR &amp;&amp; gDir &gt; 0) {
      gCR = CR; gCF = CR+Box;
    return 1;
    }
    if(gCR-Box*gReverse &gt;= CF &amp;&amp; gDir &gt; 0) {
      gCF = CF; gCR = CF-Box;
      gDir = -1; return 1;
    }
    break;
  }
  return 4; // keep bar open, call again on next tick
}
</pre>
<p>The algorithm of the points-and-line chart in its 3 variants &#8211; POINTSIZE, HIGHLOW, and CLOSE &#8211; can be read up in the TASC article. Here I&#8217;ll only illustrate the usage of the <strong>bar()</strong> function for establishing special, event-driven bars instead of the usual time bars. The function evaluates the current and previous candle, modifies the current candle if needed, and returns <strong>1</strong> for beginning a new bar or <strong>4</strong> for continuing with the current bar. This way, all imaginable sorts of event driven bars can be generated, in the same way for backtests and for live trading. These bars are also displayed on the chart, and affect the scale of the X axis.</p>
<p>Since AmiBroker did not support standard indicators on a chart with special bars, the authors had exported the created chart and imported it as a fake asset price curve to Metastocks for using indicators with it. I wonder how this would work in live trading. Fortunately, the Zorro platform has no problems of this kind, since it treats standard bars and special bars in the same way. The <strong>run</strong> function looks just as usual:</p>
<pre class="prettyprint">function run()
{
  set(PLOTNOW,TICKS);
  BarPeriod = 1440;
  LookBack = 120;
  StartDate = 2017;
  EndDate = 2025;
  BarZone = EST;
  assetAdd("DJIA","STOOQ:^DJI");
  asset("DJIA");
  plot("MACD",MACDFix(seriesC(),14),NEW,RED);
  plot("Signal",rMACDSignal,0,GREY);
 }</pre>
<p>The function uses STOOQ as a price source and plots the MACD indicator (red) and its signal line (grey). The chart below reproduces the DJIA chart in the TASC article, and applies a standard MACD:</p>
<p><img loading="lazy" decoding="async" width="885" height="479" class="wp-image-4870" src="https://financial-hacker.com/wp-content/uploads/2025/10/ein-bild-das-text-diagramm-reihe-zahl-enthalt-.png" alt="Ein Bild, das Text, Diagramm, Reihe, Zahl enthält.

KI-generierte Inhalte können fehlerhaft sein." srcset="https://financial-hacker.com/wp-content/uploads/2025/10/ein-bild-das-text-diagramm-reihe-zahl-enthalt-.png 885w, https://financial-hacker.com/wp-content/uploads/2025/10/ein-bild-das-text-diagramm-reihe-zahl-enthalt--300x162.png 300w, https://financial-hacker.com/wp-content/uploads/2025/10/ein-bild-das-text-diagramm-reihe-zahl-enthalt--768x416.png 768w" sizes="auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px" /></p>
<p>Due to the variable length of bars, the time scale on the X axis is uneven; the DJIA moved a lot more in the years 2020 and 2022 than in the other years. The code can be downloaded from the 2025 script repository.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://financial-hacker.com/the-points-and-line-chart/feed/</wfw:commentRss>
			<slash:comments>2</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 loading="lazy" 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="auto, (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 loading="lazy" 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="auto, (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>Trading the Channel</title>
		<link>https://financial-hacker.com/trading-the-channel/</link>
					<comments>https://financial-hacker.com/trading-the-channel/#comments</comments>
		
		<dc:creator><![CDATA[Petra Volkova]]></dc:creator>
		<pubDate>Wed, 09 Apr 2025 12:14:55 +0000</pubDate>
				<category><![CDATA[Indicators]]></category>
		<category><![CDATA[Petra on Programming]]></category>
		<category><![CDATA[System Development]]></category>
		<category><![CDATA[Channels]]></category>
		<category><![CDATA[Kaufman]]></category>
		<category><![CDATA[Momentum]]></category>
		<category><![CDATA[Regression]]></category>
		<guid isPermaLink="false">https://financial-hacker.com/?p=4834</guid>

					<description><![CDATA[One of the simplest form of trend trading opens positions when the price crosses its moving average, and closes or reverses them when the price crosses back. In the latest TASC issue, Perry Kaufman suggested an alternative. He is using a linear regression line with an upper and lower band for trend trading. Such a &#8230; <a href="https://financial-hacker.com/trading-the-channel/" class="more-link">Continue reading<span class="screen-reader-text"> "Trading the Channel"</span></a>]]></description>
										<content:encoded><![CDATA[<p><em>One of the simplest form of trend trading opens positions when the price crosses its moving average, and closes or reverses them when the price crosses back. In the latest TASC issue, <strong>Perry Kaufman</strong> suggested an alternative. He is using a linear regression line with an upper and lower band for trend trading. Such a band indicator can be used to trigger long or short positions when the price crosses the upper or lower band, or when it gets close.</em><span id="more-4834"></span></p>
<p>Let’s first code the bands. They are simply a regression line moved up or down so that it crosses through the highest and lowest price peaks and valleys. Here’s the piece of code in C:</p>
<pre class="prettyprint">var Slope = LinearRegSlope(seriesC(),N);
var Intercept = LinearRegIntercept(seriesC(),N);
var LinVal, HighDev = 0, LowDev = 0;
for(i=N; i&gt;0; i--) {
  LinVal = Intercept + Slope*(N-i);
  HighDev = max(HighDev,priceC(i)-LinVal);
  LowDev = min(LowDev,priceC(i)-LinVal);
}</pre>
<p><strong>N</strong> is the number of bars for which the regression line is calculated. The line has the formula <strong>y = b + m*x</strong>, where <strong>b</strong> is the intercept and <strong>m</strong> the slope. The code generates both for the previous <strong>N</strong> bars, then calculates in the loop the maximum and minimum deviations (<strong>HighDev</strong>, <strong>LowDev</strong>). The regression value (<strong>LinVal</strong>) is calculated from the intercept and slope with the above formula. Since the bar offset <strong>i</strong> runs backwards from the current bar, the bar number that’s multiplied with the slope runs from <strong>N</strong> down to <strong>0</strong>. Here’s the code applied to a SPY chart from 2025:</p>
<p><strong><img loading="lazy" decoding="async" width="701" height="405" class="wp-image-4835" src="https://financial-hacker.com/wp-content/uploads/2025/04/ein-bild-das-diagramm-text-reihe-screenshot-en.png" srcset="https://financial-hacker.com/wp-content/uploads/2025/04/ein-bild-das-diagramm-text-reihe-screenshot-en.png 701w, https://financial-hacker.com/wp-content/uploads/2025/04/ein-bild-das-diagramm-text-reihe-screenshot-en-300x173.png 300w" sizes="auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px" /></strong></p>
<p>The candles can exceed the upper and lower bands because only the close price is used for the bands. It would probably improve the system, at least in theory, when we used the high and low prices instead.</p>
<p>Kaufman suggests several methods of trading with these bands; we’re here using the ‘Inside Channel’ method since it is, according to Kaufman, the most profitable. We open a long position when the price comes within a zone around the lower band, and close the position (or open a short position) when the price comes within a zone around the upper band. Here’s the complete trading system in C for Zorro, using the above code to calculate the bands.</p>
<pre class="prettyprint">void run()
{
  BarPeriod = 1440;
  StartDate = 20100101;
  LookBack = 150;
  assetList("AssetsIB");
  asset("SPY");
  if(is(LOOKBACK)) return;

  int i, N = 40;
  var Factor = 0.2;
  var Slope = LinearRegSlope(seriesC(),N);
  var Intercept = LinearRegIntercept(seriesC(),N);
  var LinVal, HighDev = 0, LowDev = 0;
  for(i=N; i&gt;0; i--) {
    LinVal = Intercept + Slope*(N-i);
    HighDev = max(HighDev,priceC(i)-LinVal);
    LowDev = min(LowDev,priceC(i)-LinVal);
  }
  var Zone = Factor*(HighDev+LowDev);
  if(!NumOpenLong &amp;&amp; priceC(0) &lt; LinVal+LowDev+Zone)
    enterLong();
  if(!NumOpenShort &amp;&amp; priceC(0) &gt; LinVal+HighDev-Zone)
    exitLong();
}</pre>
<p>We’ve selected the <strong>AssetsIB</strong> asset list, which contains the margins, commissions and other parameters from an US broker (IBKR). So the backtest simulates trading with IBKR. The resulting equity curve with the default parameters, <strong>N = 40</strong> and <strong>Zone Factor = 20%</strong>, already shows promise with a 2.8 profit factor:</p>
<p><img loading="lazy" decoding="async" width="701" height="405" class="wp-image-4836" src="https://financial-hacker.com/wp-content/uploads/2025/04/word-image-4834-2.png" srcset="https://financial-hacker.com/wp-content/uploads/2025/04/word-image-4834-2.png 701w, https://financial-hacker.com/wp-content/uploads/2025/04/word-image-4834-2-300x173.png 300w" sizes="auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px" /></p>
<p>However, Kaufman mentioned that he tested <strong>N</strong> values from 20 to 150, and zone factors from 5% to 50%. We’ll do the same by optimizing these parameters. Of course a backtest with the best optimization result would be meaningless due to bias (see <a href="https://zorro-project.com/backtest.php">https://zorro-project.com/backtest.php</a>). Therefore we’re using <strong>walk forward optimization</strong> for an out-of-sample backtest. Since anything with Zorro is done in code, we’ll insert 4 lines of C code for the optimization:</p>
<pre class="prettyprint">set(PARAMETERS); // optimize parameters
NumWFOCycles = 5;
N = optimize(40,20,150,10);
Factor = optimize(0.2,0.05,0.5,0.05);</pre>
<p>We also changed the trading from only long positions to long and short by replacing <strong>exitLong</strong> with <strong>enterShort</strong> By default, entering a short position automatically exits the long one, and vice versa. So the system is always in the market with 1 share, either long or short. The walk forward optimization takes about 3 seconds. This is the resulting equity curve:</p>
<p><img loading="lazy" decoding="async" width="701" height="405" class="wp-image-4837" src="https://financial-hacker.com/wp-content/uploads/2025/04/word-image-4834-3.png" srcset="https://financial-hacker.com/wp-content/uploads/2025/04/word-image-4834-3.png 701w, https://financial-hacker.com/wp-content/uploads/2025/04/word-image-4834-3-300x173.png 300w" sizes="auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px" /></p>
<p>The profit factor rose to 7, with a 76% win rate &#8211; not bad for such a simple system. The code can be downloaded from the 2025 script repository on <a href="https://financial-hacker.com">https://financial-hacker.com</a>. </p>
]]></content:encoded>
					
					<wfw:commentRss>https://financial-hacker.com/trading-the-channel/feed/</wfw:commentRss>
			<slash:comments>8</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>The Gap Momentum System</title>
		<link>https://financial-hacker.com/the-gap-momentum-system/</link>
					<comments>https://financial-hacker.com/the-gap-momentum-system/#comments</comments>
		
		<dc:creator><![CDATA[Petra Volkova]]></dc:creator>
		<pubDate>Fri, 15 Mar 2024 11:49:36 +0000</pubDate>
				<category><![CDATA[Indicators]]></category>
		<category><![CDATA[Petra on Programming]]></category>
		<category><![CDATA[Momentum]]></category>
		<guid isPermaLink="false">https://financial-hacker.com/?p=4701</guid>

					<description><![CDATA[Perry Kaufman, known for his technical indicators bible, presented in TASC 1/24 a trading strategy based on upwards and downwards gaps. For his system, he invented the Gap Momentum Indicator (GAPM). Here I&#8217;m publishing the C version of his indicator, and a simple trading system based on it. The indicator is a straighforward conversion of &#8230; <a href="https://financial-hacker.com/the-gap-momentum-system/" class="more-link">Continue reading<span class="screen-reader-text"> "The Gap Momentum System"</span></a>]]></description>
										<content:encoded><![CDATA[<p><em>Perry Kaufman, known for his technical indicators bible, presented in TASC 1/24 a trading strategy based on upwards and downwards gaps. For his system, he invented the Gap Momentum Indicator (GAPM). Here I&#8217;m publishing the C version of his indicator, and a simple trading system based on it.</em><span id="more-4701"></span></p>
<p>The indicator is a straighforward conversion of Kaufman&#8217;s EasyLanguage code to C:</p>
<pre class="prettyprint">var GAPM(int Period, int SignalPeriod)
{
    var UpGaps = 0, DnGaps = 0;
    int ix;
    for(ix = 0; ix &lt; Period; ix++) {
        var Gap = priceO(ix) - priceC(ix+1);
        if(Gap &gt; 0) UpGaps += Gap;
        else if(Gap &lt; 0) DnGaps -= Gap;
    }
    var GapRatio = ifelse(DnGaps == 0,1,100*UpGaps/DnGaps);
    return SMA(series(GapRatio),SignalPeriod);
}</pre>
<p>The system trades QQQ, a NASDAQ ETF. The historical data for the backtest is loaded from Yahoo. It enters a long position when upward gaps are on the rise, and closes the position otherwise. The code in C for the Zorro platform:</p>
<pre class="prettyprint">function run()
{
    StartDate = 2011;
    EndDate = 2023;
    BarPeriod = 1440;
    Fill = 3;    // trade on next open
    var Investment = 100000;
    assetAdd("QQQ","YAHOO:*");
    asset("QQQ");
    vars Signals = series(GAPM(40,20));
    if(!NumOpenLong &amp;&amp; rising(Signals))
        enterLong(Investment/priceC());
    if(NumOpenLong &amp;&amp; falling(Signals))
        exitLong();
}</pre>
<p>The resulting equity curve:</p>
<p><img decoding="async" src="https://financial-hacker.com/wp-content/uploads/2024/03/031524_1142_TheGapMomen1.png" alt="" /></p>
<p>The result is not sensational, but the system achieved a solid 12% return on investment, well above buy-and-hold, with 56% winning trades. The GAPM indicator and the trading system can be downloaded from the 2023 script repository.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://financial-hacker.com/the-gap-momentum-system/feed/</wfw:commentRss>
			<slash:comments>11</slash:comments>
		
		
			</item>
	</channel>
</rss>
