# 历史 K 线下载

## 完整调用

```python
import os
from pathlib import Path
from exsdk import ExApi

output = Path("data")
output.mkdir(parents=True, exist_ok=True)
with ExApi(os.environ["EXSDK_TOKEN"]) as api:
    rows = api.tools.download_kline_data(
        symbol=os.environ["EXSDK_SYMBOL"],
        period="1m",
        start="20260901",
        end="20260909",
        csv_file_name=output / "history.csv",
    )
    print("写入行数", rows)
```

运行前把 `EXSDK_SYMBOL` 设置为需要下载的期货合约，并选择该合约有数据的日期范围。方法同步完成，不需要额外调用 `wait_update()`。

## 日期、周期与范围

- `start`、`end` 都是 `YYYYMMDD` 格式的有效交易日字符串，起止日都包含，且 `start <= end`。
- 夜盘归属其交易日，不按自然日切分。
- 周期与 `watch_kline()` 相同；仅支持期货。
- SDK 自动分页。单个交易日超过查询上限时会报错，不静默丢弃数据。

## CSV 格式

输出按时间升序，相同时间戳只写入一行。列与 K 线 DataFrame 相同，UTF-8 BOM 编码、不含 pandas 索引，缺失数值写为空单元格。没有数据时写出表头并返回 `0`。

```python
import pandas as pd
frame = pd.read_csv("data/history.csv", encoding="utf-8-sig")
print(frame.head())
```

## 文件与并发行为

`csv_file_name` 接受字符串或 `pathlib.Path`；父目录必须已存在。成功覆盖同名文件，失败保留原文件并清理临时文件。目录不可写、空间不足等会以 `ExError` 报告。

下载不会更新已建立的观察句柄，也不会暂停实时流；大量订阅时长时间下载可能积压尚未消费的推送。建议批量历史任务使用独立程序，避免阻塞正在驱动交易的更新循环。当前尚未结束的 K 线可能在下载后继续变化。
