You are on page 1of 22

8/19/2018 Correlation Matrix - AFL Programming - AmiBroker Community Forum

portfoliobuilder Dec '17

@reds i think the current script would not be of much use for what you are asking for. I believe you
probably need to rank the correlations ( StaticVarGenarateRanks), and then for that output that you
are looking for perhaps using AddMultiTextColumn would produce the result. I have not attempted that
as it is a big job and I am too busy. But if you are able then please come back and share with us here
on the forum. Good luck.

 Exploration with sequential watchlists, or exploration with ratios that use one security as nu…

reds  Dec '17

Thank you Larry for the suggestions. I will post back if I am able to find a solution but it may be out of
my limited abilities…Thanks…Mike

fxshrat Dec '17

@reds , this can be done by storing the corr. table to matrix at the end of exploration (using matrix
functions). The sorted top N get picked from that matrix and output via Addrow.

It is a bit tricky (but not difficult). I’m saying tricky because you have to think a little bit.

Here is proof that it is possible to do that (output of sorted table (from largest to lowest together with
standard correlation table below of it). As aside Addrow does not offer cell coloring (yet). I have output
all but of course you can pick just a top N via MxGetBlock also.

Here is another example just outputting overall top five pairs + corr.

https://forum.amibroker.com/t/correlation-matrix/1184/32 1/22
8/19/2018 Correlation Matrix - AFL Programming - AmiBroker Community Forum

So as always endless possibilities of output.

BTW, instead of using Foreign for default correlation table it is much much faster using StaticVarAdd to
store second array of Correlation function. In fact that method is lightning fast compared to using
Foreign. Milliseconds per each exploration run.

beppe Regular Dec '17

@reds here is a possible way to do it (a bit unorthodox approach):


Copy

/****** Constants *****/


// Change these as needed
MAX_ALLOWED_TICKERS = 1000; // Over this size probably it is too slow...
MAX_PAIRS_IN_TABLE = 250; // To avoid using too many columns and hit a Windows li

/***** Parameters *****/

// Number of the watchlist to use to create the correlation matrix


wlNumber = Param("Watchlist Number", 1, 0, 63, 1);
// Number of columns pair to display in resulting table
maxColRes = Param("Number of (pair) columns in results (0 = max)", 5, 0, MAX_PAIRS_
// Daily correlation look-back period
corrLB = Param("Daily correlation lookback period", 252, 50, 300, 1);
// Send trace messages for debugging purpose on progess
debugTrace = ParamToggle("Enable _TRACE()", "No|Yes", 1);

/***** Functions *****/

function _TRACE_(msg) {
https://forum.amibroker.com/t/correlation-matrix/1184/32 2/22
8/19/2018 Correlation Matrix - AFL Programming - AmiBroker Community Forum

if (debugTrace)
_TRACE(msg);
}

/***** Exploration *****/

actionStatus = Status("action");
if (( actionStatus == actionExplore ) OR (actionStatus == actionBacktest)) {
symlist = GetCategorySymbols( categoryWatchlist, wlNumber);
Filter = 0;
stockNum = Status("stocknum");
if (stockNum == 0)
{
// Do this only ONCE
if (symList != "") {
EnableTextOutput( 0 );
size = 1 + StrCount( symlist, ",");
if (maxColRes >= size) {
maxColRes = size-1;
}
if (maxColRes <= 0) {
maxColRes = size-1;
}
if (maxColRes >= MAX_PAIRS_IN_TABLE) {
maxColRes = MAX_PAIRS_IN_TABLE; //
}

_TRACE_("Selected watchlist: " + WriteVal(wlNumber, 2.0) + " - Size: "


_TRACE_("Symbols: " + symList);
if (size < MAX_ALLOWED_TICKERS+1) {
Filter = 0;
SetOption("NoDefaultColumns", True );
AddColumn(Null, "Ticker", 1.2, -1, -1, 60);
for (i = 1; i <= maxColRes; i++) {
AddColumn(Null, "T" + WriteVal(i, 1.0), 1.2, -1, -1, 60);
AddColumn(Null, "C" + WriteVal(i, 1.0), 1.2, -1, -1, 60);
}

// Get Tickers and do calculations ONCE


_TRACE_("Parsing tickers");
for( i = 0; ( sym = StrExtract( symlist, i ) ) != ""; i++ )
{
VarSetText("T_" + i, sym);
CFrgn = Foreign( sym, "C" );
logCFrgn = log( CFrgn / Ref( CFrgn, -1 ) );
VarSet("L_" + i, logCFrgn);
}
_TRACE_("Parsing tickers. Done");
// Add top row used for ticker index
mx = Matrix(size+1, size, 0);
_TRACE_("Created matrix. " + WriteVal(size+1, 3.0) + "*" + WriteVa

_TRACE_("Filling matrix with correlations.... ");


// First row is reserved to ticker indexes
https://forum.amibroker.com/t/correlation-matrix/1184/32 3/22
8/19/2018 Correlation Matrix - AFL Programming - AmiBroker Community Forum

for( col = 0; col < size; col++ )


mx[0][col] = col;

// Filling a matrix with correlation values


startCol = 0;
for( row = 0; row < size; row++ )
{
symRow = VarGetText("T_" + row);
// CRow = Foreign( symRow, "C" );
// logCRow = log( CRow / Ref( CRow, -1 ) );
if (row % 10 == 0)
_TRACE_("Row " + WriteVal(row, 3.0));
for( col = startCol; col < size; col++ )
{
symCol = VarGetText("T_" + col);
// _TRACE_("R " + WriteVal(row, 2.0) + " C " + WriteVal(col
// CCol = Foreign( symCol, "C" ); // store Foreign to varia
// LogCCol = log( CCol / Ref( CCol, -1 ) );
// corrARray = Correlation( LogCRow, LogCCol, corrLB );
// corr = LastValue(corrArray);
corr = LastValue(Correlation( VarGet("L_" + row), VarGet("L
// corr is a columm
mx[col+1][row] = corr;
// Filling the symmetrical cell
mx[row+1][col] = corr;
}
startCol += 1; // reducing number of cells to fill thanks to to
}

_TRACE_("Matrix done. Sorting - Ignoring header");

_TRACE_("Coupling elements");
// Print result in the Analisys window using AddRow (to output too
for( row = 0; row < size; row++ ) {

// we need to transpose the matrix to sort by columns - then re


// each iteration we sort on a different row for each ticker (r
// and row 0 will have the orders of correlated tickers (column
mx2 = MxTranspose(mx);
mx3 = MxSortRows(mx2, False, row+1); // sort descending
mx2 = MxTranspose(mx3);
symRow = VarGetText("T_" + row);
s = symRow + "\t";
// Skip col 0 since it is 1.0 for the ticker own correlation...
for( col = 1; col <= maxColRes; col++ )
{
symIdx = mx2[0][col]; // get the index from row 0
symCol = VarGetText("T_" + symIdx);
corr = mx2[row+1][col];
s = s + symCol + "\t" + WriteVal( corr, 3.3 ) + "\t";
}
AddRow(s);
}
_TRACE_("Coupling elements/Add rows done");
https://forum.amibroker.com/t/correlation-matrix/1184/32 4/22
8/19/2018 Correlation Matrix - AFL Programming - AmiBroker Community Forum

} else {
_TRACE_("Too many tickers. Skipping");
}
} else {
_TRACE_("Empty watchlist. Skipping");
}
}
_TRACE_("Script completed for stock " + WriteVal(stockNum, 4.0));
} else {
_TRACE_("Script ignored. Status " + WriteVal(actionStatus, 1.0));
}

w = 0; // used to set a breakpoint when using the debugger

I too used matrices and addRow().

(In this sample I applied the correlation logic used by @portfoliobuilder - using only the last value of
the correlation arrays; you may want to change it as needed).

I use a matrix to store the correlations and then sort it multiple times; one for each ticker row - using the
first row of my original unsorted matrix as an index for the tickers to display in the correlation table.

Seems to work well enough for medium/sized watchlists (I used a max of 500 tickers)

To display the resulting data in the Analysis window I used the AddRow() function with the filter set to 0
(search here in the forum other examples about its usage). Unfortunately as said also in the previous
message no colors…

For the exploration, you have to choose a watchlist (selecting its corresponding number as a
parameter).
In order to get the table a little faster, I suggest setting the analysis filter to “current” (it is actually
ignored but the process will be done only once).

This sample raw code (where I left on purpose many commented lines to show how some code was
developed/moved/replaced) is provided “as it is” (it is not fully tested); take it mainly as a starting point
for your own further development.

(All suggestions to do it in a better way are welcome!)

 How to use debugger in amibroker 6.00.1?


 OSAKA sort -- replace with matrix

beppe Regular Dec '17

P.S. Note that all the relevant code happens when the Status(“stocknum”) == 0 so it is run in a SINGLE
THREAD (I did it on purpose to be able to easily follow the code logic tracing/debugging).

reds Dec '17

Portfoliobuilder, fxshrat, and beppe…Thank you for all you recommendations and direction! I will
consider all and move forward…Happy New Year! Best…Mike

https://forum.amibroker.com/t/correlation-matrix/1184/32 5/22
8/19/2018 Correlation Matrix - AFL Programming - AmiBroker Community Forum

osinv Jan 19

Two questions about this matrix:

(1) Why are the correlation values on both sides of the diagonal sometimes different for the same pair of
symbols? Which correlation is then the good one?

(2) If we want to do a correlation analysis using the weekly or monthly returns instead of the daily
returns, would changing the "periodicity" in the settings window be the right way to do it? (Assuming that
we also change the AFL number of bars lookback also obviously)

Thanks,

Oscar

aknagdev Jul 3

How do i get Full Name of the ticker in the above matrix


i'm able to get in vertical lines but not on horizintal lines

ArnaudP 5d

Good-day Amibroker community,

I would like to seek your valuable help in resolving my challenge. I'm trying to sum up the correlation of
each and every symbol for later use in a ranking scheme.
Having browsed through the entire forum it seems there is a discussion about this topic on the old
yahoo group but I can't access it... I'm able to sum up the correlation in exploration mode but can't seem
to be able to store them into a static variable which is pretty frustrating

I attempted several ways but nothing I've tried seems to work.. the values I'm after are highlighted in
yellow on the screenshot below.

Any help or pointer would be greatly appreciated.

Thanks in advance for your time on this -

ArnaudP.

https://forum.amibroker.com/t/correlation-matrix/1184/32 6/22
8/19/2018 Correlation Matrix - AFL Programming - AmiBroker Community Forum

beppe Regular 5d

@ArnaudP do you want to store each total in a single staticVar with a name based on the column
header (for instance "CorrelationMatrixTotal_APPL", "CorrelationMatrixTotal_AXP", ...,
"CorrelationMatrixTotal_TRV") or in some other ways?

Moreover, do you want to include in the totals also the "autocorrelation" value (1.0) as displayed in the
screenshot, probably done using a AddSummaryRows(1, 1.2) line?

mradtke 5d

If you've calculated all the correlations and summed them up, then the hard word is already done. What
issue are you having with Static Variables? Could you post some code to help us help you find your
error?

ArnaudP 5d

@beppe & @mradtke . I appreciate that two legends of the amibroker community are looking into my
issue
@beppe , yes this is exactly what I intend to do, I would like to have the ability to retrieve the ColSum
correlation of each asset to add this component to a bigger weighting scheme. Basically what I'm trying
to achieve is the FAA (flexible asset allocation) scheme as detailed in the following SSRN paper:
https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2193735
While I have no problem coding it with R (as per this example:
http://systematicinvestor.github.io/strategy/Strategy-FAA )
I encounter an issue when it comes to getting the sum of the correlation to include to my three
components weighting scheme.
And yes you are right I used AddSummaryRows to obtain the top line on my screenshot.
@mradtke the code I generated is essentially the same as the one posted by portfolio builder in the
same post, my only trouble is to generate & store the cummulated correlation values of each asset.
I know it may sound trivial but I'm only beginning my journey with AFL and facing my first roadblock -
I intend to share the full FAA implementation to this forum (which is quite close to GTAA by
trendXplorer) once successfully succesffuly coded.
Thanks !
ArnaudP

mradtke 5d

We don't need the full FAA code at this point. Just a simplified version that shows how you're calculating
the sum of correlations and attempting to store them in static variables. Without seeing your code, we
really have no way to point you in the right direction other than to implement our own solution from
scratch. That's not a good use of our time nor the best way for you to improve your AFL skills.

fxshrat 5d

Here is code example


Copy

/// @link https://forum.amibroker.com/t/correlation-matrix/1184/4


/// @link https://forum.amibroker.com/t/correlation-matrix/1184/5
CorrLB = Param("Lookback", 252, 50, 300, 1); // daily correlation look-back period/

https://forum.amibroker.com/t/correlation-matrix/1184/32 7/22
8/19/2018 Correlation Matrix - AFL Programming - AmiBroker Community Forum

wlnumber = GetOption( "FilterIncludeWatchlist" ); // choose your WL in Analysis win


symlist = CategoryGetSymbols( categoryWatchlist, wlnumber );

if ( Status( "action" ) == actionExplore ) {

Filter = Status( "lastbarinrange" );


SetSortColumns(1);
Tickers = Name();

AddSummaryRows( 1, 1.5 );

logC = log( C / Ref( C, -1 ) );// does not belong within loop

/// added by fxshrat to remove stored values for summary rows


if( Status( "stocknum" ) == 0 )
StaticVarRemove( "cs_*" );

cs = 0;/// added by fxshrat


// iterate through symbols
for( i = 0; ( sym = StrExtract( symlist, i ) ) != ""; i++ )
{
Frg = Foreign( sym, "C" );
FrgLog = log( Frg / Ref( Frg, -1 ) );
Corr = Correlation( logC, FrgLog, CorrLB );
corrcond = Corr>0.6;
tickercond = Tickers == sym;
Clr = 32 + SelectedValue( Corr ) * 32;
Clr = IIf( tickercond, colorBlack, Clr );
fntcolor = IIf( tickercond, colorWhite, IIf(corrcond,colorWhite, -1 ));
cellcolor = IIf( tickercond, colorDarkBlue, IIf(corrcond, colorGreen, -1) )
AddColumn( Corr, sym, 1.3, fntcolor, cellcolor, width = 60 );

cs += SelectedValue(corr); /// added by fxshrat


}

/// @ link https://forum.amibroker.com/t/correlation-matrix/1184/26


/// added by fxshrat to store summary rows to matrix
i = Status( "Stocknum" );
StaticVarAdd( "cs_" + i, cs );
mat = Matrix( 1, StrCount( symlist, "," ) + 1 );
for( i = 0; i < MxGetSize(mat,1); i++ )
mat[0][i] = StaticVarGet( "cs_" + i );
StaticVarSet( "SummaryRowsMat", mat );
}

_TRACE( symlist );

/// added by fxshrat to call "summary rows"-matrix


mat = StaticVarGet( "SummaryRowsMat" );
if( typeof(mat) == "matrix" ) {
mstr = StrReplace(StrReplace(MxToString(mat), "{", ""), "}", "" );
_TRACE( mstr );
}

https://forum.amibroker.com/t/correlation-matrix/1184/32 8/22
8/19/2018 Correlation Matrix - AFL Programming - AmiBroker Community Forum

ArnaudP 4d

@fxshrat Thanks a lot this is definitely very helpul. Hopefully it will be of some use for other users too.
Cheers

fxshrat 4d

Here is modification to move the whole matrix part outside of exploration since (I suppose) you want to
use it elsewhere...
Copy

/// Correlation output and summary rows storage


/// @link https://forum.amibroker.com/t/correlation-matrix/1184/4
/// @link https://forum.amibroker.com/t/correlation-matrix/1184/5
/// @link https://forum.amibroker.com/t/correlation-matrix/1184/28
CorrLB = Param("Lookback", 252, 50, 300, 1); // daily correlation look-back period/

wlnumber = GetOption( "FilterIncludeWatchlist" ); // choose your WL in Analysis win


symlist = CategoryGetSymbols( categoryWatchlist, wlnumber );

stocknum = Status( "stocknum" );

if ( Status( "action" ) == actionExplore ) {

Filter = Status( "lastbarinrange" );


SetSortColumns(1);

https://forum.amibroker.com/t/correlation-matrix/1184/32 9/22
8/19/2018 Correlation Matrix - AFL Programming - AmiBroker Community Forum

Tickers = Name();

AddSummaryRows( 1, 1.5 );

logC = log( C / Ref( C, -1 ) );// does not belong within loop

/// added by fxshrat to remove stored values for summary rows


if ( stocknum == 0 )
StaticVarRemove( "cs_*" );

cs = 0;/// added by fxshrat

// iterate through symbols


for ( i = 0; ( sym = StrExtract( symlist, i ) ) != ""; i++ )
{
Frg = Foreign( sym, "C" );
FrgLog = log( Frg / Ref( Frg, -1 ) );
Corr = Correlation( logC, FrgLog, CorrLB );
corrcond = Corr>0.6;
tickercond = Tickers == sym;
Clr = 32 + SelectedValue( Corr ) * 32;
Clr = IIf( tickercond, colorBlack, Clr );
fntcolor = IIf( tickercond, colorWhite, IIf(corrcond,colorWhite, -1 ));
cellcolor = IIf( tickercond, colorDarkBlue, IIf(corrcond, colorGreen, -1) )
AddColumn( Corr, sym, 1.3, fntcolor, cellcolor, width = 60 );

cs += SelectedValue(corr); /// added by fxshrat


}

/// @ link https://forum.amibroker.com/t/correlation-matrix/1184/28


/// added by fxshrat to store correlation sum
StaticVarAdd( "cs_" + stocknum, cs );
}

/// added by fxshrat to store corr sum to "summary row" matrix vector
/// called outside after exploration being finished, for further use cases...
//if ( stocknum == 0 )
{
_TRACE( symlist );

mat = Matrix( 1, StrCount( symlist, "," ) + 1 );


for ( i = 0; i < MxGetSize(mat,1); i++ )
mat[0][i] = StaticVarGet( "cs_" + i );
mstr = StrReplace(StrReplace(MxToString(mat), "{", ""), "}", "" );
_TRACE( mstr );
}

TrendXplorer 22h

After contacting @ArnaudP in private, he asked me to share the FAA code I have for monthly data.

https://forum.amibroker.com/t/correlation-matrix/1184/32 10/22
8/19/2018 Correlation Matrix - AFL Programming - AmiBroker Community Forum

Please do comment on possible improvements. I am especially interested how to modify the code to
work with daily data while (still) observing the exact monthly endpoints (not being i.e. 4 x 21).

Importantly: this code is not to correct the matrix approach shared by @fxshrat . It's just another way,
originating from the era when AmiBroker did not have build-in matrix functions.

In the below code the correlation matrix is calculated in two different ways. For Explorations, the code
uses a loop in similar fashion to the earlier shared approached. For the rotational calculations to
determine the monthly position sizes, the code uses a custom function CalcPfC( symbol, tickerlist,
length ).

Acknowledgement goes to the old Yahoo board member SanzProphet, who kindly helped me along with
this code back in 2014.

In Exploration View the result looks like:

Running the code on the N10 investment universe and the separate out of market fund as shown on the
screenshot with TopSize=10, results in the following long term performance chart:

Point to note: next to the filterlist with both all investment assets as well as the out of market fund, the
code needs a dedicated watchlist with only the investment assets. Otherwise the correlation
calculations are off.
Copy

///////////////////////////////////////////////////////////////////////////////////
//
// --- FAA_Dual_Monthly_v1.1.afl ---
//
// --- introduction ---
//
// based on:
// "Generalized Momentum and Flexible Asset Allocation (FAA), An Heuristic Approach
// Keller and Van Putten, 2012
// FAA Electronic copy available at: http://ssrn.com/abstract=2193735
//
// FAA strategy rules:
https://forum.amibroker.com/t/correlation-matrix/1184/32 11/22
8/19/2018 Correlation Matrix - AFL Programming - AmiBroker Community Forum

// M: Calculate 4 months relative momentum on monthly returns, then rank (highest i


// V: Calculate 4 months standard deviation on monthly returns, then rank (lowest
// C: Calculate 4 month average correlation on monthly prices, then rank (lowest is
// Select top 3 assets based on final MVC ranking: 100% M + 50% V + 50% C
// From the top 3 replace asset with M <= 0 for cash (instead of FAA cash proxy: VF
// Rebalance monthly
//
// --- afl-version ---
//
// AmiBroker implementation by TrendXplorer: www.trendxplorer.info
// in collaboration with SanzProphet: sanzprophet.blogspot.com
// original version: Feb. 18, 2014, modified for BacktestRotational: Aug. 18, 2018
//
// STRATEGY SETUP:
// 1 - ADJUSTING START AND END DATES
// 2 - USE BACKTESTER SETTINGS FOR MONTHLY PERIODICITY
// 3 - SELECT FILTERLIST
// 4 - START BACKTEST
//
//
///////////////////////////////////////////////////////////////////////////////////

// --- begin of code ---

// --- inputs ---


frequency = ParamList( "Rebalance Frequency:", "Monthly|Bi-Monthly|Quarterly|A

// --- detect invest universe ---


wln_market = Param( "WatchListNumber for Market Assets:", 11, 0, 150, 1 );
marketlist = GetCategorySymbols( categoryWatchlist, wln_market );
NoM = StrCount( marketlist, "," ) + 1;

TopSize = Param( "Number of Positions", 3, 1, NoM, 1 );

MomLength = Param( "Momentum Period" , 4, 1, 12, 1 );


VolLength = Param( "Volatility Period" , 4, 1, 12, 1 );
CorLength = Param( "Correlation Period" , 4, 1, 12, 1 );

wM = Param( "Momentum Weight" , 1.0, 0.0, 1.0, 0.1 ); // weight of


wV = Param( "Volatility Weight" , 0.5, 0.0, 1.0, 0.1 ); // weight of
wC = Param( "Correlation Weight" , 0.5, 0.0, 1.0, 0.1 ); // weight of

_Cashticker = ParamStr( "Cash Proxy", "SHY" );

showCorTable = ParamToggle( "Show Correlation Table:", "No|Yes", 1 );

// --- detect tradelist ---


wlnumber = GetOption( "FilterIncludeWatchlist" );
filterlist = GetCategorySymbols( categoryWatchlist, wlnumber );

// --- backtester settings ---


SetBacktestMode( backtestRegular );
SetOption( "CommissionAmount", 0.00 );
SetOption( "InitialEquity", 100000 );
SetTradeDelays( 0, 0, 0, 0 );
https://forum.amibroker.com/t/correlation-matrix/1184/32 12/22
8/19/2018 Correlation Matrix - AFL Programming - AmiBroker Community Forum

SetOption( "MaxOpenLong", TopSize );


SetOption( "MaxOpenPositions", TopSize );
SetOption( "AllowPositionShrinking", True );
SetOption( "AllowSameBarExit", True );
SetOption( "ReverseSignalForcesExit", False );
SetOption( "HoldMinBars", 1 );
SetOption("ExtraColumnsLocation", 11 );
RoundLotSize = 0.0001;

// --- detect period ends ---


MonthEnd = Month() != Ref( Month(), 1 );
BiMonthEnd = Month()%2 == 0 AND MonthEnd;
QuarterEnd = Month()%3 == 0 AND MonthEnd;
YearEnd = Month()%12 == 0 AND MonthEnd;

// --- init rebalancing frequency ---


if ( frequency == "Monthly" ) Rebalance = MonthEnd;
if ( frequency == "Bi-Monthly" ) Rebalance = BiMonthEnd;
if ( frequency == "Quarterly" ) Rebalance = QuarterEnd;
if ( frequency == "Annually" ) Rebalance = YearEnd;
Rebalance = Rebalance OR Status( "LastBarInTest" );

// --- function for portfolio calculation provided by SanzProphet ---


function CalcPfC( symbol, tickerlist, length )
{
// This function takes a symbol from a watchlist
// and calculates the average correlation of the
// symbol to the other symbols

CorSum = 0;
if ( tickerlist != "" )
{
for ( j = 0; ( ticker = StrExtract( tickerlist, j ) ) != ""; j++ )
{
data1 = Foreign( ticker, "C" );
data2 = Foreign( symbol, "C" );
log1 = log( data1 / Ref( data1, -1 ) );
log2 = log( data2 / Ref( data2, -1 ) );
CorSum = CorSum + Correlation( log1, log2, Length );
}
}
// take out the diagonal of the correlation matrix and average
PfC = ( CorSum - 1 ) / ( j - 1 );
return ( PfC );
}

// --- init ---


SumPosSize = 0;

// --- asset selection and capital allocation routine ---


if ( ( Status( "stocknum" ) == 0 OR Status("stocknum") == -1 ) )
{
StaticVarRemove( "Mom*" );
StaticVarRemove( "Vol*" );
https://forum.amibroker.com/t/correlation-matrix/1184/32 13/22
8/19/2018 Correlation Matrix - AFL Programming - AmiBroker Community Forum

StaticVarRemove( "Cor*" );
StaticVarRemove( "MVC*" );
StaticVarRemove( "Pos*" );
StaticVarRemove( "Sum*" );
StaticVarRemove( "num*" );
StaticVarRemove( "cas*" );

for ( i = 0; ( symbol = StrExtract( marketlist, i ) ) != ""; i++ )


{
SetForeign ( symbol );

Mom = 100 * ( Close / Ref( Close, -MomLength ) - 1 );


Vol = -100 * StDev( ( Close / Ref( Close, -1 ) - 1 ), VolLength, False

RestorePriceArrays();

Cor = -CalcPfC( symbol, marketlist, CorLength ); // lowest is best

if ( symbol == _Cashticker )
{

CashMom = Mom;
Mom = Vol = Cor = Null;

StaticVarSet( "CashMom", CashMom );


}

StaticVarSet( "Mom" + symbol, Mom );


StaticVarSet( "Vol" + symbol, Vol );
StaticVarSet( "Cor" + symbol, Cor );
StaticVarSet( "number" + symbol, i + 1 );
}

// generate ranks for M, V and C


StaticVarGenerateRanks( "Rank", "Mom", 0, 1224 );
StaticVarGenerateRanks( "Rank", "Vol", 0, 1224 );
StaticVarGenerateRanks( "Rank", "Cor", 0, 1224 );

for ( i = 0; ( symbol = StrExtract( marketlist, i ) ) != ""; i++ )


{
RankMom = StaticVarGet( "RankMom" + symbol );
RankVol = StaticVarGet( "RankVol" + symbol );
RankCor = StaticVarGet( "RankCor" + symbol );

// in case of tie, RankMom is decisive through + 0.001


MVC = ( wM + 0.001 ) * RankMom + wV * RankVol + wC * RankCor;

StaticVarSet( "MVC" + symbol, -MVC );


}

// generate master ranking


StaticVarGenerateRanks( "Rank", "MVC", 0, 1224 );

for ( i = 0; ( symbol = StrExtract( marketlist, i ) ) != ""; i++ )


{
https://forum.amibroker.com/t/correlation-matrix/1184/32 14/22
8/19/2018 Correlation Matrix - AFL Programming - AmiBroker Community Forum

// --- retrieve stored values ---


RankMVC = StaticVarGet( "RankMVC" + symbol );
Mom = StaticVarGet( "Mom" + symbol );

PosSize = IIf( RankMVC <= TopSize AND Mom > 0, 100 / TopSize, 0 );

SumPosSize = SumPosSize + PosSize;

// --- store position size percentages ---


StaticVarSet( "PosSize" + symbol, PosSize );
}

// --- calculate allocation for out-of-market "cash" fund ---


PosSizeCash = 100 - SumPosSize;

// --- store value ---


StaticVarSet( "SumPosSize" , SumPosSize );
StaticVarSet( "PosSizeCash", PosSizeCash );

for ( i = 0; ( symbol = StrExtract( filterlist, i ) ) != ""; i++ )


{
if ( symbol == _Cashticker )
{
// --- check if cash symbol is part of investment universe too ---
PosSizeCash = StaticVarGet( "PosSizeCash" );
PosSize = StaticVarGet( "PosSize" + symbol );
PosSize = IIf( !IsNull( PosSize ), PosSizeCash + PosSize, PosSizeCa

SetForeign ( symbol );

Mom = 100 * ( Close / Ref( Close, -MomLength ) - 1 );

RestorePriceArrays();

StaticVarSet( "Mom" + symbol, Mom );

StaticVarSet( "number" + symbol, NoM + 1 );

StaticVarSet( "PosSize" + symbol, PosSize );

StaticVarSet( "RankMom" + symbol, Null );


StaticVarSet( "RankVol" + symbol, Null );
StaticVarSet( "RankCor" + symbol, Null );
StaticVarSet( "MVC" + symbol, Null );
StaticVarSet( "RankMVC" + symbol, Null );
}
}
}

// --- get values and ranks for M, V and C ---


symbol = Name();
Mom = StaticVarGet( "Mom" + symbol );
Vol = -StaticVarGet( "Vol" + symbol );
Cor = -StaticVarGet( "Cor" + symbol );
MVC = -StaticVarGet( "MVC" + symbol );
https://forum.amibroker.com/t/correlation-matrix/1184/32 15/22
8/19/2018 Correlation Matrix - AFL Programming - AmiBroker Community Forum

RankMom = StaticVarGet( "RankMom" + symbol );


RankVol = StaticVarGet( "RankVol" + symbol );
RankCor = StaticVarGet( "RankCor" + symbol );
RankMVC = StaticVarGet( "RankMVC" + symbol );
CashMom = StaticVarGet( "CashMom" );

PosSize = StaticVarGet( "PosSize" + symbol );


SumPosSize = StaticVarGet( "SumPosSize" );
number = StaticVarGet( "number" + symbol );

// --- set position sizes ---


SetPositionSize( PosSize, spsPercentOfEquity );

// --- re-balance at the end/close of every month ---


Buy = Rebalance AND PosSize > 0;
Sell = Rebalance;
Short = Cover = 0;
BuyPrice = Close;
SellPrice = Close;

// --- exploration filter ---


ExploreFilter = ParamToggle( "ExploreFilter", "LastBarInTest|All", 1 );
if ( ExploreFilter )
Filter = 1;
else
Filter = Status( "LastBarInTest" );

// --- sort for exploration only (not on backtest) ---


if ( Status( "actionex" ) == actionExplore )
{
// if ( showCorTable ) SetSortColumns( 2, 3 );
// else SetSortColumns( 2, -11, 10 );
SetSortColumns( 2, 3 );

// --- columns for exploration ---


ColorMom = IIf( Mom > 0 , colorBrightGreen, colorRed );
ColorCash = IIf( CashMom > 0, colorBrightGreen, colorRed );
PosColor = IIf( symbol == _Cashticker, IIf( PosSize > 0, colorYellow, colorWhi

AddColumn( number, "Symbol#", 1.0 );

// --- calculate correlation matrix for exploration ---


if ( showCorTable )
{
ticker = Name();

for ( j = 0; ( symbol = StrExtract( marketlist, j ) ) != ""; j++ )


{
data = Foreign( symbol, "Close" );
logData = log( data / Ref( data, -1 ) );
logClose = log( Close / Ref( Close, -1 ) );
CorXY = Correlation( logClose, logData, CorLength );
Color = IIf( CorXY > 0, ColorRGB( 0, 204, 0 ), IIf( CorXY < 0, colorLig
Color = IIf( ticker == symbol, colorBlack, Color );
https://forum.amibroker.com/t/correlation-matrix/1184/32 16/22
8/19/2018 Correlation Matrix - AFL Programming - AmiBroker Community Forum

AddColumn( CorXY, symbol, 2.3, 1, Color );


}
}

if ( symbol == _CashTicker )
{
AddColumn( CashMom, "Momentum", 3.3, 1, ColorMom );
}
else
{
AddColumn( Mom , "Momentum", 3.3, 1, ColorMom );
}
AddColumn( Vol , "Volatility" , 1.3 );
AddColumn( Cor , "Portf.Cor" , 1.3 );

AddColumn( RankMom, "RankMom" , 1.0 );


AddColumn( RankVol, "RankVol" , 1.0 );
AddColumn( RankCor, "RankCor" , 1.0 );
AddColumn( MVC , "MVC " , 3.3 );
AddColumn( RankMVC, "RankMVC" , 1.0 );

AddColumn( PosSize, "PosSize (%)", 3.3, 1, PosColor );


}

///////////////////////////////////////////////////////////////////////////////////
//
// --- end of code ---
//
///////////////////////////////////////////////////////////////////////////////////

portfoliobuilder 21h

@TrendXplorer thanks for sharing your code JW. I was uncertain what you were looking for with this
line,

TrendXplorer:

I am especially interested how to modify the code to work with daily data while (still) observing the
exact monthly endpoints (not being i.e. 4 x 21)

I thought perhaps you were looking for some examples of using different time frame data (in this
example daily/weekly/monthly) together. So here is a small example with a couple of different methods
of using the longer timeframe for display on the shorter time frame.
Copy

// lets compare the 126 day vs 26 week vs 6 month ROC

TimeFrameSet(inWeekly);
WeeklyROC26=ROC(C, 26);
TimeFrameRestore(); // restore time frame to original

TimeFrameSet( inMonthly);
https://forum.amibroker.com/t/correlation-matrix/1184/32 17/22
8/19/2018 Correlation Matrix - AFL Programming - AmiBroker Community Forum

MonthlyROC6= ROC(C,6);
TimeFrameRestore(); // restore time frame to original

DailyROC126= ROC(C, 126);


Weekly2DailyROC26 = TimeFrameExpand( WeeklyROC26, inWeekly ); // expand for display
Monthly2DailyROC6= TimeFrameExpand( MonthlyROC6, inMonthly); // expand for display

/// for Explore Display with Nulls ///


Weekly2DailyROC26pt = TimeFrameExpand( WeeklyROC26, inWeekly, expandPoint ); // exp
Monthly2DailyROC6pt= TimeFrameExpand( MonthlyROC6, inMonthly, expandPoint); // expa

// for display purposes


eow = DayOfWeek() > Ref(DayOfWeek(), 1); // end of week
eom = Month() != Ref(Month() , 1); // end of month (looks into future)

// Explore to debug our variables and illustrate what the calculations are doing
Filter=1;
dynamic_fg_Color = IIf(eow, colorWhite, colorDefault);
dynamic_Bk_Color = IIf(eow, colorLightBlue, colorDefault);
dynamic_fg_ColorM = IIf(eom, colorWhite, colorDefault);
dynamic_Bk_ColorM = IIf(eom, colorBlue, colorDefault);
AddColumn(eow,"End Of Week", 1.0, dynamic_fg_Color, dynamic_Bk_Color);
AddColumn(eom,"End Of Month", 1.0, dynamic_fg_ColorM, dynamic_Bk_ColorM);

AddColumn(DailyROC126, "ROC(126) daily");


AddColumn(Weekly2DailyROC26, "ROC(26) Weekly");
AddColumn(Monthly2DailyROC6, "ROC(6) Monthly");

AddColumn(Weekly2DailyROC26pt, "ROC(26) W");


AddColumn(Monthly2DailyROC6pt, "ROC(6) M");

Plot( DailyROC126, "ROC(126) daily", colorRed, styleLine );


Plot( Weekly2DailyROC26, "ROC(26) Weekly", colorBlue, styleStaircase );
Plot( Monthly2DailyROC6, "ROC(6) Monthly", colorAqua, styleStaircase );

https://forum.amibroker.com/t/correlation-matrix/1184/32 18/22
8/19/2018 Correlation Matrix - AFL Programming - AmiBroker Community Forum

I am not sure that is what you were interested in but I hope it helps.

TrendXplorer 6h

While thinking about how to explain to @portfoliobuilder what I actually was looking for, I managed to
find a partial solution (ROC solved below, but Volatility and Correlation not: array to number issue).

For running strategies like FAA with monthly lookback settings on the daily time frame I wanted to get
same end-of-the-month readings when comparing daily ROC's against monthly ROC's. Since the
number of trading days typically changes each month, using i.e. 6-months times 21 days for a
ROC(126), the reading won't always match with a 6-month ROC. This is what I meant with "preserving
monthly endpoints".

Copy

length = Param( "Length in Months", 12, 1, 12, 1 );

MonthEnd = Month() != Ref( Month(), 1 );

https://forum.amibroker.com/t/correlation-matrix/1184/32 19/22
8/19/2018 Correlation Matrix - AFL Programming - AmiBroker Community Forum

CountDays = Cum( 1 );
LastDayCount = ValueWhen( MonthEnd, CountDays, 1 );
FirstDayCount = ValueWhen( MonthEnd, CountDays, length + 1 );
DaysInPeriod = LastDayCount - FirstDayCount;

ChangeOverDays = 100 * ( Close / Ref( Close, -DaysInPeriod ) - 1 );


ChangeOverMonths = 100 * ( ValueWhen( MonthEnd, Close, 1 ) / ValueWhen( MonthEnd, C

match = ChangeOverDays == ChangeOverMonths;

Filter = MonthEnd;

matchColor = IIf( match, colorGreen, colorRed );

AddColumn( ChangeOverDays , "Daily ROC% over " + NumToStr( length, 1.0 ) + " mon
AddColumn( DaysInPeriod , "Days in " + NumToStr( length, 1.0 ) + "-month period"
AddColumn( ChangeOverMonths, "Monthly ROC% over " + NumToStr( length, 1.0 ) + " mon
AddColumn( match , "Match", 1.0, 1, matchColor

However, for calculating i.e. the (exact) 6-month volatilities and correlations on daily periodicity, the non-
stationary number of days in that period are required. Since both functions require a number instead of
an array as period input, the above used DaysInPeriod array can't be used as such and returns an
error:

Perhaps someone could show how to extract the appropriate (changing) number of days from the array
into a scalar?

portfoliobuilder 4h

@TrendXplorer for your volatility calculation I believe you are using Standard Deviation and that
indicator can already accept an Array as well as a Scalar.
http://www.amibroker.com/guide/a_varperiods.html

You may consider creating a variable-period version of correlation,


Copy

//Variable period correlation


function VarCorrelation( x, y, number )
{
nom = MA( x * y, number ) - MA( x, number ) * MA( y, number );
denom = sqrt( MA( x ^ 2, number ) - MA( x, number ) ^ 2 ) *
sqrt( MA( y ^ 2, number ) - MA( y, number ) ^ 2 );
return nom / denom;
}

Discussed in this forum thread,

How to make any function accepting variable period

https://forum.amibroker.com/t/correlation-matrix/1184/32 20/22
8/19/2018 Correlation Matrix - AFL Programming - AmiBroker Community Forum

As you know some functions accept variable periods


http://www.amibroker.com/guide/a_varperiods.html

If you need some function that is not on that list, you can usually easily implement variable-period
version using existing functions, for example:

Variable period ROC


Copy

function VarROC( array, periods )


{
prev = Ref( array, -periods );
return 100*(array - prev)/prev;
}

Variable period RSI


Copy

function VarRSI( array, periods )


{
Chg = array - Ref( array, -1 );
pc = Max( Chg, 0 );
nc = Max( -Chg, 0 );

pa = AMA( pc, 1/periods );


na = AMA( nc, 1/periods );

return 100 * pa / ( pa + na );
}

Variable period EMA


Copy

function VarEMA( array, period )


{
return AMA( array, 2 / ( period + 1 ) );
}

Variable period Correlation


Copy

//Variable period correlation


function VarCorrelation( x, y, number )
{
nom = MA( x * y, number ) - MA( x, number ) * MA( y, number );
denom = sqrt( MA( x ^ 2, number ) - MA( x, number ) ^ 2 ) *
sqrt( MA( y ^ 2, number ) - MA( y, number ) ^ 2 );
return nom / denom;
}

Variable period Stochastic %K


Copy

function VarStochK( array, period1, period2 )


{
hh = HHV( High, period1 );
ll = LLV( Low, period1 );

https://forum.amibroker.com/t/correlation-matrix/1184/32 21/22
8/19/2018 Correlation Matrix - AFL Programming - AmiBroker Community Forum

x = 100*(Close - ll)/(hh-ll);

return MA( x, period2 );


}

Doing so typically requires knowledge of how indicator works internally. Although it is good idea to
know how indicators work to build the system that is based on their inner workings, and it is really
better to use above strict implementations, sometimes users urge to have “quick” solution…

So here it is brute force solution to “any indicator with variable period” problem. It allows to
transform constant period functions into variable period functions. It does that by calculating
constant period indicator N times where N is a number of different “period” values used in the
calling code. It is not very efficient but not bad as a quick hack.
Copy

function YourConstantPeriodIndicator( constant_period )


{
// any constant period function here
return ROC( C, constant_period );
}

function YourVariablePeriodIndicator( period )


{
minperiod = LastValue( Lowest( period ) );
maxperiod = LastValue( Highest( period ) );

result = Null;

for( p = minperiod; p <= maxperiod; p++ )


{
ind = YourConstantPeriodIndicator( p );

result = IIf( period == p, ind, result );


}

return result;
}

Plot( YourVariablePeriodIndicator( Cum(1) ), "Test", colorRed );

Otherwise, as you have probably read over many different posts in the forum, if you want to process
things bar by bar, you need to write explicit loop and then loop counter gives your current bar inside the
loop. A variable would return a number instead of array if outputting an element of the array.

I tried using the built-in functions returning element of an array -- SelectedValue(), LastValue(),
BeginValue(), EndValue() , but unable to find a solution so far.

https://forum.amibroker.com/t/correlation-matrix/1184/32 22/22

You might also like