Skip to main content

Leg

Struct Leg 

pub struct Leg {
    coupons: Vec<AnyCoupon>,
    direction: Direction,
    accumulation: Accumulation,
    non_deliverable: Option<NonDeliverable>,
}
Expand description

A compiled leg: coupons in payment order, the side they are on, how they combine, and — for a non-deliverable leg — how they settle.

Fields§

§coupons: Vec<AnyCoupon>§direction: Direction§accumulation: Accumulation§non_deliverable: Option<NonDeliverable>

Implementations§

§

impl Leg

pub fn new(coupons: Vec<AnyCoupon>, direction: Direction) -> Self

A leg from already-resolved coupons, each paying on its own date.

pub fn accumulating( coupons: Vec<AnyCoupon>, direction: Direction, accumulation: Accumulation, ) -> Self

A leg whose coupons accumulate into one payment rather than paying separately — a zero-coupon swap’s fixed or floating side.

pub fn payment_dates(&self) -> Vec<NaiveDate>

The dates this leg pays on, one per payment, in leg order: each coupon’s when it pays per coupon; when it accumulates, its single payment date in place of its first accruing coupon. A principal exchange is always a payment of its own, so an accumulating leg’s exchanges stand beside its one accumulated payment.

pub fn with_exchanges( self, initial: Option<(NaiveDate, f64)>, last: Option<(NaiveDate, f64)>, ) -> Result<Self, NonDeliverableError>

This leg with principal exchanged: initial paid first and last paid last, each a (date, amount) in the leg’s currency signed as the leg is oriented — a receive-oriented cross-currency leg pays out its notional at the start (negative) and takes it back at the end. Kept as Redemption flows in the leg, so a valuation, its records and any conversion read one list.

§Errors

NonDeliverableError::UnconvertedExchange when the leg already settles non-deliverably and an exchange is added: its conversions number the payments it had, and a new payment has none. Exchange principal first, then settle the leg.

pub(crate) fn exchanging( self, initial: Option<(NaiveDate, f64)>, last: Option<(NaiveDate, f64)>, ) -> Self

with_exchanges on a leg the caller knows is deliverable.

pub fn without_exchanges(self) -> Self

This leg without its principal exchanges: its rate-bearing coupons, a non-deliverable leg keeping the conversions they pay at.

pub fn without_initial_exchange(self) -> Self

This leg without its initial exchange — every exchange paid before its first rate-bearing coupon — and that exchange’s conversion on a non-deliverable leg. Read by position, not by sign, so a leg on a negative notional loses the same exchange.

fn dropping_exchanges(self, drop: impl Fn(usize) -> bool) -> Self

This leg without the exchanges at the coupon positions drop picks, a non-deliverable leg’s conversions for them taken out with them, so the conversions still number its payments.

pub fn exchanges(&self) -> Vec<(NaiveDate, f64)>

This leg’s principal exchanges, (date, signed amount) in leg order, the leg’s direction not applied.

pub fn with_non_deliverable( self, nd: NonDeliverable, ) -> Result<Self, NonDeliverableError>

This leg settling non-deliverably: each payment converted into nd.settlement at the FX fixing on its date.

§Errors

NonDeliverableError when the settlement currency is the leg’s own, the FX series is not their pair, the fixing dates do not number the payments, or a payment fixes after it pays — each naming what failed.

pub fn non_deliverable(&self) -> Option<&NonDeliverable>

How this leg settles non-deliverably, or None for a leg paid in the currency it accrues in.

pub fn non_deliverable_payments<R: Scalar, C: CurveByIndex<R> + ?Sized>( &self, curves: &C, fixings: &FixingsView<'_, R>, as_of: NaiveDate, ) -> Result<Option<Vec<(R, NaiveDate, Conversion)>>, CashflowError>

The payments still to come as of as_of — each its projected amount in the leg’s own currency, unsigned and undiscounted, with its payment date and its conversion — for a non-deliverable leg; None for a deliverable one. A leg that accumulates makes its one payment, beside any principal exchanges.

§Errors

As cashflows.

pub fn accumulation(&self) -> Accumulation

How this leg’s coupons combine.

fn accruing(&self) -> impl Iterator<Item = &AnyCoupon>

The coupons that accrue — every one but a principal exchange.

pub fn coupons(&self) -> &[AnyCoupon]

The coupons, in order.

pub fn direction(&self) -> Direction

The side this leg is on.

pub(crate) fn with_fixed_rate(self, rate: f64) -> Self

This leg with every fixed coupon’s rate set to rate, its dates, accruals, side and accumulation kept — the leg a par-quoted swap or CDS rung is at another quote.

pub(crate) fn with_floating_spread(self, spread: f64) -> Self

This leg with every IBOR and overnight coupon’s spread set to spread, everything else kept — the leg a spread-quoted basis rung is at another quote.

pub fn flipped(self) -> Self

This leg on the other side, its coupons and accumulation untouched.

A product that can be booked either way flips its legs with itself, so what legs() hands out is the trade rather than one canonical orientation with the real one held beside it.

pub fn with_payoff(self, payoff: RatePayoff) -> Self

This leg with payoff on the rate of every IBOR, overnight, CMS and year-on-year inflation coupon, and on every CPI notional — whose bounds are annualised zero-coupon rates from its base date (see CpiRedemption). Other coupons are unchanged.

pub fn with_collar(self, collar: Collar) -> Self

This leg with collar on the rate of every IBOR, overnight and CMS coupon.

pub fn with_digital(self, digital: Digital) -> Self

This leg with digital on the rate of every IBOR, overnight and CMS coupon.

pub fn option_currency(&self) -> Option<Currency>

The currency of the first coupon on this leg carrying an option on its rate — the cap vols a product holding it must declare — or None.

pub fn yoy_vol_index(&self) -> Option<&str>

The price index of the first year-on-year coupon on this leg carrying an option on its rate — the YoY vols a product holding it must declare — or None.

pub fn cpi_vol_index(&self) -> Option<&str>

The price index of the first CPI notional on this leg carrying an option on its growth — the zero-coupon CPI vols a product holding it must declare — or None.

pub fn swaption_currency(&self) -> Option<Currency>

The currency of the first CMS coupon on this leg — the swaption vols a product holding it must declare — or None.

pub fn cms_spread_correlation(&self) -> Option<(&str, &str)>

The two swap-index codes of the first CMS spread coupon on this leg that reads its correlation from the market — the pair a product holding it must declare — or None.

pub fn price_index(&self) -> Option<&str>

The price index the leg’s CPI coupons are scaled by, or None for a leg without one — the inflation key the leg declares.

pub fn currency(&self) -> Option<Currency>

The currency the leg pays in, or None for an empty leg.

A leg whose coupons disagree is not a leg, so this reports the first and leaves the check to construction.

pub fn cashflows<R: Scalar, C: CurveByIndex<R> + ?Sized>( &self, curves: &C, fixings: &FixingsView<'_, R>, as_of: NaiveDate, ) -> Result<Vec<Cashflow<R>>, CashflowError>

This leg’s cashflows in mode R, each coupon projected off the curve curves holds for its index, as of as_of.

§Errors

Whatever a coupon reports — a missing historical fixing, a missing forward curve for an unfixed coupon, or a curve query before its own reference date.

pub fn npv<R: Scalar, C: CurveByIndex<R> + ?Sized>( &self, disc: &dyn YieldCurve<R>, curves: &C, fixings: &FixingsView<'_, R>, ) -> Result<R, CashflowError>

The leg’s present value: each coupon’s amount projected off the curve curves holds for its index, discounted on disc, valued as of the discount curve’s own reference date.

The direction’s sign is applied once here rather than per coupon, so an active mode records one negation for the leg.

§Errors

As cashflows.

pub fn coupons_npv<R: Scalar, C: CurveByIndex<R> + ?Sized>( &self, disc: &dyn YieldCurve<R>, curves: &C, fixings: &FixingsView<'_, R>, ) -> Result<R, CashflowError>

The present value of this leg’s coupons alone, its principal exchanges left out — what a cross-currency side sums its exchanges onto, in the order it always has. A per-coupon leg only.

§Errors

As npv.

pub fn accumulated_amount<R: Scalar, C: CurveByIndex<R> + ?Sized>( &self, curves: &C, fixings: &FixingsView<'_, R>, as_of: NaiveDate, ) -> Result<R, CashflowError>

What a non-summing leg pays, before discounting and before the direction’s sign: N · (growth − 1) under the leg’s accumulation.

Unsigned and undiscounted so the one caller that wants the bare amount — a zero-coupon swap quoting its own sides — reads the same arithmetic the valuation runs, rather than a second copy of it.

Every coupon counts, including one whose own accrual has passed: a zero-coupon leg has not paid until its single payment date, so a reset already behind the valuation is realised growth this leg still owes.

§Errors

As cashflows, and CashflowError::MissingContractRate where an accrued-rate leg holds a coupon carrying no contract rate to accrue.

pub fn accrued_amount(&self) -> Result<f64, CashflowError>

What an accrued-rate leg pays, needing no market at all.

The rate is written into the trade and the period is fixed, so this is contract arithmetic: N · (growth − 1), where the growth is K·τ simple, (1 + K)^τ compounded and exp(K·τ) continuous. Computing it passively is also what keeps it bit-identical to the closed form each zero-coupon pricer used to carry.

accumulated_amount is this, lifted — one body — for the leg walk that does have a market in hand.

§Errors

CashflowError::MissingContractRate where a coupon carries no contract rate to accrue.

pub fn npv_and_bpv<R: Scalar, C: CurveByIndex<R> + ?Sized>( &self, disc: &dyn YieldCurve<R>, curves: &C, fixings: &FixingsView<'_, R>, ) -> Result<(R, R), CashflowError>

The leg’s present value and its analytic annuity from one walk: (npv, bpv), both signed by the direction.

A par spread needs the floating leg’s value and its annuity over the same coupons and the same discount factors; reading them off one pass evaluates each payment’s discount factor once rather than twice.

§Errors

As npv.

fn walk<R: Scalar, C: CurveByIndex<R> + ?Sized>( &self, disc: &dyn YieldCurve<R>, curves: &C, fixings: &FixingsView<'_, R>, with_weights: bool, skip_exchanges: bool, ) -> Result<(Vec<R>, Vec<R>, Vec<f64>), CashflowError>

One pass over the future coupons: each one’s projected amount, the discount factor at its payment, and — when asked — its basis-point weight. Everything a leg-level measure fuses over, in two vectors sized once and no intermediate cashflow.

The valuation date is the discount curve’s anchor: a coupon paid on or before it has been realised, and a reset on or before it has happened. One date decides both, and already-paid coupons are dropped before projection so no historical fixing the result cannot depend on is demanded.

The boundary carry. Adjacent projected IBOR coupons share a curve date — one’s accrual end is the next’s accrual start — so the discount factor read at the end of one period is carried into the start of the next rather than read again. And when the projection curve is the discounting curve and a coupon pays on its accrual end, the same factor discounts the payment. A leg of n contiguous coupons then reads n + 1 factors off its curve, not 2n or 3n. The carried value is the identical number the curve would have produced from the identical date, so nothing about the value changes — only how often it is computed. A gap in the schedule simply misses the carry.

pub fn bpv<R: Scalar>( &self, disc: &dyn YieldCurve<R>, ) -> Result<R, CashflowError>

The leg’s analytic annuity — the value of one basis point on every coupon’s rate, discounted on disc.

A weighted sum with passive weights (notional · tau · 1bp), so an active mode records one n-ary statement rather than a chain.

§Errors

Whatever the discount curve reports.

§

impl Leg

What a bare leg reads, and its value against a market. Written here, beside the declaration it builds, so the edge points from the market layer down to the cashflow layer and not back.

pub fn projections(&self) -> Vec<String>

The distinct indices this leg’s coupons name, in first-seen order — an interpolated stub’s two tenors among them.

pub fn projections_of(coupons: &[AnyCoupon]) -> Vec<String>

The distinct indices coupons name, in first-seen order: what projections reads off a leg’s own coupons.

pub fn risk_factors<'a>( &'a self, discount: &'a CollateralSpec, projections: &'a [String], ) -> RiskFactors<'a>

What this leg declares it is priced against, discounted on discount: the first of projections (this leg’s projections) as the projection, the second as the second projection, the rest as the projection basket — each coupon is priced off the curve its own index names — and the cap vols, swaption vols, CMS spread correlation, price index and inflation vols its coupons read.

pub fn npv_on( &self, market: &MarketContext, discount: &CollateralSpec, ) -> Result<f64, PricingError>

This leg’s present value against market, discounted on discount: its own declaration resolved through MarketContext::priced.

§Errors

Whatever the resolution refuses, and whatever a coupon reports.

pub fn cashflow_records( &self, market: &MarketContext, discount: &CollateralSpec, ) -> Result<Records, PricingError>

This leg’s cashflow schedule against market, discounted on discount: the table, with its columns in their order, that AnyInstrument::cashflow_records produces for an instrument holding it, as of the discount curve’s date.

§Errors

Whatever the resolution refuses, and whatever a coupon reports.

pub fn bps( &self, market: &MarketContext, discount: &CollateralSpec, ) -> Result<f64, PricingError>

This leg’s basis-point sensitivity against market: one basis point of every accruing coupon’s rate, discounted — Σ notional · year_fraction · discount_factor · 1e-4 over the rows cashflow_records gives. A redemption accrues nothing; a paid leg’s BPS is negative. The sum of bps_by_flow.

§Errors

Whatever cashflow_records refuses.

pub fn bps_by_flow( &self, market: &MarketContext, discount: &CollateralSpec, ) -> Result<Vec<f64>, PricingError>

bps flow by flow: one figure per row of cashflow_records, in its order, each flow alone. A row that accrues nothing, a redemption, gives zero.

§Errors

Whatever cashflow_records refuses.

Trait Implementations§

§

impl Clone for Leg

§

fn clone(&self) -> Leg

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 Leg

§

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

Formats the value using the given formatter. Read more
§

impl PartialEq for Leg

§

fn eq(&self, other: &Leg) -> 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 StructuralPartialEq for Leg

Auto Trait Implementations§

§

impl Freeze for Leg

§

impl RefUnwindSafe for Leg

§

impl Send for Leg

§

impl Sync for Leg

§

impl Unpin for Leg

§

impl UnsafeUnpin for Leg

§

impl UnwindSafe for Leg

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.