Skip to main content

tushare_api/
lib.rs

1//! # tushare-rs-pro — Tushare Pro API Rust SDK
2//!
3//! 面向量化交易和金融数据分析的 Rust 客户端库,提供对 [Tushare Pro](https://tushare.pro/)
4//! 全部 API 的异步、类型安全访问。
5//!
6//! ## 核心特性
7//!
8//! - **77 个预定义模型** — 覆盖股票、基金、指数、债券、ETF、期货、期权、港股、美股、
9//!   外汇、宏观经济、行业分类等 12 大领域,开箱即用
10//! - **84 个 API 枚举** — 编译期类型安全,杜绝 API 名称拼写错误
11//! - **Derive 宏** — `#[derive(DeriveFromTushareData)]` 自动将 API 响应映射到自定义 struct
12//! - **异步架构** — 基于 `tokio` + `reqwest`,高性能并发请求
13//! - **生产就绪** — 内置限流、指数退避重试、超时控制、全面错误处理
14//!
15//! ## 快速开始
16//!
17//! ### 使用预定义模型(推荐)
18//!
19//! ```no_run
20//! use tushare_api::{TushareClient, Api, TushareEntityList, TushareRequest, request, params, fields};
21//! use tushare_api::models::DailyModel;
22//!
23//! #[tokio::main]
24//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
25//!     let client = TushareClient::from_env()?;
26//!
27//!     let req = request!(Api::Daily, {
28//!         "ts_code" => "000001.SZ",
29//!         "start_date" => "20260101",
30//!         "end_date" => "20260401"
31//!     }, [
32//!         "ts_code", "trade_date", "open", "high", "low", "close", "vol"
33//!     ]);
34//!
35//!     let data: TushareEntityList<DailyModel> = client.call_api_as(req).await?;
36//!
37//!     for d in data.iter().take(3) {
38//!         println!("{} 收盘: {:.2}", d.trade_date, d.close.unwrap_or(0.0));
39//!     }
40//!     Ok(())
41//! }
42//! ```
43//!
44//! ### 自定义 Struct
45//!
46//! ```no_run
47//! use tushare_api::{TushareClient, Api, TushareEntityList, TushareRequest, request, params, fields, DeriveFromTushareData};
48//!
49//! #[derive(Debug, Clone, DeriveFromTushareData)]
50//! pub struct MyStock {
51//!     pub ts_code: String,
52//!     pub name: String,
53//!     #[tushare(field = "list_date")]
54//!     pub listing_date: Option<String>,
55//! }
56//!
57//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
58//! let client = TushareClient::from_env()?;
59//! let stocks: TushareEntityList<MyStock> = client.call_api_as(
60//!     request!(Api::StockBasic, { "list_status" => "L" }, ["ts_code", "name", "list_date"])
61//! ).await?;
62//! println!("共 {} 只股票", stocks.len());
63//! # Ok(())
64//! # }
65//! ```
66//!
67//! ## 模块概览
68//!
69//! | 模块 | 说明 |
70//! |------|------|
71//! | [`client`] | 核心客户端 [`TushareClient`],支持 `from_env()` / `new()` / `with_timeout()` |
72//! | [`client_ex`] | 增强客户端 [`TushareClientEx`],带限流和重试 |
73//! | [`models`] | 77 个预定义数据模型,按领域分 12 个子模块 |
74//! | [`api`] | [`Api`] 枚举(84 个变体),所有 Tushare API 的类型安全标识 |
75//! | [`types`] | 请求/响应类型、`request!` 宏、[`TushareEntityList`] |
76//! | [`traits`] | [`FromTushareData`] / [`FromTushareValue`] 转换 trait |
77//! | [`error`] | [`TushareError`] 错误类型 |
78//! | [`logging`] | 日志配置 |
79
80// Allow the derive macro's generated `tushare_api::` paths to resolve within this crate
81extern crate self as tushare_api;
82
83pub mod api;
84pub mod basic_types;
85pub mod client;
86pub mod client_ex;
87pub mod custom_date_format;
88pub mod error;
89pub mod logging;
90pub mod models;
91pub mod third_party_types;
92pub mod traits;
93pub mod types;
94pub mod utils;
95
96// Re-export main types for convenience
97pub use api::Api;
98pub use client::{HttpClientConfig, TushareClient, TushareClientBuilder};
99pub use client_ex::{RetryConfig, TushareClientEx};
100pub use error::{TushareError, TushareResult};
101pub use logging::{LogConfig, LogLevel, Logger};
102pub use traits::{FromOptionalTushareValue, FromTushareData, FromTushareValue};
103pub use types::{TushareData, TushareEntityList, TushareRequest, TushareResponse};
104pub use utils::response_to_vec;
105
106// Macros are automatically exported at the crate root via #[macro_export]
107
108// Re-export procedural macros from tushare-rs-pro-derive
109pub use tushare_rs_pro_derive::FromTushareData as DeriveFromTushareData;
110
111// Re-export serde_json for user convenience
112pub use serde_json;
113
114#[cfg(test)]
115mod tests {
116    use super::*;
117    use crate::types::TushareData;
118    use serde_json::json;
119
120    #[test]
121    fn test_api_serialization() {
122        let api = Api::StockBasic;
123        assert_eq!(api.name(), "stock_basic");
124    }
125
126    #[test]
127    fn test_tushare_request_creation() {
128        let request = TushareRequest::new(
129            Api::StockBasic,
130            vec![("list_status".to_string(), "L".to_string())],
131            vec!["ts_code".to_string(), "symbol".to_string()],
132        );
133
134        assert_eq!(request.api_name, Api::StockBasic);
135        assert_eq!(request.params.len(), 1);
136        assert_eq!(request.fields.len(), 2);
137    }
138
139    #[test]
140    fn test_tushare_response_creation() {
141        let response = TushareResponse {
142            request_id: "test123".to_string(),
143            code: 0,
144            msg: None,
145            data: Some(TushareData {
146                fields: vec!["ts_code".to_string(), "name".to_string()],
147                items: vec![
148                    vec![json!("000001.SZ"), json!("平安银行")],
149                    vec![json!("000002.SZ"), json!("万科A")],
150                ],
151                has_more: false,
152                count: 2,
153            }),
154        };
155
156        assert_eq!(response.code, 0);
157        assert_eq!(
158            response
159                .data
160                .as_ref()
161                .map(|data| data.items.len())
162                .unwrap_or(0),
163            2
164        );
165        assert_eq!(
166            response
167                .data
168                .as_ref()
169                .map(|data| data.items.len())
170                .unwrap_or(0),
171            2
172        );
173    }
174}