I can't sell after the second day

Hello, how are you?

Based on the book "Trading with Automatic Systems" by Mr. Oscar G. Cagigas, I've tried to develop the "Fugax" system that he talks about on pages 91-94.
I've managed to get it to work more or less well, but the condition of selling at the first opening AFTER THE SECOND DAY is the one that I can't get to work.
Also, I don't see any operation in the backtest that indicates that the Stop Loss is triggered and that seems strange to me.
I'm attaching the AFL file in case someone can help me, and an image of some operation where you can see that it enters on one day and exits the next (not respecting the two-day thing).

/*Nombre sistema: Sistema Fugax FB
Autor: FB
Activos: Acciones Nasdaq 100
Temporalidad: Diaria
Largos/Cortos: Largos y Cortos
Resumen: 
/*Sistema Reversal que mide la aceleración del precio mediante unas bandas de aceleración.
El precio suele estar casi siempre dentro de esas bandas pero si se sale de ellas,
nos prepararemos para tomar el sentido contrario.
La tendencia de la MA30 de los cierres del activo elegido y la pendiente de la Recta de Regresión lineal de 20 periodos del SP500
se utilizarán como filtros

Cagigas nos dá estos datos:
// Setup
// 		El mínimo de hoy queda por debajo de la banda inferior
//		La media simple de 30 de los cierres está subiendo (Filtro de Tendencia)
//		EL SP500 está subiendo (Pendiente de regresión lineal de los últimos 20 cierres > 0
//
// Buy
//		Todas las condiciones del setup ocurrieron ayer
//		Hoy se abre por debajo de la banda Lowerband
//		Ponemos una orden de compra stop por encima del precio, justo en la banda Lowerband
//
// Sell 
//		Vendemos en la primera apertura con ganacias después del segundo día. Es decir, que si p.e. entramos un lunes, venderemos en la primera apertrua con ganacias a partri del miércoles inclusive
//
// Stop Loss
//		El 5% por debajo del precio de entrada*/ 

_SECTION_BEGIN("Sistema ");

#include_once "Formulas\Norgate Data\Norgate Data Functions.afl"//Para usar funciones de NorgateData

// 1. TIPO DE SISTEMA [SIEMPRE]
SetBacktestMode( backtestRegular ); 

// 2. TEMPORALIDAD [SIEMPRE]
//Diaria

// 3. PARÁMETROS DE ENTRADA [OPCIONAL] 
NumPos = Optimize("Num. Posiciones",1,1,12,1);

// 4. DETECTAR WATCHLIST (FILTER) [OPCIONAL] 
//Nada

// 5. ANALYSIS SETTINGS [SIEMPRE]
SetOption( "InitialEquity", 100000 ); 
SetOption ("MaxOpenPositions", NumPos);
SetOption ("MaxOpenLong",0);
SetOption("MaxOpenShort",0);
SetOption("SeparateLongShortRank",False);
SetOption ("AllowPositionShrinking", True); 
SetOption("CommissionMode", 2);
SetOption ("CommissionAmount", 3.00); 
SetOption ("AllowSameBarExit", True);
SetOption ("HoldMinbars", 1); 
SetOption ("ReverseSignalForcesExit", False);
SetTradeDelays(0,0,0,0);
SetOption("ActivateStopsImmediately", True);

// 6. REBALANCEO [OPCIONAL]
//Nada

//7. FILTRO DE MERCADO [OPCIONAL] 
SP500 = Foreign("$SPX", "Close"); 
PendienteSP500 = LinRegSlope(SP500, 20);

// 8. TAMAÑO DE LA POSICIÓN [SIEMPRE]
SetPositionSize(100/NumPos, spsPercentOfEquity);

// 9. CÁLCULO INDICADORES [SIEMPRE]
//Bandas de aceleración
Lowerband  = MA((L*(1-2*((((H-L)/((H+L)/2))*1000)*0.001))),20);
Higherband = MA((L*(1+2*((((H-L)/((H+L)/2))*1000)*0.001))),20);

//MA30 de los Cierres
MA30=MA(Close,30);

// 10. REGLAS DEL SISTEMA [SIEMPRE]
// Evitar Acciones Deslistadas
dt = DateTime();
bi = BarIndex();
delistedSecurity = Nz(DateTimeDiff(dt, GetFnData("DelistingDate")) >= 0);
barsBeforeDelisting = LastValue(ValueWhen(dt == GetFnData("DelistingDate"), bi, 1)) -bi;

//Que sean accciones constituyentes del índice
Constituyentes_Nasdaq100 = NorgateIndexConstituentTimeSeries("$NDX");

//Evitar Acciones que no quiero
Precio_Minimo = 5;
SharesOut = GetFnData("SharesOut");
Market_Cap = SharesOut*Close; //Nano<50M, Micro 50-300M, Small 200M-2.000M, Med 2.000-10.000M, Large 10.000-200.000M, Mega >200.000M
Vol_Promedio30d = MA(V,30);
Vol_Promedio90d = MA(V,90);
AccionesOK = Precio_Minimo AND Market_Cap >500000000 AND Vol_Promedio30d > 1000000;

//Las condiciones de Compra
C1 = Low < Lowerband; 
C2 = MA30>Ref(MA30,-1); 
C3 = PendienteSP500 >0; 
Setup = C1 AND C2 AND C3; 
C4 = Open < Ref(Lowerband,-1); 
C5 = High >= Ref(Lowerband,-1); 

BuySetup = Ref(Setup, -1) AND C4 AND C5 AND AccionesOK;
Buy = BuySetup;
BuyPrice = Ref(Lowerband,-1); 

//Inicialización de variables
priceatbuy = 0; //Se inicializa como 0 para luego almacenar el precio de compra en la primera compra que ocurra
bi = BarIndex(); //Inicializa índice de barra, útil para saber en qué día fue la compra.
nstop = 0.05; //Porcentaje para el stop loss (del 5%) en el bucle
barsSinceEntry = 0;  // Variable para contar barras desde la compra
stopprice =0;

//Bucle principal para pasar sobre todas las barras, desde la 0 a la última
for( i = 0; i < BarCount; i++ )
{
    //Condición de Compra
    if( priceatbuy == 0 && Buy[ i ] ) //Nueva Compra
    {
       priceatbuy = BuyPrice[ i ]; //Guardar el precio de compra
       stopprice = priceatbuy*(1 - nstop); // Calcular el Stop Loss
       EntryBar = bi[ i ]; //Guardar Barra de entrada
       barsSinceEntry = 0; // Reiniciar contador de barras
    }
    //Condición de Venta
	if( priceatbuy > 0) //Si estamos comprados
    {
		// Incrementar contador de barras desde la compra
        barsSinceEntry++; 
		
		//Salida por Ganancias tras dos días como mínimo
		if (barsSinceEntry > 3 && Open[ i ] > priceatbuy  ) 
		{
			Sell[ i ] = 1; // Activar señal de venta
			SellPrice[ i ] = Open[i]; // Precio de venta
			priceatbuy = 0; // Resetear el precio de compra después de vender
            barsSinceEntry = 0; // Resetear contador de barras
		}
		//Salida por Stop Loss
		else if(Low[ i ] < stopprice )
		{
			Sell[ i ] = 1; // Activar señal de venta por stop loss
			SellPrice[ i ] = stopprice; // Precio de venta por stop loss
			priceatbuy = 0; // Resetear el precio de compra después de vender
            barsSinceEntry = 0; // Resetear contador de barras
		}
	}
    else
    {
       Sell[ i ] = 0; // Asegurar que Sell solo se activa en las condiciones específicas
    } 

}

//No hay Cortos
Short = Cover =0;

// 12. TAKEPROFIT [OPCIONAL]
//Nada

// 13. ELIMINAR SEÑALES EXTRAS [OPCIONAL]
Buy = ExRem( Buy, Sell );
Sell = ExRem( Sell, Buy );

// 14. EXPLORADOR [OPCIONAL]
//Nada

// 15. GUARDAR CURVA DE CAPITAL [OPCIONAL]
//Nada

// 16. DIBUJAR INDICADORES EN EL GRÁFICO [OPCIONAL]
// Nada

_SECTION_END();

Thank you very much

barsSinceEntry++; you are incrementing in the same bar that you enter, which will work but you have to remember so. Otherwise barsSinceEntry should be 1 in the next bar

else if(Low[ i ] < stopprice && barsSinceEntry > 1) // try this

You can check stop in next bar instead of bar that you are entering. Maybe some trades are getting stopped out in initial bar itself.

1 Like

Thank you very much nsm51,
I just had a "very serious conversation" :sweat_smile:with ChatGpt who is my private AFL teacher.
He told me that I didn't count the buy bar and I had to explain to him that I did.
I'm finding ChatGpt quite useful for learning AFL but it has important gaps!! Good luck with this forum and your attention!.
Thank you very much

2 Likes

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