Esc

    The API is under testing and may change before release.

    How cashflows work

    A trade is worth what its cashflows are worth. This page explains how terms become dated amounts: what a coupon and a leg are, why a schedule needs stub rules, the coupons that read more than one rate or a price index, the options a coupon can carry, and the one table every value can be read from. Each topic's reference page has the arguments and a program you can run.

    What a leg is worth

    A swap is two legs exchanged, and each leg is a schedule of coupons. A coupon pays notional times a rate times the accrual fraction of its period under the leg's day count. A fixed coupon states its rate; a floating coupon names the index it fixes on. A EUR swap typically pays a fixed leg annually on 30E/360 against a EURIBOR leg quarterly or semiannually on ACT/360.

    Coupons and legs are values you can build and inspect. Instruments build their legs from the same coupon constructors, so a leg you compose is valued by the same code as a leg inside a trade. A leg doesn't carry its collateral, because that belongs to the trade; a leg built on its own names the key it's discounted on, the currency of its cash collateral.

    For a fixed leg every term is known from the contract and the curve, so its value can be written out by hand. Legs and coupons shows the short way: one strip constructor and one call to value it. The program below builds the same two-year fixed leg one coupon at a time, discounts each amount by hand, and prints that sum beside the strip's own value. It reads its quotes from the desk sheets.

    Rust
    use chrono::{Datelike, NaiveDate};
    use helixio_docs_sheets::{EUR_CLOSE, SOFR_CLOSE_DATE};
    use helixrs::{
        AnyCoupon, CollateralSpec, DayCountFraction, Direction, FixedRateCoupon, Leg, LegTerms,
        MarketContext, PaymentRule, QuoteSheet, Schedule, YieldCurve, calendar, fixed_rate_leg,
    };
    
    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 eur = CollateralSpec::Currency("EUR".parse()?);
        let sheet = QuoteSheet::from_rows(EUR_CLOSE.iter().copied())?;
        let market = MarketContext::as_of(close).with_recipe_quotes(&eur, &sheet)?;
        let target = calendar("EUTA")?;
        let annual = Schedule::generate(
            date((2026, 10, 5)),
            date((2028, 10, 5)),
            "1Y".parse()?,
            target.as_ref(),
            "ModFollowing".parse()?,
            "None".parse()?,
            "ShortInitial".parse()?,
            false,
            None,
            None,
        )?;
        let day_count: DayCountFraction = "30E/360".parse()?;
    
        // One fixed coupon per period: notional × rate × the period's 30E/360 fraction,
        // paid at the period's end.
        let coupons: Vec<AnyCoupon> = annual
            .periods()
            .into_iter()
            .map(|(start, end)| {
                AnyCoupon::Fixed(FixedRateCoupon {
                    accrual_start: start,
                    accrual_end: end,
                    payment_date: end,
                    notional: 10_000_000.0,
                    fixed_rate: 0.0220,
                    day_count,
                    accrual: day_count.year_fraction(start, end),
                    payment_ordinal: end.num_days_from_ce(),
                    currency: "EUR".parse().expect("a currency"),
                })
            })
            .collect();
        for coupon in &coupons {
            println!(
                "{}  {:.6}  {:.2}",
                coupon.payment_date(),
                coupon.year_fraction(),
                coupon.amount().expect("a fixed amount")
            );
        }
    
        // The leg's value is each amount times the discount factor to its payment date.
        let (curve, _) = market.curve(&"discount(EUR)".parse()?).expect("the EUR curve");
        let mut by_hand = 0.0;
        for coupon in &coupons {
            by_hand += coupon.amount().expect("a fixed amount")
                * curve.view::<f64>().discount(coupon.payment_date())?;
        }
        let strip = fixed_rate_leg(
            &annual,
            &LegTerms {
                notional: 10_000_000.0,
                day_count,
                currency: "EUR".parse()?,
                direction: Direction::Receive,
                payment: PaymentRule::none(),
            },
            0.0220,
        );
        let strip_npv = strip.npv_on(&market, &eur)?;
        println!("by hand  {by_hand:.2}");
        println!("strip    {strip_npv:.2}");
    
        Ok(())
    }
    Python
    import datetime as dt
    
    import helixio as hlx
    from desk_sheets import EUR_CLOSE, SOFR_CLOSE_DATE
    
    START, END = dt.date(2026, 10, 5), dt.date(2028, 10, 5)
    market = hlx.MarketContext(SOFR_CLOSE_DATE).with_recipe_quotes("EUR", EUR_CLOSE)
    target = hlx.Calendar("EUTA")
    annual = hlx.dates.schedule(START, END, "1Y", target)
    
    # One fixed coupon per period: notional × rate × the period's 30E/360 fraction,
    # paid at the period's end.
    coupons = [
        hlx.legs.fixed_rate_coupon(
            "EUR", start, end, end, notional=10_000_000.0, fixed_rate=0.0220, day_count="30E/360"
        )
        for start, end in annual.periods()
    ]
    for coupon in coupons:
        print(f"{coupon.payment_date()}  {coupon.year_fraction():.6f}  {coupon.amount():.2f}")
    
    # The leg's value is each amount times the discount factor to its payment date.
    curve = market.curve("discount(EUR)")
    by_hand = sum(c.amount() * curve.discount(c.payment_date()) for c in coupons)
    strip = hlx.Leg(
        hlx.legs.fixed_rate_leg(
            annual, annual.paying(0, target), "EUR", notional=10_000_000.0, fixed_rate=0.0220, day_count="30E/360"
        ),
        "Receive",
        "EUR",
    )
    strip_npv = strip.npv(market)
    print(f"by hand  {by_hand:.2f}")
    print(f"strip    {strip_npv:.2f}")
    2027-10-05  1.000000  220000.00
    2028-10-05  1.000000  220000.00
    by hand  426971.49
    strip    426971.49

    Each coupon pays a full 30E/360 year at 2.20% on ten million. The hand-discounted sum and the strip's value are the same number.

    Schedules and stubs

    A swap confirmation states an effective date, a termination date, a frequency, a calendar and a business-day convention. The schedule those generate is the leg's accrual periods. Payment is usually on the period end, or a few business days after it, on the leg's own calendar.

    When the term isn't a whole number of periods, one period is short or long: a stub, at the front or the back. A floating stub can't simply read its index, since a two-month period on a three-month index has no rate of its own length. The confirmation elects one of three readings: project over the stub's own dates, read the index's full tenor from the stub's start, or blend the two published tenors either side of the stub's length. The rules and their spellings are on from a schedule to a leg.

    Coupons that reset more than once

    Some legs pay less often than their index resets: a cross-currency leg paying semiannually on a three-month rate, or a loan paying quarterly on a one-month rate. Each payment then combines several fixings. Market practice compounds them with the spread (straight), compounds the rate but not the spread's accrual (flat), compounds the rate and adds the spread simply (spread-exclusive), or averages them. With a spread the four pay different amounts; multi-reset coupons has the formulas.

    Coupons on a swap rate

    A constant-maturity-swap coupon lets a leg follow the long end of the curve while paying short: a quarterly coupon paying the 10-year swap rate, or the 10-year less the 2-year, a bet on the curve's slope. Paying a swap rate once, on a date the swap itself doesn't pay on, isn't the same as receiving the swap. The difference is a convexity adjustment, and it depends on how volatile the swap rate is, so a CMS coupon reads the currency's swaption vols even with no option on it. See CMS coupons.

    Coupons on a price index

    Inflation swaps and linkers pay on published price indices: the euro-area HICP excluding tobacco, the US CPI-U, the UK RPI. An index is published monthly, for a reference month, some weeks after that month ends, so a contract observes it a lag before its own dates, three months for most markets. A year-on-year coupon pays the index's growth over its period; a CPI coupon pays a real rate on a notional indexed from a base level. See inflation coupons.

    Options on a coupon

    Borrowers on floating rates buy caps to limit what they pay, and lenders buy floors. A collar, a cap bought with a floor sold, limits both ways and can cost nothing upfront. A digital pays a fixed amount when the rate ends past a strike. Structured notes carry these options inside their coupons rather than as separate trades. An option still to fix is valued off the currency's cap vols, which the leg then declares it reads. See coupon options.

    Prints and projections

    A floating coupon reads a published print for a day already past and the curve's projection for a day still to come. Which is which depends only on the valuation date, and which version of a print is read depends on whether it was fetched or pinned by hand. Fixings: prints and projections explains both.

    Reading the cashflows

    A middle office reconciles a trade's value against its cashflows: which coupons are still to pay, what each will pay, what each is worth today. Every instrument and every leg answers with the same seventeen-column table, so a reconciliation written for one trade reads another, and the rows add up to the value. Cashflow records documents each column.

    See also

    • Source: crates/helixrs/src/cashflows/coupons.rs, crates/helixrs/src/cashflows/legs.rs, crates/helixrs/src/cashflows/records.rs
    • Related pages:
      • Build a leg from a schedule, the task step by step.
      • How rates products work, for the trades these legs make up.

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