Skip to main content

itofin

Idiomatic Python bindings over the libitofin Rust core, a ground-up port of QuantLib for pricing, risk, and calibration. The heavy numerics run in Rust; Python drives them. The pricing snippets below reproduce the cached Rust test oracles exactly; the abbreviated calibration snippets converge to the same targets within the tests' calibration tolerance (the full matrices live in tests/).

The API mirrors QuantLib's ql/ layout: types live in submodules (itofin.time, itofin.instruments, itofin.models, ...), while Settings and ItofinError stay at the top level.

Source API guides: currency fields, currency presets including TWD, and Black FX delta conventions. These helpers do not add currency rounding, conversion or a new option pricing engine.

Standalone constant-parameter GSR process bindings expose forward-measure transitions, not a fitted GSR model.

Pricing and process binding guides

Scope Guide Example
Ordinary bond coupon helpers BPS and ATM rate Example
Price-fed bond ATM Price-fed ATM Example
European asset-or-nothing FD pricing Asset digitals Example
European signed gap FD pricing Gap options Example
European percentage-strike FD pricing Percentage-strike options Example
Amortizing fixed-rate bonds Fixed amortization Example
Amortizing plain-Ibor bonds Ibor amortization Example
European analytic cash digitals Cash-or-nothing Example
Standalone Gaussian state process MF state Example
Standalone live-curve forward process Hull-White forward Example
Constant-notional Ibor cross-currency swaps Xccy basis Example

These helpers do not complete the wider BondFunctions overload set. The process facades are not fitted models; cash digitals cover European analytic Black-Scholes pricing, and Xccy spot is an immutable snapshot. Asset/gap FD pricing retains documented grid limitations. Amortizing constructors cover only positive, nonincreasing balances.

Install

pip install itofin

Python versions

itofin ships a single abi3 wheel that runs on CPython 3.10, 3.11, 3.12, and 3.13+. Python 3.13 is the primary, tested target; 3.10 through 3.12 are supported through the stable ABI.

Price a European option and its greeks

from itofin import Settings
from itofin.instruments import OptionType, VanillaOption
from itofin.processes import BlackScholesProcess
from itofin.time import Date, DayCounter

s = Settings()
s.set_evaluation_date(Date(15, 6, 2026))
dc = DayCounter.actual360()

process = BlackScholesProcess(60.0, 0.08, 0.0, 0.30, Date(15, 6, 2026), dc)
option = VanillaOption(OptionType.Call, 65.0, Date(15, 6, 2026) + 90, s)
option.set_engine(process)

print(f"NPV   {option.npv():.10f}")
print(f"delta {option.delta():.10f}")
print(f"vega  {option.vega():.10f}")
print(f"rho   {option.rho():.10f}")
NPV   2.1333684449
delta 0.3724827980
vega  11.3515440535
rho   5.0538998582

Price under Heston and calibrate to a flat-vol surface

Semi-analytic Heston pricing:

from itofin import Settings
from itofin.instruments import OptionType, VanillaOption
from itofin.models import HestonModel
from itofin.processes import HestonProcess
from itofin.time import Date, DayCounter

s = Settings()
s.set_evaluation_date(Date(27, 12, 2004))
dc = DayCounter.actual_actual_isda()

# HestonProcess(risk_free, dividend, spot, v0, kappa, theta, sigma, rho, reference_date, day_counter)
process = HestonProcess(
    0.0225, 0.02, 1.0, 0.1, 3.16, 0.09, 0.4, -0.2, Date(27, 12, 2004), dc
)
model = HestonModel(process)
option = VanillaOption(OptionType.Call, 1.05, Date(28, 3, 2005), s)
option.set_heston_engine(model, 64)

print(f"Heston NPV {option.npv():.10f}")
Heston NPV 0.0404774515

Calibrating the model to a flat 10% vol surface drives the vol-of-vol sigma toward zero and both v0 and theta toward the flat variance (0.10 squared = 0.01). The snippet below fits a 3-maturity by 3-strike grid; the full 21-helper matrix and its tighter tolerances live in tests/test_heston_calibration.py.

import math

from itofin import Settings
from itofin.models import CalibrationErrorType, HestonModel, HestonModelHelper
from itofin.optimization import EndCriteria, LevenbergMarquardt
from itofin.processes import HestonProcess
from itofin.termstructures import FlatForward
from itofin.time import Calendar, Date, DayCounter, Period

s = Settings()
s.set_evaluation_date(Date(15, 1, 2026))
dc = DayCounter.actual360()
ref = Date(15, 1, 2026)
risk_free = FlatForward(ref, 0.04, dc)
dividend = FlatForward(ref, 0.50, dc)
VOL = 0.10

helpers = []
for n in (1, 2, 3):
    tau = float(n)
    forward = dividend.discount(tau) / risk_free.discount(tau)  # spot = 1.0
    for moneyness in (-1.0, 0.0, 1.0):
        strike = forward * math.exp(-moneyness * VOL * math.sqrt(tau))
        helpers.append(HestonModelHelper(
            Period(n, "Years"),
            Calendar.null_calendar(),
            1.0,        # spot
            strike,
            VOL,        # 10% flat vol
            0.04,       # risk-free
            0.50,       # dividend yield
            CalibrationErrorType.RelativePriceError,
            ref,
            dc,
            s,
        ))

process = HestonProcess(0.04, 0.50, 1.0, 0.01, 0.2, 0.02, 0.5, -0.75, ref, dc)
model = HestonModel(process)
method = LevenbergMarquardt(1e-8, 1e-8, 1e-8, False)
end_criteria = EndCriteria(400, 40, 1e-8, 1e-8, 1e-8)
model.calibrate(helpers, method, end_criteria, 96)

print(f"sigma {model.sigma():.6f}")
print(f"v0    {model.v0():.6f}")
print(f"theta {model.theta():.6f}")
sigma 0.000216
v0    0.010000
theta 0.010000

Calibrate Hull-White to a swaption matrix

from itofin import Settings
from itofin.indexes import Euribor
from itofin.models import CalibrationErrorType, HullWhite, SwaptionHelper
from itofin.optimization import EndCriteria, LevenbergMarquardt
from itofin.termstructures import FlatForward
from itofin.time import Date, DayCounter, Period

s = Settings()
s.set_evaluation_date(Date(15, 2, 2002))
curve = FlatForward(Date(19, 2, 2002), 0.04875825, DayCounter.actual365_fixed())

model = HullWhite(curve, 0.1, 0.01)
index = Euribor.six_months(curve, s)

# (option tenor, swap tenor, Black vol); the full co-terminal matrix is in the tests.
swaptions = [(1, 5, 0.1148), (2, 4, 0.1108), (3, 3, 0.1070), (4, 2, 0.1021), (5, 1, 0.1000)]
helpers = [
    SwaptionHelper(
        Period(maturity, "Years"),
        Period(length, "Years"),
        vol,
        index,
        Period(1, "Years"),
        DayCounter.thirty360_bond_basis(),
        DayCounter.actual360(),
        curve,
        CalibrationErrorType.RelativePriceError,
        1.0,
    )
    for maturity, length, vol in swaptions
]

method = LevenbergMarquardt(1e-8, 1e-8, 1e-8, False)
end_criteria = EndCriteria(10000, 100, 1e-6, 1e-8, 1e-8)
model.calibrate(helpers, method, end_criteria, False)  # fix_reversion=False, fit a and sigma

print(f"a     {model.a():.7f}")
print(f"sigma {model.sigma():.7f}")
a     0.0464113
sigma 0.0057992

Price a European swaption with the Jamshidian engine

from itofin import Settings
from itofin.indexes import Euribor
from itofin.instruments import (
    EuropeanExercise,
    SettlementMethod,
    SettlementType,
    Swaption,
    SwapType,
    VanillaSwap,
)
from itofin.models import HullWhite
from itofin.termstructures import FlatForward
from itofin.time import BusinessDayConvention, Calendar, Date, DayCounter, Frequency, Schedule

s = Settings()
s.set_evaluation_date(Date(15, 1, 2026))
curve = FlatForward(Date(15, 1, 2026), 0.03, DayCounter.actual365_fixed())

fixed = Schedule(
    Date(15, 1, 2028), Date(15, 1, 2033),
    Frequency.Annual, Calendar.target(),
    BusinessDayConvention.Unadjusted,
)
floating = Schedule(
    Date(15, 1, 2028), Date(15, 1, 2033),
    Frequency.Semiannual, Calendar.target(),
    BusinessDayConvention.Unadjusted,
)
index = Euribor.six_months(curve, s)

swap = VanillaSwap(
    SwapType.Payer, 100.0,
    fixed, 0.03, DayCounter.thirty360_bond_basis(),
    floating, index, 0.0, DayCounter.actual360(), s,
)
swaption = Swaption(
    swap, EuropeanExercise(Date(15, 1, 2027)),
    SettlementType.Physical, SettlementMethod.PhysicalOTC, s,
)
swaption.set_jamshidian_engine(HullWhite(curve, 0.05, 0.01))

print(f"payer swaption NPV {swaption.npv():.10f}")
payer swaption NPV 1.5666103956

Draw random numbers as NumPy arrays

The generators under itofin.randomnumbers carry QuantLib's Python names. Sequence generators return NumPy arrays, and next_sequences(count) draws a whole (count, dimension) matrix in one call, so a path loop never crosses the binding once per path.

from itofin.randomnumbers import (
    GaussianRandomSequenceGenerator,
    UniformRandomGenerator,
    UniformRandomSequenceGenerator,
)

rng = UniformRandomGenerator(42)                       # MT19937, seeded
usg = UniformRandomSequenceGenerator(3, rng)           # 3 uniforms per sequence
gsg = GaussianRandomSequenceGenerator(usg)             # inverse-cumulative normals
print(usg.next_sequence())                             # ndarray, shape (3,)
print(gsg.next_sequences(1000).shape)                  # (1000, 3) standard normals

SobolRsg, HaltonRsg and GaussianLowDiscrepancySequenceGenerator provide the low-discrepancy counterparts with the same next_sequence / next_sequences calls.

Global bootstrap callbacks

PiecewiseYieldCurve(..., bootstrap="global") accepts keyword-only additional_penalties(times, data), additional_dates(), and additional_variables=SimpleQuoteVariables(quotes, guesses, lower_bounds). Penalties return finite residuals with a constant length during each calculation; times and data are copied lists including the reference node. Extra helpers can be repriced through helper.quote_error() inside a penalty. Additional dates and variables add unknowns and need corresponding residuals. Iterative bootstrap rejects these options.

For a futures convexity quote being fitted, pass register_conv_adj=False to its FuturesRateHelper constructor. This prevents optimizer updates from recursively invalidating the curve. The default remains observable for ordinary market quotes. See the joint futures-convexity example, checked against an independently compiled QuantLib oracle.

Callbacks run synchronously on the owning thread. Python exceptions become ItofinError from fallible pricing/bootstrap queries, including the original exception type and message. Failed queries can be retried after fixing the callback. max_date() retains its existing fallback on bootstrap failure; it neither proves a successful solve nor hides the error from a subsequent pricing query. Do not mutate quotes inside callbacks; such mutations are rejected. Callback state changes alone do not invalidate a successfully cached curve; observed market-input changes do.

Native consumers retain callbacks after the Python curve wrapper is dropped. Avoid callbacks that strongly capture the curve or an engine/model/index that retains it. Those mixed native/Python cycles need the user to break the capture; use weakref.ref(curve) for trial-curve queries. Capturing an additional helper is supported. Full mixed-graph garbage collection is tracked in #1028.

Typing checks

See typing acceptance for the pinned, bidirectional Pyright gate.

License

BSD-3-Clause, matching the libitofin core. See the repository for the layer status table, the divergences-from-QuantLib catalogue, and the Rust test oracles behind the numbers above.

Standalone plain-vanilla BlackCalculator

Immutable Black 1976 value and scalar Greeks are available through BlackCalculator. See the bounded scope and edge-case contract.

Par asset swap bindings

Plain fixed/zero bullet-bond AssetSwap supports live discounting, signed leg values, floating BPS and fair spread/clean price. Market, amortizing, callable and overnight variants are excluded. See the bounded scope and lifecycle contract.

Bounded CPI pricing

These are additive bounded routes, not CPI optionlet volatility/calibration parity.

Metadata

Release files for itofin 0.45.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for itofin 0.45.0
File Size Uploaded Provenance Actions
itofin-0.45.0.tar.gz 4.8 MB With provenance Details for itofin-0.45.0.tar.gz

Built distributions (wheels)

Table of built distributions (wheels) for itofin 0.45.0
File Actions
itofin-0.45.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.10 abi3 Linux glibc 2.17+ x86-64 Details for itofin-0.45.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
itofin-0.45.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.10 abi3 Linux glibc 2.17+ ARM64 Details for itofin-0.45.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
itofin-0.45.0-cp310-abi3-macosx_11_0_arm64.whl CPython 3.10 abi3 macOS 11.0+ ARM64 Details for itofin-0.45.0-cp310-abi3-macosx_11_0_arm64.whl
itofin-0.45.0-cp310-abi3-macosx_10_12_x86_64.whl CPython 3.10 abi3 macOS 10.12+ x86-64 Details for itofin-0.45.0-cp310-abi3-macosx_10_12_x86_64.whl

Total release size: 26.4 MB

Release files / itofin-0.45.0.tar.gz

Download URL itofin-0.45.0.tar.gz
Size 4.8 MB
Tags Source
SHA-256 checksum
How to use checksums
810e1694884bdedf7421c67012de917059abcfd2e108337603f1fbeba65fa269
BLAKE2b-256 checksum
How to use checksums
68b29b0f146a9e2a156cf43977d007d1fda5f63f28c7a6222192a80b660d9e08
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.

Transparency log

Release files / itofin-0.45.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL itofin-0.45.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 5.5 MB
Tags CPython 3.10 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
3359ddbb17d7bd57f6444d86e49b7413b6ddd755a5af685d4ed52ce09d84037c
BLAKE2b-256 checksum
How to use checksums
7d360dc1ba6aff8a7cc2cac951952c0ab3bd27b91700086361a55b532e1b81f5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.

Transparency log

Release files / itofin-0.45.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL itofin-0.45.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 5.5 MB
Tags CPython 3.10 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
2f2854df4ed9ae8a7d81b9efb5387e0e5a1a26d12fa768f8311479ba2126bc2f
BLAKE2b-256 checksum
How to use checksums
44fb4bd53fffe961f9656bc3d3c8b591fec4044449ce6a50008ea359ab2537da
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.

Transparency log

Release files / itofin-0.45.0-cp310-abi3-macosx_11_0_arm64.whl

Download URL itofin-0.45.0-cp310-abi3-macosx_11_0_arm64.whl
Size 5.2 MB
Tags CPython 3.10 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
09e04e230b011dfc10001089b96e07cbf4d3a9c4b26f07006763ac5d151ea66b
BLAKE2b-256 checksum
How to use checksums
27beab91a9b4060b35b5a2b48c8b4a4d242abe572e0751e7afe7901e0ba857b8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.

Transparency log

Release files / itofin-0.45.0-cp310-abi3-macosx_10_12_x86_64.whl

Download URL itofin-0.45.0-cp310-abi3-macosx_10_12_x86_64.whl
Size 5.3 MB
Tags CPython 3.10 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
8bc83a4046d09d59ca3f163ca483647338525d2d72ff429ea39fc9cd045091cd
BLAKE2b-256 checksum
How to use checksums
041a84a5d3cb3ba2fc5b2af39bfecafb074093fe4842409ccd681d891f6231fe
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.

Transparency log

Security for itofin 0.45.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 5 files in this release have been uploaded with provenance metadata.

Select from 5 files

Attestation for itofin-0.45.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.45.0 This release

5 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page