news 2026/10/18 21:10:45

MATLAB复现HANK模型:从离散化到脉冲响应的完整链路

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MATLAB复现HANK模型:从离散化到脉冲响应的完整链路

简介:这份资源面向宏观经济学研究者、高年级研究生及具备一定MATLAB基础的量化分析人员,提供异构代理新凯恩斯(HANK)模型的完整复制代码,用于在MATLAB环境中搭建、求解并模拟包含家庭与企业异质性的动态随机一般均衡框架,帮助理解经济波动、政策评估与财富分配等议题。压缩包共321个文件,约22.32MB,以56个m脚本、69个f90与18个f源码、75个txt说明及13个makefile为主,另含mat数据、eps与pdf图表、sh与do脚本等,覆盖模型设定、动态方程求解、参数校准与结果输出等环节。已有49人学习下载。资源不仅给出可运行的MATLAB主程序,还保留Fortran与CUDA计算代码及编译配置,便于读者对照理论推导复现数值迭代过程,并在此基础上扩展情景模拟与政策分析,是研究HANK模型的实用起点。

1. 从一台笔记本跑通 HANK:为什么宏观异质性模型突然成了刚需

如果你最近在宏观圈子里听到有人念叨“HANK”,大概率不是在聊某个开源工具,而是在说一个把代表性代理人(RANK)拆成异质性家庭的新凯恩斯框架。MATLAB 里复现 HANK 模型,核心要解决的是:当家庭面临不可保险的异质性收入风险,货币政策冲击如何通过消费函数里的边际消费倾向差异,放大或削弱总需求响应。这件事对做政策模拟、央行研究或宏观博士论文的人来说,已经从“可选加分项”变成“审稿人必问项”。但真正动手时你会发现,网上能搜到的多是论文附录里的均衡条件,真正能跑的 MATLAB 代码往往缺胳膊少腿。这篇笔记就按我自己的复现路径,把从模型离散化到脉冲响应的完整链路拆开,让你能在本地把最小可运行版本跑起来,再逐步加回真实摩擦。

2. 先搞清 HANK 和 RANK 的代码结构差在哪

2.1 异质性不是加个循环,而是状态变量的维度爆炸

RANK 模型里,家庭部门只有一个欧拉方程,加总就是代表性家庭。HANK 则要把家庭按资产和收入状态分成网格,每个格点上的消费策略函数不同,加总总消费需要做分布积分。常见做法是用离散时间、离散状态空间的动态规划,先解出个体策略函数,再找稳态分布,最后做线性化或全局解。MATLAB 里如果直接对每个家庭写循环,维度一上去就卡死,所以必须用向量化或稀疏矩阵。我一般会先把收入过程离散成有限马尔可夫链,再用“内生网格法”或“投影法”求策略函数。这一步的代码量占整个复现的六成以上,但也是最能体现模型异质性的地方。

2.2 选型:为什么我优先用投影法而不是值函数迭代

值函数迭代在 MATLAB 里写起来直观,但收敛慢,尤其当网格点超过 200 个、资产维度超过 3 层时,每轮迭代都要做插值,时间成本不可接受。投影法把策略函数近似成多项式,用配点法求系数,收敛速度快一个量级。代价是需要推导一阶条件,对新手不友好。我的建议是:先用值函数迭代在小网格上验证逻辑,再切到投影法做正式脉冲响应。下面这段代码是收入过程离散化的最小示例,用 Tauchen 方法把 AR(1) 转成马尔可夫链,这是 HANK 复现里最不容易翻车的一步。

% Tauchen 离散化 AR(1): y_t = rho * y_{t-1} + sigma * eps_t rho = 0.9; sigma = 0.1; N = 7; m = 1.5; % m 是标准差倍数 y_max = m * sigma / sqrt(1 - rho^2); y_grid = linspace(-y_max, y_max, N)'; step = y_grid(2) - y_grid(1); P = zeros(N, N); for i = 1:N for j = 1:N if j == 1 P(i,j) = normcdf((y_grid(j) - rho*y_grid(i) + step/2) / sigma); elseif j == N P(i,j) = 1 - normcdf((y_grid(j) - rho*y_grid(i) - step/2) / sigma); else P(i,j) = normcdf((y_grid(j) - rho*y_grid(i) + step/2) / sigma) ... - normcdf((y_grid(j) - rho*y_grid(i) - step/2) / sigma); end end end % 归一化每行,防止数值误差导致概率和不为 1 P = P ./ sum(P, 2);

逻辑说明:这段代码把连续收入冲击变成有限状态马尔可夫链,rho和sigma来自收入过程的估计,N是状态数,m控制网格覆盖范围。参数说明:N取 5 到 9 之间比较稳,太少会丢失异质性,太多会让后续分布迭代变慢;m一般取 1.5 到 2,太小会截断尾部,太大会让网格点稀疏。跑完检查P每行和是否为 1,以及稳态分布是否合理。这一步如果出错,后面所有脉冲响应都会歪,所以务必先画一下收入网格和转移矩阵的热力图。

3. 在 MATLAB 里搭出最小可运行 HANK 的五个步骤

3.1 步骤一:写清家庭块的对数线性化均衡条件

HANK 的家庭块核心是欧拉方程和预算约束。对数线性化后,每个异质性家庭 i 的消费增长满足:

% 家庭 i 的欧拉方程对数线性化 % c_i_t = c_i_{t+1} - sigma * (i_t - pi_{t+1}) + 收入风险项 % 这里用期望算子近似,实际代码里要按转移矩阵加权 for i = 1:N E_c_next(i) = P(i,:) * c_next; % 按转移概率求期望 c_t(i) = E_c_next(i) - sigma * (i_rate - pi_next); end

逻辑说明:P(i,:)是家庭 i 的转移概率行,c_next是下一期消费策略。参数说明:sigma是跨期替代弹性倒数,通常取 1 到 2;i_rate是名义利率,pi_next是预期通胀。注意这里没有加借贷约束,如果加,需要在每个格点判断资产下界,代码里用max函数处理。这一步的常见错误是忘记把期望算成概率加权,直接用了平均消费,结果异质性被抹平。

3.2 步骤二:用内生网格法求稳态消费策略

稳态下,家庭在给定资产和收入状态时选择消费。我一般用内生网格法:先猜一个消费策略,代入欧拉方程算残差,再更新网格。MATLAB 里可以用fminbnd对每个格点单独求,但太慢;更稳的是把残差写成向量,用fsolve一次性解。下面是一个简化版的内生网格迭代框架。

% 内生网格法求稳态消费策略 max_iter = 500; tol = 1e-6; c_policy = ones(n_asset, n_income) * 0.5; % 初始猜测 for iter = 1:max_iter c_old = c_policy; for ia = 1:n_asset for iy = 1:n_income % 当前资产和收入下的预算约束 a_now = asset_grid(ia); y_now = income_grid(iy); % 用转移概率算下一期期望边际效用 E_mu_next = 0; for iy_next = 1:n_income a_next = (1 + r) * a_now + y_now - c_policy(ia, iy); % 插值到资产网格上 c_next_interp = interp1(asset_grid, c_policy(:, iy_next), a_next, 'linear', 'extrap'); E_mu_next = E_mu_next + P(iy, iy_next) * c_next_interp^(-sigma); end % 欧拉方程残差 residual(ia, iy) = c_policy(ia, iy)^(-sigma) - beta * (1 + r) * E_mu_next; end end % 用残差更新策略,这里用简单阻尼 c_policy = c_policy - 0.1 * residual; if max(abs(c_policy(:) - c_old(:))) < tol break; end end

逻辑说明:双重循环遍历资产和收入格点,interp1把下一期资产映射到已有网格上,P是收入转移矩阵。参数说明:beta是贴现因子,通常取 0.99;r是稳态利率,由资本边际产出决定;sigma同上。阻尼系数 0.1 是为了防止震荡,如果收敛太慢可以调到 0.05。这一步跑完后,务必检查消费策略是否随资产递增、随收入递增,如果出现非单调,说明网格太粗或插值外推出了问题。

3.3 步骤三:求稳态分布并加总总消费

有了消费策略,下一步是找家庭在资产和收入网格上的稳态分布。这本质上是一个马尔可夫链的平稳分布问题,但资产转移依赖于策略函数。我一般用迭代法:从均匀分布开始,每期按策略更新资产,再按收入转移矩阵更新收入,直到分布收敛。

% 求稳态分布 dist = ones(n_asset, n_income) / (n_asset * n_income); % 初始均匀 for iter = 1:1000 dist_new = zeros(n_asset, n_income); for ia = 1:n_asset for iy = 1:n_income a_next = (1 + r) * asset_grid(ia) + income_grid(iy) - c_policy(ia, iy); % 找到最近的两个资产格点做线性分配 [~, idx] = min(abs(asset_grid - a_next)); % 简化处理:直接放到最近格点,实际应用要线性拆分 for iy_next = 1:n_income dist_new(idx, iy_next) = dist_new(idx, iy_next) + dist(ia, iy) * P(iy, iy_next); end end end if max(abs(dist_new(:) - dist(:))) < 1e-8 break; end dist = dist_new; end % 加总总消费 C_agg = sum(sum(dist .* c_policy));

逻辑说明:dist是联合分布,每轮把当前分布按策略和收入转移推到下一期。参数说明:迭代上限 1000 是保险值,通常几百轮就收敛;idx用最近邻会引入离散化误差,正式代码里应该用线性插值把质量分到相邻两个格点。这一步的坑是资产上界和下界要足够宽,否则分布会在边界堆积,导致总消费被低估。

3.4 步骤四:嵌入新凯恩斯价格粘性并做线性化

家庭块解完后,要加回厂商的卡尔沃定价。常见做法是把整个模型在稳态附近做一阶线性化,写成状态空间形式,再用gensys或自己写的小型求解器求脉冲响应。MATLAB 里可以用lyap解离散李雅普诺夫方程,但更直接的是把线性化后的系统写成A * x_{t+1} = B * x_t + C * shock_t,然后用广义 Schur 分解。下面是一个简化框架。

% 线性化系统求解:A * x_{t+1} = B * x_t + C * eps_t % 这里 x 包含消费、通胀、利率、分布的一阶矩等 A = [1, 0, 0; 0, 1, 0; 0, 0, 1]; % 占位,实际按模型填 B = [0.9, -0.1, 0; 0.1, 0.8, 0.2; 0, 0, 0.7]; C = [0; 0; 1]; % 用广义 Schur 分解求政策函数 [AA, BB, Q, Z] = qz(A, B); % 这里需要按爆炸根和稳定根拆分,代码略长,建议用 Dynare 或 gensys

逻辑说明:qz是 MATLAB 自带的广义 Schur 分解,用来处理前向变量。参数说明:A、B、C的维度取决于你保留多少状态变量,HANK 里通常至少保留总消费、通胀、名义利率和分布的均值。这一步最容易翻车的地方是线性化点选错,比如在非稳态附近线性化,脉冲响应会发散。建议先用 RANK 版本验证求解器,再换 HANK 的系数矩阵。

3.5 步骤五:跑脉冲响应并检查加总一致性

最后一步是给一个货币政策冲击,看总消费、通胀和利率的响应。跑完后必须做两个检查:一是加总一致性,即个体消费按分布加权后等于总消费;二是与 RANK 对比,HANK 的消费响应通常更平缓,因为异质性家庭有预防性储蓄。如果发现 HANK 响应比 RANK 还大,大概率是分布没收敛或线性化系数错了。

% 脉冲响应模拟 T = 40; irf = zeros(3, T); shock = 1; % 一个标准差的货币政策冲击 for t = 1:T if t == 1 irf(:, t) = C * shock; else irf(:, t) = B * irf(:, t-1); % 简化形式,实际要用政策函数 end end plot(irf'); legend('消费', '通胀', '利率');

逻辑说明:irf存脉冲响应,shock是冲击大小。参数说明:T取 40 期通常够看收敛;C是冲击对状态的影响向量。这一步的坑是冲击符号搞反,导致响应方向相反,建议先用已知的 RANK 结果对照。

4. 避坑:HANK 复现里最容易翻车的五个地方

4.1 现象:分布迭代不收敛,总消费一直漂

原因:资产网格上界太窄,家庭把资产堆在边界,插值外推导致策略函数爆炸。解决:把资产上界设到稳态资产的两倍以上,并在边界加一个“不能超过”的约束,代码里用min处理。

4.2 现象:脉冲响应里通胀响应方向反了

原因:卡尔沃定价的对数线性化符号写错,或者利率规则里的通胀系数符号搞反。解决:先跑一个纯 RANK 版本,确认通胀对利率冲击的响应是负的,再换 HANK 系数。

4.3 现象:消费策略非单调,高资产家庭反而消费更低

原因:欧拉方程里的期望边际效用算错,常见的是转移矩阵没有归一化,或者插值用了spline导致过冲。解决:改用linear插值,并在每轮迭代后检查P的行和。

4.4 现象:MATLAB 内存爆掉,循环跑不动

原因:把资产、收入、时间三维都写成显式循环,矩阵维度爆炸。解决:把收入转移写成稀疏矩阵,资产插值用interp1的向量化调用,避免三重循环。

4.5 现象:稳态利率和贴现因子不匹配,欧拉方程残差很大

原因:beta和r没有满足稳态关系beta * (1 + r) = 1。解决:先校准beta,再反推r,或者把r设成资本边际产出,再调beta使残差最小。

5. 进阶:用似然比检验判断异质性是否真的重要

跑通最小版本后,下一个问题自然是:异质性到底有没有用?我的习惯是做一个似然比检验,把 HANK 和 RANK 当成两个非嵌套模型,用模拟矩匹配或贝叶斯因子比较。具体做法是:先选几个关键矩,比如消费增长的标准差、财富分布的基尼系数、货币政策冲击下消费响应的半衰期,然后看 HANK 能否在不过度拟合的情况下同时匹配这些矩。如果 RANK 也能匹配,那异质性就是多余的。MATLAB 里可以用simulannealbnd做矩匹配,但更稳的是自己写一个网格搜索,因为参数维度通常不高。

% 矩匹配目标函数示例 target_moments = [0.05, 0.6, 8]; % 消费增长标准差、财富基尼、半衰期 param_grid = linspace(0.8, 0.99, 20); % beta 网格 loss = zeros(size(param_grid)); for i = 1:length(param_grid) beta_try = param_grid(i); % 这里调用你的 HANK 求解器,返回模拟矩 sim_moments = run_hank(beta_try); loss(i) = sum((sim_moments - target_moments).^2); end [~, idx] = min(loss); beta_hat = param_grid(idx);

逻辑说明:run_hank是你封装好的求解函数,输入参数返回模拟矩。参数说明:target_moments来自数据或文献,param_grid范围要覆盖合理区间。这一步的坑是矩的选择,如果选了太多矩,HANK 容易过拟合;选太少,又区分不出 RANK。我一般选三个:一个关于消费波动,一个关于分布,一个关于政策传导。最后提醒一句:HANK 复现最耗时的不是写代码,而是等分布迭代收敛,所以每次改参数前先存一份工作区,免得从头再来。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/18 21:10:38

深度特征映射语音增强实战:从STFT特征到全连接网络训练全解析

简介&#xff1a;一套基于深度特征映射的语音增强工程实现&#xff0c;面向计算机专业学生与开发者&#xff0c;可支撑毕业设计、课程实训及公司项目二次开发。整套资源共一百四十四个文件&#xff0c;约五十七点八一兆字节&#xff0c;核心包含四十三个Python脚本、三十八个TX…

作者头像 李华
网站建设 2026/10/18 21:07:05

VS Code 接入 MCP 服务:打造 AI 数据工作站完整指南

我个人一直觉得&#xff0c;VS Code 是个越用越“重”的编辑器&#xff0c;但这个“重”不是贬义——它意味着你可以把一大堆工具塞进去&#xff0c;让所有开发动作都在同一个窗口里完成。最近我把它正式改造成了 AI 工作站&#xff0c;核心就是接入了 Ace Data Cloud 的 MCP 服…

作者头像 李华
网站建设 2026/10/18 21:05:00

wxWidgets 3.2.8 与 Code::Blocks 25.03 配置实战:从编译到运行避坑指南

简介&#xff1a;这份资源是已预先配置好 wxWidgets 3.2.8 的 CodeBlocks 25.03 集成开发环境&#xff0c;面向希望快速上手 C 跨平台 GUI 开发的新手与有经验的开发者&#xff0c;省去手动编译配置 wxWidgets 库的繁琐过程。压缩包为 7z 格式&#xff0c;整体约 600.98MB&…

作者头像 李华
网站建设 2026/10/18 21:04:30

BrowserSkill:基于CDP的浏览器能力命令行操作系统

1. 项目概述&#xff1a;BrowserSkill 不是浏览器插件&#xff0c;而是一套面向开发者的工作流操作系统BrowserSkill 这个名字乍一听像某个 Chrome 扩展&#xff0c;但实际完全不是。我第一次在 GitHub 上看到它时也误以为是类似 Tampermonkey 的脚本管理器&#xff0c;直到 cl…

作者头像 李华
网站建设 2026/10/18 21:00:24

前后端分离项目中的Session认证实践:跨域Cookie与CORS配置指南

A同学前两天找我诉苦&#xff1a;他们组正把一个老管理系统拆成前后端分离项目&#xff0c;前端单独部署&#xff0c;后端API也单独部署&#xff0c;结果刚开工&#xff0c;认证方案就先吵起来了。团队里好几个人强烈建议换掉原先的Session登录&#xff0c;改用无状态Token&…

作者头像 李华
网站建设 2026/10/18 21:00:12

大比例尺地理实体转换规程:从要素到实体的生产实战指南

简介&#xff1a;面向基础地理信息专业人员和技术管理人员&#xff0c;这份技术规程系统规定了1∶500、1∶1 000、1∶2 000比例尺基础地理信息要素数据转换为基础地理实体数据的技术流程。正文按范围、引用文件、术语定义、基本要求、作业流程、源数据收集分析、预处理、映射转…

作者头像 李华