Metadata-Version: 2.4
Name: tdxquant
Version: 0.3.0
Summary: 通达信量化(TdxQuant) HTTP SDK —— 统一返回 DataFrame，字段金融规范化(snake_case)
Requires-Python: >=3.13
Requires-Dist: httpx>=0.27
Requires-Dist: orjson>=3.11.9
Requires-Dist: pandas>=2.0
Description-Content-Type: text/markdown

# tdxquant

[![PyPI version](https://img.shields.io/pypi/v/tdxquant.svg)](https://pypi.org/project/tdxquant/) [![Python](https://img.shields.io/pypi/pyversions/tdxquant.svg)](https://pypi.org/project/tdxquant/)

通达信量化（TdxQuant）**HTTP SDK** —— 直接调用通达信客户端官方 HTTP 接口（`POST http://127.0.0.1:17709/`），统一返回 `pandas.DataFrame`，字段重命名为金融行业规范的 **snake_case**。

> **命名**：PyPI 包名 `tdxquant`（`pip install tdxquant`），import 名 `tdxquant`（`from tdxquant import TdxAPI`）。

## 工作方式

通达信量化客户端原生提供 HTTP 调用方式（无需 tqcenter / DLL / 自建网关）：

```
你的代码(SDK) ──HTTP/JSON──► 通达信客户端(127.0.0.1:17709)
```

1. 启动支持 TQ 的通达信客户端（它会监听 `127.0.0.1:17709`）
2. SDK 直接 POST 调用，字段重命名 + DataFrame 封装在 SDK 内完成

> 请求格式：`{"id":1, "method":"<tqcenter方法名>", "params":{...}}`，`method` 为 tqcenter 函数名，`params` 为底层参数名。

## 安装

```bash
pip install tdxquant      # 从 PyPI（import 名为 tdxquant）
# 或 uv add tdxquant
```

> **本地开发**（克隆源码后）：`uv sync` 或 `pip install -e .`。
> 需要 Python ≥ 3.13、通达信金融终端（量化模拟版 / 专业研究版等支持 TQ 策略的版本）。

## 快速开始

```python
from tdxquant import TdxAPI

api = TdxAPI()   # 默认 http://127.0.0.1:17709，需通达信客户端在线

# K线（OHLCV 长表）
df = api.get_kline("000001.SZ", freq="daily", adjust="qfq", start_date="20260101")
# 实时快照
snap = api.get_snapshot("000001.SZ")
# 股票 / 板块 / ETF
api.get_stock_list()                   # 所有分类合并(带 market/category 列)
api.get_sector_list()
api.get_track_etf("000300.SH")
# 财务
api.get_financial("600519.SH", fields=["Fn193","Fn194"], start_date="20240101")
# 交易日历
api.get_trading_calendar("20260101", "20260613")
```

从别的机器调用：`TdxAPI(base_url="http://通达信机器IP:17709")`。

## 接口映射表（SDK → TdxQuant 数据源）

SDK 的业务接口按 TdxQuant 官方文档（`docs/TdxQuant_doc/TdxQuant文档`）归档，`tdxquant/api/` 下**一个 `.py` 文件对应一个文档分类**。下表标注每个 SDK 方法的数据源（TdxQuant 底层 HTTP 接口名）与文档位置；每个方法的 docstring 首部亦有同样的「数据源」标注。

### 02-通用函数 · `api/common.py`

| SDK 方法 | 数据源 TdxQuant 接口 | 文档 | 说明 |
|---|---|---|---|
| `get_trading_calendar` | `get_trading_dates` | 2.8 | 交易日历（单列 `date`） |
| `refresh_cache` | `refresh_cache` | 2.5 | 刷新行情缓存（返回 `dict`） |
| `refresh_kline` | `refresh_kline` | 2.6 | 缓存历史 K线（返回 `dict`） |
| `download_file` | `download_file` | 2.7 | 下载十大股东 / ETF 申赎清单（返回 `dict`） |

### 03-行情类信息 · `api/market.py`

| SDK 方法 | 数据源 TdxQuant 接口 | 文档 | 说明 |
|---|---|---|---|
| `get_kline` | `get_market_data` | 3.1 | K线（OHLCV 长表） |
| `get_snapshot` | `get_market_snapshot` | 3.2 | 实时快照（五档） |
| `get_instrument_info` | `get_stock_info` | 3.3 | 证券基本信息 |
| `get_more_info` | `get_more_info` | 3.4 | 证券更多信息 |
| `get_dividend_factors` | `get_divid_factors` | 3.6 | 分红送配 |
| `get_ipo_info` | `get_ipo_info` | 3.8 | 新股 / 新债申购 |
| `get_share_capital` | `get_gb_info` | 3.9 | 每日股本数据 |
| `get_share_capital_by_date` | `get_gb_info_by_date` | 3.10 | 按日期段股本数据 |

> 文档 3.5（批量获取价格和成交量 `get_pricevol`）、3.7（股票所属板块 `get_relation`）暂未实现。

### 04-财务类数据 · `api/financial.py`

| SDK 方法 | 数据源 TdxQuant 接口 | 文档 | 说明 |
|---|---|---|---|
| `get_financial` | `get_financial_data` | 4.1 | 专业财务（`FNxxx`） |
| `get_financial_by_date` | `get_financial_data_by_date` | 4.2 | 指定日期专业财务 |
| `get_stock_trade_data` | `get_gpjy_value` | 4.3 | 股票交易（`GPx`） |
| `get_stock_trade_data_by_date` | `get_gpjy_value_by_date` | 4.4 | 指定日期股票交易 |
| `get_sector_trade_data` | `get_bkjy_value` | 4.5 | 板块交易（`BKx`） |
| `get_sector_trade_data_by_date` | `get_bkjy_value_by_date` | 4.6 | 指定日期板块交易 |
| `get_market_trade_data` | `get_scjy_value` | 4.7 | 市场交易（`SCx`，无个股维度） |
| `get_market_trade_data_by_date` | `get_scjy_value_by_date` | 4.8 | 指定日期市场交易 |
| `get_stock_single_data` | `get_gp_one_data` | 4.9 | 单点数据（`GOx`） |

### 05-分类-板块成份股 · `api/sector.py`

| SDK 方法 | 数据源 TdxQuant 接口 | 文档 | 说明 |
|---|---|---|---|
| `get_stock_list` | `get_stock_list` | 5.1 | 分类成分股（`market` 不传返回全部，带 market/category 列） |
| `get_sector_list` | `get_sector_list` | 5.2 | A 股板块列表 |
| `get_sector_stocks` | `get_stock_list_in_sector` | 5.3 | 板块成分股 |

### 06-自选股-自定义板块 · `api/user_sector.py`

| SDK 方法 | 数据源 TdxQuant 接口 | 文档 | 说明 |
|---|---|---|---|
| `get_user_sectors` | `get_user_sector` | 6.1 | 用户自定义板块列表 |

> 文档 6.2~6.6（增删改 / 重命名自定义板块）需通达信客户端交互，暂未实现。

### 07-ETF-可转债-期货数据 · `api/derivatives.py`

| SDK 方法 | 数据源 TdxQuant 接口 | 文档 | 说明 |
|---|---|---|---|
| `get_track_etf` | `get_trackzs_etf_info` | 7.1 | 跟踪指数的 ETF |
| `get_convertible_bond` | `get_kzz_info` | 7.2 | 可转债信息 |

### 基础

| 方法 | 数据源 TdxQuant 接口 | 说明 |
|---|---|---|
| `health` | `get_trading_dates` | 连通检查（内部调用） |
| `close` | — | 关闭底层 HTTP 连接 |

> 文档 08-调用通达信公式、09-交易函数（`order_stock` 等）暂未实现（交易类按需求不做）。字段血缘映射见 `tdxquant/schema.py` 的 `*_FIELD_MAP`，契约测试见 `tests/test_schema.py`。

## 通用约定

- **证券代码**：`000001.SZ` / `600519.SH` / `000300.SH`（6 位 + 市场后缀；基金 `.JJ`、北交所 `.BJ`）。
- **频率 `freq`**：`1min / 5min / 15min / 30min / 60min / daily / weekly / monthly`，内部转为 tqcenter `period`（`1m / 5m / 15m / 30m / 1h / 1d / 1w / 1mon`）。
- **复权 `adjust`**：`none` 不复权 / `qfq` 前复权 / `hfq` 后复权，内部转为 tqcenter `dividend_type`（`none / front / back`）。
- **日期**：统一字符串 `YYYYMMDD`（如 `20260613`），分钟线可 `YYYYMMDDHHMMSS`。严格校验，格式不符报错。空串/None 视为"不限制"。区间型参数用 `start_date` / `end_date`，按日期点型用 `date`。
- **`code` / `stock_list`**：单只 `str` 或 `list[str]` 均可。
- **字段筛选 `fields`**：传入**通达信原始字段名**（如 `["Open","Close"]`）；财务/交易类底层参数名为 `table_list`（编码如 `Fn193`），行情类底层为 `field_list`，SDK 对外统一叫 `fields`。

---

## 接口参考（入参 / 出参 / 字段血缘）

> **字段血缘表**中「tqcenter 原字段」为通达信客户端原始返回字段名，「SDK 字段」为重命名后的列名。**未被映射命中的原字段一律转小写保留**（不丢弃、不报错）。

### 行情类

#### `get_kline(code, freq="daily", adjust="none", start_date="", end_date="", fields=None, fill_data=True)`

K线数据，返回标准 OHLCV 长表。底层 `tqcenter.get_market_data`。

| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| `code` | str \| list | — | 证券代码或列表 |
| `freq` | str | `"daily"` | 频率（见通用约定） |
| `adjust` | str | `"none"` | 复权 `none/qfq/hfq` |
| `start_date` | str | `""` | 起始 `YYYYMMDD`（分钟线可 14 位） |
| `end_date` | str | `""` | 结束日期，留空取至今 |
| `fields` | list \| None | None | 返回字段筛选（原字段名，如 `["Open","Close"]`） |
| `fill_data` | bool | `True` | 是否向后填充缺失数据 |

**出参列**：`datetime, code, open, high, low, close, volume, amount, forward_factor, open_interest`

| tqcenter 原字段 | SDK 字段 | 说明 |
|---|---|---|
| `Date`（时间轴） | `datetime` | 时间 |
| `stock_list` | `code` | 证券代码 |
| `Open` | `open` | 开盘价 |
| `High` | `high` | 最高价 |
| `Low` | `low` | 最低价 |
| `Close` | `close` | 收盘价 |
| `Volume` | `volume` | 成交量（手） |
| `Amount` | `amount` | 成交额（万元） |
| `ForwardFactor` | `forward_factor` | 前复权因子（仅 `adjust=none` 有效） |
| `VolInStock` | `open_interest` | 持仓量（期货有效） |

#### `get_snapshot(code, fields=None, max_workers=16)`

实时快照，索引为 `code`。底层 `tqcenter.get_market_snapshot`。多代码默认线程池并发（复用同一 `httpx.Client`）：单次约 3.5ms，全市场 5500+ 只约 **5s**；`max_workers=None` 或 `1` 退回串行。注意通达信客户端服务端并行上限约 12~16，超过 20 会因排队变慢。

| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| `code` | str \| list | — | 证券代码或列表 |
| `fields` | list \| None | None | 返回字段筛选（原字段名） |
| `max_workers` | int \| None | `16` | 并发线程数；`None`/`1` 串行 |

**出参列**（索引 `code`，含五档买卖盘，长度均为 5 的 list）：

| tqcenter 原字段 | SDK 字段 | 说明 |
|---|---|---|
| `ItemNum` | `tick_count` | 快照笔数 |
| `LastClose` | `last_close` | 昨收价 |
| `Open` | `open` | 开盘价 |
| `Max` | `high` | 最高价 |
| `Min` | `low` | 最低价 |
| `Now` | `last` | 最新价（现价） |
| `Volume` | `volume` | 总成交量（手） |
| `NowVol` | `last_volume` | 现手（最新成交量） |
| `Amount` | `amount` | 总成交额 |
| `Inside` | `inside_volume` | 内盘 |
| `Outside` | `outside_volume` | 外盘 |
| `TickDiff` | `tick_change` | 笔涨跌 |
| `InOutFlag` | `in_out_flag` | 内外盘标志（0 买 / 1 卖 / 2 未知） |
| `Jjjz` | `nav` | 基金净值 |
| `Buyp` | `bid_prices` | 五档买价（list） |
| `Buyv` | `bid_volumes` | 五档买量（list） |
| `Sellp` | `ask_prices` | 五档卖价（list） |
| `Sellv` | `ask_volumes` | 五档卖量（list） |
| `UpHome` | `up_count` | 上涨家数（指数） |
| `DownHome` | `down_count` | 下跌家数（指数） |
| `Before5MinNow` | `price_5min_ago` | 5 分钟前价格 |
| `Average` | `average_price` | 均价 |
| `XsFlag` | `decimal_places` | 小数位数 |
| `Zangsu` | `change_speed` | 涨速 |
| `ZAFPre3` | `pct_chg_3d` | 3 日涨幅（%） |

#### `get_instrument_info(code, fields=None)` / `get_more_info(code, fields=None)`

证券基本信息 / 更多信息，索引为 `code`。底层 `tqcenter.get_stock_info` / `get_more_info`（返回 dict，字段众多）。下表为核心映射字段，**其余字段保留原名转小写**（如 `volbase` / `minprice` / `xsflag` 等）。

| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| `code` | str \| list | — | 证券代码或列表 |
| `fields` | list \| None | None | 返回字段筛选（原字段名） |

| tqcenter 原字段 | SDK 字段 | 说明 |
|---|---|---|
| `Code` | `code` | 证券代码 |
| `Name` | `name` | 证券名称 |
| `J_zgb` | `total_share_capital` | 总股本 |
| `ActiveCapital` | `float_capital` | 流通股本 |
| `J_zltb` | `float_ratio` | 流通占比 |
| `Industry` | `industry` | 行业 |
| `J_hy` | `industry_code` | 行业代码 |
| `J_zh` | `concept_code` | 概念代码 |
| `J_country` | `region` | 地区 |
| `J_main` | `main_business` | 主营业务 |

#### `get_dividend_factors(code, start_date="", end_date="")`

分红送配（除权除息）数据。底层 `tqcenter.get_divid_factors`。

| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| `code` | str | — | 证券代码 |
| `start_date` | str | `""` | 起始日期 `YYYYMMDD` |
| `end_date` | str | `""` | 结束日期 `YYYYMMDD` |

**出参列**：`date, div_type, cash_dividend, rights_price, share_bonus, rights_issue`

> tqcenter 原始返回结构为 `{Date:[...], Type:[...], Value:[[Bonus, AllotPrice, ShareBonus, Allotment], ...]}`，SDK 按数组位置展开为下列命名列：

| tqcenter 原字段（位置） | SDK 字段 | 说明 |
|---|---|---|
| `Date`（索引） | `date` | 除权除息日 |
| `Type` | `div_type` | 分红类型 |
| `Value[0]`（`Bonus`） | `cash_dividend` | 每股派息（红利） |
| `Value[1]`（`AllotPrice`） | `rights_price` | 配股价 |
| `Value[2]`（`ShareBonus`） | `share_bonus` | 每股送转股 |
| `Value[3]`（`Allotment`） | `rights_issue` | 每股配股 |

---

### 财务类

> 财务/交易数据字段为通达信专业编码（`FNxxx` / `GPx` / `BKx` / `SCx` / `GOx`），SDK **保留编码并转小写**（如 `Fn193` → `fn193`、`GP1` → `gp1`），需对照通达信字段手册解读。时间字段 `announce_time`（公告日）/ `tag_time`（截止日）保留。
> 这些接口底层字段筛选参数名为 **`table_list`**（非行情类的 `field_list`）。专业财务需客户端先下载专业财务数据。

#### `get_financial(stock_list, fields=None, start_date="", end_date="", report_type="report_time")` / `get_financial_by_date(stock_list, fields=None, date="")`

专业财务数据。底层 `tqcenter.get_financial_data` / `get_financial_data_by_date`。

| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| `stock_list` | str \| list | — | 证券代码或列表 |
| `fields` | list \| None | None | 字段列表（通达信编码，如 `["Fn193","Fn194"]`） |
| `start_date` / `end_date` | str | `""` | 区间 `YYYYMMDD`（`end_date` 留空 SDK 自动取当天） |
| `date` | str | `""` | 指定日期版专用，报告期 `YYYYMMDD`（拆为 `year` + `mmdd` 传给底层） |
| `report_type` | str | `"report_time"` | `report_time`（截止日） / `announce_time`（公告日），仅区间版有效 |

**出参**：长表，含 `code` 列 + 各 `fnxxx` 编码字段列。

#### `get_stock_trade_data(stock_list, fields=None, start_date="", end_date="")` / `get_stock_trade_data_by_date(stock_list, fields=None, date="")`

股票交易数据（字段 `GPx`）。底层 `tqcenter.get_gpjy_value` / `get_gpjy_value_by_date`。参数同上（区间版用 `start_date`/`end_date`，按日期版用 `date`）。**出参**：长表含 `code` 列 + 各 `gpx` 字段列。

#### `get_sector_trade_data(stock_list, fields=None, start_date="", end_date="")` / `get_sector_trade_data_by_date(stock_list, fields=None, date="")`

板块交易数据（字段 `BKx`）。底层 `tqcenter.get_bkjy_value` / `get_bkjy_value_by_date`。参数与出参形态同股票交易数据，字段编码前缀为 `bkx`。

#### `get_market_trade_data(fields=None, start_date="", end_date="")` / `get_market_trade_data_by_date(fields=None, date="")`

市场交易数据（字段 `SCx`，**无个股维度**）。底层 `tqcenter.get_scjy_value` / `get_scjy_value_by_date`。

| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| `fields` | list \| None | None | 字段列表（`SCx` 编码） |
| `start_date` / `end_date` | str | `""` | 区间 `YYYYMMDD`（按日期版用 `date`） |

**出参**：扁平表，含各 `scx` 字段列（**无 `code` 列**）。

#### `get_stock_single_data(stock_list, fields=None)`

股票单个数据（非序列，字段 `GOx`）。底层 `tqcenter.get_gp_one_data`。

| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| `stock_list` | str \| list | — | 证券代码或列表 |
| `fields` | list \| None | None | 字段列表（`GOx` 编码） |

**出参**：长表，含 `code` 列 + 各 `gox` 字段列。

#### `get_share_capital(code, date_list=None, count=1)` / `get_share_capital_by_date(code, start_date="", end_date="")`

每日股本数据（总股本 / 流通股本等）。底层 `tqcenter.get_gb_info` / `get_gb_info_by_date`。

| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| `code` | str | — | 证券代码 |
| `date_list` | list | None | 指定日期列表（`get_share_capital` 专用） |
| `count` | int | `1` | 返回天数（`get_share_capital` 专用） |
| `start_date` / `end_date` | str | `""` | 区间版（`_by_date`）专用 `YYYYMMDD` |

**出参**：扁平表，字段转小写保留（如总股本、流通股本等）。

---

### 板块 / 分类

#### `get_stock_list(market=None)`

分类成分股。底层 `tqcenter.get_stock_list`（`list_type=0`）。

| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| `market` | str \| None | None | 分类代码；不传则遍历所有主要分类合并返回 |

**出参列**：`code, market, category`（`category` 为中文分类名）。
`market` 不传时，同一股票属于多个分类会重复出现多行；传具体值（如 `"5"` / `"23"`）只返回该分类。完整 `market` 取值见 `tdxquant/api/sector.py` 的 `STOCK_CATEGORY`（如 `"5"` 所有A股 / `"7"` 上证主板 / `"23"` 沪深300 / `"31"` ETF / `"32"` 可转债 / `"51"` 创业板 / `"52"` 科创板 / `"53"` 北交所 …）。

#### `get_sector_list(list_type=0)`

A 股全部板块。底层 `tqcenter.get_sector_list`。

| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| `list_type` | int | `0` | `0` 仅代码（列 `code`）/ `1` 含名称（列 `code, name`） |

#### `get_user_sectors()`

用户自定义板块列表。底层 `tqcenter.get_user_sector`。**出参列**：`code, name`（无自定义板块时为空）。

#### `get_sector_stocks(block_code, block_type=0, list_type=0)`

板块成分股。底层 `tqcenter.get_stock_list_in_sector`。

| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| `block_code` | str | — | 板块代码（如 `880081.SH`）或名称（如 `钛金属`）；`block_type=1` 时传自定义板块简称 |
| `block_type` | int | `0` | `0` 系统板块 / `1` 自定义板块简称 |
| `list_type` | int | `0` | 列表类型 |

**出参列**：单列 `code`。

---

### 证券

#### `get_convertible_bond(code, fields=None)`

可转债基础信息。底层 `tqcenter.get_kzz_info`（返回 list，取首项为单行）。下表为核心映射字段，**其余字段保留原名转小写**。

| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| `code` | str | — | 可转债代码 |
| `fields` | list \| None | None | 返回字段筛选（原字段名） |

| tqcenter 原字段 | SDK 字段 | 说明 |
|---|---|---|
| `SetCode` | `market` | 市场（0 深 / 1 沪） |
| `KZZCode` | `bond_code` | 可转债代码 |
| `HSCode` | `underlying_code` | 正股代码 |
| `ZGPrice` | `conversion_price` | 转股价 |
| `CurRate` | `coupon_rate` | 票面利率 |
| `RestScope` | `remaining_scale` | 剩余规模 |
| `PutBack` | `putback_flag` | 回售标志 |
| `ForceRedeem` | `force_redeem_flag` | 强制赎回标志 |

#### `get_ipo_info(ipo_type=0, ipo_date=0)`

新股 / 新债申购信息。底层 `tqcenter.get_ipo_info`。

| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| `ipo_type` | int | `0` | `0` 全部 / `1` 新债 / `2` 新股 |
| `ipo_date` | int | `0` | `0` 今天 / `1` 今天及以后 |

**出参列**：`market, code, name, subscribe_date, subscribe_price, subscribe_code, max_subscribe, issue_pe`

| tqcenter 原字段 | SDK 字段 | 说明 |
|---|---|---|
| `SetCode` | `market` | 市场（0 深 / 1 沪） |
| `Code` | `code` | 证券代码 |
| `Name` | `name` | 证券名称 |
| `SGDate` | `subscribe_date` | 申购日期 |
| `SGPrice` | `subscribe_price` | 申购价 |
| `SGCode` | `subscribe_code` | 申购代码 |
| `MaxSG` | `max_subscribe` | 最大申购额 |
| `PE_Issue` | `issue_pe` | 发行市盈率 |

#### `get_track_etf(zs_code)`

跟踪指定指数的 ETF 列表。底层 `tqcenter.get_trackzs_etf_info`。

| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| `zs_code` | str | — | 指数代码，如 `000300.SH` |

**出参列**：`code, name, last_price, pre_close, iopv, total_share, scale`

| tqcenter 原字段 | SDK 字段 | 说明 |
|---|---|---|
| `Code` | `code` | ETF 代码 |
| `Name` | `name` | ETF 名称 |
| `NowPrice` | `last_price` | 现价 |
| `PreClose` | `pre_close` | 昨收 |
| `IOPV` | `iopv` | 参考净值 |
| `Zgb` | `total_share` | 总份额/规模 |
| `Sz` | `scale` | 规模 |

---

### 日历 / 缓存

#### `get_trading_calendar(start_date, end_date, market="SH")`

交易日历。底层 `tqcenter.get_trading_dates`（文档 02-通用函数/2.8）。

| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| `start_date` | str | — | 起始日期 `YYYYMMDD` |
| `end_date` | str | — | 结束日期 `YYYYMMDD` |
| `market` | str | `"SH"` | 市场（默认上交所） |

**出参列**：单列 `date`。

> **说明**：`get_trading_calendar` 的底层即 `get_trading_dates`（文档 2.8），返回该区间内的交易日列表。`health()` 内部也调用同一接口做连通检查。

#### `refresh_cache(market="AG", force=False)` → dict

刷新行情缓存（刷新后 5 分钟内取数据不触发刷新）。底层 `tqcenter.refresh_cache`。

| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| `market` | str | `"AG"` | 市场标识 |
| `force` | bool | `False` | 是否强制刷新 |

#### `refresh_kline(stock_list, period="")` → dict

缓存历史 K线（仅支持 `1m/5m/1d`，不宜一次太多）。底层 `tqcenter.refresh_kline`。

| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| `stock_list` | str \| list | — | 证券代码或列表 |
| `period` | str | `""` | 周期，留空由底层默认 |

#### `download_file(code, down_time="", down_type=1)` → dict

下载特定数据文件。底层 `tqcenter.download_file`。

| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| `code` | str | — | 证券代码 |
| `down_time` | str | `""` | 下载日期 `YYYYMMDD`，留空取当天 |
| `down_type` | int | `1` | `1` 十大股东 / `2` ETF 申赎清单 |

---

### 基础

#### `health()` → dict

健康检查：试调一个轻量接口验证连通性。

**出参**：`{"status": "ok"|"error", "base_url": ..., "msg"?}`。

#### `close()`

关闭底层 HTTP 连接。支持 `with TdxAPI(...) as api:` 上下文自动关闭。

## 字段命名规范

- 全部 **snake_case 小写**，采用金融行业惯例（OHLCV / bid-ask / nav / pct_chg）。
- 原字段 → 新字段完整血缘见 `tdxquant/schema.py` 的 `*_FIELD_MAP`（字段血缘唯一真实来源），`tests/test_schema.py` 为机器校验契约，锁住映射不漂移。
- 通达信专业编码字段（`FNxxx` / `GPx` / `BKx` / `SCx` / `GOx`）保留转小写，需对照通达信字段手册。
- 未命中映射的原字段一律转小写保留（不丢弃、不报错）；`list` / `dict` 单元格（如五档盘口）不会被数值化压平。

## 异常

- `TdxQuantError`：业务错误（`result.ErrorId != "0"`），含 `.error_id` / `.error_msg`。
- `TdxQuantConnectionError`：网络/连接错误（`TdxQuantError` 子类）。

## 测试

```bash
uv run pytest                     # 单元测试（字段血缘契约 + 拼装逻辑，不依赖网络）
uv run pytest --runintegration    # 集成测试（需通达信客户端在线监听 17709）
```

集成测试默认跳过，必须显式加 `--runintegration` 才运行。

## 项目结构

```
tdxquant/
├── client.py          # HTTP 客户端（POST 17709）+ DataFrame 拼装
├── schema.py          # 字段血缘映射表（唯一真实来源）
├── enums.py           # Freq / Adjust 枚举 + validate_date 日期校验
├── exceptions.py      # 异常
└── api/               # 业务接口（mixin，按 TdxQuant 文档归档，由 TdxAPI 组合继承）
    ├── common.py       # 02-通用函数
    ├── market.py       # 03-行情类信息
    ├── financial.py    # 04-财务类数据
    ├── sector.py       # 05-分类-板块成份股
    ├── user_sector.py  # 06-自选股-自定义板块
    └── derivatives.py  # 07-ETF-可转债-期货数据

tests/                 # 单元测试（按 api 分类组织，mock _call，不依赖网络）
```

## 常见问题

- **`server return none` / 连接失败**：确认通达信客户端已启动并登录行情；SDK 默认连 `127.0.0.1:17709`。
- **`502 Bad Gateway`**：本机代理（Clash/V2Ray）劫持 localhost 请求。SDK 已默认 `trust_env=False` 直连，若仍异常请关闭代理。
- **财务/专业数据为空**：需先在通达信客户端下载对应盘后/专业财务数据。
- **`get_financial` 报 end_time 缺失**：底层要求结束日期，`end_date` 留空时 SDK 自动取当天。
