Smart alternative for brute force nested looping minimum variance approach?

For an Adaptive Asset Allocation strategy involving momentum, volatility and correlation, I am looking for a smart alternative for the current "brute force" approach for establishing the minimum variance portfolio under a long only constraint.

Given a covariance matrix and a return matrix for 3 assets, the code below calculates 3 portfolios:

  • minimum variance portfolio (unconstrained: long/short)
  • tangency portfolio (idem)
  • long only minimum variance portfolio

The first two portfolios are determined with just a couple of neat matrix calculations, without using/requiring any looping. However, establishing the portfolio weights for the last portfolio depends currently on nested looping needing the following number of cycles (per bar!):

  • 2 asset portfolio: 101 cycles
  • 3 asset portfolio: 5,151 cycles
  • 4 asset portfolio: 177K cycles
  • 5 asset portfolio: 4.7M cycles

A smarter approach would be very welcome.

JW

Matrix Results

R = MxFromString( "[ 20.0253; 20.0869; 16.3860 ]" );
A = MxFromString( "[ 0.01012086, 0.00665194, -0.00489317; 0.00665194, 0.00877455, 0.00091096; -0.00489317, 0.00091096, 0.01827133 ]" );

// --- init matrices ---
B = Matrix( 3 , 1 , 1 );
X = Matrix( 3 , 1 , 0 );
W = Matrix( 3 , 1 , 0 );

// --- minimum variance portfolio (unconstrained) ---

X  = MxInverse( A ) @ B; 
Y  = MxSum( X );
W  = X / Y;
T  = MxSum( W );

SD = ( ( MxTranspose( W ) @ A ) @ W ) * sqrt( 12 );
SD = MxSum( SD );		
SD = sqrt( SD ) * 100;		
				
P  = MxTranspose( R ) @ W;
P  = MxSum( P );

printf( " Covariance matrix: " + "\n" + MxToString( A ) + "\n" );
printf( " Expected returns: " + "\n" + MxToString( R ) + "\n" );
printf( " ############################################################ " + "\n" );
printf( "\n" );
printf( " Minimum Variance Portfolio (Unconstrained) " + "\n" );
printf( "\n" );
printf( " Matrix W: " + "\n" + MxToString( W * 100 ) + "\n" );
printf( " Sum W	: " + NumToStr( T * 100 ) + "\n" );
printf( " Return	: " + P + "\n" );
printf( " SD	: " + SD + "\n" );

// --- tangency portfolio (unconstrained) ---

E  = R - 5;
X  = MxInverse( A ) @ E; 
Y  = MxSum( X );
W  = X / Y;
T  = MxSum( W );

SD = ( ( MxTranspose( W ) @ A ) @ W ) * sqrt( 12 );
SD = MxSum( SD );		
SD = sqrt( SD ) * 100;		
				
P  = MxTranspose( R ) @ W;
P  = MxSum( P );

printf( " ############################################################ " + "\n" );
printf( "\n" );
printf( " Tangency Portfolio (Unconstrained, RF=5%%) " + "\n" );
printf( "\n" );
printf( " Matrix W: " + "\n" + MxToString( W * 100 ) + "\n" );
printf( " Sum W	: " + NumToStr( T * 100 ) + "\n" );
printf( " Return	: " + P + "\n" );
printf( " SD	: " + SD + "\n" );
printf( " ############################################################ " + "\n" );

// --- minimum variance portfolio (long only) ---

printf( "\n" );
printf( " Long Only Minimum Variance Portfolio " );

// init values ---
MinV   = 100;
cnt    = 0;

for ( i = 100 ; i >= 0;  i-- )
{	
	jMax = 100 - i;
	
	for ( j = jMax ; j >= 0 ;  j-- )	
	{
		if( i + j == 100 )
		{
			X[0][0] = i;
			X[1][0] = j;
			X[2][0] = 0;
		} else {
			X[0][0] = i;
			X[1][0] = j;
			X[2][0] = 100 - i - j;
		}

		cnt++;
												
		X    = X / 100;
		SD   = ( ( MxTranspose( X ) @ A ) @ X ) * sqrt( 12 );
		SD   = MxSum( SD );		
		SD   = sqrt( SD ) * 100;		
		P    = MxTranspose( R ) @ X;		
		P    = MxSum( P );					
						
		 // printf( MxToString( X * 100 ) + "\n" + " Sum: " + NumToStr( MxSum( X * 100 ) ) + "   &   SD: " + NumToStr( SD ) + "   &   Return: " + NumToStr( P ) + "\n" );
		
		if ( SD < MinV ) W = X;						
		MinV = Min( MinV, SD );
	}
}

printf( " (Weight Combinations: " + NumToStr( cnt ) + ")" + "\n" );
printf( "\n" );

SD   = ( ( MxTranspose( W ) @ A ) @ W ) * sqrt( 12 );
SD   = MxSum( SD );		
SD   = sqrt( SD ) * 100;		
				
P  = MxTranspose( R ) @ W;
P  = MxSum( P );

printf( " Matrix W: " + "\n" + MxToString( W * 100 ) + "\n" );
printf( " Sum W: " + NumToStr( T * 100 ) + "\n" );
printf( " Return	: " + P + "\n" );
printf( " SD	: " + SD + " (Min.SD: " + MinV + ")" + "\n" );

printf( " ############################################################ " + "\n" );

2 Likes

@TrendXplorer
Will this help?
I used this to code AFL from octave code.
The article describes the usual approach for EF:-Ef, global min var, target return
Not sure there is a quick loopless solution, but perhaps a way forward.
http://www.calculatinginvestor.com/2011/06/21/efficient-frontier-3/
fe

1 Like

Thanks for the references.

In the meantime I've found a solution without the need for brute force loops. The test setup handily finds solutions for larger variance-covariance matrices like 10x10 sized.

Solution

I used the above code provided by TrendXplorer which was a demo with some hard coded data .... and added some code to read a watchlist and process the issues in watchlist... in order to get a better appreciation of the MVP method.
My code is set to read a watchlist named "SP Sectors".

The code looks at 60 bar ROC to use as expected returns. (the 60 day setting is set as a parameter. Another parameter , lookback, in included to look at earlier data as a debug helper.

Have a couple of questions:

  1. I understand that MVP in general is very sensitive to inputs of expected returns and their distributions. Has anyone used MVP enough to have an opinion?

  2. The computation of portfolio Standard deviation is SD = ( ( MxTranspose( W ) @ A ) @ W ) * sqrt( 12 ); What is the purpose of the term sqrt(12)?

  3. Has anyone read the paper "Estimating the Global Minimum Variance Portfolio" by Alexander Kempf and Christoph Memmel? They seem to address the issue of distributions ... or at least evaluate them
    Their paper can be found at https://www.researchgate.net/publication/23544904_Estimating_the_Global_Minimum_Variance_Portfolio

Appreciate any feedback
Ara

My code additions are below:

//File: DEV MV Portfolio-2
// February 2018
//
//
//
//This program calculates Global Minimum Variance Portfolio, Tangency Portfolio and Long Only portfolio
//
// Program uses matrix algebra to do calculation
// based on paper "Portfolio Theory with matrix Algebra" - November 9 2011 - Author  not specified
// MVP calculation segment from Amibroker Forum - posted by TrendXplorer
// The code copied from the forum works with hard codes sample data and prints out debug data in interpretation window.
//
// Data needed:
// Expected Returns: Momentum for and standard deviation for specified period
//
// Calculate variances of expected returns (sigma squared) and co-variances - fill in matrix
//
// Sample of Variance and co-variance matrix for 3 element portfolio (A,B,C)
//		s2A           corrAB*sA*sB     corrAC*sA*sC     		s is standard deviation,  2 signifies squared, sA is standard deviation for A
//		corrAB*sA*sB  s2B              corrBC*sB*sC
//		corrAC*sA*sC  corrBC*sB*sC     s2C
//
// Parameters:
// - period:    sample period for momentum (expected return proxy) and standard deviation
// - lookback:  useful for debug purposes - moves back sample period by specified number of bars
// - testdata:  Uses the sample data provided by original code (for debug purposes)
//
// Enhancements to original code copied from Amibroker forum:
// - Code reads from specified watch list and computes the portfolios and displays all data on screen. The watchlist name is hard coded.
// - The code was developed with 23 inch monitor. Only minimal effort was spent to accomodate other size screens.
// - This code has been tested with a watchlist containg up to 12 symbols. Program will automatically adjust for the number of symbols.
// - The original printing in interpretation window is retained.
//
testdata	= Param( "testdata", 0, 0, 1, 1 );
SetBarsRequired( 100000, 100000 );
//
// =====================================================================================================================================
//Read Watchlist and compute number of items, momentum and standard deviation
//Compute number of issues
WL_Name 	 	= "SP Sectors"; //"MVP Develop";
WL_Num	  		= CategoryFind( WL_Name, CategoryWatchlist );
WL_List   		= CategoryGetSymbols( CategoryWatchlist, WL_Num, 0 ) ; // Get ticker symbols in CSV format
WL_Count	    = StrCount( WL_List, "," ) + 1 ;

//
if( testdata )  WL_Count = 3;											// Number of symbols in watchlist

printf( "Count " + WL_Count + "\n" );
//

//
// =====================================================================================================================================
// Create expected return matricx
//
ERmx		= Matrix( WL_count, 1, 0 );								// Expected Returns (% momentum)
//
// =====================================================================================================================================
// Print the Watchlist Issues, Momentum and Standard Deviation, as inputs to system
period		= Param( "period", 60, 20, 252, 10 );													// Momentum and standard deviation
Lookback	= Param( "Lookback", 0, 0, 264, 22 );													// ignore last lookback bars - for debug only


//
_TRACE( "MVP-array - barIndex " + WriteVal( LastValue( BarIndex(), 1.0 ) ) );

//
//	for( i = 0; ( sym = StrExtract( WL_List, i ) ) != ""; i++ )
for( i = 0; ( sym = StrExtract( WL_List, i ) ) != "" AND i < WL_Count; i++ )
    //for( i = 0; i<3; i++ )
{
    Price 		= Foreign( sym, "C" );
    momentum	= Ref( ROC( price, period ), -Lookback );				// expected return
    St_dev		= Ref( StDev( price, period ) / 100, -Lookback );
    /*
    for (k=41; k<44; k++)
    {
    _TRACE( "MVP-array - barcount " + WriteVal(BarCount,1.0) + "  k " + Writeval( k, 1.0 ) + "  sym = " + sym + WriteVal(price[k],1.2) );
    }
    */
    VarSetText( "name_"  + NumToStr( i, 1.0 ) , sym );
    VarSet( "mom_" 		+ NumToStr( i, 1.0 ) , momentum );
    VarSet( "stdev_" 	+ NumToStr( i, 1.0 ) , St_dev );
    VarSet( "price_"		+ NumToStr( i, 1.0 ) , price );
    //
    //Enter values into Matrix form
    ERmx[i][0]			= LastValue( momentum ) ;		// Verify if last value is end of period or end of array ???????  ZZZZZZZZZZZ


    //Test data
    if( testdata )
    {
        VarSetText( "name_"  + NumToStr( 0, 1.0 ) , "A" );
        VarSet( "mom_" 		+ NumToStr( 0, 1.0 ) , 20.0253 );
        VarSet( "stdev_" 	+ NumToStr( 0, 1.0 ) , 0.1 );
        ERmx[0][0]			= 20.0253;
        //
        VarSetText( "name_"  + NumToStr( 1, 1.0 ) , "B" );
        VarSet( "mom_" 		+ NumToStr( 1, 1.0 ) , 20.0869 );
        VarSet( "stdev_" 	+ NumToStr( 1, 1.0 ) , .1044 );
        ERmx[1][0]			= 20.0869;
        //

        VarSetText( "name_"  + NumToStr( 2, 1.0 ) , "C" );
        VarSet( "mom_" 		+ NumToStr( 2, 1.0 ) , 16.3860 );
        VarSet( "stdev_" 	+ NumToStr( 2, 1.0 ) , .1411 );
        ERmx[2][0]			= 16.3860;
    }





    //
    printf( "Symbol  " + VarGetText( "name_" + NumToStr( i, 1.0 ) ) + "  mom " + VarGet( "mom_" + NumToStr( i, 1.0 ) ) + "  price " + VarGet( "price_" + NumToStr( i, 1.0 ) ) + "  std " + VarGet( "stdev_" + NumToStr( i, 1.0 ) ) + "\n" );
    printf( "Symbol  " + VarGetText( "name_" + NumToStr( i, 1.0 ) ) + "  mom " + LastValue( momentum ) + "  price " + VarGet( "price_" + NumToStr( i, 1.0 ) ) + "  std " + LastValue( St_dev ) + "\n" );

}

//GfxDrawText( "AAPL",x1, (y2 + (3*y_inc)), (x1 + textblock), (y2 + (4*y_inc)) , TA_Center );
//printf("x1 " + x1 + "  y1 " + y2 + " textblock "  + textblock + "  y_inc " + y_inc +"\n");
//printf("x1 " + x1 + "  y1 " + (y2 + (3*y_inc))  + "  x2 " + (x1 + textblock) + "  y2 " + (y2 + (4*y_inc)) + "\n");
//
// =====================================================================================================================================
//Compute covariance values and populate matrices
//WL_Count		= 3;
// lookback		= 60;
VarMx			= Matrix( WL_Count, WL_Count, 0 );
//
//

//
for( i = 0; i < WL_Count; i++ )
{
    for( j = 0; j < WL_Count; j++ )
    {
        Corrxy		= Correlation( VarGet( "price_" + NumToStr( i, 1.0 ) ), VarGet( "price_" + NumToStr( j, 1.0 ) ), period );			// OK
        Covarxy		= Corrxy * VarGet( "stdev_" + NumToStr( i, 1.0 ) ) * VarGet( "stdev_" + NumToStr( j, 1.0 ) ) ;					// OK
        //
        //Corrxy		= LastValue(Correlation(VarGet( "price_" + NumToStr( i, 1.0 )), VarGet( "price_" + NumToStr( j, 1.0 )), period));
        //Covarxy		= Corrxy * LastValue(VarGet( "stdev_" + NumToStr( i, 1.0 ) ) * VarGet( "stdev_" + NumToStr( j, 1.0 ))) ;
        printf( "i " + i + "  j " + j + "Corrxy " + WriteVal( LastValue( corrxy ), 1.4 ) +  "  covarxy " + WriteVal( LastValue( covarxy ), 1.4 ) + "\n" );
        VarMx[i][j]	= LastValue( covarxy );
        //
        printf( "i " + i + "  i-std " + LastValue( VarGet( "stdev_" + NumToStr( i, 1.0 ) ) ) + "  j " + j + "  j-std " + LastValue( VarGet( "stdev_" + NumToStr( j, 1.0 ) ) )
                + " sij " + LastValue( VarGet( "stdev_" + NumToStr( i, 1.0 ) ) ) * LastValue( VarGet( "stdev_" + NumToStr( j, 1.0 ) ) ) + "\n" );
        //

        if( testdata )
        {
            VarMx[0][0]		= 0.01012086;
            VarMx[0][1]		= 0.00665194;
            VarMx[0][2]		= -0.00489317;
            VarMx[1][0]		= 0.00665194;
            VarMx[1][1]		= 0.00877455;
            VarMx[1][2]		= 0.00091096;
            VarMx[2][0]		= -0.00489317;
            VarMx[2][1]		= 0.00091096;
            VarMx[2][2]		= 0.01827133;
        }


    }
}

R	= ERMx;
A	= VarMx;
//
//
// --- minimum variance portfolio (unconstrained) ---
//
B = Matrix( WL_Count , 1 , 1 );
X = Matrix( WL_Count , 1 , 0 );
//
//X  = MxInverse( A ) @ B;
X  = MxSolve( A, B );
Y  = MxSum( X );
W  = X / Y;													// Portfolio weights
T  = MxSum( W );

SD = ( ( MxTranspose( W ) @ A ) @ W ) * sqrt( 12 / 30 * period ); // sqrt(12) - annualize standard deviation
SD = MxSum( SD );
SD = sqrt( SD ) * 100;

P  = MxTranspose( R ) @ W;
P  = MxSum( P );
//
SD1 = SD;
P1  = P;
W1	= W;														// Save Matrix for printing
printf( " Covariance matrix: " + "\n" + MxToString( A ) + "\n" );
printf( " Expected returns: " + "\n" + MxToString( R ) + "\n" );
printf( " ############################################################ " + "\n" );
printf( "\n" );
printf( " Minimum Variance Portfolio (Unconstrained) " + "\n" );
printf( "\n" );
printf( " Matrix W: " + "\n" + MxToString( W * 100 ) + "\n" );
printf( " Sum W	: " + NumToStr( T * 100 ) + "\n" );
printf( " Return	: " + P + "\n" );
printf( " SD	: " + SD + "\n" );
//
/*
//Fill in Weight Matrix
for (i=0; i<WL_Count; i++)
{
WeightMx[i][0]	=	W1[i][0]*100 
}
//
*/
// ============================================================================================================================================

//
// ============================================================================================================================================
// --- tangency portfolio (unconstrained) ---

E  = R - 5;
//X  = MxInverse( A ) @ E;
X  = MxSolve( A, E );
Y  = MxSum( X );
W  = X / Y;															// Portfolio weights
T  = MxSum( W );

SD = ( ( MxTranspose( W ) @ A ) @ W ) * sqrt( 12 / 30 * period );
SD = MxSum( SD );
SD = sqrt( SD ) * 100;

P  = MxTranspose( R ) @ W;
P  = MxSum( P );
//
SD2 = SD;
P2  = P;
W2	= W;
//
//WeightMx[0][0]		=
printf( " ############################################################ " + "\n" );
printf( "\n" );
printf( " Tangency Portfolio (Unconstrained, RF=5%%) " + "\n" );
printf( "\n" );
printf( " Matrix W: " + "\n" + MxToString( W * 100 ) + "\n" );
printf( " Sum W	: " + NumToStr( T * 100 ) + "\n" );
printf( " Return	: " + P + "\n" );
printf( " SD	: " + SD + "\n" );
printf( " ############################################################ " + "\n" );
//

// --- minimum variance portfolio (long only) ---

printf( "\n" );
printf( " Long Only Minimum Variance Portfolio " );

// init values ---
MinV   = 100;
cnt    = 0;

for( i = 100 ; i >= 0;  i-- )
{
    jMax = 100 - i;

    for( j = jMax ; j >= 0 ;  j-- )
    {
        if( i + j == 100 )
        {
            X[0][0] = i;
            X[1][0] = j;
            X[2][0] = 0;
        }
        else
        {
            X[0][0] = i;
            X[1][0] = j;
            X[2][0] = 100 - i - j;
        }

        cnt++;

        X    = X / 100;
        SD   = ( ( MxTranspose( X ) @ A ) @ X ) * sqrt( 12 / 30 * period );
        SD   = MxSum( SD );
        SD   = sqrt( SD ) * 100;
        P    = MxTranspose( R ) @ X;
        P    = MxSum( P );

        // printf( MxToString( X * 100 ) + "\n" + " Sum: " + NumToStr( MxSum( X * 100 ) ) + "   &   SD: " + NumToStr( SD ) + "   &   Return: " + NumToStr( P ) + "\n" );

        if( SD < MinV ) W = X;

        MinV = Min( MinV, SD );
    }
}

printf( " (Weight Combinations: " + NumToStr( cnt ) + ")" + "\n" );
printf( "\n" );

SD   = ( ( MxTranspose( W ) @ A ) @ W ) * sqrt( 12 ); / 30 * period );
SD   = MxSum( SD );
SD   = sqrt( SD ) * 100;

P  = MxTranspose( R ) @ W;
P  = MxSum( P );
//
SD3 = SD;
P3  = P;
W3	= W;
//

printf( " Matrix W: " + "\n" + MxToString( W * 100 ) + "\n" );
printf( " Sum W: " + NumToStr( T * 100 ) + "\n" );
printf( " Return	: " + P + "\n" );
printf( " SD	: " + SD + " (Min.SD: " + MinV + ")" + "\n" );
//

printf( " ############################################################ " + "\n" );
//
//
//Draw Screen background
TA_CENTER = 1;	  	 													// Used for gfx text formating
TA_Left   = 0;
TA_Right  = 2;
//
x1		  	= 5;
x2			= x1 + 100;
x3			= x2 + 100;
x4			= 400;
x5			= x4 + 100;
x6			= x5 + 100;
x7			= 830;
y_header  	= 20;
y1		  	= 100;
y2		  	= 80;
y3			= 350;

headerBlock	= 300;
textblock	= 120;

//
n			= 0;
pxheight	= Status( "pxheight" );
pxwidth 	= Status( "pxwidth" );
hd_font		= Min(int(pxwidth / 55),18);
tx_font		= Min(int(pxwidth / 80),12);
y_inc		= Min(int(pxheight / 40),18);  //20;
//
printf("PW " + pxwidth + "\n");

//Create Screeen Text and Headings
// =====================================================================================================================================
//Create Graphics background and text headings
GfxSetTextColor( colorBlack );
GfxSelectSolidBrush( colorLightYellow );
GfxSetBkColor( colorLightYellow );
//
GfxRectangle( 1, 1, pxwidth, pxheight );
GfxSelectFont( "Arial", pointsize = hd_font, weight = 1, italic = False, underline = False, orientation = 0 ) ;
GfxDrawText( "Minimum Variance Portfolio-2", pxwidth / 2 - HeaderBlock, y_header, pxwidth / 2 + HeaderBlock , y_header + 30, TA_Center );
//
GfxSelectFont( "Arial", pointsize = tx_font, weight = 1, italic = False, underline = False, orientation = 0 ) ;
GfxDrawText( "Portfolio", x1, y2, x1 + TextBlock , y2 + y_inc, TA_Center );
GfxDrawText( "Components", x1, y2 + y_inc, x1 + TextBlock , y2 + ( 2 * y_inc ), TA_Center );
GfxDrawText( "Momentum", x2, y2, x2 + TextBlock , y2 + y_inc, TA_Center );
GfxDrawText( "%", x2, y2 + y_inc, x2 + TextBlock , y2 + ( 2 * y_inc ), TA_Center );
GfxDrawText( "StDev", x3, y2, x3 + TextBlock , y2 + y_inc, TA_Center );
GfxDrawText( "%", x3, y2 + y_inc, x3 + TextBlock , y2 + ( 2 * y_inc ), TA_Center );
//
x_offset1	= 100;
x_offset2	= 200;
GfxDrawText( "Weights  %",   x5, y2, x5 + TextBlock , y2 + y_inc, TA_Center );
GfxDrawText( "Normal",    x4, y2 + y_inc, x4 + TextBlock , y2 + ( 2 * y_inc ), TA_Center );
GfxDrawText( "Tangent",   x5, y2 + y_inc, x5 + TextBlock , y2 + ( 2 * y_inc ), TA_Center );
GfxDrawText( "Long Only", x6, y2 + y_inc, x6 + TextBlock , y2 + ( 2 * y_inc ), TA_Center );
//
GfxDrawText( "Parameters",    x7, y2 + (1*y_inc), x7 + TextBlock , y2 + ( 2 * y_inc ), TA_Center );
GfxDrawText( "Period:",       x7-10, y2 + (3*y_inc), x7-10 + TextBlock , y2 + ( 4 * y_inc ), TA_Left );
GfxDrawText( "Lookback:",     x7-10, y2 + (4*y_inc), x7-10 + TextBlock , y2 + ( 5 * y_inc ), TA_Left );
GfxDrawText( NumToStr(period,1.0),     x7, y2 + (3*y_inc), x7 + TextBlock , y2 + ( 4 * y_inc ), TA_Right );
GfxDrawText( NumToStr(lookback,1.0),   x7, y2 + (4*y_inc), x7 + TextBlock , y2 + ( 5 * y_inc ), TA_Right );
//
// =====================================================================================================================================

//
//Draw All input data (Issues, Mementum, StDev) and computed portfolio weights

x_offset		= 0;
y_offset		= 3;
x_inc			= 100;
numblock		= 85;
textblock		= 130;

//Print Assigned weights to screen
for( i = 0; i < WL_Count; i++ )
{
//Momentum and Standard Deviation values shown on screen are multiplied by 100 to show as percentages - NOT DONE

	GfxDrawText( NumToStr( i, 1.0 ), 5, y2 + ( ( y_offset + i )*y_inc ), x1 + 20, y2 + ( ( y_offset + i + 1 )*y_inc ) , TA_Right );	
    GfxDrawText( VarGetText( "name_" + NumToStr( i, 1.0 ) ), x1 - 30, y2 + ( ( y_offset + i )*y_inc ), x1 + TextBlock, y2 + ( ( y_offset + i + 1 )*y_inc ) , TA_Center );					  // Display symbol
    GfxDrawText( NumToStr( LastValue( VarGet( "mom_"   + NumToStr( i, 1.0 ) ) ), 1.4 ), x2, y2 + ( ( y_offset + i )*y_inc ), x2 + NumBlock, y2 + ( ( y_offset + i + 1 )*y_inc ) , TA_Right ); // Display momentum
    GfxDrawText( NumToStr( LastValue( VarGet( "stdev_" + NumToStr( i, 1.0 ) )*100 ), 1.4 ), x3, y2 + ( ( y_offset + i )*y_inc ), x3 + NumBlock, y2 + ( ( y_offset + i + 1 )*y_inc ) , TA_Right ); // Display standard Deviation
    //_TRACE( "MVP - i " + Writeval( i, 1.0 ) + "  sym = " + sym +  "  mom " + Writeval(VarGet("mom_" + NumToStr(i,1.0)),1.4) + "  price " + Writeval(VarGet("price_" + NumToStr(i,1.0)),1.2)
    //		+ "  std " + Writeval(VarGet("stdev_" + NumToStr(i,1.0)),1.2) );
    _TRACE( "MVP - i " + Writeval( i, 1.0 ) + "  sym = " + sym +  "  mom " + Writeval( LastValue( momentum ), 1.4 ) + "  price " + Writeval( price, 1.2 )
            + "  std " + Writeval( LastValue( St_dev ), 1.2 ) ) ;

    GfxDrawText( NumToStr( W1[i][0] * 100, 1.2 ), x4, y2 + ( ( y_offset + i )*y_inc ), x4 + NumBlock, y2 + ( ( y_offset + i + 1 )*y_inc ) , TA_Right );
    GfxDrawText( NumToStr( W2[i][0] * 100, 1.2 ), x5, y2 + ( ( y_offset + i )*y_inc ), x5 + NumBlock, y2 + ( ( y_offset + i + 1 )*y_inc ) , TA_Right );
    GfxDrawText( NumToStr( W3[i][0] * 100, 1.2 ), x6, y2 + ( ( y_offset + i )*y_inc ), x6 + NumBlock, y2 + ( ( y_offset + i + 1 )*y_inc ) , TA_Right );
}

//
//Display covariance matrix
x_inc		= WL_Count * 70 / 2;
y3			= y2 + ( ( y_offset + i + 1 ) * y_inc );
numblock	= pxwidth	/ WL_Count * 0.8;
GfxDrawText( "Covariance Matrix   x 1000", x1 + ( x_inc ), y3, x1 + ( x_inc ) + TextBlock * 1.5 , y3 + y_inc, TA_Center );

for( i = 0; i < WL_Count; i++ )
{
    for( j = 0; j < WL_Count; j++ )
    {

        GfxDrawText( NumToStr( 1000 * VarMx[i][j], 1.4 ), x1 + ( i * numblock ), y3 + ( ( j + y_offset - 1 )*y_inc ), x1 + ( i * numblock ) + NumBlock, y3 + ( ( j + y_offset )*y_inc ) , TA_Right );
    }
}

// Display Results
//Create headers for Portfolio results
textblock	= 50;
x11			= pxwidth * 0.30;
x21			= pxwidth * 0.50;
x31			= pxwidth * 0.70;
x_offset	= 50;
y4			= pxheight - 100;
//
GfxDrawText( "Portfolio", x21 - Textblock, y4, x21 + TextBlock , y4 + y_inc, TA_Center );
//GfxDrawText( "Portfolio", pxwidth * 0.50 - TextBlock, y4, pxwidth * 0.50 + TextBlock , y4 + y_inc, TA_Center );
GfxDrawText( "Unconstrained", x11 - TextBlock, y4 + ( 1 * y_inc ), x11 + TextBlock , y4 + ( 2 * y_inc ), TA_Center );
GfxDrawText( "Tangential",    x21 - TextBlock, y4 + ( 1 * y_inc ), x21 + TextBlock , y4 + ( 2 * y_inc ), TA_Center );
GfxDrawText( "Long Only",     x31 - TextBlock, y4 + ( 1 * y_inc ), x31 + TextBlock , y4 + ( 2 * y_inc ), TA_Center );
//
GfxDrawText( "Returns", x11 - x_Offset - textblock, y4 + ( 2 * y_inc ), x11 - x_Offset + textblock , y4 + ( 3 * y_inc ), TA_Center );
GfxDrawText( "StDev",   x11 + x_Offset - textblock, y4 + ( 2 * y_inc ), x11 + x_Offset + textblock , y4 + ( 3 * y_inc ), TA_Center );
GfxDrawText( "Returns", x21 - x_Offset - textblock, y4 + ( 2 * y_inc ), x21 - x_Offset + textblock , y4 + ( 3 * y_inc ), TA_Center );
GfxDrawText( "StDev",   x21 + x_Offset - textblock, y4 + ( 2 * y_inc ), x21 + x_Offset + textblock , y4 + ( 3 * y_inc ), TA_Center );
GfxDrawText( "Returns", x31 - x_Offset - textblock, y4 + ( 2 * y_inc ), x31 - x_Offset + textblock , y4 + ( 3 * y_inc ), TA_Center );
GfxDrawText( "StDev",   x31 + x_Offset - textblock, y4 + ( 2 * y_inc ), x31 + x_Offset + textblock , y4 + ( 3 * y_inc ), TA_Center );
//
//Print to screen portfolio returns and standard deviation for standard MVP
GfxDrawText( NumToStr( P1, 1.4 ),  x11 - x_offset - textblock, y4 + ( 3 * y_inc ), x11 - x_offset + textblock, y4 + ( ( 4 )*y_inc ) , TA_Center );
GfxDrawText( NumToStr( SD1, 1.4 ), x11 + x_offset - textblock, y4 + ( 3 * y_inc ), x11 + x_offset + textblock, y4 + ( ( 4 )*y_inc ) , TA_Center );
//
//Print to screen portfolio returns and standard deviation for Tangency MVP
GfxDrawText( NumToStr( P2, 1.4 ),  x21 - x_offset - textblock, y4 + ( 3 * y_inc ), x21 - x_offset + textblock, y4 + ( ( 4 )*y_inc ) , TA_Center );
GfxDrawText( NumToStr( SD2, 1.4 ), x21 + x_offset - textblock, y4 + ( 3 * y_inc ), x21 + x_offset + textblock, y4 + ( ( 4 )*y_inc ) , TA_Center );
//
//Print to screen portfolio returns and standard deviation Long Only portfolio
x_offset	= 50;
GfxDrawText( NumToStr( P3, 1.4 ),  x31 - x_offset - textblock, y4 + ( 3 * y_inc ), x31 - x_offset + textblock, y4 + ( ( 4 )*y_inc ) , TA_Center );
GfxDrawText( NumToStr( SD3, 1.4 ), x31 + x_offset - textblock, y4 + ( 3 * y_inc ), x31 + x_offset + textblock, y4 + ( ( 4 )*y_inc ) , TA_Center );
//
RequestTimedRefresh( 1 );
//
Title = "MVPortfolio Development";

//type or paste code here
1 Like

@ara1 i don't know about the rest but I can make an educated guess concerning

Two possibilities, your afl has a mention of using 12 assets in the Watch List, so that's where the 12 comes from.

Otherwise, I think the formula is feeding in Monthly returns. To calculate volatility in annualized terms, you simply need to multiply your monthly standard deviation by the square root of 12.

So basically you see I am guessing