Appearance
CAPM Alpha
The etsr_capm correlation target adjusts each peer's return for market risk before computing correlations. The intuition: a company that returned 30% in a year when the market returned 28% and the stock has a beta of 1.0 essentially matched its risk-adjusted expectation; one that returned 30% against a 5% market with a beta of 2.0 actually underperformed its expected return. Stripping out the market risk component leaves a cleaner signal for identifying which fundamentals drive company-specific excess returns.
CAPM framework
The Capital Asset Pricing Model (Sharpe, 1964; Lintner, 1965) asserts that the expected return on a risky asset is:
where
SPY (the SPDR S&P 500 ETF) is used as the market proxy. This is the etsr_capm target's return for peer
Beta estimation
OLS regression
Beta is the OLS slope of peer monthly returns regressed on SPY monthly returns over a 5-year window:
The slope estimator is:
implemented in closed form (no matrix algebra library dependency):
Both covariance and variance are computed with
Monthly return construction
Raw daily prices from prices_daily (split- and dividend-adjusted closes) are bucketed by calendar month. The last trading day of each month is used as the month-end anchor. Returns are simple period returns:
The first month in the window is dropped (no prior reference). The series must share at least 24 aligned month-end dates between the peer and SPY; months present in one series but not the other are excluded from the alignment. Returns fewer than 24 aligned observations → beta is None (peer dropped from etsr_capm correlations).
5-year window
Beta is computed over a rolling 5-year window ending at the analysis date. Longer windows capture the full-cycle beta at the cost of responsiveness to structural shifts in the business; 24 months is the minimum for reasonable OLS stability.
Cached vs. on-demand beta
Cache column
companies.beta_5y_monthly_vs_spy stores the most recently computed 5-year monthly beta for each company. Two companion columns track provenance:
beta_window_start— start date of the 5-year windowbeta_computed_at— when the regression was last run
Refresh cadence
The recompute Lambda (eqtytrk-recompute-cache) runs recompute_all_betas() for every company nightly, triggered by the daily EventBridge schedule (08:00 UTC) and by a fire-and-forget async invoke after each successful ingest job. The Lambda iterates every ticker in companies, pulls 5 years + 14 days of daily prices for alignment slack, and UPDATEs the beta columns.
Cache-miss fallback
When a peer's beta_5y_monthly_vs_spy is NULL (newly ingested company, or the nightly run hasn't completed), the etsr_capm handler falls back to a per-request regression at query time. SPY's monthly return series is constructed once per request (lazy init) and shared across all peers that need the fallback path. The fallback produces the same result as the cache would; it is just slower. Peers with fewer than 24 aligned months even on the fallback path are dropped.
Per-peer adjustment
Because each peer has its own etsr_capm ranking can differ substantially from etsr (single shared benchmark subtraction) — companies in defensive industries with low betas may look better on a beta-adjusted basis; leveraged, high-beta names may look worse.
Limitations
- 5-year beta is backward-looking. Beta estimated over the past 5 years may not reflect the company's forward risk profile, especially after major restructurings, acquisitions, or business-model shifts.
- SPY-only market proxy. Using a single broad-market ETF as the market portfolio is a simplification. Fama & French (2015) show that a multi-factor model (market, size, value, profitability, investment) explains more cross-sectional return variation than the single-factor CAPM.
etsr_capmcorrects for market beta only. - Simple (not excess) returns. The risk-free rate is implicitly set to zero. For long windows in high-rate environments (e.g., 2022–2024), this understates the hurdle rate and makes all alphas look more positive than they should be.
- Minimum-
constraint. Newly public companies and recent index additions with fewer than 24 months of price history cannot have betas computed; they are excluded from etsr_capmcorrelations regardless of how good their fundamentals are.
Implementation notes
compute_beta()andmonthly_returns()insrc/eqtytrk/correlation/beta.pyrecompute_all_betas()in the same file; called bysrc/eqtytrk/worker/recompute_handler.py_apply_etsr_capm()insrc/eqtytrk/api/routers/analysis.py— reads fromcompanies.beta_5y_monthly_vs_spy, falls back to per-request regression on cache miss_MIN_MONTHS = 24defined at module level insrc/eqtytrk/correlation/beta.py- Cache columns:
companies.beta_5y_monthly_vs_spy,companies.beta_computed_at,companies.beta_window_start,companies.beta_window_end
References
- Sharpe, W.F. (1964). "Capital Asset Prices: A Theory of Market Equilibrium under Conditions of Risk." Journal of Finance, 19(3), 425–442.
- Lintner, J. (1965). "The Valuation of Risk Assets and the Selection of Risky Investments in Stock Portfolios and Capital Budgets." Review of Economics and Statistics, 47(1), 13–37.