finance_query/models/corporate/
equity_performance.rs1use serde::{Deserialize, Serialize};
7
8#[derive(Default, Debug, Clone, Serialize, Deserialize)]
10#[serde(rename_all = "camelCase")]
11#[non_exhaustive]
12pub struct EquityPerformance {
13 #[serde(default)]
15 pub max_age: Option<i64>,
16
17 #[serde(default)]
19 pub benchmark: Option<Benchmark>,
20
21 #[serde(default)]
23 pub performance_overview: Option<PerformanceOverview>,
24
25 #[serde(default)]
27 pub performance_overview_benchmark: Option<PerformanceOverview>,
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
32#[serde(rename_all = "camelCase")]
33pub struct Benchmark {
34 #[serde(default)]
36 pub symbol: Option<String>,
37
38 #[serde(default)]
40 pub short_name: Option<String>,
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize)]
45#[serde(rename_all = "camelCase")]
46pub struct PerformanceOverview {
47 #[serde(default)]
49 pub as_of_date: Option<crate::models::quote::FormattedValue<i64>>,
50
51 #[serde(default)]
53 pub five_days_return: Option<crate::models::quote::FormattedValue<f64>>,
54
55 #[serde(default)]
57 pub one_month_return: Option<crate::models::quote::FormattedValue<f64>>,
58
59 #[serde(default)]
61 pub three_month_return: Option<crate::models::quote::FormattedValue<f64>>,
62
63 #[serde(default)]
65 pub six_month_return: Option<crate::models::quote::FormattedValue<f64>>,
66
67 #[serde(default)]
69 pub ytd_return_pct: Option<crate::models::quote::FormattedValue<f64>>,
70
71 #[serde(default)]
73 pub one_year_total_return: Option<crate::models::quote::FormattedValue<f64>>,
74
75 #[serde(default)]
77 pub two_year_total_return: Option<crate::models::quote::FormattedValue<f64>>,
78
79 #[serde(default)]
81 pub three_year_total_return: Option<crate::models::quote::FormattedValue<f64>>,
82
83 #[serde(default)]
85 pub five_year_total_return: Option<crate::models::quote::FormattedValue<f64>>,
86
87 #[serde(default)]
89 pub ten_year_total_return: Option<crate::models::quote::FormattedValue<f64>>,
90
91 #[serde(default)]
93 pub max_return: Option<crate::models::quote::FormattedValue<f64>>,
94}
95
96impl EquityPerformance {
97 pub fn ytd_return(&self) -> Option<f64> {
99 self.performance_overview
100 .as_ref()?
101 .ytd_return_pct
102 .as_ref()?
103 .raw
104 }
105
106 pub fn benchmark_ytd_return(&self) -> Option<f64> {
108 self.performance_overview_benchmark
109 .as_ref()?
110 .ytd_return_pct
111 .as_ref()?
112 .raw
113 }
114
115 pub fn ytd_vs_benchmark(&self) -> Option<f64> {
117 let stock_ytd = self.ytd_return()?;
118 let benchmark_ytd = self.benchmark_ytd_return()?;
119 Some(stock_ytd - benchmark_ytd)
120 }
121
122 pub fn one_year_return(&self) -> Option<f64> {
124 self.performance_overview
125 .as_ref()?
126 .one_year_total_return
127 .as_ref()?
128 .raw
129 }
130
131 pub fn benchmark_one_year_return(&self) -> Option<f64> {
133 self.performance_overview_benchmark
134 .as_ref()?
135 .one_year_total_return
136 .as_ref()?
137 .raw
138 }
139
140 pub fn one_year_vs_benchmark(&self) -> Option<f64> {
142 let stock_return = self.one_year_return()?;
143 let benchmark_return = self.benchmark_one_year_return()?;
144 Some(stock_return - benchmark_return)
145 }
146
147 pub fn five_year_return(&self) -> Option<f64> {
149 self.performance_overview
150 .as_ref()?
151 .five_year_total_return
152 .as_ref()?
153 .raw
154 }
155
156 pub fn benchmark_five_year_return(&self) -> Option<f64> {
158 self.performance_overview_benchmark
159 .as_ref()?
160 .five_year_total_return
161 .as_ref()?
162 .raw
163 }
164
165 pub fn five_year_vs_benchmark(&self) -> Option<f64> {
167 let stock_return = self.five_year_return()?;
168 let benchmark_return = self.benchmark_five_year_return()?;
169 Some(stock_return - benchmark_return)
170 }
171
172 pub fn benchmark_name(&self) -> Option<&str> {
174 self.benchmark.as_ref()?.short_name.as_deref()
175 }
176}
177
178#[cfg(test)]
179mod tests {
180 use super::*;
181 use serde_json::json;
182
183 #[test]
184 fn test_equity_performance_deserialize() {
185 let json = json!({
187 "maxAge": 1,
188 "benchmark": {
189 "symbol": "^GSPC",
190 "shortName": "S&P 500"
191 },
192 "performanceOverview": {
193 "asOfDate": {"raw": 1764892800},
194 "fiveDaysReturn": {"raw": 0.030622387},
195 "oneMonthReturn": {"raw": -0.06551842},
196 "threeMonthReturn": {"raw": 0.092266984},
197 "sixMonthReturn": {"raw": 0.30325815},
198 "ytdReturnPct": {"raw": 0.35870054},
199 "oneYearTotalReturn": {"raw": 0.2578236},
200 "twoYearTotalReturn": {"raw": 2.919418},
201 "threeYearTotalReturn": {"raw": 9.992929},
202 "fiveYearTotalReturn": {"raw": 12.491636},
203 "tenYearTotalReturn": {"raw": 220.57314},
204 "maxReturn": {"raw": 4168.3716}
205 },
206 "performanceOverviewBenchmark": {
207 "asOfDate": {"raw": 1764892800},
208 "fiveDaysReturn": {"raw": 0.0031113708},
209 "oneMonthReturn": {"raw": 0.010904458},
210 "threeMonthReturn": {"raw": 0.060001526},
211 "sixMonthReturn": {"raw": 0.15676934},
212 "ytdReturnPct": {"raw": 0.16811156},
213 "oneYearTotalReturn": {"raw": 0.13090958},
214 "twoYearTotalReturn": {"raw": 0.504298},
215 "threeYearTotalReturn": {"raw": 0.71809816},
216 "fiveYearTotalReturn": {"raw": 0.85730654},
217 "tenYearTotalReturn": {"raw": 2.2846167},
218 "maxReturn": {"raw": 388.03735}
219 }
220 });
221
222 let equity_performance: EquityPerformance = serde_json::from_value(json).unwrap();
223 assert_eq!(equity_performance.max_age, Some(1));
224 assert_eq!(equity_performance.benchmark_name(), Some("S&P 500"));
225 assert_eq!(equity_performance.ytd_return(), Some(0.35870054));
226 assert_eq!(equity_performance.benchmark_ytd_return(), Some(0.16811156));
227 }
228
229 #[test]
230 fn test_equity_performance_vs_benchmark() {
231 use crate::models::quote::FormattedValue;
232
233 let equity_performance = EquityPerformance {
234 max_age: Some(1),
235 benchmark: Some(Benchmark {
236 symbol: Some("^GSPC".to_string()),
237 short_name: Some("S&P 500".to_string()),
238 }),
239 performance_overview: Some(PerformanceOverview {
240 as_of_date: Some(FormattedValue::new(1764892800)),
241 five_days_return: Some(FormattedValue::new(0.030622387)),
242 one_month_return: Some(FormattedValue::new(-0.06551842)),
243 three_month_return: Some(FormattedValue::new(0.092266984)),
244 six_month_return: Some(FormattedValue::new(0.30325815)),
245 ytd_return_pct: Some(FormattedValue::new(0.35870054)),
246 one_year_total_return: Some(FormattedValue::new(0.2578236)),
247 two_year_total_return: Some(FormattedValue::new(2.919418)),
248 three_year_total_return: Some(FormattedValue::new(9.992929)),
249 five_year_total_return: Some(FormattedValue::new(12.491636)),
250 ten_year_total_return: Some(FormattedValue::new(220.57314)),
251 max_return: Some(FormattedValue::new(4168.3716)),
252 }),
253 performance_overview_benchmark: Some(PerformanceOverview {
254 as_of_date: Some(FormattedValue::new(1764892800)),
255 five_days_return: Some(FormattedValue::new(0.0031113708)),
256 one_month_return: Some(FormattedValue::new(0.010904458)),
257 three_month_return: Some(FormattedValue::new(0.060001526)),
258 six_month_return: Some(FormattedValue::new(0.15676934)),
259 ytd_return_pct: Some(FormattedValue::new(0.16811156)),
260 one_year_total_return: Some(FormattedValue::new(0.13090958)),
261 two_year_total_return: Some(FormattedValue::new(0.504298)),
262 three_year_total_return: Some(FormattedValue::new(0.71809816)),
263 five_year_total_return: Some(FormattedValue::new(0.85730654)),
264 ten_year_total_return: Some(FormattedValue::new(2.2846167)),
265 max_return: Some(FormattedValue::new(388.03735)),
266 }),
267 };
268
269 let ytd_vs = equity_performance.ytd_vs_benchmark().unwrap();
271 assert!((ytd_vs - 0.19058898).abs() < 0.0001);
272
273 let one_year_vs = equity_performance.one_year_vs_benchmark().unwrap();
275 assert!((one_year_vs - 0.12691402).abs() < 0.0001);
276
277 let five_year_vs = equity_performance.five_year_vs_benchmark().unwrap();
279 assert!((five_year_vs - 11.634329).abs() < 0.001);
280 }
281}