The strategy involves buying the 15 US stocks with the lowest brand value, equally weighting them, and rebalancing annually. Brand values are summed for companies with multiple brands, like Volkswagen.

I. STRATEGY IN A NUTSHELL

The strategy invests in US stocks listed in Interbrand’s brand value database, buying the 15 lowest-brand-value stocks each month. Portfolios are equally weighted and rebalanced annually. For companies with multiple brands (e.g., Volkswagen, Audi, BMW, Porsche), brand values are summed. The approach targets undervalued brands to capture potential returns from low-recognition or underappreciated stocks.

II. ECONOMIC RATIONALE

Lower-brand-value stocks tend to earn a “popularity premium,” while high-brand-value stocks deliver lower returns. Behavioral biases and investor preferences drive this mispricing. The strategy focuses on financially stable multinational companies from Interbrand’s top 100 list, meeting criteria such as generating over 30% of revenue internationally, operating in at least three continents, and being listed on regulated exchanges.

III. SOURCE PAPER

 Popularity: A Bridge between Classical and Behavioral Finance [Click to Open PDF]

Roger Ibbotson,Yale School of Management; Zebra Capital Management, LLC

<Abstract>

Popularity is a word that embraces how much anything is liked, recognized, or desired. Popularity drives demand. In this book, we apply this concept to assets and securities to explain the premiums and so-called anomalies in security markets, especially the stock market. Most assets and securities have a relatively fixed supply over the short or intermediate term. Popularity represents the demand for a security — or perhaps the set of reasons why a security is demanded to the extent that it is — and thus is an important determinant of prices for a given set of expected cash flows. A common belief in the finance literature is that premiums in the market are payoffs for the risk of securities — that is, they are “risk” premiums. In classical finance, investors are risk averse, and market frictions are usually assumed away. In the broadest context, risk is unpopular. The largest risk premium is the equity risk premium (i.e., the extra expected return for investing in equities rather than bonds or risk-free assets). Other risk premiums include, for example, the interest rate term premium (because of the greater risk of longer-term bonds) and the default risk premium in bond markets. There are many premiums in the market that may or may not be related to risk, but all are related to investing in something that is unpopular in some way. We consider premiums to be the result of characteristics that are systematically unpopular — that is, popularity makes the price of a security higher and the expected return lower, all other things being equal. Preferences that influence relative popularity can and do change over time. These premiums include the size premium, the value premium, the liquidity premium, the severe downside premium, low volatility and low beta premiums, ESG premiums and discounts, competitive advantage, brand, and reputation. In general, any type of security with characteristics that tend to be overlooked or unwanted can have a premium. The title of this book refers to a bridge between classical and behavioral finance. Both approaches to finance rest on investor preferences, which we cast as popularity.

IV. BACKTEST PERFORMANCE

Annualised Return11.95%
Volatility16.73%
Beta0.958
Sharpe Ratio0.71
Sortino Ratio0.563
Maximum DrawdownN/A
Win Rate81%

V. FULL PYTHON CODE

from AlgorithmImports import *
import pandas as pd
from io import StringIO
#endregion
class InsiderTradingCombinedwithShareRepurchases(QCAlgorithm):
    def Initialize(self):
        self.SetStartDate(2000, 1, 1)
        self.SetCash(100000)
        self.long: List[Symbol] = []
        self.brands_by_year_n: Dict[int, List[str]] = {}
        market: Symbol = self.AddEquity('SPY', Resolution.Daily).Symbol
        
        # Data source: https://interbrand.com/best-global-brands/
        csv_string_file = self.Download(f'data.quantpedia.com/backtesting_data/economic/brand_value_fifteen_lowest.csv')
        # take values of each column, expect first one in each row and does not take first row as a header
        separated_file = pd.read_csv(StringIO(csv_string_file), sep=';', header=None)
        
        for row in separated_file.itertuples():
            brand_tickers = []
            for ticker in row[2:]:
                brand_tickers.append(ticker)
            self.brands_by_year_n[int(row[1])] = brand_tickers
        self.selection_flag: boll = False
        self.UniverseSettings.Resolution = Resolution.Daily
        self.AddUniverse(self.FundamentalSelectionFunction)
        self.Settings.MinimumOrderMarginPortfolioPercentage = 0.
        self.Schedule.On(self.DateRules.MonthStart(market), self.TimeRules.AfterMarketOpen(market), self.Selection)
        self.settings.daily_precise_end_time = False
        
    def OnSecuritiesChanged(self, changes: SecurityChanges) -> None:
        for security in changes.AddedSecurities:
            security.SetFeeModel(CustomFeeModel())
    def FundamentalSelectionFunction(self, fundamental: List[Fundamental]) -> List[Symbol]:
        if not self.selection_flag:
            return Universe.Unchanged
        
        year_key: int = self.Time.year - 1
        if year_key in self.brands_by_year_n:
            self.long = [f.Symbol for f in fundamental if f.Symbol.Value in self.brands_by_year_n[year_key]]
        return self.long
    def OnData(self, slice: Slice) -> None:
        if not self.selection_flag:
            return
        self.selection_flag = False
        
        # rebalance
        portfolio:List[PortfolioTarget] = [PortfolioTarget(symbol, 1. / len(self.long)) for symbol in self.long if symbol in slice and slice[symbol]]
        self.SetHoldings(portfolio, True)
        self.long.clear()
            
    def Selection(self) -> None:
        self.selection_flag = True
class CustomFeeModel(FeeModel):
    def GetOrderFee(self, parameters):
        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005
        return OrderFee(CashAmount(fee, "USD"))

VI. Backtest Performance

Leave a Reply

Discover more from Quant Buffet

Subscribe now to keep reading and get access to the full archive.

Continue reading