"""通达信数据源(mootdx TCP直连通达信服务器) 通过 TCP 协议直连通达信行情服务器,不走 HTTP,不会被限流。 主要用途: - K线数据:主数据源(稳定可靠) """ import asyncio from typing import Optional, List def _get_market(code: str) -> str: return "sh" if code.startswith("6") else "sz" def _create_client(): from mootdx.quotes import Quotes return Quotes.factory(market="std", multithread=True, heartbeat=True) def _sync_fetch_kline(code: str, days: int) -> Optional[list]: client = _create_client() klines = client.bars(symbol=code, frequency=9, offset=min(days, 800)) if klines is None or len(klines) == 0: return None result = [] prev_close = 0.0 for bar in reversed(klines): close = float(bar.close) change_pct = 0 if prev_close > 0: change_pct = (close - prev_close) / prev_close * 100 result.append( { "date": ( bar.datetime.strftime("%Y-%m-%d") if hasattr(bar.datetime, "strftime") else str(bar.datetime)[:10] ), "open": float(bar.open), "close": close, "high": float(bar.high), "low": float(bar.low), "volume": int(bar.vol) if hasattr(bar, "vol") else 0, "turnover": ( float(bar.amount) if hasattr(bar, "amount") and bar.amount else 0 ), "changePercent": round(change_pct, 2), } ) prev_close = close result.sort(key=lambda x: x["date"]) return result async def fetch_kline_history(code: str, days: int = 90) -> Optional[List[dict]]: """获取日K线(TCP直连通达信,主数据源)""" try: loop = asyncio.get_event_loop() return await loop.run_in_executor(None, _sync_fetch_kline, code, days) except ImportError: return None except Exception as e: print(f"[mootdx] fetch_kline error: {e}") return None