""" fetcher.py - 从 data_provider HTTP API 拉取 K 线数据。 """ from typing import List, Optional import requests import pandas as pd import logging logger = logging.getLogger(__name__) TIMEFRAME = "1m" PROVIDER_URL = "http://103.179.242.166" FETCH_LIMIT = 1000 _symbols_cache: Optional[List[str]] = None def get_symbols() -> list[str]: """从 data_provider /health 获取所有可用币对(缓存)。""" global _symbols_cache if _symbols_cache is not None: return _symbols_cache try: resp = requests.get(f"{PROVIDER_URL}/health", timeout=10) resp.raise_for_status() _symbols_cache = resp.json().get("symbols", []) logger.info(f"获取到 {len(_symbols_cache)} 个币对") except Exception as e: logger.error(f"获取币对列表失败: {e}") _symbols_cache = ["BTC/USDT:USDT"] return _symbols_cache def fetch_ohlcv(symbol: str) -> pd.DataFrame: """从 data_provider API 拉取某个币对最近 FETCH_LIMIT 根 1m K 线。""" url = f"{PROVIDER_URL}/api/candles" params = { "symbol": symbol, "tf": TIMEFRAME, "limit": FETCH_LIMIT, } resp = requests.get(url, params=params, timeout=30) resp.raise_for_status() data = resp.json() if not data: logger.warning(f"{symbol}: API 返回空数据") return pd.DataFrame() df = pd.DataFrame(data) df["timestamp"] = pd.to_datetime(df["timestamp"], unit="ms", utc=True) df["date"] = df["timestamp"] df = df.drop_duplicates(subset="timestamp").sort_values("timestamp").reset_index(drop=True) return df