Metadata-Version: 2.4
Name: kdata-quant
Version: 1.0.0
Summary: K线数据下载与处理模块
Author-email: your name <you@example.com>
License: MIT
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pandas>=3.0.0
Requires-Dist: numpy>=1.22
Requires-Dist: baostock>=0.8.9
Requires-Dist: akshare>=1.18
Requires-Dist: efinance>=0.5.5
Requires-Dist: aiohttp>=3.13.2
Requires-Dist: requests>=2.32.5
Requires-Dist: lxml>=6.0.2
Requires-Dist: beautifulsoup4>=4.14.2
Requires-Dist: python-dateutil>=2.9.0
Requires-Dist: pytz>=2025.2
Requires-Dist: matplotlib>=3.10.0
Requires-Dist: mplfinance>=0.12.10b0
Requires-Dist: TA-Lib>=0.4.0
Requires-Dist: fear-and-greed>=0.4
Requires-Dist: build>=1.3.0
Requires-Dist: setuptools>=80.9.0
Requires-Dist: wheel>=0.45.1
Requires-Dist: pyyaml>=6.0
Requires-Dist: mootdx2>=1.0.8
Requires-Dist: ruamel-yaml>=0.18.17
Requires-Dist: py-mini-racer>=0.6.0
Requires-Dist: longport>=3.0.0
Requires-Dist: python-dotenv>=1.0.1
Requires-Dist: yfinance>=0.2.0
Requires-Dist: pandas-market-calendars>=5.4.0
Provides-Extra: dev
Requires-Dist: pytest>=9.0.2; extra == "dev"
Dynamic: license-file

# kdata-quant

K 线数据下载与处理模块。使用 `src/` 布局，便于本地开发与打包。

**架构说明**：为了提升性能与维护性，本项目将功能整合到了三个核心模块中：
-   **`kdata.core`**: 处理配置、日期逻辑、路径映射及底层 K 线获取。
-   **`kdata.markets`**: 包含各市场（A 股、港股、美股、ETF）的下载调度与行情汇总。
-   **`kdata.tools`**: 提供 CLI 及各类扫描工具（Scanner、Batch、Premium）。

> [!TIP]
> 顶层 API（如 `kdata.get_ohlc`）保持不变，旧的子模块（如 `kdata.env`）已通过重定向兼容。

**打包说明**：默认使用 **Cython** 将业务代码编译为扩展模块并打 wheel（见下文「打包与发布」）。打 wheel 需 **`uv sync --group dev`**（含 `cython`）与本机 **C 编译器**；仅日常跑代码用 `uv sync` 即可。

**运行平台**：开发与部署以 **Linux、macOS** 为主；**不支持 Windows**（通达信 `/` mootdx 等相关流程亦按类 Unix 环境约定）。

## 快速开始

### 1. 安装

```bash
uv python pin 3.12
uv sync
# 可编辑安装：uv pip install -e .
# 若需本地编译 Cython 扩展（与 make build 一致），先执行：uv sync --group dev
```

**通达信 / mootdx（A 股、ETF、主要指数）**：在线行情依赖本机上的 mootdx 节点配置。新环境或清空 `~/.mootdx` / `~/.mootdx2` 后请先探测最快服务器：

```bash
uv run mootdx bestip
# 或（仅当缺少 config 时才调用 bestip，与脚本说明一致）：
make bestip
# 等价：uv run python scripts/ensure_mootdx_bestip.py
```

配置一般在 **`$HOME/.mootdx/config.json`**（或 `$HOME/.mootdx2/config.json`）。**`kdata-serve`、定时任务等**须与写入配置时使用**同一用户与 `HOME`**（systemd 示例见 `scripts/systemd/kdata-serve.service`）。需要刷新节点时用 `scripts/ensure_mootdx_bestip.py --force`。

更完整的说明（何时必须重跑 bestip、systemd/容器注意点）见 **[docs/MOOTDX_BESTIP.md](docs/MOOTDX_BESTIP.md)**。

### 2. 环境变量（可选）

| 环境变量 | 说明 | 默认值 |
|----------|------|--------|
| `K_DATA_CENTER` | 数据存储目录 | `./data` |
| `K_DATA_START_DATE` | 默认 K 线开始日期（未传 start_date 时使用） | `2024-01-01` |
| `KDATA_CENTRAL_URL` | 可选。K 线数据中心单一根地址；设置后 `get_ohlc` 在本地缓存未满足请求时**优先 HTTP 拉取**，失败再本地下载 | （未设置） |
| `KDATA_CENTRAL_TIMEOUT` | 请求中心的超时时间（秒） | `30` |
| `KDATA_CENTRAL_TOKEN` | 可选。与中心约定一致时，请求头携带 `Authorization: Bearer …` | （未设置） |
| `KDATA_CENTRAL_MAX_HOPS` | 分层 `kdata-serve` 时向上游转发的最大深度；超过则不再请求 `KDATA_CENTRAL_URL`，防止环路（见 `X-Kdata-Central-Depth`） | `8` |
| `KDATA_SERVE_SKIP_CENTRAL` | `kdata-serve` 处理 `/ohlc` 时，是否在本地未命中时**跳过** `KDATA_CENTRAL_URL` 向上游拉取。默认为 `0`（不跳过，即允许向上层请求）；若为数据源终点节点可设为 `1`（仅本地下载） | `0` |

```bash
export K_DATA_CENTER="$HOME/kdata_data"
export K_DATA_START_DATE="2024-01-01"
mkdir -p "$K_DATA_CENTER"
```

查看当前配置：`uv run python -c "from kdata.env import get_data_dir, get_default_start_date; print(get_data_dir(), get_default_start_date())"`

#### 跨机器：HTTP 数据中心（可选）

在**一台**可访问行情源的主机上常驻运行 **`kdata-serve`**，其它机器设置 **`KDATA_CENTRAL_URL`**（单一根地址）；`get_ohlc` 在本地缓存不足时优先向中心拉取 CSV，失败再本地下载。中间层节点也可把 **`KDATA_CENTRAL_URL`** 指向上游 **`kdata-serve`**（深度由 **`KDATA_CENTRAL_MAX_HOPS`** 与头 **`X-Kdata-Central-Depth`** 限制）。详见 [HTTP 数据中心说明](docs/LAN_SHARING.md)。

```bash
# 数据节点（示例）
uv run kdata-serve --host 0.0.0.0 --port 8765

# 其它机器
export KDATA_CENTRAL_URL="http://192.168.1.10:8765,http://192.168.1.11:8765"
```

### 3. 命令行下载

下载策略：**严格控制请求速度，保护对方服务器**，不追求并发；限速由各数据源的 pacer 统一控制。

```bash
export K_DATA_CENTER="$HOME/kdata_data"

# 单只股票
uv run kdata-download sh.688256 2024-01-01 2025-11-09
uv run kdata-download hk.00700 2024-01-01 2025-11-09
uv run kdata-download us.AAPL 2024-01-01 2025-11-09
uv run kdata-download 510300 2024-01-01 2025-11-09

uv run kdata-download us.TQQQ

# 依据 YAML 配置文件预下载 K 线数据到缓存（指定目录或单个 YAML 文件）
uv run kdata-download -b data/china
uv run kdata-download -b data/china/config_etf_all.yaml
uv run kdata-download -b data/china/config_etf_all.yaml -v

# 保存到 CSV
uv run kdata-download sh.000300 2024-01-01 2024-01-31 --out /tmp/300.csv
```

### 4. 指数成分股与 YAML

```bash
uv run download_indices.py csi300 --out data/indices
uv run download_indices.py hkg --out data/hk
uv run python rename_yaml.py -file_path data/indices/csi300.yaml
```

### 5. ETF 规模过滤工具

使用 `kdata-etf` 命令行工具对 ETF 进行市值（规模）与成交额过滤，并一键导出 YAML 配置文件。

```bash
# 更新并建立本地缓存（全市场 1700+ 支 ETF，约 2-3 分钟）
uv run kdata-etf update

# 筛选市值大于 100 亿、且今日成交额大于 1 亿的 ETF
uv run kdata-etf filter --min-scale 100 --min-vol 1

# 筛选后导出为 YAML 配置文件
uv run kdata-etf export --min-scale 50 -o target_etfs.yaml
```

-   `filter` 支持 `--min-scale` / `--max-scale`（市值，单位：亿）、`--min-vol` / `--max-vol`（单日成交额，单位：亿）、`--top-vol` 等条件。
-   `export` 继承 `filter` 的全部过滤条件，导出格式固定，可直接供自动化策略或后台脚本读取。
-   **缓存机制**：全市场 ETF 数据缓存于 `~/.kdata/etf_cache.json`，更新后即可在本地极速筛选。

详见 [kdata-etf 命令行工具使用指南](docs/kdata_etf_cli.md)。

### 6. ETF 溢价分析工具

本项目提供专门的工具用于分析 ETF 的折溢价情况（Market Price vs NAV）。

#### 单只 ETF 历史溢价获取
获取指定时间范围内的日线收盘价、单位净值及溢价率。

```bash
# 获取 510300 在 2024 年的溢价数据
uv run kdata-premium 510300 2024-01-01 2024-12-31

# 仅输出当前折溢价快照（不下载 K 线）
uv run kdata-premium 510300 --snapshot
```

#### Python API 使用

```python
from kdata import get_etf_premium_data, get_latest_etf_premium

# 获取历史溢价数据（返回 DataFrame）
df = get_etf_premium_data("510300", "2024-01-01", "2024-12-31")
print(df.head())

# 获取最新溢价快照（返回 dict）
latest = get_latest_etf_premium("510300")
print(f"当前溢价率：{latest['premium_rate']:.2f}%")

# DataFrame 列说明:
# - close: 收盘价
# - NAV(IOPV_{timestamp}): 估算的净值（基于 IOPV 溢价率反推）
# - premium: 绝对溢价额 (close - NAV)
# - premium_rate: 溢价率 (%)

# dict 字段说明:
# - code: ETF 代码
# - name: ETF 名称
# - price: 当前价格
# - nav: 估算净值
# - premium_rate: 溢价率 (%)
# - updated: 数据更新时间
```

#### 全市场折溢价扫描
扫描 `data/etf/config_etf.yaml` 中的所有 ETF，识别当前市场的套利机会（高溢价或高折价）。

```bash
# 扫描全市场 ETF 实时折溢价
uv run kdata-scan

# 仅显示折价大于 3% 的品种（简单模式）
uv run kdata-scan --min-discount-pct 3 --simple

# 开启详细日志，用于排查数据准确性问题
uv run kdata-scan --verbose --simple

# 使用自定义 LOF 配置文件扫描
uv run kdata-scan --verbose --simple --input data/etf/lof.yaml
```

- `--simple`: 终端输出精简模式，不抓取 F10（无标的指数和赎回费），速度最快。
- `--verbose`: 输出详细调试信息，包含 `mootdx` 原始报价、IOPV/bytes9 原始值及净值计算步长。
- `--min-discount-pct`: 仅保留折价大于指定百分比的品种。

扫描结果将实时显示前 10 名的溢价和折价机会，并保存至 `profitable_etfs.csv`。

### 7. ETF 官方指数过滤与标注

针对 ETF 配置文件，自动提取每只 ETF 的**跟踪指数**，并过滤出“官方”指数（如中证、沪深、恒生、MSCI 等）品种，同时在 YAML 中以注释形式标注跟踪指数名称。

```bash
# 过滤官方指数 ETF 并自动标注跟踪指数
uv run python scripts/filter_official_etfs.py \
    --input data/etf/config_etf.yaml \
    --output data/etf/official_etf.yaml
```

-   **自动清洗**：自动剔除基金公司名称前缀（如“易方达”、“华夏”）及冗长的基金合同后缀，保留纯净的指数名称。
-   **官方判定**：内置主流指数供应商识别逻辑，自动排除非标、定制或专用指数品种。
-   **YAML 格式保留**：使用 `ruamel.yaml` 确保在添加注释和过滤条目时，完整保留原文件的结构与格式。

### 8. 大盘行情与指数

获取 A 股、港股及美股的实时概览与历史 K 线。

```bash
# 基础查询 (A股 / 港股 / 美股，默认显示今日)
uv run kdata-market --cn
uv run kdata-market --hk
uv run kdata-market --usa

# 指定交易日期 (YYYY-MM-DD，省略则默认为今天)
uv run kdata-market --cn 2026-04-03
uv run kdata-market --hk 2026-04-03

# 进阶日期区间
uv run kdata-market --cn -s 2025-01-01 -e 2025-12-31  # 指定明确的开始与结束
uv run kdata-market --hk --no-history                 # 仅查看实时摘要 (不展开 K 线)
```

CLI 默认走 **`get_ohlc`**，代码与 `indices_to_check`（如 `sh.000001`、`hk.HSI`、`us.GSPC`）一致。

详见 [大盘行情获取指南](docs/market_index.md)、[数据格式说明 (OHLCV)](docs/data_format.md) 与 [时间与多市场逻辑](docs/time_and_markets.md)（结束日、逻辑「今天」、缓存与各市场收盘判断）。

## 测试

```bash
uv run pytest -q                    # 单元测试（默认不跑集成测试）
uv run pytest -m integration -v     # 集成测试（需网络）
```

详见 `tests/README.md`。

## K 线图演示

```bash
uv run python examples/demo_kline.py us.AAPL --end 2026-01-02 
uv run python examples/demo_kline.py sh.000001
export KDATA_CENTRAL_URL="http://43.163.244.203:8765"
uv run python examples/demo_kline.py us.CRCL
uv run python examples/demo_kline.py hk.00700
uv run python examples/demo_kline.py 515880 
```

支持 A 股、港股、美股、ETF，日 K/周 K，可修改 `demo_kline.py` 中 `plot_kline()` 参数自定义绘制。

## 打包与发布

| 组件 | 说明 |
|------|------|
| `setup.py` | 声明 Cython 扩展；与 `pyproject.toml` 中 `[project]` 元数据一起参与构建 |
| `pyproject.toml` | 版本号、依赖、`[build-system]`（含 `cython`）、`[tool.setuptools.packages.find]` |
| `Makefile` | 封装 `uv sync` + `uv build`，见下表 |

### Makefile 目标

| 目标 | 作用 |
|------|------|
| `make build` | Cython 编译 + 打**当前平台**的 wheel → `dist/*.whl` |
| `make build-linux` | 仅 Linux：`cibuildwheel` + Docker → `dist/*.whl`（manylinux 等） |
| `make build-macos` | 仅 macOS：本机 `uv build` → `dist/*.whl` |
| `make build-all` | 并行 `build-macos` + `build-linux` |
| `make package` | **仅 Linux**：`build-linux` + `bundle-wheels`（需 Docker）；生成 `release/kdata-<版本>-deploy-bundle.zip`（wheel + Ubuntu 部署脚本，需在目标机解压后执行） |
| `sudo make deploy-ubuntu WHEEL=dist/kdata-*.whl` | 在 **Ubuntu 目标机**安装 wheel、venv、可选 systemd（封装 `scripts/deploy_ubuntu_whl.sh`） |
| `make help` | 打印上述构建/部署命令摘要 |
| `make build-source` | 纯 Python wheel（脚本临时移走 `setup.py`），见 `scripts/build_pure_wheel.sh` |
| `make bundle-wheels` | 收集上述目录下已有 `.whl`，并与 `scripts/deploy_ubuntu_whl.sh`、`scripts/systemd/kdata-serve.service` 打成 `release/kdata-<版本>-deploy-bundle.zip`（根目录含 `DEPLOY.txt`） |
| `make clean` | 清理 `dist/`、`build/`、`*.egg-info`、源码树中误生成的 `*.c` |

### 1. 默认打包（Cython wheel）

需 **C 编译器**（macOS：Xcode Command Line Tools；Linux：`build-essential`）及 **`uv sync --group dev`**（安装 `cython` 等构建依赖）。

```bash
uv sync --group dev
make build
```

产物在 `dist/`，文件名随平台变化，版本号与 **`pyproject.toml` 中 `version`** 一致（示例：`kdata_quant-1.0.0-cp312-cp312-macosx_11_0_arm64.whl`）。

### 2. 纯 Python wheel（无 C 扩展）

由 `scripts/build_pure_wheel.sh` 临时移走 `setup.py` 后执行 `uv build`，得到不含扩展的通用 wheel。

```bash
make build-source
```

### 3. 多平台

C 扩展与 **Python 版本、操作系统、CPU 架构** 绑定，需在**各目标环境**分别执行 `make build`（本机或 CI），**不**使用 Docker 交叉编译。

CI 配置：`.github/workflows/cython-wheels.yml`，矩阵示例：

| 平台 | Runner |
|------|--------|
| Linux x86_64 | `ubuntu-latest` |
| Linux aarch64 | `ubuntu-24.04-arm`（私有仓库若无 ARM runner 可删此行） |
| macOS x86_64 | `macos-13` |
| macOS arm64 | `macos-latest` |

将各平台产出的 `.whl` 放入 `dist/`，或按目录区分（如 `dist-linux-amd64/`、`dist-linux-arm64/`），再执行 `make bundle-wheels` 生成 `deploy-bundle` zip（内含 wheel 与 Ubuntu 部署脚本，便于拷到服务器解压部署）。

### 4. PyPI 与多 wheel

- 同一版本可上传**多个**平台 wheel；`pip install` 会按环境选择匹配文件。
- **不能**用单个 wheel 覆盖所有平台。

```bash
# 将 dist/ 下所有平台 wheel 发布到 PyPI（需先 make build / build-all 生成 wheel）
TOKEN=pypi-xxx make publish

# 发布到 TestPyPI（token 同上）
make publish PYPI_URL=https://test.pypi.org/legacy/
```

## 常见故障

- **ImportError**：确保已执行 `uv sync` 或 `uv pip install -e .`
- **`uv sync` 报 longport 无当前平台 wheel**：当前环境 glibc 过旧（如旧版 Linux）。`longport` 需要 **manylinux_2_39** 类 wheel，请在 **glibc ≥ 2.39** 的环境（如较新 Ubuntu / GitHub `ubuntu-latest`）上安装或构建。
- **Cython / 链接失败**：确认已安装 C 编译器与 Python 头文件；CI 在对应 runner 上构建。
- **找不到数据目录**：检查 `K_DATA_CENTER` 环境变量设置。
- **配置了 `KDATA_CENTRAL_URL` 仍走本地下载**：检查中心是否可达、URL 是否含协议与端口；且无多余引号。中心返回 404 或无数据时会自动回退本地下载。
- **追踪 `get_ohlc` 数据从哪来**：将 logger **`kdata.core`**（及使用 `kdata-serve` 时 **`KDATA_DEBUG=1`**）设为 **DEBUG**，日志含 `get_ohlc source=...`（如 `cache_exact_file`、`central_http_ok`、`provider_cn_astock`）及中心侧 `kdata-serve /ohlc`。
- **数据准确性疑问**：执行 `kdata-scan --verbose` 查看原始行情数据及内部计算逻辑。
