Efficient frontier of an ETF portfolio, x = variance, y = annual return in %

Covariances |
A var[N*N] array containing the covariance matrix of the component returns. |

Means |
A var[N] array containing the mean of the component returns. |

N |
Number of components, at least 3. |

Cap |
Weight cap in 0..1 range; soft weight limit of a single asset at the minimum variance point, or 0 for no weight cap. |

Caps |
A var[N] array containing individual weight
limits in 0..1 range, or 0 for no weight cap. |

Weights |
A var[N] array to be filled with the capital allocation weights of the N portfolio components. The sum of the weights is 1. Pass 0 when no weights are needed. |

Variance |
The desired variance. When below the lowest variance, the return and weights at the left end of the efficient frontier are returned. |

Return |
The desired return. When below the lowest return of the efficient frontier, the variance and weights at the left end of the efficient frontier are returned. |

- For getting the minimum variance point, call
**markowitzReturn**with**Variance**at**0**. For maximum Sharpe ratio, call**markowitzReturn**with the**Variance**returned by**markowitz()**. For the maximum return point at the right side of the diagram, call**markowitzReturn**with**Variance**at**1**. For the maximum and minimum variances, call**markowitzVariance**with a return value above or below the maximum and minimum portfolio return. - Markowitz weights can be used alternatively to OptimalF factors for allocating capital to a portfolio system. Unlike
**OptimalF**, they require only a relatively short time horizon and thus can be adapted during live trading. For a long-term ETF rotation strategy, use the last year price returns of the ETFs (see example) and recalculate their markowitz weights every 4 weeks. - For calculating the returns of portfolio components with currently zero weight in real time, use phantom trades.
- It is often recommended to limit the asset weights with the
**Cap**or**Caps**parameter (f.i.**0.33**for 33% maximum weight) for getting a higher portfolio diversification. This makes the portfolio more stable and usually produces better out-of-sample results. The weight cap can be exceeded when it is too small and the resulting weights don't sum up to 1. For useful results, the weight cap should be at least two or three times the**1/N**minimum. - MVO fails when there is no point on the efficient frontier that represents the portfolio, for instance when all means are negative. This can lead to weights of zero or to a total weight less than 1.
- Applications of the
**markowitz**function are described in the Financial Hacker article Get Rich Slowly. - The Z8 and Z10 trading systems use this function for calculating optimal portfolio compositions.

#define N 10// 10 assets#define DAYS 252// 1 yearvars Returns[N]; var Means[N]; var Covariances[N][N]; function run() { BarPeriod = 1440; StartDate = 20150101; LookBack = DAYS; string Name; int n = 0; while(Name = loop(.../*list of 10 assets*/... )) { asset(Name); Returns[n] = series((price(0)-price(1))/price(1)); Means[n] = SMA(Returns[n],DAYS); n++; } int i,j; if(!is(LOOKBACK)) {// generate covariance matrixfor(i=0; i<N; i++) for(j=0; j<N; j++) Covariances[i][j] = Covariance(Returns[i],Returns[j],DAYS);// calculate efficient frontiervar OptimalV = markowitz(Covariances,Means,N); printf("\nBest daily return %.3f %% at variance %.4f", 100*markowitzReturn(0,OptimalV),OptimalV);// plot the frontierfor(i=1; i<70; i++) { var VStep = i*OptimalV*0.03; var Return = markowitzReturn(0,VStep); plotBar("Frontier",i,VStep,Return,LINE|LBL2,BLACK); } plotGraph("Max Sharpe",1./0.03,markowitzReturn(0,OptimalV),SQUARE,RED); PlotScale = 6; PlotHeight1 = 300; quit(""); } }