Trailing Stop Loop with Market Filter

Good day all,

I'm having problem coding loop trailing stop to align with the ApplyStop. I tried searching the forum but did not find the answer I need, unless I don't know where to look.

The trailing stop varies based on the market condition. If the Index closes above its 10 period moving average, the trailing stop's exit percentage will be 20%, otherwise will be 10%. I have found code that replicates how the ApplyStop behaves. However, I wish to use loop instead for further charting purposes.

As shown below picture, I need the Red Line to be the same as the Orange Line.

Any pointers will be greater appreciated!

Thanks,

image

SetOption( "InitialEquity", 200000 );
SetOption( "CommissionMode", 2 );
SetOption( "CommissionAmount", 9.50 );
SetOption( "AllowSameBarExit", False );
SetOption( "AllowPositionShrinking", False );
SetOption( "MaxOpenPositions", 20 );

SetPositionSize( 10000, spsValue );

SetTradeDelays( 1, 1, 1, 1 );

//--------------------- Buy Signal --------------------- //
Buy = C > EMA(C,70);

//--------------------- Index Filter ---------------------//
SetForeign( "$XAO" );
Index_Up = C > MA( C, 10 );
RestorePriceArrays();

//--------------------- Sell Trailing Stop --------------------- //
Sell = 0;
Exit_Percent = IIf( Index_Up, 20, 10 );
ApplyStop( stopTypeTrailing, stopModePercent, Exit_Percent, ExitAtStop = 2 );

trailARRAY = Null;
OnLastTwoBarsOfInactiveSecurity = trailstop = 0;
StopLevel = Null;
/*
for( i = 1; i < BarCount; i++ )
 {	
	 
	if(Index_Up[i] == True)
	{
		StopLevel[i] = 1 - 20/100;		
	} 
	
	if(Index_Up[i] == False)
	{
		StopLevel[i] = 1 - 10/100;
	}
	
	if( trailstop == 0 AND Buy[ i ] ) 
	{ 
		trailstop = High[ i ] * StopLevel[i];
	}
	
	else Buy[ i ] = 0; // remove excess buy signals
   
	if( trailstop > 0 AND Low[ i ] < trailstop )
	{
		Sell[ i ] = 1;
		SellPrice[ i ] = trailstop;
		trailstop = 0;
		SellType[i] = 1;
	}

	if( trailstop > 0)
	{   
		if(Index_Up[i] != Index_Up[i-1]){
			trailstop = High[ i ] * StopLevel[i];
			trailARRAY[ i ] = trailstop;
		}else{
			trailstop = Max( High[ i ] * StopLevel[i], trailstop);
			trailARRAY[ i ] = trailstop;
		}
	}

}
*/
for( i = 1; i < BarCount; i++ )
{

if( Index_Up[ i ] == True ) 
 {
  StopLevel = 1 - 20/100;
  }
  else StopLevel =1 - 10/100;
  
   if( trailstop == 0 AND Buy[ i ] ) 
   { 
      trailstop = High[ i ] * StopLevel;
   }
   else Buy[ i ] = 0; // remove excess buy signals

   if( trailstop > 0 AND Low[ i ] < trailstop  OR OnLastTwoBarsOfInactiveSecurity [ i ] == 1)
   {
      Sell[ i ] = 1;
      SellPrice[ i ] = trailstop;
      trailstop = 0;
   }

   if( trailstop > 0 )
   {
      trailstop = Max( High[ i ] * StopLevel, trailstop );
      trailARRAY[ i ] = trailstop;
   }

}

//Plot Looping Trail
Plot( trailARRAY,"trailing stop level", colorRed );

//---------------------------------- Charting ------------------------------------- //
Plot( C, "Price", colorDefault, styleBar|styleThick|styleNoTitle );
PlotShapes( Buy*shapeUpTriangle, colorGreen, 0, Low, -20 ); 
PlotShapes( ( Sell > 0 ) * shapeDownTriangle, colorRed, 0, High, -40 );

RibbonColor = IIf( Index_Up, colorGreen, colorRed ); // If Index Up is TRUE the ribbon is GREEN, If Index Up is FALSE the ribbon is Red
Plot( 1, "", RibbonColor, styleArea | styleOwnScale | styleNoLabel, -0.0001, 190 );

//Plot ApplyStop Trail
Equity( 1, 0 );
InTrade = Flip( Buy, Sell );
SetOption("EveryBarNullCheck", True );
stopline = IIf( InTrade, HighestSince( Buy, High ) * ( 1 - 0.01 * Exit_Percent ), Null );
Plot( stopline, "trailing stop line", colorOrange );
1 Like

Hi Edmund,
My first brief 'pointer' would be that ApplyStop() seems to maintain a highest High variable to hang the trailing stop from.
Keep working on it. I have learned a lot by just persisting on an exercise even if its just to gain insight.

1 Like

Thanks for the reply @JohnHT
Still trying but will keep persisting :slight_smile:

Hi Edmund,

Before I extend my thoughts I want to clarify something: in my experience trailing stops (discussing long trades here) do not reduce in value at any stage in the trade. Different factors may influence the stop to move up or to maintain its current value but it never reduces. Could you confirm that you do want the stop to actually drop in price when the Index_Up variable changes to True?

If you do I would want to investigate if ApplyStop() can actually reproduce that - I am not 100% familiar with ApplyStop().

ApplyStop will set the stop value based off the bar by bar array value (based off ApplyStop parameters).

So yes it will accommodate that method.

1 Like

Ahh I think I see. I will do some tests later to explore this.
Thanks.

Hi guys,

I might have shared the wrong code, my bad.

Managed to figure out how to get my loop to vary like how the ApplyStop() varies. Trying to figure out why certain plots are not the same. Any pointer?

NotHigh2

SetOption( "InitialEquity", 200000 );
SetOption( "CommissionMode", 2 );
SetOption( "CommissionAmount", 9.50 );
SetOption( "AllowSameBarExit", False );
SetOption( "AllowPositionShrinking", False );
SetOption( "MaxOpenPositions", 20 );

SetPositionSize( 10000, spsValue );

SetTradeDelays( 1, 1, 1, 1 );

//--------------------- Buy Signal --------------------- //
Buy = C > EMA(C,70);

//--------------------- Index Filter ---------------------//
SetForeign( "$XAO" );
Index_Up = C > MA( C, 10 );
RestorePriceArrays();

//--------------------- Sell Trailing Stop --------------------- //
Sell = 0;
Exit_Percent = IIf( Index_Up, 20, 10 );
//ApplyStop( stopTypeTrailing, stopModePercent, Exit_Percent, ExitAtStop = 2 );

trailARRAY = Null;
StopLevel = Null;
trailstop = IndexUpSet = IndexDownSet = 0;

for( i = 1; i < BarCount; i++ )
 {	
	 
	if(Index_Up[i] == True)
	{
		StopLevel[i] = 1 - 20/100;		
	} 
	
	if(Index_Up[i] == False)
	{
		StopLevel[i] = 1 - 10/100;
	}
	
	if( trailstop == 0 AND Buy[ i ] ) 
	{ 
		trailstop = High[ i ] * StopLevel[i];
	}
	
	else Buy[ i ] = 0; // remove excess buy signals
   
	if( trailstop > 0 AND Low[ i ] < trailstop )
	{
		Sell[ i ] = 1;
		SellPrice[ i ] = trailstop;
		trailstop = 0;
		SellType[i] = 1;
		IndexUpSet = IndexDownSet = 0;
	}

	if( trailstop > 0)
	{   
		if(Index_Up[i] != Index_Up[i-1]){
			if(Index_Up[i] == True){
				IndexUpSet = Max( High[ i ] * StopLevel[i], IndexUpSet);
				trailARRAY[ i ] = IndexUpSet;
				trailstop = IndexUpSet;
			}
			if(Index_Up[i] == False){
				IndexDownSet = Max( High[ i ] * StopLevel[i], IndexDownSet);
				trailARRAY[ i ] = IndexDownSet;
				trailstop = IndexDownSet;
			}
		}else{
			if(Index_Up[i] == True){
				IndexUpSet = Max( High[ i ] * StopLevel[i], IndexUpSet);
				trailARRAY[ i ] = IndexUpSet;
				trailstop = IndexUpSet;
			}
			if(Index_Up[i] == False){
				IndexDownSet = Max( High[ i ] * StopLevel[i], IndexDownSet);
				trailARRAY[ i ] = IndexDownSet;
				trailstop = IndexDownSet;
			}
		}
	}

}

//Plot Looping Trail
Plot( trailARRAY,"trailing stop level", colorRed );

//---------------------------------- Charting ------------------------------------- //
Plot( C, "Price", colorDefault, styleBar|styleThick|styleNoTitle );
PlotShapes( Buy*shapeUpTriangle, colorGreen, 0, Low, -20 ); 
PlotShapes( ( Sell > 0 ) * shapeDownTriangle, colorRed, 0, High, -40 );

RibbonColor = IIf( Index_Up, colorGreen, colorRed ); // If Index Up is TRUE the ribbon is GREEN, If Index Up is FALSE the ribbon is Red
Plot( 1, "", RibbonColor, styleArea | styleOwnScale | styleNoLabel, -0.0001, 190 );

//Plot ApplyStop Trail
Equity( 1, 0 );
InTrade = Flip( Buy, Sell );
SetOption("EveryBarNullCheck", True );
stopline = IIf( InTrade, HighestSince( Buy, High ) * ( 1 - 0.01 * Exit_Percent ), Null );
Plot( stopline, "trailing stop line", colorOrange );

Hi Edmund,
I'm pretty slow at code development these days (getting old) so excuse lack of timely response.

First an observation: Your first chart's symbol indicates a Norgate database. If that's the case your index symbol should be "$XAO.au". If my assumption is correct, "$XAO" is an invalid symbol and the price array re-assignment is not happening.

Second you will need to pay a lot more attention to all the configuration variables that ApplyStop() and the backtest engine is using to in any way duplicate its operation or indeed configure it correctly for your intended purpose. For a start, as I discovered earlier in this thread, you will need to configure it for a dynamic stop distance using the Volatile flag. Also ApplyStop() will be of course using the trade delays you have set - your looping code probably needs to reflect that too. There are other things that you need to be aware of also. Even things like the order of your calculations/tests in the loop. I certainly don't know them all.

I think experienced Amibroker users would quickly see the difficulty of trying to 're-invent the wheel' and say just rely on the proven inbuilt functionality. I also would recommend that course if at all possible. That being said, for many of my own stops I have used iteration in AFL (loops). I have not tried to replicate anything other than the very specific stop rule(s) I required at the time. I am a very visual person so the correct depiction of the stop on the chart was one criteria. Reconstructing a chart depiction of ApplyStop() I see as no problem as widely documented but you need to understand all its nuances to do it well.

One such nuance is the highest High calculation the engine uses as a reference for the stop distance parameter. In your ApplyStop() plot code you use HighestSince(). My first post referred to that but you have not seemed to address that properly yet in the loop so the code here is my initial approach. I have not tested this extensively.

As a final thought when I looked at your additions in the last conditional statement block if( trailstop > 0 ) it seemed way to complex to do the job so I have modified it but also added an alternative below in /* .... */ for your consideration.

My changes/additions all have ////// appended out to the right for visibility.

As a final thought, consider using Buy/Sell variables with slightly different names in your looping code so these independent signals can be plotted separately for comparison.

SetOption( "InitialEquity", 200000 );
SetOption( "CommissionMode", 2 );
SetOption( "CommissionAmount", 9.50 );
SetOption( "AllowSameBarExit", False );
SetOption( "AllowPositionShrinking", False );
SetOption( "MaxOpenPositions", 20 );

SetPositionSize( 10000, spsValue );

SetTradeDelays( 1, 1, 1, 1 );

//--------------------- Buy Signal --------------------- //
Buy = C > EMA(C,70);

//--------------------- Index Filter ---------------------//
SetForeign( "$XAO.au" );                                             //////
Index_Up = C > MA( C, 10 );
RestorePriceArrays();

//--------------------- Sell Trailing Stop --------------------- //
Sell = 0;
Exit_Percent = IIf( Index_Up, 20, 10 );
//ApplyStop( stopTypeTrailing, stopModePercent, Exit_Percent, ExitAtStop = 2 );

trailARRAY = Null;
StopLevel = Null;
trailstop = IndexUpSet = IndexDownSet = 0;
HighestHigh = 0;                                                     //////

for( i = 1; i < BarCount; i++ )
 {	
	 
	if(Index_Up[i] == True)
	{
		StopLevel[i] = 1 - 20/100;		
	} 
	
	if(Index_Up[i] == False)
	{
		StopLevel[i] = 1 - 10/100;
	}
	
	if( trailstop == 0 AND Buy[ i ] ) 
	{ 
	    HighestHigh = High[i];                                       //////
//	    trailstop = High[i] * StopLevel[i];                          //////
		trailstop = HighestHigh * StopLevel[i];                      //////
	}
	
	else Buy[ i ] = 0; // remove excess buy signals
   
	if( trailstop > 0 AND Low[ i ] < trailstop )
	{
		Sell[ i ] = 1;
		SellPrice[ i ] = trailstop;
		trailstop = 0;
		SellType[i] = 1;
		IndexUpSet = IndexDownSet = 0;
	}

	if( trailstop > 0)
	{   
	    HighestHigh = Max( HighestHigh, H[i] );
		if(Index_Up[i] != Index_Up[i-1]){
			if(Index_Up[i] == True){
//				IndexUpSet = Max( High[ i ] * StopLevel[i], IndexUpSet);     //////
				IndexUpSet = HighestHigh * StopLevel[i];                     //////
				trailARRAY[ i ] = IndexUpSet;
				trailstop = IndexUpSet;
			}
			if(Index_Up[i] == False){
//				IndexDownSet = Max( High[ i ] * StopLevel[i], IndexDownSet); //////
				IndexDownSet = HighestHigh * StopLevel[i];                   //////
				trailARRAY[ i ] = IndexDownSet;
				trailstop = IndexDownSet;
			}
		}else{
			if(Index_Up[i] == True){
//				IndexUpSet = Max( High[ i ] * StopLevel[i], IndexUpSet);     //////
				IndexUpSet = Max( HighestHigh * StopLevel[i], IndexUpSet);   //////
				trailARRAY[ i ] = IndexUpSet;
				trailstop = IndexUpSet;
			}
			if(Index_Up[i] == False){
//				IndexDownSet = Max( High[ i ] * StopLevel[i], IndexDownSet);   //////
				IndexDownSet = Max( HighestHigh * StopLevel[i], IndexDownSet); //////
				trailARRAY[ i ] = IndexDownSet;
				trailstop = IndexDownSet;
			}
		}
	}
/*
	if( trailstop > 0 )                                                      //////
	{
	    HighestHigh = Max( HighestHigh, High[i] );
		if( Index_Up[i] != Index_Up[i-1] )
            trailstop = HighestHigh * StopLevel[i];
        else
            trailstop = Max( HighestHigh * StopLevel[i], trailstop);
        trailARRAY[i] = trailstop;
    }                                                                        //////
*/
}

//Plot Looping Trail
Plot( trailARRAY,"trailing stop level", colorRed );

//---------------------------------- Charting ------------------------------------- //
Plot( C, "Price", colorDefault, styleBar|styleThick|styleNoTitle );
PlotShapes( Buy*shapeUpTriangle, colorGreen, 0, Low, -20 ); 
PlotShapes( ( Sell > 0 ) * shapeDownTriangle, colorRed, 0, High, -40 );

RibbonColor = IIf( Index_Up, colorGreen, colorRed ); // If Index Up is TRUE the ribbon is GREEN, If Index Up is FALSE the ribbon is Red
Plot( 1, "", RibbonColor, styleArea | styleOwnScale | styleNoLabel, -0.0001, 190 );

//Plot ApplyStop Trail
Equity( 1, 0 );
InTrade = Flip( Buy, Sell );
SetOption("EveryBarNullCheck", True );
stopline = IIf( InTrade, HighestSince( Buy, High ) * ( 1 - 0.01 * Exit_Percent ), Null );
Plot( stopline, "trailing stop line", colorOrange );

2 Likes

Some Norgate Data subscribers will have the symbol suffix '.au' on all their ASX symbols and some will have no symbol suffix on their ASX symbols. Whether you do or don't depends on the setting Norgate has applied to your account on their end - which depends on whether you have US data as well or if you only have ASX data then depends how recently you signed up or if you have requested to have ASX symbol suffix applied to your current ASX database.

If ApplyStop() does what you need it to do then use that otherwise do your own 'For Loop'.

2 Likes

Hi JohnHT,

I am very very grateful for your reply and insights. I was about to give up on this and move on to be honest.

Thank you and @TrendSurfer on your comments regarding the index symbol. Definitely a mistake, my symbols have '.au'.

Same as you, I also a visual person so part of this exercise is to allow me to play with the charts. Whilst I did say I wanted to replicate ApplyStop(), goal is to code the loop to be as close as possible. Your code seems to behave like what I was wishing to see!

There is quite some thoughts to unpack from your reply and your code so will need time to fully grasp.

Again appreciate your time and effort on this!

2 Likes

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