一文看懂:如何用 Stata 复现资产定价顶刊论文?(上)
2026/5/11 17:15:37 网站建设 项目流程

以 Bali, Brown and Tang (2017)《Is economic uncertainty priced in the cross-section of stock returns?》为例

原文的核心问题是:经济不确定性是否会在股票横截面收益中被定价。

此作者用经济不确定性指数估计个股的 uncertainty beta,并发现低不确定性 beta 股票比高不确定性 beta 股票获得更高的风险调整收益,差异大约为年化 6%。

当然,Stata 并不是实现复杂量化金融研究的最佳选择。相较于 SAS、Python 或 R,Stata 在处理超大规模金融数据时未必是最优工具,但它在数据整理、变量构造、回归估计和结果呈现方面,依然有非常清晰、稳定的优势。

这篇 JFE 讨论如何进行资产定价的文章,它的数据处理流程本身就非常偏量化金融:涉及个股月度收益、60 个月滚动回归、uncertainty beta 估计、组合排序、多因子 alpha 检验,以及 Fama-MacBeth 横截面回归,接下来就来看看我如何运用stata来完成全部的量化部分的数据分析流程。

因此,这次复现的价值不只是“用 Stata 跑出结果”,而是尝试把一篇偏量化金融的 JFE 资产定价文章,转化为一套 Stata 用户也能够理解、学习和迁移的复现路径。

由于篇幅有限,本次复现内容将分为上、中、下三个部分展开。本文作为上篇,主要讲解第一部分:基于 economic uncertainty beta 的数据处理与滚动回归实现。后续内容将继续围绕组合排序、多因子 alpha 检验以及 Fama-MacBeth 横截面回归展开。

上:前期数据处理部分

本次内容主要讲解复现过程中的前期数据处理环节。这里我可能要插入题外话,前期的数据处理和清洗往往是最重要的一步,

很多人忽视真正进入模型估计之前,首先要解决的是数据结构问题。也就是说,我们需要先把个股月度收益、公司市值(后面用于计算市值权重)、国家或地区信息、时间变量、公司金融类信息(后面计算五因子看)以及经济不确定性指数整理成一个标准的股票月度面板数据。

从数据结构上看,原始数据至少需要包含几个核心识别信息:个股识别码Symbol、年份、月份、国家或地区变量,以及对应的区域变量。其中,个股识别码用于区分不同股票;年份和月份用于建立时间序列顺序;国家或地区变量用于匹配相应的经济不确定性指数和市场收益率;

hint:月度收益率则是后续估计 uncertainty beta 的基础变量。

总体来看,这类资产定价复现数据并不是简单的截面数据,而是具有明显的多维结构:时间维度 × 国家/地区维度 × 个股维度。也正因为如此,在进入滚动回归之前,必须先把个股、时间和国家/地区之间的对应关系整理清楚。否则,后续的 economic uncertainty index 匹配、60 个月滚动回归,以及 portfolio sorting 都无法准确展开。

国家/区域的经济不确定性指数的数据整理

最重要的步骤是对于经济不确定性指数的处理。由于原始不确定性指数通常以 Excel 宽表形式储存,即每一列代表一个国家或地区,每一行代表一个年月,因此在 Stata 中不能直接用于后续合并和滚动回归。

所以,这一步首先要做的是将不确定性指数从宽表转换为长表,使其形成标准的国家,年份,月份,uncertainty index 数据结构。对应的 Stata 代码如下:

import excel "xxx.xlsx", firstrow clear ds ***xxx是国家名或者区域名称 local countries xxx xxx xxx foreach c of local countries { rename `c' unc_`c' } reshape long unc_, i(Year Month) j(Country) string save unc.dta, replace

这段代码的核心作用是:先将各国家的不确定性指数变量统一加上unc_前缀,然后通过reshape long将宽表转换成长表。转换之后,每一条观测值对应的是某一个国家在某一个月份的不确定性指数。

多源数据合并:从国家/区域-月份到个股-月份面板

在完成经济不确定性指数、市场收益率、个股收益率、公司财务变量和无风险利率的初步整理后,下一步就是将这些数据合并到同一个分析框架中。

这一部分的关键在于:不同数据集的层级并不相同。例如,经济不确定性指数和市场收益率通常是国家—月份层面;个股收益率是个股—月份层面;财务变量通常是个股—年份层面;无风险利率则是月份层面。

因此,合并数据时不能只看变量名是否一致,还要判断每个数据集的观测维度是否匹配。

对应的 Stata 代码如下:

use unc_rm.dta, clear * 1. 将国家-月份层面的不确定性指数和市场收益率合并到个股月度收益数据 merge 1:m Country ym using re.dta keep if _merge == 3 drop _merge * 2. 合并个股-年份层面的财务变量 merge m:1 Symbol Year using fin.dta keep if _merge == 3 drop _merge * 3. 合并月份层面的无风险利率 merge m:1 ym using rf.dta keep if _merge == 3 drop _merge save all_var.dta, replace

年度滚动回归:构造个股不确定性风险暴露变量

在完成多源数据合并之后,下一步进入本文复现的核心环节:估计个股层面的 economic uncertainty beta

原文的核心思想是,先通过滚动回归估计每只股票对经济不确定性指数的暴露程度,再用这一暴露程度解释未来股票收益的横截面差异。

也就是说,uncertainty beta并不是原始数据中直接给出的变量,而是需要通过滚动时间窗口逐只股票估计出来的。原文采用的是 60 个月固定窗口滚动回归,用历史收益数据估计个股对经济不确定性的暴露。

在本文的 Stata 复现中,采用年度滚动窗口的方式进行处理。

以欧洲市场为例,保留region == "Europe"的样本,并使用encode Symbol, gen(id)为每只股票生成唯一的数值型识别码。随后,将经济不确定性指数缩放为UNC,方便后续回归估计。

具体来说,对于第y年的股票样本,使用其过去 5 年的数据进行回归估计:

use all_var.dta, clear * 以欧洲样本为例 keep if region == "Europe" * 生成个股识别变量 encode Symbol, gen(id) * 缩放经济不确定性指数 gen UNC = regional_uncertainty / 1000 * 保存完整样本 tempfile full betas save `full', replace * 建立空数据集,用于储存每一年估计得到的 beta clear save `betas', emptyok replace forvalues y = 2008/2022 { local ystart = `y' - 5 local yend = `y' - 1 * 1. 提取目标年份中实际存在的股票 use `full', clear keep if year == `y' keep id duplicates drop tempfile target save `target', replace * 2. 提取过去 5 年回归样本 use `full', clear keep if inrange(year, `ystart', `yend') keep if !missing(ret_rf, UNC) * 3. 只保留目标年份中存在的股票 merge m:1 id using `target', keep(match) nogen * 4. 对每只股票分别回归,储存 UNC 的回归系数 statsby beta_unc = _b[UNC] n_obs = e(N), by(id) clear: /// regress ret_rf UNC * 5. 至少保留 30 个有效观测 keep if n_obs >= 30 * 6. 标记 beta 所对应的目标年份 gen target_year = `y' * 7. 追加保存 append using `betas' save `betas', replace } use `betas', clear save beta_unc_factor.dta, replace

需要说明的是,本文并不是对原文进行完全一比一复刻,而是基于原文的核心资产定价方法进行 Stata 复现和扩展应用。换句话说,我复现的是原文的实证逻辑和方法路径,包括 economic uncertainty beta 的构造、滚动回归、组合排序和后续横截面检验;但在样本层面,本文进一步使用了多国家股票数据。因此,这更像是一次“方法复现 + 多国家样本应用”,而不是简单地重复原文的样本和结果。

原文链接:https://mp.weixin.qq.com/s/XO2QJuLWe9EC2mc0SSCOyw

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询