Quant BuffetRelax, Not Over Thinking

Enhanced Returns of LGBT CEOs

Log in to collect

Academic paper

LGBT CEOs and stock returns: Diagnosing rainbow ceilings and cliffs

AuthorsSavva Shanaev; Arina Skorochodova; Mikhail Vasenin

Institute
  • Northumbria University

Strategy in a nutshell

This strategy invests in U.S.-listed companies led by openly LGBT CEOs. Stocks are selected from verified sources and weighted by value, with caps on maximum exposure. The portfolio is actively rebalanced: new long positions are added when CEOs publicly identify as LGBT, and positions are adjusted or exited if CEOs leave or change orientation. Returns are measured using multi-factor regressions based on the Fama-French five-factor model, with the portfolio constructed to capture potential mispricing and growth opportunities associated with LGBT leadership.

Economic rationale

The strategy leverages two behavioral phenomena: the “rainbow ceiling,” where bias causes undervaluation of firms with LGBT CEOs, and the “rainbow cliff,” where smaller underperforming firms are more likely to appoint LGBT CEOs. Exploiting these effects can generate excess returns while reflecting societal and market shifts, as undervalued or turnaround companies experience appreciation once leadership is disclosed.

Backtest performance

Annualised return16.35%
Volatility34.88%
Beta0.815
Sharpe ratio0.47
Maximum drawdown-67.23%
Win rate72%

Full Python code

from AlgorithmImports import *
import data_tools
# endregion

class EnhancedReturnsOfLGBTCEOs(QCAlgorithm):

def Initialize(self):
self.SetStartDate(2000, 1, 1)
self.SetCash(100000)

self.equally_weighted_flag:bool = False     # False - VW; True - EW

self.leverage:int = 5

self.universe:list[str] = []
self.selected_symbols:list[Symbol] = []     # currently actively traded stocks
self.market_cap:dict[Symbol, float] = {}

self.market_symbol:Symbol = self.AddEquity('SPY', Resolution.Daily).Symbol

self.LGBT_CEO_symbol:Symbol = self.AddData(data_tools.QuantpediaLGBT, 'LGBT_CEO', Resolution.Daily).Symbol

self.selection_flag:bool = False
self.UniverseSettings.Resolution = Resolution.Daily
self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)       

def OnSecuritiesChanged(self, changes):
for security in changes.AddedSecurities:
    security.SetFeeModel(data_tools.CustomFeeModel())
    security.SetLeverage(self.leverage)

def CoarseSelectionFunction(self, coarse):
if not self.selection_flag:
    return Universe.Unchanged

selected_symbols:list[Symbol] = [equity.Symbol for equity in coarse if equity.Symbol.Value in self.universe]

return selected_symbols

def FineSelectionFunction(self, fine):
if self.equally_weighted_flag:
    self.selected_symbols = list(map(lambda stock: stock.Symbol, fine))

    return self.selected_symbols
else:
    self.market_cap.clear()

    for stock in fine:
        market_cap:float = stock.MarketCap

        if market_cap == 0:
            continue

        symbol:Symbol = stock.Symbol
        self.market_cap[symbol] = market_cap

    return list(self.market_cap.keys())

def OnData(self, data: Slice):
if self.selection_flag:
    # rebalance whole active selection
    if self.equally_weighted_flag:
        length:int = len(self.selected_symbols)

        for symbol in self.selected_symbols:
            self.SetHoldings(symbol, 1 / length)
    else:
        total_cap:float = sum([x[1] for x in self.market_cap.items()])

        for symbol, market_cap in self.market_cap.items():
            self.SetHoldings(symbol, market_cap / total_cap)

    self.selection_flag = False

if self.LGBT_CEO_symbol in data and data[self.LGBT_CEO_symbol]:
    stocks:list = data[self.LGBT_CEO_symbol].GetProperty('stocks')

    for stock in stocks:
        ticker:str = stock['ticker']
        status:str = stock['status']

        if status == 'start':
            self.universe.append(ticker)
        elif status == 'end' and ticker in self.universe:
            self.universe.remove(ticker)
            self.Liquidate(ticker)

    # rebalance once the new data comes in
    self.selection_flag = True