Back to Community
The Next Quantopian-Based Paper on Uncovering Momentum

This post features the next Quantopian-based research presented in the paper “Uncovering Momentum” (http://ssrn.com/abstract=3502301) that extends the previous “Momentum with Volatility Timing” study with a top-bottom analysis of the strategy. In summary, below are the four outcomes outlined in the Conclusion section:

  1. The heterogeneous momentum behavior across market states and deciles portfolios suggests that each case can be associated with different processes and hence requires independent evaluation. The winners performance during the bull market state represents the most unblemished case for explaining the momentum effect.
  2. Detaching the volatility scaling component from the time series momentum portfolio identifies the momentum decile as a basic common block across conventional, time-series, and dual momentum strategies.
  3. Combining the in- and out-of-sample momentum decile analysis highlights the difference in performance levels between the two intervals and prompts a more asymmetrical version of the momentum definition like "achievement award for lucky winners". The small price of this award does not represent a challenge for the Efficient Market Hypothesis and defines a criterion for assessing the underlying momentum theories and models.
  4. The paper proposes to extend the scope of cross-section return studies with the analysis of temporal patterns by applying time series clustering.

This notebook is related to Section IV focusing on time series clustering of the in- and out-of-sample dataset. The figure below shows the means and standard deviations of in/out-of-sample monthly stock time series clustered within the ranking period.

Loading notebook preview...
20 responses

Yulia, very nice paper. A lot of references in the paper made me fit the advances in momentum in somewhat of a 3d space and see the progression relative to each other. I have been working with momentum in one form or another over the years and especially the TSFM moskowitz 2012 implementation that I tried to recreate last year. Breezed through the paper yesterday and will go over it in great detail after the holidays. Very well done. Congrats.

Leo,

Glad to hear you liked reading it. Yes, the paper aims to connect momentum studies across four topics
and hence there are quite a few citations. Best regards, Yulia

@Yulia,

I’ve only read the abstract so far but I look forward to reading the paper and going through the notebook. Thank you for sharing your work here!

Yulia will be hosting a live webinar based on her "Uncovering Momentum" paper this Thursday, January 30th at 11 am EST. You'll be able to view the webinar and participate in the live chat at this link, or watch just the webinar right here:

Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

Just a reminder that our live webinar for Yulia's second Quantopian-based paper, "Uncovering Momentum", is tomorrow, Thursday, January 30th at 11 am EST! It can be watched at this link, or in the player embedded in the comment above.

Hows the performance look like under Q?

Thank you everyone for joining the webinar.

Leo, Optimal. As you can see from the attached notebook, the pipeline execution time for the QTradableStocksUS universe from 07/01/04 to 09/30/19 takes around 39 seconds.

Best regards, Yulia

Good morning,

Continuing on uncovering the momentum effect via Fundamentals, intermediate results highlight the on-going broken behavior of the value factor (e.g., documented here and here). While explanation of this phenomenon is a separate topic, this post shares the significant backtest performance of growth stocks that is even much better than the quality factors investigated in the post “New Strategy - Presenting the Quality Companies in an Uptrend Model”.

As the value factor gets hot, eager to see its behavior in the next bull market.

Best regards, Yulia

Clone Algorithm
163
Loading...
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# import the base algo class. Not entirely needed but a good practice
import quantopian.algorithm as algo

# import things need to run pipeline
from quantopian.pipeline import Pipeline

# import any built-in factors and filters being used
from quantopian.pipeline.filters import QTradableStocksUS
from quantopian.pipeline.factors import SimpleMovingAverage as SMA
from quantopian.pipeline.factors import CustomFactor, Returns

# import any needed datasets
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.data.morningstar import Fundamentals as ms

# import optimize for trade execution
import quantopian.optimize as opt
 
import numpy as np 
import pandas as pd

# Set to False for the Smart Beta Factors challenge
mom_on = True

mom_t1 = 126
mom_t2 = 2

class Momentum(CustomFactor):    
    inputs = [USEquityPricing.close]  
    window_length = mom_t1
    def compute(self, today, assets, out, prices):  
        out[:] = (prices[-mom_t2] - prices[-mom_t1])/prices[-mom_t1] 

def initialize(context):
  
    # Set target number of securities to hold    
    if mom_on is True:
        context.target_stocks = 20
    else:
        context.target_stocks = 250
        context.new_stocks = 5

    # Normally a contest algo uses the default commission and slippage
    # This is unique and only required for this 'mini-contest'
    set_commission(commission.PerShare(cost=0.000, min_trade_cost=0))
    set_slippage(slippage.FixedSlippage(spread = 0.0))
    
    # Create and attach pipeline for fetching all data
    algo.attach_pipeline(make_pipeline(context), 'pipeline')    
    
    # Schedule functions
    schedule_function(
        rebalance, 
        date_rules.month_end(days_offset=6), 
        time_rules.market_close(minutes=30)
    )
    
def make_pipeline(context):
    
    universe = QTradableStocksUS()
    
    if mom_on is True:
        mom = Momentum(mask = universe)
        w10 = mom.percentile_between(90, 100, mask=universe)
        pb = ms.pb_ratio.latest.top(context.target_stocks, mask=w10) 
    else:
        pb = ms.pb_ratio.latest 
    
    # Creating a pipe
    pipe = Pipeline(columns={'pb': pb,}, screen=universe)
    
    return pipe

def rebalance(context, data):

    # Get pipeline output and select stocks
    df = algo.pipeline_output('pipeline')
    
    if mom_on is True:
        stocks_to_hold = df[df.pb].index
    else:
        stocks_to_hold = select_top_stocks(context)
    
    # Define equally-weighted portfolio
    stock_weight = 1.0 / context.target_stocks
    stock_weights = pd.Series(index=stocks_to_hold, data=stock_weight)
    
    # Create a TargetWeights objective
    target_weights = opt.TargetWeights(stock_weights) 

    # Execute the order_optimal_portfolio method
    order_optimal_portfolio(
        objective = target_weights,
        constraints = []
        )

def select_top_stocks(context):
    
    # Get pipeline output
    df = algo.pipeline_output('pipeline')
    all_stocks = df['pb']
    
    current_holdings = list(context.portfolio.positions.keys())
    
    if len(current_holdings) == 0:
        top_stocks = all_stocks.nlargest(context.target_stocks)
        return top_stocks.index
    
    common_stocks = all_stocks[all_stocks.index.isin(current_holdings)]
    extra_stocks = all_stocks[~all_stocks.index.isin(current_holdings)]
    
    n_new_stocks = context.new_stocks
    n_core_stocks = context.target_stocks - n_new_stocks
    
    common_top_stocks = common_stocks.nlargest(n_core_stocks)
    extra_top_stocks = extra_stocks.nlargest(n_new_stocks)
    top_stocks = common_top_stocks.add(extra_top_stocks)
    
    return top_stocks.index
There was a runtime error.

… furthermore, the equally weighted portfolio with 250 growth stocks seems like an appropriate solution for the recent “Build Smart Beta Factors” challenge.

Click to load notebook preview

@Yulia,

Here's a backtest of my version of Uncovering Momentum - 20 strategy over a period, including both market crashes.
I found that a simple momentum worked a little better then conventional momentum.

Clone Algorithm
50
Loading...
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Uncovering Momentum
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline.filters import QTradableStocksUS
from quantopian.pipeline.data import Fundamentals
from quantopian.pipeline.factors import Returns
from quantopian.pipeline import Pipeline
import quantopian.optimize as opt
import pandas as pd 
# -----------------------------------------------------------------------------------
QTU = QTradableStocksUS(); MOM = 126; N = 20; PCTL_LB = 90; PCTL_UB = 100; LEV = 1.0;
# -----------------------------------------------------------------------------------
def initialize(context):
    schedule_function(rebalance, date_rules.month_end(6), time_rules.market_close(minutes = 30))   
    m = QTU    
    mom = Returns(window_length = MOM + 1, mask = m) 
    w_10 = mom.percentile_between(PCTL_LB, PCTL_UB, mask = m)
    m &= w_10 & mom.isfinite()
    factor = Fundamentals.pb_ratio.latest 
    m &= factor.top(N, mask = m) & factor .isfinite()
    
    attach_pipeline(Pipeline(screen = m), 'pipeline')  

def rebalance(context, data):
    output = pipeline_output('pipeline')    
    stocks = output.index
    stock_weight = 1.0 / len(stocks)
    stock_weights = pd.Series(index = stocks, data = stock_weight)
    
    order_optimal_portfolio(opt.TargetWeights(stock_weights), [opt.MaxGrossExposure(LEV)])
    
def before_trading_start(context, data):
    record(leverage = context.account.leverage)
There was a runtime error.

@ Yulia,

Here's the performance tear sheet of the same strategy, timed by volatility with an adaptive threshold similar to what we discussed here.

Click to load notebook preview

@ Yulia,

Here's the performance tear sheet of the last strategy over period 2004-07-01 to 2020-06-05.

Click to load notebook preview

Vladimir,

My posts in this thread intentionally didn’t include momentum crashes. In brief, it followed the approach from the Uncovering Momentum paper and focused on the analysis of winners during the bull market. As you mentioned, the market downturn interval is already addressed in other threads (e.g., dual momentum strategy, momentum with volatility timing, quality companies in an uptrend).

During the bull market, the growth stocks (with and without momentum) demonstrate strong performance. Growth alone however could not achieve the impressive results of your April 26 (cum. ret.: 7.5, stocks: 450-600) and Vedran’s April 15 (cum. ret.: ~7, stocks: 450-500) solutions for the ‘Build Smart Beta Factors’ challenge. Your approach already shows exposure to negative value. Not sure if it explicitly relies on growth stocks and if not curious whether adding them could further push the results. Best regards, Yulia

I have recently joined the community and just wanted to thank you for this knowledge sharing helped me a lot and also the way you share your references made me learn so much more. Just to let you know we appreciate your work .

In the meantime, I derived an explanation for the momentum effect by extending the in/out analysis from the Uncovering Momentum paper. In short, it is not associated with behavioral models but determined by growth high volatility stocks.

The figure below elaborates this explanation by comparing the growth subsamples of momentum winners (blue) and high volatility deciles (green). As shown in the figure, the in/out interval consists of three periods: ranking, skipping, and holding. The difference in the ranking period between momentum and high volatility deciles is determined by the high returns sampled by the momentum procedure. During the skip month as the ranking period ends, momentum winners approach to the mean level of high volatility deciles. After the formation date, they both experience a similar short-term reversal.

75% of momentum winners are represented by growth stocks and therefore the contribution of value stocks is not substantial. Nonetheless, as shown in the attached notebook the corresponding value subset of high volatility deciles explain this effect as well.

Thank you for the feedback Nuno. Best regards, Yulia

Click to load notebook preview

Yulia, great research, most interesting. Thanks.

Apologies for the beginner question, but what is the difference between Downside Volatility and Realized Volatility?

For those interested, the above outlined results have been consolidated in a Towards Data Science article “Uncovering Momentum with Rolling Intertemporal Analysis”. Following this the last two sections of Uncovering Momentum are being revised.