
以下代码是在计算每只股票相对等权股票池的多日滚动CAPM betadef compute_market_beta(returns, windowBETA_WINDOW, minpBETA_MINP): 60d trailing CAPM beta of each stock vs the equal-weight universe. r_mkt returns.mean(axis1) var r_mkt.rolling(window, min_periodsminp).var() cov returns.rolling(window, min_periodsminp).cov(r_mkt) return cov.div(var, axis0)实现了如下功能1. 用等权股票池的横截面平均收益作为市场收益2. 计算市场收益的滚动方差3. 计算每只股票与市场收益的滚动协方差4. 协方差除以方差得到每只股票的滚动 beta。金融上它度量的是个股对“等权市场组合”的系统性风险暴露。核心公式是其中是个股收益是市场组合收益。代码用 pandas 的滚动协方差除以滚动方差得到随时间变化的 beta。这里进一步分析其计算逻辑适应场景以及可能需要注意或修正的事项。1 代码逻辑1.1 输入假设这里先对输入假设进行分析returns是一个DataFrame- 行日期或时间序列- 列股票- 值收益率不是价格windowBETA_WINDOW滚动窗口例如 60 个交易日。minpBETA_MINP窗口内最少需要的有效观测数用于控制 NaN。1.2 计算逻辑这里进一步分析代码的计算逻辑r_mkt returns.mean(axis1)按行求均值得到每一天的市场收益。如果 returns有 N 只股票那么这相当于一个每日再平衡的等权组合。注意它不等于市值加权指数也不是真正的市场组合。var r_mkt.rolling(window, min_periodsminp).var()对市场收益 r_mkt做滚动方差pandas 默认ddof1即样本方差。min_periods控制窗口内至少有多少个非 NaN 值才计算。cov returns.rolling(window, min_periodsminp).cov(r_mkt)对每一只股票收益与市场收益 r_mkt做滚动协方差返回结果通常是一个DataFrame列与原returns相同表示每只股票在每个日期的滚动协方差。return cov.div(var, axis0)把每只股票的滚动协方差除以市场滚动方差axis0表示按行索引对齐也就是按日期对齐。因为var是Series索引为日期所以每一行所有股票都除以当天的市场方差。最终返回一个 beta 矩阵- 行日期- 列股票- 值该股票当天的滚动 CAPM beta2. 金融相关这里从金融的角度分析以上计算逻辑。2.1 CAPM与betaCAPM 的基本形式或者其中-无风险利率-市场风险溢价-股票 i 对市场风险的暴露。beta 的定义也可以写成含义说明如下-股票与市场同步波动-进攻型、周期型市场涨跌时波动更大-防御型波动小于市场-与市场反向-理论上无系统性风险暴露。2.2 beta 是OLS回归斜率如果把个股收益对市场收益做单变量回归那么 OLS 估计的斜率就是这正是代码中cov / var做的事。因此这段代码本质上是在做滚动单因子回归但没有显式估计alpha。2.3 滚动beta的意义rolling(window60)表示用过去 60 个交易日的数据估计beta即这叫做时变beta或滚动历史beta。金融含义- 短窗口对近期市场变化更敏感但噪声大- 长窗口更稳定但对结构变化反应慢- 60 日约等于一个季度是常见折中。2.4 市场组合代理理论上CAPM 中的市场组合应包括所有可投资资产并按市值加权。现实中无法直接观测所以常用指数代理。这段代码用r_mkt returns.mean(axis1)即等权股票池作为市场代理。这意味着- 每只股票权重相同- 小盘股、波动大的股票权重可能被高估- 与真实市值加权市场组合有差异- 如果股票池本身就是当前股票池还可能存在幸存者偏差。2.5 beta的用途beta经常可能用于如下用途。计算股权资本成本组合风险管理组合 beta 是成分股 beta 的加权平均市场中性策略根据 beta 调整多空敞口对冲用股指期货对冲时合约数量与组合 beta 有关绩效归因区分 alpha 和市场 beta 收益因子模型作为市场因子暴露。3. 潜在问题3.1 等权假设问题等权市场包含个股自身可能造成偏差因为所以个股与市场协方差中包含了自身方差项。若股票池很小beta 会被高估。更严谨的做法是- 使用外部市场指数- 或计算市场收益时排除该股票自身- 或使用市值加权。3.2 缺失值处理可能不一致returns.mean(axis1)默认skipnaTrue所以某天某些股票缺失时市场收益由剩余股票平均得到。但 returns.rolling(...).cov(r_mkt)对每只股票与市场收益计算协方差时会忽略该股票自身的 NaN。这样可能出现- 市场方差var使用了某些日期- 个股协方差cov使用了另一些日期- 分子分母样本不完全一致。更严谨的做法是对每只股票先把该股票收益与市场收益对齐、dropna()再计算同一组样本上的协方差和方差。3.3 无风险利率问题CAPM 严格使用超额收益代码直接使用原始收益。若日频无风险利率变化很小近似可以接受但严谨的资产定价应使用超额收益。3.4 历史beta不等于未来beta滚动 beta 是历史估计。beta 会随公司杠杆、行业、宏观环境变化。实际中常用- Blume 调整- 贝叶斯收缩- 多因子模型- DCC-GARCH、Kalman 滤波等动态 beta 方法。3.5 非同步交易与微观结构不同市场、不同时区、停牌、涨跌停、流动性差都会导致收益率不同步从而低估或高估 beta。3.6 异常值与窗口选择极端收益会显著影响协方差和方差。可考虑- winsorize- 使用稳健回归- 调整窗口长度- 使用指数加权3.7 beta不需要年化beta 是斜率频率一致时日频、周频、月频估计的理论 beta 相同。把收益年化不会改变 beta因为协方差和方差同比例缩放。4 更严谨实现如果希望分子分母使用完全相同的样本可以这样写import pandas as pd def compute_market_beta(returns, window60, minp30): r_mkt returns.mean(axis1) betas {} for col in returns.columns: sub pd.concat([returns[col], r_mkt], axis1).dropna() sub.columns [stock, mkt] cov sub[stock].rolling(window, min_periodsminp).cov(sub[mkt]) var sub[mkt].rolling(window, min_periodsminp).var() betas[col] cov / var return pd.DataFrame(betas)如果要排除自身影响可以计算除该股票外的等权市场收益sum_ret returns.sum(axis1) count returns.notna().sum(axis1) for col in returns.columns: r_mkt_ex (sum_ret - returns[col]) / (count - returns[col].notna()) # 再用 r_mkt_ex 与 returns[col] 计算滚动 betareference---滚动单因子回归的计算和代码示例https://blog.csdn.net/liliang199/article/details/165297581