finance_query/models/fundamentals/
default_key_statistics.rs1use crate::models::format::{Both, Format};
2use finance_query_derive::FormatConvert;
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, FormatConvert)]
15#[serde(rename_all = "camelCase", bound = "")]
16#[non_exhaustive]
17pub struct DefaultKeyStatistics<F: Format = Both> {
18 #[serde(rename = "52WeekChange", skip_serializing_if = "Option::is_none")]
20 pub week_52_change: Option<F::Value<f64>>,
21
22 #[serde(rename = "SandP52WeekChange", skip_serializing_if = "Option::is_none")]
24 pub sand_p_52_week_change: Option<F::Value<f64>>,
25
26 #[serde(skip_serializing_if = "Option::is_none")]
28 pub annual_holdings_turnover: Option<Value>,
29
30 #[serde(skip_serializing_if = "Option::is_none")]
32 pub annual_report_expense_ratio: Option<Value>,
33
34 #[serde(skip_serializing_if = "Option::is_none")]
36 pub beta: Option<F::Value<f64>>,
37
38 #[serde(skip_serializing_if = "Option::is_none")]
40 pub beta3_year: Option<Value>,
41
42 #[serde(skip_serializing_if = "Option::is_none")]
44 pub book_value: Option<F::Value<f64>>,
45
46 #[serde(skip_serializing_if = "Option::is_none")]
48 pub category: Option<String>,
49
50 #[serde(skip_serializing_if = "Option::is_none")]
52 pub date_short_interest: Option<F::Value<i64>>,
53
54 #[serde(skip_serializing_if = "Option::is_none")]
56 pub earnings_quarterly_growth: Option<F::Value<f64>>,
57
58 #[serde(skip_serializing_if = "Option::is_none")]
60 pub enterprise_to_ebitda: Option<F::Value<f64>>,
61
62 #[serde(skip_serializing_if = "Option::is_none")]
64 pub enterprise_to_revenue: Option<F::Value<f64>>,
65
66 #[serde(skip_serializing_if = "Option::is_none")]
68 pub enterprise_value: Option<F::Value<i64>>,
69
70 #[serde(skip_serializing_if = "Option::is_none")]
72 pub five_year_average_return: Option<Value>,
73
74 #[serde(skip_serializing_if = "Option::is_none")]
76 pub float_shares: Option<F::Value<i64>>,
77
78 #[serde(skip_serializing_if = "Option::is_none")]
80 pub forward_eps: Option<F::Value<f64>>,
81
82 #[serde(rename = "forwardPE", skip_serializing_if = "Option::is_none")]
84 pub forward_pe: Option<F::Value<f64>>,
85
86 #[serde(skip_serializing_if = "Option::is_none")]
88 pub fund_family: Option<String>,
89
90 #[serde(skip_serializing_if = "Option::is_none")]
92 pub fund_inception_date: Option<Value>,
93
94 #[serde(skip_serializing_if = "Option::is_none")]
96 pub funding_to_date: Option<Value>,
97
98 #[serde(skip_serializing_if = "Option::is_none")]
100 pub held_percent_insiders: Option<F::Value<f64>>,
101
102 #[serde(skip_serializing_if = "Option::is_none")]
104 pub held_percent_institutions: Option<F::Value<f64>>,
105
106 #[serde(skip_serializing_if = "Option::is_none")]
108 pub implied_shares_outstanding: Option<F::Value<i64>>,
109
110 #[serde(skip_serializing_if = "Option::is_none")]
112 pub last_cap_gain: Option<Value>,
113
114 #[serde(skip_serializing_if = "Option::is_none")]
116 pub last_dividend_date: Option<F::Value<i64>>,
117
118 #[serde(skip_serializing_if = "Option::is_none")]
120 pub last_dividend_value: Option<F::Value<f64>>,
121
122 #[serde(skip_serializing_if = "Option::is_none")]
124 pub last_fiscal_year_end: Option<F::Value<i64>>,
125
126 #[serde(skip_serializing_if = "Option::is_none")]
128 pub last_split_date: Option<F::Value<i64>>,
129
130 #[serde(skip_serializing_if = "Option::is_none")]
132 pub last_split_factor: Option<String>,
133
134 #[serde(skip_serializing_if = "Option::is_none")]
136 pub latest_amount_raised: Option<Value>,
137
138 #[serde(skip_serializing_if = "Option::is_none")]
140 pub latest_funding_date: Option<Value>,
141
142 #[serde(skip_serializing_if = "Option::is_none")]
144 pub latest_implied_valuation: Option<Value>,
145
146 #[serde(skip_serializing_if = "Option::is_none")]
148 pub latest_share_class: Option<String>,
149
150 #[serde(skip_serializing_if = "Option::is_none")]
152 pub lead_investor: Option<String>,
153
154 #[serde(skip_serializing_if = "Option::is_none")]
156 pub legal_type: Option<String>,
157
158 #[serde(skip_serializing_if = "Option::is_none")]
160 pub max_age: Option<i64>,
161
162 #[serde(skip_serializing_if = "Option::is_none")]
164 pub morning_star_overall_rating: Option<Value>,
165
166 #[serde(skip_serializing_if = "Option::is_none")]
168 pub morning_star_risk_rating: Option<Value>,
169
170 #[serde(skip_serializing_if = "Option::is_none")]
172 pub most_recent_quarter: Option<F::Value<i64>>,
173
174 #[serde(skip_serializing_if = "Option::is_none")]
176 pub net_income_to_common: Option<F::Value<i64>>,
177
178 #[serde(skip_serializing_if = "Option::is_none")]
180 pub next_fiscal_year_end: Option<F::Value<i64>>,
181
182 #[serde(skip_serializing_if = "Option::is_none")]
184 pub peg_ratio: Option<Value>,
185
186 #[serde(skip_serializing_if = "Option::is_none")]
188 pub price_hint: Option<F::Value<i64>>,
189
190 #[serde(skip_serializing_if = "Option::is_none")]
192 pub price_to_book: Option<F::Value<f64>>,
193
194 #[serde(skip_serializing_if = "Option::is_none")]
196 pub price_to_sales_trailing12_months: Option<Value>,
197
198 #[serde(skip_serializing_if = "Option::is_none")]
200 pub profit_margins: Option<F::Value<f64>>,
201
202 #[serde(skip_serializing_if = "Option::is_none")]
204 pub qtd_return: Option<Value>,
205
206 #[serde(skip_serializing_if = "Option::is_none")]
208 pub revenue_quarterly_growth: Option<Value>,
209
210 #[serde(skip_serializing_if = "Option::is_none")]
212 pub shares_outstanding: Option<F::Value<i64>>,
213
214 #[serde(skip_serializing_if = "Option::is_none")]
216 pub shares_percent_shares_out: Option<F::Value<f64>>,
217
218 #[serde(skip_serializing_if = "Option::is_none")]
220 pub shares_short: Option<F::Value<i64>>,
221
222 #[serde(skip_serializing_if = "Option::is_none")]
224 pub shares_short_previous_month_date: Option<F::Value<i64>>,
225
226 #[serde(skip_serializing_if = "Option::is_none")]
228 pub shares_short_prior_month: Option<F::Value<i64>>,
229
230 #[serde(skip_serializing_if = "Option::is_none")]
232 pub short_percent_of_float: Option<F::Value<f64>>,
233
234 #[serde(skip_serializing_if = "Option::is_none")]
236 pub short_ratio: Option<F::Value<f64>>,
237
238 #[serde(skip_serializing_if = "Option::is_none")]
240 pub three_year_average_return: Option<Value>,
241
242 #[serde(skip_serializing_if = "Option::is_none")]
244 pub total_assets: Option<Value>,
245
246 #[serde(skip_serializing_if = "Option::is_none")]
248 pub total_funding_rounds: Option<Value>,
249
250 #[serde(skip_serializing_if = "Option::is_none")]
252 pub trailing_eps: Option<F::Value<f64>>,
253
254 #[serde(rename = "yield", skip_serializing_if = "Option::is_none")]
256 pub yield_value: Option<Value>,
257
258 #[serde(skip_serializing_if = "Option::is_none")]
260 pub ytd_return: Option<Value>,
261}
262
263#[cfg(test)]
264mod tests {
265 use super::*;
266
267 #[test]
268 fn test_deserialize_default_key_statistics() {
269 let json = r#"{
270 "52WeekChange": {"fmt": "17.38%", "raw": 0.173828},
271 "SandP52WeekChange": {"fmt": "11.35%", "raw": 0.11350584},
272 "beta": {"fmt": "1.11", "raw": 1.109},
273 "bookValue": {"fmt": "4.99", "raw": 4.991},
274 "enterpriseValue": {"fmt": "4.13T", "longFmt": "4,134,771,359,744", "raw": 4134771359744},
275 "forwardPE": {"fmt": "30.39", "raw": 30.387243},
276 "lastSplitFactor": "4:1",
277 "maxAge": 1,
278 "sharesOutstanding": {"fmt": "14.78B", "longFmt": "14,776,353,000", "raw": 14776353000},
279 "trailingEps": {"fmt": "7.45", "raw": 7.45}
280 }"#;
281
282 let stats: DefaultKeyStatistics = serde_json::from_str(json).unwrap();
283 assert_eq!(
284 stats.week_52_change.as_ref().map(|v| v.raw),
285 Some(Some(0.173828))
286 );
287 assert_eq!(stats.beta.as_ref().map(|v| v.raw), Some(Some(1.109)));
288 assert_eq!(stats.last_split_factor.as_deref(), Some("4:1"));
289 assert_eq!(stats.max_age, Some(1));
290 assert_eq!(
291 stats.shares_outstanding.as_ref().map(|v| v.raw),
292 Some(Some(14776353000))
293 );
294 }
295
296 #[test]
297 fn test_into_raw() {
298 let json = r#"{
299 "beta": {"fmt": "1.11", "raw": 1.109},
300 "trailingEps": {"fmt": "7.45", "raw": 7.45},
301 "lastSplitFactor": "4:1"
302 }"#;
303
304 let stats: DefaultKeyStatistics = serde_json::from_str(json).unwrap();
305 let raw = stats.into_raw();
306 assert_eq!(raw.beta, Some(1.109));
307 assert_eq!(raw.trailing_eps, Some(7.45));
308 assert_eq!(raw.last_split_factor.as_deref(), Some("4:1"));
309 }
310
311 #[test]
312 fn test_into_pretty() {
313 let json = r#"{
314 "beta": {"fmt": "1.11", "raw": 1.109},
315 "enterpriseValue": {"fmt": "4.13T", "longFmt": "4,134,771,359,744", "raw": 4134771359744}
316 }"#;
317
318 let stats: DefaultKeyStatistics = serde_json::from_str(json).unwrap();
319 let pretty = stats.into_pretty();
320 assert_eq!(pretty.beta.as_deref(), Some("1.11"));
321 assert_eq!(pretty.enterprise_value.as_deref(), Some("4.13T"));
322 }
323}