2026-03-26 00:15:30 +08:00
|
|
|
|
"""CYQ Performance (筹码分布) interface.
|
|
|
|
|
|
|
|
|
|
|
|
Fetch A-share stock chip distribution data (cost distribution and win rate) from Tushare.
|
|
|
|
|
|
This interface retrieves daily chip average cost and win rate information.
|
|
|
|
|
|
Data starts from 2018.
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
import pandas as pd
|
|
|
|
|
|
from typing import Optional
|
|
|
|
|
|
|
|
|
|
|
|
from src.data.client import TushareClient
|
2026-03-26 22:22:43 +08:00
|
|
|
|
from src.data.api_wrappers.base_sync import DateBasedSync
|
2026-03-26 00:15:30 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_cyq_perf(
|
2026-03-26 22:22:43 +08:00
|
|
|
|
trade_date: Optional[str] = None,
|
|
|
|
|
|
ts_code: Optional[str] = None,
|
2026-03-26 00:15:30 +08:00
|
|
|
|
start_date: Optional[str] = None,
|
|
|
|
|
|
end_date: Optional[str] = None,
|
|
|
|
|
|
client: Optional[TushareClient] = None,
|
|
|
|
|
|
) -> pd.DataFrame:
|
|
|
|
|
|
"""Fetch chip distribution (CYQ) performance data from Tushare.
|
|
|
|
|
|
|
|
|
|
|
|
This interface retrieves daily chip average cost and win rate information
|
|
|
|
|
|
for A-share stocks. Data starts from 2018.
|
|
|
|
|
|
|
|
|
|
|
|
Args:
|
2026-03-26 22:22:43 +08:00
|
|
|
|
trade_date: Specific trade date in YYYYMMDD format
|
|
|
|
|
|
ts_code: Stock code filter (optional, e.g., '000001.SZ')
|
|
|
|
|
|
start_date: Start date for date range query (YYYYMMDD format)
|
|
|
|
|
|
end_date: End date for date range query (YYYYMMDD format)
|
2026-03-26 00:15:30 +08:00
|
|
|
|
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:
|
|
|
|
|
|
- ts_code: Stock code
|
|
|
|
|
|
- trade_date: Trade date (YYYYMMDD)
|
|
|
|
|
|
- his_low: Historical lowest price
|
|
|
|
|
|
- his_high: Historical highest price
|
|
|
|
|
|
- cost_5pct: 5th percentile cost
|
|
|
|
|
|
- cost_15pct: 15th percentile cost
|
|
|
|
|
|
- cost_50pct: 50th percentile cost (median)
|
|
|
|
|
|
- cost_85pct: 85th percentile cost
|
|
|
|
|
|
- cost_95pct: 95th percentile cost
|
|
|
|
|
|
- weight_avg: Weighted average cost
|
|
|
|
|
|
- winner_rate: Win rate (percentage)
|
|
|
|
|
|
|
|
|
|
|
|
Example:
|
2026-03-26 22:22:43 +08:00
|
|
|
|
>>> # Get all stocks' chip distribution for a single date
|
|
|
|
|
|
>>> data = get_cyq_perf(trade_date='20240115')
|
2026-03-26 00:15:30 +08:00
|
|
|
|
>>>
|
2026-03-26 22:22:43 +08:00
|
|
|
|
>>> # Get date range data for a specific stock
|
|
|
|
|
|
>>> data = get_cyq_perf(ts_code='000001.SZ', start_date='20240101', end_date='20240131')
|
|
|
|
|
|
>>>
|
|
|
|
|
|
>>> # Get specific stock on specific date
|
|
|
|
|
|
>>> data = get_cyq_perf(ts_code='000001.SZ', trade_date='20240115')
|
2026-03-26 00:15:30 +08:00
|
|
|
|
"""
|
|
|
|
|
|
client = client or TushareClient()
|
|
|
|
|
|
|
|
|
|
|
|
# Build parameters
|
2026-03-26 22:22:43 +08:00
|
|
|
|
params = {}
|
|
|
|
|
|
if trade_date:
|
|
|
|
|
|
params["trade_date"] = trade_date
|
|
|
|
|
|
if ts_code:
|
|
|
|
|
|
params["ts_code"] = ts_code
|
2026-03-26 00:15:30 +08:00
|
|
|
|
if start_date:
|
|
|
|
|
|
params["start_date"] = start_date
|
|
|
|
|
|
if end_date:
|
|
|
|
|
|
params["end_date"] = end_date
|
|
|
|
|
|
|
|
|
|
|
|
# Fetch data using cyq_perf API
|
|
|
|
|
|
data = client.query("cyq_perf", **params)
|
|
|
|
|
|
|
|
|
|
|
|
# Rename date column if needed
|
|
|
|
|
|
if "date" in data.columns:
|
|
|
|
|
|
data = data.rename(columns={"date": "trade_date"})
|
|
|
|
|
|
|
|
|
|
|
|
return data
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-03-26 22:22:43 +08:00
|
|
|
|
class CyqPerfSync(DateBasedSync):
|
2026-03-26 00:15:30 +08:00
|
|
|
|
"""筹码分布数据批量同步管理器,支持全量/增量同步。
|
|
|
|
|
|
|
2026-03-26 22:22:43 +08:00
|
|
|
|
继承自 DateBasedSync,使用按日期并发获取数据。
|
2026-03-26 00:15:30 +08:00
|
|
|
|
|
|
|
|
|
|
Example:
|
|
|
|
|
|
>>> sync = CyqPerfSync()
|
|
|
|
|
|
>>> results = sync.sync_all() # 增量同步
|
|
|
|
|
|
>>> results = sync.sync_all(force_full=True) # 全量同步
|
|
|
|
|
|
>>> preview = sync.preview_sync() # 预览
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
table_name = "cyq_perf"
|
2026-03-26 22:22:43 +08:00
|
|
|
|
default_start_date = "20180101"
|
2026-03-26 00:15:30 +08:00
|
|
|
|
|
|
|
|
|
|
# 表结构定义
|
|
|
|
|
|
TABLE_SCHEMA = {
|
|
|
|
|
|
"ts_code": "VARCHAR(16) NOT NULL",
|
|
|
|
|
|
"trade_date": "DATE NOT NULL",
|
|
|
|
|
|
"his_low": "DOUBLE",
|
|
|
|
|
|
"his_high": "DOUBLE",
|
|
|
|
|
|
"cost_5pct": "DOUBLE",
|
|
|
|
|
|
"cost_15pct": "DOUBLE",
|
|
|
|
|
|
"cost_50pct": "DOUBLE",
|
|
|
|
|
|
"cost_85pct": "DOUBLE",
|
|
|
|
|
|
"cost_95pct": "DOUBLE",
|
|
|
|
|
|
"weight_avg": "DOUBLE",
|
|
|
|
|
|
"winner_rate": "DOUBLE",
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# 索引定义
|
|
|
|
|
|
TABLE_INDEXES = [
|
|
|
|
|
|
("idx_cyq_perf_date_code", ["trade_date", "ts_code"]),
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
# 主键定义
|
|
|
|
|
|
PRIMARY_KEY = ("ts_code", "trade_date")
|
|
|
|
|
|
|
2026-03-26 22:22:43 +08:00
|
|
|
|
def fetch_single_date(self, trade_date: str) -> pd.DataFrame:
|
|
|
|
|
|
"""获取单日所有股票的筹码分布数据。
|
2026-03-26 00:15:30 +08:00
|
|
|
|
|
|
|
|
|
|
Args:
|
2026-03-26 22:22:43 +08:00
|
|
|
|
trade_date: 交易日期(YYYYMMDD)
|
2026-03-26 00:15:30 +08:00
|
|
|
|
|
|
|
|
|
|
Returns:
|
2026-03-26 22:22:43 +08:00
|
|
|
|
包含当日所有股票筹码分布数据的 DataFrame
|
2026-03-26 00:15:30 +08:00
|
|
|
|
"""
|
2026-03-26 22:22:43 +08:00
|
|
|
|
return get_cyq_perf(trade_date=trade_date, client=self.client)
|
2026-03-26 00:15:30 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def sync_cyq_perf(
|
|
|
|
|
|
start_date: Optional[str] = None,
|
|
|
|
|
|
end_date: Optional[str] = None,
|
2026-03-26 22:22:43 +08:00
|
|
|
|
force_full: bool = False,
|
|
|
|
|
|
) -> pd.DataFrame:
|
|
|
|
|
|
"""同步筹码分布数据到 DuckDB,支持智能增量同步。
|
2026-03-26 00:15:30 +08:00
|
|
|
|
|
2026-03-26 22:22:43 +08:00
|
|
|
|
逻辑:
|
|
|
|
|
|
- 若表不存在:创建表 + 复合索引 (trade_date, ts_code) + 全量同步
|
|
|
|
|
|
- 若表存在:从 last_date + 1 开始增量同步
|
2026-03-26 00:15:30 +08:00
|
|
|
|
|
|
|
|
|
|
Args:
|
2026-03-26 22:22:43 +08:00
|
|
|
|
start_date: 起始日期(YYYYMMDD 格式,默认全量从 20180101,增量从 last_date+1)
|
|
|
|
|
|
end_date: 结束日期(YYYYMMDD 格式,默认为今天)
|
2026-03-26 00:15:30 +08:00
|
|
|
|
force_full: 若为 True,强制从 20180101 完整重载
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
2026-03-26 22:22:43 +08:00
|
|
|
|
包含同步数据的 pd.DataFrame
|
2026-03-26 00:15:30 +08:00
|
|
|
|
|
|
|
|
|
|
Example:
|
|
|
|
|
|
>>> # 首次同步(从 20180101 全量加载)
|
|
|
|
|
|
>>> result = sync_cyq_perf()
|
|
|
|
|
|
>>>
|
|
|
|
|
|
>>> # 后续同步(增量 - 仅新数据)
|
|
|
|
|
|
>>> result = sync_cyq_perf()
|
|
|
|
|
|
>>>
|
|
|
|
|
|
>>> # 强制完整重载
|
|
|
|
|
|
>>> result = sync_cyq_perf(force_full=True)
|
|
|
|
|
|
>>>
|
|
|
|
|
|
>>> # 手动指定日期范围
|
|
|
|
|
|
>>> result = sync_cyq_perf(start_date='20240101', end_date='20240131')
|
|
|
|
|
|
"""
|
2026-03-26 22:22:43 +08:00
|
|
|
|
sync_manager = CyqPerfSync()
|
2026-03-26 00:15:30 +08:00
|
|
|
|
return sync_manager.sync_all(
|
|
|
|
|
|
start_date=start_date,
|
|
|
|
|
|
end_date=end_date,
|
2026-03-26 22:22:43 +08:00
|
|
|
|
force_full=force_full,
|
2026-03-26 00:15:30 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def preview_cyq_perf_sync(
|
|
|
|
|
|
start_date: Optional[str] = None,
|
|
|
|
|
|
end_date: Optional[str] = None,
|
2026-03-26 22:22:43 +08:00
|
|
|
|
force_full: bool = False,
|
2026-03-26 00:15:30 +08:00
|
|
|
|
sample_size: int = 3,
|
|
|
|
|
|
) -> dict:
|
|
|
|
|
|
"""预览筹码分布数据同步数据量和样本(不实际同步)。
|
|
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
|
start_date: 手动指定起始日期(覆盖自动检测)
|
|
|
|
|
|
end_date: 手动指定结束日期(默认为今天)
|
2026-03-26 22:22:43 +08:00
|
|
|
|
force_full: 若为 True,预览全量同步(从 20180101)
|
|
|
|
|
|
sample_size: 预览天数(默认: 3)
|
2026-03-26 00:15:30 +08:00
|
|
|
|
|
|
|
|
|
|
Returns:
|
2026-03-26 22:22:43 +08:00
|
|
|
|
包含预览信息的字典
|
2026-03-26 00:15:30 +08:00
|
|
|
|
|
|
|
|
|
|
Example:
|
|
|
|
|
|
>>> # 预览将要同步的内容
|
|
|
|
|
|
>>> preview = preview_cyq_perf_sync()
|
|
|
|
|
|
>>>
|
|
|
|
|
|
>>> # 预览全量同步
|
|
|
|
|
|
>>> preview = preview_cyq_perf_sync(force_full=True)
|
|
|
|
|
|
"""
|
|
|
|
|
|
sync_manager = CyqPerfSync()
|
|
|
|
|
|
return sync_manager.preview_sync(
|
|
|
|
|
|
start_date=start_date,
|
|
|
|
|
|
end_date=end_date,
|
2026-03-26 22:22:43 +08:00
|
|
|
|
force_full=force_full,
|
2026-03-26 00:15:30 +08:00
|
|
|
|
sample_size=sample_size,
|
|
|
|
|
|
)
|