Replicating applystop functionality using AFL code

Hi

I have a goal to understand applystop and afl in more detail.
I would like to code a couple of simple applystop modes, as opposed to using the applystop function itself via the backtester, purely as an exercise in understanding it.

I have read the applystop documentation and looked through this forum around applystop and there is great information about it. Additionally I have read thru Dr Bandy’s Book however, I have not been able to find sample code which simulates (using AFL for loops) some of the applystop modes/features.

I have the following code, which is a simple trending system, it includes the following applystops

The applystops I am trying to replicate are the following:

ApplyStop(stopTypeProfit, stopModePoint, ProfitATR, 1, False );
ApplyStop(stopTypeTrailing, stopModePoint, StopATR, 1, False );
ApplyStop( stopTypeNBar, stopModeBars, NBARS);


	SetOption("MaxOpenPositions", 10); 
	SetOption("InitialEquity", 10000); 
	
// backtesting
	SetOption("AllowSameBarExit", True);
	SetOption("ActivateStopsImmediately",False); 
	SetOption("AllowPositionShrinking", True); 
	SetPositionSize( 100000 / 10, spsValue);
	SetTradeDelays(0,0,0,0); 
 
// Buy & Sell 
	Buy = Sell = Short = Cover = 0;  
	BuyPrice = SellPrice = Open; 
	ShortPrice = CoverPrice = 0; 	

	
//=====================================================
//      Volume  Filter (VF) - Volume   
	Volume_Threshold = 5000000; // Weekly threshold 
	TurnoverOK = Weekly_Avg_TurnOver = Ref(MA(Volume * Close,10),-1); 
//=====================================================   
//      Universe Trend Filter - UTF  
	TrendOK = EMA( C, 28 ) > EMA(C, 48);
//=====================================================
//		Universe Price Filter - UPF
	MinPrice 				= 0.2;
	MaxPrice				= 2000;
	PriceOK					= MA(C,10) > MinPrice AND MA(C,10) < MaxPrice;
//====================================================
//  *** SMACD for positionScore*** 

	mafast_Param = 20;
	maslow_Param = 26;
	SMACD_smooth =  9;//Optimize("SMACD_smooth_Param", 9, 5, 12, 1);  
	mafast = ma(C,mafast_Param);  
	maslow = ma(C,maslow_Param);  
	SMACD_osc = ((mafast - maslow)/C)*100;   //SMAC fast  
	SMACD_signal = ma(SMACD_osc,SMACD_smooth);  //SMAC slower 


Tradeable = TurnOverOK AND PriceOK AND TrendOK;
 
PositionScore =  Max(SMACD_signal + 100,0);
	
Buy = EMA(C,4)> EMA(C,15) AND TradeAble;
Sell = EMA(C,15)> EMA(C,4);
	
///https://www.amibroker.com/guide/afl/applystop.html
//ApplyStop( type, mode, amount, exitatstop, volatile = False, ReEntryDelay = 0, ValidFrom = 0, ValidTo = -1 )
//ExitAtStop
/*
ExitAtStop = 0 - means check stops using only trade price and exit at regular trade price(1)
(if you are trading on close it means that only close price will be checked for exits and exit will be done at close price)
ExitAtStop = 1 - check High-Low prices and exit intraday on price equal to stop level on the same bar when stop was triggered
ExitAtStop = 2 - check High-Low prices but exit NEXT BAR on regular trade price.
*/


ProfitATR = 10 *ATR(10); //Percentage
StopATR = 5 * ATR(10);
NBARS = 30; 


//## 3 types of Applystop
/*
ApplyStop(stopTypeProfit, stopModePoint, ProfitATR, 1, False );  
ApplyStop(stopTypeTrailing, stopModePoint, StopATR, 1, False );   
ApplyStop( stopTypeNBar, stopModeBars, NBARS);
*/

//## Following  mimics the respective applyStops above by looping through all the bars and testing each condition etc.
// If the following is uncommented then comment out the respective applystop statements above.

PriceAtBuy = 0;  // IF not 0 then we it is in a trade
HighSinceBuy = 0; // Highest price since buy required for chandelier
Exit = 0; //True if we are in exit mode, can be used for scalling out
BarsSinceBuy = 0;



for( i = 0; i < BarCount; i++ )
{
    if( PriceAtBuy == 0 AND Buy[i] == 1 )
    {
        PriceAtBuy = BuyPrice[i];   // We have a new buy
    }
    else if( PriceAtBuy > 0 )
	{
		// if here, we must be in the trade
		HighSinceBuy = Max( High[i], HighSinceBuy ); //keeps track of high price in trade for chandelier stop, not used in this case
		BarsSinceBuy++;

		//## PROFIT TARGET HIT -EXIT ApplyStop(stopTypeProfit, stopModePoint, ProfitATR, 1, False )
		if(Exit==0 AND H[i] >= ((1 + ProfitATR[i]*0.01) * PriceAtBuy))
		{
			Exit = 1;
			SellPrice[i] = Close[i];  //or do we use high price?
		}

		//## TRAILING STOP -EXIT ApplyStop(stopTypeTrailing, stopModePoint, StopATR, 1, False );
		if(L[i] <= ( 1 - StopATR[i] * 0.01 ) )
		{
			Exit = 2;
			SellPrice[i] = Close[i]; //or do we use low price?
		}

		//##TIMESTOP - EXIT ApplyStop( stopTypeNBar, stopModeBars, NBARS); 
		if ( BarsSinceBuy >= NBARS )
		{
			Exit = 3;
			SellPrice[i] = Close[i];
		}

		//# REQUIRED FOR RESETTING COUNTERS IN THIS LOOP
		if( Exit >= 1 ) //reset
		{
			Buy[i] = 0;
			Sell[i] = Exit + 1; // mark appropriate exit code
			Exit = 0;
			PriceAtBuy = 0;
			HighSinceBuy = 0;
			BarsSinceBuy = 0;

		}
	}
}


//### End of alternative APPLY STOP


I have attempted to add AFL code to replace each of these applystops individually, however I am not able to get same the results (from backtesting) between the applystops and my AFL version of it. FYI I comment out the relevant sections in the code to isolate each applystop.

My objective it to have same/similar results from backtesting when using applystop and my AFL version to confirm my understanding.

Would be appreciated if someone could assist with my understanding (from the code) with the applystop. I am sure this would benefit others as well.

Thanks
Richard

Hi @rick

There are som issues with the way you structure the for loop code to match your ApplyStop equivalent
in order to emulate applystop you need to read this carefully and understand the meaning of each parameter
https://www.amibroker.com/guide/afl/applystop.html

ApplyStop(stopTypeProfit, stopModePoint, ProfitATR, 1, False );
ApplyStop(stopTypeTrailing, stopModePoint, StopATR, 1, False );

Because False is specified in the last parameter Both these Applystops will be fixed base on the ATR value at the entry bar.

In Your code the value of the stop will change at each bar after entry.

Your calculation of the stop levels in the loop is incorrect. ProfitATR and StopATR is not a % value they are arrays containing $Values of the 10 period Average True Range * your factor. so you add or subtract them directly from the entry price to match the Applystop mode = StopModePoint..
eg ProfitStopLevel will be

// add this line to your first if statement so the stop levels remains fixed while in the trade
ProfitStopPrice = BuyPrice [i] + ProfitStopATR[i];
StopPrice = BuyPrice [i] - StopATR[i];
//Change your Profitstop if Statement to

if(Exit==0 AND H[i] >=  ProfitStopPrice )
{
   		Exit = 2;//should be = 2 as profit stop is sell = 3
   		SellPrice[i] = Max(Open [i] , ProfitStopPrice );  /*or do we use high price? No  but depends how you are setting up trades with your broker eg bracket orders or inmarket limit at the profit stop level */
}
//you need to similarly change you Trailing Stop if Statemeent 



The best way to learn is to go through detail debugging, copying and pasting doesnt give much insight to what the code is doing therefore
I would recommend you read tutorials on how tor debug your code How do I debug my formula?
use explorations to check that the code is producing stop levels you expect & plot them on a chart for a visual confirmation and also incorporate _Trace statements to see how its working bar by bar.

good luck with your journey

Richard.

1 Like

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