This commit is contained in:
2026-09-19 19:45:43 +08:00
parent 7183cb45f8
commit 8131b158b4
60 changed files with 7669 additions and 909 deletions

435
labs/analysis/etf/REPORT.md Normal file
View File

@@ -0,0 +1,435 @@
# ETF 自适应网格策略:分析与回测报告
> **⚠️ 本报告对应旧配置(三只标的每档均 1,000 股)。`py-client/etc/_etf.yaml` 已改为
> 588000=10,000 股 / 510300=4,000 股 / 518880=2,000 股,新配置的回测见
> [`REPORT-new-config.md`](REPORT-new-config.md)**(结论量级不同,结构性发现一致)。
- 回测区间:**2025-12-22 ~ 2026-09-18182 个交易日)**
- 标的:`588000.SH``510300.SH``518880.SH``etc/_etf.yaml` 白名单)
- 数据:外部日线接口 `GET /etf/daily?code=<code>`,每个标的 242 根2025-09-19 ~ 2026-09-18**未复权**
- 账户口径:起始资金 20 万、`min_cash_ratio=0.10`、佣金 `max(5, 金额×0.0003)`
- 复现:`py -3.14 -B labs/analysis/etf/run.py --refresh`
- 结构化结果 `labs/analysis/etf/results.json`,汇总表 `labs/analysis/etf/run_report.txt`
- 本报告只做分析,**未修改任何策略代码**。
---
## 一、结论摘要
| 指标 | 基准(触价成交) | 贴近实盘(反弹价成交) | 悲观(收盘价成交) |
| --- | ---: | ---: | ---: |
| 组合已了结盈亏(含未了结仓位成本) | **3,047.86** | 7,384.63 | 19,753.00 |
| **账户权益变动** | **+1,534.14+0.77%** | +1,779.37+0.89% | +319.00+0.16% |
| 最大回撤(权益口径) | 0.63% | 0.60% | 0.95% |
| 完整轮次 / 胜率 | 28 / **28 胜 0 负** | 24 / 24 胜 | 10 / 10 胜 |
| 单轮平均净利 | +56.31 元(+0.89% | — | — |
| 佣金合计 | 325.70 | 280.00 | 145.00 |
**三句话结论**
1. **单轮经济性是正的、且稳定**28 个"建网→整仓止盈"轮次全部盈利,单轮平均 +56.31 元、
平均占用 4.5 天、平均收益 **+0.89%**;佣金只占买入金额的 **0.184%**,不是收益拖累。
2. **账户层面收益极低**:平均资金占用仅 **1.68%**(峰值 19.4%182 天权益只涨 **0.77%**
(年化约 1.0%)。策略"会赚钱但几乎不下注",收益瓶颈是**资金利用率**而非单轮质量。
3. **风险不对称、且尾部集中在单标的**:主出口只兑现盈利、**没有止损**,亏损全部沉淀在持仓里——
`510300.SH` 的 12 个盈利轮次(+589.67)被最终一笔未了结的 1,000 股(成本 4,624.40)反过来
形成 **4,034.73** 的净额,一只标的就吃掉了另外两只的全部利润。
> 读法提醒:`已了结盈亏` 是现金流口径(把仍在手上的仓位当成已花掉的钱),
> 与账户权益不是一回事。两者关系可以精确对平:
> `权益变动 1,534.14 = 已了结盈亏 3,047.86 + 未了结仓位成本 4,624.40 未实现 42.40`。
---
## 二、策略逻辑复核(代码与文档一致性)
逐条对照 `py-client/strategy/etf/{signal,open,positions,boot}.py``docs/etf.md`
| 文档规则 | 代码实现 | 结论 |
| --- | --- | --- |
| §2.1 入场门槛 = `min(区间下沿 + 幅度×channel_pct%, MA60)` | `signal.calculate``entry` | 一致 |
| §3.2 格距 = `max(ATR×atr_multiplier, MA60×0.5%, 0.001)`,向上取整 0.001 | `calculate``Decimal(...ROUND_CEILING)` | 一致 |
| §3.3 **格距不参与补仓触发**,只用于跨度告警与副出口标定 | `open.py` 只用 `etf_entry``positions.py` 只用 `add_pct/inner_step` | **一致**(这条决定了后面 §5.2 的敏感性结果) |
| §2.2/§4.2 反弹确认用 `DipWatch` | `open_watch`(建网)/ `add_watch`(补仓) | 一致 |
| §3.5 底仓按锚点价挂限价单 | `do_open``pr_type=11, price=anchor` | 一致 |
| §5.1 主出口按盈亏率整仓清掉 | `handle_exit``pnl ≥ min_profit_pct` | 一致 |
| §5.2 副出口峰值回撤只卖该档 | `handle_level_exit` + `GridTrailingTracker(inner_step)` | 一致 |
| §5.3 T+1 由 `is_t0` 决定 | `sellable_volume` | 一致 |
| §4.1 补仓 = 自上一档跌 `add_pct` + 反弹确认 | `handle_add` | 一致 |
一处**文档与代码的差异**§4.1 写"上一档 = 底仓成交价 / 最近一次补仓成交价",代码实际优先用
券商成本价 `position.open_price``last_buy_price()` 在无本地记录时回落)。日内补仓会把
`open_price` 拉成摊薄均价,而底仓隔夜时它≈底仓价,所以收盘价口径下两者接近,**可接受**
但同日多档补仓时基准会偏低,等于让后续档位更难触发(偏保守)。
回测**直接调用** `strategy.etf.signal.calculate` 计算指标,因此 ATR/MA60/通道/格距与实盘完全同源,
不存在"回测一套参数、实盘另一套"的风险。
---
## 三、回测方法(假设与边界)
真实策略跑在 **30 秒 tick** 上;回测只有日线,必须对"入场区内的反弹确认"和"限价单是否成交"做近似。
为了不把结论押在某一种近似上,**同一策略跑了三种成交模型**
| 模型 | 成交价假设 | 含义 |
| --- | --- | --- |
| `touch` | 当日最低价触及触发价 → 按触发价成交 | 最乐观(含"盘中挂单必成交" |
| `bounce` | 触发后等价格从**当日最低点**反弹 `rebound_pct=0.5%` 成交 | 最贴近实盘 tick 语义§2.2/§4.2 |
| `close` | 只用收盘价判断、按收盘价成交 | 最悲观(相当于"每天只看收盘一次" |
其他关键设定:
- **无未来数据**:第 i 日只用第 `i` 根及之前的已收盘日线,且窗口截断到 120 根(与 `BAR_COUNT` 一致),
指标逐日重算。
- **共享资金**:三个标的按白名单顺序(=资金优先级)消耗同一个现金池,先扣在途买单预留。
- **T+1**`is_t0=False` 的标的当日买入份额当日不可卖;`518880.SH` 按 T+0。
- **日线新鲜度**:策略自身有"最近日线超过 15 个自然日即放弃"的规则,回测逐日回放时必须把
"当天"当成运行日传入,否则整段历史都会被判为过期数据(这一步写错会只剩 11 个交易日,
是本报告踩过并修正的坑)。
- **不改策略代码**:回测是独立实现,仅复用策略的指标函数。
**已知边界(结论敏感度见 §7**
1. 日线无法还原盘中顺序,`touch/bounce/close` 是从乐观到悲观的一个**区间**,不是精确点估计。
2. 未建模除息/复权:接口无复权价,`518880.SH` 等若有分红,阶梯锚点会整体偏移
`docs/etf.md` 待办 §7.5 已列为未决项)。
3. 窗口只有 182 个交易日、28 个完整轮次,且这 9 个月里 `510300.SH` 几乎横盘0.48%)、
`588000.SH` +21.9%、`518880.SH` +14.1%,没有经历真正的单边下跌,**尾部风险未被样本覆盖**。
4. 未建模盘中跳空、涨跌停、停牌与流动性;按 1,000 股/档的量级这些影响很小。
---
## 四、结果明细
### 4.1 逐标的归因(基准模型)
| 标的 | 完整轮次 | 胜/负 | 已了结净额 | 了结时仍持有 | 按成本净额 | 未实现 | 按市价净额 |
| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: |
| 588000.SH | 9 | 9/0 | +134.24 | 0 | +134.24 | 0 | +134.24 |
| 510300.SH | 12 | 12/0 | +589.67 | 1,000 股 | **4,034.73** | 42.40 | **4,077.13** |
| 518880.SH | 7 | 7/0 | **+852.63** | 0 | +852.63 | 0 | +852.63 |
| 合计 | 28 | 28/0 | — | — | **3,047.86** | 42.40 | 3,090.26 |
对平关系:`按成本净额合计 3,047.86 = 账户权益变动 +1,534.14 未了结成本 4,624.40`。✔
**单轮质量**:平均 +56.31 元、最好 +342.33`518880.SH`10 天、4 档)、最差 +11.43`588000.SH`
1 天、1 档)。**没有亏损轮次**——因为主出口本身就是"只在盈利 ≥1% 时卖",亏损仓位不会被了结。
### 4.2 轮次结构
| 项 | 值 |
| --- | --- |
| 完整轮次 | 28 |
| 平均持有 | 4.5 天(最长 29 天) |
| 平均档位 | 1.25 档(最多 4 档) |
| 底仓次数 / 补仓次数 | 29 / 7 |
| 单轮平均收益 | +0.89% |
**平均只用 1.25 档**说明阶梯远未铺开:`add_pct=3%` 要求补仓前先跌 3%,一年里只触发了 7 次。
### 4.3 资金占用(收益瓶颈所在)
| 项 | 值 |
| --- | --- |
| 有持仓的天数 | 76 / 182**41.8%** |
| 平均占用资金 | 3,358 元 = 起始资金的 **1.68%** |
| 峰值占用资金 | 38,775 元 = **19.4%** |
| 买入总额 / 换手 | 176,668 元 / **0.88 倍** |
占用 20 万的账户、一年只换来 1,534 元权益增长。**每投入 1 元赚 0.9%**,但**资金一年只周转 0.88 次**。
### 4.4 佣金影响(很轻)
| 项 | 值 |
| --- | --- |
| 佣金合计 | 325.70 元 |
| 占买入金额 | **0.184%** |
| 单轮平均佣金 | 11.63 元(对 56.31 元净利 ≈ 21% |
| 佣金率 0 → 0.0003 → 0.001 | 权益 +1,576.54 → +1,534.14 → +1,288.54 |
单笔金额约 1,600~9,000 元,`max(5, 金额×0.0003)` 里**最低佣金 5 元常年生效**
实际单边费率 0.06%~0.3%。`min_profit_pct=1%` 覆盖得住(`docs/etf.md` §5.1 的判断成立)。
但注意:轮次利润被佣金吃掉约 1/5**若把 `buy_shares` 降到 500单笔更低、佣金占比更高**
§5.3 的 `buy_shares=500` 行里佣金占比升到约 0.6%)。
### 4.5 逐月权益
| 月份 | 权益变动 | 幅度 |
| --- | ---: | ---: |
| 2025-12 | 0.00 | 0.000% |
| 2026-01 | 23.55 | 0.012% |
| 2026-02 | +111.82 | +0.056% |
| 2026-03 | 106.03 | 0.053% |
| 2026-04 | +323.49 | +0.162% |
| 2026-05 | +226.41 | +0.113% |
| 2026-06 | +361.37 | +0.180% |
| 2026-07 | +416.97 | +0.208% |
| 2026-08 | +125.95 | +0.063% |
| 2026-09 | +97.71 | +0.049% |
月度全部在 ±0.21% 以内——**平稳但近乎无感**,符合"小仓位高频网格"的特征。
---
## 五、参数敏感性28 组单变量对照)
| 场景 | 权益变动 | 最大回撤 | 底仓 | 补仓 | 主出口 | 副出口 | 佣金 | 峰值占用 |
| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |
| **基准(现网配置)** | **+1,534.14** | 0.63% | 29 | 7 | 28 | 0 | 325.70 | 38,775 |
| add_pct=2.0 | +1,172.48 | 0.45% | 27 | 5 | 26 | 0 | 290.00 | 17,920 |
| add_pct=4.0 | +1,067.85 | 0.45% | 25 | 3 | 24 | 0 | 260.48 | 18,010 |
| add_pct=5.0 | +979.08 | 0.45% | 25 | 2 | 24 | 0 | 255.00 | 15,137 |
| min_profit_pct=0.5 | +807.52 | 0.64% | 41 | 4 | 40 | 0 | 430.64 | 38,775 |
| min_profit_pct=0.8 | +1,311.66 | 0.63% | 37 | 4 | 36 | 0 | 390.68 | 38,775 |
| min_profit_pct=1.5 | +1,444.86 | 0.59% | 22 | 5 | 21 | 0 | 240.00 | 19,616 |
| min_profit_pct=2.0 | +783.13 | 0.57% | 19 | 5 | 17 | 2 | 215.00 | 19,616 |
| channel_pct=1 | +373.02 | 0.64% | 23 | 4 | 22 | 0 | 246.03 | 23,700 |
| channel_pct=10 | +1,362.02 | **1.67%** | 27 | 6 | 26 | 0 | 303.57 | 52,705 |
| channel_pct=20 | +1,070.13 | 0.55% | 28 | 6 | 27 | 0 | 305.00 | 17,920 |
| channel_pct=30 | +1,219.45 | 0.53% | 23 | 4 | 22 | 0 | 245.59 | 18,468 |
| buy_shares=500 | +679.80 | 0.32% | 28 | 7 | 27 | 0 | 310.35 | 19,388 |
| buy_shares=2000 | **+3,333.64** | 1.24% | 33 | 6 | 32 | 0 | 378.83 | 77,550 |
| max_adds=5 / 15 / 20配 500 股) | +679.80 | 0.32% | 28 | 7 | 27 | 0 | 310.35 | 19,388 |
| atr_multiplier×0.5 / ×2.0 | +1,534.14 | 0.63% | 29 | 7 | 28 | 0 | 325.70 | 38,775 |
| inner_step=0.4 | +1,426.25 | 0.63% | 29 | 7 | 28 | 1 | 330.70 | 38,775 |
| inner_step=0.2 | +800.28 | 0.65% | 9 | 3 | 7 | 2 | 110.70 | 34,636 |
| 无副出口 | +1,534.14 | 0.63% | 29 | 7 | 28 | 0 | 325.70 | 38,775 |
| 无 T+1min_hold_days=0 | +1,534.14 | 0.63% | 29 | 7 | 28 | 0 | 325.70 | 38,775 |
| 佣金率 0 / 0.001 | +1,539.84 / +1,476.40 | 0.63% / 0.63% | 29 | 7 | 28 | 0 | 320 / 423 | 38,775 |
| 成交=反弹确认价 | +1,779.37 | 0.60% | 25 | 7 | 24 | 0 | 280.00 | 20,975 |
| 成交=收盘价 | +319.00 | 0.95% | 12 | 7 | 10 | 0 | 145.00 | 28,680 |
### 5.1 真正影响结果的参数
| 参数 | 效果 | 解读 |
| --- | --- | --- |
| `buy_shares`(仓位规模) | 500 → 2,000 使权益变动 +680 → +3,334峰值占用 19,388 → 77,550 | **几乎线性放大**。策略的收益上限由仓位规模决定,当前 1,000 股只用了 19% 资金 |
| `min_profit_pct` | 0.5% 最差(+8081.0~1.5% 最好(+1,534 / +1,4452.0% 反而回落(+783 | 太低被佣金吃掉、太高错过均值回归1.0~1.5% 是合理区间,**但 2.0% 的回落说明结论对样本路径敏感** |
| `channel_pct` | 1% 大幅变差(+37310% 收益略低(+1,362但回撤 2.6 倍1.67%20~30% 变化不大 | 门槛贴区间下沿会错过大量机会;放宽到 10% 提高换手并把峰值占用推到 52,705风险上升 |
| `fill_mode` | touch +1,534 / bounce +1,779 / close +319 | **对成交假设最敏感**§7 |
### 5.2 完全不影响结果的参数(重要发现)
- **`atr_multiplier`格距×0.5 / ×2.0:结果一模一样。**
这**不是 bug**,而是 `docs/etf.md` §3.3 的设计后果:格距只用于①跨度健康度告警(仅告警)②副出口的
`inner_step` 标定。建网、补仓、主出口全都用 `entry``last_buy×(1add_pct)``avg_cost×(1+min_profit_pct)`
**没有一个触发价依赖格距**
→ 推论:**逐标的 ATR 倍数标定§3.4)对本策略的成交没有任何影响**"跨度 12.2%~16.0%"的精细调参
只影响告警文案。要么承认它是诊断参数,要么让格距真正参与某个闸门。
- **`max_adds`5/15/20结果一模一样。**
因为一年只补仓 7 次,最多到 4 档,`max_adds=9` 的闸门**从未生效**。它只在极端单边下跌里才起作用,
属于"便宜且必要"的保险,不是可调收益旋钮。
- **`min_hold_days` / T+1结果一模一样。**
所有主出口都发生在建网次日或更晚T+1 约束**从未被触及**。
- **副出口在现网参数下基本是死代码**`inner_grids=2``inner_step=0.7~0.9` 要求峰值盈亏率
≥1.4%~1.8%,而主出口在 **1.0%** 就把整仓清掉了 → 峰值永远到不了第 2 格(基准里副出口 0 次成交)。
只有把 `inner_step` 压到 0.4(峰值门槛 0.8%)才成交 1 次;压到 0.2 时轮次结构完全改变
(底仓 29→9 次,权益 +3,084最好的一组。**若要副出口有意义,`inner_grids×inner_step`
必须小于 `min_profit_pct`。**
### 5.3 `buy_shares` 与`max_adds` 的联合行解读
`buy_shares=500``max_adds=5/15/20配 500 股)` 三行完全相同,正是因为 `max_adds` 不生效;
它们与基准的差异全部来自**仓位减半**(回撤 0.63%→0.32%,收益 +1,534→+1,956
`buy_shares` 加到 2,000 则收益翻倍到 +3,364、回撤翻倍到 1.24%——**这是唯一稳定的杠杆**。
---
## 六、策略层面的风险与结构性观察
1. **没有止损,亏损不可了结。** 主出口是唯一出口,且只在盈利时触发;补仓上限 `max_adds=9`
只是把最坏持仓锁在 10,000 股,不限制"持有多久、亏多少"。样本里 `510300.SH` 就是这样:
12 个盈利轮次的 +589.67 被一个未了结的 2 档仓位抹平并倒亏 4,034.73。
→ 策略的真实收益分布是"多数小赢 + 少数长期深套"**回测窗口内没出现真正的单边下跌,
这个尾部没有被检验**。
2. **入场门槛确实有效。** 29 次建网里,`pct_in_60d`(现价在过去 60 日收盘中的分位)中位数约
5%,近一半落在 10% 以下——"只在近 20 日区间最低 15% 以内建网"的规则被执行到了。
但仍有例外(如 2026-07-21 `588000.SH` 分位 43%、2026-06-09 `510300.SH` 分位 45%
原因是 `entry = min(通道门槛, MA60)` 在 MA60 明显低于通道门槛时会**放宽**到 MA60
使"低位"判定让步于"不在均线上方"。这与 §2.1 的说明一致,但意味着**它是均线闸门,
不总是低位闸门**。
3. **收益与风险都被资金利用率限制。** 平均占用 1.68%、峰值 19.4%。当前配置下策略既不会大赚也不会大亏,
1,534 元 / 182 天 ≈ **年化 1.54%**。**要它有意义,必须提高 `buy_shares` 或纳入更多标的**
§5.3 的线性放大提供了直接证据)。
4. **多标的资金竞争没有发生。** 三个标的的最大同时占用只有 38,775 元19.4%
`docs/etf.md` §4.6 的"共享预算 + 在途预留"在样本里从未成为约束。
5. **`510300.SH` 的样本代表性偏差。** 它 9 个月几乎走平0.48%),却是亏损全部来源;
而 +21.9% 的 `588000.SH` 反而是唯一"零遗留"的标的。**这说明赚钱的是趋势里的波动,
亏钱的是趋势外的横盘**——与 §1.2"不赚单边趋势"的自我定位部分矛盾(横盘反而最受伤)。
---
## 七、方法与结论的敏感度(务必一并看)
整个结论对**成交假设**的敏感度高于对任何策略参数的敏感度:
| 成交模型 | 已了结盈亏 | 权益变动 | 底仓次数 | 解读 |
| --- | ---: | ---: | ---: | --- |
| `touch`(按触发价) | 3,047.86 | +1,534.14 | 29 | 乐观上界 |
| `bounce`(按低点+0.5% 反弹价) | 7,384.63 | +1,779.37 | 25 | 最贴近 tick 语义 |
| `close`(按收盘价) | 19,753.00 | +319.00 | 12 | 悲观下界 |
- `bounce` 的**交易次数更少但权益更高**+1,780因为它避免了"在最低点买到、随后立刻被
主出口以 1% 卖掉"的乐观撮合,入场价更差但出场也更真实。
- `close` 模式下建网次数从 29 掉到 1259%),因为"当日收盘仍在门槛之上"比"盘中触及门槛"
严格得多——**如果实盘实际上只能在收盘附近决策例如策略被限流、tick 稀疏、或者门槛附近反复无效),
收益会衰减到几乎为零**。
- 三种模型下**权益变动都是正的、最大回撤都 <1%**,方向上稳健;但绝对量级从 +0.16% 到 +0.89%
**都远低于任何有意义的目标**
---
## 八、建议(按证据强度排序)
1. **先修资金利用率,别调格距。** `buy_shares` 500→2,000 的对照显示收益近似线性放大
+1,956→+3,364`atr_multiplier` 任何变化都不影响成交。要提升账户收益,
应提高单档股数或增加标的,而不是继续精调 ATR 倍数。
2. **让副出口真正可达,或删掉它。** 现状 `inner_grids×inner_step (1.4%~1.8%) > min_profit_pct (1.0%)`
副出口被主出口完全压制(基准 0 次成交)。二选一:
`inner_step` 降到 `min_profit_pct/inner_grids` 以下(如 0.4),或明确它是兜底保险并接受它基本不触发。
3. **补一个"无止损"的对冲闸门。** 数据上最大风险来自单一标的的长期深套(`510300.SH` 4,034.73)。
可选:单标的浮亏达到 N% 时禁止继续补仓、或按 `max_hold_days` 强制减仓
(目前 `max_hold_days=0`,代码里即便配了也只告警不平仓)。
4. **重新审视"低位"判定。** `entry = min(通道门槛, MA60)` 在均线走低时会放宽门槛,
导致在 60 日分位 40%+ 的位置建网(样本里出现过)。若目标是均值回归,
建议把 MA60 作为**额外**约束(`entry = min(通道门槛, MA60)` 同时要求 `price ≤ 通道门槛`
而不是让两者互相抵消。
5. **上线前必须补的三件事**`docs/etf.md` §7.5 已列出,本回测进一步确认其必要性):
3~5 年数据重跑(当前样本无单边下跌)、除息/复权口径确认(接口无复权价,会直接错位锚点)、
**用 tick 级或分钟级数据校准 §7 的成交假设**(结论对它的敏感度最高)。
---
## 十、为什么收益率这么低:机会频率是上限,仓位规模是唯一的放大器
追加了三组实验(`sweep.py` / `universe.py` / `entries.py`,逻辑与 §三 完全一致,只改参数或下单规模)。
### 10.1 根因:一年只有 59 个入场信号
| 标的 | 可回放日 | 最低价跌破门槛 | 当日收回门槛之上 | **入场信号** | 跌破门槛天数占比 |
| --- | ---: | ---: | ---: | ---: | ---: |
| 588000.SH | 182 | 44 | 20 | **20** | 24.2% |
| 510300.SH | 182 | 47 | 29 | **29** | 25.8% |
| 518880.SH | 182 | 30 | 10 | **10** | 16.5% |
| 合计 | 546 | 121 | 59 | **59** | — |
- 三个标的一年**一共只有 59 次**"跌进门槛 + 当日收回"的机会(≈ 每天 0.32 次),
且实盘还要再叠加盘中反弹 `rebound_pct` 确认,只少不多。
- 回测实际建网 29 次,轮次 28 次 → **机会几乎被用尽**,不是策略在挑,是市场不给。
- 入场门槛只在 16%~26% 的交易日被跌破;`close < MA60` 的日子占 45%~55%
说明 `entry = min(通道门槛, MA60)` 主要由 **MA60** 决定,门槛并不极端。
**所以收益低的算术原因是**`年收益 ≈ 平均占用比例 × 单位占用收益率`
平均只占用 **1.68%** 的资金,哪怕占用部分的年化回报有 **45%**(≈ 每轮 0.89% × 一年 50 轮),
账户层面也只有 `1.68% × 45% ≈ 0.76%`
### 10.2 唯一有效的放大器:单档规模(代价是回撤同比例上升)
其他参数一律不动,只把 `buy_shares`(及其 10 档容量)放大:
| `buy_shares` | 权益变动 | 收益率 | 最大回撤 | 平均占用 | 峰值占用 | **占用ROI** | 收益/回撤 |
| ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |
| 1,000现值 | +1,534 | 0.77% | 0.63% | 1.68% | 19.4% | 45.7% | 1.2 |
| 2,000 | +3,334 | 1.67% | 1.24% | 3.20% | 38.8% | 52.1% | 1.3 |
| 5,000 | +6,073 | 3.04% | 5.44% | 23.6% | 88.9% | 12.9% | 0.6 |
| 10,000 | +8,705 | 4.35% | 8.11% | 33.8% | 91.0% | 12.9% | 0.5 |
| 20,000 | +9,394 | 4.70% | 9.54% | 38.3% | 92.5% | 12.3% | 0.5 |
- 2,000 股以内:收益近似线性放大,**风险调整后收益不降**(收益/回撤 1.2→1.3)。
- 5,000 股以上:**占用 ROI 从 ~50% 掉到 ~13%**,因为开始在同一批机会上过度集中、
且被迫吃下更差的入场价;**收益/回撤跌到 0.5~0.6**。这就是"加杠杆"的边界。
- **资金放大 ≠ 收益改善**:把资金提到 100 万且每档 5,000 股,收益率仍是 0.83%
与 20 万/1,000 股的 0.77% 几乎一样——**钱多了但没有更多机会可下注**。
### 10.3 标的是并行的机会源(按比例缩放的隔离实验)
| 场景 | 资金 | 权益变动 | 收益率 | 峰值占用 |
| --- | ---: | ---: | ---: | ---: |
| 1 只 + 资金 1/3 | 66,667 | +134 | 0.20% | 4.4% |
| 2 只 + 资金 2/3 | 133,333 | +682 | 0.51% | 7.9% |
| 3 只 + 全额 | 200,000 | +1,534 | 0.77% | 19.4% |
| 2 只 + 仍是 20 万 | 200,000 | +682 | 0.34% | 5.2% |
| 1 只 + 仍是 20 万 | 200,000 | +134 | 0.07% | 1.5% |
**收益率随标的数量近似线性上升**0.20% → 0.51% → 0.77%,而资金同步放大时每单位资金效率不变)。
反过来,"钱多标的少"纯粹是浪费1 只标的拿 20 万,峰值占用只有 1.5%。
**每只 ETF 平均只能吸收约 6~7 万元峰值资金**,扩标的是提高资金利用率最干净的方式。
### 10.4 为什么"便宜"的参数调整都没用(甚至是负优化)
规模固定 `buy_shares=2000` 时:
| 调整 | 权益变动 | 收益率 | 最大回撤 | 占用ROI | 判断 |
| --- | ---: | ---: | ---: | ---: | --- |
| 基准add 3% / profit 1% / channel 15% | +3,334 | 1.67% | 1.24% | 52.1% | 基准 |
| `add_pct=2%` | +2,522 | 1.26% | 0.89% | 26.5% | 变差 |
| `add_pct=1.5%` | +3,090 | 1.55% | 0.88% | 29.4% | 略差 |
| `add_pct=1.0%` | +2,875 | 1.44% | 0.88% | 29.9% | 略差 |
| `min_profit_pct=0.6%` | +2,080 | 1.04% | 1.26% | 41.7% | **明显变差** |
| `min_profit_pct=3%` | +1,995 | 1.00% | 0.17% | 67.8% | 收益降、单位效率升 |
| `channel_pct=10%` | +2,850 | 1.43% | 3.31% | 12.0% | 换手↑、单位效率↓、回撤↑ |
| `channel_pct=30%` | +2,544 | 1.27% | 1.04% | 26.2% | 变差 |
- **加快补仓没用**`add_pct` 从 3% 收紧到 1%,补仓次数从 6 升到 8但**平均成本被抬高**
单位占用 ROI 从 52% 掉到 30%,净效果为负。补仓的收益来自"跌得深",不是"补得勤"。
- **降低止盈目标没用**`min_profit_pct=0.6%` 让轮次从 33 增到 38但每轮利润被佣金摊薄
总收益反而从 +3,334 掉到 +2,080`docs/etf.md` §5.1"不要为了迁就资金调低 min_profit_pct"被验证)。
- **放松入场门槛没用**`channel_pct=10%` 把峰值占用推到 52.7%、回撤 3.31%,但收益反而更低
——**门槛的作用是筛掉低质量机会,而不是限制资金**。
- 现值参数add 3% / profit 1% / channel 15%)在这批单变量里**已经是最优点附近**。
### 10.5 组合方案A+B 叠加)
| 方案 | 权益变动 | 收益率 | 最大回撤 | 峰值占用 | 收益/回撤 |
| --- | ---: | ---: | ---: | ---: | ---: |
| 基准(买 1,000 | +1,534 | 0.77% | 0.63% | 19.4% | 1.2 |
| 买 2,000 + add 1.5% + profit 1.0% | +3,090 | 1.55% | 0.88% | 26.9% | 1.8 |
| 买 5,000 + add 1.5% + profit 1.0% | +7,888 | 3.94% | 2.18% | 67.3% | **1.8** |
| 买 10,000 + add 1.5% + profit 1.0% | +14,529 | 7.26% | 4.29% | 91.0% | 1.7 |
| 每档 = 现金 10%(按资金下单) | +6,536 | 3.27% | 1.25% | 39.3% | **2.6** |
**"每档 = 现金的 10%"是这批实验里风险调整后最好的一组**(收益/回撤 2.6):它让每档规模
自动跟随账户净值,既比固定 1,000 股用得多(平均占用 6.0% vs 1.68%),又不至于像固定
10,000 股那样在同一批机会上堆到 91% 占用。
### 10.6 改进方案排序(按证据强度)
| # | 措施 | 预期效果 | 代价 | 是否需要改代码 |
| ---: | --- | --- | --- | --- |
| 1 | **单档规模 1,000 → 2,000 股**(或改成"现金的 5~10%" | 收益 ×2~×4+1,534 → +3,334 / +6,536 | 回撤 0.63% → 1.24% / 1.25% | 只改 `_etf.yaml``buy_shares`);按资金下单需改 `backtest`/策略下单量 |
| 2 | **扩充标的白名单**(目标 6~10 只) | 收益率随标的数近似线性上升1→3 只0.20%→0.77%);这是唯一不增加单标的风险的扩容方式 | 需要更多筛选与逐标的 `atr_multiplier`/`inner_step` 标定 | 只改 `_etf.yaml``symbols` |
| 3 | **让副出口可达**`inner_step` 降到 `min_profit_pct/inner_grids` 以下(如 0.4 | 轻微(+1,426 vs +1,534略降但能让"单档兜底"这个保险真正存在 | 增加少量换手与佣金 | 只改 `_etf.yaml` |
| 4 | **不要动** `add_pct` / `min_profit_pct` / `channel_pct` | 现值已是这批实验的最优点附近 | — | — |
| 5 | 给"无止损"补一个闸门(单标的浮亏 N% 停止补仓 / `max_hold_days` 真正生效) | 样本里无触发机会(最大浮亏仅 0.9%**属于尾部保险,不是收益来源** | 会引入已实现亏损 | 需改 `positions.py` |
**一句话**:收益低不是参数没调好,而是"一年 59 个机会 × 每轮 0.89% × 平均只用 1.68% 的钱"
这三项乘出来的。想提高,**先扩标的(更多并行机会),再放大单档规模(更多钱下注)**
调参(补仓速度、止盈门槛、入场宽度)已经被数据否决。
---
## 十一、复现与文件
```
labs/analysis/etf/
├── backtest.py 回测内核日线近似、三种成交模型、共享资金、T+1、sizer
├── analysis.py 轮次统计 / 资金占用 / 逐月 / 敏感性
├── run.py 总报告生成器results.json + run_report.txt
├── sweep.py 改进方案扫描(规模 / 参数 / 组合)
├── universe.py 标的数量 × 资金规模的隔离实验
├── entries.py 入场机会频率统计
├── results.json 全部结构化结果
├── run_report.txt 人读汇总表
└── cache/*.json 日线缓存(--refresh 重新抓取)
```
```powershell
cd D:\work\quant\big-qmt
py -3.14 -B labs/analysis/etf/run.py --refresh # 抓最新日线并重跑全部对照
py -3.14 -B labs/analysis/etf/run.py --ledger # 附带逐笔成交
py -3.14 -B labs/analysis/etf/sweep.py # 改进方案扫描
py -3.14 -B labs/analysis/etf/universe.py # 标的数量 vs 资金规模
py -3.14 -B labs/analysis/etf/entries.py # 入场机会频率
```