use std::collections::HashSet;
use chrono::{Datelike, NaiveDate, Weekday};
use findates::algebra;
use findates::calendar::Calendar;
use findates::conventions::{AdjustRule, DayCount, Frequency};
use findates::schedule::Schedule;
pub struct AdjustSetup {
pub cal: Calendar,
pub test_weekend: NaiveDate,
pub test_holiday: NaiveDate,
}
impl AdjustSetup {
pub fn new() -> Self {
let mut basic_cal: Calendar = findates::calendar::basic_calendar();
let christmas_day = NaiveDate::from_ymd_opt(2023, 12, 25).unwrap();
let boxing_day = NaiveDate::from_ymd_opt(2023, 12, 26).unwrap();
let new_holidays: HashSet<NaiveDate> = [christmas_day, boxing_day].into_iter().collect();
let test_weekend: NaiveDate = NaiveDate::from_ymd_opt(2023, 9, 2).unwrap(); basic_cal.add_holidays(&new_holidays);
Self {
cal: basic_cal,
test_holiday: christmas_day,
test_weekend: test_weekend,
}
}
}
pub fn calendar_setup() -> Calendar {
let mut ny_fed_calendar: Calendar = Calendar::new();
let weekend: HashSet<Weekday> = [Weekday::Sat, Weekday::Sun].into_iter().collect();
ny_fed_calendar.add_weekends(&weekend);
let new_year_day: NaiveDate = NaiveDate::from_ymd_opt(2023, 1, 1).unwrap();
let new_year_schedule: Schedule = Schedule::new(
Frequency::Annual,
Some(&ny_fed_calendar),
Some(AdjustRule::Nearest),
);
let new_years: Vec<NaiveDate> = new_year_schedule
.generate(
&new_year_day,
&algebra::checked_add_years(&new_year_day, 10).unwrap(),
)
.unwrap();
let independence_day: NaiveDate = NaiveDate::from_ymd_opt(2023, 7, 4).unwrap();
let independence_day_sch: Schedule = Schedule::new(
Frequency::Annual,
Some(&ny_fed_calendar),
Some(AdjustRule::Nearest),
);
let indep_days = independence_day_sch
.generate(
&independence_day,
&algebra::checked_add_years(&independence_day, 10).unwrap(),
)
.unwrap();
let christmas_day: NaiveDate = NaiveDate::from_ymd_opt(2023, 12, 25).unwrap();
let christmas_day_sch: Schedule = Schedule::new(
Frequency::Annual,
Some(&ny_fed_calendar),
Some(AdjustRule::Nearest),
);
let christmas_days = christmas_day_sch
.generate(
&christmas_day,
&algebra::checked_add_years(&christmas_day, 10).unwrap(),
)
.unwrap();
let veterans_day: NaiveDate = NaiveDate::from_ymd_opt(2023, 11, 11).unwrap();
let veterans_day_sch: Schedule = Schedule::new(
Frequency::Annual,
Some(&ny_fed_calendar),
Some(AdjustRule::Nearest),
);
let veterans_days = veterans_day_sch
.generate(
&veterans_day,
&algebra::checked_add_years(&veterans_day, 10).unwrap(),
)
.unwrap();
let juneteenth_day: NaiveDate = NaiveDate::from_ymd_opt(2023, 06, 19).unwrap();
let juneteenth_day_sch: Schedule = Schedule::new(
Frequency::Annual,
Some(&ny_fed_calendar),
Some(AdjustRule::Nearest),
);
let juneteenth_days = juneteenth_day_sch
.generate(
&juneteenth_day,
&algebra::checked_add_years(&juneteenth_day, 10).unwrap(),
)
.unwrap();
let years = 2023..=2033;
let thanksgiving_days: Vec<NaiveDate>;
thanksgiving_days = years
.clone()
.map(|x| NaiveDate::from_weekday_of_month_opt(x, 11, Weekday::Thu, 4).unwrap())
.map(|x| algebra::adjust(&x, Some(&ny_fed_calendar), Some(AdjustRule::Nearest)))
.collect();
let labor_days: Vec<NaiveDate>;
labor_days = years
.clone()
.map(|x| NaiveDate::from_weekday_of_month_opt(x, 9, Weekday::Mon, 1).unwrap())
.map(|x| algebra::adjust(&x, Some(&ny_fed_calendar), Some(AdjustRule::Nearest)))
.collect();
let columbus_days: Vec<NaiveDate>;
columbus_days = years
.clone()
.map(|x| NaiveDate::from_weekday_of_month_opt(x, 10, Weekday::Mon, 2).unwrap())
.map(|x| algebra::adjust(&x, Some(&ny_fed_calendar), Some(AdjustRule::Nearest)))
.collect();
let mlkjr_days: Vec<NaiveDate>;
mlkjr_days = years
.clone()
.map(|x| NaiveDate::from_weekday_of_month_opt(x, 1, Weekday::Mon, 3).unwrap())
.map(|x| algebra::adjust(&x, Some(&ny_fed_calendar), Some(AdjustRule::Nearest)))
.collect();
let washington_days: Vec<NaiveDate>;
washington_days = years
.clone()
.map(|x| NaiveDate::from_weekday_of_month_opt(x, 2, Weekday::Mon, 3).unwrap())
.map(|x| algebra::adjust(&x, Some(&ny_fed_calendar), Some(AdjustRule::Nearest)))
.collect();
fn last_monday_of_may(year: i32) -> NaiveDate {
let may_31st = NaiveDate::from_ymd_opt(year, 5, 31).unwrap();
let delta = may_31st.weekday().num_days_from_monday();
return may_31st - chrono::Duration::days(delta as i64);
}
let memorial_days: Vec<NaiveDate>;
memorial_days = years
.clone()
.map(|x| last_monday_of_may(x))
.map(|x| algebra::adjust(&x, Some(&ny_fed_calendar), Some(AdjustRule::Nearest)))
.collect();
let all_holidays: HashSet<NaiveDate> = itertools::concat([
new_years,
christmas_days,
indep_days,
veterans_days,
juneteenth_days,
thanksgiving_days,
labor_days,
columbus_days,
mlkjr_days,
washington_days,
memorial_days,
])
.into_iter()
.collect();
ny_fed_calendar.add_holidays(&all_holidays);
return ny_fed_calendar;
}
pub fn payment_schedule_setup(calendar: &Calendar) -> (Vec<NaiveDate>, Vec<f64>, Vec<NaiveDate>) {
let issue_date = NaiveDate::from_ymd_opt(2023, 8, 15).unwrap();
let maturity_date = NaiveDate::from_ymd_opt(2033, 8, 15).unwrap();
let coupon_schedule = Schedule::new(Frequency::Semiannual, None, None);
let coupon_dates = coupon_schedule.generate(&issue_date, &maturity_date);
let coupon_dates_list: Vec<NaiveDate> = coupon_dates.unwrap().into_iter().collect();
let mut dcfs: Vec<f64> = vec![];
for i in 0..(coupon_dates_list.len() - 1) {
let dcf = algebra::day_count_fraction(
coupon_dates_list.get(i).unwrap(),
coupon_dates_list.get(i + 1).unwrap(),
DayCount::D30360Euro,
None,
None,
).unwrap();
dcfs.push(dcf);
}
let settlement_dates: Vec<NaiveDate> = coupon_dates_list
.clone()
.into_iter()
.map(|x| algebra::adjust(&x, Some(&calendar), Some(AdjustRule::Following)))
.collect();
return (coupon_dates_list, dcfs, settlement_dates);
}