use async_trait::async_trait;
use crate::data::{
BillboardDetail, BillboardItem, BlockTradeData, BondCurrentData, CapitalFlowData,
CapitalFlowHistory, ConvertibleBondCode, CurrentMarketData, DividendData, ETFCode,
ETFCurrentData, ETFMarketData, ETFMinuteData, EarningsForecast, FundHolding, IPOData,
InstitutionalResearchData, KLineType, MarginTradingData, MarketData, MinuteData, NewsArticle,
NewsCategory, NewsContent, OrderBookData, ResearchReportData, StockCode, StockConnectData,
StockInfo, StockValuation, TickData, TopHolder,
};
use crate::error::DataResult;
#[async_trait]
pub trait DataSource: Send + Sync {
fn name(&self) -> &'static str;
fn priority(&self) -> u8;
async fn is_available(&self) -> bool {
true
}
}
#[async_trait]
pub trait StockMarketSource: DataSource {
async fn get_market(
&self,
stock_code: &str,
start_date: Option<&str>,
end_date: Option<&str>,
k_type: KLineType,
) -> DataResult<Vec<MarketData>>;
async fn get_market_current(&self, stock_codes: &[&str]) -> DataResult<Vec<CurrentMarketData>>;
async fn get_market_min(&self, stock_code: &str) -> DataResult<Vec<MinuteData>>;
async fn get_order_book(&self, stock_code: &str) -> DataResult<OrderBookData> {
let _ = stock_code;
Err(crate::error::DataError::not_supported("get_order_book"))
}
async fn get_ticks(&self, stock_code: &str) -> DataResult<Vec<TickData>> {
let _ = stock_code;
Err(crate::error::DataError::not_supported("get_ticks"))
}
}
#[async_trait]
pub trait StockInfoSource: DataSource {
async fn get_all_codes(&self, limit: Option<usize>) -> DataResult<Vec<StockCode>>;
async fn get_stock_info(&self, stock_code: &str) -> DataResult<StockInfo> {
let _ = stock_code;
Err(crate::error::DataError::not_supported("get_stock_info"))
}
}
#[async_trait]
pub trait IndexMarketSource: DataSource {
async fn get_index_market(
&self,
index_code: &str,
start_date: Option<&str>,
end_date: Option<&str>,
k_type: KLineType,
) -> DataResult<Vec<MarketData>>;
async fn get_index_current(&self, index_codes: &[&str]) -> DataResult<Vec<CurrentMarketData>>;
}
pub trait FullStockSource: StockMarketSource + StockInfoSource {}
impl<T: StockMarketSource + StockInfoSource> FullStockSource for T {}
#[async_trait]
pub trait FundInfoSource: DataSource {
async fn get_all_etf_codes(&self, limit: Option<usize>) -> DataResult<Vec<ETFCode>>;
}
#[async_trait]
pub trait FundMarketSource: DataSource {
async fn get_etf_market(
&self,
fund_code: &str,
start_date: Option<&str>,
end_date: Option<&str>,
k_type: KLineType,
) -> DataResult<Vec<ETFMarketData>>;
async fn get_etf_current(&self, fund_codes: &[&str]) -> DataResult<Vec<ETFCurrentData>>;
async fn get_etf_min(&self, fund_code: &str) -> DataResult<Vec<ETFMinuteData>> {
let _ = fund_code;
Err(crate::error::DataError::not_supported("get_etf_min"))
}
}
pub trait FullFundSource: FundInfoSource + FundMarketSource {}
impl<T: FundInfoSource + FundMarketSource> FullFundSource for T {}
#[async_trait]
pub trait BondInfoSource: DataSource {
async fn get_all_bond_codes(
&self,
limit: Option<usize>,
) -> DataResult<Vec<ConvertibleBondCode>>;
}
#[async_trait]
pub trait BondMarketSource: DataSource {
async fn get_bond_current(
&self,
bond_codes: Option<&[&str]>,
) -> DataResult<Vec<BondCurrentData>>;
}
pub trait FullBondSource: BondInfoSource + BondMarketSource {}
impl<T: BondInfoSource + BondMarketSource> FullBondSource for T {}
#[async_trait]
pub trait NewsSource: DataSource {
async fn get_news(
&self,
category: NewsCategory,
page: u32,
limit: u32,
) -> DataResult<Vec<NewsArticle>>;
async fn get_news_content(&self, news_id: &str) -> DataResult<NewsContent>;
async fn search_news(
&self,
keyword: &str,
page: u32,
limit: u32,
) -> DataResult<Vec<NewsArticle>> {
let _ = (keyword, page, limit);
Err(crate::error::DataError::not_supported("search_news"))
}
}
#[async_trait]
pub trait CapitalFlowSource: DataSource {
async fn get_capital_flow(&self, stock_codes: &[&str]) -> DataResult<Vec<CapitalFlowData>>;
async fn get_capital_flow_history(
&self,
stock_code: &str,
limit: Option<usize>,
) -> DataResult<Vec<CapitalFlowHistory>>;
}
#[async_trait]
pub trait BillboardSource: DataSource {
async fn get_billboard_list(&self, date: Option<&str>) -> DataResult<Vec<BillboardItem>>;
async fn get_billboard_detail(
&self,
stock_code: &str,
date: &str,
) -> DataResult<Vec<BillboardDetail>>;
}
#[async_trait]
pub trait EarningsForecastSource: DataSource {
async fn get_earnings_forecast(
&self,
report_period: Option<&str>,
page: u32,
limit: u32,
) -> DataResult<Vec<EarningsForecast>>;
}
#[async_trait]
pub trait StockConnectSource: DataSource {
async fn get_stock_connect(&self, limit: Option<usize>) -> DataResult<Vec<StockConnectData>>;
}
#[async_trait]
pub trait MarginTradingSource: DataSource {
async fn get_margin_trading(
&self,
stock_code: &str,
limit: Option<usize>,
) -> DataResult<Vec<MarginTradingData>>;
}
#[async_trait]
pub trait IPOSource: DataSource {
async fn get_ipo_list(&self, limit: Option<usize>) -> DataResult<Vec<IPOData>>;
}
#[async_trait]
pub trait BlockTradeSource: DataSource {
async fn get_block_trades(&self, limit: Option<usize>) -> DataResult<Vec<BlockTradeData>>;
}
#[async_trait]
pub trait InstitutionalResearchSource: DataSource {
async fn get_institutional_research(
&self,
limit: Option<usize>,
) -> DataResult<Vec<InstitutionalResearchData>>;
}
#[async_trait]
pub trait ResearchReportSource: DataSource {
async fn get_research_reports(
&self,
stock_code: Option<&str>,
limit: Option<usize>,
) -> DataResult<Vec<ResearchReportData>>;
}
#[async_trait]
pub trait ValuationSource: DataSource {
async fn get_valuation(&self, stock_code: &str) -> DataResult<StockValuation>;
}
#[async_trait]
pub trait HoldingsSource: DataSource {
async fn get_top_holders(&self, stock_code: &str) -> DataResult<Vec<TopHolder>>;
async fn get_fund_holdings(
&self,
stock_code: &str,
limit: Option<usize>,
) -> DataResult<Vec<FundHolding>>;
}
#[async_trait]
pub trait DividendSource: DataSource {
async fn get_dividends(&self, stock_code: &str) -> DataResult<Vec<DividendData>>;
}
#[cfg(test)]
mod tests {
use super::*;
struct MockSource;
#[async_trait]
impl DataSource for MockSource {
fn name(&self) -> &'static str {
"mock"
}
fn priority(&self) -> u8 {
1
}
}
#[tokio::test]
async fn test_mock_source() {
let source = MockSource;
assert_eq!(source.name(), "mock");
assert_eq!(source.priority(), 1);
assert!(source.is_available().await);
}
}