Tortoise/sidecar/service.py
2026-06-23 10:37:31 +08:00

87 lines
3.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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