Files
echart/quant/usage.html
T
simonandClaude Opus 4.7 eedead0d41 feat: 全面代码更新 - ECharts 5.4.2 重构、新增量化分析模块、前端库升级
- 升级 ECharts 到 5.4.2,重构 lib/ 目录结构
- 新增 DataTables 2.x 和 FixedColumns 插件
- 新增 quant/ 宏观研究报告模块
- 重构图表页面:stock_trend、hkholdbycode 等采用 JS fetch API.doorcome.cn 模式
- 新增 CLAUDE.md 补充页面文档和新数据流说明
- 更新 inc/config.php TuShare API 配置
- 更新新闻联播分析模块 news/ 和相关研究报告 research/
- 新增 api_document/ 参考文档
- 清理 .gitignore,排除 uploads/xls/.mcp.json/ source maps 等非代码文件
- 所有 PHP 文件通过 php -l 语法检查

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 18:01:55 +08:00

1512 lines
100 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>cc-cursor 使用指南</title>
<style>
:root {
--bg: #1a1a2e; --surface: #16213e; --text: #e0e0e0; --accent: #0f9b8e;
--code-bg: #0d1117; --border: #2a2a4a; --dim: #8b8ba0;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body { background: var(--bg); color: var(--text); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; line-height: 1.7; padding: 2rem; }
.container { max-width: 960px; margin: 0 auto; background: var(--surface); border-radius: 12px; padding: 2rem 3rem; box-shadow: 0 4px 24px rgba(0,0,0,0.3); }
h1 { color: var(--accent); font-size: 2rem; border-bottom: 2px solid var(--border); padding-bottom: 0.5rem; margin-bottom: 1rem; }
h2 { color: #4ecdc4; font-size: 1.4rem; margin: 2rem 0 1rem; border-left: 3px solid var(--accent); padding-left: 0.8rem; }
h3 { color: #a8d8ea; font-size: 1.1rem; margin: 1.2rem 0 0.5rem; }
h4 { color: var(--dim); margin: 1rem 0 0.3rem; }
p { margin: 0.6rem 0; }
a { color: #6cd4ff; text-decoration: none; }
a:hover { text-decoration: underline; }
code { background: var(--code-bg); padding: 0.15em 0.4em; border-radius: 3px; font-size: 0.9em; color: #e6a23c; }
pre { background: var(--code-bg); border: 1px solid var(--border); border-radius: 8px; padding: 1rem; overflow-x: auto; margin: 0.8rem 0; }
pre code { background: none; padding: 0; color: #c9d1d9; font-size: 0.85em; }
table { border-collapse: collapse; width: 100%; margin: 0.8rem 0; }
th, td { border: 1px solid var(--border); padding: 0.5rem 0.8rem; text-align: left; }
th { background: rgba(15,155,142,0.15); color: var(--accent); }
tr:nth-child(even) { background: rgba(255,255,255,0.03); }
blockquote { border-left: 3px solid var(--accent); padding: 0.5rem 1rem; margin: 0.8rem 0; background: rgba(15,155,142,0.05); color: var(--dim); }
ul, ol { padding-left: 1.5rem; margin: 0.5rem 0; }
li { margin: 0.2rem 0; }
hr { border: none; border-top: 1px solid var(--border); margin: 2rem 0; }
.toc { background: rgba(15,155,142,0.05); border: 1px solid var(--border); border-radius: 8px; padding: 1rem 1.5rem; margin: 1rem 0 2rem 0; }
.toc > strong { color: var(--accent); font-size: 1.1rem; display: block; margin-bottom: 0.5rem; }
.toc a { color: #4ecdc4; }
.toc ul { list-style: none; padding-left: 0; }
.toc ul ul { padding-left: 1.2rem; }
.toc li { margin: 0.3rem 0; }
@media (max-width: 768px) { body { padding: 0.5rem; } .container { padding: 1rem; } }
</style>
</head>
<body>
<div class="container">
<h1 id="cc-cursor-使用指南">cc-cursor 使用指南</h1>
<div class="toc">
<ul>
<li><a href="#cc-cursor-使用指南">cc-cursor 使用指南</a><ul>
<li><a href="#1-环境准备">1. 环境准备</a><ul>
<li><a href="#硬件要求">硬件要求</a></li>
<li><a href="#python-环境">Python 环境</a></li>
<li><a href="#核心依赖">核心依赖</a></li>
<li><a href="#项目路径设置">项目路径设置</a></li>
</ul>
</li>
<li><a href="#2-数据库连接">2. 数据库连接</a><ul>
<li><a href="#建立-ssh-隧道">建立 SSH 隧道</a></li>
<li><a href="#连接信息">连接信息</a></li>
<li><a href="#数据库表">数据库表</a></li>
<li><a href="#测试连接">测试连接</a></li>
</ul>
</li>
<li><a href="#3-数据层-datamanager">3. 数据层 — DataManager</a><ul>
<li><a href="#初始化">初始化</a></li>
<li><a href="#获取股票列表">获取股票列表</a></li>
<li><a href="#获取日线数据">获取日线数据</a></li>
<li><a href="#获取财务数据">获取财务数据</a></li>
<li><a href="#数据同步">数据同步</a></li>
</ul>
</li>
<li><a href="#4-因子引擎-factorengine">4. 因子引擎 — FactorEngine</a><ul>
<li><a href="#因子注册表">因子注册表</a></li>
<li><a href="#创建因子实例">创建因子实例</a></li>
<li><a href="#计算因子">计算因子</a></li>
<li><a href="#截面因子">截面因子</a></li>
<li><a href="#因子质量检查">因子质量检查</a></li>
</ul>
</li>
<li><a href="#5-回测引擎-vectorbtengine">5. 回测引擎 — VectorBTEngine</a><ul>
<li><a href="#参数">参数</a></li>
<li><a href="#创建引擎">创建引擎</a></li>
<li><a href="#使用内置策略">使用内置策略</a></li>
<li><a href="#读取回测报告">读取回测报告</a></li>
<li><a href="#内置策略清单">内置策略清单</a></li>
<li><a href="#自定义策略">自定义策略</a></li>
<li><a href="#截面回测多股票">截面回测(多股票)</a></li>
</ul>
</li>
<li><a href="#6-参数优化-optunaengine">6. 参数优化 — OptunaEngine</a><ul>
<li><a href="#使用预置搜索空间">使用预置搜索空间</a></li>
<li><a href="#读取优化结果">读取优化结果</a></li>
<li><a href="#walk-forward-验证">Walk-Forward 验证</a></li>
<li><a href="#快捷函数">快捷函数</a></li>
<li><a href="#自定义搜索空间">自定义搜索空间</a></li>
</ul>
</li>
<li><a href="#7-ml-模型-lightgbm-catboost">7. ML 模型 — LightGBM / CatBoost</a><ul>
<li><a href="#特征工程">特征工程</a></li>
<li><a href="#数据划分">数据划分</a></li>
<li><a href="#lightgbm-训练">LightGBM 训练</a></li>
<li><a href="#catboost-训练">CatBoost 训练</a></li>
<li><a href="#特征重要性">特征重要性</a></li>
<li><a href="#交叉验证">交叉验证</a></li>
<li><a href="#模型持久化">模型持久化</a></li>
<li><a href="#ml-策略回测">ML 策略回测</a></li>
</ul>
</li>
<li><a href="#8-情绪因子-sentimentengine">8. 情绪因子 — SentimentEngine</a><ul>
<li><a href="#配置-api-key">配置 API Key</a></li>
<li><a href="#配置分析范围">配置分析范围</a></li>
<li><a href="#使用情绪引擎">使用情绪引擎</a></li>
<li><a href="#新闻数据源">新闻数据源</a></li>
<li><a href="#日期对齐机制">日期对齐机制</a></li>
</ul>
</li>
<li><a href="#9-agent-系统-命令行入口">9. Agent 系统 — 命令行入口</a><ul>
<li><a href="#注册-agent">注册 Agent</a></li>
<li><a href="#cli-命令">CLI 命令</a></li>
<li><a href="#每日流程输出">每日流程输出</a></li>
<li><a href="#日报输出">日报输出</a></li>
<li><a href="#编程调用">编程调用</a></li>
</ul>
</li>
<li><a href="#10-配置说明">10. 配置说明</a><ul>
<li><a href="#环境变量financeenv">环境变量(finance/.env</a></li>
<li><a href="#回测参数">回测参数</a></li>
<li><a href="#optuna-参数">Optuna 参数</a></li>
<li><a href="#ml-模型参数">ML 模型参数</a></li>
</ul>
</li>
<li><a href="#11-完整示例">11. 完整示例</a><ul>
<li><a href="#示例-1快速回测">示例 1:快速回测</a></li>
<li><a href="#示例-2策略寻优-walk-forward">示例 2:策略寻优 + Walk-Forward</a></li>
<li><a href="#示例-3ml-训练-回测">示例 3ML 训练 + 回测</a></li>
<li><a href="#示例-4每日-agent-运行">示例 4:每日 Agent 运行</a></li>
</ul>
</li>
<li><a href="#12-常见问题">12. 常见问题</a><ul>
<li><a href="#q-ssh-隧道连接失败">Q: SSH 隧道连接失败?</a></li>
<li><a href="#q-akshare-返回-remotedisconnected">Q: AkShare 返回 RemoteDisconnected</a></li>
<li><a href="#q-因子计算结果全是-nan">Q: 因子计算结果全是 NaN</a></li>
<li><a href="#q-回测结果为-0-笔交易">Q: 回测结果为 0 笔交易?</a></li>
<li><a href="#q-模型训练只有-2-棵树">Q: 模型训练只有 2 棵树?</a></li>
<li><a href="#q-情绪因子返回空">Q: 情绪因子返回空?</a></li>
<li><a href="#q-日报中选股为空">Q: 日报中选股为空?</a></li>
</ul>
</li>
<li><a href="#13-cli-脚本参考">13. CLI 脚本参考</a><ul>
<li><a href="#131-agent-系统入口-agent-clipy">13.1 Agent 系统入口 — agent_cli.py</a></li>
<li><a href="#132-数据层验证-demo-data-managerpy">13.2 数据层验证 — demo_data_manager.py</a></li>
<li><a href="#133-因子引擎验证-demo-factor-enginepy">13.3 因子引擎验证 — demo_factor_engine.py</a></li>
<li><a href="#134-回测引擎验证-demo-backtestpy">13.4 回测引擎验证 — demo_backtest.py</a></li>
<li><a href="#135-参数优化验证-demo-optimizerpy">13.5 参数优化验证 — demo_optimizer.py</a></li>
<li><a href="#136-ml-模型验证-demo-mlpy">13.6 ML 模型验证 — demo_ml.py</a></li>
<li><a href="#137-情绪因子快速验证-demo-sentimentpy">13.7 情绪因子快速验证 — demo_sentiment.py</a></li>
<li><a href="#138-情绪因子详细演示-demo-sentiment-detailpy">13.8 情绪因子详细演示 — demo_sentiment_detail.py</a></li>
<li><a href="#139-脚本一览">13.9 脚本一览</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
<p>Mac Mini 单机量化研究平台,覆盖数据获取 → 因子计算 → 回测 → 参数优化 → ML 模型 → 情绪因子 → Agent 系统 全链路。</p>
<hr />
<hr />
<h2 id="1-环境准备">1. 环境准备</h2>
<h3 id="硬件要求">硬件要求</h3>
<ul>
<li>macOS / Linux(本系统开发于 Mac Mini</li>
<li>内存 ≥ 16GB(ML 模型训练推荐)</li>
<li>网络:可访问东方财富 / 同花顺 API</li>
</ul>
<h3 id="python-环境">Python 环境</h3>
<div class="codehilite"><pre><span></span><code><span class="c1"># 激活 conda 环境</span>
conda<span class="w"> </span>activate<span class="w"> </span>quant
<span class="c1"># 确认 Python 版本</span>
python<span class="w"> </span>--version<span class="w"> </span><span class="c1"># → 3.11.13</span>
</code></pre></div>
<h3 id="核心依赖">核心依赖</h3>
<table>
<thead>
<tr>
<th></th>
<th>版本</th>
<th>用途</th>
</tr>
</thead>
<tbody>
<tr>
<td>pandas</td>
<td>3.0</td>
<td>数据处理</td>
</tr>
<tr>
<td>numpy</td>
<td>2.4</td>
<td>数值计算</td>
</tr>
<tr>
<td>akshare</td>
<td>1.18</td>
<td>A 股数据获取</td>
</tr>
<tr>
<td>vectorbt</td>
<td>1.0</td>
<td>回测引擎</td>
</tr>
<tr>
<td>optuna</td>
<td>4.9</td>
<td>参数优化</td>
</tr>
<tr>
<td>lightgbm</td>
<td>4.6</td>
<td>梯度提升模型</td>
</tr>
<tr>
<td>catboost</td>
<td>1.2</td>
<td>梯度提升模型</td>
</tr>
<tr>
<td>scikit-learn</td>
<td>1.9</td>
<td>特征工程</td>
</tr>
<tr>
<td>sqlalchemy</td>
<td>2.0</td>
<td>数据库 ORM</td>
</tr>
<tr>
<td>pymysql</td>
<td>1.2</td>
<td>MySQL 连接</td>
</tr>
</tbody>
</table>
<h3 id="项目路径设置">项目路径设置</h3>
<p>所有代码从 <code>finance/</code> 目录运行。Python 脚本开头加入:</p>
<div class="codehilite"><pre><span></span><code><span class="kn">import</span><span class="w"> </span><span class="nn">sys</span>
<span class="n">sys</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="s2">&quot;/path/to/cc-cursor/finance&quot;</span><span class="p">)</span>
</code></pre></div>
<hr />
<h2 id="2-数据库连接">2. 数据库连接</h2>
<h3 id="建立-ssh-隧道">建立 SSH 隧道</h3>
<p>系统通过 SSH 隧道连接远程 MariaDB</p>
<div class="codehilite"><pre><span></span><code>bash<span class="w"> </span>shared/script/autossh.sh
</code></pre></div>
<p>验证隧道:</p>
<div class="codehilite"><pre><span></span><code>lsof<span class="w"> </span>-i<span class="w"> </span>:13306<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>LISTEN
<span class="c1"># → ssh ... localhost:13306 (LISTEN) ...</span>
</code></pre></div>
<h3 id="连接信息">连接信息</h3>
<div class="codehilite"><pre><span></span><code>Host: 127.0.0.1
Port: 13306
User: myquant
Password: &lt;your-db-password&gt;
Database: myquant
</code></pre></div>
<h3 id="数据库表">数据库表</h3>
<p>所有表使用 <code>mac_</code> 前缀,与已有表隔离:</p>
<table>
<thead>
<tr>
<th>表名</th>
<th>内容</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>mac_stock_basic</code></td>
<td>A 股列表</td>
<td>5,524 只股票</td>
</tr>
<tr>
<td><code>mac_stock_daily</code></td>
<td>日线行情</td>
<td>按需同步</td>
</tr>
<tr>
<td><code>mac_stock_financial</code></td>
<td>财务指标</td>
<td>同花顺核心指标</td>
</tr>
</tbody>
</table>
<h3 id="测试连接">测试连接</h3>
<div class="codehilite"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">database.connection</span><span class="w"> </span><span class="kn">import</span> <span class="n">test_connection</span>
<span class="k">if</span> <span class="n">test_connection</span><span class="p">():</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;数据库连接成功&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;请先建立 SSH 隧道: bash shared/script/autossh.sh&quot;</span><span class="p">)</span>
</code></pre></div>
<hr />
<h2 id="3-数据层-datamanager">3. 数据层 — DataManager</h2>
<h3 id="初始化">初始化</h3>
<div class="codehilite"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">data.data_manager</span><span class="w"> </span><span class="kn">import</span> <span class="n">DataManager</span>
<span class="n">dm</span> <span class="o">=</span> <span class="n">DataManager</span><span class="p">()</span>
<span class="n">dm</span><span class="o">.</span><span class="n">init_db</span><span class="p">()</span> <span class="c1"># 首次使用创建表(幂等操作)</span>
</code></pre></div>
<h3 id="获取股票列表">获取股票列表</h3>
<div class="codehilite"><pre><span></span><code><span class="c1"># 从 DB 缓存读取(已缓存的 5,524 只 A 股)</span>
<span class="n">stocks</span> <span class="o">=</span> <span class="n">dm</span><span class="o">.</span><span class="n">get_stock_list</span><span class="p">()</span>
<span class="c1"># → DataFrame: index=ts_code, columns=[name, area, industry, ...]</span>
<span class="c1"># 强制从 AkShare 刷新</span>
<span class="n">stocks</span> <span class="o">=</span> <span class="n">dm</span><span class="o">.</span><span class="n">get_stock_list</span><span class="p">(</span><span class="n">force_refresh</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</code></pre></div>
<h3 id="获取日线数据">获取日线数据</h3>
<div class="codehilite"><pre><span></span><code><span class="c1"># 获取单只股票日线(DB 缓存优先,缺失自动补拉)</span>
<span class="n">daily</span> <span class="o">=</span> <span class="n">dm</span><span class="o">.</span><span class="n">get_daily</span><span class="p">(</span><span class="s2">&quot;000001.SZ&quot;</span><span class="p">)</span>
<span class="c1"># → DataFrame: trade_date, open, high, low, close, vol, amount, ...</span>
<span class="c1"># 指定日期范围</span>
<span class="n">daily</span> <span class="o">=</span> <span class="n">dm</span><span class="o">.</span><span class="n">get_daily</span><span class="p">(</span><span class="s2">&quot;000001.SZ&quot;</span><span class="p">,</span> <span class="n">start</span><span class="o">=</span><span class="s2">&quot;20240101&quot;</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">&quot;20241231&quot;</span><span class="p">)</span>
<span class="c1"># 直接用索引</span>
<span class="n">price</span> <span class="o">=</span> <span class="n">daily</span><span class="o">.</span><span class="n">set_index</span><span class="p">(</span><span class="s2">&quot;trade_date&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">sort_index</span><span class="p">()</span>
<span class="n">close</span> <span class="o">=</span> <span class="n">price</span><span class="p">[</span><span class="s2">&quot;close&quot;</span><span class="p">]</span>
</code></pre></div>
<h3 id="获取财务数据">获取财务数据</h3>
<div class="codehilite"><pre><span></span><code><span class="n">fina</span> <span class="o">=</span> <span class="n">dm</span><span class="o">.</span><span class="n">get_financial</span><span class="p">(</span><span class="s2">&quot;000001.SZ&quot;</span><span class="p">)</span>
<span class="c1"># → DataFrame: end_date, eps, bvps, roe, net_profit_margin, debt_to_assets, ...</span>
<span class="c1"># 数据源: stock_financial_abstract_ths(同花顺)</span>
<span class="c1"># 覆盖: 主板/创业板/科创板</span>
</code></pre></div>
<h3 id="数据同步">数据同步</h3>
<div class="codehilite"><pre><span></span><code><span class="c1"># 增量同步:从 DB 最新日期到今天的缺失数据</span>
<span class="n">n</span> <span class="o">=</span> <span class="n">dm</span><span class="o">.</span><span class="n">sync_daily</span><span class="p">(</span><span class="s2">&quot;000001.SZ&quot;</span><span class="p">)</span>
<span class="c1"># 批量同步全部股票(谨慎使用,耗时长)</span>
<span class="n">total</span> <span class="o">=</span> <span class="n">dm</span><span class="o">.</span><span class="n">sync_all_daily</span><span class="p">()</span>
</code></pre></div>
<hr />
<h2 id="4-因子引擎-factorengine">4. 因子引擎 — FactorEngine</h2>
<h3 id="因子注册表">因子注册表</h3>
<div class="codehilite"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">factors.registry</span><span class="w"> </span><span class="kn">import</span> <span class="n">get_factor</span><span class="p">,</span> <span class="n">list_factors</span><span class="p">,</span> <span class="n">list_categories</span>
<span class="c1"># 查看所有因子分类</span>
<span class="nb">print</span><span class="p">(</span><span class="n">list_categories</span><span class="p">())</span>
<span class="c1"># → [&#39;动量&#39;, &#39;RSI&#39;, &#39;MACD&#39;, &#39;量价&#39;, &#39;布林&#39;, &#39;ATR&#39;, &#39;均线&#39;, &#39;波动率&#39;, &#39;换手率&#39;, &#39;振幅&#39;, &#39;基本面&#39;, &#39;情绪&#39;]</span>
<span class="c1"># 查看某个分类下的因子</span>
<span class="nb">print</span><span class="p">(</span><span class="n">list_factors</span><span class="p">(</span><span class="s2">&quot;RSI&quot;</span><span class="p">))</span>
<span class="c1"># → [&#39;rsi_7&#39;, &#39;rsi_14&#39;]</span>
<span class="c1"># 查看全部因子</span>
<span class="n">all_factors</span> <span class="o">=</span> <span class="n">list_factors</span><span class="p">()</span>
<span class="nb">print</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">all_factors</span><span class="p">))</span>
<span class="c1"># → 34</span>
</code></pre></div>
<h3 id="创建因子实例">创建因子实例</h3>
<div class="codehilite"><pre><span></span><code><span class="c1"># 按名称获取(使用默认参数)</span>
<span class="n">factor</span> <span class="o">=</span> <span class="n">get_factor</span><span class="p">(</span><span class="s2">&quot;momentum_20&quot;</span><span class="p">)</span> <span class="c1"># 20 日动量</span>
<span class="n">factor</span> <span class="o">=</span> <span class="n">get_factor</span><span class="p">(</span><span class="s2">&quot;rsi_14&quot;</span><span class="p">)</span> <span class="c1"># 14 日 RSI</span>
<span class="n">factor</span> <span class="o">=</span> <span class="n">get_factor</span><span class="p">(</span><span class="s2">&quot;roe&quot;</span><span class="p">)</span> <span class="c1"># ROE 基本面因子</span>
<span class="n">factor</span> <span class="o">=</span> <span class="n">get_factor</span><span class="p">(</span><span class="s2">&quot;news_sent_5&quot;</span><span class="p">)</span> <span class="c1"># 5 日新闻情绪因子</span>
<span class="c1"># 自定义参数</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">factors.technical.momentum</span><span class="w"> </span><span class="kn">import</span> <span class="n">MomentumFactor</span>
<span class="n">factor</span> <span class="o">=</span> <span class="n">MomentumFactor</span><span class="p">(</span><span class="n">period</span><span class="o">=</span><span class="mi">60</span><span class="p">)</span>
</code></pre></div>
<h3 id="计算因子">计算因子</h3>
<div class="codehilite"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">factors.engine</span><span class="w"> </span><span class="kn">import</span> <span class="n">FactorEngine</span>
<span class="n">engine_fe</span> <span class="o">=</span> <span class="n">FactorEngine</span><span class="p">(</span><span class="n">dm</span><span class="p">)</span>
<span class="c1"># 单股票多因子</span>
<span class="n">factors</span> <span class="o">=</span> <span class="p">[</span>
<span class="n">get_factor</span><span class="p">(</span><span class="s2">&quot;momentum_20&quot;</span><span class="p">),</span>
<span class="n">get_factor</span><span class="p">(</span><span class="s2">&quot;rsi_14&quot;</span><span class="p">),</span>
<span class="n">get_factor</span><span class="p">(</span><span class="s2">&quot;volatility_20&quot;</span><span class="p">),</span>
<span class="n">get_factor</span><span class="p">(</span><span class="s2">&quot;ma_dev_20&quot;</span><span class="p">),</span>
<span class="p">]</span>
<span class="n">factor_df</span> <span class="o">=</span> <span class="n">engine_fe</span><span class="o">.</span><span class="n">compute</span><span class="p">(</span><span class="s2">&quot;000001.SZ&quot;</span><span class="p">,</span> <span class="n">factors</span><span class="p">)</span>
<span class="c1"># → DataFrame: index=trade_date, columns=[momentum_20, rsi_14, volatility_20, ma_dev_20]</span>
<span class="c1"># 查看因子值</span>
<span class="nb">print</span><span class="p">(</span><span class="n">factor_df</span><span class="o">.</span><span class="n">tail</span><span class="p">())</span>
<span class="nb">print</span><span class="p">(</span><span class="n">factor_df</span><span class="o">.</span><span class="n">describe</span><span class="p">())</span>
</code></pre></div>
<h3 id="截面因子">截面因子</h3>
<div class="codehilite"><pre><span></span><code><span class="c1"># 计算多只股票在某一天的因子值</span>
<span class="n">cross</span> <span class="o">=</span> <span class="n">engine_fe</span><span class="o">.</span><span class="n">compute_universe</span><span class="p">(</span>
<span class="n">factors</span><span class="o">=</span><span class="p">[</span><span class="n">get_factor</span><span class="p">(</span><span class="s2">&quot;momentum_20&quot;</span><span class="p">),</span> <span class="n">get_factor</span><span class="p">(</span><span class="s2">&quot;rsi_14&quot;</span><span class="p">)],</span>
<span class="n">date</span><span class="o">=</span><span class="s2">&quot;20250630&quot;</span><span class="p">,</span>
<span class="n">ts_codes</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;000001.SZ&quot;</span><span class="p">,</span> <span class="s2">&quot;600519.SH&quot;</span><span class="p">,</span> <span class="s2">&quot;300750.SZ&quot;</span><span class="p">],</span>
<span class="p">)</span>
<span class="c1"># → DataFrame: index=ts_code, columns=[momentum_20, rsi_14]</span>
</code></pre></div>
<h3 id="因子质量检查">因子质量检查</h3>
<div class="codehilite"><pre><span></span><code><span class="c1"># 查看 NaN 率</span>
<span class="n">total</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">factor_df</span><span class="p">)</span>
<span class="k">for</span> <span class="n">col</span> <span class="ow">in</span> <span class="n">factor_df</span><span class="o">.</span><span class="n">columns</span><span class="p">:</span>
<span class="n">nan_pct</span> <span class="o">=</span> <span class="n">factor_df</span><span class="p">[</span><span class="n">col</span><span class="p">]</span><span class="o">.</span><span class="n">isna</span><span class="p">()</span><span class="o">.</span><span class="n">sum</span><span class="p">()</span> <span class="o">/</span> <span class="n">total</span> <span class="o">*</span> <span class="mi">100</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">col</span><span class="si">}</span><span class="s2">: NaN </span><span class="si">{</span><span class="n">nan_pct</span><span class="si">:</span><span class="s2">.1f</span><span class="si">}</span><span class="s2">%&quot;</span><span class="p">)</span>
<span class="c1"># 正常范围: 技术因子 0.3%-2.1%, 基本面因子 0%</span>
</code></pre></div>
<hr />
<h2 id="5-回测引擎-vectorbtengine">5. 回测引擎 — VectorBTEngine</h2>
<h3 id="参数">参数</h3>
<ul>
<li>初始资金:100,000 元</li>
<li>手续费:0.03%(万三)</li>
<li>方向:只做多</li>
</ul>
<h3 id="创建引擎">创建引擎</h3>
<div class="codehilite"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">backtest.vectorbt.engine</span><span class="w"> </span><span class="kn">import</span> <span class="n">VectorBTEngine</span>
<span class="n">engine_bt</span> <span class="o">=</span> <span class="n">VectorBTEngine</span><span class="p">(</span>
<span class="n">initial_capital</span><span class="o">=</span><span class="mi">100_000</span><span class="p">,</span>
<span class="n">commission</span><span class="o">=</span><span class="mf">0.0003</span><span class="p">,</span>
<span class="p">)</span>
</code></pre></div>
<h3 id="使用内置策略">使用内置策略</h3>
<div class="codehilite"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">backtest.strategies.rsi_mean_revert</span><span class="w"> </span><span class="kn">import</span> <span class="n">RSIMeanRevertStrategy</span>
<span class="c1"># 创建策略</span>
<span class="n">strategy</span> <span class="o">=</span> <span class="n">RSIMeanRevertStrategy</span><span class="p">(</span><span class="n">oversold</span><span class="o">=</span><span class="mi">30</span><span class="p">,</span> <span class="n">overbought</span><span class="o">=</span><span class="mi">70</span><span class="p">)</span>
<span class="c1"># 运行回测</span>
<span class="n">report</span> <span class="o">=</span> <span class="n">engine_bt</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">strategy</span><span class="p">,</span> <span class="n">price_df</span><span class="p">,</span> <span class="n">factor_df</span><span class="p">)</span>
</code></pre></div>
<h3 id="读取回测报告">读取回测报告</h3>
<div class="codehilite"><pre><span></span><code><span class="c1"># 一行摘要</span>
<span class="nb">print</span><span class="p">(</span><span class="n">report</span><span class="o">.</span><span class="n">summary</span><span class="p">())</span>
<span class="c1"># → 收益=29.4% 年化=4.3% 回撤=-19.1% 夏普=0.37 胜率=77.1% 交易=70笔</span>
<span class="c1"># 字典格式</span>
<span class="n">metrics</span> <span class="o">=</span> <span class="n">report</span><span class="o">.</span><span class="n">to_dict</span><span class="p">()</span>
<span class="c1"># → {&#39;total_return&#39;: 29.4, &#39;cagr&#39;: 4.3, &#39;sharpe_ratio&#39;: 0.37, ...}</span>
<span class="c1"># 获取净值曲线</span>
<span class="n">equity</span> <span class="o">=</span> <span class="n">report</span><span class="o">.</span><span class="n">equity_curve</span> <span class="c1"># pd.Series</span>
<span class="n">drawdown</span> <span class="o">=</span> <span class="n">report</span><span class="o">.</span><span class="n">drawdown_curve</span> <span class="c1"># pd.Series</span>
<span class="c1"># 逐笔交易</span>
<span class="n">trades</span> <span class="o">=</span> <span class="n">report</span><span class="o">.</span><span class="n">trades_df</span> <span class="c1"># pd.DataFrame</span>
</code></pre></div>
<h3 id="内置策略清单">内置策略清单</h3>
<table>
<thead>
<tr>
<th>策略</th>
<th>类名</th>
<th>适用场景</th>
</tr>
</thead>
<tbody>
<tr>
<td>均线交叉</td>
<td><code>SMACrossStrategy(fast=5, slow=20)</code></td>
<td>趋势跟踪</td>
</tr>
<tr>
<td>RSI 反转</td>
<td><code>RSIMeanRevertStrategy(oversold=30, overbought=70)</code></td>
<td>均值回归</td>
</tr>
<tr>
<td>动量突破</td>
<td><code>MomentumBreakoutStrategy(lookback=20, exit_period=10)</code></td>
<td>动量策略</td>
</tr>
<tr>
<td>因子阈值</td>
<td><code>FactorCrossStrategy(factor_column, buy_threshold, sell_threshold)</code></td>
<td>通用因子</td>
</tr>
<tr>
<td>因子轮动</td>
<td><code>FactorRotationStrategy(factor_name, top_n=5)</code></td>
<td>截面选股</td>
</tr>
</tbody>
</table>
<h3 id="自定义策略">自定义策略</h3>
<div class="codehilite"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">backtest.base</span><span class="w"> </span><span class="kn">import</span> <span class="n">BaseStrategy</span>
<span class="k">class</span><span class="w"> </span><span class="nc">MyStrategy</span><span class="p">(</span><span class="n">BaseStrategy</span><span class="p">):</span>
<span class="n">name</span> <span class="o">=</span> <span class="s2">&quot;my_strategy&quot;</span>
<span class="n">category</span> <span class="o">=</span> <span class="s2">&quot;custom&quot;</span>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">param_a</span><span class="o">=</span><span class="mi">10</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">param_a</span> <span class="o">=</span> <span class="n">param_a</span>
<span class="k">def</span><span class="w"> </span><span class="nf">generate_signals</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">factor_df</span><span class="p">):</span>
<span class="c1"># factor_df 包含因子值和 close 列</span>
<span class="c1"># 返回: 1=买入, 0=卖出, -1=持有</span>
<span class="n">signals</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">Series</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="n">index</span><span class="o">=</span><span class="n">factor_df</span><span class="o">.</span><span class="n">index</span><span class="p">)</span>
<span class="n">signals</span><span class="p">[</span><span class="n">factor_df</span><span class="p">[</span><span class="s2">&quot;rsi_14&quot;</span><span class="p">]</span> <span class="o">&lt;</span> <span class="mi">30</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span> <span class="c1"># RSI 超卖买入</span>
<span class="n">signals</span><span class="p">[</span><span class="n">factor_df</span><span class="p">[</span><span class="s2">&quot;rsi_14&quot;</span><span class="p">]</span> <span class="o">&gt;</span> <span class="mi">70</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span> <span class="c1"># RSI 超买卖出</span>
<span class="k">return</span> <span class="n">signals</span>
<span class="n">report</span> <span class="o">=</span> <span class="n">engine_bt</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">MyStrategy</span><span class="p">(</span><span class="n">param_a</span><span class="o">=</span><span class="mi">20</span><span class="p">),</span> <span class="n">price_df</span><span class="p">,</span> <span class="n">factor_df</span><span class="p">)</span>
</code></pre></div>
<h3 id="截面回测多股票">截面回测(多股票)</h3>
<div class="codehilite"><pre><span></span><code><span class="n">report_xs</span> <span class="o">=</span> <span class="n">engine_bt</span><span class="o">.</span><span class="n">run_cross_section</span><span class="p">(</span>
<span class="n">strategy</span><span class="p">,</span>
<span class="n">price_universe</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;000001.SZ&quot;</span><span class="p">:</span> <span class="n">df1</span><span class="p">,</span> <span class="s2">&quot;600519.SH&quot;</span><span class="p">:</span> <span class="n">df2</span><span class="p">},</span>
<span class="n">factor_universe</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;000001.SZ&quot;</span><span class="p">:</span> <span class="n">f1</span><span class="p">,</span> <span class="s2">&quot;600519.SH&quot;</span><span class="p">:</span> <span class="n">f2</span><span class="p">},</span>
<span class="p">)</span>
<span class="c1"># → 等权组合回测报告</span>
</code></pre></div>
<hr />
<h2 id="6-参数优化-optunaengine">6. 参数优化 — OptunaEngine</h2>
<h3 id="使用预置搜索空间">使用预置搜索空间</h3>
<div class="codehilite"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">optimizer.engine</span><span class="w"> </span><span class="kn">import</span> <span class="n">OptunaEngine</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">optimizer.space</span><span class="w"> </span><span class="kn">import</span> <span class="n">rsi_revert_space</span><span class="p">,</span> <span class="n">sma_cross_space</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">backtest.strategies.rsi_mean_revert</span><span class="w"> </span><span class="kn">import</span> <span class="n">RSIMeanRevertStrategy</span>
<span class="n">opt_engine</span> <span class="o">=</span> <span class="n">OptunaEngine</span><span class="p">(</span><span class="n">engine_bt</span><span class="p">)</span>
<span class="c1"># 优化 RSI 反转策略参数</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">opt_engine</span><span class="o">.</span><span class="n">optimize</span><span class="p">(</span>
<span class="n">strategy_class</span><span class="o">=</span><span class="n">RSIMeanRevertStrategy</span><span class="p">,</span>
<span class="n">search_space</span><span class="o">=</span><span class="n">rsi_revert_space</span><span class="p">,</span>
<span class="n">price_df</span><span class="o">=</span><span class="n">price_df</span><span class="p">,</span>
<span class="n">factor_df</span><span class="o">=</span><span class="n">factor_df</span><span class="p">,</span>
<span class="n">metric</span><span class="o">=</span><span class="s2">&quot;sharpe&quot;</span><span class="p">,</span> <span class="c1"># 优化目标: sharpe/cagr/calmar/total_return</span>
<span class="n">n_trials</span><span class="o">=</span><span class="mi">200</span><span class="p">,</span> <span class="c1"># 试验次数</span>
<span class="p">)</span>
</code></pre></div>
<h3 id="读取优化结果">读取优化结果</h3>
<div class="codehilite"><pre><span></span><code><span class="nb">print</span><span class="p">(</span><span class="n">result</span><span class="o">.</span><span class="n">summary</span><span class="p">())</span>
<span class="c1"># → 最优参数: oversold=13, overbought=66</span>
<span class="c1"># → 最优目标 (sharpe): 0.5985</span>
<span class="c1"># 最优参数的回测报告</span>
<span class="n">best_report</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">best_report</span>
<span class="c1"># 参数重要性</span>
<span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">result</span><span class="o">.</span><span class="n">param_importance</span><span class="o">.</span><span class="n">items</span><span class="p">(),</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="o">-</span><span class="n">x</span><span class="p">[</span><span class="mi">1</span><span class="p">]):</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot; </span><span class="si">{</span><span class="n">k</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">v</span><span class="si">:</span><span class="s2">.4f</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="c1"># 试验记录</span>
<span class="n">trials</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">trials_df</span> <span class="c1"># pd.DataFrame</span>
</code></pre></div>
<h3 id="walk-forward-验证">Walk-Forward 验证</h3>
<div class="codehilite"><pre><span></span><code><span class="n">wf_result</span> <span class="o">=</span> <span class="n">opt_engine</span><span class="o">.</span><span class="n">optimize_walk_forward</span><span class="p">(</span>
<span class="n">strategy_class</span><span class="o">=</span><span class="n">RSIMeanRevertStrategy</span><span class="p">,</span>
<span class="n">search_space</span><span class="o">=</span><span class="n">rsi_revert_space</span><span class="p">,</span>
<span class="n">price_df</span><span class="o">=</span><span class="n">price_df</span><span class="p">,</span>
<span class="n">factor_df</span><span class="o">=</span><span class="n">factor_df</span><span class="p">,</span>
<span class="n">metric</span><span class="o">=</span><span class="s2">&quot;sharpe&quot;</span><span class="p">,</span>
<span class="n">n_trials</span><span class="o">=</span><span class="mi">80</span><span class="p">,</span>
<span class="n">train_window</span><span class="o">=</span><span class="mi">252</span> <span class="o">*</span> <span class="mi">3</span><span class="p">,</span> <span class="c1"># 3 年训练</span>
<span class="n">test_window</span><span class="o">=</span><span class="mi">252</span><span class="p">,</span> <span class="c1"># 1 年测试</span>
<span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">wf_result</span><span class="o">.</span><span class="n">summary</span><span class="p">())</span>
<span class="c1"># → 各窗口参数变化 + 整体收益</span>
</code></pre></div>
<h3 id="快捷函数">快捷函数</h3>
<div class="codehilite"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">optimizer.presets</span><span class="w"> </span><span class="kn">import</span> <span class="p">(</span>
<span class="n">optimize_sma_cross</span><span class="p">,</span>
<span class="n">optimize_rsi_revert</span><span class="p">,</span>
<span class="n">optimize_momentum_breakout</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">optimize_rsi_revert</span><span class="p">(</span><span class="n">price_df</span><span class="p">,</span> <span class="n">factor_df</span><span class="p">,</span> <span class="n">engine_bt</span><span class="p">,</span> <span class="n">n_trials</span><span class="o">=</span><span class="mi">100</span><span class="p">)</span>
</code></pre></div>
<h3 id="自定义搜索空间">自定义搜索空间</h3>
<div class="codehilite"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">optimizer.space</span><span class="w"> </span><span class="kn">import</span> <span class="n">SearchSpace</span>
<span class="n">my_space</span> <span class="o">=</span> <span class="n">SearchSpace</span><span class="p">(</span><span class="n">params</span><span class="o">=</span><span class="p">[</span>
<span class="p">{</span><span class="s2">&quot;name&quot;</span><span class="p">:</span> <span class="s2">&quot;fast&quot;</span><span class="p">,</span> <span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;int&quot;</span><span class="p">,</span> <span class="s2">&quot;low&quot;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="s2">&quot;high&quot;</span><span class="p">:</span> <span class="mi">30</span><span class="p">,</span> <span class="s2">&quot;step&quot;</span><span class="p">:</span> <span class="mi">1</span><span class="p">},</span>
<span class="p">{</span><span class="s2">&quot;name&quot;</span><span class="p">:</span> <span class="s2">&quot;slow&quot;</span><span class="p">,</span> <span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;int&quot;</span><span class="p">,</span> <span class="s2">&quot;low&quot;</span><span class="p">:</span> <span class="mi">15</span><span class="p">,</span> <span class="s2">&quot;high&quot;</span><span class="p">:</span> <span class="mi">120</span><span class="p">,</span> <span class="s2">&quot;step&quot;</span><span class="p">:</span> <span class="mi">5</span><span class="p">},</span>
<span class="p">])</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">opt_engine</span><span class="o">.</span><span class="n">optimize</span><span class="p">(</span><span class="n">MyStrategy</span><span class="p">,</span> <span class="n">my_space</span><span class="p">,</span> <span class="n">price_df</span><span class="p">,</span> <span class="n">factor_df</span><span class="p">)</span>
</code></pre></div>
<hr />
<h2 id="7-ml-模型-lightgbm-catboost">7. ML 模型 — LightGBM / CatBoost</h2>
<h3 id="特征工程">特征工程</h3>
<div class="codehilite"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">models.features</span><span class="w"> </span><span class="kn">import</span> <span class="n">FeatureEngine</span>
<span class="c1"># lookahead=5: 预测未来 5 个交易日收益</span>
<span class="n">fe</span> <span class="o">=</span> <span class="n">FeatureEngine</span><span class="p">(</span><span class="n">lookahead</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">label_type</span><span class="o">=</span><span class="s2">&quot;regression&quot;</span><span class="p">)</span>
<span class="c1"># 构建特征矩阵和标签</span>
<span class="n">X</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">fe</span><span class="o">.</span><span class="n">build</span><span class="p">(</span><span class="n">factor_df</span><span class="p">,</span> <span class="n">price_df</span><span class="p">,</span> <span class="n">fit</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="c1"># → X: 标准特征矩阵(去极值 → 缺失填充 → RobustScaler</span>
<span class="c1"># → y: 未来 5 日收益率(%</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;特征: </span><span class="si">{</span><span class="n">X</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="si">}</span><span class="s2"> 列, 样本: </span><span class="si">{</span><span class="n">X</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;标签: mean=</span><span class="si">{</span><span class="n">y</span><span class="o">.</span><span class="n">mean</span><span class="p">()</span><span class="si">:</span><span class="s2">.2f</span><span class="si">}</span><span class="s2">%, std=</span><span class="si">{</span><span class="n">y</span><span class="o">.</span><span class="n">std</span><span class="p">()</span><span class="si">:</span><span class="s2">.2f</span><span class="si">}</span><span class="s2">%&quot;</span><span class="p">)</span>
</code></pre></div>
<h3 id="数据划分">数据划分</h3>
<div class="codehilite"><pre><span></span><code><span class="c1"># 时间序列划分(前 70% 训练,后 30% 测试)</span>
<span class="n">n</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
<span class="n">split</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">n</span> <span class="o">*</span> <span class="mf">0.7</span><span class="p">)</span>
<span class="n">X_train</span><span class="p">,</span> <span class="n">X_test</span> <span class="o">=</span> <span class="n">X</span><span class="o">.</span><span class="n">iloc</span><span class="p">[:</span><span class="n">split</span><span class="p">],</span> <span class="n">X</span><span class="o">.</span><span class="n">iloc</span><span class="p">[</span><span class="n">split</span><span class="p">:]</span>
<span class="n">y_train</span><span class="p">,</span> <span class="n">y_test</span> <span class="o">=</span> <span class="n">y</span><span class="o">.</span><span class="n">iloc</span><span class="p">[:</span><span class="n">split</span><span class="p">],</span> <span class="n">y</span><span class="o">.</span><span class="n">iloc</span><span class="p">[</span><span class="n">split</span><span class="p">:]</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;训练集: </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">X_train</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;测试集: </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">X_test</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
</code></pre></div>
<h3 id="lightgbm-训练">LightGBM 训练</h3>
<div class="codehilite"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">models.lightgbm.model</span><span class="w"> </span><span class="kn">import</span> <span class="n">LightGBMModel</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">LightGBMModel</span><span class="p">(</span>
<span class="n">params</span><span class="o">=</span><span class="p">{</span>
<span class="s2">&quot;n_estimators&quot;</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span>
<span class="s2">&quot;learning_rate&quot;</span><span class="p">:</span> <span class="mf">0.03</span><span class="p">,</span>
<span class="s2">&quot;num_leaves&quot;</span><span class="p">:</span> <span class="mi">15</span><span class="p">,</span>
<span class="p">},</span>
<span class="n">early_stopping</span><span class="o">=</span><span class="mi">100</span><span class="p">,</span>
<span class="n">eval_ratio</span><span class="o">=</span><span class="mf">0.2</span><span class="p">,</span> <span class="c1"># 20% 做验证集</span>
<span class="p">)</span>
<span class="n">model</span><span class="o">.</span><span class="n">fit</span><span class="p">(</span><span class="n">X_train</span><span class="p">,</span> <span class="n">y_train</span><span class="p">)</span>
<span class="n">pred</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">predict</span><span class="p">(</span><span class="n">X_test</span><span class="p">)</span>
<span class="c1"># 评估</span>
<span class="n">ic</span> <span class="o">=</span> <span class="n">pred</span><span class="o">.</span><span class="n">corr</span><span class="p">(</span><span class="n">y_test</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;测试集 IC: </span><span class="si">{</span><span class="n">ic</span><span class="si">:</span><span class="s2">.4f</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
</code></pre></div>
<h3 id="catboost-训练">CatBoost 训练</h3>
<div class="codehilite"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">models.catboost.model</span><span class="w"> </span><span class="kn">import</span> <span class="n">CatBoostModel</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">CatBoostModel</span><span class="p">(</span>
<span class="n">params</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;iterations&quot;</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span> <span class="s2">&quot;learning_rate&quot;</span><span class="p">:</span> <span class="mf">0.03</span><span class="p">,</span> <span class="s2">&quot;depth&quot;</span><span class="p">:</span> <span class="mi">5</span><span class="p">},</span>
<span class="n">eval_ratio</span><span class="o">=</span><span class="mf">0.2</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">model</span><span class="o">.</span><span class="n">fit</span><span class="p">(</span><span class="n">X_train</span><span class="p">,</span> <span class="n">y_train</span><span class="p">)</span>
<span class="n">pred</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">predict</span><span class="p">(</span><span class="n">X_test</span><span class="p">)</span>
</code></pre></div>
<h3 id="特征重要性">特征重要性</h3>
<div class="codehilite"><pre><span></span><code><span class="c1"># LightGBM</span>
<span class="n">imp</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">get_feature_importance</span><span class="p">(</span><span class="n">importance_type</span><span class="o">=</span><span class="s2">&quot;gain&quot;</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">imp</span><span class="o">.</span><span class="n">head</span><span class="p">(</span><span class="mi">10</span><span class="p">))</span>
<span class="c1"># → feature, importance, importance_pct</span>
<span class="c1"># CatBoost</span>
<span class="n">imp</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">get_feature_importance</span><span class="p">()</span>
<span class="nb">print</span><span class="p">(</span><span class="n">imp</span><span class="o">.</span><span class="n">head</span><span class="p">(</span><span class="mi">5</span><span class="p">))</span>
</code></pre></div>
<h3 id="交叉验证">交叉验证</h3>
<div class="codehilite"><pre><span></span><code><span class="c1"># 5 折时间序列 CV(不 shuffle</span>
<span class="n">cv_df</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">cv_evaluate</span><span class="p">(</span><span class="n">X_train</span><span class="p">,</span> <span class="n">y_train</span><span class="p">,</span> <span class="n">n_folds</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">cv_df</span><span class="p">)</span>
<span class="c1"># → 各折 IC + MSE, 均值</span>
</code></pre></div>
<h3 id="模型持久化">模型持久化</h3>
<div class="codehilite"><pre><span></span><code><span class="c1"># 保存</span>
<span class="n">model</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s2">&quot;models/lightgbm_000001.pkl&quot;</span><span class="p">)</span>
<span class="c1"># 加载</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">LightGBMModel</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="s2">&quot;models/lightgbm_000001.pkl&quot;</span><span class="p">)</span>
</code></pre></div>
<h3 id="ml-策略回测">ML 策略回测</h3>
<div class="codehilite"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">models.backtest_integration</span><span class="w"> </span><span class="kn">import</span> <span class="n">MLStrategy</span><span class="p">,</span> <span class="n">MLBenchmark</span>
<span class="c1"># 预测值分位 → 交易信号</span>
<span class="n">strategy</span> <span class="o">=</span> <span class="n">MLStrategy</span><span class="p">(</span>
<span class="n">model</span><span class="o">=</span><span class="n">model</span><span class="p">,</span>
<span class="n">feature_engine</span><span class="o">=</span><span class="n">fe</span><span class="p">,</span>
<span class="n">buy_quantile</span><span class="o">=</span><span class="mf">0.7</span><span class="p">,</span> <span class="c1"># 预测值最高的 30% 买入</span>
<span class="n">sell_quantile</span><span class="o">=</span><span class="mf">0.3</span><span class="p">,</span> <span class="c1"># 预测值最低的 30% 卖出</span>
<span class="n">rebalance_freq</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="c1"># 每 5 日调仓</span>
<span class="p">)</span>
<span class="n">report</span> <span class="o">=</span> <span class="n">engine_bt</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">strategy</span><span class="p">,</span> <span class="n">price_df</span><span class="p">,</span> <span class="n">factor_df</span><span class="p">)</span>
<span class="c1"># 多模型对比</span>
<span class="n">benchmark</span> <span class="o">=</span> <span class="n">MLBenchmark</span><span class="p">(</span>
<span class="n">models</span><span class="o">=</span><span class="p">[</span><span class="n">lgb_model</span><span class="p">,</span> <span class="n">cb_model</span><span class="p">],</span>
<span class="n">feature_engine</span><span class="o">=</span><span class="n">fe</span><span class="p">,</span>
<span class="n">price_df</span><span class="o">=</span><span class="n">test_price</span><span class="p">,</span>
<span class="n">factor_df</span><span class="o">=</span><span class="n">test_factor</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">df</span> <span class="o">=</span> <span class="n">benchmark</span><span class="o">.</span><span class="n">run</span><span class="p">()</span>
<span class="nb">print</span><span class="p">(</span><span class="n">df</span><span class="p">)</span>
<span class="c1"># → model × (IC, total_return, sharpe, win_rate, trades)</span>
</code></pre></div>
<hr />
<h2 id="8-情绪因子-sentimentengine">8. 情绪因子 — SentimentEngine</h2>
<h3 id="配置-api-key">配置 API Key</h3>
<p>编辑 <code>finance/.env</code></p>
<div class="codehilite"><pre><span></span><code><span class="c1"># DashScope API(推荐)</span>
<span class="nv">QWEN_API_KEY</span><span class="o">=</span>sk-your-key-here
<span class="nv">QWEN_MODEL</span><span class="o">=</span>qwen-turbo
<span class="c1"># 或本地 Ollama</span>
<span class="c1"># QWEN_LOCAL_BASE_URL=http://localhost:11434/v1</span>
<span class="c1"># QWEN_LOCAL_MODEL=qwen2.5:7b</span>
</code></pre></div>
<h3 id="配置分析范围">配置分析范围</h3>
<div class="codehilite"><pre><span></span><code><span class="c1"># 按指数成分股分析(沪深300 + 中证500)</span>
<span class="nv">SENTIMENT_SCOPE_TYPE</span><span class="o">=</span>index
<span class="nv">SENTIMENT_SCOPE_INDEXES</span><span class="o">=</span><span class="m">000300</span>,000905
<span class="c1"># 按板块分析</span>
<span class="c1"># SENTIMENT_SCOPE_TYPE=sector</span>
<span class="c1"># SENTIMENT_SCOPE_SECTORS=银行,电力设备,医药生物</span>
<span class="c1"># 按自定义列表</span>
<span class="c1"># SENTIMENT_SCOPE_TYPE=custom</span>
<span class="c1"># SENTIMENT_SCOPE_CUSTOM=000001.SZ,600519.SH,300750.SZ</span>
</code></pre></div>
<h3 id="使用情绪引擎">使用情绪引擎</h3>
<div class="codehilite"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">factors.sentiment.sentiment_engine</span><span class="w"> </span><span class="kn">import</span> <span class="n">SentimentEngine</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">factors.sentiment.news_source</span><span class="w"> </span><span class="kn">import</span> <span class="n">NewsSource</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">factors.sentiment.qwen_client</span><span class="w"> </span><span class="kn">import</span> <span class="n">QwenClient</span>
<span class="n">sent</span> <span class="o">=</span> <span class="n">SentimentEngine</span><span class="p">(</span><span class="n">dm</span><span class="p">,</span> <span class="n">qwen_client</span><span class="o">=</span><span class="n">QwenClient</span><span class="p">(),</span> <span class="n">news_source</span><span class="o">=</span><span class="n">NewsSource</span><span class="p">())</span>
<span class="c1"># 单股票情绪因子</span>
<span class="n">sent_df</span> <span class="o">=</span> <span class="n">sent</span><span class="o">.</span><span class="n">compute</span><span class="p">(</span><span class="s2">&quot;000001.SZ&quot;</span><span class="p">,</span> <span class="n">max_news</span><span class="o">=</span><span class="mi">20</span><span class="p">)</span>
<span class="c1"># → DataFrame: (trade_date, news_sent_5, news_conf_5, sent_delta_5)</span>
<span class="c1"># 批量计算</span>
<span class="n">results</span> <span class="o">=</span> <span class="n">sent</span><span class="o">.</span><span class="n">compute_batch</span><span class="p">(</span>
<span class="n">ts_codes</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;000001.SZ&quot;</span><span class="p">,</span> <span class="s2">&quot;600519.SH&quot;</span><span class="p">,</span> <span class="s2">&quot;300750.SZ&quot;</span><span class="p">],</span>
<span class="n">max_news</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span>
<span class="p">)</span>
</code></pre></div>
<h3 id="新闻数据源">新闻数据源</h3>
<p>系统聚合三个数据源:</p>
<table>
<thead>
<tr>
<th>数据源</th>
<th>说明</th>
<th>配置</th>
</tr>
</thead>
<tbody>
<tr>
<td>AkShare <code>stock_news_em</code></td>
<td>东方财富个股新闻</td>
<td><code>use_akshare=True</code></td>
</tr>
<tr>
<td>MariaDB <code>xwlb_daily_ext</code></td>
<td>新闻联播分割数据</td>
<td><code>use_xwlb=True</code></td>
</tr>
<tr>
<td>MCP <code>trendradar-news</code></td>
<td>外部新闻聚合服务</td>
<td><code>use_mcp=True</code></td>
</tr>
</tbody>
</table>
<div class="codehilite"><pre><span></span><code><span class="n">news</span> <span class="o">=</span> <span class="n">NewsSource</span><span class="p">(</span>
<span class="n">use_akshare</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="c1"># 启用东方财富</span>
<span class="n">use_xwlb</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="c1"># 启用新闻联播</span>
<span class="n">use_mcp</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="c1"># 关闭 MCP</span>
<span class="p">)</span>
<span class="n">news_df</span> <span class="o">=</span> <span class="n">news</span><span class="o">.</span><span class="n">fetch</span><span class="p">(</span><span class="s2">&quot;000001.SZ&quot;</span><span class="p">,</span> <span class="n">start</span><span class="o">=</span><span class="s2">&quot;20260501&quot;</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">&quot;20260603&quot;</span><span class="p">)</span>
<span class="c1"># → DataFrame: date, title, content, source, url</span>
</code></pre></div>
<h3 id="日期对齐机制">日期对齐机制</h3>
<ul>
<li><strong>AkShare 新闻</strong><code>发布时间</code> 直接保留 → <code>align_news_to_trading_days</code> 对齐到最近交易日</li>
<li><strong>新闻联播</strong><code>news_date + 1 day</code>(晚间播出 → 次日市场影响)→ 对齐到交易日</li>
</ul>
<div class="codehilite"><pre><span></span><code>周五新闻联播 → +1 = 周六 → align → 下周一交易日
</code></pre></div>
<hr />
<h2 id="9-agent-系统-命令行入口">9. Agent 系统 — 命令行入口</h2>
<h3 id="注册-agent">注册 Agent</h3>
<div class="codehilite"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">agents.orchestrator</span><span class="w"> </span><span class="kn">import</span> <span class="n">AgentOrchestrator</span>
<span class="n">engines</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">&quot;dm&quot;</span><span class="p">:</span> <span class="n">dm</span><span class="p">,</span>
<span class="s2">&quot;fe&quot;</span><span class="p">:</span> <span class="n">engine_fe</span><span class="p">,</span>
<span class="s2">&quot;bt&quot;</span><span class="p">:</span> <span class="n">engine_bt</span><span class="p">,</span>
<span class="s2">&quot;opt&quot;</span><span class="p">:</span> <span class="n">opt_engine</span><span class="p">,</span>
<span class="s2">&quot;sent&quot;</span><span class="p">:</span> <span class="n">sent</span><span class="p">,</span>
<span class="p">}</span>
<span class="n">orch</span> <span class="o">=</span> <span class="n">AgentOrchestrator</span><span class="p">(</span><span class="o">**</span><span class="n">engines</span><span class="p">)</span>
<span class="n">orch</span><span class="o">.</span><span class="n">setup</span><span class="p">()</span>
<span class="c1"># → [Orchestrator] 已注册 4 个 Agent: [&#39;research&#39;, &#39;selection&#39;, &#39;risk&#39;, &#39;report&#39;]</span>
</code></pre></div>
<h3 id="cli-命令">CLI 命令</h3>
<div class="codehilite"><pre><span></span><code><span class="c1"># 完整每日流程(同步行情 → 风险评估 → 选股打分 → 生成日报)</span>
python<span class="w"> </span>finance/cli/agent_cli.py<span class="w"> </span>daily
<span class="c1"># 今日选股 Top 15</span>
python<span class="w"> </span>finance/cli/agent_cli.py<span class="w"> </span>picks<span class="w"> </span><span class="m">15</span>
<span class="c1"># 风险评估</span>
python<span class="w"> </span>finance/cli/agent_cli.py<span class="w"> </span>risk
<span class="c1"># 因子研究(IC 评估)</span>
python<span class="w"> </span>finance/cli/agent_cli.py<span class="w"> </span>research
<span class="c1"># 生成指定日期日报</span>
python<span class="w"> </span>finance/cli/agent_cli.py<span class="w"> </span>report<span class="w"> </span><span class="m">20260603</span>
</code></pre></div>
<h3 id="每日流程输出">每日流程输出</h3>
<div class="codehilite"><pre><span></span><code><span class="o">============================================================</span>
<span class="o">[</span><span class="n">Orchestrator</span><span class="o">]</span><span class="w"> </span><span class="n">每日流程</span><span class="w"> </span><span class="err"></span><span class="w"> </span><span class="mi">20260603</span>
<span class="o">============================================================</span>
<span class="o">[</span><span class="n">Step 1/4</span><span class="o">]</span><span class="w"> </span><span class="n">同步行情</span><span class="p">...</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="n"></span><span class="err"></span><span class="n">已是最新</span><span class="err"></span>
<span class="o">[</span><span class="n">Step 2/4</span><span class="o">]</span><span class="w"> </span><span class="n">风险评估</span><span class="p">...</span><span class="w"> </span><span class="n">high</span><span class="p">,</span><span class="w"> </span><span class="n">仓位</span><span class="w"> </span><span class="mi">30</span><span class="o">%</span>
<span class="o">[</span><span class="n">Step 3/4</span><span class="o">]</span><span class="w"> </span><span class="n">股票打分</span><span class="p">...</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="n"></span>
<span class="o">[</span><span class="n">Step 4/4</span><span class="o">]</span><span class="w"> </span><span class="n">生成日报</span><span class="p">...</span><span class="w"> </span><span class="n">reports</span><span class="o">/</span><span class="n">daily_20260603</span><span class="p">.</span><span class="n">md</span>
</code></pre></div>
<h3 id="日报输出">日报输出</h3>
<p>日报保存到 <code>finance/reports/daily_YYYYMMDD.md</code>,内容包含:</p>
<ul>
<li><strong>市场概览</strong>:上证/深证/创业板 收盘价、涨跌幅、5日/20日趋势</li>
<li><strong>今日推荐</strong>TOP 15 股票打分排名</li>
<li><strong>风险评估</strong>:风险等级、建议仓位、止损线、预警</li>
</ul>
<h3 id="编程调用">编程调用</h3>
<div class="codehilite"><pre><span></span><code><span class="c1"># 各 Agent 独立调用</span>
<span class="n">selection_result</span> <span class="o">=</span> <span class="n">orch</span><span class="o">.</span><span class="n">picks</span><span class="p">(</span><span class="n">date</span><span class="o">=</span><span class="s2">&quot;20260603&quot;</span><span class="p">,</span> <span class="n">top_n</span><span class="o">=</span><span class="mi">15</span><span class="p">)</span>
<span class="n">risk_result</span> <span class="o">=</span> <span class="n">orch</span><span class="o">.</span><span class="n">risk_check</span><span class="p">()</span>
<span class="n">research_result</span> <span class="o">=</span> <span class="n">orch</span><span class="o">.</span><span class="n">run_research_cycle</span><span class="p">()</span>
<span class="n">report_result</span> <span class="o">=</span> <span class="n">orch</span><span class="o">.</span><span class="n">generate_report</span><span class="p">(</span><span class="n">date</span><span class="o">=</span><span class="s2">&quot;20260603&quot;</span><span class="p">)</span>
</code></pre></div>
<hr />
<h2 id="10-配置说明">10. 配置说明</h2>
<h3 id="环境变量financeenv">环境变量(<code>finance/.env</code></h3>
<div class="codehilite"><pre><span></span><code><span class="c1"># ── Qwen API ──────────────────────</span>
<span class="nv">QWEN_API_KEY</span><span class="o">=</span>sk-xxx<span class="w"> </span><span class="c1"># DashScope API Key</span>
<span class="nv">QWEN_MODEL</span><span class="o">=</span>qwen-turbo<span class="w"> </span><span class="c1"># 模型选择: qwen-turbo/plus/max</span>
<span class="c1"># ── 本地 Ollama(可选) ──────────</span>
<span class="c1"># QWEN_LOCAL_BASE_URL=http://localhost:11434/v1</span>
<span class="c1"># QWEN_LOCAL_MODEL=qwen2.5:7b</span>
<span class="c1"># ── 数据库 ───────────────────────</span>
<span class="nv">MAC_DB_HOST</span><span class="o">=</span><span class="m">127</span>.0.0.1
<span class="nv">MAC_DB_PORT</span><span class="o">=</span><span class="m">13306</span>
<span class="nv">MAC_DB_USER</span><span class="o">=</span>myquant
<span class="nv">MAC_DB_PASSWORD</span><span class="o">=</span>&lt;your-db-password&gt;
<span class="nv">MAC_DB_NAME</span><span class="o">=</span>myquant
<span class="c1"># ── 情绪分析范围 ─────────────────</span>
<span class="nv">SENTIMENT_SCOPE_TYPE</span><span class="o">=</span>index
<span class="nv">SENTIMENT_SCOPE_INDEXES</span><span class="o">=</span><span class="m">000300</span>,000905
<span class="nv">SENTIMENT_MAX_NEWS_PER_STOCK</span><span class="o">=</span><span class="m">20</span>
<span class="c1"># ── MCP 新闻服务(可选) ─────────</span>
<span class="nv">NEWS_MCP_URL</span><span class="o">=</span>http://192.168.1.160:3333/mcp
</code></pre></div>
<h3 id="回测参数">回测参数</h3>
<div class="codehilite"><pre><span></span><code><span class="n">VectorBTEngine</span><span class="p">(</span>
<span class="n">initial_capital</span><span class="o">=</span><span class="mi">100_000</span><span class="p">,</span> <span class="c1"># 初始资金(元)</span>
<span class="n">commission</span><span class="o">=</span><span class="mf">0.0003</span><span class="p">,</span> <span class="c1"># 手续费(万三)</span>
<span class="p">)</span>
</code></pre></div>
<h3 id="optuna-参数">Optuna 参数</h3>
<div class="codehilite"><pre><span></span><code><span class="n">opt_engine</span><span class="o">.</span><span class="n">optimize</span><span class="p">(</span>
<span class="n">n_trials</span><span class="o">=</span><span class="mi">200</span><span class="p">,</span> <span class="c1"># 试验次数</span>
<span class="n">metric</span><span class="o">=</span><span class="s2">&quot;sharpe&quot;</span><span class="p">,</span> <span class="c1"># 优化目标</span>
<span class="c1"># 可选: cagr, calmar, total_return, return_over_dd, win_rate, profit_factor</span>
<span class="p">)</span>
</code></pre></div>
<h3 id="ml-模型参数">ML 模型参数</h3>
<div class="codehilite"><pre><span></span><code><span class="c1"># LightGBM 推荐参数</span>
<span class="n">LightGBMModel</span><span class="p">(</span><span class="n">params</span><span class="o">=</span><span class="p">{</span>
<span class="s2">&quot;n_estimators&quot;</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span>
<span class="s2">&quot;learning_rate&quot;</span><span class="p">:</span> <span class="mf">0.03</span><span class="p">,</span>
<span class="s2">&quot;num_leaves&quot;</span><span class="p">:</span> <span class="mi">15</span><span class="p">,</span>
<span class="s2">&quot;min_data_in_leaf&quot;</span><span class="p">:</span> <span class="mi">20</span><span class="p">,</span>
<span class="s2">&quot;feature_fraction&quot;</span><span class="p">:</span> <span class="mf">0.7</span><span class="p">,</span>
<span class="s2">&quot;bagging_fraction&quot;</span><span class="p">:</span> <span class="mf">0.7</span><span class="p">,</span>
<span class="p">})</span>
<span class="c1"># CatBoost 推荐参数</span>
<span class="n">CatBoostModel</span><span class="p">(</span><span class="n">params</span><span class="o">=</span><span class="p">{</span>
<span class="s2">&quot;iterations&quot;</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span>
<span class="s2">&quot;learning_rate&quot;</span><span class="p">:</span> <span class="mf">0.03</span><span class="p">,</span>
<span class="s2">&quot;depth&quot;</span><span class="p">:</span> <span class="mi">5</span><span class="p">,</span>
<span class="s2">&quot;min_data_in_leaf&quot;</span><span class="p">:</span> <span class="mi">20</span><span class="p">,</span>
<span class="p">})</span>
</code></pre></div>
<hr />
<h2 id="11-完整示例">11. 完整示例</h2>
<h3 id="示例-1快速回测">示例 1:快速回测</h3>
<div class="codehilite"><pre><span></span><code><span class="kn">import</span><span class="w"> </span><span class="nn">sys</span><span class="p">;</span> <span class="n">sys</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="s2">&quot;finance&quot;</span><span class="p">)</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">data.data_manager</span><span class="w"> </span><span class="kn">import</span> <span class="n">DataManager</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">factors.registry</span><span class="w"> </span><span class="kn">import</span> <span class="n">get_factor</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">factors.engine</span><span class="w"> </span><span class="kn">import</span> <span class="n">FactorEngine</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">backtest.vectorbt.engine</span><span class="w"> </span><span class="kn">import</span> <span class="n">VectorBTEngine</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">backtest.strategies.rsi_mean_revert</span><span class="w"> </span><span class="kn">import</span> <span class="n">RSIMeanRevertStrategy</span>
<span class="c1"># 数据</span>
<span class="n">dm</span> <span class="o">=</span> <span class="n">DataManager</span><span class="p">();</span> <span class="n">dm</span><span class="o">.</span><span class="n">init_db</span><span class="p">()</span>
<span class="n">price</span> <span class="o">=</span> <span class="n">dm</span><span class="o">.</span><span class="n">get_daily</span><span class="p">(</span><span class="s2">&quot;000001.SZ&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">set_index</span><span class="p">(</span><span class="s2">&quot;trade_date&quot;</span><span class="p">)</span>
<span class="c1"># 因子</span>
<span class="n">engine_fe</span> <span class="o">=</span> <span class="n">FactorEngine</span><span class="p">(</span><span class="n">dm</span><span class="p">)</span>
<span class="n">factor_df</span> <span class="o">=</span> <span class="n">engine_fe</span><span class="o">.</span><span class="n">compute</span><span class="p">(</span><span class="s2">&quot;000001.SZ&quot;</span><span class="p">,</span> <span class="p">[</span><span class="n">get_factor</span><span class="p">(</span><span class="s2">&quot;rsi_14&quot;</span><span class="p">)])</span>
<span class="c1"># 回测</span>
<span class="n">engine_bt</span> <span class="o">=</span> <span class="n">VectorBTEngine</span><span class="p">()</span>
<span class="n">report</span> <span class="o">=</span> <span class="n">engine_bt</span><span class="o">.</span><span class="n">run</span><span class="p">(</span>
<span class="n">RSIMeanRevertStrategy</span><span class="p">(</span><span class="n">oversold</span><span class="o">=</span><span class="mi">30</span><span class="p">,</span> <span class="n">overbought</span><span class="o">=</span><span class="mi">70</span><span class="p">),</span>
<span class="n">price</span><span class="p">,</span> <span class="n">factor_df</span><span class="p">,</span>
<span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">report</span><span class="o">.</span><span class="n">summary</span><span class="p">())</span>
</code></pre></div>
<h3 id="示例-2策略寻优-walk-forward">示例 2:策略寻优 + Walk-Forward</h3>
<div class="codehilite"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">optimizer.engine</span><span class="w"> </span><span class="kn">import</span> <span class="n">OptunaEngine</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">optimizer.space</span><span class="w"> </span><span class="kn">import</span> <span class="n">rsi_revert_space</span>
<span class="n">opt_engine</span> <span class="o">=</span> <span class="n">OptunaEngine</span><span class="p">(</span><span class="n">engine_bt</span><span class="p">)</span>
<span class="c1"># 寻优</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">opt_engine</span><span class="o">.</span><span class="n">optimize</span><span class="p">(</span>
<span class="n">RSIMeanRevertStrategy</span><span class="p">,</span> <span class="n">rsi_revert_space</span><span class="p">,</span>
<span class="n">price</span><span class="p">,</span> <span class="n">factor_df</span><span class="p">,</span> <span class="n">metric</span><span class="o">=</span><span class="s2">&quot;sharpe&quot;</span><span class="p">,</span> <span class="n">n_trials</span><span class="o">=</span><span class="mi">200</span><span class="p">,</span>
<span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">result</span><span class="o">.</span><span class="n">summary</span><span class="p">())</span>
<span class="c1"># Walk-Forward 验证</span>
<span class="n">wf</span> <span class="o">=</span> <span class="n">opt_engine</span><span class="o">.</span><span class="n">optimize_walk_forward</span><span class="p">(</span>
<span class="n">RSIMeanRevertStrategy</span><span class="p">,</span> <span class="n">rsi_revert_space</span><span class="p">,</span>
<span class="n">price</span><span class="p">,</span> <span class="n">factor_df</span><span class="p">,</span> <span class="n">n_trials</span><span class="o">=</span><span class="mi">80</span><span class="p">,</span>
<span class="n">train_window</span><span class="o">=</span><span class="mi">756</span><span class="p">,</span> <span class="n">test_window</span><span class="o">=</span><span class="mi">252</span><span class="p">,</span>
<span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">wf</span><span class="o">.</span><span class="n">summary</span><span class="p">())</span>
</code></pre></div>
<h3 id="示例-3ml-训练-回测">示例 3ML 训练 + 回测</h3>
<div class="codehilite"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">models.features</span><span class="w"> </span><span class="kn">import</span> <span class="n">FeatureEngine</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">models.lightgbm.model</span><span class="w"> </span><span class="kn">import</span> <span class="n">LightGBMModel</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">models.backtest_integration</span><span class="w"> </span><span class="kn">import</span> <span class="n">MLStrategy</span>
<span class="c1"># 特征工程</span>
<span class="n">fe</span> <span class="o">=</span> <span class="n">FeatureEngine</span><span class="p">(</span><span class="n">lookahead</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span>
<span class="n">X</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">fe</span><span class="o">.</span><span class="n">build</span><span class="p">(</span><span class="n">factor_df</span><span class="p">,</span> <span class="n">price</span><span class="p">,</span> <span class="n">fit</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">split</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">X</span><span class="p">)</span> <span class="o">*</span> <span class="mf">0.7</span><span class="p">)</span>
<span class="c1"># 训练</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">LightGBMModel</span><span class="p">(</span><span class="n">params</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;n_estimators&quot;</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span> <span class="s2">&quot;learning_rate&quot;</span><span class="p">:</span> <span class="mf">0.03</span><span class="p">})</span>
<span class="n">model</span><span class="o">.</span><span class="n">fit</span><span class="p">(</span><span class="n">X</span><span class="o">.</span><span class="n">iloc</span><span class="p">[:</span><span class="n">split</span><span class="p">],</span> <span class="n">y</span><span class="o">.</span><span class="n">iloc</span><span class="p">[:</span><span class="n">split</span><span class="p">])</span>
<span class="c1"># 回测</span>
<span class="n">strategy</span> <span class="o">=</span> <span class="n">MLStrategy</span><span class="p">(</span><span class="n">model</span><span class="p">,</span> <span class="n">fe</span><span class="p">)</span>
<span class="n">report</span> <span class="o">=</span> <span class="n">engine_bt</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">strategy</span><span class="p">,</span> <span class="n">price</span><span class="p">,</span> <span class="n">factor_df</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">report</span><span class="o">.</span><span class="n">summary</span><span class="p">())</span>
<span class="nb">print</span><span class="p">(</span><span class="n">model</span><span class="o">.</span><span class="n">get_feature_importance</span><span class="p">()</span><span class="o">.</span><span class="n">head</span><span class="p">(</span><span class="mi">5</span><span class="p">))</span>
</code></pre></div>
<h3 id="示例-4每日-agent-运行">示例 4:每日 Agent 运行</h3>
<div class="codehilite"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">agents.orchestrator</span><span class="w"> </span><span class="kn">import</span> <span class="n">AgentOrchestrator</span>
<span class="n">orch</span> <span class="o">=</span> <span class="n">AgentOrchestrator</span><span class="p">(</span>
<span class="n">dm</span><span class="o">=</span><span class="n">dm</span><span class="p">,</span> <span class="n">fe</span><span class="o">=</span><span class="n">engine_fe</span><span class="p">,</span> <span class="n">bt</span><span class="o">=</span><span class="n">engine_bt</span><span class="p">,</span> <span class="n">opt</span><span class="o">=</span><span class="n">opt_engine</span><span class="p">,</span> <span class="n">sent</span><span class="o">=</span><span class="n">sent</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">orch</span><span class="o">.</span><span class="n">setup</span><span class="p">()</span>
<span class="n">results</span> <span class="o">=</span> <span class="n">orch</span><span class="o">.</span><span class="n">run_daily</span><span class="p">()</span>
<span class="c1"># 获取结果</span>
<span class="n">sel</span> <span class="o">=</span> <span class="n">results</span><span class="p">[</span><span class="s2">&quot;selection&quot;</span><span class="p">]</span>
<span class="n">risk</span> <span class="o">=</span> <span class="n">results</span><span class="p">[</span><span class="s2">&quot;risk&quot;</span><span class="p">]</span>
<span class="n">report_path</span> <span class="o">=</span> <span class="n">results</span><span class="p">[</span><span class="s2">&quot;report&quot;</span><span class="p">][</span><span class="s2">&quot;report_path&quot;</span><span class="p">]</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;日报: </span><span class="si">{</span><span class="n">report_path</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
</code></pre></div>
<hr />
<h2 id="12-常见问题">12. 常见问题</h2>
<h3 id="q-ssh-隧道连接失败">Q: SSH 隧道连接失败?</h3>
<div class="codehilite"><pre><span></span><code><span class="c1"># 检查端口</span>
lsof<span class="w"> </span>-i<span class="w"> </span>:13306<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>LISTEN
<span class="c1"># 重新建立</span>
bash<span class="w"> </span>shared/script/autossh.sh
</code></pre></div>
<h3 id="q-akshare-返回-remotedisconnected">Q: AkShare 返回 RemoteDisconnected</h3>
<p>这是 AkShare 的 curl_cffi 在连续请求时偶发的连接问题。系统已内置 3 次递增间隔重试 + fallback 机制,通常第 2-3 次重试会成功。如果持续失败:</p>
<ul>
<li>等待 30 秒后重试</li>
<li>减少并发请求频率</li>
<li>检查网络是否能访问 eastmoney.com</li>
</ul>
<h3 id="q-因子计算结果全是-nan">Q: 因子计算结果全是 NaN</h3>
<ul>
<li>技术因子:前 N 个周期内 NaN 是正常的(如 20 日动量前 19 天为 NaN)</li>
<li>基本面因子:检查财务数据是否已同步(<code>dm.get_financial(ts_code)</code></li>
<li>情绪因子:检查是否配置了 <code>QWEN_API_KEY</code></li>
</ul>
<h3 id="q-回测结果为-0-笔交易">Q: 回测结果为 0 笔交易?</h3>
<ul>
<li>检查策略参数是否过于严格(如 RSI oversold=10 过少触发)</li>
<li>使用 <code>OptunaEngine.optimize()</code> 寻找更优参数</li>
<li>检查因子值是否合理(<code>factor_df.describe()</code></li>
</ul>
<h3 id="q-模型训练只有-2-棵树">Q: 模型训练只有 2 棵树?</h3>
<p>当验证集损失不下降时,早停会在很少的迭代后触发。这是单股票预测的正常现象(信号噪声比低)。建议:</p>
<ul>
<li>设置 <code>eval_ratio=0.0</code> 禁用早停</li>
<li>降低 <code>learning_rate</code> 到 0.01</li>
<li>增加 <code>min_data_in_leaf</code> 防止过拟合</li>
</ul>
<h3 id="q-情绪因子返回空">Q: 情绪因子返回空?</h3>
<ul>
<li>确认 <code>.env</code><code>QWEN_API_KEY</code> 已配置</li>
<li>检查网络是否能访问 <code>dashscope.aliyuncs.com</code></li>
<li>如果使用本地 Ollama,确认服务运行中:<code>curl http://localhost:11434/api/tags</code></li>
</ul>
<h3 id="q-日报中选股为空">Q: 日报中选股为空?</h3>
<p>日报只对 DB 中有日线缓存的股票打分。需要先同步目标股票池的数据:</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># 同步单只</span>
<span class="n">dm</span><span class="o">.</span><span class="n">sync_daily</span><span class="p">(</span><span class="s2">&quot;000001.SZ&quot;</span><span class="p">)</span>
<span class="c1"># 按范围批量同步(需先配置 SENTIMENT_SCOPE</span>
<span class="n">codes</span> <span class="o">=</span> <span class="n">sent</span><span class="o">.</span><span class="n">get_scope_stocks</span><span class="p">()</span>
<span class="k">for</span> <span class="n">code</span> <span class="ow">in</span> <span class="n">codes</span><span class="p">[:</span><span class="mi">10</span><span class="p">]:</span>
<span class="n">dm</span><span class="o">.</span><span class="n">sync_daily</span><span class="p">(</span><span class="n">code</span><span class="p">)</span>
</code></pre></div>
<hr />
<h2 id="13-cli-脚本参考">13. CLI 脚本参考</h2>
<p>所有脚本位于 <code>finance/cli/</code>,需在项目根目录或 <code>finance/</code> 下运行。</p>
<hr />
<h3 id="131-agent-系统入口-agent-clipy">13.1 Agent 系统入口 — <code>agent_cli.py</code></h3>
<div class="codehilite"><pre><span></span><code><span class="nb">cd</span><span class="w"> </span>finance<span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span>python<span class="w"> </span>cli/agent_cli.py<span class="w"> </span>&lt;命令&gt;<span class="w"> </span><span class="o">[</span>参数<span class="o">]</span>
</code></pre></div>
<table>
<thead>
<tr>
<th>命令</th>
<th>说明</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>daily [DATE]</code></td>
<td>完整每日流程(增量同步已缓存→评估风险→选股→日报)</td>
<td><code>agent_cli.py daily</code></td>
</tr>
<tr>
<td><code>picks [N] [DATE]</code></td>
<td>多因子选股 Top N(需已缓存)</td>
<td><code>agent_cli.py picks 15</code></td>
</tr>
<tr>
<td><code>risk</code></td>
<td>市场风险评估(等级、仓位、止损)</td>
<td><code>agent_cli.py risk</code></td>
</tr>
<tr>
<td><code>research</code></td>
<td>因子发现:遍历因子计算 IC/IC_IR 排名</td>
<td><code>agent_cli.py research</code></td>
</tr>
<tr>
<td><code>report [DATE]</code></td>
<td>生成日报(含三指数行情+选股+情绪+风险评估)</td>
<td><code>agent_cli.py report</code></td>
</tr>
<tr>
<td><code>warmup [N]</code></td>
<td>首次批量预热范围股票到 DB 缓存(每批 N 只,默认 50)</td>
<td><code>agent_cli.py warmup 50</code></td>
</tr>
</tbody>
</table>
<p><strong><code>daily</code> 流程</strong></p>
<div class="codehilite"><pre><span></span><code>[Step 1/4] 增量同步 → 只更新已缓存股票(最新则 0.04s 跳过)
→ 未缓存提示:运行 &#39;agent_cli.py warmup&#39; 首次预热
[Step 2/4] 风险评估 → high/medium/low + 仓位建议 + 预警
[Step 3/4] 股票打分 → DB 缓存命中率 + 多因子等权打分 → Top 15
[Step 4/4] 日报生成 → 三指数行情 (Tushare) + 情绪摘要 + 风险预警
→ reports/daily_YYYYMMDD.md
</code></pre></div>
<p><strong>数据源优先级</strong>Tushare → AkShare<code>.env</code> 配置 <code>TUSHARE_TOKEN</code></p>
<hr />
<h3 id="132-数据层验证-demo-data-managerpy">13.2 数据层验证 — <code>demo_data_manager.py</code></h3>
<div class="codehilite"><pre><span></span><code>python<span class="w"> </span>cli/demo_data_manager.py<span class="w"> </span><span class="o">[</span>--ts_code<span class="w"> </span>CODE<span class="o">]</span><span class="w"> </span><span class="o">[</span>--start<span class="w"> </span>YYYYMMDD<span class="o">]</span>
</code></pre></div>
<table>
<thead>
<tr>
<th>参数</th>
<th>默认值</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>--ts_code</code></td>
<td><code>000001.SZ</code></td>
<td>测试股票代码</td>
</tr>
<tr>
<td><code>--start</code></td>
<td><code>20250101</code></td>
<td>起始日期 YYYYMMDD</td>
</tr>
</tbody>
</table>
<p>5 步验证:数据库连接 → 建表 → 股票列表 → 日线获取(双源fallback) → 增量同步。</p>
<hr />
<h3 id="133-因子引擎验证-demo-factor-enginepy">13.3 因子引擎验证 — <code>demo_factor_engine.py</code></h3>
<div class="codehilite"><pre><span></span><code>python<span class="w"> </span>cli/demo_factor_engine.py<span class="w"> </span><span class="o">[</span>--ts_code<span class="w"> </span>CODE<span class="o">]</span><span class="w"> </span><span class="o">[</span>--ts_code2<span class="w"> </span>CODE<span class="o">]</span>
</code></pre></div>
<table>
<thead>
<tr>
<th>参数</th>
<th>默认值</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>--ts_code</code></td>
<td><code>000001.SZ</code></td>
<td>测试股票代码</td>
</tr>
<tr>
<td><code>--ts_code2</code></td>
<td><code>600519.SH</code></td>
<td>截面测试第二只股票</td>
</tr>
</tbody>
</table>
<p>验证:因子注册表(12分类/34因子)→ 技术因子计算(describe统计) → 基本面因子(ROE/PE/PB/EP) → NaN 覆盖率检查 → 双股票截面因子。</p>
<hr />
<h3 id="134-回测引擎验证-demo-backtestpy">13.4 回测引擎验证 — <code>demo_backtest.py</code></h3>
<div class="codehilite"><pre><span></span><code>python<span class="w"> </span>cli/demo_backtest.py<span class="w"> </span><span class="o">[</span>--ts_code<span class="w"> </span>CODE<span class="o">]</span>
</code></pre></div>
<table>
<thead>
<tr>
<th>参数</th>
<th>默认值</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>--ts_code</code></td>
<td><code>000001.SZ</code></td>
<td>回测股票代码</td>
</tr>
</tbody>
</table>
<p>测试 5 个内置策略:</p>
<table>
<thead>
<tr>
<th>策略</th>
<th>参数</th>
</tr>
</thead>
<tbody>
<tr>
<td>SMACrossStrategy</td>
<td>(5,20) / (10,60)</td>
</tr>
<tr>
<td>RSIMeanRevertStrategy</td>
<td>(30,70) / (20,80)</td>
</tr>
<tr>
<td>MomentumBreakoutStrategy</td>
<td>lookback=20</td>
</tr>
<tr>
<td>FactorCrossStrategy</td>
<td>momentum_20 &gt; 0</td>
</tr>
<tr>
<td>FactorRotationStrategy</td>
<td>momentum top 20%</td>
</tr>
</tbody>
</table>
<hr />
<h3 id="135-参数优化验证-demo-optimizerpy">13.5 参数优化验证 — <code>demo_optimizer.py</code></h3>
<div class="codehilite"><pre><span></span><code>python<span class="w"> </span>cli/demo_optimizer.py<span class="w"> </span><span class="o">[</span>--ts_code<span class="w"> </span>CODE<span class="o">]</span><span class="w"> </span><span class="o">[</span>--trials<span class="w"> </span>N<span class="o">]</span>
</code></pre></div>
<table>
<thead>
<tr>
<th>参数</th>
<th>默认值</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>--ts_code</code></td>
<td><code>000001.SZ</code></td>
<td>回测股票代码</td>
</tr>
<tr>
<td><code>--trials</code></td>
<td><code>200</code></td>
<td>Optuna 试验次数</td>
</tr>
</tbody>
</table>
<p>对 RSI 反转策略执行参数寻优 + Walk-Forward 验证。输出最优 vs 默认对比表 + 参数重要性排序。</p>
<hr />
<h3 id="136-ml-模型验证-demo-mlpy">13.6 ML 模型验证 — <code>demo_ml.py</code></h3>
<div class="codehilite"><pre><span></span><code>python<span class="w"> </span>cli/demo_ml.py<span class="w"> </span><span class="o">[</span>--ts_code<span class="w"> </span>CODE<span class="o">]</span><span class="w"> </span><span class="o">[</span>--lookahead<span class="w"> </span>N<span class="o">]</span>
</code></pre></div>
<table>
<thead>
<tr>
<th>参数</th>
<th>默认值</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>--ts_code</code></td>
<td><code>000001.SZ</code></td>
<td>训练股票代码</td>
</tr>
<tr>
<td><code>--lookahead</code></td>
<td><code>5</code></td>
<td>预测未来 N 日收益</td>
</tr>
</tbody>
</table>
<p>完整 ML pipeline:特征工程(25因子→Winsorize→RobustScaler) → LightGBM训练(IC/CV) → CatBoost训练 → MLBenchmark对比(IC/收益/夏普/胜率)。</p>
<hr />
<h3 id="137-情绪因子快速验证-demo-sentimentpy">13.7 情绪因子快速验证 — <code>demo_sentiment.py</code></h3>
<div class="codehilite"><pre><span></span><code>python<span class="w"> </span>cli/demo_sentiment.py<span class="w"> </span><span class="o">[</span>--ts_code<span class="w"> </span>CODE<span class="o">]</span><span class="w"> </span><span class="o">[</span>--no-qwen<span class="o">]</span>
</code></pre></div>
<table>
<thead>
<tr>
<th>参数</th>
<th>默认值</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>--ts_code</code></td>
<td><code>000001.SZ</code></td>
<td>测试股票代码</td>
</tr>
<tr>
<td><code>--no-qwen</code></td>
<td>flag</td>
<td>跳过 Qwen API 调用</td>
</tr>
</tbody>
</table>
<p>6 步验证:新闻数据源(三源聚合) → 日期对齐 → Qwen 客户端状态 → SentimentEngine全链路 → 分析范围解析。</p>
<p>适合快速检查情绪因子系统是否就绪。</p>
<hr />
<h3 id="138-情绪因子详细演示-demo-sentiment-detailpy">13.8 情绪因子详细演示 — <code>demo_sentiment_detail.py</code></h3>
<div class="codehilite"><pre><span></span><code>python<span class="w"> </span>cli/demo_sentiment_detail.py<span class="w"> </span><span class="o">[</span>选项<span class="o">]</span>
</code></pre></div>
<p>最详细的情绪因子脚本,支持完整命令行参数和逐步输出。</p>
<table>
<thead>
<tr>
<th>参数</th>
<th>类型</th>
<th>默认值</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>--ts_code</code></td>
<td>str</td>
<td><code>000001.SZ</code></td>
<td>股票代码,多个用逗号分隔</td>
</tr>
<tr>
<td><code>--date</code></td>
<td>str</td>
<td>今天</td>
<td>目标日期 YYYYMMDD</td>
</tr>
<tr>
<td><code>--start</code></td>
<td>str</td>
<td>date-30天</td>
<td>起始日期 YYYYMMDD</td>
</tr>
<tr>
<td><code>--end</code></td>
<td>str</td>
<td>date</td>
<td>结束日期 YYYYMMDD</td>
</tr>
<tr>
<td><code>--scope-type</code></td>
<td>str</td>
<td>-</td>
<td>分析范围:<code>index</code>/<code>sector</code>/<code>custom</code>/<code>all</code></td>
</tr>
<tr>
<td><code>--scope-indexes</code></td>
<td>str</td>
<td><code>000300</code></td>
<td>指数代码(逗号分隔)</td>
</tr>
<tr>
<td><code>--scope-sectors</code></td>
<td>str</td>
<td>-</td>
<td>板块名称(逗号分隔)</td>
</tr>
<tr>
<td><code>--max-news</code></td>
<td>int</td>
<td>.env 配置</td>
<td>最大新闻条数</td>
</tr>
<tr>
<td><code>--max-analyze</code></td>
<td>int</td>
<td><code>50</code></td>
<td>Qwen API 分析最大条数(控制成本)</td>
</tr>
<tr>
<td><code>--no-xwlb</code></td>
<td>flag</td>
<td>-</td>
<td>禁用新闻联播数据源</td>
</tr>
<tr>
<td><code>--no-akshare</code></td>
<td>flag</td>
<td>-</td>
<td>禁用东方财富数据源</td>
</tr>
<tr>
<td><code>--no-mcp</code></td>
<td>flag</td>
<td>-</td>
<td>禁用 MCP 数据源</td>
</tr>
<tr>
<td><code>--source</code></td>
<td>str</td>
<td>-</td>
<td>仅用指定数据源:<code>xwlb</code>/<code>akshare</code>/<code>mcp</code></td>
</tr>
<tr>
<td><code>--no-qwen</code></td>
<td>flag</td>
<td>-</td>
<td>跳过 Qwen API 调用(仅演示数据流)</td>
</tr>
</tbody>
</table>
<p>使用示例:</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># 默认演示(000001.SZ,最近30天,全数据源)</span>
python<span class="w"> </span>cli/demo_sentiment_detail.py
<span class="c1"># 指定股票和日期</span>
python<span class="w"> </span>cli/demo_sentiment_detail.py<span class="w"> </span>--ts_code<span class="w"> </span><span class="m">600519</span>.SH<span class="w"> </span>--date<span class="w"> </span><span class="m">20260603</span>
<span class="c1"># 多股票 + 日期范围</span>
python<span class="w"> </span>cli/demo_sentiment_detail.py<span class="w"> </span>--ts_code<span class="w"> </span><span class="m">000001</span>.SZ,300316.SZ<span class="w"> </span>--start<span class="w"> </span><span class="m">20260501</span><span class="w"> </span>--end<span class="w"> </span><span class="m">20260603</span>
<span class="c1"># 按指数成分股分析</span>
python<span class="w"> </span>cli/demo_sentiment_detail.py<span class="w"> </span>--scope-type<span class="w"> </span>index<span class="w"> </span>--scope-indexes<span class="w"> </span><span class="m">000300</span>
<span class="c1"># 按板块分析</span>
python<span class="w"> </span>cli/demo_sentiment_detail.py<span class="w"> </span>--scope-type<span class="w"> </span>sector<span class="w"> </span>--scope-sectors<span class="w"> </span>银行,电力设备
<span class="c1"># 只看东方财富新闻,不调用 Qwen</span>
python<span class="w"> </span>cli/demo_sentiment_detail.py<span class="w"> </span>--source<span class="w"> </span>akshare<span class="w"> </span>--no-qwen<span class="w"> </span>--max-news<span class="w"> </span><span class="m">20</span>
</code></pre></div>
<p>输出 6 步详情:</p>
<div class="codehilite"><pre><span></span><code>Step 0: 初始化引擎(显示数据源、API状态、范围、Tushare可用性)
Step 1: 按数据源分别拉取新闻(xwlb/AkShare/MCP 各自数量 + 双源fallback
Step 2: 新闻详情(按来源分开展示标题/内容/链接)
Step 3: 日期对齐(xwlb +1day偏移 + 非交易日对齐 + DB缓存检查→sync补齐)
Step 4: Qwen 情绪分析(每条新闻的分数/置信度/主题/来源标签)
Step 5: 因子计算(weighted sent / confidence-weighted / momentum + 公式说明)
Step 6: 结果输出(因子值表 + 历史统计 + 每新闻情绪贡献明细)
</code></pre></div>
<hr />
<h3 id="139-脚本一览">13.9 脚本一览</h3>
<table>
<thead>
<tr>
<th>脚本</th>
<th>参数</th>
<th>用途</th>
<th style="text-align: center;">数据源 fallback</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>agent_cli.py</code></td>
<td>子命令 + 参数</td>
<td>日常操作入口</td>
<td style="text-align: center;"></td>
</tr>
<tr>
<td><code>demo_data_manager.py</code></td>
<td><code>--ts_code</code> <code>--start</code></td>
<td>Sprint 0 验证</td>
<td style="text-align: center;"></td>
</tr>
<tr>
<td><code>demo_factor_engine.py</code></td>
<td><code>--ts_code</code> <code>--ts_code2</code></td>
<td>Sprint 1 验证</td>
<td style="text-align: center;"></td>
</tr>
<tr>
<td><code>demo_backtest.py</code></td>
<td><code>--ts_code</code></td>
<td>Sprint 2 验证</td>
<td style="text-align: center;"></td>
</tr>
<tr>
<td><code>demo_optimizer.py</code></td>
<td><code>--ts_code</code> <code>--trials</code></td>
<td>Sprint 3 验证</td>
<td style="text-align: center;"></td>
</tr>
<tr>
<td><code>demo_ml.py</code></td>
<td><code>--ts_code</code> <code>--lookahead</code></td>
<td>Sprint 4 验证</td>
<td style="text-align: center;"></td>
</tr>
<tr>
<td><code>demo_sentiment.py</code></td>
<td><code>--ts_code</code> <code>--no-qwen</code></td>
<td>Sprint 5 快速验证</td>
<td style="text-align: center;"></td>
</tr>
<tr>
<td><code>demo_sentiment_detail.py</code></td>
<td>14 个 argparse 参数</td>
<td>Sprint 5 详细演示</td>
<td style="text-align: center;"></td>
</tr>
</tbody>
</table>
</div>
</body>
</html>