Trouble referencing earlier values

Hi all,
I would be really grateful for some help with a coding problem I have.

I am working on a trend following idea that detects when a trending stock takes a breather (I call each breather area a Base, where price levels out for a bit) from its trend and then breaks out. I am writing code that detects the Bases.

An example of the problem I'm having is with a variable called BaseLength. My code successfully calculates the baseLength when it detects a low bar in the base. I want to keep incrementing the BaseLength for subsequent bars to the right, until a break out occurs. I think I could probably change my code to use valuewhen(baseLength>0, barindex()) however I would really like to know why my current code doesn't work as it's fairly fundemental to my understanding of array processing!

My code currently says...

BaseLength			=   IIf(uneventfulDay AND NOT SetByLoop, ValueWhen(BaseLength>0,BaseLength+1), BaseLength);

It seems to only increment for one bar, then it propagates the same value without incrementing. I did previously using the following, which I also couldn't get to work...

BaseLength			=   IIf(uneventfulDay AND NOT SetByLoop, ref(BaseLength,-1)+1, BaseLength);

I attach my whole code if needed.

//================================================================================================================

function lowBar(arr, bars)
{
return arr==LLV(arr,bars);
}

//================================================================================================================

function highBar(arr, bars)
{
return arr==HHV(arr,bars);
}

//================================================================================================================

// OVERVIEW
// This code is still work in progress. Its aim is to trade trending stocks that break out from temporary breathers (called Bases in this code) 
// The main terms are...

//    	initialBase0 - this is where the trend might begin. It is below the 200MA and is a low bar.
//		newBaseStarts - a new base can start when price has risen at least 20% from the previous (or original base)
//		BaseTop, BaseBottom, BaseLength describe the dimensions of the base
//
//		If price drops below the BaseBottom, the BaseBottom can be lowered as long as it is not within 20% of the previous base. 
//		The BaseTop can rise when the BaseTop is breached within a threshold and returns within the base.
//
//		For bars where nothing happens to change the dimensions of the base, there is a section that carries the values forward to the next bar for convenient referencing
//		It is that section which doesn't seem to work.


// initialise variables
//------------------------------------------------------------------------------------------
BaseTop 		= 	0;
BaseBottom 		= 	0;
BaseNo			=	-1;
BaseLength 		= 	0;
PreviousBaseTop = 	9999;
minBaseLength 	= 	10;
maxBaseLength 	= 	100;
dVI 			= 	MA(L,200);
IsLowBar		=	lowbar(Low, minBaseLength);
BuyThreshold	=	1.005;
BuySetup		=	0;
setByLoop		=	0;




// set initial base 0
//------------------------------------------------------------------------------------------
initialBase0 = islowbar AND
				(
					(baseNo==-1 AND L < dVI)
					//OR
					//(baseNo==0 AND Low < PreviousBaseTop)
				);

BaseNo 				= IIf(initialBase0, 0, BaseNo);
PreviousBaseTop 	= IIf(initialBase0, Low, PreviousBaseTop);
BaseTop 			= IIf(initialBase0, Low, BaseTop);
BaseBottom 			= IIf(initialBase0, Low, BaseBottom);
BaseLength			= IIf(initialBase0, 0, BaseLength);




// new base starts
//------------------------------------------------------------------------------------------
newBaseStarts		=	NOT initialBase0 AND islowbar AND 
						L >= Ref(BaseTop,-1)*1.2 AND
						L > Ref(BaseBottom,-1);
						
previousBaseTop 	= IIf(newBaseStarts, Ref(BaseTop,-1),previousBaseTop);
BaseNo 				= IIf(newBaseStarts, Ref(BaseNo,-1)+1,BaseNo);
BaseBottom			= IIf(newBaseStarts, Low,BaseBottom);
BaseTop				= IIf(newBaseStarts, High,BaseTop);



// base length and base top
//------------------------------------------------------------------------------------------
for (i=minBaseLength; i<BarCount;i++)
	{
	// calculate length
	for (x=1;(i-x)>0 AND x<= maxBaseLength AND newBaseStarts[i] ; x++)
		{
		// update Base Top
		if (H[i-x]>BaseTop[i])
			BaseTop[i] = H[i-x];
			
		// calculate length
		if (L[i-x]<BaseBottom[i])
			{
			// add length to bars to the left
			for (z=1; z<=x; z++)
			{
				BaseLength[i-x+z]=z;
				setByLoop[i-x+z]=1;
			}
			break;
			}
		}
	}



// reset Bases when price drops
//------------------------------------------------------------------------------------------
resetBases 			= BaseNo > 0 AND 
					  Ref(Low,-1)>= Ref(PreviousBaseTop,-1)*1.2 AND
					  Low < Ref(PreviousBaseTop,-1)*1.2;

BaseBottom			=	IIf(resetBases, 9999,BaseBottom);
BaseTop				=	IIf(resetBases, 0, BaseTop);
BaseLength			=	IIf(resetBases, 0, BaseLength);
PreviousBaseTop		=	IIf(resetBases, 9999, PreviousBaseTop);
BaseNo				=	IIf(resetBases, 0, BaseNo);
		



// lowerBaseBottom
//------------------------------------------------------------------------------------------
lowerBaseBottom 	=	islowbar AND
						L < Ref(BaseBottom, -1) AND
						L > PreviousBaseTop*1.2;
						
BaseBottom			= IIf(lowerBaseBottom, Low, BaseBottom);



// Raise BaseTop
//------------------------------------------------------------------------------------------
RaiseBaseTop 		=	Ref(High, -1) > Ref(BaseTop,-1) AND 
						Ref(High, -1) < Ref(BaseTop,-1)*BuyThreshold AND
						L < ref(BaseTop,-1);
						
BaseTop				=	IIf(RaiseBaseTop, HHV(H, BaseLength), BaseTop);



// Buy Signal
//------------------------------------------------------------------------------------------
BuySignal			=	Cross(H, BaseTop*BuyThreshold) AND 
						(BaseNo==1 OR BaseNo==2 OR BaseNo == 3);
						
BuySetup			=	IIf(BuySignal, 1,BuySetup);


// bring forward values if they have not been set
//------------------------------------------------------------------------------------------
uneventfulDay		=	NOT initialBase0 AND
						NOT newBaseStarts AND
						NOT resetBases;
						
PreviousBaseTop		= 	IIf(uneventfulDay, Ref(PreviousBaseTop,-1), PreviousBaseTop);

//BaseTop 			=	IIf(uneventfulDay AND NOT RaiseBaseTop, ref(BaseTop,-1),BaseTop);
BaseTop 			=	IIf(uneventfulDay AND NOT RaiseBaseTop, ValueWhen(BaseTop>0,BaseTop),BaseTop);
BaseBottom 			=	IIf(uneventfulDay AND NOT LowerBaseBottom, valuewhen(BaseBottom>0,BaseBottom),BaseBottom);
BaseNo	 			=	IIf(uneventfulDay, Ref(BaseNo,-1),BaseNo);

//BaseLength			=   IIf(uneventfulDay AND NOT SetByLoop, ref(BaseLength,-1)+1, BaseLength);
BaseLength			=   IIf(uneventfulDay AND NOT SetByLoop, ValueWhen(BaseLength>0,BaseLength+1), BaseLength);
CarryForward		=   IIf(uneventfulDay AND NOT SetByLoop, 1,0);
// Interpretation
//------------------------------------------------------------------------------------------
printf("\n\ninitialBase0 = "+initialBase0);
printf("\nnewBaseStarts="+newBaseStarts);
printf("\nBaseLength="+BaseLength);
printf("\nresetBases="+resetBases);
printf("\nuneventfulDay="+uneventfulDay);
printf("\nlowerBaseBottom="+lowerBaseBottom);
printf("\nRaiseBaseTop="+RaiseBaseTop);
printf("\n\nBaseBottom="+BaseBottom);
printf("\n\nBaseTop="+BaseTop);

printf("\nSetbyloop="+Setbyloop);
printf("\nCarryForward="+CarryForward);

_SECTION_BEGIN("Price");
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 ) ) ));
Plot( C, "Close", ParamColor("Color", colorDefault ), styleNoTitle | ParamStyle("Style") | GetPriceStyle() ); 
_SECTION_END();

_SECTION_BEGIN("MA1");
P = ParamField("Price field",-1);
Periods = Param("Periods", 200, 2, 300, 1, 10 );
Plot( MA( P, Periods ), _DEFAULT_NAME(), ParamColor( "Color", colorCycle ), ParamStyle("Style") ); 
_SECTION_END();

If you want to sum then you have to use Cum, Sum or SumSince.

So I guess you want sum since some event?

So for example

//... other code from above ...
cs = SumSince( uneventfulDay AND NOT SetByLoop, BaseLength > 0);
BaseLength = BaseLength  + cs;

So play around yourself with other alternatives if you want to sum differently since upper one is just quick example..

And use debugging methods if you want to know what happens
How to debug...

2 Likes

Thanks for your reply. As I understand it, SumSince isn't quite what I need because the conditions (uneventfulDay AND NOT SetByLoop) apply to the current bar rather than an earlier bar.

I attach a picture which illustrates the problem a bit more. In the picture below, I believe that the BaseLength values 20 and 1 are both set by my function above. The value 19 is the low bar and is set by my loop.
CBOE%20BaseLength%20example

What did I say to you?

  1. I said to you which array functions you would have to use for incrementing.
  2. Next one I said that I posted just quick example on how to apply such function.
  3. Then I said you have to play around with mentioned functions yourself if you want to have different summing as in my example. Example means example.

Still fact remains for summing the solution is one of those mentioned array functions.
Why? Your post #1 implied via IIf function to add "1" to Baselength if your condition (uneventfulDay AND NOT SetByLoop) is true otherwise just keep Baselength. I told you that you can not use IIf function for that.

So again either use Sum or SumSince. Here is next one..
Either use Sum or SumSince line. Both lines do the same thing.

BL_not_zero = BaseLength > 0;

cond1 = uneventfulDay AND NOT SetByLoop;
cond2 = Ref(BL_not_zero,-1) AND NOT BL_not_zero;

//cs = Sumsince(cond2, cond1) + ValueWhen(cond2, cond1);
cs = Sum(cond1, BarsSince(cond2)+1);

BaseLength2 = IIf(BL_not_zero, BaseLength, ValueWhen(cond2, Ref(BaseLength,-1))+cs);

Entire code

//================================================================================================================

function lowBar(arr, bars)
{
return arr==LLV(arr,bars);
}

//================================================================================================================

function highBar(arr, bars)
{
return arr==HHV(arr,bars);
}

//================================================================================================================

// OVERVIEW
// This code is still work in progress. Its aim is to trade trending stocks that break out from temporary breathers (called Bases in this code) 
// The main terms are...

//    	initialBase0 - this is where the trend might begin. It is below the 200MA and is a low bar.
//		newBaseStarts - a new base can start when price has risen at least 20% from the previous (or original base)
//		BaseTop, BaseBottom, BaseLength describe the dimensions of the base
//
//		If price drops below the BaseBottom, the BaseBottom can be lowered as long as it is not within 20% of the previous base. 
//		The BaseTop can rise when the BaseTop is breached within a threshold and returns within the base.
//
//		For bars where nothing happens to change the dimensions of the base, there is a section that carries the values forward to the next bar for convenient referencing
//		It is that section which doesn't seem to work.


// initialise variables
//------------------------------------------------------------------------------------------
BaseTop 		= 	0;
BaseBottom 		= 	0;
BaseNo			=	-1;
BaseLength 		= 	0;
PreviousBaseTop = 	9999;
minBaseLength 	= 	10;
maxBaseLength 	= 	100;
dVI 			= 	MA(L,200);
IsLowBar		=	lowbar(Low, minBaseLength);
BuyThreshold	=	1.005;
BuySetup		=	0;
setByLoop		=	0;




// set initial base 0
//------------------------------------------------------------------------------------------
initialBase0 = islowbar AND
				(
					(baseNo==-1 AND L < dVI)
					//OR
					//(baseNo==0 AND Low < PreviousBaseTop)
				);

BaseNo 				= IIf(initialBase0, 0, BaseNo);
PreviousBaseTop 	= IIf(initialBase0, Low, PreviousBaseTop);
BaseTop 			= IIf(initialBase0, Low, BaseTop);
BaseBottom 			= IIf(initialBase0, Low, BaseBottom);
BaseLength			= IIf(initialBase0, 0, BaseLength);




// new base starts
//------------------------------------------------------------------------------------------
newBaseStarts		=	NOT initialBase0 AND islowbar AND 
						L >= Ref(BaseTop,-1)*1.2 AND
						L > Ref(BaseBottom,-1);
						
previousBaseTop 	= IIf(newBaseStarts, Ref(BaseTop,-1),previousBaseTop);
BaseNo 				= IIf(newBaseStarts, Ref(BaseNo,-1)+1,BaseNo);
BaseBottom			= IIf(newBaseStarts, Low,BaseBottom);
BaseTop				= IIf(newBaseStarts, High,BaseTop);



// base length and base top
//------------------------------------------------------------------------------------------
for (i=minBaseLength; i<BarCount;i++)
	{
	// calculate length
	for (x=1;(i-x)>0 AND x<= maxBaseLength AND newBaseStarts[i] ; x++)
		{
		// update Base Top
		if (H[i-x]>BaseTop[i])
			BaseTop[i] = H[i-x];
			
		// calculate length
		if (L[i-x]<BaseBottom[i])
			{
			// add length to bars to the left
			for (z=1; z<=x; z++)
			{
				BaseLength[i-x+z]=z;
				setByLoop[i-x+z]=1;
			}
			break;
			}
		}
	}



// reset Bases when price drops
//------------------------------------------------------------------------------------------
resetBases 			= BaseNo > 0 AND 
					  Ref(Low,-1)>= Ref(PreviousBaseTop,-1)*1.2 AND
					  Low < Ref(PreviousBaseTop,-1)*1.2;

BaseBottom			=	IIf(resetBases, 9999,BaseBottom);
BaseTop				=	IIf(resetBases, 0, BaseTop);
BaseLength			=	IIf(resetBases, 0, BaseLength);
PreviousBaseTop		=	IIf(resetBases, 9999, PreviousBaseTop);
BaseNo				=	IIf(resetBases, 0, BaseNo);
		



// lowerBaseBottom
//------------------------------------------------------------------------------------------
lowerBaseBottom 	=	islowbar AND
						L < Ref(BaseBottom, -1) AND
						L > PreviousBaseTop*1.2;
						
BaseBottom			= IIf(lowerBaseBottom, Low, BaseBottom);



// Raise BaseTop
//------------------------------------------------------------------------------------------
RaiseBaseTop 		=	Ref(High, -1) > Ref(BaseTop,-1) AND 
						Ref(High, -1) < Ref(BaseTop,-1)*BuyThreshold AND
						L < ref(BaseTop,-1);
						
BaseTop				=	IIf(RaiseBaseTop, HHV(H, BaseLength), BaseTop);



// Buy Signal
//------------------------------------------------------------------------------------------
BuySignal			=	Cross(H, BaseTop*BuyThreshold) AND 
						(BaseNo==1 OR BaseNo==2 OR BaseNo == 3);
						
BuySetup			=	IIf(BuySignal, 1,BuySetup);


// bring forward values if they have not been set
//------------------------------------------------------------------------------------------
uneventfulDay		=	NOT initialBase0 AND
						NOT newBaseStarts AND
						NOT resetBases;
						
PreviousBaseTop		= 	IIf(uneventfulDay, Ref(PreviousBaseTop,-1), PreviousBaseTop);

//BaseTop 			=	IIf(uneventfulDay AND NOT RaiseBaseTop, ref(BaseTop,-1),BaseTop);
BaseTop 			=	IIf(uneventfulDay AND NOT RaiseBaseTop, ValueWhen(BaseTop>0,BaseTop),BaseTop);
BaseBottom 			=	IIf(uneventfulDay AND NOT LowerBaseBottom, valuewhen(BaseBottom>0,BaseBottom),BaseBottom);
BaseNo	 			=	IIf(uneventfulDay, Ref(BaseNo,-1),BaseNo);


//BaseLength=   IIf(uneventfulDay AND NOT SetByLoop, ref(BaseLength,-1)+1, BaseLength);
// Commented by fxshrat
//BaseLength=   IIf(uneventfulDay AND NOT SetByLoop, ValueWhen(BaseLength>0,BaseLength+1), BaseLength);


// Addtion by fxshrat start ##############################################
/// @link https://forum.amibroker.com/t/trouble-referencing-earlier-values/11235/4
BL_not_zero = BaseLength > 0;
cond1 = uneventfulDay AND NOT SetByLoop;
cond2 = Ref(BL_not_zero,-1) AND ! BL_not_zero;
//cs = Sumsince(cond2, cond1) + ValueWhen(cond2, cond1);
cs = Sum(cond1, BarsSince(cond2)+1);
BaseLength2 = IIf(BL_not_zero, BaseLength, ValueWhen(cond2, Ref(BaseLength,-1))+cs);
// Addtion by fxshrat end ##############################################

CarryForward		=   IIf(uneventfulDay AND NOT SetByLoop, 1,0);
// Interpretation
//------------------------------------------------------------------------------------------
printf("\n\ninitialBase0 = "+initialBase0);
printf("\nnewBaseStarts="+newBaseStarts);
printf("\nBaseLength="+BaseLength);
printf("\nresetBases="+resetBases);
printf("\nuneventfulDay="+uneventfulDay);
printf("\nlowerBaseBottom="+lowerBaseBottom);
printf("\nRaiseBaseTop="+RaiseBaseTop);
printf("\n\nBaseBottom="+BaseBottom);
printf("\n\nBaseTop="+BaseTop);

printf("\nSetbyloop="+Setbyloop);
printf("\nCarryForward="+CarryForward);

_SECTION_BEGIN("Price");
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 ) ) ));
Plot( C, "Close", ParamColor("Color", colorDefault ), styleNoTitle | ParamStyle("Style") | GetPriceStyle() ); 
_SECTION_END();

_SECTION_BEGIN("MA1");
P = ParamField("Price field",-1);
Periods = Param("Periods", 200, 2, 300, 1, 10 );
Plot( MA( P, Periods ), _DEFAULT_NAME(), ParamColor( "Color", colorCycle ), ParamStyle("Style") ); 
_SECTION_END();

// Addtion by fxshrat start ##############################################
Plot( cond1, "\ncond1", colorWhite, styleOwnScale | styleStaircase );
Plot( cond2, "\ncond2", colorBlue, styleOwnScale | styleStaircase );
Plot( BaseLength, "\nBaseLength", colorRed, styleLeftAxisScale );
Plot( BaseLength2, "\nBaseLength + incrementing", colorOrange, styleLeftAxisScale );
// Addtion by fxshrat end ##############################################

As you can see in below picture

Red line is original Baselength of before incrementing.
Orange one is Baselength + increments if "uneventfulDay AND NOT SetByLoop" is true. And those increments added to last value of BaseLength before changing to zero.
White line is condition "uneventfulDay AND NOT SetByLoop" returning one or zero.

Replace name BaseLength2 by Baselength. I only named it differently for separation purpose.

Note: Picture is showing how I understand what you want to do. And I only made for BaseLength.

148


Side note: You can not expect full hand holding the whole time. You need to think and debug yourself too. I posted link to debugging thread in post #2. Have you read it? Have you applied anything mentioned there? It doesn't look like you did.

1 Like