87 lines
3.6 KiB
Python
87 lines
3.6 KiB
Python
"""统一数据获取与缓存服务。"""
|
||
|
||
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]) |