feat(data): 添加每日筹码及胜率数据接口 (cyq_perf)

- 新增 api_cyq_perf 模块,支持筹码分布数据获取和同步
- 在 sync_registry 中注册 cyq_perf 同步器
This commit is contained in:
2026-03-26 22:22:43 +08:00
parent 6730acbae1
commit d4e0e2a0b6
9 changed files with 261 additions and 230 deletions

View File

@@ -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 参数传递

View File

@@ -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 |