1use std::fmt::Display;
6
7use rust_decimal::Decimal;
8
9#[derive(Debug, Default, Clone, Eq, PartialEq, PartialOrd, Ord)]
10pub struct Price {
11 pub symbol: String,
13 pub id: i64,
14 pub date: String,
15 pub time: String,
16 pub value: i64,
17 pub denom: i64,
18 pub currency: String,
19}
20
21impl Price {
22 pub fn new() -> Self {
23 Self::default()
24 }
25
26 pub fn to_decimal(&self) -> Decimal {
27 let scale = self.scale();
28
29 Decimal::new(self.value, scale)
30 }
31
32 pub fn scale(&self) -> u32 {
33 let denom_f = self.denom as f64;
34 let scale = denom_f.log10();
35
36 scale as u32
37 }
38
39 pub fn default_time() -> String {
40 "00:00:00".to_owned()
41 }
42}
43
44#[derive(Debug, Default)]
45pub struct PriceFilter {
46 pub symbol: Option<String>,
47 pub date: Option<String>,
48 pub time: Option<String>,
49}
50
51impl PriceFilter {
52 pub fn new() -> Self {
53 Self::default()
54 }
55}
56
57#[derive(Debug, Default, PartialEq)]
58pub struct SecurityFilter {
59 pub currency: Option<String>,
60 pub agent: Option<String>,
61 pub exchange: Option<String>,
62 pub symbol: Option<String>,
63}
64
65impl SecurityFilter {
66 pub fn new() -> Self {
67 Self {
68 currency: None,
69 agent: None,
70 exchange: None,
71 symbol: None,
72 }
73 }
74}
75
76#[derive(Debug)]
77pub struct SecuritySymbol {
78 pub namespace: String,
79 pub mnemonic: String,
80}
81
82impl SecuritySymbol {
83 pub fn new(symbol: &str) -> SecuritySymbol {
85 let mut namespace = String::default();
87 let mut mnemonic = symbol.to_uppercase();
88
89 let parts: Vec<&str> = symbol.split(':').collect();
91 if parts.len() > 1 {
92 namespace = parts[0].to_uppercase();
93 mnemonic = parts[1].to_uppercase();
94 }
95 log::debug!("parts: {:?}", &parts);
96
97 SecuritySymbol {
98 namespace,
99 mnemonic,
100 }
101 }
102
103 pub fn new_separated(exchange: &str, symbol: &str) -> Self {
104 Self {
105 namespace: exchange.to_uppercase(),
106 mnemonic: symbol.to_uppercase()
107 }
108 }
109}
110
111impl Display for SecuritySymbol {
112 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
113 write!(f, "{}:{}", self.namespace, self.mnemonic)?;
114 Ok(())
115 }
116}
117
118impl From<&str> for SecuritySymbol {
119 fn from(item: &str) -> Self {
120 SecuritySymbol::new(item)
121 }
122}
123
124
125#[cfg(test)]
126mod tests {
127 use super::*;
128
129 #[test]
130 fn test_parse() {
131 let s = SecuritySymbol::new("XETRA:EL4X");
132
133 assert_eq!(s.namespace, "XETRA");
134 assert_eq!(s.mnemonic, "EL4X");
135 }
136
137 #[test]
138 fn test_parse_currency() {
139 let s = SecuritySymbol::new("AUD");
140
141 assert_eq!(s.namespace, "");
142 assert_eq!(s.mnemonic, "AUD");
143 }
144
145 #[test]
146 fn scale_calculation() {
147 let mut p = Price::new();
148
149 p.value = 12345;
151 p.denom = 100;
152 assert_eq!(2, p.scale());
153
154 p.value = 12345;
155 p.denom = 1000;
156 assert_eq!(3, p.scale());
157 }
158
159 #[test]
160 fn price_value() {
161 let mut p = Price::new();
162 p.value = 12345;
164 p.denom = 100;
165
166 let actual = p.to_decimal();
167
168 assert_eq!(actual, Decimal::from_str_exact("123.45").unwrap());
169 assert_eq!(actual.to_string(), "123.45");
170 }
171
172 #[test]
173 fn test_sec_filter_default() {
175 let def = SecurityFilter::default();
176 let new = SecurityFilter::new();
177
178 assert_eq!(def, new);
179 }
180}