Skip to main content

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_policy and @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:

  1. Parameter: immutable model parameters
  2. Boundary: state/value boundaries
  3. Policy: policy variable initialization and update rules
  4. Model: 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_newton
  • lm
  • broyden
  • lbfgs
  • bisection
  • hybr
  • broyden1
  • krylov

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:

  • Config
  • Solver
  • Grid, Grids, ImmutableBoundary
  • AbstractBoundary, BoundaryConditionTarget
  • AbstractModel, AbstractParameter
  • AbstractPolicy, AbstractPolicyDict
  • explicit_policy, implicit_policy
  • LinearInitialValue, QuadraticInitialValue
  • load

Examples

Two complete examples are available in:

  • src/example/BCW2011Liquidation.py
  • src/example/BCW2011Hedging.py

They show full model construction, solver configuration, and boundary search.

Documentation

Additional guides are in docs/:

  • docs/getting-started.md
  • docs/modeling-guide.md
  • docs/solver-guide.md
  • docs/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

finhjb-0.1.2.tar.gz (27.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

finhjb-0.1.2-py3-none-any.whl (38.7 kB view details)

Uploaded Python 3

File details

Details for the file finhjb-0.1.2.tar.gz.

File metadata

  • Download URL: finhjb-0.1.2.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

Hashes for finhjb-0.1.2.tar.gz
Algorithm Hash digest
SHA256 4cdccab544790884b87027e78751bc5102345fb0a50ebcb76209908db18e5ac8
MD5 b47d0f72641a7109cad08fb0ce99321f
BLAKE2b-256 20bed75762a15eff16a1bcb8aa4bfa920e2a023f02981b54a136317e8c4f0a07

See more details on using hashes here.

Provenance

The following attestation bundles were made for finhjb-0.1.2.tar.gz:

Publisher: python-publish.yml on Su-luoya/FinHJB

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file finhjb-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: finhjb-0.1.2-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

Hashes for finhjb-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 0429b4a7fac8c263c267a161493ffb5dbff32b6a7139fe60be9cd407338496b4
MD5 c711dfe2424e4031c51404132883c1df
BLAKE2b-256 0d09fb3b8357ada652481301fa93b97422cd8f06f065fc282ad8ac18d65747cd

See more details on using hashes here.

Provenance

The following attestation bundles were made for finhjb-0.1.2-py3-none-any.whl:

Publisher: python-publish.yml on Su-luoya/FinHJB

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page