"""统一数据获取与缓存服务。""" from __future__ import annotations from typing import List, Optional from sidecar.config import SidecarConfig from sidecar.models import KlineBar, Snapshot from sidecar.sources.base import MarketDataSource from sidecar.symbols import normalize_symbol from sidecar.storage import DuckDBStore class UnifiedDataService: """统一行情获取与缓存服务。""" def __init__( self, store: DuckDBStore, config: SidecarConfig, kline_source: MarketDataSource, snapshot_sources: List[MarketDataSource], ) -> None: """ 功能说明:创建统一数据服务。 参数说明:store 为 DuckDB 仓储,config 为配置,kline_source 为 K 线源,snapshot_sources 为快照源列表。 返回值说明:无返回值。 注意事项:快照源按列表顺序尝试,前一个失败会自动降级到下一个。 """ self.store = store self.config = config self.kline_source = kline_source self.snapshot_sources = snapshot_sources def get_kline(self, symbol: str, period: str = "day", limit: int = 800, refresh: bool = False) -> List[KlineBar]: """ 功能说明:获取统一 K 线数据并自动缓存。 参数说明:symbol 为股票代码,period 为周期,limit 为最大条数,refresh 表示是否强制刷新。 返回值说明:返回按日期升序排列的 KlineBar 列表。 注意事项:缓存数量达到 limit 且未强制刷新时直接返回本地数据。 """ normalized = normalize_symbol(symbol) if not refresh: cached = self.store.load_kline(normalized, period, limit) if len(cached) >= limit: return cached bars = self.kline_source.fetch_kline(normalized, period, limit) self.store.save_kline(bars) return self.store.load_kline(normalized, period, limit) def get_snapshot(self, symbol: str, refresh: bool = False) -> Snapshot: """ 功能说明:获取统一行情快照并自动缓存。 参数说明:symbol 为股票代码,refresh 表示是否强制刷新。 返回值说明:返回 Snapshot 快照。 注意事项:默认使用未过期缓存;远端失败时会尝试下一个数据源。 """ normalized = normalize_symbol(symbol) if not refresh: cached = self.store.load_snapshot(normalized) if cached is not None: return cached last_error = None for source in self.snapshot_sources: try: snapshot = source.fetch_snapshot(normalized) self.store.save_snapshot(snapshot, self.config.snapshot_ttl_seconds) return snapshot except Exception as exc: last_error = exc raise RuntimeError("所有快照数据源均失败: %s" % symbol) from last_error def create_default_service(config: SidecarConfig) -> UnifiedDataService: """ 功能说明:创建默认 sidecar 服务实例。 参数说明:config 为 sidecar 配置。 返回值说明:返回 UnifiedDataService。 注意事项:默认 K 线使用 mootdx,快照优先腾讯财经并回退到 mootdx。 """ from sidecar.sources.mootdx_source import MootdxSource from sidecar.sources.tencent import TencentFinanceSource store = DuckDBStore(config.db_path) mootdx = MootdxSource() tencent = TencentFinanceSource(config.request_timeout_seconds) return UnifiedDataService(store, config, mootdx, [tencent, mootdx])