Momentum Factor Back Test

I would appreciate anyone’s scripting help for the following strategy:

  • Universe: 25 ETFs (broadly diversified)
  • Ranked by "Momentum Score" based on monthly performance. Momentum Score = (1Mo% + 3Mo% + 6Mo% +12Mo%) / 4
  • Buy (on 1st of month based on prior month's closing data): Top 8 ranking securities based on "Momentum Score" AND have a monthly close > MA10
  • Sell: Securities that fall out of top 8 rank in "Momentum Score" OR have a monthly close < MA10
Initially, the first 8 purchases would be equal weight. After launch, proceeds of securities sold would be distributed equally into new eligible buys. If less than 8 securities are eligible, the remaining "buy" securities would be rebalanced to equal weight.

I’ve attached a workbook of my initial universe and the Momentum Score discussed above. I also included the excel file of my security universe in the event the workbook doesn’t open correctly.

Lastly, I’m open to suggestions if there’s anything regarding this strategy that I’m clearly not considering. All ears on my end.


BCPMo.owb (44.4 KB)

BCP-Mo.xlsx (8.82 KB)

Thanks Dan - you can use a backtest set to Rebalance using your MOM Score formula, and CLOSE()>MA(BARS=10, CALC=Close) as the filter (note: if you run the test on a monthly timeframe and you won’t have to specify the timeframe in the formula).

See here for more details on running a rebalancing test:

The only issue is that the rebalancing occurs if they fall out of the top 8 at the end of the next month - we can’t include ‘or close < 10MA.’

Here’s how the setup should look to rebalance monthly with 12.5% per trade (Equity Percentage for Position Sizing), and max 8 positions. Codes to Test is your ETF list saved as a Symbol List.


Thanks, Darren. This was a helpful start. However, the back test still has me going to cash periodically. I was hoping to design a strategy that was always fully invested in the top 8 screeners from my ETF universe. I’ve attached screenshots of my setup and results. ResultsSetup

Hi Daniel,

I think there’s a conflict between monthly data and monthly rebalancing, so change the Data Timeframe to 1 Day and it should work as expected.

If you wanted to add the filter you would use CLOSE()>MA(Month(PERIODAMOUNT=1), BARS=10, CALC=Close), and then you may see cash positions if that condition hasn’t been met by at least 8 of the ETFs (ie if only 6 are trading above their 10 month MA then 25% will be in cash).

Thanks, Darren! Do you know why the “Ending Balance” of $1,507,009 in the results below is different than the ending value of $1,163,748 on the Equity Curve?


I think it’s the Date Range ending on the rebalance date - we’ll have to take a look at that. In the meantime, if you change the end date to 4/1/20 then they will match.