Files
big-qmt/py-client/strategy/etf/data.py
2026-09-17 00:56:05 +08:00

56 lines
2.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.
"""ETF 专用历史日线适配,不依赖或修改 QMT SDK。"""
from datetime import date, datetime
import math
import re
import httpx
DAILY_URL = 'http://go.apinb.com/a/get_daily'
def daily_bars(client: httpx.Client, code: str, today: date, count: int = 120) -> list[dict]:
"""读取指定证券日线;只使用 code 参数,截取历史窗口在本地完成。"""
response = client.get(DAILY_URL, params={'code': code})
response.raise_for_status()
return parse_daily(response.json(), code, today, count)
def parse_daily(payload: dict, code: str, today: date, count: int = 120) -> list[dict]:
"""校验业务状态、证券归属和 OHLC将 trade_date 转为指标需要的 date。"""
if type(count) is not int or count <= 0:
raise ValueError('日线数量必须为正整数')
if not isinstance(payload, dict) or type(payload.get('code')) is not int or payload['code'] != 0:
raise ValueError(f'日线接口业务失败:{payload.get("message", "状态无效") if isinstance(payload, dict) else "响应非对象"}')
details = payload.get('details')
if not isinstance(details, list) or not details:
raise ValueError(f'{code} 日线接口未返回有效 details 列表')
bars = {}
for row in details:
if not isinstance(row, dict) or row.get('ts_code') != code:
raise ValueError(f'{code} 日线证券代码不一致')
stamp = str(row.get('trade_date', ''))
if not re.fullmatch(r'[0-9]{8}', stamp):
raise ValueError(f'{code} 日线日期无效:{stamp}')
day = datetime.strptime(stamp, '%Y%m%d').date()
# 当前日及未来日线均不可用于盘中指标,先过滤再截取最近 count 根。
if day >= today:
continue
if stamp in bars:
raise ValueError(f'{code} 日线日期重复:{stamp}')
values = {}
for key in ('open', 'high', 'low', 'close'):
value = row.get(key)
if isinstance(value, bool) or not isinstance(value, (int, float, str)):
raise ValueError(f'{code} 日线 {key} 无效')
value = float(value)
if not math.isfinite(value) or value <= 0:
raise ValueError(f'{code} 日线 {key} 非有限正数')
values[key] = value
if not (values['low'] <= values['open'] <= values['high']
and values['low'] <= values['close'] <= values['high']):
raise ValueError(f'{code} 日线 OHLC 关系异常')
bars[stamp] = dict(date=stamp, **values)
return [bars[stamp] for stamp in sorted(bars)[-count:]]