1use serde::{Deserialize, Serialize};
2
3pub mod screener_types {
5 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10 pub enum ScreenerType {
11 AggressiveSmallCaps,
14 DayGainers,
16 DayLosers,
18 GrowthTechnologyStocks,
20 MostActives,
22 MostShortedStocks,
24 SmallCapGainers,
26 UndervaluedGrowthStocks,
28 UndervaluedLargeCaps,
30 ConservativeForeignFunds,
33 HighYieldBond,
35 PortfolioAnchors,
37 SolidLargeGrowthFunds,
39 SolidMidcapGrowthFunds,
41 TopMutualFunds,
43 }
44
45 impl ScreenerType {
46 pub fn as_scr_id(&self) -> &'static str {
48 match self {
49 ScreenerType::AggressiveSmallCaps => "aggressive_small_caps",
50 ScreenerType::DayGainers => "day_gainers",
51 ScreenerType::DayLosers => "day_losers",
52 ScreenerType::GrowthTechnologyStocks => "growth_technology_stocks",
53 ScreenerType::MostActives => "most_actives",
54 ScreenerType::MostShortedStocks => "most_shorted_stocks",
55 ScreenerType::SmallCapGainers => "small_cap_gainers",
56 ScreenerType::UndervaluedGrowthStocks => "undervalued_growth_stocks",
57 ScreenerType::UndervaluedLargeCaps => "undervalued_large_caps",
58 ScreenerType::ConservativeForeignFunds => "conservative_foreign_funds",
59 ScreenerType::HighYieldBond => "high_yield_bond",
60 ScreenerType::PortfolioAnchors => "portfolio_anchors",
61 ScreenerType::SolidLargeGrowthFunds => "solid_large_growth_funds",
62 ScreenerType::SolidMidcapGrowthFunds => "solid_midcap_growth_funds",
63 ScreenerType::TopMutualFunds => "top_mutual_funds",
64 }
65 }
66
67 pub fn parse(s: &str) -> Option<Self> {
77 s.parse().ok()
78 }
79
80 pub fn valid_types() -> &'static str {
82 "aggressive-small-caps, day-gainers, day-losers, growth-technology-stocks, \
83 most-actives, most-shorted-stocks, small-cap-gainers, undervalued-growth-stocks, \
84 undervalued-large-caps, conservative-foreign-funds, high-yield-bond, \
85 portfolio-anchors, solid-large-growth-funds, solid-midcap-growth-funds, \
86 top-mutual-funds"
87 }
88
89 pub fn all() -> &'static [ScreenerType] {
91 &[
92 ScreenerType::AggressiveSmallCaps,
93 ScreenerType::DayGainers,
94 ScreenerType::DayLosers,
95 ScreenerType::GrowthTechnologyStocks,
96 ScreenerType::MostActives,
97 ScreenerType::MostShortedStocks,
98 ScreenerType::SmallCapGainers,
99 ScreenerType::UndervaluedGrowthStocks,
100 ScreenerType::UndervaluedLargeCaps,
101 ScreenerType::ConservativeForeignFunds,
102 ScreenerType::HighYieldBond,
103 ScreenerType::PortfolioAnchors,
104 ScreenerType::SolidLargeGrowthFunds,
105 ScreenerType::SolidMidcapGrowthFunds,
106 ScreenerType::TopMutualFunds,
107 ]
108 }
109 }
110
111 impl std::str::FromStr for ScreenerType {
112 type Err = ();
113
114 fn from_str(s: &str) -> Result<Self, Self::Err> {
115 match s.to_lowercase().replace('_', "-").as_str() {
116 "aggressive-small-caps" => Ok(ScreenerType::AggressiveSmallCaps),
117 "day-gainers" | "gainers" => Ok(ScreenerType::DayGainers),
118 "day-losers" | "losers" => Ok(ScreenerType::DayLosers),
119 "growth-technology-stocks" | "growth-tech" => {
120 Ok(ScreenerType::GrowthTechnologyStocks)
121 }
122 "most-actives" | "actives" => Ok(ScreenerType::MostActives),
123 "most-shorted-stocks" | "most-shorted" => Ok(ScreenerType::MostShortedStocks),
124 "small-cap-gainers" => Ok(ScreenerType::SmallCapGainers),
125 "undervalued-growth-stocks" | "undervalued-growth" => {
126 Ok(ScreenerType::UndervaluedGrowthStocks)
127 }
128 "undervalued-large-caps" | "undervalued-large" => {
129 Ok(ScreenerType::UndervaluedLargeCaps)
130 }
131 "conservative-foreign-funds" => Ok(ScreenerType::ConservativeForeignFunds),
132 "high-yield-bond" => Ok(ScreenerType::HighYieldBond),
133 "portfolio-anchors" => Ok(ScreenerType::PortfolioAnchors),
134 "solid-large-growth-funds" => Ok(ScreenerType::SolidLargeGrowthFunds),
135 "solid-midcap-growth-funds" => Ok(ScreenerType::SolidMidcapGrowthFunds),
136 "top-mutual-funds" => Ok(ScreenerType::TopMutualFunds),
137 _ => Err(()),
138 }
139 }
140 }
141}
142
143pub mod sector_types {
147 use serde::{Deserialize, Serialize};
148
149 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
151 #[serde(rename_all = "kebab-case")]
152 pub enum SectorType {
153 Technology,
155 FinancialServices,
157 ConsumerCyclical,
159 CommunicationServices,
161 Healthcare,
163 Industrials,
165 ConsumerDefensive,
167 Energy,
169 BasicMaterials,
171 RealEstate,
173 Utilities,
175 }
176
177 impl SectorType {
178 pub fn as_api_path(&self) -> &'static str {
180 match self {
181 SectorType::Technology => "technology",
182 SectorType::FinancialServices => "financial-services",
183 SectorType::ConsumerCyclical => "consumer-cyclical",
184 SectorType::CommunicationServices => "communication-services",
185 SectorType::Healthcare => "healthcare",
186 SectorType::Industrials => "industrials",
187 SectorType::ConsumerDefensive => "consumer-defensive",
188 SectorType::Energy => "energy",
189 SectorType::BasicMaterials => "basic-materials",
190 SectorType::RealEstate => "real-estate",
191 SectorType::Utilities => "utilities",
192 }
193 }
194
195 pub fn display_name(&self) -> &'static str {
197 match self {
198 SectorType::Technology => "Technology",
199 SectorType::FinancialServices => "Financial Services",
200 SectorType::ConsumerCyclical => "Consumer Cyclical",
201 SectorType::CommunicationServices => "Communication Services",
202 SectorType::Healthcare => "Healthcare",
203 SectorType::Industrials => "Industrials",
204 SectorType::ConsumerDefensive => "Consumer Defensive",
205 SectorType::Energy => "Energy",
206 SectorType::BasicMaterials => "Basic Materials",
207 SectorType::RealEstate => "Real Estate",
208 SectorType::Utilities => "Utilities",
209 }
210 }
211
212 pub fn valid_types() -> &'static str {
214 "technology, financial-services, consumer-cyclical, communication-services, \
215 healthcare, industrials, consumer-defensive, energy, basic-materials, \
216 real-estate, utilities"
217 }
218
219 pub fn all() -> &'static [SectorType] {
221 &[
222 SectorType::Technology,
223 SectorType::FinancialServices,
224 SectorType::ConsumerCyclical,
225 SectorType::CommunicationServices,
226 SectorType::Healthcare,
227 SectorType::Industrials,
228 SectorType::ConsumerDefensive,
229 SectorType::Energy,
230 SectorType::BasicMaterials,
231 SectorType::RealEstate,
232 SectorType::Utilities,
233 ]
234 }
235 }
236
237 impl std::str::FromStr for SectorType {
238 type Err = ();
239
240 fn from_str(s: &str) -> Result<Self, Self::Err> {
241 match s.to_lowercase().replace('_', "-").as_str() {
242 "technology" | "tech" => Ok(SectorType::Technology),
243 "financial-services" | "financials" | "financial" => {
244 Ok(SectorType::FinancialServices)
245 }
246 "consumer-cyclical" => Ok(SectorType::ConsumerCyclical),
247 "communication-services" | "communication" => Ok(SectorType::CommunicationServices),
248 "healthcare" | "health" => Ok(SectorType::Healthcare),
249 "industrials" | "industrial" => Ok(SectorType::Industrials),
250 "consumer-defensive" => Ok(SectorType::ConsumerDefensive),
251 "energy" => Ok(SectorType::Energy),
252 "basic-materials" | "materials" => Ok(SectorType::BasicMaterials),
253 "real-estate" | "realestate" => Ok(SectorType::RealEstate),
254 "utilities" | "utility" => Ok(SectorType::Utilities),
255 _ => Err(()),
256 }
257 }
258 }
259
260 impl std::fmt::Display for SectorType {
261 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
262 write!(f, "{}", self.display_name())
263 }
264 }
265}
266
267pub mod screener_query {
271 use serde::{Deserialize, Serialize};
272
273 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
277 #[serde(rename_all = "UPPERCASE")]
278 pub enum QuoteType {
279 #[default]
281 #[serde(rename = "EQUITY")]
282 Equity,
283 #[serde(rename = "MUTUALFUND")]
285 MutualFund,
286 }
287
288 impl QuoteType {
289 pub fn valid_types() -> &'static str {
291 "equity, mutualfund"
292 }
293 }
294
295 impl std::str::FromStr for QuoteType {
296 type Err = ();
297
298 fn from_str(s: &str) -> Result<Self, Self::Err> {
299 match s.to_lowercase().replace(['-', '_'], "").as_str() {
300 "equity" | "stock" | "stocks" => Ok(QuoteType::Equity),
301 "mutualfund" | "fund" | "funds" => Ok(QuoteType::MutualFund),
302 _ => Err(()),
303 }
304 }
305 }
306
307 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
309 #[serde(rename_all = "UPPERCASE")]
310 pub enum SortType {
311 #[serde(rename = "ASC")]
313 Asc,
314 #[default]
316 #[serde(rename = "DESC")]
317 Desc,
318 }
319
320 impl std::str::FromStr for SortType {
321 type Err = ();
322
323 fn from_str(s: &str) -> Result<Self, Self::Err> {
324 match s.to_lowercase().as_str() {
325 "asc" | "ascending" => Ok(SortType::Asc),
326 "desc" | "descending" => Ok(SortType::Desc),
327 _ => Err(()),
328 }
329 }
330 }
331
332 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
334 #[serde(rename_all = "lowercase")]
335 pub enum Operator {
336 #[serde(rename = "eq")]
338 Eq,
339 #[serde(rename = "gt")]
341 Gt,
342 #[serde(rename = "gte")]
344 Gte,
345 #[serde(rename = "lt")]
347 Lt,
348 #[serde(rename = "lte")]
350 Lte,
351 #[serde(rename = "btwn")]
353 Between,
354 }
355
356 impl std::str::FromStr for Operator {
357 type Err = ();
358
359 fn from_str(s: &str) -> Result<Self, Self::Err> {
360 match s.to_lowercase().as_str() {
361 "eq" | "=" | "==" => Ok(Operator::Eq),
362 "gt" | ">" => Ok(Operator::Gt),
363 "gte" | ">=" => Ok(Operator::Gte),
364 "lt" | "<" => Ok(Operator::Lt),
365 "lte" | "<=" => Ok(Operator::Lte),
366 "btwn" | "between" => Ok(Operator::Between),
367 _ => Err(()),
368 }
369 }
370 }
371
372 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
374 #[serde(rename_all = "lowercase")]
375 pub enum LogicalOperator {
376 #[default]
378 And,
379 Or,
381 }
382
383 impl std::str::FromStr for LogicalOperator {
384 type Err = ();
385
386 fn from_str(s: &str) -> Result<Self, Self::Err> {
387 match s.to_lowercase().as_str() {
388 "and" | "&&" => Ok(LogicalOperator::And),
389 "or" | "||" => Ok(LogicalOperator::Or),
390 _ => Err(()),
391 }
392 }
393 }
394
395 #[allow(missing_docs)]
399 pub mod equity_fields {
400 pub const EOD_PRICE: &str = "eodprice";
402 pub const INTRADAY_PRICE_CHANGE: &str = "intradaypricechange";
403 pub const INTRADAY_PRICE: &str = "intradayprice";
404 pub const PERCENT_CHANGE: &str = "percentchange";
405 pub const LASTCLOSE_52WK_HIGH: &str = "lastclose52weekhigh.lasttwelvemonths";
406 pub const FIFTY_TWO_WK_PCT_CHANGE: &str = "fiftytwowkpercentchange";
407 pub const LASTCLOSE_52WK_LOW: &str = "lastclose52weeklow.lasttwelvemonths";
408 pub const INTRADAY_MARKET_CAP: &str = "intradaymarketcap";
409 pub const LASTCLOSE_MARKET_CAP: &str = "lastclosemarketcap.lasttwelvemonths";
410
411 pub const REGION: &str = "region";
413 pub const SECTOR: &str = "sector";
414 pub const PEER_GROUP: &str = "peer_group";
415 pub const INDUSTRY: &str = "industry";
416 pub const EXCHANGE: &str = "exchange";
417
418 pub const BETA: &str = "beta";
420 pub const AVG_DAILY_VOL_3M: &str = "avgdailyvol3m";
421 pub const PCT_HELD_INSIDER: &str = "pctheldinsider";
422 pub const PCT_HELD_INST: &str = "pctheldinst";
423 pub const DAY_VOLUME: &str = "dayvolume";
424 pub const EOD_VOLUME: &str = "eodvolume";
425
426 pub const SHORT_PCT_SHARES_OUT: &str = "short_percentage_of_shares_outstanding.value";
428 pub const SHORT_INTEREST: &str = "short_interest.value";
429 pub const SHORT_PCT_FLOAT: &str = "short_percentage_of_float.value";
430 pub const DAYS_TO_COVER: &str = "days_to_cover_short.value";
431 pub const SHORT_INTEREST_PCT_CHANGE: &str = "short_interest_percentage_change.value";
432
433 pub const BOOK_VALUE_SHARE: &str = "bookvalueshare.lasttwelvemonths";
435 pub const MARKET_CAP_TO_REVENUE: &str = "lastclosemarketcaptotalrevenue.lasttwelvemonths";
436 pub const TEV_TO_REVENUE: &str = "lastclosetevtotalrevenue.lasttwelvemonths";
437 pub const PRICE_BOOK_RATIO: &str = "pricebookratio.quarterly";
438 pub const PE_RATIO: &str = "peratio.lasttwelvemonths";
439 pub const PRICE_TANGIBLE_BOOK: &str = "lastclosepricetangiblebookvalue.lasttwelvemonths";
440 pub const PRICE_EARNINGS: &str = "lastclosepriceearnings.lasttwelvemonths";
441 pub const PEG_RATIO_5Y: &str = "pegratio_5y";
442
443 pub const CONSECUTIVE_DIV_YEARS: &str = "consecutive_years_of_dividend_growth_count";
445 pub const ROA: &str = "returnonassets.lasttwelvemonths";
446 pub const ROE: &str = "returnonequity.lasttwelvemonths";
447 pub const FORWARD_DIV_PER_SHARE: &str = "forward_dividend_per_share";
448 pub const FORWARD_DIV_YIELD: &str = "forward_dividend_yield";
449 pub const RETURN_ON_CAPITAL: &str = "returnontotalcapital.lasttwelvemonths";
450
451 pub const TEV_EBIT: &str = "lastclosetevebit.lasttwelvemonths";
453 pub const NET_DEBT_EBITDA: &str = "netdebtebitda.lasttwelvemonths";
454 pub const TOTAL_DEBT_EQUITY: &str = "totaldebtequity.lasttwelvemonths";
455 pub const LT_DEBT_EQUITY: &str = "ltdebtequity.lasttwelvemonths";
456 pub const EBIT_INTEREST_EXP: &str = "ebitinterestexpense.lasttwelvemonths";
457 pub const EBITDA_INTEREST_EXP: &str = "ebitdainterestexpense.lasttwelvemonths";
458 pub const TEV_EBITDA: &str = "lastclosetevebitda.lasttwelvemonths";
459 pub const TOTAL_DEBT_EBITDA: &str = "totaldebtebitda.lasttwelvemonths";
460
461 pub const QUICK_RATIO: &str = "quickratio.lasttwelvemonths";
463 pub const ALTMAN_Z_SCORE: &str =
464 "altmanzscoreusingtheaveragestockinformationforaperiod.lasttwelvemonths";
465 pub const CURRENT_RATIO: &str = "currentratio.lasttwelvemonths";
466 pub const OCF_TO_CURRENT_LIAB: &str =
467 "operatingcashflowtocurrentliabilities.lasttwelvemonths";
468
469 pub const TOTAL_REVENUES: &str = "totalrevenues.lasttwelvemonths";
471 pub const NET_INCOME_MARGIN: &str = "netincomemargin.lasttwelvemonths";
472 pub const GROSS_PROFIT: &str = "grossprofit.lasttwelvemonths";
473 pub const EBITDA_1YR_GROWTH: &str = "ebitda1yrgrowth.lasttwelvemonths";
474 pub const DILUTED_EPS_CONT_OPS: &str = "dilutedepscontinuingoperations.lasttwelvemonths";
475 pub const QUARTERLY_REV_GROWTH: &str = "quarterlyrevenuegrowth.quarterly";
476 pub const EPS_GROWTH: &str = "epsgrowth.lasttwelvemonths";
477 pub const NET_INCOME: &str = "netincomeis.lasttwelvemonths";
478 pub const EBITDA: &str = "ebitda.lasttwelvemonths";
479 pub const DILUTED_EPS_1YR_GROWTH: &str = "dilutedeps1yrgrowth.lasttwelvemonths";
480 pub const REVENUE_1YR_GROWTH: &str = "totalrevenues1yrgrowth.lasttwelvemonths";
481 pub const OPERATING_INCOME: &str = "operatingincome.lasttwelvemonths";
482 pub const NET_INCOME_1YR_GROWTH: &str = "netincome1yrgrowth.lasttwelvemonths";
483 pub const GROSS_PROFIT_MARGIN: &str = "grossprofitmargin.lasttwelvemonths";
484 pub const EBITDA_MARGIN: &str = "ebitdamargin.lasttwelvemonths";
485 pub const EBIT: &str = "ebit.lasttwelvemonths";
486 pub const BASIC_EPS_CONT_OPS: &str = "basicepscontinuingoperations.lasttwelvemonths";
487 pub const NET_EPS_BASIC: &str = "netepsbasic.lasttwelvemonths";
488 pub const NET_EPS_DILUTED: &str = "netepsdiluted.lasttwelvemonths";
489
490 pub const TOTAL_ASSETS: &str = "totalassets.lasttwelvemonths";
492 pub const COMMON_SHARES_OUT: &str = "totalcommonsharesoutstanding.lasttwelvemonths";
493 pub const TOTAL_DEBT: &str = "totaldebt.lasttwelvemonths";
494 pub const TOTAL_EQUITY: &str = "totalequity.lasttwelvemonths";
495 pub const TOTAL_CURRENT_ASSETS: &str = "totalcurrentassets.lasttwelvemonths";
496 pub const CASH_AND_ST_INVESTMENTS: &str =
497 "totalcashandshortterminvestments.lasttwelvemonths";
498 pub const TOTAL_COMMON_EQUITY: &str = "totalcommonequity.lasttwelvemonths";
499 pub const TOTAL_CURRENT_LIAB: &str = "totalcurrentliabilities.lasttwelvemonths";
500 pub const TOTAL_SHARES_OUT: &str = "totalsharesoutstanding";
501
502 pub const LEVERED_FCF: &str = "leveredfreecashflow.lasttwelvemonths";
504 pub const CAPEX: &str = "capitalexpenditure.lasttwelvemonths";
505 pub const CASH_FROM_OPS: &str = "cashfromoperations.lasttwelvemonths";
506 pub const LEVERED_FCF_1YR_GROWTH: &str = "leveredfreecashflow1yrgrowth.lasttwelvemonths";
507 pub const UNLEVERED_FCF: &str = "unleveredfreecashflow.lasttwelvemonths";
508 pub const CASH_FROM_OPS_1YR_GROWTH: &str = "cashfromoperations1yrgrowth.lasttwelvemonths";
509
510 pub const ESG_SCORE: &str = "esg_score";
512 pub const ENVIRONMENTAL_SCORE: &str = "environmental_score";
513 pub const GOVERNANCE_SCORE: &str = "governance_score";
514 pub const SOCIAL_SCORE: &str = "social_score";
515 pub const HIGHEST_CONTROVERSY: &str = "highest_controversy";
516 }
517
518 #[allow(missing_docs)]
520 pub mod fund_fields {
521 pub const EOD_PRICE: &str = "eodprice";
523 pub const INTRADAY_PRICE_CHANGE: &str = "intradaypricechange";
524 pub const INTRADAY_PRICE: &str = "intradayprice";
525
526 pub const CATEGORY_NAME: &str = "categoryname";
528 pub const PERFORMANCE_RATING: &str = "performanceratingoverall";
529 pub const INITIAL_INVESTMENT: &str = "initialinvestment";
530 pub const ANNUAL_RETURN_RANK: &str = "annualreturnnavy1categoryrank";
531 pub const RISK_RATING: &str = "riskratingoverall";
532 pub const EXCHANGE: &str = "exchange";
533 }
534
535 pub const VALID_EQUITY_FIELDS: &[&str] = &[
537 equity_fields::EOD_PRICE,
538 equity_fields::INTRADAY_PRICE_CHANGE,
539 equity_fields::INTRADAY_PRICE,
540 equity_fields::PERCENT_CHANGE,
541 equity_fields::LASTCLOSE_52WK_HIGH,
542 equity_fields::FIFTY_TWO_WK_PCT_CHANGE,
543 equity_fields::LASTCLOSE_52WK_LOW,
544 equity_fields::INTRADAY_MARKET_CAP,
545 equity_fields::LASTCLOSE_MARKET_CAP,
546 equity_fields::REGION,
547 equity_fields::SECTOR,
548 equity_fields::PEER_GROUP,
549 equity_fields::INDUSTRY,
550 equity_fields::EXCHANGE,
551 equity_fields::BETA,
552 equity_fields::AVG_DAILY_VOL_3M,
553 equity_fields::PCT_HELD_INSIDER,
554 equity_fields::PCT_HELD_INST,
555 equity_fields::DAY_VOLUME,
556 equity_fields::EOD_VOLUME,
557 equity_fields::SHORT_PCT_SHARES_OUT,
558 equity_fields::SHORT_INTEREST,
559 equity_fields::SHORT_PCT_FLOAT,
560 equity_fields::DAYS_TO_COVER,
561 equity_fields::SHORT_INTEREST_PCT_CHANGE,
562 equity_fields::BOOK_VALUE_SHARE,
563 equity_fields::MARKET_CAP_TO_REVENUE,
564 equity_fields::TEV_TO_REVENUE,
565 equity_fields::PRICE_BOOK_RATIO,
566 equity_fields::PE_RATIO,
567 equity_fields::PRICE_TANGIBLE_BOOK,
568 equity_fields::PRICE_EARNINGS,
569 equity_fields::PEG_RATIO_5Y,
570 equity_fields::CONSECUTIVE_DIV_YEARS,
571 equity_fields::ROA,
572 equity_fields::ROE,
573 equity_fields::FORWARD_DIV_PER_SHARE,
574 equity_fields::FORWARD_DIV_YIELD,
575 equity_fields::RETURN_ON_CAPITAL,
576 equity_fields::TEV_EBIT,
577 equity_fields::NET_DEBT_EBITDA,
578 equity_fields::TOTAL_DEBT_EQUITY,
579 equity_fields::LT_DEBT_EQUITY,
580 equity_fields::EBIT_INTEREST_EXP,
581 equity_fields::EBITDA_INTEREST_EXP,
582 equity_fields::TEV_EBITDA,
583 equity_fields::TOTAL_DEBT_EBITDA,
584 equity_fields::QUICK_RATIO,
585 equity_fields::ALTMAN_Z_SCORE,
586 equity_fields::CURRENT_RATIO,
587 equity_fields::OCF_TO_CURRENT_LIAB,
588 equity_fields::TOTAL_REVENUES,
589 equity_fields::NET_INCOME_MARGIN,
590 equity_fields::GROSS_PROFIT,
591 equity_fields::EBITDA_1YR_GROWTH,
592 equity_fields::DILUTED_EPS_CONT_OPS,
593 equity_fields::QUARTERLY_REV_GROWTH,
594 equity_fields::EPS_GROWTH,
595 equity_fields::NET_INCOME,
596 equity_fields::EBITDA,
597 equity_fields::DILUTED_EPS_1YR_GROWTH,
598 equity_fields::REVENUE_1YR_GROWTH,
599 equity_fields::OPERATING_INCOME,
600 equity_fields::NET_INCOME_1YR_GROWTH,
601 equity_fields::GROSS_PROFIT_MARGIN,
602 equity_fields::EBITDA_MARGIN,
603 equity_fields::EBIT,
604 equity_fields::BASIC_EPS_CONT_OPS,
605 equity_fields::NET_EPS_BASIC,
606 equity_fields::NET_EPS_DILUTED,
607 equity_fields::TOTAL_ASSETS,
608 equity_fields::COMMON_SHARES_OUT,
609 equity_fields::TOTAL_DEBT,
610 equity_fields::TOTAL_EQUITY,
611 equity_fields::TOTAL_CURRENT_ASSETS,
612 equity_fields::CASH_AND_ST_INVESTMENTS,
613 equity_fields::TOTAL_COMMON_EQUITY,
614 equity_fields::TOTAL_CURRENT_LIAB,
615 equity_fields::TOTAL_SHARES_OUT,
616 equity_fields::LEVERED_FCF,
617 equity_fields::CAPEX,
618 equity_fields::CASH_FROM_OPS,
619 equity_fields::LEVERED_FCF_1YR_GROWTH,
620 equity_fields::UNLEVERED_FCF,
621 equity_fields::CASH_FROM_OPS_1YR_GROWTH,
622 equity_fields::ESG_SCORE,
623 equity_fields::ENVIRONMENTAL_SCORE,
624 equity_fields::GOVERNANCE_SCORE,
625 equity_fields::SOCIAL_SCORE,
626 equity_fields::HIGHEST_CONTROVERSY,
627 ];
628
629 pub const VALID_FUND_FIELDS: &[&str] = &[
631 fund_fields::EOD_PRICE,
632 fund_fields::INTRADAY_PRICE_CHANGE,
633 fund_fields::INTRADAY_PRICE,
634 fund_fields::CATEGORY_NAME,
635 fund_fields::PERFORMANCE_RATING,
636 fund_fields::INITIAL_INVESTMENT,
637 fund_fields::ANNUAL_RETURN_RANK,
638 fund_fields::RISK_RATING,
639 fund_fields::EXCHANGE,
640 ];
641
642 pub fn is_valid_equity_field(field: &str) -> bool {
644 VALID_EQUITY_FIELDS.contains(&field)
645 }
646
647 pub fn is_valid_fund_field(field: &str) -> bool {
649 VALID_FUND_FIELDS.contains(&field)
650 }
651
652 pub fn is_valid_field(field: &str, quote_type: QuoteType) -> bool {
654 match quote_type {
655 QuoteType::Equity => is_valid_equity_field(field),
656 QuoteType::MutualFund => is_valid_fund_field(field),
657 }
658 }
659}
660
661pub mod indices {
663 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
665 pub enum Region {
666 Americas,
668 Europe,
670 AsiaPacific,
672 MiddleEastAfrica,
674 Currencies,
676 }
677
678 impl std::str::FromStr for Region {
679 type Err = ();
680
681 fn from_str(s: &str) -> Result<Self, Self::Err> {
682 match s.to_lowercase().replace(['-', '_'], "").as_str() {
683 "americas" | "america" => Ok(Region::Americas),
684 "europe" | "eu" => Ok(Region::Europe),
685 "asiapacific" | "asia" | "apac" => Ok(Region::AsiaPacific),
686 "middleeastafrica" | "mea" | "emea" => Ok(Region::MiddleEastAfrica),
687 "currencies" | "currency" | "fx" => Ok(Region::Currencies),
688 _ => Err(()),
689 }
690 }
691 }
692
693 impl Region {
694 pub fn parse(s: &str) -> Option<Self> {
696 s.parse().ok()
697 }
698
699 pub fn symbols(&self) -> &'static [&'static str] {
701 match self {
702 Region::Americas => AMERICAS,
703 Region::Europe => EUROPE,
704 Region::AsiaPacific => ASIA_PACIFIC,
705 Region::MiddleEastAfrica => MIDDLE_EAST_AFRICA,
706 Region::Currencies => CURRENCIES,
707 }
708 }
709
710 pub fn as_str(&self) -> &'static str {
712 match self {
713 Region::Americas => "americas",
714 Region::Europe => "europe",
715 Region::AsiaPacific => "asia-pacific",
716 Region::MiddleEastAfrica => "middle-east-africa",
717 Region::Currencies => "currencies",
718 }
719 }
720
721 pub fn all() -> &'static [Region] {
723 &[
724 Region::Americas,
725 Region::Europe,
726 Region::AsiaPacific,
727 Region::MiddleEastAfrica,
728 Region::Currencies,
729 ]
730 }
731 }
732
733 pub const AMERICAS: &[&str] = &[
735 "^GSPC", "^DJI", "^IXIC", "^NYA", "^XAX", "^RUT", "^VIX", "^GSPTSE", "^BVSP", "^MXX", "^IPSA", "^MERV", ];
748
749 pub const EUROPE: &[&str] = &[
751 "^FTSE", "^GDAXI", "^FCHI", "^STOXX50E", "^N100", "^BFX", "^BUK100P", "MOEX.ME", "^125904-USD-STRD", ];
761
762 pub const ASIA_PACIFIC: &[&str] = &[
764 "^N225", "^HSI", "000001.SS", "^KS11", "^TWII", "^STI", "^AXJO", "^AORD", "^NZ50", "^BSESN", "^JKSE", "^KLSE", ];
777
778 pub const MIDDLE_EAST_AFRICA: &[&str] = &[
780 "^TA125.TA", "^CASE30", "^JN0U.JO", ];
784
785 pub const CURRENCIES: &[&str] = &[
787 "DX-Y.NYB", "^XDB", "^XDE", "^XDN", "^XDA", ];
793
794 pub fn all_symbols() -> Vec<&'static str> {
796 Region::all()
797 .iter()
798 .flat_map(|r| r.symbols().iter().copied())
799 .collect()
800 }
801}
802
803#[allow(missing_docs)]
808pub mod fundamental_types {
809 pub const TOTAL_REVENUE: &str = "TotalRevenue";
813 pub const OPERATING_REVENUE: &str = "OperatingRevenue";
814 pub const COST_OF_REVENUE: &str = "CostOfRevenue";
815 pub const GROSS_PROFIT: &str = "GrossProfit";
816 pub const OPERATING_EXPENSE: &str = "OperatingExpense";
817 pub const SELLING_GENERAL_AND_ADMIN: &str = "SellingGeneralAndAdministration";
818 pub const RESEARCH_AND_DEVELOPMENT: &str = "ResearchAndDevelopment";
819 pub const OPERATING_INCOME: &str = "OperatingIncome";
820 pub const NET_INTEREST_INCOME: &str = "NetInterestIncome";
821 pub const INTEREST_EXPENSE: &str = "InterestExpense";
822 pub const INTEREST_INCOME: &str = "InterestIncome";
823 pub const NET_NON_OPERATING_INTEREST_INCOME_EXPENSE: &str =
824 "NetNonOperatingInterestIncomeExpense";
825 pub const OTHER_INCOME_EXPENSE: &str = "OtherIncomeExpense";
826 pub const PRETAX_INCOME: &str = "PretaxIncome";
827 pub const TAX_PROVISION: &str = "TaxProvision";
828 pub const NET_INCOME_COMMON_STOCKHOLDERS: &str = "NetIncomeCommonStockholders";
829 pub const NET_INCOME: &str = "NetIncome";
830 pub const DILUTED_EPS: &str = "DilutedEPS";
831 pub const BASIC_EPS: &str = "BasicEPS";
832 pub const DILUTED_AVERAGE_SHARES: &str = "DilutedAverageShares";
833 pub const BASIC_AVERAGE_SHARES: &str = "BasicAverageShares";
834 pub const EBIT: &str = "EBIT";
835 pub const EBITDA: &str = "EBITDA";
836 pub const RECONCILED_COST_OF_REVENUE: &str = "ReconciledCostOfRevenue";
837 pub const RECONCILED_DEPRECIATION: &str = "ReconciledDepreciation";
838 pub const NET_INCOME_FROM_CONTINUING_OPERATION_NET_MINORITY_INTEREST: &str =
839 "NetIncomeFromContinuingOperationNetMinorityInterest";
840 pub const NORMALIZED_EBITDA: &str = "NormalizedEBITDA";
841 pub const TOTAL_EXPENSES: &str = "TotalExpenses";
842 pub const TOTAL_OPERATING_INCOME_AS_REPORTED: &str = "TotalOperatingIncomeAsReported";
843
844 pub const TOTAL_ASSETS: &str = "TotalAssets";
848 pub const CURRENT_ASSETS: &str = "CurrentAssets";
849 pub const CASH_CASH_EQUIVALENTS_AND_SHORT_TERM_INVESTMENTS: &str =
850 "CashCashEquivalentsAndShortTermInvestments";
851 pub const CASH_AND_CASH_EQUIVALENTS: &str = "CashAndCashEquivalents";
852 pub const CASH_FINANCIAL: &str = "CashFinancial";
853 pub const RECEIVABLES: &str = "Receivables";
854 pub const ACCOUNTS_RECEIVABLE: &str = "AccountsReceivable";
855 pub const INVENTORY: &str = "Inventory";
856 pub const PREPAID_ASSETS: &str = "PrepaidAssets";
857 pub const OTHER_CURRENT_ASSETS: &str = "OtherCurrentAssets";
858 pub const TOTAL_NON_CURRENT_ASSETS: &str = "TotalNonCurrentAssets";
859 pub const NET_PPE: &str = "NetPPE";
860 pub const GROSS_PPE: &str = "GrossPPE";
861 pub const ACCUMULATED_DEPRECIATION: &str = "AccumulatedDepreciation";
862 pub const GOODWILL: &str = "Goodwill";
863 pub const GOODWILL_AND_OTHER_INTANGIBLE_ASSETS: &str = "GoodwillAndOtherIntangibleAssets";
864 pub const OTHER_INTANGIBLE_ASSETS: &str = "OtherIntangibleAssets";
865 pub const INVESTMENTS_AND_ADVANCES: &str = "InvestmentsAndAdvances";
866 pub const LONG_TERM_EQUITY_INVESTMENT: &str = "LongTermEquityInvestment";
867 pub const OTHER_NON_CURRENT_ASSETS: &str = "OtherNonCurrentAssets";
868 pub const TOTAL_LIABILITIES_NET_MINORITY_INTEREST: &str = "TotalLiabilitiesNetMinorityInterest";
869 pub const CURRENT_LIABILITIES: &str = "CurrentLiabilities";
870 pub const PAYABLES_AND_ACCRUED_EXPENSES: &str = "PayablesAndAccruedExpenses";
871 pub const ACCOUNTS_PAYABLE: &str = "AccountsPayable";
872 pub const CURRENT_DEBT: &str = "CurrentDebt";
873 pub const CURRENT_DEFERRED_REVENUE: &str = "CurrentDeferredRevenue";
874 pub const OTHER_CURRENT_LIABILITIES: &str = "OtherCurrentLiabilities";
875 pub const TOTAL_NON_CURRENT_LIABILITIES_NET_MINORITY_INTEREST: &str =
876 "TotalNonCurrentLiabilitiesNetMinorityInterest";
877 pub const LONG_TERM_DEBT: &str = "LongTermDebt";
878 pub const LONG_TERM_DEBT_AND_CAPITAL_LEASE_OBLIGATION: &str =
879 "LongTermDebtAndCapitalLeaseObligation";
880 pub const NON_CURRENT_DEFERRED_REVENUE: &str = "NonCurrentDeferredRevenue";
881 pub const NON_CURRENT_DEFERRED_TAXES_LIABILITIES: &str = "NonCurrentDeferredTaxesLiabilities";
882 pub const OTHER_NON_CURRENT_LIABILITIES: &str = "OtherNonCurrentLiabilities";
883 pub const STOCKHOLDERS_EQUITY: &str = "StockholdersEquity";
884 pub const COMMON_STOCK_EQUITY: &str = "CommonStockEquity";
885 pub const COMMON_STOCK: &str = "CommonStock";
886 pub const RETAINED_EARNINGS: &str = "RetainedEarnings";
887 pub const ADDITIONAL_PAID_IN_CAPITAL: &str = "AdditionalPaidInCapital";
888 pub const TREASURY_STOCK: &str = "TreasuryStock";
889 pub const TOTAL_EQUITY_GROSS_MINORITY_INTEREST: &str = "TotalEquityGrossMinorityInterest";
890 pub const WORKING_CAPITAL: &str = "WorkingCapital";
891 pub const INVESTED_CAPITAL: &str = "InvestedCapital";
892 pub const TANGIBLE_BOOK_VALUE: &str = "TangibleBookValue";
893 pub const TOTAL_DEBT: &str = "TotalDebt";
894 pub const NET_DEBT: &str = "NetDebt";
895 pub const SHARE_ISSUED: &str = "ShareIssued";
896 pub const ORDINARY_SHARES_NUMBER: &str = "OrdinarySharesNumber";
897
898 pub const OPERATING_CASH_FLOW: &str = "OperatingCashFlow";
902 pub const CASH_FLOW_FROM_CONTINUING_OPERATING_ACTIVITIES: &str =
903 "CashFlowFromContinuingOperatingActivities";
904 pub const NET_INCOME_FROM_CONTINUING_OPERATIONS: &str = "NetIncomeFromContinuingOperations";
905 pub const DEPRECIATION_AND_AMORTIZATION: &str = "DepreciationAndAmortization";
906 pub const DEFERRED_INCOME_TAX: &str = "DeferredIncomeTax";
907 pub const CHANGE_IN_WORKING_CAPITAL: &str = "ChangeInWorkingCapital";
908 pub const CHANGE_IN_RECEIVABLES: &str = "ChangeInReceivables";
909 pub const CHANGES_IN_ACCOUNT_RECEIVABLES: &str = "ChangesInAccountReceivables";
910 pub const CHANGE_IN_INVENTORY: &str = "ChangeInInventory";
911 pub const CHANGE_IN_ACCOUNT_PAYABLE: &str = "ChangeInAccountPayable";
912 pub const CHANGE_IN_OTHER_WORKING_CAPITAL: &str = "ChangeInOtherWorkingCapital";
913 pub const STOCK_BASED_COMPENSATION: &str = "StockBasedCompensation";
914 pub const OTHER_NON_CASH_ITEMS: &str = "OtherNonCashItems";
915 pub const INVESTING_CASH_FLOW: &str = "InvestingCashFlow";
916 pub const CASH_FLOW_FROM_CONTINUING_INVESTING_ACTIVITIES: &str =
917 "CashFlowFromContinuingInvestingActivities";
918 pub const NET_PPE_PURCHASE_AND_SALE: &str = "NetPPEPurchaseAndSale";
919 pub const PURCHASE_OF_PPE: &str = "PurchaseOfPPE";
920 pub const SALE_OF_PPE: &str = "SaleOfPPE";
921 pub const CAPITAL_EXPENDITURE: &str = "CapitalExpenditure";
922 pub const NET_BUSINESS_PURCHASE_AND_SALE: &str = "NetBusinessPurchaseAndSale";
923 pub const PURCHASE_OF_BUSINESS: &str = "PurchaseOfBusiness";
924 pub const SALE_OF_BUSINESS: &str = "SaleOfBusiness";
925 pub const NET_INVESTMENT_PURCHASE_AND_SALE: &str = "NetInvestmentPurchaseAndSale";
926 pub const PURCHASE_OF_INVESTMENT: &str = "PurchaseOfInvestment";
927 pub const SALE_OF_INVESTMENT: &str = "SaleOfInvestment";
928 pub const NET_OTHER_INVESTING_CHANGES: &str = "NetOtherInvestingChanges";
929 pub const FINANCING_CASH_FLOW: &str = "FinancingCashFlow";
930 pub const CASH_FLOW_FROM_CONTINUING_FINANCING_ACTIVITIES: &str =
931 "CashFlowFromContinuingFinancingActivities";
932 pub const NET_ISSUANCE_PAYMENTS_OF_DEBT: &str = "NetIssuancePaymentsOfDebt";
933 pub const NET_LONG_TERM_DEBT_ISSUANCE: &str = "NetLongTermDebtIssuance";
934 pub const LONG_TERM_DEBT_ISSUANCE: &str = "LongTermDebtIssuance";
935 pub const LONG_TERM_DEBT_PAYMENTS: &str = "LongTermDebtPayments";
936 pub const NET_SHORT_TERM_DEBT_ISSUANCE: &str = "NetShortTermDebtIssuance";
937 pub const NET_COMMON_STOCK_ISSUANCE: &str = "NetCommonStockIssuance";
938 pub const COMMON_STOCK_ISSUANCE: &str = "CommonStockIssuance";
939 pub const COMMON_STOCK_PAYMENTS: &str = "CommonStockPayments";
940 pub const REPURCHASE_OF_CAPITAL_STOCK: &str = "RepurchaseOfCapitalStock";
941 pub const CASH_DIVIDENDS_PAID: &str = "CashDividendsPaid";
942 pub const COMMON_STOCK_DIVIDEND_PAID: &str = "CommonStockDividendPaid";
943 pub const NET_OTHER_FINANCING_CHARGES: &str = "NetOtherFinancingCharges";
944 pub const END_CASH_POSITION: &str = "EndCashPosition";
945 pub const BEGINNING_CASH_POSITION: &str = "BeginningCashPosition";
946 pub const CHANGESIN_CASH: &str = "ChangesinCash";
947 pub const EFFECT_OF_EXCHANGE_RATE_CHANGES: &str = "EffectOfExchangeRateChanges";
948 pub const FREE_CASH_FLOW: &str = "FreeCashFlow";
949 pub const CAPITAL_EXPENDITURE_REPORTED: &str = "CapitalExpenditureReported";
950}
951
952#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
954pub enum StatementType {
955 Income,
957 Balance,
959 CashFlow,
961}
962
963impl StatementType {
964 pub fn as_str(&self) -> &'static str {
966 match self {
967 StatementType::Income => "income",
968 StatementType::Balance => "balance",
969 StatementType::CashFlow => "cashflow",
970 }
971 }
972
973 pub fn get_fields(&self) -> &'static [&'static str] {
977 match self {
978 StatementType::Income => &INCOME_STATEMENT_FIELDS,
979 StatementType::Balance => &BALANCE_SHEET_FIELDS,
980 StatementType::CashFlow => &CASH_FLOW_FIELDS,
981 }
982 }
983}
984
985const INCOME_STATEMENT_FIELDS: [&str; 30] = [
987 fundamental_types::TOTAL_REVENUE,
988 fundamental_types::OPERATING_REVENUE,
989 fundamental_types::COST_OF_REVENUE,
990 fundamental_types::GROSS_PROFIT,
991 fundamental_types::OPERATING_EXPENSE,
992 fundamental_types::SELLING_GENERAL_AND_ADMIN,
993 fundamental_types::RESEARCH_AND_DEVELOPMENT,
994 fundamental_types::OPERATING_INCOME,
995 fundamental_types::NET_INTEREST_INCOME,
996 fundamental_types::INTEREST_EXPENSE,
997 fundamental_types::INTEREST_INCOME,
998 fundamental_types::NET_NON_OPERATING_INTEREST_INCOME_EXPENSE,
999 fundamental_types::OTHER_INCOME_EXPENSE,
1000 fundamental_types::PRETAX_INCOME,
1001 fundamental_types::TAX_PROVISION,
1002 fundamental_types::NET_INCOME_COMMON_STOCKHOLDERS,
1003 fundamental_types::NET_INCOME,
1004 fundamental_types::DILUTED_EPS,
1005 fundamental_types::BASIC_EPS,
1006 fundamental_types::DILUTED_AVERAGE_SHARES,
1007 fundamental_types::BASIC_AVERAGE_SHARES,
1008 fundamental_types::EBIT,
1009 fundamental_types::EBITDA,
1010 fundamental_types::RECONCILED_COST_OF_REVENUE,
1011 fundamental_types::RECONCILED_DEPRECIATION,
1012 fundamental_types::NET_INCOME_FROM_CONTINUING_OPERATION_NET_MINORITY_INTEREST,
1013 fundamental_types::NORMALIZED_EBITDA,
1014 fundamental_types::TOTAL_EXPENSES,
1015 fundamental_types::TOTAL_OPERATING_INCOME_AS_REPORTED,
1016 fundamental_types::DEPRECIATION_AND_AMORTIZATION,
1017];
1018
1019const BALANCE_SHEET_FIELDS: [&str; 48] = [
1021 fundamental_types::TOTAL_ASSETS,
1022 fundamental_types::CURRENT_ASSETS,
1023 fundamental_types::CASH_CASH_EQUIVALENTS_AND_SHORT_TERM_INVESTMENTS,
1024 fundamental_types::CASH_AND_CASH_EQUIVALENTS,
1025 fundamental_types::CASH_FINANCIAL,
1026 fundamental_types::RECEIVABLES,
1027 fundamental_types::ACCOUNTS_RECEIVABLE,
1028 fundamental_types::INVENTORY,
1029 fundamental_types::PREPAID_ASSETS,
1030 fundamental_types::OTHER_CURRENT_ASSETS,
1031 fundamental_types::TOTAL_NON_CURRENT_ASSETS,
1032 fundamental_types::NET_PPE,
1033 fundamental_types::GROSS_PPE,
1034 fundamental_types::ACCUMULATED_DEPRECIATION,
1035 fundamental_types::GOODWILL,
1036 fundamental_types::GOODWILL_AND_OTHER_INTANGIBLE_ASSETS,
1037 fundamental_types::OTHER_INTANGIBLE_ASSETS,
1038 fundamental_types::INVESTMENTS_AND_ADVANCES,
1039 fundamental_types::LONG_TERM_EQUITY_INVESTMENT,
1040 fundamental_types::OTHER_NON_CURRENT_ASSETS,
1041 fundamental_types::TOTAL_LIABILITIES_NET_MINORITY_INTEREST,
1042 fundamental_types::CURRENT_LIABILITIES,
1043 fundamental_types::PAYABLES_AND_ACCRUED_EXPENSES,
1044 fundamental_types::ACCOUNTS_PAYABLE,
1045 fundamental_types::CURRENT_DEBT,
1046 fundamental_types::CURRENT_DEFERRED_REVENUE,
1047 fundamental_types::OTHER_CURRENT_LIABILITIES,
1048 fundamental_types::TOTAL_NON_CURRENT_LIABILITIES_NET_MINORITY_INTEREST,
1049 fundamental_types::LONG_TERM_DEBT,
1050 fundamental_types::LONG_TERM_DEBT_AND_CAPITAL_LEASE_OBLIGATION,
1051 fundamental_types::NON_CURRENT_DEFERRED_REVENUE,
1052 fundamental_types::NON_CURRENT_DEFERRED_TAXES_LIABILITIES,
1053 fundamental_types::OTHER_NON_CURRENT_LIABILITIES,
1054 fundamental_types::STOCKHOLDERS_EQUITY,
1055 fundamental_types::COMMON_STOCK_EQUITY,
1056 fundamental_types::COMMON_STOCK,
1057 fundamental_types::RETAINED_EARNINGS,
1058 fundamental_types::ADDITIONAL_PAID_IN_CAPITAL,
1059 fundamental_types::TREASURY_STOCK,
1060 fundamental_types::TOTAL_EQUITY_GROSS_MINORITY_INTEREST,
1061 fundamental_types::WORKING_CAPITAL,
1062 fundamental_types::INVESTED_CAPITAL,
1063 fundamental_types::TANGIBLE_BOOK_VALUE,
1064 fundamental_types::TOTAL_DEBT,
1065 fundamental_types::NET_DEBT,
1066 fundamental_types::SHARE_ISSUED,
1067 fundamental_types::ORDINARY_SHARES_NUMBER,
1068 fundamental_types::DEPRECIATION_AND_AMORTIZATION,
1069];
1070
1071const CASH_FLOW_FIELDS: [&str; 47] = [
1073 fundamental_types::OPERATING_CASH_FLOW,
1074 fundamental_types::CASH_FLOW_FROM_CONTINUING_OPERATING_ACTIVITIES,
1075 fundamental_types::NET_INCOME_FROM_CONTINUING_OPERATIONS,
1076 fundamental_types::DEPRECIATION_AND_AMORTIZATION,
1077 fundamental_types::DEFERRED_INCOME_TAX,
1078 fundamental_types::CHANGE_IN_WORKING_CAPITAL,
1079 fundamental_types::CHANGE_IN_RECEIVABLES,
1080 fundamental_types::CHANGES_IN_ACCOUNT_RECEIVABLES,
1081 fundamental_types::CHANGE_IN_INVENTORY,
1082 fundamental_types::CHANGE_IN_ACCOUNT_PAYABLE,
1083 fundamental_types::CHANGE_IN_OTHER_WORKING_CAPITAL,
1084 fundamental_types::STOCK_BASED_COMPENSATION,
1085 fundamental_types::OTHER_NON_CASH_ITEMS,
1086 fundamental_types::INVESTING_CASH_FLOW,
1087 fundamental_types::CASH_FLOW_FROM_CONTINUING_INVESTING_ACTIVITIES,
1088 fundamental_types::NET_PPE_PURCHASE_AND_SALE,
1089 fundamental_types::PURCHASE_OF_PPE,
1090 fundamental_types::SALE_OF_PPE,
1091 fundamental_types::CAPITAL_EXPENDITURE,
1092 fundamental_types::NET_BUSINESS_PURCHASE_AND_SALE,
1093 fundamental_types::PURCHASE_OF_BUSINESS,
1094 fundamental_types::SALE_OF_BUSINESS,
1095 fundamental_types::NET_INVESTMENT_PURCHASE_AND_SALE,
1096 fundamental_types::PURCHASE_OF_INVESTMENT,
1097 fundamental_types::SALE_OF_INVESTMENT,
1098 fundamental_types::NET_OTHER_INVESTING_CHANGES,
1099 fundamental_types::FINANCING_CASH_FLOW,
1100 fundamental_types::CASH_FLOW_FROM_CONTINUING_FINANCING_ACTIVITIES,
1101 fundamental_types::NET_ISSUANCE_PAYMENTS_OF_DEBT,
1102 fundamental_types::NET_LONG_TERM_DEBT_ISSUANCE,
1103 fundamental_types::LONG_TERM_DEBT_ISSUANCE,
1104 fundamental_types::LONG_TERM_DEBT_PAYMENTS,
1105 fundamental_types::NET_SHORT_TERM_DEBT_ISSUANCE,
1106 fundamental_types::NET_COMMON_STOCK_ISSUANCE,
1107 fundamental_types::COMMON_STOCK_ISSUANCE,
1108 fundamental_types::COMMON_STOCK_PAYMENTS,
1109 fundamental_types::REPURCHASE_OF_CAPITAL_STOCK,
1110 fundamental_types::CASH_DIVIDENDS_PAID,
1111 fundamental_types::COMMON_STOCK_DIVIDEND_PAID,
1112 fundamental_types::NET_OTHER_FINANCING_CHARGES,
1113 fundamental_types::END_CASH_POSITION,
1114 fundamental_types::BEGINNING_CASH_POSITION,
1115 fundamental_types::CHANGESIN_CASH,
1116 fundamental_types::EFFECT_OF_EXCHANGE_RATE_CHANGES,
1117 fundamental_types::FREE_CASH_FLOW,
1118 fundamental_types::CAPITAL_EXPENDITURE_REPORTED,
1119 fundamental_types::DEPRECIATION_AND_AMORTIZATION,
1120];
1121
1122#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1124pub enum Frequency {
1125 Annual,
1127 Quarterly,
1129}
1130
1131impl Frequency {
1132 pub fn as_str(&self) -> &'static str {
1134 match self {
1135 Frequency::Annual => "annual",
1136 Frequency::Quarterly => "quarterly",
1137 }
1138 }
1139
1140 pub fn prefix(&self, field: &str) -> String {
1151 format!("{}{}", self.as_str(), field)
1152 }
1153}
1154
1155#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
1157pub enum Interval {
1158 #[serde(rename = "1m")]
1160 OneMinute,
1161 #[serde(rename = "5m")]
1163 FiveMinutes,
1164 #[serde(rename = "15m")]
1166 FifteenMinutes,
1167 #[serde(rename = "30m")]
1169 ThirtyMinutes,
1170 #[serde(rename = "1h")]
1172 OneHour,
1173 #[serde(rename = "1d")]
1175 OneDay,
1176 #[serde(rename = "1wk")]
1178 OneWeek,
1179 #[serde(rename = "1mo")]
1181 OneMonth,
1182 #[serde(rename = "3mo")]
1184 ThreeMonths,
1185}
1186
1187impl Interval {
1188 pub fn as_str(&self) -> &'static str {
1190 match self {
1191 Interval::OneMinute => "1m",
1192 Interval::FiveMinutes => "5m",
1193 Interval::FifteenMinutes => "15m",
1194 Interval::ThirtyMinutes => "30m",
1195 Interval::OneHour => "1h",
1196 Interval::OneDay => "1d",
1197 Interval::OneWeek => "1wk",
1198 Interval::OneMonth => "1mo",
1199 Interval::ThreeMonths => "3mo",
1200 }
1201 }
1202}
1203
1204impl std::fmt::Display for Interval {
1205 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1206 f.write_str(self.as_str())
1207 }
1208}
1209
1210#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
1212pub enum TimeRange {
1213 #[serde(rename = "1d")]
1215 OneDay,
1216 #[serde(rename = "5d")]
1218 FiveDays,
1219 #[serde(rename = "1mo")]
1221 OneMonth,
1222 #[serde(rename = "3mo")]
1224 ThreeMonths,
1225 #[serde(rename = "6mo")]
1227 SixMonths,
1228 #[serde(rename = "1y")]
1230 OneYear,
1231 #[serde(rename = "2y")]
1233 TwoYears,
1234 #[serde(rename = "5y")]
1236 FiveYears,
1237 #[serde(rename = "10y")]
1239 TenYears,
1240 #[serde(rename = "ytd")]
1242 YearToDate,
1243 #[serde(rename = "max")]
1245 Max,
1246}
1247
1248impl TimeRange {
1249 pub fn as_str(&self) -> &'static str {
1251 match self {
1252 TimeRange::OneDay => "1d",
1253 TimeRange::FiveDays => "5d",
1254 TimeRange::OneMonth => "1mo",
1255 TimeRange::ThreeMonths => "3mo",
1256 TimeRange::SixMonths => "6mo",
1257 TimeRange::OneYear => "1y",
1258 TimeRange::TwoYears => "2y",
1259 TimeRange::FiveYears => "5y",
1260 TimeRange::TenYears => "10y",
1261 TimeRange::YearToDate => "ytd",
1262 TimeRange::Max => "max",
1263 }
1264 }
1265}
1266
1267impl std::fmt::Display for TimeRange {
1268 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1269 f.write_str(self.as_str())
1270 }
1271}
1272
1273#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
1278pub enum Region {
1279 Argentina,
1281 Australia,
1283 Brazil,
1285 Canada,
1287 China,
1289 Denmark,
1291 Finland,
1293 France,
1295 Germany,
1297 Greece,
1299 HongKong,
1301 India,
1303 Israel,
1305 Italy,
1307 Malaysia,
1309 NewZealand,
1311 Norway,
1313 Portugal,
1315 Russia,
1317 Singapore,
1319 Spain,
1321 Sweden,
1323 Taiwan,
1325 Thailand,
1327 Turkey,
1329 UnitedKingdom,
1331 #[default]
1333 UnitedStates,
1334 Vietnam,
1336}
1337
1338impl Region {
1339 pub fn lang(&self) -> &'static str {
1350 match self {
1351 Region::Argentina => "es-AR",
1352 Region::Australia => "en-AU",
1353 Region::Brazil => "pt-BR",
1354 Region::Canada => "en-CA",
1355 Region::China => "zh-CN",
1356 Region::Denmark => "da-DK",
1357 Region::Finland => "fi-FI",
1358 Region::France => "fr-FR",
1359 Region::Germany => "de-DE",
1360 Region::Greece => "el-GR",
1361 Region::HongKong => "zh-Hant-HK",
1362 Region::India => "en-IN",
1363 Region::Israel => "he-IL",
1364 Region::Italy => "it-IT",
1365 Region::Malaysia => "ms-MY",
1366 Region::NewZealand => "en-NZ",
1367 Region::Norway => "nb-NO",
1368 Region::Portugal => "pt-PT",
1369 Region::Russia => "ru-RU",
1370 Region::Singapore => "en-SG",
1371 Region::Spain => "es-ES",
1372 Region::Sweden => "sv-SE",
1373 Region::Taiwan => "zh-TW",
1374 Region::Thailand => "th-TH",
1375 Region::Turkey => "tr-TR",
1376 Region::UnitedKingdom => "en-GB",
1377 Region::UnitedStates => "en-US",
1378 Region::Vietnam => "vi-VN",
1379 }
1380 }
1381
1382 pub fn region(&self) -> &'static str {
1393 match self {
1394 Region::Argentina => "AR",
1395 Region::Australia => "AU",
1396 Region::Brazil => "BR",
1397 Region::Canada => "CA",
1398 Region::China => "CN",
1399 Region::Denmark => "DK",
1400 Region::Finland => "FI",
1401 Region::France => "FR",
1402 Region::Germany => "DE",
1403 Region::Greece => "GR",
1404 Region::HongKong => "HK",
1405 Region::India => "IN",
1406 Region::Israel => "IL",
1407 Region::Italy => "IT",
1408 Region::Malaysia => "MY",
1409 Region::NewZealand => "NZ",
1410 Region::Norway => "NO",
1411 Region::Portugal => "PT",
1412 Region::Russia => "RU",
1413 Region::Singapore => "SG",
1414 Region::Spain => "ES",
1415 Region::Sweden => "SE",
1416 Region::Taiwan => "TW",
1417 Region::Thailand => "TH",
1418 Region::Turkey => "TR",
1419 Region::UnitedKingdom => "GB",
1420 Region::UnitedStates => "US",
1421 Region::Vietnam => "VN",
1422 }
1423 }
1424
1425 pub fn cors_domain(&self) -> &'static str {
1436 match self {
1437 Region::Argentina => "ar.finance.yahoo.com",
1438 Region::Australia => "au.finance.yahoo.com",
1439 Region::Brazil => "br.financas.yahoo.com",
1440 Region::Canada => "ca.finance.yahoo.com",
1441 Region::China => "cn.finance.yahoo.com",
1442 Region::Denmark => "dk.finance.yahoo.com",
1443 Region::Finland => "fi.finance.yahoo.com",
1444 Region::France => "fr.finance.yahoo.com",
1445 Region::Germany => "de.finance.yahoo.com",
1446 Region::Greece => "gr.finance.yahoo.com",
1447 Region::HongKong => "hk.finance.yahoo.com",
1448 Region::India => "in.finance.yahoo.com",
1449 Region::Israel => "il.finance.yahoo.com",
1450 Region::Italy => "it.finance.yahoo.com",
1451 Region::Malaysia => "my.finance.yahoo.com",
1452 Region::NewZealand => "nz.finance.yahoo.com",
1453 Region::Norway => "no.finance.yahoo.com",
1454 Region::Portugal => "pt.finance.yahoo.com",
1455 Region::Russia => "ru.finance.yahoo.com",
1456 Region::Singapore => "sg.finance.yahoo.com",
1457 Region::Spain => "es.finance.yahoo.com",
1458 Region::Sweden => "se.finance.yahoo.com",
1459 Region::Taiwan => "tw.finance.yahoo.com",
1460 Region::Thailand => "th.finance.yahoo.com",
1461 Region::Turkey => "tr.finance.yahoo.com",
1462 Region::UnitedKingdom => "uk.finance.yahoo.com",
1463 Region::UnitedStates => "finance.yahoo.com",
1464 Region::Vietnam => "vn.finance.yahoo.com",
1465 }
1466 }
1467}
1468
1469impl std::str::FromStr for Region {
1470 type Err = ();
1471
1472 fn from_str(s: &str) -> Result<Self, Self::Err> {
1473 match s.to_uppercase().as_str() {
1474 "AR" => Ok(Region::Argentina),
1475 "AU" => Ok(Region::Australia),
1476 "BR" => Ok(Region::Brazil),
1477 "CA" => Ok(Region::Canada),
1478 "CN" => Ok(Region::China),
1479 "DK" => Ok(Region::Denmark),
1480 "FI" => Ok(Region::Finland),
1481 "FR" => Ok(Region::France),
1482 "DE" => Ok(Region::Germany),
1483 "GR" => Ok(Region::Greece),
1484 "HK" => Ok(Region::HongKong),
1485 "IN" => Ok(Region::India),
1486 "IL" => Ok(Region::Israel),
1487 "IT" => Ok(Region::Italy),
1488 "MY" => Ok(Region::Malaysia),
1489 "NZ" => Ok(Region::NewZealand),
1490 "NO" => Ok(Region::Norway),
1491 "PT" => Ok(Region::Portugal),
1492 "RU" => Ok(Region::Russia),
1493 "SG" => Ok(Region::Singapore),
1494 "ES" => Ok(Region::Spain),
1495 "SE" => Ok(Region::Sweden),
1496 "TW" => Ok(Region::Taiwan),
1497 "TH" => Ok(Region::Thailand),
1498 "TR" => Ok(Region::Turkey),
1499 "GB" | "UK" => Ok(Region::UnitedKingdom),
1500 "US" => Ok(Region::UnitedStates),
1501 "VN" => Ok(Region::Vietnam),
1502 _ => Err(()),
1503 }
1504 }
1505}
1506
1507#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
1513pub enum ValueFormat {
1514 #[default]
1517 Raw,
1518 Pretty,
1521 Both,
1524}
1525
1526impl std::str::FromStr for ValueFormat {
1527 type Err = ();
1528
1529 fn from_str(s: &str) -> Result<Self, Self::Err> {
1530 match s.to_lowercase().as_str() {
1531 "raw" => Ok(ValueFormat::Raw),
1532 "pretty" | "fmt" => Ok(ValueFormat::Pretty),
1533 "both" | "full" => Ok(ValueFormat::Both),
1534 _ => Err(()),
1535 }
1536 }
1537}
1538
1539impl ValueFormat {
1540 pub fn parse(s: &str) -> Option<Self> {
1542 s.parse().ok()
1543 }
1544
1545 pub fn as_str(&self) -> &'static str {
1547 match self {
1548 ValueFormat::Raw => "raw",
1549 ValueFormat::Pretty => "pretty",
1550 ValueFormat::Both => "both",
1551 }
1552 }
1553
1554 pub fn transform(&self, value: serde_json::Value) -> serde_json::Value {
1581 match self {
1582 ValueFormat::Both => value, _ => self.transform_recursive(value),
1584 }
1585 }
1586
1587 fn transform_recursive(&self, value: serde_json::Value) -> serde_json::Value {
1588 use serde_json::Value;
1589
1590 match value {
1591 Value::Object(map) => {
1592 if self.is_formatted_value(&map) {
1594 return self.extract_value(&map);
1595 }
1596
1597 let transformed: serde_json::Map<String, Value> = map
1599 .into_iter()
1600 .map(|(k, v)| (k, self.transform_recursive(v)))
1601 .collect();
1602 Value::Object(transformed)
1603 }
1604 Value::Array(arr) => Value::Array(
1605 arr.into_iter()
1606 .map(|v| self.transform_recursive(v))
1607 .collect(),
1608 ),
1609 other => other,
1611 }
1612 }
1613
1614 fn is_formatted_value(&self, map: &serde_json::Map<String, serde_json::Value>) -> bool {
1616 if !map.contains_key("raw") {
1620 return false;
1621 }
1622
1623 let known_keys = ["raw", "fmt", "longFmt"];
1624 let unknown_keys = map
1625 .keys()
1626 .filter(|k| !known_keys.contains(&k.as_str()))
1627 .count();
1628
1629 unknown_keys == 0
1631 }
1632
1633 fn extract_value(&self, map: &serde_json::Map<String, serde_json::Value>) -> serde_json::Value {
1635 match self {
1636 ValueFormat::Raw => {
1637 map.get("raw").cloned().unwrap_or(serde_json::Value::Null)
1639 }
1640 ValueFormat::Pretty => {
1641 map.get("fmt")
1643 .or_else(|| map.get("longFmt"))
1644 .cloned()
1645 .unwrap_or(serde_json::Value::Null)
1646 }
1647 ValueFormat::Both => {
1648 serde_json::Value::Object(map.clone())
1650 }
1651 }
1652 }
1653}
1654
1655#[cfg(test)]
1656mod tests {
1657 use super::*;
1658
1659 #[test]
1660 fn test_interval_as_str() {
1661 assert_eq!(Interval::OneMinute.as_str(), "1m");
1662 assert_eq!(Interval::FiveMinutes.as_str(), "5m");
1663 assert_eq!(Interval::OneDay.as_str(), "1d");
1664 assert_eq!(Interval::OneWeek.as_str(), "1wk");
1665 }
1666
1667 #[test]
1668 fn test_time_range_as_str() {
1669 assert_eq!(TimeRange::OneDay.as_str(), "1d");
1670 assert_eq!(TimeRange::OneMonth.as_str(), "1mo");
1671 assert_eq!(TimeRange::OneYear.as_str(), "1y");
1672 assert_eq!(TimeRange::Max.as_str(), "max");
1673 }
1674}