# tdx RESTful API 接口文档

基于 **Gin** 的通达信行情网关。入口：`cmd/api`，实现：`extend/httpserver`。

## 启动

### 本地调试

```bash
# 项目根目录
go run ./cmd/api

# 端口占用时
ADDR=:18080 go run ./cmd/api
```

### Docker（对外提供 API）

```bash
# 构建并后台启动, 映射宿主机 8080
docker compose up -d --build

# 查看日志
docker compose logs -f tdx-api

# 本机验证
curl http://127.0.0.1:8080/health

# 局域网其它机器: http://<宿主机IP>:8080/health
```

仅构建镜像：

```bash
docker build -t tdx-api:latest .
docker run -d --name tdx-api -p 8080:8080 \
  -e GIN_MODE=release -e EXHQ=1 \
  -v tdx-data:/app/data \
  tdx-api:latest
```

容器需能访问公网通达信行情（TCP **7709** / 扩展 **7727**）。数据目录挂载到 `/app/data`（gbbq 缓存等）。

| 环境变量 | 说明 | 默认 |
| --- | --- | --- |
| `ADDR` | 监听地址 | `:8080` |
| `GIN_MODE` | Gin 模式：`debug` / `release` / `test` | 本地 `debug`，容器 `release` |
| `EXHQ` | 是否启用扩展行情 `/ex/*`：`1` 开 / `0` 关 | `1` |
| `DISABLE_CONCENTRATION` | `1` 关闭全 A 集中度回补/16:00 任务 | `0` |

### 调用注意（常见“不通”原因）

1. **缺必填参数**会返回 `code=1` 或 HTTP 400，不是没实现。例如 `/quote` 必须带 `codes`，`/block/data` 必须带 `file`。
2. **中文参数请 URL 编码**，或用支持 UTF-8 的客户端（Apifox / Postman）。PowerShell/部分终端直接写 `name=创业板指` 可能乱码导致“未找到”。
3. **扩展行情 `/ex/*`** 依赖独立服务器（7727）。`cmd/api` 默认 `EXHQ=1` 启用；若启动失败或你设了 `EXHQ=0`，这些路由不存在（404）。
4. 本地默认若 `:8080` 被占用，请用 `ADDR=:18080 go run ./cmd/api`，请求也要打到对应端口。

## 统一响应

**成功**

```json
{
  "code": 0,
  "msg": "ok",
  "data": {}
}
```

**失败**

```json
{
  "code": 1,
  "msg": "错误信息",
  "data": null
}
```

---

## 1. 首页与健康检查

| 方法 | 路径 | 参数 | 说明 |
| --- | --- | --- | --- |
| GET | `/` | 无 | 首页：渲染本接口文档（HTML） |
| GET | `/docs.md` | 无 | 原始 Markdown |
| GET | `/health` | 无 | 健康检查 |

```bash
curl "http://127.0.0.1:18080/health"
```

```json
{
  "code": 0,
  "msg": "ok",
  "data": { "status": "running", "framework": "gin" }
}
```

---

## 2. 代码 / 数量

| 方法 | 路径 | 参数 | 说明 |
| --- | --- | --- | --- |
| GET | `/count` | `exchange` | 指定交易所证券数量 |
| GET | `/code` | `exchange`, `start` | 证券代码（分页） |
| GET | `/code/all` | `exchange` | 全部证券代码 |
| GET | `/code/stocks` | 无 | 全部股票代码（带前缀） |
| GET | `/code/etfs` | 无 | 全部 ETF 代码 |
| GET | `/code/indexes` | 无 | 全部指数代码 |
| GET | `/search` | `q`, `type`, `limit`, `members` | **聚合搜索**：个股 / ETF / 指数成分 / 概念板块 / 行业板块 |

`exchange`：`sh` / `sz` / `bj`。

### `GET /search`

按**代码或名称**模糊搜索，一次返回五类结果：个股、ETF、指数、概念板块、行业板块。全市场代码、指数成分、概念板块（`block_gn.dat`）和行业板块（`tdxhy.cfg` 归集）由后台**每日 16:30** 拉取并落盘，接口只读内存，避免每次现拉通达信。

| 落盘 | 说明 |
| --- | --- |
| 文件 | `data/search/universe.json`（容器内 `/app/data/search/universe.json`） |
| 启动 | 有文件则秒级加载；无概念/行业的旧文件会后台补拉；无文件则异步全量构建（期间接口返回「尚未就绪」） |
| 定时 | 每天 **16:30** 刷新并覆盖 JSON |

| 参数 | 说明 |
| --- | --- |
| `q` | 必填。代码或名称关键字，如 `茅台` / `600519` / `沪深300` / `锂电池` / `银行` / `sz000001`；也可用 `keyword` |
| `type` | 可选。`stock` / `etf` / `index` / `concept` / `industry`，逗号组合；也可用 `概念`、`行业`；默认全部 |
| `limit` | 可选。每类最多条数，默认 `20`，最大 `100` |
| `members` | 可选。`1` 时给命中的指数、概念、行业附带成分股列表（结果很少或精确命中时才展开，防过大） |

```bash
curl "http://127.0.0.1:8088/search?q=茅台"
curl "http://127.0.0.1:8088/search?q=000001"
curl "http://127.0.0.1:8088/search?q=沪深300&members=1"
curl "http://127.0.0.1:8088/search?q=50&type=etf&limit=10"
curl "http://127.0.0.1:8088/search?q=锂电池&type=concept"
curl "http://127.0.0.1:8088/search?q=银行&type=industry&members=1"
```

```json
{
  "code": 0,
  "msg": "ok",
  "data": {
    "q": "茅台",
    "stocks": [
      { "code": "600519", "full_code": "sh600519", "name": "贵州茅台", "market": 1 }
    ],
    "etfs": [],
    "indexes": [],
    "concepts": [],
    "industries": []
  }
}
```

指数命中示例（`members=1`）：

```json
{
  "q": "沪深300",
  "stocks": [],
  "etfs": [],
  "indexes": [
    {
      "code": "000300",
      "full_code": "sh000300",
      "name": "沪深300",
      "source": "block_zs",
      "member_count": 300,
      "members": [
        { "code": "600519", "name": "贵州茅台" }
      ]
    }
  ],
  "concepts": [],
  "industries": []
}
```

说明：

- `indexes` 来自 `/index/constituents` 同源数据（block_zs + spblock）。用成分股代码/名称搜索时，也可能返回其所属指数。
- `concepts` 与 `/block/concept` 同源（`block_gn.dat`，`source=block_gn`）。`index` 为板块指数代码（如 `880978`），`full_code` 为带市场前缀的代码（如 `sh880978`）。
- `industries` 与 `/block/industry` 同源（`tdxhy.cfg` 按通达信新行业归集，`source=tdxhy`）。`code` 为行业码（`Txxxx`），`index` 为匹配到的 `880xxx`。
- 用成分股代码，或成分股名称精确匹配时，也会返回其所属概念、行业。已有旧索引文件会在启动后后台补拉这两类数据。

概念 / 行业命中示例（`members=1`）：

```json
{
  "q": "锂电池",
  "stocks": [],
  "etfs": [],
  "indexes": [],
  "concepts": [
    {
      "name": "锂电池",
      "index": "880978",
      "full_code": "sh880978",
      "source": "block_gn",
      "member_count": 50,
      "members": [
        { "code": "300750", "name": "宁德时代" }
      ]
    }
  ],
  "industries": []
}
```

### `GET /market/concentration`

全 A 股**日线成交额集中度**：当日成交额排名前 **5%** 股票的成交额合计 ÷ 全 A 总成交额。

| 参数 | 说明 |
| --- | --- |
| `start` | 可选。起始日 `YYYYMMDD` |
| `end` | 可选。结束日 `YYYYMMDD` |

**增量逻辑**

- 结果落盘：`data/concentration/ashare_concentration.json`（容器内 `/app/data/concentration/ashare_concentration.json`）
- 文件不存在时：服务启动后异步按月回补，起始日 **2024-09-24**
- 文件已存在：只补缺失交易日；交易日 **16:00** 自动计算当日并写入
- 可用 `DISABLE_CONCENTRATION=1` 关闭后台任务

```bash
curl "http://127.0.0.1:8088/market/concentration"
curl "http://127.0.0.1:8088/market/concentration?start=20240924&end=20241031"
```

```json
{
  "code": 0,
  "msg": "ok",
  "data": {
    "version": 1,
    "top_pct": 0.05,
    "from": "20240924",
    "updated_at": "2026-08-03T16:05:00+08:00",
    "status": "idle",
    "points": [
      {
        "date": "20240924",
        "concentration": 0.3125,
        "total_amount": 1200000000000,
        "top_amount": 375000000000,
        "stock_count": 5100,
        "top_count": 255
      }
    ]
  }
}
```

`status`：`idle` / `backfilling` / `updating` / `error`；回补过程中 `message` 会显示进度。金额单位为**元**。

---

## 3. 行情 / 财务

| 方法 | 路径 | 参数 | 说明 |
| --- | --- | --- | --- |
| GET | `/quote` | `codes` 或 `code` | **五档盘口报价**（对应 `GetQuote`） |
| GET | `/call_auction` | `code` | 集合竞价 |
| GET | `/gbbq` | `code` | 除权除息 / 股本变更 |
| GET | `/finance` | `exchange`, `code` | 财务信息 |
| GET | `/company/category` | `exchange`, `code` | F10 目录 |
| GET | `/company/content` | `exchange`, `code`, `filename`, `start`, `length` | F10 内容 |

### `GET /quote`

实时五档买卖盘口。对应客户端 `GetQuote`。

| 参数 | 说明 |
| --- | --- |
| `codes` | 多码逗号分隔，如 `sz000001,sh600519`；可省略前缀（按规则自动补） |
| `code` | 单码快捷参数；仅传 `code` 时 `data` 为对象而非数组 |
| 数量上限 | 单次最多 **80** 个代码 |

价格单位均为**元**；成交量/五档量为**手**；成交额为**元**。

```bash
curl "http://127.0.0.1:8088/quote?codes=sz000001,sh600519"
curl "http://127.0.0.1:8088/quote?code=600519"
curl "http://127.0.0.1:8088/quote?codes=000001,600519"
```

```json
{
  "code": 0,
  "msg": "ok",
  "data": [
    {
      "market": 0,
      "code": "000001",
      "full_code": "sz000001",
      "name": "平安银行",
      "server_time": "113000",
      "last": 11.52,
      "open": 11.50,
      "high": 11.60,
      "low": 11.48,
      "price": 11.55,
      "volume": 123456,
      "amount": 142000000.0,
      "bid_vol": 100,
      "inner": 60000,
      "outer": 63456,
      "change": 0.03,
      "change_pct": 0.26,
      "bid": [
        { "price": 11.54, "volume": 200 },
        { "price": 11.53, "volume": 300 },
        { "price": 11.52, "volume": 400 },
        { "price": 11.51, "volume": 500 },
        { "price": 11.50, "volume": 600 }
      ],
      "ask": [
        { "price": 11.55, "volume": 180 },
        { "price": 11.56, "volume": 220 },
        { "price": 11.57, "volume": 260 },
        { "price": 11.58, "volume": 300 },
        { "price": 11.59, "volume": 340 }
      ]
    }
  ]
}
```

字段说明：`bid` 买1→买5，`ask` 卖1→卖5；`change` / `change_pct` 相对昨收。

---

## 4. 分时 / 成交

| 方法 | 路径 | 参数 | 说明 |
| --- | --- | --- | --- |
| GET | `/minute` | `code` | 当日分时 |
| GET | `/minute/history` | `date`, `code` | 历史分时 |
| GET | `/trade` | `code`, `start`, `count` | 当日分笔（分页） |
| GET | `/trade/all` | `code` | 当日全部分笔 |
| GET | `/trade/history` | `date`, `code`, `start`, `count` | 历史分笔（分页） |
| GET | `/trade/history/day` | `date`, `code` | 指定日全部分笔 |

`date` 格式：`YYYYMMDD`。

---

## 5. K 线（股票）

| 方法 | 路径 | 参数 | 说明 |
| --- | --- | --- | --- |
| GET | `/kline` | `type`, `code`, `start`, `count`, `fq` | 指定类型 K 线（分页） |
| GET | `/kline/all` | `type`, `code`, `fq` | 指定类型全部 K 线 |
| GET | `/kline/minute` | `code`, `start`, `count`, `fq` | 1 分钟 |
| GET | `/kline/minute/all` | `code`, `fq` | 全部 1 分钟 |
| GET | `/kline/5minute` | `code`, `start`, `count`, `fq` | 5 分钟 |
| GET | `/kline/5minute/all` | `code`, `fq` | 全部 5 分钟 |
| GET | `/kline/15minute` | `code`, `start`, `count`, `fq` | 15 分钟 |
| GET | `/kline/15minute/all` | `code`, `fq` | 全部 15 分钟 |
| GET | `/kline/30minute` | `code`, `start`, `count`, `fq` | 30 分钟 |
| GET | `/kline/30minute/all` | `code`, `fq` | 全部 30 分钟 |
| GET | `/kline/60minute` | `code`, `start`, `count`, `fq` | 60 分钟 |
| GET | `/kline/60minute/all` | `code`, `fq` | 全部 60 分钟 |
| GET | `/kline/day` | `code`, `start`, `count`, `fq` | 日 K |
| GET | `/kline/day/all` | `code`, `fq` | 全部日 K |
| GET | `/kline/week` | `code`, `start`, `count`, `fq` | 周 K |
| GET | `/kline/week/all` | `code`, `fq` | 全部周 K |
| GET | `/kline/month` | `code`, `start`, `count`, `fq` | 月 K |
| GET | `/kline/month/all` | `code`, `fq` | 全部月 K |
| GET | `/kline/quarter` | `code`, `start`, `count`, `fq` | 季 K |
| GET | `/kline/quarter/all` | `code`, `fq` | 全部季 K |
| GET | `/kline/year` | `code`, `start`, `count`, `fq` | 年 K |
| GET | `/kline/year/all` | `code`, `fq` | 全部年 K |

**复权参数 `fq`（个股 K 线）**

| 值 | 说明 |
| --- | --- |
| `qfq`（默认）或 `1` | 前复权（对齐通达信） |
| `hfq` 或 `2` | 后复权 |
| `raw` / `bfq` / `none` / `0` | 不复权 |

只复权 OHLC/昨收，成交量与成交额不复权。依赖 gbbq 股本变迁数据。

**`type` 对照**

| 值 | 说明 |
| --- | --- |
| `0` | 5 分钟 |
| `1` | 15 分钟 |
| `2` | 30 分钟 |
| `3` | 60 分钟 |
| `4` | 日 K（变体，数值需除以 100） |
| `5` | 周 |
| `6` | 月 |
| `7` | 1 分钟 |
| `8` | 1 分钟（变体） |
| `9` | 日 |
| `10` | 季 |
| `11` | 年 |

```bash
# 默认前复权
curl "http://127.0.0.1:18080/kline/day?code=sh600519&start=0&count=5"
# 后复权 / 不复权
curl "http://127.0.0.1:18080/kline/day?code=sh600519&start=0&count=5&fq=hfq"
curl "http://127.0.0.1:18080/kline/day?code=sh600519&start=0&count=5&fq=raw"
```

个股 K 线每根额外返回 **`Turnover`（换手率，单位 %）**，按当日流通股本计算：`成交量(股) / 流通股本 × 100`（成交量字段 `Volume` 为手，内部按 ×100 换算）。无股本数据时为 `0`。

```json
{
  "code": 0,
  "msg": "ok",
  "data": {
    "Count": 1,
    "List": [
      {
        "Last": 11630,
        "Open": 11630,
        "High": 11700,
        "Low": 11500,
        "Close": 11650,
        "Volume": 2024978,
        "Amount": 2318839808000,
        "Time": "2026-07-31T15:00:00+08:00",
        "Turnover": 1.05
      }
    ]
  }
}
```

---

## 6. 指数 K 线

| 方法 | 路径 | 参数 | 说明 |
| --- | --- | --- | --- |
| GET | `/index` | `type`, `code`, `start`, `count` | 指定类型指数 K 线（分页） |
| GET | `/index/all` | `type`, `code` | 指定类型全部指数 K 线 |
| GET | `/index/minute` | `code`, `start`, `count` | 指数 1 分钟 |
| GET | `/index/5minute` | `code`, `start`, `count` | 指数 5 分钟 |
| GET | `/index/15minute` | `code`, `start`, `count` | 指数 15 分钟 |
| GET | `/index/30minute` | `code`, `start`, `count` | 指数 30 分钟 |
| GET | `/index/60minute` | `code`, `start`, `count` | 指数 60 分钟 |
| GET | `/index/day` | `code`, `start`, `count` | 指数日 K |
| GET | `/index/day/all` | `code` | 全部指数日 K |
| GET | `/index/week/all` | `code` | 全部指数周 K |
| GET | `/index/month/all` | `code` | 全部指数月 K |
| GET | `/index/quarter/all` | `code` | 全部指数季 K |
| GET | `/index/year/all` | `code` | 全部指数年 K |

指数代码示例：`sz399006`（创业板指）、`sh000300`（沪深300）。

---

## 7. 指数成分（推荐）

通达信把指数成分拆在两份文件里：

| 来源 | 内容 |
| --- | --- |
| `block_zs.dat` | 沪深300、上证50、创业板指等（单板块上限 400） |
| `spblock.dat` | 中证500/1000/2000/A500、国证2000 等超限成分 |

**请优先使用合并接口**，不要只用 `/spblock`（其中没有沪深300）。

| 方法 | 路径 | 参数 | 说明 |
| --- | --- | --- | --- |
| GET | `/index/constituents` | `name`（可选） | 完整指数成分 = block_zs + spblock；回填指数代码与成分中文名 |
| GET | `/spblock` | `name`（可选） | 仅 spblock.dat 原始专业板块（无沪深300） |

### `GET /index/constituents`

```bash
curl "http://127.0.0.1:18080/index/constituents"
curl "http://127.0.0.1:18080/index/constituents?name=创业板指"
curl "http://127.0.0.1:18080/index/constituents?name=沪深300"
curl "http://127.0.0.1:18080/index/constituents?name=中证2000"
```

**`data` 字段**

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `name` | string | 指数/板块名称 |
| `code` | string | 指数代码（6 位），如创业板指 `399006`、沪深300 `000300`；未匹配时为空 |
| `codes` | array | 成分股列表 |
| `codes[].code` | string | 成分股 6 位代码 |
| `codes[].name` | string | 成分股中文名称 |
| `source` | string | 成分来源：`block_zs` 或 `spblock` |

```json
{
  "code": 0,
  "msg": "ok",
  "data": {
    "name": "创业板指",
    "code": "399006",
    "codes": [
      { "code": "300001", "name": "特锐德" },
      { "code": "300002", "name": "神州泰岳" }
    ],
    "source": "block_zs"
  }
}
```

说明：

- 同名多市场指数代码优先上证（如沪深300 → `000300` 而非 `399300`）。
- 部分指数（如中证2000）在通达信代码表中无标准指数码时，`code` 可能为空，但 `codes` 成分仍完整。

### `GET /spblock`

```bash
curl "http://127.0.0.1:18080/spblock"
curl "http://127.0.0.1:18080/spblock?name=中证2000"
```

返回原始专业板块列表，`codes` 为字符串数组（7 字符：市场标志 + 6 位代码），**不含中文名、不含沪深300**。

---

## 8. 板块成分 / 行业归属

### 推荐：概念 / 行业专用接口

| 方法 | 路径 | 参数 | 说明 |
| --- | --- | --- | --- |
| GET | `/block/concept` | `name`, `codes` | **全部概念板块** + 成分股（含中文名、板块指数 id） |
| GET | `/block/industry` | `name`, `codes` | **全部行业板块** + 成分股（通达信新行业归集） |

| 参数 | 说明 |
| --- | --- |
| `name` | 可选。按板块名称取单个，如 `锂电池`、`银行` |
| `codes` | 默认返回成分；设为 `0` 时仅返回列表（名称/指数 id/数量），体积更小 |

```bash
# 全部概念板块+成分
curl "http://127.0.0.1:18080/block/concept"
# 仅概念列表(不含成分明细)
curl "http://127.0.0.1:18080/block/concept?codes=0"
# 单个概念
curl "http://127.0.0.1:18080/block/concept?name=锂电池"

# 全部行业板块+成分
curl "http://127.0.0.1:18080/block/industry"
curl "http://127.0.0.1:18080/block/industry?name=银行"
curl "http://127.0.0.1:18080/block/industry?codes=0"
```

```json
{
  "code": 0,
  "msg": "ok",
  "data": [
    {
      "name": "银行",
      "code": "T1001",
      "index": "88047x",
      "type": 2,
      "count": 42,
      "codes": [
        { "code": "000001", "name": "平安银行" },
        { "code": "600036", "name": "招商银行" }
      ]
    }
  ]
}
```

说明：

- **概念**：来自 `block_gn.dat` + `tdxzs` 回填指数 id。
- **行业**：多数行情服务器无 `block_hy.dat`，本接口用 `tdxhy.cfg` 按通达信新行业码归集；`code` 为 `Txxxx`，`name` 来自 `incon.dat`，`index` 为匹配到的 `880xxx`。

### `GET /block/data` · `GET /block/data/index`（通用）

| 参数 | 说明 |
| --- | --- |
| `file` | 必填。完整文件名或简称：`zs`/`gn`/`fg`/`hy`（→ `block_*.dat`） |
| `name` | 可选。按板块名称取单个板块 |
| `codes` | 默认返回成分；`0` 仅列表 |

```bash
curl "http://127.0.0.1:18080/block/data/index?file=gn"
curl "http://127.0.0.1:18080/block/data?file=fg"
```

### `GET /tdx/hy`

全市场通达信新行业 + 申万行业归属；行业码经 `incon.dat` 翻译中文名。

| 参数 | 说明 |
| --- | --- |
| `code` | 可选。六位码或带前缀，如 `000001` / `sz000001` |

```bash
curl "http://127.0.0.1:18080/tdx/hy?code=000001"
curl "http://127.0.0.1:18080/tdx/hy?code=sh600519"
```

```json
{
  "code": 0,
  "msg": "ok",
  "data": {
    "market": 0,
    "code": "000001",
    "name": "平安银行",
    "tdx_hy": "T1001",
    "tdx_hy_name": "银行",
    "sw_hy": "X500102",
    "sw_hy_name": "股份制银行"
  }
}
```

## 9. 个股统计 / 资金流向

对应客户端：`GetTdxStat` / `GetTdxStat2`。数据来自 `zhb.zip` 内 `tdxstat.cfg` / `tdxstat2.cfg`（全市场盘后逐股）。默认只返回已核验字段；传 `fields=1` 可附带全部原始列。

### `GET /tdx/stat`

个股综合统计：市盈 TTM/静态市盈、股息率、涨跌幅、连涨连跌天数、区间涨跌幅（5/10/20/60 日 / YTD）。

| 参数 | 说明 |
| --- | --- |
| `code` | 可选。六位码或带前缀，如 `000001` / `sz000001` |
| `fields` | 可选。`1` / `true` / `raw` 时附带全部原始字段数组 |

```bash
curl "http://127.0.0.1:18080/tdx/stat?code=sh600519"
curl "http://127.0.0.1:18080/tdx/stat?code=600519&fields=1"
```

```json
{
  "code": 0,
  "msg": "ok",
  "data": {
    "market": 1,
    "code": "600519",
    "name": "贵州茅台",
    "date": "20260801",
    "pe_ttm": 20.5,
    "pe_static": 21.1,
    "div_yield": 3.2,
    "trend_days": 2,
    "change_pct": 0.85,
    "chg5": 1.2,
    "chg10": -0.3,
    "chg20": 2.1,
    "chg60": 5.6,
    "chg_ytd": 8.9
  }
}
```

### `GET /tdx/stat2`

个股资金流向相关字段 + 所属/领涨板块指数代码；板块名经 `tdxzs.cfg` 翻译。

| 参数 | 说明 |
| --- | --- |
| `code` | 可选。六位码或带前缀 |
| `fields` | 可选。`1` / `true` / `raw` 时附带全部原始字段数组 |

```bash
curl "http://127.0.0.1:18080/tdx/stat2?code=000001"
```

```json
{
  "code": 0,
  "msg": "ok",
  "data": {
    "market": 0,
    "code": "000001",
    "name": "平安银行",
    "date": "20260801",
    "amount": 123456.78,
    "amount_prev": 98765.43,
    "ipo_price": 19.0,
    "high_52w": 13.5,
    "low_52w": 9.8,
    "block_index": "880515",
    "block_name": "银行"
  }
}
```

不传 `code` 时返回全市场数组。

## 10. 其它板块 / 报表文件

| 方法 | 路径 | 参数 | 说明 |
| --- | --- | --- | --- |
| GET | `/block/file` | `file` | 板块原始文件 |
| GET | `/report/file` | `file` | 报表文件 |
| GET | `/zhb/files` | 无 | zhb.zip 内文件列表 |
| GET | `/tdx/zs` | 无 | tdxzs 板块指数配置 |
| GET | `/tdx/bk` | 无 | tdxbk 板块简称↔全称 |
| GET | `/tdx/xgsg` | 无 | 新股申购 |

---

## 11. 扩展行情

`cmd/api` 默认已启用（`EXHQ=1`）。设 `EXHQ=0` 时 `/ex/*` 不注册（404）。扩展行情连的是 7727 端口，个别节点可能超时，属上游网络问题。

| 方法 | 路径 | 参数 | 说明 |
| --- | --- | --- | --- |
| GET | `/ex/markets` | 无 | 扩展市场列表 |
| GET | `/ex/count` | 无 | 扩展证券数量 |
| GET | `/ex/instruments` | `start`, `count` | 证券列表（分页） |
| GET | `/ex/quote` | `market`, `code` | 实时报价 |
| GET | `/ex/quote_list` | `market`, `category`, `start`, `count` | 报价列表 |
| GET | `/ex/bars` | `category`, `market`, `code`, `start`, `count` | K 线（`category` 同股票 K 线 type） |
| GET | `/ex/minute` | `market`, `code` | 分时 |
| GET | `/ex/minute/hist` | `market`, `code`, `date` | 历史分时 |
| GET | `/ex/trade` | `market`, `code`, `start`, `count` | 分笔 |
| GET | `/ex/trade/hist` | `market`, `code`, `date`, `start`, `count` | 历史分笔 |
| GET | `/ex/bars/range` | `market`, `code`, `date`, `date2` | 日期区间 K 线 |

### 常用 `market`（节选）

| market | 说明 | shortName |
| --- | --- | --- |
| `30` | 上海期货（含沪金 AU） | QS |
| `28` | 郑州商品 | QZ |
| `29` | 大连商品 | QD |
| `47` | 中金所期货 | CZ |
| `46` | 上海黄金（现货/延期） | SG |
| `31` | 香港主板 | KH |
| `60` | 主力期货合约 | MA |

完整列表：`GET /ex/markets`。

### 示例：沪金（上海期货黄金）

通达信里「沪金」对应 **上海期货 `market=30`**，常用代码：

| code | 名称 |
| --- | --- |
| `AUL8` | 黄金主连（推荐看盘） |
| `AUL7` | 黄金次连 |
| `AU2608` | 黄金 2608 合约（具体月份会变） |

```bash
# 市场列表 / 品种数量
curl "http://127.0.0.1:8088/ex/markets"
curl "http://127.0.0.1:8088/ex/count"

# 品种分页（全市场很大，按需翻页）
curl "http://127.0.0.1:8088/ex/instruments?start=0&count=50"

# 沪金主连 — 实时报价
curl "http://127.0.0.1:8088/ex/quote?market=30&code=AUL8"

# 沪金具体合约
curl "http://127.0.0.1:8088/ex/quote?market=30&code=AU2608"

# 沪金主连 — 分时 / 日K / 分笔
curl "http://127.0.0.1:8088/ex/minute?market=30&code=AUL8"
curl "http://127.0.0.1:8088/ex/bars?category=9&market=30&code=AUL8&start=0&count=20"
curl "http://127.0.0.1:8088/ex/trade?market=30&code=AUL8&start=0&count=30"

# 历史分时 / 历史分笔 / 日期区间K（date=YYYYMMDD）
curl "http://127.0.0.1:8088/ex/minute/hist?market=30&code=AUL8&date=20260731"
curl "http://127.0.0.1:8088/ex/trade/hist?market=30&code=AUL8&date=20260731&start=0&count=50"
curl "http://127.0.0.1:8088/ex/bars/range?market=30&code=AUL8&date=20260701&date2=20260731"

# 上期所报价列表（category=3 表示期货）
curl "http://127.0.0.1:8088/ex/quote_list?market=30&category=3&start=0&count=20"

# 上海黄金所现货（不是期货沪金）
curl "http://127.0.0.1:8088/ex/quote?market=46&code=Au99.99"
```

`/ex/quote` 返回示例（字段节选）：

```json
{
  "code": 0,
  "msg": "ok",
  "data": {
    "market": 30,
    "code": "AUL8",
    "preClose": 891.92,
    "open": 882.06,
    "high": 887.58,
    "low": 878.10,
    "price": 886.82,
    "chiCang": 181243,
    "zongLiang": 178245
  }
}
```

本地 `go run` 时把端口改成你的 `ADDR`（如 `18080`）。Docker 默认映射见 `docker-compose.yml`（当前为 **8088**）。

---

## 通用参数

| 参数 | 说明 | 示例 |
| --- | --- | --- |
| `exchange` | 交易所：`sh` / `sz` / `bj` | `sh` |
| `code` | 证券代码，可带前缀 | `600519` / `sh600519` |
| `codes` | 多代码，逗号分隔 | `sz000001,sh600519` |
| `type` | K 线类型，见上表 | `9` |
| `start` | 起始位置 | `0` |
| `count` | 数量 | `100` |
| `date` / `date2` | 日期 `YYYYMMDD` | `20240101` |
| `file` | 板块/报表文件名 | `block_gn.dat` |
| `name` | 指数/板块名称 | `创业板指` |
| `fq` | 复权：`qfq`(默认) / `hfq` / `raw` | `qfq` |
| `market` | 扩展行情市场代码 | `30`（上期所/沪金） |
| `category` | 扩展行情：报价列表品种类 / K 线周期 | 期货列表 `3`；日 K `9` |
| `filename` | F10 文件名 | `300052.txt` |
| `length` | 读取长度 | `5000` |

---

## 相关文件

| 路径 | 说明 |
| --- | --- |
| `cmd/api/main.go` | 服务入口 |
| `extend/httpserver/` | Gin 路由与 handler |
| `extend/httpserver/README.md` | 包级说明（与本文同步） |
