How to calculate the exact number of stocks above & below a MA

Dear Group,

I am crating a composite to check number of stocks in a watchlist "NIFTY 500" which are above and below their 50 DMA. Possibility of C=MA50 is pretty remote. The afl is as follows:

_SECTION_BEGIN("Advance Decline Line 500");

MA20 = EMA(C,20);
MA50 = EMA(C,50);
MA100 = EMA(C,100);
MA200 = EMA(C,200);

if( InWatchListName("NSE - NIFTY 500") AND Name()!="NIFTY 500" ) AddToComposite(C>MA50,"~NSE - NIFTY 500 Above MA50","X",flags = atcFlagDefaults); 
if( InWatchListName("NSE - NIFTY 500") AND Name()!="NIFTY 500" ) AddToComposite(C<MA50,"~NSE - NIFTY 500 Below MA50","X",flags = atcFlagDefaults);
//if( InWatchListName("NSE - NIFTY 500") AND Name()!="NIFTY 500" ) AddToComposite(C=MA50,"~NSE - NIFTY 500 At MA50","X",flags = atcFlagDefaults);

ScripF1="~NSE - NIFTY 500 Above MA50";
ScripF2="~NSE - NIFTY 500 Below MA50";
//ScripF3="~NSE - NIFTY 500 At MA50";

 
CloseF1=Foreign(ScripF1,"Close");
CloseF2=Foreign(ScripF2,"Close");
//CloseF3=Foreign(ScripF3,"Close");
CloseTotal = CloseF1 + CloseF2;
//CloseTotal = CloseF1 + CloseF2 +CloseF3;

_N(Title = StrFormat("{{NAME}} - {{INTERVAL}} {{DATE}} Open %g, Hi %g, Lo %g, Close %g (%.1f%%) {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 ) ) ));


Graph0=Plot(CloseF1, "Adv Line", colorGreen, styleThick);

Graph1=Plot(CloseF2, "Dec Line", colorRed, styleThick);

Graph2=Plot(CloseTotal, "Adv-Dec Line", colorBlack, styleDots);

//Graph3=Plot(C,"Close",colorBlack,styleCandle);

Filter=1;


AddColumn(CloseF1,"Above50MA",1.0);
AddColumn(CloseF2,"Below50MA",1.0);
AddColumn(CloseTotal,"Total",1.0);

_SECTION_END();

Issue is the Total Number of stocks (CloseTotal = CloseF1 + CloseF2) seems to be varying with dates. The sample of Watchlist is list of Top 500 stocks in Indian Equities and therefore possibility of new listings within the space is that much difficult.
So there seems to be something wrong out there. Whether it has to do with the flags, am bit perplexed

FWIW, you do not need ATC (AddToComposite) but can use StaticVarAdd() function.
Also since you have multiple MA in your code you can save multiple composites at same time.

And BTW, you just need to create single composite per MA for either above OR below.
E.g. the ones that are below MA can be calculated by num_below = num_all - num_above; where num_above is the data of composite and num_all being number of symbols in watchlist. So just one composite required per MA.


Anyway as for multiple composites via StaticVarAdd() see here:


As for changing index memberships and historical plot...You would need vendor providing historical membership array flag (or doing yourself -> more work).

So then you could use

above = C > MA200 AND is_index_member;


Don't do that. Graph* is legacy.

Simply write

Plot(CloseF1, "Adv Line", colorGreen, styleThick);

Plot(CloseF2, "Dec Line", colorRed, styleThick);

Plot(CloseTotal, "Adv-Dec Line", colorBlack, styleDots);

Thanks a lot @fxshrat for the guidance. However the total number of symbols don't seem to match as I go into older dates. The difference is more pronounced when I am utilising the longer term average (200 DMA).

I bifurcated the code in two parts for cross check. Code 1 is for stocks above the MA

/// Set symbol list in Analysis Filter - Include
/// And enable pad&align
/// Set Periodicity in analysis General settings
/// Create composite ARRAY via SCAN 
/// @link https://forum.amibroker.com/t/percentage-stock-price-nyse-above-the-200-day-moving-average/19377/8
/// by AmiBroker.com and fxshrat@gmail.com
list_name = CategoryGetName(categoryGroup, 5);
symbol_name = "~AboveMA_"+list_name;
cnt = "~cnt_"+list_name;
periods = MxFromString("[50;200]");// MA periods
rows = MxGetSize(periods, 0);
persist = False;
if ( Status( "action" ) == actionScan ) 
{
    /// derived from AB manual
    /// @link https://www.amibroker.com/guide/afl/staticvaradd.html
    if ( Status( "stocknum" ) == 0 ) 
    {
        // remove any earier composite values
        StaticVarRemove(symbol_name+"*");
        StaticVarRemove(cnt);
    }   
    // Iterating periods
    for ( i = 0; i < rows; i++ ) 
		StaticVarAdd(symbol_name+"_"+ i, C >= MA(C, periods[i][0]), True, persist);
		StaticVarAdd(cnt, 1, True, persist);
    Buy = 0;
}

colors = "colorBlue,colorRed";
// Iterating periods
for ( i = 0; i < rows; i++ ) 
{
	Stocks_aboveMA = Nz(StaticVarGet(symbol_name+"_"+i));
	pcnt_aboveMA = Nz(StaticVarGet(symbol_name+"_"+i) / StaticVarGet(cnt))*100;
	titles = StrFormat("Percentage > %g-day MA", periods[i][0]);
	Plot(pcnt_aboveMA, titles, VarGet(StrExtract(colors,i)), styleThick);
	Filter = 1;
	AddColumn(Stocks_aboveMA,"Count+"+periods[i][0],1.0);
	AddColumn(pcnt_aboveMA,"Percent"+periods[i][0],1.2);
}

The second code I modified for stocks below the MA

/// Set symbol list in Analysis Filter - Include
/// And enable pad&align
/// Set Periodicity in analysis General settings
/// Create composite ARRAY via SCAN 
/// @link https://forum.amibroker.com/t/percentage-stock-price-nyse-Below-the-200-day-moving-average/19377/8
/// by AmiBroker.com and fxshrat@gmail.com
list_name = CategoryGetName(categoryGroup, 5);
symbol_name = "~BelowMA_"+list_name;
cnt = "~cnt_"+list_name;
periods = MxFromString("[50;200]");// MA periods
rows = MxGetSize(periods, 0);
persist = False;
if ( Status( "action" ) == actionScan ) 
{
    /// derived from AB manual
    /// @link https://www.amibroker.com/guide/afl/staticvaradd.html
    if ( Status( "stocknum" ) == 0 ) 
    {
        // remove any earier composite values
        StaticVarRemove(symbol_name+"*");
        StaticVarRemove(cnt);
    }   
    // Iterating periods
    for ( i = 0; i < rows; i++ ) 
		StaticVarAdd(symbol_name+"_"+ i, C <= MA(C, periods[i][0]), True, persist);
		StaticVarAdd(cnt, 1, True, persist);
    Buy = 0;
}

colors = "colorBlue,colorRed";
// Iterating periods
for ( i = 0; i < rows; i++ ) 
{
	Stocks_BelowMA = Nz(StaticVarGet(symbol_name+"_"+i));
	pcnt_BelowMA = Nz(StaticVarGet(symbol_name+"_"+i) / StaticVarGet(cnt))*100;
	titles = StrFormat("Percentage > %g-day MA", periods[i][0]);
	Plot(pcnt_BelowMA, titles, VarGet(StrExtract(colors,i)), styleThick);
	Filter = 1;
	AddColumn(Stocks_BelowMA,"Count-"+periods[i][0],1.0);
	AddColumn(pcnt_BelowMA,"Percent"+periods[i][0],1.2);
}

Then I took the output in exploration. While the difference is not big in latest quotes, It's substantial in older quotes
Flaw 50-200 2

I am missing something there as same issue had arisen in the AddToComposite quotes.

However the total number of symbols don't seem to match as I go into older dates.

Have you enabled "Pad&align" as instructed in the code?

Yes I have
Flaw 50-200 2

Some of your symbols simply have SHORT history.

1 Like

@Tomasz indeed there is a SHORT history. The constituents are changed semi annual and almost 5% cases are those wherein such issue of SHORT history is there.

Will like to have suggestions on SCAN specifications. I was running it on 'All Quotes' by default. As a change do I run it on say "75 bars" (approx 3 months). Would this save the earlier values as indicator?

While I am toggling between indices, I am seeing the variations. So would 'AddToComposite' be better bet in terms of saving the historical values, while running it on 75 bars?

1 Like

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

Stocks above MA

Refering to above, the PLOT is working proper on Daily Time Scale

However when put on weekly scale it's getting distorted

Clearly the "Y-axis" scale is incorrect. Check your data in the period of August 2019 till July 2020.

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?

@Tomasz appologies for the delayed response. But still a bit confused on the flow of things.

Did some explorations on the longer time frame (Some 5000 bars) on 2 different dates. Like you mentioned the number of stocks below a moving average when turned 0, the percentage turned negative (Which is a bit confusing on 2 counts, case 1 - that how can ALL stocks in a portfolio of 500 stocks go below 200 DMA & 50 DMA., case 2 - Percentage is negative: Screenshot attached)

In fact the sudden FALL from 200 count of 173 is surprising.

Will have to modify the code, so stuck up on this

_SECTION_BEGIN("Moving Average 20-50-200 Counter");

// Dynamic watchlist display name retrieval
currentWatchlistIndex = GetOption("FilterIncludeWatchlist");
display_name = CategoryGetName(categoryWatchlist, currentWatchlistIndex);

// Variables Initialization
list_name = CategoryGetName(categoryGroup, 5);
symbol_name = "~AboveMA_" + list_name;
cnt = "~cnt_" + list_name;
periods = MxFromString("[20;50;200]"); // MA periods
rows = MxGetSize(periods, 0);
persist = False;

// Scan action
if (Status("action") == actionScan) {
    if (Status("stocknum") == 0) {
        StaticVarRemove(symbol_name + "*");
        StaticVarRemove(cnt + "*");
    }

    for (i = 0; i < rows; i++) {
        maPeriod = periods[i][0];
        maCountVar = cnt + "_" + maPeriod;
        maSymbolVar = symbol_name + "_" + i;

        // Initialize count variables for each MA period
        StaticVarSet(maCountVar, 0, persist);
        StaticVarSet(maSymbolVar, 0, persist);
        
        // Check if there's enough data to calculate the MA
        if (BarCount >= maPeriod) {
            StaticVarAdd(maSymbolVar, C >= MA(C, maPeriod), True, persist);
            StaticVarAdd(maCountVar, 1, True, persist);
        }
    }
}

// Display Columns and Plotting
for (i = 0; i < rows; i++) {
    maPeriod = periods[i][0];
    maCountVar = cnt + "_" + maPeriod;
    maSymbolVar = symbol_name + "_" + i;
    
    // Get the count of stocks with sufficient data for MA calculation
    maCount = Nz(StaticVarGet(maCountVar));
    
    // Get the count of stocks above MA
    Stocks_aboveMA = Nz(StaticVarGet(maSymbolVar));

    // Calculate percentage above MA using IIf with additional check to avoid division by zero
    pcnt_aboveMA = IIf(maCount > 0, (Stocks_aboveMA / maCount) * 100, 0);

    // Plotting and Adding columns
    title = StrFormat("%% > %g-day MA (%s)", maPeriod, display_name);
    color = ColorHSB( ( i * 64 ) % 255, 240, 240 );
    Plot(pcnt_aboveMA, title, color, styleThick);
    AddColumn(Stocks_aboveMA, "Count+" + NumToStr(maPeriod), 1.0);
    AddColumn(pcnt_aboveMA, "Percent" + NumToStr(maPeriod), 1.2);
}

// Plot reference lines
Plot(10, "10%", colorBlack, styleLine | styleNoTitle);
Plot(30, "30%", colorBlue, styleLine | styleNoTitle | styleDashed);
Plot(50, "50%", colorBlack, styleLine | styleNoTitle);
Plot(70, "70%", colorBlue, styleLine | styleNoTitle | styleDashed);
Plot(90, "90%", colorBlack, styleLine | styleNoTitle);

// Sorting
SetSortColumns(-2);

_SECTION_END();

Tried out some PUSH THROUGH, but unfortunately, the plot seems pretty skewed once before 2019