There is a very large body of academic support for the momentum effect in stock prices. Multitude of papers support in one way or another the presence of this effect that basically says that the price of an asset will continue moving in a given direction for a certain time interval. Of these momentum supporting papers, this paper by Lo and MacKinlay set an strong support with the following conclusion:
"We have rejected the random walk hypothesis for weekly stock market returns by using a simple volatility-based specification test. These rejections cannot be explained completely by infrequent trading or time-varying volatilities. "
The wording of this conclusion, or similar conclusions, appears repeatedly in finance literature and is of the maximum importance on the predictability of the market:
"The results documented here reliably reject the hypothesis that the stocks prices follow random walks." From this paper.
"The random walk hypothesis for daily returns is rejected for Indian market by using the Q statistic." From here.
"Applying the Zivot–Andrews test to stock prices of seventeen emerging markets, we reach several interesting conclusions. The gain in test power allows us to reject the random walk hypothesis at the 1% or 5% significance level in ten markets." From here.
The controversy is ongoing in any case as we can find as many publications that say that the prices follow a random walk:
"In this paper, it has been established that the JSE stock prices are uncorrelated and therefore follow a random walk. This finding has major implications to investors, policymakers, and researchers which means, inter alia, that the inability to predict future stock prices implies that investors cannot beat the market trading rules. " From this very recent research paper.
"KSE-100 Index follows the Random Walk Hypothesis (RWH) and Efficient Market Hypothesis (EMH) according to the results of the tests used." From this other paper.
Controversy regarding this random walk on Wall Street is served, was served as early as 1973, alive and generating confusion in market operators and regulators. In order to profit by trading, in order to maintain a balanced portfolio of assets, in order to operate under healthy markets that ultimately allocate more resources to better outcomes determining if the pricing of assets follows this random walk or not is of the utmost importance, as it will guide the quantitative approaches that may offer the best results.
We will not venture a position in the camp of random walk or in the camp of predictable components, we do not dare. We will only try to make a small profit using the rejection of the random walk hypothesis and checking for the presence of, in this publication, momentum effects, as it surprises us that with the recent increase of availability of market data, computational power and general interest in the topic confusion seems to be increasing and not decreasing. And we suspect it may not be resolved in the near or far future.
We will use some of the information in this paper: "Fact, Fiction and Momentum Investing", in which the UMD (Up Minus Down) momentum strategy is described in its most simple form: we will enter long positions in past good performers and short positions in past bad performers. Initially, following the first model that we find in this paper, we are going to look back at the 1-month returns and hold the position for a month. We will hold 15 stocks in each direction to obtain a minimum of market risk diversification and we will do it twice, for large capitalization stocks only first and for small capitalization stocks only second. We will start January 1st 2012 and finish September 2020. This is how these strategies looked like in the past years, large cap stocks:
Small cap stocks:
The same strategy for two different cross sections yields completely different results. The small capitalization stocks belong to the bottom capitalization in the top 2000 stocks trading in NYSE and NASDAQ. These 8 year backtests indicate two things of which we can be certain:
Momentum trading did not behave equally for both small caps and large caps.
Momentum trading alone was not a good strategy in any of the cases.
So, selecting stocks for the next month solely based in their previous month performance may not be the best of strategies, even if the long to short ratio of the strategy was 1 most of the market risk is apparently still present.
Being in this period momentum chasing such a poor performer for small caps, what about its evil (or good) twin? Reversal trading. What if we take the same model we have used for the small caps but instead of buying winners and selling losers we do the opposite? This is what we get for this model:
In this period, the reversal effect for small capitalization stocks seems to be stronger than momentum in terms of profitability, even if it still does not destroy our equity in the 8 year period, most of the returns are concentrated in the recovery phase of the February-March 2020 COVID19 sharp drops and "sharpish" recoveries, so this effect could also be not good enough to build a complete strategy on. Is there, or are there, other uncomplicated angles from which we can attack the momentum baselines? As our long/short strategies seem no to be protecting us properly from the hazards of the market let's see what happens if we can take the simple road of chasing a long only reversal for these small cap stocks:
Still not universally good. 2012 to 2014 was a good period, it is a 100% gain period, reversal works!, as is the beginning of 2020, but if there is no other signal telling us what is the general behaviour of the market, momentum chasing or reverting strategies are doomed to fail in the longer run. It may seem that the movements of the market are indeed random when in fact what we are missing is the capability to identify what "type" of randomness is operating in a given market period. It is clear from the back tests above that long streaks of winning and losing months are not only attributable to luck, there is apparently something attracting or repelling stocks in other "unseen" states of the market, this states cannot be apparently perceived by price actions alone. Momentum is apparently at play, but not all the time, and not pushing you in the same direction, other sources or data are needed to construct market beating strategies for sure.
Remember that our publications are not financial advice. Ostirion.net does not hold any positions on any of the mentioned instruments at the time of publication. If you need further information, asset management support, automated trading strategy development or tactical strategy deployment you can contact us here.
Here is the code for these momentum/reversal trials:
And this snippet is the universe selection by market capitalization and traded volume:
from QuantConnect.Data.UniverseSelection import *
from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel
Universe model that selects stocks by capitalization. It performs an initial
selection by traded volume to improve algorithm speed.
def __init__(self, filterFineData=True, universeSettings=None, securityInitializer=None):
Initializes a new default instance of the Capitalization Universe Model.
super().__init__(filterFineData, universeSettings, securityInitializer)
self.numberOfSymbolsCoarse = 2000
self.num_symbols = 50
self.price_limit = 1
self.last_month = -1 # Start first period
self.is_take_top = True
def SelectCoarse(self, algorithm, coarse):
Drop securities which have no fundamental data or have too low prices.
Select those by dollar volume ordered accorsing to self.is_take_top.
if algorithm.Time.month == self.last_month:
self.last_month = algorithm.Time.month
selected = sorted([x for x in coarse if x.HasFundamentalData and x.Price > self.price_limit],
key=lambda x: x.DollarVolume, reverse=self.is_take_top)
return [x.Symbol for x in selected[:self.numberOfSymbolsCoarse]]
def SelectFine(self, algorithm, fine):
''' Selects the stocks by market cap '''
sorted_market_cap = sorted([x for x in fine if x.MarketCap > 0],
key=lambda x: x.MarketCap, reverse=self.is_take_top)
return [x.Symbol for x in sorted_market_cap[:self.num_symbols]]