twstock/
lib.rs

1//! # Taiwan Stock Exchange (TWSE) API
2//!
3//! `twstock` is a library for fetching data from the Taiwan Stock Exchange (TWSE) API.
4//!
5//! Behind the scenes, it uses the reqwest crate to make HTTP requests to their server.
6//!
7//! # Example:
8//! ```rust
9//! use twstock::*;
10//!
11//! async fn fetch() {
12//!     let client = Client::new();
13//!     match client
14//!         .realtime()
15//!         .fetch(Stock {
16//!             kind: StockKind::Live,
17//!             code: 2330,
18//!         })
19//!         .await
20//!     {
21//!         Ok(x) => assert_eq!(x.name, "台積電"),
22//!         Err(err) => match err {
23//!             Error::MarketClosed => {}
24//!             _ => panic!("unexpected error: {:?}", err),
25//!         },
26//!     };
27//! }
28//! ```
29//!
30//! # Features:
31//! - `serde`: Enable serde support
32//! - `native-tls`: Use the native-tls backend
33//! - `native-tls-vendored`: Use the native-tls backend with vendored OpenSSL
34//! - `rustls-tls`: Use the rustls backend
35//!
36//! Don't forget to disable default features if you want to use a specific TLS backend.
37
38pub mod history;
39pub mod list;
40pub mod realtime;
41
42use reqwest::Client as HttpClient;
43
44fn get_time_zone() -> chrono::FixedOffset {
45    chrono::FixedOffset::east_opt(8 * 3600).unwrap()
46}
47
48/// Error type that may occur when interacting with the TWSE API
49#[derive(Debug, thiserror::Error)]
50pub enum Error {
51    #[error(transparent)]
52    Reqwest(#[from] reqwest::Error),
53    #[error("Rate limit exceeded")]
54    RateLimitExceeded,
55    /// Incompatible API, the upstream API has changed
56    #[error("incompatible upstream api")]
57    IncompatibleApi,
58    #[error("date does not exist")]
59    DateDoesNotExist,
60    #[error("Error message from upstream: `{0}`")]
61    StatMessage(String),
62    #[error("market is closed")]
63    MarketClosed,
64}
65
66#[derive(Debug, Hash, Clone, PartialEq, PartialOrd, Default)]
67#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
68/// Stock identifier and its variant
69pub struct Stock {
70    pub kind: StockKind,
71    pub code: u32,
72}
73
74#[derive(Debug, Hash, Clone, PartialEq, Eq, PartialOrd, Ord, Default)]
75#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
76/// variant of stock
77///
78/// The number is intentionally set to match the value used in the upstream API
79pub enum StockKind {
80    #[default]
81    Live = 2,
82    OverTheCounter = 4,
83}
84
85/// Client for fetching data from the Taiwan Stock Exchange (TWSE) API
86#[derive(Default)]
87pub struct Client(HttpClient);
88
89impl Client {
90    /// Create a new client
91    pub fn new() -> Self {
92        Self::default()
93    }
94}
95
96// if not TLS feature enabled, compile error
97#[cfg(not(any(
98    feature = "default-tls",
99    feature = "native-tls",
100    feature = "native-tls-vendored",
101    feature = "rustls-tls"
102)))]
103compile_error!("TLS feature is not enabled");