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}