feat(data): 添加每日筹码及胜率数据接口 (cyq_perf)
- 新增 api_cyq_perf 模块,支持筹码分布数据获取和同步 - 在 sync_registry 中注册 cyq_perf 同步器
This commit is contained in:
@@ -531,6 +531,7 @@ def get_{data_type}(
|
||||
start_date: Optional[str] = None,
|
||||
end_date: Optional[str] = None,
|
||||
ts_code: Optional[str] = None,
|
||||
client: Optional[TushareClient] = None, # 关键:可选客户端参数,用于共享速率限制
|
||||
) -> pd.DataFrame:
|
||||
"""Fetch {数据描述} from Tushare.
|
||||
|
||||
@@ -541,6 +542,9 @@ def get_{data_type}(
|
||||
start_date: Start date (YYYYMMDD format)
|
||||
end_date: End date (YYYYMMDD format)
|
||||
ts_code: Stock code filter (optional)
|
||||
client: Optional TushareClient instance for shared rate limiting.
|
||||
If None, creates a new client. For concurrent sync operations,
|
||||
pass a shared client to ensure proper rate limiting.
|
||||
|
||||
Returns:
|
||||
pd.DataFrame with columns:
|
||||
@@ -552,12 +556,12 @@ def get_{data_type}(
|
||||
Example:
|
||||
>>> # Get all stocks for a single date
|
||||
>>> data = get_{data_type}(trade_date='20240101')
|
||||
>>>
|
||||
>>>
|
||||
>>> # Get date range data
|
||||
>>> data = get_{data_type}(start_date='20240101', end_date='20240131')
|
||||
"""
|
||||
client = TushareClient()
|
||||
|
||||
client = client or TushareClient() # 如果没有提供则创建新实例
|
||||
|
||||
# Build parameters
|
||||
params = {}
|
||||
if trade_date:
|
||||
@@ -568,14 +572,14 @@ def get_{data_type}(
|
||||
params["end_date"] = end_date
|
||||
if ts_code:
|
||||
params["ts_code"] = ts_code
|
||||
|
||||
|
||||
# Fetch data
|
||||
data = client.query("{tushare_api_name}", **params)
|
||||
|
||||
|
||||
# Rename date column if needed
|
||||
if "date" in data.columns:
|
||||
data = data.rename(columns={"date": "trade_date"})
|
||||
|
||||
|
||||
return data
|
||||
```
|
||||
|
||||
@@ -596,6 +600,7 @@ def get_{data_type}(
|
||||
ts_code: str,
|
||||
start_date: Optional[str] = None,
|
||||
end_date: Optional[str] = None,
|
||||
client: Optional[TushareClient] = None, # 关键:可选客户端参数,用于共享速率限制
|
||||
) -> pd.DataFrame:
|
||||
"""Fetch {数据描述} for a specific stock.
|
||||
|
||||
@@ -603,20 +608,23 @@ def get_{data_type}(
|
||||
ts_code: Stock code (e.g., '000001.SZ')
|
||||
start_date: Start date (YYYYMMDD format)
|
||||
end_date: End date (YYYYMMDD format)
|
||||
client: Optional TushareClient instance for shared rate limiting.
|
||||
If None, creates a new client. For concurrent sync operations,
|
||||
pass a shared client to ensure proper rate limiting.
|
||||
|
||||
Returns:
|
||||
pd.DataFrame with {数据描述} data
|
||||
"""
|
||||
client = TushareClient()
|
||||
|
||||
client = client or TushareClient() # 如果没有提供则创建新实例
|
||||
|
||||
params = {"ts_code": ts_code}
|
||||
if start_date:
|
||||
params["start_date"] = start_date
|
||||
if end_date:
|
||||
params["end_date"] = end_date
|
||||
|
||||
|
||||
data = client.query("{tushare_api_name}", **params)
|
||||
|
||||
|
||||
return data
|
||||
```
|
||||
|
||||
@@ -751,6 +759,8 @@ Skill 会自动:
|
||||
- [ ] 已创建 `tests/test_{data_type}.py` 测试文件
|
||||
### 10.2 接口实现
|
||||
- [ ] 数据获取函数使用 `TushareClient`
|
||||
- [ ] **关键**:数据获取函数接受 `client: Optional[TushareClient] = None` 参数用于共享速率限制
|
||||
- [ ] **关键**:Sync 类在 `fetch_single_date()` / `fetch_single_stock()` 中传递 `self.client`
|
||||
- [ ] 函数包含完整的 Google 风格文档字符串
|
||||
- [ ] 日期参数使用 `YYYYMMDD` 格式
|
||||
- [ ] 返回的 DataFrame 包含 `ts_code` 和 `trade_date` 字段
|
||||
@@ -790,6 +800,6 @@ Skill 会自动:
|
||||
|
||||
---
|
||||
|
||||
**最后更新**: 2026-02-23
|
||||
**最后更新**: 2026-03-26
|
||||
|
||||
**版本**: v2.0 - 更新 DuckDB 存储规范,添加 Skill 自动化说明
|
||||
**版本**: v2.1 - 更新速率限制规范,强调多线程场景下 client 参数传递
|
||||
@@ -184,6 +184,57 @@ def get_xxx(period: str, fields: Optional[str] = None) -> pd.DataFrame:
|
||||
|
||||
---
|
||||
|
||||
## 速率限制规范(关键)
|
||||
|
||||
### 问题背景
|
||||
|
||||
财务数据同步使用 VIP 接口(如 `income_vip`、`balancesheet_vip`)按季度获取全市场数据。在并发场景下,如果每个线程创建独立的 `TushareClient` 实例,每个实例会有独立的令牌桶限流器,导致**限流失效**。
|
||||
|
||||
**实际案例**:
|
||||
- 配置 `RATE_LIMIT=150`,理论上每分钟最多 150 次请求
|
||||
- 如果 10 个线程各自创建独立客户端,实际并发数 = 10 × 150 = 1500 次/分钟
|
||||
- 结果:触发 Tushare API 限流,请求失败
|
||||
|
||||
### 解决方案
|
||||
|
||||
**必须**在数据获取函数中接受可选的 `client` 参数,并在同步类中传递共享实例:
|
||||
|
||||
```python
|
||||
from src.data.client import TushareClient
|
||||
from typing import Optional
|
||||
|
||||
# 1. 数据获取函数必须支持 client 参数
|
||||
def get_{data_type}(
|
||||
period: str,
|
||||
client: Optional[TushareClient] = None, # 关键参数
|
||||
) -> pd.DataFrame:
|
||||
"""Fetch financial data.
|
||||
|
||||
Args:
|
||||
period: 报告期(YYYYMMDD)
|
||||
client: Optional TushareClient for shared rate limiting
|
||||
"""
|
||||
client = client or TushareClient() # 如果没有提供则创建新实例
|
||||
return client.query("{api_name}", period=period)
|
||||
|
||||
# 2. 同步类中传递共享 client
|
||||
class XXXQuarterSync(QuarterBasedSync):
|
||||
def fetch_single_quarter(self, period: str) -> pd.DataFrame:
|
||||
# 使用 self.client(基类创建的共享实例)
|
||||
return get_{data_type}(period=period, client=self.client)
|
||||
```
|
||||
|
||||
### 关键规则
|
||||
|
||||
1. **数据获取函数**:必须接受 `client: Optional[TushareClient] = None` 参数
|
||||
2. **同步类实现**:必须在 `fetch_single_quarter()` 中传递 `self.client`
|
||||
3. **基类保证**:`QuarterBasedSync` 基类在 `__init__` 中创建 `self.client = TushareClient()`
|
||||
4. **使用模式**:数据获取函数使用 `client = client or TushareClient()` 模式
|
||||
|
||||
**注意**:`TushareClient` 内部使用**类级别共享限流器**(`_shared_limiter`),确保所有实例共享同一个令牌桶,但前提是必须复用同一个客户端实例。
|
||||
|
||||
---
|
||||
|
||||
## 类设计规范
|
||||
|
||||
### 类命名规范
|
||||
@@ -1284,6 +1335,7 @@ self.storage.flush()
|
||||
|
||||
| 日期 | 版本 | 变更内容 |
|
||||
|------|------|----------|
|
||||
| 2026-03-26 | v1.4 | 添加速率限制规范:<br>- 强调多线程场景下 client 参数传递<br>- 添加实际案例分析<br>- 说明 TushareClient 共享限流器机制 |
|
||||
| 2026-03-08 | v1.3 | 现金流量表接口实现:<br>- 完成 `api_cashflow.py` 封装<br>- 添加 95 个现金流量表完整字段<br>- 更新调度中心注册<br>- 更新文档标记现金流为已实现 |
|
||||
| 2026-03-08 | v1.2 | 资产负债表接口实现:<br>- 完成 `api_balance.py` 封装<br>- 添加 157 个资产负债表完整字段<br>- 更新调度中心注册<br>- 更新文档中的资产负债表示例为完整实现 |
|
||||
| 2026-03-08 | v1.1 | 完善实际编码细节:<br>- 添加首次同步优化说明<br>- 添加日期格式转换规范<br>- 添加存储层 UPSERT 禁用说明<br>- 添加删除计数处理说明<br>- 扩充常见问题(Q7-Q9) |
|
||||
|
||||
Reference in New Issue
Block a user