Can a Trailing Stop be applied to entry bar?

Hi,

If I am trading on a Weekly or Monthly bar and entering on the Open of the bar, where a single bar represents the Week or the Month, can I apply a Trailing stop as coded below? It would seem to be peeking in that it does not know the sequence of the High-Low on the entry bar.

Thanks,

Mike

_SECTION_BEGIN("Trading System");
SetChartOptions(0,chartShowArrows|chartShowDates);
_N(Title = StrFormat("{{NAME}} – {{INTERVAL}} {{DATE}} Open %g, Hi %g, Lo %g, Close %g (%.1f%%) {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 ) ) ));
SetOption("MaxOpenPositions", 28);

SetTradeDelays( 1,1,1,1);
SetOption( "InitialEquity", 200000);
SetOption("FuturesMode" ,True);
SetOption("MinShares",1);
Leverage=1.00;
SetOption("AccountMargin",100);
SetPositionSize (((100/1)*Leverage),spsPercentofEquity);
SetOption( "AllowPositionShrinking", True );

BuyPrice=Open;
ShortPrice=Open;
SellPrice=Open;
CoverPrice=Open;

LookBack =1; //24*4;// optimize("LookBack",12,96,96*15,96);//24*4;// 8=2 days back on 15-min chart, 1=6hours,0.5=3hours,etc..  (24hours*multiple)/4(15-minute bars)
function mROC( symbol, mode ) 
{ 
   fO = Foreign( symbol, "O"); 
   fC = Foreign( symbol, "C"); 
   fH = Foreign( symbol, "H");    
   fL = Foreign( symbol, "L"); 
    
   switch ( mode ) 
   { 
      case "CC1":       
         returnvalue = ROC( fC, LookBack ); 
      break; 
       
      case "OC0": 
         returnvalue = (fC- fO)/fO*100; 
      break; 
       
      case "HC0": //HCO
         returnvalue = (fC - fH)/fH*100;       
      break; 
       
      case "LC0": //LC0
         returnvalue = (fC - fL)/fL*100;   //  returnvalue = (fC - fL)/fL*100;          
      break;       
       
      default: 
         returnvalue = Null;          
      break;    
   } 
    
   return returnvalue; 
} 

n = Name();

weight1 =optimize("Weight1",0.5,-1.5,1.5,0.1);
weight2 =optimize("Weight2",0.4,-1.5,1.5,0.1);
weight3 =optimize("Weight3",0.1,-1.5,1.5,0.1);
weight4 =optimize("Weight4",-0.8,-1.5,1.5,0.1);
weight5 =optimize("Weight5",-0.2,-1.5,1.5,0.1);

//FXCM DECIMALS OPTIMIZE from SCRATCH
AUDCAD_IDEALPRO_CASH_30Val		=mROC("NZDUSD.FXCM","CC1")*Weight1+mROC("EURUSD.FXCM","CC1")*Weight2+mROC("USDJPY.FXCM","CC1")*Weight3+mROC("USDCHF.FXCM","CC1")*Weight4+mROC("GBPNZD.FXCM","CC1")*Weight5;
AUDCHF_IDEALPRO_CASH_30Val		=mROC("EURUSD.FXCM","CC1")*Weight1+mROC("USDCAD.FXCM","CC1")*Weight2+mROC("EURNZD.FXCM","CC1")*Weight3+mROC("EURAUD.FXCM","CC1")*Weight4+mROC("EURGBP.FXCM","CC1")*Weight5;
AUDJPY_IDEALPRO_CASH_30Val		=mROC("EURGBP.FXCM","CC1")*Weight1+mROC("GBPCAD.FXCM","CC1")*Weight2+mROC("GBPAUD.FXCM","CC1")*Weight3+mROC("GBPCHF.FXCM","CC1")*Weight4+mROC("CHFJPY.FXCM","CC1")*Weight5;     

Val=IIF(n=="AUDCAD.FXCM",	AUDCAD_IDEALPRO_CASH_30Val,
IIF(n=="AUDCHF.FXCM",	AUDCHF_IDEALPRO_CASH_30Val	,
IIF(n=="AUDJPY.FXCM",	AUDJPY_IDEALPRO_CASH_30Val	,
AUDJPY_IDEALPRO_CASH_30Val)));

Buy=   Val >1.00;
Sell = Val < 1.0 ;

Short= Val<-1.00;
Cover= Val>-1.0;

TrailStop = 0.250;
StopLoss=1.00;

SetOption("ActivateStopsImmediately", True) ;
ApplyStop( stopTypeTrailing, stopModePercent, TrailStop, 1, False, 0, 0);
ApplyStop( stopTypeLoss, stopModePercent, StopLoss, 1, False, 0, 0, -1, 0 );

//Target=0.2;
//ApplyStop(stopTypeProfit,stopModePercent,Target,1,False,0,0);
//ApplyStop( stopTypeNBar, stopModeBars, 2, 0, volatile = False, ReEntryDelay = 10, ValidFrom = 0, ValidTo = -1, ActivationFloor = 0 );

No matter what duration your bars are, there will always be ambiguity if you use both a stop and profit target because you don't know if the price within the bar went up and then down or vice versa. However, you may want to look at the SetStopPrecedence function, which will allow you to control whether stop losses are processed first (the more conservative approach) or profit targets first (the more optimistic approach).

2 Likes

Matt,

Thanks for the SetStopPrecedence function. By default, per Tomasz's notes, it looks to be the Conservative approach.
Fixed Ruin stop (loosing 99.96% of the starting capital)
Max. loss stop
Profit target stop
Trailing stop
N-bar stop

In my code, I am not using a pure Profit Target, just the Stop Loss and Trailing Stop. Assuming I am entering on a Weekly bar, on Monday's Open, if the low of the bar is below the Stop Loss, the trade is exited at the Stop Loss as expected in every case.

I can remove the Stop Loss and only implement the Trailing Stop, which is effectively a stop loss and profit target in one function. However as a single Weekly OHLC the price sequence of Monday through Friday is masked so a Trailing stop does not seem as if it can be implemented on the entry bar of a trade with the trade exiting on the same bar. As you mentioned in a previous post, if it seems to good to be true, it probably isn't.

How exactly is the Trailing stop being implemented? Let's assume a 0.25 cent trail stop and we enter at $10.00. Can the Trail be coded so that the Trail is moved higher with each 0.25 cents advance by 0.25? So that if it never advances to 10.25, the stop will be 9.75 but if it moves to 10.25, the stop is moved to 10.00? Do one of the trail stop modes accomplish this?

Any suggestions how to implement a Trailing stop on a weekly bar?

Thanks,

Mike

I don't use ApplyStop() very often, but I believe that the way the trailing stop will work is as follows:

  1. On the entry bar of a long trade, the stop price is set to the entry price less the stop amount.
  2. On the second bar of the trade, the stop price will be set to the entry bar high less the stop amount
  3. On all subsequent bars, the trailing stop price will be the max of the previous trailing stop price and the high of the previous bar less the stop amount.

Therefore, if you're entering at the open, there should be no ambiguity about executing stops on the entry bar.

I don't believe ApplyStop() can move the stop price in "steps" as you are describing. However, recent versions of AB do include an Activation Floor parameter which can be used to delay the start of a stop or profit target. As always, the best approach is to code some simple test cases, run a backtest, and then look at a number of trades to be sure you understand why AmiBroker is exiting on a particular bar at a particular price.

With respect to your explanation above, are all details re a Trailing Stop? If I am entering on the Open of a Weekly bar, a bar that displays the OHLC for the week, and am only using the Trail stop, I still think there is ambiguity as to the sequencing each day that is represented in that bar.

To reduce the ambiguity, I have added "TimeFrameSet( inWeekly );" and "TimeFrameRestore(); " and am now running the script on Daily data. Does this make sense to you? The "val" is still calculated on a weekly scale, but the trades is executed on Daily bars.

Thanks for your time and input!

Mike

_SECTION_BEGIN("Trading System");
SetChartOptions(0,chartShowArrows|chartShowDates);
_N(Title = StrFormat("{{NAME}} – {{INTERVAL}} {{DATE}} Open %g, Hi %g, Lo %g, Close %g (%.1f%%) {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 ) ) ));
SetOption("MaxOpenPositions", 28);

SetTradeDelays( 1,1,1,1);
SetOption( "InitialEquity", 200000);
SetOption("FuturesMode" ,True);
SetOption("MinShares",1);
Leverage=1.00;
SetOption("AccountMargin",100);
SetPositionSize (((100/1)*Leverage),spsPercentofEquity);
SetOption( "AllowPositionShrinking", True );

TimeFrameSet( inWeekly );

BuyPrice=Open;
ShortPrice=Open;
SellPrice=Open;
CoverPrice=Open;

LookBack =1; //24*4;// optimize("LookBack",12,96,96*15,96);//24*4;// 8=2 days back on 15-min chart, 1=6hours,0.5=3hours,etc..  (24hours*multiple)/4(15-minute bars)
function mROC( symbol, mode ) 
{ 
   fO = Foreign( symbol, "O"); 
   fC = Foreign( symbol, "C"); 
   fH = Foreign( symbol, "H");    
   fL = Foreign( symbol, "L"); 
    
   switch ( mode ) 
   { 
      case "CC1":       
         returnvalue = ROC( fC, LookBack ); 
      break; 
       
      case "OC0": 
         returnvalue = (fC- fO)/fO*100; 
      break; 
       
      case "HC0": //HCO
         returnvalue = (fC - fH)/fH*100;       
      break; 
       
      case "LC0": //LC0
         returnvalue = (fC - fL)/fL*100;   //  returnvalue = (fC - fL)/fL*100;          
      break;       
       
      default: 
         returnvalue = Null;          
      break;    
   } 
    
   return returnvalue; 
} 

n = Name();

weight1 =optimize("Weight1",0.5,-1.5,1.5,0.1);
weight2 =optimize("Weight2",0.4,-1.5,1.5,0.1);
weight3 =optimize("Weight3",0.1,-1.5,1.5,0.1);
weight4 =optimize("Weight4",-0.8,-1.5,1.5,0.1);
weight5 =optimize("Weight5",-0.2,-1.5,1.5,0.1);

//FXCM DECIMALS OPTIMIZE from SCRATCH
AUDCAD_IDEALPRO_CASH_30Val		=mROC("NZDUSD.FXCM","CC1")*Weight1+mROC("EURUSD.FXCM","CC1")*Weight2+mROC("USDJPY.FXCM","CC1")*Weight3+mROC("USDCHF.FXCM","CC1")*Weight4+mROC("GBPNZD.FXCM","CC1")*Weight5;
AUDCHF_IDEALPRO_CASH_30Val		=mROC("EURUSD.FXCM","CC1")*Weight1+mROC("USDCAD.FXCM","CC1")*Weight2+mROC("EURNZD.FXCM","CC1")*Weight3+mROC("EURAUD.FXCM","CC1")*Weight4+mROC("EURGBP.FXCM","CC1")*Weight5;
AUDJPY_IDEALPRO_CASH_30Val		=mROC("EURGBP.FXCM","CC1")*Weight1+mROC("GBPCAD.FXCM","CC1")*Weight2+mROC("GBPAUD.FXCM","CC1")*Weight3+mROC("GBPCHF.FXCM","CC1")*Weight4+mROC("CHFJPY.FXCM","CC1")*Weight5;     

TimeFrameRestore(); // restore time frame to original

Val=IIF(n=="AUDCAD.FXCM",	AUDCAD_IDEALPRO_CASH_30Val,
IIF(n=="AUDCHF.FXCM",	AUDCHF_IDEALPRO_CASH_30Val	,
IIF(n=="AUDJPY.FXCM",	AUDJPY_IDEALPRO_CASH_30Val	,
AUDJPY_IDEALPRO_CASH_30Val)));

Buy=   Val >1.00;
Sell = Val < 1.0 ;

Short= Val<-1.00;
Cover= Val>-1.0;

TrailStop = 0.250;
StopLoss=1.00;

SetOption("ActivateStopsImmediately", True) ;
ApplyStop( stopTypeTrailing, stopModePercent, TrailStop, 1, False, 0, 0);
//ApplyStop( stopTypeLoss, stopModePercent, StopLoss, True, False, 0, 0, -1, 0 );

When you test on weekly bars, you enter and exit sometime within that bar. You can no longer determine whether your exit was on Tuesday or Thursday, unless you later look at more granular data. This is no different than trading on daily bars and not being able to tell whether your exit occurred at 10:15 AM or 2:30 PM.

What IS different about weekly and monthly bars is that the underlying data within them is often not continuous. In most cases, when I test on daily bars I can assume that the market was open for the entire duration of the bar. With weekly bars, many markets are closed during some parts of the bar and open during other parts of the bar. If the price of my trading instrument gaps up or down at the daily market open, that could trigger an exit with my broker that is beyond my anticipated stop price. However, a backtest on weekly bars will assume that prices are continuous, and will exit at my specified stop price.

Is this what you mean by "ambiguity"? If not, you'll need to explain in more detail.

I am modeling and trading FX which pretty much trades 24x5 except for weekends so there are few times where a market is closed and few gaps.

By ambiguity I am referring to what you stated, "You can no longer determine...". What I am seeing is that the high if the entry bar, the only bar representing the week, is being used to determine the Trailing stop price level. So, if I use a fixed stop loss of 1.5%, and the low of the entry bar is dwon 2% from the Open, the strategy will exit -1.5%. However, if the fixed stop loss is not hit and the FX pair moves up and down throughout the week,and makes a new high on Thursday it uses the high on Thursday as the "high" to determine the Trail Stop level, meanwhile I could have easily been "trailed"out of my position on Tuesday on an advance and then a retracement. This is the ambiguity.

My thought was to reduce the ambiguity by calc the model val based on weekly data and then executing on daily data, assuming I understand and have implemented the "TimeFrameSet(inWeekly) " correctly. Does it look correct?

This will not eliminate the ambiguity as you point that exists in Daily data as well but it should reduce it somewhat. If I set the fixed stop loss and the Trailing Stop to the same percentage, if the low is broken on the first day of the trade I will be stopped out and each subsequent day the Trailing stop should move with the pricing.

I really appreciate your help & direction!

Mike

I think you should take a close look at your trades again, because I don't believe that the trailing stop will use the current bar's high as the reference point, it will use the previous bar's high (or an earlier one). I ran a couple of quick tests on both daily and weekly bars, and this seems to hold true.

I ran it on Daily data just to make sure that if I was not implementing the TimeFrameSet incorrectly.

It is entering Long on the Open as it should but all trades are exited on the entry bar ata Trail that is based on the entry bar's high.

When you tested, did you use the below settings?
TrailStop = 0.20;
SetOption("ActivateStopsImmediately", True) ;
ApplyStop( stopTypeTrailing, stopModePercent, TrailStop);////, 1, False, 0, 0);

Are you sure you don't have any stops enabled in your Analysis Settings window?

If you can't figure this out, I suggest you post the details of a trade that you believe is exiting incorrectly, along with a few bars of data which cover the period in which the trade occurs. It would also be a good idea to use the simplest possible code that exhibits the problem.

All stops in Analysis window are disabled.

If I turn off ActivateStopsImmediately all stops will be executed as expected on the second bar but that the first week w/o stops which is not good.

I will post some details. I probably have an incorrect setting somewhere in the code or in AmiBroker.

Thank you!

Mike

OK, I see now. You are correct that with ActivateStopsImmediately enabled, then the trailing stop uses the current bar's high to find the exit price. I have never worked with anyone who wanted their trailing stops to work like that, though I'm sure some people do or else @Tomasz would not have implemented it that way. However, this illustrates the reason that I seldom use ApplyStop() and write my own stop logic in the CBT instead: I like having complete control over how my stops will work.

In this case, combining a fixed stop with a trailing stop and turning ActivateStopsImmediately off might give you what you want.

I would like it work as you thought, based on the previous bar high so no peekiing at the current bar's high.

I have tried your latest suggestion of combining a fixed stop with ValidFrom set to 0 and the Trailing set to 1 or even 2 with ActivateStopsImmediately=False but still some Trailing stops are executed on the entry bar.

I will find a workaround but feel better that at least you see it too and I do not have a bad setting set in AmiBroker.

Thanks again for all your help & time!

Mike

Look exactly in the users' guide AFL Function Reference - APPLYSTOP
There are literally listed ALL supported scenarios one by one. Pick one of them that you want. If you don't want any them, implement your own stop: AmiBroker Knowledge Base » How to plot a trailing stop in the Price chart

1 Like

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