Pulses used in PositionScore not working

I’m playing with rotational strategies. Right now I am using the S&P500 sector etfs such as XLY, XLF etc in my backtesting. i have the complete code at the bottom of this post.

I wanted to see how a rotational strategy would perform rotating sectors on a monthly basis, or an x * monthly basis. The problem is that I am unable to get a backtest result. I have isolated the problem to the folloiwng code:


    NumSymbols = CategoryCountSymbols( categoryWatchlist, SectorETFs );
    MaxNumberSymbols = Param( "Displayed Symbols", 5, 0, NumSymbols, 1 );
    freq = Param("Holding Period in Months", 3, 1,12, 1 ) * 22;
    lookback = Param("Momentum Lookback Period in Days", 5, 1, 20, 1 );    
    CountMonths = Cum(Month() != Ref(Month(), -1 ));
    //Plot(Cum(Month()),"counting months",colorOrange);
    nMonth = CountMonths % freq == 0; // % brings back the remainder of CountMonths/freq. If equal to zero, then that is the month to rotate sectors/stocks
    nMonthPulse = ExRem(nMonth, ! nMonth) ;

For some reason, the pulses generated from these lines do not work for PositionScore, even though I am able to plot the pulses. if I use the pulses from the following code, the backtester works fine:

UpCondST = MACD()>0;
UpPulseST = ExRem(UpCondST, ! UpCondST);

So, if I substitute nMonthPulse with UpPulse in the PositionScore function I get a backtest result. I’ve played around with the nMonthPulse code and it appears to be in the Cum() function. So, I am stumped to why pulses from nMonthPulse don’t work and they do with UpPulseST.

I used another way of achieving a somewhat monthly pulse by the following code:

pi = 3.1415926;
LPV[0]=-1; //initializing the first lunar phase value
LPV90 = 0;

MonthDays=30 * freq; // this is one complete 2 pi radian lunar phase cycle
//First New Moon: Jan 1 1900	7:52 AM. 7:52 AM is 0.3278 of a day.
TD = DaysSince1900(); // today's date as a serial number of days since first new moon. Jan 1 1900 is serial number 2, so I have to compensate for that.
                      // I also have to subtract 0.3278 from the day count to compensate for the 7:52 AM.
LPV = sin((TD-(2-0.3278))/MonthDays * 2 * pi); // Gives position in Lunar cycle for each day of data
LPV90 = cos((TD-(2-0.3278))/MonthDays * 2 * pi);

MoonSquare= LPV > 0;
MoonPulse = ExRem(MoonSquare, ! MoonSquare);

The pulses from this code work well also.

Any help to further my understanding will be greatly appreciated. Thank you!

I set the watchlist ( I used watchlist number 63) for the following symbols:
XLY, XLK, XLI, XLB, XLE, XLP, XLV, XLU, XLF, SPY

SetBarsRequired( sbrAll, sbrAll ); // Ensure that when I use the zoom feature on the charts
// that my indicators do not change.


// counting symbols in a watchlist
function CategoryCountSymbols( category, number )
{
    NumCommas = StrCount( list = CategoryGetSymbols( category, number ), "," );
    return IIf( list == "", 0, NumCommas + 1 );
}




SetForeign( "SPY" );

UpCondST = MACD()>0;
UpPulseST = ExRem(UpCondST, ! UpCondST);
DownCondST = ! UpCondST;
DownCondLT = MACD(12,50);

    Plot( UpCondST, "UpPulse", colorblue );

    SectorETFs = 63; // Associating the Watchlist Number to the Watchlist Name

    NumSymbols = CategoryCountSymbols( categoryWatchlist, SectorETFs );
    MaxNumberSymbols = Param( "Displayed Symbols", 5, 0, NumSymbols, 1 );
    freq = Param("Holding Period in Months", 3, 1,12, 1 ) * 22;
    lookback = Param("Momentum Lookback Period in Days", 5, 1, 20, 1 );    
    CountMonths = Cum(Month() != Ref(Month(), -1 ));
    //Plot(Cum(Month()),"counting months",colorOrange);
    nMonth = CountMonths % freq == 0; // % brings back the remainder of CountMonths/freq. If equal to zero, then that is the month to rotate sectors/stocks
    nMonthPulse = ExRem(nMonth, ! nMonth) ;

	RestorePriceArrays();
	


    SymbolList = CategoryGetSymbols( categorywatchlist, SectorETFs );

if( Status( "stocknum" ) == 0 )
{
    StaticVarRemove( "Performance*" );

    for( i = 1; ( CurrentSymbol = StrExtract( SymbolList, i - 1 ) ) != "SPY"; i++ )  // First symbol is at position zero in SymbolList
    {
        SetForeign( CurrentSymbol ); // Goes back to UpCondST to find out how many bars to Spy low from that date
        
        Performance =  C / Ref( C, -1 * lookback ) ; // The formula for momentum is actually C / Ref( C, -1 * lookback) -1. I removed the "-1" to keep the result a positive number and proportionate to the rank of each stock.
        //Performance =  Ref( C, -1 * lookback ) / C; // Inverse momentum. This puts the slowest momentum stock as the top rank.
        
        RestorePriceArrays();
        StaticVarSet( "Performance" + CurrentSymbol, Performance );

    }

}


Symbol = Name();

Performance = StaticVarGet( "Performance" + Symbol );

SetBacktestMode( backtestRotational );

SetOption( "MaxOpenPositions",  MaxNumberSymbols );
SetOption( "WorstRankHeld", MaxNumberSymbols );
PositionScore = IIf( DownCondLT AND DownCondST, scoreExitAll,
                           IIf( nMonthPulse, Performance, scoreNoRotate ) );
/*PositionScore = IIf( DownCondLT AND DownCondST, scoreExitAll,
                           IIf( UpPulseST, Performance, scoreNoRotate ) ); */  
                         
SetPositionSize( 100 / MaxNumberSymbols, spsPercentOfEquity );



Plot( nMonthPulse+1,"Month",colorGreen); 

It always helps when you are precise with your description.
You are sitting with your code for hours/days, but we do not.
I have read your post but really there is not a single sentence that explains what are you expecting and what are you getting instead.

“Not working” is generic and means nothing. You need to be clear and precise. What do you mean with “not working”. Are you getting NO trades at all, or trades in wrong days or… ?

Did you run exploration like explained here:
http://www.amibroker.com/kb/2014/09/29/debugging-techniques-part-1-exploration/

A very first thing you should do is to display those two variables:

nMonth = CountMonths % freq == 0; 
nMonthPulse = ExRem(nMonth, ! nMonth) ;

in the exploration

Sorry,

By not working I mean that I run the backtest and it doesn’t show any trading using the nMonthPulse. I.e. the starting capital doesn’t change. When I use the UpPulseST pulses from my MACD routine, the backtest gave results.

Hope that helps.

Did you run exploration comparing nMonthPulse with UpPulseST as I wrote in earlier reply?

I guess not.

If you actually run the exploration as I wrote before:

freq = Param("Holding Period in Months", 3, 1,12, 1 ) * 22;
CountMonths = Cum(Month() != Ref(Month(), -1 ));
//Plot(Cum(Month()),"counting months",colorOrange);
nMonth = CountMonths % freq == 0; // % brings back the remainder of CountMonths/freq.
nMonthPulse = ExRem(nMonth, ! nMonth) ;

AddColumn( CountMonths, "CountMonths");
AddColumn( nMonthPulse, "NmonthPulse", 1 );
Filter = 1;

you will notice that that your nMonthPulse is ZERO everywhere except for month 66.

Why?

Because your

CountMonths % freq 

is never equal to zero except for month 66.

Why is so? Because your freq variable is not equal to 3 as you think it is but 66, because you are multiplying the number of months from parameter by 22.

freq = Param("Holding Period in Months", 3, 1,12, 1 ) * 22; // surprise * 22 !!!

Later in the code you forget the fact that you multiplied it by 22 and you do modulo operation thinking that it is 3.

A classic example when using exploration and/or debugging by the user would quickly reveal the problem.

Bottom line: Use exploration and the debugger, all the time
http://www.amibroker.com/kb/2014/09/29/debugging-techniques-part-1-exploration/

Keep your code clean. Make sure to use meaningful names for variables so you know what they mean. Don’t use generic names like freq. Use meaningful names like RotationPeriodInMonths
and make sure that variable values actually represent what they are supposed to represent.

3 Likes