Appel NASDAQ Weekly Relative Strength Indicator (multi-time frame with foreign securities)

I am trying to mimic a version of the NASDAQ/NYSE relative strength indicator that Gerald Appel wrote about in Chapter 2 of his book, "Technical Analysis - Power Tools for Active Investors". I have used a version of this for a long time, with the difference being that I use the SPX instead of the NYSE composite index.

The idea behind the indicator is that when the NASDAQ is leading, that is a bullish state for the market.

To determine the lead/lag you simply take a ratio of the NADSAQ:SPX at the end of each week.Then starting in week 10, you calculate the 10-week moving average. If the current ratio is above the average, the NASDAQ is leading. If it is below the average, the NASDAQ is lagging the SPX.

I tried program it in AFL, and am struggling. I believe my issue is likely that I am not using the "timeframe" calcs properly. (I have not used them to this point.) Below is a screenshot of recent readings in an excel spreadsheet I use. Please note that the indicator should not "flip" during the week. If it is labeled "Lead" on Friday at the close, then it should stay that way until at least next Friday at the close (assuming you are looking at a daily or intraday exploration or chart).

2018-11-11

Here is my latest attempt at the code:


SPX = Foreign("$SPX","Close");
COMP = Foreign("$COMP","Close");

TimeFrameSet(inWeekly);
SPXW = SPX;
COMPW = COMP;
TimeFrameRestore();


SPXweekly = TimeFrameExpand(SPXW,inWeekly);
COMPweekly = TimeFrameExpand(COMPW,inWeekly);

Ratio = COMPweekly / SPXweekly;
AvgRatio = MA(Ratio,10);
COMPleading = AvgRatio > Ratio;


//Explore
Filter = 1;
AddColumn(close,"close",1.2);
AddColumn(SPX,"SPX",1.2);	
AddColumn(SPXW,"SPXW",1.2);	
AddColumn(SPXweekly,"SPX Weekly",1.2);
AddColumn(COMPleading,"AppelRS",1.0);

Here is what my explore results are:

2018-11-11-2

In this case SPX is the security I ran the exploration on, but I use $SPX as a foreign because I want to be able to refer to this indicator even if I am looking at MSFT or GOOG or $RUT or anything.

Thanks for any suggestions...

For starters, you need to use TimeFrameCompress() instead of TimeFrameSet(). The latter just works on the built-in arrays (OHLC, etc.).

Yes, that's it. No problem.

You have to insert Foreign function(s) into TimeFrameSet...TimeFrameRestore procedures to calculate on compressed interval. The same applies to the ratios since you want to get them from Weekly interval. COMPleading can be put afterwards since it is just comparing one with the other one.

Here is fix

sym1 = "$SPX";
sym2 = "$COMP";

SPX = Foreign(sym1,"Close");//selected interval's array
COMP = Foreign(sym2,"Close");//selected interval's array

TimeFrameSet(inWeekly);
	SPXW = Foreign(sym1,"Close");// compressed interval's array
	COMPW = Foreign(sym2 ,"Close");// compressed interval's array
	
	Ratio = COMPW / SPXW;
	AvgRatio = MA(Ratio,10);
TimeFrameRestore();

SPXweekly = TimeFrameExpand(SPXW,inWeekly);
COMPweekly = TimeFrameExpand(COMPW,inWeekly);
Ratio = TimeFrameExpand(Ratio,inWeekly);
AvgRatio = TimeFrameExpand(AvgRatio,inWeekly);

COMPleading = AvgRatio > Ratio;

//Explore
Filter = 1;
AddColumn(DayOfWeek(),"WKD",1.0);
AddColumn(close,"close",1.2);
AddColumn(SPX,"SPX",1.2);	
//AddColumn(SPXW,"SPXW",1.2);// Outputs interval compressed array	
AddColumn(SPXweekly,"SPX Weekly",1.2);
AddColumn(COMPweekly,"COMP Weekly",1.2);
AddColumn(Ratio,"Ratio",1.2);
AddColumn(AvgRatio,"AvgRatio",1.2);
AddColumn(COMPleading,"AppelRS",1.0);

What? Where you got that fairy tale from?
Of course TimeFrameSet works with Foreign/SetForeign too.
You just have to incorporate it correctly.

Also TimeFrameSet works with non array functions too.

selected_interval = Interval(2);

TimeFrameSet(inWeekly);
    compressed_interval = Interval(2);
TimeFrameRestore();

// No expanding of compressed_interval variable
// required since it is just string not array of numbers.

Filter = Status("LastBarInRange");

AddTextColumn(selected_interval ,"selected_interval",1.0);
AddTextColumn(compressed_interval ,"compressed_interval",1.0);

906

4 Likes

Thanks @mradtke and @fxshrat for your help. I have attempted to implement @fxshrat's code, but am still struggling the achieve my intended results. I'll try and explain below. First, I should note that I am running this using daily timeframe, but looking for SPX and COMP weekly readings (on Friday's close) for my calc, in case I had not made that clear before. (I think I did as it appeared @fxshrat was on same wavelength, but perhaps not.)

I left @fxshrat's code the same, except I added a little to the exploration. The new exploration code is here:

//Explore
Filter = 1;
AddColumn(DayOfWeek(),"WKD",1.0);
AddColumn(close,"close",1.2);
AddColumn(SPX,"SPX",1.2);	
AddColumn(COMP,"COMP");  //added new line
AddColumn(SPXW,"SPXW",1.2);// Outputs interval compressed array	- showed this one
AddColumn(SPXweekly,"SPX Weekly",1.2);
AddColumn(COMPweekly,"COMP Weekly",1.2);
AddColumn(Ratio,"Ratio",1.2);
AddColumn(AvgRatio,"AvgRatio",1.2);
AddColumn(COMPleading,"AppelRS",1.0);

Below are screenshots of my results with notes:
appExp1

Here is the same exploration from the top...in 1990...

appExp2

Easy to see here that SPX and COMP columns are correct, but SPX Weekly and COMP Weekly are off.

If I use $SPX as the security that I have set to "current" when I run the exploration, I get slightly different results as shown below:
appExp3

I thought I might upload an .apx file, in case I messed up something in settings, but the forum says that type of file is not authorized.

Appreciate any thoughts.

Yes, you have to apply a little bit of a trick here by using SetForeign instead of Foreign.
Here are two versions working for me.

/// @link https://forum.amibroker.com/t/appel-nasdaq-weekly-relative-strength-indicator-multi-time-frame-with-foreign-securities/9158/5
/// by fxshrat
/// version 1
sym1 = "^GSPC";
sym2 = "^IXIC";

SPX = Foreign(sym1,"C");//selected interval's array
COMP = Foreign(sym2,"C");//selected interval's array

SetForeign( sym1 );
TimeFrameSet(inWeekly);   
    SPXW = C;// compressed interval's array   
TimeFrameRestore();
SPXweekly = TimeFrameExpand(SPXW,inWeekly);

SetForeign( sym2 );
TimeFrameSet(inWeekly);
    COMPW = C;// compressed interval's array

    Ratio = COMPW / SPXW;// using compressed arrays
    AvgRatio = MA(Ratio,10);
TimeFrameRestore();   

COMPweekly = TimeFrameExpand(COMPW,inWeekly);
Ratio = TimeFrameExpand(Ratio,inWeekly);
AvgRatio = TimeFrameExpand(AvgRatio,inWeekly);

COMPleading = AvgRatio > Ratio;

//Explore
Filter = 1;
AddColumn(DayOfWeek(),"WKD",1.0);
AddColumn(close,"close",1.2);
AddColumn(SPX,"SPX",1.2);   
//AddColumn(SPXW,"SPXW",1.2);// Outputs interval compressed array   
AddColumn(SPXweekly,"SPX Weekly",1.2);
AddColumn(COMPweekly,"COMP Weekly",1.2);
AddColumn(Ratio,"Ratio",1.2);
AddColumn(AvgRatio,"AvgRatio",1.2);
AddColumn(COMPleading,"AppelRS",1.0);

This one does work for me too

/// @link https://forum.amibroker.com/t/appel-nasdaq-weekly-relative-strength-indicator-multi-time-frame-with-foreign-securities/9158/5
/// by fxshrat
/// Version 2
sym1 = "^GSPC";
sym2 = "^IXIC";

SPX = Foreign(sym1,"C");//selected interval's array
COMP = Foreign(sym2,"C");//selected interval's array

SetForeign( sym1 );
TimeFrameSet(inWeekly);   
    SPXW = C;// compressed interval's array   

SetForeign( sym2 );
TimeFrameSet(inWeekly);
    COMPW = C;// compressed interval's array
   
    Ratio = COMPW / SPXW;// using compressed arrays
    AvgRatio = MA(Ratio,10);
TimeFrameRestore();   

SPXweekly = TimeFrameExpand(SPXW,inWeekly);
COMPweekly = TimeFrameExpand(COMPW,inWeekly);
Ratio = TimeFrameExpand(Ratio,inWeekly);
AvgRatio = TimeFrameExpand(AvgRatio,inWeekly);

COMPleading = AvgRatio > Ratio;

//Explore
Filter = 1;
AddColumn(DayOfWeek(),"WKD",1.0);
AddColumn(close,"close",1.2);
AddColumn(SPX,"SPX",1.2);   
//AddColumn(SPXW,"SPXW",1.2);// Outputs interval compressed array   
AddColumn(SPXweekly,"SPX Weekly",1.2);
AddColumn(COMPweekly,"COMP Weekly",1.2);
AddColumn(Ratio,"Ratio",1.2);
AddColumn(AvgRatio,"AvgRatio",1.2);
AddColumn(COMPleading,"AppelRS",1.0);

509

3 Likes

@QEdges there is an alternative that I had coded a couple of years ago after reading your stuff,

A relevant read, http://www.amibroker.com/kb/2014/10/20/foreign-timeframeset/

// an important read on two alternate ways using Foreign vs SetForeign
///@link http://www.amibroker.com/kb/2014/10/20/foreign-timeframeset/

SP500 = Foreign( "$SPX", "C" ); 
Nasdaq = Foreign( "$COMP", "C" );

SP500weeklyC = TimeFrameCompress( SP500, inWeekly );
NasdaqweeklyC = TimeFrameCompress( Nasdaq, inWeekly );

Ratio = NasdaqweeklyC / SP500weeklyC;
Ratio10 = MA( Ratio, 10 );

RatioExpanded = TimeFrameExpand( Ratio, inWeekly ); 
Ratio10Expanded = TimeFrameExpand( Ratio10, inWeekly ); 

////////////////////////
// Exploration
////////////////////////
dow = DayOfWeek();
FirstDayofWeek = dow < Ref( dow, -1 );// Start Of Week
color = IIf( FirstDayofWeek , colorLightBlue , colorDefault );

Filter = True;
AddColumn( DayOfWeek(), "WKD", 1.0, colorDefault, color );
AddColumn(C, "Current Symbol");
AddColumn(SP500, "SP500 daily C");
AddColumn(Nasdaq, "NDX daily C");
AddColumn(TimeFrameExpand(SP500weeklyC, inWeekly), "SP500 weekly C");
AddColumn(TimeFrameExpand(NasdaqweeklyC, inWeekly), "Nasdaq weekly C");
AddColumn(RatioExpanded, "Ratio Expanded", 1.4 );
AddColumn( Ratio10Expanded, "Ratio10 Expanded", 1.4 );

image

4 Likes

Thanks @fxshrat ! I have been toying with version1 above and it appears to work great.

Though after getting it to work I noted that I made one little error initially.
COMPleading should be Ratio > AvgRatio, and I had it reversed. So I made that change and have pasted it with your code below for people that wish to use it...

/// @link https://forum.amibroker.com/t/appel-nasdaq-weekly-relative-strength-indicator-multi-time-frame-with-foreign-securities/9158/5
/// by fxshrat
/// version 1
sym1 = "$SPX";
sym2 = "$COMP";

SPX = Foreign(sym1,"C");//selected interval's array
COMP = Foreign(sym2,"C");//selected interval's array

SetForeign( sym1 );
TimeFrameSet(inWeekly);   
    SPXW = C;// compressed interval's array   
TimeFrameRestore();
SPXweekly = TimeFrameExpand(SPXW,inWeekly);

SetForeign( sym2 );
TimeFrameSet(inWeekly);
    COMPW = C;// compressed interval's array

    Ratio = COMPW / SPXW;// using compressed arrays
    AvgRatio = MA(Ratio,10);
TimeFrameRestore();   

COMPweekly = TimeFrameExpand(COMPW,inWeekly);
Ratio = TimeFrameExpand(Ratio,inWeekly);
AvgRatio = TimeFrameExpand(AvgRatio,inWeekly);

COMPleading = Ratio > AvgRatio;  //Ratio needs to be above Avg Ratio

//Explore
Filter = 1;
AddColumn(DayOfWeek(),"WKD",1.0);
AddColumn(close,"close",1.2);
AddColumn(SPX,"SPX",1.2);   
AddColumn(COMP,"COMP");
//AddColumn(SPXW,"SPXW",1.2);// Outputs interval compressed array	
AddColumn(SPXweekly,"SPX Weekly",1.2);
AddColumn(COMPweekly,"COMP Weekly",1.2);
AddColumn(Ratio,"Ratio",1.6);
AddColumn(AvgRatio,"AvgRatio",1.6);
AddColumn(COMPleading,"AppelRS",1.0);

Thanks again!

Thanks @portfoliobuilder ! I wish I had spotted that link you shared yesterday. It appears you are using TimeFrameCompress as @mradtke suggested earlier (but I failed to implement properly in my own attempts).

Good to know there are a few ways to achieve this. Thanks for all the help.

The reason for using SetForeign with TimeFrameSet is that foreign symbol has to be placed before switching/compressing to different interval. So it got nothing to do with built-in arrays since Foreign() calls inbuilt OHLCVOI, Aux1, Aux2 arrays too (just the ones of other symbol). It is just the order of code position being important. Foreign() sets to different symbol, calls array and restores to original symbol array within single function. That's why you can not put it before TimeFrameSet (which requires price/volume arrays to be set after its call). So kind of chicken/egg "what first" problem. So you have to use SetForeign instead. First SetForeign, then TimeFrameSet, ...., restoring both (timeframe and symbol) via TimeFrameRestore() or RestorePriceArrays().That's the whole mystery (if there are errors in upper text then feel free to correct).

I prefer TimeFrameSet as it provides more flexibility and better readable code and if you want to add more foreign price/volume arrays then one call of SetForeign & TimeFrameSet is faster than using multiple Foreign and TimeFrameCompress calls per symbol.

3 Likes