rateslib/scheduling/calendars/
adjuster.rs1use crate::scheduling::DateRoll;
2use chrono::prelude::*;
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
7pub enum Adjuster {
8    Actual {},
10    Following {},
12    ModifiedFollowing {},
14    Previous {},
16    ModifiedPrevious {},
18    FollowingSettle {},
20    ModifiedFollowingSettle {},
22    PreviousSettle {},
24    ModifiedPreviousSettle {},
26    BusDaysLagSettle(i32),
29    CalDaysLagSettle(i32),
32    FollowingExLast {},
34    FollowingExLastSettle {},
36}
37
38pub trait Adjustment {
40    fn adjust<T: DateRoll>(&self, udate: &NaiveDateTime, calendar: &T) -> NaiveDateTime;
42
43    fn adjusts<T: DateRoll>(&self, udates: &Vec<NaiveDateTime>, calendar: &T)
45        -> Vec<NaiveDateTime>;
46}
47
48pub trait CalendarAdjustment {
50    fn adjust(&self, udate: &NaiveDateTime, adjuster: &Adjuster) -> NaiveDateTime
52    where
53        Self: Sized + DateRoll,
54    {
55        adjuster.adjust(udate, self)
56    }
57
58    fn adjusts(&self, udates: &Vec<NaiveDateTime>, adjuster: &Adjuster) -> Vec<NaiveDateTime>
60    where
61        Self: Sized + DateRoll,
62    {
63        adjuster.adjusts(udates, self)
64    }
65}
66
67impl Adjustment for Adjuster {
68    fn adjust<T: DateRoll>(&self, udate: &NaiveDateTime, calendar: &T) -> NaiveDateTime {
69        match self {
70            Adjuster::Actual {} => *udate,
71            Adjuster::Following {} => calendar.roll_forward_bus_day(udate),
72            Adjuster::Previous {} => calendar.roll_backward_bus_day(udate),
73            Adjuster::ModifiedFollowing {} => calendar.roll_mod_forward_bus_day(udate),
74            Adjuster::ModifiedPrevious {} => calendar.roll_mod_backward_bus_day(udate),
75            Adjuster::FollowingSettle {} => calendar.roll_forward_settled_bus_day(udate),
76            Adjuster::PreviousSettle {} => calendar.roll_backward_settled_bus_day(udate),
77            Adjuster::ModifiedFollowingSettle {} => {
78                calendar.roll_forward_mod_settled_bus_day(udate)
79            }
80            Adjuster::ModifiedPreviousSettle {} => {
81                calendar.roll_backward_mod_settled_bus_day(udate)
82            }
83            Adjuster::BusDaysLagSettle(n) => calendar.lag_bus_days(udate, *n, true),
84            Adjuster::CalDaysLagSettle(n) => {
85                let adj = if *n < 0 {
86                    Adjuster::PreviousSettle {}
87                } else {
88                    Adjuster::FollowingSettle {}
89                };
90                calendar.add_cal_days(udate, *n, &adj)
91            }
92            Adjuster::FollowingExLast {} => calendar.roll_forward_bus_day(udate), Adjuster::FollowingExLastSettle {} => calendar.roll_forward_settled_bus_day(udate), }
95    }
96
97    fn adjusts<T: DateRoll>(
98        &self,
99        udates: &Vec<NaiveDateTime>,
100        calendar: &T,
101    ) -> Vec<NaiveDateTime> {
102        match self {
103            Adjuster::FollowingExLast {} | Adjuster::FollowingExLastSettle {} => {
104                let mut adates: Vec<NaiveDateTime> = udates
105                    .iter()
106                    .map(|udate| self.adjust(udate, calendar))
107                    .collect();
108                adates[udates.len() - 1] = udates[udates.len() - 1];
109                adates
110            }
111            _ => udates
112                .iter()
113                .map(|udate| self.adjust(udate, calendar))
114                .collect(),
115        }
116    }
117}
118
119#[cfg(test)]
121mod tests {
122    use super::*;
123    use crate::scheduling::{ndt, Cal};
124
125    fn fixture_hol_cal() -> Cal {
126        let hols = vec![ndt(2015, 9, 5), ndt(2015, 9, 7)]; Cal::new(hols, vec![5, 6])
128    }
129
130    #[test]
131    fn test_adjusts() {
132        let cal = fixture_hol_cal();
133        let udates = vec![
134            ndt(2015, 9, 4),
135            ndt(2015, 9, 5),
136            ndt(2015, 9, 6),
137            ndt(2015, 9, 7),
138        ];
139        let result = Adjuster::Following {}.adjusts(&udates, &cal);
140        assert_eq!(
141            result,
142            vec![
143                ndt(2015, 9, 4),
144                ndt(2015, 9, 8),
145                ndt(2015, 9, 8),
146                ndt(2015, 9, 8)
147            ]
148        );
149    }
150
151    #[test]
152    fn test_adjusts_ex_last() {
153        let cal = fixture_hol_cal();
155        let udates = vec![
156            ndt(2015, 9, 4),
157            ndt(2015, 9, 5),
158            ndt(2015, 9, 6),
159            ndt(2015, 9, 7),
160        ];
161        let result = Adjuster::FollowingExLast {}.adjusts(&udates, &cal);
162        assert_eq!(
163            result,
164            vec![
165                ndt(2015, 9, 4),
166                ndt(2015, 9, 8),
167                ndt(2015, 9, 8),
168                ndt(2015, 9, 7)
169            ]
170        );
171    }
172}