rateslib/curves/interpolation/
intp_linear_zero_rate.rs1use crate::curves::interpolation::utils::linear_zero_interp;
2use crate::curves::nodes::NodesTimestamp;
3use crate::curves::CurveInterpolation;
4use crate::dual::Number;
5use bincode::config::legacy;
6use bincode::serde::{decode_from_slice, encode_to_vec};
7use chrono::NaiveDateTime;
8use pyo3::prelude::*;
9use pyo3::types::{PyBytes, PyTuple};
10use pyo3::{pyclass, pymethods, Bound, PyResult, Python};
11use serde::{Deserialize, Serialize};
12use std::cmp::PartialEq;
13
14#[pyclass(module = "rateslib.rs")]
18#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
19pub struct LinearZeroRateInterpolator {}
20
21#[pymethods]
22
23impl LinearZeroRateInterpolator {
24 #[new]
25 pub fn new() -> Self {
26 LinearZeroRateInterpolator {}
27 }
28
29 pub fn __setstate__(&mut self, state: Bound<'_, PyBytes>) -> PyResult<()> {
31 *self = decode_from_slice(state.as_bytes(), legacy()).unwrap().0;
32 Ok(())
33 }
34 pub fn __getstate__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyBytes>> {
35 Ok(PyBytes::new(py, &encode_to_vec(&self, legacy()).unwrap()))
36 }
37 pub fn __getnewargs__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyTuple>> {
38 Ok(PyTuple::empty(py))
39 }
40}
41
42impl CurveInterpolation for LinearZeroRateInterpolator {
43 fn interpolated_value(&self, nodes: &NodesTimestamp, date: &NaiveDateTime) -> Number {
44 let x = date.and_utc().timestamp();
45 let index = self.node_index(nodes, x);
46
47 macro_rules! interp {
48 ($Variant: ident, $indexmap: expr) => {{
49 let (x0, _) = $indexmap.get_index(0_usize).unwrap();
50 let (x2, y2) = $indexmap.get_index(index + 1_usize).unwrap();
51 let (x1, y1) = $indexmap.get_index(index).unwrap();
52 Number::$Variant(linear_zero_interp(
53 *x0 as f64, *x1 as f64, y1, *x2 as f64, y2, x as f64,
54 ))
55 }};
56 }
57 match nodes {
58 NodesTimestamp::F64(m) => interp!(F64, m),
59 NodesTimestamp::Dual(m) => interp!(Dual, m),
60 NodesTimestamp::Dual2(m) => interp!(Dual2, m),
61 }
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68 use crate::curves::nodes::Nodes;
69 use crate::scheduling::ndt;
70 use indexmap::IndexMap;
71
72 fn nodes_timestamp_fixture() -> NodesTimestamp {
73 let nodes = Nodes::F64(IndexMap::from_iter(vec![
74 (ndt(2000, 1, 1), 1.0_f64),
75 (ndt(2001, 1, 1), 0.99_f64),
76 (ndt(2002, 1, 1), 0.98_f64),
77 ]));
78 NodesTimestamp::from(nodes)
79 }
80
81 #[test]
82 fn test_log_linear() {
83 let nts = nodes_timestamp_fixture();
84 let ll = LinearZeroRateInterpolator::new();
85 let result = ll.interpolated_value(&nts, &ndt(2001, 7, 1));
86 assert_eq!(result, Number::F64(0.9850443279738612));
90 }
91
92 #[test]
93 fn test_log_linear_first_period() {
94 let nts = nodes_timestamp_fixture();
95 let ll = LinearZeroRateInterpolator::new();
96 let result = ll.interpolated_value(&nts, &ndt(2000, 7, 1));
97 assert_eq!(result, Number::F64(0.9950147597711371));
101 }
102}