Skip to main content

BondFuturePosition

Struct BondFuturePosition 

pub struct BondFuturePosition {
    pub delivery: NaiveDate,
    pub deliverables: Vec<Deliverable>,
    pub(crate) repo_keys: Vec<String>,
    pub currency: Currency,
    pub collateral: CollateralSpec,
    pub contracts: f64,
    pub contract_size: f64,
    pub traded_price: f64,
    pub side: f64,
}
Expand description

A bookable bond future position: a basket, a size, and a traded price.

The contract BondFuture is reference data — a delivery date and a list of ISINs. This is a position in it, and the difference is what makes it valuable on a book: it carries its deliverables already resolved to bonds, so pricing consults no security master, and it carries one repo key per deliverable, so the seam can hand it one carry curve per row.

The value is undiscounted. A bond future is margined daily, so the position settles variation margin rather than a discounted claim, exactly as RateFuture does.

Fields§

§delivery: NaiveDate

The delivery date the basket forwards to.

§deliverables: Vec<Deliverable>

The deliverables, resolved once at construction.

§repo_keys: Vec<String>

The carry keys, BondFuturePosition::CARRY_TIERS per deliverable, in deliverable order then tier order.

The passive analytics run a cascade against the market — the row’s own key, then its repo group, then its currency, then the discount curve — and the position declares the whole cascade rather than a preferred key from it. Declaring one key was the first shape and it was wrong: against a market holding a security-tier repo curve the analytics carried the row on it and the position did not, and the two named different prices for a basket both could price — 0.61 of a price point on the fixture, with no principled account of the difference.

The seam carries a flat key list and resolves each key independently, so the cascade crosses it as a fixed-stride run and the pricer takes the first key that resolved. A deliverable with no repo group repeats its own key in that slot: the tiers are a preference order, not a set, and a key resolved twice costs one lookup and preserves the order exactly.

Which keys are asked is fixed at construction; whether one resolves stays a pricing-time question, which is why the resolved slot is an Option and a row no key answers carries on the discount curve.

Not public, and read through carry_keys. The list is a pure function of deliverables — carry_cascade is that function — and it exists as a field only because risk_factors hands out keys borrowed from the position, so something here must own the strings.

Two mechanisms guard the correspondence between this list and the basket, because they cover different populations. Narrowing the field to the crate means no caller outside it can set the two apart — a struct literal that desynchronised them no longer compiles. Inside the crate a literal still can, which is why cascade_is_well_formed is checked where the declaration is made. Neither is redundant: without the check a short list reads past the end of the resolved slots into exactly the discount-curve fall back a market gap produces, and prices silently.

§currency: Currency

The currency the position settles in.

§collateral: CollateralSpec

The collateral its discounting is read under.

§contracts: f64

The number of contracts held.

§contract_size: f64

The face each contract delivers — 100_000 for the Treasury complex. A price point is worth contract_size / 100.

§traded_price: f64

The price the position was struck at, per 100.

§side: f64

+1 long, −1 short.

Implementations§

§

impl BondFuturePosition

pub const CARRY_TIERS: usize = 3

How many carry keys a deliverable declares: the security, group and currency tiers of RepoTier, in that order.

pub fn carry_cascade(deliverable: &Deliverable) -> [String; 3]

One deliverable’s carry cascade, in preference order: its own key, its repo group, its currency.

The single definition of a row’s run. A deliverable with no repo group repeats its own key rather than shortening the run — the tiers are a preference order, not a set, so a key resolved twice costs one lookup and keeps the stride exactly CARRY_TIERS wide. Stating the width and the content in one place is what keeps them from drifting.

pub fn carry_keys(&self) -> &[String]

The declared carry keys: one CARRY_TIERS-wide run per deliverable, in deliverable order then tier order.

pub fn cascade_is_well_formed(&self) -> bool

Whether the declared key list holds exactly one full run per deliverable.

The correspondence the seam cannot express: it carries the cascade as a flat list with no arity, so this is the only thing standing between a desynchronised list and a silent mispricing.

pub fn new( future: &BondFuture, securities: &Securities, contracts: f64, contract_size: f64, traded_price: f64, ) -> Result<Self, BondFutureError>

A position in future, resolving every basket ISIN through the security master once, here, so that pricing never needs one.

Each row declares its whole carry cascade — its ISIN, its repo group, its currency — so the position and the passive analytics carry every row the same way on any market both can price.

§Errors

BondFutureError::UnknownDeliverable for an ISIN the master does not hold, and BondFutureError::NotFixedCoupon for a deliverable that is not a fixed-coupon bond.

pub fn from_deliverables( delivery: NaiveDate, deliverables: Vec<Deliverable>, contracts: f64, contract_size: f64, traded_price: f64, ) -> Self

A position over deliverables the caller has already resolved.

§Panics

If deliverables is empty: the position takes its currency from the first deliverable, and a basket with nothing in it has no currency to take. A future over no deliverable is not a position.

pub fn short(self) -> Self

The short side.

pub fn price_point_value(&self) -> f64

What one price point is worth to this position.

§

impl BondFuturePosition

pub fn model_price<R: Scalar>( &self, view: &PricingView<'_, R>, ) -> Result<R, PricingError>

The theoretical futures price: the cheapest-to-deliver’s forward clean price over its conversion factor.

Mode-generic, which is the whole point — the passive analytics on BondFuture answer the same question without derivatives, and this answers it in whichever mode the caller lifted, so a booked position reports risk.

Each row carries on its own basket curve, falling back to the discount curve where the market holds none, exactly as analyze_resolved does.

§Errors

PricingError for a curve that will not resolve or answer, and for an empty basket or a delivery on or before the valuation date.

fn repo_basket_curve<'v, R: Scalar>( view: &'v PricingView<'_, R>, i: usize, ) -> Option<&'v ResolvedCurve<'v, R>>

The carry curve for deliverable i: the first of its declared cascade that resolved, or None for the discount fall back — a row no key answered, or a basket the view did not resolve because no repo basket was declared.

The keys cross the seam as a flat list with a fixed stride, so row i’s tiers are the run at i · CARRY_TIERS, in preference order. Taking the first Some of that run is the cascade analyze_resolved walks.

Trait Implementations§

§

impl Clone for BondFuturePosition

§

fn clone(&self) -> BondFuturePosition

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
§

impl Debug for BondFuturePosition

§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
§

impl PartialEq for BondFuturePosition

§

fn eq(&self, other: &BondFuturePosition) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
§

impl<R: Scalar> Priceable<R> for BondFuturePosition

§

fn npv(&self, view: &PricingView<'_, R>) -> Result<R, PricingError>

side · contracts · price-point value · (model − traded), in the position’s currency and undiscounted: a daily-margined future settles variation margin, so there is no discounted claim to value.

§

fn par_rate(&self, view: &PricingView<'_, R>) -> Result<R, PricingError>

The futures price at which the position is worth nothing — its model price.

§

fn par_spread(&self, _view: &PricingView<'_, R>) -> Result<R, PricingError>

The par (breakeven) floating-leg spread. Zero for a product with no floating leg. Read more
§

impl PricingRiskFactors for BondFuturePosition

§

fn risk_factors(&self) -> Result<RiskFactors<'_>, PricingError>

Discounts on the declared collateral and carries every deliverable on its own key — the variadic repo slot, mirroring the credit basket an nth-to-default swap declares.

The cascade crosses the seam as a flat list read at a fixed stride, and the seam carries no arity: nothing downstream can tell a run short of its basket from a market holding no curve, because both surface as a None slot and both are read as the discount-curve fall back. So the correspondence is checked here, where the list is committed to, rather than at the read that cannot distinguish them.

§Errors

PricingError::MalformedDeclaration when the declared key list does not hold exactly one CARRY_TIERS-wide run per deliverable.

§

impl Product for BondFuturePosition

§

fn currency(&self) -> Currency

The currency the product pays in. An FX product values in its quote currency; a book converts.
§

fn contract_dates(&self) -> Vec<(&'static str, NaiveDate)>

The contract dates the product resolved to, as (name, date) pairs — exactly the dates its stated constructor takes, so a product built through a derived form can be read back and rebuilt through the stated one. Empty for a product with no stated form. No default: every product states which it is — see AnyInstrument::contract_dates.
§

fn legs(&self) -> Option<Vec<&Leg>>

The legs the product itself holds, in a declared order, or None for a product that holds none — see AnyInstrument::legs. No default: every product states which it is.
§

fn final_payment_date(&self) -> Option<NaiveDate>

The date of the product’s final payment, where a calibration rung can be built on it; None for a product no ladder is built from.
§

fn restruck_at_rate(&self, _rate: f64) -> Option<AnyInstrument>

This product re-struck at the par rate rate — the scalar a par calibration rung on it is quoted in — or None for a product that carries no such scalar. What a quote scenario moves a rung to.
§

fn restruck_at_spread(&self, _spread: f64) -> Option<AnyInstrument>

This product re-struck at the basis spread spread on its spread leg, or None for a product that quotes none.
§

impl StructuralPartialEq for BondFuturePosition

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.