Skip to main content

Book

Struct Book 

pub struct Book {
    trades: Vec<Trade>,
    reporting: Option<Currency>,
    scales: Scales,
    market: Option<MarketContext>,
    fetched: FetchReport,
    moved_from: Option<MovedFrom>,
}
Expand description

A collection of trades valued together.

No scalar type parameter — see the module note. The mode is chosen when a value is asked for, not when the book is built.

Fields§

§trades: Vec<Trade>§reporting: Option<Currency>

The currency the book reports in. None means the trades’ own single currency — a mixed-currency book must declare one, because amounts in different currencies do not add.

§scales: Scales

The scale each quantity kind reports in where a measure does not state its own.

§market: Option<MarketContext>

The market the book’s verbs value against, at the as_of each is asked for. Not part of equality: two books of the same trades are the same book whatever they are marked against.

§fetched: FetchReport

What the book’s last fetch asked for and got. Not part of equality.

§moved_from: Option<MovedFrom>

The market demand_for moved away from, kept until install settles the fetch: put back on a refusal, forgotten on success. Not part of equality.

Implementations§

§

impl Book

pub fn from_fpml( documents: &[(&str, &str)], options: &ReadOptions<'_>, reporting: Option<Currency>, ) -> FpmlBook

The book of every trade documents hold, each document a (label, text) pair, read under options and reporting in reporting where given; refusals are reported beside it.

pub fn from_fpml_strict( documents: &[(&str, &str)], options: &ReadOptions<'_>, reporting: Option<Currency>, ) -> Result<Book, Refusal>

from_fpml, failing at the first refusal and booking nothing.

§Errors

The first Refusal, in reading order.

§

impl Book

pub fn new() -> Self

An empty book.

pub fn of(trades: Vec<Trade>) -> Self

A book over trades.

pub fn reporting_in(self, currency: Currency) -> Self

This book reporting in currency: every aggregate — value, scenario value, risk — converts per-trade values into it through the market’s FX spots. Required for a mixed-currency book; harmless on a single-currency one.

pub fn scaled(self, scales: Scales) -> Self

This book reporting each quantity kind in scales wherever a measure does not state its own scale — ahead of a preset’s default, behind the measure’s. See Request::resolve.

pub fn scales(&self) -> &Scales

The default scales this book reports in.

pub fn available_measures_on( &self, market: Option<&MarketContext>, ) -> Result<Vec<&'static Preset>, PricingError>

The catalogued measures this book’s trades can answer, in catalogue order.

With no market, a preset is listed when some trade declares its axis — read off the same RiskFactors a trade declares to be priced — and a bumped one when some trade reads what it bumps. With a market, a par preset is dropped when a curve a trade reads on its axis is held without the ladder that calibrated it, and a vol preset when a surface a trade reads is not held — the refusals a report would otherwise meet after paying for the pass.

§Errors

PricingError from a trade that cannot state its risk factors.

pub(crate) fn reporting_currency( &self, ) -> Result<Option<Currency>, PricingError>

The currency aggregates report in: the declared one, or the single currency the trades share. None for an empty book.

§Errors

PricingError::MixedCurrencyBook if the trades span currencies and none was declared.

pub fn with(self, trade: Trade) -> Self

Adds a trade.

pub fn add( self, id: impl Into<String>, instrument: AnyInstrument, quantity: f64, ) -> Self

Books quantity of instrument under id — with on the trade’s three terms, the line a desk writes.

pub fn extend(self, trades: impl IntoIterator<Item = Trade>) -> Self

This book with every trade of trades booked, in order — with over a list, the form for a book of many trades.

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

The book’s present value against market.

The bare verb: it lifts and views the market itself, in the passive mode, so nothing is recorded. A caller holding a view already values through npv_with.

§Errors

Whatever resolution or a pricer reports.

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

Each trade’s value against market, in booking order: trade, its npv_ccy and npv_local in it, quantity applied, and the P&L currency pnl_ccy — the reporting one — with npv_pnl converted into it at the market’s spot. npv_pnl sums to npv_on.

§Errors

PricingError::MixedCurrencyBook for a mixed book with no reporting currency, as npv_on; otherwise whatever resolution or a pricer reports, named by trade.

pub fn trades(&self) -> &[Trade]

The trades, in booking order.

pub fn len(&self) -> usize

How many trades the book holds.

pub fn is_empty(&self) -> bool

Whether the book holds no trades.

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

The book’s value in mode R, against a market view the caller holds.

A generic method on a non-generic type: this is where the mode enters, and it enters here only. The _with form of npv: it borrows the caller’s view rather than lifting the market itself.

§Errors

Whatever resolution or a pricer reports.

pub fn risk_with( &self, market: &MarketContext, tape: &mut Tape<f64>, ) -> Result<(f64, RiskVector), RiskError>

The book’s value and its risk vector, from one pass.

One forward pass, one seed, one reverse sweep, one collection — for the whole book, however many trades and curves it touches.

§Errors

RiskError from the valuation or the read-back.

§Panics

If another recording is already open on this thread.

pub fn risk_on( &self, market: &MarketContext, ) -> Result<(f64, RiskVector), RiskError>

The book’s value and its risk vector, with no tape to supply.

The reverse mode is selected internally and the tape is created and dropped here, so a caller never names one. That is what lets a binding layer offer risk without depending on the AD backend at all — the Python crate cannot mention a tape because it cannot reach one.

The tape is thread-local and kept warm: the first risk pass on a thread grows it, and every later pass on that thread reuses the buffers — Tape::record clears the recording and keeps the capacity — so a steady-state caller allocates no tape memory. The buffers stay at the largest book ever risked on the thread; that is the cost of never paying for growth twice. A caller that wants to own the tape uses risk_with.

§Errors

RiskError from the valuation or the read-back.

§Panics

If another recording is already open on this thread, including a re-entrant risk from inside a valuation.

pub fn report_on<R: Into<Request> + Copy>( &self, market: &MarketContext, measures: &[R], ) -> Result<Vec<Row>, RiskError>

measures over this book against market, from one risk pass on the thread’s warm tape — report with no tape to supply, as risk is to risk_with.

§Errors

RiskError from the valuation or the read-back.

§Panics

If another recording is already open on this thread.

pub fn implied_vol_on( &self, market: &MarketContext, premium: Option<f64>, ) -> Result<f64, PricingError>

The single flat volatility under which every option in the book, priced at it by its own formula, sums to premium — or, with no premium, to the book’s own value under market: the quote a strategy trades at.

The book is one strategy or it is nothing: every trade an FxOption on one currency pair (Black-76 on the parity forward), or every trade a surface-engine EuropeanSwaption in one currency (Black-76 or Bachelier by the surface’s convention). A straddle at one strike therefore returns the surface’s vol at that strike exactly; a strangle returns the one vol between its wings that reprices the pair.

Solved by Brent on the relative residual Σ qᵢ·npvᵢ(σ) / premium − 1, so the tolerance is scale-free, over [1e-6, 5] for a lognormal quote and [1e-8, 1] in rate units for a normal one.

§Errors

UnsupportedForProduct for an empty book, a mixed one, a Hull-White swaption or a zero premium; UnbracketedSolve when no vol in the bracket reaches the premium; SolverUnconverged if Brent gives up; otherwise whatever resolution or a pricer reports.

fn strategy_options(&self) -> Vec<(&AnyInstrument, f64)>

Every option the book holds with its quantity, a straddle read as its two options.

pub fn through(&self, lens: &Lens) -> Book

The book restricted to the trades lens selects.

pub fn attach_market(self, market: MarketContext) -> Self

This book carrying market: the market its verbs value against, at the as_of each is asked for. Attaching does no IO — a snapshot the market lacks is fetched by fetch_market_data, and no other Rust verb calls a source.

pub fn market_context(&self) -> Option<&MarketContext>

The market this book carries, if any.

pub fn fetch_report(&self) -> &FetchReport

What the book’s last fetch asked for and got.

pub fn fetch_market_data( &mut self, as_of: NaiveDate, ) -> Result<(), SnapshotError>

Fetches what this book needs at as_of from its market’s data source and keeps it: the market (an undated one where the book carries none) is moved to as_of, and recipes, the demand, one fetch and the build follow. Where the market already holds everything the book reads, no source is called. On a refusal the book’s market is left as it was, and fetch_report still says what was asked.

The one Rust verb that does IO, and so the one taking &mut self.

The market keeps the snapshot of every date it was fetched at, so a book valued daily for a year holds a year of them; drop the dates no longer needed with MarketContext::without.

§Errors

SnapshotError — a refused recipe, the source’s own failure, every gap at once, or a curve that did not solve.

fn fetch_moving( &mut self, as_of: NaiveDate, demand: &Demand, ) -> Result<(), SnapshotError>

The fetch past fetch_market_data’s fast path: recipes, the demand, one fetch and the build, the market moved to as_of on the way — the caller restores it on a refusal.

fn fetch_base(&self, as_of: NaiveDate) -> MarketContext

The book’s market at as_of as a fetch starts from: the market it carries (an undated one where it carries none), moved to as_of.

pub fn recipe_ask( &self, as_of: NaiveDate, ) -> Result<Option<RecipeAsk>, SnapshotError>

The first half of a fetch: what a recipe source must be asked before the demand at as_of can be stated — or None where nothing is to be asked: the date asks the source for nothing, or every key the book reads has the caller’s own recipe or was already asked at that date.

§Errors

SnapshotError::Pricing where a trade cannot state what it reads.

pub fn demand_for( &mut self, as_of: NaiveDate, recipes: &[RecipeSpec], ) -> Result<Demand, SnapshotError>

The second half’s start: recipes — a source’s answer to recipe_ask — kept as the source’s recipes for as_of, the book’s market moved to as_of, and that date’s demand. Recipes given where nothing was asked are kept too, and no key is recorded as asked.

§Errors

SnapshotError::Recipe naming a recipe the builder refuses; Pricing where a trade cannot state what it reads.

fn remember_the_move(&mut self)

Keeps the market a fetch is about to move away from — the first one, where a fetch is already in flight.

fn settle(&mut self, succeeded: bool)

Ends a fetch begun by demand_for: on success the market it moved away from is forgotten, on a refusal it is put back.

pub fn install( &mut self, demand: &Demand, data: &MarketData, ) -> Result<(), SnapshotError>

The last half: data — a source’s answer to demand — built into the book’s market at demand.as_of as MarketContext::with_market_data builds it, and kept; fetch_report written from the two, on a refusal as well. A demand that asks nothing and names no gap changes nothing and leaves the last report standing.

§Errors

SnapshotError — every gap at once, a stamp from the future, a curve that did not solve — leaving the market as it was; Malformed where demand was stated for another state of the book’s market than the one it would be built into.

fn install_on_the_move( &mut self, demand: &Demand, data: &MarketData, ) -> Result<(), SnapshotError>

install’s body, the market already moved to the demand’s date; install settles the move.

fn date_or_market( &self, as_of: Option<NaiveDate>, ) -> Result<NaiveDate, PricingError>

The book’s market at as_of, borrowed where it is already there. as_of, else the date of the market the book carries.

§Errors

PricingError::Undated with no date given and none on the market.

fn market_at( &self, as_of: NaiveDate, ) -> Result<Cow<'_, MarketContext>, PricingError>

pub fn npv( &self, as_of: impl Into<Option<NaiveDate>>, ) -> Result<f64, PricingError>

The book’s present value at as_of, against the market it carries.

§Errors

PricingError::NoSnapshot where the book’s market holds no snapshot at as_of — fetch one with fetch_market_data — and whatever resolution or a pricer reports.

pub fn npv_by_trade( &self, as_of: impl Into<Option<NaiveDate>>, ) -> Result<Records, PricingError>

Each trade’s value at as_of, in its own currency and in the P&L currency: npv_by_trade_on against the market the book carries.

§Errors

As npv and npv_by_trade_on.

pub fn risk( &self, as_of: impl Into<Option<NaiveDate>>, ) -> Result<(f64, RiskVector), RiskError>

The book’s value and its risk vector at as_of, from one pass.

§Errors

As npv, and the read-back.

§Panics

If another recording is already open on this thread.

pub fn report<R: Into<Request> + Copy>( &self, measures: &[R], as_of: impl Into<Option<NaiveDate>>, ) -> Result<Vec<Row>, RiskError>

measures over this book at as_of, from one risk pass.

§Errors

As risk; a bumped measure is refused before the pass.

§Panics

If another recording is already open on this thread.

pub fn implied_vol( &self, premium: Option<f64>, as_of: NaiveDate, ) -> Result<f64, PricingError>

The one flat volatility the book’s options reprice to premium at, at as_of — see implied_vol_on.

§Errors

As implied_vol_on, and a missing snapshot.

pub fn available_measures( &self, as_of: NaiveDate, ) -> Result<Vec<&'static Preset>, PricingError>

The catalogued measures this book can answer, limited to those its market at as_of can supply where it holds a snapshot there. Never fetches.

§Errors

PricingError from a trade that cannot state its risk factors.

pub fn credit_bumps( &self, kind: Sensitivity, bump: f64, as_of: NaiveDate, ) -> Result<Vec<(String, f64)>, CreditBumpError>

The bumped sensitivity kind at as_of: one (key, value) row per credit index or entity, as the module function it names computes it.

§Errors

As the module function, and a missing snapshot.

pub fn under( &self, scenario: &Scenario, as_of: NaiveDate, ) -> Result<Book, ScenarioError>

This book on its market at as_of under scenario: a new book whose market is the shocked one, at as_of.

§Errors

ScenarioError from the shock, and a missing snapshot.

pub fn explain_pnl( &mut self, as_of1: NaiveDate, as_of2: NaiveDate, order: &[RiskAxis], ) -> Result<ExplainReport, BookPnlError>

The step-revaluation explain of this book from its snapshot at as_of1 to as_of2 — see explain.

Within one day (as_of1 == as_of2) the snapshot held is the start, it is fetched again from the market’s source (which answers the latest it holds), and the new snapshot — kept as the book’s — is the end.

Across days the snapshot held at as_of1 is the start and the book’s fetch at as_of2 the end, and two legs come first: the cash the book was paid after as_of1 and up to as_of2, and the carry — the book on as_of1’s quotes rebuilt at as_of2, each print it reads in between at the forecast as_of1’s curves projected, less its value at as_of1. The rest is the same-day ladder from that rolled market. What no source serves — vols, credit curves, model marks — is not rolled: the rolled market takes it as as_of2 holds it, so its day’s move lands in the carry.

§Errors

BookPnlError.

fn explained_across_days( &mut self, as_of1: NaiveDate, as_of2: NaiveDate, order: &[RiskAxis], ) -> Result<ExplainReport, BookPnlError>

explain_pnl across days. On any failure the book keeps the market it had.

fn rolled( &self, before: &MarketContext, after: &MarketContext, ) -> Result<MarketContext, BookPnlError>

before’s quotes rebuilt at after’s date: after’s recipes, the strips and spots before was fetched from, the prints before held, and each print learnt since at the forecast before projected it at. What no source serves is carried from after.

fn cash_paid( &self, before: &MarketContext, to: NaiveDate, ) -> Result<f64, BookPnlError>

What the book is paid after before’s date and up to to, in its reporting currency at before’s spots: each trade’s cashflow rows paying in that window, as before projects them, signed by side and scaled by quantity.

pub fn predicted_pnl( &mut self, as_of1: NaiveDate, as_of2: NaiveDate, ) -> Result<PredictedPnl, BookPnlError>

The predicted explain from as_of1 to as_of2, on the terms of explain_pnl.

§Errors

BookPnlError.

pub fn reset_pnl( &mut self, as_of1: NaiveDate, as_of2: NaiveDate, ) -> Result<ResetPnl, BookPnlError>

The reset P&L from as_of1 to as_of2, on the terms of explain_pnl.

§Errors

BookPnlError.

fn refetched<T>( &mut self, as_of1: NaiveDate, as_of2: NaiveDate, attribute: impl FnOnce(&Book, &MarketContext, &MarketContext) -> Result<T, PnlError>, ) -> Result<T, BookPnlError>

attribute run over the held snapshot at as_of1 and a fresh fetch of the same date, which becomes the book’s. The fetch asks again for every print the day’s earlier fetch learnt, so a fixing restated during the day reaches the reset leg rather than being attributed to the curves. What the source does not serve — vols, credit curves, model marks — is carried from the held snapshot, so the fetch leaves it where it was. On any failure the book keeps the market it had.

Trait Implementations§

§

impl Clone for Book

§

fn clone(&self) -> Book

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 Book

§

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

Formats the value using the given formatter. Read more
§

impl Default for Book

§

fn default() -> Book

Returns the “default value” for a type. Read more
§

impl PartialEq for Book

Trades, reporting currency and scales; the market a book carries and its last fetch are not what the book is.

§

fn eq(&self, other: &Self) -> 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.

Auto Trait Implementations§

§

impl !Freeze for Book

§

impl !RefUnwindSafe for Book

§

impl !UnwindSafe for Book

§

impl Send for Book

§

impl Sync for Book

§

impl Unpin for Book

§

impl UnsafeUnpin for Book

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.