diff --git a/API_DOCUMENTATION.md b/API_DOCUMENTATION.md new file mode 100644 index 0000000..5520f11 --- /dev/null +++ b/API_DOCUMENTATION.md @@ -0,0 +1,769 @@ +# 行情数据服务 API 文档 + +> 版本:v1.0.0 +> 更新时间:2026-03-11 + +## 目录 + +- [概述](#概述) +- [认证方式](#认证方式) +- [股票接口](#股票接口) +- [期货接口](#期货接口) +- [管理接口](#管理接口) +- [WebSocket 实时行情](#websocket-实时行情) +- [数据模型](#数据模型) +- [错误码](#错误码) + +--- + +## 概述 + +### 基础信息 + +| 项目 | 说明 | +|------|------| +| 协议 | HTTP/1.1 或 HTTP/2 | +| 数据格式 | JSON | +| 字符编码 | UTF-8 | +| 日期格式 | YYYYMMDD (如:20260301) | +| 时间戳格式 | ISO 8601 (如:2026-03-01T09:30:00) | + +### 基础 URL + +``` +http://:8080/v1 +``` + +### 通用响应结构 + +所有接口返回统一的响应格式: + +```json +{ + "code": 0, // 状态码,0表示成功 + "message": "success", // 提示信息 + "data": {} // 响应数据(具体结构见各接口) +} +``` + +--- + +## 认证方式 + +API 使用 `X-API-Key` 请求头进行认证(健康检查接口除外)。 + +```http +X-API-Key: YOUR_API_KEY +``` + +**响应示例(认证失败):** + +```json +{ + "detail": "Missing API Key" +} +``` + +--- + +## 股票接口 + +### 1. 查询股票K线 + +获取指定股票的K线数据。 + +**请求信息:** + +| 项目 | 说明 | +|------|------| +| 方法 | GET | +| 路径 | `/stock/klines/{symbol}` | +| 认证 | 需要 | + +**路径参数:** + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| symbol | string | 是 | 标的代码,如 `000001.SZ` | + +**查询参数:** + +| 参数 | 类型 | 必填 | 默认值 | 说明 | +|------|------|------|--------|------| +| start | string | 是 | - | 开始日期 YYYYMMDD | +| end | string | 是 | - | 结束日期 YYYYMMDD | +| freq | string | 否 | `1d` | 周期:`1m`, `5m`, `15m`, `30m`, `60m`, `1d`, `1w`, `1month` | +| adjust | string | 否 | - | 复权类型:`qfq`(前复权), `hfq`(后复权),空值为不复权 | + +**请求示例:** + +```bash +curl -X GET "http://localhost:8080/v1/stock/klines/000001.SZ?start=20250301&end=20250310&freq=1d&adjust=qfq" \ + -H "X-API-Key: YOUR_API_KEY" +``` + +**响应示例:** + +```json +{ + "code": 0, + "message": "success", + "data": { + "symbol": "000001.SZ", + "name": "平安银行", + "freq": "1d", + "adjust": "qfq", + "count": 8, + "items": [ + { + "symbol": "000001.SZ", + "time": "2026-03-01T00:00:00", + "open": 10.50, + "high": 10.80, + "low": 10.40, + "close": 10.65, + "volume": 1500000, + "amount": 15975000.00, + "trade_date": "2026-03-01", + "is_limit_up": false, + "is_limit_down": false, + "total_market_cap": 250000000000.00, + "float_market_cap": 200000000000.00, + "inst_holding_ratio": 25.5, + "trading_days": 5200 + } + ] + } +} +``` + +--- + +### 2. 批量查询股票K线 + +批量查询多只股票的K线数据。 + +**请求信息:** + +| 项目 | 说明 | +|------|------| +| 方法 | POST | +| 路径 | `/stock/klines/batch` | +| 认证 | 需要 | + +**请求体:** + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| symbols | array | 是 | 标的代码列表,最多100只 | +| start | string | 是 | 开始日期 YYYYMMDD | +| end | string | 是 | 结束日期 YYYYMMDD | +| freq | string | 否 | 周期,默认 `1d` | +| adjust | string | 否 | 复权类型 | + +**请求示例:** + +```bash +curl -X POST "http://localhost:8080/v1/stock/klines/batch" \ + -H "X-API-Key: YOUR_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "symbols": ["000001.SZ", "000002.SZ"], + "start": "20250301", + "end": "20250310", + "freq": "1d" + }' +``` + +**响应示例:** + +```json +{ + "code": 0, + "message": "success", + "data": { + "results": [ + { + "symbol": "000001.SZ", + "success": true, + "error": null, + "data": { + "count": 8, + "items": [...] + } + }, + { + "symbol": "000002.SZ", + "success": false, + "error": "symbol not found", + "data": null + } + ] + } +} +``` + +--- + +### 3. 查询股票列表 + +获取所有可用股票标的。 + +**请求信息:** + +| 项目 | 说明 | +|------|------| +| 方法 | GET | +| 路径 | `/stock/symbols` | +| 认证 | 需要 | + +**查询参数:** + +| 参数 | 类型 | 必填 | 默认值 | 说明 | +|------|------|------|--------|------| +| exchange | string | 否 | - | 交易所筛选:`SZ`, `SH`, `BJ` | +| keyword | string | 否 | - | 关键词搜索(代码或名称) | +| page | integer | 否 | 1 | 页码 | +| size | integer | 否 | 20 | 每页数量,最大100 | + +**响应示例:** + +```json +{ + "code": 0, + "message": "success", + "data": { + "total": 5000, + "page": 1, + "size": 20, + "items": [ + { + "symbol_id": "000001.SZ", + "symbol_type": "stock", + "exchange": "SZ", + "name": "平安银行", + "name_en": "Ping An Bank", + "list_date": "1991-04-03T00:00:00", + "industry": "银行", + "status": "active" + } + ] + } +} +``` + +--- + +### 4. 查询股票交易日历 + +获取指定日期范围内的交易日。 + +**请求信息:** + +| 项目 | 说明 | +|------|------| +| 方法 | GET | +| 路径 | `/stock/trading-dates` | +| 认证 | 需要 | + +**查询参数:** + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| start | string | 是 | 开始日期 YYYYMMDD | +| end | string | 是 | 结束日期 YYYYMMDD | + +**响应示例:** + +```json +{ + "code": 0, + "message": "success", + "data": { + "start": "20250301", + "end": "20250310", + "total_days": 10, + "trading_days": 7, + "trading_dates": ["20250301", "20250302", "20250303", "20250306", "20250307", "20250310"] + } +} +``` + +--- + +## 期货接口 + +### 1. 查询期货K线 + +获取指定期货合约的K线数据。 + +**请求信息:** + +| 项目 | 说明 | +|------|------| +| 方法 | GET | +| 路径 | `/futures/klines/{symbol}` | +| 认证 | 需要 | + +**路径参数:** + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| symbol | string | 是 | 合约代码,如 `CU2504.SHFE` | + +**查询参数:** + +| 参数 | 类型 | 必填 | 默认值 | 说明 | +|------|------|------|--------|------| +| start | string | 是 | - | 开始日期 YYYYMMDD | +| end | string | 是 | - | 结束日期 YYYYMMDD | +| freq | string | 否 | `1d` | 周期 | + +**响应示例:** + +```json +{ + "code": 0, + "message": "success", + "data": { + "symbol": "CU2504.SHFE", + "name": "沪铜2504", + "freq": "1d", + "adjust": "", + "count": 10, + "items": [ + { + "symbol": "CU2504.SHFE", + "time": "2026-03-01T00:00:00", + "open": 69000.00, + "high": 69500.00, + "low": 68800.00, + "close": 69200.00, + "volume": 12500, + "amount": 865000000.00, + "open_interest": 45000 + } + ] + } +} +``` + +--- + +### 2. 批量查询期货K线 + +**请求信息:** + +| 项目 | 说明 | +|------|------| +| 方法 | POST | +| 路径 | `/futures/klines/batch` | +| 认证 | 需要 | + +**请求体:** 同股票批量查询 + +--- + +### 3. 查询期货列表 + +**请求信息:** + +| 项目 | 说明 | +|------|------| +| 方法 | GET | +| 路径 | `/futures/symbols` | +| 认证 | 需要 | + +**查询参数:** + +| 参数 | 类型 | 必填 | 默认值 | 说明 | +|------|------|------|--------|------| +| exchange | string | 否 | - | 交易所:`CFFEX`, `SHFE`, `DCE`, `CZCE`, `INE`, `GFEX` | +| underlying | string | 否 | - | 品种筛选,如 `CU`, `RB` | +| keyword | string | 否 | - | 关键词搜索 | +| page | integer | 否 | 1 | 页码 | +| size | integer | 否 | 20 | 每页数量 | + +--- + +### 4. 查询期货交易日历 + +**请求信息:** + +| 项目 | 说明 | +|------|------| +| 方法 | GET | +| 路径 | `/futures/trading-dates` | +| 认证 | 需要 | + +--- + +### 5. 获取品种合约列表 + +获取指定品种的所有可交易合约。 + +**请求信息:** + +| 项目 | 说明 | +|------|------| +| 方法 | GET | +| 路径 | `/futures/contracts` | +| 认证 | 需要 | + +**查询参数:** + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| underlying | string | 是 | 品种代码,如 `CU`, `RB` | +| exchange | string | 否 | 交易所筛选 | + +**响应示例:** + +```json +{ + "code": 0, + "message": "success", + "data": { + "underlying": "CU", + "count": 12, + "items": [ + { + "symbol_id": "CU2504.SHFE", + "symbol_type": "futures", + "exchange": "SHFE", + "name": "沪铜2504", + "underlying": "CU", + "contract_month": "2504", + "list_date": "2024-04-16T00:00:00", + "delist_date": "2025-04-15T00:00:00", + "status": "active" + } + ] + } +} +``` + +--- + +### 6. 查询主力连续合约K线(预留) + +**请求信息:** + +| 项目 | 说明 | +|------|------| +| 方法 | GET | +| 路径 | `/futures/continuous/{underlying}` | +| 认证 | 需要 | + +**路径参数:** + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| underlying | string | 是 | 品种代码 | + +**查询参数:** 同期货K线查询 + +> 注:当前返回空数据,功能预留 + +--- + +## 管理接口 + +### 1. 健康检查 + +检查服务健康状态(无需认证)。 + +**请求信息:** + +| 项目 | 说明 | +|------|------| +| 方法 | GET | +| 路径 | `/admin/health` | +| 认证 | 不需要 | + +**响应示例:** + +```json +{ + "status": "healthy", + "timestamp": "2026-03-11T08:30:00" +} +``` + +--- + +### 2. 获取数据源状态 + +获取当前数据源配置和状态。 + +**请求信息:** + +| 项目 | 说明 | +|------|------| +| 方法 | GET | +| 路径 | `/admin/source/status` | +| 认证 | 需要 | + +**响应示例:** + +```json +{ + "code": 0, + "message": "success", + "data": { + "stock": { + "active_source": "custom", + "standby_sources": [], + "status": "healthy" + }, + "futures": { + "active_source": "custom", + "standby_sources": [], + "status": "healthy" + } + } +} +``` + +--- + +### 3. 切换数据源 + +切换股票/期货的数据源。 + +**请求信息:** + +| 项目 | 说明 | +|------|------| +| 方法 | POST | +| 路径 | `/admin/source/switch` | +| 认证 | 需要 | + +**请求体:** + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| asset_class | string | 是 | 资产类别:`stock`, `futures`, `all` | +| source | string | 是 | 目标数据源名称 | +| sync_backfill | boolean | 否 | 是否同步补录 | +| start_date | string | 否 | 补录开始日期 YYYYMMDD | + +**请求示例:** + +```bash +curl -X POST "http://localhost:8080/v1/admin/source/switch" \ + -H "X-API-Key: YOUR_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "asset_class": "all", + "source": "custom", + "sync_backfill": false + }' +``` + +--- + +### 4. 历史数据补录 + +启动历史数据补录任务。 + +**请求信息:** + +| 项目 | 说明 | +|------|------| +| 方法 | POST | +| 路径 | `/admin/backfill` | +| 认证 | 需要 | + +**请求体:** + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| asset_class | string | 是 | 资产类别 | +| symbols | array | 是 | 标的列表,空数组表示全部 | +| start | string | 是 | 开始日期 YYYYMMDD | +| end | string | 是 | 结束日期 YYYYMMDD | +| freqs | array | 是 | 需要补录的周期列表 | +| source | string | 否 | 指定数据源 | + +--- + +## WebSocket 实时行情 + +### 连接信息 + +| 项目 | 说明 | +|------|------| +| URL | `ws://:8080/v1/stream` | +| 协议 | WebSocket | +| 认证 | 通过 `X-API-Key` Header | + +### 连接示例 + +```javascript +const ws = new WebSocket('ws://localhost:8080/v1/stream'); +ws.onopen = () => { + // 订阅股票行情 + ws.send(JSON.stringify({ + action: 'subscribe', + symbols: ['000001.SZ', '000002.SZ'] + })); +}; +ws.onmessage = (event) => { + const data = JSON.parse(event.data); + console.log(data); +}; +``` + +### 消息格式 + +**客户端 → 服务器(订阅):** + +```json +{ + "action": "subscribe", + "symbols": ["000001.SZ", "CU2504.SHFE"] +} +``` + +**客户端 → 服务器(取消订阅):** + +```json +{ + "action": "unsubscribe", + "symbols": ["000001.SZ"] +} +``` + +**服务器 → 客户端(行情推送):** + +```json +{ + "type": "tick", + "symbol": "000001.SZ", + "time": "2026-03-11T09:30:00.123", + "price": 10.65, + "volume": 1000, + "amount": 10650.00 +} +``` + +--- + +## 数据模型 + +### K线周期 (Frequency) + +| 值 | 说明 | +|------|------| +| `1m` | 1分钟 | +| `5m` | 5分钟 | +| `15m` | 15分钟 | +| `30m` | 30分钟 | +| `60m` | 60分钟 | +| `1d` | 日线 | +| `1w` | 周线 | +| `1month` | 月线 | + +### 复权类型 (AdjustType) + +| 值 | 说明 | +|------|------| +| `` | 不复权 | +| `qfq` | 前复权 | +| `hfq` | 后复权 | + +### 交易所 (Exchange) + +**股票交易所:** + +| 值 | 说明 | +|------|------| +| `SZ` | 深交所 | +| `SH` | 上交所 | +| `BJ` | 北交所 | + +**期货交易所:** + +| 值 | 说明 | +|------|------| +| `CFFEX` | 中金所 | +| `SHFE` | 上期所 | +| `DCE` | 大商所 | +| `CZCE` | 郑商所 | +| `INE` | 上期能源 | +| `GFEX` | 广期所 | + +### K线数据字段 (KLineItem) + +| 字段 | 类型 | 说明 | +|------|------|------| +| symbol | string | 标的代码 | +| time | datetime | 时间戳 | +| open | float | 开盘价 | +| high | float | 最高价 | +| low | float | 最低价 | +| close | float | 收盘价 | +| volume | int | 成交量(股/手) | +| amount | float | 成交额(元) | +| open_interest | int | 持仓量(期货特有) | +| settlement | float | 结算价(期货特有) | +| adj_factor | float | 复权系数(股票特有) | +| trade_date | string | 交易日 YYYY-MM-DD | +| is_limit_up | boolean | 是否涨停(股票) | +| is_limit_down | boolean | 是否跌停(股票) | +| total_market_cap | float | 总市值(元) | +| float_market_cap | float | 流通市值(元) | +| inst_holding_ratio | float | 机构持仓占比(%) | +| trading_days | int | 可交易日数 | + +--- + +## 错误码 + +| 状态码 | 说明 | +|--------|------| +| 200 | 成功 | +| 401 | 未认证(缺少 API Key) | +| 422 | 请求参数错误 | +| 500 | 服务器内部错误 | +| 503 | 服务不可用 | + +**业务错误码:** + +| code | 说明 | +|------|------| +| 0 | 成功 | +| 1001 | 标的不存在 | +| 1002 | 日期格式错误 | +| 1003 | 频率不支持 | +| 2001 | 数据源连接失败 | +| 2002 | 数据源切换失败 | + +--- + +## 附录 + +### 常用标的代码示例 + +**股票:** + +| 代码 | 名称 | +|------|------| +| `000001.SZ` | 平安银行 | +| `000002.SZ` | 万科A | +| `600000.SH` | 浦发银行 | +| `600519.SH` | 贵州茅台 | + +**期货:** + +| 代码 | 名称 | +|------|------| +| `CU2504.SHFE` | 沪铜2504 | +| `RB2505.SHFE` | 螺纹钢2505 | +| `M2505.DCE` | 豆粕2505 | +| `CF2505.CZCE` | 棉花2505 | + +--- + +**文档结束** diff --git a/API_KLINE_RESPONSE.md b/API_KLINE_RESPONSE.md index 32203d3..b9bfdb7 100644 --- a/API_KLINE_RESPONSE.md +++ b/API_KLINE_RESPONSE.md @@ -163,5 +163,5 @@ python test_klines_api.py ```bash curl -X GET "http://localhost:8080/v1/stock/klines/000001.SZ?start=20260301&end=20260310&freq=1d" \ - -H "X-API-Key: demo-api-key-2024" + -H "X-API-Key: YOUR_API_KEY" ``` diff --git a/QUICKSTART.md b/QUICKSTART.md index 0840d5f..b74c8a9 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -269,13 +269,13 @@ curl http://localhost:8080/v1/admin/health # 查询股票K线 curl "http://localhost:8080/v1/stock/klines/000001.SZ?start=20250301&end=20250307&freq=1d" \ - -H "X-API-Key: demo-api-key-2024" + -H "X-API-Key: YOUR_API_KEY" # 热加载配置 curl -X POST http://localhost:8080/v1/admin/system/reload # WebSocket测试 -wscat -c ws://localhost:8080/v1/stream -H "X-API-Key: demo-api-key-2024" +wscat -c ws://localhost:8080/v1/stream -H "X-API-Key: YOUR_API_KEY" > {"action":"subscribe","symbols":["000001.SZ"]} ``` diff --git a/app/__pycache__/main.cpython-311.pyc b/app/__pycache__/main.cpython-311.pyc index ca6054d..2a5ef01 100644 Binary files a/app/__pycache__/main.cpython-311.pyc and b/app/__pycache__/main.cpython-311.pyc differ diff --git a/app/api/__pycache__/routes.cpython-311.pyc b/app/api/__pycache__/routes.cpython-311.pyc index f954d97..94c12df 100644 Binary files a/app/api/__pycache__/routes.cpython-311.pyc and b/app/api/__pycache__/routes.cpython-311.pyc differ diff --git a/app/api/routes.py b/app/api/routes.py index 2189e05..7621c19 100644 --- a/app/api/routes.py +++ b/app/api/routes.py @@ -22,7 +22,10 @@ config = get_config() # 认证依赖 def verify_api_key(x_api_key: Optional[str] = Header(None)): - """验证API Key""" + """验证API Key,根据配置决定是否启用""" + if not config.server.auth_enabled: + # 认证已禁用,跳过验证 + return x_api_key or "anonymous" if not x_api_key: raise HTTPException(status_code=401, detail="Missing API Key") # TODO: 验证API Key有效性 diff --git a/app/core/__pycache__/config.cpython-311.pyc b/app/core/__pycache__/config.cpython-311.pyc index 51ef055..b3995bf 100644 Binary files a/app/core/__pycache__/config.cpython-311.pyc and b/app/core/__pycache__/config.cpython-311.pyc differ diff --git a/app/core/config.py b/app/core/config.py index 8a9f080..c23c623 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -12,7 +12,8 @@ class ServerConfig(BaseModel): """服务器配置""" port: int = 8080 mode: str = "debug" # debug/release - api_key: str = "demo-api-key-2024" + api_key: str = "" + auth_enabled: bool = True # 是否启用API Key认证 class DatabaseConfig(BaseModel): @@ -49,34 +50,34 @@ class SourceInfo(BaseModel): class SourceConfig(BaseModel): """源配置""" - active: str = "amazingdata" + active: str = "custom" list: Dict[str, SourceInfo] = Field(default_factory=dict) class SourcesConfig(BaseModel): """数据源配置""" stock: SourceConfig = Field(default_factory=lambda: SourceConfig( - active="amazingdata", + active="custom", list={ - "amazingdata": SourceInfo(type="sdk", config={ + "custom": SourceInfo(type="sdk", config={ "username": "", "password": "", "host": "", "port": "8080", - "local_path": "./amazing_data_cache/", + "local_path": "./custom_data_cache/", "use_local_cache": "true" }) } )) futures: SourceConfig = Field(default_factory=lambda: SourceConfig( - active="amazingdata", + active="custom", list={ - "amazingdata": SourceInfo(type="sdk", config={ + "custom": SourceInfo(type="sdk", config={ "username": "", "password": "", "host": "", "port": "8080", - "local_path": "./amazing_data_cache/", + "local_path": "./custom_data_cache/", "use_local_cache": "true" }) } diff --git a/app/main.py b/app/main.py index 42b0ac1..15438c6 100644 --- a/app/main.py +++ b/app/main.py @@ -569,7 +569,7 @@ ADMIN_HTML = '''