Original paper
Abstract
This document provides an overview of the UMO factor. It describes its motivation, construction, and how to obtain it and use it. Behavioral theories suggest that investor misperceptions and market mispricing will be correlated across firms. The UMO factor uses equity and debt financing to identify common misvaluation across firms. UMO is a zero-investment portfolio that goes long on firms that issue securities and short on firms that repurchase. UMO captures comovement in returns beyond that in standard multifactor models, substantially improves the Sharpe ratio of the tangency portfolio, and carries heavy weight in the tangency portfolio. Loadings on UMO strongly predict the cross-section of returns on both portfolios and individual stocks, even among firms not recently involved in external financing activities, and even after controlling for other standard predictors. UMO was proposed by Hirshleifer and Jiang (2010), who provide further evidence suggesting that UMO loadings proxy for the common component of a stock's misvaluation. For further details, see Hirshleifer, David, and Danling Jiang, "A Financing-Based Misvaluation Factor and the Cross-Section of Expected Returns," Review of Financial Studies (2010), 23(9), 3401-3436.
Keywords:Â Misvaluation Factor, New Issues, Repurchases, External Financing, Return Predictability
Trading rules
- Investment universe: NYSE, AMEX, and NASDAQ stocks
- Overvalued portfolio: Firms with IPOs, SEOs, and debt offerings (straight and convertible) within the past 24 months
- Undervalued portfolio: Firms with equity or debt reduction exceeding 1% of average total assets in either of the two most recent fiscal years
- Exclusions: Firms meeting both overvalued and undervalued criteria
- Position: Long on undervalued portfolio, short on overvalued portfolio
- Rebalancing: Yearly at the end of June, with equal weighting for stocks
Python code
Backtrader
import backtrader as bt
import pandas as pd
class RepurchaseNewIssueEffect(bt.Strategy):
def __init__(self):
self.date_month = None
def next(self):
current_date = self.data.datetime.date()
if self.date_month != current_date.month and current_date.month == 6:
self.date_month = current_date.month
overvalued_stocks = []
undervalued_stocks = []
for stock_data in self.datas:
stock = stock_data._name
# Implement logic to filter stocks based on IPOs, SEOs, and debt offerings
# within the past 24 months as well as equity/debt reduction criteria.
# This information is not directly available in price data and needs
# to be obtained from a different source (e.g., financial statements).
if stock_meets_overvalued_criteria(stock):
overvalued_stocks.append(stock_data)
elif stock_meets_undervalued_criteria(stock):
undervalued_stocks.append(stock_data)
# Equal weight for stocks in the overvalued and undervalued portfolios
overvalued_weight = -1 / len(overvalued_stocks)
undervalued_weight = 1 / len(undervalued_stocks)
# Open positions
for stock_data in overvalued_stocks:
self.order_target_percent(stock_data, target=overvalued_weight)
for stock_data in undervalued_stocks:
self.order_target_percent(stock_data, target=undervalued_weight)
# Implement helper functions for filtering stocks based on IPOs, SEOs, debt offerings
# and equity/debt reduction criteria. You will need additional data sources for this.
def stock_meets_overvalued_criteria(stock):
pass # Implement the logic here
def stock_meets_undervalued_criteria(stock):
pass # Implement the logic here
# Initialize the Backtrader engine
cerebro = bt.Cerebro()
# Add data feeds for each stock in the investment universe (NYSE, AMEX, NASDAQ)
# You will need to obtain the stock data from a source and add it to the cerebro object
# Example: cerebro.adddata(stock_data)
# Add the strategy to the cerebro object
cerebro.addstrategy(RepurchaseNewIssueEffect)
# Run the backtest
results = cerebro.run()
Please note that the provided code is a starting point and requires additional data sources and modifications to handle IPOs, SEOs, debt offerings, and equity/debt reduction criteria. The logic for filtering stocks based on these criteria should be implemented in the stock_meets_overvalued_criteria
and stock_meets_undervalued_criteria
functions.