Esc

    The API is under testing and may change before release.

    Cashflow records

    This page lists the cashflow table every instrument and every leg reports: its seventeen columns, what each holds and when it's empty, and the basis points by flow that read off the same rows. One row is one coupon, exchange or payment still owed.

    Quick example

    This reads the table of a seasoned two-year SOFR swap, receiving 4.50% fixed, adds up its rows, and reads the fixed leg's basis points flow by flow. The example reads its quotes and prints from the desk sheets; load them once and it runs as shown.

    Rust
    use chrono::NaiveDate;
    use helixio_docs_sheets::{SOFR_CLOSE_DATE, USD_SOFR_CLOSE, USD_SOFR_PRINTS};
    use helixrs::{
        CollateralSpec, FixingKey, FixingStore, MarketContext, QuoteSheet, Termination, template,
    };
    
    type Outcome<T> = Result<T, Box<dyn std::error::Error>>;
    
    fn date((year, month, day): (i32, u32, u32)) -> NaiveDate {
        NaiveDate::from_ymd_opt(year, month, day).expect("a real calendar date")
    }
    
    fn main() -> Outcome<()> {
        let close = date(SOFR_CLOSE_DATE);
        let sheet = QuoteSheet::from_rows(USD_SOFR_CLOSE.iter().copied())?;
        let prints: Vec<(FixingKey, NaiveDate, f64)> = USD_SOFR_PRINTS
            .iter()
            .map(|(index, day, value)| (FixingKey::Typed((*index).to_owned()), date(*day), *value))
            .collect();
        let market = MarketContext::as_of(close)
            .with_fixings(FixingStore::from_observations_checked(&prints)?)
            .with_recipe_quotes(&CollateralSpec::Currency("USD".parse()?), &sheet)?;
        // A two-year SOFR swap traded a week before the close, receiving fixed.
        let swap_at = |fixed_rate: f64| -> Outcome<_> {
            Ok(template("USD-SOFR-OIS")?
                .swap(date((2026, 9, 24)))?
                .with_maturity("2Y".parse::<Termination>()?)?
                .with_notional(10_000_000.0)
                .with_fixed_rate(fixed_rate)
                .build()?)
        };
        let swap = swap_at(0.0450)?;
    
        let table = swap.cashflow_records(&market)?;
        let columns: Vec<&str> = table.columns().collect();
        println!("{}", columns.join(", "));
    
        let text = |name: &str| table[name].text().expect("text");
        let numbers = |name: &str| table[name].numbers().expect("numbers");
        let dates = |name: &str| table[name].dates().expect("dates");
        let (kind, side, pay) = (text("kind"), text("direction"), dates("payment_date"));
        let (rate, amount, pv) = (numbers("rate"), numbers("amount"), numbers("pv"));
        for i in 0..table.len() {
            println!(
                "{:<9} {:<7} {}  {:.6}  {:12.2}  {:12.2}",
                kind[i],
                side[i],
                pay[i].expect("a payment date"),
                rate[i],
                amount[i],
                pv[i]
            );
        }
    
        // The rows add up to the value.
        let total: f64 = pv.iter().sum();
        let npv = swap.npv(&market)?;
        println!("sum of pv  {total:.2}");
        println!("npv        {npv:.2}");
    
        // What one basis point on each row's rate is worth, for the fixed leg. The leg is
        // linear in its rate, so its flows add up to the swap restruck a basis point
        // higher, less the swap.
        let usd = CollateralSpec::Currency("USD".parse()?);
        let bps = swap.legs().expect("a swap's legs")[0].bps_by_flow(&market, &usd)?;
        let one_bp = swap_at(0.0451)?.npv(&market)? - npv;
        let shown: Vec<String> = bps.iter().map(|b| format!("{b:.4}")).collect();
        println!("bps by flow  {}", shown.join("  "));
        println!("sum          {:.4}", bps.iter().sum::<f64>());
        println!("restruck     {one_bp:.4}");
    
        Ok(())
    }
    Python
    import datetime as dt
    
    import helixio as hlx
    from desk_sheets import SOFR_CLOSE_DATE, USD_SOFR_CLOSE, USD_SOFR_PRINTS
    
    market = (
        hlx.MarketContext(SOFR_CLOSE_DATE)
        .with_fixings(USD_SOFR_PRINTS)
        .with_recipe_quotes("USD", USD_SOFR_CLOSE)
    )
    
    def swap_at(fixed_rate):
        """A two-year SOFR swap traded a week before the close, receiving fixed."""
        return (
            hlx.templates.get("USD-SOFR-OIS")
            .swap(dt.date(2026, 9, 24))
            .with_maturity("2Y")
            .with_notional(10_000_000.0)
            .with_fixed_rate(fixed_rate)
            .build()
        )
    
    swap = swap_at(0.0450)
    
    table = swap.cashflow_records(market)
    print(", ".join(table.columns))
    
    rows = table.to_dict()
    for kind, side, pay, rate, amount, pv in zip(
        rows["kind"], rows["direction"], rows["payment_date"], rows["rate"], rows["amount"], rows["pv"]
    ):
        print(f"{kind:<9} {side:<7} {pay}  {rate:.6f}  {amount:12.2f}  {pv:12.2f}")
    
    # The rows add up to the value, summed in row order.
    total = 0.0
    for pv in rows["pv"]:
        total += pv
    npv = swap.npv(market)
    print(f"sum of pv  {total:.2f}")
    print(f"npv        {npv:.2f}")
    
    # What one basis point on each row's rate is worth, for the fixed leg. The leg is
    # linear in its rate, so its flows add up to the swap restruck a basis point
    # higher, less the swap.
    bps = swap.legs()[0].bps_by_flow(market)
    one_bp = swap_at(0.0451).npv(market) - npv
    print("bps by flow  " + "  ".join(f"{b:.4f}" for b in bps))
    print(f"sum          {sum(bps):.4f}")
    print(f"restruck     {one_bp:.4f}")
    kind, direction, currency, accrual_start, accrual_end, payment_date, fixing_date, notional, year_fraction, rate, amount, discount_factor, pv, settlement_currency, fx_fixing_date, leg, index
    Fixed     Receive 2027-09-30  0.045000     456250.00     436885.13
    Fixed     Receive 2028-10-02  0.045000     457500.00     417609.42
    Overnight Pay     2027-09-30  0.043800     444085.44    -425236.88
    Overnight Pay     2028-10-02  0.047934     487333.97    -444842.09
    sum of pv  -15584.41
    npv        -15584.41
    bps by flow  970.8558  928.0209
    sum          1898.8768
    restruck     1898.8768

    The rows add up to the swap's value. The fixed leg's flows add up to what restriking the swap one basis point higher is worth.

    How it's priced

    A row ii carries an amount aia_i, the discount factor DiD_i to its payment date and the side sis_i of its leg (+1+1 receive, −1-1 pay). Its present value and the instrument's value are

    pvi=si ai Di,V=∑ipvi.\mathrm{pv}_i = s_i\, a_i\, D_i, \qquad V = \sum_i \mathrm{pv}_i.

    A flow's basis-point value is what one basis point on its rate is worth, bpsi=si Ni τi⋅10−4⋅Di\mathrm{bps}_i = s_i\, N_i\, \tau_i \cdot 10^{-4} \cdot D_i, and a leg's flows sum to the leg's.

    API

    Symbol Meaning Rust Python
    the table an instrument's rows AnyInstrument::cashflow_records Instrument.cashflow_records
    the table a leg's rows leg_cashflow_records inside MarketContext::priced, or Leg::cashflow_records Leg.cashflow_records
    column names the seventeen columns, in order CASHFLOW_COLUMNS Records.columns
    bpsi\mathrm{bps}_i basis points by flow Leg::bps_by_flow Leg.bps_by_flow
    ∑ibpsi\sum_i \mathrm{bps}_i the leg's basis points Leg::bps Leg.bps

    Instrument.cashflow_records(...), Leg.cashflow_records(...) and Leg.bps_by_flow(...):

    Argument Type Default Meaning
    market MarketContext required the market the rows are projected and discounted on

    In Rust a leg's reads also take the discount key, as Leg::npv_on does.

    The columns

    Read the table with Records.to_dict() in Python, or by column name in Rust (table["pv"], then .numbers(), .dates() or .text()). An empty date is None; an empty number is NaN.

    Column Type Unit or values Sign Empty when
    kind text Fixed, Ibor, Overnight, Redemption, MultiReset, Cms, CmsSpread, Cpi, CpiRedemption, YoyInflation, RangeAccrual, Settlement — never
    direction text Receive or Pay: the row's leg — never
    currency text the currency the row pays in — never
    accrual_start date the start of the accrual period — a redemption
    accrual_end date the end of the accrual period — a redemption
    payment_date date the day the row pays — a reset inside a leg that pays once at the end
    fixing_date date the day a floating rate fixes — a fixed coupon, a redemption, an overnight coupon (it fixes daily)
    notional number in currency unsigned never
    year_fraction number the accrual fraction under the coupon's day count — the settlement row of a leg that pays once
    rate number decimal: the contract rate, the fixing, or its projection — a redemption, a settlement row
    amount number in currency: what this row pays unsigned a reset inside a leg that pays once
    discount_factor number to payment_date; for a converted row, the conversion and the discount in one factor — a reset inside a leg that pays once
    pv number today's value, in the settlement currency where there is one signed by direction a reset inside a leg that pays once
    settlement_currency text the currency a non-deliverable leg settles in — "" for a trade settled in its own currency
    fx_fixing_date date the day the FX fixing converting the row is taken — no conversion, or one at an agreed rate
    leg number the row's leg, by its position in the order the instrument declares them: 0, 1, … — never; a leg on its own is 0
    index text the index code the row resets on — "" for a fixed coupon or a redemption

    Defaults and limits

    • What's owed: a coupon paying on or before the valuation date is left out, as the valuation leaves it out, so a seasoned trade's table is shorter rather than missing.
    • A leg that pays once: a zero-coupon leg reports each reset as a row with its money columns empty, then one Settlement row carrying the payment.
    • All or nothing: a missing historical fixing refuses the whole table, rather than leaving one row projected.
    • Sign: amount is unsigned and pv is signed, so the side is never lost. A paid leg's basis points are negative.
    • A redemption gives zero basis points, because it accrues no rate.

    See also

    • Source: crates/helixrs/src/cashflows/records.rs, crates/helixrs/src/market/store.rs
    • Related pages:
      • Legs and coupons, the coupons the rows come from.
      • Fixings: prints and projections, which prints a row's rate reads.
      • How cashflows work, why one table serves every product.

    From the 0.0 line at revision bf7f2e2. Every printed number is that revision's own output.