# Adapting BCW To Your Model Use this page once you can reproduce BCW and the question becomes: how do I change the economics without breaking the numerical structure all at once? Read it after the four BCW walkthroughs and [Modeling Guide](./modeling-guide.md). If you are not using BCW as the starting template, return to [Library Quickstart](./quickstart-library.md) instead. The guiding principle is simple: - copy the BCW structure aggressively, - change the economics gradually, - re-validate after every small step. Treat the four BCW walkthroughs as the theory-to-code source material. This page starts after you already understand how each paper equation was turned into a `Parameter` / `Boundary` / `PolicyDict` / `Policy` / `Model` implementation. ## Suggested Prerequisites - [Getting Started](./getting-started.md) - [BCW2011 Liquidation Walkthrough](./bcw2011-liquidation-walkthrough.md) - [BCW2011 Refinancing Walkthrough](./bcw2011-refinancing-walkthrough.md) - [BCW2011 Hedging Walkthrough](./bcw2011-hedging-walkthrough.md) - [BCW2011 Credit Line Walkthrough](./bcw2011-credit-line-walkthrough.md) - [Modeling Guide](./modeling-guide.md) ## Choose The Right Starting Template | Your model resembles... | Best starting file | |---|---| | one state variable, one control, liquidation at the left edge, endogenous payout boundary | `src/example/BCW2011Liquidation.py` | | one state variable, one control, equity issuance or cash-target smooth pasting | `src/example/BCW2011Refinancing.py` | | one state variable, two controls, hedge demand, or control-dependent variance | `src/example/BCW2011Hedging.py` | | one state variable with debt and cash regions, or a state domain that crosses zero | `src/example/BCW2011CreditLine.py` | If you are unsure, start from liquidation. It is easier to debug one control than two, and it gives you the cleanest reference for the payout-side boundary logic. Also keep the execution contract unchanged while you adapt a case: run from the repository root and keep imports in the BCW style `from src.example.bcw2011 import ...`. Do not reintroduce relative imports or local-directory execution assumptions inside `src/example/`. ## What You Can Usually Reuse Almost Verbatim The following parts are often reusable with only renaming: - the overall file structure, - the `Parameter` / `Boundary` / `PolicyDict` / `Policy` / `Model` split, - the `Solver(...)` construction pattern, - the diagnostic code that prints `grid.boundary`, `grid.df.head()`, and `grid.df.tail()`, - save/load patterns for solved outputs. This is a feature, not a weakness. The whole point of learning BCW first is to inherit a clean one-dimensional HJB workflow. ## What You Must Re-Think Carefully These are the parts you should not copy blindly: - the economic parameter list, - the HJB residual signs and drift terms, - policy formulas and first-order conditions, - boundary-value formulas, - the boundary-search target, - any refinancing or issuance logic, - interpretation of policy columns. If you copy these mechanically, the code may run while solving the wrong model. ## Recommended Migration Order ## Step 1: Duplicate A BCW Script Create a new working file by copying the closest BCW example. Do not start from a blank file unless you already know the package internals very well. ## Step 2: Rename The Economic Objects Rename: - `Parameter` - `PolicyDict` - `Boundary` - `Policy` - `Model` Even if the code is still BCW under the hood, renaming early helps you keep the new model mentally separate. ## Step 3: Replace Parameters First Edit only the `Parameter` class first. Success condition: - the file still imports, - the solver still constructs, - any derived parameter logic is clear and local. Do not touch the residual yet. ## Step 4: Get A Fixed-Boundary Solve Working Before boundary search, aim for: ```python state, history = solver.solve() ``` Why this matters: - it isolates HJB and policy logic from boundary-search logic, - it tells you whether the base equations are coherent, - it gives you a clean debugging surface. First checks: ```python print(type(state).__name__) print(state.df.head()) print(state.df.tail()) ``` ## Step 5: Replace The Policy Logic Implement your actual controls next. Decision rule: - use `@explicit_policy` if you have a direct update, - use `@implicit_policy` if your control is naturally defined through a residual or FOC. Validate after this step: - every required policy key exists, - each array matches the grid length, - the resulting policy columns look economically interpretable. ## Step 6: Replace The HJB Residual Only after the policy is coherent should you rewrite `Model.hjb_residual`. Good practice: - keep the residual algebra readable, - assign intermediate terms meaningful names, - compare each term against your theoretical equation. Bad practice: - writing the whole residual in one dense line and then trying to debug sign errors by inspection. ## Step 7: Re-Introduce Endogenous Boundaries Once the fixed-boundary solve is stable, choose the right workflow: - `boundary_search()` if a condition such as `d2v[-1] = 0` determines a boundary, - `boundary_update()` if the solved grid implies a new boundary directly, - both, if your model truly needs both stages. Do not add this layer before the fixed-boundary baseline works. ## Step 8: Add Persistence And Diagnostics After you trust the solve, add: - `grid.save(...)`, - `load_grid(...)`, - continuation or sensitivity runs if needed, - plots or custom auxiliary diagnostics. This is the right time to make analysis convenient, because now you have something worth analyzing. ## A Good Validation Ladder At each stage, ask only one question: 1. does the file import? 2. does `Solver(...)` construct? 3. does `solve()` return a sensible state? 4. do the value/policy curves have the right shape? 5. do boundary conditions hold? 6. only then: do comparative statics make sense? That ordering prevents you from trying to interpret economics from a numerically broken object. ## What To Copy From BCW, Specifically ### Usually safe to copy - the class layout, - typed `PolicyDict` declarations, - the pattern `Boundary(p=parameter, s_min=..., s_max=...)`, - `Solver(..., number=..., config=...)`, - result inspection snippets. ### Must be rewritten - parameter values and meanings, - boundary formulas, - FOC logic, - HJB drift/diffusion terms, - boundary targets, - economic interpretation text. ## Common Migration Mistakes ### Changing everything at once If you simultaneously change: - parameters, - boundaries, - controls, - residual, - search target, then a failure gives you no clue where to look. ### Starting with sensitivity analysis Continuation is valuable, but it is a multiplier on top of a base solve. If the base solve is wrong, sensitivity analysis only generates more wrong solves. ### Keeping BCW diagnostics but forgetting BCW assumptions changed Example: - `d2v[-1]` is central for BCW's payout-side condition, - but your model might require a different right-boundary condition. Reuse the diagnostic pattern, not the literal target without thought. ## A Suggested Work Sequence For Researchers 1. reproduce liquidation unchanged, 2. reproduce the closest advanced BCW case unchanged: refinancing for issuance boundaries, hedging for two controls, credit line for piecewise state regions, 3. fork the closer example, 4. change parameters and names, 5. get `solve()` stable, 6. add your actual boundary logic, 7. write down your own success checks, 8. only then begin comparative statics or paper tables. ## When To Move Beyond Liquidation As A Template Move to the refinancing template if your model needs: - issuance with value matching at the left edge, - an interior cash target `m`, - smooth pasting around an issuance point. Move to the hedging template if your model needs: - more than one control, - control-dependent state variance, - costly or constrained hedge demand. Move to the credit-line template if your model needs: - separate debt and cash regions, - a state domain with `s_min < 0`, - different HJB residuals on different parts of the state grid. If none of those apply, staying closer to liquidation keeps the code easier to reason about. ## Final Rule Of Thumb The first successful custom model should be boring. That means: - one file, - clear class boundaries, - a stable fixed-boundary solve, - obvious diagnostics, - only one new economic idea at a time. That "boring" path is the fastest way to get to a credible research workflow. ## Related Pages - Return to [Modeling Guide](./modeling-guide.md) for interface details. - Return to [Solver Guide](./solver-guide.md) for workflow decisions. - Use [Results and Diagnostics](./results-and-diagnostics.md) to build a success checklist after each change.