RSI Reading At High/Low of Day(Bar)

In another platform I created an indicator a long time ago that would tell me the RSI (using a smoothed RSI) value that would have occurred at the high and the low of the day. For instance, on 9/12/18 GOOGL closed at 1171.60. Its 2-period RSI closed at 25.73.

The indicator will look at the high of the day and tell me what the 2-period RSI would have closed at if GOOGL had closed there. In this case, the high was 1190.69 and the 2-period RSI High reading for the day would have been 71.31. The low of 1166.16 would have produced an RSI(2) reading of 21.69. Looking at these indicators on my chart I could see that the 2-period RSI readings on 9/12/18 for GOOGL would have ranged from 21.69 to 71.31, and that the closing RSI reading would have been 25.73.

Code that works in the other platform can be seen below. (Not AFL - my AFL attempt is coming next.)

if CurrentBar = 1 then
	begin
	NetChgAvgClose = ( Close - Close[Length] ) / Length ;
	TotChgAvgClose = Average( AbsValue( Close - Close[1] ), Length ) ;
	NetChgAvgHigh = NetChgAvgClose ;
	NetChgAvgLow = NetChgAvgClose ;
	end
else
	begin
	ChangeClose = Close - Close[1] ;
	ChangeHigh = High - Close[1] ;
	ChangeLow = Low - Close[1] ;
	NetChgAvgClose = NetChgAvgClose[1] + SF * ( ChangeClose - NetChgAvgClose[1] ) ;
	NetChgAvgHigh = NetChgAvgClose[1] + SF * ( ChangeHigh - NetChgAvgClose[1] ) ;
	NetChgAvgLow = NetChgAvgClose[1] + SF * ( ChangeLow - NetChgAvgClose[1] ) ;
	TotChgAvgClose = TotChgAvgClose[1] + SF * ( AbsValue( ChangeClose ) - TotChgAvgClose[1] ) ;
	TotChgAvgHigh = TotChgAvgClose[1] + SF * ( AbsValue( ChangeHigh ) - TotChgAvgClose[1] ) ;
	TotChgAvgLow = TotChgAvgClose[1] + SF * ( AbsValue( ChangeLow ) - TotChgAvgClose[1] ) ;
	end ;

if TotChgAvgClose <> 0 then
	ChgRatioClose = NetChgAvgClose / TotChgAvgClose 
else
	ChgRatioClose = 0 ;

if TotChgAvgHigh <> 0 then
	ChgRatioHigh = NetChgAvgHigh / TotChgAvgHigh 
else
	ChgRatioHigh = 0 ;

if TotChgAvgLow <> 0 then
	ChgRatioLow = NetChgAvgLow / TotChgAvgLow 
else
	ChgRatioLow = 0 ;

RSICloseVal = 50 * ( ChgRatioClose + 1 ) ;
RSIHighVal = 50 * ( ChgRatioHigh + 1 ) ;
RSILowVal = 50 * ( ChgRatioLow + 1 ) ;


Plot1( RSICloseVal, "RSIClose" ) ;
Plot2( RSIHighVal, "RSIHigh" ) ;
Plot3( RSILowVal, "RSILow" ) ;

I have been trying to translate it to AFL, and can’t seem to get it right. My “current” AFL attempt is below. (Note that I am only looking to get the RSI Bar High reading in this code. I believe I will need a separate function to get the rsiBarLow.)

function rsiBarHigh (length)
{

	bi = BarIndex();
	
	if (bi == 1 )
	{
	NetChgAvgClose = ( Close - Ref(Close,-length) ) / Length ;
	TotChgAvgClose = MA( Abs( Close - Ref(Close,-1) ), Length ) ;
	NetChgAvgHigh = NetChgAvgClose ;
	NetChgAvgLow = NetChgAvgClose ;
	}
	else
	{
	SF = 1 / length;
	ChangeClose = Close - Ref(Close,-1); 
	ChangeHigh = High - Ref(Close,-1) ;
	ChangeLow = Low - Ref(Close,-1) ;
	NetChgAvgClose = Ref(NetChgAvgClose,-1) + SF * ( ChangeClose - Ref(NetChgAvgClose,-1) ) ;
	NetChgAvgHigh = Ref(NetChgAvgClose,-1) + SF * ( ChangeHigh - Ref(NetChgAvgClose,-1) ) ;
	NetChgAvgLow = Ref(NetChgAvgClose,-1) + SF * ( ChangeLow - Ref(NetChgAvgClose,-1) ) ;
	TotChgAvgClose = Ref(TotChgAvgClose,-1) + SF * ( Abs( ChangeClose ) - Ref(TotChgAvgClose,-1) ) ;
	TotChgAvgHigh = Ref(TotChgAvgClose,-1) + SF * ( Abs( ChangeHigh ) - Ref(TotChgAvgClose,-1) ) ;
	TotChgAvgLow = Ref(TotChgAvgClose,-1) + SF * ( Abs( ChangeLow ) - Ref(TotChgAvgClose,-1) ) ;
	}
	
	ChgRatioClose = IIf(TotChgAvgClose != 0, NetChgAvgClose / TotChgAvgClose, 0);
	ChgRatioHigh = IIf(TotChgAvgHigh != 0, NetChgAvgHigh / TotChgAvgHigh, 0);
	ChgRatioLow = IIf(TotChgAvgLow != 0, NetChgAvgLow / TotChgAvgLow, 0);
	

	//_RSICloseVal = 50 * ( ChgRatioClose + 1 ) ;
	_RSIBarHigh = 50 * ( ChgRatioHigh + 1 ) ;
	//_RSILowVal = 50 * ( ChgRatioLow + 1 ) ;
	
	return _RSIBarHigh;	
}
	
Plot(rsiBarHigh( Param("Length",2,2,30,1)),"RSI Bar High", ParamColor("Color", colorGreen ), ParamStyle("Style", 0, maskAll ) );

I think my primary problem is in the 1st part of the “if” statement. I am sure I am writing it wrong, though I have tried several iterations. Suggestions are greatly appreciated.

Since bi is an array, you can't use it in an if() statement that way. I'm not sure exactly what your formula is (it doesn't look like the standard RSI formula), but wouldn't you need to loop through all of the bars? If your formula doesn't require looping then perhaps you should be using iif() when assigning NetChgAvgClose, NetChgAvgHigh, etc.

1 Like

@QEdges I haven't had time to really try but perhaps you will find this information useful.
https://www.amibroker.com/guide/afl/rsi.html

Perhaps substitute High and Low within this,

// Internally RSI is implemented as follows
//
function BuiltInRSIEquivalent( period )
{
    P = N = 0;

    result = Null;

    for( i = 1; i < BarCount; i++ )
    {
        diff = C[ i ] - C[ i - 1 ];
        W = S = 0;

        if( diff > 0 ) W = diff;

        if( diff < 0 ) S = -diff;

        P = ( ( period - 1 ) * P + W ) / period;
        N = ( ( period - 1 ) * N + S ) / period;

        if( i >= period )
            result[ i ] = 100 * P / ( P + N );
    }

    return result;
}

Plot( BuiltInRSIEquivalent( 14 ), "RSI 1", colorRed );
Plot( RSI( 14 ), "RSI 2", colorBlue );
// or run an Exploration to confirm
Filter=1;
AddColumn(BuiltInRSIEquivalent( 14 ), "BuiltInRSIEquivalent( 14 )");
AddColumn(RSI( 14 ), "RSI( 14 )");
2 Likes

Thanks @mradtke and @portfoliobuilder !

The looping hint helped and the code @portfoliobuilder supplied helped me get the syntax correct. Below is the rsiHighBar:

// High of Bar RSI
//
function RSIbarHigh( length )
{
 	SF = 1 / length;
    result = Null;
    NetChgAvgClose = TotChgAvgClose = NetChgAvgHigh = 0;

    for( i = 1; i < BarCount; i++ )
    {
        if( i <= length )
        {
			NetChgAvgClose[i] = ( Close[i] - Close[Length] ) / Length ;
            TotChgAvgClose[i] = 1; // MA( Abs( Close[i] - Close[i-1] ), Length ) ;
            NetChgAvgHigh[i] = NetChgAvgClose[i] ;
        }
        
        changeclose = Close[i] - Close[i - 1];
        changehigh = High[i] - Close[i - 1];
        NetChgAvgClose[i] = NetChgAvgClose[i-1] + SF * ( ChangeClose[i] - NetChgAvgClose[i-1] ) ;
		NetChgAvgHigh[i] = NetChgAvgClose[i-1] + SF * ( ChangeHigh[i] - NetChgAvgClose[i-1] ) ;
		TotChgAvgClose[i] = TotChgAvgClose[i-1] + SF * ( Abs( ChangeClose[i] ) - TotChgAvgClose[i-1] ) ;
		TotChgAvgHigh[i] = TotChgAvgClose[i-1] + SF * ( Abs( ChangeHigh[i] ) - TotChgAvgClose[i-1] ) ; 
        
		ChgRatioHigh[i] = IIf(TotChgAvgHigh[i] != 0, NetChgAvgHigh[i] / TotChgAvgHigh[i], 0);
		
        if( i > length )
            result[ i ] = 50 * (ChgRatioHigh[i] + 1);
    }

    return result;
}

//Plot( RSIbarHigh( Param("RSI Length",2,2,30,1)), "RSI Bar High", colorRed );
//Plot( RSI( 2 ), "RSI 2", colorBlue );
// or run an Exploration to confirm
//Filter=1;
//AddColumn(RSIbarHigh( 2 ), "RSIbarHigh( 2 )");
//AddColumn(RSI( 2 ), "RSI( 2 )");

Next is the Low:

// Low of Bar RSI
//
function RSIbarLow( length )
{
 	SF = 1 / length;
    result = Null;
    NetChgAvgClose = TotChgAvgClose = NetChgAvgLow = 0;

    for( i = 1; i < BarCount; i++ )
    {
        if( i <= length )
        {
			NetChgAvgClose[i] = ( Close[i] - Close[Length] ) / Length ;
            TotChgAvgClose[i] = 1; // MA( Abs( Close[i] - Close[i-1] ), Length ) ;
            NetChgAvgLow[i] = NetChgAvgClose[i] ;
        }
        
        changeclose = Close[i] - Close[i - 1];
        changeLow = Low[i] - Close[i - 1];
        NetChgAvgClose[i] = NetChgAvgClose[i-1] + SF * ( ChangeClose[i] - NetChgAvgClose[i-1] ) ;
		NetChgAvgLow[i] = NetChgAvgClose[i-1] + SF * ( ChangeLow[i] - NetChgAvgClose[i-1] ) ;
		TotChgAvgClose[i] = TotChgAvgClose[i-1] + SF * ( Abs( ChangeClose[i] ) - TotChgAvgClose[i-1] ) ;
		TotChgAvgLow[i] = TotChgAvgClose[i-1] + SF * ( Abs( ChangeLow[i] ) - TotChgAvgClose[i-1] ) ; 
        
		ChgRatioLow[i] = IIf(TotChgAvgLow[i] != 0, NetChgAvgLow[i] / TotChgAvgLow[i], 0);
		
        if( i > length )
            result[ i ] = 50 * (ChgRatioLow[i] + 1);
    }

    return result;
}

//Plot( RSIbarLow( Param("RSI Length",2,2,30,1)), "RSI Bar Low", colorRed );
//Plot( RSI( 2 ), "RSI 2", colorBlue );
// or run an Exploration to confirm
//Filter=1;
//AddColumn(RSIbarLow( 2 ), "RSIbarLow( 2 )");
//AddColumn(RSI( 2 ), "RSI( 2 )");

I will note I was getting a syntax error in line 14 when I tried to utilize my old code. But that is just a starting value for a exponential ma, so it does not really matter, and I replaced it with "1" and it still syncs up quickly.

I also created an "RSI Bars" set of code to add the high, low, close RSIs to a chart all at once.

#include <rsiBarHigh.afl>
#include <rsiBarLow.afl>

rsiLength = Param("RSIlength",2,2,30,1,0);

RH = rsiBarHigh(rsiLength);
RL = rsiBarLow(rsiLength);	
RS = RSI(rsiLength);

Plot( RH, "RSI Bar High", colorRed );
Plot( RS, "RSI (Close)", colorOrange );
Plot( RL, "RSI Bar Low", colorRed );

Here is how it looks:
RSI%20Bars%20chart

It shows the bands around the standard RSI. Personally, I would prefer if it drew a High-Low-Close bar for each date rather than having connecting lines that look like bands. But I could not figure out how to accomplish that. Suggestions on that are welcome, but it is not imperative to solve.

Thanks again!

3 Likes

@QEdges did you try using PlotOHLC() for that?

https://www.amibroker.com/guide/afl/plotohlc.html

5 Likes

Not sure if that's what you want...
(made some other changes...)

procedure RSIbarHLC( length )
{
 	/// https://forum.amibroker.com/t/rsi-reading-at-high-low-of-day-bar/7999/6

 	SF = 1 / length; 	
    
	ChangeClose = Close - Ref(Close,-1); 
	ChangeHigh = High - Ref(Close,-1); 
	ChangeLow = Low - Ref(Close,-1);    

	NetChgAvgClose = TotChgAvgClose = 0;
	NetChgAvgHigh = TotChgAvgHigh = 0;
	NetChgAvgLow = TotChgAvgLow = 0;
    
	rc = (C-Ref(C,-length))/length;
	myMA = MA( abs(C - Ref(C, -1 )), length );

	for( i = 1; i < BarCount; i++ )
	{
		if( i <= length )
		{
			NetChgAvgClose[i] = rc[i];
			TotChgAvgClose[i] = myMA[i]; 
			NetChgAvgHigh[i] = NetChgAvgClose[i];
			NetChgAvgLow[i] = NetChgAvgClose[i];
		} 
		else 
		{       
			prev1 = NetChgAvgClose[i-1];
			prev2 = TotChgAvgClose[i-1];
	
			NetChgAvgClose[i] = prev1 + SF * ( ChangeClose[i] - prev1 );
			NetChgAvgHigh[i] = prev1 + SF * ( ChangeHigh[i] - prev1 );
			NetChgAvgLow[i] = prev1 + SF * ( ChangeLow[i] - prev1 );
			
			TotChgAvgClose[i] = prev2 + SF * ( Abs( ChangeClose[i] ) - prev2 );
			TotChgAvgHigh[i] = prev2 + SF * ( Abs( ChangeHigh[i] ) - prev2 ); 
			TotChgAvgLow[i] = prev2 + SF * ( Abs( ChangeLow[i] ) - prev2 );
		}        
	}  

	VarSet( "RSIBarClose", 50 * (Nz(NetChgAvgClose / (TotChgAvgClose)) + 1) );
	VarSet( "RSIBarHigh", 50 * (Nz(NetChgAvgHigh / (TotChgAvgHigh)) + 1) );
	VarSet( "RSIBarLow", 50 * (Nz(NetChgAvgLow / (TotChgAvgLow)) + 1) );
}

length = Param("RSI Length",2,2,30,1);

RSIbarHLC( length );

//Plot( RSIBarClose, "RSI Bar Close", colorGold );
//Plot( RSIBarHigh, "RSI Bar High", colorGreen );
//Plot( RSIBarLow, "RSI Bar Low", colorRed );

PlotOHLC( Null, RSIBarHigh, RSIBarLow, RSI( length ), "RSI_HLC(" + length + ")", colorGreen, styleBar );

43

6 Likes

Thanks @Milosz for the suggestion, and @fxshrat for the code update. Looks great!

I made one minor change to the plot staements at the bottom of the code, so that the high and low values would also appear in the box.

//Plot( RSIBarClose, "RSI Bar Close", colorGold );
Plot( RSIBarHigh, "RSI Bar High", colorGreen, styleNoDraw );
Plot( RSIBarLow, "RSI Bar Low", colorRed, styleNoDraw );

PlotOHLC( Null, RSIBarHigh, RSIBarLow, RSI( length ), "RSI_HLC(" + length + ")", colorGrey40, styleBar );

You can see the effect here:
GOOGLrsiBars

And here is the full code from @fxshrat with my minor plot change at the bottom. Thanks to all of you for the help with this!

procedure RSIbarHLC( length )
{
 	/// https://forum.amibroker.com/t/rsi-reading-at-high-low-of-day-bar/7999/6

 	SF = 1 / length; 	
    
	ChangeClose = Close - Ref(Close,-1); 
	ChangeHigh = High - Ref(Close,-1); 
	ChangeLow = Low - Ref(Close,-1);    

	NetChgAvgClose = TotChgAvgClose = 0;
	NetChgAvgHigh = TotChgAvgHigh = 0;
	NetChgAvgLow = TotChgAvgLow = 0;
    
	rc = (C-Ref(C,-length))/length;
	myMA = MA( abs(C - Ref(C, -1 )), length );

	for( i = 1; i < BarCount; i++ )
	{
		if( i <= length )
		{
			NetChgAvgClose[i] = rc[i];
			TotChgAvgClose[i] = myMA[i]; 
			NetChgAvgHigh[i] = NetChgAvgClose[i];
			NetChgAvgLow[i] = NetChgAvgClose[i];
		} 
		else 
		{       
			prev1 = NetChgAvgClose[i-1];
			prev2 = TotChgAvgClose[i-1];
	
			NetChgAvgClose[i] = prev1 + SF * ( ChangeClose[i] - prev1 );
			NetChgAvgHigh[i] = prev1 + SF * ( ChangeHigh[i] - prev1 );
			NetChgAvgLow[i] = prev1 + SF * ( ChangeLow[i] - prev1 );
			
			TotChgAvgClose[i] = prev2 + SF * ( Abs( ChangeClose[i] ) - prev2 );
			TotChgAvgHigh[i] = prev2 + SF * ( Abs( ChangeHigh[i] ) - prev2 ); 
			TotChgAvgLow[i] = prev2 + SF * ( Abs( ChangeLow[i] ) - prev2 );
		}        
	}  

	VarSet( "RSIBarClose", 50 * (Nz(NetChgAvgClose / (TotChgAvgClose)) + 1) );
	VarSet( "RSIBarHigh", 50 * (Nz(NetChgAvgHigh / (TotChgAvgHigh)) + 1) );
	VarSet( "RSIBarLow", 50 * (Nz(NetChgAvgLow / (TotChgAvgLow)) + 1) );
}

length = Param("RSI Length",2,2,30,1);

RSIbarHLC( length );

//Plot( RSIBarClose, "RSI Bar Close", colorGold );
Plot( RSIBarHigh, "RSI Bar High", colorGreen, styleNoDraw );
Plot( RSIBarLow, "RSI Bar Low", colorRed, styleNoDraw );

PlotOHLC( Null, RSIBarHigh, RSIBarLow, RSI( length ), "RSI_HLC(" + length + ")", colorGrey40, styleBar );

2 Likes

Guys, has no one seeing it yet?

The whole looping code can be much more simplified by removing the loop completely and as such it can be made a lot lot faster just using array processing.

Why?

In case you haven't realized yet but the calculations of NetChgAvgClose and TotChgAvgClose are just the same ones as of AMA function.

Anyway here is much more simplified non-loop version (more than 90% faster than previous one):

procedure RSIbarHLC( length )
{
 	/// https://forum.amibroker.com/t/rsi-reading-at-high-low-of-day-bar/7999/8
 	/// non-loop version by fxshrat@gmail.com

 	SF = 1 / length;  
 	SF2 = 1 - SF;   

	ChangeClose = Close - Ref(Close,-1); 
	ChangeHigh = SF * (High - Ref(Close,-1)); 
	ChangeLow = SF * (Low - Ref(Close,-1)); 
	
	rc = (C-Ref(C,-length))/length;
	myMA = MA( abs(ChangeClose), length );

	bicond = BarIndex() <= length;

	NetChgAvgClose = IIf(bicond, rc, AMA(ChangeClose, SF));	
	prev1 = SF2 * Ref(NetChgAvgClose,-1);
	NetChgAvgHigh = IIf(bicond, NetChgAvgClose, ChangeHigh + prev1);	
	NetChgAvgLow = IIf(bicond, NetChgAvgClose, ChangeLow + prev1);	
	
	TotChgAvgClose = IIf(bicond, myMA, AMA(abs(ChangeClose), SF));
	prev2 = SF2 * Ref(TotChgAvgClose,-1);
	TotChgAvgHigh = abs(ChangeHigh) + prev2;	
	TotChgAvgLow = abs(ChangeLow) + prev2; 

	VarSet( "RSIBarClose", 50 * (Nz(NetChgAvgClose / (TotChgAvgClose)) + 1) );
	VarSet( "RSIBarHigh", 50 * (Nz(NetChgAvgHigh / (TotChgAvgHigh)) + 1) );
	VarSet( "RSIBarLow", 50 * (Nz(NetChgAvgLow / (TotChgAvgLow)) + 1) );
}


length = Param("RSI Length",2,2,30,1);
RSIbarHLC( length );

//Plot( RSIBarClose, "RSI Bar Close", colorGold );
Plot( RSIBarHigh, "RSI Bar High", colorGreen, styleNoDraw );
Plot( RSIBarLow, "RSI Bar Low", colorRed, styleNoDraw );

PlotOHLC( Null, RSIBarHigh, RSIBarLow, RSI( length ), "RSI_HLC(" + length + ")", colorGrey40, styleBar );

In my test the results are the same ones....

7 Likes

Thanks @fxshrat . Great stuff. I thought we would be able to use arrays but could not figure it out. This now provides great example for both looping and arrays, and is something I will be able to refer back to.

I should also point out for those that do not realize it, the 2 methods will give slightly different answers early on, but they will eventually sync up. With a 2-period RSI it looked like it took about 13 bars to sync up. With a 14-period RSI, it is considerably longer (about 130 bars). That is the nature of an EMA. The starting point matters but the further you are from the starting point, the less it matters. And the longer the EMA you use, the longer it will take to sync up. The math is all correct. But if you are using this, you do want to be able to bring in more data than just the data you are evaluating. That way, you can be confident in the numbers.