Metadata-Version: 2.4
Name: n-ashare-market
Version: 0.4.0
Summary: Agent-ready A-share market and research data SDK with Tushare, iFinD, MinIO, REST and MCP.
Project-URL: Documentation, https://gitlab.thoughtyard.com.cn/aion/ashare-market-sdk
Project-URL: Repository, https://gitlab.thoughtyard.com.cn/aion/ashare-market-sdk.git
Project-URL: Issues, https://gitlab.thoughtyard.com.cn/aion/ashare-market-sdk/-/issues
Keywords: a-share,market-data,tushare,minio,mcp,fastapi
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Office/Business :: Financial :: Investment
Classifier: Typing :: Typed
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Requires-Dist: fastapi<1,>=0.115
Requires-Dist: httpx<1,>=0.28
Requires-Dist: mcp[cli]<2,>=1.27
Requires-Dist: minio<8,>=7.2
Requires-Dist: pandas<3,>=2.2
Requires-Dist: pyarrow<23,>=18
Requires-Dist: pydantic<3,>=2.10
Requires-Dist: pydantic-settings<3,>=2.7
Requires-Dist: tushare<2,>=1.4
Requires-Dist: uvicorn[standard]<1,>=0.34
Provides-Extra: dev
Requires-Dist: ruff<1,>=0.11; extra == "dev"
Provides-Extra: release
Requires-Dist: build<2,>=1.2; extra == "release"
Requires-Dist: twine<7,>=6; extra == "release"

# n-ashare-market

面向程序与 Agent 的 A 股市场数据 SDK。当前版本提供：

- Tushare 历史日线：`none / qfq / hfq`；
- iFinD `THS_RQ` 实时行情快照；
- Insight 历史 tick 与 `1/5/15/30/60min` K 线；
- Insight 实时 tick/1min 单会话订阅与 SSE；
- 完整覆盖旧 `ashare-history-system` 的 41 个数据集与 8 个引用表；
- 在旧范围之上额外提供财务报表、Insight 1min/tick 和实时能力；
- MinIO raw/curated Parquet、覆盖清单、实时归档和签名下载；
- MinIO 实时小对象安全 compact；
- 本地/远程 Python SDK；
- FastAPI REST/OpenAPI；
- MCP tools/resources；
- JSON 友好的来源、新鲜度、覆盖度和 artifact 元数据。

Insight 使用独立 subprocess bridge，可继续运行在供应商要求的 Python 3.7 环境，主 SDK 保持 Python 3.11+。

## 1. 架构

```text
Tushare history ─┐
iFinD snapshot ──┼─ MarketDataService ─ normalization ─ MinIO curated/catalog
Insight bridge ──┘                           └────────── MinIO realtime/artifacts
                           │
                           ├─ Python SDK
                           ├─ REST / OpenAPI
                           ├─ CLI
                           └─ MCP Server
```

MinIO 是持久化缓存和分发层，不承担实时消息总线职责。实时请求先由 iFinD 返回给调用方，再将快照微批归档到 MinIO。

详细设计见 [docs/architecture.md](docs/architecture.md)，数据目录和全量重建见
[docs/research.md](docs/research.md)，旧系统逐项覆盖见
[docs/legacy-coverage.md](docs/legacy-coverage.md)。

## 2. 安装

Python 需要 3.11 或更高版本。

```bash
cd ashare-market-sdk
python -m venv .venv
. .venv/bin/activate
pip install -e .
cp .env.example .env
```

从 PyPI 安装发布版本：

```bash
pip install n-ashare-market
```

### 从 Git 仓库安装 Python SDK

仓库发布后，客户端不需要复制源码。推荐打 tag 后固定版本安装：

```bash
pip install "n-ashare-market @ git+https://gitlab.thoughtyard.com.cn/aion/ashare-market-sdk.git@v0.4.0"
```

私有仓库建议使用已经配置好的 SSH key，避免把访问 token 写入命令或日志：

```bash
pip install "n-ashare-market @ git+ssh://git@gitlab.thoughtyard.com.cn/aion/ashare-market-sdk.git@v0.4.0"
```

如果以后把它放在一个 monorepo 的 `ashare-market-sdk/` 子目录，则使用：

```bash
pip install "n-ashare-market @ git+https://gitlab.example.com/YOUR_ORG/YOUR_REPO.git@v0.4.0#subdirectory=ashare-market-sdk"
```

安装后验证命令是否在 PATH（这一步由部署人员执行）：

```bash
ashare-market --help
```

iFinD 的 `iFinDPy` 使用官方 SDK 安装包，不包含在 PyPI 依赖中。运行 REST/MCP 的 Python 环境必须能够执行：

```python
import iFinDPy
```

默认使用主服务当前 Python 运行 Insight bridge，不需要配置解释器路径。如果供应商 SDK 只能安装在
独立 Python 环境，该环境至少需要 Insight SDK、pandas 和可写 Parquet 的 pyarrow，再覆盖：

```dotenv
ASHARE_MARKET_INSIGHT_USERNAME=...
ASHARE_MARKET_INSIGHT_PASSWORD=...
ASHARE_MARKET_INSIGHT_PYTHON=/absolute/path/to/separate/.venv/bin/python
```

桥接部署细节见 [docs/insight.md](docs/insight.md)。

然后在 `.env` 中配置：

```dotenv
ASHARE_MARKET_TUSHARE_TOKEN=...
ASHARE_MARKET_IFIND_USERNAME=...
ASHARE_MARKET_IFIND_PASSWORD=...
```

不要把真实 token、用户名或密码提交到仓库。

## 3. 启动 MinIO

```bash
docker compose -f deploy/docker-compose.minio.yml up -d
ashare-market ensure-buckets
```

默认地址：

- S3 API：`http://127.0.0.1:9000`
- Console：`http://127.0.0.1:9001`

`ensure-buckets` 会创建并启用版本控制：

- `ashare-curated`
- `ashare-raw`
- `ashare-realtime`
- `ashare-artifacts`
- `ashare-catalog`

### 一键启动完整服务

配置好 `.env` 后，一条命令启动 MinIO、REST API、历史同步和实时监督器：

```bash
./deploy/start.sh
```

停止服务：

```bash
./deploy/stop.sh
```

不使用 Docker 时可先启动 MinIO，然后直接运行：

```bash
ashare-market serve --host 0.0.0.0 --port 8020
```

默认自动同步 `stock_basic,trade_cal,daily,daily_basic,adj_factor`。首次运行会按照 coverage 断点回补历史，之后在配置的数据就绪时间后增量刷新。实时订阅只有在
`ASHARE_MARKET_RUNTIME_REALTIME_SYMBOLS` 明确配置股票列表时才启用。运行状态可通过
`GET /v1/runtime` 查看。

## 4. Python SDK

### 本地模式

本地模式在当前 Python 进程中直接调用 Tushare、iFinD 和 MinIO。

```python
from ashare_market import AshareMarketClient

with AshareMarketClient() as client:
    bars = client.history.daily(
        ["000001.SZ", "600000.SH"],
        "2025-01-01",
        "2025-03-31",
        adjustment="qfq",
        cache_policy="cache_first",
    )
    print(bars.dataframe)
    print(bars.meta)

    # 标准化前的 Tushare pro_bar 原始字段。
    raw_bars = client.history.raw_daily(
        "000001.SZ",
        "2025-01-01",
        "2025-01-31",
    )

    quotes = client.realtime.quotes(["000001.SZ", "600000.SH"])
    print(quotes.dataframe)

    artifact = client.history.export_daily(
        "000001.SZ",
        "2020-01-01",
        "2025-01-01",
        file_format="parquet",
    )
    print(artifact["download_url"])

    minute = client.history.minutes(
        "000001.SZ",
        "2026-07-16 09:30:00+08:00",
        "2026-07-16 15:00:00+08:00",
        frequency="5min",
        adjustment="qfq",
    )

    ticks = client.history.ticks(
        "000001.SZ",
        "2026-07-16 09:30:00+08:00",
        "2026-07-16 10:00:00+08:00",
    )

    indicators = client.research.query(
        "fina_indicator",
        symbols="000001.SZ",
        start_date="2024-01-01",
        end_date="2026-07-17",
    )

    # reference 数据集不需要日期，使用 TTL 缓存。
    stocks = client.research.query("stock_basic")
```

### 远程模式

```python
from ashare_market import AshareMarketClient

with AshareMarketClient(
    base_url="http://127.0.0.1:8020",
    api_key="your-api-key",
) as client:
    bars = client.history.daily("000001.SZ", "2025-01-01", "2025-01-31")
    index_bars = client.research.query(
        "index_daily",
        symbols="000300.SH",
        start_date="2025-01-01",
        end_date="2025-01-31",
    )
```

### SDK 主服务应该在哪里运行

生产环境推荐在一台常驻 Linux 数据服务器上运行单实例 REST 服务和 MCP 服务。Tushare、iFinD、
Insight 与 MinIO 凭证只放在服务器；研究终端、策略程序和 Agent 只安装 Python 包并使用上面的
`base_url` 远程模式。这样缓存、额度控制、Insight 会话和审计口径只有一份。

- REST 主服务使用单 Uvicorn worker；当前 Insight session 状态在进程内，多 worker 会产生多个互不共享的会话。
- MCP stdio 可运行在 Agent 所在机器并通过远程 Python SDK/REST 访问主服务；受信任环境也可直接在数据服务器运行 MCP。
- MinIO 开发时可以同机，生产建议独立磁盘或独立节点，并备份 catalog bucket。
- 只有单机研究或开发场景才建议本地模式；它会让每个客户端分别持有 Provider 登录和频次。

systemd 示例见 [deploy/ashare-market.service.example](deploy/ashare-market.service.example)，完整运维说明见
[docs/operations.md](docs/operations.md)。

### 缓存策略

| 策略 | 行为 |
|---|---|
| `cache_only` | 只读 MinIO，不调用 Provider；允许返回部分覆盖 |
| `cache_first` | coverage commit 完整时读 MinIO，否则从 Tushare 刷新并写 MinIO |
| `refresh` | 强制从 Tushare 获取，并发布新的不可变对象和 commit |
| `direct` | 直接从 Tushare 获取，不读写 MinIO |

## 5. REST / OpenAPI

```bash
ashare-market api --host 127.0.0.1 --port 8020
```

- OpenAPI：`http://127.0.0.1:8020/docs`
- `GET /health`：只显示配置能力，不登录 Provider；
- `GET /ready`：连接 MinIO 并确保 bucket 存在；
- `GET /v1/datasets`；
- `GET /v1/datasets/{name}/schema`；
- `GET /v1/compatibility/ashare-history-system`；
- `POST /v1/history/daily`；
- `POST /v1/history/daily-raw`；
- `POST /v1/realtime/quotes`；
- `POST /v1/coverage/daily`。
- `POST /v1/coverage/daily-raw`；
- `POST /v1/history/intraday`；
- `POST /v1/coverage/intraday`；
- `POST /v1/realtime/sessions`；
- `GET /v1/realtime/sessions/{id}/events`；
- `GET /v1/realtime/sessions/{id}/stream`；
- `POST /v1/realtime/compact`。
- `GET /v1/research/datasets`；
- `POST /v1/research/query`；
- `POST /v1/research/coverage`；
- `POST /v1/research/sync`。
- `POST /v1/datasets/sync`（通用别名）。

日线示例：

```bash
curl -X POST http://127.0.0.1:8020/v1/history/daily \
  -H 'Content-Type: application/json' \
  -H 'X-API-Key: your-api-key' \
  -d '{
    "symbols":["000001.SZ"],
    "start_date":"2025-01-01",
    "end_date":"2025-01-31",
    "adjustment":"qfq",
    "cache_policy":"cache_first"
  }'
```

当结果超过 `ASHARE_MARKET_API_MAX_ROWS`，接口只返回受控行数，同时自动在 MinIO 创建完整 Parquet artifact，并在 `meta.artifact.download_url` 返回限时下载地址。

## 6. MCP / Agent

stdio 模式：

```bash
ashare-market mcp --transport stdio
```

Streamable HTTP：

```bash
ashare-market mcp --transport streamable-http
```

可用工具：

- `market_list_datasets`
- `market_get_schema`
- `market_get_legacy_coverage`
- `market_get_realtime_quotes`
- `market_get_daily_bars`
- `market_get_raw_daily_bars`
- `market_get_raw_daily_coverage`
- `market_get_daily_coverage`
- `market_create_daily_export`
- `market_get_minute_bars`
- `market_get_tick_history`
- `market_get_intraday_coverage`
- `market_create_intraday_export`
- `market_start_insight_session`
- `market_get_insight_session`
- `market_get_insight_events`
- `market_stop_insight_session`
- `market_compact_realtime`
- `market_list_research_datasets`
- `market_query_research`
- `market_get_research_coverage`
- `market_create_research_export`
- `market_sync_research_dataset`
- `market_sync_dataset`

可用 resources：

- `ashare://datasets/catalog`
- `ashare://datasets/{dataset}/schema`
- `ashare://research/catalog`
- `ashare://compatibility/ashare-history-system`

通用 stdio MCP 配置示例：

```json
{
  "mcpServers": {
    "ashare-market": {
      "command": "/absolute/path/to/ashare-market-sdk/.venv/bin/ashare-market-mcp",
      "env": {
        "ASHARE_MARKET_MINIO_ENDPOINT": "127.0.0.1:9000"
      }
    }
  }
}
```

凭证应配置在服务器的 `.env` 或密钥系统中，不要复制到 Agent prompt 或 MCP tool 参数里。

## 7. CLI

```bash
ashare-market datasets
ashare-market legacy-coverage
ashare-market daily --symbols 000001.SZ --start 2025-01-01 --end 2025-01-31
ashare-market quotes --symbols 000001.SZ,600000.SH
ashare-market coverage --symbols 000001.SZ --start 2025-01-01 --end 2025-01-31
ashare-market daily --symbols 000001.SZ --start 2020-01-01 --end 2025-01-01 --export parquet
ashare-market intraday --symbols 000001.SZ \
  --start '2026-07-16 09:30:00+08:00' --end '2026-07-16 15:00:00+08:00' \
  --kind 5min --adjustment qfq

# 实时 session 由常驻 API 服务持有；CLI 通过 REST 操作它。
ashare-market --base-url http://127.0.0.1:8020 stream-start \
  --symbols 000001.SZ,600000.SH --tick --kline
ashare-market --base-url http://127.0.0.1:8020 stream-sessions
ashare-market --base-url http://127.0.0.1:8020 stream-events SESSION_ID --after 0
ashare-market --base-url http://127.0.0.1:8020 stream-stop SESSION_ID

ashare-market compact-realtime --dataset tick --trade-date 2026-07-17

ashare-market research-list
ashare-market research fina_indicator --symbols 000001.SZ \
  --start 2024-01-01 --end 2026-07-17

# 默认按 coverage 断点续跑；不传日期时使用数据集默认全量起点。
ashare-market research-sync daily_basic
ashare-market research-sync income --start 2010-01-01 --end 2026-07-17
# `sync` 是面向全部注册数据集的等价短命令。
ashare-market sync daily
ashare-market sync weekly
ashare-market sync etf_daily --symbols 510300.SH,159915.SZ
ashare-market sync index_daily --symbols 000300.SH
ashare-market sync kline_5min --symbols 000001.SZ --start 2026-01-01 --end 2026-07-17
```

## 8. 当前边界

- 股票、ETF、指数和概念/行业代码型行情要求明确代码列表；全市场日频与事件表支持按日期分块同步。
- MinIO catalog 采用不可变 JSON commit；对象达到较大规模后再引入数据库或 Iceberg catalog。
- iFinD 实时快照为请求式 `THS_RQ`；推送式 tick/1min 由 Insight 提供。
- 当前实时 manager 状态保存在 API 进程内，API 重启后需重新创建 session；已归档数据不受影响。
- 不提供旧 Parquet 迁移器；历史研究数据通过 `research-sync` 从 Provider 重新获取。
- 已覆盖旧系统全部 41+8 数据；基金范围目前仅包含旧系统已有的场内 ETF 日线，不扩展债券、期货、宏观和海外市场。
- MinIO 内数据的共享范围必须符合 Tushare、iFinD 和 Insight 的账户授权与再分发条款。
