Sweet Trailing Stop, Could Use Some Guidance

Hi All,
As you read you will likely identify some holes in my understanding of AmiBroker and AFL. I'm not asking for explicit answers to my questions, moreso links to resources or explanations of concepts I'm missing. The goal is AmiBroker mastery. While it may take more time to figure out the issues with a little direction (instead of handing me the answer), I find that learning process tends to stick better. So please dive on in and any help you can provide I will greatly appreciate.

Intended Function

  • A signal is generated using 1-min candles when the EMA(C, 20) crosses above the EMA(C, 50)
  • Entry and exit are monitored using 1-sec candles (price occasionally hits a profitable exit and a stop loss in a one-minute time frame, thus I need that resolution to understand which occurs first)
  • After the signal occurs an entry price is calculated. It's the signal bar's close minus some multiple of the ATR
  • Price needs to come down and hit our entry before a minute transpires (I think this is what my code does, but not 100% sure)
  • After the signal occurs a stop price is calculated. Initially it's entry price minus 5.25 points
  • If price exceeds entry by 2.75 points, we lock in 0.5 points profit, if price exceeds entry by 5.25 points we lock in 3.25 points profit (there are two more levels, but you get the idea, click here to see)
  • When price touches the stop price, we exit the trade at the stop price

If I look at my chart, everything looks like it works, however, I'm still lacking sufficient understanding of how the back tester works. While I see a trade on 12/28/2022 on my chart, it does no appear on my back test trade report.
For reference

Running a back test I get the following: Error 15. Endless loop detected in FOR loop
I don't have a FOR loop in my code. I'm assuming it resides somewhere in the back testing. Currently I'm trying to run the test for 3 years of data. That's 31.5M+ bars. Inside Database Settings the largest allowable value is 1,000,000. That's less than 31.5M. Is this an issue?
My next point of investigation was Tools > Preferences > AFL Tab. There I maxed out the Endless Loop Threshold to 999999999. I still get the Error 15, however, I do not have a FOR loop in my code... what am I missing?

So after reading all this... please tell me what concepts I am missing? What resources should I study to fill in the blanks? Any and all assistance will be greatly appreciated. I went ahead and posted my code below.

Code for Price Chart

SetChartOptions(2,chartWrapTitle);
_SECTION_BEGIN("Price");
SetChartOptions(0,chartShowArrows|chartShowDates);
SetChartOptions(2,chartWrapTitle);
_N(Title = StrFormat("{{NAME}} - {{INTERVAL}} {{DATE}} Open %g, Hi %g, Lo %g, Close %g (%.1f%%) {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 ) ) ));
Plot( C, "Close", ParamColor("Color", colorDefault ), styleNoTitle | ParamStyle("Style") | GetPriceStyle() ); 
_SECTION_END();

SetTradeDelays(0,0,0,0); 
SetOption("FuturesMode", True); 
SetOption("InitialEquity", 10000);  
SetOption("MaxOpenPositions", 100); 
SetOption("CommissionMode", 3 ); 
SetOption("CommissionAmount", 0.56); 
SetOption("AllowSameBarExit", True); 
 
MarginDeposit 			= 50; 
RoundLotSize 			= 1; 
TickSize				= 0.25; 
PointValue				= 5.0; 

SetPositionSize( 10, spsPercentOfEquity );
//SetPositionSize( 100, spsShares); 
//SetBarsRequired(2400); 

function RoundToTick(Value){

	integral = Prec(Value,0);
	decimal = Value - integral;
	
	newDec = IIf(decimal < 0.125,0.00,
	IIf(decimal >= 0.125 && decimal < 0.375,0.25,
	IIf(decimal >= 0.375 && decimal < 0.625,0.50,
	IIf(decimal >= 0.625 && decimal < 0.875,0.75,
	IIf(decimal >= 0.875,1.00,0)))));
	
	return integral + newDec;
}

/* Check for entry
*/
TimeFrameSet(in1Minute);
AtrPeriod		= 14;
TradeCooldown	= 14;
Ema20 			= EMA(C, 20);
Ema50 			= EMA(C, 50);
BuySignal 		= Ref(Cross(Ema20, Ema50), -1);

EntryOffset 	= -.85 * ATR(AtrPeriod);
EntryPrice 		= RoundToTick(ValueWhen(BuySignal, C + EntryOffset));
TimeFrameRestore();

BuySignal = TimeFrameExpand(BuySignal, in1Minute);
EntryPrice = TimeFrameExpand(EntryPrice, in1Minute);
TradeCoolDown = TimeFrameExpand(TradeCoolDown, in1Minute) * 60;

Buy = Ref(BuySignal, -1) && L < EntryPrice;
Buy = ExRem(Buy, BarsSince(Buy) == TradeCoolDown);
//BuyPrice = IIf(Buy, EntryPrice, Null);
BuyPrice = RoundToTick(ValueWhen(Buy, EntryPrice));

/*	Trailing Stop (expand for notes)
	1) Initial StopLength = 10 ticks (2.5 points) 
	2)	Trigger0 = EntryPrice + 10 ticks (2.5 points) 
		Stop0 = Entry + 4 ticks (1 point) 
	3)	Trigger1 = EntryPrice + 20 ticks (5 points) 
		Stop1 = HighSinceEntry - 15 ticks (3.75 points) 
	4)	Trigger2 = EntryPrice + 35 ticks (8.75 points) 
		Stop2 = HighSinceEntry - 10 ticks (2.5 points) 
	5)	Trigger3 = EntryPrice + 50 ticks (12.5 points) 
		Stop3 = HighSinceEntry -  4 ticks (1.0 point) 
*/

ProfitTrigger 	= EntryPrice + 2.75;  // i think this is OK... but double check --> i keep  taking this down and profits keep going up... not sure if this is behaving correctly 
Trigger01 		= EntryPrice + 5.25;
Trigger02 		= EntryPrice + 7.5;
Trigger03 		= EntryPrice + 9.75;

StopInit 		= EntryPrice - 5.25;
ProfitLock 		= EntryPrice + 0.5;
Trail01 		= 3.25;
Trail02 		= 2.0;
Trail03 		= 1.0;

HighSinceBuy = IIf(Buy, H, HighestSince(Buy, H)); 
LowSinceBuy = IIf(Buy, L, LowestSince(Buy, L));
Trail = IIf(HighSinceBuy >= Trigger03, Trail03, IIf(HighSinceBuy >= Trigger02, Trail02, IIf(HighSinceBuy >= Trigger01, Trail01, Null)));
StopLong = IIf(Buy, StopInit, IIf(IsEmpty(Trail), IIf(HighSinceBuy >= ProfitTrigger, ProfitLock, StopInit), HighSinceBuy - Trail));
StopLong = IIf(!Buy && Ref(BarsSince(L <= StopLong), -1) < BarsSince(Buy), Null, StopLong);

Sell = L <= StopLong; 
Sell = ExRem(Sell, Ref(Buy, 1)); 
SellPrice = RoundToTick(StopLong);
BuySignal = ExRem(BuySignal, Sell);
BarsSinceBuy = BarsSince(Buy); 
BarsSinceSell = BarsSince(Sell); 
IsLong = Buy && Sell || (BarsSinceBuy < Ref(BarsSinceSell,-1)) || (BarsSinceBuy >=0 && IsEmpty(Ref(BarsSinceSell, -1)));

Profit = IIf(Ref(Sell, -1) && Ref(SellPrice > BuyPrice, -1), Ref(SellPrice - BuyPrice, -1), Null);
Loss = IIf(Ref(Sell, -1) && Ref(SellPrice < BuyPrice, -1), Ref(SellPrice - BuyPrice, -1), Null);

BuyPrice = IIf(IsLong, BuyPrice, Null);
ProfitTrigger = IIf(IsLong, ProfitTrigger, Null); 
Trigger01 = IIf(IsLong, Trigger01, Null); 
Trigger02 = IIf(IsLong, Trigger02, Null); 
Trigger03 = IIf(IsLong, Trigger03, Null); 

ProfitLock = IIf(IsLong, ProfitLock, Null); 
Trail01 = IIf(IsLong, Trail01, Null);
Trail02 = IIf(IsLong, Trail02, Null);
Trail03 = IIf(IsLong, Trail03, Null);

/* Plot Charty Thingers
Plot(BuyLimitPrice,"BuyLimitPrice",IIf(Low < BuyLimitPrice - 0.01,colorGrey50,colorGrey50),styleDashed|styleThick);
*/
Plot(Ema20, "EMA(20)", ColorRGB(255,0,255));
Plot(Ema50, "EMA(50)", ColorRGB(180,180,180));
Plot(StopLong, "StopLong", ColorRGB(255,0,255), styleStaircase | styleThick); 
Plot(ProfitTrigger, "ProfitTrigger", colorDarkRed, styleStaircase | styleThick); 
Plot(Trigger01, "Trigger01", colorOrange, styleStaircase | styleThick); 
Plot(Trigger02, "Trigger02", colorGreen, styleStaircase | styleThick); 
Plot(Trigger03, "Trigger03", colorIndigo, styleStaircase | styleThick); 

Plot(IIf(BarsSince(Ref(BuySignal, -1)) < 3,EntryPrice,Null), "PotentialEntryPrice",colorLightBlue, styleDots | styleNoLine);
Plot(BuyPrice, "BuyPrice", colorBlue, styleDots | styleNoLine | styleThick); 
Plot(SellPrice, "SellPrice", colorBlack, styleStaircase | styleThick); 

PlotShapes(BuySignal * shapeHollowUpArrow, colorGreen, 0, Low);
PlotShapes(Buy * shapeUpArrow, colorGreen, 0, Low);
PlotShapes(Sell * shapeDownArrow, colorRed, 0, High);

Code for Separate Panel

SetTradeDelays(0,0,0,0); 
SetOption("FuturesMode", True); 
SetOption("InitialEquity", 10000);  
SetOption("MaxOpenPositions", 100); 
SetOption("CommissionMode", 3 ); 
SetOption("CommissionAmount", 0.56); 
SetOption("AllowSameBarExit", True); 
 
MarginDeposit 			= 50; 
RoundLotSize 			= 1; 
TickSize				= 0.25; 
PointValue				= 5.0; 

SetPositionSize( 10, spsPercentOfEquity );
//SetPositionSize( 100, spsShares); 
//SetBarsRequired(2400); 

function RoundToTick(Value){

	integral = Prec(Value,0);
	decimal = Value - integral;
	
	newDec = IIf(decimal < 0.125,0.00,
	IIf(decimal >= 0.125 && decimal < 0.375,0.25,
	IIf(decimal >= 0.375 && decimal < 0.625,0.50,
	IIf(decimal >= 0.625 && decimal < 0.875,0.75,
	IIf(decimal >= 0.875,1.00,0)))));
	
	return integral + newDec;
}

/* Check for entry
*/
TimeFrameSet(in1Minute);
AtrPeriod		= 14;
TradeCooldown	= 14;
Ema20 			= EMA(C, 20);
Ema50 			= EMA(C, 50);
BuySignal 		= Ref(Cross(Ema20, Ema50), -1);

EntryOffset 	= -.85 * ATR(AtrPeriod);
EntryPrice 		= RoundToTick(ValueWhen(BuySignal, C + EntryOffset));
TimeFrameRestore();

BuySignal = TimeFrameExpand(BuySignal, in1Minute);
EntryPrice = TimeFrameExpand(EntryPrice, in1Minute);
TradeCoolDown = TimeFrameExpand(TradeCoolDown, in1Minute) * 60;

Buy = Ref(BuySignal, -1) && L < EntryPrice;
Buy = ExRem(Buy, BarsSince(Buy) == TradeCoolDown);
//BuyPrice = IIf(Buy, EntryPrice, Null);
BuyPrice = RoundToTick(ValueWhen(Buy, EntryPrice));

/*	Trailing Stop (expand for notes)
	1) Initial StopLength = 10 ticks (2.5 points) 
	2)	Trigger0 = EntryPrice + 10 ticks (2.5 points) 
		Stop0 = Entry + 4 ticks (1 point) 
	3)	Trigger1 = EntryPrice + 20 ticks (5 points) 
		Stop1 = HighSinceEntry - 15 ticks (3.75 points) 
	4)	Trigger2 = EntryPrice + 35 ticks (8.75 points) 
		Stop2 = HighSinceEntry - 10 ticks (2.5 points) 
	5)	Trigger3 = EntryPrice + 50 ticks (12.5 points) 
		Stop3 = HighSinceEntry -  4 ticks (1.0 point) 
*/

ProfitTrigger 	= EntryPrice + 2.75;  // i think this is OK... but double check --> i keep  taking this down and profits keep going up... not sure if this is behaving correctly 
Trigger01 		= EntryPrice + 5.25;
Trigger02 		= EntryPrice + 7.5;
Trigger03 		= EntryPrice + 9.75;

StopInit 		= EntryPrice - 5.25;
ProfitLock 		= EntryPrice + 0.5;
Trail01 		= 3.25;
Trail02 		= 2.0;
Trail03 		= 1.0;

HighSinceBuy = IIf(Buy, H, HighestSince(Buy, H)); 
LowSinceBuy = IIf(Buy, L, LowestSince(Buy, L));
Trail = IIf(HighSinceBuy >= Trigger03, Trail03, IIf(HighSinceBuy >= Trigger02, Trail02, IIf(HighSinceBuy >= Trigger01, Trail01, Null)));
StopLong = IIf(Buy, StopInit, IIf(IsEmpty(Trail), IIf(HighSinceBuy >= ProfitTrigger, ProfitLock, StopInit), HighSinceBuy - Trail));
StopLong = IIf(!Buy && Ref(BarsSince(L < StopLong), -1) < BarsSince(Buy), Null, StopLong);

Sell = L <= StopLong; 
Sell = ExRem(Sell, Ref(Buy, 1)); 
SellPrice = RoundToTick(StopLong);

BarsSinceBuy = BarsSince(Buy); 
BarsSinceSell = BarsSince(Sell); 
IsLong = Buy && Sell || (BarsSinceBuy < Ref(BarsSinceSell,-1)) || (BarsSinceBuy >=0 && IsEmpty(Ref(BarsSinceSell, -1)));

Profit = IIf(Ref(Sell, -1) && Ref(SellPrice > BuyPrice, -1), Ref(SellPrice - BuyPrice, -1), Null);
Loss = IIf(Ref(Sell, -1) && Ref(SellPrice < BuyPrice, -1), Ref(SellPrice - BuyPrice, -1), Null);

BuyPrice = IIf(IsLong, BuyPrice, Null);
ProfitTrigger = IIf(IsLong, ProfitTrigger, Null); 
Trigger01 = IIf(IsLong, Trigger01, Null); 
Trigger02 = IIf(IsLong, Trigger02, Null); 
Trigger03 = IIf(IsLong, Trigger03, Null); 

ProfitLock = IIf(IsLong, ProfitLock, Null); 
Trail01 = IIf(IsLong, Trail01, Null);
Trail02 = IIf(IsLong, Trail02, Null);
Trail03 = IIf(IsLong, Trail03, Null);

	/* Plot Sector Omega (Sub-Panel Plots)
	*/
Plot(Profit, "Profit", colorLime, styleArea);
Plot(IsLong, "IsLong", colorGrey50, styleArea);
Plot(Loss, "Loss", colorRed, styleArea);
Plot(0,"0",colorBlack,styleThick);
Plot (2 * Buy, "Buy", colorBlue, styleThick | styleArea);

//Plot(ATR(AtrPeriod)*AtrCheck,"AtrCheck",ColorRGB(222,222,222), styleArea);
//Plot(TradeAge, "TradeAge", colorBlack);

@nxg380 welcome to this Community.

Let's start with an easy answer about the database size. Please see this past thread where there are also considerations about the overall "limits" to consider when using any software and in particular Amibroker.

I suggest also to read this other thread about limit orders (and its links).

I'm not particularly qualified to comment on your code and the issues you reported since I do not trade futures and in particular in real-time, but in any case, examining the "detailed report" (search the forum since it was cited many times) could help you to better understand how Amibroker works. And be sure to have also a good grasp of the content of this part of the manual.

Regarding the "loop", probably, it is best to address the question directly to @Tomasz.

2 Likes

@beppe , much appreciated. I'll get to studying tonight.

Also, I have played around with ApplyStop() and went through the KB tutorial on how to plot ApplyStop(). I got the version in the tutorial working, but when I scroll back through my chart moves back and forth through time VERY SLOWLY (my PC is super-strong). Is this normal? So this is why I went the route I did. I will try the Limit Order route now. That was on my radar, but I think I just forgot about it :stuck_out_tongue: cuz life and brain derps.
One last thing: I was thinking about going back to the ApplyStop() approach (without plotting) once I got my stop line working as intended. Thoughts?

Open/Edit your formula
At the menu click Tools->Code Check & Profile
What it says ?

This single thing explains everything. Data alone for SINGLE SYMBOL with that many bars is 1.2GB. That is more or less the same amount of data as 2 hour movie in MP4 format. Just reading this file from SSD drive takes 3 seconds. This is just reading and does not include doing ANY calculations.

It is well advised to keep number of bars, per single symbol, below 15 million.

Please read Performance tuning tips
and Efficient use of multithreading
(please read till the very end, ESPECIALLY including Doing the math & resonable expectations part)

Instead of using TICK data and TimeFrameSet( in1Minute ), switch PERIODICITY in the Analysis to 1-minute (the same with chart).

@Tomasz, thank you. I went through the links you sent me and started playing around with some settings. This lead me to discover that the 3-year back test was impractical and unnecessary. I reduced the date range to a 1-year back test and everything worked as intended. I really appreciate your insight. One last question: can you point me to the definition of Periodicity? I can't seem to find it anywhere. I can guess at what it means, but I'd rather hear it from the expert.

@beppe appreciate the links you sent. Definitely brought to light some points with limit orders.

@awilson muito obrigado, unfortunately I did not save the version that uses ApplyStop(). I will go back and play with that, and then let you know what I see under Code Check.

In the Analysis Settings there is a periodicity combo box that you can use

1 Like

@nxg380, "Periodicity" as mentioned by @Tomasz is the term used in the Analysis settings to choose the "bar interval" applied to the data for scans, explorations, or backtests.
(Here in the section titled "Changing bar interval (periodicity)" the terms are synonymous).

Often, when learning AFL, there is confusion between periodicity vs. supporting multiple timeframes in Amibroker.
I suggest carefully reading and studying the documentation and also the multiple threads discussing this topic in the forum (here is an example)

Also, in general, a good read is this KB article explaining How does the intraday-to-daily compression work? in AB.

I can't thank you enough Beppe. @Tomasz, thank you again as well. All of these resources are clearing things up tremendously.

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