7 Sprints 全部完成: Sprint 0: 基础设施 (DataManager + MariaDB) Sprint 1: 因子引擎 (34因子/12分类) Sprint 2: VectorBT 回测 (5策略+截面) Sprint 3: Optuna 优化 (+Walk-Forward) Sprint 4: ML 模型 (LightGBM+CatBoost) Sprint 5: Qwen 情绪因子 (三源新闻+日期对齐) Sprint 6: Agent 系统 (4Agent+日报.md/.html) 生产加固 (15项): Tushare双源fallback, SSH自动恢复, pool_pre_ping, save_daily先删后插, load_dotenv绝对路径, 日报5d/20d修复, RiskAgent改上证指数, 昨日对比+数据截止, mac_report utf8mb4, CLAUDE-*.md 9条已知Bug, demo全参数化, djapi数据源归一化, indexDatas API修正 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1512 lines
100 KiB
HTML
1512 lines
100 KiB
HTML
<!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-训练-回测">示例 3:ML 训练 + 回测</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">"/path/to/cc-cursor/finance"</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: <your-db-password>
|
||
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">"数据库连接成功"</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">"请先建立 SSH 隧道: bash shared/script/autossh.sh"</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">"000001.SZ"</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">"000001.SZ"</span><span class="p">,</span> <span class="n">start</span><span class="o">=</span><span class="s2">"20240101"</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">"20241231"</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">"trade_date"</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">"close"</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">"000001.SZ"</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">"000001.SZ"</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"># → ['动量', 'RSI', 'MACD', '量价', '布林', 'ATR', '均线', '波动率', '换手率', '振幅', '基本面', '情绪']</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">"RSI"</span><span class="p">))</span>
|
||
<span class="c1"># → ['rsi_7', 'rsi_14']</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">"momentum_20"</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">"rsi_14"</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">"roe"</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">"news_sent_5"</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">"momentum_20"</span><span class="p">),</span>
|
||
<span class="n">get_factor</span><span class="p">(</span><span class="s2">"rsi_14"</span><span class="p">),</span>
|
||
<span class="n">get_factor</span><span class="p">(</span><span class="s2">"volatility_20"</span><span class="p">),</span>
|
||
<span class="n">get_factor</span><span class="p">(</span><span class="s2">"ma_dev_20"</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">"000001.SZ"</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">"momentum_20"</span><span class="p">),</span> <span class="n">get_factor</span><span class="p">(</span><span class="s2">"rsi_14"</span><span class="p">)],</span>
|
||
<span class="n">date</span><span class="o">=</span><span class="s2">"20250630"</span><span class="p">,</span>
|
||
<span class="n">ts_codes</span><span class="o">=</span><span class="p">[</span><span class="s2">"000001.SZ"</span><span class="p">,</span> <span class="s2">"600519.SH"</span><span class="p">,</span> <span class="s2">"300750.SZ"</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">"</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">%"</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"># → {'total_return': 29.4, 'cagr': 4.3, 'sharpe_ratio': 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">"my_strategy"</span>
|
||
<span class="n">category</span> <span class="o">=</span> <span class="s2">"custom"</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">"rsi_14"</span><span class="p">]</span> <span class="o"><</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">"rsi_14"</span><span class="p">]</span> <span class="o">></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">"000001.SZ"</span><span class="p">:</span> <span class="n">df1</span><span class="p">,</span> <span class="s2">"600519.SH"</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">"000001.SZ"</span><span class="p">:</span> <span class="n">f1</span><span class="p">,</span> <span class="s2">"600519.SH"</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">"sharpe"</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">" </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">"</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">"sharpe"</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">"name"</span><span class="p">:</span> <span class="s2">"fast"</span><span class="p">,</span> <span class="s2">"type"</span><span class="p">:</span> <span class="s2">"int"</span><span class="p">,</span> <span class="s2">"low"</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="s2">"high"</span><span class="p">:</span> <span class="mi">30</span><span class="p">,</span> <span class="s2">"step"</span><span class="p">:</span> <span class="mi">1</span><span class="p">},</span>
|
||
<span class="p">{</span><span class="s2">"name"</span><span class="p">:</span> <span class="s2">"slow"</span><span class="p">,</span> <span class="s2">"type"</span><span class="p">:</span> <span class="s2">"int"</span><span class="p">,</span> <span class="s2">"low"</span><span class="p">:</span> <span class="mi">15</span><span class="p">,</span> <span class="s2">"high"</span><span class="p">:</span> <span class="mi">120</span><span class="p">,</span> <span class="s2">"step"</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">"regression"</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">"特征: </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"> 行"</span><span class="p">)</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"标签: 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">%"</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">"训练集: </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"> 行"</span><span class="p">)</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"测试集: </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"> 行"</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">"n_estimators"</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span>
|
||
<span class="s2">"learning_rate"</span><span class="p">:</span> <span class="mf">0.03</span><span class="p">,</span>
|
||
<span class="s2">"num_leaves"</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">"测试集 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">"</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">"iterations"</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span> <span class="s2">"learning_rate"</span><span class="p">:</span> <span class="mf">0.03</span><span class="p">,</span> <span class="s2">"depth"</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">"gain"</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">"models/lightgbm_000001.pkl"</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">"models/lightgbm_000001.pkl"</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">"000001.SZ"</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">"000001.SZ"</span><span class="p">,</span> <span class="s2">"600519.SH"</span><span class="p">,</span> <span class="s2">"300750.SZ"</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">"000001.SZ"</span><span class="p">,</span> <span class="n">start</span><span class="o">=</span><span class="s2">"20260501"</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">"20260603"</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">"dm"</span><span class="p">:</span> <span class="n">dm</span><span class="p">,</span>
|
||
<span class="s2">"fe"</span><span class="p">:</span> <span class="n">engine_fe</span><span class="p">,</span>
|
||
<span class="s2">"bt"</span><span class="p">:</span> <span class="n">engine_bt</span><span class="p">,</span>
|
||
<span class="s2">"opt"</span><span class="p">:</span> <span class="n">opt_engine</span><span class="p">,</span>
|
||
<span class="s2">"sent"</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: ['research', 'selection', 'risk', 'report']</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">"20260603"</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">"20260603"</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><your-db-password>
|
||
<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">"sharpe"</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">"n_estimators"</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span>
|
||
<span class="s2">"learning_rate"</span><span class="p">:</span> <span class="mf">0.03</span><span class="p">,</span>
|
||
<span class="s2">"num_leaves"</span><span class="p">:</span> <span class="mi">15</span><span class="p">,</span>
|
||
<span class="s2">"min_data_in_leaf"</span><span class="p">:</span> <span class="mi">20</span><span class="p">,</span>
|
||
<span class="s2">"feature_fraction"</span><span class="p">:</span> <span class="mf">0.7</span><span class="p">,</span>
|
||
<span class="s2">"bagging_fraction"</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">"iterations"</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span>
|
||
<span class="s2">"learning_rate"</span><span class="p">:</span> <span class="mf">0.03</span><span class="p">,</span>
|
||
<span class="s2">"depth"</span><span class="p">:</span> <span class="mi">5</span><span class="p">,</span>
|
||
<span class="s2">"min_data_in_leaf"</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">"finance"</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">"000001.SZ"</span><span class="p">)</span><span class="o">.</span><span class="n">set_index</span><span class="p">(</span><span class="s2">"trade_date"</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">"000001.SZ"</span><span class="p">,</span> <span class="p">[</span><span class="n">get_factor</span><span class="p">(</span><span class="s2">"rsi_14"</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">"sharpe"</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-训练-回测">示例 3:ML 训练 + 回测</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">"n_estimators"</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span> <span class="s2">"learning_rate"</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">"selection"</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">"risk"</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">"report"</span><span class="p">][</span><span class="s2">"report_path"</span><span class="p">]</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"日报: </span><span class="si">{</span><span class="n">report_path</span><span class="si">}</span><span class="s2">"</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">"000001.SZ"</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">&&</span><span class="w"> </span>python<span class="w"> </span>cli/agent_cli.py<span class="w"> </span><命令><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 跳过)
|
||
→ 未缓存提示:运行 'agent_cli.py warmup' 首次预热
|
||
[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 > 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> |