pub struct TushareClient { /* private fields */ }Expand description
Tushare API client
Implementations§
Sourcepub fn builder() -> TushareClientBuilder
pub fn builder() -> TushareClientBuilder
Create client builder
Examples found in repository?
10async fn main() -> Result<(), Box<dyn std::error::Error>> {
11 println!("=== Tushare API Tracing Integration Example ===");
12
13 // Method 1: Using tracing-log bridge (recommended for mixed ecosystems)
14 #[cfg(all(feature = "tracing", feature = "tracing-log"))]
15 {
16 println!("\n--- Method 1: Using tracing-log bridge ---");
17 use tracing_subscriber;
18 use tracing_log::LogTracer;
19
20 // Initialize log-to-tracing bridge
21 LogTracer::init()?;
22
23 // Set up tracing subscriber
24 tracing_subscriber::fmt()
25 .with_env_filter("debug")
26 .with_target(false)
27 .with_thread_ids(true)
28 .with_level(true)
29 .with_max_level(tracing::Level::DEBUG)
30 .init();
31 }
32
33 // Method 2: Using native tracing feature (when library is compiled with tracing feature)
34 #[cfg(feature = "tracing")]
35 {
36 println!("\n--- Method 2: Using native tracing feature ---");
37 println!("库和用户程序都使用 tracing\n");
38
39 // 直接初始化 tracing subscriber
40 tracing_subscriber::fmt()
41 .with_max_level(tracing::Level::DEBUG)
42 .init();
43 }
44
45 println!("初始化 Tushare 客户端...");
46
47 let client = TushareClient::builder()
48 .with_token("demo_token_for_testing")
49 .with_log_level(LogLevel::Debug)
50 .log_requests(true)
51 .log_responses(false)
52 .log_performance(true)
53 .build()?;
54
55 println!("创建测试请求...");
56
57 let mut params = HashMap::new();
58 params.insert("list_status".to_string(), "L".to_string());
59
60 let request = TushareRequest {
61 api_name: Api::StockBasic,
62 params,
63 fields: vec!["ts_code".to_string(), "name".to_string()],
64 };
65
66 println!("发送 API 请求(注意观察日志输出)...");
67
68 // 这会触发我们库的日志输出
69 match client.call_api(request).await {
70 Ok(_response) => {
71 println!("✅ API 调用成功(实际会因为 token 无效而失败,但能看到日志)");
72 }
73 Err(e) => {
74 println!("❌ API 调用失败(预期行为): {}", e);
75 }
76 }
77
78 #[cfg(not(feature = "tracing"))]
79 {
80 println!("\n--- Tracing feature not enabled ---");
81 println!("To enable tracing support, compile with: cargo build --features tracing");
82 println!("Or add tracing-log bridge support with: cargo build --features tracing-log");
83 }
84
85 println!("\n=== 总结 ===");
86 #[cfg(feature = "tracing")]
87 println!("✅ 使用了原生 tracing 支持,日志输出更加结构化");
88
89 #[cfg(not(feature = "tracing"))]
90 println!("✅ 使用了 tracing-log 桥接,成功捕获了库的 log 输出");
91
92 Ok(())
93}Sourcepub fn from_env() -> TushareResult<Self>
pub fn from_env() -> TushareResult<Self>
Create a new Tushare client from TUSHARE_TOKEN environment variable with default timeout settings
§Errors
Returns TushareError::InvalidToken if TUSHARE_TOKEN environment variable does not exist or is empty
§Example
use tushare_api::{TushareClient, TushareResult};
// Requires TUSHARE_TOKEN environment variable to be set
let client = TushareClient::from_env()?;Examples found in repository?
12async fn main() -> Result<(), Box<dyn std::error::Error>> {
13 // Create client (you need to set TUSHARE_TOKEN environment variable)
14 let client = TushareClient::from_env()?;
15
16 // Create request for stock basic data
17 let request = request!(Api::StockBasic, {
18 "list_status" => "L"
19 }, [
20 "ts_code", "symbol", "name"
21 ]);
22
23 // Use the new generic method to get TushareEntityList<Stock> directly
24 let stock_list: TushareEntityList<Stock> = client.call_api_as(request).await?;
25
26 // Display the results
27 println!("Found {} stocks:", stock_list.len());
28 for (i, stock) in stock_list.iter().take(10).enumerate() {
29 println!("{}. {} ({}) - {}", i + 1, stock.ts_code, stock.symbol, stock.name);
30 }
31
32 if stock_list.len() > 10 {
33 println!("... and {} more stocks", stock_list.len() - 10);
34 }
35
36 // Show pagination info
37 println!("Total records: {}", stock_list.count());
38 println!("Has more pages: {}", stock_list.has_more());
39
40 Ok(())
41}More examples
12async fn main() -> Result<(), Box<dyn std::error::Error>> {
13 // Create client (you need to set TUSHARE_TOKEN environment variable)
14 let client = TushareClient::from_env()?;
15
16 // Create request for stock basic data
17 let request = request!(Api::StockBasic, {
18 "list_status" => "L"
19 }, [
20 "ts_code", "symbol", "name"
21 ]);
22
23 // Method 1: Use the generic call_api_as method with TushareEntityList
24 println!("=== Method 1: Using call_api_as with TushareEntityList ===");
25 let stock_list: TushareEntityList<Stock> = client.call_api_as(request.clone()).await?;
26
27 println!("Found {} stocks:", stock_list.len());
28 for (i, stock) in stock_list.iter().take(5).enumerate() {
29 println!("{}. {} ({}) - {}", i + 1, stock.ts_code, stock.symbol, stock.name);
30 }
31
32 // Show pagination info
33 println!("Total records: {}", stock_list.count());
34 println!("Has more pages: {}", stock_list.has_more());
35
36 // Method 2: Use the traditional call_api and manual conversion
37 println!("\n=== Method 2: Using call_api + manual conversion ===");
38 let response = client.call_api(request).await?;
39 let stocks: Vec<Stock> = tushare_api::utils::response_to_vec(response)?;
40
41 println!("Found {} stocks:", stocks.len());
42 for (i, stock) in stocks.iter().take(5).enumerate() {
43 println!("{}. {} ({}) - {}", i + 1, stock.ts_code, stock.symbol, stock.name);
44 }
45
46 Ok(())
47}111async fn main() -> Result<(), Box<dyn std::error::Error>> {
112 // Set up logging
113 env_logger::init();
114
115 // Create client from environment variable
116 let client = TushareClient::from_env()?;
117
118 // Create request for daily stock data
119 let request = TushareRequest::new(
120 Api::Daily,
121 params![
122 "ts_code" => "000001.SZ",
123 "start_date" => "20240101",
124 "end_date" => "20240131"
125 ],
126 fields![
127 "ts_code", "trade_date", "open", "high", "low", "close", "vol", "amount"
128 ]
129 );
130
131 println!("Fetching daily stock data with custom Decimal types...");
132
133 // Call API and get typed response with automatic conversion
134 let stock_prices: TushareEntityList<StockPrice> = client.call_api_as(request).await?;
135
136 println!("Retrieved {} stock price records", stock_prices.len());
137 println!("Has more data: {}", stock_prices.has_more());
138 println!("Total count: {}", stock_prices.count());
139
140 // Display first few records
141 for (i, price) in stock_prices.iter().take(5).enumerate() {
142 println!("\nRecord {}:", i + 1);
143 println!(" Stock Code: {}", price.ts_code);
144 println!(" Trade Date: {}", price.trade_date);
145 println!(" Open Price: {}", price.open_price);
146 println!(" High Price: {}", price.high_price);
147 println!(" Low Price: {}", price.low_price);
148 println!(" Close Price: {}", price.close_price);
149
150 if let Some(vol) = &price.volume {
151 println!(" Volume: {}", vol);
152 }
153
154 if let Some(amount) = &price.amount {
155 println!(" Amount: {}", amount);
156 }
157 }
158
159 Ok(())
160}86async fn main() -> Result<(), Box<dyn std::error::Error>> {
87 // 创建客户端
88 let client = TushareClient::from_env()?;
89
90 println!("=== 示例1: 使用 FromTushareData 派生宏获取股票基本信息 ===");
91
92 let request = request!(Api::StockBasic, {
93 "list_status" => "L"
94 }, [
95 "ts_code", "symbol", "name", "area", "industry", "market", "list_date"
96 ]);
97
98 // 直接获取 TushareEntityList<Stock> 类型
99 let stock_list: TushareEntityList<Stock> = client.call_api_as(request).await?;
100
101 println!("找到 {} 只股票:", stock_list.len());
102 for (i, stock) in stock_list.iter().take(5).enumerate() {
103 println!("{}. {} ({}) - {} [{}] {}",
104 i + 1,
105 stock.ts_code,
106 stock.symbol,
107 stock.name,
108 stock.area.as_deref().unwrap_or("未知"),
109 stock.industry.as_deref().unwrap_or("未知行业")
110 );
111 }
112
113 // 显示分页信息
114 println!("总记录数: {}, 是否有更多页面: {}", stock_list.count(), stock_list.has_more());
115
116 println!("\n=== 示例2: 获取简单股票信息 ===");
117
118 let simple_request = request!(Api::StockBasic, {
119 "list_status" => "L"
120 }, [
121 "ts_code", "symbol", "name"
122 ]);
123
124 let simple_stock_list: TushareEntityList<SimpleStock> = client.call_api_as(simple_request).await?;
125
126 println!("找到 {} 只股票 (简化版):", simple_stock_list.len());
127 for (i, stock) in simple_stock_list.iter().take(3).enumerate() {
128 println!("{}. {} ({}) - {}", i + 1, stock.ts_code, stock.symbol, stock.name);
129 }
130
131 println!("\n=== 示例3: 获取基金信息 ===");
132
133 let fund_request = request!(Api::FundBasic, {
134 "market" => "E"
135 }, [
136 "ts_code", "name", "management", "custodian", "fund_type", "found_date", "list_date", "status"
137 ]);
138
139 let fund_list: TushareEntityList<Fund> = client.call_api_as(fund_request).await?;
140
141 println!("找到 {} 只基金:", fund_list.len());
142 for (i, fund) in fund_list.iter().take(3).enumerate() {
143 println!("{}. {} - {} [{}] 管理人: {}",
144 i + 1,
145 fund.ts_code,
146 fund.name,
147 fund.fund_type.as_deref().unwrap_or("未知类型"),
148 fund.management.as_deref().unwrap_or("未知")
149 );
150 }
151
152 Ok(())
153}Sourcepub fn from_env_with_timeout(
connect_timeout: Duration,
timeout: Duration,
) -> TushareResult<Self>
pub fn from_env_with_timeout( connect_timeout: Duration, timeout: Duration, ) -> TushareResult<Self>
Create a new Tushare client from TUSHARE_TOKEN environment variable with custom timeout settings
§Arguments
connect_timeout- Connection timeout durationtimeout- Request timeout duration
§Errors
Returns TushareError::InvalidToken if TUSHARE_TOKEN environment variable does not exist or is empty
§Example
use tushare_api::{TushareClient, TushareResult};
use std::time::Duration;
// Requires TUSHARE_TOKEN environment variable to be set
let client = TushareClient::from_env_with_timeout(
Duration::from_secs(5), // Connection timeout 5 seconds
Duration::from_secs(60) // Request timeout 60 seconds
)?;Sourcepub fn with_timeout(
token: &str,
connect_timeout: Duration,
timeout: Duration,
) -> Self
pub fn with_timeout( token: &str, connect_timeout: Duration, timeout: Duration, ) -> Self
Create a new Tushare client with custom timeout settings
§Arguments
token- Tushare API Tokenconnect_timeout- Connection timeout durationtimeout- Request timeout duration
§Example
use tushare_api::TushareClient;
use std::time::Duration;
let client = TushareClient::with_timeout(
"your_token_here",
Duration::from_secs(5), // Connection timeout 5 seconds
Duration::from_secs(60) // Request timeout 60 seconds
);Sourcepub async fn call_api(
&self,
request: TushareRequest,
) -> TushareResult<TushareResponse>
pub async fn call_api( &self, request: TushareRequest, ) -> TushareResult<TushareResponse>
Call Tushare API with flexible string types support
§Arguments
request- API request parameters, supports direct use of string literals
§Returns
Returns API response result
§Example
use tushare_api::{TushareClient, TushareRequest, Api, params, fields, request};
let client = TushareClient::new("your_token_here");
// Now you can use string literals directly!
let request = request!(Api::StockBasic, {
"list_status" => "L"
}, [
"ts_code", "name"
]);
let response = client.call_api(request).await?;
println!("Response: {:?}", response);Examples found in repository?
12async fn main() -> Result<(), Box<dyn std::error::Error>> {
13 // Create client (you need to set TUSHARE_TOKEN environment variable)
14 let client = TushareClient::from_env()?;
15
16 // Create request for stock basic data
17 let request = request!(Api::StockBasic, {
18 "list_status" => "L"
19 }, [
20 "ts_code", "symbol", "name"
21 ]);
22
23 // Method 1: Use the generic call_api_as method with TushareEntityList
24 println!("=== Method 1: Using call_api_as with TushareEntityList ===");
25 let stock_list: TushareEntityList<Stock> = client.call_api_as(request.clone()).await?;
26
27 println!("Found {} stocks:", stock_list.len());
28 for (i, stock) in stock_list.iter().take(5).enumerate() {
29 println!("{}. {} ({}) - {}", i + 1, stock.ts_code, stock.symbol, stock.name);
30 }
31
32 // Show pagination info
33 println!("Total records: {}", stock_list.count());
34 println!("Has more pages: {}", stock_list.has_more());
35
36 // Method 2: Use the traditional call_api and manual conversion
37 println!("\n=== Method 2: Using call_api + manual conversion ===");
38 let response = client.call_api(request).await?;
39 let stocks: Vec<Stock> = tushare_api::utils::response_to_vec(response)?;
40
41 println!("Found {} stocks:", stocks.len());
42 for (i, stock) in stocks.iter().take(5).enumerate() {
43 println!("{}. {} ({}) - {}", i + 1, stock.ts_code, stock.symbol, stock.name);
44 }
45
46 Ok(())
47}More examples
10async fn main() -> Result<(), Box<dyn std::error::Error>> {
11 println!("=== Tushare API Tracing Integration Example ===");
12
13 // Method 1: Using tracing-log bridge (recommended for mixed ecosystems)
14 #[cfg(all(feature = "tracing", feature = "tracing-log"))]
15 {
16 println!("\n--- Method 1: Using tracing-log bridge ---");
17 use tracing_subscriber;
18 use tracing_log::LogTracer;
19
20 // Initialize log-to-tracing bridge
21 LogTracer::init()?;
22
23 // Set up tracing subscriber
24 tracing_subscriber::fmt()
25 .with_env_filter("debug")
26 .with_target(false)
27 .with_thread_ids(true)
28 .with_level(true)
29 .with_max_level(tracing::Level::DEBUG)
30 .init();
31 }
32
33 // Method 2: Using native tracing feature (when library is compiled with tracing feature)
34 #[cfg(feature = "tracing")]
35 {
36 println!("\n--- Method 2: Using native tracing feature ---");
37 println!("库和用户程序都使用 tracing\n");
38
39 // 直接初始化 tracing subscriber
40 tracing_subscriber::fmt()
41 .with_max_level(tracing::Level::DEBUG)
42 .init();
43 }
44
45 println!("初始化 Tushare 客户端...");
46
47 let client = TushareClient::builder()
48 .with_token("demo_token_for_testing")
49 .with_log_level(LogLevel::Debug)
50 .log_requests(true)
51 .log_responses(false)
52 .log_performance(true)
53 .build()?;
54
55 println!("创建测试请求...");
56
57 let mut params = HashMap::new();
58 params.insert("list_status".to_string(), "L".to_string());
59
60 let request = TushareRequest {
61 api_name: Api::StockBasic,
62 params,
63 fields: vec!["ts_code".to_string(), "name".to_string()],
64 };
65
66 println!("发送 API 请求(注意观察日志输出)...");
67
68 // 这会触发我们库的日志输出
69 match client.call_api(request).await {
70 Ok(_response) => {
71 println!("✅ API 调用成功(实际会因为 token 无效而失败,但能看到日志)");
72 }
73 Err(e) => {
74 println!("❌ API 调用失败(预期行为): {}", e);
75 }
76 }
77
78 #[cfg(not(feature = "tracing"))]
79 {
80 println!("\n--- Tracing feature not enabled ---");
81 println!("To enable tracing support, compile with: cargo build --features tracing");
82 println!("Or add tracing-log bridge support with: cargo build --features tracing-log");
83 }
84
85 println!("\n=== 总结 ===");
86 #[cfg(feature = "tracing")]
87 println!("✅ 使用了原生 tracing 支持,日志输出更加结构化");
88
89 #[cfg(not(feature = "tracing"))]
90 println!("✅ 使用了 tracing-log 桥接,成功捕获了库的 log 输出");
91
92 Ok(())
93}Sourcepub async fn call_api_as<T>(
&self,
request: TushareRequest,
) -> TushareResult<TushareEntityList<T>>where
T: FromTushareData,
pub async fn call_api_as<T>(
&self,
request: TushareRequest,
) -> TushareResult<TushareEntityList<T>>where
T: FromTushareData,
Call Tushare API with automatic type conversion to TushareEntityList<T>
This method provides a clean, type-safe way to get paginated API responses.
You specify the entity type T, and get back a TushareEntityList<T> with
built-in pagination metadata.
§Type Parameters
T- The entity type that implementsFromTushareData
§Arguments
request- API request parameters
§Returns
Returns a TushareEntityList<T> containing:
items: Vec<T>- The converted data itemshas_more: bool- Whether more pages are availablecount: i64- Total number of records across all pages
§Example
use tushare_api::{TushareClient, Api, request, TushareEntityList, params, fields, TushareRequest, DeriveFromTushareData};
#[derive(Debug, Clone, DeriveFromTushareData)]
pub struct Stock {
pub ts_code: String,
pub name: String,
pub area: Option<String>,
}
let client = TushareClient::from_env()?;
// Clean, intuitive API call
let stocks: TushareEntityList<Stock> = client.call_api_as(request!(
Api::StockBasic, {
"list_status" => "L",
"limit" => "100"
}, [
"ts_code", "name", "area"
]
)).await?;
// Access pagination info
println!("Current page: {} stocks", stocks.len());
println!("Total available: {} stocks", stocks.count());
println!("Has more pages: {}", stocks.has_more());
// Iterate over items
for stock in &stocks {
println!("{}: {} ({})",
stock.ts_code,
stock.name,
stock.area.as_deref().unwrap_or("Unknown"));
}Examples found in repository?
12async fn main() -> Result<(), Box<dyn std::error::Error>> {
13 // Create client (you need to set TUSHARE_TOKEN environment variable)
14 let client = TushareClient::from_env()?;
15
16 // Create request for stock basic data
17 let request = request!(Api::StockBasic, {
18 "list_status" => "L"
19 }, [
20 "ts_code", "symbol", "name"
21 ]);
22
23 // Use the new generic method to get TushareEntityList<Stock> directly
24 let stock_list: TushareEntityList<Stock> = client.call_api_as(request).await?;
25
26 // Display the results
27 println!("Found {} stocks:", stock_list.len());
28 for (i, stock) in stock_list.iter().take(10).enumerate() {
29 println!("{}. {} ({}) - {}", i + 1, stock.ts_code, stock.symbol, stock.name);
30 }
31
32 if stock_list.len() > 10 {
33 println!("... and {} more stocks", stock_list.len() - 10);
34 }
35
36 // Show pagination info
37 println!("Total records: {}", stock_list.count());
38 println!("Has more pages: {}", stock_list.has_more());
39
40 Ok(())
41}More examples
12async fn main() -> Result<(), Box<dyn std::error::Error>> {
13 // Create client (you need to set TUSHARE_TOKEN environment variable)
14 let client = TushareClient::from_env()?;
15
16 // Create request for stock basic data
17 let request = request!(Api::StockBasic, {
18 "list_status" => "L"
19 }, [
20 "ts_code", "symbol", "name"
21 ]);
22
23 // Method 1: Use the generic call_api_as method with TushareEntityList
24 println!("=== Method 1: Using call_api_as with TushareEntityList ===");
25 let stock_list: TushareEntityList<Stock> = client.call_api_as(request.clone()).await?;
26
27 println!("Found {} stocks:", stock_list.len());
28 for (i, stock) in stock_list.iter().take(5).enumerate() {
29 println!("{}. {} ({}) - {}", i + 1, stock.ts_code, stock.symbol, stock.name);
30 }
31
32 // Show pagination info
33 println!("Total records: {}", stock_list.count());
34 println!("Has more pages: {}", stock_list.has_more());
35
36 // Method 2: Use the traditional call_api and manual conversion
37 println!("\n=== Method 2: Using call_api + manual conversion ===");
38 let response = client.call_api(request).await?;
39 let stocks: Vec<Stock> = tushare_api::utils::response_to_vec(response)?;
40
41 println!("Found {} stocks:", stocks.len());
42 for (i, stock) in stocks.iter().take(5).enumerate() {
43 println!("{}. {} ({}) - {}", i + 1, stock.ts_code, stock.symbol, stock.name);
44 }
45
46 Ok(())
47}111async fn main() -> Result<(), Box<dyn std::error::Error>> {
112 // Set up logging
113 env_logger::init();
114
115 // Create client from environment variable
116 let client = TushareClient::from_env()?;
117
118 // Create request for daily stock data
119 let request = TushareRequest::new(
120 Api::Daily,
121 params![
122 "ts_code" => "000001.SZ",
123 "start_date" => "20240101",
124 "end_date" => "20240131"
125 ],
126 fields![
127 "ts_code", "trade_date", "open", "high", "low", "close", "vol", "amount"
128 ]
129 );
130
131 println!("Fetching daily stock data with custom Decimal types...");
132
133 // Call API and get typed response with automatic conversion
134 let stock_prices: TushareEntityList<StockPrice> = client.call_api_as(request).await?;
135
136 println!("Retrieved {} stock price records", stock_prices.len());
137 println!("Has more data: {}", stock_prices.has_more());
138 println!("Total count: {}", stock_prices.count());
139
140 // Display first few records
141 for (i, price) in stock_prices.iter().take(5).enumerate() {
142 println!("\nRecord {}:", i + 1);
143 println!(" Stock Code: {}", price.ts_code);
144 println!(" Trade Date: {}", price.trade_date);
145 println!(" Open Price: {}", price.open_price);
146 println!(" High Price: {}", price.high_price);
147 println!(" Low Price: {}", price.low_price);
148 println!(" Close Price: {}", price.close_price);
149
150 if let Some(vol) = &price.volume {
151 println!(" Volume: {}", vol);
152 }
153
154 if let Some(amount) = &price.amount {
155 println!(" Amount: {}", amount);
156 }
157 }
158
159 Ok(())
160}86async fn main() -> Result<(), Box<dyn std::error::Error>> {
87 // 创建客户端
88 let client = TushareClient::from_env()?;
89
90 println!("=== 示例1: 使用 FromTushareData 派生宏获取股票基本信息 ===");
91
92 let request = request!(Api::StockBasic, {
93 "list_status" => "L"
94 }, [
95 "ts_code", "symbol", "name", "area", "industry", "market", "list_date"
96 ]);
97
98 // 直接获取 TushareEntityList<Stock> 类型
99 let stock_list: TushareEntityList<Stock> = client.call_api_as(request).await?;
100
101 println!("找到 {} 只股票:", stock_list.len());
102 for (i, stock) in stock_list.iter().take(5).enumerate() {
103 println!("{}. {} ({}) - {} [{}] {}",
104 i + 1,
105 stock.ts_code,
106 stock.symbol,
107 stock.name,
108 stock.area.as_deref().unwrap_or("未知"),
109 stock.industry.as_deref().unwrap_or("未知行业")
110 );
111 }
112
113 // 显示分页信息
114 println!("总记录数: {}, 是否有更多页面: {}", stock_list.count(), stock_list.has_more());
115
116 println!("\n=== 示例2: 获取简单股票信息 ===");
117
118 let simple_request = request!(Api::StockBasic, {
119 "list_status" => "L"
120 }, [
121 "ts_code", "symbol", "name"
122 ]);
123
124 let simple_stock_list: TushareEntityList<SimpleStock> = client.call_api_as(simple_request).await?;
125
126 println!("找到 {} 只股票 (简化版):", simple_stock_list.len());
127 for (i, stock) in simple_stock_list.iter().take(3).enumerate() {
128 println!("{}. {} ({}) - {}", i + 1, stock.ts_code, stock.symbol, stock.name);
129 }
130
131 println!("\n=== 示例3: 获取基金信息 ===");
132
133 let fund_request = request!(Api::FundBasic, {
134 "market" => "E"
135 }, [
136 "ts_code", "name", "management", "custodian", "fund_type", "found_date", "list_date", "status"
137 ]);
138
139 let fund_list: TushareEntityList<Fund> = client.call_api_as(fund_request).await?;
140
141 println!("找到 {} 只基金:", fund_list.len());
142 for (i, fund) in fund_list.iter().take(3).enumerate() {
143 println!("{}. {} - {} [{}] 管理人: {}",
144 i + 1,
145 fund.ts_code,
146 fund.name,
147 fund.fund_type.as_deref().unwrap_or("未知类型"),
148 fund.management.as_deref().unwrap_or("未知")
149 );
150 }
151
152 Ok(())
153}