<?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>Amibroker &#8211; The Financial Hacker</title>
	<atom:link href="https://financial-hacker.com/tag/amibroker/feed/" rel="self" type="application/rss+xml" />
	<link>https://financial-hacker.com</link>
	<description>A new view on algorithmic trading</description>
	<lastBuildDate>Wed, 15 Oct 2025 09:02:08 +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>Amibroker &#8211; The Financial Hacker</title>
	<link>https://financial-hacker.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<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 fetchpriority="high" 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="(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>A Better Stock Rotation System</title>
		<link>https://financial-hacker.com/a-better-stock-rotation-system/</link>
					<comments>https://financial-hacker.com/a-better-stock-rotation-system/#comments</comments>
		
		<dc:creator><![CDATA[Petra Volkova]]></dc:creator>
		<pubDate>Sun, 27 Jul 2025 14:26:47 +0000</pubDate>
				<category><![CDATA[Petra on Programming]]></category>
		<category><![CDATA[System Development]]></category>
		<category><![CDATA[Amibroker]]></category>
		<category><![CDATA[Portfolio rotation]]></category>
		<guid isPermaLink="false">https://financial-hacker.com/?p=4861</guid>

					<description><![CDATA[A stock rotation system is normally a safe haven, compared to other algorithmic systems. There’s no risk of losing all capital, and you can expect small but steady gains. The catch: Most of those systems, and also the ETFs derived from them, do not fare better than the stock index. Many fare even worse. But &#8230; <a href="https://financial-hacker.com/a-better-stock-rotation-system/" class="more-link">Continue reading<span class="screen-reader-text"> "A Better Stock Rotation System"</span></a>]]></description>
										<content:encoded><![CDATA[<p><em>A stock rotation system is normally a safe haven, compared to other algorithmic systems. There’s no risk of losing all capital, and you can expect small but steady gains. The catch: Most of those systems, and also the ETFs derived from them, do not fare better than the stock index. Many fare even worse. But how can you make sure that your rotation strategy beats the index? There is a way.</em></p>
<p><span id="more-4861"></span></p>
<p>In the TASC July 2026 issue, <strong>Markos Katsanos</strong> suggests a solution for a better stock rotation system. He applies two twists: Excluding the top performers, which often experience a reversal to the mean, and filtering out bear market situations. This improves stock rotation systems a lot.</p>
<p>The code of his system is unfortunately written in Amibroker languge, which means that for using it with any other platform, one must rewrite it from scratch. Amibroker does not use buy or sell orders. Instead it has a ‘portfolio rotation mode’ that is set up with many variables. Zorro’s C language has no special rotation mode, but uses buy and sell orders for rotating, just as for any other strategy. This requires rewriting the Amibroker code, but the positive side is that the script becomes much shorter and easier to comprehend.</p>
<pre class="prettyprint">var Score[1000],Weights[1000];

void run()
{
  StartDate = 2012;
  EndDate = 2025;
  BarPeriod = 1440;
  LookBack = 252; // 1 year

  Capital = slider(1,10000,0,20000,"Capital","");
  assetList("AssetsNASDAQ");
  assetAdd("QQQ","STOOQ:QQQ"); // for the bear market detection
  asset("QQQ");
// set up variables
  int MaxOpenPositions = 15;
  int ROCBars = 100;
  int ExitBars = 20;
  int MAPeriod = 300;
  int ExcludeTopN = 2;
// bear market filter
  var MAQQQ = ZMA(seriesC(),MAPeriod);
  bool Bear = MAQQQ &lt; ref(MAQQQ,1);
  if(Day%ExitBars == 0) {
// assign a score to any asset
     for(listed_assets) {
       asset(Asset);
       if(Asset == "QQQ" || Bear)
         Score[Itor] = 0; // don't trade the index
       else
         Score[Itor] = ROC(seriesC(),ROCBars);
     }
// exclude the N top scores
     int i;
     for(i=0; i&lt;ExcludeTopN; i++)
       Score[MaxIndex(Score,NumAssetsListed)] = 0;

// rotate the positions
    distribute(Weights,Score,NumAssetsListed,MaxOpenPositions,0.5);
     rotate(0); // decrease positions
     rotate(1); // increase positions
   }
}</pre>
<p>We’re loading all NASDAQ stocks from an asset list (<strong>AssetsNASDAQ</strong>), and add the <strong>‘QQQ’</strong> index ETF because we’re needing that for the bear market filter. The <strong>MAQQQ</strong> variable holds the average index value, determined with a zero-lag moving average (<strong>ZMA</strong>). The ZMA has two advantages over a standard moving average: faster reaction (as the name says) and not needing a long data history. We assume a bear market when the average is falling.</p>
<p>Next, we check if we have reached the rotation date (<strong>Day%ExitBars</strong> is the number of days since start modulo the number of days for a rotation). If so, we loop over all assets and assign every one a score, depending on its N-day rate of return (<strong>ROC</strong>). The <strong>Itor</strong> variable is the number of the asset in the loop. The QQQ index gets no score, and in a bear market none of them gets a score.</p>
<p>Next, we remove the two top performers, since we assume they are overbought. The <strong>distribute</strong> function takes the scores and converts them to weights, while all weights sum up to 1. The function can be looked up in the Zorro manual (<a href="https://zorro-project.com/manual/en/renorm.htm">https://zorro-project.com/manual/en/renorm.htm</a>). Finally we perform the actual rotation. This is a bit tricky, because we need two steps. The first step reduces all positions that ought to be reduced. The second step increases all positions that ought to be increased. This order is important, because if we increased a position first, the total volume could exceed our capital on the broker account.</p>
<p>The <strong>rotate</strong> function is not a Zorro function, but just assigns new position sizes to any asset of the portfolio:</p>
<pre class="prettyprint">void rotate(int Buy)
{
  for(listed_assets) {
    asset(Asset);
    int NewLots = Capital*Weights[Itor]/MarginCost;
    if(NewLots &lt; LotsPool)
      exitLong(0,0,LotsPool-NewLots);
    else if(Buy &amp;&amp; NewLots &gt; LotsPool)
      enterLong(NewLots-LotsPool);
  }
}</pre>
<p>Since I see from Markos Katsanos&#8217; code that he optimized his variables, I have to do the same. For this, his variables now get optimization ranges:</p>
<pre class="prettyprint">set(PARAMETERS); // parameter optimization
setf(TrainMode,TRADES|GENETIC); // size matters
int MaxOpenPositions = optimize(15,5,30,5);
int ROCBars = optimize(100,50,250,50);
int ExitBars = optimize(20,10,50,5);
int MAPeriod = optimize(300,100,1000,100);
int ExcludeTopN = optimize(2,1,5,1);</pre>
<p>We’re using genetic optimization with considering the trade volume (<strong>TRADES|GENETIC</strong>). The optimization takes about one minute. It’s in-sample, so take the result with a grain of salt. This is the equity curve resulting from a backtest:</p>
<p><img decoding="async" width="768" height="465" class="wp-image-4862" src="https://financial-hacker.com/wp-content/uploads/2025/07/word-image-4861-1.png" srcset="https://financial-hacker.com/wp-content/uploads/2025/07/word-image-4861-1.png 768w, https://financial-hacker.com/wp-content/uploads/2025/07/word-image-4861-1-300x182.png 300w" sizes="(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px" /></p>
<p>In the backtest, we’re reinvesting profits; for this replace <strong>Capital</strong> with <strong>Equity</strong> in the <strong>rotate</strong> function. The blue bars are the account equity, the black line is the QQQ index. We can see that the account has far less drawdowns than the index. The black line in the small chart below is our trade volume, which is zero when a bear market is detected. The green line is the QQQ average, with bear market situations indicated in red. In 2022, the year when the Russian attack on Ukraine began, the system did not trade at all since the bear market filter was active almost the whole year.</p>
<p>The system produces 32% CAGR, with a 14% worst drawdown. This replicates Markos Katsanos’ results, but again, keep in mind that this is from an in-sample optimization. When applying walk-forward optimization (left as an exercise to the reader :), the CAGR goes down to 22%. Still a good performance, well beyond the NASDAQ index.</p>
<p>The code can be downloaded from the 2025 script repository.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://financial-hacker.com/a-better-stock-rotation-system/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
			</item>
	</channel>
</rss>
