Esc

    The API is under testing and may change before release.

    Quote sheets and recipes

    This page lists what you need to turn a desk's quote sheet into a market in one call: how a sheet is written, which recipe reads it, the arguments the call takes, and what it refuses. Every later page builds its market this way.

    Quick example

    The example reads its quotes from the desk sheets; load them once and it runs as shown. It lists the shipped recipes, marks a USD market from every segment of the SOFR close, prices each quote back, and shows a template the recipe doesn't list being refused.

    Rust
    use std::collections::BTreeSet;
    
    use chrono::NaiveDate;
    use helixio_docs_sheets::{SOFR_CLOSE_DATE, USD_SOFR_LADDER};
    use helixrs::{CollateralSpec, MarketContext, QuoteSheet, YieldCurve};
    
    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 usd = CollateralSpec::Currency("USD".parse()?);
    
        // A bare market already knows how to build every curve helixio ships a recipe
        // for. Each row is one segment of one curve: which template quotes it, and in
        // which role.
        let base = MarketContext::as_of(close);
        let rows = base.recipes();
        let (key, curve, role, template) = (
            rows["key"].text().expect("text"),
            rows["curve"].text().expect("text"),
            rows["role"].text().expect("text"),
            rows["template"].text().expect("text"),
        );
        let keys: BTreeSet<&str> = key.iter().map(String::as_str).collect();
        println!("recipe keys {}", keys.len());
        for i in 0..rows.len() {
            if key[i] == "USD" {
                println!("USD  {:<17} {:<12} {}", curve[i], role[i], template[i]);
            }
        }
    
        // The sheet names every segment the USD recipe builds from, short end first: a
        // deposit at a tenor, a policy meeting at its decision date, futures at their
        // contract codes (quoted as prices), and swaps at their tenors.
        let ladder = QuoteSheet::from_rows(USD_SOFR_LADDER.iter().copied())?;
        let market = base.clone().with_recipe_quotes(&usd, &ladder)?;
        let quotes = USD_SOFR_LADDER.len();
        let (discount, _) = market.curve(&"discount(USD)".parse()?).expect("the USD curve");
        println!("quotes      {quotes}");
        println!("parameters  {}", discount.parameter_count());
    
        // Each quote became a rung: an instrument struck at that quote. The curve was
        // solved so that every rung is worth nothing on it — so pricing each one back
        // is the check that the market says what the sheet said.
        let mut worst: f64 = 0.0;
        for rung in base.recipe_rungs(&usd, &ladder)? {
            let value = rung.instrument.npv(&market)?;
            worst = worst.max(value.abs());
            println!("{}  quote {:.6}", rung.pillar, rung.quote);
        }
        println!("largest rung value per unit notional below 1e-12: {}", if worst < 1e-12 { "yes" } else { "no" });
    
        // A template the recipe does not list is refused, and the refusal names the
        // templates it does list, so a mistyped sheet fails where it is written.
        let stray = QuoteSheet::from_rows([("USD-LIBOR-3M", "5Y", 0.05)])?;
        let refused = base
            .with_recipe_quotes(&usd, &stray)
            .expect_err("an unlisted template must be refused");
        let names_listed = refused.to_string().contains("USD-SOFR-OIS");
        println!(
            "refused, naming the listed USD-SOFR-OIS: {}",
            if names_listed { "yes" } else { "no" }
        );
    
        Ok(())
    }
    Python
    import helixio as hlx
    from desk_sheets import SOFR_CLOSE_DATE, USD_SOFR_LADDER
    
    # A bare market already knows how to build every curve helixio ships a recipe
    # for. Each row is one segment of one curve: which template quotes it, and in
    # which role.
    base = hlx.MarketContext(SOFR_CLOSE_DATE)
    rows = base.recipes().to_dict()
    keys = sorted(set(rows["key"]))
    print(f"recipe keys {len(keys)}")
    for key, curve, role, template in zip(rows["key"], rows["curve"], rows["role"], rows["template"]):
        if key == "USD":
            print(f"USD  {curve:<17} {role:<12} {template}")
    
    # The sheet names every segment the USD recipe builds from, short end first: a
    # deposit at a tenor, a policy meeting at its decision date, futures at their
    # contract codes (quoted as prices), and swaps at their tenors.
    market = base.with_recipe_quotes("USD", USD_SOFR_LADDER)
    quotes = sum(len(segment) for segment in USD_SOFR_LADDER.values())
    curve = market.curve("discount(USD)")
    print(f"quotes      {quotes}")
    print(f"parameters  {curve.parameter_count()}")
    
    # Each quote became a rung: an instrument struck at that quote. The curve was
    # solved so that every rung is worth nothing on it — so pricing each one back
    # is the check that the market says what the sheet said.
    worst = 0.0
    for rung in base.recipe_rungs("USD", USD_SOFR_LADDER):
        value = rung.instrument().npv(market)
        worst = max(worst, abs(value))
        print(f"{rung.pillar()}  quote {rung.quote():.6f}")
    print(f"largest rung value per unit notional below 1e-12: {'yes' if worst < 1e-12 else 'no'}")
    
    # A template the recipe does not list is refused, and the refusal names the
    # templates it does list, so a mistyped sheet fails where it is written.
    try:
        base.with_recipe_quotes("USD", {"USD-LIBOR-3M": {"5Y": 0.05}})
    except ValueError as error:
        unlisted = str(error)
        print(f"refused, naming the listed USD-SOFR-OIS: {'yes' if 'USD-SOFR-OIS' in unlisted else 'no'}")
    else:
        raise AssertionError("an unlisted template must be refused")
    recipe keys 32
    USD  discount          deposit      USD-SOFR-DEPO
    USD  discount          policy       USD-SOFR-MeetingOIS
    USD  discount          futures      USD-SOFR-3M-FUT
    USD  discount          swaps        USD-SOFR-OIS
    USD  projection(SOFR)  telescoping  
    quotes      7
    parameters  7
    2026-10-08  quote 0.038900
    2026-12-10  quote 0.038800
    2027-06-16  quote 0.043500
    2027-09-15  quote 0.044500
    2028-10-10  quote 0.045900
    2031-10-08  quote 0.047100
    2036-10-08  quote 0.048300
    largest rung value per unit notional below 1e-12: yes
    refused, naming the listed USD-SOFR-OIS: yes

    Each quote prices back to nothing on the market it marked, and the curve has one pillar per quote.

    How it's priced

    Each quote qjq_j is the value at which its instrument is fair: a fixed rate at which a par swap is worth nothing, or the price that fixes a future's rate (100−p)/100(100 - p)/100. Writing PjP_j for the instrument's value per unit notional, struck at its quote, the solved curve DD satisfies

    Pj ⁣(qj; D)=0,j=1,…,n.P_j\!\left(q_j;\ D\right) = 0, \qquad j = 1, \dots, n.

    With nn quotes and nn pillars the solve is exact to its tolerance, so pricing each rung back is the check that the market says what the sheet said. Why a desk quotes the front and the back of a curve in different instruments, and why SOFR uses one curve for two roles, is covered in how a market is built.

    API

    Symbol Meaning Rust Python
    qjq_j a quote at its locator a (template, locator, quote) row of QuoteSheet::from_rows {template: {locator: quote}}
    RR the recipe for a key MarketContext::recipe, listed by MarketContext::recipes MarketContext.recipe, listed by MarketContext.recipes
    Pj(qj;⋅)P_j(q_j; \cdot) the rung each quote becomes MarketContext::recipe_rungs MarketContext.recipe_rungs
    DD the solved curve, pinned under its roles MarketContext::with_recipe_quotes MarketContext.with_recipe_quotes

    MarketContext.with_recipe_quotes(key, quotes, ...) takes:

    Argument Type Default Meaning
    key str required the collateral key whose recipe reads the sheet, such as "USD" or "KRW-CSA-USD"
    quotes dict[str, dict[Locator, float]] required the sheet: quotes by template, then by locator. In Rust, a QuoteSheet
    notional float 1.0 the notional each rung is built on
    interpolation Interpolation | str "loglinear" how the solved curve interpolates between pillars
    tension float | None None the tension of a tension spline, when that interpolation is chosen
    end_slopes tuple[float, float] | None None end slopes for a spline that takes them
    tolerance Tolerance | None None the solver's tolerance; None uses the library's

    A locator is written the way a desk writes it on a sheet:

    Locator Example Used for
    tenor "5Y" deposits, swaps
    decision date "2026-10-28" meeting swaps
    contract code "MAR27" futures
    window "MAR27 - JUN27", "2026-12-10 - 2026-12-31" forward swaps over a window

    Defaults and limits

    • Keys: a bare market lists every recipe helixio ships with recipes(), before it holds a curve. The recipe keys catalog lists them.
    • Unlisted templates are refused: a sheet naming a template the key's recipe doesn't list raises ValueError where it is written, naming the templates the recipe takes.
    • Inspecting the rungs: recipe_rungs(key, quotes) returns the unsolved rungs, so you can inspect, drop or add one before solving them with with_curve_helpers. with_recipe_quotes(key, quotes) is exactly with_curve_helpers(recipe_rungs(key, quotes)).
    • Futures: a futures rung carries its rate, not its price, as the quote it reprices.

    See also

    • Source: crates/helixrs/src/market/store.rs, crates/helixrs/src/calibration.rs, crates/helixrs/src/statics/recipes/spec.rs
    • Related pages:
      • How a market is built, for what a recipe knows and how the two routes compare by hand.
      • Recipe keys, for every key helixio ships.
      • Curve helpers, for building the rungs yourself.
      • Data sources, for a sheet fetched rather than stated.

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