quant_primitives/
interval.rs1use chrono::Duration;
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5use std::fmt;
6use std::str::FromStr;
7use thiserror::Error;
8
9#[derive(Debug, Error, PartialEq, Eq)]
11pub enum IntervalError {
12 #[error("unknown interval: {0}")]
14 Unknown(String),
15}
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
22pub enum Interval {
23 Minute,
25 Hour,
27 Day,
29 Week,
31}
32
33impl Interval {
34 pub fn as_str(&self) -> &'static str {
36 match self {
37 Interval::Minute => "1m",
38 Interval::Hour => "1h",
39 Interval::Day => "1d",
40 Interval::Week => "1w",
41 }
42 }
43
44 pub fn periods_per_year(&self, is_crypto: bool) -> u32 {
51 match (self, is_crypto) {
52 (Interval::Minute, true) => 525_600, (Interval::Minute, false) => 98_280, (Interval::Hour, true) => 8_760, (Interval::Hour, false) => 1_638, (Interval::Day, true) => 365,
57 (Interval::Day, false) => 252,
58 (Interval::Week, _) => 52,
59 }
60 }
61
62 pub fn lower_intervals(&self) -> &'static [Interval] {
67 match self {
68 Interval::Minute => &[],
69 Interval::Hour => &[Interval::Minute],
70 Interval::Day => &[Interval::Hour, Interval::Minute],
71 Interval::Week => &[Interval::Day, Interval::Hour, Interval::Minute],
72 }
73 }
74}
75
76impl fmt::Display for Interval {
77 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78 f.write_str(self.as_str())
79 }
80}
81
82impl Serialize for Interval {
83 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
84 serializer.serialize_str(self.as_str())
85 }
86}
87
88impl<'de> Deserialize<'de> for Interval {
89 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
90 let s = String::deserialize(deserializer)?;
91 s.parse().map_err(serde::de::Error::custom)
92 }
93}
94
95impl FromStr for Interval {
96 type Err = IntervalError;
97
98 fn from_str(s: &str) -> Result<Self, Self::Err> {
99 match s.to_lowercase().as_str() {
100 "1m" | "m" | "min" | "minute" => Ok(Interval::Minute),
101 "1h" | "h" | "hour" | "hourly" => Ok(Interval::Hour),
102 "1d" | "d" | "day" | "daily" => Ok(Interval::Day),
103 "1w" | "w" | "week" | "weekly" => Ok(Interval::Week),
104 _ => Err(IntervalError::Unknown(s.to_string())),
105 }
106 }
107}
108
109pub fn interval_duration(interval: Interval) -> Duration {
111 match interval {
112 Interval::Minute => Duration::minutes(1),
113 Interval::Hour => Duration::hours(1),
114 Interval::Day => Duration::days(1),
115 Interval::Week => Duration::weeks(1),
116 }
117}
118
119#[cfg(test)]
120#[path = "interval_tests.rs"]
121mod tests;