1pub use self::MarketType::*;
28pub use self::news::*;
29pub use crate::chart::*;
30pub use crate::quote::models::*;
31
32use chrono::Duration;
33use iso_currency::Currency;
34use serde::{Deserialize, Deserializer, Serialize};
35use std::{collections::HashMap, fmt::Display};
36pub mod news;
37pub mod pine_indicator;
38
39pub trait MarketSymbol {
44 fn new<S: Into<String>>(symbol: S, exchange: S) -> Self;
46 fn symbol(&self) -> &str;
48 fn exchange(&self) -> &str;
50 fn id(&self) -> String {
52 format!("{}:{}", self.exchange(), self.symbol())
53 }
54}
55
56impl MarketSymbol for Symbol {
57 fn symbol(&self) -> &str {
58 &self.symbol
59 }
60
61 fn exchange(&self) -> &str {
62 &self.exchange
63 }
64
65 fn id(&self) -> String {
66 Symbol::id(self)
67 }
68
69 fn new<S: Into<String>>(symbol: S, exchange: S) -> Self {
70 Self {
71 symbol: symbol.into(),
72 exchange: exchange.into(),
73 ..Default::default()
74 }
75 }
76}
77
78#[derive(Debug, Clone, Default, Serialize, Deserialize)]
80pub struct ChartDrawing {
81 pub success: bool,
82 pub payload: ChartDrawingSource,
83}
84
85#[derive(Debug, Clone, Default, Serialize, Deserialize)]
87pub struct ChartDrawingSource {
88 pub sources: HashMap<String, ChartDrawingSourceData>,
89}
90
91#[derive(Debug, Clone, Default, Serialize, Deserialize)]
93#[serde(rename_all = "camelCase")]
94pub struct ChartDrawingSourceData {
95 id: String,
96 symbol: String,
97 currency_id: String,
98 server_update_time: i64,
99 state: ChartDrawingSourceState,
100}
101
102#[derive(Debug, Clone, Default, Serialize, Deserialize)]
104#[serde(rename_all = "camelCase")]
105pub struct ChartDrawingSourceState {
106 points: Vec<ChartDrawingSourceStatePoint>,
107}
108
109#[derive(Debug, Clone, Default, Serialize, Deserialize)]
111pub struct ChartDrawingSourceStatePoint {
112 time_t: i64,
113 offset: i64,
114 price: f64,
115}
116
117#[derive(Clone, Serialize, Deserialize, Debug, Default)]
125pub struct UserCookies {
126 pub id: u32,
127 pub username: String,
128 pub private_channel: String,
129 pub auth_token: String,
130 #[serde(default)]
131 pub session: String,
132 #[serde(default)]
133 pub session_signature: String,
134 pub session_hash: String,
135 #[serde(default)]
136 pub device_token: String,
137}
138
139#[derive(Debug, Clone, Default, Deserialize)]
144pub struct SymbolSearchResponse {
145 #[serde(rename(deserialize = "symbols_remaining"))]
146 pub remaining: u64,
147 pub symbols: Vec<Symbol>,
148}
149
150#[derive(Clone, PartialEq, Deserialize, Serialize, Debug, Default, Hash)]
165pub struct Symbol {
166 pub symbol: String,
167 #[serde(default)]
168 pub description: String,
169 #[serde(default, rename(deserialize = "type"))]
170 pub market_type: String,
171 #[serde(default)]
172 pub exchange: String,
173 #[serde(default)]
177 pub prefix: String,
178 #[serde(default)]
179 pub currency_code: String,
180 #[serde(default, rename(deserialize = "provider_id"))]
181 pub data_provider: String,
182 #[serde(default, rename(deserialize = "country"))]
183 pub country_code: String,
184 #[serde(default, rename(deserialize = "typespecs"))]
185 pub type_specs: Vec<String>,
186 #[serde(default, rename(deserialize = "source2"))]
187 pub exchange_source: ExchangeSource,
188}
189
190#[bon::bon]
191impl Symbol {
192 #[builder]
193 pub fn new<S: Into<String>>(
194 symbol: S,
195 exchange: S,
196 currency: Option<Currency>,
197 prefix: Option<S>,
198 ) -> Self {
199 Self {
200 symbol: symbol.into(),
201 exchange: exchange.into(),
202 currency_code: currency.map(|c| c.to_string()).unwrap_or_default(),
203 prefix: prefix.map(|p| p.into()).unwrap_or_default(),
204 ..Default::default()
205 }
206 }
207
208 pub fn id(&self) -> String {
209 let prefix = if !self.prefix.is_empty() {
210 &self.prefix
211 } else {
212 &self.exchange
213 };
214 format!("{}:{}", prefix, self.symbol)
215 }
216}
217
218#[derive(Clone, PartialEq, Deserialize, Serialize, Debug, Default, Hash)]
223pub struct ExchangeSource {
224 pub id: String,
225 pub name: String,
226 pub description: String,
227}
228
229#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy, PartialEq, Eq, Hash)]
231pub enum SessionType {
232 #[default]
234 Regular,
235 Extended,
237 PreMarket,
239 PostMarket,
241}
242
243impl Display for SessionType {
244 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
245 match self {
246 SessionType::Regular => write!(f, "regular"),
247 SessionType::Extended => write!(f, "extended"),
248 SessionType::PreMarket => write!(f, "premarket"),
249 SessionType::PostMarket => write!(f, "postmarket"),
250 }
251 }
252}
253
254#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy)]
259pub enum MarketAdjustment {
260 #[default]
262 Splits,
263 Dividends,
265}
266
267impl Display for MarketAdjustment {
268 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
269 match self {
270 MarketAdjustment::Splits => write!(f, "splits"),
271 MarketAdjustment::Dividends => write!(f, "dividends"),
272 }
273 }
274}
275
276#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy)]
278pub enum MarketStatus {
279 Holiday,
281 #[default]
283 Open,
284 Close,
286 Post,
288 Pre,
290}
291
292impl Display for MarketStatus {
293 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
294 match self {
295 MarketStatus::Holiday => write!(f, "holiday"),
296 MarketStatus::Open => write!(f, "market"),
297 MarketStatus::Close => write!(f, "out_of_session"),
298 MarketStatus::Post => write!(f, "post_market"),
299 MarketStatus::Pre => write!(f, "pre_market"),
300 }
301 }
302}
303
304#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy, PartialEq, Eq, Hash)]
308pub enum Timezone {
309 AfricaCairo,
311 AfricaCasablanca,
312 AfricaJohannesburg,
313 AfricaLagos,
314 AfricaNairobi,
315 AfricaTunis,
316 AmericaAnchorage,
317 AmericaArgentinaBuenosAires,
318 AmericaBogota,
319 AmericaCaracas,
320 AmericaChicago,
321 AmericaElSalvador,
322 AmericaJuneau,
323 AmericaLima,
324 AmericaLosAngeles,
325 AmericaMexicoCity,
326 AmericaNewYork,
327 AmericaPhoenix,
328 AmericaSantiago,
329 AmericaSaoPaulo,
330 AmericaToronto,
331 AmericaVancouver,
332 AsiaAlmaty,
333 AsiaAshkhabad,
334 AsiaBahrain,
335 AsiaBangkok,
336 AsiaChongqing,
337 AsiaColombo,
338 AsiaDhaka,
339 AsiaDubai,
340 AsiaHoChiMinh,
341 AsiaHongKong,
342 AsiaJakarta,
343 AsiaJerusalem,
344 AsiaKarachi,
345 AsiaKathmandu,
346 AsiaKolkata,
347 AsiaKuwait,
348 AsiaManila,
349 AsiaMuscat,
350 AsiaNicosia,
351 AsiaQatar,
352 AsiaRiyadh,
353 AsiaSeoul,
354 AsiaShanghai,
355 AsiaSingapore,
356 AsiaTaipei,
357 AsiaTehran,
358 AsiaTokyo,
359 AsiaYangon,
360 AtlanticReykjavik,
361 AustraliaAdelaide,
362 AustraliaBrisbane,
363 AustraliaPerth,
364 AustraliaSydney,
365 EuropeAmsterdam,
366 EuropeAthens,
367 EuropeBelgrade,
368 EuropeBerlin,
369 EuropeBratislava,
370 EuropeBrussels,
371 EuropeBucharest,
372 EuropeBudapest,
373 EuropeCopenhagen,
374 EuropeDublin,
375 EuropeHelsinki,
376 EuropeIstanbul,
377 EuropeLisbon,
378 EuropeLondon,
379 EuropeLuxembourg,
380 EuropeMadrid,
381 EuropeMalta,
382 EuropeMoscow,
383 EuropeOslo,
384 EuropeParis,
385 EuropeRiga,
386 EuropeRome,
387 EuropeStockholm,
388 EuropeTallinn,
389 EuropeVilnius,
390 EuropeWarsaw,
391 EuropeZurich,
392 PacificAuckland,
393 PacificChatham,
394 PacificFakaofo,
395 PacificHonolulu,
396 PacificNorfolk,
397 USMountain,
398 #[default]
399 EtcUTC,
400}
401
402impl Display for Timezone {
403 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
404 match self {
405 Timezone::AfricaCairo => write!(f, "Africa/Cairo"),
406 Timezone::AfricaCasablanca => write!(f, "Africa/Casablanca"),
407 Timezone::AfricaJohannesburg => write!(f, "Africa/Johannesburg"),
408 Timezone::AfricaLagos => write!(f, "Africa/Lagos"),
409 Timezone::AfricaNairobi => write!(f, "Africa/Nairobi"),
410 Timezone::AfricaTunis => write!(f, "Africa/Tunis"),
411 Timezone::AmericaAnchorage => write!(f, "America/Anchorage"),
412 Timezone::AmericaArgentinaBuenosAires => write!(f, "America/Argentina/Buenos_Aires"),
413 Timezone::AmericaBogota => write!(f, "America/Bogota"),
414 Timezone::AmericaCaracas => write!(f, "America/Caracas"),
415 Timezone::AmericaChicago => write!(f, "America/Chicago"),
416 Timezone::AmericaElSalvador => write!(f, "America/El_Salvador"),
417 Timezone::AmericaJuneau => write!(f, "America/Juneau"),
418 Timezone::AmericaLima => write!(f, "America/Lima"),
419 Timezone::AmericaLosAngeles => write!(f, "America/Los_Angeles"),
420 Timezone::AmericaMexicoCity => write!(f, "America/Mexico_City"),
421 Timezone::AmericaNewYork => write!(f, "America/New_York"),
422 Timezone::AmericaPhoenix => write!(f, "America/Phoenix"),
423 Timezone::AmericaSantiago => write!(f, "America/Santiago"),
424 Timezone::AmericaSaoPaulo => write!(f, "America/Sao_Paulo"),
425 Timezone::AmericaToronto => write!(f, "America/Toronto"),
426 Timezone::AmericaVancouver => write!(f, "America/Vancouver"),
427 Timezone::AsiaAlmaty => write!(f, "Asia/Almaty"),
428 Timezone::AsiaAshkhabad => write!(f, "Asia/Ashkhabad"),
429 Timezone::AsiaBahrain => write!(f, "Asia/Bahrain"),
430 Timezone::AsiaBangkok => write!(f, "Asia/Bangkok"),
431 Timezone::AsiaChongqing => write!(f, "Asia/Chongqing"),
432 Timezone::AsiaColombo => write!(f, "Asia/Colombo"),
433 Timezone::AsiaDhaka => write!(f, "Asia/Dhaka"),
434 Timezone::AsiaDubai => write!(f, "Asia/Dubai"),
435 Timezone::AsiaHoChiMinh => write!(f, "Asia/Ho_Chi_Minh"),
436 Timezone::AsiaHongKong => write!(f, "Asia/Hong_Kong"),
437 Timezone::AsiaJakarta => write!(f, "Asia/Jakarta"),
438 Timezone::AsiaJerusalem => write!(f, "Asia/Jerusalem"),
439 Timezone::AsiaKarachi => write!(f, "Asia/Karachi"),
440 Timezone::AsiaKathmandu => write!(f, "Asia/Kathmandu"),
441 Timezone::AsiaKolkata => write!(f, "Asia/Kolkata"),
442 Timezone::AsiaKuwait => write!(f, "Asia/Kuwait"),
443 Timezone::AsiaManila => write!(f, "Asia/Manila"),
444 Timezone::AsiaMuscat => write!(f, "Asia/Muscat"),
445 Timezone::AsiaNicosia => write!(f, "Asia/Nicosia"),
446 Timezone::AsiaQatar => write!(f, "Asia/Qatar"),
447 Timezone::AsiaRiyadh => write!(f, "Asia/Riyadh"),
448 Timezone::AsiaSeoul => write!(f, "Asia/Seoul"),
449 Timezone::AsiaShanghai => write!(f, "Asia/Shanghai"),
450 Timezone::AsiaSingapore => write!(f, "Asia/Singapore"),
451 Timezone::AsiaTaipei => write!(f, "Asia/Taipei"),
452 Timezone::AsiaTehran => write!(f, "Asia/Tehran"),
453 Timezone::AsiaTokyo => write!(f, "Asia/Tokyo"),
454 Timezone::AsiaYangon => write!(f, "Asia/Yangon"),
455 Timezone::AtlanticReykjavik => write!(f, "Atlantic/Reykjavik"),
456 Timezone::AustraliaAdelaide => write!(f, "Australia/Adelaide"),
457 Timezone::AustraliaBrisbane => write!(f, "Australia/Brisbane"),
458 Timezone::AustraliaPerth => write!(f, "Australia/Perth"),
459 Timezone::AustraliaSydney => write!(f, "Australia/Sydney"),
460 Timezone::EuropeAmsterdam => write!(f, "Europe/Amsterdam"),
461 Timezone::EuropeAthens => write!(f, "Europe/Athens"),
462 Timezone::EuropeBelgrade => write!(f, "Europe/Belgrade"),
463 Timezone::EuropeBerlin => write!(f, "Europe/Berlin"),
464 Timezone::EuropeBratislava => write!(f, "Europe/Bratislava"),
465 Timezone::EuropeBrussels => write!(f, "Europe/Brussels"),
466 Timezone::EuropeBucharest => write!(f, "Europe/Bucharest"),
467 Timezone::EuropeBudapest => write!(f, "Europe/Budapest"),
468 Timezone::EuropeCopenhagen => write!(f, "Europe/Copenhagen"),
469 Timezone::EuropeDublin => write!(f, "Europe/Dublin"),
470 Timezone::EuropeHelsinki => write!(f, "Europe/Helsinki"),
471 Timezone::EuropeIstanbul => write!(f, "Europe/Istanbul"),
472 Timezone::EuropeLisbon => write!(f, "Europe/Lisbon"),
473 Timezone::EuropeLondon => write!(f, "Europe/London"),
474 Timezone::EuropeLuxembourg => write!(f, "Europe/Luxembourg"),
475 Timezone::EuropeMadrid => write!(f, "Europe/Madrid"),
476 Timezone::EuropeMalta => write!(f, "Europe/Malta"),
477 Timezone::EuropeMoscow => write!(f, "Europe/Moscow"),
478 Timezone::EuropeOslo => write!(f, "Europe/Oslo"),
479 Timezone::EuropeParis => write!(f, "Europe/Paris"),
480 Timezone::EuropeRiga => write!(f, "Europe/Riga"),
481 Timezone::EuropeRome => write!(f, "Europe/Rome"),
482 Timezone::EuropeStockholm => write!(f, "Europe/Stockholm"),
483 Timezone::EuropeTallinn => write!(f, "Europe/Tallinn"),
484 Timezone::EuropeVilnius => write!(f, "Europe/Vilnius"),
485 Timezone::EuropeWarsaw => write!(f, "Europe/Warsaw"),
486 Timezone::EuropeZurich => write!(f, "Europe/Zurich"),
487 Timezone::PacificAuckland => write!(f, "Pacific/Auckland"),
488 Timezone::PacificChatham => write!(f, "Pacific/Chatham"),
489 Timezone::PacificFakaofo => write!(f, "Pacific/Fakaofo"),
490 Timezone::PacificHonolulu => write!(f, "Pacific/Honolulu"),
491 Timezone::PacificNorfolk => write!(f, "Pacific/Norfolk"),
492 Timezone::USMountain => write!(f, "US/Mountain"),
493 Timezone::EtcUTC => write!(f, "Etc/UTC"),
494 }
495 }
496}
497
498#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy, PartialEq, Eq, Hash)]
516pub enum Interval {
517 OneSecond = 0,
519 FiveSeconds = 1,
521 TenSeconds = 2,
523 FifteenSeconds = 3,
525 ThirtySeconds = 4,
527 OneMinute = 5,
529 ThreeMinutes = 6,
531 FiveMinutes = 7,
533 FifteenMinutes = 8,
535 ThirtyMinutes = 9,
537 FortyFiveMinutes = 10,
539 OneHour = 11,
541 TwoHours = 12,
543 FourHours = 13,
545 #[default]
547 OneDay = 14,
548 OneWeek = 15,
550 OneMonth = 16,
552 OneQuarter = 17,
554 SixMonths = 18,
556 Yearly = 19,
558}
559
560impl Interval {
561 pub fn longer(self) -> Interval {
562 match self {
563 Interval::OneSecond => Interval::FiveSeconds,
564 Interval::FiveSeconds => Interval::TenSeconds,
565 Interval::TenSeconds => Interval::FifteenSeconds,
566 Interval::FifteenSeconds => Interval::ThirtySeconds,
567 Interval::ThirtySeconds => Interval::OneMinute,
568 Interval::OneMinute => Interval::ThreeMinutes,
569 Interval::ThreeMinutes => Interval::FiveMinutes,
570 Interval::FiveMinutes => Interval::FifteenMinutes,
571 Interval::FifteenMinutes => Interval::ThirtyMinutes,
572 Interval::ThirtyMinutes => Interval::FortyFiveMinutes,
573 Interval::FortyFiveMinutes => Interval::OneHour,
574 Interval::OneHour => Interval::TwoHours,
575 Interval::TwoHours => Interval::FourHours,
576 Interval::FourHours => Interval::OneDay,
577 Interval::OneDay => Interval::OneWeek,
578 Interval::OneWeek => Interval::OneMonth,
579 Interval::OneMonth => Interval::OneQuarter,
580 Interval::OneQuarter => Interval::SixMonths,
581 _ => self, }
583 }
584}
585
586impl From<u8> for Interval {
587 fn from(value: u8) -> Self {
588 match value {
589 0 => Interval::OneSecond,
590 1 => Interval::FiveSeconds,
591 2 => Interval::TenSeconds,
592 3 => Interval::FifteenSeconds,
593 4 => Interval::ThirtySeconds,
594 5 => Interval::OneMinute,
595 6 => Interval::ThreeMinutes,
596 7 => Interval::FiveMinutes,
597 8 => Interval::FifteenMinutes,
598 9 => Interval::ThirtyMinutes,
599 10 => Interval::FortyFiveMinutes,
600 11 => Interval::OneHour,
601 12 => Interval::TwoHours,
602 13 => Interval::FourHours,
603 14 => Interval::OneDay,
604 15 => Interval::OneWeek,
605 16 => Interval::OneMonth,
606 17 => Interval::OneQuarter,
607 18 => Interval::SixMonths,
608 _ => Interval::Yearly, }
610 }
611}
612
613impl From<Interval> for Duration {
614 fn from(interval: Interval) -> Self {
615 match interval {
616 Interval::OneSecond => Duration::seconds(1),
617 Interval::FiveSeconds => Duration::seconds(5),
618 Interval::TenSeconds => Duration::seconds(10),
619 Interval::FifteenSeconds => Duration::seconds(15),
620 Interval::ThirtySeconds => Duration::seconds(30),
621 Interval::OneMinute => Duration::minutes(1),
622 Interval::ThreeMinutes => Duration::minutes(3),
623 Interval::FiveMinutes => Duration::minutes(5),
624 Interval::FifteenMinutes => Duration::minutes(15),
625 Interval::ThirtyMinutes => Duration::minutes(30),
626 Interval::FortyFiveMinutes => Duration::minutes(45),
627 Interval::OneHour => Duration::hours(1),
628 Interval::TwoHours => Duration::hours(2),
629 Interval::FourHours => Duration::hours(4),
630 Interval::OneDay => Duration::days(1),
631 Interval::OneWeek => Duration::weeks(1),
632 Interval::OneMonth => Duration::days(30), Interval::OneQuarter => Duration::days(90), Interval::SixMonths => Duration::days(180), Interval::Yearly => Duration::days(365), }
637 }
638}
639
640impl From<&str> for Interval {
641 fn from(value: &str) -> Self {
642 match value {
643 "1s" => Interval::OneSecond,
644 "5s" => Interval::FiveSeconds,
645 "10s" => Interval::TenSeconds,
646 "15s" => Interval::FifteenSeconds,
647 "30s" => Interval::ThirtySeconds,
648 "1m" => Interval::OneMinute,
649 "3m" => Interval::ThreeMinutes,
650 "5m" => Interval::FiveMinutes,
651 "15m" => Interval::FifteenMinutes,
652 "30m" => Interval::ThirtyMinutes,
653 "45m" => Interval::FortyFiveMinutes,
654 "1h" => Interval::OneHour,
655 "2h" => Interval::TwoHours,
656 "4h" => Interval::FourHours,
657 "1d" => Interval::OneDay,
658 "7d" => Interval::OneWeek,
659 "30d" => Interval::OneMonth,
660 "120d" => Interval::OneQuarter,
661 "180d" => Interval::SixMonths,
662 "1y" => Interval::Yearly,
663 _ => Interval::OneDay,
664 }
665 }
666}
667
668impl Display for Interval {
669 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
670 let time_interval = match self {
671 Interval::OneSecond => "1S",
672 Interval::FiveSeconds => "5S",
673 Interval::TenSeconds => "10S",
674 Interval::FifteenSeconds => "15S",
675 Interval::ThirtySeconds => "30S",
676 Interval::OneMinute => "1",
677 Interval::ThreeMinutes => "3",
678 Interval::FiveMinutes => "5",
679 Interval::FifteenMinutes => "15",
680 Interval::ThirtyMinutes => "30",
681 Interval::FortyFiveMinutes => "45",
682 Interval::OneHour => "1H",
683 Interval::TwoHours => "2H",
684 Interval::FourHours => "4H",
685 Interval::OneDay => "1D",
686 Interval::OneWeek => "1W",
687 Interval::OneMonth => "1M",
688 Interval::OneQuarter => "3M",
689 Interval::SixMonths => "6M",
690 Interval::Yearly => "12M",
691 };
692 write!(f, "{time_interval}")
693 }
694}
695
696#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy)]
700pub enum LanguageCode {
701 Arabic,
703 Chinese,
705 Czech,
707 Danish,
709 Catalan,
711 Dutch,
713 #[default]
715 English,
716 Estonian,
718 French,
720 German,
722 Greek,
724 Hebrew,
726 Hungarian,
728 Indonesian,
730 Italian,
732 Japanese,
734 Korean,
736 Persian,
738 Polish,
740 Portuguese,
742 Romanian,
744 Russian,
746 Slovak,
748 Spanish,
750 Swedish,
752 Thai,
754 Turkish,
756 Vietnamese,
758 Norwegian,
760 Malay,
762 TraditionalChinese,
764}
765
766impl Display for LanguageCode {
767 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
768 match *self {
769 LanguageCode::Arabic => write!(f, "ar"),
770 LanguageCode::Chinese => write!(f, "zh"),
771 LanguageCode::Czech => write!(f, "cs"),
772 LanguageCode::Danish => write!(f, "da_DK"),
773 LanguageCode::Catalan => write!(f, "ca_ES"),
774 LanguageCode::Dutch => write!(f, "nl_NL"),
775 LanguageCode::English => write!(f, "en"),
776 LanguageCode::Estonian => write!(f, "et_EE"),
777 LanguageCode::French => write!(f, "fr"),
778 LanguageCode::German => write!(f, "de"),
779 LanguageCode::Greek => write!(f, "el"),
780 LanguageCode::Hebrew => write!(f, "he_IL"),
781 LanguageCode::Hungarian => write!(f, "hu_HU"),
782 LanguageCode::Indonesian => write!(f, "id_ID"),
783 LanguageCode::Italian => write!(f, "it"),
784 LanguageCode::Japanese => write!(f, "ja"),
785 LanguageCode::Korean => write!(f, "ko"),
786 LanguageCode::Persian => write!(f, "fa"),
787 LanguageCode::Polish => write!(f, "pl"),
788 LanguageCode::Portuguese => write!(f, "pt"),
789 LanguageCode::Romanian => write!(f, "ro"),
790 LanguageCode::Russian => write!(f, "ru"),
791 LanguageCode::Slovak => write!(f, "sk_SK"),
792 LanguageCode::Spanish => write!(f, "es"),
793 LanguageCode::Swedish => write!(f, "sv"),
794 LanguageCode::Thai => write!(f, "th"),
795 LanguageCode::Turkish => write!(f, "tr"),
796 LanguageCode::Vietnamese => write!(f, "vi"),
797 LanguageCode::Norwegian => write!(f, "no"),
798 LanguageCode::Malay => write!(f, "ms_MY"),
799 LanguageCode::TraditionalChinese => write!(f, "zh_TW"),
800 }
801 }
802}
803
804#[derive(Debug, Clone, PartialEq, Serialize)]
809#[serde(untagged)]
810pub enum FinancialPeriod {
811 FiscalYear,
813 FiscalQuarter,
815 FiscalHalfYear,
817 TrailingTwelveMonths,
819 UnknownPeriod(String),
821}
822
823impl<'de> Deserialize<'de> for FinancialPeriod {
824 fn deserialize<D>(deserializer: D) -> Result<FinancialPeriod, D::Error>
825 where
826 D: Deserializer<'de>,
827 {
828 let s: String = Deserialize::deserialize(deserializer)?;
829 match s.as_str() {
830 "FY" => Ok(FinancialPeriod::FiscalYear),
831 "FQ" => Ok(FinancialPeriod::FiscalQuarter),
832 "FH" => Ok(FinancialPeriod::FiscalHalfYear),
833 "TTM" => Ok(FinancialPeriod::TrailingTwelveMonths),
834 _ => Ok(FinancialPeriod::UnknownPeriod(s)),
835 }
836 }
837}
838
839impl Display for FinancialPeriod {
840 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
841 match *self {
842 FinancialPeriod::FiscalYear => write!(f, "FY"),
843 FinancialPeriod::FiscalQuarter => write!(f, "FQ"),
844 FinancialPeriod::FiscalHalfYear => write!(f, "FH"),
845 FinancialPeriod::TrailingTwelveMonths => write!(f, "TTM"),
846 FinancialPeriod::UnknownPeriod(ref s) => write!(f, "{s}"),
847 }
848 }
849}
850
851#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy, PartialEq, Eq, Hash)]
856pub enum SymbolType {
857 #[default]
859 Stock,
860 Index,
862 Forex,
864 Futures,
866 Bitcoin,
868 Crypto,
870 Undefined,
872 Expression,
874 Spread,
876 Cfd,
878 Economic,
880 Equity,
882 Dr,
884 Bond,
886 Right,
888 Warrant,
890 Fund,
892 Structured,
894 Commodity,
896 Fundamental,
898 Spot,
900}
901
902impl Display for SymbolType {
903 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
904 match *self {
905 SymbolType::Stock => write!(f, "stock"),
906 SymbolType::Index => write!(f, "index"),
907 SymbolType::Forex => write!(f, "forex"),
908 SymbolType::Futures => write!(f, "futures"),
909 SymbolType::Bitcoin => write!(f, "bitcoin"),
910 SymbolType::Crypto => write!(f, "crypto"),
911 SymbolType::Undefined => write!(f, "undefined"),
912 SymbolType::Expression => write!(f, "expression"),
913 SymbolType::Spread => write!(f, "spread"),
914 SymbolType::Cfd => write!(f, "cfd"),
915 SymbolType::Economic => write!(f, "economic"),
916 SymbolType::Equity => write!(f, "equity"),
917 SymbolType::Dr => write!(f, "dr"),
918 SymbolType::Bond => write!(f, "bond"),
919 SymbolType::Right => write!(f, "right"),
920 SymbolType::Warrant => write!(f, "warrant"),
921 SymbolType::Fund => write!(f, "fund"),
922 SymbolType::Structured => write!(f, "structured"),
923 SymbolType::Commodity => write!(f, "commodity"),
924 SymbolType::Fundamental => write!(f, "fundamental"),
925 SymbolType::Spot => write!(f, "spot"),
926 }
927 }
928}
929
930#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy, PartialEq, Eq, Hash)]
935pub enum MarketType {
936 #[default]
938 All,
939 Stocks(StocksType),
941 Funds(FundsType),
943 Futures,
945 Forex,
947 Crypto(CryptoType),
949 Indices,
951 Bonds,
953 Economy,
955}
956
957#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy, PartialEq, Eq, Hash)]
959pub enum StocksType {
960 #[default]
962 All,
963 Common,
965 Preferred,
967 DepositoryReceipt,
969 Warrant,
971}
972
973#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy, PartialEq, Eq, Hash)]
975pub enum CryptoType {
976 #[default]
978 All,
979 Spot,
981 Futures,
983 Swap,
985 Index,
987 Fundamental,
989}
990
991#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy, PartialEq, Eq, Hash)]
993pub enum FundsType {
994 #[default]
996 All,
997 ETF,
999 MutualFund,
1001 Trust,
1003 REIT,
1005}
1006
1007#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy, PartialEq, Eq, Hash)]
1012pub enum CryptoCentralization {
1013 #[default]
1015 CEX,
1016 DEX,
1018}
1019
1020impl From<&str> for MarketType {
1021 fn from(value: &str) -> Self {
1022 match value {
1023 "all" | "undefined" => All,
1024 "stock" => Stocks(StocksType::All),
1025 "common_stock" => Stocks(StocksType::Common),
1026 "preferred_stock" => Stocks(StocksType::Preferred),
1027 "depository_receipt" => Stocks(StocksType::DepositoryReceipt),
1028 "warrant" => Stocks(StocksType::Warrant),
1029 "fund" => Funds(FundsType::All),
1030 "etf" => Funds(FundsType::ETF),
1031 "mutual_fund" => Funds(FundsType::MutualFund),
1032 "trust_fund" => Funds(FundsType::Trust),
1033 "reit" => Funds(FundsType::REIT),
1034 "futures" => Futures,
1035 "forex" => Forex,
1036 "crypto" => Crypto(CryptoType::All),
1037 "crypto_spot" => Crypto(CryptoType::Spot),
1038 "crypto_futures" => Crypto(CryptoType::Futures),
1039 "crypto_swap" => Crypto(CryptoType::Swap),
1040 "crypto_index" => Crypto(CryptoType::Index),
1041 "crypto_fundamental" => Crypto(CryptoType::Fundamental),
1042 "index" => Indices,
1043 "bond" => Bonds,
1044 "economic" => Economy,
1045 _ => All,
1046 }
1047 }
1048}
1049
1050impl Display for MarketType {
1051 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1052 match *self {
1053 All => write!(f, "undefined"),
1054 Stocks(t) => match t {
1055 StocksType::All => write!(f, "stocks"),
1056 StocksType::Common => write!(f, "common_stock"),
1057 StocksType::Preferred => write!(f, "preferred_stock"),
1058 StocksType::DepositoryReceipt => write!(f, "depository_receipt"),
1059 StocksType::Warrant => write!(f, "warrant"),
1060 },
1061 Funds(t) => match t {
1062 FundsType::All => write!(f, "funds"),
1063 FundsType::ETF => write!(f, "etf"),
1064 FundsType::MutualFund => write!(f, "mutual_fund"),
1065 FundsType::Trust => write!(f, "trust_fund"),
1066 FundsType::REIT => write!(f, "reit"),
1067 },
1068 Futures => write!(f, "futures"),
1069 Forex => write!(f, "forex"),
1070 Crypto(t) => match t {
1071 CryptoType::All => write!(f, "crypto"),
1072 CryptoType::Spot => write!(f, "crypto_spot"),
1073 CryptoType::Futures => write!(f, "crypto_futures"),
1074 CryptoType::Swap => write!(f, "crypto_swap"),
1075 CryptoType::Index => write!(f, "crypto_index"),
1076 CryptoType::Fundamental => write!(f, "crypto_fundamental"),
1077 },
1078 Indices => write!(f, "index"),
1079 Bonds => write!(f, "bond"),
1080 Economy => write!(f, "economic"),
1081 }
1082 }
1083}
1084
1085impl Display for CryptoCentralization {
1086 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1087 match *self {
1088 CryptoCentralization::CEX => write!(f, "cex"),
1089 CryptoCentralization::DEX => write!(f, "dex"),
1090 }
1091 }
1092}
1093
1094#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy)]
1096pub enum FuturesProductType {
1097 SingleStock,
1099 WorldIndices,
1101 #[default]
1103 Currencies,
1104 InterestRates,
1106 Energy,
1108 Agriculture,
1110 Metals,
1112 Weather,
1114}
1115
1116impl Display for FuturesProductType {
1117 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1118 match *self {
1119 FuturesProductType::SingleStock => write!(f, "Financial%2FEquity"),
1120 FuturesProductType::WorldIndices => write!(f, "Financial%2FIndex"),
1121 FuturesProductType::Currencies => write!(f, "Financial%2FCurrency"),
1122 FuturesProductType::InterestRates => write!(f, "=Financial%2FInterestRate"),
1123 FuturesProductType::Energy => write!(f, "Financial%2FEnergy"),
1124 FuturesProductType::Agriculture => write!(f, "Financial%2FAgriculture"),
1125 FuturesProductType::Metals => write!(f, "Financial%2FMetals"),
1126 FuturesProductType::Weather => write!(f, "Financial%2FWeather"),
1127 }
1128 }
1129}
1130
1131#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy)]
1136pub enum StockSector {
1137 CommercialServices,
1139 Communications,
1141 ConsumerDurables,
1143 ConsumerNonDurables,
1145 ConsumerServices,
1147 DistributionServices,
1149 ElectronicTechnology,
1151 EnergyMinerals,
1153 #[default]
1155 Finance,
1156 Government,
1158 HealthServices,
1160 HealthTechnology,
1162 IndustrialServices,
1164 Miscellaneous,
1166 NonEnergyMinerals,
1168 ProcessIndustries,
1170 ProducerManufacturing,
1172 RetailTrade,
1174 TechnologyServices,
1176 Transportation,
1178 Utilities,
1180}
1181
1182impl Display for StockSector {
1183 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1184 match *self {
1185 StockSector::CommercialServices => write!(f, "Commercial+Services"),
1186 StockSector::Communications => write!(f, "Communications"),
1187 StockSector::ConsumerDurables => write!(f, "Consumer+Durables"),
1188 StockSector::ConsumerNonDurables => write!(f, "Consumer+Non-Durables"),
1189 StockSector::ConsumerServices => write!(f, "Consumer+Services"),
1190 StockSector::DistributionServices => write!(f, "Distribution+Services"),
1191 StockSector::ElectronicTechnology => write!(f, "Electronic+Technology"),
1192 StockSector::EnergyMinerals => write!(f, "Energy+Minerals"),
1193 StockSector::Finance => write!(f, "Finance"),
1194 StockSector::Government => write!(f, "Government"),
1195 StockSector::HealthServices => write!(f, "Health+Services"),
1196 StockSector::HealthTechnology => write!(f, "Health+Technology"),
1197 StockSector::IndustrialServices => write!(f, "Industrial+Services"),
1198 StockSector::Miscellaneous => write!(f, "Miscellaneous"),
1199 StockSector::NonEnergyMinerals => write!(f, "Non-Energy+Minerals"),
1200 StockSector::ProcessIndustries => write!(f, "Process+Industries"),
1201 StockSector::ProducerManufacturing => write!(f, "Producer+Manufacturing"),
1202 StockSector::RetailTrade => write!(f, "Retail+Trade"),
1203 StockSector::TechnologyServices => write!(f, "Technology+Services"),
1204 StockSector::Transportation => write!(f, "Transportation"),
1205 StockSector::Utilities => write!(f, "Utilities"),
1206 }
1207 }
1208}
1209
1210#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy)]
1214pub enum EconomicSource {
1215 #[default]
1217 WorldBank,
1218 EUROSTAT,
1220 AKAMAI,
1222 TransparencyInternational,
1224 OrganizationForEconomicCooperationAndDevelopment,
1226 WorldEconomicForum,
1228 WageIndicatorFoundation,
1230 BureauOfLaborStatistics,
1232 FederalReserve,
1234 StockholmInternationalPeaceResearchInstitute,
1236 InstituteForEconomicsAndPeace,
1238 BureauOfEconomicAnalysis,
1240 WorldGoldCouncil,
1242 CensusBureau,
1244 CentralBankOfWestAfricanStates,
1246 InternationalMonetaryFund,
1248 USEnergyInformationAdministration,
1250 StatisticCanada,
1252 OfficeForNationalStatistics,
1254 StatisticsNorway,
1256}
1257
1258#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy)]
1262pub enum EconomicCategory {
1263 #[default]
1265 GDP,
1266 Labor,
1268 Prices,
1270 Health,
1272 Money,
1274 Trade,
1276 Government,
1278 Business,
1280 Consumer,
1282 Housing,
1284 Taxes,
1286}
1287
1288impl Display for EconomicSource {
1289 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1290 match *self {
1291 EconomicSource::WorldBank => write!(f, "__WB"),
1292 EconomicSource::EUROSTAT => write!(f, "__EUROSTAT"),
1293 EconomicSource::AKAMAI => write!(f, "__AKAMAI"),
1294 EconomicSource::TransparencyInternational => write!(f, "__TI"),
1295 EconomicSource::OrganizationForEconomicCooperationAndDevelopment => write!(f, "__OECD"),
1296 EconomicSource::WorldEconomicForum => write!(f, "__WEF"),
1297 EconomicSource::WageIndicatorFoundation => write!(f, "__WIF"),
1298 EconomicSource::BureauOfLaborStatistics => write!(f, "USBLS"),
1299 EconomicSource::FederalReserve => write!(f, "USFR"),
1300 EconomicSource::StockholmInternationalPeaceResearchInstitute => write!(f, "__SIPRI"),
1301 EconomicSource::InstituteForEconomicsAndPeace => write!(f, "__IEP"),
1302 EconomicSource::BureauOfEconomicAnalysis => write!(f, "USBEA"),
1303 EconomicSource::WorldGoldCouncil => write!(f, "__WGC"),
1304 EconomicSource::CensusBureau => write!(f, "USCB"),
1305 EconomicSource::CentralBankOfWestAfricanStates => write!(f, "__BCEAO"),
1306 EconomicSource::InternationalMonetaryFund => write!(f, "__IMF"),
1307 EconomicSource::USEnergyInformationAdministration => write!(f, "__UEIA"),
1308 EconomicSource::StatisticCanada => write!(f, "CASC"),
1309 EconomicSource::OfficeForNationalStatistics => write!(f, "GBONS"),
1310 EconomicSource::StatisticsNorway => write!(f, "NOSN"),
1311 }
1312 }
1313}
1314
1315impl Display for EconomicCategory {
1316 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1317 match *self {
1318 EconomicCategory::GDP => write!(f, "gdp"),
1319 EconomicCategory::Labor => write!(f, "lbr"),
1320 EconomicCategory::Prices => write!(f, "prce"),
1321 EconomicCategory::Health => write!(f, "hlth"),
1322 EconomicCategory::Money => write!(f, "mny"),
1323 EconomicCategory::Trade => write!(f, "trd"),
1324 EconomicCategory::Government => write!(f, "gov"),
1325 EconomicCategory::Business => write!(f, "bsnss"),
1326 EconomicCategory::Consumer => write!(f, "cnsm"),
1327 EconomicCategory::Housing => write!(f, "hse"),
1328 EconomicCategory::Taxes => write!(f, "txs"),
1329 }
1330 }
1331}
1332
1333#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Default)]
1337pub struct TechnicalAnalysisRecommendations {
1338 #[serde(rename = "Other")]
1340 pub other: f64,
1341 #[serde(rename = "All")]
1343 pub all: f64,
1344 #[serde(rename = "MA")]
1346 pub ma: f64,
1347}
1348
1349pub type TechnicalAnalysisRecommendation = TechnicalAnalysisRecommendations;
1351pub type PeriodRecommendation = TechnicalAnalysisRecommendations;
1353
1354#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
1356pub enum TechnicalAnalysisPeriod {
1357 #[serde(rename = "1")]
1359 Minute1,
1360 #[serde(rename = "5")]
1362 Minute5,
1363 #[serde(rename = "15")]
1365 Minute15,
1366 #[serde(rename = "60")]
1368 Hour1,
1369 #[serde(rename = "240")]
1371 Hour4,
1372 #[serde(rename = "1D")]
1374 Day1,
1375 #[serde(rename = "1W")]
1377 Week1,
1378 #[serde(rename = "1M")]
1380 Month1,
1381}
1382
1383impl TechnicalAnalysisPeriod {
1384 pub const ALL: [Self; 8] = [
1386 Self::Minute1,
1387 Self::Minute5,
1388 Self::Minute15,
1389 Self::Hour1,
1390 Self::Hour4,
1391 Self::Day1,
1392 Self::Week1,
1393 Self::Month1,
1394 ];
1395
1396 pub const fn as_str(&self) -> &'static str {
1398 match self {
1399 Self::Minute1 => "1",
1400 Self::Minute5 => "5",
1401 Self::Minute15 => "15",
1402 Self::Hour1 => "60",
1403 Self::Hour4 => "240",
1404 Self::Day1 => "1D",
1405 Self::Week1 => "1W",
1406 Self::Month1 => "1M",
1407 }
1408 }
1409}
1410
1411pub type Period = TechnicalAnalysisPeriod;
1413
1414impl Display for TechnicalAnalysisPeriod {
1415 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1416 f.write_str(self.as_str())
1417 }
1418}
1419
1420#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Default)]
1422pub struct TechnicalAnalysis {
1423 #[serde(rename = "1")]
1425 pub period_1m: TechnicalAnalysisRecommendations,
1426 #[serde(rename = "5")]
1428 pub period_5m: TechnicalAnalysisRecommendations,
1429 #[serde(rename = "15")]
1431 pub period_15m: TechnicalAnalysisRecommendations,
1432 #[serde(rename = "60")]
1434 pub period_1h: TechnicalAnalysisRecommendations,
1435 #[serde(rename = "240")]
1437 pub period_4h: TechnicalAnalysisRecommendations,
1438 #[serde(rename = "1D")]
1440 pub period_1d: TechnicalAnalysisRecommendations,
1441 #[serde(rename = "1W")]
1443 pub period_1w: TechnicalAnalysisRecommendations,
1444 #[serde(rename = "1M")]
1446 pub period_1m_month: TechnicalAnalysisRecommendations,
1447}
1448
1449impl TechnicalAnalysis {
1450 pub fn get(&self, period: TechnicalAnalysisPeriod) -> &TechnicalAnalysisRecommendations {
1452 match period {
1453 TechnicalAnalysisPeriod::Minute1 => &self.period_1m,
1454 TechnicalAnalysisPeriod::Minute5 => &self.period_5m,
1455 TechnicalAnalysisPeriod::Minute15 => &self.period_15m,
1456 TechnicalAnalysisPeriod::Hour1 => &self.period_1h,
1457 TechnicalAnalysisPeriod::Hour4 => &self.period_4h,
1458 TechnicalAnalysisPeriod::Day1 => &self.period_1d,
1459 TechnicalAnalysisPeriod::Week1 => &self.period_1w,
1460 TechnicalAnalysisPeriod::Month1 => &self.period_1m_month,
1461 }
1462 }
1463
1464 pub fn period(&self, period: TechnicalAnalysisPeriod) -> &TechnicalAnalysisRecommendations {
1466 self.get(period)
1467 }
1468
1469 pub fn get_by_str(&self, period: &str) -> Option<&TechnicalAnalysisRecommendations> {
1471 match period {
1472 "1" => Some(&self.period_1m),
1473 "5" => Some(&self.period_5m),
1474 "15" => Some(&self.period_15m),
1475 "60" => Some(&self.period_1h),
1476 "240" => Some(&self.period_4h),
1477 "1D" => Some(&self.period_1d),
1478 "1W" => Some(&self.period_1w),
1479 "1M" => Some(&self.period_1m_month),
1480 _ => None,
1481 }
1482 }
1483}
1484
1485impl std::ops::Index<TechnicalAnalysisPeriod> for TechnicalAnalysis {
1486 type Output = TechnicalAnalysisRecommendations;
1487
1488 fn index(&self, period: TechnicalAnalysisPeriod) -> &Self::Output {
1489 self.get(period)
1490 }
1491}
1492
1493impl std::ops::Index<&str> for TechnicalAnalysis {
1494 type Output = TechnicalAnalysisRecommendations;
1495
1496 fn index(&self, period: &str) -> &Self::Output {
1497 self.get_by_str(period)
1498 .unwrap_or_else(|| panic!("invalid period: {period}"))
1499 }
1500}
1501
1502#[cfg(test)]
1503mod tests {
1504 use super::*;
1505
1506 #[test]
1507 fn test_symbol_id_prefers_prefix_over_exchange() {
1508 let sym_prefixed = Symbol {
1509 symbol: "SPY".to_string(),
1510 exchange: "NYSE Arca".to_string(),
1511 prefix: "AMEX".to_string(),
1512 ..Default::default()
1513 };
1514 assert_eq!(sym_prefixed.id(), "AMEX:SPY");
1515 assert_eq!(MarketSymbol::id(&sym_prefixed), "AMEX:SPY");
1516
1517 let sym_empty_prefix = Symbol {
1518 symbol: "BTCUSDT".to_string(),
1519 exchange: "BINANCE".to_string(),
1520 prefix: "".to_string(),
1521 ..Default::default()
1522 };
1523 assert_eq!(sym_empty_prefix.id(), "BINANCE:BTCUSDT");
1524 assert_eq!(MarketSymbol::id(&sym_empty_prefix), "BINANCE:BTCUSDT");
1525 }
1526
1527 #[test]
1528 fn test_symbol_builder_with_prefix() {
1529 let sym = Symbol::builder()
1530 .symbol("SPY")
1531 .exchange("NYSE Arca")
1532 .prefix("AMEX")
1533 .build();
1534 assert_eq!(sym.id(), "AMEX:SPY");
1535
1536 let sym_default = Symbol::builder()
1537 .symbol("BTCUSDT")
1538 .exchange("BINANCE")
1539 .build();
1540 assert_eq!(sym_default.id(), "BINANCE:BTCUSDT");
1541 }
1542
1543 #[test]
1544 fn test_period_properties() {
1545 assert_eq!(TechnicalAnalysisPeriod::ALL.len(), 8);
1546 assert_eq!(Period::Day1.as_str(), "1D");
1547 assert_eq!(format!("{}", Period::Month1), "1M");
1548 }
1549}