sábado, 29 de mayo de 2021

Stop Loss en un Spread

Hay muchas formas de operar Spreads en Amibroker, pero todas ellas requieren que se cierre la posición si la pérdida conjunta supera un cierto umbral. Si no lo hiciéramos así el riesgo sería ilimitado. 

El código que comparto hoy modifica el Backstester (Custom BackTester) para sumar el beneficio de las dos patas del spread y cerrar la posición si excede el nivel de stop loss. 

También incluye estadísticas adicionales por parejas de operaciones, como el Profit Factor, ganancias y pérdidas promedio, máxima pérdida, etc.



STOP LOSS SPREAD

//********************************************
// STOP LOSS LOW LEVEL CBT PARA UN SPREAD 
//  OSCAR G. CAGIGAS
// 9 ABRIL 2021

//********************************************
//PÉRDIDA CONJUNTA PARA CERRAR EL SPREAD
stoploss = 4000;
//PROCEDIMIENTO CBT
SetCustomBacktestProc( "" ); // enable custom bt proc 
if ( Status( "action" ) == actionPortfolio ) 

    bo   = GetBacktesterObject();   //  Get backtester object 
    bo.PreProcess();   //  Do pre-processing

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%% BUCLE POR LAS BARRAS PARA STOP LOSS %%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
for ( i = 0; i < BarCount; i++ )   //  bucle por las barras
    { 
        
        bo.ProcessTradeSignals(i);     //ACTUALIZAR EL EQUITY
        
        suma = 0; 
  
        for ( trade = bo.GetFirstOpenPos(); trade; trade = bo.GetNextOpenPos() )   //  bucle sobre las pos abiertas 
        { 
            suma  = suma + trade.GetProfit();   //  sumamos beneficios de las dos patas
        }
        
        //STOP LOSS ORDINARIO//
        if ( suma[i] < -stoploss )
        {
for ( trade = bo.GetFirstOpenPos(); trade; trade = bo.GetNextOpenPos() )   //  bucle sobre las pos abiertas 
{
bo.ExitTrade( i, trade.Symbol, trade.GetPrice(i,"C"), 2); //exit reason = 2 muestra "stop loss" en el reporte
}
  }
 
bo.UpdateStats( i, 1 );   //  Update MAE/MFE stats for bar   
        bo.UpdateStats( i, 2 );   //  Update stats at bar's end 
    }   //%%% fin del bucle por las barras
    bo.PostProcess();   //  Do post-processing 
    
    //-------------------------------------------------------------------------------------------------------------
    
//AHORA SACAMOS LAS ESTADÍSTICAS POR OPERACIÓN CONJUNTA
contador = 1; 
fecha1e = fecha1s = 0; //fecha de entrada y de salida de la primera pareja del par
profit = NumTrades = pos = neg = NumPos = NumNeg = Num = result = maxper = 0;
   
//#############################################################################
//####################### OPERACIONES CERRADAS ################################
//#############################################################################  
for( trade = bo.GetFirstTrade(); trade; trade = bo.GetNextTrade() ) 

//si es el segundo símbolo del par
if (contador == 2 ) 
{
result = profit + trade.getprofit(); 
profit = 0; 
}
else 
{
profit = trade.getprofit(); 
result = 0; 
contador = 1; 
fecha1e = trade.EntryDateTime;
fecha1s = trade.ExitDateTime;
}
//descomentar para ver el número de trade de la pareja
//trade.AddCustomMetric("contador",contador); 
if ( trade.EntryDateTime == fecha1e && trade.ExitDateTime == fecha1s ) //si cuadran las fechas

trade.AddCustomMetric("Spread",result); //mostrar solo el profit conjunto
}

NumTrades++; 
contador++;

//AHORA CALCULAMOS ESTADÍSTICAS DE SPREAD (CON EL RESULTADO POR PAREJAS "RESULT")
if (result > 0) //LAS GANANCIAS

pos = pos + result; 
NumPos++;

else if (result < 0) //LAS PÉRDIDAS

neg = neg + result; 
NumNeg++;
if (result < maxper) 
maxper = result; //MÁXIMA PERDIDA

} //### fin del bucle por las ops cerradas

//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
//&&&&&&&&&&&&&&&&&&&&&&& OPERACIONES ABIERTAS &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
for( trade = bo.GetFirstOpenPos(); trade; trade = bo.GetNextOpenPos() ) 

      // calculamos el beneficio a partir del objeto GetPercentProfit
if (contador == 2 ) 
{
result = profit + trade.getprofit(); 
profit = 0;  
}
else 
{
profit = trade.getprofit(); 
result = 0; 
contador = 1; 
fecha1e = trade.EntryDateTime;
fecha1s = trade.ExitDateTime;
}
//descomentar para ver el número de trade de la pareja
//trade.AddCustomMetric("contador",contador); 
if ( trade.EntryDateTime == fecha1e && trade.ExitDateTime == fecha1s ) //si cuadran las fechas

trade.AddCustomMetric("Spread",result); //mostrar solo el profit conjunto
}
else 
{
profit = trade.getprofit(); 
result = 0; 
contador = 1; 
fecha1e = trade.EntryDateTime;
fecha1s = trade.ExitDateTime;
trade.AddCustomMetric("Profit",result); 
}
NumTrades++; 
contador++;

//AHORA CALCULAMOS ESTADÍSTICAS DE SPREAD (CON EL RESULTADO POR PAREJAS "RESULT")
if (result > 0) //LAS GANANCIAS

pos = pos + result; 
NumPos++;

else if (result < 0) //LAS PÉRDIDAS

neg = neg + result; 
NumNeg++;
if (result < maxper) maxper = result; //MÁXIMA PERDIDA

} //&&& fin del bucle por las ops abiertas 
   
bo.ListTrades(); //LISTAR TRADES
PF = pos/-neg; //profit factor
Num = NumPos + NumNeg; //número de operaciones (parejas)
media = ( pos + neg ) / Num; //GANANCIA MEDIA POR OPERACIÓN
  
//MÉTRICAS AÑADIDAS//
formatoNum = StrFormat("%g", Num); 
bo.AddCustomMetric( "Spread Statistics", "" ); 
bo.AddCustomMetric( "#Trades", formatoNum ); 
bo.AddCustomMetric( "Win%", 100*NumPos/Num ); 
bo.AddCustomMetric( "PF", PF );
bo.AddCustomMetric( "Avg Gain", Pos/NumPos );  
bo.AddCustomMetric( "Avg Loss", Neg/NumNeg );   
bo.AddCustomMetric( "Avg P/L", media );  
bo.AddCustomMetric( "MaxLoss", maxper );      
}

1 comentario:

ENTRADAS POPULARES