Skip to content

Commit

Permalink
feat: Change the definition of difference between dates
Browse files Browse the repository at this point in the history
feat: Change to use Real trait
feat: Add spline interpolation
  • Loading branch information
nakashima-hikaru committed Jun 10, 2024
1 parent d93232f commit f0ebf1c
Show file tree
Hide file tree
Showing 11 changed files with 630 additions and 48 deletions.
596 changes: 589 additions & 7 deletions Cargo.lock

Large diffs are not rendered by default.

21 changes: 11 additions & 10 deletions crates/qlab-instrument/src/bond.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use num_traits::{Float, FromPrimitive};
use num_traits::real::Real;
use num_traits::FromPrimitive;
use qlab_error::QLabResult;
use qlab_math::interpolation::Method;
use qlab_termstructure::yield_curve::YieldCurve;
Expand Down Expand Up @@ -30,7 +31,7 @@ pub struct Bond<V> {
bond_cash_flows: Vec<BondCashFlow<V>>,
}

impl<V: Float + FromPrimitive + MulAssign<V> + AddAssign<V>> Bond<V> {
impl<V: Real + FromPrimitive + MulAssign<V> + AddAssign<V>> Bond<V> {
/// Creates a new bond with the given parameters.
///
/// This function calculates the cash flows for the bond based on the provided parameters.
Expand Down Expand Up @@ -112,15 +113,15 @@ impl<V: Float + FromPrimitive + MulAssign<V> + AddAssign<V>> Bond<V> {
let first_prior = first_coupon_date.checked_sub_months(months_in_regular_coupon_period)?;
match first_prior.cmp(&issue_date) {
Ordering::Less => {
let coupon_fraction = V::from_i32(first_coupon_date - issue_date)?
/ V::from_i32(first_coupon_date - first_prior)?;
let coupon_fraction = V::from_i64(first_coupon_date - issue_date)?
/ V::from_i64(first_coupon_date - first_prior)?;
bond_cash_flows[0].payment_amount *= coupon_fraction;
}
Ordering::Greater => {
let second_prior =
first_prior.checked_sub_months(months_in_regular_coupon_period)?;
let coupon_fraction = V::from_i32(first_prior - issue_date)?
/ V::from_i32(first_prior - second_prior)?;
let coupon_fraction = V::from_i64(first_prior - issue_date)?
/ V::from_i64(first_prior - second_prior)?;
bond_cash_flows[0].payment_amount += coupon_fraction * regular_coupon_payment;
}
Ordering::Equal => {}
Expand All @@ -140,15 +141,15 @@ impl<V: Float + FromPrimitive + MulAssign<V> + AddAssign<V>> Bond<V> {
penultimate_coupon_date.checked_add_months(months_in_regular_coupon_period)?;
match maturity_date.cmp(&maturity_regular_date) {
Ordering::Less => {
let coupon_fraction = V::from_i32(maturity_date - penultimate_coupon_date)?
/ V::from_i32(maturity_regular_date - penultimate_coupon_date)?;
let coupon_fraction = V::from_i64(maturity_date - penultimate_coupon_date)?
/ V::from_i64(maturity_regular_date - penultimate_coupon_date)?;
final_coupon *= coupon_fraction;
}
Ordering::Greater => {
let next_regular_date =
maturity_regular_date.checked_add_months(months_in_regular_coupon_period)?;
let extra_coupon_fraction = V::from_i32(maturity_date - maturity_regular_date)?
/ V::from_i32(next_regular_date - maturity_regular_date)?;
let extra_coupon_fraction = V::from_i64(maturity_date - maturity_regular_date)?
/ V::from_i64(next_regular_date - maturity_regular_date)?;
final_coupon += extra_coupon_fraction * regular_coupon_payment;
}
Ordering::Equal => {}
Expand Down
1 change: 1 addition & 0 deletions crates/qlab-math/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ description = "Mathematics related code for the qlab"
[dependencies]
num-traits = { workspace = true }
qlab-error = { workspace = true }
spline-interpolation = { version = "0.1.0", path = "src/interpolation/spline-interpolation", default-features = false }

[lints]
workspace = true
7 changes: 3 additions & 4 deletions crates/qlab-math/src/interpolation.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
use num_traits::Float;
use num_traits::real::Real;
use qlab_error::QLabResult;

pub mod linear;

#[derive(Copy, Clone, Debug)]
pub(crate) struct Point<V: Float> {
pub(crate) struct Point<V: Real> {
x: V,
y: V,
}

#[allow(private_bounds)]
pub trait Method<V: Float> {
pub trait Method<V: Real> {
/// Fits the model to the given data points.
///
/// This function adjusts the parameters of the model to minimize the difference
Expand Down
10 changes: 5 additions & 5 deletions crates/qlab-math/src/interpolation/linear.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::interpolation::{Method, Point};
use num_traits::Float;
use num_traits::real::Real;
use qlab_error::ComputeError::InvalidInput;
use qlab_error::QLabResult;
use std::fmt::Debug;
Expand All @@ -13,7 +13,7 @@ use std::fmt::Debug;
/// # Examples
///
/// ```
/// use num_traits::Float;
/// use num_traits::real::Real;
/// use qlab_math::interpolation::linear::Linear;
/// use qlab_math::interpolation::Method;
///
Expand All @@ -26,11 +26,11 @@ use std::fmt::Debug;
///
/// ```
#[derive(Default)]
pub struct Linear<V: Float> {
pub struct Linear<V: Real> {
points: Vec<Point<V>>,
}

impl<V: Float> Linear<V> {
impl<V: Real> Linear<V> {
/// Creates a new instance of the `QLab` struct.
///
/// # Arguments
Expand All @@ -50,7 +50,7 @@ impl<V: Float> Linear<V> {
}
}

impl<V: Float + Debug> Method<V> for Linear<V> {
impl<V: Real + Debug> Method<V> for Linear<V> {
fn fit(&mut self, xs_and_ys: &[(V, V)]) -> QLabResult<()> {
let mut points = Vec::with_capacity(xs_and_ys.len());
for &(x, y) in xs_and_ys {
Expand Down
9 changes: 5 additions & 4 deletions crates/qlab-termstructure/src/yield_curve.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use num_traits::{Float, FromPrimitive};
use num_traits::real::Real;
use num_traits::FromPrimitive;
use qlab_error::ComputeError::InvalidInput;
use qlab_error::QLabResult;
use qlab_math::interpolation::Method;
Expand All @@ -8,15 +9,15 @@ use std::marker::PhantomData;

/// A trait representing a yield curve with discount factor calculations.
///
/// The trait is generic over the type of Floating point values (`V`) and the day count convention (`D`).
pub struct YieldCurve<D: DayCount, V: Float + FromPrimitive, I: Method<V>> {
/// The trait is generic over the type of Realing point values (`V`) and the day count convention (`D`).
pub struct YieldCurve<D: DayCount, V: Real + FromPrimitive, I: Method<V>> {
settlement_date: Date,
interpolator: I,
_phantom: PhantomData<V>,
_day_count: PhantomData<D>,
}

impl<V: Float + FromPrimitive, D: DayCount, I: Method<V>> YieldCurve<D, V, I> {
impl<V: Real + FromPrimitive, D: DayCount, I: Method<V>> YieldCurve<D, V, I> {
/// Creates a new instance of the `QLab` struct.
///
/// # Arguments
Expand Down
6 changes: 3 additions & 3 deletions crates/qlab-time/src/date.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::business_day_convention::DateRolling;
use crate::calendar::Calendar;
use crate::period::Period;
use chrono::{Datelike, NaiveDate};
use chrono::{Datelike, NaiveDate, TimeDelta};
use std::fmt;
use std::fmt::{Debug, Formatter};
use std::ops::Sub;
Expand Down Expand Up @@ -238,10 +238,10 @@ impl From<NaiveDate> for Date {
}

impl Sub for Date {
type Output = i32;
type Output = i64;

fn sub(self, rhs: Self) -> Self::Output {
self.0.num_days_from_ce() - rhs.0.num_days_from_ce()
(self.0 - rhs.0).num_days()
}
}

Expand Down
6 changes: 3 additions & 3 deletions crates/qlab-time/src/day_count.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ pub mod act_365;
pub mod thirty_360;

use crate::date::Date;
use num_traits::{Float, FromPrimitive};
use num_traits::{real::Real, FromPrimitive};
use qlab_error::QLabResult;

pub trait DayCount {
/// Calculates the day count fraction between two dates.
///
/// This function calculates the day count fraction between `date1` and `date2`
/// using a generic type `V`, which must implement the `Float` and `FromPrimitive`
/// using a generic type `V`, which must implement the `Real` and `FromPrimitive`
/// traits. The day count fraction represents the portion of a year between the two
/// dates, expressed as a fraction.
///
Expand All @@ -26,7 +26,7 @@ pub trait DayCount {
///
/// # Errors
/// An error occurs if a cast from `V` to a primitive type fails.
fn calculate_day_count_fraction<V: Float + FromPrimitive>(
fn calculate_day_count_fraction<V: Real + FromPrimitive>(
date1: Date,
date2: Date,
) -> QLabResult<V>;
Expand Down
9 changes: 4 additions & 5 deletions crates/qlab-time/src/day_count/act_360.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
use crate::date::Date;
use crate::day_count::DayCount;
use num_traits::{Float, FromPrimitive};
use num_traits::{real::Real, FromPrimitive};
use qlab_error::{ComputeError, QLabResult};

#[derive(Debug)]
pub struct Act360;

impl DayCount for Act360 {
fn calculate_day_count_fraction<V: Float + FromPrimitive>(
fn calculate_day_count_fraction<V: Real + FromPrimitive>(
date1: Date,
date2: Date,
) -> QLabResult<V> {
let date_diff = V::from_i32(date2 - date1)
let date_diff = V::from_i64(date2 - date1)
.ok_or_else(|| ComputeError::CastNumberError(format!("{}", date2 - date1).into()))?;
let denomination = V::from_i32(360)
.ok_or_else(|| ComputeError::CastNumberError(format!("{}", 360).into()))?;
let denomination = V::from_i32(360).unwrap();

Ok(date_diff.div(denomination))
}
Expand Down
9 changes: 4 additions & 5 deletions crates/qlab-time/src/day_count/act_365.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
use crate::date::Date;
use crate::day_count::DayCount;
use num_traits::Float;
use num_traits::real::Real;
use num_traits::FromPrimitive;
use qlab_error::{ComputeError, QLabResult};

#[derive(Debug)]
pub struct Act365;

impl DayCount for Act365 {
fn calculate_day_count_fraction<V: Float + FromPrimitive>(
fn calculate_day_count_fraction<V: Real + FromPrimitive>(
date1: Date,
date2: Date,
) -> QLabResult<V> {
let date_diff = V::from_i32(date2 - date1)
let date_diff = V::from_i64(date2 - date1)
.ok_or_else(|| ComputeError::CastNumberError(format!("{}", date2 - date1).into()))?;
let denomination = V::from_i32(365)
.ok_or_else(|| ComputeError::CastNumberError(format!("{}", 365).into()))?;
let denomination = V::from_i32(365).unwrap();

Ok(date_diff.div(denomination))
}
Expand Down
4 changes: 2 additions & 2 deletions crates/qlab-time/src/day_count/thirty_360.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::date::Date;
use crate::day_count::DayCount;
use num_traits::{Float, FromPrimitive};
use num_traits::{real::Real, FromPrimitive};
use qlab_error::ComputeError::InvalidInput;
use qlab_error::{ComputeError, QLabResult};

Expand All @@ -25,7 +25,7 @@ impl Thirty360 {
}

impl DayCount for Thirty360 {
fn calculate_day_count_fraction<V: Float + FromPrimitive>(
fn calculate_day_count_fraction<V: Real + FromPrimitive>(
date1: Date,
date2: Date,
) -> QLabResult<V> {
Expand Down

0 comments on commit f0ebf1c

Please sign in to comment.