<?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>Portfolio rotation &#8211; The Financial Hacker</title>
	<atom:link href="https://financial-hacker.com/tag/portfolio-rotation/feed/" rel="self" type="application/rss+xml" />
	<link>https://financial-hacker.com</link>
	<description>A new view on algorithmic trading</description>
	<lastBuildDate>Sun, 27 Jul 2025 14:26:47 +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>Portfolio rotation &#8211; The Financial Hacker</title>
	<link>https://financial-hacker.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<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 fetchpriority="high" 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>
		<item>
		<title>Petra on Programming: Four Dimensions of Strength</title>
		<link>https://financial-hacker.com/petra-on-programming-4-dimensions-of-strength/</link>
					<comments>https://financial-hacker.com/petra-on-programming-4-dimensions-of-strength/#comments</comments>
		
		<dc:creator><![CDATA[Petra Volkova]]></dc:creator>
		<pubDate>Thu, 20 Aug 2020 10:37:07 +0000</pubDate>
				<category><![CDATA[Indicators]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Portfolio rotation]]></category>
		<category><![CDATA[RS4R]]></category>
		<guid isPermaLink="false">https://financial-hacker.com/?p=3585</guid>

					<description><![CDATA[In the S&#38;C September 2020 article &#8220;Tracking Relative Strength In Four Dimensions&#8221;, James Garofallou presents a metric for evaluating a security&#8217;s strength relative to 11 major market sectors and over several time periods. All this information is squeezed into a single value. Maybe at cost of losing other important information? In this article we&#8217;ll look &#8230; <a href="https://financial-hacker.com/petra-on-programming-4-dimensions-of-strength/" class="more-link">Continue reading<span class="screen-reader-text"> "Petra on Programming: Four Dimensions of Strength"</span></a>]]></description>
										<content:encoded><![CDATA[<p><em>In the S&amp;C September 2020 article &#8220;Tracking Relative Strength In Four Dimensions&#8221;, James Garofallou presents a metric for evaluating a security&#8217;s strength relative to 11 major market sectors and over several time periods. All this information is squeezed into a single value. Maybe at cost of losing other important information? In this article we&#8217;ll look into how to program such a beast, and how it fares when we use it for rebalancing a stock portfolio.</em><span id="more-3585"></span></p>
<p>For getting the 4-dimensional relative strength we start with two dimensions. The <strong>RS2</strong> indicator divides a securities&#8217; price by a market index, then calculates four moving averages of the result and encodes their relations in a number that is then returned. Here&#8217;s the RS2 code:</p>
<pre class="prettyprint">var RS2(var Close, string Index)
{
   assetAdd(strf("IDX%i",NumIndex),strf("YAHOO:%s",Index)); 
   if(!asset(Asset)) return quit("Index not found!");
   var RS2 = Close/priceClose(0);
   var Fast = EMA(series(RS2),10*PERIOD);
   var Med = SMA(series(Fast),7*PERIOD);
   var Slow = SMA(series(Fast),15*PERIOD);
   var VSlow = SMA(series(Slow),30*PERIOD);
   if(Fast &gt;= Med &amp;&amp; Med &gt;= Slow &amp;&amp; Slow &gt;= VSlow)
      return 10;
   else if(Fast &gt;= Med &amp;&amp; Med &gt;= Slow &amp;&amp; Slow &lt; VSlow)
      return 9;
   else if(Fast &lt; Med &amp;&amp; Med &gt;= Slow &amp;&amp; Slow &gt;= VSlow)
      return 9;
   else if(Fast &lt; Med &amp;&amp; Med &gt;= Slow &amp;&amp; Slow &lt; VSlow)
      return 5;
   else
      return 0;
}
</pre>
<p>The code above takes the Close of the security and the name of the index for the division. It gets the index price from Yahoo, then determines 4 moving averages as prescribed by the author, and returns either 10, 9, 5, or 0 depending on how fast the price quotient is rising. Note that I had to multiply all MA periods with a predefined PERIOD factor. That&#8217;s because I could at first not reproduce the author&#8217;s charts, until I found out that his MA periods are apparently not days, but candle width units of his chart. He used 3-day candles for some reason. So I had to multiply all MA periods with a PERIOD of 3. Without this correction, the resulting charts would be very different.</p>
<p>The next step is the RS4, which combines the RS2 values of 11 major market indexes. I used the same Fidelity indexes as the author. The C code of the RS4 indicator:</p>
<pre class="prettyprint">var RS4(var Close)
{
  var RS3 = RS2(Close,"FXAIX") // SPX 500
    + RS2(Close,"FNCMX") // Nasdaq
    + RS2(Close,"FSMDX") // Mid Cap
    + RS2(Close,"FSSNX") // Small Cap
    + RS2(Close,"FSPGX") // Large Growth
    + RS2(Close,"FLCOX") // Large Val
    + RS2(Close,"FPADX") // Emerging Market
    + RS2(Close,"FSRNX") // Real Estate
    + RS2(Close,"FSAGX") // Gold
    + RS2(Close,"FSUTX") // Utilities
    + RS2(Close,"FTBFX"); // Total Bond
  return 10*RS3/11;
}</pre>
<p>The returned value is multiplied with 10 and normalized by the number of indexes. Now we got all 4 dimensions together, the 4th one apparently being the normalization. We can now reproduce the author&#8217;s chart with a smoothed RS4 – named &#8220;RS4osc&#8221; – and a further smoothed signal line. For the security we&#8217;re using Fidelity Gold, FSAGX. The code:</p>
<pre class="prettyprint">voidrun()
{
  BarPeriod = 1440;
  StartDate = 20181201;
  EndDate = 20200415;
  LookBack = 200;
  assetAdd("Gold","YAHOO:FSAGX");
  asset("Gold");
  var RS4Osc = SMA(series(RS4(priceClose(0))),3*PERIOD);
  var Mv = SMA(series(RS4Osc),5*PERIOD);
  plot("RS4Osc",RS4Osc,NEW|LINE,BLUE);
  plot("Mv",Mv,LINE,RED);
}</pre>
<p>The resulting chart:</p>
<p><img decoding="async" src="https://financial-hacker.com/wp-content/uploads/2020/08/082020_1037_PetraonProg1-1.png" alt="" /></p>
<p>Before you even try: No, the red and blue line crossings in the chart do not indicate profitable trade entries. Not even the author claims that. So what do we do with this indicator? Since it represents strength, let&#8217;s try it in a basic portfolio rotation system. Of a universe of 10 major stocks, it shall select the 4 strongest stocks and invest in them according to their strength. The portfolio is rebalanced at any month. First, we use a simple momentum based strength. The code:</p>
<pre class="prettyprint">void run() 
{
  BarPeriod = 1440;
  LookBack = 200;
  StartDate = 2012;
  EndDate = 2020;
  Capital = 10000;
  var Weights[10],Strengths[10];
  string Stock,Stocks[10];
  assetList("assetsIB");
  while(Stock = loop("AAPL","MSFT","XOM","AMZN","JNJ","FB","GE","TSLA","JPM","PG"))
  {
    if(Init) assetHistory(Stock,FROM_STOOQ);
    asset(Stock);
    Stocks[Itor1] = Stock;
    Strengths[Itor1] = RET(30*PERIOD);
  }
  if(month(0) != month(1)) // at any month
  {
    distribute(Weights,Strengths,10,4,0);
    int i;
    for(i = 0; i&lt;10; i++) {
      asset(Stocks[i]);
      int NewShares = Weights[i]*Balance/priceClose(0) - LotsPool;
      if(NewShares &gt; 0)
        enterLong(NewShares);
      else if(NewShares &lt; 0)
        exitLong("",-NewShares);
    }
  } 
}</pre>
<p>I&#8217;ve used the 10 top stocks from the S&amp;P 500. The strength is simply defined as the stock return over 30*3 days, which is the same as the &#8220;very long&#8221; MA period of the RS2. The <a href="https://manual.zorro-project.com/distribute.htm">distribute</a> function in the code is a special Zorro function that sorts the stocks according to their strength, and assigns weights among the 4 strongest stocks. The remaining 6 weaker stocks get weight 0. The weights are then converted to positions and rebalanced at the first workday of any month by buying or selling stocks.</p>
<p>The resulting equity curve (mind the Covid-19 drop):</p>
<p><img decoding="async" src="https://financial-hacker.com/wp-content/uploads/2020/08/082020_1037_PetraonProg2-1.png" alt="" /></p>
<p>In the backtest from 2012-2020, this system achieves 47% CAGR, mostly due to the strong volatility at the end. It&#8217;s not an optimal system and you would probably not want to trade it live. Now what happens when we replace the 90-day return with the RS4? For this we only need to change the line where the strength is calculated:</p>
<pre class="prettyprint">Strengths[Itor1] = RS4(priceClose(0));</pre>
<p>The equity curve of the RS4-based portfolio rotation system:</p>
<p><img decoding="async" src="https://financial-hacker.com/wp-content/uploads/2020/08/082020_1037_PetraonProg3-1.png" alt="" /></p>
<p>The CAGR has dropped to 35%. The Covid-19 drop is not as significant, but the the recovery afterwards isn&#8217;t either. Although the equity curve looks less volatile, the Sharpe Ratio is in fact lower, 1.01 compared to 1.11 with the previous return-based system.</p>
<p>Does this mean that the RS4 is inferior to a simple 90-day return? No, because I just tried it with the first and simplest stock rotation system that came in mind. For really judging the RS4, a lot more tests with a lot more systems and with walk forward analysis had to be done.</p>
<p>The RS2 and RS4 indicators, as well as the code for the portfolio rotation system can be downloaded from the 2020 script repository.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://financial-hacker.com/petra-on-programming-4-dimensions-of-strength/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Get Rich Slowly</title>
		<link>https://financial-hacker.com/get-rich-slowly/</link>
					<comments>https://financial-hacker.com/get-rich-slowly/#comments</comments>
		
		<dc:creator><![CDATA[jcl]]></dc:creator>
		<pubDate>Sat, 02 Jul 2016 14:15:00 +0000</pubDate>
				<category><![CDATA[System Development]]></category>
		<category><![CDATA[Correlation matrix]]></category>
		<category><![CDATA[Covariance matrix]]></category>
		<category><![CDATA[Efficient frontier]]></category>
		<category><![CDATA[ETF]]></category>
		<category><![CDATA[Heatmap]]></category>
		<category><![CDATA[Markowitz]]></category>
		<category><![CDATA[Mean-variance optimization]]></category>
		<category><![CDATA[Money management]]></category>
		<category><![CDATA[MVO]]></category>
		<category><![CDATA[Portfolio rotation]]></category>
		<category><![CDATA[Robo-advisor]]></category>
		<category><![CDATA[Sharpe ratio]]></category>
		<guid isPermaLink="false">http://www.financial-hacker.com/?p=1702</guid>

					<description><![CDATA[Most trading systems are of the get-rich-quick type. They exploit temporary market inefficiencies and aim for annual returns in the 100% area. They require regular supervision and adaption to market conditions, and still have a limited lifetime. Their expiration is often accompanied by large losses. But what if you&#8217;ve nevertheless collected some handsome gains, and &#8230; <a href="https://financial-hacker.com/get-rich-slowly/" class="more-link">Continue reading<span class="screen-reader-text"> "Get Rich Slowly"</span></a>]]></description>
										<content:encoded><![CDATA[<p>Most trading systems are of the get-rich-quick type. They exploit temporary market inefficiencies and aim for annual returns in the 100% area. They require regular supervision and adaption to market conditions, and still have a limited lifetime. Their expiration is often accompanied by large losses. But what if you&#8217;ve nevertheless collected some handsome gains, and now want to park them in a more safe haven? Put the money under the pillow? Take it into the bank? Give it to a hedge funds? Obviously, all that goes against an algo trader&#8217;s honor code. Here&#8217;s an alternative.<span id="more-1702"></span></p>
<p>The old-fashioned investing method is buying some low-risk stocks and then waiting a long time. Any portfolio of stocks has a certain mean return and a certain fluctuation in value; you normally want to minimize the latter and maximize the former. Since the mean return and the fluctuation changes all the time, this task requires rebalancing the portfolio in regular intervals. The <strong>optimal capital allocation</strong> among the portfolio components produces either maximum mean return for a given allowed risk, or minimum risk &#8211; respectively, minimum variance &#8211; for a given mean return. This optimal allocation is often very different to investing the same amount in all N components of the portfolio. An easy way to solve this mean / variance optimization problem was published 60 years ago by <a href="https://en.wikipedia.org/wiki/Harry_Markowitz" target="_blank" rel="noopener noreferrer"><strong>Harry Markowitz</strong></a>. It won him later the Nobel prize.</p>
<h3>The unfashionable Markowitz</h3>
<p>Unfortunately, Markowitz got largely out of fashion since then. The problem is the same as with all trading algorithms: You can only calculate the optimal capital allocation in hindsight. Optimized portfolios mysteriously failed in live trading. They were said to often return less than a simple 1/N capital distribution. But this was challenged recently in <a href="http://papers.ssrn.com/sol3/papers.cfm?abstract_id=2606884">an interesting paper</a> (1) by Keller, Butler, and Kipnis, of which I quote the first paragraph:</p>
<p><em>Mean-Variance Optimization (MVO) as introduced by Markowitz (1952) is often presented as an elegant but impractical theory. MVO is an<strong> &#8220;unstable and error-maximizing</strong>&#8221; procedure (Michaud 1989), and is &#8220;<strong>nearly always beaten by simple 1/N portfolios</strong>&#8221; (DeMiguel, 2007). And to quote Ang (2014): &#8220;Mean-variance weights <strong>perform horribly</strong>… The optimal mean-variance portfolio is a complex function of estimated means, volatilities, and correlations of asset returns. There are many parameters to estimate. Optimized mean-variance portfolios can <strong>blow up</strong> when there are tiny errors in any of these inputs&#8230;&#8221;.</em></p>
<p>The optimized portfolios of the quoted authors indeed blew up. But Markowitz is not to blame. They just did not understand what &#8216;optimal capital allocation&#8217; means. Suppose you have a portfolio of very similar assets, all with almost identical mean return and variance, only one of them is a tiny bit better. The Markowitz algorithm will then tend to assign all capital to that single asset. That&#8217;s just logical, as it is the optimal capital allocation. But it&#8217;s not the optimal portfolio. You don&#8217;t want to expose all capital to a single stock. If that company goes belly up, your portfolio will too. This is the mentioned &#8216;stability problem&#8217;. However there is a simple and obvious solution: a per-asset weight limit.</p>
<p>Aside from that, the Markowitz vituperators used too long, mean-reverting time periods for sampling the returns and covariances, and they applied the MVO algorithm wrongly to mixed long/short portfolios. When correctly applied to a momentum-governed time period and long-only, well diversified portfolios with a weight limit, MVO produced out of sample results <strong>far superior to 1/N</strong>. This was proven by testing a number of example portfolios in (1) with a R MVO implementation by fellow blogger <a href="http://quantstrattrader.wordpress.com/">Ilya Kipnis</a>.</p>
<p>However, a R implementation is not very practical for live trading. For this we have to implement MVO in a real trade platform. Then we can park our money in an optimized portfolio of stocks and ETFs, let the platform rebalance the capital allocation in regular intervals, lean back, wait, and get rich slowly.</p>
<h3>Implementing MVO</h3>
<p>The Zorro implementation is based on Markowitz&#8217; 1959 publication (2). In chapter 8, he described the MVO algorithm in a clear and easy to follow way. For simple minded programmers like me, he even included a brief introduction to linear algebra! I only modified his original algorithm by adding the mentioned weight constraint. This constraint stabilizes the algorithm and keeps the portfolio diversified.</p>
<p>In wise anticipation of future computing machines, Markowitz also included an example portfolio for checking if you programmed his algorithm correctly. The proof:</p>
<pre class="prettyprint">function main()
{
	var Means[3] = { .062,.146,.128 };
	var Covariances[3][3] = {.0146,.0187,.0145,.0187,.0854,.0104,.0145,.0104,.0289};
	var Weights[3];
	
	var BestVariance = markowitz(Covariances,Means,3,0);

	markowitzReturn(Weights,1);
	printf("\nMax:  %.2f %.2f %.2f",Weights[0],Weights[1],Weights[2]);
	markowitzReturn(Weights,BestVariance);
	printf("\nBest: %.2f %.2f %.2f",Weights[0],Weights[1],Weights[2]);
	markowitzReturn(Weights,0);
	printf("\nMin:  %.2f %.2f %.2f",Weights[0],Weights[1],Weights[2]);
}</pre>
<p>The means and covariances arrays in the script are from Markowitz&#8217; example portfolio. The <strong>markowitz</strong> function runs the algorithm and returns the variance value associated with the best Sharpe ratio. The <strong>markowitzReturn</strong> function then calculates the capital allocation weights with the maximum mean return for a given variance. The weights for maximum, best, and minimum variance are printed. If I did it right, they should be exactly the same as in Markowitz&#8217; publication:</p>
<pre class="prettyprint">Max:  0.00 1.00 0.00
Best: 0.00 0.22 0.78
Min:  0.99 0.00 0.01
</pre>
<h3>Selecting the assets</h3>
<p>For long-term portfolios you can&#8217;t use the same high-leverage Forex or CFD instruments that you preferred for your short-term strategies. Instead you normally invest in stocks, ETFs, or similar instruments. They offer several advantages for algo trading:</p>
<ul style="list-style-type: square;">
<li><strong>No zero-sum game.</strong> In the long run, stocks and index ETFs have positive mean returns due to dividends and accumulated value, while Forex pairs and index CFDs have negative mean returns due to swap/rollover fees.<br />
  </li>
<li><strong>Serious brokers.</strong> Stock/ETF brokers are all regulated, what can not be said of all Forex/CFD brokers.<br />
  </li>
<li><strong>More data</strong> for your algorithms, such as volume and market depth information.<br />
  </li>
<li><strong>Bigger choice of assets</strong> from many different market sectors.<br />
   </li>
<li><strong>More trading methods,</strong> such as pairs trading (&#8220;stat arb&#8221;), trading risk-free assets such as T-bills, or trading volatility.</li>
</ul>
<p>The obvious disadvantage is low leverage, like 1:2 compared with 1:100 or more for Forex instruments. Low leverage is ok for a long-term system, but not for getting rich quick. More restrictions apply to long-term portfolios. MVO obviously won&#8217;t work well with components that have no positive mean return. And it won&#8217;t work well either when the returns are strongly correlated. So when selecting assets for your long-term portfolio, you have to look not only for returns, but also for correlation. Here&#8217;s the main part of a Zorro script for that:</p>
<pre class="prettyprint">#define NN  30  // max number of assets

function run()
{
	BarPeriod = 1440;
	NumYears = 7;
	LookBack = 6*252; // 6 years

	string	Names[NN];
	vars	Returns[NN];
	var	Correlations[NN][NN];

	int N = 0;
	while(Names[N] = loop( 
		"TLT","LQD","SPY","GLD","VGLT","AOK"))
	{
		if(is(INITRUN))
			assetHistory(Names[N],FROM_YAHOO);
		asset(Names[N]);
		Returns[N] = series((priceClose(0)-priceClose(1))/priceClose(1));
		if(N++ &gt;= NN) break;
	}
	if(is(EXITRUN)) {
		int i,j;
		for(i=0; i&lt;N; i++)
		for(j=0; j&lt;N; j++)
			Correlations[N*i+j] = 
				Correlation(Returns[i],Returns[j],LookBack);
		plotHeatmap("Correlation",Correlations,N,N);
		for(i=0; i&lt;N; i++)
			printf("\n%i - %s: Mean %.2f%%  Variance %.2f%%",
				i+1,Names[i],
				100*annual(Moment(Returns[i],LookBack,1)),
				252*100*Moment(Returns[i],LookBack,2));
	}
}
</pre>
<p>The script first sets up some parameters, then goes into a loop over <strong>N</strong> assets. Here I&#8217;ve just entered some popular ETFs; for replacing them, websites such as <a href="http://etfdb.com/etfs/">etfdb.com</a> give an overview and help searching for the optimal ETF combination.</p>
<p>In the initial run, the asset prices are downloaded from Yahoo. They are corrected for splits and dividends. The <strong>assetHistory</strong> function stores them as historical price data files. Then the assets are selected and their returns are calculated and stored in the <strong>Returns</strong> data series. This is repeated with all 1-day bars of a 7 years test period (obviously the period depends on since when the selected ETFs are available). In the final run the script prints the annual mean returns and variances of all assets, which are the first and second <strong>moments</strong> of the return series. The <strong>annual</strong> function and the 252 multiplication factor convert daily values to annual values. The results for the selected ETFs:</p>
<pre class="prettyprint">1 - TLT: Mean 10.75% Variance 2.29%
2 - LQD: Mean 6.46% Variance 0.31%
3 - SPY: Mean 13.51% Variance 2.51%
4 - GLD: Mean 3.25% Variance 3.04%
5 - VGLT: Mean 9.83% Variance 1.65%
6 - AOK: Mean 4.70% Variance 0.23%</pre>
<p>The ideal ETF has high mean return, low variance, and low correlation to all other assets of the portfolio. The correlation can be seen in the <strong>correlation matrix</strong> that is computed from all collected returns in the above code, then plotted in a <strong>N*N</strong> heatmap:</p>
<p><a href="http://www.financial-hacker.com/wp-content/uploads/2016/12/Heatmap_s-1.png"><img decoding="async" class="alignnone wp-image-1777 size-full" src="http://www.financial-hacker.com/wp-content/uploads/2016/12/Heatmap_s-1.png" width="379" height="351" srcset="https://financial-hacker.com/wp-content/uploads/2016/12/Heatmap_s-1.png 379w, https://financial-hacker.com/wp-content/uploads/2016/12/Heatmap_s-1-300x278.png 300w" sizes="(max-width: 379px) 85vw, 379px" /></a></p>
<p>The correlation matrix contains the correlation coefficients of every asset with every other asset. The rows and columns of the heatmap are the 6 assets. The colors go from blue for low correlation between the row and column asset, to red for high correlation. Since any asset correlates perfectly with itself, we always have a red diagonal. But you can see from the other red squares that some of my 6 popular ETFs were no good choice. Finding the perfect ETF combination, with the heatmap as blue as possible, is left as an exercise to the reader.</p>
<h3>The efficient frontier</h3>
<p>After selecting the assets for our portfolio, we now have to calculate the optimal capital allocation, using the MVO algorithm. However, &#8220;optimal&#8221; depends on the desired risk, i.e. volatility of the portfolio. For every risk value there&#8217;s a optimal allocation that generates the maximum return. So the optimal allocation is not a point, but a curve in the return / variance plane, named the <strong>Efficient Frontier</strong>. We can calculate and plot it with this script:</p>
<pre class="prettyprint">function run()
{
	... // similar to Heatmap script
 
	if(is(EXITRUN)) {
		int i,j;
		for(i=0; i&lt;N; i++) {
			Means[i] = Moment(Returns[i],LookBack,1);
			for(j=0; j&lt;N; j++)
				Covariances[N*i+j] =
					Covariance(Returns[i],Returns[j],LookBack);	
		}

		var BestV = markowitz(Covariances,Means,N,0);	
		var MinV = markowitzVariance(0,0);
		var MaxV = markowitzVariance(0,1);

		int Steps = 50;
		for(i=0; i&lt;Steps; i++) {
			var V = MinV + i*(MaxV-MinV)/Steps;
			var R = markowitzReturn(0,V);
			plotBar("Frontier",i,V,100*R,LINE|LBL2,BLACK);
		}
		plotGraph("Max Sharpe",(BestV-MinV)*Steps/(MaxV-MinV),
			100*markowitzReturn(0,BestV),SQUARE,GREEN);
	}
}</pre>
<p>I&#8217;ve omitted the first part since it&#8217;s identical to the heatmap script. Only the covariance matrix is now calculated instead of the correlation matrix. Covariances and mean returns are fed to the <strong>markowitz</strong> function that again returns the variance with the best Sharpe ratio. The subsequent calls to <strong>markowitzVariance</strong> also return the highest and the lowest variance of the efficient frontier and establish the borders of the plot. Finally the script plots 50 points of the annual mean return from the lowest to the highest variance:</p>
<p><a href="http://www.financial-hacker.com/wp-content/uploads/2016/12/EFrontier_s.png"><img decoding="async" class="alignnone wp-image-1780 size-full" src="http://www.financial-hacker.com/wp-content/uploads/2016/12/EFrontier_s.png" width="629" height="301" srcset="https://financial-hacker.com/wp-content/uploads/2016/12/EFrontier_s.png 629w, https://financial-hacker.com/wp-content/uploads/2016/12/EFrontier_s-300x144.png 300w" sizes="(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px" /></a></p>
<p>At the right side we can see that the portfolio reaches a maximum annual return of about 12.9%, which is simply all capital allocated to SPY. On the left side we achieve only 5.4% return, but with less than a tenth of the daily variance. The green dot is the point on the frontier with the best Sharpe ratio (= return divided by square root of variance) at 10% annual return and 0.025 variance. This is the optimal portfolio &#8211; at least in hindsight. </p>
<h3>Experiments</h3>
<p>How will a mean / variance optimized portfolio fare in an out of sample test, compared with with 1/N? Here&#8217;s a script for experiments with different portfolio compositions, lookback periods, weight constraints, and variances:</p>
<pre class="prettyprint">#define DAYS	252 // 1 year lookback period
#define NN	30  // max number of assets

function run()
{
	... // similar to Heatmap script

	int i,j;
	static var BestVariance = 0;
	if(tdm() == 1 &amp;&amp; !is(LOOKBACK)) {
		for(i=0; i&lt;N; i++) {
			Means[i] = Moment(Returns[i],LookBack,1);
			for(j=0; j&lt;N; j++)
				Covariances[N*i+j] = Covariance(Returns[i],Returns[j],LookBack);	
		}
		BestVariance = markowitz(Covariances,Means,N,0.5);
	}
	
	var Weights[NN]; 
	static var Return, ReturnN, ReturnMax, ReturnBest, ReturnMin;
	if(is(LOOKBACK)) {
		Month = 0;
		ReturnN = ReturnMax = ReturnBest = ReturnMin = 0;
	}

	if(BestVariance &gt; 0) {
		for(Return=0,i=0; i&lt;N; i++) Return += (Returns[i])[0]/N; // 1/N 
		ReturnN = (ReturnN+1)*(Return+1)-1;
		
		markowitzReturn(Weights,0);	// min variance
		for(Return=0,i=0; i&lt;N; i++) Return += Weights[i]*(Returns[i])[0];
		ReturnMin = (ReturnMin+1)*(Return+1)-1;
		
		markowitzReturn(Weights,1);	// max return
		for(Return=0,i=0; i&lt;N; i++) Return += Weights[i]*(Returns[i])[0];
		ReturnMax = (ReturnMax+1)*(Return+1)-1;

		markowitzReturn(Weights,BestVariance); // max Sharpe
		for(Return=0,i=0; i&lt;N; i++) Return += Weights[i]*(Returns[i])[0];
		ReturnBest = (ReturnBest+1)*(Return+1)-1;

		plot("1/N",100*ReturnN,AXIS2,BLACK);
		plot("Max Sharpe",100*ReturnBest,AXIS2,GREEN);
		plot("Max Return",100*ReturnMax,AXIS2,RED);
		plot("Min Variance",100*ReturnMin,AXIS2,BLUE);
	}
}</pre>
<p>The script goes through 7 years of historical data, and stores the daily returns in the <strong>Returns</strong> data series. At the first trading day of every month (<strong>tdm() == 1</strong>) it computes the means and the covariance matrix of the last 252 days, then calculates the efficient frontier. This time we also apply a 0.5 weight constraint to the minimum variance point. Based on this efficient frontier, we compute the daily total return with equal weights (<strong>ReturnN</strong>), best Sharpe ratio (<strong>ReturnBest</strong>), minimum variance (<strong>ReturnMin</strong>) and maximum Return (<strong>ReturnMax</strong>). The weights remain unchanged until the next rebalancing, this way establishing an out of sample test. The four daily returns are added up to 4 different equity curves :</p>
<p> <a href="http://www.financial-hacker.com/wp-content/uploads/2016/12/MVO_AOK-1.png"><img loading="lazy" decoding="async" class="alignnone wp-image-1788 size-full" src="http://www.financial-hacker.com/wp-content/uploads/2016/12/MVO_AOK-1.png" width="1079" height="301" srcset="https://financial-hacker.com/wp-content/uploads/2016/12/MVO_AOK-1.png 1079w, https://financial-hacker.com/wp-content/uploads/2016/12/MVO_AOK-1-300x84.png 300w, https://financial-hacker.com/wp-content/uploads/2016/12/MVO_AOK-1-768x214.png 768w, https://financial-hacker.com/wp-content/uploads/2016/12/MVO_AOK-1-1024x286.png 1024w" sizes="auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px" /></a></p>
<p>We can see that MVO improves the portfolio in all three variants, in spite of its bad reputation. The black line is the 1/N portfolio with equal weights for all asset. The blue line is the minimum variance portfolio &#8211; we can see that it produces slightly better profits than 1/N, but with much lower volatility. The red line is the maximum return portfolio with the best profit, but high volatility and sharp drawdowns. The green line, the maximum Sharpe portfolio, is somewhere inbetween. Different portfolio compositions can produce a different order of lines, but the blue and green lines have almost always a much better Sharpe ratio than the black line. Since the minimum variance portfolio can be traded with higher leverage due to the smaller drawdowns, it often produces the highest profits.</p>
<p>For checking the monthly rebalancing of the capital allocation weights, we can display the weights in a heatmap:</p>
<p><a href="http://www.financial-hacker.com/wp-content/uploads/2016/12/MVO_s.png"><img loading="lazy" decoding="async" class="alignnone wp-image-1790 size-full" src="http://www.financial-hacker.com/wp-content/uploads/2016/12/MVO_s.png" width="1551" height="162" srcset="https://financial-hacker.com/wp-content/uploads/2016/12/MVO_s.png 1551w, https://financial-hacker.com/wp-content/uploads/2016/12/MVO_s-300x31.png 300w, https://financial-hacker.com/wp-content/uploads/2016/12/MVO_s-768x80.png 768w, https://financial-hacker.com/wp-content/uploads/2016/12/MVO_s-1024x107.png 1024w, https://financial-hacker.com/wp-content/uploads/2016/12/MVO_s-1200x125.png 1200w" sizes="auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px" /></a></p>
<p>The horizontal axis is the month of the simulation, the vertical axis the asset number. High weights are red and low weights are blue. The weight distribution above is for the maximum Sharpe portfolio of the 6 ETFs.</p>
<h3>The final money parking system</h3>
<p>After all those experiments we can now code our long-term system. It shall work in the following way:</p>
<ul style="list-style-type: square;">
<li>The efficient frontier is calculated from daily returns of the last 252 trading days, i.e. one year. That&#8217;s a good time period for MVO according to (1), since most ETFs show 1-year momentum.<br />
  </li>
<li>The system rebalances the portfolio once per month. Shorter time periods, such as daily or weekly rebalancing, showed no advantage in my tests, but reduced the profit due to higher trading costs. Longer time periods, such as 3 months, let the system deteriorate.<br />
  </li>
<li> The point on the efficient frontier can be set up with a slider between minimum variance and maximum Sharpe. This way you can control the risk of the system. <br />
  </li>
<li>We use a 50% weight constraint at minimum variance. It&#8217;s then not anymore the optimal portfolio, but according to (1) &#8211; and my tests have confirmed this &#8211; it often improves the out of sample balance due to better diversification.</li>
</ul>
<p>Here&#8217;s the script:</p>
<pre class="prettyprint">#define LEVERAGE 4	// 1:4 leverage
#define DAYS	252 	// 1 year
#define NN	30	// max number of assets

function run()
{
	BarPeriod = 1440;
	LookBack = DAYS;

	string Names[NN];
	vars	Returns[NN];
	var	Means[NN];
	var	Covariances[NN][NN];
	var	Weights[NN];

	var TotalCapital = slider(1,1000,0,10000,"Capital","Total capital to distribute");
	var VFactor = slider(2,10,0,100,"Risk","Variance factor");
	
	int N = 0;
	while(Names[N] = loop( 
		"TLT","LQD","SPY","GLD","VGLT","AOK"))
	{
		if(is(INITRUN))
			assetHistory(Names[N],FROM_YAHOO);
		asset(Names[N]);
		Returns[N] = series((priceClose(0)-priceClose(1))/priceClose(1));
		if(N++ &gt;= NN) break;
	}

	if(is(EXITRUN)) {
		int i,j;
		for(i=0; i&lt;N; i++) {
			Means[i] = Moment(Returns[i],LookBack,1);
			for(j=0; j&lt;N; j++)
				Covariances[N*i+j] = Covariance(Returns[i],Returns[j],LookBack);	
		}
		var BestVariance = markowitz(Covariances,Means,N,0.5);
		var MinVariance = markowitzVariance(0,0);
		markowitzReturn(Weights,MinVariance+VFactor/100.*(BestVariance-MinVariance));

		for(i=0; i&lt;N; i++) {
			asset(Names[i]);
			MarginCost = priceClose()/LEVERAGE;
			int Position = TotalCapital*Weights[i]/MarginCost;
			printf("\n%s:  %d Contracts at %.0f$",Names[i],Position,priceClose());
		}
	}
}</pre>
<p>On Zorro&#8217;s panel you can set up the invested capital with a slider (<strong>TotalCapital</strong>) between 0 and 10,000$. A second slider (<strong>VFactor</strong>) is for setting up the desired risk from 0 to 100%: At 0 you&#8217;re trading with minimum variance, at 100 with maximum Sharpe ratio.</p>
<p><a href="http://www.financial-hacker.com/wp-content/uploads/2016/05/sliders.png"><img loading="lazy" decoding="async" class="alignnone wp-image-1808 size-full" src="http://www.financial-hacker.com/wp-content/uploads/2016/05/sliders.png" width="289" height="85" /></a></p>
<p>This script advises only, but does not trade: For automated trading it, you would need an <a href="http://www.financial-hacker.com/dear-brokers/" target="_blank" rel="noopener noreferrer">API plugin</a> to a ETF broker, such as IB. But the free Zorro version only has plugins for Forex/CFD brokers; the IB plugin is not free. However, since positions are only opened or closed once per month and price data is free from Yahoo, you do not really need an API connection for trading a MVO portfolio. Just fire up the above script once every month, and check what it prints out:</p>
<pre class="prettyprint">TLT:  0 Contracts at 129$
LQD:  0 Contracts at 120$
SPY:  3 Contracts at 206$
GLD:  16 Contracts at 124$
VGLT:  15 Contracts at 80$
AOK:  0 Contracts at 32$
</pre>
<p>Apparently, the optimal portfolio for this month consists of 3 contracts SPY, 16 contracts GLD, and 15 VGLT contracts. You can now manually open or close those positions in your broker&#8217;s trading platform until your portfolio matches the printed advice. Leverage is 4 by default, but you can change this to your broker&#8217;s leverage in the #define at the begin of the script. For a script that trades, simply replace the <strong>printf</strong> statement with a trade command that opens or closes the difference to the current position of the asset. This, too, is left as an exercise to the reader&#8230;</p>
<h3>MVO vs. OptimalF</h3>
<p>It seems natural to use MVO not only for a portfolio of many assets, but also for a portfolio of many trading systems. I&#8217;ve tested this with the <a href="http://manual.zorro-project.com/zsystems.htm" target="_blank" rel="noopener noreferrer">Z12 system</a> that comes with Zorro and contains about 100 different system/asset combinations. It turned out that MVO did not produce better results than Ralph Vince&#8217;s <strong>OptimalF</strong> factors that are originally used by the system. OptimalF factors do not consider correlations between components, but they do consider the drawdown depths, while MVO is only based on means and covariances. The ultimate solution for such a portfolio of many trading systems might be a combination of MVO for the capital distribution and OptimalF for weight constraints. I have not tested this yet, but it&#8217;s on my to do list.</p>
<p>I&#8217;ve added all scripts to the 2016 script repository. You&#8217;ll need Zorro 1.44 or above for running them. And after you made your first million with the MVO script, don&#8217;t forget to <a href="http://manual.zorro-project.com/restrictions.htm" target="_blank" rel="noopener noreferrer">sponsor</a> Zorro generously! <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<hr />
<h3>Papers</h3>
<ol>
<li>Momentum and Markowitz &#8211; A Golden Combination: <a href="http://papers.ssrn.com/sol3/papers.cfm?abstract_id=2606884" target="_blank" rel="noopener noreferrer">Keller.Butler.Kipnis.2015</a><br />
  </li>
<li>Harry M. Markowitz, Portfolio Selection, Wiley 1959<br />
  </li>
<li>MVO overview at <a href="https://www.guidedchoice.com/video/dr-harry-markowitz-father-of-modern-portfolio-theory/" target="_blank" rel="noopener noreferrer">guidedchoice.com</a></li>
</ol>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://financial-hacker.com/get-rich-slowly/feed/</wfw:commentRss>
			<slash:comments>89</slash:comments>
		
		
			</item>
	</channel>
</rss>
