ApplyStop stopTypeNBar - N-bar stop returning stops greater than N Bars?

I have a formula with the apply stop N bar stop however some of the backtest trades are being stopped out at >N bars, in the example below the stop is 10 bars with a 1 bar trade delay so should all be 11 bars however some trades are much greater than 11 bars.

Here is my formula with some help previously from @fxshrat

_SECTION_BEGIN("Random_Entry_Random_Exit");

SetTradeDelays(1,1,1,1);

maxpos = 1; // maximum number of open positions
SetOption("InitialEquity", 100000 ); // set initial equity = 100K
SetOption( "MaxOpenPositions", maxpos );
SetPositionSize( 1000, spsValue ); // 1K in each trade


RandomNumber = Random();
Buy = RandomNumber > 0.9;
Sell = 0;

NBarStop = 10;
ApplyStop(stopTypeNBar, stopModeBars, NBarStop);

BuyPrice = Close;
SellPrice = Close;

if ( Status("action") == actionIndicator) {
   eq = Equity(1,0);

   Plot( C, "Price", colorDefault, styleBar );

   PlotShapes(Buy*shapeUpArrow, colorGreen, 0, L);
   PlotShapes((Sell>0)*shapeDownArrow, colorRed, 0, H);
   
}
_SECTION_END();

screen shot example showing majority of trades at N+1 bars however some also > N+1 bars
image

also with the example of the longest trade at 27 bars
image

When I view the chart, the plotted green buy and red sell arrows do not correspond with the entry and exit dates on the list of trades in the backtest results.

Also, every time I left click on the chart the location of the plotted buy and sell arrows change position.
image

image

Also, if I right click and select edit formula on the chart window, a new window is opened in the formula editor with a new copy of my formula duplicated under the original copy.
image

I'm not sure if the above issues I am having are related or unrelated and being a beginner I am struggling to problem solve the issues so any suggestions are appreciated.

First your indicator code is DIFFERENT than your backtest code. This

// THIS makes your code running differently (and uncomparable) in chart and backtester
if ( Status("action") == actionIndicator) { 
   eq = Equity(1,0);

will change the SIGNALS your formula is generating depending if it is run as chart or as backtest. Don't do that.

Secondly, remember that Equity() is a single-security backtester, and in Analysis you are running PORTFOLIO backtest. that is totally different thing. TO compare apples to apples you have to remove that conditional part.

As to number of bars you see, you don't tell the settings but I suspect that you are using "Pad and align" option, and those problematic symbols (1AD.au) have data holes (i.e. they are NOT trading every day). N-bar exit in regular mode is counted in actual individual symbol bars, but when you use "pad and align" and reference symbol has MORE bars than given symbol, in the report you will see those reference bars.

Edit: the guess about data holes was right but I should have written the other way round (see explanation below).

2 Likes

hello @Tomasz,

I have removed the sections of code you mentioned, I will be honest and say I did not code these sections myself so I don not fully understand their use or implications.

My objective is to code a simple random entry, random bar exit system as a benchmark for future testing.

my setting are below;

image

image

image

image

image

image

I have tried again with this formula but am having the same issues as previously posted.

_SECTION_BEGIN("Random_Entry_Random_Exit");

SetTradeDelays(1,1,1,1);

maxpos = 1; // maximum number of open positions
SetOption("InitialEquity", 100000 ); // set initial equity = 100K
SetOption( "MaxOpenPositions", maxpos );
SetPositionSize( 1000, spsValue ); // 1K in each trade

RandomNumber = Random();
Buy = RandomNumber > 0.9;
Sell = 0;

//Short = RandomNumber < 0.5; 
//Cover = RandomNumber > 0.5; 

NBarStop = 10;
ApplyStop(stopTypeNBar, stopModeBars, NBarStop);

BuyPrice = Close;
SellPrice = Close;

//if ( Status("action") == actionIndicator) {
//eq = Equity(1,0);

Plot( C, "Price", colorDefault, styleBar );
PlotShapes(Buy*shapeUpArrow, colorGreen, 0, L);
PlotShapes((Sell>0)*shapeDownArrow, colorRed, 0, H);
	
//PlotShapes((Ref(Buy, -Status("BuyDelay")) > 0) * shapeUpArrow, colorGreen, 0, L);
//PlotShapes((Ref((Sell>0),-Status("SellDelay")) > 0) * shapeDownArrow, colorRed, 0, H);

_SECTION_END();

there is a gremlin somewhere :japanese_goblin:

thanks in advance

With 'Pad & Align' ON ($XAO.au) you will get in the backtest report a maximum of 11 Trade Days.

image

1 Like

That is direct consequence of the fact that you are using RANDOM ENTRY. The code that you run is generating RANDOM entry points EACH TIME it executes.
Each chart refresh means separate execution of your formula. Since your formula has RANDOM entries, each time chart is refreshed you will get DIFFERENT (random) entry points. And obviously they will NOT correspond to analysis output because it was a result of previous (different) execution.

The program is doing exactly what you told it to do - generates RANDOM output every time it is run.

See this:

To get stable output from RANDOM data you would need to generate random numbers JUST ONCE, store them in static variable and use stored values instead of generating new random data over and over again.

3 Likes

@Tomasz
That makes sense, is it possible to reference say a static list of variables in the form of a CSV file with a list of random numbers between 0-1 and apply these to a buy signal?

Yes, that is correct. I was right that I wrote that you have data holes, but I should write the other way round with regards to Pad and align option. The fact that backtester counts number of bars using each symbol data, one of two possibilities exist:

  1. without Pad and Align, you are exiting at 11th bar counting from individual symbol data bars. Now if given symbol has data holes and other symbols have more data it will result in higher number reported in the trade list BECAUSE OF EXTRA BARS that other symbols have, but this one doesn't. In portfolio backtest you are trading portfolio, not one symbol, so equity is created so it contains ALL bars that are present in ANY security under test.

  2. with Pad and align, all symbols data are padded and aligned with exactly same datetimestamps so all have the same number of bars, and you are getting exit at 11th bar of EQUITY, which may or may not be 11th trading bar of individual symbol (if it is missing data).

It is CRUCIAL to know your data.

Check your data for data holes and similar errors using
Tools->Database Purify tool.

3 Likes

What has struck me about my last few weeks trying to learn this game is that it is truly a dangerous minefield for the ignorant and uneducated.

Thanks I have now included padding and am reporting the correct number of days.

In which instances should padding be turned off?

Yes you could but it is faster to just use static variables.

RandomNumber = StaticVarGet("Random" + Name() );

if( IsNull( LastValue( RandomNumber ) ) )
{
   // generate random number ONCE only if static variable is not present
   RandomNumber = Random();
   StaticVarSet( "Random" + Name(), RandomNumber );
} 

4 Likes

@Tomasz

excellent thanks you I'm now on the road to random success :slight_smile:

Padding makes your life easier and in many cases (ranking, composites) it is strongly recommended, but you need to know what is written in the manual

Pad and align to reference symbol

[...] it may introduce some slight changes to indicator values when your data has holes and holes are filled with previous bar data. The feature is intended to be used when your system uses general market timing (generates global signals based on data and/or indicators calculated using Foreign from 'reference' symbol) or when you are creating composites out of unaligned data.

2 Likes

Hi @Tomasz

This code is returning no backtest results, can you see any errors, maybe I have misinterpreted your advice.

_SECTION_BEGIN("Random_Entry_Random_Exit");

SetTradeDelays(1,1,1,1);

maxpos = 1; // maximum number of open positions
SetOption("InitialEquity", 100000 ); // set initial equity = 100K
SetOption( "MaxOpenPositions", maxpos );
SetPositionSize( 1000, spsValue ); // 1K in each trade

RandomNumber = StaticVarGet("Random" + Name() );

if( IsNull( LastValue( RandomNumber ) ) )
{
   // generate random number ONCE only if static variable is not present
   RandomNumber = Random();
   StaticVarSet( "Random" + Name(), RandomNumber );
}

Buy = RandomNumber > 0.5;
Sell = 0; 

NBarStop = 10;
ApplyStop(stopTypeNBar, stopModeBars, NBarStop);

BuyPrice = Close;
SellPrice = Close;

Plot( C, "Price", colorDefault, styleBar );
PlotShapes(Buy*shapeUpArrow, colorGreen, 0, L);
PlotShapes((Sell>0)*shapeDownArrow, colorRed, 0, H);

_SECTION_END();

ApplyStop() arguments don't seem to match the definition.

ApplyStop( type, mode, amount, exitatstop, volatile = False, ReEntryDelay = 0, ValidFrom = 0, ValidTo = -1, ActivationFloor = 0 )

stopModeBars being used by you ?

I have thought the same thing but have seen others post without specifying

exitatstop, volatile = False, ReEntryDelay = 0,

To get better understanding of what is happening in your code and how functions work, use advice given here: How do I debug my formula?

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