Skip to main content

rustyqlib/rates/
fra.rs

1use chrono::{Local, NaiveDate};
2use crate::core::traits::Rates;
3use crate::rates::utils::{DayCountConvention,TermStructure};
4
5/*
6    A forward rate agreement or simply "forward contract" is an agreement to exchange a fixed pre-agreed rate for a
7    floating rate is not known until some specified
8    future fixing date. The FRA payment occurs on or soon after this date
9    on the FRA settlement date. Typically the timing gap is two days.
10
11 */
12
13pub struct FRA {
14    pub start_date: NaiveDate, //The date the FRA starts to accrue interest
15    pub maturity_date: NaiveDate,
16    pub valuation_date: NaiveDate,
17    pub notional: f64,
18    pub currency: String,
19    pub fix_rate: f64,
20    pub day_count: DayCountConvention,
21    pub business_day_adjustment: i8,
22    pub term_structure: Option<TermStructure>,
23}
24impl FRA {
25    pub fn new(start_date: NaiveDate, maturity_date: NaiveDate, valuation_date: NaiveDate,
26               notional: f64, fix_rate: f64, day_count: DayCountConvention,
27               business_day_adjustment: i8) -> FRA {
28        FRA {
29            start_date,
30            maturity_date,
31            valuation_date,
32            notional,
33            currency: String::from("USD"),
34            fix_rate,
35            day_count,
36            business_day_adjustment,
37            term_structure: None,
38        }
39    }
40    pub fn builder(start_date: String,maturity_date:String,notional: f64, fix_rate: f64,day_count: String) ->FRA{
41
42        let today = Local::now().date_naive();
43        let start_date = NaiveDate::parse_from_str(&start_date, "%Y-%m-%d").expect("Invalid date format");
44        let maturity_date = NaiveDate::parse_from_str(&maturity_date, "%Y-%m-%d").expect("Invalid date format");
45        let mut fra = FRA {
46            start_date: start_date,
47            maturity_date: maturity_date,
48            valuation_date: today,
49            notional: notional,
50            currency: String::from("USD"),
51            fix_rate: fix_rate,
52            day_count: DayCountConvention::Act360,
53            business_day_adjustment: 0,
54            term_structure: None,
55        };
56        match day_count.as_str() {
57            "Act360" |"A360" => {
58                fra.day_count = DayCountConvention::Act360;
59            }
60            "Act365" |"A365" => {
61                fra.day_count = DayCountConvention::Act365;
62            }
63            "Thirty360" |"30/360" => {
64                fra.day_count = DayCountConvention::Thirty360;
65            }
66            _ => {}
67        }
68        fra
69    }
70    pub fn get_year_fraction(&self,date:NaiveDate) -> f64 {
71        let duration = self.maturity_date.signed_duration_since(date);
72        let year_fraction = duration.num_days() as f64 / self.day_count.num_of_days() as f64;
73        year_fraction
74    }
75    pub fn get_discount_factor(&self,df_start_date:f64) -> f64 {
76        let year_fraction = self.get_year_fraction(self.start_date);
77        let discount_factor = df_start_date / (1.0 + self.fix_rate * year_fraction);
78        discount_factor
79    }
80}
81
82impl Rates for FRA{
83    fn get_implied_rates(&self) -> f64 {
84        let curve = self.term_structure.as_ref().expect("Term structure is not set");
85        let df = curve.interpolate_log_linear(self.valuation_date,self.maturity_date);
86        let implied_rate = (1.0/df - 1.0)/self.get_year_fraction(self.valuation_date);
87        return implied_rate;
88    }
89    fn get_maturity_date(&self) -> NaiveDate {
90        self.maturity_date
91    }
92    fn get_rate(&self) -> f64 {
93        let df = self.get_maturity_discount_factor();
94        let time = self.get_year_fraction(self.valuation_date);
95        -df.ln() / time
96    }
97    fn get_maturity_discount_factor(&self) -> f64 {
98        let curve = self.term_structure.as_ref().expect("Term structure is not set");
99        let df = curve.interpolate_log_linear(self.valuation_date,self.start_date);
100        self.get_discount_factor(df)
101    }
102    fn get_day_count(&self) -> &DayCountConvention {
103        &self.day_count
104    }
105    fn set_term_structure(&mut self,term_structure:TermStructure) {
106        self.term_structure = Some(term_structure);
107    }
108}