Skip to main content

tradingview/models/
mod.rs

1//! Shared data types used across the crate.
2//!
3//! This module defines the core domain model for interacting with TradingView:
4//! market data types, symbol representations, time intervals, and search
5//! responses. Most types are `Serialize` + `Deserialize` for wire compatibility
6//! with TradingView's protocols.
7//!
8//! # Key Types
9//!
10//! | Type | Purpose |
11//! |------|---------|
12//! | [`Symbol`] | A tradable instrument (e.g. `BINANCE:BTCUSDT`) |
13//! | [`Interval`] | Time granularity for OHLCV bars |
14//! | [`SymbolType`] / [`MarketType`] | Categorization of instruments |
15//! | [`ChartOptions`] | Configuration for chart data subscriptions |
16//! | [`UserCookies`] | Authenticated session state |
17//! | [`OHLCV`] | A single OHLCV bar with timestamp |
18//!
19//! [`Symbol`]: Symbol
20//! [`Interval`]: Interval
21//! [`SymbolType`]: SymbolType
22//! [`MarketType`]: MarketType
23//! [`ChartOptions`]: crate::chart::ChartOptions
24//! [`UserCookies`]: UserCookies
25//! [`OHLCV`]: crate::chart::OHLCV
26
27pub 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
39/// Trait for types that carry a symbol–exchange pair.
40///
41/// Provides a standard way to construct the TradingView-style identifier
42/// `"EXCHANGE:SYMBOL"` (e.g. `"BINANCE:BTCUSDT"`).
43pub trait MarketSymbol {
44    /// Create a new instance from symbol and exchange strings.
45    fn new<S: Into<String>>(symbol: S, exchange: S) -> Self;
46    /// The raw symbol/ticker (e.g. `"BTCUSDT"`).
47    fn symbol(&self) -> &str;
48    /// The exchange name (e.g. `"BINANCE"`).
49    fn exchange(&self) -> &str;
50    /// The combined identifier `"EXCHANGE:SYMBOL"`.
51    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    fn new<S: Into<String>>(symbol: S, exchange: S) -> Self {
65        Self {
66            symbol: symbol.into(),
67            exchange: exchange.into(),
68            ..Default::default()
69        }
70    }
71}
72
73/// A chart drawing retrieved from TradingView (lines, shapes, annotations, etc.).
74#[derive(Debug, Clone, Default, Serialize, Deserialize)]
75pub struct ChartDrawing {
76    pub success: bool,
77    pub payload: ChartDrawingSource,
78}
79
80/// Container for chart drawing source data, keyed by drawing ID.
81#[derive(Debug, Clone, Default, Serialize, Deserialize)]
82pub struct ChartDrawingSource {
83    pub sources: HashMap<String, ChartDrawingSourceData>,
84}
85
86/// Per-drawing metadata: symbol, currency, update time, and state.
87#[derive(Debug, Clone, Default, Serialize, Deserialize)]
88#[serde(rename_all = "camelCase")]
89pub struct ChartDrawingSourceData {
90    id: String,
91    symbol: String,
92    currency_id: String,
93    server_update_time: i64,
94    state: ChartDrawingSourceState,
95}
96
97/// The geometric state of a drawing: a collection of time/price anchor points.
98#[derive(Debug, Clone, Default, Serialize, Deserialize)]
99#[serde(rename_all = "camelCase")]
100pub struct ChartDrawingSourceState {
101    points: Vec<ChartDrawingSourceStatePoint>,
102}
103
104/// A single anchor point in a chart drawing (time, offset, price).
105#[derive(Debug, Clone, Default, Serialize, Deserialize)]
106pub struct ChartDrawingSourceStatePoint {
107    time_t: i64,
108    offset: i64,
109    price: f64,
110}
111
112/// Authenticated TradingView user session state.
113///
114/// Contains the credentials needed for premium features: auth token, session
115/// hash, device token, and private channel ID. Obtain via
116/// [`UserCookies::login`].
117///
118/// Serialize to JSON for session persistence across restarts.
119#[derive(Clone, Serialize, Deserialize, Debug, Default)]
120pub struct UserCookies {
121    pub id: u32,
122    pub username: String,
123    pub private_channel: String,
124    pub auth_token: String,
125    #[serde(default)]
126    pub session: String,
127    #[serde(default)]
128    pub session_signature: String,
129    pub session_hash: String,
130    #[serde(default)]
131    pub device_token: String,
132}
133
134/// Response from the TradingView symbol search endpoint.
135///
136/// `remaining` counts how many results are left beyond the returned page.
137/// `symbols` is the current page of matches.
138#[derive(Debug, Clone, Default, Deserialize)]
139pub struct SymbolSearchResponse {
140    #[serde(rename(deserialize = "symbols_remaining"))]
141    pub remaining: u64,
142    pub symbols: Vec<Symbol>,
143}
144
145/// A tradable instrument on TradingView.
146///
147/// The canonical identifier is `"EXCHANGE:SYMBOL"` (e.g. `"NASDAQ:AAPL"`,
148/// `"BINANCE:BTCUSDT"`). Use [`Symbol::id()`] to obtain this string.
149///
150/// Construct via the builder:
151///
152/// ```rust
153/// use tradingview::Symbol;
154/// let sym = Symbol::builder()
155///     .symbol("BTCUSDT")
156///     .exchange("BINANCE")
157///     .build();
158/// ```
159#[derive(Clone, PartialEq, Deserialize, Serialize, Debug, Default, Hash)]
160pub struct Symbol {
161    pub symbol: String,
162    #[serde(default)]
163    pub description: String,
164    #[serde(default, rename(deserialize = "type"))]
165    pub market_type: String,
166    #[serde(default)]
167    pub exchange: String,
168    #[serde(default)]
169    pub currency_code: String,
170    #[serde(default, rename(deserialize = "provider_id"))]
171    pub data_provider: String,
172    #[serde(default, rename(deserialize = "country"))]
173    pub country_code: String,
174    #[serde(default, rename(deserialize = "typespecs"))]
175    pub type_specs: Vec<String>,
176    #[serde(default, rename(deserialize = "source2"))]
177    pub exchange_source: ExchangeSource,
178}
179
180#[bon::bon]
181impl Symbol {
182    #[builder]
183    pub fn new<S: Into<String>>(symbol: S, exchange: S, currency: Option<Currency>) -> Self {
184        Self {
185            symbol: symbol.into(),
186            exchange: exchange.into(),
187            currency_code: currency.map(|c| c.to_string()).unwrap_or_default(),
188            ..Default::default()
189        }
190    }
191
192    pub fn id(&self) -> String {
193        format!("{}:{}", self.exchange, self.symbol)
194    }
195}
196
197/// Metadata about an exchange / data source.
198///
199/// Returned as part of [`Symbol`] search results to identify the originating
200/// market data provider.
201#[derive(Clone, PartialEq, Deserialize, Serialize, Debug, Default, Hash)]
202pub struct ExchangeSource {
203    pub id: String,
204    pub name: String,
205    pub description: String,
206}
207
208/// Which part of the trading session to request.
209#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy, PartialEq, Eq, Hash)]
210pub enum SessionType {
211    /// Standard market hours.
212    #[default]
213    Regular,
214    /// Extended-hours trading.
215    Extended,
216    /// Pre-market session.
217    PreMarket,
218    /// Post-market / after-hours session.
219    PostMarket,
220}
221
222impl Display for SessionType {
223    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
224        match self {
225            SessionType::Regular => write!(f, "regular"),
226            SessionType::Extended => write!(f, "extended"),
227            SessionType::PreMarket => write!(f, "premarket"),
228            SessionType::PostMarket => write!(f, "postmarket"),
229        }
230    }
231}
232
233/// Data adjustment applied to historical OHLCV bars.
234///
235/// When `Splits`, prices are adjusted for stock splits. When `Dividends`,
236/// prices are adjusted for dividend payments.
237#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy)]
238pub enum MarketAdjustment {
239    /// Adjust for stock splits.
240    #[default]
241    Splits,
242    /// Adjust for dividend payments.
243    Dividends,
244}
245
246impl Display for MarketAdjustment {
247    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
248        match self {
249            MarketAdjustment::Splits => write!(f, "splits"),
250            MarketAdjustment::Dividends => write!(f, "dividends"),
251        }
252    }
253}
254
255/// Current market session status as reported by TradingView.
256#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy)]
257pub enum MarketStatus {
258    /// Market is closed for a holiday.
259    Holiday,
260    /// Regular market hours — market is open.
261    #[default]
262    Open,
263    /// Market is closed (out of session).
264    Close,
265    /// Post-market / after-hours trading.
266    Post,
267    /// Pre-market trading.
268    Pre,
269}
270
271impl Display for MarketStatus {
272    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
273        match self {
274            MarketStatus::Holiday => write!(f, "holiday"),
275            MarketStatus::Open => write!(f, "market"),
276            MarketStatus::Close => write!(f, "out_of_session"),
277            MarketStatus::Post => write!(f, "post_market"),
278            MarketStatus::Pre => write!(f, "pre_market"),
279        }
280    }
281}
282
283/// IANA timezone identifier for exchange trading schedules.
284///
285/// Maps to TradingView's timezone format. Default is [`EtcUTC`](Timezone::EtcUTC).
286#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy, PartialEq, Eq, Hash)]
287pub enum Timezone {
288    /// Africa/Cairo
289    AfricaCairo,
290    AfricaCasablanca,
291    AfricaJohannesburg,
292    AfricaLagos,
293    AfricaNairobi,
294    AfricaTunis,
295    AmericaAnchorage,
296    AmericaArgentinaBuenosAires,
297    AmericaBogota,
298    AmericaCaracas,
299    AmericaChicago,
300    AmericaElSalvador,
301    AmericaJuneau,
302    AmericaLima,
303    AmericaLosAngeles,
304    AmericaMexicoCity,
305    AmericaNewYork,
306    AmericaPhoenix,
307    AmericaSantiago,
308    AmericaSaoPaulo,
309    AmericaToronto,
310    AmericaVancouver,
311    AsiaAlmaty,
312    AsiaAshkhabad,
313    AsiaBahrain,
314    AsiaBangkok,
315    AsiaChongqing,
316    AsiaColombo,
317    AsiaDhaka,
318    AsiaDubai,
319    AsiaHoChiMinh,
320    AsiaHongKong,
321    AsiaJakarta,
322    AsiaJerusalem,
323    AsiaKarachi,
324    AsiaKathmandu,
325    AsiaKolkata,
326    AsiaKuwait,
327    AsiaManila,
328    AsiaMuscat,
329    AsiaNicosia,
330    AsiaQatar,
331    AsiaRiyadh,
332    AsiaSeoul,
333    AsiaShanghai,
334    AsiaSingapore,
335    AsiaTaipei,
336    AsiaTehran,
337    AsiaTokyo,
338    AsiaYangon,
339    AtlanticReykjavik,
340    AustraliaAdelaide,
341    AustraliaBrisbane,
342    AustraliaPerth,
343    AustraliaSydney,
344    EuropeAmsterdam,
345    EuropeAthens,
346    EuropeBelgrade,
347    EuropeBerlin,
348    EuropeBratislava,
349    EuropeBrussels,
350    EuropeBucharest,
351    EuropeBudapest,
352    EuropeCopenhagen,
353    EuropeDublin,
354    EuropeHelsinki,
355    EuropeIstanbul,
356    EuropeLisbon,
357    EuropeLondon,
358    EuropeLuxembourg,
359    EuropeMadrid,
360    EuropeMalta,
361    EuropeMoscow,
362    EuropeOslo,
363    EuropeParis,
364    EuropeRiga,
365    EuropeRome,
366    EuropeStockholm,
367    EuropeTallinn,
368    EuropeVilnius,
369    EuropeWarsaw,
370    EuropeZurich,
371    PacificAuckland,
372    PacificChatham,
373    PacificFakaofo,
374    PacificHonolulu,
375    PacificNorfolk,
376    USMountain,
377    #[default]
378    EtcUTC,
379}
380
381impl Display for Timezone {
382    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
383        match self {
384            Timezone::AfricaCairo => write!(f, "Africa/Cairo"),
385            Timezone::AfricaCasablanca => write!(f, "Africa/Casablanca"),
386            Timezone::AfricaJohannesburg => write!(f, "Africa/Johannesburg"),
387            Timezone::AfricaLagos => write!(f, "Africa/Lagos"),
388            Timezone::AfricaNairobi => write!(f, "Africa/Nairobi"),
389            Timezone::AfricaTunis => write!(f, "Africa/Tunis"),
390            Timezone::AmericaAnchorage => write!(f, "America/Anchorage"),
391            Timezone::AmericaArgentinaBuenosAires => write!(f, "America/Argentina/Buenos_Aires"),
392            Timezone::AmericaBogota => write!(f, "America/Bogota"),
393            Timezone::AmericaCaracas => write!(f, "America/Caracas"),
394            Timezone::AmericaChicago => write!(f, "America/Chicago"),
395            Timezone::AmericaElSalvador => write!(f, "America/El_Salvador"),
396            Timezone::AmericaJuneau => write!(f, "America/Juneau"),
397            Timezone::AmericaLima => write!(f, "America/Lima"),
398            Timezone::AmericaLosAngeles => write!(f, "America/Los_Angeles"),
399            Timezone::AmericaMexicoCity => write!(f, "America/Mexico_City"),
400            Timezone::AmericaNewYork => write!(f, "America/New_York"),
401            Timezone::AmericaPhoenix => write!(f, "America/Phoenix"),
402            Timezone::AmericaSantiago => write!(f, "America/Santiago"),
403            Timezone::AmericaSaoPaulo => write!(f, "America/Sao_Paulo"),
404            Timezone::AmericaToronto => write!(f, "America/Toronto"),
405            Timezone::AmericaVancouver => write!(f, "America/Vancouver"),
406            Timezone::AsiaAlmaty => write!(f, "Asia/Almaty"),
407            Timezone::AsiaAshkhabad => write!(f, "Asia/Ashkhabad"),
408            Timezone::AsiaBahrain => write!(f, "Asia/Bahrain"),
409            Timezone::AsiaBangkok => write!(f, "Asia/Bangkok"),
410            Timezone::AsiaChongqing => write!(f, "Asia/Chongqing"),
411            Timezone::AsiaColombo => write!(f, "Asia/Colombo"),
412            Timezone::AsiaDhaka => write!(f, "Asia/Dhaka"),
413            Timezone::AsiaDubai => write!(f, "Asia/Dubai"),
414            Timezone::AsiaHoChiMinh => write!(f, "Asia/Ho_Chi_Minh"),
415            Timezone::AsiaHongKong => write!(f, "Asia/Hong_Kong"),
416            Timezone::AsiaJakarta => write!(f, "Asia/Jakarta"),
417            Timezone::AsiaJerusalem => write!(f, "Asia/Jerusalem"),
418            Timezone::AsiaKarachi => write!(f, "Asia/Karachi"),
419            Timezone::AsiaKathmandu => write!(f, "Asia/Kathmandu"),
420            Timezone::AsiaKolkata => write!(f, "Asia/Kolkata"),
421            Timezone::AsiaKuwait => write!(f, "Asia/Kuwait"),
422            Timezone::AsiaManila => write!(f, "Asia/Manila"),
423            Timezone::AsiaMuscat => write!(f, "Asia/Muscat"),
424            Timezone::AsiaNicosia => write!(f, "Asia/Nicosia"),
425            Timezone::AsiaQatar => write!(f, "Asia/Qatar"),
426            Timezone::AsiaRiyadh => write!(f, "Asia/Riyadh"),
427            Timezone::AsiaSeoul => write!(f, "Asia/Seoul"),
428            Timezone::AsiaShanghai => write!(f, "Asia/Shanghai"),
429            Timezone::AsiaSingapore => write!(f, "Asia/Singapore"),
430            Timezone::AsiaTaipei => write!(f, "Asia/Taipei"),
431            Timezone::AsiaTehran => write!(f, "Asia/Tehran"),
432            Timezone::AsiaTokyo => write!(f, "Asia/Tokyo"),
433            Timezone::AsiaYangon => write!(f, "Asia/Yangon"),
434            Timezone::AtlanticReykjavik => write!(f, "Atlantic/Reykjavik"),
435            Timezone::AustraliaAdelaide => write!(f, "Australia/Adelaide"),
436            Timezone::AustraliaBrisbane => write!(f, "Australia/Brisbane"),
437            Timezone::AustraliaPerth => write!(f, "Australia/Perth"),
438            Timezone::AustraliaSydney => write!(f, "Australia/Sydney"),
439            Timezone::EuropeAmsterdam => write!(f, "Europe/Amsterdam"),
440            Timezone::EuropeAthens => write!(f, "Europe/Athens"),
441            Timezone::EuropeBelgrade => write!(f, "Europe/Belgrade"),
442            Timezone::EuropeBerlin => write!(f, "Europe/Berlin"),
443            Timezone::EuropeBratislava => write!(f, "Europe/Bratislava"),
444            Timezone::EuropeBrussels => write!(f, "Europe/Brussels"),
445            Timezone::EuropeBucharest => write!(f, "Europe/Bucharest"),
446            Timezone::EuropeBudapest => write!(f, "Europe/Budapest"),
447            Timezone::EuropeCopenhagen => write!(f, "Europe/Copenhagen"),
448            Timezone::EuropeDublin => write!(f, "Europe/Dublin"),
449            Timezone::EuropeHelsinki => write!(f, "Europe/Helsinki"),
450            Timezone::EuropeIstanbul => write!(f, "Europe/Istanbul"),
451            Timezone::EuropeLisbon => write!(f, "Europe/Lisbon"),
452            Timezone::EuropeLondon => write!(f, "Europe/London"),
453            Timezone::EuropeLuxembourg => write!(f, "Europe/Luxembourg"),
454            Timezone::EuropeMadrid => write!(f, "Europe/Madrid"),
455            Timezone::EuropeMalta => write!(f, "Europe/Malta"),
456            Timezone::EuropeMoscow => write!(f, "Europe/Moscow"),
457            Timezone::EuropeOslo => write!(f, "Europe/Oslo"),
458            Timezone::EuropeParis => write!(f, "Europe/Paris"),
459            Timezone::EuropeRiga => write!(f, "Europe/Riga"),
460            Timezone::EuropeRome => write!(f, "Europe/Rome"),
461            Timezone::EuropeStockholm => write!(f, "Europe/Stockholm"),
462            Timezone::EuropeTallinn => write!(f, "Europe/Tallinn"),
463            Timezone::EuropeVilnius => write!(f, "Europe/Vilnius"),
464            Timezone::EuropeWarsaw => write!(f, "Europe/Warsaw"),
465            Timezone::EuropeZurich => write!(f, "Europe/Zurich"),
466            Timezone::PacificAuckland => write!(f, "Pacific/Auckland"),
467            Timezone::PacificChatham => write!(f, "Pacific/Chatham"),
468            Timezone::PacificFakaofo => write!(f, "Pacific/Fakaofo"),
469            Timezone::PacificHonolulu => write!(f, "Pacific/Honolulu"),
470            Timezone::PacificNorfolk => write!(f, "Pacific/Norfolk"),
471            Timezone::USMountain => write!(f, "US/Mountain"),
472            Timezone::EtcUTC => write!(f, "Etc/UTC"),
473        }
474    }
475}
476
477/// Time interval (granularity) for OHLCV/candle bars.
478///
479/// This is one of the most-used types in the crate. Every historical and
480/// real-time data request specifies an interval. The default is `OneDay`.
481///
482/// # Conversion
483///
484/// - `From<&str>` parses common string representations (`"1h"`, `"1D"`, `"1W"`, etc.).
485/// - `From<u8>` maps TradingView's numeric interval codes.
486/// - `From<Interval> for chrono::Duration` provides an approximate duration.
487/// - [`Display`] outputs the TradingView wire format.
488///
489/// # Navigation
490///
491/// [`Interval::longer()`] steps up to the next coarser interval.
492///
493/// [`Interval::longer()`]: Interval::longer()
494#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy, PartialEq, Eq, Hash)]
495pub enum Interval {
496    /// 1 second.
497    OneSecond = 0,
498    /// 5 seconds.
499    FiveSeconds = 1,
500    /// 10 seconds.
501    TenSeconds = 2,
502    /// 15 seconds.
503    FifteenSeconds = 3,
504    /// 30 seconds.
505    ThirtySeconds = 4,
506    /// 1 minute.
507    OneMinute = 5,
508    /// 3 minutes.
509    ThreeMinutes = 6,
510    /// 5 minutes.
511    FiveMinutes = 7,
512    /// 15 minutes.
513    FifteenMinutes = 8,
514    /// 30 minutes.
515    ThirtyMinutes = 9,
516    /// 45 minutes.
517    FortyFiveMinutes = 10,
518    /// 1 hour.
519    OneHour = 11,
520    /// 2 hours.
521    TwoHours = 12,
522    /// 4 hours.
523    FourHours = 13,
524    /// 1 day (default).
525    #[default]
526    OneDay = 14,
527    /// 1 week.
528    OneWeek = 15,
529    /// 1 month.
530    OneMonth = 16,
531    /// 1 quarter (~3 months).
532    OneQuarter = 17,
533    /// 6 months.
534    SixMonths = 18,
535    /// 1 year.
536    Yearly = 19,
537}
538
539impl Interval {
540    pub fn longer(self) -> Interval {
541        match self {
542            Interval::OneSecond => Interval::FiveSeconds,
543            Interval::FiveSeconds => Interval::TenSeconds,
544            Interval::TenSeconds => Interval::FifteenSeconds,
545            Interval::FifteenSeconds => Interval::ThirtySeconds,
546            Interval::ThirtySeconds => Interval::OneMinute,
547            Interval::OneMinute => Interval::ThreeMinutes,
548            Interval::ThreeMinutes => Interval::FiveMinutes,
549            Interval::FiveMinutes => Interval::FifteenMinutes,
550            Interval::FifteenMinutes => Interval::ThirtyMinutes,
551            Interval::ThirtyMinutes => Interval::FortyFiveMinutes,
552            Interval::FortyFiveMinutes => Interval::OneHour,
553            Interval::OneHour => Interval::TwoHours,
554            Interval::TwoHours => Interval::FourHours,
555            Interval::FourHours => Interval::OneDay,
556            Interval::OneDay => Interval::OneWeek,
557            Interval::OneWeek => Interval::OneMonth,
558            Interval::OneMonth => Interval::OneQuarter,
559            Interval::OneQuarter => Interval::SixMonths,
560            _ => self, // Yearly remains the same
561        }
562    }
563}
564
565impl From<u8> for Interval {
566    fn from(value: u8) -> Self {
567        match value {
568            0 => Interval::OneSecond,
569            1 => Interval::FiveSeconds,
570            2 => Interval::TenSeconds,
571            3 => Interval::FifteenSeconds,
572            4 => Interval::ThirtySeconds,
573            5 => Interval::OneMinute,
574            6 => Interval::ThreeMinutes,
575            7 => Interval::FiveMinutes,
576            8 => Interval::FifteenMinutes,
577            9 => Interval::ThirtyMinutes,
578            10 => Interval::FortyFiveMinutes,
579            11 => Interval::OneHour,
580            12 => Interval::TwoHours,
581            13 => Interval::FourHours,
582            14 => Interval::OneDay,
583            15 => Interval::OneWeek,
584            16 => Interval::OneMonth,
585            17 => Interval::OneQuarter,
586            18 => Interval::SixMonths,
587            _ => Interval::Yearly, // Default to Yearly for any other value
588        }
589    }
590}
591
592impl From<Interval> for Duration {
593    fn from(interval: Interval) -> Self {
594        match interval {
595            Interval::OneSecond => Duration::seconds(1),
596            Interval::FiveSeconds => Duration::seconds(5),
597            Interval::TenSeconds => Duration::seconds(10),
598            Interval::FifteenSeconds => Duration::seconds(15),
599            Interval::ThirtySeconds => Duration::seconds(30),
600            Interval::OneMinute => Duration::minutes(1),
601            Interval::ThreeMinutes => Duration::minutes(3),
602            Interval::FiveMinutes => Duration::minutes(5),
603            Interval::FifteenMinutes => Duration::minutes(15),
604            Interval::ThirtyMinutes => Duration::minutes(30),
605            Interval::FortyFiveMinutes => Duration::minutes(45),
606            Interval::OneHour => Duration::hours(1),
607            Interval::TwoHours => Duration::hours(2),
608            Interval::FourHours => Duration::hours(4),
609            Interval::OneDay => Duration::days(1),
610            Interval::OneWeek => Duration::weeks(1),
611            Interval::OneMonth => Duration::days(30), // Approximation
612            Interval::OneQuarter => Duration::days(90), // Approximation
613            Interval::SixMonths => Duration::days(180), // Approximation
614            Interval::Yearly => Duration::days(365),  // Approximation
615        }
616    }
617}
618
619impl From<&str> for Interval {
620    fn from(value: &str) -> Self {
621        match value {
622            "1s" => Interval::OneSecond,
623            "5s" => Interval::FiveSeconds,
624            "10s" => Interval::TenSeconds,
625            "15s" => Interval::FifteenSeconds,
626            "30s" => Interval::ThirtySeconds,
627            "1m" => Interval::OneMinute,
628            "3m" => Interval::ThreeMinutes,
629            "5m" => Interval::FiveMinutes,
630            "15m" => Interval::FifteenMinutes,
631            "30m" => Interval::ThirtyMinutes,
632            "45m" => Interval::FortyFiveMinutes,
633            "1h" => Interval::OneHour,
634            "2h" => Interval::TwoHours,
635            "4h" => Interval::FourHours,
636            "1d" => Interval::OneDay,
637            "7d" => Interval::OneWeek,
638            "30d" => Interval::OneMonth,
639            "120d" => Interval::OneQuarter,
640            "180d" => Interval::SixMonths,
641            "1y" => Interval::Yearly,
642            _ => Interval::OneDay,
643        }
644    }
645}
646
647impl Display for Interval {
648    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
649        let time_interval = match self {
650            Interval::OneSecond => "1S",
651            Interval::FiveSeconds => "5S",
652            Interval::TenSeconds => "10S",
653            Interval::FifteenSeconds => "15S",
654            Interval::ThirtySeconds => "30S",
655            Interval::OneMinute => "1",
656            Interval::ThreeMinutes => "3",
657            Interval::FiveMinutes => "5",
658            Interval::FifteenMinutes => "15",
659            Interval::ThirtyMinutes => "30",
660            Interval::FortyFiveMinutes => "45",
661            Interval::OneHour => "1H",
662            Interval::TwoHours => "2H",
663            Interval::FourHours => "4H",
664            Interval::OneDay => "1D",
665            Interval::OneWeek => "1W",
666            Interval::OneMonth => "1M",
667            Interval::OneQuarter => "3M",
668            Interval::SixMonths => "6M",
669            Interval::Yearly => "12M",
670        };
671        write!(f, "{time_interval}")
672    }
673}
674
675/// Supported UI language for TradingView responses (news, descriptions, etc.).
676///
677/// Default is [`English`](LanguageCode::English).
678#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy)]
679pub enum LanguageCode {
680    /// Arabic.
681    Arabic,
682    /// Chinese (Simplified).
683    Chinese,
684    /// Czech.
685    Czech,
686    /// Danish.
687    Danish,
688    /// Catalan.
689    Catalan,
690    /// Dutch.
691    Dutch,
692    /// English (default).
693    #[default]
694    English,
695    /// Estonian.
696    Estonian,
697    /// French.
698    French,
699    /// German.
700    German,
701    /// Greek.
702    Greek,
703    /// Hebrew.
704    Hebrew,
705    /// Hungarian.
706    Hungarian,
707    /// Indonesian.
708    Indonesian,
709    /// Italian.
710    Italian,
711    /// Japanese.
712    Japanese,
713    /// Korean.
714    Korean,
715    /// Persian (Farsi).
716    Persian,
717    /// Polish.
718    Polish,
719    /// Portuguese.
720    Portuguese,
721    /// Romanian.
722    Romanian,
723    /// Russian.
724    Russian,
725    /// Slovak.
726    Slovak,
727    /// Spanish.
728    Spanish,
729    /// Swedish.
730    Swedish,
731    /// Thai.
732    Thai,
733    /// Turkish.
734    Turkish,
735    /// Vietnamese.
736    Vietnamese,
737    /// Norwegian.
738    Norwegian,
739    /// Malay.
740    Malay,
741    /// Chinese (Traditional).
742    TraditionalChinese,
743}
744
745impl Display for LanguageCode {
746    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
747        match *self {
748            LanguageCode::Arabic => write!(f, "ar"),
749            LanguageCode::Chinese => write!(f, "zh"),
750            LanguageCode::Czech => write!(f, "cs"),
751            LanguageCode::Danish => write!(f, "da_DK"),
752            LanguageCode::Catalan => write!(f, "ca_ES"),
753            LanguageCode::Dutch => write!(f, "nl_NL"),
754            LanguageCode::English => write!(f, "en"),
755            LanguageCode::Estonian => write!(f, "et_EE"),
756            LanguageCode::French => write!(f, "fr"),
757            LanguageCode::German => write!(f, "de"),
758            LanguageCode::Greek => write!(f, "el"),
759            LanguageCode::Hebrew => write!(f, "he_IL"),
760            LanguageCode::Hungarian => write!(f, "hu_HU"),
761            LanguageCode::Indonesian => write!(f, "id_ID"),
762            LanguageCode::Italian => write!(f, "it"),
763            LanguageCode::Japanese => write!(f, "ja"),
764            LanguageCode::Korean => write!(f, "ko"),
765            LanguageCode::Persian => write!(f, "fa"),
766            LanguageCode::Polish => write!(f, "pl"),
767            LanguageCode::Portuguese => write!(f, "pt"),
768            LanguageCode::Romanian => write!(f, "ro"),
769            LanguageCode::Russian => write!(f, "ru"),
770            LanguageCode::Slovak => write!(f, "sk_SK"),
771            LanguageCode::Spanish => write!(f, "es"),
772            LanguageCode::Swedish => write!(f, "sv"),
773            LanguageCode::Thai => write!(f, "th"),
774            LanguageCode::Turkish => write!(f, "tr"),
775            LanguageCode::Vietnamese => write!(f, "vi"),
776            LanguageCode::Norwegian => write!(f, "no"),
777            LanguageCode::Malay => write!(f, "ms_MY"),
778            LanguageCode::TraditionalChinese => write!(f, "zh_TW"),
779        }
780    }
781}
782
783/// Financial reporting period for fundamental data.
784///
785/// Serialized as an untagged string (`"FY"`, `"FQ"`, `"FH"`, `"TTM"`, or any
786/// other custom period string).
787#[derive(Debug, Clone, PartialEq, Serialize)]
788#[serde(untagged)]
789pub enum FinancialPeriod {
790    /// Fiscal year.
791    FiscalYear,
792    /// Fiscal quarter.
793    FiscalQuarter,
794    /// Fiscal half-year.
795    FiscalHalfYear,
796    /// Trailing twelve months.
797    TrailingTwelveMonths,
798    /// Catch-all for unrecognized period strings.
799    UnknownPeriod(String),
800}
801
802impl<'de> Deserialize<'de> for FinancialPeriod {
803    fn deserialize<D>(deserializer: D) -> Result<FinancialPeriod, D::Error>
804    where
805        D: Deserializer<'de>,
806    {
807        let s: String = Deserialize::deserialize(deserializer)?;
808        match s.as_str() {
809            "FY" => Ok(FinancialPeriod::FiscalYear),
810            "FQ" => Ok(FinancialPeriod::FiscalQuarter),
811            "FH" => Ok(FinancialPeriod::FiscalHalfYear),
812            "TTM" => Ok(FinancialPeriod::TrailingTwelveMonths),
813            _ => Ok(FinancialPeriod::UnknownPeriod(s)),
814        }
815    }
816}
817
818impl Display for FinancialPeriod {
819    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
820        match *self {
821            FinancialPeriod::FiscalYear => write!(f, "FY"),
822            FinancialPeriod::FiscalQuarter => write!(f, "FQ"),
823            FinancialPeriod::FiscalHalfYear => write!(f, "FH"),
824            FinancialPeriod::TrailingTwelveMonths => write!(f, "TTM"),
825            FinancialPeriod::UnknownPeriod(ref s) => write!(f, "{s}"),
826        }
827    }
828}
829
830/// Broad instrument type classification.
831///
832/// Used in symbol search filtering and displayed in TradingView's symbol info.
833/// Default is [`Stock`](SymbolType::Stock).
834#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy, PartialEq, Eq, Hash)]
835pub enum SymbolType {
836    /// Common or preferred stock.
837    #[default]
838    Stock,
839    /// Market index.
840    Index,
841    /// Forex / currency pair.
842    Forex,
843    /// Futures contract.
844    Futures,
845    /// Bitcoin-denominated instrument.
846    Bitcoin,
847    /// Cryptocurrency.
848    Crypto,
849    /// Unclassified / undefined.
850    Undefined,
851    /// Pine Script expression.
852    Expression,
853    /// Spread instrument.
854    Spread,
855    /// Contract for difference.
856    Cfd,
857    /// Economic indicator.
858    Economic,
859    /// Equity.
860    Equity,
861    /// Depository receipt (ADR, GDR).
862    Dr,
863    /// Bond.
864    Bond,
865    /// Rights offering.
866    Right,
867    /// Warrant.
868    Warrant,
869    /// Fund (ETF, mutual fund, REIT).
870    Fund,
871    /// Structured product.
872    Structured,
873    /// Commodity.
874    Commodity,
875    /// Fundamental data.
876    Fundamental,
877    /// Spot market instrument.
878    Spot,
879}
880
881impl Display for SymbolType {
882    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
883        match *self {
884            SymbolType::Stock => write!(f, "stock"),
885            SymbolType::Index => write!(f, "index"),
886            SymbolType::Forex => write!(f, "forex"),
887            SymbolType::Futures => write!(f, "futures"),
888            SymbolType::Bitcoin => write!(f, "bitcoin"),
889            SymbolType::Crypto => write!(f, "crypto"),
890            SymbolType::Undefined => write!(f, "undefined"),
891            SymbolType::Expression => write!(f, "expression"),
892            SymbolType::Spread => write!(f, "spread"),
893            SymbolType::Cfd => write!(f, "cfd"),
894            SymbolType::Economic => write!(f, "economic"),
895            SymbolType::Equity => write!(f, "equity"),
896            SymbolType::Dr => write!(f, "dr"),
897            SymbolType::Bond => write!(f, "bond"),
898            SymbolType::Right => write!(f, "right"),
899            SymbolType::Warrant => write!(f, "warrant"),
900            SymbolType::Fund => write!(f, "fund"),
901            SymbolType::Structured => write!(f, "structured"),
902            SymbolType::Commodity => write!(f, "commodity"),
903            SymbolType::Fundamental => write!(f, "fundamental"),
904            SymbolType::Spot => write!(f, "spot"),
905        }
906    }
907}
908
909/// Market category for filtering symbol search results.
910///
911/// The `Stocks`, `Crypto`, and `Funds` variants each carry a sub-type for
912/// finer-grained filtering. Default is [`All`].
913#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy, PartialEq, Eq, Hash)]
914pub enum MarketType {
915    /// All markets (no filter).
916    #[default]
917    All,
918    /// Stocks, with optional sub-type.
919    Stocks(StocksType),
920    /// Funds (ETF, mutual fund, REIT, trust), with optional sub-type.
921    Funds(FundsType),
922    /// Futures contracts.
923    Futures,
924    /// Forex / currencies.
925    Forex,
926    /// Cryptocurrencies, with optional sub-type.
927    Crypto(CryptoType),
928    /// Market indices.
929    Indices,
930    /// Bonds.
931    Bonds,
932    /// Economic indicators / data.
933    Economy,
934}
935
936/// Stock sub-type for use with [`MarketType::Stocks`].
937#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy, PartialEq, Eq, Hash)]
938pub enum StocksType {
939    /// All stock types.
940    #[default]
941    All,
942    /// Common stock.
943    Common,
944    /// Preferred stock.
945    Preferred,
946    /// Depository receipt (ADR, GDR).
947    DepositoryReceipt,
948    /// Warrant.
949    Warrant,
950}
951
952/// Crypto sub-type for use with [`MarketType::Crypto`].
953#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy, PartialEq, Eq, Hash)]
954pub enum CryptoType {
955    /// All crypto types.
956    #[default]
957    All,
958    /// Spot market.
959    Spot,
960    /// Futures / perpetual contracts.
961    Futures,
962    /// Swap contracts.
963    Swap,
964    /// Crypto index.
965    Index,
966    /// Fundamental crypto data.
967    Fundamental,
968}
969
970/// Fund sub-type for use with [`MarketType::Funds`].
971#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy, PartialEq, Eq, Hash)]
972pub enum FundsType {
973    /// All fund types.
974    #[default]
975    All,
976    /// Exchange-Traded Fund.
977    ETF,
978    /// Mutual fund.
979    MutualFund,
980    /// Trust.
981    Trust,
982    /// Real Estate Investment Trust.
983    REIT,
984}
985
986/// Centralization level for crypto markets.
987///
988/// Controls whether to search centralized or decentralized exchanges.
989/// Default is [`CEX`](CryptoCentralization::CEX).
990#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy, PartialEq, Eq, Hash)]
991pub enum CryptoCentralization {
992    /// Centralized exchange (e.g. Binance, Coinbase).
993    #[default]
994    CEX,
995    /// Decentralized exchange (e.g. Uniswap, PancakeSwap).
996    DEX,
997}
998
999impl From<&str> for MarketType {
1000    fn from(value: &str) -> Self {
1001        match value {
1002            "all" | "undefined" => All,
1003            "stock" => Stocks(StocksType::All),
1004            "common_stock" => Stocks(StocksType::Common),
1005            "preferred_stock" => Stocks(StocksType::Preferred),
1006            "depository_receipt" => Stocks(StocksType::DepositoryReceipt),
1007            "warrant" => Stocks(StocksType::Warrant),
1008            "fund" => Funds(FundsType::All),
1009            "etf" => Funds(FundsType::ETF),
1010            "mutual_fund" => Funds(FundsType::MutualFund),
1011            "trust_fund" => Funds(FundsType::Trust),
1012            "reit" => Funds(FundsType::REIT),
1013            "futures" => Futures,
1014            "forex" => Forex,
1015            "crypto" => Crypto(CryptoType::All),
1016            "crypto_spot" => Crypto(CryptoType::Spot),
1017            "crypto_futures" => Crypto(CryptoType::Futures),
1018            "crypto_swap" => Crypto(CryptoType::Swap),
1019            "crypto_index" => Crypto(CryptoType::Index),
1020            "crypto_fundamental" => Crypto(CryptoType::Fundamental),
1021            "index" => Indices,
1022            "bond" => Bonds,
1023            "economic" => Economy,
1024            _ => All,
1025        }
1026    }
1027}
1028
1029impl Display for MarketType {
1030    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1031        match *self {
1032            All => write!(f, "undefined"),
1033            Stocks(t) => match t {
1034                StocksType::All => write!(f, "stocks"),
1035                StocksType::Common => write!(f, "common_stock"),
1036                StocksType::Preferred => write!(f, "preferred_stock"),
1037                StocksType::DepositoryReceipt => write!(f, "depository_receipt"),
1038                StocksType::Warrant => write!(f, "warrant"),
1039            },
1040            Funds(t) => match t {
1041                FundsType::All => write!(f, "funds"),
1042                FundsType::ETF => write!(f, "etf"),
1043                FundsType::MutualFund => write!(f, "mutual_fund"),
1044                FundsType::Trust => write!(f, "trust_fund"),
1045                FundsType::REIT => write!(f, "reit"),
1046            },
1047            Futures => write!(f, "futures"),
1048            Forex => write!(f, "forex"),
1049            Crypto(t) => match t {
1050                CryptoType::All => write!(f, "crypto"),
1051                CryptoType::Spot => write!(f, "crypto_spot"),
1052                CryptoType::Futures => write!(f, "crypto_futures"),
1053                CryptoType::Swap => write!(f, "crypto_swap"),
1054                CryptoType::Index => write!(f, "crypto_index"),
1055                CryptoType::Fundamental => write!(f, "crypto_fundamental"),
1056            },
1057            Indices => write!(f, "index"),
1058            Bonds => write!(f, "bond"),
1059            Economy => write!(f, "economic"),
1060        }
1061    }
1062}
1063
1064impl Display for CryptoCentralization {
1065    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1066        match *self {
1067            CryptoCentralization::CEX => write!(f, "cex"),
1068            CryptoCentralization::DEX => write!(f, "dex"),
1069        }
1070    }
1071}
1072
1073/// Futures product category for filtering futures symbol search.
1074#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy)]
1075pub enum FuturesProductType {
1076    /// Single-stock futures.
1077    SingleStock,
1078    /// World index futures.
1079    WorldIndices,
1080    /// Currency futures (default).
1081    #[default]
1082    Currencies,
1083    /// Interest rate futures.
1084    InterestRates,
1085    /// Energy futures.
1086    Energy,
1087    /// Agricultural futures.
1088    Agriculture,
1089    /// Metals futures.
1090    Metals,
1091    /// Weather derivatives.
1092    Weather,
1093}
1094
1095impl Display for FuturesProductType {
1096    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1097        match *self {
1098            FuturesProductType::SingleStock => write!(f, "Financial%2FEquity"),
1099            FuturesProductType::WorldIndices => write!(f, "Financial%2FIndex"),
1100            FuturesProductType::Currencies => write!(f, "Financial%2FCurrency"),
1101            FuturesProductType::InterestRates => write!(f, "=Financial%2FInterestRate"),
1102            FuturesProductType::Energy => write!(f, "Financial%2FEnergy"),
1103            FuturesProductType::Agriculture => write!(f, "Financial%2FAgriculture"),
1104            FuturesProductType::Metals => write!(f, "Financial%2FMetals"),
1105            FuturesProductType::Weather => write!(f, "Financial%2FWeather"),
1106        }
1107    }
1108}
1109
1110/// Stock market sector classification.
1111///
1112/// Used in symbol search filtering for equity instruments.
1113/// Default is [`Finance`](StockSector::Finance).
1114#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy)]
1115pub enum StockSector {
1116    /// Commercial services.
1117    CommercialServices,
1118    /// Communications.
1119    Communications,
1120    /// Consumer durables.
1121    ConsumerDurables,
1122    /// Consumer non-durables.
1123    ConsumerNonDurables,
1124    /// Consumer services.
1125    ConsumerServices,
1126    /// Distribution services.
1127    DistributionServices,
1128    /// Electronic technology.
1129    ElectronicTechnology,
1130    /// Energy minerals.
1131    EnergyMinerals,
1132    /// Finance (default).
1133    #[default]
1134    Finance,
1135    /// Government.
1136    Government,
1137    /// Health services.
1138    HealthServices,
1139    /// Health technology.
1140    HealthTechnology,
1141    /// Industrial services.
1142    IndustrialServices,
1143    /// Miscellaneous.
1144    Miscellaneous,
1145    /// Non-energy minerals.
1146    NonEnergyMinerals,
1147    /// Process industries.
1148    ProcessIndustries,
1149    /// Producer manufacturing.
1150    ProducerManufacturing,
1151    /// Retail trade.
1152    RetailTrade,
1153    /// Technology services.
1154    TechnologyServices,
1155    /// Transportation.
1156    Transportation,
1157    /// Utilities.
1158    Utilities,
1159}
1160
1161impl Display for StockSector {
1162    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1163        match *self {
1164            StockSector::CommercialServices => write!(f, "Commercial+Services"),
1165            StockSector::Communications => write!(f, "Communications"),
1166            StockSector::ConsumerDurables => write!(f, "Consumer+Durables"),
1167            StockSector::ConsumerNonDurables => write!(f, "Consumer+Non-Durables"),
1168            StockSector::ConsumerServices => write!(f, "Consumer+Services"),
1169            StockSector::DistributionServices => write!(f, "Distribution+Services"),
1170            StockSector::ElectronicTechnology => write!(f, "Electronic+Technology"),
1171            StockSector::EnergyMinerals => write!(f, "Energy+Minerals"),
1172            StockSector::Finance => write!(f, "Finance"),
1173            StockSector::Government => write!(f, "Government"),
1174            StockSector::HealthServices => write!(f, "Health+Services"),
1175            StockSector::HealthTechnology => write!(f, "Health+Technology"),
1176            StockSector::IndustrialServices => write!(f, "Industrial+Services"),
1177            StockSector::Miscellaneous => write!(f, "Miscellaneous"),
1178            StockSector::NonEnergyMinerals => write!(f, "Non-Energy+Minerals"),
1179            StockSector::ProcessIndustries => write!(f, "Process+Industries"),
1180            StockSector::ProducerManufacturing => write!(f, "Producer+Manufacturing"),
1181            StockSector::RetailTrade => write!(f, "Retail+Trade"),
1182            StockSector::TechnologyServices => write!(f, "Technology+Services"),
1183            StockSector::Transportation => write!(f, "Transportation"),
1184            StockSector::Utilities => write!(f, "Utilities"),
1185        }
1186    }
1187}
1188
1189/// Source organization for economic indicator data.
1190///
1191/// Default is [`WorldBank`](EconomicSource::WorldBank).
1192#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy)]
1193pub enum EconomicSource {
1194    /// World Bank.
1195    #[default]
1196    WorldBank,
1197    /// Eurostat (EU statistical office).
1198    EUROSTAT,
1199    /// Akamai (internet/connectivity data).
1200    AKAMAI,
1201    /// Transparency International.
1202    TransparencyInternational,
1203    /// OECD.
1204    OrganizationForEconomicCooperationAndDevelopment,
1205    /// World Economic Forum.
1206    WorldEconomicForum,
1207    /// WageIndicator Foundation.
1208    WageIndicatorFoundation,
1209    /// U.S. Bureau of Labor Statistics.
1210    BureauOfLaborStatistics,
1211    /// U.S. Federal Reserve.
1212    FederalReserve,
1213    /// Stockholm International Peace Research Institute.
1214    StockholmInternationalPeaceResearchInstitute,
1215    /// Institute for Economics and Peace.
1216    InstituteForEconomicsAndPeace,
1217    /// U.S. Bureau of Economic Analysis.
1218    BureauOfEconomicAnalysis,
1219    /// World Gold Council.
1220    WorldGoldCouncil,
1221    /// U.S. Census Bureau.
1222    CensusBureau,
1223    /// Central Bank of West African States.
1224    CentralBankOfWestAfricanStates,
1225    /// International Monetary Fund.
1226    InternationalMonetaryFund,
1227    /// U.S. Energy Information Administration.
1228    USEnergyInformationAdministration,
1229    /// Statistics Canada.
1230    StatisticCanada,
1231    /// UK Office for National Statistics.
1232    OfficeForNationalStatistics,
1233    /// Statistics Norway.
1234    StatisticsNorway,
1235}
1236
1237/// Economic indicator category for filtering economic data.
1238///
1239/// Default is [`GDP`](EconomicCategory::GDP).
1240#[derive(Debug, Default, Clone, Deserialize, Serialize, Copy)]
1241pub enum EconomicCategory {
1242    /// Gross Domestic Product.
1243    #[default]
1244    GDP,
1245    /// Labor market indicators.
1246    Labor,
1247    /// Price indices (CPI, PPI, etc.).
1248    Prices,
1249    /// Health-related indicators.
1250    Health,
1251    /// Money supply and monetary indicators.
1252    Money,
1253    /// Trade balance and trade indicators.
1254    Trade,
1255    /// Government spending and fiscal data.
1256    Government,
1257    /// Business confidence and activity.
1258    Business,
1259    /// Consumer confidence and spending.
1260    Consumer,
1261    /// Housing market indicators.
1262    Housing,
1263    /// Tax-related data.
1264    Taxes,
1265}
1266
1267impl Display for EconomicSource {
1268    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1269        match *self {
1270            EconomicSource::WorldBank => write!(f, "__WB"),
1271            EconomicSource::EUROSTAT => write!(f, "__EUROSTAT"),
1272            EconomicSource::AKAMAI => write!(f, "__AKAMAI"),
1273            EconomicSource::TransparencyInternational => write!(f, "__TI"),
1274            EconomicSource::OrganizationForEconomicCooperationAndDevelopment => write!(f, "__OECD"),
1275            EconomicSource::WorldEconomicForum => write!(f, "__WEF"),
1276            EconomicSource::WageIndicatorFoundation => write!(f, "__WIF"),
1277            EconomicSource::BureauOfLaborStatistics => write!(f, "USBLS"),
1278            EconomicSource::FederalReserve => write!(f, "USFR"),
1279            EconomicSource::StockholmInternationalPeaceResearchInstitute => write!(f, "__SIPRI"),
1280            EconomicSource::InstituteForEconomicsAndPeace => write!(f, "__IEP"),
1281            EconomicSource::BureauOfEconomicAnalysis => write!(f, "USBEA"),
1282            EconomicSource::WorldGoldCouncil => write!(f, "__WGC"),
1283            EconomicSource::CensusBureau => write!(f, "USCB"),
1284            EconomicSource::CentralBankOfWestAfricanStates => write!(f, "__BCEAO"),
1285            EconomicSource::InternationalMonetaryFund => write!(f, "__IMF"),
1286            EconomicSource::USEnergyInformationAdministration => write!(f, "__UEIA"),
1287            EconomicSource::StatisticCanada => write!(f, "CASC"),
1288            EconomicSource::OfficeForNationalStatistics => write!(f, "GBONS"),
1289            EconomicSource::StatisticsNorway => write!(f, "NOSN"),
1290        }
1291    }
1292}
1293
1294
1295impl Display for EconomicCategory {
1296    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1297        match *self {
1298            EconomicCategory::GDP => write!(f, "gdp"),
1299            EconomicCategory::Labor => write!(f, "lbr"),
1300            EconomicCategory::Prices => write!(f, "prce"),
1301            EconomicCategory::Health => write!(f, "hlth"),
1302            EconomicCategory::Money => write!(f, "mny"),
1303            EconomicCategory::Trade => write!(f, "trd"),
1304            EconomicCategory::Government => write!(f, "gov"),
1305            EconomicCategory::Business => write!(f, "bsnss"),
1306            EconomicCategory::Consumer => write!(f, "cnsm"),
1307            EconomicCategory::Housing => write!(f, "hse"),
1308            EconomicCategory::Taxes => write!(f, "txs"),
1309        }
1310    }
1311}