Initial commit: cc-cursor 全链路量化研究平台
7 Sprints 全部完成: Sprint 0: 基础设施 (DataManager + MariaDB) Sprint 1: 因子引擎 (34因子/12分类) Sprint 2: VectorBT 回测 (5策略+截面) Sprint 3: Optuna 优化 (+Walk-Forward) Sprint 4: ML 模型 (LightGBM+CatBoost) Sprint 5: Qwen 情绪因子 (三源新闻+日期对齐) Sprint 6: Agent 系统 (4Agent+日报.md/.html) 生产加固 (15项): Tushare双源fallback, SSH自动恢复, pool_pre_ping, save_daily先删后插, load_dotenv绝对路径, 日报5d/20d修复, RiskAgent改上证指数, 昨日对比+数据截止, mac_report utf8mb4, CLAUDE-*.md 9条已知Bug, demo全参数化, djapi数据源归一化, indexDatas API修正 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
import pandas as pd
|
||||
|
||||
|
||||
# 导入当站目录的config文件
|
||||
try:
|
||||
# 尝试相对导入(作为包的一部分)
|
||||
from .config import TS_TOKEN, START_DATE, END_DATE, PRECISION_CONFIG
|
||||
from .stock_utils import *
|
||||
except (ImportError, SystemError):
|
||||
# 失败则使用绝对导入(直接运行脚本)
|
||||
from config import TS_TOKEN, START_DATE, END_DATE, PRECISION_CONFIG
|
||||
from stock_utils import *
|
||||
|
||||
from .data_source import get_tushare_pro
|
||||
pro = get_tushare_pro()
|
||||
|
||||
def get_index_by_name(index_name: str) -> pd.DataFrame:
|
||||
"""
|
||||
通过指数名称查询指数基本信息(使用tushare的index_basic接口)
|
||||
|
||||
Args:
|
||||
index_name (str): 要查询的指数名称(支持模糊匹配,如"上证")
|
||||
|
||||
Returns:
|
||||
pd.DataFrame: 包含查询结果的DataFrame,列包括:
|
||||
- ts_code: 指数代码
|
||||
- name: 指数名称
|
||||
- fullname: 指数全称
|
||||
- market: 市场
|
||||
- publisher: 发布方
|
||||
- index_type: 指数类型
|
||||
- etc.
|
||||
|
||||
Raises:
|
||||
Exception: 当tushare接口调用失败时抛出异常
|
||||
|
||||
Example:
|
||||
>>> df = get_index_by_name("上证50")
|
||||
>>> print(df[['ts_code', 'name']])
|
||||
"""
|
||||
try:
|
||||
# 调用tushare接口查询指数信息
|
||||
df = pro.index_basic(name=index_name)
|
||||
|
||||
# 检查返回结果是否为空
|
||||
if df.empty:
|
||||
print(f"未找到名称包含'{index_name}'的指数")
|
||||
return pd.DataFrame() # 返回空DataFrame保持类型一致
|
||||
|
||||
return df
|
||||
|
||||
except Exception as e:
|
||||
print(f"查询指数信息失败: {str(e)}")
|
||||
return pd.DataFrame()
|
||||
|
||||
def get_index_daily_data(ts_code: str, start_date: str = START_DATE, end_date: str = END_DATE) -> pd.DataFrame:
|
||||
"""
|
||||
通过指数代码查询日线行情数据(合并基本行情和扩展行情)
|
||||
|
||||
Args:
|
||||
ts_code (str): 指数代码(如"000001.SH")
|
||||
start_date (str): 开始日期(格式"YYYYMMDD",默认使用config中的START_DATE)
|
||||
end_date (str): 结束日期(格式"YYYYMMDD",默认使用config中的END_DATE)
|
||||
|
||||
Returns:
|
||||
pd.DataFrame: 合并后的日线行情数据,包含以下列(示例):
|
||||
- ts_code: 指数代码
|
||||
- trade_date: 交易日期
|
||||
- close: 收盘点位
|
||||
- open: 开盘点位
|
||||
- high: 最高点位
|
||||
- low: 最低点位
|
||||
- pe: 市盈率
|
||||
- pb: 市净率
|
||||
- etc.
|
||||
|
||||
Raises:
|
||||
Exception: 当tushare接口调用失败或数据合并失败时抛出异常
|
||||
|
||||
Example:
|
||||
>>> df = get_index_daily_data("000001.SH")
|
||||
>>> print(df[['trade_date', 'close', 'pe']].head())
|
||||
"""
|
||||
try:
|
||||
start_date = date_format_correction(start_date)
|
||||
end_date = date_format_correction(end_date)
|
||||
|
||||
# 1. 查询日线基本行情(核心数据,必须成功)
|
||||
daily_df = pro.index_daily(
|
||||
ts_code=ts_code,
|
||||
start_date=start_date,
|
||||
end_date=end_date,
|
||||
fields="ts_code,trade_date,open,high,low,close,pre_close,change,pct_chg,vol,amount"
|
||||
)
|
||||
if daily_df is None or daily_df.empty:
|
||||
print("未找到指数{}在{}到{}期间的行情数据".format(ts_code, start_date, end_date))
|
||||
return pd.DataFrame()
|
||||
|
||||
# 2. 尝试查询扩展行情(PE/PB 等,需要高权限,失败不阻塞)
|
||||
try:
|
||||
daily_basic_df = pro.index_dailybasic(
|
||||
ts_code=ts_code,
|
||||
start_date=start_date,
|
||||
end_date=end_date,
|
||||
fields="ts_code,trade_date,total_mv,float_mv,pe,pe_ttm,pb,turnover_rate,turnover_rate_f"
|
||||
)
|
||||
if daily_basic_df is not None and not daily_basic_df.empty:
|
||||
daily_df = pd.merge(
|
||||
daily_df, daily_basic_df,
|
||||
on=['ts_code', 'trade_date'],
|
||||
how='left'
|
||||
)
|
||||
except Exception as e:
|
||||
print("index_dailybasic 不可用(权限不足或接口变更): {}".format(e))
|
||||
|
||||
return daily_df
|
||||
|
||||
except Exception as e:
|
||||
print("查询指数日线行情失败: {}".format(e))
|
||||
raise # 抛出而非静默返回空,让 view 层返回错误信息
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 测试指数查询
|
||||
print("测试指数查询:")
|
||||
index_df = get_index_by_name("中证500")
|
||||
if not index_df.empty:
|
||||
print(index_df[['ts_code', 'name']].head())
|
||||
else:
|
||||
print("未查询到指数信息")
|
||||
|
||||
'''# 测试指数行情获取
|
||||
print("\n测试指数日线行情:")
|
||||
test_code = "000016.SH" # 上证50指数代码
|
||||
daily_data = get_index_daily_data(test_code, start_date="20230101", end_date="20231231")
|
||||
|
||||
if not daily_data.empty:
|
||||
print(f"获取到{daily_data.shape[0]}条数据")
|
||||
# 显示关键列的前5行
|
||||
print(daily_data[['trade_date', 'close', 'pe', 'pb']].head())
|
||||
|
||||
# 数据完整性检查
|
||||
print("\n数据完整性检查:")
|
||||
print(daily_data[['close', 'pe']].describe())
|
||||
else:
|
||||
print(f"未获取到指数{test_code}的行情数据")'''
|
||||
Reference in New Issue
Block a user