Financial maths library for risk-neutral pricing and risk

Overview

QuantMath

Financial maths library for risk-neutral pricing and risk

Api Documentation

Goals

Some quant math libraries are really just a collection of pricing formulae. This hopes to be that (see the math module) but also much more. This library is intended to be plugged into the risk and pricing infrastructure in an investment bank or hedge fund. This does not preclude the use of the library for academic work, but will introduce a level of real-world messiness that is often missing from academia.

Lifecycle and Flows

QuantMath is responsible for managing the lifecycle of financial instruments (see the instrument module). As products make payments or as dividends go ex, this results in the instrument splitting into multiple flows. Nothing ever disappears. The SecDB library at Goldman Sachs is famous for taking this philosophy to extremes, but QuantMath is at least capable of the same level of discipline. It is vital to correctly model when flows go ex -- when they cease to be part of the value of this instrument, and are owned by the counterparty (even if not yet settled).

Settlement

Most investment banks skirt around the issues of settlement. What is the value of an equity? Is it the spot price, or is it the spot price discounted from the date when the payment for the equity would actually be received (e.g. T+2). QuantMath intends to allow rigour in settlement, in the premium payment, the payoff, and in the underlying hedges.

Risk and Scenarios

QuantMath is designed to make it easy to reuse calculations that have not changed as a result of a risk bump. For example, if you have an exotic product with multiple equity underlyings, bumping one of those underlyings only results in the affected Monte-Carlo paths being reevaluated. In my experience this is a vital optimisation, and QuantMath makes it possible from the lowest levels such as bootstrapping dividend curves, to the highest, such as reuse of Longstaff-Schwarz optimisation.

Recursive Instruments

It is common to build instruments recursively. A basket contains composite or quanto underliers, then a dynamic index maintains the basket -- finally an exotic product is written with the dynamic index as an underlying. The library must therefore manage this sort of recursive product, whether valuing in Monte-Carlo, analytically or via a finite difference engine.

Simplicity, Orthogonality and Encapsulation

The library must be easy for quants to work in and for IT systems to work with. Adding a new risk, instrument or model should normally mean changes to only one file (and maybe a list of files in mod.rs). The interface to IT should be data-driven, so IT do not need to rebuild every time an instrument or model is added. Models, instruments and risks should be orthogonal, so any can be used with any (subject to sensible mathematical restrictions). If things go wrong, it should be easy to debug just QuantMath, without having to debug the containing IT system. This means that QuantMath should be runnable purely from serialised state, such as JSON files.

The Architecture

The library has a strict hierarchy of modules. Ideally there should be no backward dependencies, such that the library could be split into a separate crate for each module. If you are looking at the library for the first time, it may be best to start from the top level (Facade). Starting at the top level, the modules are:

Facade

This is the interface that IT systems talk to. It is data-driven, so adding a new product or model should not affect the IT systems at all.

Pricers

A pricer evaluates an instrument given market data and a choice of model. We currently have two pricers: Monte-Carlo, which evaluates instruments by averaging across many random paths; self-pricer, which relies on instruments knowing how to price themselves. I hope to add at least one finite difference backward-induction engine.

Models

Models of how we expect prices to change in the future. All are stochastic, but some have stochastic volatility or rates. Examples of models are BGM (Brace Gatarek Musiela), Black, Heston.

Risk

Defines how market data can be bumped, and manages the dependencies when this happens. This contain definitions of risk reports, such as Delta, Gamma, Vega and Volga for all underliers matching some criteria.

Instruments

Defines financial products, indices, assets and currencies. Anything that has a price. Some instruments know how to price themselves (basically, any instrument where the price is well-defined and not model-dependent -- remember this module is lower than models). Some instruments know how to price themselves in a Monte-Carlo framework, given paths of their underliers.

Data

The input market data; vol surfaces, dividends, spot prices, yield curves etc. Also defines bumps to these data items. Most risks are calculated by bumping these inputs.

Math

Low level mathematical formulae, from the Black-Scholes formula to interpolation and quadrature. Where possible, we use functionality from well-established crates in Rust, such as ndarray and statrs, so this is mainly quant-specific maths.

Dates

Dates are very important for financial maths software. We use explicit dates everywhere rather than year-fractions, which is essential for handling settlement correctly. This module also handles date arithmetic, such as date rules and day counts.

Core

Very low-level functionality, such as the definition of the Error struct, and required extensions to serde, such as dedup (deduplication of nodes in directed acyclic graph) and factories (using tagged_serde to handle polymorphic nodes in serialization and deserialization).

Comments
  • Sort out price recursion

    Sort out price recursion

    The price method needs to take a date (or a vector of them), let's call it the val_date. The price returned should be the expected screen price as of the val date. Flows that go ex should be triggered by the val date. Discounting should be to the val_date plus the standard settlement.

    The Priceable interface should also support a method that returns the discount date given a val date. Then if you want to discount to a particular date, rather than using standard settlement, you can do so easily.

    opened by MarcusRainbow 1
  • Serialisation

    Serialisation

    We need a way to construct the building blocks of QuantMath by deserialising some text representation such as JSON or XML. Similarly, we need a way of serialising out a QuantMath state, so it can be deserialised later. Ideally, this should be automated, for example using serde, so there is no code to maintain.

    opened by MarcusRainbow 1
  • Calibrators

    Calibrators

    This needs a whole new module, probably living above pricers. An easy calibrator to start off with would be a European vol calibrator. Feed it a European price, and it calculates the implied volatility. This should be pretty straightforward, given the ease of bumping a pricer.

    opened by MarcusRainbow 1
  • Implement risks

    Implement risks

    These should live in the risks project. Simple examples would be a delta to a single asset. More useful and interesting examples would be a report showing delta, gamma and optionally cross gamma to all assets matching some criteria.

    The single asset risks would be a nice easy project for someone with not much financial knowledge.I am thinking:

    • Delta and gamma
    • Dividend risk
    • Yield risk (PV01)
    • Vega and volgamma
    • Cost-of-carry risk
    • Vanna (bump to the spot and bump to vol)
    opened by MarcusRainbow 1
  • Thread safety

    Thread safety

    Currently, the whole library is built around Rc containers, and is thread-unsafe. There are a few ways in which the library could be multithreaded:

    • Externally, so the same market data and instrument definitions are used for different calculations simultaneously. This means using Arc for the market data and instrument definitions, I think.
    • Monte-Carlo. Splitting the paths so different paths are performed on different CPUs, then doing a join and average.
    • Risks, so different risks are calculated in different threads.
    opened by MarcusRainbow 1
  • Fix test cases

    Fix test cases

    1. risk::deltagamma::tests::serde_delta_gamma_report_roundtrip fix this test case by adding tolerance
    2. Some cases I use dyn as rust compiler says warning: trait objects without an explicit dyn are deprecated
    3. add .travis.yml
    opened by ninkoze 0
  • Thread safety

    Thread safety

    Added Send + Sync to all the objects that are passed through the external interface, as we have no way of policing whether they are used in different threads. Fix all the compile errors that result.

    The effect is that all Rc containers are now Arc. This makes sense, as we really only use sharing when external users want it. For example, a user may use the same instrument and market data in different threads. It adds an overhead to cloning an Arc, but we do not do that very often.

    opened by MarcusRainbow 0
  • Generate and test the c interface

    Generate and test the c interface

    quantmath.h is generated using cbindgen. Currently, this is done manually, with the command line (run from the quantmath root directory):

    ../cbindgen-master/target/debug/cbindgen -c cbindgen.toml > quantmath.h

    Do not edit this file, which is a generated file. I have added a directory src/cpp-test containing a test of the C interface written in C++. To build this test, use the command line from within that directory,

    g++ -std=c++11 -I../.. -o quantmath_runner quantmath_runner.cpp ../../target/debug/libquantmath.dylib

    I have added some test files that allow the test code to be executed. To run these, use the command line:

    ./quantmath_runner first_test.txt

    opened by MarcusRainbow 0
  • Create Facade module

    Create Facade module

    The facade is an easy-to-use data-driven interface to QuantMath. It can be used alongside lower-level calls. For example, the facade could be used to create an instrument, while the market data could be supplied by direct calls into the data module.

    The facade is currently Rust code, but the intention is to mirror the functions in the facade with C-style or JNI interfaces, to allow interoperability with other languages.

    As part of this checkin, complete the serialization and deserialization of all objects required for pricing.

    opened by MarcusRainbow 0
  • Implement deduplication for DAGs of shared objects

    Implement deduplication for DAGs of shared objects

    This initial commit does not use the deduplication for any real QuantMath objects. That is likely to be rather more complicated, because we also want to support polymorphism.

    This commit also includes polymorphic serialization for many types.

    opened by MarcusRainbow 0
  • Serialization/deserialization for vol surfaces

    Serialization/deserialization for vol surfaces

    Vol surfaces and their contained objects such as cubic spline interpolators and calendars. Calendars are serialized with all their holidays. We may want a more concise serialization.

    opened by MarcusRainbow 0
  • Interested in collaborating

    Interested in collaborating

    Hello,

    Earlier this evening I randomly came across your post on users.rust-lang.org from several months ago looking for feedback on this library. I wasn't previously aware of the project and was impressed by its breadth and the amount of work that's already gone into it. I run a trading operation on a rust codebase so this is definitely of major interest to me! I'd be interested in collaborating and wanted to send some initial thoughts from a couple hours with the code.

    You mentioned in the post you were new to rust, so I included various recommendations from my own experience. Perhaps some of it will be obvious or things you already know - but I thought it couldn't hurt. Like you, I see rust as an incredible tool for this application, owing to the great performance, powerful type system, modern packaging system, etc. But there are definitely still bumps along the way during the learning curve.

    In any event, here are various thoughts I jotted down while diving into the project for the first time:

    • The number one thing I wanted/expected to see are some examples. Examples are integrated into cargo (cargo run --example pricing) and I often start there when I'm looking at a project for the first time.

    • On the other hand, there's plenty of tests. (Second step is often git clone then cargo test for me). Perhaps some of the tests include code that would be suitable to use in examples. Do you have any recommendations on which ones to look at?

    • One of the biggest issues I face is needing to use different number types in different situations and performance and ergonomics pitfalls associated with juggling all of them, converting from one to the other, etc. In many cases, correct precision is required and a decimal type is needed. (I have been using the rust wrapper to the decNumber lib for over a year, it seems by my lights to be the best choice at the moment). In many other cases, the performance hit from using decimal is very, very steep compared to the floating point primitives (f64/f32). Rust tends very much towards prudence when it comes to floating point, with a carefully designed api, but it still takes a lot of care to avoid blowups. A third option that sometimes presents itself is to use integer types as fixed-point, for instance when the precision of prices is static. This can be very fast and precise, but it's not always available. I saw that the library generally uses f64, I was wondering if you had further thoughts on how that has worked for you in this application.

    • I'm intrigued by the date functionality here; it might be worth pursuing it as a stand-alone crate. Currently the chrono crate has a pretty good handle on power/completeness/correctness and it works very well with serde for deserialization. However, the main chrono DateTime<Utc> type is somewhat heavyweight: it's an i32 for the date, two u32s for the time, plus an offset enum (which I believe is zero-sized, however). I frequently use nanosecond timestamps stored in an i64/u64 for performance, and there's no good library that I've seen that focuses less on the kitchen sink, and more on the most performant possible way to store/operate on times.

    • Regarding the Error struct defined in core::qm:

      pub struct Error {
          message: String 
      }
      

      (Haven't been able to tell if this is widely used throughout the library or not). Error-handling has been a moving target in rust, with the std Error trait falling out of favor and several different crates trying to make error-handling more ergonomic have risen and fallen. Personally, I have come to prefer using Error enums defined on a per-crate or per-mod basis. In this case, it might look something like this:

      pub enum Error {
          Io(std::io::Error),
          ShapeError(ndarray::ShapeError)
          // ...
      }
      

      A lot of the time I keep it even simpler with "zero-size" enums with no data associated with each variant, but the variant name alone is enough to act on the error.

      The advantages of localized, lightweight error types include:

      • In rust, matching on or otherwise manipulating/operating on types is very ergonomic and powerful, while matching/operating on strings is relatively painful, owing to the strict ownership semantics and String/str divergence.

      • If latency is a priority, as it often is in trading, incurring a heap allocation (for the message String) just to handle an error is somewhat wasteful.

      • This is especially true because in idiomatic rust, program crashes are very rare and there's little need to gather as much information as possible for piecing together what went wrong after the fact. Your debugging time is more likely to be spent on the front-end getting the program to compile in the first place.

    • Regarding this comment/question:

      impl Black76 {
          pub fn new() -> Result<Black76, qm::Error> {
      
              // For some reason we cannot use the ? operator for this sort of error.
              // as a workaround, do it manually for now.
              match Normal::new(0.0, 1.0) {
                  Ok(normal) => Ok(Black76 { normal: normal }),
                  Err(e) => Err(qm::Error::new(&format!("RSStat error: {}", e)))
              }
          }
          // ...
      }
      

      The Normal::new function from the statrs crate returns Result<T, StatsError>. Since Black76::new returns Result<Self, qm::Error>, you would only be able to use the question mark operator if a From<_> impl exists to convert a StatsError into a qm::Error. You already have a long list of these From<_> impls in core::qm, so perhaps you discovered this along the way.

      Incidentally, the statrs::StatsError is a great example of a robust, but lightweight error enum that covers the various types of errors that can come from the library without any allocations. &'static str (string literals) used in many of the variants are very ergonomic for that purpose.

      In this case, however, handling the error isn't even necessary. The error can only arise if either argument is NaN or a negative value is passed as the std_dev argument, which is clearly is not the case since it's being passed float literals. In my judgement, this is a perfect use of .unwrap() or .expect("statrs::Normal::new(0.0, 1.0)"). I typically note why an unwrap is safe with a quick comment.

    • One test failed on my machine (using nightly-2018-12-02), which seems to be a floating point issue:

      thread 'math::brent::tests::problem_of_the_day' panicked at 'result=192.80753261197134 expected=192.80752497643797', src/math/brent.rs:146:9
      

    Hope these initial comments are helpful to you. I'm looking forward to delving further into this. I'd be interested to hear what the current status on the project is, and if you have any ideas for areas where collaboration would be especially useful.

    Jonathan

    opened by jonathanstrong 2
  • Discount date

    Discount date

    At present, the price returned by all pricers is discounted to the settlement date of the instrument being priced. This means that equities value at spot, listed options value at their screen price etc.

    This matches the accounting policy in many banks (though not Goldman Sachs) but it is not really consistent. To be properly consistent, the price should be discounted to the same date, for all instruments. This means that not all instruments can value at their spot price.

    We should also support pricing to a consistent discount date. This means supplying an optional discount date to pricer.price, which can use the credit id of contained instruments, plus their settlements, to work out how to discount the price to the supplied date.

    opened by MarcusRainbow 0
  • StickySpot dynamic

    StickySpot dynamic

    What it does now is to just leave spot alone. It ought to make spot drop by the amount of any dividends going ex (or use the ex-from date to drop dividends -- it would be interesting to investigate this alternative)

    opened by MarcusRainbow 0
  • ex dates

    ex dates

    Every instrument should have an ex date, at least optionally. Even cash and stock should have an optional ex date, in case they are the result of some transfer to a third party.

    Closely associated with a fixing table, maybe contained within it, should be a date after which any payments that are ex should not be included. This is normally the same as the spot date. However, during theta calculation, it may optionally be left where it is, while the spot date is bumped forward. This has the effect of leaving all payments in the same ex state, which means there should be no large jumps due to the theta bump.

    opened by MarcusRainbow 0
  • Multiple results from price or mc_price

    Multiple results from price or mc_price

    At present, these methods just return Result<f64, qm:Error>, which means that a lot of the detail of pricing is lost. There are two kinds of things that could be returned:

    1. A recursive breakdown of how the price was calculated. For example, the price of a basket is the weighted sum of the components. If the weights and components were also returned, it would allow the user to show breakdown of the price and also the risks by component, without any further calculation.
    2. Pricer-dependent outputs. For example, a Monte-Carlo pricer could output a convergence graph. Again, this could be summed for risks, showing convergence of the risks as well. Pricers for dynamic indices could show the contribution from fees. (This can be important for recursive dynamic indices, where there may be rules for netting out fees other than at the top level.)

    I think this means returning some kind of structure, containing top-level price, recursive price breakdown, and pricer-specific (and maybe model specific) outputs.

    opened by MarcusRainbow 0
Owner
Marcus Rainbow
Game developer (Rampage for Amstrad CPC); Locomotive software; Monotype systems; ... ; Morgan Stanley (global head of equities quant dev)
Marcus Rainbow
Diem’s mission is to build a trusted and innovative financial network that empowers people and businesses around the world.

Note to readers: On December 1, 2020, the Libra Association was renamed to Diem Association. The project repos are in the process of being migrated. A

Diem 16.7k Jan 8, 2023
Diem’s mission is to build a trusted and innovative financial network that empowers people and businesses around the world.

Note to readers: On December 1, 2020, the Libra Association was renamed to Diem Association. The project repos are in the process of being migrated. A

Diem 16.7k Jan 9, 2023
Prototype risk modeling simulation for Portfolio using Arbiter.

proto-sim Prototype simulation using Arbiter as the simulation & agent engine. Build & Run build.sh cargo run Arbiter config The arbiter.toml config

Primitive 13 Aug 14, 2023
A vertically scalable stream processing framework focusing on low latency, helping you scale and consume financial data feeds.

DragonflyBot A vertically scalable stream processing framework focusing on low latency, helping you scale and consume financial data feeds. Design The

null 17 Jul 12, 2023
Safeguard your financial privacy with zero-knowledge proofs.

Spinner The Spinner project (https://spinner.cash) takes a privacy first approach to protect users crypto assets. It is a layer-2 protocol built on th

Spinner 21 Dec 28, 2022
A command line tool for managing financial investment portfolios written in Rust.

A command line tool for managing financial investment portfolios written in Rust. This project is the modern successor of finance. Installation You ca

Markus Zoppelt 15 Dec 21, 2022
High-level networking library that extends the bevy_replicon library to allow snapshot interpolation and client-side prediction

bevy_replicon_snap A Snapshot Interpolation plugin for the networking solution bevy_replicon in the Bevy game engine. This library is a very rough pro

Ben 3 Oct 15, 2023
Library with support for de/serialization, parsing and executing on data-structures and network messages related to Bitcoin

Rust Bitcoin Library with support for de/serialization, parsing and executing on data-structures and network messages related to Bitcoin. Heads up for

Rust Bitcoin Community 1.3k Dec 29, 2022
Mundane is a Rust cryptography library backed by BoringSSL that is difficult to misuse, ergonomic, and performant (in that order).

Mundane Mundane is a Rust cryptography library backed by BoringSSL that is difficult to misuse, ergonomic, and performant (in that order). Issues and

Google 1.1k Jan 3, 2023
Zei is a library that provide tools to create and verify public transaction with confidential data.

#Zei: Findora's Cryptographic Library Zei is a library that provide tools to create and verify public transaction with confidential data. Support: Bas

Findora Foundation 0 Oct 23, 2022
Helper library for interacting with Terra assets (SDK coins and CW20 tokens)

terra-asset Helpers for interacting with Terra assets, including native coins and CW20 tokens Usage This crate contains two struct types: AssetInfo st

larry 9 Jan 3, 2022
Meta-repository for Miscreant: misuse-resistant symmetric encryption library with AES-SIV (RFC 5297) and AES-PMAC-SIV support

The best crypto you've never heard of, brought to you by Phil Rogaway A misuse resistant symmetric encryption library designed to support authenticate

miscreant. 480 Dec 8, 2022
Aya is an eBPF library for the Rust programming language, built with a focus on developer experience and operability.

Aya API docs | Chat | Aya-Related Projects Overview eBPF is a technology that allows running user-supplied programs inside the Linux kernel. For more

null 1.5k Jan 6, 2023
A library to help you sew up your Ethereum project with Rust and just like develop in a common backend

SewUp Secondstate EWasm Utility Program, a library helps you sew up your Ethereum project with Rust and just like development in a common backend. The

Second State 48 Dec 18, 2022
Enigma Core library. The domain: Trusted and Untrusted App in Rust.

Enigma Core library Service Master Develop CI Badge Pure Rust Enclave && Untrusted in Rust. Core is part of the Enigma node software stack. The Core c

SCRT Labs 89 Sep 14, 2022
Dexios-Core is a library used for managing cryptographic functions and headers that adhere to the Dexios format.

What is it? Dexios-Core is a library used for managing cryptographic functions and headers that adhere to the Dexios format. Security Dexios-Core uses

brxken 3 Jul 4, 2022
STARK - SNARK recursive zero knowledge proofs, combinaison of the Winterfell library and the Circom language

STARK - SNARK recursive proofs The point of this library is to combine the SNARK and STARK computation arguments of knowledge, namely the Winterfell l

Victor Colomb 68 Dec 5, 2022
RGB smart contracts: client-facing library & command-line for desktop and mobile

RGB smart contracts RGB is confidential & scalable client-validated smart contracts for Bitcoin & Lightning. It embraces the concepts of private & mut

RGB: scalable & private smart contracts for bitcoin & lightning 4 Mar 15, 2023
A library facilitating the signing and broadcasting of transactions on Cosmos SDK-based blockchains

txf Transaction factory - a library facilitating the signing and broadcasting of transactions (txs) on Cosmos SDK-based blockchains. How to use Exampl

larry 5 Jun 29, 2023