use dates::Date;
use math::interpolation::Interpolate;
use math::interpolation::Linear;
use math::interpolation::Extrap;
use core::qm;
use core::factories::TypeId;
use core::factories::Registry;
use core::factories::Qrc;
use std::sync::Arc;
use std::fmt::Debug;
use erased_serde as esd;
use serde as sd;
use serde_tagged as sdt;
use serde_tagged::de::BoxFnSeed;
use serde::Deserialize;
pub trait RateCurve : esd::Serialize + TypeId + Sync + Send + Debug {
fn base_date(&self) -> Date;
fn is_zero(&self) -> bool { false }
fn r_and_t(&self, date: Date) -> Result<(f64, f64), qm::Error>;
fn rt(&self, date: Date) -> Result<f64, qm::Error> {
let (r, t) = self.r_and_t(date)?;
Ok(r * t)
}
fn df(&self, from: Date, to: Date) -> Result<f64, qm::Error> {
if from == to {
return Ok(1.0) }
let from_rt = self.rt(from)?;
let to_rt = self.rt(to)?;
Ok((to_rt - from_rt).exp())
}
}
pub type RcRateCurve = Qrc<RateCurve>;
pub type TypeRegistry = Registry<BoxFnSeed<RcRateCurve>>;
impl<'de> sd::Deserialize<'de> for RcRateCurve {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: sd::Deserializer<'de>
{
sdt::de::external::deserialize(deserializer, get_registry())
}
}
pub fn get_registry() -> &'static TypeRegistry {
lazy_static! {
static ref REG: TypeRegistry = {
let mut reg = TypeRegistry::new();
reg.insert("ZeroRateCurve", BoxFnSeed::new(ZeroRateCurve::from_serial));
reg.insert("RateCurveAct365", BoxFnSeed::new(RateCurveAct365::from_serial));
reg.insert("AnnualisedFlatBump", BoxFnSeed::new(AnnualisedFlatBump::from_serial));
reg.insert("ContinuouslyCompoundedFlatBump", BoxFnSeed::new(ContinuouslyCompoundedFlatBump::from_serial));
reg.insert("RelativeBump", BoxFnSeed::new(RelativeBump::from_serial));
reg
};
}
®
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ZeroRateCurve {
base: Date
}
impl TypeId for ZeroRateCurve {
fn type_id(&self) -> &'static str { "ZeroRateCurve" }
}
impl RateCurve for ZeroRateCurve {
fn r_and_t(&self, _date: Date) -> Result<(f64, f64), qm::Error> {
Ok((0.0, 0.0))
}
fn base_date(&self) -> Date { self.base }
fn is_zero(&self) -> bool { true }
}
impl ZeroRateCurve {
pub fn new(base_date: Date) -> ZeroRateCurve {
ZeroRateCurve { base: base_date }
}
pub fn from_serial<'de>(de: &mut esd::Deserializer<'de>) -> Result<RcRateCurve, esd::Error> {
Ok(Qrc::new(Arc::new(ZeroRateCurve::deserialize(de)?)))
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct RateCurveAct365 {
base: Date,
interp: Linear<Date>,
}
impl TypeId for RateCurveAct365 {
fn type_id(&self) -> &'static str { "RateCurveAct365" }
}
impl RateCurve for RateCurveAct365 {
fn r_and_t(&self, date: Date) -> Result<(f64, f64), qm::Error> {
let act = date - self.base;
if act == 0 {
return Ok((0.0, 0.0))
}
let t = (act as f64) / 365.0;
let r = self.interp.interpolate(date)?;
Ok((r, t))
}
fn base_date(&self) -> Date {
self.base
}
}
impl RateCurveAct365 {
pub fn new(base: Date, curve: &[(Date, f64)], left: Extrap, right: Extrap)
-> Result<RateCurveAct365, qm::Error> {
let interp = Linear::new(curve, left, right)?;
Ok(RateCurveAct365 { base: base, interp: interp })
}
pub fn from_serial<'de>(de: &mut esd::Deserializer<'de>) -> Result<RcRateCurve, esd::Error> {
Ok(Qrc::new(Arc::new(RateCurveAct365::deserialize(de)?)))
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct AnnualisedFlatBump {
curve: RcRateCurve,
bump: f64
}
impl TypeId for AnnualisedFlatBump {
fn type_id(&self) -> &'static str { "AnnualisedFlatBump" }
}
impl RateCurve for AnnualisedFlatBump {
fn r_and_t(&self, date: Date) -> Result<(f64, f64), qm::Error> {
let (r, t) = self.curve.r_and_t(date)?;
let r_bumped = (r.exp() + self.bump).ln();
Ok((r_bumped, t))
}
fn base_date(&self) -> Date {
self.curve.base_date()
}
}
impl AnnualisedFlatBump {
pub fn new(curve: RcRateCurve, bump: f64) -> AnnualisedFlatBump {
AnnualisedFlatBump { curve: curve, bump: bump }
}
pub fn from_serial<'de>(de: &mut esd::Deserializer<'de>) -> Result<RcRateCurve, esd::Error> {
Ok(Qrc::new(Arc::new(AnnualisedFlatBump::deserialize(de)?)))
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ContinuouslyCompoundedFlatBump {
curve: RcRateCurve,
bump: f64
}
impl TypeId for ContinuouslyCompoundedFlatBump {
fn type_id(&self) -> &'static str { "ContinuouslyCompoundedFlatBump" }
}
impl RateCurve for ContinuouslyCompoundedFlatBump {
fn r_and_t(&self, date: Date) -> Result<(f64, f64), qm::Error> {
let (r, t) = self.curve.r_and_t(date)?;
Ok((r + self.bump, t))
}
fn base_date(&self) -> Date {
self.curve.base_date()
}
}
impl ContinuouslyCompoundedFlatBump {
pub fn new(curve: RcRateCurve, bump: f64)
-> ContinuouslyCompoundedFlatBump {
ContinuouslyCompoundedFlatBump { curve: curve, bump: bump }
}
pub fn from_serial<'de>(de: &mut esd::Deserializer<'de>) -> Result<RcRateCurve, esd::Error> {
Ok(Qrc::new(Arc::new(ContinuouslyCompoundedFlatBump::deserialize(de)?)))
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct RelativeBump {
curve: RcRateCurve,
one_plus_bump: f64
}
impl TypeId for RelativeBump {
fn type_id(&self) -> &'static str { "RelativeBump" }
}
impl RateCurve for RelativeBump {
fn r_and_t(&self, date: Date) -> Result<(f64, f64), qm::Error> {
let (r, t) = self.curve.r_and_t(date)?;
Ok((r * self.one_plus_bump, t))
}
fn base_date(&self) -> Date {
self.curve.base_date()
}
}
impl RelativeBump {
pub fn new(curve: RcRateCurve, bump: f64) -> RelativeBump {
RelativeBump { curve: curve, one_plus_bump: bump }
}
pub fn from_serial<'de>(de: &mut esd::Deserializer<'de>) -> Result<RcRateCurve, esd::Error> {
Ok(Qrc::new(Arc::new(RelativeBump::deserialize(de)?)))
}
}
#[cfg(test)]
mod tests {
use super::*;
use math::numerics::approx_eq;
use serde_json;
#[test]
fn zero_curve() {
let base = Date::from_ymd(2017, 01, 01);
let c = ZeroRateCurve::new(base);
assert_rt(c.rt(base + 7), 0.0);
}
#[test]
fn check_curves() {
let base = Date::from_ymd(2017, 01, 01);
let d = base;
let points = [(d, 0.05), (d + 14, 0.08), (d + 56, 0.09),
(d + 112, 0.085), (d + 224, 0.082)];
let c = RateCurveAct365::new(base, &points,
Extrap::Flat, Extrap::Flat).unwrap();
assert_rt(c.rt(d + 0), 0.05 * 0.0 / 365.0);
assert_rt(c.rt(d + 7), 0.065 * 7.0 / 365.0);
assert_rt(c.rt(d + 14), 0.08 * 14.0 / 365.0);
assert_rt(c.rt(d + 224), 0.082 * 224.0 / 365.0);
assert_rt(c.rt(d + 365), 0.082 * 365.0 / 365.0);
}
#[test]
fn rate_curve_serde() {
let base = Date::from_ymd(2017, 01, 01);
let d = base;
let points = [(d, 0.05), (d + 14, 0.08)];
let curve = RateCurveAct365::new(base, &points,
Extrap::Flat, Extrap::Flat).unwrap();
let serialized = serde_json::to_string(&curve).unwrap();
assert_eq!(serialized, r#"{"base":"2017-01-01","interp":{"left":"Flat","right":"Flat","points":[["2017-01-01",0.05],["2017-01-15",0.08]]}}"#);
let deserialized: RateCurveAct365 = serde_json::from_str(&serialized).unwrap();
assert_rt(deserialized.rt(d + 0), 0.05 * 0.0 / 365.0);
assert_rt(deserialized.rt(d + 14), 0.08 * 14.0 / 365.0);
assert_rt(deserialized.rt(d + 15), 0.08 * 15.0 / 365.0);
}
#[test]
fn rate_curve_tagged_serde() {
let base = Date::from_ymd(2017, 01, 01);
let d = base;
let points = [(d, 0.05), (d + 14, 0.08)];
let curve = RcRateCurve::new(Arc::new(RateCurveAct365::new(base, &points,
Extrap::Flat, Extrap::Flat).unwrap()));
let bumped = RcRateCurve::new(Arc::new(RelativeBump::new(curve, 0.01)));
let serialized = serde_json::to_string(&bumped).unwrap();
assert_eq!(serialized, r#"{"RelativeBump":{"curve":{"RateCurveAct365":{"base":"2017-01-01","interp":{"left":"Flat","right":"Flat","points":[["2017-01-01",0.05],["2017-01-15",0.08]]}}},"one_plus_bump":0.01}}"#);
let deserialized: RcRateCurve = serde_json::from_str(&serialized).unwrap();
assert_rt(deserialized.rt(d + 0), 0.05 * 0.01 * 0.0 / 365.0);
assert_rt(deserialized.rt(d + 14), 0.08 * 0.01 * 14.0 / 365.0);
assert_rt(deserialized.rt(d + 15), 0.08 * 0.01 * 15.0 / 365.0);
}
fn assert_rt(rt: Result<f64, qm::Error>, v: f64) {
let interpolated = rt.unwrap();
assert!(approx_eq(interpolated, v, 1e-12), "interpolated={} v={}",
interpolated, v);
}
}