domingo, 13 de junio de 2021

COINTEGRACIÓN con Amibroker

La cointegración es una propiedad matemática de los precios que nos dice si estos son estacionarios y si esto se mantiene con el tiempo. El código que se anexa debajo permite operar la cointegración de dos pares mediante el método de regresión lineal.


Los detalles de la cointegración se pueden encontrar en el informe de Onda4 con el mismo nombre que recopila los artículos entre el 20 de abril y el 8 de mayo de 2021.

El fichero include "StopLossSpread" se corresponde con el código publicado en la entrada anterior.


CÓDIGO DE COINTEGRACIÓN

//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// SPREAD EN STOCKS BASADO EN COINTEGRACIÓN 
// OSCAR G. CAGIGAS  
// 16 ABRIL 2021 
// MODELO SIN DRIFT
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 
 
//VARIABLES 
OptimizerSetEngine("spso"); 
t_critico = -Optimize("t critico", 1, 1,3,0.5); 
Zref = Optimize("zref",1.2,1.2,2,0.1); 
per = Optimize("Per",70,10,80,5);  
perZ = Optimize("PerZ",45,10,100,5);  
 
//SETTINGS 
SetOption("initialequity",100000); 
SetBacktestMode(backtestRegular); 
SetOption("WarningLevel", 1 );  //quitar el aviso de división por cero   
BuyPrice = SellPrice = ShortPrice = CoverPrice = C; 
SetTradeDelays(0,0,0,0); 
 
//VALORES DEL SPREAD 
symbol1 = "ESS";  
symbol2 = "UDR"; 
 
//BUSCAR MULTIPLICADORES Y DIMENSIONAMIENTO// 
SetOption("CommissionMode", 2); 
SetOption("commissionamount",20);    //$40 por operación completa 
SetPositionSize(50, spsPercentOfEquity); 
 
//CARGAMOS DATOS DE CADA SIMBOLO// 
C1 = Foreign(symbol1,"C");  
C2 = Foreign(symbol2,"C"); 
  
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 
//&&&&&&&&&&&& REGRESIÓN LINEAL SIN DRIFT &&&&&&&&&&&&&&&&&&&& 
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 
 
//REGRESIÓN LINEAL SIN DRIFT (ALFA = 0)
beta = Sum( C2*C1, per) / Sum( C1^2 , per); //solución exacta cuando alfa es cero
C2_est = C1*beta; 
diff = C2_est - C2;  
 
//TEST DE DICKEY-FULLER 
delta = diff - Ref(diff,-1);  
laggedX = Ref(diff,-1);  
b_delta = Sum( delta*laggedX , per)/ Sum( laggedX^2 , per);  
a_delta = MA(delta,per) - b_delta*MA(laggedX,per); 
delta_est = a_delta + b_delta*laggedX;
SSR = Sum( (delta_est - delta)^2, per); //Suma Cuadrados Residuos
sigma_est = sqrt( SSR/ (per - 2)); //estimador de sigma o error estándar de regresión
Sx =  Sum( laggedX ^ 2 , per ) - (1 / per) * Sum( laggedX, per ) ^ 2; //suma(X-mX)^2
se = sigma_est / sqrt(Sx); //error estándar del coeficiente beta
t_stat = Nz(b_delta/se); //t_stat inicial

//FIABLE (SE PUEDE OPERAR)
fiable = t_stat < t_critico; //si fiable entramos y si no, no 
 
//Z-SCORE DE LA DIFERENCIA 
ZScore = ( diff - MA( diff, perZ ) ) / StDev( diff, perZ );  
 
//********************************************************************* 
 
//ABRIR LARGOS, CORTOS Y CERRAR SPREAD  
//TODO VA REFERIDO AL SÍMBOLO 2 
SetForeign(symbol2);  
AbrirLargos =  fiable AND Cross( Zscore, Zref); 
AbrirCortos =  fiable AND Cross( -Zref, Zscore); 
CerrarSpread = Cross(Zscore,0) OR Cross(0,Zscore); 
RestorePriceArrays();  
 
//DEFINICION PARA EVITAR ERRORES// 
Buy = Sell = Short = Cover = 0; 
 
//SI ABRIRLARGOS COMPRAMOS EL SPREAD 
if( Name() == symbol2 ) 
    Buy = AbrirLargos; 
    Short = AbrirCortos; 
    Sell = Cover = CerrarSpread;     
else if( Name() == symbol1 ) 
    Short = AbrirLargos; 
    Buy = AbrirCortos; 
    Sell = Cover = CerrarSpread; 
 
//********************************************************************************************** 
//*********************************** PARTE GRÁFICA ******************************************** 
//********************************************************************************************** 
 
//CALCULAR GANANCIA INDIVIDUAL Y DEL SPREAD 
Equity(1,0); 
saldo = Foreign("~~~EQUITY", "C" ); 
SpreadGain = Saldo - ValueWhen( Buy OR Short, saldo ); 
color = IIf( Name() == symbol1, colorGreen, colorBlue ); 

if ( NOT ParamToggle("Ocultar Precios","No|Yes",0) ) 
//SALIDA GRÁFICA// 
N = int(saldo*0.5/C); 
correl = Correlation( ROC(C1,1), ROC(C2,1), 252); 
SetChartOptions( 0, chartShowDates ); 
Plot( C, "Last ", colorGrey50, styleBar ); 
Title = StrFormat( "{{NAME}} - {{INTERVAL}} {{DATE}} Open %g, Hi %g, Lo %g, Close %g (%.1f%%) {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 ) ) ) 
+ "\n" + FullName() + "\n" + EncodeColor( colorBlue ) + "SISTEMA COSTA" 
+ "\n" + EncodeColor( colorGrey40 ) + "N = " + WriteVal(N, 1)  
+ "\n" + EncodeColor( Colorblack ) + "Spread Gain = " + WriteVal( spreadGain, 1 ) 
+ "\n" + EncodeColor( Colorgrey50 ) + "Corr = " + WriteVal( Correl, 1.4 ) 
+ "\n" + "t_stat = " + WriteVal( t_stat, 1.4 );  

//CIRCULOS EN PANTALLA// 
PlotShapes( IIf( Buy, shapeUpArrow, shapeNone ), colorGreen, 0, L, -15 ); 
PlotShapes( IIf( Buy , shapeHollowCircle, shapeNone ), colorGreen, 0, BuyPrice, 0 ); 
PlotShapes( IIf( Short , shapeDownArrow, shapeNone ), colorBrown, 0, H, -15 ); 
PlotShapes( IIf( Short, shapeHollowCircle, shapeNone ), colorBrown, 0, ShortPrice, 0 ); 
PlotShapes( IIf( Sell AND NOT Short, shapeDownArrow, shapeNone ), colorRed, 0, H, -15 ); 
PlotShapes( IIf( Sell AND NOT Short, shapeHollowCircle, shapeNone ), colorRed, 0, SellPrice, 0 ); 
PlotShapes( IIf( Cover AND NOT Buy, shapeUpArrow, shapeNone ), colorDarkGreen, 0, L, -15 ); 
PlotShapes( IIf( Cover AND NOT Buy, shapeHollowCircle, shapeNone ), colorDarkGreen, 0, CoverPrice, 0 ); 
 
//LETREROS// 
dist = 2 * ATR( 10 ); 
for( i = 0; i < BarCount; i++ ) 
if( Buy[i] ) PlotText( "Long " + NumToStr( ValueWhen( Buy[i], BuyPrice[i] ), 1.4 ), i, L[ i ] - dist[i], colorGreen ); 
if( Short[i] ) PlotText( "Short " + NumToStr( ValueWhen( Short[i], ShortPrice[i] ), 1.4 ), i, H[ i ] + dist[i], colorBrown ); 
if( Sell[i] AND NOT Short[i] ) PlotText( "Exit " + NumToStr( ValueWhen( Sell[i], SellPrice[i] ), 1.4 ), i, H[ i ] + dist[i], colorRed ); 
if( Cover[i] AND NOT Buy[i] ) PlotText( "Cover " + NumToStr( ValueWhen( Cover[i], CoverPrice[i] ), 1.4 ), i, L[ i ] - dist[i], colorDarkGreen ); 
//PINTAR INDICADORES
if ( ParamToggle("Pintar Diferencia","No|Yes",0) )
{
Plot(diff,"diff",colorGreen,styleLeftAxisScale|styleThick);
Plot(0,"0",colorGrey50,styleLeftAxisScale|styleLine);
Plot(20,"",colorAqua,styleNoDraw|styleLeftAxisScale);
}
if ( ParamToggle("Pintar ZScore","No|Yes",0) )
{
Plot(zscore,"zscore",colorOrange,styleLeftAxisScale|styleThick);
Plot(0,"0",colorGrey50,styleLeftAxisScale|styleLine);
Plot(Zref,"+Zref",colorGrey50,styleLeftAxisScale|styleLine);
Plot(-Zref,"-Zref",colorGrey50,styleLeftAxisScale|styleLine);
Plot(20,"",colorAqua,styleNoDraw|styleLeftAxisScale);
}
if ( ParamToggle("Pintar Estimación","No|Yes",0) )
{
if(Name() == symbol2) 
{
Plot(C2_est,"C2_est",colorRed,styleThick);
}
}
if ( ParamToggle("Pintar Beta","No|Yes",0) )
{
Plot( beta, "beta",colorRed,styleOwnScale);
}
if ( ParamToggle("Pintar Error esti","No|Yes",0) )
{
Plot( se, "err est",colorRed,styleLeftAxisScale);
}
if ( ParamToggle("Pintar t","No|Yes",0) )
{
Plot( t_stat, "t_stat",colorBlue,styleLeftAxisScale);
Plot(t_critico,"t_critico",colorBlue,styleLeftAxisScale|styleLine);
Plot( 2, "Ribbon", IIf( fiable , colorGreen, colorWhite ),
styleOwnScale|styleArea|styleNoLabel, -0.5, 100 );
}
//PINTAR LA GANANCIA DEL SPREAD
if ( ParamToggle("Pintar Ganancia","No|Yes",0) ) 
{
Plot(saldo,"Equity",colorgrey50,styleOwnScale|styleThick);
}
//COMPROBAR SI EL TICKER ES CORRECTO//
if( Name() != symbol1 AND Name() != symbol2 )
{
GfxSetBkColor( 11); GfxSelectFont( "Tahoma", 20 ); 
GfxSetBkMode( 2 ); GfxTextOut("SELECT: "+symbol1+" or "+symbol2, 40, 20 ); 
 
//STOP LOSS (COMPROBAR IMPORTE EN EL INCLUDE) 
#include <StopLossSpread.afl> 
 
//MOSTRAR CÁLCULOS 
Filter = Name() == symbol1; 
AddColumn( c1, "    c1   ", 1.2); 
AddColumn( c2, "    c2   ", 1.2 ); 
AddColumn( beta, "   Beta   ", 1.4); 
AddColumn( C2_est, "   C2_est   ", 1.4 ); 
AddColumn( diff, "    diff    ", 1.4 ); 
AddColumn( se, "   sta err   ",1.4); 
AddColumn( t_stat, "    t_stat    ", 1.4); 




4 comentarios:

  1. Buen día, Don Oscar, el ultimo informe referente a este tema donde puedo descargarlo? Saludos desde Venezuela.

    Lo un punto importante antes de implementar la operativa, es realizar un Explorer, buscando las acciones con mejor correlación e integración posible, cierto?

    ResponderEliminar
    Respuestas
    1. El libro de Cointegración está disponible bajo suscripción en la zona privada de clientes de Onda4. Sí, es muy importante buscar entre los valores de alta correlación. Saludos

      Eliminar
  2. Oscar, al hacer el backtest sale algo muy raro. Cuando activo en settings > "positions: long/short", en los resultados sale o dos compras o dos ventas en el mismo dia, es decir o compra dos veces o vende dos veces, y todas las operaciones son sobre la misma pata del spread haciendo durante todo el backtest como si la otra pata no existiese y duplicando las operaciones del mismo lado. Y si pongo long only, sí que sale la otra pata del par, pero obviamente no adopta la posición contraria con la otra pata del par. Hay que desactivar alguna cosa?

    ResponderEliminar
    Respuestas
    1. Eso suena a un problema con los settings. Prueba un código más sencillo de spreads y cuando haga bien las entradas puedes usar esos settings para la cointegración. Saludos

      Eliminar

ENTRADAS POPULARES