"""真实数据源集成测试。""" import os import random from pathlib import Path import pytest from sidecar.config import SidecarConfig from sidecar.service import UnifiedDataService from sidecar.sources.mootdx_source import MootdxSource from sidecar.sources.tencent import TencentFinanceSource from sidecar.storage import DuckDBStore pytestmark = pytest.mark.skipif( os.getenv("RUN_REAL_MARKET_TESTS") != "1", reason="真实网络测试需设置 RUN_REAL_MARKET_TESTS=1", ) def test_3_1_real_tencent_snapshot() -> None: """ 功能说明:验证腾讯财经真实快照接口可用。 参数说明:无。 返回值说明:无返回值。 注意事项:用例编号 3-1,需要可访问 qt.gtimg.cn。 """ snapshot = TencentFinanceSource(timeout_seconds=10).fetch_snapshot("600000") assert snapshot.symbol == "sh600000" assert snapshot.name assert snapshot.price is not None assert snapshot.source == "tencent" def test_3_2_real_mootdx_kline() -> None: """ 功能说明:验证 mootdx 真实 K 线接口可用。 参数说明:无。 返回值说明:无返回值。 注意事项:用例编号 3-2,需要可连接通达信行情服务器。 """ bars = MootdxSource().fetch_kline("600000", "day", 5) assert len(bars) > 0 assert bars[-1].symbol == "sh600000" assert bars[-1].close is not None assert bars[-1].source == "mootdx" def test_3_3_real_unified_service_cache(tmp_path: Path) -> None: """ 功能说明:验证统一服务可使用真实数据源写入 DuckDB 缓存。 参数说明:tmp_path 为 pytest 临时目录。 返回值说明:无返回值。 注意事项:用例编号 3-3,同时覆盖腾讯快照、mootdx K 线和 DuckDB 往返。 """ config = SidecarConfig(db_path=str(tmp_path / "real.duckdb"), snapshot_ttl_seconds=60) store = DuckDBStore(config.db_path) mootdx = MootdxSource() service = UnifiedDataService(store, config, mootdx, [TencentFinanceSource(10), mootdx]) bars = service.get_kline("600000", limit=5, refresh=True) snapshot = service.get_snapshot("600000", refresh=True) assert len(bars) > 0 assert store.load_kline("sh600000", "day", 5) assert snapshot.price is not None assert store.load_snapshot("sh600000") is not None def assert_random_kline_prices_match(symbols, sample_size: int, seed: int) -> None: """ 功能说明:随机抽取多个代码的 K 线价格并比较 mootdx 与腾讯财经是否基本一致。 参数说明:symbols 为待比较代码列表,sample_size 为抽样值数量,seed 为固定随机种子。 返回值说明:无返回值。 注意事项:仅比较 OHLC 价格,成交量和成交额因接口口径差异不参与比较。 """ fields = ["open", "high", "low", "close"] mootdx = MootdxSource() tencent = TencentFinanceSource(timeout_seconds=10) candidates = [] for symbol in symbols: mootdx_bars = {bar.trade_date: bar for bar in mootdx.fetch_kline(symbol, "day", 60)} tencent_bars = {bar.trade_date: bar for bar in tencent.fetch_kline(symbol, "day", 60)} for trade_date in sorted(set(mootdx_bars) & set(tencent_bars)): for field in fields: mootdx_value = getattr(mootdx_bars[trade_date], field) tencent_value = getattr(tencent_bars[trade_date], field) if mootdx_value is not None and tencent_value is not None: candidates.append((symbol, trade_date, field, mootdx_value, tencent_value)) assert len(candidates) >= sample_size samples = random.Random(seed).sample(candidates, sample_size) mismatches = [ (symbol, trade_date, field, mootdx_value, tencent_value) for symbol, trade_date, field, mootdx_value, tencent_value in samples if abs(mootdx_value - tencent_value) > 0.05 ] assert mismatches == [] def test_3_4_real_mootdx_index_kline_matches_tencent() -> None: """ 功能说明:验证 mootdx 指数 K 线与腾讯财经 K 线价格基本一致。 参数说明:无。 返回值说明:无返回值。 注意事项:用例编号 3-4,随机抽取上证指数、深证成指、创业板指共 100 个 OHLC 值对比。 """ assert_random_kline_prices_match(["sh000001", "sz399001", "sz399006"], 100, 20260623) def test_3_5_real_mootdx_component_kline_matches_tencent() -> None: """ 功能说明:验证三大指数代表成分股的 mootdx K 线与腾讯财经 K 线价格基本一致。 参数说明:无。 返回值说明:无返回值。 注意事项:用例编号 3-5,分别选取贵州茅台、平安银行、宁德时代并随机抽取 100 个 OHLC 值对比。 """ assert_random_kline_prices_match(["sh600519", "sz000001", "sz300750"], 100, 20260624)