Betting Against Beta Factor: How It Works and QuantConnect Implementation
The betting against beta factor generates alpha by constructing a market-neutral portfolio that is long low-beta assets and short high-beta assets, with both sides leveraged to achieve zero net market exposure.
The betting against beta (BAB) factor capitalizes on the empirical violation of the Capital Asset Pricing Model (CAPM), where low-beta securities consistently deliver higher risk-adjusted returns than their high-beta counterparts. This comprehensive guide examines the mechanics of the BAB factor and its concrete implementation in the paperswithbacktest/awesome-systematic-trading repository, featuring production-ready QuantConnect algorithms for both U.S. equities and international markets.
What Is the Betting Against Beta Factor?
The betting against beta factor is a systematic long-short equity strategy first formalized by Frazzini and Pedersen (2014) that exploits the "low-beta anomaly." While CAPM predicts a linear relationship between beta and expected returns, empirical evidence shows that low-beta (low-risk) stocks actually outperform high-beta stocks on a risk-adjusted basis. The BAB strategy captures this spread by buying the lowest-beta securities and selling the highest-beta securities, then scaling both legs so the combined portfolio carries no systematic market risk.
Step-by-Step Implementation Logic
Estimating Rolling Beta Against SPY
The strategy calculates each asset’s beta relative to the S&P 500 ETF (SPY) using a one-year rolling window of daily returns (252 trading days, implemented as 12 months × 21 days). In static/strategies/betting-against-beta-factor-in-stocks.py (lines 92-106), beta is computed as:
[ \beta_i = \frac{\operatorname{Cov}(r_i, r_m)}{\operatorname{Var}(r_m)} ]
The implementation uses np.cov and np.var on the return series stored in a RollingWindow[float] structure (lines 24-28). A similar calculation appears in the country ETF version at lines 84-89 of static/strategies/betting-against-beta-factor-in-country-equity-indexes.py.
Constructing Long and Short Baskets by Decile
Assets are ranked by their estimated beta values. The algorithm selects the bottom decile (lowest 10%) to form the long basket and the top decile (highest 10%) for the short basket. This decile split is executed in lines 112-116 of the stock implementation and lines 93-98 of the country ETF file, using numpy.percentile to establish the cutoff thresholds.
Scaling Positions to Achieve Zero Beta
To achieve market neutrality, the portfolio applies leverage adjustment so that the average beta of the long basket equals 1 and the short basket equals -1. The algorithm calculates:
long_lvg = 1 / long_mean_betashort_lvg = 1 / short_mean_beta
These leverage factors are then applied to position sizing, subject to a user-defined leverage_cap to prevent excessive exposure. This critical scaling occurs at lines 124-136 in the stock strategy and lines 99-108 in the international equities version, ensuring the combined portfolio has theoretically zero correlation with the market.
Monthly Rebalancing Workflow
The strategy re-evaluates betas and rebalances positions once per month. In the stock implementation, Schedule.On (line 41) triggers the selection logic at the start of each month, while the country ETF version checks monthly flags within OnData (around line 72). The OnData method (lines 40-58) clears existing positions and establishes new holdings using self.SetHoldings with the computed leverage weights.
QuantConnect Architecture and Key Components
The repository implements the betting against beta factor using several specialized QuantConnect framework components:
-
RollingWindow[float]— Stores the last 252 daily closing prices for each asset, providing the rolling lookback window required for beta calculation (stock file, lines 24-28). -
CoarseSelectionFunction/FineSelectionFunction— Filters the universe to the most liquid securities and computes beta for each candidate before portfolio construction (stock file, lines 48-81). -
OnData— Executes the trading logic only when the monthly rebalance flag is set, liquidating previous positions and deploying capital into the new decile-weighted baskets (stock file, lines 40-58). -
CustomFeeModel— Applies a transparent transaction cost structure (0.5 basis points per trade) to ensure backtest realism (lines 67-71 in both strategy files).
Practical Code Examples
Running the Stock BAB Strategy
# In a QuantConnect notebook or local LEAN environment
from Algorithms.BettingAgainstBetaFactorInStocks import BettingAgainstBetaFactorinStocks
algorithm = BettingAgainstBetaFactorinStocks()
algorithm.Initialize() # Sets start date, cash, universe, and monthly schedule
# The framework automatically handles beta calculation and monthly rebalancing.
Running the Country-ETF BAB Strategy
from Algorithms.BettingAgainstBetaFactorInInternationalEquities import BettingAgainstBetaFactorinInternationalEquities
algorithm = BettingAgainstBetaFactorinInternationalEquities()
algorithm.Initialize()
# Monthly rebalancing and cross-sectional beta calculation are performed inside OnData().
Standalone Beta Calculation
import numpy as np
def compute_beta(asset_prices, market_prices):
"""Calculate beta against a market benchmark using 252-day window logic."""
asset_ret = np.diff(asset_prices) / asset_prices[:-1]
market_ret = np.diff(market_prices) / market_prices[:-1]
cov = np.cov(asset_ret, market_ret)[0, 1]
var = np.var(market_ret)
return cov / var
# Example usage with RollingWindow data:
beta = compute_beta(np.array(asset_window), np.array(market_window))
Summary
- The betting against beta factor exploits the low-beta anomaly by buying low-risk assets and selling high-risk assets, correcting for the systematic bias against low-beta securities.
- Beta estimation uses a 252-day rolling window against SPY, implemented with
numpycovariance and variance functions in the strategy files. - Decile ranking separates the universe into extreme beta baskets, with the bottom 10% going long and top 10% going short.
- Leverage scaling (
1/mean_beta) ensures the long side has beta of 1 and the short side beta of -1, creating a zero-beta portfolio. - The strategy rebalances monthly using QuantConnect's
Schedule.OnandOnDatamethods, with full implementations available for both individual stocks and country-level ETFs.
Frequently Asked Questions
What is the betting against beta factor?
The betting against beta factor is a quantitative investment strategy that generates returns by betting on the empirical finding that low-beta assets outperform high-beta assets on a risk-adjusted basis. It creates a market-neutral portfolio by combining leveraged long positions in low-beta securities with leveraged short positions in high-beta securities.
How is beta calculated in the BAB implementation?
Beta is calculated as the covariance between the asset's daily returns and the market's daily returns (using SPY as the proxy), divided by the variance of the market returns. The implementation in static/strategies/betting-against-beta-factor-in-stocks.py uses np.cov and np.var on a rolling 252-day window of prices stored in a RollingWindow[float] object.
Why does the strategy apply leverage adjustment?
The leverage adjustment ensures the portfolio achieves zero market exposure. Without scaling, the long low-beta basket would have a beta less than 1 and the short high-beta basket a beta greater than 1 in absolute terms, leaving net market risk. By scaling each basket to unit beta (1/long_mean_beta and 1/short_mean_beta), the strategy neutralizes systematic risk and isolates the alpha from the beta spread.
Can the BAB factor be traded with instruments other than individual stocks?
Yes. The repository includes static/strategies/betting-against-beta-factor-in-country-equity-indexes.py, which applies the identical betting against beta logic to a universe of country ETFs. This demonstrates that the factor is robust across different asset classes and geographic markets, provided a reliable market benchmark (like SPY or a global index) is available for beta calculation.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →