use crate::models::format::{Both, Format};
use finance_query_derive::FormatConvert;
use serde::{Deserialize, Serialize};
use super::{
BalanceSheetHistory, BalanceSheetHistoryQuarterly, CalendarEvents, CashflowStatementHistory,
CashflowStatementHistoryQuarterly, Earnings, EarningsHistory, EarningsTrend, EquityPerformance,
FundOwnership, FundPerformance, FundProfile, IncomeStatementHistory,
IncomeStatementHistoryQuarterly, IndexTrend, IndustryTrend, InsiderHolders,
InsiderTransactions, InstitutionOwnership, MajorHoldersBreakdown, NetSharePurchaseActivity,
QuoteSummaryResponse, RecommendationTrend, SecFilings, SectorTrend, TopHoldings,
UpgradeDowngradeHistory,
};
#[derive(Debug, Clone, Serialize, Deserialize, FormatConvert)]
#[cfg_attr(feature = "dataframe", derive(crate::ToDataFrame))]
#[serde(rename_all = "camelCase", bound = "")]
#[non_exhaustive]
pub struct Quote<F: Format = Both> {
pub symbol: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub logo_url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub company_logo_url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub short_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub long_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub exchange: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub exchange_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub quote_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub currency: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub currency_symbol: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub underlying_symbol: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub from_currency: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub to_currency: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub regular_market_price: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub regular_market_change: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub regular_market_change_percent: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub regular_market_time: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub regular_market_day_high: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub regular_market_day_low: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub regular_market_open: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub regular_market_previous_close: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub regular_market_volume: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub market_state: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub day_high: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub day_low: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub open: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub previous_close: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub volume: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub all_time_high: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub all_time_low: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub pre_market_price: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub pre_market_change: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub pre_market_change_percent: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub pre_market_time: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub post_market_price: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub post_market_change: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub post_market_change_percent: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub post_market_time: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub average_daily_volume10_day: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub average_daily_volume3_month: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub average_volume: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub average_volume10days: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub market_cap: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub enterprise_value: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub enterprise_to_revenue: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub enterprise_to_ebitda: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub price_to_book: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub price_to_sales_trailing12_months: Option<F::Value<f64>>,
#[serde(rename = "forwardPE", skip_serializing_if = "Option::is_none")]
pub forward_pe: Option<F::Value<f64>>,
#[serde(rename = "trailingPE", skip_serializing_if = "Option::is_none")]
pub trailing_pe: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub beta: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub fifty_two_week_high: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub fifty_two_week_low: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub fifty_day_average: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub two_hundred_day_average: Option<F::Value<f64>>,
#[serde(rename = "52WeekChange", skip_serializing_if = "Option::is_none")]
pub week_52_change: Option<F::Value<f64>>,
#[serde(rename = "SandP52WeekChange", skip_serializing_if = "Option::is_none")]
pub sand_p_52_week_change: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub dividend_rate: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub dividend_yield: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub trailing_annual_dividend_rate: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub trailing_annual_dividend_yield: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub five_year_avg_dividend_yield: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ex_dividend_date: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub payout_ratio: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub last_dividend_value: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub last_dividend_date: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub bid: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub bid_size: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ask: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ask_size: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub shares_outstanding: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub float_shares: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub implied_shares_outstanding: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub held_percent_insiders: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub held_percent_institutions: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub shares_short: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub shares_short_prior_month: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub short_ratio: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub short_percent_of_float: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub shares_percent_shares_out: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub date_short_interest: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub current_price: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub target_high_price: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub target_low_price: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub target_mean_price: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub target_median_price: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub recommendation_mean: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub recommendation_key: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub number_of_analyst_opinions: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub total_cash: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub total_cash_per_share: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ebitda: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub total_debt: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub total_revenue: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub net_income_to_common: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub debt_to_equity: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub revenue_per_share: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub return_on_assets: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub return_on_equity: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub free_cashflow: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub operating_cashflow: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub profit_margins: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub gross_margins: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ebitda_margins: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub operating_margins: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub gross_profits: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub earnings_growth: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub revenue_growth: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub earnings_quarterly_growth: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub current_ratio: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub quick_ratio: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub trailing_eps: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub forward_eps: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub book_value: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sector: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sector_key: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sector_disp: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub industry: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub industry_key: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub industry_disp: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub long_business_summary: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub website: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ir_website: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub address1: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub city: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub state: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub zip: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub country: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub phone: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub full_time_employees: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub category: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub fund_family: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub audit_risk: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub board_risk: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub compensation_risk: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub shareholder_rights_risk: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub overall_risk: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub time_zone_full_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub time_zone_short_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub gmt_off_set_milliseconds: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub first_trade_date_epoch_utc: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub message_board_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub exchange_data_delayed_by: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub nav_price: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub total_assets: Option<F::Value<i64>>,
#[serde(rename = "yield", skip_serializing_if = "Option::is_none")]
pub yield_value: Option<F::Value<f64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub last_split_factor: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub last_split_date: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub last_fiscal_year_end: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub next_fiscal_year_end: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub most_recent_quarter: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub price_hint: Option<F::Value<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tradeable: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub financial_currency: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub company_officers: Option<Vec<super::CompanyOfficer>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub earnings: Option<Earnings>,
#[serde(skip_serializing_if = "Option::is_none")]
pub calendar_events: Option<CalendarEvents>,
#[serde(skip_serializing_if = "Option::is_none")]
pub recommendation_trend: Option<RecommendationTrend>,
#[serde(skip_serializing_if = "Option::is_none")]
pub upgrade_downgrade_history: Option<UpgradeDowngradeHistory>,
#[serde(skip_serializing_if = "Option::is_none")]
pub earnings_history: Option<EarningsHistory>,
#[serde(skip_serializing_if = "Option::is_none")]
pub earnings_trend: Option<EarningsTrend>,
#[serde(skip_serializing_if = "Option::is_none")]
pub insider_holders: Option<InsiderHolders>,
#[serde(skip_serializing_if = "Option::is_none")]
pub insider_transactions: Option<InsiderTransactions>,
#[serde(skip_serializing_if = "Option::is_none")]
pub institution_ownership: Option<InstitutionOwnership>,
#[serde(skip_serializing_if = "Option::is_none")]
pub fund_ownership: Option<FundOwnership>,
#[serde(skip_serializing_if = "Option::is_none")]
pub major_holders_breakdown: Option<MajorHoldersBreakdown>,
#[serde(skip_serializing_if = "Option::is_none")]
pub net_share_purchase_activity: Option<NetSharePurchaseActivity>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sec_filings: Option<SecFilings>,
#[serde(skip_serializing_if = "Option::is_none")]
pub balance_sheet_history: Option<BalanceSheetHistory>,
#[serde(skip_serializing_if = "Option::is_none")]
pub balance_sheet_history_quarterly: Option<BalanceSheetHistoryQuarterly>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cashflow_statement_history: Option<CashflowStatementHistory>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cashflow_statement_history_quarterly: Option<CashflowStatementHistoryQuarterly>,
#[serde(skip_serializing_if = "Option::is_none")]
pub income_statement_history: Option<IncomeStatementHistory>,
#[serde(skip_serializing_if = "Option::is_none")]
pub income_statement_history_quarterly: Option<IncomeStatementHistoryQuarterly>,
#[serde(skip_serializing_if = "Option::is_none")]
pub equity_performance: Option<EquityPerformance>,
#[serde(skip_serializing_if = "Option::is_none")]
pub index_trend: Option<IndexTrend>,
#[serde(skip_serializing_if = "Option::is_none")]
pub industry_trend: Option<IndustryTrend>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sector_trend: Option<SectorTrend>,
#[serde(skip_serializing_if = "Option::is_none")]
pub fund_profile: Option<FundProfile>,
#[serde(skip_serializing_if = "Option::is_none")]
pub fund_performance: Option<FundPerformance>,
#[serde(skip_serializing_if = "Option::is_none")]
pub top_holdings: Option<TopHoldings>,
}
impl Quote<Both> {
pub(crate) fn from_response(
response: &QuoteSummaryResponse,
logo_url: Option<String>,
company_logo_url: Option<String>,
) -> Self {
let price = response.price.as_ref();
let quote_type = response.quote_type.as_ref();
let summary_detail = response.summary_detail.as_ref();
let financial_data = response.financial_data.as_ref();
let key_stats = response.default_key_statistics.as_ref();
let asset_profile = response.asset_profile.as_ref();
let summary_profile = response.summary_profile.as_ref();
Self {
symbol: response.symbol.clone(),
logo_url,
company_logo_url,
short_name: price
.and_then(|p| p.short_name.clone())
.or_else(|| quote_type.and_then(|q| q.short_name.clone())),
long_name: price
.and_then(|p| p.long_name.clone())
.or_else(|| quote_type.and_then(|q| q.long_name.clone())),
exchange: price
.and_then(|p| p.exchange.clone())
.or_else(|| quote_type.and_then(|q| q.exchange.clone())),
exchange_name: price.and_then(|p| p.exchange_name.clone()),
quote_type: price
.and_then(|p| p.quote_type.clone())
.or_else(|| quote_type.and_then(|q| q.quote_type.clone())),
currency: price.and_then(|p| p.currency.clone()).or_else(|| {
summary_detail
.and_then(|s| s.currency.clone())
.or_else(|| financial_data.and_then(|f| f.financial_currency.clone()))
}),
currency_symbol: price.and_then(|p| p.currency_symbol.clone()),
underlying_symbol: price
.and_then(|p| p.underlying_symbol.clone())
.or_else(|| quote_type.and_then(|q| q.underlying_symbol.clone())),
from_currency: price
.and_then(|p| p.from_currency.clone())
.or_else(|| summary_detail.and_then(|s| s.from_currency.clone())),
to_currency: price
.and_then(|p| p.to_currency.clone())
.or_else(|| summary_detail.and_then(|s| s.to_currency.clone())),
regular_market_price: price.and_then(|p| p.regular_market_price.clone()),
regular_market_change: price.and_then(|p| p.regular_market_change.clone()),
regular_market_change_percent: price
.and_then(|p| p.regular_market_change_percent.clone()),
regular_market_time: price.and_then(|p| p.regular_market_time),
regular_market_day_high: price.and_then(|p| p.regular_market_day_high.clone()),
regular_market_day_low: price.and_then(|p| p.regular_market_day_low.clone()),
regular_market_open: price.and_then(|p| p.regular_market_open.clone()),
regular_market_previous_close: price
.and_then(|p| p.regular_market_previous_close.clone()),
regular_market_volume: price.and_then(|p| p.regular_market_volume.clone()),
market_state: price.and_then(|p| p.market_state.clone()),
day_high: summary_detail.and_then(|s| s.day_high.clone()),
day_low: summary_detail.and_then(|s| s.day_low.clone()),
open: summary_detail.and_then(|s| s.open.clone()),
previous_close: summary_detail.and_then(|s| s.previous_close.clone()),
volume: summary_detail.and_then(|s| s.volume.clone()),
all_time_high: summary_detail.and_then(|s| s.all_time_high.clone()),
all_time_low: summary_detail.and_then(|s| s.all_time_low.clone()),
pre_market_price: price.and_then(|p| p.pre_market_price.clone()),
pre_market_change: price.and_then(|p| p.pre_market_change.clone()),
pre_market_change_percent: price.and_then(|p| p.pre_market_change_percent.clone()),
pre_market_time: price.and_then(|p| p.pre_market_time),
post_market_price: price.and_then(|p| p.post_market_price.clone()),
post_market_change: price.and_then(|p| p.post_market_change.clone()),
post_market_change_percent: price.and_then(|p| p.post_market_change_percent.clone()),
post_market_time: price.and_then(|p| p.post_market_time),
average_daily_volume10_day: price
.and_then(|p| p.average_daily_volume10_day.clone())
.or_else(|| summary_detail.and_then(|s| s.average_daily_volume10_day.clone())),
average_daily_volume3_month: price.and_then(|p| p.average_daily_volume3_month.clone()),
average_volume: summary_detail.and_then(|s| s.average_volume.clone()),
average_volume10days: summary_detail.and_then(|s| s.average_volume10days.clone()),
market_cap: price.and_then(|p| p.market_cap.clone()),
enterprise_value: key_stats.and_then(|k| k.enterprise_value.clone()),
enterprise_to_revenue: key_stats.and_then(|k| k.enterprise_to_revenue.clone()),
enterprise_to_ebitda: key_stats.and_then(|k| k.enterprise_to_ebitda.clone()),
price_to_book: key_stats.and_then(|k| k.price_to_book.clone()),
price_to_sales_trailing12_months: summary_detail
.and_then(|s| s.price_to_sales_trailing12_months.clone()),
forward_pe: summary_detail
.and_then(|s| s.forward_pe.clone())
.or_else(|| key_stats.and_then(|k| k.forward_pe.clone())),
trailing_pe: summary_detail.and_then(|s| s.trailing_pe.clone()),
beta: summary_detail
.and_then(|s| s.beta.clone())
.or_else(|| key_stats.and_then(|k| k.beta.clone())),
fifty_two_week_high: summary_detail.and_then(|s| s.fifty_two_week_high.clone()),
fifty_two_week_low: summary_detail.and_then(|s| s.fifty_two_week_low.clone()),
fifty_day_average: summary_detail.and_then(|s| s.fifty_day_average.clone()),
two_hundred_day_average: summary_detail.and_then(|s| s.two_hundred_day_average.clone()),
week_52_change: key_stats.and_then(|k| k.week_52_change.clone()),
sand_p_52_week_change: key_stats.and_then(|k| k.sand_p_52_week_change.clone()),
dividend_rate: summary_detail.and_then(|s| s.dividend_rate.clone()),
dividend_yield: summary_detail.and_then(|s| s.dividend_yield.clone()),
trailing_annual_dividend_rate: summary_detail
.and_then(|s| s.trailing_annual_dividend_rate.clone()),
trailing_annual_dividend_yield: summary_detail
.and_then(|s| s.trailing_annual_dividend_yield.clone()),
five_year_avg_dividend_yield: summary_detail
.and_then(|s| s.five_year_avg_dividend_yield.clone()),
ex_dividend_date: summary_detail.and_then(|s| s.ex_dividend_date.clone()),
payout_ratio: summary_detail.and_then(|s| s.payout_ratio.clone()),
last_dividend_value: key_stats.and_then(|k| k.last_dividend_value.clone()),
last_dividend_date: key_stats.and_then(|k| k.last_dividend_date.clone()),
bid: summary_detail.and_then(|s| s.bid.clone()),
bid_size: summary_detail.and_then(|s| s.bid_size.clone()),
ask: summary_detail.and_then(|s| s.ask.clone()),
ask_size: summary_detail.and_then(|s| s.ask_size.clone()),
shares_outstanding: key_stats.and_then(|k| k.shares_outstanding.clone()),
float_shares: key_stats.and_then(|k| k.float_shares.clone()),
implied_shares_outstanding: key_stats
.and_then(|k| k.implied_shares_outstanding.clone()),
held_percent_insiders: key_stats.and_then(|k| k.held_percent_insiders.clone()),
held_percent_institutions: key_stats.and_then(|k| k.held_percent_institutions.clone()),
shares_short: key_stats.and_then(|k| k.shares_short.clone()),
shares_short_prior_month: key_stats.and_then(|k| k.shares_short_prior_month.clone()),
short_ratio: key_stats.and_then(|k| k.short_ratio.clone()),
short_percent_of_float: key_stats.and_then(|k| k.short_percent_of_float.clone()),
shares_percent_shares_out: key_stats.and_then(|k| k.shares_percent_shares_out.clone()),
date_short_interest: key_stats.and_then(|k| k.date_short_interest.clone()),
current_price: financial_data.and_then(|f| f.current_price.clone()),
target_high_price: financial_data.and_then(|f| f.target_high_price.clone()),
target_low_price: financial_data.and_then(|f| f.target_low_price.clone()),
target_mean_price: financial_data.and_then(|f| f.target_mean_price.clone()),
target_median_price: financial_data.and_then(|f| f.target_median_price.clone()),
recommendation_mean: financial_data.and_then(|f| f.recommendation_mean.clone()),
recommendation_key: financial_data.and_then(|f| f.recommendation_key.clone()),
number_of_analyst_opinions: financial_data
.and_then(|f| f.number_of_analyst_opinions.clone()),
total_cash: financial_data.and_then(|f| f.total_cash.clone()),
total_cash_per_share: financial_data.and_then(|f| f.total_cash_per_share.clone()),
ebitda: financial_data.and_then(|f| f.ebitda.clone()),
total_debt: financial_data.and_then(|f| f.total_debt.clone()),
total_revenue: financial_data.and_then(|f| f.total_revenue.clone()),
net_income_to_common: key_stats.and_then(|k| k.net_income_to_common.clone()),
debt_to_equity: financial_data.and_then(|f| f.debt_to_equity.clone()),
revenue_per_share: financial_data.and_then(|f| f.revenue_per_share.clone()),
return_on_assets: financial_data.and_then(|f| f.return_on_assets.clone()),
return_on_equity: financial_data.and_then(|f| f.return_on_equity.clone()),
free_cashflow: financial_data.and_then(|f| f.free_cashflow.clone()),
operating_cashflow: financial_data.and_then(|f| f.operating_cashflow.clone()),
profit_margins: financial_data.and_then(|f| f.profit_margins.clone()),
gross_margins: financial_data.and_then(|f| f.gross_margins.clone()),
ebitda_margins: financial_data.and_then(|f| f.ebitda_margins.clone()),
operating_margins: financial_data.and_then(|f| f.operating_margins.clone()),
gross_profits: financial_data.and_then(|f| f.gross_profits.clone()),
earnings_growth: financial_data.and_then(|f| f.earnings_growth.clone()),
revenue_growth: financial_data.and_then(|f| f.revenue_growth.clone()),
earnings_quarterly_growth: key_stats.and_then(|k| k.earnings_quarterly_growth.clone()),
current_ratio: financial_data.and_then(|f| f.current_ratio.clone()),
quick_ratio: financial_data.and_then(|f| f.quick_ratio.clone()),
trailing_eps: key_stats.and_then(|k| k.trailing_eps.clone()),
forward_eps: key_stats.and_then(|k| k.forward_eps.clone()),
book_value: key_stats.and_then(|k| k.book_value.clone()),
sector: asset_profile
.and_then(|a| a.sector.clone())
.or_else(|| summary_profile.and_then(|s| s.sector.clone())),
sector_key: asset_profile.and_then(|a| a.sector_key.clone()),
sector_disp: asset_profile.and_then(|a| a.sector_disp.clone()),
industry: asset_profile
.and_then(|a| a.industry.clone())
.or_else(|| summary_profile.and_then(|s| s.industry.clone())),
industry_key: asset_profile.and_then(|a| a.industry_key.clone()),
industry_disp: asset_profile.and_then(|a| a.industry_disp.clone()),
long_business_summary: asset_profile
.and_then(|a| a.long_business_summary.clone())
.or_else(|| summary_profile.and_then(|s| s.long_business_summary.clone())),
address1: asset_profile
.and_then(|a| a.address1.clone())
.or_else(|| summary_profile.and_then(|s| s.address1.clone())),
city: asset_profile
.and_then(|a| a.city.clone())
.or_else(|| summary_profile.and_then(|s| s.city.clone())),
state: asset_profile
.and_then(|a| a.state.clone())
.or_else(|| summary_profile.and_then(|s| s.state.clone())),
zip: asset_profile
.and_then(|a| a.zip.clone())
.or_else(|| summary_profile.and_then(|s| s.zip.clone())),
country: asset_profile
.and_then(|a| a.country.clone())
.or_else(|| summary_profile.and_then(|s| s.country.clone())),
phone: asset_profile
.and_then(|a| a.phone.clone())
.or_else(|| summary_profile.and_then(|s| s.phone.clone())),
full_time_employees: asset_profile
.and_then(|a| a.full_time_employees)
.or_else(|| summary_profile.and_then(|s| s.full_time_employees)),
website: asset_profile
.and_then(|a| a.website.clone())
.or_else(|| summary_profile.and_then(|s| s.website.clone())),
ir_website: summary_profile.and_then(|s| s.ir_website.clone()),
category: key_stats.and_then(|k| k.category.clone()),
fund_family: key_stats.and_then(|k| k.fund_family.clone()),
audit_risk: asset_profile.and_then(|a| a.audit_risk),
board_risk: asset_profile.and_then(|a| a.board_risk),
compensation_risk: asset_profile.and_then(|a| a.compensation_risk),
shareholder_rights_risk: asset_profile.and_then(|a| a.shareholder_rights_risk),
overall_risk: asset_profile.and_then(|a| a.overall_risk),
time_zone_full_name: quote_type.and_then(|q| q.time_zone_full_name.clone()),
time_zone_short_name: quote_type.and_then(|q| q.time_zone_short_name.clone()),
gmt_off_set_milliseconds: quote_type.and_then(|q| q.gmt_off_set_milliseconds),
first_trade_date_epoch_utc: quote_type.and_then(|q| q.first_trade_date_epoch_utc),
message_board_id: quote_type.and_then(|q| q.message_board_id.clone()),
exchange_data_delayed_by: price.and_then(|p| p.exchange_data_delayed_by),
nav_price: summary_detail.and_then(|s| s.nav_price.clone()),
total_assets: summary_detail.and_then(|s| s.total_assets.clone()),
yield_value: summary_detail.and_then(|s| s.yield_value.clone()),
last_split_factor: key_stats.and_then(|k| k.last_split_factor.clone()),
last_split_date: key_stats.and_then(|k| k.last_split_date.clone()),
last_fiscal_year_end: key_stats.and_then(|k| k.last_fiscal_year_end.clone()),
next_fiscal_year_end: key_stats.and_then(|k| k.next_fiscal_year_end.clone()),
most_recent_quarter: key_stats.and_then(|k| k.most_recent_quarter.clone()),
price_hint: price.and_then(|p| p.price_hint.clone()),
tradeable: summary_detail.and_then(|s| s.tradeable),
financial_currency: financial_data.and_then(|f| f.financial_currency.clone()),
company_officers: asset_profile.map(|a| a.company_officers.clone()),
earnings: response.earnings.clone(),
calendar_events: response.calendar_events.clone(),
recommendation_trend: response.recommendation_trend.clone(),
upgrade_downgrade_history: response.upgrade_downgrade_history.clone(),
earnings_history: response.earnings_history.clone(),
earnings_trend: response.earnings_trend.clone(),
insider_holders: response.insider_holders.clone(),
insider_transactions: response.insider_transactions.clone(),
institution_ownership: response.institution_ownership.clone(),
fund_ownership: response.fund_ownership.clone(),
major_holders_breakdown: response.major_holders_breakdown.clone(),
net_share_purchase_activity: response.net_share_purchase_activity.clone(),
sec_filings: response.sec_filings.clone(),
balance_sheet_history: None,
balance_sheet_history_quarterly: None,
cashflow_statement_history: None,
cashflow_statement_history_quarterly: None,
income_statement_history: None,
income_statement_history_quarterly: None,
equity_performance: response.equity_performance.clone(),
index_trend: response.index_trend.clone(),
industry_trend: response.industry_trend.clone(),
sector_trend: response.sector_trend.clone(),
fund_profile: response.fund_profile.clone(),
fund_performance: response.fund_performance.clone(),
top_holdings: response.top_holdings.clone(),
}
}
pub fn live_price(&self) -> Option<f64> {
if self.market_state.as_deref() == Some("POST") {
self.post_market_price
.as_ref()
.and_then(|p| p.raw)
.or_else(|| self.regular_market_price.as_ref()?.raw)
} else if self.market_state.as_deref() == Some("PRE") {
self.pre_market_price
.as_ref()
.and_then(|p| p.raw)
.or_else(|| self.regular_market_price.as_ref()?.raw)
} else {
self.regular_market_price.as_ref()?.raw
}
}
pub fn day_range(&self) -> Option<(f64, f64)> {
let low = self.regular_market_day_low.as_ref()?.raw?;
let high = self.regular_market_day_high.as_ref()?.raw?;
Some((low, high))
}
pub fn week_52_range(&self) -> Option<(f64, f64)> {
let low = self.fifty_two_week_low.as_ref()?.raw?;
let high = self.fifty_two_week_high.as_ref()?.raw?;
Some((low, high))
}
pub fn is_market_open(&self) -> bool {
self.market_state.as_deref() == Some("REGULAR")
}
pub fn is_pre_market(&self) -> bool {
self.market_state.as_deref() == Some("PRE")
}
pub fn is_post_market(&self) -> bool {
self.market_state.as_deref() == Some("POST")
}
}