Metadata-Version: 2.4
Name: top369
Version: 0.8.1
Summary: 股票数据API服务平台官方 Python SDK (tushare 风格)
Author: top369 platform
License-Expression: MIT
Keywords: stock,quant,tushare,finance,a-share,A股,量化,行情
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: Natural Language :: Chinese (Simplified)
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Office/Business :: Financial :: Investment
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Operating System :: OS Independent
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.25
Requires-Dist: pandas>=1.3
Provides-Extra: mcp
Requires-Dist: mcp<2,>=1.2; extra == "mcp"
Dynamic: license-file

# top369 Python SDK

股票数据API服务平台官方 Python SDK，tushare 风格封装——用过 `ts.pro_api()` 即可 10 秒上手。

## 安装

```bash
pip install top369          # Python SDK
pip install "top369[mcp]"   # 含 MCP Server: Claude/Cursor 直接查A股(需 Python 3.10+)
```

依赖仅 `requests` + `pandas`。

## 安装即测（不用写代码）

```bash
top369-demo                # 跑通全部接口演示; API Key 从环境变量 TOP369_API_KEY 读, 未设则交互粘贴
python -m top369.demo      # 等价写法
```

demo 按 Key 档位自适应：先显示账户档位与今日用量，档位达不到要求的接口会打印后端提示并跳过，不中断。

## 快速上手

```python
import top369 as gp

pro = gp.pro_api('sk-xxxx')   # 控制台获取 Key; 默认连 https://api.369.top
                              # 长驻脚本退出前 pro.close() 释放连接(可选)

# 查询当前所有正常上市交易的股票列表
data = pro.stock_list(page=1, page_size=200,
                      fields='code,name,market,type')
```

> tushare 老用户可用 `pro.query('daily', ...)` 通用调用，见文末「tushare 迁移对照」
> ——新用户忽略此行。

## 市场覆盖与扩展约定

当前全部数据方法 = **A股域**（方法名不带市场前缀，如 `pro.day_kline()`）。
港股/美股二期接入时新方法统一带市场前缀：`pro.hk_day()` / `pro.us_day()`，
与后端路由 `/api/hk/...`、文档页 `/docs/hk/day` 三层命名对齐——
A 股保持短名（tushare `daily`/`hk_daily` 同款惯例），不存在同名歧义。

## 标的代码：四种写法都认

后端统一收口，**不用自己改写**（tushare 迁移用户可直接粘 `ts_code`）：

| 写法 | 例子 | 说明 |
|---|---|---|
| 市场前缀 | `sh600519` | 平台内部/响应用法，**响应统一回这种** |
| 裸 6 位码 | `600519` | 同码多市场按 股票>ETF>可转债>指数 择优 |
| 点号前缀 | `sh.600519` | 等价于市场前缀 |
| 点号后缀 | `600519.SH` | tushare `ts_code` / AlphaFeed 习惯 |

```python
pro.day_kline(code='600519.SH')   # 四种写法完全等价; 显式写了市场则不做择优
                                  # (如 000300.SH 是沪深300指数, 不会判成深市股票)
```

本地转换/校验而不发请求时用 `symbols` 模块：

```python
from top369 import normalize, to_dot, to_plain, market_of

normalize('600519.SH')     # 'sh600519'  → 平台写法
to_dot('sz000001')         # '000001.SZ' → 喂 tushare 等外部库
to_plain('sh.600519')      # '600519'
market_of('000001.SZ')     # 'sz'
```

## 接口一览

| SDK 方法 | 对应 tushare | 说明 |
|---|---|---|
| `pro.stock_list()` | `stock_basic` | 证券清单（实为列表，故名 stock_list；`df.attrs['total']` 为总数） |
| `pro.day_kline()` | `daily` | 日K线；单票区间+复权 / `date=`全市场单日截面(调度落库)。kline 词族: 粒度_kline(day/minute/period) |
| `pro.day_batch(codes)` | `day_batch` | 批量日K≤100码一次HTTP往返(按码数计点)，复权/截尾语义与单票一致；`day_kline(codes=)` 自动转发此端点 |
| `pro.adjust_factor(code, adjust)` | `adj_factor` | 复权因子序列（qfq 最新因子恒为 1.0；可据因子本地复权任意字段） |
| `pro.minute(code, date)` | `minute` | 分时数据 |
| `pro.tick(code, date)` | `tick` | 分笔成交 |
| `pro.financial(code)` | `financial` | 财务数据（约579字段宽表） |
| `pro.blocks(code)` | `concept` 类 | 所属板块（单列 blocks） |
| `pro.trade_calendar(start_date, end_date)` | `trade_cal` | 交易日历（单列 date，升序；缺省当年至今） |
| `pro.stock_info(code)` | — | 单票基本信息 |
| `pro.st_list(date, sec_type)` | — | ST股名单（每日快照还原历史戴帽；`df.attrs['date'/'total']`） |
| `pro.name_history(code)` | `namechange` 类 | 个股名称/ST/停牌时间线（快照自2026-09-01起） |
| `pro.minute_kline(code, period)` | `stk_mins` | 1/5/15/30/60 分钟K线；`period=1` 可加 `merge_days=N`(1≤N≤10) 合并最近N个交易日（实盘用，实时行带 is_realtime 标记） |
| `pro.iter_minute_kline(code, period, start_date)` | — | 分钟K长历史分块迭代器：按交易日历自动切窗口（1分钟10交易日/块，其余250交易日/块）旧→新逐块 yield，26年分钟史不再手动倒切窗口 |
| `pro.batch(fn, items, workers=4)` | — | 通用并发批量执行器：线程池+共享限速（429全池退避/日配额用尽全局中止）+失败汇总 `{ok, failed}`，覆盖 financial/margin个股 等无批量端点的接口 |
| `pro.special_list(list_name/code)` | — | 特殊名单三模式：无参=名单目录（名称+成员数）/ `list_name=`名单全量成员 / `code=`个股所属名单反查（沪深港通/融资融券/指数成分/专精特新...） |
| `pro.hsgt(market)` | — | 沪深港通标的（sh/sz/hk/all，扁平 market/code 列） |
| `pro.f10(code, category, section)` | — | F10公司资料结构化（股东研究/分红扩股/股本/财务分析/高层治理等17栏目；category缺省=栏目清单；专业版） |
| `pro.lhb(date, start_date, end_date, code)` | `top_list` 类 | 龙虎榜每日明细（2023起，上榜原因/净买额；专业版） |
| `pro.lhb_detail(code, date)` | `top_inst` 类 | 个股买卖前5营业部席位明细（专业版） |
| `pro.lhb_history(code)` | — | 个股历次上榜记录（2021起；专业版） |
| `pro.margin(scope, code, date)` | `margin` 类 | 融资融券：scope=market 全市场余额序列 / scope=stock+code 个股全历史2010起 / scope=stock+date 全市场单日截面（专业版） |
| `pro.tick_stats(code)` | `moneyflow` 类 | 每日内外盘主动买卖/大单统计（2026-08起；基础版） |
| `pro.zdt(view)` | — | 涨跌停：ladder 连板天梯·个股 / dt 跌停名单 / stat 涨停揭秘统计（专业版） |
| `pro.zdt_board_stat()` | — | 连板天梯·板块统计（板块涨停家数/高度；专业版） |
| `pro.quote_snapshot(code, date)` | — | 盘后五档快照（收盘价/量额/买卖五档；基础版） |
| `pro.market_breadth()` | — | 大盘涨跌分布（上涨/下跌家数+涨幅档位，1990起；基础版） |
| `pro.ah_premium(code)` | — | AH溢价表（A/H收盘价+港元汇率+溢价率；专业版） |
| `pro.apis()` | — | 接口总览（REPL一屏看全：api=中文接口名 / **sdk=SDK方法名** / path/group/档位/一句话说明，真值来自文档站）；`pro.help('day_kline')` 打印某方法签名与说明 |
| `pro.account()` / `pro.usage()` | — | 当前 Key 的账户信息（档位/积分/配额）与今日用量；返回原始 dict |
| `pro.quota_left()` | — | 今日剩余配额（usage 包装：used/remaining/limit） |
| `pro.is_trading_day(date?)` | — | 是否 A 股交易日（定时脚本"今天要不要跑"闸口） |
| `pro.last_trading_day(ref?)` | — | ref 前最近一个 A 股交易日（盘后任务"拉哪天的数据"闸口） |
| `pro.period_kline(freq)` | — | 周/月/年K线（SDK本地聚合，复权次序保证正确；`limit`=最近N个周期）——服务端不做周期接口，一行可自算的派生数据不进API面 |
| `pro.query('day_kline', ...)` | `query` 类 | 通用调用风格（未知名/未知参数直接报错；tushare 迁移用户可选，新用户用上面的扁平方法） |

所有方法支持 tushare 风格的 `fields='col1,col2'` 列过滤（`account`/`usage` 除外）。

## 常用示例

```python
# 每日盘后调度: 全市场单日截面落库(1次调用替代5400次逐码循环)
if not pro.is_trading_day():                    # 今天要不要跑
    exit(0)
d = pro.last_trading_day()                      # 拉哪天的数据(节假日自动回退)
if pro.quota_left()['remaining'] < 50:          # 配额不足提前降级
    ...
df = pro.day_kline(date=d)                      # ~8700行全市场当日行情
m = pro.margin(scope='stock', date=d)           # ~4000行全市场两融截面(T+1披露)

# 一批研究标的(≤100码)批量取, 一次HTTP往返(按码数计点: 50码=50点)
df = pro.day_batch(codes='sz000911,sh600519,bj832566',
                         start_date='2026-09-01', limit=10)

# 频率超限与日配额用尽的区分降级
try:
    df = pro.day_kline(code='sz000911')
except RateLimited as e:                        # 频率超限: 按窗口等待后重试
    time.sleep(e.retry_after + 1)
except QuotaExceeded:                           # 日配额用尽: 等明天(含RateLimited父类)
    ...

# 日线: 不指定 limit = 全历史(≤1万根, 研究拉史建议配 limit 或 start_date 截尾)
df = pro.day_kline(code='sz000911', start_date='2026-01-01',
                   adjust='qfq', limit=100)
print(df.tail())          # date/open/high/low/close/volume/amount/turnover
print(df['name'].iloc[0]) # 元信息已平铺为列(code/name/...每行同值, print即所见)
                          # df.attrs 同样保留(name/adjust等), 老代码不受影响

# 60分钟K线
df = pro.minute_kline(code='sz000911', period=60)

# 分笔
df = pro.tick(code='sz000911', date='2026-08-28')

# 交易日历(按交易日循环, 不空跑节假日)
df = pro.trade_calendar(start_date='2026-01-01')
for d in df['date']:
    ...
```

## 不要 DataFrame？

```python
pro = gp.pro_api('sk-xxxx', to_dataframe=False)   # 全部接口返回原始结构(信封里的 data)
pro.to_dataframe = True                           # 也可运行时随时切换
```

（`to_dataframe=False` 时 `fields` 过滤不生效——原始结构上没有列可挑。）

## 认证与限流

- 认证走 `X-API-Key` 请求头，SDK 自动携带；网络错误自动重试 2 次（指数退避）
- 平台按**会员档位**控制可调用的接口（体验版注册即得 → 基础版/专业版/旗舰版）：
  低档调用高档接口返回 403，错误信息带所需档位与价格；
  会员到期自动回落体验版权益，不整体拦截。各档位不按次扣费，仅受 RPM/日配额约束
- `pro.account()` / `pro.usage()` 随时可查自己的档位与用量

## 错误处理

四类异常按**处理动作**分——先拦具体的，基类兜底：

| 异常 | HTTP | 含义 | 该做什么 |
|---|---|---|---|
| `AuthError` | 401/403 | Key无效 / 档位不足 | 勿重试，修 Key 或升级档位 |
| `RateLimited` | 429 | **频率**超限 | `time.sleep(e.retry_after + 1)` 后重试（子类） |
| `QuotaExceeded` | 429 | **日配额**用尽 | 等明天（RateLimited 的父类，兜底捕获即此语义） |
| `GupiaoApiError` | 其他 | 服务端/参数错误 | 看人话错误信息（e.status_code） |

```python
from top369 import AuthError, GupiaoApiError, QuotaExceeded, RateLimited

try:
    df = pro.day_kline(code='sz000001', limit=10)
except AuthError as e:
    print('Key无效/档位不足, 勿重试:', e)
except RateLimited as e:                    # 先拦子类: 频率超限可立即恢复
    time.sleep(e.retry_after + 1)
except QuotaExceeded as e:                  # 父类兜底: 日配额用尽, 等明天
    print('今日配额用尽, 明日再跑:', e)
except GupiaoApiError as e:
    print(e, e.status_code)
```

## tushare 迁移对照

从 tushare 来的用户：`daily` 等通用调用名保留，脚本可低成本平移。

| tushare 写法 | 本平台等价 |
|---|---|
| `pro.daily(ts_code='600519.SH')` | `pro.day_kline(code='600519.SH')`（或 `pro.query('daily', ...)`） |
| `pro.stk_mins(...)` | `pro.minute_kline(period=...)` |
| `pro.trade_cal()` | `pro.trade_calendar()` |
| `pro.namechange(...)` | `pro.name_history(code=...)` |
| `pro.query('任意接口', **kw)` | `pro.query('接口名', **kw)`（参数名同本文档表格） |
| `pro_df = ts.pro_api(token)` | `pro = gp.pro_api(key)` |

本文档其余示例一律用主名（扁平方法有 IDE 补全与中文 docstring）。

## MCP 接入：让 Claude / Cursor 直接查A股数据

不用写代码——把平台作为 MCP Server 挂进 AI 编程助手，Agent 即可直接调用全部数据工具
（行情/K线/财务/**ST名单/名称历史/沪深港通**/F10公司资料/龙虎榜/涨跌停天梯/融资融券/AH溢价等 45 个，
含全市场单日截面(day_kline/margin 传 date)与调度闸口(is_trading_day/last_trading_day)）。

要求 Python 3.10+：

```bash
pip install "top369[mcp]"
```

**Claude Desktop**（`claude_desktop_config.json`）或 **Cursor**（`mcp.json`）：

```json
{
  "mcpServers": {
    "top369": {
      "command": "top369-mcp",
      "env": {
        "TOP369_API_KEY": "sk-xxxxxxxxxxxx"
      }
    }
  }
}
```

> Windows 若报「找不到 top369-mcp」（pip 脚本目录不在 PATH），把配置里的
> `"command": "top369-mcp"` 换成 `"command": "cmd"` + `"args": ["/c", "top369-mcp"]`。

环境变量：

| 变量 | 说明 |
|---|---|
| `TOP369_API_KEY` | API Key（sk-开头，必填） |
| `TOP369_BASE_URL` | 服务地址，缺省 `https://api.369.top`（自建/联调时覆盖） |

工具与 SDK 方法**同名同参**（`day_kline` / `minute_kline` / `st_list` / `name_history`
/ `special_list` / `hsgt` ...），SDK 文档的用法直接适用。行为约定：

- 结果为紧凑 JSON，行表默认最多 100 行（可传 `max_rows` 调整，硬上限 500），
  超出会带 `_truncated` 提示——收窄日期区间或用 `fields` 挑字段
- `stock_list` 检索参数三层统一（HTTP / SDK / MCP）二选一：`name=`（股票名称
  模糊匹配）或 `code=`（四种代码写法都认，后端归一精确匹配）；互斥与
  “name 像代码”护栏由后端统一校验，违反返回 400
- 出错返回结构化 `{"error", "status", "hint"}`，例如档位不足的 403 会提示用
  `account` 工具查档位、429 会提示用 `usage` 查余量——Agent 可自我纠正

## 其他语言

SDK 只是薄封装，后端是标准 REST，任何语言直接调用：

```
GET /api/a/stock/day_kline?code=sz000911&limit=10
X-API-Key: sk-xxxx
```

响应统一信封 `{code, message, data}`，接口文档见 `https://api.369.top/docs`。
