This is a Python library for solving Hamilton-Jacobi-Bellman (HJB) equations using JAX. It provides a framework for numerical solutions to dynamic optimization problems in finance and economics.
Project description
FinHJB
FinHJB is a Python library for solving one-dimensional Hamilton-Jacobi-Bellman (HJB) problems with JAX.
It provides a structured workflow for:
- defining model parameters, boundaries, policy rules, and residual equations,
- solving with policy iteration,
- searching for optimal boundaries,
- running parameter sensitivity analysis.
The package is built around typed interfaces (AbstractModel, AbstractPolicy, AbstractBoundary, AbstractParameter) and a high-level orchestrator (Solver).
Features
- JAX-based numerical core with optional JIT compilation
- Flexible policy updates via
@explicit_policyand@implicit_policy - Multiple boundary search methods (
gauss_newton,lm,broyden,lbfgs,bisection,hybr,broyden1,krylov) - Built-in continuation workflow for parameter paths (
sensitivity_analysis) - Serializable result containers (
Grid,Grids,SensitivityResult)
Installation
This project requires Python >=3.13.
Install from source in editable mode:
pip install -e .
If you use uv:
uv sync
To include the development dependency group with uv:
uv sync --group dev
Quick Start
The minimal workflow has 4 pieces:
Parameter: immutable model parametersBoundary: state/value boundariesPolicy: policy variable initialization and update rulesModel: HJB residual and optional boundary conditions
Then pass them to Solver.
from dataclasses import dataclass
import jax.numpy as jnp
from jaxtyping import Array
import finhjb as fjb
class Parameter(fjb.AbstractParameter):
r: float = 0.06
sigma: float = 0.10
theta: float = 1.5
class PolicyDict(fjb.AbstractPolicyDict):
investment: Array
@dataclass
class Boundary(fjb.AbstractBoundary[Parameter]):
@staticmethod
def compute_v_left(p: Parameter) -> float:
return 0.9
@staticmethod
def compute_v_right(p: Parameter, s_max: float) -> float:
return 1.0 + 0.1 * s_max
@dataclass
class Policy(fjb.AbstractPolicy):
@staticmethod
def initialize(grid: fjb.Grid, p: Parameter) -> PolicyDict:
return PolicyDict(investment=jnp.full_like(grid.s, 0.1))
@staticmethod
@fjb.explicit_policy(order=1)
def update_investment(grid: fjb.Grid) -> fjb.Grid:
grid.policy["investment"] = jnp.maximum(1e-6, 0.5 * grid.v / grid.dv)
return grid
@dataclass
class Model(fjb.AbstractModel[Parameter, PolicyDict]):
@staticmethod
def hjb_residual(v, dv, d2v, s, policy, jump, boundary, p):
inv = policy["investment"]
return -p.r * v + (s - inv) * dv + 0.5 * p.sigma**2 * d2v
parameter = Parameter()
boundary = Boundary(p=parameter, s_min=0.0, s_max=0.2)
model = Model(policy=Policy())
config = fjb.Config(
pi_method="scan",
pi_max_iter=50,
pi_tol=1e-8,
)
solver = fjb.Solver(
boundary=boundary,
model=model,
policy_guess=True,
number=500,
config=config,
)
state, history = solver.solve()
print(state.converged, state.best_error)
df = state.df
Boundary Search
If your model provides boundary_condition() targets, you can search for boundaries directly:
search_state = solver.boundary_search(method="bisection", verbose=True)
print(search_state.optimal_boundary)
print(search_state.best_error)
Supported methods:
gauss_newtonlmbroydenlbfgsbisectionhybrbroyden1krylov
Sensitivity Analysis
Run path-following continuation on one parameter:
import jax.numpy as jnp
result = solver.sensitivity_analysis(
method="hybr",
param_name="sigma",
param_values=jnp.linspace(0.05, 0.20, 10),
)
print(result.df.head())
Save and Load
Main objects support pickle-based save/load:
Grid.save(path)Grids.save(path)SensitivityResult.save(path)fjb.load(path)
state.grid.save("single_grid")
loaded = fjb.load("single_grid")
Public API
Top-level exports include:
ConfigSolverGrid,Grids,ImmutableBoundaryAbstractBoundary,BoundaryConditionTargetAbstractModel,AbstractParameterAbstractPolicy,AbstractPolicyDictexplicit_policy,implicit_policyLinearInitialValue,QuadraticInitialValueload
Examples
Two complete examples are available in:
src/example/BCW2011Liquidation.pysrc/example/BCW2011Hedging.py
They show full model construction, solver configuration, and boundary search.
Documentation
Additional guides are in docs/:
docs/getting-started.mddocs/modeling-guide.mddocs/solver-guide.mddocs/api-reference.md
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file finhjb-0.1.1.tar.gz.
File metadata
- Download URL: finhjb-0.1.1.tar.gz
- Upload date:
- Size: 27.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c46c3120e5a5958ae4cfaa2fbbd5fb0448bd2e0b5af96f14c041b4d7d1d52c93
|
|
| MD5 |
d506b72fee36fbd60ea1d79dbcf98dc4
|
|
| BLAKE2b-256 |
d4a5982bf74dd8e3f083bc0c9a5b1f962508aaa3c0bb92759039c4fd51f2d9bf
|
Provenance
The following attestation bundles were made for finhjb-0.1.1.tar.gz:
Publisher:
python-publish.yml on Su-luoya/FinHJB
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
finhjb-0.1.1.tar.gz -
Subject digest:
c46c3120e5a5958ae4cfaa2fbbd5fb0448bd2e0b5af96f14c041b4d7d1d52c93 - Sigstore transparency entry: 1059479616
- Sigstore integration time:
-
Permalink:
Su-luoya/FinHJB@33b72981cc30cae4445d882b40b7b8a0c36c71a6 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/Su-luoya
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@33b72981cc30cae4445d882b40b7b8a0c36c71a6 -
Trigger Event:
release
-
Statement type:
File details
Details for the file finhjb-0.1.1-py3-none-any.whl.
File metadata
- Download URL: finhjb-0.1.1-py3-none-any.whl
- Upload date:
- Size: 38.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5fa1f7d1a18eec0a7a5feac5040489e0ea31665cf376d08f1cd8447d2c34370d
|
|
| MD5 |
43319ec30974ef169639a9e093dbfc01
|
|
| BLAKE2b-256 |
5b3acdc1d57f7618fb9464f4f5708472a7f884b8a559d47fffe38f85d4ce48b2
|
Provenance
The following attestation bundles were made for finhjb-0.1.1-py3-none-any.whl:
Publisher:
python-publish.yml on Su-luoya/FinHJB
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
finhjb-0.1.1-py3-none-any.whl -
Subject digest:
5fa1f7d1a18eec0a7a5feac5040489e0ea31665cf376d08f1cd8447d2c34370d - Sigstore transparency entry: 1059479617
- Sigstore integration time:
-
Permalink:
Su-luoya/FinHJB@33b72981cc30cae4445d882b40b7b8a0c36c71a6 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/Su-luoya
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@33b72981cc30cae4445d882b40b7b8a0c36c71a6 -
Trigger Event:
release
-
Statement type: