1use crate::models::format::{Both, Format};
6use finance_query_derive::FormatConvert;
7use serde::{Deserialize, Serialize};
8
9use super::{
10 BalanceSheetHistory, BalanceSheetHistoryQuarterly, CalendarEvents, CashflowStatementHistory,
11 CashflowStatementHistoryQuarterly, Earnings, EarningsHistory, EarningsTrend, EquityPerformance,
12 FundOwnership, FundPerformance, FundProfile, IncomeStatementHistory,
13 IncomeStatementHistoryQuarterly, IndexTrend, IndustryTrend, InsiderHolders,
14 InsiderTransactions, InstitutionOwnership, MajorHoldersBreakdown, NetSharePurchaseActivity,
15 QuoteSummaryResponse, RecommendationTrend, SecFilings, SectorTrend, TopHoldings,
16 UpgradeDowngradeHistory,
17};
18
19#[derive(Debug, Clone, Serialize, Deserialize, FormatConvert)]
54#[cfg_attr(feature = "dataframe", derive(crate::ToDataFrame))]
55#[serde(rename_all = "camelCase", bound = "")]
56#[non_exhaustive]
57pub struct Quote<F: Format = Both> {
58 pub symbol: String,
60
61 #[serde(skip_serializing_if = "Option::is_none")]
63 pub logo_url: Option<String>,
64
65 #[serde(skip_serializing_if = "Option::is_none")]
67 pub company_logo_url: Option<String>,
68
69 #[serde(skip_serializing_if = "Option::is_none")]
72 pub short_name: Option<String>,
73
74 #[serde(skip_serializing_if = "Option::is_none")]
76 pub long_name: Option<String>,
77
78 #[serde(skip_serializing_if = "Option::is_none")]
80 pub exchange: Option<String>,
81
82 #[serde(skip_serializing_if = "Option::is_none")]
84 pub exchange_name: Option<String>,
85
86 #[serde(skip_serializing_if = "Option::is_none")]
88 pub quote_type: Option<String>,
89
90 #[serde(skip_serializing_if = "Option::is_none")]
92 pub currency: Option<String>,
93
94 #[serde(skip_serializing_if = "Option::is_none")]
96 pub currency_symbol: Option<String>,
97
98 #[serde(skip_serializing_if = "Option::is_none")]
100 pub underlying_symbol: Option<String>,
101
102 #[serde(skip_serializing_if = "Option::is_none")]
104 pub from_currency: Option<String>,
105
106 #[serde(skip_serializing_if = "Option::is_none")]
108 pub to_currency: Option<String>,
109
110 #[serde(skip_serializing_if = "Option::is_none")]
113 pub regular_market_price: Option<F::Value<f64>>,
114
115 #[serde(skip_serializing_if = "Option::is_none")]
117 pub regular_market_change: Option<F::Value<f64>>,
118
119 #[serde(skip_serializing_if = "Option::is_none")]
121 pub regular_market_change_percent: Option<F::Value<f64>>,
122
123 #[serde(skip_serializing_if = "Option::is_none")]
125 pub regular_market_time: Option<i64>,
126
127 #[serde(skip_serializing_if = "Option::is_none")]
129 pub regular_market_day_high: Option<F::Value<f64>>,
130
131 #[serde(skip_serializing_if = "Option::is_none")]
133 pub regular_market_day_low: Option<F::Value<f64>>,
134
135 #[serde(skip_serializing_if = "Option::is_none")]
137 pub regular_market_open: Option<F::Value<f64>>,
138
139 #[serde(skip_serializing_if = "Option::is_none")]
141 pub regular_market_previous_close: Option<F::Value<f64>>,
142
143 #[serde(skip_serializing_if = "Option::is_none")]
145 pub regular_market_volume: Option<F::Value<i64>>,
146
147 #[serde(skip_serializing_if = "Option::is_none")]
149 pub market_state: Option<String>,
150
151 #[serde(skip_serializing_if = "Option::is_none")]
154 pub day_high: Option<F::Value<f64>>,
155
156 #[serde(skip_serializing_if = "Option::is_none")]
158 pub day_low: Option<F::Value<f64>>,
159
160 #[serde(skip_serializing_if = "Option::is_none")]
162 pub open: Option<F::Value<f64>>,
163
164 #[serde(skip_serializing_if = "Option::is_none")]
166 pub previous_close: Option<F::Value<f64>>,
167
168 #[serde(skip_serializing_if = "Option::is_none")]
170 pub volume: Option<F::Value<i64>>,
171
172 #[serde(skip_serializing_if = "Option::is_none")]
175 pub all_time_high: Option<F::Value<f64>>,
176
177 #[serde(skip_serializing_if = "Option::is_none")]
179 pub all_time_low: Option<F::Value<f64>>,
180
181 #[serde(skip_serializing_if = "Option::is_none")]
184 pub pre_market_price: Option<F::Value<f64>>,
185
186 #[serde(skip_serializing_if = "Option::is_none")]
188 pub pre_market_change: Option<F::Value<f64>>,
189
190 #[serde(skip_serializing_if = "Option::is_none")]
192 pub pre_market_change_percent: Option<F::Value<f64>>,
193
194 #[serde(skip_serializing_if = "Option::is_none")]
196 pub pre_market_time: Option<i64>,
197
198 #[serde(skip_serializing_if = "Option::is_none")]
200 pub post_market_price: Option<F::Value<f64>>,
201
202 #[serde(skip_serializing_if = "Option::is_none")]
204 pub post_market_change: Option<F::Value<f64>>,
205
206 #[serde(skip_serializing_if = "Option::is_none")]
208 pub post_market_change_percent: Option<F::Value<f64>>,
209
210 #[serde(skip_serializing_if = "Option::is_none")]
212 pub post_market_time: Option<i64>,
213
214 #[serde(skip_serializing_if = "Option::is_none")]
217 pub average_daily_volume10_day: Option<F::Value<i64>>,
218
219 #[serde(skip_serializing_if = "Option::is_none")]
221 pub average_daily_volume3_month: Option<F::Value<i64>>,
222
223 #[serde(skip_serializing_if = "Option::is_none")]
225 pub average_volume: Option<F::Value<i64>>,
226
227 #[serde(skip_serializing_if = "Option::is_none")]
229 pub average_volume10days: Option<F::Value<i64>>,
230
231 #[serde(skip_serializing_if = "Option::is_none")]
234 pub market_cap: Option<F::Value<i64>>,
235
236 #[serde(skip_serializing_if = "Option::is_none")]
238 pub enterprise_value: Option<F::Value<i64>>,
239
240 #[serde(skip_serializing_if = "Option::is_none")]
242 pub enterprise_to_revenue: Option<F::Value<f64>>,
243
244 #[serde(skip_serializing_if = "Option::is_none")]
246 pub enterprise_to_ebitda: Option<F::Value<f64>>,
247
248 #[serde(skip_serializing_if = "Option::is_none")]
250 pub price_to_book: Option<F::Value<f64>>,
251
252 #[serde(skip_serializing_if = "Option::is_none")]
254 pub price_to_sales_trailing12_months: Option<F::Value<f64>>,
255
256 #[serde(rename = "forwardPE", skip_serializing_if = "Option::is_none")]
259 pub forward_pe: Option<F::Value<f64>>,
260
261 #[serde(rename = "trailingPE", skip_serializing_if = "Option::is_none")]
263 pub trailing_pe: Option<F::Value<f64>>,
264
265 #[serde(skip_serializing_if = "Option::is_none")]
268 pub beta: Option<F::Value<f64>>,
269
270 #[serde(skip_serializing_if = "Option::is_none")]
273 pub fifty_two_week_high: Option<F::Value<f64>>,
274
275 #[serde(skip_serializing_if = "Option::is_none")]
277 pub fifty_two_week_low: Option<F::Value<f64>>,
278
279 #[serde(skip_serializing_if = "Option::is_none")]
281 pub fifty_day_average: Option<F::Value<f64>>,
282
283 #[serde(skip_serializing_if = "Option::is_none")]
285 pub two_hundred_day_average: Option<F::Value<f64>>,
286
287 #[serde(rename = "52WeekChange", skip_serializing_if = "Option::is_none")]
289 pub week_52_change: Option<F::Value<f64>>,
290
291 #[serde(rename = "SandP52WeekChange", skip_serializing_if = "Option::is_none")]
293 pub sand_p_52_week_change: Option<F::Value<f64>>,
294
295 #[serde(skip_serializing_if = "Option::is_none")]
298 pub dividend_rate: Option<F::Value<f64>>,
299
300 #[serde(skip_serializing_if = "Option::is_none")]
302 pub dividend_yield: Option<F::Value<f64>>,
303
304 #[serde(skip_serializing_if = "Option::is_none")]
306 pub trailing_annual_dividend_rate: Option<F::Value<f64>>,
307
308 #[serde(skip_serializing_if = "Option::is_none")]
310 pub trailing_annual_dividend_yield: Option<F::Value<f64>>,
311
312 #[serde(skip_serializing_if = "Option::is_none")]
314 pub five_year_avg_dividend_yield: Option<F::Value<f64>>,
315
316 #[serde(skip_serializing_if = "Option::is_none")]
318 pub ex_dividend_date: Option<F::Value<i64>>,
319
320 #[serde(skip_serializing_if = "Option::is_none")]
322 pub payout_ratio: Option<F::Value<f64>>,
323
324 #[serde(skip_serializing_if = "Option::is_none")]
326 pub last_dividend_value: Option<F::Value<f64>>,
327
328 #[serde(skip_serializing_if = "Option::is_none")]
330 pub last_dividend_date: Option<F::Value<i64>>,
331
332 #[serde(skip_serializing_if = "Option::is_none")]
335 pub bid: Option<F::Value<f64>>,
336
337 #[serde(skip_serializing_if = "Option::is_none")]
339 pub bid_size: Option<F::Value<i64>>,
340
341 #[serde(skip_serializing_if = "Option::is_none")]
343 pub ask: Option<F::Value<f64>>,
344
345 #[serde(skip_serializing_if = "Option::is_none")]
347 pub ask_size: Option<F::Value<i64>>,
348
349 #[serde(skip_serializing_if = "Option::is_none")]
352 pub shares_outstanding: Option<F::Value<i64>>,
353
354 #[serde(skip_serializing_if = "Option::is_none")]
356 pub float_shares: Option<F::Value<i64>>,
357
358 #[serde(skip_serializing_if = "Option::is_none")]
360 pub implied_shares_outstanding: Option<F::Value<i64>>,
361
362 #[serde(skip_serializing_if = "Option::is_none")]
364 pub held_percent_insiders: Option<F::Value<f64>>,
365
366 #[serde(skip_serializing_if = "Option::is_none")]
368 pub held_percent_institutions: Option<F::Value<f64>>,
369
370 #[serde(skip_serializing_if = "Option::is_none")]
372 pub shares_short: Option<F::Value<i64>>,
373
374 #[serde(skip_serializing_if = "Option::is_none")]
376 pub shares_short_prior_month: Option<F::Value<i64>>,
377
378 #[serde(skip_serializing_if = "Option::is_none")]
380 pub short_ratio: Option<F::Value<f64>>,
381
382 #[serde(skip_serializing_if = "Option::is_none")]
384 pub short_percent_of_float: Option<F::Value<f64>>,
385
386 #[serde(skip_serializing_if = "Option::is_none")]
388 pub shares_percent_shares_out: Option<F::Value<f64>>,
389
390 #[serde(skip_serializing_if = "Option::is_none")]
392 pub date_short_interest: Option<F::Value<i64>>,
393
394 #[serde(skip_serializing_if = "Option::is_none")]
397 pub current_price: Option<F::Value<f64>>,
398
399 #[serde(skip_serializing_if = "Option::is_none")]
401 pub target_high_price: Option<F::Value<f64>>,
402
403 #[serde(skip_serializing_if = "Option::is_none")]
405 pub target_low_price: Option<F::Value<f64>>,
406
407 #[serde(skip_serializing_if = "Option::is_none")]
409 pub target_mean_price: Option<F::Value<f64>>,
410
411 #[serde(skip_serializing_if = "Option::is_none")]
413 pub target_median_price: Option<F::Value<f64>>,
414
415 #[serde(skip_serializing_if = "Option::is_none")]
417 pub recommendation_mean: Option<F::Value<f64>>,
418
419 #[serde(skip_serializing_if = "Option::is_none")]
421 pub recommendation_key: Option<String>,
422
423 #[serde(skip_serializing_if = "Option::is_none")]
425 pub number_of_analyst_opinions: Option<F::Value<i64>>,
426
427 #[serde(skip_serializing_if = "Option::is_none")]
429 pub total_cash: Option<F::Value<i64>>,
430
431 #[serde(skip_serializing_if = "Option::is_none")]
433 pub total_cash_per_share: Option<F::Value<f64>>,
434
435 #[serde(skip_serializing_if = "Option::is_none")]
437 pub ebitda: Option<F::Value<i64>>,
438
439 #[serde(skip_serializing_if = "Option::is_none")]
441 pub total_debt: Option<F::Value<i64>>,
442
443 #[serde(skip_serializing_if = "Option::is_none")]
445 pub total_revenue: Option<F::Value<i64>>,
446
447 #[serde(skip_serializing_if = "Option::is_none")]
449 pub net_income_to_common: Option<F::Value<i64>>,
450
451 #[serde(skip_serializing_if = "Option::is_none")]
453 pub debt_to_equity: Option<F::Value<f64>>,
454
455 #[serde(skip_serializing_if = "Option::is_none")]
457 pub revenue_per_share: Option<F::Value<f64>>,
458
459 #[serde(skip_serializing_if = "Option::is_none")]
461 pub return_on_assets: Option<F::Value<f64>>,
462
463 #[serde(skip_serializing_if = "Option::is_none")]
465 pub return_on_equity: Option<F::Value<f64>>,
466
467 #[serde(skip_serializing_if = "Option::is_none")]
469 pub free_cashflow: Option<F::Value<i64>>,
470
471 #[serde(skip_serializing_if = "Option::is_none")]
473 pub operating_cashflow: Option<F::Value<i64>>,
474
475 #[serde(skip_serializing_if = "Option::is_none")]
478 pub profit_margins: Option<F::Value<f64>>,
479
480 #[serde(skip_serializing_if = "Option::is_none")]
482 pub gross_margins: Option<F::Value<f64>>,
483
484 #[serde(skip_serializing_if = "Option::is_none")]
486 pub ebitda_margins: Option<F::Value<f64>>,
487
488 #[serde(skip_serializing_if = "Option::is_none")]
490 pub operating_margins: Option<F::Value<f64>>,
491
492 #[serde(skip_serializing_if = "Option::is_none")]
494 pub gross_profits: Option<F::Value<i64>>,
495
496 #[serde(skip_serializing_if = "Option::is_none")]
499 pub earnings_growth: Option<F::Value<f64>>,
500
501 #[serde(skip_serializing_if = "Option::is_none")]
503 pub revenue_growth: Option<F::Value<f64>>,
504
505 #[serde(skip_serializing_if = "Option::is_none")]
507 pub earnings_quarterly_growth: Option<F::Value<f64>>,
508
509 #[serde(skip_serializing_if = "Option::is_none")]
512 pub current_ratio: Option<F::Value<f64>>,
513
514 #[serde(skip_serializing_if = "Option::is_none")]
516 pub quick_ratio: Option<F::Value<f64>>,
517
518 #[serde(skip_serializing_if = "Option::is_none")]
521 pub trailing_eps: Option<F::Value<f64>>,
522
523 #[serde(skip_serializing_if = "Option::is_none")]
525 pub forward_eps: Option<F::Value<f64>>,
526
527 #[serde(skip_serializing_if = "Option::is_none")]
529 pub book_value: Option<F::Value<f64>>,
530
531 #[serde(skip_serializing_if = "Option::is_none")]
534 pub sector: Option<String>,
535
536 #[serde(skip_serializing_if = "Option::is_none")]
538 pub sector_key: Option<String>,
539
540 #[serde(skip_serializing_if = "Option::is_none")]
542 pub sector_disp: Option<String>,
543
544 #[serde(skip_serializing_if = "Option::is_none")]
546 pub industry: Option<String>,
547
548 #[serde(skip_serializing_if = "Option::is_none")]
550 pub industry_key: Option<String>,
551
552 #[serde(skip_serializing_if = "Option::is_none")]
554 pub industry_disp: Option<String>,
555
556 #[serde(skip_serializing_if = "Option::is_none")]
558 pub long_business_summary: Option<String>,
559
560 #[serde(skip_serializing_if = "Option::is_none")]
562 pub website: Option<String>,
563
564 #[serde(skip_serializing_if = "Option::is_none")]
566 pub ir_website: Option<String>,
567
568 #[serde(skip_serializing_if = "Option::is_none")]
570 pub address1: Option<String>,
571
572 #[serde(skip_serializing_if = "Option::is_none")]
574 pub city: Option<String>,
575
576 #[serde(skip_serializing_if = "Option::is_none")]
578 pub state: Option<String>,
579
580 #[serde(skip_serializing_if = "Option::is_none")]
582 pub zip: Option<String>,
583
584 #[serde(skip_serializing_if = "Option::is_none")]
586 pub country: Option<String>,
587
588 #[serde(skip_serializing_if = "Option::is_none")]
590 pub phone: Option<String>,
591
592 #[serde(skip_serializing_if = "Option::is_none")]
594 pub full_time_employees: Option<i64>,
595
596 #[serde(skip_serializing_if = "Option::is_none")]
598 pub category: Option<String>,
599
600 #[serde(skip_serializing_if = "Option::is_none")]
602 pub fund_family: Option<String>,
603
604 #[serde(skip_serializing_if = "Option::is_none")]
607 pub audit_risk: Option<i32>,
608
609 #[serde(skip_serializing_if = "Option::is_none")]
611 pub board_risk: Option<i32>,
612
613 #[serde(skip_serializing_if = "Option::is_none")]
615 pub compensation_risk: Option<i32>,
616
617 #[serde(skip_serializing_if = "Option::is_none")]
619 pub shareholder_rights_risk: Option<i32>,
620
621 #[serde(skip_serializing_if = "Option::is_none")]
623 pub overall_risk: Option<i32>,
624
625 #[serde(skip_serializing_if = "Option::is_none")]
628 pub time_zone_full_name: Option<String>,
629
630 #[serde(skip_serializing_if = "Option::is_none")]
632 pub time_zone_short_name: Option<String>,
633
634 #[serde(skip_serializing_if = "Option::is_none")]
636 pub gmt_off_set_milliseconds: Option<i64>,
637
638 #[serde(skip_serializing_if = "Option::is_none")]
640 pub first_trade_date_epoch_utc: Option<i64>,
641
642 #[serde(skip_serializing_if = "Option::is_none")]
644 pub message_board_id: Option<String>,
645
646 #[serde(skip_serializing_if = "Option::is_none")]
648 pub exchange_data_delayed_by: Option<i32>,
649
650 #[serde(skip_serializing_if = "Option::is_none")]
653 pub nav_price: Option<F::Value<f64>>,
654
655 #[serde(skip_serializing_if = "Option::is_none")]
657 pub total_assets: Option<F::Value<i64>>,
658
659 #[serde(rename = "yield", skip_serializing_if = "Option::is_none")]
661 pub yield_value: Option<F::Value<f64>>,
662
663 #[serde(skip_serializing_if = "Option::is_none")]
666 pub last_split_factor: Option<String>,
667
668 #[serde(skip_serializing_if = "Option::is_none")]
670 pub last_split_date: Option<F::Value<i64>>,
671
672 #[serde(skip_serializing_if = "Option::is_none")]
674 pub last_fiscal_year_end: Option<F::Value<i64>>,
675
676 #[serde(skip_serializing_if = "Option::is_none")]
678 pub next_fiscal_year_end: Option<F::Value<i64>>,
679
680 #[serde(skip_serializing_if = "Option::is_none")]
682 pub most_recent_quarter: Option<F::Value<i64>>,
683
684 #[serde(skip_serializing_if = "Option::is_none")]
687 pub price_hint: Option<F::Value<i64>>,
688
689 #[serde(skip_serializing_if = "Option::is_none")]
691 pub tradeable: Option<bool>,
692
693 #[serde(skip_serializing_if = "Option::is_none")]
695 pub financial_currency: Option<String>,
696
697 #[serde(skip_serializing_if = "Option::is_none")]
700 pub company_officers: Option<Vec<super::CompanyOfficer>>,
701
702 #[serde(skip_serializing_if = "Option::is_none")]
704 pub earnings: Option<Earnings>,
705
706 #[serde(skip_serializing_if = "Option::is_none")]
708 pub calendar_events: Option<CalendarEvents>,
709
710 #[serde(skip_serializing_if = "Option::is_none")]
712 pub recommendation_trend: Option<RecommendationTrend>,
713
714 #[serde(skip_serializing_if = "Option::is_none")]
716 pub upgrade_downgrade_history: Option<UpgradeDowngradeHistory>,
717
718 #[serde(skip_serializing_if = "Option::is_none")]
720 pub earnings_history: Option<EarningsHistory>,
721
722 #[serde(skip_serializing_if = "Option::is_none")]
724 pub earnings_trend: Option<EarningsTrend>,
725
726 #[serde(skip_serializing_if = "Option::is_none")]
728 pub insider_holders: Option<InsiderHolders>,
729
730 #[serde(skip_serializing_if = "Option::is_none")]
732 pub insider_transactions: Option<InsiderTransactions>,
733
734 #[serde(skip_serializing_if = "Option::is_none")]
736 pub institution_ownership: Option<InstitutionOwnership>,
737
738 #[serde(skip_serializing_if = "Option::is_none")]
740 pub fund_ownership: Option<FundOwnership>,
741
742 #[serde(skip_serializing_if = "Option::is_none")]
744 pub major_holders_breakdown: Option<MajorHoldersBreakdown>,
745
746 #[serde(skip_serializing_if = "Option::is_none")]
748 pub net_share_purchase_activity: Option<NetSharePurchaseActivity>,
749
750 #[serde(skip_serializing_if = "Option::is_none")]
752 pub sec_filings: Option<SecFilings>,
753
754 #[serde(skip_serializing_if = "Option::is_none")]
759 pub balance_sheet_history: Option<BalanceSheetHistory>,
760
761 #[serde(skip_serializing_if = "Option::is_none")]
766 pub balance_sheet_history_quarterly: Option<BalanceSheetHistoryQuarterly>,
767
768 #[serde(skip_serializing_if = "Option::is_none")]
773 pub cashflow_statement_history: Option<CashflowStatementHistory>,
774
775 #[serde(skip_serializing_if = "Option::is_none")]
780 pub cashflow_statement_history_quarterly: Option<CashflowStatementHistoryQuarterly>,
781
782 #[serde(skip_serializing_if = "Option::is_none")]
787 pub income_statement_history: Option<IncomeStatementHistory>,
788
789 #[serde(skip_serializing_if = "Option::is_none")]
794 pub income_statement_history_quarterly: Option<IncomeStatementHistoryQuarterly>,
795
796 #[serde(skip_serializing_if = "Option::is_none")]
798 pub equity_performance: Option<EquityPerformance>,
799
800 #[serde(skip_serializing_if = "Option::is_none")]
802 pub index_trend: Option<IndexTrend>,
803
804 #[serde(skip_serializing_if = "Option::is_none")]
806 pub industry_trend: Option<IndustryTrend>,
807
808 #[serde(skip_serializing_if = "Option::is_none")]
810 pub sector_trend: Option<SectorTrend>,
811
812 #[serde(skip_serializing_if = "Option::is_none")]
814 pub fund_profile: Option<FundProfile>,
815
816 #[serde(skip_serializing_if = "Option::is_none")]
818 pub fund_performance: Option<FundPerformance>,
819
820 #[serde(skip_serializing_if = "Option::is_none")]
822 pub top_holdings: Option<TopHoldings>,
823}
824
825impl Quote<Both> {
826 pub(crate) fn from_response(
837 response: &QuoteSummaryResponse,
838 logo_url: Option<String>,
839 company_logo_url: Option<String>,
840 ) -> Self {
841 let price = response.price.as_ref();
842 let quote_type = response.quote_type.as_ref();
843 let summary_detail = response.summary_detail.as_ref();
844 let financial_data = response.financial_data.as_ref();
845 let key_stats = response.default_key_statistics.as_ref();
846 let asset_profile = response.asset_profile.as_ref();
847 let summary_profile = response.summary_profile.as_ref();
848
849 Self {
850 symbol: response.symbol.clone(),
851 logo_url,
852 company_logo_url,
853
854 short_name: price
857 .and_then(|p| p.short_name.clone())
858 .or_else(|| quote_type.and_then(|q| q.short_name.clone())),
859
860 long_name: price
861 .and_then(|p| p.long_name.clone())
862 .or_else(|| quote_type.and_then(|q| q.long_name.clone())),
863
864 exchange: price
865 .and_then(|p| p.exchange.clone())
866 .or_else(|| quote_type.and_then(|q| q.exchange.clone())),
867
868 exchange_name: price.and_then(|p| p.exchange_name.clone()),
869
870 quote_type: price
871 .and_then(|p| p.quote_type.clone())
872 .or_else(|| quote_type.and_then(|q| q.quote_type.clone())),
873
874 currency: price.and_then(|p| p.currency.clone()).or_else(|| {
875 summary_detail
876 .and_then(|s| s.currency.clone())
877 .or_else(|| financial_data.and_then(|f| f.financial_currency.clone()))
878 }),
879
880 currency_symbol: price.and_then(|p| p.currency_symbol.clone()),
881
882 underlying_symbol: price
883 .and_then(|p| p.underlying_symbol.clone())
884 .or_else(|| quote_type.and_then(|q| q.underlying_symbol.clone())),
885 from_currency: price
886 .and_then(|p| p.from_currency.clone())
887 .or_else(|| summary_detail.and_then(|s| s.from_currency.clone())),
888 to_currency: price
889 .and_then(|p| p.to_currency.clone())
890 .or_else(|| summary_detail.and_then(|s| s.to_currency.clone())),
891
892 regular_market_price: price.and_then(|p| p.regular_market_price.clone()),
894 regular_market_change: price.and_then(|p| p.regular_market_change.clone()),
895 regular_market_change_percent: price
896 .and_then(|p| p.regular_market_change_percent.clone()),
897 regular_market_time: price.and_then(|p| p.regular_market_time),
898 regular_market_day_high: price.and_then(|p| p.regular_market_day_high.clone()),
899 regular_market_day_low: price.and_then(|p| p.regular_market_day_low.clone()),
900 regular_market_open: price.and_then(|p| p.regular_market_open.clone()),
901 regular_market_previous_close: price
902 .and_then(|p| p.regular_market_previous_close.clone()),
903 regular_market_volume: price.and_then(|p| p.regular_market_volume.clone()),
904 market_state: price.and_then(|p| p.market_state.clone()),
905
906 day_high: summary_detail.and_then(|s| s.day_high.clone()),
908 day_low: summary_detail.and_then(|s| s.day_low.clone()),
909 open: summary_detail.and_then(|s| s.open.clone()),
910 previous_close: summary_detail.and_then(|s| s.previous_close.clone()),
911 volume: summary_detail.and_then(|s| s.volume.clone()),
912
913 all_time_high: summary_detail.and_then(|s| s.all_time_high.clone()),
915 all_time_low: summary_detail.and_then(|s| s.all_time_low.clone()),
916
917 pre_market_price: price.and_then(|p| p.pre_market_price.clone()),
919 pre_market_change: price.and_then(|p| p.pre_market_change.clone()),
920 pre_market_change_percent: price.and_then(|p| p.pre_market_change_percent.clone()),
921 pre_market_time: price.and_then(|p| p.pre_market_time),
922 post_market_price: price.and_then(|p| p.post_market_price.clone()),
923 post_market_change: price.and_then(|p| p.post_market_change.clone()),
924 post_market_change_percent: price.and_then(|p| p.post_market_change_percent.clone()),
925 post_market_time: price.and_then(|p| p.post_market_time),
926
927 average_daily_volume10_day: price
930 .and_then(|p| p.average_daily_volume10_day.clone())
931 .or_else(|| summary_detail.and_then(|s| s.average_daily_volume10_day.clone())),
932 average_daily_volume3_month: price.and_then(|p| p.average_daily_volume3_month.clone()),
933 average_volume: summary_detail.and_then(|s| s.average_volume.clone()),
934 average_volume10days: summary_detail.and_then(|s| s.average_volume10days.clone()),
935
936 market_cap: price.and_then(|p| p.market_cap.clone()),
939 enterprise_value: key_stats.and_then(|k| k.enterprise_value.clone()),
940 enterprise_to_revenue: key_stats.and_then(|k| k.enterprise_to_revenue.clone()),
941 enterprise_to_ebitda: key_stats.and_then(|k| k.enterprise_to_ebitda.clone()),
942 price_to_book: key_stats.and_then(|k| k.price_to_book.clone()),
943 price_to_sales_trailing12_months: summary_detail
944 .and_then(|s| s.price_to_sales_trailing12_months.clone()),
945
946 forward_pe: summary_detail
949 .and_then(|s| s.forward_pe.clone())
950 .or_else(|| key_stats.and_then(|k| k.forward_pe.clone())),
951 trailing_pe: summary_detail.and_then(|s| s.trailing_pe.clone()),
952
953 beta: summary_detail
956 .and_then(|s| s.beta.clone())
957 .or_else(|| key_stats.and_then(|k| k.beta.clone())),
958
959 fifty_two_week_high: summary_detail.and_then(|s| s.fifty_two_week_high.clone()),
961 fifty_two_week_low: summary_detail.and_then(|s| s.fifty_two_week_low.clone()),
962 fifty_day_average: summary_detail.and_then(|s| s.fifty_day_average.clone()),
963 two_hundred_day_average: summary_detail.and_then(|s| s.two_hundred_day_average.clone()),
964 week_52_change: key_stats.and_then(|k| k.week_52_change.clone()),
965 sand_p_52_week_change: key_stats.and_then(|k| k.sand_p_52_week_change.clone()),
966
967 dividend_rate: summary_detail.and_then(|s| s.dividend_rate.clone()),
969 dividend_yield: summary_detail.and_then(|s| s.dividend_yield.clone()),
970 trailing_annual_dividend_rate: summary_detail
971 .and_then(|s| s.trailing_annual_dividend_rate.clone()),
972 trailing_annual_dividend_yield: summary_detail
973 .and_then(|s| s.trailing_annual_dividend_yield.clone()),
974 five_year_avg_dividend_yield: summary_detail
975 .and_then(|s| s.five_year_avg_dividend_yield.clone()),
976 ex_dividend_date: summary_detail.and_then(|s| s.ex_dividend_date.clone()),
977 payout_ratio: summary_detail.and_then(|s| s.payout_ratio.clone()),
978 last_dividend_value: key_stats.and_then(|k| k.last_dividend_value.clone()),
979 last_dividend_date: key_stats.and_then(|k| k.last_dividend_date.clone()),
980
981 bid: summary_detail.and_then(|s| s.bid.clone()),
983 bid_size: summary_detail.and_then(|s| s.bid_size.clone()),
984 ask: summary_detail.and_then(|s| s.ask.clone()),
985 ask_size: summary_detail.and_then(|s| s.ask_size.clone()),
986
987 shares_outstanding: key_stats.and_then(|k| k.shares_outstanding.clone()),
989 float_shares: key_stats.and_then(|k| k.float_shares.clone()),
990 implied_shares_outstanding: key_stats
991 .and_then(|k| k.implied_shares_outstanding.clone()),
992 held_percent_insiders: key_stats.and_then(|k| k.held_percent_insiders.clone()),
993 held_percent_institutions: key_stats.and_then(|k| k.held_percent_institutions.clone()),
994 shares_short: key_stats.and_then(|k| k.shares_short.clone()),
995 shares_short_prior_month: key_stats.and_then(|k| k.shares_short_prior_month.clone()),
996 short_ratio: key_stats.and_then(|k| k.short_ratio.clone()),
997 short_percent_of_float: key_stats.and_then(|k| k.short_percent_of_float.clone()),
998 shares_percent_shares_out: key_stats.and_then(|k| k.shares_percent_shares_out.clone()),
999 date_short_interest: key_stats.and_then(|k| k.date_short_interest.clone()),
1000
1001 current_price: financial_data.and_then(|f| f.current_price.clone()),
1003 target_high_price: financial_data.and_then(|f| f.target_high_price.clone()),
1004 target_low_price: financial_data.and_then(|f| f.target_low_price.clone()),
1005 target_mean_price: financial_data.and_then(|f| f.target_mean_price.clone()),
1006 target_median_price: financial_data.and_then(|f| f.target_median_price.clone()),
1007 recommendation_mean: financial_data.and_then(|f| f.recommendation_mean.clone()),
1008 recommendation_key: financial_data.and_then(|f| f.recommendation_key.clone()),
1009 number_of_analyst_opinions: financial_data
1010 .and_then(|f| f.number_of_analyst_opinions.clone()),
1011 total_cash: financial_data.and_then(|f| f.total_cash.clone()),
1012 total_cash_per_share: financial_data.and_then(|f| f.total_cash_per_share.clone()),
1013 ebitda: financial_data.and_then(|f| f.ebitda.clone()),
1014 total_debt: financial_data.and_then(|f| f.total_debt.clone()),
1015 total_revenue: financial_data.and_then(|f| f.total_revenue.clone()),
1016 net_income_to_common: key_stats.and_then(|k| k.net_income_to_common.clone()),
1017 debt_to_equity: financial_data.and_then(|f| f.debt_to_equity.clone()),
1018 revenue_per_share: financial_data.and_then(|f| f.revenue_per_share.clone()),
1019 return_on_assets: financial_data.and_then(|f| f.return_on_assets.clone()),
1020 return_on_equity: financial_data.and_then(|f| f.return_on_equity.clone()),
1021 free_cashflow: financial_data.and_then(|f| f.free_cashflow.clone()),
1022 operating_cashflow: financial_data.and_then(|f| f.operating_cashflow.clone()),
1023
1024 profit_margins: financial_data.and_then(|f| f.profit_margins.clone()),
1027 gross_margins: financial_data.and_then(|f| f.gross_margins.clone()),
1028 ebitda_margins: financial_data.and_then(|f| f.ebitda_margins.clone()),
1029 operating_margins: financial_data.and_then(|f| f.operating_margins.clone()),
1030 gross_profits: financial_data.and_then(|f| f.gross_profits.clone()),
1031
1032 earnings_growth: financial_data.and_then(|f| f.earnings_growth.clone()),
1034 revenue_growth: financial_data.and_then(|f| f.revenue_growth.clone()),
1035 earnings_quarterly_growth: key_stats.and_then(|k| k.earnings_quarterly_growth.clone()),
1036
1037 current_ratio: financial_data.and_then(|f| f.current_ratio.clone()),
1039 quick_ratio: financial_data.and_then(|f| f.quick_ratio.clone()),
1040
1041 trailing_eps: key_stats.and_then(|k| k.trailing_eps.clone()),
1043 forward_eps: key_stats.and_then(|k| k.forward_eps.clone()),
1044 book_value: key_stats.and_then(|k| k.book_value.clone()),
1045
1046 sector: asset_profile
1049 .and_then(|a| a.sector.clone())
1050 .or_else(|| summary_profile.and_then(|s| s.sector.clone())),
1051 sector_key: asset_profile.and_then(|a| a.sector_key.clone()),
1052 sector_disp: asset_profile.and_then(|a| a.sector_disp.clone()),
1053 industry: asset_profile
1054 .and_then(|a| a.industry.clone())
1055 .or_else(|| summary_profile.and_then(|s| s.industry.clone())),
1056 industry_key: asset_profile.and_then(|a| a.industry_key.clone()),
1057 industry_disp: asset_profile.and_then(|a| a.industry_disp.clone()),
1058 long_business_summary: asset_profile
1059 .and_then(|a| a.long_business_summary.clone())
1060 .or_else(|| summary_profile.and_then(|s| s.long_business_summary.clone())),
1061 address1: asset_profile
1062 .and_then(|a| a.address1.clone())
1063 .or_else(|| summary_profile.and_then(|s| s.address1.clone())),
1064 city: asset_profile
1065 .and_then(|a| a.city.clone())
1066 .or_else(|| summary_profile.and_then(|s| s.city.clone())),
1067 state: asset_profile
1068 .and_then(|a| a.state.clone())
1069 .or_else(|| summary_profile.and_then(|s| s.state.clone())),
1070 zip: asset_profile
1071 .and_then(|a| a.zip.clone())
1072 .or_else(|| summary_profile.and_then(|s| s.zip.clone())),
1073 country: asset_profile
1074 .and_then(|a| a.country.clone())
1075 .or_else(|| summary_profile.and_then(|s| s.country.clone())),
1076 phone: asset_profile
1077 .and_then(|a| a.phone.clone())
1078 .or_else(|| summary_profile.and_then(|s| s.phone.clone())),
1079 full_time_employees: asset_profile
1080 .and_then(|a| a.full_time_employees)
1081 .or_else(|| summary_profile.and_then(|s| s.full_time_employees)),
1082
1083 website: asset_profile
1084 .and_then(|a| a.website.clone())
1085 .or_else(|| summary_profile.and_then(|s| s.website.clone())),
1086 ir_website: summary_profile.and_then(|s| s.ir_website.clone()),
1087
1088 category: key_stats.and_then(|k| k.category.clone()),
1089 fund_family: key_stats.and_then(|k| k.fund_family.clone()),
1090
1091 audit_risk: asset_profile.and_then(|a| a.audit_risk),
1093 board_risk: asset_profile.and_then(|a| a.board_risk),
1094 compensation_risk: asset_profile.and_then(|a| a.compensation_risk),
1095 shareholder_rights_risk: asset_profile.and_then(|a| a.shareholder_rights_risk),
1096 overall_risk: asset_profile.and_then(|a| a.overall_risk),
1097
1098 time_zone_full_name: quote_type.and_then(|q| q.time_zone_full_name.clone()),
1100 time_zone_short_name: quote_type.and_then(|q| q.time_zone_short_name.clone()),
1101 gmt_off_set_milliseconds: quote_type.and_then(|q| q.gmt_off_set_milliseconds),
1102 first_trade_date_epoch_utc: quote_type.and_then(|q| q.first_trade_date_epoch_utc),
1103 message_board_id: quote_type.and_then(|q| q.message_board_id.clone()),
1104 exchange_data_delayed_by: price.and_then(|p| p.exchange_data_delayed_by),
1105
1106 nav_price: summary_detail.and_then(|s| s.nav_price.clone()),
1108 total_assets: summary_detail.and_then(|s| s.total_assets.clone()),
1109 yield_value: summary_detail.and_then(|s| s.yield_value.clone()),
1110
1111 last_split_factor: key_stats.and_then(|k| k.last_split_factor.clone()),
1113 last_split_date: key_stats.and_then(|k| k.last_split_date.clone()),
1114 last_fiscal_year_end: key_stats.and_then(|k| k.last_fiscal_year_end.clone()),
1115 next_fiscal_year_end: key_stats.and_then(|k| k.next_fiscal_year_end.clone()),
1116 most_recent_quarter: key_stats.and_then(|k| k.most_recent_quarter.clone()),
1117
1118 price_hint: price.and_then(|p| p.price_hint.clone()),
1121 tradeable: summary_detail.and_then(|s| s.tradeable),
1122 financial_currency: financial_data.and_then(|f| f.financial_currency.clone()),
1123
1124 company_officers: asset_profile.map(|a| a.company_officers.clone()),
1126 earnings: response.earnings.clone(),
1127 calendar_events: response.calendar_events.clone(),
1128 recommendation_trend: response.recommendation_trend.clone(),
1129 upgrade_downgrade_history: response.upgrade_downgrade_history.clone(),
1130 earnings_history: response.earnings_history.clone(),
1131 earnings_trend: response.earnings_trend.clone(),
1132 insider_holders: response.insider_holders.clone(),
1133 insider_transactions: response.insider_transactions.clone(),
1134 institution_ownership: response.institution_ownership.clone(),
1135 fund_ownership: response.fund_ownership.clone(),
1136 major_holders_breakdown: response.major_holders_breakdown.clone(),
1137 net_share_purchase_activity: response.net_share_purchase_activity.clone(),
1138 sec_filings: response.sec_filings.clone(),
1139 balance_sheet_history: None,
1142 balance_sheet_history_quarterly: None,
1143 cashflow_statement_history: None,
1144 cashflow_statement_history_quarterly: None,
1145 income_statement_history: None,
1146 income_statement_history_quarterly: None,
1147 equity_performance: response.equity_performance.clone(),
1148 index_trend: response.index_trend.clone(),
1149 industry_trend: response.industry_trend.clone(),
1150 sector_trend: response.sector_trend.clone(),
1151 fund_profile: response.fund_profile.clone(),
1152 fund_performance: response.fund_performance.clone(),
1153 top_holdings: response.top_holdings.clone(),
1154 }
1155 }
1156
1157 pub fn live_price(&self) -> Option<f64> {
1162 if self.market_state.as_deref() == Some("POST") {
1163 self.post_market_price
1164 .as_ref()
1165 .and_then(|p| p.raw)
1166 .or_else(|| self.regular_market_price.as_ref()?.raw)
1167 } else if self.market_state.as_deref() == Some("PRE") {
1168 self.pre_market_price
1169 .as_ref()
1170 .and_then(|p| p.raw)
1171 .or_else(|| self.regular_market_price.as_ref()?.raw)
1172 } else {
1173 self.regular_market_price.as_ref()?.raw
1174 }
1175 }
1176
1177 pub fn day_range(&self) -> Option<(f64, f64)> {
1179 let low = self.regular_market_day_low.as_ref()?.raw?;
1180 let high = self.regular_market_day_high.as_ref()?.raw?;
1181 Some((low, high))
1182 }
1183
1184 pub fn week_52_range(&self) -> Option<(f64, f64)> {
1186 let low = self.fifty_two_week_low.as_ref()?.raw?;
1187 let high = self.fifty_two_week_high.as_ref()?.raw?;
1188 Some((low, high))
1189 }
1190
1191 pub fn is_market_open(&self) -> bool {
1193 self.market_state.as_deref() == Some("REGULAR")
1194 }
1195
1196 pub fn is_pre_market(&self) -> bool {
1198 self.market_state.as_deref() == Some("PRE")
1199 }
1200
1201 pub fn is_post_market(&self) -> bool {
1203 self.market_state.as_deref() == Some("POST")
1204 }
1205}