Skip to content

ahmedriza/rust-quantlib

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

81 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

rust-quantlib

This is a pure Rust implementation of the excellent QuantLib library. QuantLib is an outstanding piece of work by a team of dedicated professionals in the field. Many thanks for their continuing work.

This is a work in progress. At present the focus is on implementing the essential building blocks of the library, closely following the QuantLib implementations.

Examples can be found in the examples directory. Use cargo run --example <name> where <name> is the name of the example binary (without the .rs suffix), e.g.:

cargo run --example bonds

Example

The following demonstrates an example of using the library for pricing bonds. More examples can be found in the examples directory of the source. We will add more examples there as work on the library progresses.

use rust_quantlib::context::pricing_context::PricingContext;
use rust_quantlib::datetime::calendar::Calendar;
use rust_quantlib::datetime::daycounter::DayCounter;
use rust_quantlib::datetime::frequency::Frequency;
use rust_quantlib::datetime::holidays::unitedstates::UnitedStates;
use rust_quantlib::datetime::period::Period;
use rust_quantlib::datetime::schedulebuilder::ScheduleBuilder;
use rust_quantlib::datetime::timeunit::TimeUnit::*;
use rust_quantlib::datetime::{date::Date, months::Month::*};
use rust_quantlib::instruments::bond::Bond;
use rust_quantlib::instruments::fixedratebond::FixedRateBond;
use rust_quantlib::instruments::zerocouponbond::ZeroCouponBond;
use rust_quantlib::rates::compounding::Compounding;
use rust_quantlib::types::{Integer, Real};

/// This example shows how to calcualate the maturity yield on US Treasury Bills, Notes
/// and Bonds using real market data.
pub fn main() {
    let pricing_context = PricingContext::new(Date::new(6, June, 2022));
    let common_data = CommonData::new(pricing_context, 1);

    let mut results = vec![];
    zero_coupon_bonds(&common_data, make_tbill_market_data(), &mut results);
    fixed_rate_bonds(&common_data, make_bond_market_data(), &mut results);

    show_results(results);
}

pub fn zero_coupon_bonds(
    cd: &CommonData,
    market_data: TBillMarketData,
    results: &mut Vec<Result>
) {
    for i in 0..market_data.maturities.len() {
        let maturity_date = market_data.maturities[i];
        let discount_yield = market_data.discount_yields[i] / 100.0;

        let zcb = ZeroCouponBond::new(
            cd.settlement_days,
            &cd.calendar,
            cd.face_amount,
            maturity_date,
        );
        // Calcualte the price from the discount yield
        let price = zcb.price_from_discount_yield(discount_yield, cd.settlement_date);
        // Calculate yield
        let bond_yield = 100.0
            * zcb.bond_yield(
                price,
                cd.daycounter.clone(),
                cd.compounding.clone(),
                cd.frequency,
                cd.settlement_date,
            );

        results.push(Result {
            bond_description: format!("{:?}/{:?}", zcb, zcb.period(cd.pricing_context.eval_date)),
            price,
            bond_yield,
        });
    }
}

pub fn fixed_rate_bonds(cd: &CommonData, md: BondMarketData, results: &mut Vec<Result>) {
    for (i, maturity) in md.maturities.iter().enumerate() {
        let ref_start = maturity - md.periods[i];
        let schedule = ScheduleBuilder::new(
            cd.pricing_context,
            ref_start,
            *maturity,
            Period::from(cd.frequency),
            cd.calendar.clone(),
        )
        .build();
        let frb = FixedRateBond::new(
            cd.settlement_days,
            cd.face_amount,
            schedule,
            vec![md.coupons[i] / 100.0],
            cd.daycounter.clone(),
        );
        let price = md.clean_prices[i];
        // Calculate yield
        let bond_yield = 100.0
            * frb.bond_yield(
                price,
                cd.daycounter.clone(),
                cd.compounding.clone(),
                cd.frequency,
                cd.settlement_date,
            );

        results.push(Result {
            bond_description: format!("{:?}/{:?}", frb, md.periods[i]),
            price,
            bond_yield,
        })
    }
}

pub fn make_tbill_market_data() -> TBillMarketData {
    TBillMarketData {
        maturities: vec![
            Date::new(5, July, 2022),
            Date::new(2, August, 2022),
            Date::new(8, September, 2022),
            Date::new(8, December, 2022),
            Date::new(18, May, 2023),
        ],
        discount_yields: vec![0.851, 1.016, 1.214, 1.694, 2.111],
    }
}

pub fn make_bond_market_data() -> BondMarketData {
    BondMarketData {
        coupons: vec![2.5, 2.75, 2.625, 2.75, 2.875, 3.25, 2.875],
        clean_prices: vec![
            99.0 + (18.0 + 3.0 / 4.0) / 32.0,
            99.0 + (17.0 + 3.0 / 8.0) / 32.0,
            98.0 + (7.0 + 1.0 / 2.0) / 32.0,
            98.0 + (4.0 + 1.0 / 4.0) / 32.0,
            98.0 + (25.0 + 3.0 / 4.0) / 32.0,
            97.0 + (25.0 + 1.0 / 2.0) / 32.0,
            94.0 + (12.0 + 1.0 / 2.0) / 32.0,
        ],
        periods: vec![
            Period::new(2, Years),
            Period::new(3, Years),
            Period::new(5, Years),
            Period::new(7, Years),
            Period::new(10, Years),
            Period::new(20, Years),
            Period::new(30, Years),
        ],
        maturities: vec![
            Date::new(31, May, 2024),
            Date::new(15, May, 2025),
            Date::new(31, May, 2027),
            Date::new(31, May, 2029),
            Date::new(15, May, 2032),
            Date::new(15, May, 2042),
            Date::new(15, May, 2052),
        ],
    }
}

pub fn show_results(results: Vec<Result>) {
    println!(
        "{:>2} {:<20} {:6} {:8}",
        "#", "Bond Description", "price", "yield"
    );
    println!("{:<}", "-".repeat(37));
    for (i, r) in results.iter().enumerate() {
        println!(
            "{:2} {:<20} {:.3} {:.3}%",
            i + 1,
            r.bond_description,
            r.price,
            r.bond_yield
        );
    }
}

/// Common data for pricing
pub struct CommonData {
    pub pricing_context: PricingContext,
    pub settlement_days: Integer,
    pub settlement_date: Date,
    pub calendar: Calendar,
    pub daycounter: DayCounter,
    pub compounding: Compounding,
    pub frequency: Frequency,
    pub face_amount: Real,
}

/// US Treasury Bill market data
pub struct TBillMarketData {
    pub discount_yields: Vec<Real>,
    pub maturities: Vec<Date>,
}

/// US Note and Bond market data
pub struct BondMarketData {
    pub coupons: Vec<Real>,
    pub clean_prices: Vec<Real>,
    pub periods: Vec<Period>,
    pub maturities: Vec<Date>,
}

pub struct Result {
    pub bond_description: String,
    pub price: Real,
    pub bond_yield: Real,
}

impl CommonData {
    pub fn new(pricing_context: PricingContext, settlement_days: Integer) -> Self {
        let settlement_date = pricing_context.eval_date + settlement_days;
        Self {
            pricing_context,
            settlement_days,
            settlement_date,
            calendar: UnitedStates::government_bond(),
            daycounter: DayCounter::actual_actual_old_isma(),
            compounding: Compounding::SimpleThenCompounded,
            frequency: Frequency::Semiannual,
            face_amount: 100.0,
        }
    }
}
Output
# Bond Description price yield
1 ZCB/2022-07-05/1M 99.934 0.863%
2 ZCB/2022-08-02/2M 99.842 1.032%
3 ZCB/2022-09-08/3M 99.686 1.235%
4 ZCB/2022-12-08/6M 99.134 1.732%
5 ZCB/2023-05-18/12M 97.977 2.174%
6 FRB/2024-05-31/2Y 99.586 2.716%
7 FRB/2025-05-15/3Y 99.543 2.913%
8 FRB/2027-06-01/5Y 98.234 3.009%
9 FRB/2029-05-31/7Y 98.133 3.049%
10 FRB/2032-05-17/10Y 98.805 3.015%
11 FRB/2042-05-15/20Y 97.797 3.403%
12 FRB/2052-05-15/30Y 94.391 3.166%

References

About

QuantLib in Rust

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages