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.1.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.1-py3-none-any.whl (38.7 kB view details)

Uploaded Python 3

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

Hashes for finhjb-0.1.1.tar.gz
Algorithm Hash digest
SHA256 c46c3120e5a5958ae4cfaa2fbbd5fb0448bd2e0b5af96f14c041b4d7d1d52c93
MD5 d506b72fee36fbd60ea1d79dbcf98dc4
BLAKE2b-256 d4a5982bf74dd8e3f083bc0c9a5b1f962508aaa3c0bb92759039c4fd51f2d9bf

See more details on using hashes here.

Provenance

The following attestation bundles were made for finhjb-0.1.1.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.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

Hashes for finhjb-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 5fa1f7d1a18eec0a7a5feac5040489e0ea31665cf376d08f1cd8447d2c34370d
MD5 43319ec30974ef169639a9e093dbfc01
BLAKE2b-256 5b3acdc1d57f7618fb9464f4f5708472a7f884b8a559d47fffe38f85d4ce48b2

See more details on using hashes here.

Provenance

The following attestation bundles were made for finhjb-0.1.1-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