diff --git a/.obsidian/workspace.json b/.obsidian/workspace.json index c44c8aa..309833e 100644 --- a/.obsidian/workspace.json +++ b/.obsidian/workspace.json @@ -13,12 +13,12 @@ "state": { "type": "markdown", "state": { - "file": "FleetingNotes/用工管理平台/未命名.md", + "file": "FleetingNotes/GridSeeker/数据构建过程.md", "mode": "source", "source": false }, "icon": "lucide-file", - "title": "未命名" + "title": "数据构建过程" } } ] @@ -209,10 +209,12 @@ "components:AI 对话(新标签页)": false } }, - "active": "524297c86c58320c", + "active": "a2bf9b96c388dec4", "lastOpenFiles": [ - "FleetingNotes/未命名", + "FleetingNotes/GridSeeker/版本进程.md", + "FleetingNotes/GridSeeker/数据构建过程.md", "FleetingNotes/用工管理平台/未命名.md", + "FleetingNotes/GridSeeker", "FleetingNotes/用工管理平台", "FleetingNotes/其他项目/量化工具/缠论研习社/外部接口.md", "settings/archived/公司工作/资源汇总/创医元公司信息.md", @@ -250,7 +252,6 @@ "FleetingNotes/护理平台/产品逻辑概要设计.canvas", "FleetingNotes/护理平台/阶段规划图/第一阶段功能模块图.excalidraw.md", "FleetingNotes/护理平台/阶段规划图/第三阶段功能模块图.excalidraw.md", - "FleetingNotes/护理平台/阶段规划图/第二阶段功能模块图.excalidraw.md", "FleetingNotes/大健康商城/商城平台订货收款功能.canvas", "FleetingNotes/大健康商城/版本规划.canvas", "FleetingNotes/其他项目/亲子时光/界面功能与接口.canvas", @@ -265,7 +266,6 @@ "settings/archived/attachments/Pasted image 20220610010324.png", "settings/archived/attachments/Pasted image 20220609234642.png", "settings/components/公司账户管理表.components", - "settings/components/tasks-trace.components", - "settings/components/20250123101427.components" + "settings/components/tasks-trace.components" ] } \ No newline at end of file diff --git a/FleetingNotes/GridSeeker/数据构建过程.md b/FleetingNotes/GridSeeker/数据构建过程.md new file mode 100644 index 0000000..12897c7 --- /dev/null +++ b/FleetingNotes/GridSeeker/数据构建过程.md @@ -0,0 +1,252 @@ +# v6.4 训练数据从零构建完整指南 + +本文档结合项目从 v3.0 至 v6.4 的全部历史版本,梳理训练数据的完整构建逻辑,并给出从原始行情数据出发,**不依赖任何已有训练文件**重建全套训练样本的标准流程。 + +--- + +## 1. 历史版本数据演化脉络 + +### 1.1 关键节点 + +| 版本 | 数据核心变化 | 对后续的影响 | +|:---|:---|:---| +| v3.0 之前 | 逐日价格命中入样(收盘价在 `[7,10]` 即采样) | 被废弃 | +| v3.0 ~ v3.2 | **股票级长期过滤 + 全历史滑窗** | 奠定主训练框架,沿用至今 | +| v3.3 ~ v3.6 | 特征消融与增强(34 基础特征定型) | 特征体系成形 | +| v4.0 ~ v4.4 | 引入 `period_id` 用于 Top 标签构造 | 标签更公平 | +| v5.0 | 主训练帧固化(`v5.0_training_frame.parquet`) | v5.1 ~ v6.4 全部依赖此帧 | +| v6.3 share-fix | 重算 4 个 `total_share` 相关特征,产出 `share_fixed_training_frame.parquet` | v6.4 直接使用 | +| v6.4 | 复用 v6.3 训练样本,仅新增 Meta Ranker | 当前生产基线 | + +### 1.2 核心继承关系 + +``` +v3.0 样本构造逻辑 (长期过滤+滑窗) + └── v5.0 首次生成主训练帧 + └── v5.1/v5.2/v5.3 复用同一样本,追加特征 + └── v6.3 share-fix 修复股本特征 + └── v6.4 直接使用 (share_fixed_training_frame.parquet) +``` + +> **结论**:v6.4 的训练样本本质上是 v5.0 时代首次生成的,之后只在同一样本上追加或修正特征,**从未重建过样本集**。 + +--- + +## 2. 构建概览 + +重建 v6.4 训练数据需要严格按照以下步骤: + +1. 准备原始数据(K线、股本、市场情绪、指数) +2. 对全市场股票进行**股票级长期过滤**(`batch_filter`) +3. 对通过过滤的股票进行**全历史滑窗采样**(窗口 120 天,步长 20 天) +4. 计算多维特征(基础、负向、独立性、行业、情绪) +5. 计算标签(`y_rounds`:未来 60 天网格轮回数) +6. 合并输出为单个 Parquet 文件 + +下面逐一展开。 + +--- + +## 3. 数据准备 + +### 3.1 原始数据清单 + +| 数据 | 时间范围 | 股票范围 | 必要字段 | +|:---|:---|:---|:---| +| 个股日 K 线 | **≥ 2018‑01‑01** ~ 2026‑04‑30 | 沪市主板(600/601/603/605)
深市主板(000/001/002/003)
创业板(300/301) | `date`, `open`, `high`, `low`, `close`, `volume` | +| 股本数据 | 最新快照 | 全市场 | `total_share` | +| 全市场涨跌比 | 2018‑01‑01 ~ 2026‑04‑30 | — | `date`, `advance_ratio` | +| 沪深 300 指数日线 | 2018‑01‑01 ~ 2026‑04‑30 | — | `date`, `open`, `high`, `low`, `close` | +| 中证 500 指数日线 | 2018‑01‑01 ~ 2026‑04‑30 | — | `date`, `open`, `high`, `low`, `close` | +| 中证 1000 指数日线 | 2018‑01‑01 ~ 2026‑04‑30 | — | `date`, `open`, `high`, `low`, `close` | + +### 3.2 K 线清洗规则 + +- 删除 `open`、`high`、`low`、`close`、`volume` 中存在 NaN 的行。 +- 删除 `open`、`high`、`low`、`close` ≤ 0 的行。 +- 删除 `high < max(open, low, close)` 或 `low > min(open, high, close)` 的异常行。 +- 按 `date` 升序排序,重复日期保留最后一条。 +- 重置索引。 + +### 3.3 股本数据处理 + +- 从股本快照中读取每只股票最新的 `total_share`(总股本,单位:亿股)。 +- 提供映射字典 `{stock_code: total_share}`,用于计算市值相关特征。 + +### 3.4 市场情绪与指数数据 + +- 全市场涨跌比用于计算 4 个宽松情绪因子(`relaxed_emotion`)。 +- 沪深 300、中证 500、中证 1000 指数日线用于计算独立性特征(振幅独特性等)。 + +--- + +## 4. 股票级长期过滤 (batch_filter) + +### 4.1 过滤函数签名 + +``` +batch_filter(stock_data_dict, + grid_lower=1, + grid_upper=11, + price_upper=14, + lookback=180, + ratio_threshold=0.5) +``` + +### 4.2 四个必须同时满足的条件 + +1. **最新收盘价** ∈ `[1, 14]` 元 + (低于 1 元有退市风险,高于 14 元远离网格上界 11 元,不纳入训练) + +2. **过去 180 天至少有一天收盘价** ∈ `[1, 11]` 元 + (保证该股票曾踏入网格区间) + +3. **过去 180 天收盘价在 `[1, 11]` 内的天数占比 ≥ 50%** + (排除偶尔路过网格的股票,保留长期在区间内活动的标的) + +4. **非 ST、上市满 180 天** + (剔除风险警示股和次新股) + +### 4.3 过滤后预期 + +- 历史经验:在 2018‑2026 年全市场数据上,通过过滤的股票数约为 **1,500 ~ 1,800 只**。 + +--- + +## 5. 全历史滑窗采样 + +### 5.1 窗口参数 + +| 参数 | 值 | 说明 | +|:---|:---|:---| +| 观察窗口 | **120** 个交易日 | 用于计算特征 | +| 标签窗口 | **60** 个交易日 | 紧随观察窗口之后,用于计算标签 | +| 滑动步长 | **20** 个交易日 | 每个位置生成一个样本 | +| `period_id` | `start // 60` | 用于同一时期内 Top 标签的相对排名 | + +### 5.2 采样流程 + +对每只通过过滤的股票,从其 K 线数据第 `0` 天开始,以步长 20 天滑动: + +```python +max_start = len(df) - 120 - 60 +for start in range(0, max_start + 1, 20): + obs_window = df[start : start + 120] + future_window = df[start + 120 : start + 120 + 60] + period_id = start // 60 + # 计算特征、标签... +``` + +--- + +## 6. 特征计算 + +### 6.1 基础特征(34 维) + +调用 `calculate_features(obs_window, total_share=..., feature_version='v3.3')`,包括: + +- **价格波动类**:`price_cv`, `volatility_20d`, `avg_daily_amp`, `atr_pct`, `bb_width`, `amplitude_cv` 等 +- **成交量与资金类**:`amount_mean_20d`, `amount_cv_20d`, `turnover_proxy_20d`, `volume_ratio`, `obv_slope`, `liquidity_drying_up_20d` +- **趋势与位置类**:`trend_slope_60d`, `trend_slope_20d`, `trend_abs_slope_20d`, `drawdown_60d`, `range_position_60d`, `intraday_trend_strength` +- **网格结构类**:`grid_room_balance`, `grid_touch_count_60d`, `dist_to_grid_upper`, `dist_to_grid_lower`, `cross_freq_x_bb` +- **市值类**:`ln_float_mv`, `mv_vol_interact`, `small_cap_premium`, `amplitude_uniqueness_20d`(需要 `total_share`) + +### 6.2 负向特征 + +调用 `calculate_negative_features(obs_window)`。 + +### 6.3 市场独立性特征 + +调用 `calculate_independence_features(obs_window)`,基于沪深 300 指数计算。 + +### 6.4 行业独立性特征 + +调用 `calculate_sector_independence_features(obs_window)`。 + +### 6.5 宽松情绪特征(4 维) + +调用 `calculate_relaxed_emotion_features(emotion_window, market_regime_data)`。 + +**⚠️ 关键约束**:情绪特征的历史窗口必须为 **180 天**,而非观察窗口的 120 天。 + +正确做法: +```python +# 从观察窗口结束日向前回溯 180 天作为情绪窗口 +hist_end = start + 120 +hist_start = max(0, hist_end - 180) +emotion_window = df[hist_start : hist_end] +``` + +--- + +## 7. 标签计算 + +**v6.4 使用 `y_rounds`**(未来 60 天网格匹配轮回数)。 + +调用 `calc_grid_rounds(future_window, grids=[1,2,...,11])`,模拟网格交易(基准价 10 元,每格 200 股,LIFO),统计有效轮回次数。 + +> **注意**:v6.4 的标签是轮回数,不是利润。若需切换到收益导向标签(v7.0),请使用 `total_return_60d`(已实现利润 + 期末持仓市值)。 + +--- + +## 8. 最终输出 + +每条样本包含以下字段: + +| 字段 | 说明 | +|:---|:---| +| `stock_code` | 股票代码 | +| `obs_start` | 观察窗口开始日期 | +| `obs_end` | 观察窗口结束日期 | +| `future_start` | 标签窗口开始日期 | +| `future_end` | 标签窗口结束日期 | +| `period_id` | 时期 ID(`start // 60`) | +| 34 基础特征 | 如 `price_cv` 等 | +| 负向特征 | 如 `trend_consistency_20d` 等 | +| 市场独立性特征 | 如 `amplitude_uniqueness_20d` 等 | +| 行业独立性特征 | 如 `sector_amplitude_deviation_20d` 等 | +| 4 情绪特征 | `relaxed_panic_amplification_ratio` 等 | +| `y_rounds` | 标签(网格匹配轮回数) | + +输出格式:**单个 Parquet 文件**,约 21 万条样本,覆盖 1,500 ~ 1,800 只股票。 + +--- + +## 9. 关键约束与常见错误 + +| 约束 | 正确值 | 常见错误 | +|:---|:---|:---| +| K 线时间范围 | **≥ 2018‑01‑01** | 从 2020 年开始 → 过滤后股票数锐减 | +| 股票范围 | 沪深主板 + 创业板 | 仅 600 开头 → 过滤后股票数不足 | +| 观察窗口 | 120 天 | — | +| 标签窗口 | 60 天 | — | +| 滑窗步长 | 20 天 | — | +| 情绪特征历史窗 | **180 天** | 错误使用 120 天 → 情绪因子值偏移 | +| `batch_filter` 的 `ratio_threshold` | **0.5** | 0.3 会引入偶尔路过的股票 | +| `batch_filter` 的 `price_upper` | **14** | 提高到 18 会增加高价股,但匹配度下降 | +| 标签 | `y_rounds`(轮回数) | 改用利润标签会改变模型行为 | + +--- + +## 10. 如果数据源暂未就绪 + +**务实方案**:直接复用 v6.3 的 `share_fixed_training_frame.parquet`(211,976 条,1,799 只股票),然后在其上追加计算 v7.0 所需的 `total_return_60d` 标签和新特征。 + +此方案的优势: +- 保留 v6.3 已验证的样本规模和股票覆盖 +- 避免从零重建的复杂性和潜在偏差 +- 可快速启动收益导向实验 + +待全市场数据(2018‑2026)完全就绪后,再按本文档启动完整的从零重建。 + +--- + +## 11. 与 v7.0 的关系 + +v7.0 的训练数据构建流程与 v6.4 **完全一致**,差异仅在: + +- 标签从 `y_rounds` 改为 `total_return_60d` +- 新增 2 个规模中性化特征(`amount_to_mv_ratio`、`obv_slope_to_mv`) +- 新增 3 个指数独立性特征(基于沪深 300、中证 500、中证 1000) + +若数据源已就绪,可以直接按 v7.0 的标签和特征一步到位生成训练样本,无需先重建 v6.4 再修改。 \ No newline at end of file diff --git a/FleetingNotes/GridSeeker/版本进程.md b/FleetingNotes/GridSeeker/版本进程.md new file mode 100644 index 0000000..81a7842 --- /dev/null +++ b/FleetingNotes/GridSeeker/版本进程.md @@ -0,0 +1,207 @@ +好的,我把从项目启动到现在的全部版本迭代、核心发现和关键转折点,按时间线梳理清楚。 + +--- + +# 网格交易选股模型 — 全版本历史总结 + +## 第一阶段:原型搭建(v1.0 ~ v3.6) + +### v1.0:从零开始 +**核心目标**:验证“用机器学习预测网格匹配次数”是否可行。 + +**做了什么**: +- 用 180 天沪深主板个股历史数据,按 [1,2,...,11] 元网格模拟交易 +- 计算每只股票在历史区间内的网格成交次数作为标签 +- 用随机森林(RandomForestRegressor)训练,预测“未来 60 天匹配次数” +- 在 278 只股票上做了初步验证 + +**关键发现**:机器学习预测网格匹配次数是可行的。但 278 只股票的样本量太小,模型泛化能力有限。 + +--- + +### v2.0 ~ v2.1.1:扩大规模 + 引入市值因子 +**核心目标**:从 278 只扩展到全市场 1404 只,验证策略在全市场是否成立。 + +**做了什么**: +- 扩展到全市场股票(5~15 元区间),训练样本约 30,000 条 +- 引入 3 个市值因子(流通市值对数、市值波动交互、小市值溢价) +- 在模型协同上做了第一次尝试:把 Rank 模型的预测值作为 Top 模型的输入特征 + +**关键发现**: +- 市值因子有效——小市值股票确实更有弹性,触发网格的概率更高 +- “让 Top 站在 Rank 肩膀上”这个协同思路第一次被验证 + +--- + +### v3.0 ~ v3.6:特征消融与精简 +**核心目标**:从 36 个特征逐步消融,找到最精简有效的特征集。 + +**做了什么**: +- 每轮消融删除重要性最低的几个特征,看 Spearman 是否下降 +- 引入负向指标(流动性枯竭、价格呆滞等),让模型学会“识别不适合网格的标的” +- 最终精简到 34 维基础特征,Spearman 稳定在 0.53 附近 + +**关键发现**: +- 特征不是越多越好。34 维中最后 6 个重要性极低的特征被删除后,Spearman 反而微升 +- 负向指标中只有“流动性枯竭”被模型充分吸收,其他几个效果有限 + +--- + +## 第二阶段:架构升级(v4.0 ~ v5.4) + +### v4.0 ~ v4.1:三模型协同架构确立 +**核心目标**:从单模型升级为 Rank → Top → Stacking 三层协同。 + +**做了什么**: +- **Rank(回归)**:全市场排序,预测匹配次数 +- **Top(分类)**:识别头部 5% 的特等契合标的 +- **Stacking(融合)**:综合 Rank 和 Top 的输出,产出最终评分 +- Top 模型的训练标签从“全市场 P95”改为“同 period 内 P95”,更公平 + +**关键发现**: +- 三层协同比单模型显著提升——Top 模型 PR-AUC 0.34,命中率 100% +- Stacking 层能有效融合两个上游信号 + +--- + +### v5.0 ~ v5.3:情绪因子探索 +**核心目标**:引入恐慌/贪婪情绪因子,让模型感知市场环境。 + +**做了什么**: +- 构造恐慌期弹性因子(恐慌日振幅放大比、反弹强度) +- 构造贪婪期独立因子(贪婪日相对涨幅、振幅比) +- 多次调整阈值(从极端阈值放宽到温和阈值) + +**关键发现**: +- 情绪因子对 Rank 有正向贡献(Spearman 从 0.50 提到 0.53) +- 但对 Top 模型始终没有产生增益——Top 做的是头部精选,情绪信号在头部样本上的区分度不够 +- **教训**:情绪因子更适合做负向过滤(识别“该淘汰的”),不适合做正向精选(识别“该买的”) + +--- + +### v5.4-E:模型协同的突破 +**核心目标**:让 Top 模型真正受益于 Rank 的排序信号。 + +**做了什么**: +- 把 Rank 模型的预测值(`rank_predicted_rounds`)作为 Top 模型的第 35 维输入特征 +- 分层标签 + 头部权重训练 Top 模型 + +**关键发现**: +- 这是 v5.x 系列最重要的突破——Top PR-AUC 从 0.30 提升到 0.33 +- “让 Top 站在 Rank 肩膀上”被反复验证有效 + +--- + +## 第三阶段:交易系统化(v6.0 ~ v6.3) + +### v6.0 ~ v6.1:Stacking 融合 + 知识蒸馏 +**核心目标**:用一个模型统一 Rank 和 Top 的能力。 + +**做了什么**: +- 尝试用 MLP 多任务学习同时做回归和分类(v6.0,失败) +- 尝试用知识蒸馏让 MLP 学习 Teacher 模型(v6.1,效果不如 LightGBM) + +**关键发现**: +- **MLP 在表格数据上不如 LightGBM**——这是被反复验证的教训 +- 之后不再尝试深度学习替代树模型 + +--- + +### v6.2 ~ v6.3:全系统收敛 +**核心目标**:把最优特征集、最优模型架构、最优参数固化。 + +**做了什么**: +- 修复 total_share 数据源(4 个特征之前因为数据缺失被填 0,修复后恢复正常) +- 回测收益 148%,夏普 1.74,最大回撤 -19.78% +- v6.3 被确立为生产基线 + +**关键发现**: +- v6.3 的生产基线是在“旧规则训练数据(9.0-9.8)+ 三模型协同”这个体系下被验证稳定的 + +--- + +## 第四阶段:风控与仓位管理(v6.4 ~ v6.5) + +### v6.4:Meta Ranker 的诞生 +**核心目标**:用利润预测替代价格一刀切规则。 + +**做了什么**: +- 在 Stacking 之上新增 Meta Ranker:输入价格 + Stacking 评分 + Rank 预测轮数,输出预测利润 +- 跑 720 种参数组合的规则探索,找到最优配置 +- 训练样本 1288 条,Spearman 0.77 + +**关键发现**: +- **Meta Ranker 是这个阶段最重要的突破**——收益从 148% 提升到 152%,回撤从 -19.78% 降到 -10.10%,夏普从 1.74 提到 2.16 +- Meta Ranker 需要约 1000 条以上训练样本才能稳定 +- 它的成功高度依赖上游模型评分分布与策略边界的匹配 + +--- + +### v6.5:叶子 Embedding 增强(进行中) +**核心目标**:用树模型的叶子节点编码作为 Embedding 特征,增强上游模型。 + +**做了什么**: +- 从 v6.3 Rank 模型的 500 棵树中提取叶子编号 +- 构造 20 组叶子编码特征(基于目标编码的交互特征) +- 加入训练数据后,Rank Spearman 从 0.54 飙升到 0.74 + +**关键发现**: +- 叶子 Embedding 是最有效的特征增强方式——三列新特征包揽重要性前 3 名 +- 但 Meta Ranker 训练样本在 v6.5 的模型体系下反复不足,流程多次阻塞 + +--- + +## 第五阶段:收益导向重构(v7.0 探索中) + +### v7.0 的规划(尚未完成) +**核心目标**:把整条链路的训练目标从“匹配轮数(y_rounds)”改为“总回报(total_return_60d)”。 + +**为什么要改**: +- 当前体系前三层(Rank/Top/Stacking)都在预测“匹配轮数”,只有最后一层 Meta Ranker 预测“利润” +- 这导致前后层目标错位——上游选的是“最活跃的”,但实盘需要的是“最赚钱的” + +**怎么做**: +- 从零重建训练样本,标签改为 `total_return_60d`(已实现利润 + 期末持仓市值) +- 全链路用新标签重训,让 Rank/Top/Stacking 都直接学习收益规律 +- 同时引入规模中性化特征(纠正大盘股成交额偏差)和三指数独立震荡特征(沪深300/中证500/中证1000) + +**当前状态**: +- 训练样本生成完成(约 4.9 万条,正回报占比约 11.6%) +- 从零重建的数据源因 K 线时间范围(2020 年起)和股票覆盖(仅 600 开头)不足,无法复现 v6.3 的 1,799 只过滤后股票数 +- **当前卡点**:数据源覆盖问题,需要 2018 年起、全市场(含深市和创业板)的 K 线数据 + +--- + +## 全版本关键教训 + +| 教训 | 来源版本 | 说明 | +|:---|:---|:---| +| **情绪因子适合负向过滤,不适合正向精选** | v5.x | 对 Rank 有效,对 Top 无效 | +| **MLP 在表格数据上不如 LightGBM** | v6.0-v6.1 | 深度学习不是万能药 | +| **叶子 Embedding 是最强特征增强** | v6.5 | 非线性的树结构编码,比 PCA 强 10 倍 | +| **Meta Ranker 是体系最关键一环** | v6.4 | 用利润预测替代价格一刀切,夏普提升 24% | +| **训练数据必须与策略边界匹配** | v7.0 | 上游模型评分分布偏移会导致可买标的枯竭 | +| **从零重建比复用旧样本更难** | v7.0 | 数据源时间范围和股票覆盖是关键约束 | +| **规则探索需要专门为每个模型体系做一次** | v6.4/v6.5 | 同一参数在不同模型上效果截然不同 | + +--- + +## 当前最优体系(v6.4 生产基线) + +| 组件 | 版本 | 核心指标 | +|:---|:---|:---| +| Rank | v6.3 原始 | Spearman 0.5355 | +| Top | v6.3 原始 | PR-AUC 0.3389 | +| Stacking | v6.3 原始 | Spearman 0.6932 | +| Meta Ranker | v2(1288 条训练) | Spearman 0.7663 | +| **整体回测** | — | **收益 152.15%,回撤 -10.10%,夏普 2.16** | + +--- + +## 下一步方向 + +| 优先级 | 方向 | 预期收益 | 风险 | +| :---- | :-------------------------------------------- | :--- | :-- | +| **1** | v6.7:叶子 Embedding 增强 v6.4 上游 + 复用 Meta Ranker | 低 | 低 | +| **2** | v7.0:收益导向全链路重训(需先解决数据源问题) | 高 | 高 | +| **3** | 市场风格 Embedding(大小盘/牛熊切换) | 中 | 中 | \ No newline at end of file