Correlation symbols with open trade symbols

In order to create a condition based on correlation between symbols and open trade symbols, I would need to get the close arrays of each symbols in an open trade situations. (I don't want to trade symbols with high correlation)
So I would have to go to custom backtested to identify open trade symbols and after that take them as a foreign to calculate the correlation with the symbol which I am running the code.
I guess I should be use a code similar to next, but I don't know how to get the symbol to be used as a foreign...
Could you help me?

SetCustomBacktestProc( "" );

if ( Status( "action" ) == actionPortfolio )
{
    bo = GetBacktesterObject();
    // run default backtest procedure without generating the trade list
    bo.Backtest( True );

    // iterate through open positions
    for ( trade = bo.GetFirstOpenPos( ); trade; trade = bo.GetNextOpenPos( ) )
    {
        // Get symbols I DON'T KNOW HOW I DO IT

    }

    // generate trade list
    bo.ListTrades( );
}

// your trading system here
Buy = BuyCondition AND CorrelationCondition;
Sell = SellCondition;

Thank you very much!!!

for ( trade = bo.GetFirstOpenPos( ); trade; trade = bo.GetNextOpenPos( ) )
{
    // Get symbols 
    Symbol = trade.symbol;
    SymbolClose = Foreign(Symbol, "Close"); 
   // Whatever processing you need to do on this symbol's close array here
}

Ref: https://www.amibroker.com/guide/a_custombacktest.html

Don't forget the custom backtest runs in the second phase of the backtest, so you can't reuse anything calculated there as a condition in the regular code. The regular AFL strategy code has already been processed before the custom backtest is ran.

1 Like

First of all, sorry because I didn't response to last post... I was involved in other trading topics.
I have just returned to this topic after studying Custom Backtester Interface in deep.
Trying to put into practice what I was reading I have written next code, but I didn't get what I am looking for.
It is a very simple trading system (just to see if my needs are getting). I don't want to trade symbols with high correlationa at the same time, so I want to check if the new signals have high correlation with trades already open.

// TESTING SISTEM
// Coding by Santiago Vázquez 22/08/2018 

SystemName="TESTING";

SetChartOptions(0, chartShowDates|chartWrapTitle);

//#include <optimizar_montecarlo.afl>
#include <Multiplicadores ESIGNAL.afl>

OptimizerSetEngine("spso");

SetOption("ActivateStopsImmediately",False);
SetOption("ReverseSignalForcesExit",1);

_SECTION_BEGIN("CBI");
SetCustomBacktestProc( "" );

if ( Status( "action" ) == actionPortfolio )
{
    bo = GetBacktesterObject();
        
    bo.Backtest( True ); // run default backtest procedure without generating the trade list
    
    bo.PreProcess(); // Do pre-processing (always required)
    
    for (i=0; i < BarCount; i++) // Loop through all bars
    {
		for ( trade = bo.GetFirstOpenPos(i); trade; trade = bo.GetNextOpenPos(i) ) // iterate through open positions at this bar
		{
			// Get symbols
			Symboltrade = trade.symbol;
			SymbolTradeClose = Foreign(Symboltrade, "Close"); 
		}

		for(sig = bo.getfirstsignal(i); sig; sig = bo.GetNextSignal(i)) // Loop through all signals at this bar
		{
			// Get symbols
			Symbolcheck = sig.symbol; // Do I need to call the symbol or Can I just use C  to calculate correlation and not using this line?
			SymbolcheckClose = Foreign(Symbolcheck, "Close");
			
			if(Correlation(SymbolTradeClose, SymbolcheckClose, termCorrelation) > CorrelationLevel)
				sig.PosSize = 0;
				
		}	
		bo.ProcessTradeSignals(i); //Process trades at bar (always required)
	}
	bo.PostProcess();
    // generate trade list
    bo.ListTrades( );
}
_SECTION_END();

_SECTION_BEGIN("Variables");
Risk = Param("System Risk ", 3000, 1000, 6000, 1000);

maxpositions = Param("Max. Open Positions", 3, 1, 50);
SetOption("MaxOpenPositions", maxpositions);
_SECTION_END();

// OPERATIVA
_SECTION_BEGIN("Trend");
periodoMT = Param("Trend term", 220, 90, 300, 10); 
TrendAverage = MA(C, periodoMT);

CondUpTrend = C >= TrendAverage; 
CondDownTrend = C < TrendAverage;

// PLOTTING TREND
PlotAv = ParamToggle("Plotting Trend","No|Yes", 0);

if(PlotAv==1)
{
Plot(TrendAverage, "Trend term", colorBlue, styleNoTitle + styleline);
}
_SECTION_END();

_SECTION_BEGIN("OSCILATOR");
// OSCILATOR CONDITION
OverSold = Param("Oversold", 30, 5, 45, 5);
Overbought = Param("Overbought", 70, 55, 95, 5);
lengthRSI = Param("Length RSI", 20, 5, 20, 5);

RSIwork = RSI(lengthRSI);
CondOverSold = RSIwork < OverSold; 
CondOverbought = RSIwork > Overbought;

//PLOTTING RSI 
pintarRSI = ParamToggle("Plot RSI","No|Yes", 0);

if(pintarRSI==1)
{
Plot(OverSold, "Oversold", colorgreen, styleLine + styleThick +  styleLeftAxisScale + styledashed);
Plot(Overbought, "Overbougth", colorred, styleLine + styleThick +  styleLeftAxisScale + styledashed);
Plot(RSIwork, "RSI", colororange, styleLine + styleThick +  styleLeftAxisScale);
}
_SECTION_END();

_SECTION_BEGIN("STOP LOSS");
STP = ParamToggle("Stop", "Fix|Trailing", 1);
pintarSTOP = ParamToggle("Plotting Stop","No|Yes", 0);
nSTOP = Param("nStop", 3, 4, 5.5, 0.5); 
STOP= nSTOP*ATR(20); //stop loss multiplier 
_SECTION_END();

_SECTION_BEGIN("Limitations");
// NO HIGH VOLATILITY TRADES
porcentVolati = Param("Lim Volatility (%)", 10, 0, 50, 1);
CriterioVol = STOP * PointValue <= Risk*(porcentVolati/100 + 1);

termCorrelation = Param("Correlation Term", 90, 20, 300, 10);
CorrelationLevel = Param("Correlation Level", .8, 0, 1, 0.1);

_SECTION_END();

// ACTIVACIONES
Buy = CondUpTrend AND CondOverSold AND  CriterioVol;
Sell = CondOverbought;

Short = CondDownTrend AND CondOverbought AND CriterioVol;
Cover = CondOverSold;
	
// DELETING EXTRASIGNAL
Buy = ExRem(Buy, Sell OR Short);
Short = ExRem(Short, Cover OR Buy);
Sell = ExRem(Sell, Buy);
Cover = ExRem(Cover, Short);

// STOP LOSS
if(STP==0)
{
// FIXING STOP
ApplyStop(stopTypeloss, stopModePoint, STOP, True, false);
}
else
{
// TRAILING STOP
ApplyStop(stopTypeTrailing, stopModePoint, Ref(STOP, -1), True, True);
}
Equity(1); 
SetOption("EveryBarNullCheck", True);
intradeLong = Flip(Buy, Sell OR Short);
intradeshort = Flip(Short, Cover OR Buy);

if(STP==0)
{
stoplineLONG = IIf(intradeLong, (valuewhen(Buy, BuyPrice -  STOP)), Null);
stoplineSHORT =  IIf(intradeshort, (valuewhen(Short, shortprice + STOP)), Null);
}
else
{
stoplineLONG = IIf(intradeLong ,(HighestSince(Buy, H) -  STOP), Null);
stoplineSHORT = IIf(intradeshort,(LowestSince(Short, L) + STOP), Null);
}

// SYSTEM RISK AND CONTRACTS PER TRADE
if(STP==0)
{
MarketRisk = IIf(intradelong, (C-(valuewhen(Buy, buyprice -  STOP)))*PointValue, IIf(intradeshort,  ((valuewhen(Short, shortprice + STOP))- C)*PointValue, STOP*PointValue));
}
else
{
MarketRisk = IIf(intradelong, (C-(HighestSince(Buy, H)-STOP))*PointValue, IIf(intradeshort,  ((LowestSince(Short, L) +STOP)- C)*PointValue, STOP*PointValue)); 
}
NumFut = Max(1,int(Nz(Risk/MarketRisk)));
MarginDeposit = 1; PositionSize = NumFut;

// PLOTTING STOP
if(pintarSTOP==1)
{
Plot( stoplineLONG, "trailing stop line", colorLightGrey, styleLine+styleDashed+styleThick );
Plot( stoplineSHORT, "trailing stop line", colorLightGrey, styleLine+styleDashed+styleThick );
}


// PLOTTING CHART 

Plot(C, "Price", colorBlack, styleThick | styleNoTitle | styleBar);

// TITLE
Title1 = StrFormat(EncodeColor( colorBlue ) +  SystemName + " " + Date() + EncodeColor( colorRed )   
+"\n" + EncodeColor( colorBlue ) + Name() + " Open %g, Hi %g, Lo %g, Close %g (%.1f%%)", O, H, L, C, SelectedValue( ROC( C, 1 )))
+"\n"+ EncodeColor(colorGrey40)+"ATR(20) = "+WriteVal(ATR(20),1.4)+" Pts"
+"\n"+"Volatility = "+WriteVal(PointValue*ATR(20),1.2)+"$";

Title2 = "\n" + "Contracts = " + NumFut + " Risk = " + Prec(Risk, 2)  +"$"+ "  Stop Risk = " + Prec(MarketRisk, 2)  +"$";

if(STP==0)
{
Title3 = "\n" + EncodeColor(colorRed) + WriteIf (intradeLong OR intradeshort,"SL = ", "") 
+ WriteIf(intradeLong, WriteVal((valuewhen(Buy, buyprice -  STOP))),"")
+ WriteIf(intradeshort, WriteVal((valuewhen(Short, shortprice + STOP))),""); 
}
else
{
Title3 = "\n" + EncodeColor(colorRed) + WriteIf (intradeLong OR intradeshort,"SL = ", "") 
+ WriteIf(intradeLong, WriteIf(IsEmpty(Ref(stoplineLONG, -1)), WriteVal(stoplineLONG), WriteVal(Ref(stoplineLONG, -1))),"")
+ WriteIf(intradeshort, WriteIf(IsEmpty(Ref(stoplineSHORT, -1)), WriteVal(stoplineSHORT), WriteVal(Ref(stoplineSHORT, -1))),""); 
}
Title = Title1 + Title2 + Title3;

// PLOTTING ACTIVATION SIGNALS
distancia = 3*ATR(14);
for(i=0; i<BarCount; i++)
{
if(Buy[i]) PlotText("buy\n" + BuyPrice[i], i, H[i]-distancia[i], colorGreen);
if(Sell[i] AND !Short[i]) PlotText("sell\n" + SellPrice[i], i, L[i]+distancia[i], colorRed);
if(Short[i]) PlotText("short\n" + ShortPrice[i], i,  L[i]+distancia[i], colorRed);
if(Cover[i] AND !Buy[i]) PlotText("cover\n" + CoverPrice[i], i, H[i]-distancia[i], colorGreen);
}

//PLOTTIN SHAPES//   
PlotShapes(IIf(Buy,shapeUpArrow,shapeNone),colorGreen,0,L,-15);   
PlotShapes(IIf(Buy,shapeHollowCircle,shapeNone),colorGreen,0,BuyPrice,0);   
PlotShapes(IIf(Sell AND !Short,shapeDownArrow,shapeNone),colorRed,0,H,-15);   
PlotShapes(IIf(Sell AND !Short ,shapeHollowCircle,shapeNone),colorRed,0,SellPrice,0);   
PlotShapes(IIf(Short,shapeDownArrow,shapeNone),colorBrown,0,H,-15);   
PlotShapes(IIf(Short,shapeHollowCircle,shapeNone),colorBrown,0,ShortPrice,0);   
PlotShapes(IIf(Cover AND !Buy,shapeUpArrow,shapeNone),colorDarkGreen,0,L,-15);   
PlotShapes(IIf(Cover AND !Buy,shapeHollowCircle,shapeNone),colorDarkGreen,0,CoverPrice,0);   

In addition to that, I got an error

Captura

It seem that the loop through all bars doesn't work properly....

Anybody could help me, please?

@svaztej, without looking deeply at the rest of the code (that depends also from an include file) I see that this line of code is wrong:

for ( trade = bo.GetFirstOpenPos(i); trade; trade = bo.GetNextOpenPos(i) ) 

Both GetFirstOpenPos() and GetNextOpenPos() DO NOT require a paramater (no "i").

Should be:

for ( trade = bo.GetFirstOpenPos(); trade; trade = bo.GetNextOpenPos() )  

There are probably other errors to fix (it seems you define some variables in the wrong place in the code and probably there is also an "if/iif" mistake), but at first, I suggest to get rid of errors one at a time!

2 Likes

First of all, thank you very much again for your attention!!!
The correction you gave me I have already changed, but I didn't get the goal...
On the other hand, it is true you tell me about the include. I noted after posting my issue....
This include only give us the point value of the different futures...
I show you here... meanwhile I go on studying where is the mistake...

//---------------------------------------//
//	CODIGO DE MULTIPLICADORES DE FUTUROS	
//	OSCAR G. CAGIGAS
//	14 ENERO 2015
// 	MODIFICADO POR SANTIAGO VAZQUEZ
//	AJUSTADOS TICKER ESIGNAL
//---------------------------------------//

//CAPITAL INICIAL Y COMISIONES//
Com = Param("Comisión", 100, 10, 150, 10);
SetOption( "initialequity", 100000 ); // starting capital   
SetOption("PriceBoundChecking",1);
SetOption("CommissionMode", 2);
SetOption("commissionamount",Com);  //COMISIÓN INDIVIDUAL (ENTRADA O SALIDA)

//ESCOGEMOS EL MULTIPLICADOR PARA CADA MERCADO//
switch( Name() )
{
 // FUTUROS DE DIVISAS	
	case "6A #F":		mul=100000;			break;		//AUSTRALIAN DOLLAR-GLOBEX
	case "6B #F":		mul=62500; 			break;		//BRITISH POUND-GLOBEX
	case "6C #F":		mul=100000;			break;		//CANADIAN DOLLAR-GLOBEX
	case "6E #F":		mul=125000; 		break;		//EURO-GLOBEX
	case "6J #F":		mul=12500000; 		break;		//JAPANESE YEN-GLOBEX
	case "6L #F":		mul=100000;			break;		//BRAZILIAN REAL-GLOBEX 
	case "6M #F":		mul=500000; 		break;		//MEXICAN PESO-GLOBEX
	case "6N #F":		mul=100000; 		break;		//NEW ZEALAND DOLLAR-GLOBEX	
	case "6R #F":		mul=2500000;		break;		//RUSSIAN RUBLE-GLOBEX
	case "6S #F":		mul=125000; 		break;		//SWISS FRANC-GLOBEX
	case "6Z #F":		mul=500000;			break;		//SOUTH AFRICAN ZAR-GLOBEX
	
	case "CZK #F":		mul=4000000;		break;		//CZECH KORUNA-GLOBEX
	
	case "HUF #F":		mul=30000000;		break;		//HUGARIAN FLORIN-GLOBEX
	
	case "PLN #F": 		mul=500000;			break;		//POLISH ZLOTY-GLOBEX
	
	case "RF #F": 		mul=125000;			break;		//EURO/SWISS FRANC
	case "RP #F": 		mul=125000;			break;		//EURO/BRITISH POUND
	case "RY #F":		mul=125000;    		break;      //EURO/JAPANESE YEN
	
// FUTUROS DE INDICES
	case "DX #F":		mul=1000;			break;		//US DOLLAR INDEX

	case "ES #F":		mul=50;				break;		//MINI SP500
	
	case "NKD #F":		mul=5;				break;		//NIKKEI 225-GLOBEX	
	case "NQ #F":		mul=20;				break;		//MINI NASDAQ 100
	
	case "RTY #F":		mul=50;				break;		//MINI RUSSELL 2000 
	
	case "YM #F":		mul=5;				break;		//MINI DOW JONES
	
// FUTUROS DE MATERIAS PRIMAS	
	case "CC #F":		mul=10;				break;		//COCOA
	case "CL #F":		mul=1000;			break;		//CRUDE OIL
	case "CT #F":		mul=50;				break;		//COTTON (*)
	
	case "GC #F":		mul=100;			break;		//GOLD
	case "GF #F":		mul=500;			break;		//FEEDER CATTLE (*)

	case "HE #F":		mul=400;			break;		//LEAN HOG
	case "HG #F":		mul=25000;			break;		//COPPER
	case "HO #F":		mul=42000;			break;		//HEATING OIL
	
	case "JO #F":		mul=15000;			break;		//ORANGE JUICE NYBOT
	
	case "KC #F":		mul=37500;			break;		//COFFE
	case "KE #F":		mul=50;				break;		//KANSAS WHEAT 
	
	case "LBS #F":		mul=110;			break;		//LUMBER GLOBEX
	case "LE #F":		mul=400;			break;		//LIVE CATTLE
	
	case "NG #F":		mul=10000;			break;		//NATURAL GAS
	
	case "PA #F":		mul=100;			break;		//PALADIUM
	case "PL #F":		mul=50;				break;		//PLATINUM
	
	case "QM #F":		mul=500;			break;		//MINI CRUDE OIL
	case "QYC #F":		mul=10;				break;		//MINI CORN-COMPOSITE
	case "QYK #F":		mul=10;				break;		//MINI SOYBEAN-COMPOSITE	
	case "QYW #F":		mul=10;				break;		//MINI WHEAT-COMPOSITE

	case "SB #F":		mul=112000;			break;		//SUGAR
	case "SI #F":		mul=5000;			break;		//SILVER
		
	case "XBZ #F":		mul=1000;			break;		//BRENT CRUDE OIL-LAST DAY
	case "XQC #F":		mul=12500;			break;		//E-MINI COPPER FUTURES
	case "XRB #F":		mul=42000;			break;		//NY HARBOR RBOB GASOLINE BLENDSTOCK
	
	case "YG #F":		mul=32.15;			break;		//MINI GOLD
	
	case "ZC #F":		mul=50;				break;		//CORN
	case "ZH #F":		mul=29000;			break;		//DENATURED FUEL ETHANOL
	case "ZL #F":		mul=600;			break;		//SOYBEAN OIL
	case "ZM #F":		mul=100;			break;		//SOYBEAN MEAL
	case "ZO #F":		mul=50;				break;		//OATS
	case "ZQI #F":		mul=2500;			break;		//MINI SILVER 
	case "ZR #F":		mul=20;				break;		//RICE ECBOT
	case "ZS #F":		mul=50;				break;		//SOYBEANS
	case "ZW #F":		mul=50;				break;		//WHEAT

// FUTUROS DE BONOS	
	case "ZB #F":		mul=1000;			break;		//30 Year US Treasury Bond
	case "ZF #F":		mul=1000;			break;		//5 Year US Treasury Bond
	case "ZN #F":		mul=1000;			break;		//10 Year US Treasury Bond
	case "ZT #F":		mul=2000;			break;		//2 Year US Treasury Bond
 //-----------
 default: mul=1; break;  //EL RESTO
} PointValue=mul;

Believe me, I appreciate your help a lot....
Thank you very much!!!

@beppe
I have leave out "i"

for ( trade = bo.GetFirstOpenPos(); trade; trade = bo.GetNextOpenPos() )

Now, when I run the code I get some erros regarding with non inicializate variables and with IF structure

I show you one example of the window error

image

I tought I didn't have to located that variables before the CBI formula, since this run in the second fase of backtest...

If I change the position of that variables, puting them at the begining of the code (to be inicializated)

termCorrelation = Param("Correlation Term", 90, 20, 300, 10);
CorrelationLevel = Param("Correlation Level", .8, 0, 1, 0.1);

_SECTION_BEGIN("CBI");
SetCustomBacktestProc( "" );

if ( Status( "action" ) == actionPortfolio )
{
    bo = GetBacktesterObject();.......

now I get the problem with IF structure. It seem to be a boolean condition, so I can't find the mistake...

So I keep lost!!!

On the other hand, don't pay attention with rest of the code (It is a very simple trading system, with some structures to visualize the different indicators and stops). Of course, any suggestion or improvement are welcome...

Thank you very much again!

I have noted that the return of correlation is an array, so I should take the i element in for statment (but I get an error again).

Having done more test, I have also noted that if we see the "i" bar, with this code we don't take all the open trades, so I think that

for ( trade = bo.GetFirstOpenPos(i); trade; trade = bo.GetNextOpenPos(i) ) // iterate through open positions at this bar
		{
			// Get symbols
			Symboltrade = trade.symbol;
			SymbolTradeClose = Foreign(Symboltrade, "Close"); 
		}

should place like below:

termCorrelation = Param("Correlation Term", 90, 20, 300, 10);
CorrelationLevel = Param("Correlation Level", .8, 0, 1, 0.1);

_SECTION_BEGIN("CBI");
SetCustomBacktestProc( "" );

if ( Status( "action" ) == actionPortfolio )
{
    bo = GetBacktesterObject();
        
    bo.Backtest( True ); // run default backtest procedure without generating the trade list
    
    bo.PreProcess(); // Do pre-processing (always required)
    
    for (i=0; i < BarCount; i++) // Loop through all bars
    {
		for(sig = bo.getfirstsignal(i); sig; sig = bo.GetNextSignal(i)) // Loop through all signals at this bar
		{
			// Get symbols
			Symbolcheck = sig.symbol; // Do I need to call the symbol or Can I just use C  to calculate correlation and not using this line?
			SymbolcheckClose = Foreign(Symbolcheck, "Close");
			
			for ( trade = bo.GetFirstOpenPos(); trade; trade = bo.GetNextOpenPos() ) // iterate through open positions at this bar
			{
			// Get symbols
			Symboltrade = trade.symbol;
			SymbolTradeClose = Foreign(Symboltrade, "Close");
			
				if(Correlation(SymbolTradeClose, SymbolcheckClose, termCorrelation)[i] > CorrelationLevel)
				sig.PosSize = 0; // Could be sig.Price = -1 too?
			}
		}
		bo.ProcessTradeSignals(i); //Process trades at bar (always required)
	}
	bo.PostProcess();
    // generate trade list
    bo.ListTrades( );
}
_SECTION_END();

As you see, I have placed

termCorrelation = Param("Correlation Term", 90, 20, 300, 10);
CorrelationLevel = Param("Correlation Level", .8, 0, 1, 0.1);

before the CBI section code, and take the i-element of the correlation array.

Now, I get a new error with the [i] structure...

@svaztej as you have seen, the IF error is because the Correlation function returns an ARRAY and not a numeric value.

You could assign the result to an array and then (since you are in a Bar-by-Bar loop) check the specific element like in the following snippet:

	corr = Correlation( SymbolTradeClose, SymbolCheckClose, termCorrelation ); // returns an array 
	if( corr[i] > CorrelationLevel )
	{
        // some code
	}
	else
	{
       // other code
	}

but this is quite inefficient (you are recalculating the correlation array for every bar.... not a good thing to do).

In any case, it will allow you to move a little bit forward, but you'll soon discover that the code may still not produce the results you expect.

I'm no expert at all using the CBI, but for what I have seen examining a bit your code you'll have to modify and refactor it to achieve what you have in mind.

Loops, as you already realized, need to be nested, some extra backtest function call may be required (I will check only entries), some others need to be verified (is bo.Backtest(True) appropriate here?), and probably to make it more efficient the calculations on the correlation arrays should be done in advance.

So, it seems that you still have some work to keep you busy for a while!

To focus on the task to full debug the "custom backtest" part I suggest to greatly simplify your code (I will drop all the stops. weight, risk, volatility, point calculation stuff) and use a very basic system with a watchlist of stocks, using a generous amount of _TRACE() calls to follow what is going on in the custom backtest procedure.

I hope that someone with more experience than me using the CBI could provide you with further and better guidance.

1 Like

Thank you very much again...

I think I need to learn how to use _TRACE(). I usually debug codes with filter and exploration of variables which I am interested. Of course I will simplify the code. Actually I used the template of all my systems....

And despite you couldn't give me the solution, I really apreciate you gave me a response with some help.

In any case, I go on learning AB... Little by little, when my free time alows it.
If I get some solution I will write in this post and if anybody could give me some help, is very welcome!!

Thank you very much!

Hi,
Has anyone found a solution for this issue?

As expected @beppe solution is very inefficient:

	corr = Correlation( SymbolTradeClose, SymbolCheckClose, termCorrelation ); // returns an array 
	if( corr[i] > CorrelationLevel )
	{
        // some code
	}
	else
	{
       // other code
	}

I tried to use the example for variable period in https://www.amibroker.com/guide/afl/correlation.html:

function Correl( 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; 
} 

But I can't figure out how to send the required period to the function when in CBT.

Caveat: Although the formula quoted here (Correl function coded in AFL) is mathematically correct, it may show significant numerical accuracy problems in practice (due to limited resolution of IEEE standard). Built-in Correlation() function is much much more precise.

2 Likes

I see, can you please tell if there's a way to use the built-in Correlation() function in an efficient way when in CBT (not calculation for the entire history each time it's called).
Or alternatively what is the syntax for sending the period I need to Correl when in the CBT so I can tests and see how accurate it is?

For example on bar i when I call Correl(symbol1, symbol2, 10), how do I send to the function the values of symbol1[i-10] to symbol1[i] and symbol2[i-10] to symbol2[i].

Thanks

Knowledge Base has article that explains how to pass any indicator value into CBT phase:
http://www.amibroker.com/kb/2014/11/20/how-to-show-indicator-values-in-backtest-trade-list/

1 Like

Passing the values to the CBT phase means that I will need to calculate all the correlation pairs in advance, and that will be very resource intensive.

If that is the only way to use the Correlation() function then can you please tell me what is the syntax for the second solution? On bar i when I call Correl(symbol1, symbol2, 10), how do I send to the function the values of symbol1[i-10] to symbol1[i] and symbol2[i-10] to symbol2[i]?

1 Like

After a time out of programing in AB I have retaken the activity with this issue.
I have coded the solution in the CBI to avoid trading symbols with high correlation which I shared with you and I would like some regarding comment to be sure that everything is ok.

_SECTION_BEGIN( "CBI" );
// Correlation parameters
termCorrelation = Param("Correlation Term", 90, 20, 300, 10);
CorrelationLevel = Param("Correlation Level", .6, 0, 1, 0.1);

SetCustomBacktestProc( "" );

if( Status( "action" ) == actionPortfolio )
{
    bo = GetBacktesterObject();

    bo.Backtest( True ); 
    
    bo.PreProcess(); // Do pre-processing (always required)

    for( i = 0; i < BarCount; i++ ) // Loop through all bars
    {
        for( sig = bo.getfirstsignal( i ); sig; sig = bo.GetNextSignal( i ) ) // Loop through all signals at this bar
        {
			if( sig.IsEntry() )
			{
				for( trade = bo.GetFirstOpenPos(); trade; trade = bo.GetNextOpenPos() )  // iterate through open positions
				{
					// Get symbols
					Symbolcheck = sig.symbol;
					SymbolcheckClose = Foreign( Symbolcheck, "Close" );
					
					Symboltrade = trade.symbol;
					SymbolTradeClose = Foreign( Symboltrade, "Close" );
					
					// Correlation between traded symbol and tested symbol					
					corr = Correlation( SymbolTradeClose, SymbolcheckClose, termCorrelation );
					
					// Excluding trades
					if (corr > CorrelationLevel OR corr < -CorrelationLevel)
					{	
						sig.PosSize = 0;
					}
				}
			}	
        }
		bo.ProcessTradeSignals( i ); //Process trades at bar (always required)
    }
    bo.PostProcess();
}
_SECTION_END();

First, performing two Foreign() calls inside the bar-by-bar loop of the CBT is inefficient and will slow down your CBT drastically. You really should consider the solution provided by @Tomasz unless you have such a large watchlist that calculating all the pairwise correlations is simply not feasible.

Second, you are assigning the result of the Correlation() function to a variable named corr. That result is an array which is calculated from all the bars which are available in the CBT. This leads to two problems, one of which you can solve:

  1. You are comparing the corr variable (which is an array) to CorrelationLevel. You should be using the bar index (in your case, the variable i) to access a specific element of the corr array instead.
  2. Because you are calling the Foreign() function in the CBT, there is no price history from before the first bar of the backtest. That in turn means that you can't calculate a correlation of N bars until you are at least N+2 bars into your backtest, because there is not sufficient data available for the calculation. In contrast, when you call functions in Phase 1, AmiBroker will attempt to load enough history prior to the start date of the backtest to ensure that all function results (indicators, etc.) will be valid as of the start date.
1 Like

Hay Matt @mradtke,
First of all thank you very much for your answer...
Of course, you are right with the problem with the correlation array. I didn`t realice.... :blush:
I have solved the problem with the bars I need to make correlation with this code by @beppe (Thanks again for that).
The template to create this code I took from an article by Wayne (Users' knowledge base), which I show you below

http://www.amibroker.org/userkb/2008/03/16/amibroker-custom-backtester-interface-2/

Here Wayne wrote:

SetCustomBacktestProc("");
if (Status("action") == actionPortfolio) {
    bo = GetBacktesterObject();    //  Get backtester object
    bo.PreProcess();    //  Do pre-processing (always required)
    for (i = 0; i < BarCount; i++)    //  Loop through all bars
    {
        for (sig = bo.GetFirstSignal(i); sig; sig = bo.GetNextSignal(i))
        {    //  Loop through all signals at this bar 
                . . . .
        }    //  End of for loop over signals at this bar
        bo.ProcessTradeSignals(i);    //  Process trades at bar (always required)
    }    //  End of for loop over bars
    bo.PostProcess();    //  Do post-processing (always required)
}

Regarding with this, to get the correlation of a pair of symbols I need to use a loop for all the bars, for this reason I use that loop a long all the bars, if not, I would use just the values a long the open positions.
In any case I know I should have some mistake, since this is my first code in the CBI.

After making the correction you suggested I show you below again, waiting for a new comment you want to tell me...

_SECTION_BEGIN( "CBI" );
// Correlation parameters
termCorrelation = Param("Correlation Term", 90, 20, 300, 10);
CorrelationLevel = Param("Correlation Level", .8, 0, 1, 0.1);

SetCustomBacktestProc( "" );

if( Status( "action" ) == actionPortfolio )
{
    bo = GetBacktesterObject();

    bo.Backtest( True ); 
    
    bo.PreProcess(); // Do pre-processing (always required)

    for( i = 0; i < BarCount; i++ ) // Loop through all bars
    {
        for( sig = bo.getfirstsignal( i ); sig; sig = bo.GetNextSignal( i ) ) // Loop through all signals at this bar
        {
			if( sig.IsEntry() )
			{
				for( trade = bo.GetFirstOpenPos(); trade; trade = bo.GetNextOpenPos() )  // iterate through open positions
				{
					// Get symbols
					Symbolcheck = sig.symbol;
					SymbolcheckClose = Foreign( Symbolcheck, "Close" );
					
					Symboltrade = trade.symbol;
					SymbolTradeClose = Foreign( Symboltrade, "Close" );
					
					// Correlation between traded symbol and tested symbol					
					corr = Correlation( SymbolTradeClose, SymbolcheckClose, termCorrelation );
					
					// Excluding trades
					if( sig.IsLong() )
					{
						if( trade.IsLong )
						{
							if( corr[i] > CorrelationLevel)
							sig.PosSize = 0; 
						}
						
						else
						{
							if( corr[i] < -CorrelationLevel )
							sig.PosSize = 0; 
						}
					}
					
					else
					{
						if( trade.IsLong )
						{
							if( corr[i] < -CorrelationLevel )
							sig.PosSize = 0; 
						}
						
						else
						{
							if( corr[i] > CorrelationLevel)
							sig.PosSize = 0; 
						}
					}
				}
			}	
        }
		bo.ProcessTradeSignals( i ); //Process trades at bar (always required)
    }
    bo.PostProcess();
}
_SECTION_END();

Of course I appreciate any other help or step to follow... I am learning a lot for all of you. :blush:

This topic was automatically closed 100 days after the last reply. New replies are no longer allowed.