把 BCW 改成你自己的模型#

当你已经能复现 BCW,而问题变成“怎样改经济设定、又不要一次把数值结构改崩”时,就应该看这一页。

建议在四个 BCW walkthrough 和 建模指南 之后阅读。如果你根本不打算把 BCW 当模板,而是直接从自己的问题开始建模,请改看 库快速上手

核心原则很简单:

  • 结构尽量大胆复用 BCW,

  • 经济设定逐步改,

  • 每改一步都重新验证。

四个 BCW walkthrough 应该被当成“理论到代码”的底稿来读。这一页默认你已经理解论文方程是怎样落到 Parameter / Boundary / PolicyDict / Policy / Model 上的。

建议先具备的上下文#

先选对模板#

你的模型更像……

最适合起步的模板

一维状态、一个控制、左端 liquidation、右端内生 payout 边界

src/example/BCW2011Liquidation.py

一维状态、一个控制、带股权发行或内部现金目标 m

src/example/BCW2011Refinancing.py

一维状态、两个控制、对冲需求或控制影响方差

src/example/BCW2011Hedging.py

一维状态跨越债务区和现金区,或状态域需要穿过零点

src/example/BCW2011CreditLine.py

如果拿不准,先从 liquidation 开始。一个控制总比两个控制更容易调,而且它给了你最干净的 payout-side 边界基线。

另外,在你开始改写之前,先保持这套执行约定不变:从仓库根目录运行,并继续使用 from src.example.bcw2011 import ... 这一类绝对导入。不要再把相对导入或“切进 src/example/ 本地直跑”的假设带回来。

哪些部分通常可以原样复用#

下面这些结构,很多时候可以几乎照搬:

  • 整个文件的组织方式;

  • Parameter / Boundary / PolicyDict / Policy / Model 的分工;

  • Solver(...) 的构造模式;

  • 打印 grid.boundarygrid.df.head()grid.df.tail() 的诊断代码;

  • 保存和重载结果的写法。

这并不是“偷懒”,恰恰是 BCW 主线存在的价值:让你先继承一个稳定的一维 HJB 工作流。

哪些部分绝不能盲抄#

以下内容必须重新思考,而不能机械复制:

  • 经济参数列表;

  • HJB 残差中的符号和漂移项;

  • 控制变量的 FOC 或显式策略;

  • 边界值公式;

  • 边界搜索目标;

  • 再融资或发行逻辑;

  • 结果的经济解释。

如果这些部分不重写,你的代码可能“能跑”,但解的其实不是你的模型。

推荐迁移顺序#

第一步:复制最接近的 BCW 脚本#

先复制最像你目标问题的 BCW 文件,不要从空白文件开始。

除非你已经非常熟悉 FinHJB 内部接口,否则从零写会让你同时处理太多不确定性。

第二步:先改名字#

尽早把这些类改成你自己的语义命名:

  • Parameter

  • PolicyDict

  • Boundary

  • Policy

  • Model

即便底层逻辑暂时还是 BCW,先把概念边界划清楚,会让你后续不容易混淆。

第三步:先只改参数#

第一轮只改 Parameter 类。

这一阶段的成功标准是:

  • 文件还能导入;

  • Solver(...) 还能构造;

  • 派生参数逻辑是清晰、局部且可解释的。

先不要动残差。

第四步:先让固定边界求解稳定#

在引入边界搜索之前,先争取让下面这个最简单工作流跑通:

state, history = solver.solve()

为什么这一步很关键:

  • 它把 HJB 主体和边界搜索分开了;

  • 它能先告诉你方程和策略是否自洽;

  • 调试面最干净。

第一批检查建议是:

print(type(state).__name__)
print(state.df.head())
print(state.df.tail())

第五步:再替换策略逻辑#

接着实现你真正需要的控制变量。

一个实用决策规则:

  • 有稳定闭式更新,用 @explicit_policy

  • 更自然地写成残差或 FOC,就用 @implicit_policy

这一阶段要确认:

  • 所有策略键都存在;

  • 每个数组长度和网格一致;

  • 求出来的策略列至少能被经济学解释。

第六步:再替换 HJB 残差#

只有当策略层已经清楚之后,再改 Model.hjb_residual

好的做法:

  • 把残差拆成有含义的中间项;

  • 每一项都能对应回你的理论方程;

  • 用变量名表达经济含义。

不好的做法:

  • 把整个残差塞成一行,再靠肉眼找符号错。

第七步:最后再引入内生边界#

当固定边界求解已经稳定后,再决定用哪种边界工作流:

  • 如果边界通过一个数值条件来确定,用 boundary_search()

  • 如果当前解可以直接推出新的边界,用 boundary_update()

  • 只有当模型确实需要时,才把两者都加进来。

不要在固定边界都还没稳定时,就先加这一层复杂度。

第八步:最后补上保存和诊断#

当你已经相信这个解可信之后,再加入:

  • grid.save(...)

  • load_grid(...)

  • continuation / sensitivity

  • 图形或自定义辅助诊断

这时再做分析工具建设,效率最高,因为你已经有一个值得分析的对象。

一条很稳的验证阶梯#

每一步只回答一个问题:

  1. 文件能导入吗?

  2. Solver(...) 能构造吗?

  3. solve() 能返回一个像样的 state 吗?

  4. 价值函数和策略形状合理吗?

  5. 边界条件满足了吗?

  6. 最后才问 comparative statics 是否合理。

这个顺序能避免你对一个数值上本来就坏掉的对象做经济解释。

具体说,哪些 BCW 部分可以抄,哪些必须改#

通常可以直接复用的#

  • 类的分层结构;

  • PolicyDict 的类型声明方式;

  • Boundary(p=parameter, s_min=..., s_max=...) 的组织模式;

  • Solver(..., number=..., config=...) 的写法;

  • 打印和保存结果的诊断套路。

必须重写的#

  • 参数值和参数含义;

  • 边界公式;

  • FOC 逻辑;

  • HJB 漂移和扩散项;

  • 边界目标函数;

  • 结果的经济解释。

迁移时最常见的错误#

一次把所有东西都改了#

如果你同时改:

  • 参数,

  • 边界,

  • 控制变量,

  • 残差,

  • 搜索目标,

那么一旦失败,你几乎无法定位到底是哪一层出了问题。

还没跑稳 baseline 就开始做 sensitivity analysis#

continuation 很有价值,但它只是把基础求解放大很多次。如果 base solve 本身是错的,sensitivity 只会生成更多错误解。

还用 BCW 的诊断规则,但 BCW 的边界条件早就不适用了#

例如:

  • d2v[-1] 对 BCW 的 payout-side 条件非常关键;

  • 但你的模型右边界条件可能根本不是这一条。

你可以复用“诊断的习惯”,不能无脑复用“诊断的对象”。

给研究者的推荐工作流#

  1. 先一字不改地复现 liquidation;

  2. 再一字不改地复现最接近你的高级 BCW 案例:发行边界用 refinancing,双控制用 hedging,分段状态域用 credit line;

  3. 复制更接近你的那个示例;

  4. 先改参数和命名;

  5. 先让 solve() 稳定;

  6. 再加你的边界逻辑;

  7. 为自己的模型写一套成功检查点;

  8. 最后才做 comparative statics、图表和论文数值结果。

什么时候该从 liquidation 切到别的模板#

当你的模型需要下面这些结构时,更适合切到 refinancing:

  • 左边界有发行 value matching;

  • 存在内部现金目标 m

  • 需要围绕发行点做 smooth pasting。

当你的模型需要下面这些结构时,更适合切到 hedging:

  • 多于一个控制变量;

  • 方差项本身受控制变量影响;

  • 对冲需求带有成本或约束。

当你的模型需要下面这些结构时,更适合切到 credit line:

  • 债务区和现金区的 HJB 不一样;

  • 状态域需要 s_min < 0

  • 同一条网格上要拼接分段 residual。

如果都没有,尽量留在 liquidation 这条更简单的主线,会更容易调试。

最后一条经验法则#

第一个成功的自定义模型,最好是“朴素的”。

所谓朴素,意思是:

  • 一个文件先跑通;

  • 类职责清晰;

  • 固定边界先稳定;

  • 诊断项简单直接;

  • 每次只引入一个新的经济想法。

这条“看上去不花哨”的路径,往往反而是最快进入可信研究工作流的方式。

相关页面#