Metadata-Version: 2.4
Name: gsdatabase
Version: 0.2.0
Summary: GS 因子数据 SDK：tushare 风格接口，token 鉴权，DataFrame 返回
License: Proprietary
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: requests>=2.28
Requires-Dist: pandas>=1.5
Requires-Dist: pyarrow>=12.0
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"

# gsdatabase

GS 因子数据 SDK。tushare 风格接口：token 鉴权，DataFrame 返回，对接门户 `/api/v1` 开放接口。

## 安装

```bash
pip install gsdatabase
```

## 快速开始

```python
import gsdatabase as gs

gs.set_token("gsk_...")        # 门户个人中心生成；一次设置写入 ~/.gsdatabase/token
api = gs.pro_api()

# 我能看哪些因子 / 组合
factors = api.factor_list()
portfolios = api.portfolio_list()

# 回答"最近一年沪深300里表现好的因子有哪些"
top = (api.factor_performance(universe="沪深300", start_date="20250723")
          .sort_values("hedge_annualized_return", ascending=False)
          .head(20))

# 单因子明细：分组回测净值 / 日频 IC
nav = api.factor_backtest_daily(schema_name="order_time_gather_rolling",
                                factor_name="order_time_gather_rolling_001",
                                start_date="20250101")
ic = api.factor_ic_daily(schema_name="order_time_gather_rolling",
                         factor_name="order_time_gather_rolling_001")

# 原始因子值（长表 date/symbol/value，大表建议限定日期区间）
df = api.alpha_factor(schema_name="order_time_gather_rolling",
                      factor_name="order_time_gather_rolling_001",
                      start_date="20250101", end_date="20250630")

# 整个 schema 的因子值宽表：(date, symbol) 索引，列 = 因子名
# 一年 × 30 因子约数千万行，分钟级耗时；单因子失败自动跳过并 warning
wide = api.alpha_factor_all("order_time_gather_rolling",
                            start_date="20250101", end_date="20251231")

# 数据目录（免鉴权）与用量/配额
print(api.catalog())           # 全部数据集的参数与字段说明
usage = api.usage(days=30)     # 近 30 天调用统计
print(usage.attrs["quota"])    # {"daily_row_quota": ..., "used_today": ..., "remaining_today": ...}
```

## 数据集一览

| 方法 | 必填参数 | 说明 |
| --- | --- | --- |
| `factor_list()` | — | 可见因子清单 |
| `portfolio_list()` | — | 可见组合清单 |
| `factor_performance(universe, start_date, end_date)` | — | 因子绩效汇总（对冲收益/IC/ICIR） |
| `portfolio_performance(universe, start_date, end_date)` | — | 组合绩效汇总 |
| `factor_backtest_daily(schema_name, factor_name, ...)` | schema_name, factor_name | 分组回测日频净值 |
| `factor_ic_daily(schema_name, factor_name, ...)` | schema_name, factor_name | 日频 IC/RankIC |
| `portfolio_backtest_daily(portfolio_name, ...)` | portfolio_name | 组合日频净值 |
| `alpha_factor(schema_name, factor_name, ...)` | schema_name, factor_name | 原始因子值长表（大表推荐 arrow） |
| `alpha_factor_all(schema_name, ...)` | schema_name | 整 schema 因子值宽表（并发拉取） |

日期参数同时接受 `YYYYMMDD` 与 `YYYY-MM-DD`，输出统一 `YYYYMMDD` 字符串。
方法名与服务端 dataset id 一一对应；服务端新增数据集时可直接
`api.query("new_dataset", **params)` 或 `api.new_dataset(**params)` 使用，无需升级 SDK。

## 服务地址（base_url）

三级优先级，从高到低：

1. 显式入参：`gs.pro_api(base_url="https://...")`
2. 环境变量：`GSDB_BASE_URL`
3. 默认值：`https://gsdatabase.net:21985`（生产公网入口）

```bash
# 本地开发直连开发后端（注意直连 FastAPI 的 8000，不走 Vite）
export GSDB_BASE_URL=http://127.0.0.1:8000
python your_script.py
```

## 分页与配额

- 服务端按 cursor 分页：json 单页上限 1 万行，arrow 单页上限 10 万行；SDK 自动续拉
  全部分页并 concat（`paginate=False` 关闭，只取一页）
- 传输层默认 arrow 二进制（更快更省带宽、dtype 保真），`gs.pro_api(fmt="json")` 可切换
- 限频（40201）SDK 按服务端返回的 `retry_after` 自动退避重试；当日行数配额用尽抛
  `QuotaError`，配额与用量见 `api.usage()`

## 错误码

所有异常继承 `gsdatabase.GsdbError`（`e.code` / `e.msg`）：

| code | HTTP | 异常 | 含义 |
| --- | --- | --- | --- |
| 40001 | 401 | `AuthError` | token 缺失、无效或已吊销 |
| 40002 | 401 | `AuthError` | token 过期 |
| 40004 | 403 | `PermissionError_` | 无数据权限 |
| 40101 | 422 | `ParamError` | 参数错误 |
| 40102 | 404 | `ParamError` | dataset 不存在 |
| 40201 | 429 | `RateLimitError` | 频率超限（自动退避重试） |
| 40202 | 429 | `QuotaError` | 当日行数配额用尽 |
| 50000 | 500 | `ServerError` | 服务端错误（自动重试） |
| 50001 | 504 | `ServerError` | 查询超时（自动重试） |
| 50003 | 503 | `ServerError` | 依赖暂时不可用，如数据库抖动（按服务端 `retry_after` 自动退避重试） |
| -1 | — | `GsdbError` | 网络错误 / SDK 本地校验失败 |

## 发布（维护者）

- 发新版：同步提升 `pyproject.toml` 的 `version` 与 `gsdatabase/_version.py` 的
  `_FALLBACK` 并提交，再执行：

  ```bash
  scripts/release.sh          # 校验干净 → 打 tag v<version> → 构建 wheel 到 dist/
  ```

- 发给客户的永远是 tag 构建的 wheel，不是工作区代码。
- 发布前先跑单测与手动冒烟（冒烟默认跳过，需显式测试 token）：

  ```bash
  python -m pytest -q
  GSDB_TEST_TOKEN=gsk_xxx python scripts/smoke.py
  ```
