# analysis **Repository Path**: quant-seminar/analysis ## Basic Information - **Project Name**: analysis - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: dev - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-04-09 - **Last Updated**: 2026-05-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # analysis `analysis` 是 Seminar 项目的分析服务,位于 `data` 数据基座之上。它不直接维护日频行情和因子数据,而是调用 `data` 服务获取 parquet 数据,再完成单因子测试和多因子策略回测,并将结果保存为 pickle 文件供 `card` 服务转换为结构化卡片 JSON。 ## 功能概览 - 单因子测试:基于 DolphinDB `factorBacktest` 模块计算分组收益、IC、Rank IC、显著性和分组回测指标。 - 多因子策略回测:基于 `bt` 包构造选股和调仓策略,输出策略净值、基准净值和换手率。 - 结果持久化:分析结果可保存到 `media/{file_id}.pkl`。 - 媒体下载:通过 `/media/{file_id}` 返回 pickle 二进制内容。 - WebSocket 状态反馈:运行过程中持续向客户端发送参数 schema、运行状态和完成信息。 ## 服务结构 ```text analysis |-- main.py |-- config.py |-- core | |-- routers | | |-- factor | | | |-- views.py | | | `-- single_analysis.py | | |-- backtest | | | |-- views.py | | | `-- factor_strategy.py | | `-- media/views.py | |-- utils | | |-- fetch.py | | |-- ws.py | | |-- ts_api.py | | `-- logging.py | `-- database/session.py `-- pyproject.toml ``` ## 依赖关系 ```text client | | WebSocket v analysis | | POST /stock/daily/query v data | | query / upload / run scripts v DolphinDB analysis -> media/*.pkl -> card ``` `analysis` 依赖以下外部能力: - `data` 服务:查询基础因子、派生因子和预处理后的因子。 - Tushare:获取指数成分股和基准指数行情。 - DolphinDB:运行 `ta`、`factorBacktest` 等分析脚本。 - `bt`:执行多因子策略回测。 - `quantstats`:当前主要由 `card` 服务消费回测结果时计算绩效指标。 ## 配置 服务会加载当前目录和上级目录的 `.env`: ```env PROD=true DOLPHIN_HOST=dolphindb DOLPHIN_PORT=8848 DOLPHIN_USERNAME=admin DOLPHIN_PASSWORD=123456 TUSHARE_TOKEN=... DATA_SERVICE_URL=http://seminar-data:8000 ``` pickle 文件保存目录由 `config.SAVE_DIR` 决定,默认为: ```text analysis/media ``` ## 启动 本地开发: ```bash uv sync uvicorn main:app --host 127.0.0.1 --port 8001 --reload ``` 通过主项目 Docker Compose: ```bash docker compose up --build seminar-analysis ``` 在主项目 `docker-compose.yml` 中,容器端口 `8000` 默认映射到主机端口 `8801`。 ## WebSocket 协议 单因子测试和策略回测都使用相同的 WebSocket 交互模式。 服务端消息格式: ```json { "type": "WAITING_PARAM", "text": "..." } ``` 消息类型: | 类型 | 说明 | | --- | --- | | `WAITING_PARAM` | 服务等待客户端提交参数;`text` 通常是 Pydantic JSON Schema 或参数错误信息 | | `RUNNING` | 任务运行状态 | | `FINISHED` | 任务完成;`text` 是文件 id 或即将发送 bytes 的提示 | | `ERROR` | 任务失败 | 典型流程: 1. 客户端连接 WebSocket。 2. 服务端发送 `WAITING_PARAM` 和参数 schema。 3. 客户端发送参数 JSON。 4. 服务端发送若干 `RUNNING` 状态。 5. 服务端发送 `FINISHED`。 6. 如果结果不保存文件,服务端随后发送 pickle bytes。 7. WebSocket 关闭。 ## 单因子测试 路径: ```text WS /factor/single-analysis ``` 参数模型: | 字段 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | `index_code` | `399300.SZ`, `000852.SH`, `932000.CSI` | `399300.SZ` | 股票池指数代码 | | `period` | `DAILY`, `WEEKLY`, `MONTHLY` | `DAILY` | 调仓或分析频率 | | `derive_factors` | `dict` | 必填 | 派生因子定义,参考 `data` 服务的因子 DSL | | `start_date` | `str` | `2010.01.01` | DolphinDB 分析开始日期 | | `end_date` | `str` | `2026.01.01` | DolphinDB 分析结束日期 | 运行流程: 1. 使用 Tushare `index_weight` 获取指数最新成分股。 2. 从 `derive_factors` 中取最后一个因子名作为目标因子。 3. 调用 `data` 服务查询: - `circ_mv` - `pct_chg_hfq` - `derive_factors` 中定义的目标因子 4. 对目标因子执行 `preprocess`。 5. 查询沪深 300 指数日收益作为 benchmark。 6. 上传数据到 DolphinDB。 7. 调用 `singleFactorAnalysis` 和 `getFactorIc`。 8. 保存结果到 `media/{file_id}.pkl`。 9. WebSocket 返回 `file_id`。 返回 pickle 顶层结构: ```python { "factor_analysis": dict, "ic_analysis": pandas.DataFrame } ``` `factor_analysis` 字段: | 字段 | 类型 | 说明 | | --- | --- | --- | | `title1` | `str` | 分组净值曲线标题 | | `title2` | `str` | 多空收益曲线标题 | | `retTable` | `DataFrame` | 多空收益率和累计多空收益率 | | `timeIndex` | `ndarray` | 时间索引 | | `netValue` | `list` | 分组净值,首个元素通常是 `rows x 10` 数组 | | `backtest` | `DataFrame` | 各分组、H-L、benchmark 的回测指标 | | `icTest` | `dict` | IC 均值、标准差、IR、Rank IC 等统计 | | `retStat` | `dict` | 分组收益显著性统计 | | `groupRet` | `DataFrame` | 各组每日收益和 H-L 收益 | `ic_analysis` 字段: ```text time, IC, Rank_IC ``` ## 多因子策略回测 路径: ```text WS /backtest/factor-strategy ``` 参数模型: | 字段 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | `price_field` | `close`, `close_hfq` | `close` | 回测使用的价格字段 | | `description` | `str` | 必填 | 本次回测说明,通常为 markdown | | `factor_names` | `list[str]` | 必填 | 用于合成策略信号的因子列 | | `derive_factors` | `dict` | 必填 | 派生因子定义 | | `n_select` | `int` | `10` | 每次选取因子值最高的股票数量 | | `rebalance_period` | `周度`, `月度`, `季度`, `年度` | `季度` | 调仓周期 | | `rebalance_method` | `等权重`, `最大夏普`, `风险平价` | `风险平价` | 权重方法 | | `index_code` | `399300.SZ`, `000852.SH`, `932000.CSI` | `399300.SZ` | 股票池指数代码 | | `benchmark_code` | `399300.SZ`, `000852.SH`, `932000.CSI` | `399300.SZ` | 基准指数代码 | | `start_date` | `str` | `2010.01.01` | 回测开始日期 | | `end_date` | `str` | `2026.01.01` | 回测结束日期 | | `save_file` | `bool` | `False` | 是否保存为文件并返回 file id | 运行流程: 1. 使用 Tushare `index_weight` 获取指数最新成分股。 2. 调用 `data` 服务查询价格字段、`circ_mv` 和 `derive_factors`。 3. 对 `factor_names` 执行 `preprocess`。 4. 将多个因子合成为一个 `factor` 信号。 5. 使用 `bt` 构造策略: - 按设定周期运行调仓。 - 使用最近可用因子截面选出前 `n_select` 只股票。 - 按等权、最大夏普或风险平价生成权重。 - 执行再平衡。 6. 获取基准指数净值。 7. 输出策略净值、基准净值和换手率。 返回 pickle 顶层结构: ```python { "description": str, "values": pandas.DataFrame } ``` `values` 使用 `DatetimeIndex`,列为: | 字段 | 说明 | | --- | --- | | `benchmark` | 基准净值序列 | | `strategy` | 策略净值序列 | | `turnover` | 换手率序列 | 当 `save_file=false` 时,WebSocket 会直接发送 pickle bytes。当 `save_file=true` 时,结果保存到 `media/{file_id}.pkl`,WebSocket 返回 `file_id`。 ## 媒体文件接口 路径: ```text GET /media/{file_id} ``` 读取 `media/{file_id}.pkl` 并返回: ```text Content-Type: application/octet-stream ``` 如果文件不存在,返回 `404`。 ## 与 card 服务的关系 `card` 服务负责把 pickle 结果转换为飞书卡片所需的结构化 JSON。 对应关系: | analysis 输出 | card 入口 | card 消费字段 | | --- | --- | --- | | 单因子测试 pkl | `/single-factor-analysis` | `factor_analysis`, `ic_analysis` | | 多因子策略回测 pkl | `/factor-strategy-backtest` | `description`, `values` | 单因子卡片会提取 IC 统计、分组收益、IC 曲线、多空收益曲线、分组净值曲线和回测表格。 策略回测卡片会基于 `values` 重新计算累计收益、CAGR、夏普、最大回撤、波动率、Calmar、滚动夏普、滚动 beta、回撤详情等指标。 ## 注意事项 - `derive_factors` 的结构由 `data` 服务定义,完整说明见 `data` 服务 `/stock/daily/metadata` 返回的 `instruct`。 - 单因子测试当前使用 `derive_factors` 中最后一个因子作为目标因子。 - 单因子测试会固定查询 `circ_mv` 和 `pct_chg_hfq`,其中 `circ_mv` 用于预处理和市值加权,`pct_chg_hfq` 用作收益率。 - 多因子回测会对 `factor_names` 执行预处理后合成一个总因子。 - `start_date` 和 `end_date` 在 `analysis` 内部部分场景使用 `YYYY.MM.DD`,调用 `data` 服务时会转换为 `YYYY-MM-DD`。 - `media` 下的 pkl 是跨服务契约的一部分,修改结构时需要同步更新 `card` 服务。