# 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-07-12 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # analysis `analysis` 是 Seminar 项目的分析服务,位于 `data` 数据基座之上。它通过 WebSocket 接收研究参数, 调用 `data` 服务获取 parquet 数据,执行因子分析或策略回测,并将结果保存为 `media/{report_id}.parquet`。 ## 功能概览 - `single factor analysis`:单因子分析,一次运行同时输出因子分析结果和单因子回测结果。 - `multi factor strategy`:多因子策略回测,按多个因子合成选股信号并输出与单因子回测一致的回测结构。 - `condition select strategy`:条件选股回测,构造选股条件字段和排序字段,每期选择满足条件且排序最高的股票。 - `specify select strategy`:自主选股回测,对用户给定股票列表按手动权重或自动权重持有。 - 媒体文件:所有分析结果保存为 parquet,通过 `/media/{report_id}` 下载。 - WebSocket 状态反馈:运行过程中发送参数 schema、进度、完成报告 id 或错误信息。 ## 服务结构 ```text analysis |-- main.py |-- config.py |-- core | |-- routers | | |-- factor | | | |-- views.py | | | `-- single_factor_analysis.py | | |-- backtest | | | |-- views.py | | | |-- multi_factor_strategy.py | | | |-- condition_select_strategy.py | | | `-- specify_select_strategy.py | | `-- media/views.py | |-- utils | | |-- fetch.py | | |-- ws.py | | |-- ts_api.py | | `-- logging.py | `-- database/session.py `-- pyproject.toml ``` ## 依赖关系 ```text client / arena-backend | | WebSocket v analysis | | POST /stock/daily/query v data | v DolphinDB analysis -> media/*.parquet -> arena-backend ``` `analysis` 依赖: - `data` 服务:查询基础因子、派生因子和预处理后的因子。 - DolphinDB:通过 `use factor` 和 `use backtest` 加载因子分析、策略回测模块函数。 - Tushare:获取基准指数行情。 ## 配置 服务会加载当前目录和上级目录的 `.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 ``` parquet 文件保存目录由 `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 协议 服务端消息格式由 `core.utils.ws.MessageType` 控制: ```json { "type": "RUNNING", "text": "获取数据中..." } ``` 常见消息类型: | 类型 | 说明 | | --- | --- | | `WAITING_PARAM` | 服务等待客户端提交参数,`text` 通常是 Pydantic JSON Schema 或参数错误信息 | | `RUNNING` | 任务运行进度 | | `FINISHED` | 任务完成,`text` 是 `report_id` | | `ERROR` | 任务失败,`text` 是错误摘要 | 典型流程: 1. 客户端连接 WebSocket。 2. 服务端发送 `WAITING_PARAM` 和参数 schema。 3. 客户端发送参数 JSON。 4. 服务端发送若干 `RUNNING` 状态。 5. 服务端发送 `FINISHED`,`text` 为报告 id。 6. 服务端关闭连接。 ## 通用回测参数 以下参数由所有回测入口统一继承,并原样传给 DolphinDB `runBacktest`: | 字段 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | `initial_capital` | `float` | `1000000` | 初始资金,必须大于 0 | | `buy_fee_rate` | `float` | `0.0003` | 买入手续费率,小数形式,即 0.03% | | `sell_fee_rate` | `float` | `0.0013` | 卖出手续费率,小数形式,即 0.13% | | `minimum_fee` | `float` | `5` | 单笔最低手续费 | | `slippage_rate` | `float` | `0` | 滑点率,小数形式 | | `lot_size` | `int` | `100` | 每手股数,必须为非负整数;0 表示不按整手取整 | 这些参数适用于单因子策略、多因子策略、条件选股策略和自选股策略。 ## Single Factor Analysis 路径: ```text WS /factor/single-factor-analysis ``` 参数模型: | 字段 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | `start_date` | `str` | `2020.01.01` | 分析开始日期 | | `end_date` | `str` | `2026.01.01` | 分析结束日期 | | `rf` | `float` | `0.0` | 无风险利率 | | `index_code` | `000016.SH`, `000300.SH`, `000905.SH`, `000852.SH` | `000300.SH` | 股票池指数代码 | | `benchmark_code` | `000016.SH`, `000300.SH`, `000905.SH`, `000852.SH` | `000300.SH` | 参考基准 | | `derive_factors` | `dict` | 必填 | 用户构造因子,结构见 `data` 服务 `/stock/daily/metadata` | | `n_groups` | `int` | `5` | 因子分组数 | | `n_select` | `int` | `10` | 单因子回测每期选择股票数量 | | `max_lags` | `int` | `10` | 生成 `ret0` 到 `ret{max_lags-1}` 的未来相邻收益,用于 IC 衰减分析 | | `drop_st` | `bool` | `true` | 是否按 `data` 服务规则剔除 ST 股票 | | `price_field` | `close`, `close_hfq` | `close_hfq` | forward return 和回测价格字段 | | `rebalance_period` | `DAILY`, `WEEKLY`, `MONTHLY`, `QUARTERLY` | `MONTHLY` | 回测调仓周期 | 运行流程: 1. 使用 `data` 的历史指数成分能力获取每日股票池。 2. 从 `derive_factors` 中取最后一个因子名作为目标因子。 3. 调用 `data` 查询价格、市值、行业、估值字段、目标因子和 `ret0..retN` future return。 4. 上传因子样本到 DolphinDB,调用 `factor` 模块生成 IC 表和分组收益表。 5. 基于 DolphinDB 返回的预处理因子表和分组收益表计算 MSCI 风格历史拥挤度。 6. 上传价格宽表到 DolphinDB,调用 `backtest` 模块生成单因子策略回测表。 7. 将 IC、分组收益、拥挤度、回测结果按交易日拼成一张 parquet 表并返回 `report_id`。 返回 parquet 按交易日建立索引,列包括 `ret{lag}_ic`、`ret{lag}_rank_ic`、 `ret{lag}_group{n}`、`valuation_spread`、`intra_group_correlation`、`factor_relative_volatility`、 `factor_return_zscore`、`crowding`、`net_value`、`turnover`、`benchmark_net_value`,以及 DolphinDB 回测表中的费用和现金。股票持仓压缩为 `positions` 嵌套列,每个元素包含 `code`、`share`、 `price` 和 `market_value`,不再保留每只股票的空持仓宽列。 ## Multi Factor Strategy 路径: ```text WS /backtest/multi-factor-strategy ``` 参数模型: | 字段 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | `price_field` | `close`, `close_hfq` | `close` | 回测价格字段 | | `factor_names` | `list[str]` | 必填 | 参与合成策略信号的最终因子名 | | `derive_factors` | `dict` | 必填 | 多个因子的构造定义 | | `n_select` | `int` | `10` | 每期选择股票数量 | | `rebalance_period` | `周度`, `月度`, `季度`, `年度` | `季度` | 调仓周期 | | `rebalance_method` | `等权重`, `最大夏普`, `风险平价` | `风险平价` | 权重方法 | | `index_code` | `000016.SH`, `000300.SH`, `000905.SH`, `000852.SH` | `000300.SH` | 股票池指数代码 | | `benchmark_code` | `000016.SH`, `000300.SH`, `000905.SH`, `000852.SH` | `000300.SH` | 参考基准 | | `start_date` | `str` | `2010.01.01` | 回测开始日期 | | `end_date` | `str` | `2026.01.01` | 回测结束日期 | 运行流程: 1. 使用 `data` 的历史指数成分能力获取每日股票池。 2. 调用 `data` 查询价格字段和 `derive_factors`。 3. 对 `factor_names` 执行预处理。 4. 将多个因子求和合成为 `factor` 信号。 5. 调用 DolphinDB `backtest` 模块按调仓周期和权重方法执行策略回测。 6. 查询基准指数净值。 7. 输出与单因子回测一致的回测 DataFrame。 8. 保存 parquet 并返回 `report_id`。 返回 parquet 是一个 DataFrame,列为: | 字段 | 说明 | | --- | --- | | `time` | 日期 | | `net_value` | 策略净值 | | `turnover` | 换手率 | | `benchmark_net_value` | 基准净值 | 这个结构与 single factor analysis 中 `backtest` 字段保持一致,便于 Arena 和其它展示层复用同一套回测图表与指标计算。 ## Condition Select Strategy 路径: ```text WS /backtest/condition-select-strategy ``` 参数模型: | 字段 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | `price_field` | `close`, `close_hfq` | `close` | 回测价格字段 | | `condition_field` | `str` | `signal` | 选股条件字段,布尔值或数值大于 0 表示入选 | | `sort_field` | `str` | `factor` | 排序字段 | | `derive_factors` | `dict` | `{}` | 构造选股条件字段与排序字段的派生因子定义 | | `n_select` | `int` | `10` | 每期选择满足条件且排序最高的股票数量 | | `sort_ascending` | `bool` | `false` | 是否按排序字段升序选择,默认降序选择最高值 | | `rebalance_period` | `日度`, `周度`, `月度`, `季度`, `年度` | `日度` | 调仓周期 | | `rebalance_method` | `等权重`, `最大夏普`, `风险平价` | `风险平价` | 权重方法 | | `index_code` | `000016.SH`, `000300.SH`, `000905.SH`, `000852.SH` | `000300.SH` | 股票池指数代码 | | `benchmark_code` | `000016.SH`, `000300.SH`, `000905.SH`, `000852.SH` | `000300.SH` | 参考基准 | | `start_date` | `str` | `2010.01.01` | 回测开始日期 | | `end_date` | `str` | `2026.01.01` | 回测结束日期 | 运行流程: 1. 使用 `data` 的历史指数成分能力获取每日股票池。 2. 调用 `data` 查询价格字段,并根据 `derive_factors` 构造 `condition_field` 和 `sort_field`。 3. 每个调仓日只使用当前日期之前最近一次可见的条件与排序字段。 4. 过滤满足 `condition_field` 的股票,并按 `sort_field` 排序选择前 `n_select` 只。 5. 调用 DolphinDB `backtest` 模块按调仓周期和权重方法执行策略回测。 6. 查询基准指数净值。 7. 输出与单因子回测一致的回测 DataFrame。 8. 保存 parquet 并返回 `report_id`。 返回 parquet 是一个 DataFrame,列为: | 字段 | 说明 | | --- | --- | | `time` | 日期 | | `net_value` | 策略净值 | | `turnover` | 换手率 | | `benchmark_net_value` | 基准净值 | ## Specify Select Strategy 路径: ```text WS /backtest/specify-select-strategy ``` 参数模型: | 字段 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | `price_field` | `close`, `close_hfq` | `close_hfq` | 回测价格字段 | | `stocks` | `list[str]` | 必填 | 自选股票列表 | | `auto_weight` | `bool` | `true` | 是否使用自动权重 | | `stock_weights` | `list[{code, weight}]` | `[]` | 手动权重配置,`auto_weight=false` 时必填 | | `rebalance_period` | `日度`, `周度`, `月度`, `季度`, `年度` | `月度` | 调仓周期 | | `rebalance_method` | `等权重`, `最大夏普`, `风险平价` | `等权重` | 自动权重方法 | | `benchmark_code` | `000016.SH`, `000300.SH`, `000905.SH`, `000852.SH` | `000300.SH` | 参考基准 | | `start_date` | `str` | `2010.01.01` | 回测开始日期 | | `end_date` | `str` | `2026.01.01` | 回测结束日期 | 运行流程: 1. 调用 `data` 查询自选股票的价格字段。 2. 每个调仓日保留最近 3 个月价格完整、且上一交易日价格可用的自选股票。 3. `auto_weight=true` 时,使用 `rebalance_method` 指定的自动权重方法。 4. `auto_weight=false` 时,使用 `stock_weights`,并对当前实际可持有股票重新归一化。 5. 调用 DolphinDB `backtest` 模块按调仓周期执行策略回测。 6. 查询基准指数净值。 7. 输出与单因子回测一致的回测 DataFrame。 8. 保存 parquet 并返回 `report_id`。 返回 parquet 是一个 DataFrame,列为: | 字段 | 说明 | | --- | --- | | `time` | 日期 | | `net_value` | 策略净值 | | `turnover` | 换手率 | | `benchmark_net_value` | 基准净值 | ## 策略推荐接口 三个策略提供独立的最新推荐持仓接口: ```text POST /backtest/multi-factor-strategy/recommend POST /backtest/condition-select-strategy/recommend POST /backtest/specify-select-strategy/recommend ``` 接口自动查询截至当前日期的最新可用交易数据,找到最近一次调仓日,并复用对应策略的选股、 股票资格检查和权重计算逻辑。返回值直接是 `code -> weight` JSON;没有合格股票时返回空对象。 ```json { "600941.SH": 0.25, "601336.SH": 0.25, "000001.SZ": 0.5 } ``` 多因子推荐接收 `price_field`、`factor_names`、`derive_factors`、`n_select`、 `rebalance_period`、`rebalance_method`、`index_code` 和 `start_date`。 条件选股推荐接收 `price_field`、`condition_field`、`sort_field`、`derive_factors`、 `n_select`、`sort_ascending`、`rebalance_period`、`rebalance_method`、`index_code` 和 `start_date`。 自选股推荐接收 `price_field`、`stocks`、`auto_weight`、`stock_weights`、 `rebalance_period`、`rebalance_method` 和 `start_date`。`auto_weight=false` 时必须提供 `stock_weights`。 推荐持仓只计算目标权重,因此不接收初始资金、手续费、滑点、整手、基准或结束日期参数。 ## 媒体文件接口 路径: ```text GET /media/{report_id} ``` 读取 `media/{report_id}.parquet` 并返回: ```text Content-Type: application/vnd.apache.parquet ``` 如果文件不存在,返回 `404`。 ## 与 data 的契约 - `derive_factors` 的结构由 `data` 服务定义,完整说明见 `/stock/daily/metadata` 返回的 `instruct`。 - `data` 会根据命名派生因子依赖自动确定计算顺序;`analysis` 不应依赖 JSON key 顺序。 - 单因子分析使用 `derive_factors` 中最后一个 key 作为目标因子。 - 多因子策略使用 `factor_names` 明确声明哪些派生列是最终参与策略的因子,中间构造列不应放入 `factor_names`。 - 条件选股策略使用 `condition_field` 和 `sort_field` 明确声明最终参与选股的字段,二者可以来自 `derive_factors` 或基础因子。 ## 与 Arena 的关系 - Arena 后端从 `/media/{report_id}` 读取 parquet,抽取并保存列表 metrics;报告接口直接转发 parquet 二进制。 - Arena 前端在 Web Worker 中解析 parquet,按列名前缀还原逻辑表,再计算派生指标和渲染图表。 - parquet 列名、嵌套持仓结构和前端派生指标逻辑是跨服务契约,修改前应同步更新 README、Arena 解析器和相关测试。 ## 注意事项 - 日期入参在 `analysis` 中使用 `YYYY.MM.DD`,调用 `data` 服务时会转换为 `YYYY-MM-DD`。 - 单因子分析中的目标因子会在测试前由 `data` 做行业中性化、去极值、标准化等预处理。 - 多因子策略的 `factor_names` 只应包含最终因子,不应包含中间构造字段。 - `media` 下 parquet 是运行生成物,通常不提交到 Git。