- docker-compose: 下线 Python backend/config-service,切换至 config-service-rs - archive: 归档 legacy Python 目录至 archive/python/* - services: 新增/更新 common-contracts、api-gateway、各 provider、report-generator-service、config-service-rs - data-persistence-service: API/system 模块与模型/DTO 调整 - frontend: 更新 useApi 与 API 路由 - docs: 更新路线图并勾选光荣退役 - cleanup: 移除 data-distance-service 占位测试
64 lines
2.2 KiB
Rust
64 lines
2.2 KiB
Rust
use crate::error::AppError;
|
|
use crate::mapping::{map_financial_statements, map_profile};
|
|
use common_contracts::dtos::{CompanyProfileDto, TimeSeriesFinancialDto};
|
|
use anyhow::anyhow;
|
|
|
|
#[derive(Clone)]
|
|
pub struct YFinanceDataProvider {
|
|
client: reqwest::Client,
|
|
}
|
|
|
|
impl YFinanceDataProvider {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
client: reqwest::Client::new(),
|
|
}
|
|
}
|
|
|
|
pub async fn fetch_all_data(
|
|
&self,
|
|
symbol: &str,
|
|
) -> Result<(CompanyProfileDto, Vec<TimeSeriesFinancialDto>), AppError> {
|
|
let (summary_raw, financials_raw) = self.fetch_raw_data(symbol).await?;
|
|
let profile = map_profile(&summary_raw, symbol)?;
|
|
let financials = map_financial_statements(&financials_raw, symbol)?;
|
|
Ok((profile, financials))
|
|
}
|
|
|
|
async fn fetch_raw_data(
|
|
&self,
|
|
symbol: &str,
|
|
) -> Result<(serde_json::Value, serde_json::Value), AppError> {
|
|
// Yahoo quoteSummary: assetProfile + quoteType
|
|
let summary_url = format!(
|
|
"https://query1.finance.yahoo.com/v10/finance/quoteSummary/{}?modules=assetProfile,quoteType",
|
|
symbol
|
|
);
|
|
// Yahoo financials: income/balance/cashflow histories
|
|
let financials_url = format!(
|
|
"https://query1.finance.yahoo.com/v10/finance/quoteSummary/{}?modules=incomeStatementHistory,balanceSheetHistory,cashflowStatementHistory",
|
|
symbol
|
|
);
|
|
|
|
let summary_task = self.client.get(&summary_url).send();
|
|
let financials_task = self.client.get(&financials_url).send();
|
|
|
|
let (summary_res, financials_res) = tokio::try_join!(summary_task, financials_task)
|
|
.map_err(|e| AppError::ServiceRequest(e))?;
|
|
|
|
let summary_res = summary_res.error_for_status()?;
|
|
let financials_res = financials_res.error_for_status()?;
|
|
|
|
let summary_json: serde_json::Value = summary_res
|
|
.json()
|
|
.await
|
|
.map_err(|e| AppError::DataParsing(anyhow!(e)))?;
|
|
let financials_json: serde_json::Value = financials_res
|
|
.json()
|
|
.await
|
|
.map_err(|e| AppError::DataParsing(anyhow!(e)))?;
|
|
|
|
Ok((summary_json, financials_json))
|
|
}
|
|
}
|