Happy new year. This post will be a quick one covering the relationship between the simple moving average and time series momentum. The implication is that one can potentially derive better time series momentum indicators than the classical one applied in so many papers.
Okay, so the main idea for this post is quite simple:
I’m sure we’re all familiar with classical momentum. That is, the price now compared to the price however long ago (3 months, 10 months, 12 months, etc.). E.G. P(now) – P(10)
And I’m sure everyone is familiar with the simple moving average indicator, as well. E.G. SMA(10).
Well, as it turns out, these two quantities are actually related.
It turns out, if instead of expressing momentum as the difference of two numbers, it is expressed as the sum of returns, it can be written (for a 10 month momentum) as:
MOM_10 = return of this month + return of last month + return of 2 months ago + … + return of 9 months ago, for a total of 10 months in our little example.
This can be written as MOM_10 = (P(0) – P(1)) + (P(1) – P(2)) + … + (P(9) – P(10)). (Each difference within parentheses denotes one month’s worth of returns.)
Which can then be rewritten by associative arithmetic as: (P(0) + P(1) + … + P(9)) – (P(1) + P(2) + … + P(10)).
In other words, momentum — aka the difference between two prices, can be rewritten as the difference between two cumulative sums of prices. And what is a simple moving average? Simply a cumulative sum of prices divided by however many prices summed over.
Here’s some R code to demonstrate.
require(quantmod) require(TTR) require(PerformanceAnalytics) getSymbols('SPY', from = '1990-01-01') monthlySPY <- Ad(SPY)[endpoints(SPY, on = 'months')] monthlySPYrets <- Return.calculate(monthlySPY) #dividing by 10 since that's the moving average period for comparison signalTSMOM <- (monthlySPY - lag(monthlySPY, 10))/10 signalDiffMA <- diff(SMA(monthlySPY, 10)) # rounding just sum(round(signalTSMOM, 3)==round(signalDiffMA, 3), na.rm=TRUE)
With the resulting number of times these two signals are equal:
In short, every time.
Now, what exactly is the punchline of this little example? Here’s the punchline:
The simple moving average is…fairly simplistic as far as filters go. It works as a pedagogical example, but it has some well known weaknesses regarding lag, windowing effects, and so on.
Here’s a toy example how one can get a different momentum signal by changing the filter.
toyStrat <- monthlySPYrets * lag(signalTSMOM > 0) emaSignal <- diff(EMA(monthlySPY, 10)) emaStrat <- monthlySPYrets * lag(emaSignal > 0) comparison <- cbind(toyStrat, emaStrat) colnames(comparison) <- c("DiffSMA10", "DiffEMA10") charts.PerformanceSummary(comparison) table.AnnualizedReturns(comparison)
With the following results:
DiffSMA10 DiffEMA10 Annualized Return 0.1051 0.0937 Annualized Std Dev 0.1086 0.1076 Annualized Sharpe (Rf=0%) 0.9680 0.8706
While the difference of EMA10 strategy didn’t do better than the difference of SMA10 (aka standard 10-month momentum), that’s not the point. The point is that the momentum signal is derived from a simple moving average filter, and that by using a different filter, one can still use a momentum type of strategy.
Or, put differently, the main/general takeaway here is that momentum is the slope of a filter, and one can compute momentum in an infinite number of ways depending on the filter used, and can come up with a myriad of different momentum strategies.
Thanks for reading.
NOTE: I am currently contracting in Chicago, and am always open to networking. Contact me at my email at firstname.lastname@example.org or find me on my LinkedIn here.
Thanks for the nice post. It is very important to point out this analogy. Levin and Pedersen have also done that in “Which trend is your friend?” here: http://papers.ssrn.com/sol3/papers.cfm?abstract_id=2603731
I’ve seen that paper, and might explore it in the future more.
I don’t understand what lag() is doing in your second code snippet, can you explain? Thanks!
Removing lookahead bias.
Pingback: Quantocracy's Daily Wrap for 01/13/2016 | Quantocracy
Pingback: Best Links of the Week | Quantocracy
Hi. I also complained to Quantocracy curator for plummeting quality of quant articles. I expect more from you guys. If you have nothing new to add maybe it is better not posting these trivialities.
Judging by the upvotes on quantocracy, a lot of people found it helpful.
I enjoyed this article , I’ve got a basic question to ask if that’s OK. I didn’t find anything related on my searches.
What do you mean by “windowing effects” , I’m assuming this is related to the look back period of the indicator, but i was not aware of any issues relating to it ?
Thanks for your time!
Basically that because you don’t have an infinite memory process, that you just suddenly drop data.