sábado, 28 de diciembre de 2019

El sistema de Connors RSI2

Vamos a ver un sistema de trading clásico cuya lógica es bien simple. Se trata del sistema de Connors que utiliza un RSI de 2 sesiones para las entradas y una media de corto plazo para las salidas. Las reglas son las siguientes:

  • Si el cierre está por encima de una media de 200 entonces estamos alcistas
  • Si estamos alcistas y el RSI(2) cae por debajo de 30 compramos
  • Si estamos comprados y el cierre supera una media de 10 sesiones cerramos los largos
  • El sistema es solo largo y hay un stop loss de 6 desviaciones estándar

Debajo vemos que esta lógica funciona muy bien en los índices, que por su naturaleza tienen un comportamiento de reversión a la media (comprar cuando caen). Debajo vemos el Nasdaq100 pero en general este sistema va bien en cualquier índice:



Cuando lo probamos en el futuro mini del SP500 vemos que funciona muy bien. Debajo se puede ver la curva de capital en el SP500 desde el año 2000 y descontando $100 por operación en concepto de comisiones y deslizamiento. Los parámetros que vimos en la descripción del sistema son optimizables. En esta curva de capital del SP500 los parámetros utilizados han sido: 250 para la media de largo plazo, 26 para el umbral de compra y 8 para la media de salir de los largos.

El sistema ha generado unas 300 operaciones en el periodo con un 78% de aciertos. La relación entre ganancia y drawdown es superior a 8 y tiene unos ratios muy buenos como un Sharpe de 1.40. Podríamos decir que se trata de un buen sistema de trading.




Como viene siendo habitual el código de debajo incluye la gestión del dimensionamiento mediante un modelo de Carver para un objetivo de volatilidad anual. El fichero include <futuros.afl> contiene los multiplicadores de los futuros y se puede encontrar en este blog.

CÓDIGO DEL SISTEMA

//-------------------------------------------------------     
// SISTEMA CONNORS RSI2
// OSCAR G. CAGIGAS   
// 10 ABRIL 2018
//------------------------------------------------------- 

//VARIABLES OPTIMIZABLES// 
nstop = 6;//Optimize("nstop",5,4,6,1);  
med = Optimize("med",250,200,600,50);
umbral = Optimize("umbral",26,4,30,2);
med2 = Optimize("med2",8,4,12,1);
//----------------------------------------------------------------

//PESO EN LA CARTERA//   
iw = 0.2; 

//PARAMETROS DE GESTION DE CAPITAL
Eq = 100000;
tavol = 0.3;
idm = 2;

//CAPITAL INICIAL Y COMISIONES//  
SetOption( "initialequity", 100000 ); // starting capital     
SetOption("PriceBoundChecking",1);  
SetOption("CommissionMode", 2);  
SetOption("commissionamount",50);  //COMISIÓN INDIVIDUAL (ENTRADA O SALIDA)  
SetOption("WarningLevel", 1 );  
  
//DIMENSIONAMIENTO//   
#include <futuros.afl>   
SetOption("maxopenpositions",4);  
    
//DESVIACION STANDARD EXPONENCIAL    
desv_carver = sqrt( EMA( ( C-Ref(C,-1) )^2, 36 ) ) ;    
  
//----NÚMERO DE FUTUROS EN BASE AL FORECAST ANTERIOR, VOLATILIDAD Y EQUITY----    
dvt = Eq * tavol / 16; //daily volatility target    
ivv = desv_carver * PointValue; //instrument value volatility    
vs = Nz(dvt / ivv);  //volatility scalar    
pos = vs * iw * idm;  //forecast de 10 siempre  
numfut = round(pos);  //el número de contratos    
MarginDeposit = 1; PositionSize = NumFut;    

//----------------------------------------------------------
     
//mostrar indicadores//
pintarRSI=ParamToggle("Pintar RSI", "No|Yes", 0);
pintarMed=ParamToggle("Pintar Media", "No|Yes", 0);

//DEFINICIONES//
alcista = C > MA(C,med);

//ENTRY// 
Buy = setupa = alcista AND RSI(2) < umbral;

//EXIT// 
Sell = C > MA(C,med2);

//PANIC STOP// 
STOP=Nz(nstop * desv_carver);  
ApplyStop(stopTypeLoss,stopModePoint, STOP,1,0); 
Equity(1,0); 

//remove excesive signals// 
Buy=ExRem(Buy,Sell); 
Sell=ExRem(Sell,Buy); 

//LONG ONLY//
Short=Cover=0;

//largo o corto//   
largo=Flip(Buy,Sell OR Short);    
corto=Flip(Short,Cover OR Buy);    

//SALIDA GRAFICA//
Color = IIf(setupa,colorGreen,colorlightBlue);
Plot(C,"PRICE",Color,styleBar|styleThick,Null,Null,0,0,1);    
PlotShapes(IIf(Buy,shapeUpArrow,shapeNone),colorGreen,0,L,-15);    
PlotShapes(IIf(Buy,shapeHollowCircle,shapeNone),colorGreen,0,BuyPrice,0);    
PlotShapes(IIf(Sell AND NOT Corto,shapeDownArrow,shapeNone),colorRed,0,H,-15);    
PlotShapes(IIf(Sell AND NOT Corto,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 NOT Largo,shapeUpArrow,shapeNone),colorDarkGreen,0,L,-15);    
PlotShapes(IIf(Cover AND NOT Largo,shapeHollowCircle,shapeNone),colorDarkGreen,0,CoverPrice,0);    

if (pintarRSI)
{
Plot(RSI(2),"RSI(2)",colorBlue,styleThick|styleLeftAxisScale);
Plot(umbral,"Umbral",colorBlack,styleLine|styleLeftAxisScale);
Plot(400,"",colorAqua,styleNoDraw|styleLeftAxisScale);
}

if (pintarMed)
{
Plot(MA(C,med),"MA(" + med + ")",colorBlue,styleThick);
Plot(MA(C,med2),"MA(" + med2 + ")",colorRed,styleThick);
}
   
//PLOTTEXT//    
dist = 2*ATR(10);     
for( i = 0; i < BarCount; i++ )     
{     
if( Buy[i] ) PlotText( "Long "+NumToStr(ValueWhen(Buy[i],BuyPrice[i]),1.2), i, L[ i ]-dist[i], colorGreen );     
if( Sell[i] AND NOT Short[i]) PlotText( "Exit " + NumToStr(ValueWhen(Sell[i],SellPrice[i]),1.2), i, H[ i ]+dist[i], colorRed );     
if( Short[i] ) PlotText( "Short "+NumToStr(ValueWhen(Short[i],ShortPrice[i]),1.2), i, H[ i ]+dist[i], colorBrown );     
if( Cover[i] AND NOT Buy[i]) PlotText( "Cover " + NumToStr(ValueWhen(Cover[i],CoverPrice[i]),1.2), i, L[ i ]-dist[i], colorBlack );     
}     
    
//CHART// 
Sellstop = ValueWhen(Buy,BuyPrice-STOP);    
color = IIf(numfut == 0, colorLavender, 0); 
SetChartOptions(0,chartShowDates);     
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)+"SIST CONNORS RSI2"    
+"\n"+EncodeColor(colorGrey40)+"STDEV = "+WriteVal(desv_carver,1.6)+" Pts ; x"   + WriteVal(PointValue,1.0)
+"\n"+EncodeColor(colorRed)+"VOLAT = $"+WriteVal(ivv,1.2)  
+"\n"+ EncodeColor(colorRed)+"SL = "+NumToStr(sellstop,1.2)
+" ; RISK = "+WriteVal((C-sellstop)*PointValue*NumFut,1.0)
+"\n"+"daily volat target = " + WriteVal(dvt,1.0)  
+"\n"+"volat scalar = " + WriteVal(vs,1.2)  
+"\n"+"inst weight = " + WriteVal(100*iw,1.0) +" %" 
+"\n"+"ins div mul = " + WriteVal(idm,1.2)  
+"\n"+"pos = " + WriteVal(pos,1.2)  
+"\n"+EncodeColor(colorBlue)+"NumFut = " + WriteVal(numfut,1.0);

//PINTAMOS EL STOP//
stopline = IIf(largo OR Buy OR sell, ValueWhen(Buy, buyprice-stop), Null);
Plot(stopline, "SL", colorRed,styleDashed);

GfxSetOverlayMode(1);
GfxSelectFont("Tahoma", Status("pxheight")/30 );
GfxSetTextAlign( 6 );// center alignment
GfxSetTextColor( ColorRGB( 200, 200, 200 ) );
GfxSetBkMode(1); // transparent
GfxTextOut( "CRSI2", Status("pxwidth")/10, Status("pxheight")/2.6 );

2 comentarios:

  1. Hola,
    Una observación: ¿Qué ocurre cuando RSI(2) cae por debajo de 30 pero el precio está por encima de la media de 10? ¿Compramos? ¿Esperamos a que el precio esté por debajo de la media?
    Saludos y feliz 2020

    ResponderEliminar
    Respuestas
    1. Buena pregunta :) Todo depende de cómo lo hayas programado. En un principio esto no ocurrirá mucho, pero si lo quieres tener en cuenta entonces tienes que añadir AND C < MA(C,med2) en la compra para que solo compre si estamos por debajo. En el código no está incluido pero se puede añadir. Tal cual está ahora la posición se cerraría justo después de abrirla. No he revisado una a una las operaciones para ver si esto ocurre con la suficiente frecuencia como para que sea un problema, pero en cualquier caso tienes razón y el código estará más correcto si añadimos esto.

      Eliminar

ENTRADAS POPULARES