Bond bindings¶
Go and Python expose the existing Rust fixed-rate, zero-coupon and floating
bonds through one shared Bond interface. The foundation below covers fixed and
zero bonds; floating controls and coupon pricers build
on that same base. Yield and Z-spread analytics also use
this interface without an engine. Callable construction
also inherits this interface, with explicit distinctions between contractual
cash-flow analytics and option-adjusted pricing.
Python¶
from itofin import Settings
from itofin.instruments import FixedRateBond, ZeroCouponBond
from itofin.pricingengines import DiscountingBondEngine
from itofin.termstructures import FlatForward
from itofin.time import BusinessDayConvention, Calendar, Date, DayCounter, Frequency, Schedule
settings = Settings()
settings.set_evaluation_date(Date(15, 3, 2026))
calendar = Calendar.null_calendar()
day_counter = DayCounter.actual360()
curve = FlatForward(Date(15, 3, 2026), 0.031, day_counter)
engine = DiscountingBondEngine(curve, settings)
schedule = Schedule(
Date(15, 1, 2026), Date(15, 1, 2030), Frequency.Annual,
calendar, BusinessDayConvention.Unadjusted,
)
bond = FixedRateBond(2, 250.0, schedule, [0.045], day_counter, settings)
bond.set_engine(engine)
print(bond.npv(), bond.clean_price(), bond.dirty_price())
zero = ZeroCouponBond(2, calendar, 250.0, Date(17, 1, 2027), settings)
zero.set_engine(engine)
print(zero.settlement_value(), zero.settlement_date())
FixedRateBond and ZeroCouponBond inherit a nonconstructible Bond base.
Constructors require explicit settings and retain them. DiscountingBondEngine
retains the curve and settings; attaching an engine with different settings fails.
Python objects follow the existing thread-confined facade contract.
Fixed bonds accept coupon vectors, payment convention/calendar, redemption, issue date, ex-coupon period/calendar/convention/end-of-month and a first-period day counter. Omitted payment calendar uses the schedule's calendar. Defaults are Following, redemption 100, no issue/ex-coupon/first-period override, Unadjusted ex-coupon convention and false ex-coupon end-of-month. Explicit zero ex-coupon period retains the Rust meaning: ex-coupon on the payment date.
Go¶
Run go run ./examples/bonds from sdk/go after building the C library.
package main
import (
"errors"
"fmt"
itofin "github.com/benbenbang/libitofin/sdk/go"
"log"
)
func main() {
if err := run(); err != nil {
log.Fatal(err)
}
}
func run() (err error) {
s, err := itofin.NewSession()
if err != nil {
return err
}
defer func() { err = errors.Join(err, s.Close()) }()
today, err := itofin.NewDate(15, 1, 2024)
if err != nil {
return err
}
maturity, err := itofin.NewDate(15, 1, 2027)
if err != nil {
return err
}
settings, err := s.NewSettings()
if err != nil {
return err
}
if err = settings.SetEvaluationDate(today); err != nil {
return err
}
calendar, err := s.NullCalendar()
if err != nil {
return err
}
counter, err := s.Actual365Fixed()
if err != nil {
return err
}
curve, err := s.NewFlatForward(today, .04, counter)
if err != nil {
return err
}
engine, err := s.NewDiscountingBondEngine(curve, settings, nil)
if err != nil {
return err
}
bond, err := s.NewZeroCouponBond(itofin.ZeroCouponBondConfig{BondConfig: itofin.BondConfig{SettlementDays: 2, FaceAmount: 1000, Calendar: calendar, Settings: settings, IssueDate: &today}, MaturityDate: maturity})
if err != nil {
return err
}
if err = bond.SetEngine(engine); err != nil {
return err
}
price, err := bond.CleanPrice()
if err != nil {
return err
}
fmt.Printf("Zero-coupon clean price per 100: %.12f\n", price)
return nil
}
Expected clean price per 100: 88.701763880339.
Common valuation and ownership¶
| Query | Meaning |
|---|---|
| NPV | Currency value discounted to the curve reference date |
| Settlement value | Dirty currency value at settlement |
| Clean/dirty price | Quote per 100 of outstanding notional |
| Accrued amount | Accrued interest per 100, optionally at an explicit date |
| Notional | Outstanding currency amount, optionally at an explicit date |
| Settlement date | Evaluation/explicit date advanced by business-day lag, floored at issue |
| Maturity date | Contractual maturity, potentially different from the payment date |
| Cashflows/redemptions | Retained legs; flows survive instrument-wrapper disposal |
Engines observe retained market dependencies. Quote and evaluation-date changes
invalidate prices lazily. The new bond facades also refresh cached prices after
changes to the settings' reference-date event and today's cash-flow flags.
freeze pins cached results for unexpired instruments; native/core expiry
bypasses freeze and still returns zero. recalculate refreshes results while
keeping the bond frozen; unfreeze restores live pricing. Quotes still use the current
notional and accrual rules. Freezing before calculation does not manufacture a
price and returns a missing-result error.
include_settlement_date_flows=None lets the engine use the settings'
reference-date event policy. An explicit override applies to reference-date
valuation. Settlement-date cash flows are normally excluded, but the existing
core today's-cash-flow override takes precedence on the evaluation date.
Expiry, zero-notional prices and adjusted payment dates retain the Rust rules.
Call Recalculate/recalculate after silent calendar holiday mutations when a
new settlement date must refresh an already cached settlement value. These
facades do not change the existing core calendar notification contract.
Face amount and redemption must be positive finite values. Coupon rates and resulting monetary amounts must be finite. Date/holiday-table boundaries and settlement overflows raise ordinary binding errors instead of native panics. Dirty quotes keep the core arithmetic order for ordinary inputs and divide currency value by notional before multiplying by 100 when the original scaling overflows, keeping representable quotes usable with very large face amounts.
Verification¶
Tracked Python native fixtures were generated independently with QuantLib 1.43. They cover fixed/step-up/ex-coupon legs, non-par redemption, adjusted zero-coupon payments and expiry. Additional tests cover dependency retention, changing quotes/settings, freeze/recalculate/unfreeze, extreme scales and invalid inputs. Generated Python stubs and the C/Go coverage inventory remain required gates.