Help coding a trend following system

Hello. I’m new to Amibroker and currently learning by trial and error. I’m trying to code a trend following system with the following attributes and it’s not quite working as I would like.

Time frame is daily chart and closing prices.

Stocks and ETF’s with at least a 2 billion market cap, and at least 1 million in average daily volume.

Enter long when closing price crosses above the 200 day simple moving average.

First 30 days of the trade will have a fixed stop of two times ATR14. Stop point equals entry price minus 2 times the ATR14 on the day of entry.

Position sizing based off 1% of trading account max loss per trade. $100,000 account equals $1,000 risk on any one trade. Number of shares equals 1% risk divided by 2*ATR14.

After thirty days the sell signal is a close below the 200 day SMA.

This is what I have so far.


_SECTION_BEGIN("200 SMA Trend Following System");

SetOption("maxopenpositions",20);
SetOption("InitialEquity",100000);


entrysignal=Cross(C,MA(Close,200));
exitsignal=Cross(2 * ATR( 14 ),C);

Riskpct=1;
stopsize= entrysignal-exitsignal;
SetPositionSize((Riskpct/stopsize*C),spsPercentOfEquity);

Plot( MA( C, 200 ),"200SMA",colorLime,styleLine);

Buy = Cross(C,MA(Close,200));
Sell=Cross(MA(C,200),C);

MinHoldBars = 30;

Buy = Buy AND Status("barinrange");

BarsInTrade = 0;
for( i = 0; i < BarCount; i++ )
{
  // if in-trade, then increase bar counter
  if( BarsInTrade > 0 ) BarsInTrade ++;
  else
  if( Buy[ i ] ) BarsInTrade = 1; // on buy signal start counting bars-in-trade
 
  // if we are in trade - remove sells occurring too soon
  if( BarsInTrade < MinHoldBars ) Sell[ i ] = 0;
  else
  if( Sell[ i ] ) BarsInTrade = 0; // on sell reset barsintrade flag
}


Buy = ExRem( Buy, Sell);
sell = ExRem( sell, buy );


ApplyStop( stopTypeLoss, stopModePoint, 2 * ATR( 14 ),1,0, 0, 0, 30 );

/*ATR Stop Length*/
stoplength=(2*ATR(14));

/*Plotting the Trailing Stop*/

Equity(1,0); //Evaluate stops, all quotes
intrade = Flip(Buy,Sell); //True when Buy, Flase when Sell
SetOption("EverybarNullCheck",True); //Checks for null bars
stopline=IIf(intrade,HighestSince(Buy,BuyPrice-stoplength),Null);

Plot(stopline,"Stop Loss",colorRed,styleLine);


PlotShapes(IIf(Buy, shapeSquare, shapeNone),colorGreen, 0, L, Offset=-75);
PlotShapes(IIf(Buy, shapeSquare, shapeNone),colorLime, 0,L, Offset=-85);
PlotShapes(IIf(Buy, shapeUpArrow, shapeNone),colorWhite, 0,L, Offset=-80);
PlotShapes(IIf(Sell, shapeSquare, shapeNone),colorRed, 0, H, Offset=75);
PlotShapes(IIf(Sell, shapeSquare, shapeNone),colorOrange, 0,H, Offset=85);
PlotShapes(IIf(Sell, shapeDownArrow, shapeNone),colorWhite, 0,H, Offset=-80);

_SECTION_END(); 

The problems I’m seeing are my losses are exceeding 1% of my trading account position sizing. How do I plot a horizontal line for the first 30 days of the trade based off 2 times ATR14, instead of the trailing plot I have now? The system is intermittently not reentering trades after being stopped out.

Thanks,
John

1 Like

@Jcpilot may I suggest that you break down various parts of your code and debug them with Explorations. Unless I am misunderstanding your intent I just do not understand your code.

For example these lines?
entrysignal=Cross(C,MA(Close,200));
exitsignal=Cross(2 * ATR( 14 ),C)

Each generates a zero or a one. But a couple of lines later you have stopsize= entrysignal-exitsignal;
What does that generate, a zero or a one again. Is that what you want for a denominator in a later line,

SetPositionSize((Riskpct/stopsize*C),spsPercentOfEquity);

An here, exitsignal=Cross(2 * ATR( 14 ),C);
Do you know what values you have in that equation and how the heck is 2*ATR ever going to crossover the Closing price?

Perhaps I am misunderstanding your intention but I do suggest you read this and try a few lines like below,
http://www.amibroker.com/kb/2014/09/29/debugging-techniques-part-1-exploration/

// Explore //
Filter = entrysignal OR exitsignal;
AddColumn( Close, "Close" );
AddColumn( 2 * ATR( 14 ), "2 * ATR( 14 )" );
AddColumn( entrysignal, "entrysignal" );
AddColumn( exitsignal, "exitsignal" );
AddColumn( stopsize, "stopsize" );

Maybe get an output like this and see if that is what you meant to code,

Good luck.

1 Like

portfoliobuilder,

I was unaware of Explorations, that looks like it will be helpful. My problem is that I don’t understand my code lol. Coding is new to me and I don’t understand the flow yet but I will get it. I’m reading one of Howard Bandy’s books right now.

I’m trying to set a fixed 2ATR14 stop based on the day the system goes long, and maintain that for 30 days. My current code is trailing by 2ATR14.

Thank you for the reply, and have a great day.

John

I was expecting “entrysignal” and “exitsignal” to generate values, not a zero or one. That’s helpful.

@Jcpilot if you read a couple of the Howard Bandy books you will be off to a good start. A few other resources worth reviewing are on this thread here,

For many years users used an external application called DebugView to debug their code,
https://www.amibroker.com/guide/afl/_trace.html

And last year AmiBroker added it's own debug functionality,
https://www.amibroker.com/guide/h_debugger.html

I'm just a non-programmer who likes to use EXPLORE while building code. Look into each calculation and see if my code is actually producing the intended calculations.

I've coded a quick little example (may not be correct) for you below where a simple two moving average crossover system is coded and your STOP, which i feel is more like an Initial Stop (since you do not want a Trailing Stop).

fastma = MA( Close, 10 );
slowma = MA( Close, 60 );

Buy =  Ref( Cross( fastma, slowma ), -1 );
Sell = Ref( Cross( slowma, fastma ), -1 );

BuyPrice = Open;
Sellprice = Open;

InTrade = Flip( Buy, Sell );

StopCalculation = ValueWhen( Buy, 2 * ATR( 14 ), 1 );

ApplyStop( stopTypeLoss, stopModePoint, StopCalculation );

InitialStop = BuyPrice - StopCalculation;

stopline = IIf( InTrade, ValueWhen( Buy, InitialStop ), Null );

// Exploration
dynamic_color = IIf( Cross( fastma, slowma ), colorYellow, colorDefault );
Filter = 1;
AddColumn( Close, "Close" );
AddColumn( fastma, "fastma", 1.2, colorDefault, dynamic_color );
AddColumn( slowma, "slowma", 1.2, colorDefault, dynamic_color );
AddColumn( Open, "Open" );
AddColumn( Buy, "Buy Signal", 1.0, colorDefault, iif( Buy, colorLime, colorDefault ) );
AddColumn( ValueWhen( Buy, BuyPrice, 1 ), "BuyPrice" );
AddColumn( 2 * ATR( 14 ), "2*ATR(14)" );
AddColumn( stopline, "stopline", 1.2, colorWhite, colorBlue );

// Charting //
Plot( stopline, "Initial stop line", colorRed, styleThick );

The exploration produces this type of result which helps me see the calculations and if they are as hoped for.

And the plot of your initial Stop on an earlier trade.

7 Likes

I'm finally getting back to this after reading several of Howard Bandy's books, and the online Amibroker guides and examples. Thank you @portfoliobuilder for having the patience to to help me on my first go with this. I took your advice and used Explore with many AddColumn rows to see what was going on in my code. That and a linked chart were very helpful at seeing what was going on. I've made progress but I am stuck with excess signals recalculating my stop price while I'm in a trade. I'm not looking for someone to write the code for me, just a push in the right direction.

My goal with this code is to go long with a close above the 200 day moving average. For the first 30 days the stop will be a close below a fixed value based on the entry day ATR, not a trailing stop. After thirty days the exit signal will be a close below the 200 day moving average. The entire code is posted first and my observations afterwards.

200 Day Simple Moving Average Trend Following System

_SECTION_BEGIN("200 SMA Trend Following System test");
SetChartOptions(0,chartShowArrows|chartShowDates, 0, 0, 0, 50);
_N(Title = StrFormat("{{NAME}} - {{INTERVAL}} {{DATE}} Open %g, High %g, Low %g, Close %g (%.1f%%) {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 ) ) ));
Plot( C, "Close", ParamColor("Color", colorDefault ), styleNoTitle | ParamStyle("Style") | GetPriceStyle() );

SetOption( "maxopenpositions", 20 );
SetOption( "InitialEquity", 100000 );
SetOption( "ExtraColumnsLocation", 1 ); /*	change the location of custom columns added during backtest/optimization.*/
SetTradeDelays( 0, 0, 0, 0 ); /*	(buydelay, selldelay, shortdelay, coverdelay) Sets trade delays applied by the backtester*/

bi = BarIndex();
SMA = MA( C, 200 );
BuySignal = Cross( C, SMA );
SellSignal = Cross( SMA, C );

//Buy = BuySignal;	/*	Same results as Buy = Cross( C, SMA ); */
Buy = Cross( C, SMA );
Buy = ( Buy AND Status( "barinrange" ) ); /*	First filter out buy signals occurring outside testing range */

BuyBarIndex = ValueWhen( Buy, bi );
BuyBarPrice = ValueWhen( Buy, Close );
BuyBarATR = ValueWhen( Buy, ATR(14) );
StopLength = ( 2 * BuyBarATR );
StopPrice = ( BuyBarPrice - StopLength );
StopSignal = ( C <= StopPrice );
InitialStopPeriod = ( bi <= ( BuyBarIndex + 30 ) );

Sell = ( InitialStopPeriod AND StopSignal ) OR ( SellSignal AND NOT InitialStopPeriod );
SellP = ValueWhen( Sell, SellPrice );
Buy = ExRem( Buy, Sell );
Sell = ExRem( Sell, Buy );

/*	ExRemSpan prevented the StopPrice from getting recalculated when additional BuySignal were True, but it also prevented re-entering trades after being stopped out. */
//Buy = ExRemSpan( BuySignal, 30 ); 

//Buy = Flip( BuySignal, SellSignal ); //	This results in constant buy and sell signals
//Sell = Flip( SellSignal, BuySignal );

ATRStopPeriod = 30; //	Initial stop is fixed for 30 days
BarsInTrade = 0;
for( i = 0; i < BarCount; i++ ) 
{ 
	// if in-trade, then increase bar counter
	if( BarsInTrade > 0 ) BarsInTrade ++;
	else
	if( Buy[ i ] ) BarsInTrade = 1; // on buy signal (True or False) start counting bars-in-trade
	
	// If in-trade, remove excess BuySignals
	if( BarsInTrade < ATRStopPeriod )  BuySignal[ i ]  =  0 ;
	else
	if( StopSignal[ i ] ) BarsInTrade = 0; // on stop reset barsintrade flag
	
}

// Explore //
/**	@Link http://www.amibroker.com/guide/h_exploration.html */

Filter = 1; /* all symbols and quotes accepted */

AddColumn( SMA, "200 SMA" );
AddColumn( C, "Close", 1.2, colorDefault, IIf( Buy, colorLime, colorDefault ) );

AddColumn( Buy, "Buy", 1, colorDefault, IIf( Buy, colorLime, colorDefault ) );
AddColumn( Sell, "Sell" , 1, colorDefault, IIf( Sell, colorRed, colorDefault ) );

AddColumn( BuySignal, "BuySignal", 1, colorDefault, IIf( BuySignal, colorLime, colorDefault ) );
AddColumn( SellSignal, "SellSignal" , 1, colorDefault, IIf( SellSignal, colorRed, colorDefault ) );
AddColumn( StopSignal, "StopSignal" , 1, colorDefault, IIf( Sell, colorRed, colorDefault ) );

AddColumn( BuyBarPrice, "BuyBarPrice", 1.2, colorDefault, IIf( Buy, colorLime, colorDefault ) );
AddColumn( SellP, "SellPrice", 1.2, colorDefault, IIf( Sell, colorRed, colorDefault ) );
AddColumn( StopPrice, "StopPrice" , 1.2, colorDefault, IIf( Sell, colorRed, colorDefault ) );

AddColumn( bi, "Bar Index", 1 , colorDefault, IIf( Buy, colorLime, colorDefault ) );
AddColumn( BuyBarIndex, "BuyBarIndex" , 1, colorDefault, IIf( Buy, colorLime, colorDefault ) );
AddColumn( BarsInTrade, "BarsInTrade" , 1 );// colorDefault, IIf(BarsInTrade > 0, colorRed, colorDefault ) );

AddColumn( StopLength, "StopLength", 1.2, colorDefault, IIf( BuySignal, colorLime, colorDefault ) );
AddColumn( BuyBarATR, "ATR(14)", 1.2, colorDefault, IIf( BuySignal, colorLime, colorDefault ) );
AddColumn( InitialStopPeriod, "InitialStopPeriod", 1, colorDefault, IIf( Buy, colorLime, colorDefault ) );

AddColumn( BarCount, "BarCount", 1);
AddColumn( ValueWhen( BuySignal, bi ), "BuySignal BarIndex" , 1, colorDefault, IIf( BuySignal, colorLime, colorDefault ) );
AddColumn( ValueWhen( BuySignal, Close ), "BuySignal Close" , 1.2, colorDefault, IIf( BuySignal, colorLime, colorDefault ) );

//	Plots
Plot( IIf( bi > ( BuyBarIndex + 30 ), Null, StopPrice ), "Stop", colorRed, styleLine | styleNoLabel );

Plot( SMA,"200SMA", colorLime, styleLine );
PlotShapes( IIf( Buy, shapeSquare, shapeNone ),colorGreen, 0, L, Offset=-75);
PlotShapes( IIf( Buy, shapeSquare, shapeNone ), colorLime, 0, L, Offset=-85);
PlotShapes( IIf( Buy, shapeUpArrow, shapeNone ), colorWhite, 0, L, Offset=-80);
PlotShapes( IIf( Sell, shapeSquare, shapeNone ), colorRed, 0, H, Offset=75);
PlotShapes( IIf( Sell, shapeSquare, shapeNone ), colorOrange, 0, H, Offset=85);
PlotShapes( IIf( Sell, shapeDownArrow, shapeNone ),colorWhite, 0, H, Offset=-80);

_SECTION_END(); 

The issue I'm having is the stop price is getting recalculated every time BuySignal is True. I tried referencing the BarIndex of the Buy == 1 signal, but it is still recalculating the stop price when it sees subsequent BuySignal == 1. I've tried Buy = BuySignal and Buy = Cross( C, SMA ) with the same output. That kinda makes sense but I was hoping that Buy would yield a different True False than the BuySignal bool when referencing the BarIndex of Buy == 1. It makes sense in my mind to differentiate between Buy and BuySignal but they are same thing within my code. Am I on the right path, or should I think of this differently?

I'm guessing my solution will be in a switch loop but my understanding of loops is still a little fuzzy. I tried various combinations in the current for loop without getting the desired results. I could remove the BuySignal but I would get the same StopPrice recalculation.

In this picture you can see that the plot of the ATR Stop recalculation as well as the extension of the ATR Stop period beyond the 30 days I was after.

200Day%20System%20Screen%20Shot%203

Here's a shot of the analysis window with exploration results.

Analysis%20Screenshot%202

I had success with ExRemSpan eliminating the StopPrice recalculation but created a new problem of not re entering trades on a BuySignal after being stopped out of a trade prior to the 30 day numbars value in the exremspan( ARRAY1, numbars ). I tried putting an array in the numbars value but it gave me an error.

200Day%20System%20Screen%20Shot%202

1 Like

Hi @Jcpilot,

Quite impressive the effort you have made so far. :+1:

Since you have a For Loop in your code, remove the ExRem lines and control the excessive signals via your For Loop.

eg:

//Inside the For Loop
if( inTrade )
{
	// do something
	Buy[i] = False;
}

Start with that and see how you go.

2 Likes

Hi Jcpilot,

Thank you for posting your code!
Have you considered adding some short-side logic? Strategy seems to avoid many of the market declines over the year, doing exceptionally well in 2008 and multiple other months in Cash while the markets are taking a hit.

Thanks,

Mike