RustQuant_time/
calendar.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// RustQuant: A Rust library for quantitative finance tools.
// Copyright (C) 2022-2024 https://github.com/avhz
// Dual licensed under Apache 2.0 and MIT.
// See:
//      - LICENSE-APACHE.md
//      - LICENSE-MIT.md
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//! This module defines a `Calendar` type and its methods.

use crate::utilities::is_weekend;
use time::Date;
use RustQuant_iso::{ISO_10383, ISO_3166};

/// Calendar metadata struct.
pub struct CalendarMetadata {
    /// Name of the calendar, typically the country name, but could also be
    /// a region/subdivision or a special calendar, such as a financial calendar (e.g. NYSE).
    pub name: &'static str,

    /// ISO 3166-1 country code.
    pub country_code: ISO_3166,

    /// ISO 10383 market identifier code.
    pub market_identifier_code: ISO_10383,
}

/// Calendar trait.
pub trait Calendar {
    /// Name of the calendar, typically the country name, but could also be
    /// a region/subdivision or a special calendar, such as a financial calendar (e.g. NYSE).
    fn name(&self) -> &'static str;

    /// Check if the date is a holiday (but not a weekend).
    /// This is the primary method to implement for a calendar.
    fn is_holiday(&self, date: Date) -> bool;

    /// Returns the ISO 3166-1 country code.
    fn country_code(&self) -> ISO_3166;

    /// Returns the ISO 10383 market identifier code.
    fn market_identifier_code(&self) -> ISO_10383;

    /// Check if the date is a business day.
    /// A business day is a day that is not a holiday and not a weekend.
    fn is_business_day(&self, date: Date) -> bool {
        !is_weekend(date) && !self.is_holiday(date)
    }

    /// Function to list all holidays for a given range of `Date`s.
    fn all_holidays_between(&self, start_date: Date, end_date: Date) -> Vec<Date> {
        let mut holidays = Vec::new();

        let mut temp_date = start_date;

        while temp_date <= end_date {
            if self.is_holiday(temp_date) {
                holidays.push(temp_date);
            }

            temp_date = temp_date.next_day().unwrap();
        }

        holidays.sort();

        holidays
    }

    /// Function to list all business days for a given range of `Date`s.
    fn all_business_days_between(&self, start_date: Date, end_date: Date) -> Vec<Date> {
        let mut business_days = Vec::new();

        let mut temp_date = start_date;

        while temp_date <= end_date {
            if self.is_business_day(temp_date) {
                business_days.push(temp_date);
            }

            temp_date = temp_date.next_day().unwrap();
        }

        business_days.sort();

        business_days
    }
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// IMPLEMENTATIONS
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

impl CalendarMetadata {
    /// New calendar metadata.
    pub fn new(
        name: &'static str,
        country_code: ISO_3166,
        market_identifier_code: ISO_10383,
    ) -> Self {
        Self {
            name,
            country_code,
            market_identifier_code,
        }
    }

    /// Returns the name of the calendar.
    pub fn name(&self) -> &'static str {
        self.name
    }

    /// Returns the ISO 3166-1 country code.
    pub fn country_code(&self) -> ISO_3166 {
        self.country_code
    }

    /// Returns the ISO 10383 market identifier code.
    pub fn market_identifier_code(&self) -> ISO_10383 {
        self.market_identifier_code
    }
}