1use chrono::{Local, NaiveDate, Weekday};
2use chrono::Datelike;
3use crate::rates::deposits::Deposit;
4use crate::core::traits::Rates;
5use serde::{Serialize,Deserialize};
6fn is_weekend(date: NaiveDate) -> bool {
7 let day_of_week = date.weekday();
9 day_of_week == Weekday::Sat || day_of_week == Weekday::Sun
10}
11
12fn is_holiday(date: NaiveDate) -> bool {
13 if date.month() == 12 && date.day() == 25{
15 return true;
16 }
17 else if date.month() == 1 && date.day() == 1{ return true;
19 }
20 else if date.month() == 1 && date.weekday() == Weekday::Mon
21 && date.day() > 14 && date.day() <= 21 {
22 return true;
24 }
25 else if date.month() == 11 &&
26 date.weekday() == Weekday::Thu && date.day() > 21 && date.day() <= 28{
27 return true;
29 }
30 else if date.month() == 9 && date.weekday() == Weekday::Mon && date.day() <= 7{
31 return true;
33 }
34 return false;
35}
36
37fn adjust_for_weekend(mut date: NaiveDate) -> NaiveDate {
38 while is_weekend(date) || is_holiday(date) {
40 date += chrono::Duration::days(1);
41 }
42 date
43}
44#[derive(Clone,Debug,Serialize,Deserialize)]
45pub enum DayCountConvention{
46 Act365,
47 Act360,
48 Thirty360,
49}
50impl DayCountConvention{
51 pub fn num_of_days(&self) -> usize
52 {
53 match self {
54 DayCountConvention::Act365 => 365,
55 DayCountConvention::Act360 => 360,
56 DayCountConvention::Thirty360 => 360,
57 }
58 }
59 pub fn get_year_fraction(&self,start_date:NaiveDate,maturity_date:NaiveDate) -> f64 {
60 let duration = maturity_date.signed_duration_since(start_date);
61 let year_fraction = duration.num_days() as f64 / self.num_of_days() as f64;
62 year_fraction
63 }
64}
65
66#[derive(Clone,Debug)]
67pub struct TermStructure {
68 pub date: Vec<NaiveDate>,
69 pub discount_factor: Vec<f64>,
70 pub rate: Vec<f64>,
71 pub day_count: DayCountConvention,
72}
73
74impl TermStructure {
75 pub fn new(date: Vec<NaiveDate>, discount_factor: Vec<f64>,rate:Vec<f64>,day_count:DayCountConvention) -> TermStructure {
76 TermStructure {
77 date,
78 discount_factor,
79 rate,
80 day_count
81 }
82 }
83
84 pub fn interpolate_log_linear(&self,val_date:NaiveDate,maturity_date:NaiveDate)-> f64{
85 let year_fraction = self.get_year_fraction(val_date);
86 let target_yf = maturity_date.signed_duration_since(val_date).num_days() as f64
87 / self.day_count.num_of_days() as f64;
88 let mut df1 = 1.0;
89 let mut df2 = 1.0;
90 let mut t1 = 0.0;
91 let mut t2 = 0.0;
92 for (i, time) in year_fraction.iter().enumerate() {
93 if time==&target_yf{
94 return self.discount_factor[i];
95 }
96 else if time< &target_yf {
97 t1 = *time;
98 df1 = self.discount_factor[i];
99 }
100 else if time> &target_yf {
101 t2 = *time;
102 df2 = self.discount_factor[i];
103 break;
104 }
105
106 }
107 let log_df1 = f64::ln(df1);
108 let log_df2 = f64::ln(df2);
109 let w = (target_yf - t1) / (t2 - t1);
110 let log_df = log_df1 + w * (log_df2 - log_df1);
111 let df = f64::exp(log_df);
112 return df;
113 }
116 pub fn get_year_fraction(&self,val_date:NaiveDate) -> Vec<f64> {
117 let mut year_fraction_vec:Vec<f64> = Vec::new();
118 for time in self.date.iter() {
119 let duration = time.signed_duration_since(val_date);
120 let year_fraction = duration.num_days() as f64 / self.day_count.num_of_days() as f64;
121 year_fraction_vec.push(year_fraction);
122 }
123 year_fraction_vec
124 }
125 pub fn rates(&self,val_date:NaiveDate) -> Vec<f64> {
126 let mut rates:Vec<f64> = Vec::new();
127 for i in 0..self.discount_factor.len() {
128 let rate = (1.0 / self.discount_factor[i] - 1.0) / self.day_count.get_year_fraction(val_date,self.date[i]);
129 rates.push(rate);
130 }
131 return rates;
132 }
133 pub fn build_term_structure(&self,_valuation_date:NaiveDate,deposits:Vec<Deposit>) -> TermStructure {
134 let mut discount_factor:Vec<f64> = Vec::new();
135 let mut rate:Vec<f64> = Vec::new();
136 let mut dates:Vec<NaiveDate> = Vec::new();
137 for deposit in deposits.iter() {
138 discount_factor.push(deposit.get_discount_factor());
139 dates.push(deposit.get_maturity_date());
140 rate.push(deposit.get_rate());
141 }
142 let day_count = deposits[0].day_count.clone();
143 let term_structure = TermStructure::new(dates,discount_factor,rate,day_count);
144 return term_structure;
145 }
146}
147
148pub fn convert_mm_to_date(mut date: String) -> NaiveDate {
149 let current_date = Local::now().date_naive();
150 date.pop();
151 let month = date.parse::<u32>().unwrap();
152
153 let (new_year, new_month) = if current_date.month() + month > 12 {
154 let year = ((current_date.month() + month) / 12) as i32;
155 let m:u32 = (year * 12) as u32;
156 let new_month = current_date.month() + month;
157 (current_date.year() + year, new_month-m)
158 } else {
159 (current_date.year(), current_date.month() + month)
160 };
161 let date_in_months = current_date.with_year(new_year).unwrap_or(current_date)
162 .with_month(new_month).unwrap_or(current_date);
163 let mut maturity_date = date_in_months;
164 maturity_date = adjust_for_weekend(maturity_date);
165 return maturity_date;
166}
167