影子模式戰情板
| 型態 | 筆數 | 勝率 | 平均R | 合計R |
|---|---|---|---|---|
| 擴散回碰 | 33 | 21.2% | -0.14 | -4.7 |
| 等距發散 | 29 | 10.3% | -0.61 | -17.7 |
| 收斂上彎 | 8 | 0.0% | -1.04 | -8.3 |
| 位階 | 筆數 | 勝率 | 平均R | 合計R |
|---|---|---|---|---|
| 位階1 | 51 | 13.7% | -0.34 | -17.2 |
| 位階2 | 12 | 16.7% | -0.63 | -7.5 |
| 位階1.5 | 7 | 14.3% | -0.86 | -6.0 |
| 出場原因 | 筆數 | 勝率 | 平均R | 合計R |
|---|---|---|---|---|
| 觸及停損 | 56 | 0.0% | -1.03 | -57.6 |
| 保本後收盤跌破MA30 | 7 | 100.0% | +2.96 | +20.7 |
| 災難停損(結構線下0.5R) | 4 | 0.0% | -1.50 | -6.0 |
| 保本後收盤跌破MA30|芭樂價已部分停利 | 2 | 100.0% | +6.04 | +12.1 |
| 觸及保本停損 | 1 | 100.0% | +0.10 | +0.1 |
| 加碼分組 | 筆數 | 勝率 | 平均R | 合計R |
|---|---|---|---|---|
| 無加碼 | 70 | 14.3% | -0.44 | -30.7 |
| 型態 | 筆數 | 勝率 | 平均R | 合計R |
|---|---|---|---|---|
| 擴散回碰 | 317 | 36.9% | +0.64 | +203.6 |
| 等距發散 | 315 | 32.7% | +0.56 | +177.9 |
| 收斂上彎 | 12 | 41.7% | +0.17 | +2.0 |
| 盤整突破 | 11 | 54.5% | +0.98 | +10.8 |
| 位階 | 筆數 | 勝率 | 平均R | 合計R |
|---|---|---|---|---|
| 位階1 | 362 | 36.5% | +0.57 | +205.9 |
| 位階2 | 293 | 33.8% | +0.64 | +188.5 |
| 出場原因 | 筆數 | 勝率 | 平均R | 合計R |
|---|---|---|---|---|
| 觸及停損 | 398 | 0.0% | -1.00 | -398.0 |
| 保本後收盤跌破MA30 | 193 | 100.0% | +2.38 | +459.1 |
| 觸及保本停損 | 26 | 0.0% | +0.00 | +0.0 |
| 移動停損(自最高10.3R回吐至3.1R) | 3 | 100.0% | +5.76 | +17.3 |
| 移動停損(自最高11.5R回吐至3.4R) | 2 | 100.0% | +8.02 | +16.0 |
| 移動停損(自最高12.3R回吐至3.7R) | 2 | 100.0% | +7.96 | +15.9 |
| 移動停損(自最高14.6R回吐至4.4R) | 2 | 100.0% | +10.27 | +20.5 |
| 移動停損(自最高13.2R回吐至4.0R) | 2 | 100.0% | +9.12 | +18.2 |
| 移動停損(自最高10.8R回吐至3.2R) | 2 | 100.0% | +7.56 | +15.1 |
| 移動停損(自最高10.5R回吐至3.1R) | 2 | 100.0% | +6.98 | +14.0 |
| 移動停損(自最高14.1R回吐至4.2R) | 2 | 100.0% | +9.84 | +19.7 |
| 移動停損(自最高11.0R回吐至3.3R) | 1 | 100.0% | +7.71 | +7.7 |
| 移動停損(自最高13.4R回吐至4.0R) | 1 | 100.0% | +9.41 | +9.4 |
| 移動停損(自最高11.6R回吐至3.5R) | 1 | 100.0% | +7.60 | +7.6 |
| 移動停損(自最高11.3R回吐至3.4R) | 1 | 100.0% | +5.94 | +5.9 |
| 移動停損(自最高19.5R回吐至5.8R) | 1 | 100.0% | +13.63 | +13.6 |
| 移動停損(自最高13.3R回吐至4.0R) | 1 | 100.0% | +9.28 | +9.3 |
| 移動停損(自最高10.2R回吐至3.1R) | 1 | 100.0% | +6.90 | +6.9 |
| 移動停損(自最高10.9R回吐至3.3R) | 1 | 100.0% | +5.92 | +5.9 |
| 移動停損(自最高10.1R回吐至3.0R) | 1 | 100.0% | +6.38 | +6.4 |
| 移動停損(自最高17.2R回吐至5.2R) | 1 | 100.0% | +11.41 | +11.4 |
| 移動停損(自最高12.9R回吐至3.9R) | 1 | 100.0% | +5.94 | +5.9 |
| 移動停損(自最高20.8R回吐至6.2R) | 1 | 100.0% | +16.88 | +16.9 |
| 移動停損(自最高11.7R回吐至3.5R) | 1 | 100.0% | +7.65 | +7.7 |
| 移動停損(自最高16.6R回吐至5.0R) | 1 | 100.0% | +12.18 | +12.2 |
| 移動停損(自最高11.4R回吐至3.4R) | 1 | 100.0% | +7.96 | +8.0 |
| 移動停損(自最高11.2R回吐至3.3R) | 1 | 100.0% | +7.81 | +7.8 |
| 移動停損(自最高23.8R回吐至7.1R) | 1 | 100.0% | +16.68 | +16.7 |
| 移動停損(自最高16.8R回吐至5.0R) | 1 | 100.0% | +12.36 | +12.4 |
| 移動停損(自最高15.0R回吐至4.5R) | 1 | 100.0% | +9.49 | +9.5 |
| 移動停損(自最高12.4R回吐至3.7R) | 1 | 100.0% | +8.27 | +8.3 |
| 移動停損(自最高10.6R回吐至3.2R) | 1 | 100.0% | +7.06 | +7.1 |
| 加碼分組 | 筆數 | 勝率 | 平均R | 合計R |
|---|---|---|---|---|
| 無加碼 | 635 | 33.2% | +0.35 | +220.8 |
| 有加碼(1次) | 19 | 100.0% | +8.25 | +156.7 |
| 有加碼(2次) | 1 | 100.0% | +16.88 | +16.9 |
| 型態 | 筆數 | 勝率 | 平均R | 合計R |
|---|---|---|---|---|
| 擴散回碰 | 313 | 35.8% | +0.53 | +167.3 |
| 等距發散 | 293 | 33.1% | +0.56 | +163.6 |
| 盤整突破 | 12 | 50.0% | +0.46 | +5.5 |
| 收斂上彎 | 12 | 16.7% | -0.58 | -6.9 |
| 位階 | 筆數 | 勝率 | 平均R | 合計R |
|---|---|---|---|---|
| 位階1 | 345 | 33.9% | +0.35 | +120.2 |
| 位階2 | 285 | 35.1% | +0.73 | +209.3 |
| 出場原因 | 筆數 | 勝率 | 平均R | 合計R |
|---|---|---|---|---|
| 觸及停損 | 391 | 0.0% | -1.00 | -391.0 |
| 保本後收盤跌破MA30 | 127 | 99.2% | +2.26 | +286.7 |
| 觸及保本停損 | 13 | 0.0% | -0.15 | -1.9 |
| 移動停損(自最高3.3R回吐至3.0R) | 7 | 71.4% | +0.65 | +4.6 |
| 移動停損(自最高2.7R回吐至3.0R) | 5 | 100.0% | +0.79 | +3.9 |
| 移動停損(自最高2.9R回吐至3.0R) | 4 | 75.0% | +0.72 | +2.9 |
| 移動停損(自最高2.6R回吐至3.0R) | 4 | 75.0% | +0.86 | +3.4 |
| 移動停損(自最高2.5R回吐至3.0R) | 3 | 66.7% | +0.30 | +0.9 |
| 移動停損(自最高3.2R回吐至3.0R) | 3 | 33.3% | +0.37 | +1.1 |
| 移動停損(自最高10.7R回吐至3.2R) | 3 | 100.0% | +7.97 | +23.9 |
| 移動停損(自最高4.3R回吐至3.0R) | 2 | 100.0% | +1.41 | +2.8 |
| 移動停損(自最高3.9R回吐至3.0R) | 2 | 100.0% | +1.18 | +2.4 |
| 移動停損(自最高10.2R回吐至3.1R) | 2 | 100.0% | +6.67 | +13.3 |
| 移動停損(自最高5.2R回吐至3.0R) | 2 | 100.0% | +2.76 | +5.5 |
| 移動停損(自最高3.4R回吐至3.0R) | 2 | 100.0% | +1.71 | +3.4 |
| 移動停損(自最高3.0R回吐至3.0R) | 2 | 100.0% | +1.23 | +2.5 |
| 移動停損(自最高2.8R回吐至3.0R) | 2 | 100.0% | +1.32 | +2.6 |
| 移動停損(自最高10.5R回吐至3.1R) | 2 | 100.0% | +9.20 | +18.4 |
| 移動停損(自最高3.6R回吐至3.0R) | 2 | 50.0% | +0.79 | +1.6 |
| 移動停損(自最高4.5R回吐至3.0R) | 2 | 100.0% | +2.29 | +4.6 |
| 移動停損(自最高4.4R回吐至3.0R) | 2 | 100.0% | +2.72 | +5.4 |
| 移動停損(自最高12.2R回吐至3.7R) | 2 | 100.0% | +10.30 | +20.6 |
| 移動停損(自最高3.1R回吐至3.0R) | 2 | 100.0% | +1.60 | +3.2 |
| 移動停損(自最高6.0R回吐至3.0R) | 2 | 100.0% | +1.88 | +3.8 |
| 移動停損(自最高3.8R回吐至3.0R) | 2 | 100.0% | +1.65 | +3.3 |
| 移動停損(自最高7.4R回吐至3.0R) | 1 | 100.0% | +1.53 | +1.5 |
| 移動停損(自最高6.9R回吐至3.0R) | 1 | 100.0% | +5.91 | +5.9 |
| 移動停損(自最高13.1R回吐至3.9R) | 1 | 100.0% | +10.27 | +10.3 |
| 移動停損(自最高3.5R回吐至3.0R) | 1 | 100.0% | +1.60 | +1.6 |
| 移動停損(自最高12.4R回吐至3.7R) | 1 | 100.0% | +7.86 | +7.9 |
| 移動停損(自最高9.0R回吐至3.0R) | 1 | 100.0% | +3.63 | +3.6 |
| 移動停損(自最高19.5R回吐至5.8R) | 1 | 100.0% | +14.65 | +14.7 |
| 移動停損(自最高9.8R回吐至3.0R) | 1 | 100.0% | +5.26 | +5.3 |
| 移動停損(自最高10.6R回吐至3.2R) | 1 | 100.0% | +6.73 | +6.7 |
| 移動停損(自最高16.4R回吐至4.9R) | 1 | 100.0% | +15.66 | +15.7 |
| 移動停損(自最高8.2R回吐至3.0R) | 1 | 100.0% | +4.98 | +5.0 |
| 移動停損(自最高5.8R回吐至3.0R) | 1 | 100.0% | +3.09 | +3.1 |
| 移動停損(自最高13.7R回吐至4.1R) | 1 | 100.0% | +12.74 | +12.7 |
| 移動停損(自最高9.1R回吐至3.0R) | 1 | 100.0% | +2.35 | +2.4 |
| 移動停損(自最高12.5R回吐至3.7R) | 1 | 100.0% | +12.16 | +12.2 |
| 移動停損(自最高6.6R回吐至3.0R) | 1 | 100.0% | +1.44 | +1.4 |
| 移動停損(自最高4.2R回吐至3.0R) | 1 | 100.0% | +1.70 | +1.7 |
| 移動停損(自最高4.0R回吐至3.0R) | 1 | 100.0% | +1.05 | +1.1 |
| 移動停損(自最高10.0R回吐至3.0R) | 1 | 100.0% | +8.47 | +8.5 |
| 移動停損(自最高10.9R回吐至3.3R) | 1 | 100.0% | +9.04 | +9.0 |
| 移動停損(自最高5.1R回吐至3.0R) | 1 | 100.0% | +3.39 | +3.4 |
| 移動停損(自最高20.2R回吐至6.1R) | 1 | 100.0% | +17.86 | +17.9 |
| 移動停損(自最高12.3R回吐至3.7R) | 1 | 100.0% | +7.66 | +7.7 |
| 移動停損(自最高4.1R回吐至3.0R) | 1 | 100.0% | +1.11 | +1.1 |
| 移動停損(自最高20.8R回吐至6.2R) | 1 | 100.0% | +17.08 | +17.1 |
| 移動停損(自最高11.0R回吐至3.3R) | 1 | 100.0% | +9.23 | +9.2 |
| 移動停損(自最高10.1R回吐至3.0R) | 1 | 100.0% | +9.38 | +9.4 |
| 移動停損(自最高5.0R回吐至3.0R) | 1 | 100.0% | +1.70 | +1.7 |
| 移動停損(自最高11.5R回吐至3.4R) | 1 | 100.0% | +9.32 | +9.3 |
| 移動停損(自最高6.8R回吐至3.0R) | 1 | 100.0% | +4.20 | +4.2 |
| 移動停損(自最高5.4R回吐至3.0R) | 1 | 100.0% | +5.56 | +5.6 |
| 移動停損(自最高8.1R回吐至3.0R) | 1 | 100.0% | +5.42 | +5.4 |
| 移動停損(自最高11.2R回吐至3.3R) | 1 | 100.0% | +8.37 | +8.4 |
| 移動停損(自最高15.1R回吐至4.5R) | 1 | 100.0% | +12.85 | +12.8 |
| 移動停損(自最高3.7R回吐至3.0R) | 1 | 100.0% | +2.44 | +2.4 |
| 移動停損(自最高4.6R回吐至3.0R) | 1 | 100.0% | +2.02 | +2.0 |
| 移動停損(自最高18.1R回吐至5.4R) | 1 | 100.0% | +17.73 | +17.7 |
| 移動停損(自最高17.2R回吐至5.2R) | 1 | 100.0% | +17.94 | +17.9 |
| 移動停損(自最高17.7R回吐至5.3R) | 1 | 100.0% | +15.52 | +15.5 |
| 移動停損(自最高7.1R回吐至3.0R) | 1 | 100.0% | +2.69 | +2.7 |
| 加碼分組 | 筆數 | 勝率 | 平均R | 合計R |
|---|---|---|---|---|
| 無加碼 | 433 | 7.4% | -0.74 | -321.5 |
| 有加碼(1次) | 147 | 91.8% | +2.66 | +390.3 |
| 有加碼(2次) | 50 | 100.0% | +5.21 | +260.7 |
「一成」用的是 2026-10-08 那一天的 池=100 快照。那個定義太嚴 —— 它只是某一天的名單,而回測是跨 365 天×2、逐日建池跑的。 問「回測有沒有可能告訴我這檔的事」,該看回測實際進過場的標的:
| 比對基準 | 涵蓋線上 70 筆 | 這些單線上總R |
|---|---|---|
| (甲) 2026-10-08 那天的 池=100 快照 | 7/70 = 10.0% | −8.04 |
| (丙) 回測兩份樣本實際進過場的 197 個標的 | 20/70 = 28.6% | −22.18 |
| (乙) 300 檔候選超集快照 | 30/70 = 42.9% | −32.30 |
三個數字都對,但講的不是同一件事。該用的是 (丙) 的 28.6%,不是 10%。 母體分歧這件事本身不變(池 100 vs 線上實際 453、T1 vs T1+T2 是結構性的, 不靠百分比成立),但「一成」這個說法要收回 —— 它寫進了 commit 8fc4ac2 的訊息跟前面那一節,以這一節為準。
(線上也多了兩筆:1000PEPEUSDT −1.50(11-11 平)、COLLECTUSDT −1.18(11-12 平), 所以分母從 69 變 70。)
| 母體 | 樣本 | 筆數 | 每筆R | 去最好3 | 勝率 | 到4R | 穿破−1R | 分層 |
|---|---|---|---|---|---|---|---|---|
| 池100/T1 | 樣本內 | 383 | +1.548 | +1.273 | 38.9% | 41.3% | 195 | T1 383 |
| 池100/T1+T2 | 樣本內 | 550 | +1.204 | +1.010 | 35.5% | 37.5% | 293 | T1 368/T2 182 |
| 池100/T1 | 樣本外 | 384 | +0.883 | +0.782 | 37.5% | 37.8% | 208 | T1 384 |
| 池100/T1+T2 | 樣本外 | 599 | +0.706 | +0.640 | 34.9% | 35.2% | 328 | T1 363/T2 236 |
兩份樣本都變差,方向一致。 去最好3 樣本內 −0.263、樣本外 −0.142。
逐筆配對的「被改到」是 0 筆 —— 加了 T2 之後,留下來的 T1 單一筆都沒變。 回測沒有全域持倉上限,所以 T2 不會跟 T1 搶格子。那差額是哪來的?
兩塊,而且都量到了:
1. 新增的 T2 單比較弱:樣本內 182 筆每筆 +0.673、樣本外 236 筆 +0.444, 都明顯低於 T1。混進去就把平均拉下來 —— 純算術。 2. 同標的冷靜期把 16 筆 T1 單擠掉了:T1-only 383 筆 → T1+T2 裡只剩 368 筆 T1, 共同 367 筆。消失的 16 筆裡 13 筆在同一標的上找得到更早的 T2 進場 (PAXGUSDT、CHZUSDT×2、BERAUSDT、ZROUSDT、TAOUSDT、FILUSDT×3、 NEARUSDT、TRXUSDT、INTCUSDT、AAVEUSDT),剩下 3 筆是 MSFTUSDT,沒找到。 機制是「出場後冷靜根數」:T2 先進場,等它出場後的冷靜期蓋掉了後面那個 T1 訊號。
| T1 | T2 | |
|---|---|---|
| 回測 樣本內 每筆R | 約 +1.6(383 筆) | +0.673(182 筆) |
| 回測 樣本外 每筆R | +0.883(384 筆) | +0.444(236 筆) |
| 線上 每筆R | −0.674(54 筆) | +0.456(15 筆) |
回測說 T1 比 T2 好;線上說 T2 比 T1 好。兩邊符號是反的。
這不急著下結論,因為兩邊的 T1/T2 本來就不是同一個東西: 線上的分層來自朋友的儀表板、從 453 檔裡挑;回測是 assign_tiers 自算、 從當日前 100 檔裡挑(設定.ini 第 32 行記著自算 vs 他的 T1 重疊約 80%)。 方案 C(池=300)會把「從多寬的池子裡挑」這一項拉近,跑完再看這個矛盾還在不在。
所以「要不要在回測裡做 T2」這件事,第一階段的答案是「回測說不要」, 但那個答案建立在一個只涵蓋線上 28.6% 的母體上 —— 等 C 跑完才算數。
拿 tier_want 的預設重跑 ATR1220 那一組設定:
`` 耗時 27.1 分 重跑 a236f8728b6386bd978e0e5364f5ca3c 回測結果_驗tier_ATR1220.csv 基準 a236f8728b6386bd978e0e5364f5ca3c 回測結果_重跑_ATR1220.csv 對得上 ✓ 這個改動是行為中性的 重跑 383 筆 每筆 +1.548 分層分布 {'T1': 383} ``
所以 11-12 改 daily_tier_map/tier_at/進場門檻那一輪沒有動到任何行為, 底下 T1/T2 的比較可以信。
我原本以為 池 100→300 要多抓一堆標的。實際看日誌:
| 母體 | 要模擬的標的數 |
|---|---|
| 池100/T1-only | 242 檔 |
| 池100/T1+T2 | 270 檔 |
| 池300/T1+T2 | ~298 檔(超集就 300,日線全在快取) |
原因是 候選超集=300 把母體上限鎖在 300,池 100→300 改的是每天誰有資格進 RS 排名(當日成交額前 100 名 vs 前 300 名),不是要模擬的總檔數。 所以一組約 30 分,不是我先前估的 50~60 分。
這也讓 池=300 的意義更清楚:超集 300 檔、每日池也取 300 → RS 排名幾乎是在 整個超集裡競爭,T1(composite 前 20)會從一個寬 3 倍的池子裡挑, 比較接近線上從 453 檔裡挑的樣子。
全部重掃(判定 5 + ATR 5 + 保本 8 + 校準 1,扣掉共用的現況組約 17 組 × 兩份樣本 × 30 分)要 19 小時。只量有決策意義的方向:
| 組 | 為什麼量它 |
|---|---|
| C_判定盤中低點 | 11-05 套用的「收盤+災難停損1.5」是目前最大的改動,先確認新母體裡它還是對的。唯一的「回到舊規則」對照 |
| C_保本2.5 | 往下。TAUSDT 那類(最高到過 +2.57R 卻收 −1.5R)會被救到 |
| C_保本8.0 | 往上。舊母體樣本內的峰,但配對後增益不存在 —— 換母體再驗 |
| C_ATR關掉 | 收緊到純結構位。舊母體樣本內的峰 |
| C_ATR2025 | 放寬一倍。舊母體樣本內顯著更差、樣本外符號翻正 |
五組 × 兩份樣本 = 10 跑 ≈ 5 小時。基準組就是 C池300T1T2(現況), 同母體同窗口,所以每一組都配得起來。
run_stage2.py 開頭先檢查基準組:兩份樣本的 去最好3 都要 > 0。 至少一邊 ≤ 0 就不跑那五組,直接寫:
> 在線上實際交易的母體裡這套策略沒有邊 —— 不跑五組參數掃描。 > 這比任何參數結論都重要,要先處理這件事。
理由是不想在「邊已經不在了」的情況下再燒五小時調參數 —— 那時候要談的不是參數。
照既有規矩:(1) 兩份樣本的去最好3 都要贏現況;(2) 逐筆配對 |t| ≥ 2 且兩份樣本 同號(符號翻面就是沒東西);(3) 尾巴不能變長(最差R、穿破−1R); (4) 到 4R 的密度不能被砍掉。全部過才談套用,只過一兩條就是留著不動。
套用本身(真的去改 設定.ini 的交易參數)仍然是獨立的一步, 會把四條判準逐條列出來再動。
這一條要先釘死,因為做錯方向代價很大。用今天的成交額名次切 300:
| 筆數 | 合計R | |
|---|---|---|
| 線上賺錢的單,標的在前 300 內 | 4 | +12.76 |
| 線上賺錢的單,標的在 300 名外 | 6 | +20.10 |
300 名外那六筆:STABLEUSDT +6.15(名次 412)、DODOXUSDT +5.92(517)、 SOLVUSDT +4.24(393)、COLLECTUSDT +2.53(479)、GRVTUSDT +1.16(422)、 TRUTHUSDT +0.10(409)。
所以如果把線上的 池大小 從 700 改成 300 來「完全同步」,會砍掉目前獲利的 六成以上(毛利 +32.86R 裡的 +20.10R)。 (名次用今天的快照、不是當時的,暴衝過的幣當時可能排得更前面,所以這個數字 是指示性的。但方向很清楚。)
結論:C 只動掃描,不動線上任何設定。 涵蓋率從 10% 拉到 ~43%, 剩下那段差距(池 300 vs 線上實際 453)是刻意留的,記成一筆欠著的決定, 不是當成解決了。
第一階段(在跑),三個母體的對照,兩份樣本:
1. 池100/T1(= 11-12 以前所有結論的母體,已有:ATR1220/ATR1220_外) 2. 池100/T1+T2(只換分層、其他全同 → 可以逐筆配對,分離出 T2 的效果) 3. 池300/T1+T2(方案 C 本身)
前面還有一道對帳:拿 tier_want 的預設重跑 ATR1220,必須逐字重現 md5 a236f8728b6386bd978e0e5364f5ca3c。對不上就是 11-12 那個改動不是行為中性的, 底下 T1/T2 的結論全部不能信 —— 所以對帳沒過就不會往下跑。
第二階段(要先看第一階段):把掃描宣告的母體(驗證_高原_重跑.py 的 天數, 池 與 分層)改成 池=300/("T1","T2"),然後在那個母體裡重新量 出場參數(判定/災難停損/保本門檻/ATR 下限)。
為什麼不現在就改宣告:改了會讓 37 份既有指紋全部對不上 → 三個題目 18 組 × 兩份 樣本全要重跑,好幾個小時。而這件事值不值得做,要看第一階段的答案:
「幣安前 100 大、只做 T1」那個母體裡,而線上一直在一個沒有任何證據的 地方交易。那時候要談的不是調參數。
池(100 vs 700)跟分層(T1 vs T1,T2)這兩條現在每天都會在 healthcheck 報。 先不寫進 刻意不同 —— 現在的狀態確實是分歧的,紅燈是對的。 第二階段把宣告改成 池300/T1+T2 之後,分層那條會真的消失, 池那條(300 vs 線上 453)才寫進 刻意不同 並附上這一節的理由。
沒有改任何交易參數。
使用者問「依照這陣子的交易紀錄,有沒有什麼能改善的」。 翻完 69 筆之後,答案不是某個參數,是一件更根本的事: 所有出場參數的結論,是在一個只占線上 10% 交易的母體上量出來的。
<!-- 核對 檔=交易紀錄_快照_20261112.csv 分組=分層 -->
| 分層 | 筆數 | 總R | 每筆R | 勝率% |
|---|---|---|---|---|
| T1 | 55 | -37.57 | -0.683 | 9.1 |
| T2 | 15 | +6.84 | +0.456 | 33.3 |
(as-of 2026-11-12 13:02,70 筆。指著凍結快照、不指 交易紀錄.csv —— 指著活檔的話每平倉一筆就紅一次,那種紅燈沒人會看。)
全部 70 筆(2026-10-18 ~ 11-12):總R −30.73、每筆 −0.439、勝率 14.3%。 (這一節原本寫 69 筆/−29.55,是 11-12 中午以前的數字;之後 COLLECTUSDT −1.18 平倉。) 按版本:過渡 5 筆 −5.00/v10 47 筆 −18.18/v11 2 筆 −2.63/v12 15 筆 −3.74。 現行規則(v11+v12,收盤判定之後)17 筆、每筆 −0.375 —— 回測同一套規則說樣本內 +1.548、樣本外 +0.883。
<!-- 核對 檔=交易紀錄_快照_20261112.csv 分組=位階 -->
| 位階 | 筆數 | 總R | 每筆R | 勝率% |
|---|---|---|---|---|
| 位階1 | 51 | -17.19 | -0.337 | 13.7 |
| 位階1.5 | 7 | -6.00 | -0.857 | 14.3 |
| 位階2 | 12 | -7.54 | -0.628 | 16.7 |
位階這一刀沒看出東西(三層都在虧,勝率都 14~17%)。有東西的是分層。
保本門檻R = 4.0,所以「最高R 有沒有到過 4R」決定保本/移動停損/跌破MA30 這些規則有沒有機會啟動。
| 最高R 到得了 | 線上 v11+v12 | 線上 v10 | 回測樣本內 | 回測樣本外 |
|---|---|---|---|---|
| ≥ 2.0R | 29.4% | 27.7% | — | — |
| ≥ 4.0R | 17.6% (3/17) | 14.9% (7/47) | 41.3% | 37.8% |
| ≥ 8.0R | 5.9% | 6.4% | — | — |
線上只有 ~15% 的單拿得到保本保護,回測有 ~40%。 所以 11-05 到 11-07 那三輪(收盤判定、災難停損、保本門檻、ATR 下限) 調的全是「到得了 4R 以後」的規則 —— 那段在線上八成五的單身上從來沒執行到。
| 項目 | 線上實際 | 回測釘的 | 卡不卡 |
|---|---|---|---|
| 池 | [掃盤] 池大小 = 700,門檻 1.5M → 實際 453 檔 | 驗證_高原_重跑.py:97 池=100(≥34.4M) | 卡死 |
| 分層 | [參數] 只做分層 = T1,T2 | 回測.py:956 寫死 T1-only | 卡死 |
| 連敗熔斷 | 5 連敗停 12 小時 | 沒有這個機制 | 真的,但只有 10% |
| 同時持倉 | 最多 20 | 不設上限(回測.py:1241 自己寫著) | 沒卡到(峰值 11) |
| 資金費率上限 | 0.1 | 沒有 | 沒量 |
| BTC 濾網 | 讀 −5/−10 兩個鍵 | 寫死 −5,不讀鍵 | 同值,目前沒差 |
硬證據:
樣本外那份也一樣(384/384)。回測從來沒有評估過 T2。
2026-10-08 那天的快照):只有 7/69 筆(10%) 的標的在池裡, 62 筆(90%) 的標的回測的池從來沒有包含過。 連 300 檔的候選超集都比不到一半(30/69 在內)。
排在前 100 名(=回測池)的只有 9/69 筆 = 13%。兩個快照講同一件事。
的新標的(ARIAUSDT 現在排第 28、329M),15 個是量就是小(CTRUSDT 0.8M、 METISUSDT 0.8M、TAKEUSDT 0.6M)。
STABLEUSDT +6.15(現在排 412)、DODOXUSDT +5.92(517)、SOLVUSDT +4.24(393)、 COLLECTUSDT +2.53(479)、MERLUSDT +1.90(284)、ARIAUSDT +6.77/+2.84(新上架)。
也就是說:回測在量「幣安前 100 大、只做 T1」這套系統; 線上在跑「門檻 1.5M 以上 453 檔、做 T1+T2」那套。 兩者交集 10%。 出場規則對齊得再好(11-12 已經確認是同一支 trail_update、 設定 11 鍵一致)也沒用 —— 進場母體不一樣,結論就搬不過去。
線上對照.py 就是為了抓這種分歧寫的。它沒抓到,有兩個原因:
1. 第一段 回 = any(有提到(k, f) for f in 責["回測"] + 共用檔) —— 共用檔 = ["shadow_bot.py"] 被 OR 進「回測」那一欄。 [參數] 的鍵只要 shadow_bot.py 提過,回測欄就是「是」。 只做分層 就是這樣躲過去的:它在 [參數]、線上讀它、 而 回測.py 連這個字串都沒有,表格卻一片空白。 這支的 docstring 其實自己承認過「那一欄的空白不代表沒問題」, 但沒人把它變成一個會叫的檢查。 2. 區段負責 只有 參數/台股/美股,[掃盤] 整段被 continue 跳過 —— 而 池大小 = 700 就住在 [掃盤]。
兩個都修了(commit 見下):加了「回測主程式」欄(只看 回測.py,不含共用檔), 並把 [掃盤]/[儀表板] 納入。改完它立刻標出 17 個鍵, 只做分層 與 池大小 都在裡面。
這是這個模式的第 8 次。前七次記在 [[verify-tools-carry-stale-rules]]。 這次壞的是守門工具自己的涵蓋範圍,而且它在 docstring 裡寫著自己有這個洞。
我先用 交易紀錄 重建熔斷,算出「鎖住 190/579 小時 = 33%」。 後來去翻機器自己的 logs/執行紀錄_*.log 數 [熔斷] 訊息: 1719 輪掃描裡 174 輪被熔斷擋住 = 10%。我的重建高估了三倍。 機器自己的日誌就是 ground truth,別拿重建當證據 —— 跟 [[backtest-metric-as-artifact]] 同一條教訓。
同樣地,「同時持倉上限 20」我本來列成差異,一量峰值只有 11,從來沒卡到, 就不能拿它解釋。列出來的差異不等於有影響,每一條都要量。
改的全是量測能力,沒有動任何交易參數:
t1_at → tier_at,進場門檻改成比 tier_want,run() 多一個 tier_want=None(None = ("T1",) = 11-12 以前的行為)。 預設行為一字不變,對帳用重跑 ATR1220 驗 md5 逐字相同。 池不用改 —— pool_size 本來就是 run() 的參數,min_vol 本來就讀設定檔。
沒有改:池大小、只做分層、連敗熔斷筆數、任何出場參數。 因為資料還不能說該往哪邊走,而那是使用者的決定,不是我的:
但注意:線上在回測池內的那 7 筆是 0 勝、每筆 −1.149 —— 收回去不見得更好,而且會砍掉目前全部的獲利來源。
先量得到才談得上選。下一步(已排):池=100 不動、只把分層從 T1 換成 T1+T2, 兩份樣本都跑 —— K 線全在快取裡,不用再打幣安。 池 100→700 要抓 400 多檔新標的,那是另一件事,要先問。
healthcheck 這輪冒出兩個異常,查完一個是誤報、一個是真的但只有一筆:
1. STABLEUSDT(誤報,已擋):紀錄「保本後收盤跌破MA30|芭樂價已部分停利」 +6.15R,重跑說「芭樂價停利(12.0R)」+12.00R。根因在 shadow_bot.py:1560: if bonanza_frac >= 1.0 or 部分出場盒 is None: → 整筆平掉。 驗證出場._出場參數 有傳 bonanza_frac=0.2、沒傳 部分出場盒, 所以重跑在 12R 就整筆結束。線上實際是賣 20%、剩下抱到跌破 MA30,混合成本 +6.15R。 重跑路徑沒有「部分出場後繼續抱」的模型 → 這條驗不了,照「加碼單不重跑」的 既有寫法跳過。R 數本身還是有在驗:healthcheck 上面那段「R 數對不上」 早就會算芭樂混合(應該 = _芭比 * _芭R + (1.0 - _芭比) * 應該)。 欠著:要真的驗得了,驗證出場.重跑 得傳 部分出場盒 並算混合 R。 (這是同一個模式的第 9 次,而且是第一次燒到真的線上單。)
2. MERLUSDT(真的,但只有一筆,不處理):同一根(11-10 07:00 收盤)、 同一個出場原因,紀錄成交 0.03292、重跑用 0.03276 —— 差 +0.49%,R 差 0.18。 我原本以為這是「掃盤在 :02、回測用 :00 收盤」的執行落差, 於是把所有同出場原因的單都量了一次:現行規則 15 筆裡 14 筆價差是 0.000%, 線上成交價跟那根收盤價一模一樣。所以這不是系統性落差,MERLUSDT 是單一例外。 容忍值 0.15R 不動 —— 能調大的警報等於沒有警報 (同 單筆容忍R 那段註解的理由)。留著讓它叫。
11-06 掀開的問題是:「放寬停損沒用」這個寫進 設定.ini 的結論是在盤中低點 判定下量的,理由(「被掃的照樣 −1.00R」)在收盤判定下不成立。五格在現行規則 (收盤/災1.5/群組位階)下重跑完,兩份樣本都跑了。
結論:不動。停損距離下限ATR倍數 維持 1.2、停損ATR放寬倍數 維持 2.0。 舊結論的判決活下來了,但它的理由要整段換掉 —— 新的理由是量出來的。
樣本外那條是這輪順手補的 —— 驗證_高原_重跑.py 原本樣本外一律不對帳 (對 = 題.get("對帳") if not 窗口尾 else None),等於一半的結論沒有地板。 ATR 題跟 保本門檻R 題的「現況」組生效設定完全一樣,所以兩題互當對方的對帳組。 已加 對帳_外 鍵,並拿一份數字不同的檔(保本2.5_外,407 筆 +0.850)驗過它會叫。
<!-- 核對 多檔 檔欄=來源檔 -->
| 組 | ATR下限/放寬 | 筆數 | 每筆R | 去最好3 | 10R+密度 | 時序回撤 | 穿破−1R | 來源檔 |
|---|---|---|---|---|---|---|---|---|
| ATR關掉 | 0/0 | 392 | +1.564 | +1.340 | 4.6% | 19.3 | 199 | 回測結果_重跑_ATR關掉.csv |
| ATR0808 | 0.8/1.5 | 387 | +1.553 | +1.326 | 4.7% | 17.7 | 196 | 回測結果_重跑_ATR0808.csv |
| ATR1220(現況) | 1.2/2.0 | 383 | +1.548 | +1.273 | 4.4% | 14.3 | 195 | 回測結果_重跑_ATR1220.csv |
| ATR1520 | 1.5/2.0 | 378 | +1.488 | +1.209 | 4.2% | 14.3 | 194 | 回測結果_重跑_ATR1520.csv |
| ATR2025 | 2.0/2.5 | 352 | +1.317 | +1.065 | 3.7% | 16.3 | 184 | 回測結果_重跑_ATR2025.csv |
單調:越緊越好、越寬越差。峰在「完全關掉」。
<!-- 核對 多檔 檔欄=來源檔 -->
| 組 | ATR下限/放寬 | 筆數 | 每筆R | 去最好3 | 10R+密度 | 時序回撤 | 穿破−1R | 來源檔 |
|---|---|---|---|---|---|---|---|---|
| ATR關掉 | 0/0 | 394 | +0.933 | +0.784 | 2.5% | 24.2 | 220 | 回測結果_重跑_ATR關掉_外.csv |
| ATR0808 | 0.8/1.5 | 392 | +0.980 | +0.846 | 2.3% | 23.5 | 212 | 回測結果_重跑_ATR0808_外.csv |
| ATR1220(現況) | 1.2/2.0 | 384 | +0.883 | +0.782 | 2.3% | 26.1 | 208 | 回測結果_重跑_ATR1220_外.csv |
| ATR1520 | 1.5/2.0 | 381 | +0.896 | +0.789 | 2.1% | 26.3 | 206 | 回測結果_重跑_ATR1520_外.csv |
| ATR2025 | 2.0/2.5 | 355 | +0.920 | +0.823 | 2.0% | 17.8 | 187 | 回測結果_重跑_ATR2025_外.csv |
順序整個打散。樣本內第一名的「關掉」在樣本外掉到第四(+0.784,跟現況 +0.782 幾乎同一點)。樣本內最差的 2025 在樣本外變第二好。這就是鋸齒,不是高原。
同一個(標的+進場時間)在兩組裡相減,消掉市場的共同波動:
| 組 | 樣本內 配對差/筆 | t | 樣本外 配對差/筆 | t |
|---|---|---|---|---|
| ATR關掉 | +0.051 | +0.32 | +0.064 | +0.80 |
| ATR0808 | +0.004 | +0.03 | +0.078 | +1.27 |
| ATR1520 | −0.085 | −2.18 | +0.023 | +0.46 |
| ATR2025 | −0.260 | −2.79 | +0.106 | +1.07 |
樣本內唯一兩個「說得出話」的(1520、2025)說的是放寬顯著更差。 到了樣本外,這兩個符號翻過來變成正的,而且都說不出話。
樣本內唯一站得住的結果,樣本外不但沒複製,還反向。 這個旋鈕沒有東西。
| ATR關掉 | 現況 1.2 | ATR2025 | |
|---|---|---|---|
| 樣本內 穿破−1R | 199/392 = 50.8% | 195/383 = 50.9% | 184/352 = 52.3% |
| 樣本外 穿破−1R | 220/394 = 55.8% | 208/384 = 54.2% | 187/355 = 52.7% |
把停損放寬一倍,穿破 −1R 的比率樣本內還上升。原因很直白:穿破是 「收盤一根棒子跳過停損價」造成的,那在任何停損寬度下都會發生。 11-06 量到的「停損單平均R 隨停距單調改善」是真的,但它是單筆虧損大小 的梯度,不是穿破頻率的梯度 —— 我當時沒把這兩件事分開。
回測輸出有 續抱R(完全不出場、抱滿追蹤期、期末收盤結算)跟 出場早了R = 續抱R − R數(正的=抱著會更好)。註解明寫「出場後最大R 是 事後最優點,拿來比會高估續抱的好處」,所以只用 續抱R。
停損出場的單(災難+觸及),按停損距離分帶,出場早了R:
| 停損距離 | 樣本內 筆數/平均/中位 | 樣本外 筆數/平均/中位 |
|---|---|---|
| <1.5% | 63/+1.73/+0.98 | 31/+1.12/+0.58 |
| 1.5~2.5% | 63/+0.86/−0.58 | 92/+0.73/+0.17 |
| 2.5~4.0% | 62/+0.37/+0.14 | 84/+0.65/+0.11 |
| 4.0~6.0% | 31/+0.55/−0.17 | 28/+1.07/+0.22 |
| ≥6% | 14/+0.24/+0.29 | 5/−0.69/−0.81 |
樣本內完全符合使用者的話:停損最緊那一帶,抱著平均會多賺 1.73R、 中位數 +0.98R,59% 的單抱著會多賺超過 0.5R —— 而且隨停損放寬單調衰減 (+1.73 → +0.86 → +0.37 → +0.24)。
樣本外這個梯度幾乎消失:最緊那帶 +1.12,但 4~6% 那帶是 +1.07,差不多; ≥6% 只有 5 筆。跟配對 t 的結論一致:這個效應在一份樣本裡看得見,另一份看不見。
TAUSDT 最高到過 +2.57R,所以門檻降到 2.5 會救到它。配對之後:
| 組 | 樣本內 配對差/筆 | t | 只看被改到的 | 樣本外 配對差/筆 | t |
|---|---|---|---|---|---|
| 保本2.0 | −0.147 | −1.43 | −0.472(117 筆) | −0.017 | −0.20 |
| 保本2.5 | −0.118 | −1.37 | −0.479(93 筆) | +0.017 | +0.27 |
救得到 TAUSDT,但代價是被它改到的那 93~117 筆每筆平均掉 0.47R (提早被保本停損掃出去,後面的行情沒了)。樣本內淨負、樣本外歸零。 往上調(6.0/8.0)11-06 已經判過不套用。兩個方向都沒東西。
三個旋鈕、兩個方向,全部量過:
| 旋鈕 | 方向 | 判決 |
|---|---|---|
| 停損距離下限ATR倍數 | 放寬 | 樣本內顯著更差、樣本外符號翻正但說不出話 → 不動 |
| 停損距離下限ATR倍數 | 收緊/關掉 | 兩份樣本都說不出話(t +0.32/+0.80)→ 不動 |
| 保本門檻R | 往下 2.0/2.5 | 樣本內淨負、樣本外歸零 → 不動 |
| 保本門檻R | 往上 6.0/8.0 | 11-06 判過,配對後增益不存在 → 不動 |
| 災難停損R | 放大/關掉 | 配對 +0.023(t +0.80)、最差單筆 −3.61 → 不動(而且使用者說 1.5R 可接受) |
TAUSDT 那筆 −1.50R 是收盤填價規則的價錢,不是某個參數設錯。 系統現在站在這個曲面的平坦處;能動的旋鈕都量過了,沒有一個站得住。
這一輪沒有改任何參數。
使用者問:ATR 這一輪量出來的結論要套到線上,線上現在是不是也在同一個模式。 查完的答案是「是」,而且是最強的那種是。但查的過程又挖到兩個「拿一套跟線上 不同的規則去驗線上」,跟 [[verify-tools-carry-stale-rules]] 同一個家族。
回測.py:703 呼叫的是 B.trail_update —— 就是 shadow_bot.py:1413 那一支。 收盤判定、災難價、跳空照實的判斷全部長在那支裡面(shadow_bot.py:1501~1535), 線上跟回測共用。所以「填價規則有沒有對齊」在這一層不可能分歧, 會分歧的只有傳進去的參數。
掃描釘的 共同覆蓋 vs 線上實際生效(設定.ini 有就用它、沒有就用程式 fallback): 位階定義/只做位階/位階2守住/位階2站上倍數/停損判定/災難停損R/停損跳空照實/ 最多加碼次數/乖離警戒百分比/停損距離下限ATR倍數/停損ATR放寬倍數 —— 11/11 一致。
其中要特別記一筆:ATR 這兩個鍵幣圈 設定.ini 裡根本沒有。 線上 shadow_bot.py:2279-2280 跟 回測 回測.py:344-345 都是 cfg_num(..., 1.2) /(..., 2.0) 的 fallback,掃描釘的也是 1.2/2.0 —— 三邊剛好一致,但那個 1.2 只活在程式碼裡,沒有寫在設定檔。如果這輪量完決定放寬,要把鍵加進 [參數] (兩邊讀同一個鍵,加了就會同步;不加而只改程式 fallback 會變成兩處要記得改)。
回測結果_重跑_ATR1220.csv 跟 回測結果_重跑_判定_收盤災1.5.csv md5 一模一樣(a236f8728b6386bd978e0e5364f5ca3c)。這比「數字對得上」強一級。 (順手校正一個我自己的記錄誤差:這兩份檔的原始列數是 385、每筆 +1.542; 報表印的 383 筆/+1.548 是因為 驗證_高原_重跑.py:264 的 讀() 會濾掉 未平倉=="是" 的 2 筆。383/+1.548 那組數字沒錯,只是它是濾過的。)
線上對照.py 的第二段表直接點出來:這兩個鍵 回測.py:410-411 讀了也傳了 (→ 707-708),線上沒讀,所以 trail_update 靜默吃函式預設(收盤/0)。
今天沒有行為差異 —— 兩個鍵在 設定.ini 裡都不存在,回測也落在同一組 fallback。 但這就是 2026-10-19 [台股] 停損判定 空轉兩天的同一顆地雷:以後有人把 出場MA模式 寫進設定檔,只有回測會變、線上不會。已接上(shadow_bot.py:2526), 線上對照.py 現在幣圈兩欄都是「是」。行為不變。 (附帶:出場MA模式=斜率 2026-09-11 掃過,四個窗口全輸,見 設定.ini 第 221 行。)
驗證出場.py 的迴圈跑 幣圈/美股/台股 三個市場,但 重跑() 從來沒收到市場, 一律吃 市場="參數"(幣圈區段)。實際差多少:
| 區段 | 保本門檻R | 災難停損R | 停損判定 | 移停啟動R | 芭樂價R |
|---|---|---|---|---|---|
| 參數(幣圈) | 4.0 | 1.5 | 收盤 | 9999 | 12 |
| 台股 | 2.5 | 0.0 | 收盤 | 10 | 0 |
| 美股 | 2.5 | 0.0 | 盤中低點 | 10 | 0 |
五個全都不一樣。而 設定.ini[已決定] 還明寫著 禁用.台股.災難停損R = 是, 等於這支會拿一個已決定不要用的機制去驗台股的單。
還沒燒到:交易紀錄_台股.csv 不存在、交易紀錄_美股.csv 0 筆, 所以到今天為止沒有任何一筆被錯驗。台美股一上線就會燒,現在拆掉。 幣圈的數字完全沒動(55 筆/30 相符/25 筆舊規則版本,修前修後一樣)。
同一支還有第二個小毛病:「整筆從未達 2.5R」是寫死的字串, 實際重跑用的是設定檔的 4.0 —— 判定邏輯沒錯(它用的是真值), 但報表上印 2.5、做的是 4.0,讀報表的人會被騙。連 docstring 第一行也是 2.5。 兩處都改成按市場從設定檔讀。
股票回測.py/股票模式.py 還有 6 個參數沒傳進 trail_update: bonanza_R(設定檔 12 → 吃到 0)、bonanza_frac(0.2 → 1.0)、bonanza_done、 部分出場盒、ma_exit_mode、slope_bars。前兩個是真的分歧(芭樂價機制在台美股 等於沒有),後四個目前落在同樣的預設。另外 [美股] 沒有 停損判定 鍵, fallback 是盤中低點,跟 [台股] 的收盤不一致。台美股擱置中,照舊不動,記著。
這一輪沒有改任何交易參數。 改的兩個檔都是「讓驗證的東西跟線上一致」。
使用者看板子上兩筆單:「這兩個都做得不錯,大時區的圖都是可以的。 不過 TA 停損空間太近,均線沒怎麼變化就出場了。」
TAUSDT 2026-11-05 20:02 進 → 11-06 00:02 出,持倉 4.0 小時 進場 0.07201/原始停損 0.0709107/出場 0.0703611 停損距離 1.53%、R數 −1.50(封在災難停損上限)、最高R +2.57、MAE_R −2.31 停損來源 突兀量低點-0.5ATR(突兀量後 2 根回測不破)、型態 等距發散、位階1、規劃風報比 6.37
同一天最近 12 筆裡,停損最近的兩筆是 TAUSDT 1.53% 跟 JSTUSDT 1.40% —— 正好就是唯二穿破 −1R 的兩筆(−1.50、−1.13),其餘 10 筆停距都在 3~7%,全部停在 −1.00。
第一輪我算出「線上穿破−1R 只有 3/55,回測 195/383」,看起來是天大的差異。 拆開規則版本就沒了:
| 規則版本 | 筆數 | 每筆R | 穿破−1R | 期間 |
|---|---|---|---|---|
| v9→v10 過渡 | 5 | −1.000 | 0/5 | 10-21~10-25 |
| v10 | 47 | −0.387 | 1/47 | 10-21~11-05 |
| v11 | 2 | −1.315 | 2/2 | 11-06 |
| v12 | 1 | +2.840 | 0/1 | 11-06 |
線上 52/55 是盤中低點規則(碰到就成交在停損價,剛好 −1.00)。 收盤判定 11-05 才套,已平倉只有 3 筆。 不分版本比,就是拿兩套規則互相解釋 —— 跟 10-17 台股那次誤報同一個坑。
所以:使用者的觀察在僅有的 3 筆新規則單上完全對上(穿破的兩筆就是最窄的兩筆), 但 n=3,還不能當結論。有資料的地方是回測。
基準 判定_收盤災1.5,停損出場單依停損距離分桶:
| 停距% | 樣本內 停損單平均R | 打到 −1.5 上限 | 樣本外 停損單平均R |
|---|---|---|---|
| < 1.5% | −1.296 | 26/59(44%) | −1.234 |
| 1.5~2% | −1.191 | 6/34 | −1.224 |
| 2~3% | −1.233 | 17/58 | −1.228 |
| 3~4% | −1.191 | 7/32 | −1.199 |
| 4~6% | −1.138 | 2/30 | −1.196 |
| ≥ 6% | −1.073 | 0/12 | −1.138 |
設定.ini 裡寫著:
> 先試的方向是放寬停損(停損距離下限ATR倍數),五格掃完結論是這個旋鈕沒用: > 關掉 +1.193/0.8-1.5 +1.186/1.2-2.0(現況) +1.144/1.5-2.0 +1.092/2.0-2.5 +1.045 > 原因是 R 用停損寬度計價:停損×k = 部位÷k,被掃的照樣 −1.00R, > 但每一筆贏單的 R 全部÷k。
「被掃的照樣 −1.00R」只在盤中低點判定下成立。
證據(硬的):回測結果_重跑_ATR1220.csv 跟 回測結果_重跑_判定_盤中低點.csv md5 一模一樣(4e8d868063a3b240236528b2a42d8923)—— 那輪的基準組就是盤中低點,整輪跑在 盤中低點/災難停損R 0 之下(CSV 日期 10/30~31)。
改成收盤判定之後,虧損大小變成 (收盤−停損)/風險,會隨停損寬度動(上表)。 所以放寬停損現在多了一邊當初不存在的好處:
兩邊同一個數量級了。舊結論的理由已經不成立,結論本身要重驗。
這是兩天內第 6 次「改了系統、沒改驗證它的東西」。前五次記在 [[verify-tools-carry-stale-rules]]。這次不一樣的是:壞掉的不是工具的程式碼, 是一個寫進設定檔、當成已知事實在用的結論。
而且它差點自己複製一次:驗證_高原_重跑.py 的 main() 看到 CSV 存在就 「讀既有結果(不重跑)」,所以今天重跑 ATR 會直接沿用那五份舊規則的檔, 把舊數字印成今天的結論。已修(規則指紋,commit ac2dcae)。
ATR 五格在現行規則(收盤/災1.5/群組位階)下重跑,兩份樣本,約四小時。 ATR1220 的生效設定跟 共同覆蓋 完全一樣,所以它應該逐字重現 判定_收盤災1.5(383 筆 +1.548)—— 這是這輪的對帳,對不上底下全部不能信。
沒有改任何參數。 這一輪只是量。
<!-- 核對 多檔 檔欄=來源檔 -->
| 組 | 保本門檻R | 筆數 | 每筆R | 去最好3 | 10R+密度 | 時序回撤 | 穿破−1R | 來源檔 |
|---|---|---|---|---|---|---|---|---|
| 保本2.0 | 2.0 | 414 | +0.823 | +0.729 | 1.9% | 23.2 | 160 | 回測結果_重跑_保本2.0_外.csv |
| 保本2.5 | 2.5 | 407 | +0.850 | +0.755 | 2.0% | 24.8 | 181 | 回測結果_重跑_保本2.5_外.csv |
| 保本4.0(現況) | 4.0 | 384 | +0.883 | +0.782 | 2.3% | 26.1 | 208 | 回測結果_重跑_保本4.0_外.csv |
| 保本5.0 | 5.0 | 374 | +0.896 | +0.792 | 2.7% | 26.8 | 216 | 回測結果_重跑_保本5.0_外.csv |
| 保本6.0 | 6.0 | 367 | +0.844 | +0.722 | 3.3% | 50.5 | 227 | 回測結果_重跑_保本6.0_外.csv |
| 保本8.0 | 8.0 | 358 | +0.926 | +0.802 | 5.0% | 59.1 | 235 | 回測結果_重跑_保本8.0_外.csv |
| 保本12.0 | 12.0 | 343 | +0.608 | +0.429 | 11.7% | 104.2 | 256 | 回測結果_重跑_保本12.0_外.csv |
| 保本關掉 | 9999 | 306 | −0.939 | −0.964 | 0.0% | 287.3 | 235 | 回測結果_重跑_保本關掉_外.csv |
三個理由,一個比一個硬。
一、稜線散了。 樣本內 6.0→8.0 是一段往上的稜線(+1.412 / +1.466)。 樣本外 6.0 掉到 +0.722,比現況 +0.782 還差,8.0 才回到 +0.802。 中間凹一格 = 8.0 的左鄰居是壞的。這不是高原上的峰,是鋸齒。 專案自己的判準:峰要在高原中間、鄰居要好 —— 這一格過不了。
二、增益縮水 10 倍。 樣本內 8.0 贏現況 +0.193,樣本外只剩 +0.020。
三、配對之後那 +0.020 連方向都沒有。
這一條是這輪最重要的方法學收穫,單獨寫在下面。
八組跑同一個窗口、同一批進場訊號,但筆數不一樣(樣本內 354~415)。 出場規則一變,「同一標的一次只能有一筆」+「出場後冷靜 3 根」就會讓 後面放進來的單也跟著變。拿兩個不同母體的平均數相減, 等於把「母體換了」算到旋鈕頭上。
同一個 (標的, 進場時間) 在兩組裡是同一筆單的兩種命運,可以直接相減。 (先驗過 16 個檔都沒有重複鍵,有重複就會被 dict 靜靜蓋掉。)
| 保本門檻R | 樣本內 配對差 | t | 樣本外 配對差 | t | 樣本外 只看被改到的 |
|---|---|---|---|---|---|
| 2.0 | −0.147 | −1.43 | −0.017 | −0.20 | −0.050(131 筆) |
| 2.5 | −0.118 | −1.37 | +0.017 | +0.27 | +0.072(92 筆) |
| 5.0 | −0.007 | −0.12 | −0.001 | −0.01 | −0.006(49 筆) |
| 6.0 | +0.088 | +0.89 | −0.066 | −0.69 | −0.321(76 筆) |
| 8.0 | +0.134 | +0.97 | −0.001 | −0.01 | −0.003(102 筆) |
| 12.0 | −0.067 | −0.34 | −0.266 | −1.30 | −0.774(118 筆) |
| 關掉 | −2.014 | −7.36 | −1.778 | −11.18 | −4.945(110 筆) |
2.0~12.0 之間沒有任何一格的 |t| 到得了 2。 唯一說得出話的是「關掉」, 而那證實的是閘門機制(下一節),不是門檻值有東西。
最乾淨的一行:樣本內,調到 8.0 在它改到的 91 筆上一筆加 +0.518R; 樣本外,在它改到的 102 筆上一筆加 −0.003R。 同樣的機制、同樣的筆數規模, 效果在一個樣本裡存在、在另一個裡剛好是零。這就是過擬合的教科書定義。
結論不變(當時就沒套用),但理由從「代價太大要你決定」變成 「增益是假的,沒有東西要權衡」。這兩句話的份量差很多。
工具已經修好:驗證_高原_重跑.py 的報表現在固定印配對差與 t, 判讀那段會在 |t| < 2 時明講「這個差說不出話」。以後每一題都自動擋這個坑。
shadow_bot.py:1567 是 elif be: —— 「保本後收盤跌破MA30」被保本當閘門擋著。 門檻 9999 = 那條出場永遠不觸發,而它佔現況 32% 的出場(121/383)。 所以保本門檻R 真正的意思是 「什麼時候從結構停損交棒給 MA30 跟隨出場」,不是「什麼時候開始保護資本」。 配對 t = −7.36 / −11.18 證實這個閘門是真的、而且很大 —— 有東西的是閘門存不存在, 不是閘門擺在 4 還是 8。
<!-- 核對 多檔 檔欄=來源檔 -->
| 組 | 保本門檻R | 筆數 | 每筆R | 去最好3 | 10R+密度 | 時序回撤 | 穿破−1R | 來源檔 |
|---|---|---|---|---|---|---|---|---|
| 保本2.0 | 2.0 | 415 | +1.324 | +1.068 | 3.6% | 8.8 | 154 | 回測結果_重跑_保本2.0.csv |
| 保本2.5 | 2.5 | 404 | +1.353 | +1.091 | 3.7% | 11.4 | 171 | 回測結果_重跑_保本2.5.csv |
| 保本4.0(現況) | 4.0 | 383 | +1.548 | +1.273 | 4.4% | 14.3 | 195 | 回測結果_重跑_保本4.0.csv |
| 保本5.0 | 5.0 | 375 | +1.592 | +1.311 | 5.1% | 21.6 | 205 | 回測結果_重跑_保本5.0.csv |
| 保本6.0 | 6.0 | 367 | +1.698 | +1.412 | 6.0% | 20.4 | 214 | 回測結果_重跑_保本6.0.csv |
| 保本8.0(峰) | 8.0 | 354 | +1.762 | +1.466 | 7.3% | 20.8 | 222 | 回測結果_重跑_保本8.0.csv |
| 保本12.0 | 12.0 | 338 | +1.481 | +1.167 | 13.3% | 38.4 | 242 | 回測結果_重跑_保本12.0.csv |
| 保本關掉 | 9999 | 268 | −0.945 | −0.973 | 0.0% | 253.2 | 208 | 回測結果_重跑_保本關掉.csv |
對帳:保本4.0 逐字重現 判定_收盤災1.5(383 筆 +1.548 / 383 筆 +1.548)✓
每筆 −0.945、10R+ 密度 0.0%、回撤 253.2,這組數字不合理到必須先查。 查出來是 shadow_bot.py:1567 的一行:
`` elif be: ... exit_reason = "保本後收盤跌破MA%d" % ma_n ``
「保本後收盤跌破MA30」這個出場被保本當閘門擋著。 保本門檻設 9999 = be 永遠不成立 = 那條出場永遠不觸發,而它在現況佔 32% 的出場 (121/383)。移動停損也要 be(本來就關著)。
所以「關掉保本」實際上是把主要的獲利了結路徑整個拔掉 —— 剩下的出場只有 觸及停損/災難停損/芭樂12R,單子只能一路騎到崩回 −1.5R。 那組數字是對的,只是它在量一個沒人會想跑的設定。
我原本把它當成「什麼時候開始保護資本」。它其實是「什麼時候從結構停損 交棒給 MA30 跟隨出場」。 門檻拉高不是「晚一點保護」,是 晚一點讓 MA30 這條出場開始作用。
這樣整條曲線就講得通了:
→ 10R+ 只有 3.6%、每筆最低,但回撤也最低(8.8)
但去最好3 掉回 +1.167、回撤翻到 38.4 —— 怪物單變多,但更多單原形畢露
峰在 8.0,去最好3 +1.466 vs 現況 +1.273(+0.193), 10R+ 密度 4.4% → 7.3%(沒在砍尾巴,反而養尾巴), 最差單筆一樣 −1.50(災難停損在八格裡全部封得住)。
鄰居:6.0 是 +1.412、12.0 掉到 +1.167。 所以 6.0~8.0 是一段稜線,12.0 開始崩 —— 是內部峰不是邊界峰了。
代價寫清楚:回撤 14.3 → 20.8(+45%)、穿破−1R 195→222。
沒有套用。 兩個理由:
1. 還沒驗樣本外。 單一樣本的峰不能套,這是 10-24 六H張開% 的教訓。 已經丟出去跑(八組,約三小時)。 2. 回撤 +45% 不是微調。使用者 2026-09-27 講過「可以犧牲獲利換取更大的 R 數」, 方向上支持拉高門檻;但 8.8(2.0 那格)到 20.8(8.0 那格)是兩倍多, 這個取捨要他自己看著數字決定,不是我代選。
設定.ini 裡 保本門檻R 那段註解(如果有)跟決策紀錄舊的描述, 都把它講成「保護資本的門檻」。它更準的描述是 「結構停損交棒給 MA30 出場的門檻」。下一輪整理文件時改掉。
使用者:「完成後整個再從頭到尾大檢查一次」。
| 檢查 | 結果 | 動作 |
|---|---|---|
| 測試健檢.py(用壞資料驗守門的會不會叫) | 7 條偵測路徑全部會叫 | — |
| 回測健檢.py | 146 類問題 → 0 | 兩條不變式過期,修掉 |
| 核對.py | 15 張表 0 問題 | — |
| 抽查.py 3 | 3 筆攤開算式全對 | — |
| 熔斷驗證.py | 跑得動 | 發現熔斷可能在幫倒忙,記著 |
| 驗證出場.py | 54 筆、29 相符、現行版本的單沒有誤觸 | — |
| 線上對照.py | 只有回測讀 0、沒人讀 0 | — |
| 底圖對照.py | 掃描底圖=線上 | — |
| healthcheck.py | 一切正常 | — |
#5「觸及停損 ⇒ R 必須是 −1.00」 寫的時候只有盤中低點判定 (碰到停損成交在停損價,所以剛好 −1)。台股 2026-10-17、幣圈 2026-11-05 改成收盤判定後,成交在收盤價,R 本來就低於 −1。 → 台股那邊它已經喊狼來了 20 天。
改成只驗方向:停損出場不可能虧不到 1R(那才是不變式); 比 −1 更差的印提醒並列出最差值(=那一輪的災難停損上限)。
#4「無加碼單的 R數 要等於 (出場價−進場價)/風險」 失敗的 50 個檔全是底艙檔。 我第一次改錯了 —— 以為部分出場只會讓記錄的 R 偏低,想用方向區分。 算一筆就知道不對:
8039.TW 記1.54 重算0.08,檔名「底艙3R出50束下緣」 → 0.5×3.0R(先賣一半)+ 0.5×0.08R(剩下那半)= 1.54 ✓
部分出場可以把 R 推高或低,取決於先落袋那段比最後出場好還是差。 所以正確條件不是方向,是這個檔認不認得出部分出場: 芭樂有 芭樂部分停利 欄可以逐筆排除,底艙沒有任何欄位記它。 → 認不出來的檔印「驗不了」並講明原因,不紅燈也不假裝通過。
而且我驗了「改完還會不會叫」:拿 回測結果_重跑_判定_收盤災1.5.csv 做兩個壞檔(一筆 R數 +3、一筆「觸及停損」改成 −0.30),兩條都抓到, 乾淨檔通過。不是把檢查關掉,是不再誤報。
欠著:股票回測.py 跟 回測.py 的輸出要加一個部分出場標記欄, 否則底艙開著的市場永遠驗不了 #4。
→ 一個都沒有。程式裡沒有下單路徑。
在 commit 時把值抹掉,所以金鑰結構性地進不了 git。驗過: 本機 api_key 66 字、git 裡是空的。而且這個 repo 沒有遠端。
api_key|api_secret|telegram_token|telegram_chat_id, 而 設定.ini 有三組 帳號/密碼([儀表板]、[台股]、[美股]), 六個值都以明文進了 git —— 其中 [儀表板] 那組是朋友的帳密。 已把 帳號|密碼 加進 filter,驗過:要進 git 的版本六個全空、 工作區的值完好(線上照樣讀得到)。 但 git 歷史裡舊 commit 還有明文。 沒有遠端所以沒離開這台機器; 要清歷史是改寫歷史的操作,那個等使用者決定,我不自己做。
熔斷驗證.py:目前線上是「連敗5筆休息12小時」,它擋掉的 71 筆 如果讓它們開成是 勝率 35.2%、合計 +53.6R。 那支工具自己寫著「這個數字是正的就代表熔斷在幫倒忙」。
但它讀的是 回測結果_low.csv(2025-11-10~2026-09-04), 不是現在這一套(群組底圖+收盤判定+災難停損)。所以數字方向可以看、 不能直接拿來關熔斷。排進待驗。
→ 改成 20。鍵真的不見時才會用到,但用一個早就不存在的上限去判是錯的。
跟我 11-05 在 驗證_高原 兩支寫錯的是同一句。幣圈回測不設全域持倉上限 (回測.py:19),補進來的機制是「同一標的一次一筆」+出場後冷靜根數。 → 更正,並註明同一個錯出現在哪幾支。
是同一個模式出現了五次:
| # | 日期 | 哪裡 | 什麼 |
|---|---|---|---|
| 1 | 11-05 | healthcheck 單筆上限 | 寫死 −1R,收盤判定後上限是 1.5R |
| 2 | 11-05 | 驗證出場._出場參數 | 漏傳 4 個鍵,拿舊規則驗新規則 |
| 3 | 11-06 | 回測健檢 #5 | 「觸及停損⇒−1.00」是盤中低點的性質 |
| 4 | 11-06 | 回測健檢 #4 | 底艙部分出場沒欄位可認 |
| 5 | 11-06 | 熔斷驗證/驗證_高原×2 註解 | 持倉上限的機制說法 |
全部是「改了系統、但沒改驗證系統的東西」。 底圖對照.py 守住了設定層面的這一類(掃描釘的 vs 線上生效), 但驗證工具自己對規則的假設沒有東西在守。
那個該怎麼守還沒有答案 —— 寫下來,不要忘記。 一個可能的方向:回測輸出把當輪的關鍵規則(停損判定、災難停損R、 位階定義、部分出場機制)寫成欄位,驗證工具就能照檔案自己說的規則去驗, 而不是照寫程式那天的假設。
使用者:「要跟討論的一致 要不然沒有意義」。
這句話是對的,而且是整件事的重點:掃描量的如果不是線上在跑的那套, 那些數字就不是在講線上會發生什麼事 —— 不管它們多漂亮、多穩健、過幾個樣本外。
| 檔案 | 改動 |
|---|---|
| 設定.ini [參數] | 新增 位階定義 = 群組、只做位階 = 位階0,位階1,位階1.5,位階2 |
| 設定.ini [已決定] | 同步兩行,讓 healthcheck.檢查已決定() 從此守著它們 |
| shadow_bot.py | 規則版本 v11 → v12(改了進場語意,線上可比較樣本歸零) |
備份 設定.ini.bak_位階群組四全開_20261106。UTF-8 無 BOM、LF。 寫入用 os.replace 原子換檔 —— 線上掃盤是排程每小時跑, 直接 write 有毫秒級機會讓某一輪讀到半個檔案。這是在動一個正在跑的系統。
跟 shadow_bot.py:2245/2246 都讀得到,沒有分歧
線上原本完全不做位階0 跟位階1.5(54 筆全是位階1 ×44、位階2 ×10)。 從現在起兩個都做,而且位階的分類器本身換了一個。 回測裡位階1.5 是最大的一桶(196/383=51%,每筆 +1.706R), 所以筆數應該會明顯變多。
v12 的可比較樣本是 0 筆。 這是改進場語意的代價,不是 bug。
支持「群組比較好」的測量是 2026-09-21 的: 群組四全開 0.882/0.759 vs 現行對照 0.841/0.750,只做位階1+2 是 0.749/0.673。
那個測量在八個改動之前,而且是在舊的出場規則(盤中低點、沒有災難停損)下量的。 我建議的是先拿今天這一套設定把兩個底圖各跑一次同批比較再決定; 使用者選擇直接套用,理由是「要跟討論的一致」—— 這個理由本身成立, 因為不對齊的話後面每一次掃描都是白跑。
但要寫下來:「群組比現行好」這件事,在今天的設定下還沒有重驗過。 那是一個欠著的驗證,不是已經成立的結論。排在保本門檻R 外推之後。
46 天沒人發現,不是因為沒人細心,是因為沒有東西在守「一致」這件事。 專案本來已經有兩個同型的機制,而且都有效: [已決定] + healthcheck.檢查已決定() 守設定檔的值、 核對.py 守文件裡的表格。掃描的底圖沒人守,所以它可以安靜地歪一個半月。
現在有了(底圖對照.py,接在 healthcheck 裡每輪跑)。 而且它在被修好之前是紅的,那正是它該有的樣子 —— 一個欠著的決定應該一直發出聲音,直到有人決定。
<!-- 核對 多檔 檔欄=來源檔 -->
| 組 | 保本門檻R | 筆數 | 每筆R | 去最好3 | 10R+密度 | 時序回撤 | 最差單筆 | 穿破−1R | 來源檔 |
|---|---|---|---|---|---|---|---|---|---|
| 保本2.0 | 2.0 | 415 | +1.324 | +1.068 | 3.6% | 8.8 | −1.50 | 154 | 回測結果_重跑_保本2.0.csv |
| 保本2.5 | 2.5 | 404 | +1.353 | +1.091 | 3.7% | 11.4 | −1.50 | 171 | 回測結果_重跑_保本2.5.csv |
| 保本4.0(現況) | 4.0 | 383 | +1.548 | +1.273 | 4.4% | 14.3 | −1.50 | 195 | 回測結果_重跑_保本4.0.csv |
| 保本5.0 | 5.0 | 375 | +1.592 | +1.311 | 5.1% | 21.6 | −1.50 | 205 | 回測結果_重跑_保本5.0.csv |
| 保本6.0 | 6.0 | 367 | +1.698 | +1.412 | 6.0% | 20.4 | −1.50 | 214 | 回測結果_重跑_保本6.0.csv |
保本4.0 應該逐字重現 判定_收盤災1.5(因為共同覆蓋改成收盤/1.5 之後兩者生效設定一樣): 383 筆 +1.548 / 383 筆 +1.548 → 對得上。 11-05 那次換釘子是乾淨的。
去最好3 單調往上一路到邊界:1.068 → 1.091 → 1.273 → 1.311 → 1.412, 峰就在 6.0,也就是我自己設的格子邊緣。
照這個專案的規矩(參數高原 vs 尖點):峰在邊界=還沒找到轉折, 不知道 6.0 是高原的中段還是上升段的半路。拿它改參數就是在猜。 已加三格往外推:8.0 / 12.0 / 關掉(9999=永遠不保本),跑著。
不是只有 4.0 那一格剛好有效。
是真的讓單子跑完 —— 跟機制預期一致:門檻高 → 停損留在原始停損更久 → 不會在保本價被一根回踩切掉。
代價也看得見:回撤從 8.8 一路到 20.4,穿破 −1R 從 154 到 214。 所以這一題最後大概不是「哪一格每筆R 最高」,是「願意用多少回撤換多少每筆R」。 那個取捨使用者 2026-09-27 講過方向(「可以犧牲獲利換取更大的 R 數」), 但 8.8 → 20.4 是兩倍以上,不是微調,得等外推跑完看完整形狀再談。
使用者問:「那要怎麼解套 危險的問題這個部分/那這樣可以拿去幣圈用了嗎」。 查下去發現「危險的問題」比我上一段寫的嚴重得多。
| 位階定義 | 只做位階 | 實際筆數 | |
|---|---|---|---|
| 線上 | 現行(程式 fallback) | 位階1,位階2(fallback) | 54 筆:位階1 ×44、位階2 ×10 |
| 每一次掃描 | 群組(共同覆蓋釘死) | 位階0,位階1,位階1.5,位階2 | 383 筆:1.5 ×196、1 ×78、0 ×58、2 ×51 |
設定.ini [參數] 這兩個鍵都沒有(只有 位階2守住、位階2站上倍數)。 所以線上吃程式 fallback,掃描吃釘子,兩邊從來沒有對過。
而且 現行 跟 群組 是兩個不同的分類器 —— classify_position 在 mode == "群組" 時整支轉給 _位階_群組,而 現行 那條路根本不會回傳位階1.5 (shadow_bot.py:795)。所以不是「線上少做了 1.5 那一桶」, 是兩邊的位階標籤根本不是同一個意思,不能照標籤互相換算。
決策紀錄 2026-09-21 那段自己寫著: > 群組定義四個全開,兩個窗口都小勝現行對照(0.882 vs 0.841、0.759 vs 0.750)… > 只做位階1+位階2 會變差(0.749/0.673),因為丟掉了 1.5 的量。 > 尚未套用:是否把線上改成「群組定義+四個全開」還沒拍板。
那是 46 天前。之後套了八個改動(關加碼、乖離 3.5、關移停、關首段回檔、 芭樂部分停利、跳空照實、台股收盤判定、幣圈收盤判定+災難停損), 每一個都是在群組底圖上驗的,而線上一路跑現行。
結論講白:線上現在跑的這一套,從 2026-09-21 之後就沒有被回測過。
「釘子沒釘」會跟著設定檔漂,對帳當場就炸(11-03 踩過,當天就抓到)。 「釘在跟線上不同的值上」不會炸 —— 它安靜地量一套平行宇宙, 每一行數字看起來都很正常,判讀、高原、樣本外全部照跑。
這個專案已經有兩個「兩份真相要對帳」的機制,而且都有效: [已決定] + healthcheck.檢查已決定() 守設定檔, 核對.py 守文件裡的表格。掃描的底圖沒有任何東西在守。
新增 底圖對照.py。對每一個 共同覆蓋 的鍵拿三個值比:
1. 掃描釘的值(AST 讀 驗證_高原_重跑.共同覆蓋,不 import) 2. 設定.ini 寫的值 3. 線上程式的 fallback(regex 從 shadow_bot.py 原始碼讀出來,不是猜的)
線上實際生效 = 設定.ini 有就用它、沒有就用 fallback。 釘的值 ≠ 線上實際生效 → 異常,除非寫進 刻意不同 並附理由 (刻意不同 現在是空的 —— 空的才是健康,每一條都是一個欠著的決定)。
接進 healthcheck,每輪都查,明細多一行「掃描底圖=線上」。 現在它是紅的,而且應該保持紅的直到有人決定,這就是重點。
跑出來十一個鍵裡九個一致(停損判定、災難停損R、乖離、加碼、ATR 兩個… 全部對得上),只有位階那兩個不一致 —— 所以範圍很清楚,不是到處都歪。
線上影子模式 54 筆已結清(2026-10-18 ~ 11-06):
| 線上 54 筆 | 回測 383 筆(群組底圖) | |
|---|---|---|
| 勝率 | 13.0% | 39% |
| 每筆R | −0.478R | +1.548R |
| 總R | −25.8R | — |
| 觸及停損 | 85% | 44% |
| 到得了保本 | 13%(7/54) | 39%(150/383) |
線上最高R 的分布:只有 12 筆曾經超過 2.6R,最好的一筆 14.8R。 單子跑不起來,85% 直接吃停損。
這個差距不是調參數能補的,而且目前還不能歸因,因為上面那件事: 回測的 383 筆跟線上的 54 筆用的是不同的分類器,兩邊不可比。 在底圖對齊之前,「回測說 +1.5R、線上做出 −0.48R」這句話本身沒有意義。
所以順序是: 1. 先把底圖對齊(決定位階那一題,見下) 2. 再用對齊後的設定跑一次線上那一段期間(2026-10-18~11-06), 才分得出「行情差」還是「線上跟回測不等價」 3. 兩者都清楚了,再談參數 4. 真錢在這些之後,而且紅線 1 不變:這套系統不下任何真實訂單
現在正在跑的 保本門檻R 五組是在群組底圖上跑的。 如果位階那一題選「把線上改成群組」,這一輪就是對的; 選「把掃描改回現行」,這一輪要重跑。等使用者決定,沒有白跑的風險比較大的那一邊。
11-05 把線上與回測改成 停損判定 = 收盤 + 災難停損R = 1.5 之後, 驗證_高原_重跑.py 的 共同覆蓋 還釘著 盤中低點 / 災難停損R 0。
這比沒釘更危險。沒釘會跟著 設定.ini 漂(11-03 踩過,當場看得出來, 因為對帳會炸);釘在過期的值上不會炸,它會安靜地量一套已經不存在的系統, 而且每一行數字看起來都很正常。
改成現況值(收盤 / 1.5)。連帶三件事:
而掃描40 是在 盤中低點 / 0 / 乖離7 之下跑的。共同覆蓋 一改它就會對不上, 而那個「對不上」會被讀成「工具壞了」—— 11-03 就誤判過一次。 標籤維持 校準_乖離7:生效設定跟改制前完全一樣(以前共同覆蓋就是盤中低點/0、 組只改乖離;現在組把三個都寫明),所以既有 CSV 直接重用。 已驗:547 筆 +1.335 / 去3 +1.142,對得上。
退場的 判定_盤中低點 標成「← 現況」,判讀那段也在拿峰去跟不存在的系統比。
那一輪跑的是哪一套;11-03 那次混亂的根源就是這個。
保本門檻R = 4.0 從初始存檔點(3b1f2a3)到現在一次都沒動過, 而它是在 盤中低點 判定之下定的。收盤判定會讓保本停損也變成 「收盤跌破進場價才認」,所以這一題非重測不可。
掃描30(收盤、沒有災難停損)當時最刺眼的那一行就是保本: 「觸及保本停損」平均 −3.50R —— 保本機制直接失效。 現在這個破口補上了。去程式裡確認過(不是推論): _災難價 = cur_stop - (災難停損R - 1.0) × risk_u(shadow_bot.py:1513), 而 be_stop = entry + 保本緩衝R × risk_u(shadow_bot.py:1463,緩衝 0.1)。所以
| 狀態 | cur_stop | 災難單掛在 | 單筆上限 |
|---|---|---|---|
| 還沒保本 | 進場 − 1.0×風險 | 進場 − 1.5×風險 | 1.5R |
| 已保本 | 進場 + 0.1×風險 | 進場 − 0.4×風險 | 0.4R |
災難價跟著 cur_stop 走,所以保本一推上去、上限也跟著收緊 —— 一筆走到保本又反轉的單最多賠 0.4R,不是掃描30 時代的 −3.50R。 破口補好了,但門檻擺哪裡沒有重測過。
(附帶效果:保本後反轉破了 0.4R 的單,出場原因會記成「災難停損」而不是 「觸及保本停損」—— 讀報表時要知道,觸及保本停損 那一桶現在只剩 溫和的保本出場。不是 bug,是 _災難觸 先判。)
兩個方向都有道理,所以只能量:
| 門檻 | 好處 | 代價 |
|---|---|---|
| 低(2.0) | 早點保本,少賠 | 收盤模式下更容易被一根回踩掃掉,吃掉後面的大單 |
| 高(6.0) | 讓單子跑完 | 從 +3R 翻回 −0.5R 的次數變多 |
掃五格:2.0 / 2.5(台美股在用的值)/ 4.0(現況) / 5.0 / 6.0。
現況那一組同時是這一輪的對帳組:保本4.0 應該逐字重現 回測結果_重跑_判定_收盤災1.5.csv(383 筆 +1.548), 因為釘子改成 收盤/1.5 之後兩者的生效設定完全一樣。 對不上就是改釘子改壞了,底下的結論全部不能信 —— 這一輪的對帳同時在驗 「換釘子」這件事本身。
樣本內五組約兩小時(獨立行程,PID 2104,落 保本門檻R.log)。 出來之後要過樣本外才算數;但如果樣本內就是一片平的高原、峰在 4.0, 就不用跑樣本外了 —— 那代表這個旋鈕沒東西。
使用者:「繼續維持 然後看有沒有任何可以改進的地方」、 「還有討論區修改後的問題可以刪除避免版面混亂」。
GRVTUSDT 2026-11-03 07:02 進場、2026-11-05 21:02 出場,−1.18R。 設定是 19:25 改的,所以這筆是新規則的第一筆。查完確認正常: 停損 0.21218,收盤 0.2098 跌破它 → 照收盤判定成交在收盤價, 不是停損價,所以賠 1.18R;封在 1.5R 以內,災難停損沒被觸發 (所以出場原因是「觸及停損」不是「災難停損」)。停損沒有失效。
但這一筆讓健檢同時報兩個異常,而那兩個報法都已經過期了。順著查下去 一共七個洞,全部修掉:
| # | 哪裡 | 是什麼 |
|---|---|---|
| 1 | healthcheck.py | 「單筆不得超過 −1R」寫死 1.0,新規則下應該是 1.5 |
| 2 | 驗證出場.py | _出場參數 沒傳 4 個鍵給 trail_update,靜默吃預設值 |
| 3 | 線上對照.py | 只掃 4 個呼叫點,看不到 驗證出場.py 這第 5 個 |
| 4 | shadow_bot.py | 規則版本 沒升 —— 改了出場語意就該升 |
| 5 | 戰情板.py | _md行內 的取代字串是真的 0x01 控制字元,不是 \1 |
| 6 | 戰情板.py | 決策紀錄的標題印兩次 |
| 7 | 核對.py | 讀CSV 沒排除未平倉的列 |
-1R 的地板換成 1.5R 的天花板,但不能直接把 1.0 改成 1.5 —— 改設定之前出場的單當下確實受 −1R 管,拿新上限回頭看等於放過真正的異常。 所以做成分段表 單筆上限分段 = {"crypto": [("2026-11-05 19:25", 1.5)]}。
而且刻意不去讀 設定.ini。 旁邊 單筆容忍R 的註解寫得很清楚: 「放進設定檔就會有人(包括我)在它報警時去調大它,那等於把警報關掉」。 同一個理由適用:要改 災難停損R 就得同時改 healthcheck.py 這一行, 那個摩擦是刻意的。
_出場參數 漏了 停損判定、災難停損R、跳空照實、芭樂價出場比例 四個鍵,所以 trail_update 吃預設值(盤中低點 / 0 / False / 整筆平掉)。 健檢報的「出場跟規則重跑不符(紀錄 −1.18R/重跑 −1.00R)」就是這樣來的 —— 重跑是對的,是重跑用的規則錯了。
這支的 docstring 第一句自己寫著「出場參數一律從設定檔讀, 不要再讓它吃 trail_update 的預設值」,2026-09-19 就為同一件事修過一次。 意圖寫對了,後來加的鍵沒跟上。
補完之後 GRVT 那筆對上了。
線上對照.py 存在的理由就是抓「trail_update 少傳一個參數」這種分歧, 但它只掃 回測檔 + 線上檔 四個檔。驗證出場.py 是第五個呼叫點,不在裡面。
加進去之後又暴露掃描器本身兩個毛病,一起修:
(驗證出場.py 第 3 行那句說明)。→ 用三引號奇偶數跳過字串內的。
B.trail_update(..., ma_n=30, 參數),所有參數都在那個 dict 裡, 但掃描器只找 名=,於是整欄印成「否」—— 那是假的**漏傳,比不列更糟。 → 標成「展開」,並在表下面寫明「要去組那個 dict 的函式裡查」。
使用者的規則:「改變進出場語意才歸零,判準是同一段 K 線會不會跑出 不同的進場、出場或加碼行為」。停損判定改收盤就是在改出場語意 —— 同一根 K 棒,影線戳破停損從「出場」變成「不出場」。所以必須升版。
v10 … → v11 幣圈收盤判定+災難停損1.5R(取代v10的-1R地板;…)。 線上的可比較樣本歸零,這是改這種東西的代價,不是 bug。
順帶:驗證出場.py 本來沒有按規則版本分流(healthcheck 有), 所以升版後它把 26 筆舊單全列成「需要看一下」。照 healthcheck 同一套做法 分成兩區:「現行規則版本的單」跟「舊規則版本、對不上是正常的」。 警報長成狼來了就等於沒有警報。
_md行內 的兩個 re.sub 取代字串裡是真的 0x01 控制字元,不是反向 參照 \1(應該是哪一次用 non-raw 字串寫檔時 "\1" 就被解釋成 chr(1) 了)。 結果是:**全部 86 條決策紀錄裡每一個 程式碼 跟 \*\*粗體\*\* 的內容 在板上都被吃掉**。我那段新寫的「改了哪四個地方」表格整片空白就是這個。
決策紀錄的標題用 日期|題目 切。我後來寫的 9 條標題用的是全形空白不是 |, partition 回傳 (全句, '', ''),於是標題跟右上角標籤印出同一句。 兩邊都修:9 條標題補上 |(86 條現在格式一致), renderer 也改成沒有 | 時不要重複印。
讀CSV 沒有濾掉 未平倉 = 是。那些列的 R數 是浮動的、不是已實現的 (回測結果_重跑_* 每份都有 2 筆)。三支驗證工具都有濾,只有這支沒有。
先在複本上試再動:排除之後原本那 13 張表全部還是過, 所以這個修法不會改到任何既有結論。
順便把停損判定的樣本內表加上 <!-- 核對 多檔 檔欄=來源檔 -->, 現在每次 python 核對.py 都會從 CSV 重算它的筆數與每筆R。14 張表、0 個問題。
回撤那一欄故意改名叫「時序回撤」:核對.py 的回撤是照 CSV 列序累加, 而 CSV 照標的分組寫,跟 驗證_高原.統計() 的「照出場時間排」本來就不一樣。 改名讓核對跳過那一欄,同時把這個差別寫在表頭上,不要兩種定義混在同一個數字。
11-03 我寫「挑子集 ≠ 重跑」的原因是「濾掉的單會空出 最多同時持倉 的位子 跟 最短間隔分鐘 的檔」。兩個都錯:
最多同時持倉 —— 那個鍵只有線上在讀。
(55 分鐘打一次朋友的站)。
真正的機制是同一個標的一次只能有一筆(回測.py:925 持倉中不評估進場) + 出場後冷靜根數 = 3 的冷靜期。濾掉一筆,那個標的那段時間就沒被占住、 冷靜期也沒啟動,原本被擋掉的下一筆就補進來。
結論不受影響(替補的 123 筆是量到的,不是推論的), 但解釋錯了就會讓下一次判斷走錯方向。已改:驗證_高原.py(3 處)、 驗證_高原_重跑.py、本檔 11-03 那一段。
使用者:「討論區修改後的問題可以刪除避免版面混亂」。
先查出為什麼會亂:看報表.parse_todo 只抓每個 - 項目的第一行, 第二行以後丟掉。而「已經決定」那 20 條全是三到八行的長段落, 所以板上看到的是 20 個半句話配冒號。而且那一區用 E() 不渲染 Markdown, 粗體 在板上就是四個星號。
三件事一起做:
1. 渲染共用:_md行內 搬到 看報表.md行內,戰情板.py 改成委派。 parse_todo 的 docstring 本來就寫「兩邊共用這一份解析」, 但渲染沒共用,結果同一個 在一邊是粗體、在另一邊是四個星號。 順便加 刪除線(標「這條已經不成立」用的)。 2. 刪六條:朋友儀表板 A/B 不採用、四條已處理的舊問題、停損模式就是 low、 T2 標的沒有資料可比、出場原因「加碼後調高停損」已獨立出來、位階倉位倍數不採用。 判準:還在管事情的留(紅線、現行設定、計數規則), 「某個 bug 修好了」「某個誤記更正了」一律刪。 3. 改四條已經跟現況不符的**(這四條不能刪,刪掉就只剩錯的印象): - 「加碼保留」→ 2026-10-19 三個市場全部關掉加碼 - 「乖離警戒 7」→ 幣圈現在 3.5,而且理由只剩「每筆R +5%」 - 「停損拉太高容易被掃出去…這個旋鈕不是解法」→ 11-05 找到解法了 - 「被洗出場 36% 躲不掉」→ 前半句還對,後半句被推翻(45% 掃完回到 +2R)
另外刪掉一個死掉的待議項目:「首段回檔濾網 50% 是否合適」—— 那個濾網 2026-10-03 就關掉了,同一份檔案的「已決定」區還寫著「已關掉」, 兩區自己打對臺。還有一個四欄全空的空殼項目(## 台股/美股 那個分隔標題 被當成一個待議項目),改成 ###。
待議從 6 項(含 1 死 1 空殼)變 4 項,已決定從 20 條半句話變 14 條完整單行。
六個台美股側舊洞(不再有 驗證出場 的假漏傳)
26 筆舊版本單另外歸一區
修完 線上對照.py 之後它又吐出一個被藏起來的分歧: 鍵對應 裡 bonanza_frac 寫成「芭樂出場比例」,少一個「價」, 查不到就印「(無)」,於是真正的分歧被蓋掉了。改成 芭樂價出場比例 之後:
吃到 1.0 —— 台美股的芭樂價是整筆平掉**,不是賣 20%。
台美股根本沒有芭樂價機制。
兩個都是舊洞(跟這次改動無關),而且 2026-09-27 使用者拍板「台美股先擱置」, 所以沒有動:補上去等於改台美股的出場行為,那要先有數據跟點頭。 記在這裡是為了下次做台美股時第一件事就看到它。
台美股側 trail_update 的漏傳現在共 6 個: bonanza_R / bonanza_frac / bonanza_done / 部分出場盒(四個都是芭樂價那組)、 ma_exit_mode / slope_bars(這兩個連 shadow_bot 也沒傳,但設定檔也沒有那兩個鍵, 所以三邊一致吃預設值,不是分歧)。
CSV 是照標的分組寫的,所以兩者本來就不一樣(停損判定那張表 時序回撤 13.6,列序算是 11.5)。時序才是對的 —— 回撤是時間序列的概念。 但 核對.py 現在驗著的 13 張舊表都是照列序寫進去的,統一過去會讓它們全部報錯, 那要一張一張重算確認,不是改一行的事。這一輪只把差別寫清楚、欄位改名區分, 沒有統一。
使用者:「一單最多輸1.5R可以接受」。
這是改系統怎麼吃虧損,不是加濾網,所以上一輪我停在「等點頭」。點頭了,套上去。
| 檔案 | 改動 |
|---|---|
| 設定.ini [參數] | 停損判定 = 盤中低點 → 收盤;新增 災難停損R = 1.5 |
| 設定.ini [已決定] | 參數.停損判定 改 收盤;新增 參數.災難停損R = 1.5 |
| 設定.ini [已決定] | 刪掉 禁用.參數.災難停損R = 是,連理由一起換掉 |
| 策略板.py | 「結果還沒出來」換成 ATR 結論 + 新的「一之四」整段 |
備份:設定.ini.bak_幣圈收盤災1.5_20261105。UTF-8 無 BOM、LF,改完驗過。
禁用.參數.災難停損R = 是 的理由是 2026-10-19 寫的: 「真正的虧損來自跨日跳空,掛單封不住跳空,反而把『跳空下去又拉回來』 變成『在跳空最低點被掃掉』」。
兩件事讓它套不到幣圈:
1. 證據是台股的。 掃描28/29 兩支都是 import 股票回測、S.run("tw", ...), 幣圈從頭到尾沒跑過。幣圈是被連坐的。 2. 那個理由在幣圈不成立。 掃描30 的 跳空照實 vs 跳空美化 兩組數字 完全一樣(每筆 1.511/1.511、穿破−1R 3/3)。永續合約連續交易, 30 分 K 幾乎不會開盤就跳過停損 —— 沒有跳空可封。
台股那一條留著。 台股的跳空是真的,而且證據就是在台股身上取得的。 這一條是「跨市場不等價」的又一個實例:幣圈驗過的不能搬台股,台股否決的 也不能連坐幣圈。
trail_update 是回測(回測.py:711)跟線上(shadow_bot.py:2524) 同一支函式,兩個鍵都是它的參數,各自從自己的 cp 讀 (shadow_bot.py:2210/2214、回測.py:337/341)。
線上對照.py 跑過:[參數] 共 63 個鍵(多了 災難停損R 那一個), 「只有回測讀」0 個、「沒人讀」0 個。trail_update 四個呼叫點的少傳清單 沒有新增,還是原本那六個(bonanza 三個、ma_exit_mode、slope_bars、部分出場盒, 全是台美股側的舊洞)。
不是 [台股] 停損判定 = 收盤 那種「設定對了、股票模式.py 整支 grep 不到」的狀況。
healthcheck.檢查已決定() → 全部對上。(新增的 參數.災難停損R = 1.5 跟 [參數] 的值一致;禁用.台股.災難停損R 仍然成立,因為 [台股] 沒有那個鍵。)
新增 停損判定診斷.py:讀那 10 份 回測結果_重跑_判定_*.csv, 指標借 驗證_高原.統計(),寫出 停損判定診斷.json 給策略板讀。
為什麼要這一步:11-03 那個「挑子集 ≠ 重跑」的錯,起因就是我拿手算的上限 當成實測值。板上手寫數字=同一件事會有兩組版本。現在板上的每一格都是從 CSV 算的,跟掃描 log 對不上就是那支壞了。
順手抓到自己兩個講錯的地方(都已修):
錯。正確是:在四個收盤組裡兩份都最低(14.3/26.1),但對現況是 樣本內略差 13.6 → 14.3、樣本外比較好 27.4 → 26.1。 樣本內最低的那一格還是現況。
−1.00R 的地板沒有了。線上出現第一筆 R數 < −1 的單是預期行為,不是 bug, 但要去確認它封在 −1.5R、而且出場原因是「災難停損」。 回測說樣本內 51%、樣本外 54% 的單會落在這一區。 如果線上穿破的比例明顯高過這個,或有單賠超過 1.5R,那就是 災難停損R 在線上沒生效 —— 先看 shadow_bot.py:1513-1534 那段有沒有被走到。
python 驗證_高原_重跑.py 校準(乖離退回 7、其他照 掃描40):
既有 547 筆 +1.335 / 重跑 547 筆 +1.335 → 對得上 ✓
去最好3 也是 +1.142 對 +1.142。逐字重現 掃描40,所以底下的數字可以信。
<!-- 核對 多檔 檔欄=來源檔 -->
| 組 | 判定/災難R | 筆數 | 每筆R | 去最好3 | 去最好10 | 10R+密度 | 時序回撤 | 最差單筆 | 穿破−1R | 來源檔 |
|---|---|---|---|---|---|---|---|---|---|---|
| 盤中低點(現況) | 盤中低點/0 | 403 | +1.406 | +1.144 | +0.820 | 4.0% | 13.6 | −1.00 | 0 | 回測結果_重跑_判定_盤中低點.csv |
| 收盤 無上限 | 收盤/0 | 381 | +1.574 | +1.297 | +0.958 | 4.5% | 17.4 | −3.61 | 196 | 回測結果_重跑_判定_收盤無上限.csv |
| 收盤+災難1.5 | 收盤/1.5 | 383 | +1.548 | +1.273 | +0.934 | 4.4% | 14.3 | −1.50 | 195 | 回測結果_重跑_判定_收盤災1.5.csv |
| 收盤+災難2.0 | 收盤/2.0 | 383 | +1.547 | +1.271 | +0.933 | 4.4% | 16.8 | −2.00 | 194 | 回測結果_重跑_判定_收盤災2.0.csv |
| 收盤+災難2.5 | 收盤/2.5 | 383 | +1.551 | +1.275 | +0.937 | 4.4% | 16.1 | −2.50 | 197 | 回測結果_重跑_判定_收盤災2.5.csv |
(「時序回撤」故意不叫「回撤」:核對.py 的回撤是照 CSV 列序算的, 而 CSV 照標的分組寫,跟這裡「照出場時間排」的定義不同。改名讓核對跳過那一欄, 其餘的 筆數/每筆R 會被每次 python 核對.py 重算比對。)
災難停損R 封得住。 最差單筆從 −3.61 變成剛好 −1.50/−2.00/−2.50,上限精準咬住。 台股那個「掛單封不住跳空」的否決理由在幣圈確實不成立 —— 已實測,不是推論。
| 組 | 樣本內 去3 | 樣本外 去3 | 內→外保留 | 10R+密度 內/外 | 回撤 內/外 |
|---|---|---|---|---|---|
| 盤中低點(現況) | +1.144 | +0.661 | 0.58 | 4.0% / 2.0% | 13.6 / 27.4 |
| 收盤 無上限 | +1.297 | +0.848 | 0.65 | 4.5% / 2.3% | 17.4 / 26.6 |
| 收盤+災難1.5 | +1.273 | +0.782 | 0.61 | 4.4% / 2.3% | 14.3 / 26.1 |
| 收盤+災難2.0 | +1.271 | +0.815 | 0.64 | 4.4% / 2.3% | 16.8 / 26.6 |
| 收盤+災難2.5 | +1.275 | +0.821 | 0.64 | 4.4% / 2.3% | 16.1 / 26.6 |
四組收盤變體在兩份樣本都贏現況,而且樣本外的增益(+0.121~+0.187)比樣本內 (+0.127~+0.153)還大。10R+ 密度兩份都升(沒砍尾巴)、回撤樣本外還比現況低。 1.5/2.0/2.5 三格在兩份裡都是一片平的 —— 是高原不是尖點。 跟 2026-10-24 六H張開% 在樣本外翻掉的情況完全相反。
| 虧損側每筆 | 獲利側每筆 | 勝率 | |
|---|---|---|---|
| 現況 | −1.000 | +5.509 | 37.0% |
| 收盤+災難1.5 | −1.183 | +5.838 | 38.9% |
每一筆輸單多賠 0.18R,買到贏單大 6% + 勝率多 1.9 個百分點。
> 2026-11-05 修正這三個數字。 原本寫 −1.188 / +5.799 / 39.2%,那是我 > 用 R數 >= 0 切兩側算的。專案自己的 驗證_高原.統計() 是用 R數 > 0, > 差的那一筆剛好是 0.00R。兩種算法都不算錯,但板上、設定檔跟這裡一律跟 > 統計() 走,否則同一件事會有兩組數字。做成 停損判定診斷.py → > 停損判定診斷.json 之後,板上的數字就是從 CSV 算出來的,不再手寫。 去最好10 從 +0.820 升到 +0.934(+14%) —— 不是三筆也不是十筆運氣,是整片往上。
白話:影線戳破停損不算,要收盤收在停損下面才認輸。多撐一根K棒的代價是 輸的時候多賠一點,好處是插針掃不掉你。
工具印的「硬停損率 63%→44%」有一半是改名字造成的:收盤模式下 66 筆的 出場原因變成「災難停損(結構線下0.5R)」而不是「觸及停損」。 真實的停損類出場合計 61% vs 現況 63%,幾乎沒動;掃完又回 +2R 的比例 48%→43%。
所以這個改動不是讓你少被掃。它是讓被掃的那些單多跑一根K棒,少數撐過去的 接上移動停損走完。這跟 ATR 那一輪有本質差別 —— ATR 連停損率都動不了。
trail_update 是回測跟線上共用的出場引擎(回測.py:703、shadow_bot.py:2518), 停損判定 跟 災難停損R 都是它的參數,兩邊各自從 cp 讀。 (對比 10-17 的教訓:[台股] 停損判定 = 收盤 套了兩天,股票模式.py 整支 grep 不到「停損判定」四個字 —— 台股線上有這個洞,幣圈沒有。)
建議 [參數] 停損判定 = 收盤 + 災難停損R = 1.5。 挑 1.5 不是因為平均值最高(2.0/2.5 樣本外高 4%),是因為尾巴最短: 最差單筆 −1.50,回撤兩份樣本都最低(14.3/26.1)。同樣報酬買最短的尾巴, 符合使用者 09-27 講的「可以犧牲獲利換取更大的 R 數」。
但要先讓他知道代價:−1.00R 的地板沒有了。 現況每筆輸單剛好 −1.000R、穿破 0 筆; 改完一半以上的輸單會賠超過 1R(上限封在 1.5R)。這是改系統吃虧損的方式, 不是調一個濾網 —— 設定.ini 一個字都沒動,等他點頭。
另外 災難停損R 目前在 設定.ini 的「已決定不要做」清單裡 (禁用.參數.災難停損R = 是)。要套用的話那一行也要改,並把上面的 「台股證據不能套幣圈」寫進去,否則下一輪又會被那行擋掉。
使用者:「改門檻整批重跑 這個有結論了嗎 大時區可以的前提下 到底是要改哪個出來這個能做的出來嗎」
五組跑完(365 天/池 100/END 1791454961881/乖離 3.5):
| 組 | 觸發→放寬 | 筆數 | 每筆R | 去最好3 | 10R+密度 | 回撤 | 硬停損率 |
|---|---|---|---|---|---|---|---|
| 關掉 | 0→0 | 419 | +1.404 | +1.193 | 4.3% | 15.1 | 64% |
| ATR0808 | 0.8→1.5 | 411 | +1.401 | +1.186 | 4.4% | 13.6 | 63% |
| ATR1220(現況) | 1.2→2.0 | 403 | +1.406 | +1.144 | 4.0% | 13.6 | 63% |
| ATR1520 | 1.5→2.0 | 398 | +1.358 | +1.092 | 3.8% | 12.6 | 63% |
| ATR2025 | 2.0→2.5 | 366 | +1.287 | +1.045 | 3.6% | 15.7 | 64% |
去最好3 單調下降:越墊越差。峰在「關掉」,但只比現況好 +0.050(4%), 而且買來的是更大的回撤(15.1 vs 13.6)。五格全部落在 10% 以內 —— 這是一片很平、略微下傾的高原,不是有峰的旋鈕。
決定性的那一欄是硬停損率:五格全都是 63~64%,完全沒動。 墊高停損不會讓你少被掃,只會把每一筆贏單的 R 除掉 —— 這正好是 10-30 那個「R 是用停損寬度計價的」推論所預測的。 ATR 下限不是「被掃出去」的解方。這一題結案,現況不動。
重跑的基準列對不上 掃描40(403 筆 vs 547 筆),一開始看起來像程式歪了。 查下來是兩件事,都是我的問題:
(1) 沒釘的參數會跟著 設定.ini 漂。 驗證_高原_重跑.py 的 共同覆蓋 沒釘乖離,所以它吃的是當下的 設定.ini(10-30 已改成 3.5), 而 掃描40 是乖離 7 跑的。已把每一個會影響結果的鍵都釘進 共同覆蓋 (乖離、災難停損R、ATR 兩個鍵),並加一個「校準」題目專門重現 掃描40 對帳。
(2) 比對之下,比出一件更重要的事:
| 筆數 | 每筆R | 去最好3 | 總R | |
|---|---|---|---|---|
| 乖離 7 全跑(掃描40) | 547 | +1.335 | +1.142 | +730.4 |
| ↳ 子集 乖離≤3.5 | 291 | +1.648 | +1.286 | +479.7 |
| 乖離 3.5 實際全跑 | 403 | +1.406 | +1.144 | +566.8 |
| ↳ 子集裡本來就有的 | 280 | +1.716 | +1.340 | +480.5 |
| ↳ 空出位子補進來的 | 123 | +0.702 | +0.402 | +86.3 |
10-30 我用「從既有 CSV 挑子集」推薦乖離 3.5,說去最好3 從 +1.142 升到 +1.286。 實際重跑是 +1.144 —— 跟沒改一樣。
機制很具體:同一個標的一次只能有一筆(回測.py:925 持倉中不評估進場), 出場後還有 出場後冷靜根數(預設 3 根)的冷靜期。濾掉 256 筆高乖離單, 那些標的那段時間就沒被占住、冷靜期也沒啟動,原本被擋掉的下一筆就補進來, 而那批比較差(123 筆 +0.702),把分數整個拉回原點。
> 2026-11-05 更正這段的機制。 原本寫「空出 最多同時持倉 的位子跟 > 最短間隔分鐘 的檔」—— 兩個都錯:回測.py:19 明文「同一時間允許的持倉數 > 不設限」,整支 grep 不到 最多同時持倉(那個鍵只有線上在讀); > 最短間隔分鐘 根本不是交易間隔,是 [儀表板] 那段的連線節流(55 分鐘 > 打一次朋友的站)。觀察跟表格的數字都沒錯,錯的是我給的原因 —— > 而「上限不是實測」這個結論不受影響,因為替補單是量到的,不是推論的。
影響範圍:驗證_高原.py 的每一個結論都是上限,不是實測值。 包含還沒套用的 風報比門檻 2.5→4.94。已經把這段警告寫進那支的檔頭跟判讀輸出, 並讓它在筆數掉超過 30% 時直接標「非跑重跑不可」。
乖離 3.5 要不要退回 7? 數字擺出來:每筆R +1.335→+1.406(+5%)、 去最好3 +1.142→+1.144(沒變)、總R +730→+567(−22%)。 使用者 09-27 講過「可以犧牲獲利換取更大的 R 數」,3.5 做的正好是這件事 (每筆升、總R 降),所以沒有退回,留 3.5。但要誠實記著: 當初那個「去最好3 大勝」的理由是假的,現在它的依據只剩「每筆R +5%」。 要退回隨時可以,改一個數字。
「大時區沒變就被插針掃掉、行情回來」這件事,會動它的旋鈕不是停損擺多寬, 是停損怎麼判:
幣圈測過一半了(掃描30,10-19,乖離 7):
| 停損判定 | 筆 | 每筆R | 去3 | 10R+密度 | 回撤 | 最差單筆 | 穿破 −1R |
|---|---|---|---|---|---|---|---|
| 收盤 | 558 | +1.770 | +1.432 | 6.1% | 33.4 | −7.53R | 245 筆 (44%) |
| 盤中低點 跳空照實(現況) | 600 | +1.520 | +1.205 | 5.0% | 17.2 | −2.46 | 8 筆 (1.3%) |
去最好3 高 19%、尾巴還更粗。但回撤翻倍、44% 的單穿破 −1R、單筆最大虧 −7.5R。 當初沒採用是對的。
#### 沒試過的那一格:收盤 + 災難停損R
災難停損R > 0 時,在結構線下方 (災難停損R−1)×風險 處掛一張真硬停損 (shadow_bot.py:1513),把收盤模式的單筆虧損上限封回 災難停損R。 也就是「影線不出場、但真的崩了就認」—— 正好補收盤模式唯一的破口。
設定.ini 把 災難停損R 列在「已決定不要做」: 「雙層停損否決:真正的虧損來自跨日跳空,掛單封不住跳空, 反而把『跳空下去又拉回來』變成『在跳空最低點被掃掉』」
但那是台股的證據。 掃描28/29 都是 import 股票回測、只跑 tw。 幣圈從來沒測過這個組合(掃描30 三組的 災難停損R 都是 0)。
而且那個否決理由在幣圈不成立,證據就在掃描30 自己身上:
| 掃描30 | 每筆R | 去3 | 穿破 |
|---|---|---|---|
| 盤中低點 跳空照實 | +1.520 | +1.205 | 8 |
| 盤中低點 跳空美化 | +1.520 | +1.206 | 8 |
「跳空照實」這個修正整件事就是在處理跳空,它在幣圈改不動任何數字, 就是在說幣圈 24 小時連續交易沒有跨日跳空問題。台股那邊它是全部的故事。 跨市場不等價 —— 這正是不能照搬的那種情況。
#### 正在跑
python 驗證_高原_重跑.py 停損判定,四組(基準沿用 ATR1220,設定完全相同):
| 組 | 停損判定 | 災難停損R |
|---|---|---|
| 判定_盤中低點(現況) | 盤中低點 | 0 |
| 判定_收盤無上限 | 收盤 | 0 |
| 判定_收盤災1.5 | 收盤 | 1.5 |
| 判定_收盤災2.0 | 收盤 | 2.0 |
| 判定_收盤災2.5 | 收盤 | 2.5 |
判讀規則先寫下來: 去最好3 是主指標,但最差單筆跟穿破 −1R 筆數是否決條款。 災難停損R 要是封不住(穿破還是一大堆),這一題就結案。 封住了也還要再過樣本外才算數。
使用者:「這個解法很對 停損擺哪裡(結構位 vs ATR)跟進場時機 往這個方向去處理解套」
幣圈的 ATR 停損下限寫死在兩個地方:
`` if at20 and (entry - stop) < 1.2 * at20: stop = entry - 2 * at20 ``
回測.py 一份、shadow_bot.py 一份。台股/美股早就有 停損距離下限ATR倍數 = 1.5 這個鍵(市場診斷.py 的檔頭早就記過這個差異),幣圈沒有。 要掃這個旋鈕得先讓它可以被設定,所以拉成兩個鍵:
預設值就是原本寫死的那兩個數字,連 停損來源 字串都一樣("%g" % 2.0 = "2"), 所以不設 = 行為不變。兩個都設 0 = 關掉這道保護、純用結構位。 兩邊讀同一組鍵,線上對照.py 不會再出現新的分歧。
驗證_高原.py 只掃「進場當下就決定」的欄位(改門檻只是挑子集,秒級)。 引擎參數會改變每一筆的走勢,一定要重跑 —— 它的輸出一直在提這支檔名,今天才真的寫出來。
第一輪掃 ATR 停損下限五格:關掉/0.8→1.5/1.2→2.0(現況)/1.5→2.0/2.0→2.5。 每組落 回測結果_重跑_<標籤>.csv,重跑時直接讀既有檔不重算(一組 20 分鐘,中斷不要從頭來)。 判讀跟 驗證_高原.py 同一套:看去最好3 不看生每筆R、看鄰居、看 10R+ 密度有沒有被砍、看回撤。 基準那一列一定要跟 掃描40 對得上,對不上就是這支本身有問題,先別信結論。
五組還在跑(2026-10-30 當下)。
驗證_掃出去.py 加了第五段,落 掃出去診斷.json,策略板讀那個檔。
#### ✓ 兩份樣本唯一同向的線索:停損貼得越近越容易被撿走
| 樣本 | 停損距離 | 筆數 | 被掃掉 | 掃完回 +2R | 比例 |
|---|---|---|---|---|---|
| 樣本內 | ≤1.5% | 107 | 70 | 46 | 66% |
| 樣本內 | 其餘 | 440 | 273 | 109 | 40% |
| 樣本外 | ≤1.5% | 64 | 41 | 30 | 73% |
| 樣本外 | 其餘 | 468 | 330 | 149 | 45% |
兩份都同向、差距都很大。這就是他看到的那件事的機制: 停損貼太近 → 被插針撿走 → 行情沒有你繼續走。
#### ✗ 但「停損距離」不能當濾網 —— 過不了第二份樣本
| 停損距離 | 樣本內 每筆R | 樣本內 去最好3 | 樣本外 每筆R | 樣本外 去最好3 |
|---|---|---|---|---|
| ≤1.5% | +1.300 | +0.666 | +1.072 | +0.575 |
| 1.5~2.5% | +1.234 | +0.788 | +0.844 | +0.595 ←樣本外最好 |
| 2.5~3.5% | +2.185 | +1.447 ←樣本內最好 | +0.587 | +0.348 |
| 3.5~5% | +0.975 | +0.714 | +0.313 | +0.135 |
| >5% | +0.703 | +0.254 | +0.694 | +0.253 |
樣本內最好的桶是 2.5~3.5%,樣本外最好的是 1.5~2.5% —— 不一致。 跟 10-24 六H張開% 一模一樣的下場。當成門檻用也一樣:下限拉高,樣本外單調變差 (0.659 → 0.655 → 0.602 → 0.478)。沒有做成濾網。
方向上也不該做成濾網:緊停損那批單的問題是停損擺錯地方,不是那些單不該做。 濾掉它們=連單一起丟掉;該做的是把停損墊高——那正是上面那支在掃的事。
#### 現有那道墊高,兩份樣本的去最好3 都比純結構差
| 樣本 | 停損來源 | 筆數 | 每筆R | 去最好3 |
|---|---|---|---|---|
| 樣本內 | 純結構 | 458 | +1.256 | +1.076 |
| 樣本內 | 墊到 2xATR | 89 | +1.742 | +0.892 |
| 樣本外 | 純結構 | 446 | +0.721 | +0.630 |
| 樣本外 | 墊到 2xATR | 86 | +0.334 | −0.006 |
(注意生每筆R 在樣本內是反過來的:墊高組 +1.742 > 純結構 +1.256。 去極值之後翻面 —— 又一次「生峰被一兩筆大單頂起來」。)
但這一格不是乾淨的實驗。 墊高只套用在「結構停損本來就貼得很近」的那批單上, 所以兩組是不同的單,不是同一批單的兩種停損。拿它下結論等於拿兩群不一樣的人比身高。 乾淨的做法就是改門檻整批重跑 —— 那是第二節那支在做的事。
寫判讀文字時自己抓到一個錯:原本只印「兩份同向 ✓」,沒印往哪個方向, 會被讀成「墊高是好的」。實際上兩份的去最好3 都是墊高那組比較差。已改成印出方向跟數字。
同一批切法下還看到(只有樣本內,沒驗樣本外,所以不是結論):
沒有動。紅線 7:不主動加使用者沒要求的濾網。要動的話得先過樣本外。
使用者:「進退場可以用箭頭還是其他放是顯示 這樣圖面上不曉得是甚麼時候進場跟出場 知道價格而已」 以及:「好幾筆大時區看起來都沒什麼變化就自己被掃出去了」
改之前:進場只有一條水平價格線(進場 5653)——價格看得到,哪一根看不到。 出場有一條垂直虛線+一個點。
改之後:
三個呼叫點都接上了:已平倉圖、持倉中的圖(最需要知道什麼時候進的)、大時區圖。
做的時候踩到一個自己造的錯:大時區圖是用 mark_t + mark_label="進場" 標進場那一根的, 我把 mark_t 的箭頭寫死成紅色 ▼,結果圖上出現 64 個紅色 ▼ 配「進場」兩個字。 改成由 mark_label 推方向,並留 mark_dir 可以明講。驗過:現在方向跟文字 0 筆對不上。
看過一次渲染結果,進出場靠很近時兩個標籤會疊,所以進場標籤往左掛、出場往右掛,自然錯開。
新增 驗證_掃出去.py。幣圈 547 筆裡 343 筆(63%)是觸及停損,全部 −1.00R。 那 343 筆被掃掉之後行情怎麼走:
| 掃完之後最高回到 | 筆數 | 佔停損單 |
|---|---|---|
| ≥ +4R(照樣噴) | 96 | 28% |
| +2 ~ +4R | 59 | 17% |
| +1 ~ +2R | 45 | 13% |
| 0 ~ +1R(只彈一下) | 69 | 20% |
| < 0(繼續跌,停損是對的) | 74 | 只有 22% |
掃完又回到 +2R 以上的有 155 筆 = 停損單的 45%、全部單的 28%。 他看到的不是偶爾幾筆,是停損單裡的多數派。 按進場時的六H狀態切(bull 42%/mixed 50%/bear 46%)—— 三種狀態都一樣, 所以不是「大時區判斷不好」造成的,大時區當下看起來沒變是真的沒變。
#### 我第一版算錯了,自己抓到
第一版算:343 筆從 −1.00R 變 −1.50R =多賠 172R,撿回 43 筆賺 265R → 淨 +94R,該放寬。 錯的。 錯在 R 的尺:每筆風險固定本金 1%,停損拉寬 1.5 倍 = 部位變成 1/1.5。所以
放寬停損不是「多賠一點換撿回幾筆」,是拿全部贏單的 R 去換那幾筆。
| k(停損放寬倍數) | 還是被掃 | 撿回幾筆 | 撿回的R | 贏單的R | 估計總R |
|---|---|---|---|---|---|
| 1.00(現況) | 343 | 0 | 0 | 1073 | +730 |
| 1.25 | 320 | 23 | 97 | 859 | +636 |
| 1.50 | 304 | 39 | 123 | 716 | +534 |
| 2.00 | 266 | 77 | 175 | 537 | +446 |
| 3.00 | 229 | 114 | 164 | 358 | +293 |
單調往下。放寬停損在任何倍數都更差。
k=1.0 估出 +730,跟實際 +730.4 對上 —— 這一列是校準列,對得上才代表算法沒歪。 (第一次沒對上,估出 +822。原因:出場後最低R 是出場之後才開始量的, 會放過 14 筆「停損後就沒再更低」的單,把它們算成「1.0R 留得住」, 但它們明明已經被掃到 −1R。要跟 MAE_R 取 min 才是全程最低—— 停損單的 MAE_R 中位是 −1.14,掃到的那一根常常插更深。)
#### 所以該動的是什麼
不是停損寬度,是停損擺哪裡(結構位 vs ATR)跟進場時機。 同樣的停損距離,進得離均線近一點,插針掃到的機率本來就低 —— 那正好是今天乖離 7→3.5 在做的事。那個改動的硬停損率實測是降的(60% vs 69%)。
※ 全部是 CSV 事後回推的估算。保本門檻R/底艙啟動R/芭樂價R 都用 R 計價, 停損一變那些門檻的價格距離也變,出場序列會整個不一樣。要定案得重跑回測。
使用者:「應該要改成跟回測一樣才有同樣的標準 因為我們有通樣的篩選方式 所以不一定要去朋友網站是否拿標的」
上一節量出「回測跟線上在做兩個不同的池」之後,他選了把線上改成跟回測一樣。 理由是他自己講的:真正的篩選是 T桑 那幾道關,不是再疊一層別人的動能排名。
| 設定 | 改前 | 改後 |
|---|---|---|
| [台股] 使用儀表板 | 是(朋友儀表板動能排名) | 否(自算,走 _twse_universe) |
| [台股] 只做分層 | T1,T2 | 全部(不分層) |
沒改的三個鍵:池大小 = 40、最低成交金額 = 50000000、排除ETF = 否。 查過回測的 g() 讀的是 [台股] 同一區段同一個鍵,所以這三個本來就一致。
使用儀表板 = 否 只解決「池從哪來」。只做分層 = T1,T2 還會再篩一層: assign_tiers 把 rs_7d<0 且 rs_24h<=0 的標的整檔丟掉(連 T3 都不給), 而回測是「池裡 40 檔全部拿去跑關卡」,沒有這一層。
拿改完第一輪的池量這一層的代價:
| 照舊的分層走 | 檔數 |
|---|---|
| 自算池 | 40 |
| 只做分層=T1,T2 收得到 | 17 |
| 被丟掉、進不了候選 | 23 |
被丟掉的 23 檔裡有 10 檔是回測賺過錢的 (2303、2308、2327、2330、2383、2409、2454、3026、3037、6669), 那些檔在回測裡共 16 筆、總R +144.5、每筆 +9.031。
最清楚的一檔是 2308 台達電:回測在它身上賺了 +25.50R 跟 +22.98R 兩筆, 而它今天的 composite 是 −16.83(負的)—— 分層那一層會直接把它丟掉。 那一層砍掉的正好是回測賺錢的那一半。
候選順序改成照成交金額高到低(=回測逐檔跑的順序),不是照 composite。 照 composite 會變成「RS 高的先搶倉位」,回測沒有這個偏好。
selfscan 本來沒有快取檢查,因為以前只在「他的站掛掉」時才會跑到 (九月 447 次只用過 5 次)。改成固定自算之後,每輪要抓 41 次 Yahoo, 一天 24 輪=約 1000 次,純屬浪費 —— 池是「成交金額前 40」,一天變一次。
加了快取守門,沿用同區段已有的 最短間隔分鐘 = 230,並在寫檔時補 _fetched_ms (本來沒寫,所以沒有東西可以判齡)。
驗過了:跑一輪真的,池 40 檔、來源 self、不分層。 原本線上看不到的 14 檔有 12 檔進來了(2330 台積電、2317 鴻海、2454 聯發科、 2308 台達電…)。沒進的 0056、2313 只是今天不在成交金額前 40 —— 池本來就天天輪動。
還沒驗:新池會不會真的跑出單。今天 0050 跌 3.41%(查過是真的, 108.65 → 104.95),大盤濾網擋著,候選迴圈根本沒走到。 所以「改完會不會有單」目前只有推論沒有實測。 已經在策略板上寫明白這件事,不要讓上面那張「線上看得到/看不到」的表 被當成新池的數字 —— 那張表是舊池量的。
但美股回測那份 CSV 的池大小檔內沒記,而且美股線上有成交紀錄, 嚴重程度不明。沒量過就不動。
現在兩邊池一樣了,這個分歧的影響變得比以前大(同時有訊號的檔會變多)。
使用者:「用上去 然後台股方便做出來效果如何/台股都沒有任何單」 接著:「時間看調整成9-13:30」
兩份樣本都同向,四個軸同向,10R+ 密度兩邊都上升(尾巴沒被砍):
| 門檻 | 樣本內 每筆R | 樣本內 去最好3 | 樣本外 每筆R | 樣本外 去最好3 |
|---|---|---|---|---|
| ≤7.0(舊) | +1.335 | +1.142 | +0.659 | +0.582 |
| ≤4.5 | +1.652 | +1.354 | +0.815 | +0.709 |
| ≤3.5(新) | +1.648 | +1.286 | +0.913 | +0.784 |
| ≤3.0 | +1.907 | +1.489 | +0.849 | +0.687 |
| ≤2.5 | +1.732 | +1.241 | +0.625 | +0.423 |
取 3.5 不取 3.0:3.0 樣本內更好但樣本外掉下來,而 ≤2.5 兩份樣本都是懸崖。 3.5 在高原(3.0~4.5)靠近中間,兩份樣本都還在高原上。
設定.ini 裡順手改掉一句已經不成立的註解: 原本台股/美股那兩段寫「【幣圈不動】幣圈 [參數] 乖離警戒 本來就是 7」, 現在幣圈是 3.5,所以兩段各補一行說明。 另外原本掛在那裡的「收緊之後下影線插針掃停損的風險上升」查過不成立: 硬停損率 60% vs 69%、64% vs 76%,收緊之後反而更低。
台股 45 筆已平倉單的 進場乖離% 最大值是 6.95。 也就是說 乖離警戒 = 7 這道門檻在台股從來沒擋掉過任何一筆, 「台股也是 7」一直是個沒發生過的事件,不是一個驗過的結論。
往下收會發生這件事:
| 門檻 | 筆數 | 每筆R | 去最好3 |
|---|---|---|---|
| ≤7.0(現況=全部) | 45 | +6.176 | +3.663 |
| ≤6.0 | 27 | +7.761 | +3.562 |
| ≤5.0 | 16 | +7.690 | +1.814 |
| ≤4.0 | 11 | +10.222 | +1.623 |
| ≤3.5 | 8 | +13.024 | +0.946 |
| ≤3.0 | 5 | +15.720 | −0.295 |
| ≤2.5 | 3 | +25.643 | −1.160 |
每筆R 一路往上、去最好3 一路往下,這就是樂透籤的標準長相: 拔掉最好的 3 筆就什麼都不剩,≤3.0 以下直接變負。 幣圈那邊是兩個指標同時上升,完全相反。
→ 台股/美股 乖離警戒百分比 維持 7,沒有改。 這是 [[backtest-cross-market-not-equivalent]] 的第三個實例: 幣圈驗過的改動搬到台股反向。
線上台股從 2026-09-05 跑到今天共 1224 輪,開倉 0:
| 這一輪發生什麼 | 輪數 |
|---|---|
| 休市(K棒太舊)整輪不掃 | 998(82%) |
| 大盤濾網擋掉 | 48 |
| 真的掃了候選 | 178 |
那 178 輪裡做了 5907 次候選評估,全部被擋。擋在哪:
| 擋關理由 | 次數 | 佔比 |
|---|---|---|
| 60M 排列✗斜率✗(還沒折回多頭) | 1341 | 22.7% |
| 均線不是收斂上彎/擴散回碰/盤整突破 | 835 | 14.1% |
| 日線 近12根內均線曾交叉/排列亂掉 | 779 | 13.2% |
| 60M 排列✓斜率✗ | 421 | 7.1% |
| 不明確=均線沒在收斂、也不是位階2 | 367 | 6.2% |
| 60M 排列✗斜率↑ | 221 | 3.7% |
三個 60M 關卡加起來 33.5%,是最大一道牆。
但真正的原因是池不一樣,不是關卡太嚴。
對照結果:
(2330 台積電、2317 鴻海、2454 聯發科、2308 台達電、2303 聯電…,還有 0056 這檔 ETF)
也就是說:回測那個 +6.176/筆,三分之二來自線上永遠掃不到的標的。 把它切到線上真的看得到的範圍,去極值之後幾乎沒有優勢。 這不是「線上運氣差」,是回測跟線上在做兩個不同的市場。
另外 線上對照.py 也印出 [台股] 大盤暫停進場門檻 是「只有線上讀」—— 回測完全沒模擬大盤濾網,所以回測那 45 筆裡有一部分是線上會被擋掉的時段。
今天擋下來的 -3.41% 查過是真的:0050.TW 從 108.65 掉到 104.95。濾網沒壞。
→ 待決定:台股要嘛把線上池改成跟回測一樣(成交金額前 40), 要嘛拿線上那個池重跑回測。兩個池不能各自聲稱自己的數字。 沒有自己動,因為這會整個換掉台股在做什麼。
使用者:「時間看調整成9-13:30」
原本只有 休市判定分鐘 = 70(最後一根 60 分 K 多久沒更新)在判休市,兩頭都不準:
第二個才是真的有害:那一輪如果開倉,進場價是當天拿不到的收盤價。 台股每天 5 輪會掃,其中 14:05 這輪是無效的。
做法:[台股] 交易時段 = 09:00-13:30 + 時區偏移小時 = 8, 不在時段內整輪不掃新倉(既有持倉照常更新)。
休市判定分鐘 保留,兩個條件要同時成立才掃:
美股 交易時段 留空=行為不變。理由:ET 有日光節約時間,這台機器在 UTC+8, 寫死偏移會在換季那兩週錯一小時。台股全年 UTC+8 沒這個問題。
誠實講清楚這個改動買到什麼:它不會讓 09:05 那輪變得能用—— 那個時間點 Yahoo 真的還沒有今天的 1H K 棒,T桑的突兀量根本算不出來, 拿不到資料就開不了有效的倉。它買到的是拿掉 14:05 那輪的無效進場。 所以台股每天真正能掃的是 10:05/11:05/12:05/13:05 四輪。 要在時段內掃更密,是排程要跑更勤(例如每 15 分鐘一次),不是程式問題。
新增 測試_交易時段.py:29 項,涵蓋解析(留空/看不懂/收盤早於開盤/超過24小時)、 邊界(09:00 算在內、13:30 起算收盤、14:05 不在)、週末、留空時行為不變、 以及時區偏移真的有作用(同一個 UTC 時刻,+8 判在、0 判不在)。 寫測試時抓到一個真的錯:注入的時間沒有換算成交易所時區,直接讀 現.hour。 正式跑不會踩到(現是 None 時建構在正確時區),但正確性不該靠這個,已修。
| 筆數 | 每筆R | |
|---|---|---|
| 實際 | 547 | +1.335 |
| 打亂後 中位 | 325 | +0.059 |
| 打亂後 最好那次 | — | +0.255 |
p(每筆R)= 0.032、p(總R)= 0.032,兩個都是 0/30。 實際是最好那次排列的 5 倍、是中位數的 23 倍。
① 打亂後連筆數都少了三分之一(547 → 中位 325)。 洗過的資料裡本來就比較少出現「糾結完走出來」的形狀。 這不是 p 值的一部分,但它是結構確實存在的旁證 —— 如果我們找的形狀只是雜訊,洗牌後數量應該差不多。
② 打亂之後還是小賺(中位 +0.059)。 那一塊不是趨勢。洗牌保留每根的漲跌分布,所以本來會漲的標的洗完照樣漲, 那是「買一個往上的東西+停損在 −1R」的底盤。 實際 +1.335 比那個底盤高 23 倍,高出來的才是趨勢那一塊。 這個數字很重要:它說明優勢不是來自「幣圈長期往上」。
③ 這個 p 不涵蓋選池與大盤濾網(日線沒被打亂)。 它只說「在同樣的母體與大盤背景下,日內進出場規則有沒有抓到趨勢」。 不要拿它去蓋選池那一塊。
兩個不衝突,而且剛好互補 —— 「這東西有效」跟「這東西有樣本內數字那麼好」是兩個問題。 第一個答案是有,第二個答案是沒有。
一輪 18 分鐘,30 輪 9 小時,中途被中斷過一次。 每輪結果本來就落檔成 回測結果_MCPT_<種子>.csv,直接拿來當斷點, 重跑時讀既有結果不重算。
策略板「驗證」那一頁現在三段都有實數: 參數高原(含乖離兩份樣本對照)/樣本外/MCPT p 值。 不是只存在對話裡。
使用者:「這樣是不是大時區的設定 判定好一點可以躲掉不少根本只是反彈的單」
定義:進場後最高R 連 1 都沒到過就死掉(彈一下、沒走出來)。
| 筆數 | 反彈單 | 佔比 | 反彈單合計R | |
|---|---|---|---|---|
| 樣本內 | 547 | 176 | 32% | −176.0R |
| 樣本外 | 532 | 189 | 36% | −189.0R |
問題是真的:三分之一的筆數是純虧損的彩券。躲掉它們就是這題的價值。
反彈率(最高R<1 的比例):
| 進場當下 6H 排列 | 樣本內 | 樣本外 |
|---|---|---|
| bull | 35.6% | 37.0% |
| mixed | 30.2% | 37.0% |
| bear | 27.0% | 32.1% |
樣本內 bear 最低、樣本外 bull 最高,兩份樣本的順序是翻的。 位階(長均 MA60 算的分層)也翻:樣本內 位階1 最好(+2.192)、樣本外 位階2 最好(+1.081)。 6H 張開幅度:樣本內 4~7% 每筆最高(+1.936)、樣本外 <2% 最高(+0.892),也翻。
所以 2026-10-24 那個「6H張開% ≥4.36 像高原」的結論,樣本外推翻了。 那是樣本內的雜訊。這也是為什麼高原圖不夠 —— 高原只證明「不是尖點」, 證明不了「換個期間還在」。
乖離門檻掃描(現在 乖離警戒百分比 = 7,三個市場都是 7):
| 門檻 | 樣本內 每筆R | 樣本內 去最好3 | 樣本外 每筆R | 樣本外 去最好3 |
|---|---|---|---|---|
| ≤7.0(現況) | +1.335 | +1.142 | +0.659 | +0.582 |
| ≤5.0 | +1.548 | +1.272 | +0.816 | +0.720 |
| ≤4.5 | +1.652 | +1.354 | +0.815 | +0.709 |
| ≤3.5 | +1.648 | +1.286 | +0.913 | +0.784 |
| ≤3.0 | +1.907 | +1.489 | +0.849 | +0.687 |
| ≤2.5 | +1.732 | +1.241 | +0.625 | +0.423 |
| ≤2.0 | +1.857 | +1.220 | +0.608 | +0.330 |
兩份樣本都在 3.0~4.5 附近是高原,而且 ≤2.5 以下兩邊一起垮。 樣本外 ≤2.5 的去最好3 從 0.784 掉到 0.423 —— 那個懸崖兩邊都有,不是我挑的。
≤3.5 相對 ≤7 的改善,四個軸在兩份樣本全部同向: 樣本內 每筆 1.335→1.648、去最好3 1.142→1.286、勝率 37.1%→39.5%、10R+密度 4.0%→4.8% 樣本外 每筆 0.659→0.913、去最好3 0.582→0.784、勝率 30.3%→35.8%、10R+密度 1.9%→2.6% 10R+ 密度兩邊都上升 —— 尾巴沒被砍。
換三種反彈定義,看 乖離≤4.5 vs >4.5 的反彈率差:
| 反彈定義 | 樣本內 差 | 樣本外 差 |
|---|---|---|
| 最高R < 0.5 | −1.7pt | −1.8pt |
| 最高R < 1.0 | +1.3pt | +6.4pt |
| 最高R < 2.0 | +7.7pt | +10.2pt |
門檻放寬差距才拉開。追高的單不是進場就掛,是彈一下走不遠。 那正是使用者說的「根本只是反彈」。
原文(設定.ini:793):「收緊之後進場更貼近均線,下影線插針掃停損的風險上升。」
| 樣本 | 乖離組 | 停損距離%中位 | 硬停損率 | 最差R | MAE_R中位 |
|---|---|---|---|---|---|
| 樣本內 | ≤3.5 | 2.0 | 60% | −1.00 | −1.04 |
| 樣本內 | >4.5 | 3.95 | 69% | −1.00 | −1.06 |
| 樣本外 | ≤3.5 | 2.1 | 64% | −1.00 | −1.04 |
| 樣本外 | >4.5 | 3.77 | 76% | −1.00 | −1.07 |
反過來:乖離收緊之後硬停損率是下降的(兩份樣本都是), 最差R 全部守在 −1.00,MAE 中位沒有差別。擔心的方向錯了。
相關係數 樣本內 0.045 / 樣本外 −0.034。二維表(每筆R):
| 風報<4.94 | 風報≥4.94 | |
|---|---|---|
| 樣本內 乖離>4.5 | +0.705 (130) | +0.869 (64) |
| 樣本內 乖離≤4.5 | +1.096 (251) | +3.020 (102) |
| 樣本外 乖離>4.5 | +0.383 (138) | +0.435 (62) |
| 樣本外 乖離≤4.5 | +0.700 (240) | +1.116 (92) |
兩份樣本的最佳格都是同一格。
設定.ini:769 已經有三市場單調的證據,機制也寫清楚了: 「乖離大 → 停損必須放遠 → R 被壓扁。R = 價格走幅 ÷ 停損距離, 所以貼著均線進場不是美學問題,是讓分母變小。」 當時 台股 10→7,幣圈留在 7 沒動。 使用者自己 2026-10-10 對圖時也說過:「現在會比較等到大時區接近碰到均線時進場」。
建議 [參數] 乖離警戒百分比 7 → 3.5(幣圈)。 沒有自己改 —— 這會改變線上掃描的行為。 台股/美股同一個參數也是 7,但這次只驗了幣圈, 跨市場不等價([[backtest-cross-market-not-equivalent]]),要各自驗。
一個誠實的保留:門檻是我同時看兩份樣本挑的,所以樣本外已經被我看過了。 真正乾淨的驗證要第三段期間。但 ≤2.5 的懸崖兩邊都在,不是只有一邊。
使用者桌面那個壓縮檔(20MB,解到隔離資料夾只讀不執行)。 它的均線判定比我們簡單:只有 站上5/20/60/240日線、MA20上升中、 4均線多頭排列、20日突破(src/markets/tw/screener/catalog.js:9)。 我們已經有三線排列、張開%、糾結、束上升、底部發散、位階分層。均線這塊沒東西可借。
它真正的東西是幾何型態比對:51 個型態(W底/頭肩/三角/楔形/旗形/9種諧波×多空), 多尺度 ZigZag 轉折點 → 硬性幾何門檻 → 正規化重取樣 40 點 → 帶寬 DTW 相似度 → 70~77 分門檻 (src/components/patterns/matcher.js,351 行,純 JS 零套件)。 那是我們沒有的,而且確實是「圖形」。
但現在不建議做。 我們的問題不是「偵測不到型態」, 是「優勢樣本外砍半、三分之一的單是反彈」。 蓋一個型態比對引擎是大工程而且沒有證據說它會改善那兩件事; 乖離那條是兩份樣本驗過的、改一行設定。先做有證據的那個。
樣本外 2024-10-08 ~ 2025-10-08(設定逐字相同,一次都沒跑過),2115 秒跑完。
| 筆數 | 每筆R | 去最好3 | 勝率 | 回撤 | 10R+ | 最佳 | 最差 | |
|---|---|---|---|---|---|---|---|---|
| 樣本內 | 547 | +1.335 | +1.142 | 37.1% | 15.6 | 22 筆(4.0%) | +47.2 | −1.00 |
| 樣本外 | 532 | +0.659 | +0.582 | 30.3% | 34.3 | 10 筆(1.9%) | +15.5 | −1.00 |
① 回撤才是壞消息,不是每筆R。 每筆R 掉一半只是賺比較少;回撤 15.6 → 34.3(2.2 倍)是同樣的部位會痛兩倍。 照樣本內那個 15.6 去抓部位會出事。抓部位要用 34.3。
② 大單密度砍半:4.0% → 1.9%,最佳單筆 47.2 → 15.5。 這套方法不是靠勝率活的(勝率本來就 30~37%),吃的就是大單。
③ 停損守住了。 兩段最差單筆都是 −1.00R,預掛單有效。這條是唯一全綠的。
原本會想說「那一年行情比較差」。查了 BTC 日線: 樣本外 BTC 站上 MA60 的天數佔 90%,樣本內只有 67% —— 那一年 BTC 更強。
真正的差別是有沒有噴出的月份: 樣本內 2026-05 +167R、2026-08 +114.6R、2026-09 +245.5R -> 三個月 527R,佔全年 730R 的 72% 樣本外 最好的一個月 2024-11 +120.5R,沒有任何一個月接近那個量級
所以這套方法的年度成績,實際上是由兩三個山寨噴出的月份決定的。 其餘月份(樣本外 2024-12:85 筆每筆 +0.094、2025-05~09 每筆 0.41~0.45) 基本上是在打平。這不是缺陷,是順勢系統的本來面目 —— 但它意味著「平均每筆 1.335R」這句話會讓人誤判, 因為那個平均不是每個月都在發生。
樣本外最深回撤發生在 2024-12-13 → 2025-01-02(三週), 樣本內那個 15.6R 只花四天(2026-09-27 → 10-01)。 樣本外是慢性失血,樣本內是急跌。 前者更難撐。
門檻 ≥4.94 相對門檻外的優勢:
| 軸 | 樣本內 | 樣本外 | 剩下 |
|---|---|---|---|
| 每筆R | +1.228 | +0.258 | 21% |
| 去最好3 | +0.846 | +0.083 | 10% |
| 10R+密度 | +5.5pt | +2.8pt | 52% |
三個軸都同方向,所以不是我挑數字挑出來的。 但去極值只剩 10%,代表樣本外的好處幾乎全來自幾筆大單,不是整體體質。 方向可以信,幅度不要照樣本內的數字去設預期。 所以 風報比門檻 維持 2.5,沒有改。
樣本外 BTC 站上 MA60 佔 90%,所以這道濾網在那一年只擋掉 53 筆。 站上 +0.687 vs 跌破 +0.399,方向對但樣本太小(53 筆)說不了話。 這個發現還沒被真正檢驗過 —— 要一段 BTC 長時間在 MA60 下方的期間才測得動。
1. 驗證_樣本外.py 原本只比 每筆R 的方向就印「✓ 活下來了」。 太寬鬆 —— 它會把「優勢只剩大單」誤判成「優勢成立」。 改成三個軸(每筆R/去最好3/10R+密度)分開列,各自報剩幾成。 2. 原本沒有把回撤納入判讀。而這次回撤才是最壞的那個數字。 加了 ①b(回撤)與 ①c(大單還在不在)兩段。
使用者:「未計手續費與滑價 這個不納入討論。我們趨勢有做到哪裡、該停損才是重要的, 不是刷交易量造成的,所以手續費不討論」→「可以開始做」
不是「縮小」是「拿掉」。理由不是懶得算 —— 這套一年 547 筆、持倉以天計, 不是靠週轉率賺錢的系統,摩擦實測 −3.5%/−2.6%,小到不會改變任何一個決策。 但擺在「報酬」「風險」兩欄裡會跟 10R+ 貢獻、最大回撤 搶同樣的視覺權重。 算法留在這份紀錄(上一節),要的時候三行算得回來。
| 檔 | 問什麼 | 成本 |
|---|---|---|
| 驗證_高原.py | 這個門檻是高原的中間,還是運氣撐的尖點 | 秒級(只掃進場當下就決定的欄位) |
| 驗證_樣本外.py | 同一套設定丟到沒看過的期間還成不成立 | 一輪回測 |
| 驗證_MCPT.py | 把 K 棒順序打亂,隨機做不做得出這個成績 | 30 輪回測 |
| 測試_MCPT打亂.py | 打亂函式本身對不對 | 秒級 |
三個結果都接到 策略板 第五個檢視「驗證」,不是只存在我講的話裡。
1. 欄位走白名單。 CSV 裡一半是結果欄(持倉小時/最高R/出場原因/MAE_R…), 拿它們當濾網 = 挑贏的單 = 數字全假。不在白名單直接拒絕,不是警告。 2. 峰看「去最好3筆」不看生每筆R。 生峰容易被一兩筆大單頂起來。 實測:規劃風報比 的生峰在 ≥7.83(只剩 28 筆),去極值峰在 ≥4.94(166 筆)。 第一版判讀只看生峰、而且把「峰在邊界」一律判成假象, 結果把單調階梯誤判成尖點。單調階梯是高原被樣本數切掉右半邊,不是尖點,要分開講。
現在 設定.ini 風報比門檻 = 2.5。高原表(幣圈 547 筆,樣本內):
| 門檻 | 筆數 | 每筆R | 去最好3 | 勝率 | 10R+密度 |
|---|---|---|---|---|---|
| 不設(現況 2.5) | 547 | +1.335 | +1.142 | 37.1% | 4.0% |
| ≥3.50 | 356 | +1.476 | +1.206 | 36.8% | 5.3% |
| ≥4.00 | 277 | +1.740 | +1.395 | 40.1% | 6.1% |
| ≥4.50 | 221 | +2.028 | +1.598 | 40.7% | 7.7% |
| ≥4.94 | 166 | +2.191 | +1.621 | 42.2% | 7.8% |
| ≥5.50 | 114 | +2.049 | +1.354 | 43.9% | 7.0% |
| ≥6.50 | 67 | +2.412 | +1.273 | 46.3% | 6.0% |
形狀是單調階梯(16/18 步上升)。四項全贏基準,而且 10R+ 密度 4.0% → 7.8% 等於翻倍 —— 尾巴不但沒被砍,還變濃。 這跟 二H需要發散(大單 22→7)跟 掃描40 的 6H 方向關卡(22→9)剛好相反。
而且它正好就是使用者講的那件事:目標能跑多遠 ÷ 停損擺多近。
#### 三道防偽都過了 1. 跟停損距離是不是同一件事? 相關只有 −0.238。二維交叉表: 固定停損距離分三組,風報比高的三組都贏(+0.438/+1.536/+0.778); 反過來固定風報比,停損遠近差 −0.465/+0.024/−0.125,沒有方向。 → 真正的變數是風報比,停損距離只是它的代理。 2. 目標價有沒有偷看未來? 目標價 = max(前高, 測幅), 前高取 _高序[-45:-3]、測幅取 _測序[-80:],而序列本身是 k30[:i+1] / k6h[:j6+1](回測.py:929,939)—— 全部截到當下那根。沒有。 3. 是不是尖點? 單調階梯,不是。
#### 但它還是樣本內 事後在既有 CSV 上切出來的,跟 BTC 大盤濾網同一個毛病。 所以樣本外那一輪會順便檢驗它(驗證_樣本外.py 裡已經寫死這個切法, 跑完自動比對兩段方向一不一致)。方向對了才叫驗證。
1. 只打亂 30 分,日線不動。 回測裡 1H/2H/4H/6H 全部由 30 分重採樣(回測.py:671-675), 所以打亂 30 分會一致地打亂所有日內時框,不會自相矛盾。 日線獨立抓,用在選池(當日成交額)、大盤濾網、分層 —— 那三件保持真實。 所以這個 p 值問的是「在同樣母體與大盤背景下,日內進出場規則有沒有抓到趨勢」, 不涵蓋選池與大盤濾網,不要拿它去蓋那兩樣。 2. 打亂掛在 回測.cached_klines 外面,快取已熱所以不多打幣安一次(紅線5)。
打亂法用 Masters 的 bar permutation:每根拆成 log(o_t/c_{t-1})、log(h_t/o_t)、log(l_t/o_t)、log(c_t/o_t) 四個綁一起洗牌再重建, 影線比例保持真實,只有順序是假的。
測試_MCPT打亂.py 七條全過:長度/時間戳/量不變、第一根不動、影線合法、 價格為正、漲跌幅分布原封不動(標準差 0.008990 = 0.008990)、 自相關 −0.0433 → −0.0014、同種子可重現。 最後兩條是靈魂 —— 分布沒變代表只換順序,自相關被打掉代表趨勢結構真的被破壞了。
547 筆 每筆 +1.335,95% 區間 +0.962 ~ +1.741,重抽樣後平均 ≤0 的比例 0.0000。 → 不是純波動。但這一題很弱:它只說「不是 0」,沒說「不是運氣」。
引擎參數的高原(保本門檻R/移動停損/底艙啟動R/芭樂價R)。 那些會改變每一筆的結果,不能從既有 CSV 事後切,每個門檻都要重跑一輪。 現在那張高原表只涵蓋「進場當下就決定」的欄位。
使用者給了 https://github.com/Blave-TW/blave-agent —— 「把我們的優點融合進去,再參考頁面修改成類似這樣介面比較乾淨」
1. 三欄 label→value(Returns/Risk/Trading),不是一排大數字磚。密度高但不吵。 2. 分頁,不是九段往下堆。 3. 每組數字上面一行講清楚它是哪來的:BTCUSDT · 1d · 2020-01-01→2026-10-14 · fee 0.05%。 4. 月報酬熱力圖。 5. MCPT p 值/樣本外 當一等公民指標,跟 Sharpe 並列。
| 他們的 | 我們改成 | 備註 |
|---|---|---|
| Returns/Risk/Trading 三欄 | 報酬/風險/交易三欄 | label 掛 title 解釋,R 這套術語下次打開不一定還記得 |
| 分頁 | 側邊欄四檢視:總覽/訊號/策略/調整 | 九段收成四個,回應他 10-21「很亂、沒有一個方向」 |
| 脈絡行 | 幣圈 · 30M/2H/6H · 近365天 · 池100逐日建池 · 截止2026-10-08 + 來源檔名 + 摩擦成本 | |
| 月報酬熱力圖 | 每月入袋R(照出場月算) | 10-24 剛量到月份效應很大,這格直接有用 |
| MCPT p 值 | 我們沒有,現在擺的是去最好1/3筆 | 頁面上誠實寫「Blave 那邊對應的是 MCPT,比這個嚴謹,我們還沒有」 |
分頁用純 CSS(radio :checked),沿用 戰情板 既有做法,整頁 0 個 script。 顏色一行沒動 —— 全部走 戰情板.CSS 既有的 light/dark token。
我們三支回測的檔頭都老實寫了「未計手續費與滑價」,但那是免責聲明不是數字。 不用改引擎也算得出來:每一筆的 停損距離% 就是 1R 等於價格的百分之幾, 所以 來回摩擦% ÷ 停損距離% = 這一筆被吃掉幾個 R。
| 市場 | 來回摩擦 | 停損距離中位 | 每筆吃掉 | 總R → 扣後 | 每筆R → 扣後 |
|---|---|---|---|---|---|
| 幣圈 | 0.100%(幣安永續 taker 來回;山寨滑價另計,沒猜) | 2.82% | 0.047R | 730.4 → 704.5(−3.5%) | +1.335 → +1.288 |
| 台股 | 0.585%(手續費 0.1425% 買+賣 + 證交稅賣出 0.3%,沒假設折扣) | 4.05% | 0.162R | 277.9 → 270.6(−2.6%) | +6.176 → +6.014 |
小,但從此頁面上有數字而不是免責聲明。引擎沒有改 —— 這是頁面層的補算。
1. 三頁都缺 <!doctype html> 與 <meta charset>。 Cloudflare Pages 自己會送 charset=utf-8 的標頭,所以線上看不出來; 但使用者本機直接打開 .html 就是亂碼(playwright 抓到標題是「蝑𣇉裦」), 而且沒有 doctype 等於整頁跑在 quirks mode。三頁都補了。 2. 同一頁出現兩組不同的台股數字。 表格讀手寫的 回測預期(39 筆 +6.322 勝率71.8%), 下面的績效卡讀實算(45 筆 +6.176 勝率68.9%)—— 那正好就是他最早抱怨的「不曉得哪個數字算哪一版」,被我自己做出來一次。 修法:表格改讀同一個 讀回測(),手寫那組數字整個刪掉,只留算不出來的那一句註記。 3. 底艙那兩處 6.322 是 10-21 量的(當時 39 筆),跟現在 45 筆的 6.176 對不起來 —— 窗口滑動(見 [[backtest-stock-window-slides]])。兩個當時都是真的, 所以不是刪掉而是標上量測時點,並寫明「要看的是兩組的方向差,不要拿去對帳」。
回測來源 裡美股不寫池大小。設定.ini 現在是 150,但那份 CSV 是哪個池跑的檔內沒記, 舊的手寫註記寫 40。兩個都可能,所以寫「池大小檔內沒記」—— 猜一個寫上去是在製造假確定。
原本寫「這一頁不自己算績效…不自動聚合三十幾個不同年份的掃描檔」。 改版後每個市場只認一份宣告來源,檔名印在頁面上,所以是 「手寫一組數字」換成「指定一份檔案、數字自己長出來」, 不曉得哪個數字算哪一版的問題照樣不會回來。
只能標成「事後在既有資料上切的,不是事前登記的假設」。
掃描40 的 6H 張開%≥3% 就有這個味道(3% 好、5% 垮),高原圖會直接看出來。
使用者 2026-10-21:「幣圈看起來進出場 6h還不是多頭或是均線翻轉就進場了, 要注意是否有符合我們之前討論的圖形」 2026-10-24:「重點是我們有做到趨勢,勝率部分占獲利的比例不大, 要確切閃開大時區還在盤整或是下跌的,減少我們勝率下降」
他講的事實是對的:547 筆裡進場當下 6H 是 bull 的只有 264 筆(48%), mixed 172、bear 111。確實有兩成是在 6H 空排的狀態下進場。
| 設定 | 筆數 | 勝率% | 總R | 每筆R | 去最好3 | 回撤 | 10R+筆 | 最差R |
|---|---|---|---|---|---|---|---|---|
| 現況 6H只看糾結 | 547 | 37.1 | 730.4 | 1.335 | 1.142 | 15.6 | 22 | −1.00 |
| 6H束上升+多排 | 259 | 34.7 | 298.9 | 1.154 | 0.813 | 14.6 | 9 | −1.00 |
每筆 −0.181、去最好3 掉到 0.813(就輸了)、大單 22→9(−59%), 而且勝率也一起降(37.1→34.7)。 不是「砍尾巴換勝率」那種取捨 —— 兩邊都輸。
CSV 本來就記了進場當下的 六H狀態,所以直接拆,不用重跑。
| 進場當下 6H | 筆數 | 勝率% | 總R | 每筆R | 去最好3 | 10R+筆 |
|---|---|---|---|---|---|---|
| bull | 264 | 35.6 | 303.9 | 1.151 | 0.816 | 10 |
| mixed | 172 | 35.5 | 209.4 | 1.217 | 0.840 | 6 |
| bear | 111 | 43.2 | 217.1 | 1.956 | 1.373 | 6 |
生數字看起來「6H 空排反而最好」,但那是月份效應: 111 筆 bear 有 56 筆(50%)落在 2026-05/08/09,那三個月所有組都翻倍。
同月對照(只算 bear 當月 ≥4 筆的 11 個月,月份等權): bear +1.432 / 非bear +1.423 —— 差 0.009R,等於零。
所以結論不是「空排比較好」,是 6H 的均線排列對結果沒有判別力。 往任何方向加嚴都只是砍樣本。11 個月裡 bear 贏 8 個,但幅度被 2026-03 那 2 筆(BRUSDT +19.23、C98USDT +2.60,當月 per +10.9)吹大。
另外 547 筆全部都是 六H張開% ≤ 六H張開前%(6H 束在收縮)—— 六H要收縮 那道關卡確實有在生效,沒有漏。
拿本機 kline_cache 的 BTC 日線(840 根,2024-06-21~2026-10-08,沒打幣安) 算出每一根的均線排列(30/45/60)、收盤在不在 MA60 上、束有沒有比 20 根前高, 再跟每一筆的進場時間對起來:
| 進場當下 BTC 日線 | 筆數 | 勝率% | 總R | 每筆R | 去最好1 | 去最好3 | 回撤 | 10R+筆(密度) |
|---|---|---|---|---|---|---|---|---|
| bull | 365 | 38.9 | 550.0 | 1.507 | 1.381 | 1.250 | 15.6 | 15 (4.1%) |
| mixed(大盤盤整) | 67 | 26.9 | 41.4 | 0.619 | 0.337 | −0.052 | 10.0 | 2 (3.0%) |
| bear | 115 | 37.4 | 139.0 | 1.209 | 0.936 | 0.629 | 14.9 | 5 (4.3%) |
| 站上 MA60 | 366 | 39.6 | 569.8 | 1.557 | 1.432 | 1.302 | 15.6 | 16 (4.4%) |
| 跌破 MA60 | 181 | 32.0 | 160.6 | 0.887 | 0.713 | 0.474 | 14.9 | 6 (3.3%) |
| 束 20 根往上 | 314 | 37.6 | 475.1 | 1.513 | 1.367 | 1.215 | 15.6 | 13 (4.1%) |
| 束沒往上 | 233 | 36.5 | 255.3 | 1.096 | 0.961 | 0.783 | 14.9 | 9 (3.9%) |
BTC mixed 是全部切法裡唯一去極值後不賺的一格(去最好3 −0.052) —— 那正好就是他說的「大時區還在盤整」。只是「大時區」要讀成大盤,不是個股的 6H。
BTC 站上 MA60 四條標準全過: ① 每筆 1.335→1.557(+0.222) ② 去最好1 1.251→1.432、去最好3 1.142→1.302,都升 —— 去極值仍贏 ③ 10R+ 22→16 筆,但密度 4.0%→4.4% 上升(樣本砍掉 1/3,大單密度沒掉) ④ 最差 −1.00 不變 ⑤ 勝率 37.1→39.6(+2.5pt)—— 他要的那一項
1. 這是事後在既有資料上切的,不是事前登記的假設(紅線6)。 會相信它的理由是三個變種(均線排列/站上MA60/束往上)全部同方向, 不是從一堆切法裡挑出好看的那個。但要算數必須寫成關卡重跑 —— 關卡會改變 逐日建池 與 最多同時持倉 下實際拿到哪些單,事後切做不到。 2. 它不是免費的。總R 730.4→569.8(−160.6R,−22%),回撤 15.6 沒變好。 而且它會整月關掉,包含 2025-11(11 筆 +2.285)與 2026-07(29 筆 +1.267) 這兩個其實不錯的月。 3. 月份等權只剩 4 個月可比(好 +1.152 / 壞 +0.899) —— 薄,但同方向。 不過對「大盤濾網」來說月份等權本來就是錯的對照 —— 它的本職就是壞月份要關掉,把月份效應扣掉等於把要測的東西扣掉。 這跟個股 6H 的測法不一樣:個股 6H 應該在任何行情都有效,所以同月對照才對。
「6H 圖形不合格」不只有均線排列一種讀法。價格相對 6H 束的位置沒量過 —— CSV 沒記這一欄,kline_archive 的 6H 只有 500 根(約 2026-05~09), 涵蓋不到一年,要測得重跑。所以掃描40 否掉的是「6H 均線排列」, 不是他講的每一種圖形。
仍然預設否,設定.ini 沒設,行為沒變。
(他要的是閃開盤整/下跌,但他講的是個股 6H),所以不自己加。
> 「加碼就是拿獲利去賭接下來的趨勢會不會走出來,怎麼會越虧越多, > 應該是本倉有獲利的額度了才能去加碼然後提高停損至少保住一些獲利或是打平, > 而不可能變成大虧或是虧 1r」
他描述的機制本來就寫在設定檔裡。 加碼模式 = 調停損 + 加碼後最壞R = 0 的字面意思就是「先決定加多少,再把共用停損反解到整筆最壞=打平」, 而 plan_addon 的 調停損 分支也確實擋著: if s_new <= shared_stop: return None(算出來的停損沒比現在高就不准加)。 設計是對的,是實作把它破壞掉的。
shadow_bot.py:1427 `` be, cur_stop = True, be_stop # 直接賦值,不是 max() ` 時序:加碼門檻R = 2.0、保本門檻R = 4.0`,所以
停損往下搬了 1.27R,而搬掉的正好是加碼換來的保護。 接著放大後的倉位在 +0.1R 出場:初倉賺 0.1R,加在 +2.74R 的那半虧 2.64R。
回測730(沒有線上那個重跑 bug)穿破 −1R 的 3 筆:
| 標的 | R數 | 出場價所在 | R數_初始倉 | 加碼時R | 加碼後停損R | 加碼量佔初倉% | 手算混合R |
|---|---|---|---|---|---|---|---|
| 1000PEPEUSDT | −2.46 | +0.100R | 0.10 | 2.74 | +1.37 | 97.1% | −2.463 |
| RESOLVUSDT | −1.07 | +0.100R | 0.10 | 1.30 | +0.65 | 97.8% | −1.074 |
| 龙虾USDT | −1.83 | +0.100R | 0.10 | 2.59 | +1.30 | 77.2% | −1.822 |
三筆出場價都正好落在保本價 +0.100R、出場原因都是「觸及保本停損」, 而手算的混合 R 跟記錄吻合到小數第二位。機制確認無誤。
| Bug | 筆數 | 超額虧損 | 範圍 |
|---|---|---|---|
| 重跑時停損被重設(2026-10-19 已修) | 6 | −20.52R | 線上獨有 |
| 保本蓋掉加碼停損(本輪修) | 1 | −0.63R | 回測+線上共用 |
線上那場災難 97% 是重跑 bug(六筆出場價都正好在 −1.000R, 卻帶著放大 2~4 倍的倉位);回測看得到的那 3 筆才是保本覆蓋 bug。 兩個 bug 一個多月(v5→v9)都沒有任何測試或檢查攔到。
cur_stop = max(cur_stop, be_stop)。停損只升不降 —— 這本來就是整支程式 到處寫著的原則(移動停損那段是 max、plan_addon 註解寫「只升不降: 算出來比現在低就不接受」),只有保本這一行漏了。
單元測試(拿修正前的備份對照,證明測試抓得到): `` 加碼已把停損上調到 113.70(+1.37R),maxR 到 4R: 修正前的備份 cur_stop = 101.00 混合R −2.463 現在的程式 cur_stop = 113.70 混合R +0.040 對照組(沒加碼,停損在 90)兩版都是 101.00 —— 修正沒有動到正常保本 `` 1000PEPEUSDT 本來該是 +0.040R(打平),正是使用者說的 「至少保住一些獲利或是打平」。
今天的行為影響是零:三個市場 最多加碼次數 已經是 0, 而加碼是保本之前唯一會把停損推高的路徑,所以 max() 與直接賦值等價。 這是「恢復加碼的三個條件」裡的第一條。
10 條,覆蓋:保本不准往下搬(含加碼已上調的兩種幅度)、移動停損也只升不降、 沒加碼的單成交在停損價且正好 −1R、跳空照實的開/關行為、 plan_addon 調停損 在停損算不夠高時回 None。 拿修正前的備份跑過,確認它會掛 —— 會過但抓不到 bug 的測試沒有意義。
| 設定 | 筆數 | 勝率% | 總R | 每筆R | 回撤 | 最佳R | 最差R | 穿破−1R | 10R+筆 | 10R+總R |
|---|---|---|---|---|---|---|---|---|---|---|
| 加碼ON(含 bug) | 600 | 45.0 | 912.1 | 1.520 | 17.2 | 74.1 | −2.46 | 3 | 30 | 707.8 |
| 加碼OFF | 547 | 37.1 | 730.4 | 1.335 | 15.6 | 47.2 | −1.00 | 0 | 22 | 397.4 |
關掉的代價不小:每筆 −12%、最佳單 74.1→47.2、 10R+ 的大單從 30 筆 707.8R 掉到 22 筆 397.4R。 那正是使用者說的「拿獲利去賭趨勢會不會走出來」——賭對時大單就是從那裡來的。 注意 ON 那一組是含 bug 的版本(3 筆被保本蓋掉、共 −5.4R), 所以修好之後的 ON 應該更好,掃描36 在驗。
不自己把加碼打開 —— 那是風險姿態的改變,等掃描36 的數字連同判定一起給使用者決定。
掃描30(365 窗口,釘窗口沿用掃描20/25/26/27):
| 設定 | 筆數 | 每筆R | 回撤 | 最差單筆 | 穿破−1R | 保本平均R |
|---|---|---|---|---|---|---|
| 盤中低點 跳空美化 | 605 | 1.511 | 17.2 | −2.46 | 3 | −0.61 |
| 盤中低點 跳空照實 | 605 | 1.511 | 17.2 | −2.46 | 3 | −0.63 |
| 收盤 | 564 | 1.755 | 33.4 | −7.53 | 245 | −3.50 |
一、跳空照實對幣圈幾乎零影響(1.511 vs 1.511、最差單筆一樣)。 永續合約連續交易,30 分 K 很少開盤就跳過停損 —— 跳空是股票市場的現象。 設定仍寫 停損跳空照實 = 是,為的是三個市場口徑一致,不是為了改行為。
二、收盤模式正是使用者說幣圈一定要避免的那個東西:它等於不掛預掛單, 所以 245/564 筆穿破、保本機制平均變 −3.50R。期望值 +0.24R 不拿來換 −1R 上限。 台股用收盤、幣圈用盤中低點,兩邊不同是有原因的: 台股的跨日跳空讓「填得到停損價」這個假設失效(所以收盤反而誠實), 幣圈連續交易、預掛單填得到,所以盤中低點才是對的模型。
> 「停損的部分要確定,因為有單跑到 −6R 這不應該發生,我記得不是有預掛單 > 這樣避免插針整個倉位消失,幣圈一定要有的狀況」 > 「加碼部分先都不討論,先把台股做好的部分套用配合幣圈進去,用一樣的方式去做單」 > 「這個部分要確定執行的策略,幣面再發生這樣的情況跑出來的數值完全沒參考價值」
他說對了,而且程度比我一開始報的嚴重。
線上幣圈 114 筆已結清,總 R −9.72R。其中 7 筆加碼單破了 −1R 上限, 超出設計上限的部分(R + 1 的總和)合計 −21.15R = 總虧損的 218%。
| 代號 | R數 | 加碼次數 | 規則版本 |
|---|---|---|---|
| FLUIDUSDT | −6.61 | 2 | v9 |
| BNCUSDT | −5.02 | 2 | v5→v6 過渡 |
| KMNOUSDT | −4.86 | 1 | v9 |
| KAVAUSDT | −3.50 | 1 | v5→v6 過渡 |
| 0GUSDT | −3.46 | 1 | v8 |
| VTHOUSDT | −3.07 | 1 | v5 |
| BTWUSDT | −1.63 | 2 | v5 |
停損沒被破掉的話,線上是 +11.4R 而不是 −9.72R。 而且分布在 v5/v5→v6/v8/v9 四個版本 —— 從 2026-09-15 引入「加碼調停損」 那天起就一直在漏,而且從來沒有任何檢查攔到。
| 樣本 | 筆數 | 最差單筆 | 穿破 −1R |
|---|---|---|---|
| 線上 沒加碼 | 89 | −1.00 | 0 |
| 線上 有加碼 | 25 | −6.61 | 7 |
| 回測730 沒加碼 | 676 | −1.00 | 0 |
| 回測730 有加碼 | 507 | −2.46 | 3 |
破掉 −1R 的唯一途徑就是加碼。 盤中低點模式的成交價就是 cur_stop, 那本來就是「停損單掛在那裡、碰到就成交」的預掛單模型。
shadow_bot.py:2419:K 線涵蓋進場那根時,程式刻意把 cur_stop / be / maxH / maxR 重設,從進場重跑 —— 這是 2026-09-06 一個正確的 修正(否則「今天的停損」會去判「昨天的 K 棒」,龙虾USDT 那次就是這樣誤出場)。
但緊接著的 子倉/加碼次數/最後加碼時間ms/初始風險USDT 一律從存檔還原。 於是重跑時倉位是加碼放大後的(幣圈 加碼比例 = 1.0,兩次加碼=4 倍), 停損卻是加碼之前的;而 add_count 已滿又讓重跑不會再加碼, 停損永遠不會被上調。第一根碰到原始停損就出場,損益用 4 倍倉位算 → −6.61R。
同一個檔案裡「芭樂價部分停利」的註解把道理講得很清楚: 「跟加碼一樣持久化,不隨每輪重跑重算 —— 子倉的量在部分賣出後就改掉了, 重跑沒有『賣之前的量』可以還原」。加碼是同一個道理,但它「上調停損」那一半 被重設了,兩半不一致。
回測沒有這個 bug(單向前跑、不重播),所以回測永遠看不到這類單 —— 回測 1183 筆只有 3 筆穿破,線上 30 筆就 2 筆。
修法:新存 加碼後停損,重跑時只在 K棒時間 >= 最後加碼時間ms 之後 把 cur_stop 墊上去。用時間閘門而不是直接還原 目前停損, 才不會把 2026-09-06 修掉的問題帶回來。
1. 三個市場 最多加碼次數 = 0。依據使用者 2026-10-16 「加碼限量這個可以先不考慮,先把本單做好」與這次的「用一樣的方式去做單」。 這不是「划不划算」的決定 —— −1R 上限是硬需求,不拿來換績效。 2. healthcheck.py 新增 檢查單筆上限():每一筆已結清單虧損不得超過 −1R (幣圈容忍 0.05R;台美股跨日跳空落在開盤時段的列提醒不算異常), 加碼次數不得超過設定值。容忍值刻意寫死在程式裡、不放設定.ini —— 放進設定檔就會有人(包括我)在它報警時去調大它,那等於把警報關掉。 用開倉時間比對關閉時刻:關閉前開的單是既成事實(收成一行提醒), 關閉後再出現才算異常。 3. 加碼模式 = 調停損 留在設定檔但不生效,並記下恢復加碼的三個條件: 調停損要能保證整筆最壞不超過 −1R;重跑的停損狀態要跟加碼狀態一致; 回測與線上要能重現同一筆單的 R。
線上「有加碼 25 筆每筆 +0.709R/沒加碼 89 筆 −0.308R」 不能當成加碼有效。加碼門檻是 maxR >= 2R,所以「有加碼」那組是 用結果篩出來的(條件於已經在賺)。它只證明「賺的單會被加碼」。 回測那邊同樣的陷阱更誇張:「無加碼 勝率 4.9%/有加碼 勝率 95.4%」。 要知道關掉的真實代價,只能整個關掉重跑同一個窗口(掃描34)。
掃描27 的結論是「幣圈不套收盤」,依據是: 盤中低點 最差 −2.46R、穿破−1R 僅 3/1183 筆; 收盤 最差 −7.53R、穿破 493/1105 筆、「觸及保本停損」平均從 −0.53R 變 −3.50R。
但那個 −1R 上限是假的(見上面「跳空照實」那段)。 原本的否決理由建立在同一個假象上,所以掃描30 重跑 (盤中低點美化/盤中低點照實/收盤,365 窗口,釘窗口沿用掃描20/25/26/27)。
第一組已對上掃描27(605筆 每筆 1.511 最差 −2.46R),其餘進行中。
幣圈與台股不同的地方要記著:幣圈開 5x 槓桿 (使用者:「原本 5x 要少 100% 是 20% 跌幅」),一筆 −7R 的意義跟台股不一樣。 所以即使收盤的期望值更高,也要先看最差單筆與保本失效的幅度,不能照台股的結論直接搬。
標出「只有回測讀」「只有線上讀」「沒人讀」; 再列 trail_update 四個呼叫點的參數對照,以及少傳的那一邊實際吃到什麼值。 已知盲點:shadow_bot.py 同時是共用函式庫和幣圈線上掃描, 所以 [參數] 區段兩欄一定都是「是」—— 那一欄的空白不代表沒問題。
回測.py(幣圈)2026-10-06 補過「窗口結束仍未平倉的單」, 股票回測.py 從來沒補,整支 grep 不到「未平倉」。 持倉越長丟掉越多,而底艙平均持倉是全進全出的三倍。本輪照同一套補上 (寫進 CSV、預設不計入統計,所以既有數字逐位元不變)。
| 截止日 | 現況每筆R | 底艙每筆R | 倍數 | 底艙未平倉 | 對照組未平倉 |
|---|---|---|---|---|---|
| 不切 | 1.374 (45) | 4.073 (39) | 2.96x | 2筆 +1.7R | 2筆 +1.7R |
| 2026-07-01 | 1.374 (45) | 2.831 (36) | 2.06x | 3筆 +73.1R | 0筆 |
| 2026-04-01 | 1.430 (41) | 2.542 (32) | 1.78x | 4筆 +25.3R | 1筆 −0.8R |
倍數單調下降看起來像偏差,但底艙的未平倉單正好是還在趨勢上的贏家。 含未實現重算是 2.90x / 3.27x / 2.15x,沒有單調下降。 真實區間夾在 1.78x(全排除)到 3.27x(含未實現)之間。
(出0%口徑,2R 是五個值裡的內部峰頂,不是格子邊界)
| 設定(不切 / 04-01) | 每筆R | 勝率% | 回撤 |
|---|---|---|---|
| 現況 全進全出 | 1.374 / 1.430 | 64.4 / 63.4 | 3.6 |
| 啟動2R 出0% | 8.574 / 5.146 | 56.4 / 48.4 | 6.9 |
| 啟動2R 出15% | 7.448 / 4.516 | 66.7 / 61.3 | 5.8 |
| 啟動2R 出30% | 6.322 / 3.885 | 71.8 / 67.7 | 5.3 |
部分停利對 R 數的貢獻是負的(賣掉的那塊不能再跟趨勢走), 它買到的是勝率與回撤。所以 底艙出場比例 是偏好旋鈕,不是最佳化目標。
理由:使用者明確要「底艙」這個形狀(先落袋一部分、剩下續抱), 而且這一格同時贏過現況的每筆R(4.6倍)與勝率(71.8% vs 64.4%)。 代價是回撤 3.6 → 5.3R。要更大的 R 把比例調小,要更穩就調大。
線上同步:股票模式.py 原本 0 處,本輪補上,狀態存進 positions_tw.json 的 底艙已出/底艙已實現R/底艙剩餘/底艙停損。 注意小時線只抓 60 天而底艙可能抱 100 天以上,靠狀態逐輪累進 —— 股票模式.py 要持續跑,停跑超過 60 天會漏 K 棒。
先做雙層停損(結構線收盤判定 + 災難硬單封上限)。測出來災難R=1.3 (上限應該 −1.3R)跑出 −2.31R。追下去不是雙層停損寫錯,是更底層的假設:
盤中低點 模式的成交價寫死 cur_stop,等於假設跳空也填得到停損價。
這是土狗那次的同一個教訓(「停損價成交是假的,舊正結果全虛胖」), 只是這次出現在台股,而且我前一天還拿那個 −1.00R 當「R 風控成立」的證據。
| 標的 | 出場時間 | 判定 | 美化R | 照實R |
|---|---|---|---|---|
| 2317 | 2025-07-02 09:00 | 跨日跳空 | −1.00 | −1.14 |
| 6669 | 2025-12-15 09:00 | 跨日跳空 | −1.00 | −1.18 |
| 6669 | 2026-01-09 09:00 | 跨日跳空 | −1.00 | −1.83 |
| 2330 | 2026-06-08 09:00 | 跨日跳空 | −1.00 | −2.31 |
零筆落在盤中時段,所以不是模型太悲觀,就是事實。
| 窗口 | 設定 | 每筆R | 最差單筆 | 穿破−1R |
|---|---|---|---|---|
| 全期 | 盤中低點 美化(原基準) | 1.316 | −1.00 | 0 |
| 全期 | 盤中低點 照實 | 1.261 | −2.31 | 4 |
| 全期 | 收盤 | 1.374 | −2.05 | 14 |
| 近365 | 盤中低點 照實 | 1.353 | −2.31 | 3 |
| 近365 | 收盤 | 1.657 | −2.05 | 7 |
收盤兩個軸都贏:期望值更高,而且最差單筆還比較好。 機制很直接 —— 收盤模式成交在收盤價,它不需要「填得到停損價」這個假設; 盤中低點才是需要假設的那一邊。
所以我當天早上「退回盤中低點」的決定是錯的,當天下午改回收盤。 那個錯誤的根源是:拿一個被美化的指標(−1.00R 上限)當作論證的前提。
| 設定 | 全期 | 近365 | 最差單筆 |
|---|---|---|---|
| 收盤 | 1.374 | 1.657 | −2.05 |
| 收盤+災難1.5R | 1.366 | 1.638 | −2.31 |
| 收盤+災難1.3R | 1.374 | 1.640 | −2.31 |
真正的虧損來自跨日跳空,掛單封不住跳空,反而把「跳空下去又拉回來、 原本撐過去」的單變成「在跳空最低點被掃掉」。 程式保留(災難停損R 預設 0)。
全期 0.898 → 0.862(只影響 1 筆)、近365 完全不受影響。
套用 [台股] 停損判定 = 收盤 兩天後才發現: 股票模式.py 整支檔案 grep 不到「停損判定」四個字。 那個設定只對回測生效,台股線上一直跑舊行為。 不是「代價沒評估」,是「這個設定在線上是空的」。
同一形狀的洞之前已經抓到四個(突兀量倍數寫死、池大小 150 vs 40、 sys.argv 被吃掉、併根跨日),每次都靠手動翻程式碼。所以做成 線上對照.py。
| 參數 | 設定.ini 寫 | 台股實際吃到 | 性質 |
|---|---|---|---|
| 停損判定 | [台股] 收盤 | 盤中低點 | 回測有、線上沒讀 |
| 保本門檻R | [參數] 4.0 | 2.5 | 兩邊都沒傳 → 吃函式預設 |
| 芭樂價R | [參數] 12 | 0 | 股票完全沒有部分停利 |
第二列最毒:設定.ini 看起來三個市場都 4.0R 保本,實際上股票是 2.5R, 而這個差異沒有任何人決定過 —— 是少傳一個具名參數造成的。 之前每一次台股回測都是 2.5R,而我一直以為是 4.0。
加碼在 股票模式.py(線上)有 17 處,股票回測.py 是 0 處。 整支股票回測沒有任何加碼程式碼,而 [台股] 最多加碼次數 = 2。 所以台美股的每一個回測數字描述的策略,都不是線上在跑的那個。
不是理論分歧,已經發生過 —— 交易紀錄_美股.csv: ILMN 加碼次數 1 加碼時R 2.69 出場 觸及保本停損 R數 0.00
連帶更正我 2026-10-18 的一個錯誤結論:當時把「最多加碼次數」列為死參數, 解釋成「它沒有生效路徑」。真正原因是回測沒有這段程式。 推參數看結果沒變,只能證明「在回測裡是死的」,不能推論「在線上是死的」。
處理:[台股]/[美股] 最多加碼次數 = 0,讓線上對齊已驗證的模型。 依據使用者 2026-10-16「加碼限量這個可以先不考慮,先把本單做好」。 要恢復的條件是先在 股票回測.py 實作加碼並驗過。幣圈不受影響(兩邊都有)。
保本門檻R/保本緩衝R/停損判定 接上 股票模式.py 與 股票回測.py, 停損判定 也接上 shadow_bot.py(幣圈線上,拆地雷用)。 設定.ini 先寫成「現在實際在跑的值」,所以接線後逐位元相同(已驗)。
使用者:「改不改應該都沒辦法用台股的模式去複製美股。所以先把台股/幣圈 一個一個處理好了,這樣不會到處都洞。先把同樣模式可套用的兩個市場做到好」
池深度是第六個否定(也是最乾淨的一個):
| 美股池大小 | 筆數 | 每筆R 全期 | 每筆R 近365 | 勝率% | 最佳R |
|---|---|---|---|---|---|
| 40 | 17 | 0.898 | 0.624 | 52.9 | 5.7 |
| 80 | 29 | 0.391 | 0.311 | 41.4 | 5.7 |
| 120 | 40 | 0.230 | −0.071 | 35.0 | 5.7 |
| 150 | 52 | 0.004 | −0.303 | 28.8 | 5.7 |
最佳R 不管挖多深都釘在 5.7,所以深層標的加進來的是輸家不是大贏家。 而 [美股] 池大小 = 150 正是線上在用的深度 —— 回測說那個深度每筆 R 趨近 0、 近 365 天是負的,而回測從來只測 40。
結論:美股單少不是設定錯,是這套方法在那個市場的真實產出。 台股成交金額排名會自然浮出高波動中型股(金像電、玉晶光、景碩、創意、 國巨、大立光),美股排名到 150 名還是 JPM、PG 這類權值股。 要在美股拿到台股的量,得換選股條件(成交金額÷市值、或 ATR%),那是另一條線。
使用者的對照設計很好:「以美股的 TSM 去做整理,台股台積電抓得到, 看看美股台積電卡在什麼判定」—— 同一家公司、兩個市場, 差異就一定在設定或資料,不在標的本身。
| 關卡 | 台股 2330 | 美股 TSM |
|---|---|---|
| 日線均線交叉(12根) | 不存在 | 擋 38.6% |
| 小時區未多排 | 60.8%(1H) | 70.5%(2H) |
| 乖離過大 | 51.0% | 75.9% |
| 找不到突兀量 | 29.7% | 73.1% |
| 停損距離在雜訊裡 | 69.9% | 85.7% |
| 最後成交 | 4筆 +1.112 | 1筆 −1.000 |
| 標的 | 找得到突兀量 | 量倍數90分位 | 99分位 |
|---|---|---|---|
| 2330 台股 | 40.9% | 1.94 | 4.33 |
| 2454 台股 | 35.7% | 2.01 | 4.56 |
| TSM 美股2H | 34.0% | 1.97 | 4.23 |
| NVDA 美股2H | 24.2% | 1.96 | 3.35 |
90 分位四個幾乎一樣,但美股的尾巴比較短—— 美股成交量天天都大,很少出現「相對近期特別突出」的那一根。
| 嘗試 | 全期 | 近365天 | 判定 |
|---|---|---|---|
| 突兀量倍數 2.5→1.8 | 0.898→1.641 | 0.624→0.083 | 樣本內好、樣本外崩,過擬合 |
| 突兀量倍數 2.5→2.0 | →1.047 | →0.160 | 同上 |
| 關掉日線結構(跟台股對齊) | →0.699 | →0.526 | 兩窗口都差 |
| 關突兀量+停損掛束下緣 | →0.892 | →−0.074 | 勝率 50%→30% |
| 關突兀量+停損掛近30根低點 | →0.995 | →−0.723 | 同上 |
| 關突兀量+束下緣+底艙 | →1.854 | →−0.055 | 全期最佳單 37.6R,樣本外仍負 |
結論:突兀量在美股是「稀少但有效」,不是「無效」。 拿掉它,進場只剩均線,勝率直接掉 20 個百分點。 美股單少(17筆/兩年)是這套方法在那個市場的真實產出,不是設定錯誤。
突兀量倍數、需要突兀量、停損錨點(突兀量/束下緣/近期低點)、 停損錨點回看根數、底艙啟動R/底艙出場比例/底艙停損均線(可填束下緣/束中線/束上緣)、 目標價測幅用大時區、ATR下限不得超過結構停損、停損掛大時區均線、停損判定。
做這支的理由是使用者的批評:「我之前說過為什麼兩邊策略一樣、一直另一邊沒有單可以開, 都回覆我沒問題」。「沒單」不是答案,是待查的現象。 第一次跑就發現 12 個參數值不同、20 個只有台美股有(含 停損距離下限atr倍數=1.5,幣圈沒有)。
報告實際數值 vs 門檻。第一版用日線近似算停損,高估 3~7 倍, 害我誤判「停損上限 12% 是主因」(其實那是死參數)。近似值不能拿來下定性結論。
使用者:「趨勢對的標的,我們至少底艙也跟著一起上去」 「該出場還是要出場。挑對時機進場,確認趨勢走向,大時區不要被甩出去」
台美股原本是全進全出(股票回測.py 裡「芭樂」出現 0 次,幣圈有部分停利), 所以只能在「早出場 R 小」和「晚出場回撤大」之間二選一。
第一版沒用:只把底艙停損掛上大時區均線,但出場仍由 trail_update 的小時區規則決定 —— 持倉時間 445 小時一秒沒變。 第二版:底艙啟動後脫離小時區規則,只看大時區均線(只升不降)。
| 台股 全期 | 筆數 | 總R | 每筆R | 回撤 | 最佳R | 5R+ | 持倉時 |
|---|---|---|---|---|---|---|---|
| 現況(全進全出) | 45 | 61.8 | 1.374 | 3.6 | 9.6 | 6 | 445 |
| 底艙 3R出50% 束下緣 | 39 | 158.8 | 4.073 | 4.4 | 31.4 | 15 | 1372 |
| 底艙 2R出50% 束下緣 | 39 | 188.0 | 4.822 | 4.9 | 30.9 | 20 | 1684 |
近365天同向(1.657 → 4.502)。R 記帳逐筆驗過:3037 純R 59.82 → 0.5×3 + 0.5×59.82 = 31.41,跟記錄吻合,沒有重複計算;未平倉 0 筆。
使用者:「我看的都是三條均線的整體呈現圖形,不是單一條」。 實測 束下緣 ≡ 單條MA40,數字完全一樣(4.073、31.4、1372)—— MA40 之所以看起來好,只是因為多頭排列時它剛好就是三條裡最低的。 梯度也合理:束上緣 1.773 → 束中線 2.812 → 束下緣 4.073, 越要求「整體形狀壞掉」才出場,底艙跟得越久。 用束就沒有「挑哪條」的過擬合風險。
還沒解決:最晚出場 2026-07-17,持倉動輒 1372~1684 小時(約兩個月), 所以近三個月的單還開著沒結算,數字偏向「已經走完的趨勢」。 要用更早的截止日重跑才知道這個倖存者偏差有多大。
停損觸發原本是 if b["l"] <= cur_stop —— 盤中最低點,下影線插針就出場。 使用者:「貼著均線很容易像之前被插針一下碰到均線就出去」。
代價有多大:幣圈730 硬停損 880 筆(74.4%),出場之後 沒再漲 15% / 0~1R 15% / 1~3R 28% / 3~6R 21% / 6R以上 21%,平均還能再走 3.93R。 賺錢的 519 筆裡 12% 曾經回到 −0.8R。
台股雙窗口都好而且筆數完全相同=純出場改動: 全期 45筆 1.316→1.374、硬停損 37.8%→33.3%; 近365 24筆 1.449→1.657、硬停損 37.5%→29.2%、回撤 3.0→2.3。
美股不套:全期 0.898→0.884(略差)、近365 0.624→0.748(較好),方向不一致, 而且筆數變了(17→16)=不是乾淨樣本。
實作放在 trail_update(幣圈回測/線上、股票回測/線上四支共用), 改一處四邊同步。收盤模式的成交價用收盤價不是停損價—— 那模式等於不掛硬停損單,快速崩跌會穿過去(土狗那次的教訓)。
三個市場三個窗口,按進場乖離分組全部同向單調:
| 進場乖離% | 幣圈730(1183筆) | 幣圈365(605筆) | 台股(60筆) |
|---|---|---|---|
| 0~2% | 1.523 | 2.331 | 5.225 |
| 2~4% | 1.262 | 1.264 | 1.564 |
| 4~6% | 1.129 | 1.434 | 1.473 |
| 6~9% | 0.460 | 0.739 | 1.062 |
單一變因掃描,兩市場兩窗口四格全部同向: 台股 全期 1.244→1.564、近365 0.842→1.360; 美股 全期 0.670→0.898、近365 0.121→0.624。每筆升、回撤降、硬停損降。
機制:乖離大 → 停損必須放遠 → R 被壓扁。幣圈730 實測 乖離 −9~2%:停損距離 2.15%、每筆R 1.576;乖離 6~9%:停損距離 4.45%、每筆R 0.460。 R = 價格走幅 ÷ 停損距離,所以「貼著均線進場」是讓分母變小。
最賺的單也是貼著均線出來的:LAB 74.1R(乖離1.66%)、SOON 60.8R(0.88%)、 ETH 57.6R(0.20%)。10R+ 比例:乖離 0~2% 是 4.9%,6~9% 只有 2.6%。
回測與線上都是卡在 乖離警戒(回測.py:995、股票回測.py:368、 shadow_bot.py:2849、股票模式.py:908 四處都是 if dev > dev_warn: continue)。 幣圈實際成交單最大乖離正好 7.00%、超過的 0 筆。掃描26 把上限 18→12→9→6 調四次,四組數字完全一樣。
我一度宣稱「線上會做回測沒模擬過的單」——那是錯的,我只看了 股票模式.py 的第一道檢查就下結論,下面還有第二道 dev > dev_warn 也會 continue。
同一組設定、同一天跑兩次,美股結果不一樣:
| 時間 | 結果 |
|---|---|
| 14:51 | 23筆 每筆 +0.710 回撤 3.0R |
| 22:59 | 21筆 每筆 +0.549 回撤 5.2R |
台股同一組兩次完全相同(63筆 +1.450)。差別在於這兩次之間美股開盤了: yahoo_chart(sym,"60d",...) 的視窗會滑動,新 K 棒進來、最舊的掉出去,候選母體跟著變。
影響:
股票回測沒有。下一輪要補,否則任何股票結論都會被資料視窗滑動污染。
使用者自己從圖上算的大/小時區比例是 1:3~1:4: 台股 1H:1日 ≈ 1:4.5(一天約 4.5 小時)符合;美股 1H:1日 ≈ 1:6.5 太寬。 使用者原話:「照美股我剛看完應該是 2h:1日 可以達到1:3」。
| 筆數 | 勝率 | 每筆R | 硬停損 | 回撤 | |
|---|---|---|---|---|---|
| 1H(原本) | 20 | 25.0% | −0.178 | 75.0% | 9.2R |
| 2H | 23 | 47.8% | +0.710 | 52.2% | 4.2R |
1H 是虧的、2H 是賺的。 套用理由是三件事疊起來,不是單看回測數字: (1) 使用者自己算出來的結構理由;(2) 原設定是虧錢的,留著比換掉更糟; (3) 出場會自動跟著變慢(trail_update 吃的就是進場那個序列), 而使用者說「台美股抱單時間長這點是很能接受的」—— 硬停損 75%→52% 正是這個效果。
n=20 vs 23,統計上分不出高低,這點寫進設定檔註解了。
幣圈那個改動拿到台美股,兩邊都變差。這組測試是在三處不同步都修好的正確基準上跑的 (先前測過一次沒效,但那是用壞掉的否決方式跑的,基準不一樣,所以重測)。
| 市場 | 現況 | 加允許橫向 |
|---|---|---|
| 台股 | 63筆 每筆 +1.450 回撤 4.1R | 65筆 +1.382 回撤 5.1R |
| 美股 2H | 21筆 每筆 +0.549 回撤 5.2R | 22筆 +0.479 回撤 6.2R |
差集(共同進場 0 筆數字不同,樣本乾淨):
機制(漏斗說得很清楚):放寬確實有效,但下一關全部接收了。 台股「1H未多排」擋掉率 60.5% → 40.1%(多過 9,563 根), 緊接著「型態不明確」26.3% → 48.1%(多擋 8,612 根),淨增只有 2 筆。
而且多做的那幾筆進場乖離明顯偏高(台股 4.55%/7.04%/8.04%,其中 3 筆直接觸及停損)。 原因想得通:均線糾結時 MA 擠成一束,突破棒一拉開就離均線很遠 —— 在股票上等於在追高。幣圈波動大、乖離上限相對寬鬆,所以同一道放寬換到的是不同的東西。
幣圈多做 88 筆每筆 +2.446;台股多做 4 筆是虧的。 這不是「結論套不到股票」, 是股票的瓶頸根本不在那一關(台股前三大是乖離 73.9%、停損距離在雜訊裡 73.6%、風報比 81.8%)。
→ [參數] 小時區允許橫向 = 是(幣圈)、[台股]/[美股] 都明寫 = 否。 行為上預設本來就是否,寫進去是為了把陰性結果留在使用的地方,免得下一輪盲目重試。
使用者原話:「大時區發散,可能小時區是橫向區間而已」、 「小時區應該要能接受橫向,因為一定有盤整均線糾結建立支撐的過程」。
原本進場硬性要求 ma_bull(進場時框) —— 小時區必須已經折回多頭排列。 改成「已翻多 或 均線張開幅度還低於這檔自己歷史的 35 分位(還在橫)」。 門檻用分位數不寫死(不同幣波動差很大)。
| 365天 | 730天 | |
|---|---|---|
| 現況 | 585筆 每筆 1.324 回撤 17.7 | 1128筆 每筆 1.041 回撤 33.0 |
| 允許橫向 | 600筆 每筆 1.520 回撤 17.2 | 1178筆 每筆 1.169 回撤 32.6 |
| 最佳單 | 60.8 → 74.1 | 60.8 → 74.1 |
| 大單數 | 39 → 43 | 58 → 65 |
差集法(共同進場兩側數字完全相同=純進場改動,樣本乾淨):
| 365天 | 730天 | |
|---|---|---|
| 共同進場 | 517筆 +1.352 | 981筆 +1.083 |
| 被擠掉的 | 68筆 +1.045 | 152筆 +0.742 |
| 多做的 | 88筆 +2.446(大單率 10.2%) | 202筆 +1.565(大單率 6.9%) |
多做的那批含全場最佳單 74.1R —— 現況根本做不到的一筆。 脆弱度:抽掉最賺三筆後 365 +1.199 vs 現況 +1.057;730 +1.005 vs 現況 +0.903。
統計顯著性還是拿不到(要約 2.5 萬筆)。套用的依據是 兩窗口、差集、脆弱度、回撤、大單數、最佳單全部同向 —— 這是這個系統能給出的最強證據。
為什麼不是改大時區:同一批裡「大時區發散」那兩組兩個窗口都比現況差 (730:0.984/1.029 vs 現況 1.038)。六組「把糾結換成發散」的設定全部輸 (0.877~1.198 vs 現況 1.324)。瓶頸在小時區,不在大時區;需要大時區收縮 是承重的。
台股 池40、兩年多:63筆 勝率 57.1% 總R +91.4 每筆 +1.450 硬停損 42.9% 回撤 4.1R
| 關卡 | 到達 | 擋掉 | 擋掉率 |
|---|---|---|---|
| 3日線空頭 | 63804 | 7579 | 11.9% |
| 日線空頭 | 56225 | 7504 | 13.3% |
| 日線base回檔 | 48721 | 1805 | 3.7% |
| 1H未多排 | 46916 | 28362 | 60.5% |
| 型態不明確 | 18554 | 4888 | 26.3% |
| 首段回檔過深 | 13666 | 1517 | 11.1% |
| 位階0/不明確 | 12149 | 3630 | 29.9% |
| 乖離過大 | 8519 | 6296 | 73.9% |
| 找不到突兀量 | 2223 | 796 | 35.8% |
| 停損距離太遠 | 1427 | 33 | 2.3% |
| 停損距離在雜訊裡 | 1394 | 1026 | 73.6% |
| 風報比不足 | 368 | 301 | 81.8% |
瓶頸在後段三關(乖離、停損距離在雜訊裡、風報比),不是日線結構那幾關。 這跟幣圈不一樣,是下一輪該查的方向。
使用者說「現在的實測非常差」。有相當一部分不是策略差,是回測在騙人。
| 處 | 寫死了什麼 | 設定.ini 實際是 | 修完台股 |
|---|---|---|---|
| 股票回測.py | 日線結構=True | [台股] 需要日線結構檢查 = 否 | 23筆 +1.011 → 45筆 +1.705 |
| 股票回測.py:99 | 大時區否決="排列"、日線否決="排列" | [台股] = 排列+斜率 | 45筆 → 63筆 +1.450 |
| 股票模式.py | yahoo_chart(sym,"60d","60m")、畫面印死「進場時框 60M」 | (當時還沒有這個設定) | 見下一節 |
第三處是預防性的:套用 [美股] 進場時框 = 2H 之前先補好線上, 否則就會變成「回測跑 2H、線上跑 1H」—— 正是前兩處的同一種錯。
這類 bug 的共同形狀:設定檔說一套、程式做另一套,而且不會報錯。 所以今天又加了第四道防線:股票模式.py 讀到「小時區允許橫向 = 是」會 raise SystemExit 直接擋下(線上沒實作這個功能),寧可開不起來也不要默默不一致。
漏斗前後錯三次,三次原因都不同,記下來免得再犯:
1. 第一版:按「擋掉次數」由大到小排。關卡是串聯的,前面的關分母大幾十倍, 次數不能跨關比。害我把 4H 空頭否決當成技術面第三大關(實際只擋 12.4%)。 2. 第二版:改成記「每道關第一次被觸發的順序」當評估順序。 但不同標的會先撞到不同的關,順序被打亂了 —— 程式裡第 2、3 道的「日線空頭/日線base回檔」被排到第 10、11 位, 分母用錯,算出 89.6%/94.2% 這種假的高擋掉率。 3. 第三版(正確):不推測。順序直接抄程式碼裡的關卡位置成一份明確清單, 清單旁邊註明「改動關卡順序時要同步這份清單」,另外印出不在清單裡的關卡當自我檢查。 另有一個小 bug:擋("(放行)...") 把放行當成擋掉在扣,算出負的到達數(−8815)。
翻掉的歸因:日線base回檔的真實擋掉率是 3.7%,不是 94.2%; 日線空頭 13.3%,不是 89.6%。我先前說「日線關卡是股票的瓶頸」是錯的。
另外:第二版我用字串切片換掉列印段,順手把「寫 CSV + 算統計 + 印摘要」整段吃掉 (NameError: name 'out' is not defined)。之後改成只插入、不切片,並加斷言。
回測.py 和 股票回測.py 的最大回撤、連敗,都是直接照 已平倉 串列的順序累加的。 但那個串列是一檔一檔跑出來的 —— 1000BONK 全跑完、再 1000FLOKI、再 1000PEPE。 所以算出來的是「照字母順序把每檔做完」的累積回落,不是資金曲線,沒有風險管理意義。
修法(兩個檔案都改):先按出場時間排序,再累加。
``python _依時 = sorted(已平倉, key=lambda t: (t.get("出場時間") or t.get("進場時間") or "")) Rs時 = [float(t["R數"]) for t in _依時] ``
被翻掉的結論(我自己先前講錯的,列出來):
| 我當時說的 | 正確數字 |
|---|---|
| 三時框收箱型 回撤 14.9→10.9,總R÷回撤 51.4→76.3 | 總R÷回撤 26.6(比現況差) |
| 加碼限量 回撤降 27% | 19.0 vs 17.7(變差) |
| 中MA60改2H 回撤 13.2 | 18.9 |
| 以等風險換算的整段倉位計算 | 全部作廢,重算 |
教訓跟漏斗那次一樣:量測工具自己要先驗過。這是 2026-10-08~09 兩天內 第二個自己製造的量測 bug(第一個是漏斗排序),而兩次都讓我對著假數字推理了好幾小時。
加碼限量 與 加碼限量+次數上限4 的 365 天結果逐筆完全相同 (540 筆、雜湊 6b2246e4b50c6195)。把次數上限從 2 放到 4 一點影響都沒有。
加碼次數分布解釋了原因:
| 0 次 | 1 次 | 2 次 | |
|---|---|---|---|
| 現況(調停損) | 334 | 250 | 1 |
| 加碼限量 | 377 | 163 | 0 |
限量 模式下連第二次加碼都加不出來,所以次數上限是 2 還是 4 完全無關。 而現況模式下第二次加碼也只發生 1 次。
所以要更正掃描10 的歸因:我當時寫「最多加碼次數 = 2 不是隨便訂的保護, 它是承重的」。實際上次數上限本身幾乎沒在作用 —— 承重的是 加碼模式 = 調停損 的棘輪,次數上限只是把棘輪限制在兩格。 掃描10 把兩個設定綁在一起改,所以把功勞歸給了錯的那一個。
三組拼起來才完整:
| 加碼模式 | 次數上限 | 結果 |
|---|---|---|
| 調停損 | 2 | 現況:加碼量佔初倉 94%、最佳單 60.8R |
| 調停損 | 無限 | 掃10:棘輪跑掉、硬停損 94%、系統垮 |
| 限量 | 2 或 4(無差別) | 加碼量 3%、最佳單腰斬到 32.8R |
結論不變(現況在加碼這軸是局部最佳),但歸因修正了。
這是今天第八次更正自己的歸因,而模式從頭到尾一樣: 兩個設定綁在一起改 → 把功勞歸給錯的那一個。 所以後面每一輪都堅持單一變因,而且先讀計數器再給解釋。
| 掃描16(365天) | 筆數 | 每筆R | 回撤 | 大單 | 最佳 |
|---|---|---|---|---|---|
| 現況 | 585 | 1.317 | 14.9 | 39 | 60.8 |
| 大時區停損加目標 | 21 | 1.710 | 5.0 | 2 | 18.6 |
| 大時區停損加目標_上限20 | 33 | 0.921 | 6.8 | 1 | 13.8 |
放寬停損距離上限到 20% 只從 21 筆變 33 筆,而且每筆R 從 1.710 掉到 0.921。
跑之前寫下的停止條件觸發:「365 天做不到 100 筆就收掉」。 信賴區間工具算過 21 筆的設定需要約 3005 筆才能跟現況分出高低 —— 幣圈一年產 21 筆,要一百多年。
收掉的理由不是規則差(那 21 筆每筆 1.710R、回撤只有 5.0,品質是高的), 是它產不出足夠樣本來證明自己。使用者的標準是「要確認成果是好的才能實施」, 確認不了就不能實施。
這條線共花四輪(11、12、16、21),我在歸因上猜錯三次: 停損距離上限 → 風報比/目標前高 → 目標測幅。 每次都是「只換一半」,而且每次我都以為這次換完了。
「加法版」—— 現況的收縮檢查照跑,另外放行空排箱型(大時區收縮或形狀)。
| 筆數 | 每筆R | 總R | 回撤 | |
|---|---|---|---|---|
| 現況 | 585 | 1.317 | 770.2 | 14.9 |
| 收縮或箱型 | 606 | 1.318 | 798.6 | 15.7 |
整體看起來毫無變化(每筆R 差 0.001,遠在噪音底線 0.01 內)。但差集不是這樣說的:
| 筆數 | 每筆R | 大單 | |
|---|---|---|---|
| 共同進場(兩側逐筆相同) | 567 | +1.240 | 35 |
| 被擠掉的 | 18 | +3.747 | 4 |
| 多做的 | 39 | +2.455 | 3 |
多做的 39 筆品質很好(含 AR +29.03R、AAVE +22.13R,全是保本後跌破 MA30 出場), 但它們擠掉了 18 筆更好的(+3.747、4 筆大單)。淨效果只剩 +28R,等於白做。
真正的瓶頸不是濾網,是配位。 系統按候選排名先到先佔填那 20 個持倉位, 一筆平庸的早單會卡住後面更好的單。這解釋了今天每一輪的現象:
| 那一輪放寬了什麼 | 多做 | 擠掉 |
|---|---|---|
| 掃13 空頭否決改形狀 | 150 筆 +0.937 | 32 筆 +0.739 |
| 掃17 只收箱型 | 40 筆 +2.396 | 486 筆 +1.212 |
| 掃19 加法版 | 39 筆 +2.455 | 18 筆 +3.747 |
每次放寬濾網,好處都被擠出效應吃掉。
使用者 2026-10-08 早就講過:「不用限制持倉上限,如果是好的東西當然進場不要緊」。 最多同時持倉 2026-09 從 6 調到 20(v9),看來 20 還是不夠。
為什麼調高上限不會偷偷放大風險:每筆風險% = 總風險預算% ÷ 最多筆數, 所以調高上限會自動縮小每筆倉位、總風險預算不變;而 R 是用「每筆自己的風險」 正規化的,所以 R 的數學完全不受倉位大小影響。
掃描23 在驗(2x2:現況/上限40/收縮或箱型/收縮或箱型+上限40), 重點看「被擠掉」那一格有沒有降到接近 0。
把漏斗從「按擋掉次數排序」改成「按評估順序列印,並算出每道關的擋掉率」。 改法:記每道關第一次被觸發的順序,再用「總評估數 − 前面累計擋掉數」反推到達數。
為什麼非改不可:關卡是串聯的。排前面的關分母是「全部候選 × 所有K棒」, 排後面的只剩倖存者,分母差幾十倍。按次數排序會把前面的關看得過重。
改完的真實排名(60天/池25 驗證跑):
| 關卡 | 到達 | 擋掉 | 擋掉率 |
|---|---|---|---|
| 不在當日 T1 名單 | 176840 | 160450 | 90.7% |
| 需要大時區收縮 | 13042 | 7427 | 56.9% |
| 1H 收盤跌破 MA60 | 3877 | 1715 | 44.2% |
| 4H base 品質 | 2162 | 672 | 31.1% |
| 30M 還沒折回多頭 | 5615 | 1738 | 31.0% |
| 4H 空頭排列 | 16390 | 2037 | 12.4% |
| 停損距離上限 | 88 | 12 | 13.6% |
| 風報比 < 2.5 | 1490 | 118 | 7.9% |
翻盤一:4H 空頭否決其實很小。 我 2026-10-08 一整天反覆寫 「4H 空頭否決擋 3855 次/18798 次,是技術面第三大」,還為它做了 空頭否決用形狀、跑了整個掃描13(四組、約 2.5 小時)。 按擋掉率它只有 12.4%,排倒數第三。 那些大數字全是因為它排在 T1 前面。
翻盤二:第二大的關卡我從沒檢查過。 1H 收盤跌破 MA60,擋掉率 44.2%。 語意是「30M 已折回多頭,但 1H 收盤在 MA60 以下就不做」(1H MA60=60 小時記憶)。 使用者 2026-10-08 說「不用太在意時區內的小震盪」—— 這道關可能正是在用 小時區雜訊擋掉大時區還好的單。已做成獨立開關 中時區MA60時框(1H/2H/關), 掃描24 在單獨驗。
教訓:看到一個數字先問「它的分母是什麼」。 舊漏斗沒說分母,我就把次數當成重要性,錯了一整天。
| # | 題目 | 我的推理 | 實際 |
|---|---|---|---|
| 1 | 芭樂價 | 最高R 分布是真的 | 被 12R 全出場截斷 |
| 2 | 加碼用進場規則 | 進場關卡會擋住加碼 | 加碼數反而 5 倍 |
| 3 | 大時區停損 | 停損距離上限是瓶頸 | 放寬後筆數更少;真因是測幅沒換 |
| 4 | 剛發散 | 第一個有鑑別力的進場特徵 | 放大 20 倍塌到 +0.947 |
| 5 | 均線出場 | 30M MA30 把大單提早砍掉 | 吐回只有 22%,是全場最好的出場 |
| 6 | 加碼棘輪 | 是漏水,拆掉會更好 | 是「能加大倉」的對價,拆掉總R 少 129 |
六次都是先給解釋、再驗證,六次都錯。 而每次真正查出真相的方法都是同一個:讀計數器、算分布、做差集。
往後的做法:有計數器就先讀計數器,不要先給解釋。 已過濾樣本裡的任何分組差異,只能當「值得去驗」,不能當結論 (放大測試:放寬濾網後看每筆R 是優雅退化還是崩塌)。
使用者 2026-10-08:「我沒有說過箱型,請問是何出? 我主要做的就是均線發散。箱型只是均線在糾結過程而已,K線上下跳動。 大時區發散,可能小時區是橫向區間而已」
兩個要更正的地方:
1. 空排箱型 是我在 大時區形狀.py 裡取的標籤,機械定義是 「6H 三線空頭排列、但張開幅度沒在往下拉開」。 使用者做的是均線發散(多頭排列、三線往上拉開)—— 正好相反。 所以掃描17 那 40 筆 +2.396R 是數據自己撿到的東西,不是使用者的圖形。 我先前寫「使用者最早的直覺講對了」是錯的,該收回。 (那個發現本身仍然成立、值得另案處理,但不要掛在使用者頭上。)
2. 使用者的設定在原本系統裡結構上做不到,所以一次都沒被測過。 進場硬性要求 ma_bull(s30) —— 30M 必須已經是多頭排列。 「小時區是橫向區間」會被這一關直接擋掉。 所以先前量到的「平行發散 +0.962 / 剛發散 +0.988」不是這個設定的成績: 那是「6H 發散 + 30M 已經翻多」,等於追在後面。
已實作:shadow_bot.ma_sideways_rel() —— 30M 均線張開幅度低於這檔自己歷史的 35 分位就算還在橫 (分位數不寫死,使用者 2026-09 定過的規矩)。 開關 小時區允許橫向:ma_bull(s30) 那一關改成「已翻多 或 還在橫」, 進場時機仍由突兀量與乖離上限把關。掃描20 在驗(四組,含只放寬小時區的分離變因)。
要留意的可能結果:如果關卡計數顯示「靠大時區發散、小時區還在橫」 只被觸發個位數次,代表這個設定在幣圈很罕見 —— 那本身就是答案。
我原本的主張(根據吐回比例拆解): 「加碼後調高停損」10 筆、最高R 平均 14.57 → 入帳 1.32(吐回 90.9%), 其中大單 2 筆最高R 平均 48.91 → 入帳 6.06(吐回 87.6%)。 我說這是漏水、約值 100R,要用 加碼模式 = 限量 修掉。
結果相反:
| 加碼單 | 平均加碼量佔初倉 | 最佳單 | 前5大總R | 總R | 回撤 | |
|---|---|---|---|---|---|---|
| 現況(調停損) | 251 筆 43% | 94% | 60.8 | 221.4 | 770.4 | 14.9 |
| 加碼限量 | 163 筆 30% | 3% | 32.8 | 133.1 | 641.5 | 10.9 |
限量 不是「拆掉棘輪」,是等於關掉加碼。 停損不動時, 在更高價位加倉會讓整筆風險上升,風險公式 整筆最壞 >= floor_R(0) 幾乎不給加 (加碼量 94% → 3%)。所以最賺的單剛好腰斬: SOON 60.8→32.8、ETH 57.6→30.6 —— 少掉的正是那 94% 的加碼部位。
正確結論:「加碼後把停損拉到打平」是「能把倉加大一倍」的對價。 那 10 筆吐回 90.9% 是必要成本,而且划算 —— 光前 5 大單就差 +88R,遠超那 10 筆損失的約 100R 毛額。
掃描10 留下的問題一併結清:最多加碼次數 = 2 承重、 加碼模式 = 調停損 也承重。現況在加碼這個軸上是局部最佳。
沒有套用。 掃描18 的 限量 否決。 掃描22 另測第三條路(加碼後最壞R 從 0 放到 −0.5/−1, 讓停損坐低一點但加碼量不變)—— 標記為參數測試,有機制有預測。
| 停損 | 目標前高 | 目標測幅 | 365天筆數 | |
|---|---|---|---|---|
| 掃描11 | 6H | 4H | 30M | 19 |
| 掃描12(上限放寬20) | 6H | 4H | 30M | 15 |
| 掃描16 | 6H | 6H | 30M | 21 |
| 掃描21 | 6H | 6H | 6H | 在跑 |
掃描16 證明「把目標前高也搬到 6H」只從 19 筆變成 21 筆。 我「兩次各換一半、整組換就會通」的解釋站不住。
診斷(第一次真的去讀計數器而不是推理):
| 關卡 | 現況 | 掃描16 的設定 | 倍數 |
|---|---|---|---|
| 停損距離上限 | 36 | 1157 | 32x |
| 風報比 < 2.5 | 282 | 1021 | 3.6x |
風報比完全沒被修好。原因:目標價 = max(前高, 測幅), 而 6H 前高在上升趨勢中常常低於現價(正在創新高), 這時目標價完全由測幅決定 —— 而測幅還在量 30M 的波段高度 (seg = s30[-80:])。rr = 獲利% / 停損距離%: 分母用 6H 的尺、分子用 30M 的尺,照樣崩。
已修:_測序 = s6 if (三時框 or 目標用大時區) else s30,兩邊同步。
停止條件(寫在跑之前):掃描21 的 365 天做不到 100 筆就收掉這條路 —— 信賴區間工具算出 21 筆的設定需要約 3005 筆才能確認,驗不完就不能實施。
關卡計數器 2026-10-08 早上才加進回測,但掃描腳本為了避開 cp950 編碼問題 把標準輸出整個丟進 os.devnull —— 於是工具做了卻一直沒被讀到。 我因此在「大時區停損」這一題上連續猜錯三次。
已修:掃描21 起,漏斗寫進 漏斗_掃描NN_<天數>_<組名>.log 永久留檔。
順帶更正一個我一直在引用的過期數字。現況的進場漏斗(120天/池40):
| 關卡 | 擋掉次數 |
|---|---|
| (不在當日 T1 名單) | 521035 |
| (K線不足) | 23533 |
| 需要大時區收縮 | 13702 ← 技術面第一 |
| 4H 空頭排列 | 4002 |
| 30M 還沒折回多頭 | 2975 |
| 1H 跌破 MA60 | 2955 |
| 4H base 品質 | 1933 |
| 乖離警戒(>7%) | 879 |
| 型態不明確 | 625 |
| 風報比 < 2.5 | 282 |
| 停損距離上限 | 36 |
我在前面幾段寫「4H 空頭否決擋 3855 次是技術面第三大」—— 那是舊排名。 真正第一大的是 需要大時區收縮(13702 次),是 4H 那道的 3.4 倍。 系統最主要的進場約束一直是「6H 還在收縮」,不是空頭否決。
起因:使用者「單少不要緊,拿到台美股去做就好……不過要確認成果是好的才能實施」。
新寫 實驗腳本/信賴區間.py:bootstrap 10000 次(seed 固定可重現)+ 抽掉最賺 1/3 筆的脆弱度 + 估「要多少筆才能跟現況分出高低」。
| 組 | 筆數 | 每筆R | 90%信賴區間 | 抽掉最賺3筆 | 要分高低需幾筆 |
|---|---|---|---|---|---|
| 只收箱型 | 139 | +1.992 | +1.095 ~ +3.034 | +1.139 | 約 1444 筆 |
| 現況 | 585 | +1.317 | +0.940 ~ +1.736 | +1.057 | — |
| 大時區停損加目標 | 21 | +1.710 | +0.100 ~ +3.600 | +0.089 | 約 3005 筆 |
兩個結論: 1. 365 天的幣圈分不出任何一組的高低 —— 所有信賴區間互相重疊。 2. 低筆數的設定不可能驗完:139 筆/年要湊 1444 筆=十年;21 筆/年=一百多年。
而且我得更正自己一直在用的紀律:我把「四窗口穩健」當把關標準, 但 365 與 730 是重疊的(730 包含 365),它們不是兩個獨立確認, 是同一批資料看兩次。使用者說的換市場(台股/美股)才是真正獨立的確認 —— 不同標的、不同時期、不同參與者。這一點使用者的直覺比我的紀律對。
可用的替代門檻:既然拿不到統計顯著,就改用脆弱度 —— 抽掉最賺三筆之後還贏不贏現況。只收箱型過(1.139 vs 1.057), 大時區停損不過(0.089 vs 1.057,完全靠 2~3 筆撐)。 這擋不掉運氣,但至少擋掉「靠少數幾筆撐起來」的假象。
設計:其餘全部不動,只把 需要大時區收縮 那一關換成形狀白名單 (大時區收縮改形狀 + 大時區可接受形狀)。單一變因。
| 大時區那一關換成什麼 | 筆數 | 每筆R | 回撤 | 大單率 | 硬停損 |
|---|---|---|---|---|---|
| 只收箱型(掃17) | 139 | +1.992 | 8.8 | 7.2% | 68.3% |
| 現況(要糾結) | 585 | +1.317 | 14.9 | 6.7% | 72.8% |
| 收縮改剛發散(掃15) | 341 | +0.877 | 18.6 | 5.3% | 76.8% |
跨批可比的依據:掃15/16/17/19/20 的「現況」逐筆雜湊完全相同 (8815438d3b3598c2,585 筆)—— 這是釘候選母體換來的。
只收箱型的差集:
| 筆數 | 每筆R | |
|---|---|---|
| 共同進場(兩側完全相同) | 99 | +1.829 |
| 只有現況做到(被擋掉) | 486 | +1.212 |
| 只有箱型組做到 | 40 | +2.396 |
那 40 筆是全場最高的每筆R。但等風險比較下現況還是贏 (都縮放到回撤 14.9:現況 770.2R vs 只收箱型 468.8R)。
結論:「只收箱型」挑得準但挑太少,不採用。正確做法是加法(掃描19)。 「只做剛發散」整組否決 —— 兩個獨立批次一致(掃15 341筆/0.877、掃14 345筆/0.922)。
第三組(三時框 + 收空排箱型)的 365 天:
| 筆數 | 每筆R | 總R | 回撤 | 總R÷回撤 | 大單 | |
|---|---|---|---|---|---|---|
| 現況 | 587 | 1.306 | 766.6 | 14.9 | 51.4 | 38 |
| 三時框 | 520 | 0.971 | 504.8 | 17.0 | 29.7 | 28 |
| 三時框收箱型 | 735 | 1.132 | 832.2 | 10.9 | 76.3 | 41 |
差集(收箱型 vs 三時框,其餘完全相同=單獨看箱型的貢獻):
| 筆數 | 每筆R | 大單率 | |
|---|---|---|---|
| 加收箱型後多出來的 | 227 | +1.494 | 6.2% |
| 加收箱型後反而少做的 | 12 | +0.983 | 8.3% |
那 227 筆 +1.494R —— 比現況基準 +1.306 高,也比被三時框擋掉的那批 +1.367 高。
同一個形狀在兩組設定下的表現(這一段是重點):
| 6H 形狀 | 現況 | 三時框收箱型 | 放大 | 判定 |
|---|---|---|---|---|
| 空排箱型 | 114 筆 +2.017(大單率 8.8%) | 226 筆 +1.505(6.2%) | 2x | 優雅退化 |
| 剛發散 | 16 筆 +1.809(12.5%) | 325 筆 +0.947(5.2%) | 20x | 直接塌掉 |
| 平行發散 | 75 筆 +0.865(4.0%) | 184 筆 +1.001(5.4%) | 2.5x | 本來就平庸 |
「放大時撐不撐得住」就是真訊號與樣本假象的分界線。 剛發散那 16 筆是被其餘 21 道關卡挑出來的,放大 20 倍就沒了。 箱型放大 2 倍還有 +1.505,而且在「現況」這一組裡它本來就已經是最賺的格子。 這個判準比「樣本內哪一格數字漂亮」可靠得多,以後驗任何進場特徵都該這樣看。
空排箱型是什麼:6H 三線仍是空頭排列(短均線在下),但張開幅度沒有在往下拉開 —— 跌完之後橫著整理的箱子。不是真空頭(真空頭全樣本只有 1~2 筆、每筆 −0.445R)。
使用者最早的直覺是對的,後來的規格把它排除了。 原話(2026-10-08): 先說「6h 均線是否空頭、往下均勻發散 —— 變成我們做的均線箱反而[是我們要的]」 後說「大時區我覺得只有兩種圖形能接收:1.糾結後剛發散 2.穩定平行發散」 兩句互相矛盾。我照後面那句實作(可接受 = (剛發散, 平行發散)), 結果把最賺的形狀擋在門外。數據站在前面那一句。
還不能套用:收箱型這一組同時動了四件事(拿掉 4H/日線空頭否決、 base 與目標價前高搬 6H、中時區 1H→2H),箱型的功勞有多少被那些拖掉或撐起來, 分不出來。而且整組對現況的差集仍然是「換進來 +1.132 < 換掉 +1.367」。 掃描17 把「專打箱型」單獨拆出來驗:其餘全部不動, 只把 需要大時區收縮 換成形狀白名單(新設定 大時區可接受形狀,逗號分隔)。
同批三個「現況」的基準漂移(給以後對照用): 掃13 587 筆/1.311(即時母體 A)、掃14 587 筆/1.306(即時母體 B)、 掃16 585 筆/1.317(已釘住的母體 C)。全部落在 ±0.011 噪音底線內。
三時框 = 30M 進場 / 2H 中時區 / 6H 大時區,連帶拿掉 4H 與日線空頭否決、 需要大時區收縮 由形狀分類接手、base 與目標價前高搬到 6H。
365 天差集法:
| 筆數 | 每筆R | 大單率 | |
|---|---|---|---|
| 共同進場(兩側數字相同) | 75 | +0.169 | 1.3% |
| 只有現況做到(被三時框擋掉) | 512 | +1.472 | 7.2% |
| 只有三時框做到 | 445 | +1.106 | 6.1% |
換進來的比換掉的差。 整體 587 筆/1.306 → 520 筆/0.971,回撤 14.9 → 17.0。
門檻本身沒做錯:把 520 筆回推進場當下的 6H 形狀, 100% 落在剛發散或平行發散,零洩漏。
但我前一段的結論被打掉了:
| 6H 形狀 | 掃描10 樣本(31/127 筆) | 三時框實際做出來(336/184 筆) |
|---|---|---|
| 剛發散 | 每筆 +2.141 大單率 12.9% | 每筆 +0.954 大單率 5.4% |
| 平行發散 | 每筆 +1.014 大單率 4.7% | 每筆 +1.001 大單率 5.4% |
我說「6H 形狀是第一個真正分得出大單的進場特徵」—— 這句是錯的。 讓系統真的去做 336 筆剛發散(而非原本的 31 筆),每筆R 從 +2.141 塌到 +0.954。 而且剛發散還略差於平行發散。
原因是我自己在同一天寫進這份檔的那段警告(見「形狀比對」那節): 那 31 筆剛發散之所以賺,是因為它們同時通過了 需要大時區收縮、 4H 空頭否決與其餘 21 道關。形狀不是它們賺錢的原因,其他關卡才是。 我寫了那段警告,然後在 n=31 的格子上又犯同一個錯。 規則:已過濾樣本裡的任何分組差異,一律只能當「值得去驗」,不能當結論。
要守住的分界 —— 精確的結論不是「剛發散沒用」,而是 「剛發散在拿掉其他關卡之後沒用」。三時框一次動了四件事,其中只有 需要大時區收縮 跟剛發散定義上互斥;4H 與日線那兩道空頭否決並不互斥, 是為了「收斂時框」被我一起拿掉的。
還沒試的乾淨測法(掃描15):保留 4H/日線空頭否決、保留 base 與目標價在 4H, 只把 需要大時區收縮 換成「6H 必須剛發散」。那才是單獨測形狀假設。
沒有套用。 730 天還在跑,但 365 已經夠清楚,而且機制講得通。
怎麼發現的:掃描13 與掃描14 的「現況」用同一個 end_ms、同一組設定, 結果不完全一樣 —— 587 筆/每筆 1.311 vs 587 筆/每筆 1.306。
逐筆對照:586 筆連 R 數都一模一樣,只有一筆被換掉:
| 標的 | 進場時間 | R數 | |
|---|---|---|---|
| 掃13 做了 | SUSHIUSDT | 2026-09-05 22:00 | +11.60 |
| 掃14 做了 | COTIUSDT | 2026-09-05 11:00 | +8.87 |
COTI 在 11:00 搶到一個持倉位(最多同時持倉 = 20)把 22:00 的 SUSHI 擠掉。 整個 0.005 每筆R 的差距就是這一次換位。
根因:build_universe() 打的 /fapi/v1/ticker/24hr 是24 小時滾動的即時快照, 前 300 名每分鐘都在變。2026-10-03 加了釘窗口之後,這裡就是剩下唯一的噪音來源。
已修:build_universe(min_vol, pool_size, 快取鍵) —— 按「批次窗口的那一天」(end_ms // 86400000)把快照存檔共用。 同一批、就算跨午夜,候選母體都一樣。順便少打一次幣安(紅線 5)。 沒有引入未來資訊:存的就是原本會拿到的那一份即時快照,只是把它凍結。 只在「看起來抓完整」時才存(跟 cached_klines 同一個原則)。
驗證:同一個快取鍵連呼叫兩次 → 300 檔、0.00s 走快取、兩份完全相同。
兩件要記住的事: 1. 噪音底線量到的 ±0.011 每筆R,現在知道它是什麼了 —— 不是浮點誤差也不是隨機,是「持倉上限把哪一檔擠掉」的離散跳動。 一次換位就值 0.005。所以小於 0.01 每筆R 的差異一律不要解讀。 2. 掃描13/14 這兩批之後重跑不會逐筆相同(它們用的快照已經過去了)。 逐筆可重現從下一批開始。
順帶:最多同時持倉 = 20 會造成擠出效應 —— 掃描13 放寬空頭否決後多開 150 筆,同時擠掉了 32 筆現況做得到的單(每筆 +0.739R)。 評估放寬濾網時,差集的兩邊都要看,不能只看多出來的那一邊。
90 天/池30 的小窗口冒煙測(只為確認不會零筆、不會炸):
| 筆數 | 每筆R | |
|---|---|---|
| 共同進場 | 6 | +0.348 |
| 只有現況做到(被三時框擋掉) | 96 | +1.571 |
| 只有三時框做到(新多的) | 83 | +0.367 |
重疊只有 6 筆。 這是結構性的、不是巧合: 現況 需要大時區收縮 = 是 要求 6H 正在收斂, 三時框要求 剛發散/平行發散 —— 定義上互斥。
所以「三時框比較差」這個講法不成立,它換掉的是整個選股方向。 小窗口(n=83/96)也不能當結論。正式判讀等掃描14 的 365/730 兩窗口。
但這一測有價值:它讓我發現自己漏掉了使用者規格的一半 —— 原話是「2.穩定平行發散(小時區回檔進場)」,括號裡那句是條件不是註解。 查了之後確認小時區回檔已經有現成的實作: 乖離上限百分比 18 / 乖離警戒百分比 7,而且實測進場乖離從沒超過 7%, 等於已經在要求「離 MA30 不遠」。所以不另外加濾網(紅線 7)。
背景:前一段證明了型態/位階/停損來源等進場當下的分類欄位全部沒有鑑別力 (大單率比值 0.8~1.1x)。這一段換成用 大時區形狀.py 的五分類再問一次。
做法:把掃描10 的 730 天 1120 筆,逐筆回推到進場當下的 6H 形狀 (用 分類(kl, end=進場那根),不是用事後的圖)。1120 筆全部算得出來,沒有漏。
| 6H 形狀(進場當下) | 筆數 | 占比 | 每筆R | 總R | 大單率 |
|---|---|---|---|---|---|
| 剛發散 | 31 | 2.8% | +2.141 | +66.4 | 12.9% |
| 平行發散 | 127 | 11.3% | +1.014 | +128.8 | 4.7% |
| 收斂中 | 474 | 42.3% | +0.921 | +436.6 | 5.7% |
| 空排箱型 | 285 | 25.4% | +1.076 | +306.8 | 3.9% |
| 真空頭 | 2 | 0.2% | −0.445 | −0.9 | 0.0% |
| 其他 | 201 | 17.9% | +0.949 | +190.8 | 5.0% |
三件事:
1. 使用者的兩種形狀裡只有第一種站得住。 「糾結後剛發散」每筆 +2.141R、大單率 12.9%,是收斂中的 2.3 倍; 「穩定平行發散」+1.014 只是平均水準。 混在一起測會互相稀釋 —— 所以掃描14 另外開一組 三時框只收剛發散。
2. 系統現在把 42% 的單押在表現低於平均的「收斂中」, 而且是被 需要大時區收縮 = 是 強迫的。這個設定 2026-09-14 上線時 四窗口是贏的,但當時沒有形狀分類、分不出「收斂中」和「剛發散」。
3. 真空頭全樣本只有 2 筆。 坐實了用排列順序判空頭是在誤殺 —— 真正該擋的東西幾乎不存在,被擋掉的 3855 次絕大多數是箱型與走平。
這是倖存者偏差下仍然浮出來的訊號,所以比前面那些 0.8~1.1x 的結果可信: 1120 筆全都通過了同一套 21 道關卡,在這種情況下還能差 2.3 倍, 代表 6H 形狀帶的資訊不在那 21 道關卡裡。 但 n=31 很小,而且仍然只是「通過關卡的樣本內」的比較 —— 要當結論還是得靠掃描14 放寬規則後的差集法。
使用者的話:「6h 均線是否空頭、往下均勻發散 —— 變成我們做的均線箱反而[是我要的]」、 「沒錯,應該是看大時區均線圖形決定空頭」。
先修正我自己講錯的一句:我說過「系統根本不該有 21% 在大時區空排時進場」。 這句是錯的 —— 幣圈沒有 6H 空頭否決,只有日線和 4H 有。 另外「收斂中 46%」也是預期內的,因為 需要大時區收縮 = 是 就是在要求這個。
把 582 筆進場回推到進場當下的 6H 狀態,排列順序=「空排」的有 124 筆,再依形狀細分:
| 空排底下的細分 | 筆數 | 每筆R | 大單率 |
|---|---|---|---|
| 往下均勻發散(真空頭) | 1 | +0.11 | 0% |
| 已張開但走平 | 94 | +1.31 | 8.5% |
| 糾結箱型 | 29 | +4.09 | 10.3% ← 全場最高 |
「空排」124 筆裡真空頭只有 1 筆。 絕大多數是箱型/走平, 而箱型那 29 筆是全場最賺的一群。
而 4H 那道 ma_state(s4) == "bear" 在關卡計數裡擋了 3855 次,技術面第三大。 按同樣比例推,那 3855 次裡絕大多數也不是真空頭。
結論:用排列順序判空頭會把最賺的一群誤殺。改用「形狀」。
已實作: · shadow_bot.ma_bear_expanding() —— 只有「空排且張開幅度正在放大」才算空頭, 箱型與走平回傳 False。 · 大時區形狀.py —— 分類器,回傳 空頭/空排箱型/收斂中/剛發散/平行發散/其他。 門檻全部是這檔自己歷史的分位數,沒有寫死絕對值。 · 開關 空頭否決用形狀(掃描13 在驗)、三時框架構(掃描14 在驗),預設都關。
注意那 29 筆的 n 很小而且同樣有倖存者偏差,所以沒有直接拿它當結論套用; 掃描14 把「收不收空排箱型」做成單獨一組(三時框接受箱型)來驗。
使用者的規格:「最主要是你要能掃出這樣的均線圖形,該設置一個這樣的程式, 然後相近 90% 才考慮進場。」
做法:新寫 圖形比對.py —— 形狀向量() 取進場前 80 根, 切 24 段算 (短中差、價離長、長線斜率) 共 3K 維、各自正規化;相似度() 用 (cosine+1)/2。
結果(730 天 1120 筆):
| 比的是什麼 | 平均相似度 |
|---|---|
| 最賺 40 筆 彼此 | 0.593 |
| 虧損 60 筆 彼此 | 0.598 |
| 跨組(賺 vs 虧) | 0.596 |
三個數字一樣。 大單跟虧單的均線形狀無法區分。
但方法本身有鑑別力:同一套程式量使用者自己挑的 4 張台股圖, 彼此 0.793 vs 隨機抽樣 0.558。
結論:這是倖存者偏差,不是方法失效。 1120 筆全都已經通過 21 道關卡,長相本來就被濾成同一副樣子—— 在被濾過的樣本裡問「哪種形狀賺」,問不出東西。 要驗形狀假設,必須先把濾網放寬、讓系統做到它原本做不到的形狀,才有東西可比。 這直接決定了掃描13/14 的做法:改規則 + 差集法,不是在舊資料上挖。
問題:使用者「開始看如何才能打出大R」。先問最基本的:大單可不可以在進場當下認出來?
先確認集中度(730 天 1117 筆): 90.7% 的總R 來自 5.2% 的單(58 筆)。 所以「提高每筆R」實際上等於 「多抓到那 58 筆、少做其餘 1059 筆」,不是把平均往上推。
把所有進場當下的分類欄位對「是不是大單」做比率:
| 欄位 | 大單率比值(最高組/最低組) |
|---|---|
| 型態(等距發散/擴散回碰/盤整突破/收斂上彎/不明確) | 0.8 ~ 1.1x |
| 位階(0/1/1.5/2) | 0.8 ~ 1.1x |
| 六H狀態 | 0.8 ~ 1.1x |
| 二H發散 | 0.8 ~ 1.1x |
| 停損來源 | 0.8 ~ 1.1x |
全部沒有鑑別力。 只有兩個弱訊號: · 規劃風報比 Q1 大單率 8.6% vs Q4 3.2%(非單調,中間兩組亂) · 進場乖離% 對每筆R 單調:Q1 +1.255 / Q4 +0.563(離均線越近越好)
結論:現有欄位挑不出大單。要往「圖形」走。
使用者的構想:「接下來要克服大時區如何定停損點」。 小時區停損太近,常在糾結處被洗掉;大時區(6H)的結構低點應該撐得住。
掃描11(停損改抓 6H 最近 6 根的結構低):
| 筆數 | 每筆R | 回撤 | 大單 | |
|---|---|---|---|---|
| 現況 | 579 | 1.351 | 14.8 | 40 |
| 大時區停損6根 | 19 | 1.289 | 6.0 | 1 |
579 → 19 筆。我當時歸因於「停損距離上限」把寬停損擋掉,於是掃描12 把上限從 10% 放寬到 20%。
掃描12 的結果把我的歸因打掉:
| 筆數 | 每筆R | 回撤 | |
|---|---|---|---|
| 現況(上限10) | 580 | 1.350 | 14.8 |
| 只放上限到20 | 587 | 1.335 | 14.8 |
| 大時區10根+上限20 | 15 | 1.813 | 3.0 |
放寬上限之後筆數反而更少(19 → 15)。 單獨放寬上限只多 7 筆, 證明上限根本不是瓶頸。這一步是這兩輪唯一真正有用的產出: 它逼我去把關卡計數器加進回測(關卡計數 = collections.Counter(),30 道關自動計數)。
計數器查出真因:兩道關串聯 · 停損距離(dpct > stop_far or dpct < stop_min)被觸發 38 倍 · 風報比 被觸發 3.8 倍
根本的設計缺陷是我自己造的:只把停損換成大時區,目標價還留在 4H。 rr = 獲利% / 停損距離% —— 分子是小尺量的(4H 前高),分母是大尺量的(6H 結構低,距離大得多)。 小尺的分子除大尺的分母,風報比必然崩。
結論:規則本身沒被否決,是實驗設計錯了。換時框必須整組一起換。 這條教訓直接寫進了後來的三時框架構(目標價前高同步 4H → 6H)。
沒有套用,開關留著(停損用大時區、大時區停損回看根數,預設否)。
使用者的模型:「加碼跟原始單一樣,只是系統檢測已經有單去調整下單比例而已, 應該不用另外再去限制,就只是單走不走得出第二輪第三輪。」
查出來的現況跟直覺相反: · 進場要過 21 道關;加碼只要 2 項(新的突兀量+回測不破) · 再用 加碼門檻R 2.0/冷靜 6 根/最多 2 次/總保證金 2 倍 硬綁住 也就是「技術上寬鬆很多、用次數和倉位硬綁」。
實作方案 A:持倉中照跑完整 21 道進場關卡,過了就加碼,並拿掉三道限制。
| 365 現況 | 365 (A) | 730 現況 | 730 (A) | |
|---|---|---|---|---|
| 筆數 | 573 | 1149 | 1120 | 2322 |
| 每筆R | 1.318 | 0.315 | 1.008 | 0.306 |
| 回撤 | 14.8 | 22.8 | 15.4 | 28.8 |
| 硬停損 | 72% | 93% | 75% | 94% |
| 大單筆數 | 39 | 19 | 58 | 28 |
| 最佳單R | 60.8 | 114.9 | 60.8 | 153.4 |
我的預測錯了,而且是反過來的。 我預測「進場關卡的位階/乖離會在加碼時刻 擋下來,導致加碼數趨近零」。實際上進場關卡根本沒擋:
現況 571 筆 有加碼 247 筆(43.3%) 加碼總次數 248 平均持倉 26.7 小時 加碼用進場規則 1147 筆 有加碼 857 筆(74.7%) 加碼總次數 1246 平均持倉 9.2 小時
崩掉的真正機制(從程式碼推出):plan_addon 在 加碼模式=調停損 下, 每加一次碼就把停損反解到「整筆最壞=加碼後最壞R(0)」並只升不降。 原本 最多加碼次數 = 2 把這個棘輪限制在兩格;拿掉之後它一路往上棘輪, 直到停損貼在價格下面,任何回檔就掃掉。三個數字完全吻合: 加碼次數 5 倍、持倉剩三分之一、硬停損 94%。
結論:最多加碼次數 = 2 不是隨便訂的保護,它是承重的。 使用者說「應該不用另外再去限制」—— 在目前這套停損機制下,那個限制拿掉系統會垮。
但這反而支持使用者的另一個判斷:他說「大時區停損也解決了加碼的問題」。 棘輪的根源是「加碼後把停損拉到打平」。如果停損改由大時區結構決定、 不隨加碼上移,棘輪就不存在,加碼次數也就不需要人為限制。 所以順序是:先驗大時區停損,再把加碼模型疊上去,不要反過來。 (值得留意:(A) 的最佳單衝到 153.4R、前5大 453.1 vs 現況 213.1 —— 「不限次數加碼」確實能把少數單推得極遠,代價是把其餘 2300 筆殺光。)
沒有套用,開關留著(加碼用進場規則,預設否)。
回歸測試:這是第一次動到核心迴圈(持倉/進場的分流), 所以同批的「現況」組就是回歸測試 —— 573 筆/每筆 1.318 vs 掃描9 的 572 筆/1.316,預設路徑沒被改壞。
兩個問題都來自使用者。
幣圈路徑用到日線的有三處,這一輪只測了第一處: a. 日線空頭排列否決 ← 這輪測這個 b. 掃盤 RS(7/14/30 天相對強弱)用日線收盤 c. T1 分層的 ma_confirmed = 日線 MA30>MA45>MA60
| 365 現況 → 關掉 | 730 現況 → 關掉 | |
|---|---|---|
| 筆數 | 572 → 573 | 1117 → 1122 |
| 每筆R | 1.316 → 1.351 | 0.952 → 0.950 |
關掉這道關卡,365 只多進 2 筆、730 只多進 6 筆。 原因:只做 T1,而 T1 的條件本身就要求日線 ma_confirmed == 2 —— 一檔日線均線多頭排列的幣不可能同時是日線空排,所以這道否決在 T1 身上是恆真的。 730 多進的 6 筆每筆 +0.245R(低於整體 0.952),證據方向還偏負。
結論:使用者說「幣圈不該用日線」方向是對的,但拔掉這一關等於沒拔。 真正讓日線影響結果的是 T1 分層本身(100% 的單的來源),那是另一個量級的工程。 沒有套用,開關留著(日線空頭否決,預設是)。
判法:關掉濾網,單獨看多出來的那些單賺不賺(實驗腳本/只在某組出現的單.py)。
| 365 | 730 | |
|---|---|---|
| 多進的單 | 125 筆,每筆 +1.000R | 257 筆,每筆 +0.949R |
| 基準組整體 | 每筆 +1.316R | 每筆 +0.952R |
| 多進的單型態 | 不明確 114/等距發散6/擴散回碰5 | 不明確 225/等距發散16/擴散回碰15 |
多進的單90% 是「不明確」(四種球種都不像),365 明顯稀釋、730 持平, 而 730 回撤從 15.8 升到 19.5。型態分類沒有收太緊,維持現狀。
順帶補了一個線上有、回測沒有的不一致:需要型態 線上早就是開關 (shadow_bot.py:2068),回測卻寫死。這次補上。
起因:使用者問「只是單純部份艙位掛單芭樂價而已,要回測哪個部份不太理解」。 查下去發現現在的實作根本不是使用者描述的東西 —— 使用者 2026-09-27 說的是「部分艙位掛一個高價讓插針有機會吃到」, 但程式是「價格碰到 12R 就把整筆倉位平掉」,而且移動停損 09-30 關掉之後 它變成唯一的高位停利,730 天觸發 34~35 次。所以這不是參數要調,是實作不符意圖。
第一個發現:12R 整筆平掉砍掉了每一筆最會跑的單。 730 天/關首段回檔那一版(1090 筆)裡,芭樂價觸發 34 筆, 34/34 全部在出場後繼續上漲,出場後最大R 中位數 +20.71、平均 +26.88、最大 +126.63。
第二個發現:舊資料無法回答「插針價該設多少」,因為它被自己審查了。 整筆平掉會讓 最高R 停止成長,所以 >=15R 只有 1 筆(0.2%)。 改成只賣 20% 之後倉位還開著,才看到真實分布(365 天 553 筆):
| 最高R 水位 | 整筆平掉(被截斷) | 只賣20%(未截斷) |
|---|---|---|
| >=10R | 33(6.0%) | 33(6.0%) |
| >=12R | 24(4.3%) | 24(4.3%) |
| >=15R | 1(0.2%) | 15(2.7%) |
| >=20R | 1 | 7(1.3%) |
| >=30R | 0 | 5(0.9%) |
| >=40R | 0 | 3(0.5%) |
| >=80R | 0 | 2(0.4%) |
| 最大值 | 22.5R | 126.6R |
使用者原本考慮把芭樂價拉到 40R 當純插針單。資料顯示 40R 一年只碰到 3 筆(0.5%), 確實是插針性質,但也等於這個機制幾乎不作用。使用者看完選了「12R 賣 20%」—— 留在有實測效益的那一邊。
<!-- 核對 多檔 檔欄=來源檔 -->
| 設定 | 筆數 | 每筆R | 總R | 回撤 | 來源檔 |
|---|---|---|---|---|---|
| 365 比例1.0 整筆 | 554 | 1.071 | 593.3 | 17.4 | 回測結果_掃描7_365_比例10現況整筆.csv |
| 365 比例0.5 | 553 | 1.101 | 609.0 | 17.4 | 回測結果_掃描7_365_比例05.csv |
| 365 比例0.2 | 553 | 1.121 | 619.7 | 17.4 | 回測結果_掃描7_365_比例02.csv |
| 730 比例1.0 整筆 | 1097 | 0.922 | 1011.5 | 15.4 | 回測結果_掃描7_730_比例10現況整筆.csv |
| 730 比例0.5 | 1099 | 0.911 | 1001.4 | 15.4 | 回測結果_掃描7_730_比例05.csv |
| 730 比例0.2 | 1097 | 0.909 | 996.7 | 15.4 | 回測結果_掃描7_730_比例02.csv |
回測健檢.py 10 檔全過。整批共用 end_ms(釘窗口),組間差異只剩規則本身。
| 比例 | 365 Δ總R | 730 Δ總R | 最佳單R | 前5大總R |
|---|---|---|---|---|
| 1.0(基準) | — | — | 22.1/23.1 | 108/111 |
| 0.7 | +9.0 | −9.4 | 36.1 | 141.5 |
| 0.5 | +15.7 | −10.1 | 46.0 | 165.4 |
| 0.3 | +22.8 | −13.0 | 55.9 | 189.5 |
| 0.2 | +26.4 | −14.8 | 60.8 | 201.4 |
嚴格按四窗口穩健標準,這個改動沒有乾淨通過 —— 730 的總R 是變差的(−1.5%)。 結構上看得出原因:前 5 大多了 90.5R,但總R 少了 14.8R, 代表前 5 名以外的單合計少賺約 105R —— 原本在 12R 落袋的單, 現在留 80% 繼續跑,後來被跌破 MA30 在更低的位置出場。
套用依據是使用者記在 CLAUDE.md 的取捨偏好(2026-09-27 原話): 「可以犧牲獲利換取更大的 R 數」、「回撤變大是預期中的代價,不是否決理由」。 這裡連回撤都沒變(兩窗口都一模一樣 17.4/15.4), 付的是 730 總R 的 1.5%,換到最佳單 23→61、前5大佔總R 比重 11%→20%。 所以這筆是偏好驅動的決定,不是數據壓倒性勝出。 將來若覺得不對,改回 1.0 即可。
已套用(2026-10-03,使用者:「那就20% 12R這樣就好」):
只改幣圈;台股/美股沒有這個鍵,吃預設 1.0(整筆),行為不變。 芭樂價R 維持 12。
v7 收在 1 筆,v8 從 0 開始。
這次改的是出場規則,照 CLAUDE.md 的判準:已開的單是混血,新舊都不計入。 備份 positions.json.bak_過渡v8_20261003。
刻意用「可選的收集盒」而不是多一個回傳值 —— 它有五個呼叫點 (回測.py、shadow_bot、驗證出場.py、股票回測.py、股票模式.py), 改回傳值個數會把五個全弄壞,而股票那兩個是擱置狀態不該動。 回傳仍是 6 個,沒傳盒子的呼叫點行為完全不變。
芭樂已實現USDT),不隨每輪重跑重算 —— 子倉的量賣出後就改了, 重跑沒有「賣之前的量」可以還原。平倉 R 把已實現那塊加回來。
(R數 = 已實現 + 剩餘未實現,不等於 (出場−進場)/風險,跟加碼單同理)。舊檔沒這欄仍通過。
每一筆部分停利過的持倉誤報(它們「停在 12R 以上還抱著」正是規則要的)。 改成只在「設定是整筆平掉且還沒部分停利過」時才叫。反向測試雙向都驗過。
不寫清楚又會變成「看起來像漏出場其實是規則」那類誤解(兩把尺那次就是)。
驗證:trail_update 四條路徑單元測試(1.0/有盒/沒盒安全退回/已做過不再觸發); R 帳務手算吻合(進場100/停損98、12R 賣30%、剩餘抱到110 → (3×24+7×10)/20 = 7.100); healthcheck 反向測試雙向正確。
背景:掃描6(365 篩選)有兩個候選。這一輪把它們放上 730 確認窗, 並補測 乖離警戒 15(因為 10 是掃描邊界)。 這是第一批釘住窗口的掃描(回測.run(end_ms=...),整批共用 end_ms = 1790965933934), 所以組間差異只剩規則本身,不需要再扣噪音。
<!-- 核對 多檔 檔欄=來源檔 -->
| 設定 | 筆數 | 每筆R | 總R | 回撤 | 來源檔 |
|---|---|---|---|---|---|
| 365 現況 | 458 | 0.940 | 430.5 | 26.7 | 回測結果_掃描8_365_現況.csv |
| 365 首段回檔濾網關 | 550 | 1.015 | 558.4 | 19.4 | 回測結果_掃描8_365_首段回檔濾網關.csv |
| 365 首段回檔70 | 530 | 0.975 | 516.6 | 22.1 | 回測結果_掃描8_365_首段回檔70.csv |
| 365 乖離警戒10 | 506 | 0.970 | 490.8 | 27.1 | 回測結果_掃描8_365_乖離警戒10.csv |
| 365 乖離警戒15 | 547 | 0.920 | 503.2 | 28.4 | 回測結果_掃描8_365_乖離警戒15.csv |
| 730 現況 | 919 | 0.841 | 772.6 | 17.7 | 回測結果_掃描8_730_現況.csv |
| 730 首段回檔濾網關 | 1090 | 0.903 | 984.4 | 15.4 | 回測結果_掃描8_730_首段回檔濾網關.csv |
| 730 首段回檔70 | 1054 | 0.858 | 904.0 | 16.0 | 回測結果_掃描8_730_首段回檔70.csv |
| 730 乖離警戒10 | 1004 | 0.836 | 839.8 | 19.1 | 回測結果_掃描8_730_乖離警戒10.csv |
| 730 乖離警戒15 | 1063 | 0.845 | 898.6 | 22.8 | 回測結果_掃描8_730_乖離警戒15.csv |
回測健檢.py 10 檔全過。
| 365 現況 → 關掉 | 730 現況 → 關掉 | |
|---|---|---|
| 筆數 | 458 → 550 | 919 → 1090 |
| 每筆R | 0.940 → 1.015 | 0.841 → 0.903 |
| 總R | 430.5 → 558.4(+128) | 772.6 → 984.4(+212) |
| 回撤 | 26.7 → 19.4(−7.3) | 17.7 → 15.4(−2.3) |
| 大單筆數 | 24 → 32 | 36 → 49 |
| 總R÷回撤 | 16.1 → 28.8 | 43.6 → 63.9 |
沒有任何一項變差,回撤還是降低的。 中間值 70 在兩窗口都介於現況與關掉之間 (單調),所以沒有理由選 70。
掃描6(未釘窗口的另一批)也測到同樣結果(462→548、0.976→1.013、26.7→19.4、25→32), 兩個獨立批次複現。
為什麼:這條濾網的用意是「首段回檔太深的不要碰」,但實測它系統性地擋掉會走成大單的標的 —— 730 大單從 36 筆變 49 筆(+36%)。掃描6 把它收緊到 30% 時最明顯: 總R 只剩 169、大單從 25 筆剩 9 筆。形狀跟移動停損那次一樣。
| 365 | 730 | |
|---|---|---|
| 每筆R | 0.940 → 0.970(+0.030) | 0.841 → 0.836(−0.005) |
| 回撤 | 26.7 → 27.1(+0.4) | 17.7 → 19.1(+1.4) |
| 總R | +60 | +67 |
| 總R÷回撤 | 16.1 → 18.1 | 43.6 → 44.0(幾乎沒變) |
365 說每筆R 變好、回撤幾乎不變;730 說每筆R 持平偏差、回撤明確變大。 總R 上升純粹來自多做 85 筆,不是品質提升 —— 總R÷回撤 在 730 幾乎沒動。 依四窗口穩健標準不該套用,跟掃描3 那個「早期乾淨」濾網一樣是跨窗口不一致。
15 也不行:730 的回撤一路升到 22.8,總R÷回撤 掉到 39.4(比現況 43.6 差)。 乖離警戒維持 7。
掃描6 我說「乖離警戒10 回撤 26.7→28.8(+7.9%)是要付的代價」。 釘住窗口後 365 的回撤只有 26.7→27.1(+0.4)——那個回撤差大部分是窗口噪音。 這也暴露一件事:我當時只量了「每筆R」的噪音底線(±0.011),沒量回撤的, 而回撤的噪音明顯更大。釘窗口之後這個問題消失,之後的掃描都該釘。
已套用(2026-10-03,使用者:「可以套用」):
UTF-8 無 BOM 已驗)。只改幣圈 —— 這個鍵在 [台股]、[美股] 也有(522、581 行), 盲目 replace 會改錯區,所以用逐行+區段判斷只動 [參數] 的那一處。 首段回檔上限百分比 = 50 因此失效,刻意留著:改回「是」就一鍵復原。
(備份 .bak_升v7_20261003)。v6 收在 4 筆,v7 從 0 開始。
其餘全部維持現值:乖離警戒 7、乖離上限 18、日線base回檔 35、 停損距離上限10/下限0.5、加碼後上調停損 否。
持倉版本標記(修正了一次):套用時手上 4 筆持倉。我一開始把 v6 進場的 ATHUSDT 標成「v6→v7過渡單」,這是錯的。 需要首段回檔濾網 是純進場濾網,不改變任何已開倉位的出場行為 —— ATHUSDT 進場在 v6、出場行為完全沒變,整條生命都屬於 v6,是乾淨樣本, 標成過渡等於白丟一筆有效資料。已改回 v6。 (另外 3 筆是 v5→v6 那次的過渡單,維持原標 —— 那次改的是出場規則, 已開的單才真的是混血。) 這個判準已寫進 CLAUDE.md(備份 .bak_過渡單原則_20261003),免得下次再標錯。
背景:2026-10-02 審視盤點出沒掃過的進場濾網;使用者批准排掃。 一次只動一個旋鈕,現況有重跑=同批基準。噪音底線 ±0.011(見同日窗口漂移那段), 所以 Δ每筆R 絕對值 < 0.022 一律視為分不出來。
<!-- 核對 多檔 檔欄=來源檔 -->
| 設定 | 筆數 | 每筆R | 總R | 回撤 | 來源檔 |
|---|---|---|---|---|---|
| 現況 | 462 | 0.976 | 451.0 | 26.7 | 回測結果_掃描6_365_現況.csv |
| 乖離上限12 | 464 | 0.965 | 447.9 | 26.7 | 回測結果_掃描6_365_乖離上限12.csv |
| 乖離上限25 | 464 | 0.965 | 447.9 | 26.7 | 回測結果_掃描6_365_乖離上限25.csv |
| 乖離警戒5 | 378 | 0.915 | 346.0 | 25.1 | 回測結果_掃描6_365_乖離警戒5.csv |
| 乖離警戒10 | 505 | 0.998 | 504.1 | 28.8 | 回測結果_掃描6_365_乖離警戒10.csv |
| 日線base回檔25 | 440 | 0.950 | 418.2 | 24.7 | 回測結果_掃描6_365_日線base回檔25.csv |
| 日線base回檔45 | 462 | 0.953 | 440.2 | 26.7 | 回測結果_掃描6_365_日線base回檔45.csv |
| 停損上限6 | 435 | 0.980 | 426.4 | 28.4 | 回測結果_掃描6_365_停損上限6.csv |
| 停損上限15 | 458 | 0.947 | 433.5 | 26.7 | 回測結果_掃描6_365_停損上限15.csv |
| 停損下限1.0 | 434 | 0.943 | 409.4 | 26.7 | 回測結果_掃描6_365_停損下限10.csv |
| 加碼後上調停損是 | 451 | 0.948 | 427.7 | 26.7 | 回測結果_掃描6_365_加碼後上調停損是.csv |
| 首段回檔30 | 305 | 0.554 | 168.9 | 20.8 | 回測結果_掃描6_365_首段回檔30.csv |
| 首段回檔70 | 529 | 0.970 | 513.4 | 23.1 | 回測結果_掃描6_365_首段回檔70.csv |
| 首段回檔濾網關 | 548 | 1.013 | 555.0 | 19.4 | 回測結果_掃描6_365_首段回檔濾網關.csv |
回測健檢.py 14 檔全過。
| 首段回檔上限 | 筆數 | 每筆R | 總R | 回撤 | 大單筆數 |
|---|---|---|---|---|---|
| 30 | 305 | 0.554 | 168.9 | 20.8 | 9 |
| 50(現況) | 462 | 0.976 | 451.0 | 26.7 | 25 |
| 70 | 529 | 0.970 | 513.4 | 23.1 | 30 |
| 關掉 | 548 | 1.013 | 555.0 | 19.4 | 32 |
關掉比現況:總R +104、回撤降 7.3、大單多 7 筆、每筆R +0.037(噪音的 3.4 倍)。 收緊到 30 是災難:總R 只剩 169、大單從 25 筆剩 9 筆 —— 這條濾網直接砍掉會走的大單。 形狀跟移動停損那次一樣:一個以為在保護的機制,實際在砍掉趨勢單。
註:這類「進場濾網」不適用 共同進場比較.py 的交集法。 交集法是為出場規則改動設計的(進場集合固定、只比出場)。 進場濾網的全部意義就是改變進場集合,取交集會把要測的東西本身消掉。 所以這裡看的是全樣本的 總R/每筆R/回撤,這是正確的比法。
12 與 25 兩組位元級完全相同(464 筆/0.965/26.7/大單25/硬344/加碼單192)。 原因:進場乖離最大值只有 7.00 —— 乖離警戒百分比 = 7 比它緊得多,上限永遠碰不到。 附帶證實:回測在窗口相同時是確定性的,不含隨機性,噪音純粹來自窗口邊界。
| 乖離警戒 | 筆數 | 每筆R | 總R | 回撤 | 大單筆數 |
|---|---|---|---|---|---|
| 5 | 378 | 0.915 | 346.0 | 25.1 | 19 |
| 7(現況) | 462 | 0.976 | 451.0 | 26.7 | 25 |
| 10 | 505 | 0.998 | 504.1 | 28.8 | 28 |
總R +53 但回撤 26.7→28.8。10 又是掃描邊界、趨勢單調(第三次了:芭樂價R=12、 移停回吐0.75、現在這個)。 交互作用要注意:乖離上限 = 18 之所以無效是因為警戒 7 更緊; 把警戒放寬過 18,那個上限就會開始作用。所以補測範圍最多到 18。
| 現況(否) | 改成 是 | |
|---|---|---|
| 筆數 | 462 | 451 |
| 每筆R | 0.976 | 0.948 |
| 總R | 451.0 | 427.7 |
| 大單每筆R | 15.33 | 14.53 |
| 加碼單數 | 193 | 173(−10.4%) |
加碼單少 20 筆,證實了先從程式碼推出的機制:addon_stop_for_size() 不吃 shared_stop,而 加碼模式=調停損 已經會把停損反解到「整筆最壞=加碼後最壞R」, 所以開啟 move_stop 不會讓停損更高,只會讓 s_new <= shared_stop 更容易成立 → 拒絕更多加碼。它是加碼濾網,不是停損調整器。 而被拒絕的那些加碼是該加的(大單每筆R 掉 0.80)。維持「否」。
全部還沒套用。 兩個候選(首段回檔關掉、乖離警戒10)都要先過 730 確認窗, 而且兩者都會改變進場語意 → v6 樣本歸零。要一次到位。
怎麼發現的:掃描6 跑「乖離上限 12」(比現況 18 更嚴)卻跑出更多筆數 (462 → 464)。更嚴的濾網不該讓筆數變多,所以去驗參數到底有沒有生效。
查到的第一件事:乖離上限百分比 根本碰不到。
| 設定 | 筆數 | 進場乖離% 最大 | >12% 筆數 | >18% 筆數 |
|---|---|---|---|---|
| 現況(上限18) | 462 | 7.00 | 0 | 0 |
| 上限12 | 464 | 7.00 | 0 | 0 |
來源:回測結果_掃描6_365_現況.csv、回測結果_掃描6_365_乖離上限12.csv。 沒有任何一筆的進場乖離超過 7.00 —— 真正在擋的是 乖離警戒百分比 = 7。 所以 乖離上限百分比 在幣圈是無效參數,掃它沒有意義(18 或 12 都一樣)。 那 6 個「沒掃過的濾網」裡,這一個可以直接從清單劃掉。
查到的第二件事(更重要):那 2 筆差異是窗口漂移造成的。
被擋掉的 3 筆進場乖離是 2.15 / 4.68 / 6.22,遠低於 12 —— 不是乖離擋的。 而且三筆的進場時間完全相同,都在窗口起點附近。查最早進場時間:
現況 run 最早進場 2025-10-02 23:30 乖離上限12 run 最早進場 2025-10-03 00:00
回測.py:377 原本是 end_ms = B.now_ms() —— 窗口錨在「現在」。 兩組相隔 27 分鐘開跑,窗口起點就差 30 分鐘,窗口邊界進不進得去那幾根 就變了,再透過 出場後冷靜根數(回測.py:539)的連鎖往後擴散。
這給了一個免費但嚴謹的噪音量測。 既然 乖離上限 已證實從不作用, 這兩組其實是同設定跑兩次:
| 現況(18) | 乖離上限12 | 差 | |
|---|---|---|---|
| 筆數 | 462 | 464 | 2 |
| 每筆R | 0.976 | 0.965 | 0.011 |
| 回撤 | 26.7 | 26.7 | 0 |
| 大單每筆R | 15.33 | 15.33 | 0 |
每筆R 的噪音底線 ≈ ±0.011(單一組重複觀測,不是嚴格的標準差)。
回頭重新判讀過去的結論:
Δ 分別是 0.097 與 0.076 —— 噴音底線的 7~9 倍,結論站得住。 而且那是用 共同進場比較.py 取交集算的,已經排掉進場換人的影響。
當時說「走平」是對的,但更準確的說法是「分不出來」。
現在知道根因就是這個窗口漂移。
比噪音底線大,但那是沒取交集的全樣本數字,證據仍然偏弱,維持不動的結論。
已修:回測.run() 加可選參數 end_ms(備份 回測.py.bak_釘窗口_20261003)。 不傳就還是錨在現在,完全向後相容。 實驗腳本/param_sweep7.py 已改成整批共用一個 end_ms,並把它寫進 CSV 以便重現。
掃描6 不中斷:它是粗篩,用途是淘汰明顯變差的組,噪音 ±0.011 不影響這個判斷。 判讀時 Δ 每筆R < 0.02 一律視為分不出來。升到 730 確認時會用釘住的窗口。
問題:使用者要求「從頭到尾再審視一下有沒有甚麼地方遺漏需要調整修改」。
怎麼查(都是機械檢查,不是靠印象): 1. 把 設定.ini 每個區段的鍵逐一去 *.py 找字串 —— 57 個 [參數] 鍵全部有被讀到,沒有孤兒參數。 (第一次跑出 13 個「沒讀到」是假警報:configparser 預設把鍵轉小寫。改 optionxform = str 後歸零。) 2. 把 實驗.py 的 預設 字典跟 設定.ini 現值逐項對照。 3. 讀 logs/執行紀錄_*.log 找被 except 吞掉的錯誤。 4. 把 [參數] 的鍵去所有掃描檔/實驗腳本找,列出從來沒被掃過的。
logs/執行紀錄_2026-10-02.log:1781:
(漏斗統計寫檔失敗,不影響本輪:NameError("name 'io' is not defined"))
shadow_bot.py 沒有 import io,而 09-24 我加的那行寫檔是全檔唯一用到 io 模組的地方。 每輪都丟 NameError 被 except 吃掉 → 漏斗.json 從來沒產生過 → 戰情板那一區一直是空的。 已修:改用跟全檔一致的內建 open(備份 .bak_修漏斗io_20261002)。 驗證:手動餵三筆 SKIP_LOG 進 漏斗(),寫檔成功 504 bytes、總關數 21。 (測試用的假 漏斗.json 已刪掉 —— 不能讓戰情板顯示捏造的數字,下一輪掃盤會產生真的。)
教訓:except Exception 把錯誤印進 log 卻不中斷,等於功能壞掉沒人知道。 這次是靠翻 log 才發現,不是靠任何自動檢查。
實驗.py 的 預設 字典裡 移動停損啟動R = 10,但 設定.ini 09-30 已改 9999。 那個檔自己的註解就警告過這件事:「線上一改,這裡就要跟著改,否則每一批的『現況』 那一列比的都不是現況」—— 結果就是這樣。 已修成 9999,另修掉兩段過期說明與「芭樂價8R」(現在是 12)。備份 .bak_同步現況_20261002。 (大時區倍數 查過是 實驗.py 專用旋鈕、不是 設定.ini 的鍵,不算漂移。)
檢查持倉() 原本涵蓋:停損只能往上、R 數重算、最高R>=目前R、保本規則、已保本→停損>=進場價。 沒有芭樂價。移動停損 09-30 關掉之後芭樂價變成唯一的高位停利 (掃描5:芭樂出場 365天 8→19 筆、730天 14→29 筆),漏了就是整段獲利沒鎖住。 已加(備份 .bak_加芭樂檢查_20261002),並抽出通用的 _門檻() 沿用 _保本R 的教訓 (讀不到一定印警告,不要靜靜用寫死值)。 用初始倉的尺判,跟 trail_update 一致。 反向測試:把 PORTALUSDT 的最高價改成初始倉尺 13R,健檢確實叫出來;還原後「一切正常」。
卡面 最高R 是加碼感知的混合尺(損益USDT ÷ 初倉風險USDT),加碼後被倉位倍數放大。 但所有出場規則在 trail_update 裡都用初始倉的尺 (最高價-進場價)/(進場價-原始停損)。 09-30 的 SOMIUSDT 卡面寫 14.69R、芭樂價設 12R 卻沒出場 —— 看起來像 bug, 其實初始倉的尺只有 9.06R,規則完全正確。 這個落差已經讓 healthcheck 誤報過一次(09-22)、也讓我自己看錯過一次(09-30)。 已修:加碼過的部位把兩個數字都印出來(備份 .bak_兩把尺顯示_20261002)。 驗證:目前兩筆加碼持倉顯示「規則看的最高 +3.13R / +3.07R」,跟手算一致。
shadow_bot.py:2358 的 if ... >= max_pos: break 不印、不進 SKIP_LOG, 所以 log 與漏斗都看不到「最多同時持倉 = 6」多常在擋進場。 已修:補 pskip 訊息並在 關卡 清單加一關(21 關),讓漏斗統計得到。 措辭刻意寫「還有 N 檔候選沒評估」而不是「少賺 N 筆」—— 那些候選多半也會被技術面關卡擋掉,這個數字是機會成本的上界,不是實際損失。 這只是觀測性,不改任何規則,所以不影響樣本計數。
相關的已知限制(不是 bug,已在 回測.py:19 明文):回測不設持倉數上限。 所以回測的每筆R 是規則的期望值,不是「最多 6 筆」帳戶實際能拿到的; 回測的回撤是 R 單位、不是帳戶回撤。線上樣本長大後兩者有落差,這是原因之一。
移動停損關掉後,移動停損最大回吐R、移動停損回吐比例、ATR移動停損倍數 對幣圈完全無效(只在 if be and maxR_now >= trail_start_R: 分支內被用到)。 刻意不刪:啟動R 改回 10 就能一鍵復原。已在 設定.ini 加註(備份 .bak_標註失效_20261002)。 只改 [參數] 那一處 —— [台股]、[美股] 的啟動R 還是 10,那邊仍然有效。 (這裡差點出錯:那兩行在三個區段都有,count == 1 的檢查擋下了盲目 replace。) 另修 驗證出場.py 的過期說明(備份 .bak_同步現況_20261002)。
30 個 [參數] 鍵沒出現在任何掃描/實驗檔。多數不該掃(資金管理、資料源、 熔斷門檻這類不影響 R 統計 —— 回測倉位倍數全 1.0),但這幾個是真的進出場濾網、 值得排進待驗清單:
| 參數 | 現值 | 為什麼值得驗 |
|---|---|---|
| 乖離上限百分比 | 18 | 直接擋進場,從沒驗過 |
| 乖離警戒百分比 | 7 | 同上;決策紀錄曾提「對台股可能太寬」但幣圈也沒驗 |
| 日線base回檔上限百分比 | 35 | 跟掃描3 否決掉的「早期乾淨」是互補的濾網 |
| 首段回檔上限百分比 | 50 | 已在 覆盤待議.md |
| 停損距離上限/下限百分比 | 10 / 0.5 | 會改變可進場的標的集合 |
| 需要均線全確認 | 否 | 開了會大幅縮小候選 |
| 加碼後上調停損 | 否 | 跟加碼模式=調停損 的交互沒驗過 |
另有 8 個掃過但 決策紀錄.md 沒記結論(突兀量回看根數、追高上下限、 需要大時區收縮、需要4H結構檢查、保本門檻R、加碼冷靜根數…)。
都沒有動。照紅線 6/7:不主動加濾網、不為了數字好看調參數。等使用者決定要不要排。
問題:掃描4 顯示回吐比例放愈寬愈好,但 0.75 是掃描邊界、曲線單調,可能還沒到頂。 補測「完全關掉」才能知道該討論的是參數還是機制存廢。
怎麼驗:實驗腳本/param_sweep5.py。四組 × 兩窗口,一次只動一個旋鈕。 「關掉」= 移動停損啟動R = 9999,因為移動停損只在 trail_update 的 if be and maxR_now >= trail_start_R: 分支內生效 —— 不會連帶關掉保本(2.5R)與保本後跌破MA30,那兩條是獨立分支。
【重要】基準有漂移,不要跨批比:同樣是「365天/回吐0.3」, 掃描4 是 442 筆/每筆 1.113/回撤 16.4,這一批是 435 筆/每筆 0.940/回撤 22.2。 差一天而已,回撤差 35%。逐日建池會用當下的幣安資料重建,新上市幣進池、歷史被延長。 所以這一段的每個數字只能跟同批的 0.940 比。
<!-- 核對 多檔 檔欄=來源檔 -->
| 設定 | 筆數 | 每筆R | 總R | 勝率% | 回撤 | 大單每筆R | 移停筆數 | 芭樂筆數 | MA出場 | 來源檔 |
|---|---|---|---|---|---|---|---|---|---|---|
| 現況 回吐0.3 | 435 | 0.940 | 408.9 | 44.8 | 22.2 | 13.21 | 24 | 8 | 74 | 回測結果_掃描5_365_現況回吐03.csv |
| 回吐0.75 | 434 | 1.024 | 444.3 | 44.9 | 22.2 | 14.53 | 8 | 18 | 80 | 回測結果_掃描5_365_回吐075.csv |
| 回吐0.9 | 433 | 1.055 | 456.6 | 45.3 | 22.2 | 14.82 | 6 | 19 | 81 | 回測結果_掃描5_365_回吐09.csv |
| 關掉移停 | 433 | 1.055 | 456.6 | 45.3 | 22.2 | 14.82 | 6 | 19 | 81 | 回測結果_掃描5_365_關掉移停啟動R9999.csv |
回測健檢.py 四檔全過(結束碼 0)。表格用多檔模式核對:每一列從自己那格的檔重算。
數據裡最關鍵的三件事:
1. 曲線到頂了,頂點就是「關掉」。 0.9 與「關掉」逐筆比對 433 列只差 1 列, 而且差的只有標籤文字(BULLAUSDT:回吐至9.5R vs 回吐至3.0R), 出場價與 R 數完全相同 —— 因為加碼早把停損推到 1.78R,移停算出的 1.05R 被 max() 蓋掉。 對照組:0.75 vs 0.9 有 322 列不同,證明旋鈕確實有作用,不是沒套用。
2. 回撤四組完全一樣(22.2)。 使用者原本準備「犧牲獲利換 R 數」, 但這裡不需要犧牲任何東西:每筆R +12%、總R +47.7、大單每筆R +12%、勝率 +0.5%,回撤不動。 原因跟掃描4 一樣:移停要 10R 才啟動,只有約 5% 的單走得到。
3. 接手的是芭樂價與 MA30:芭樂 8→19 筆、MA 74→81 筆、移停 24→6 筆。 移動停損原本掃掉的單,改由「漲到 12R 鎖住」或「收盤跌破 MA30」處理,兩者都是更晚的出場。 (剩下那 6 筆「移停」是 2026-09-28 記錄的誤標 —— 加碼調停損,關掉移停後它們仍在, 6/6 都是 加碼次數≥1 且 R數_初始倉 精確等於 加碼後停損R。這反過來獨立驗證了那個診斷。)
<!-- 核對 多檔 檔欄=來源檔 -->
| 設定 | 筆數 | 每筆R | 總R | 勝率% | 回撤 | 大單每筆R | 移停筆數 | 芭樂筆數 | MA出場 | 來源檔 |
|---|---|---|---|---|---|---|---|---|---|---|
| 現況 回吐0.3 | 903 | 0.777 | 701.5 | 43.4 | 21.5 | 13.70 | 39 | 14 | 156 | 回測結果_掃描5_730_現況回吐03.csv |
| 回吐0.75 | 901 | 0.843 | 759.4 | 43.7 | 21.2 | 15.26 | 16 | 28 | 165 | 回測結果_掃描5_730_回吐075.csv |
| 回吐0.9 | 902 | 0.844 | 761.6 | 43.8 | 21.2 | 15.46 | 15 | 29 | 164 | 回測結果_掃描5_730_回吐09.csv |
| 關掉移停 | 903 | 0.843 | 761.1 | 43.5 | 21.2 | 15.46 | 16 | 29 | 164 | 回測結果_掃描5_730_關掉移停啟動R9999.csv |
回測健檢.py 四檔全過(結束碼 0)。
四組的進場集合兩兩差 7~29 筆(0.8~3.2%)。原因在 回測.py:539: 出場時設 cooldown_until = i + 出場後冷靜根數(現值 3),同一檔出場後要等 3 根才能再進。 改出場規則 → 出場時間位移 → 冷靜窗位移 → 後面哪些訊號進得去跟著變。
驗證這不是資料漂移:四檔是依序跑的(0.3 最早、關掉最晚),但 ARUSDT 2025-08-08 那筆 是「0.75 與 關掉 有、0.3 與 0.9 沒有」—— 不隨時間順序,所以是規則回饋,不是幣安資料變動。 (註:我沒有把這一筆追到最初的分歧點,只確認了機制存在與方向。)
後果:組間 0.001 等級的每筆R 差距分不出是規則造成的還是進場換人造成的。 所以下面再做一次受控比較。
重跑指令:python 實驗腳本/共同進場比較.py 掃描5 365 730 (同一批標的、同一批進場點,差異只剩出場規則。)
| 窗口 | 設定 | 每筆R | 總R | 勝率% | 大單每筆R |
|---|---|---|---|---|---|
| 365(共同 431 筆) | 0.3 現況 | 0.955 | 411.4 | 45.0 | 13.21 |
| 0.75 | 1.034 | 445.9 | 45.0 | 14.53 | |
| 0.9 | 1.052 | 453.4 | 45.0 | 14.82 | |
| 關掉移停 | 1.052 | 453.4 | 45.0 | 14.82 | |
| 730(共同 884 筆) | 0.3 現況 | 0.790 | 698.0 | 43.6 | 13.67 |
| 0.75 | 0.858 | 758.5 | 43.6 | 15.26 | |
| 0.9 | 0.866 | 766.0 | 43.6 | 15.46 | |
| 關掉移停 | 0.866 | 766.0 | 43.6 | 15.46 |
0.9 與「關掉」在兩個窗口都是完全相同的數字,所以 0.9 就已經等於關掉。 勝率四組完全一致(45.0/43.6)—— 進場集合固定、出場規則只動獲利單的出場點, 本來就不該動勝率。這也反過來說明受控比較有效。
兩個窗口都通過,而且方向一致:關掉移動停損比現況好。
| 365 受控 | 730 受控 | |
|---|---|---|
| 每筆R | 0.955 → 1.052(+10.2%) | 0.790 → 0.866(+9.6%) |
| 大單每筆R | 13.21 → 14.82(+12.2%) | 13.67 → 15.46(+13.1%) |
| 回撤(全樣本) | 22.2 → 22.2(不動) | 21.5 → 21.2(略降) |
| 勝率 | 45.0 → 45.0 | 43.6 → 43.6 |
使用者原本準備「犧牲獲利換取更大的 R 數」,但這裡不需要犧牲任何東西。 回撤沒變大、勝率沒變差,大單拿得更多。
為什麼:移動停損要 10R 才啟動,只有約 5% 的單走得到;走到 10R 的單本來就在趨勢裡, 這時候收緊停損等於在最會跑的單上提早下車。關掉之後接手的是 芭樂價(12R 鎖住)與保本後跌破MA30 —— 兩者都是更晚的出場。 出場結構(730):移停 39→16 筆、芭樂 14→29 筆、MA 156→164 筆。 (剩下那 16 筆「移停」是誤標的加碼調停損,見同日另一段。)
怎麼套用(如果要套):移動停損啟動R 從 10 改成 9999。 不要改 回吐比例—— 讓那個參數留在 0.3,等於機制關著但參數沒被動過, 將來若要復原只要把啟動R 改回 10。
已套用(2026-09-30,使用者:「可以 直接套用」):
只改幣圈。[台股]、[美股] 那兩個同名參數維持 10 —— 證據只來自幣圈回測, 而且使用者 2026-09-27 說股票先擱置。 回吐比例 0.3、最大回吐R 3.0 原封不動留著,機制關著但參數沒被動過, 將來要復原只要把啟動R 改回 10。
(備份 .bak_升v6_20260930)。v5 收在 22 筆,v6 從 0 開始。
套用當下手上有 6 筆持倉,處理方式: 規則版本 原本是平倉時才用全域值蓋章,所以這 6 筆 v5 進場的單會被記成 v6, 弄髒剛歸零的樣本;但它們也不該算 v5(從現在起的出場行為是 v6)。 所以在 positions.json 把它們標成 v5→v6過渡單(v5進場/關掉移停後出場) 不計入樣本, 並改 shadow_bot.py 平倉蓋章為 pos.get("規則版本") or 規則版本(2 處), 兩邊都不計入。備份 positions.json.bak_過渡單_20260930。
這個改動沒有回頭影響任何已開的單:6 筆裡只有 SOMIUSDT 接近門檻 —— 顯示的 最高R 14.69 是混合成本的尺,但 trail_update 內部用初始倉的尺,換算後是 9.06R, 還沒到 10(停損確實停在 +0.10R 的保本位)。差約 1.6% 的價格就會觸發,現在不會了。 其餘 5 筆最高R(初始尺)都遠低於 10。
問題:讀 掃描4 的逐筆檔時發現,730 天基準組有 45 筆標示「移動停損」, 但其中 18 筆的出場原因寫「自最高 4~9R 回吐」—— 而 移動停損啟動R = 10, 不到 10R 根本不該進移停分支。
怎麼驗:把「移動停損」出場依原因字串裡回報的起點 R 拆成兩群, 對 掃描4 全部 14 個逐筆檔各算一次。
數據(來源:回測結果_掃描4_*.csv,14 檔逐筆重算):
| 回吐比例 | 730 真移停(起點≥10R)筆數 | 每筆R | 730 假移停(起點<10R)筆數 | 每筆R |
|---|---|---|---|---|
| 0.3(現況) | 27 | 11.81 | 18 | 0.20 |
| 0.4 | 18 | 10.02 | 18 | 0.20 |
| 0.5 | 8 | 8.52 | 18 | 0.20 |
| 0.6 | 6 | 7.12 | 18 | 0.20 |
| 0.75 | 2 | 2.57 | 18 | 0.20 |
365 天同樣模式:真移停 21→2 筆,假移停固定 8 筆。
「假移停」那群在七組設定裡筆數與每筆R 完全不變,代表它不受這個旋鈕控制。 再查 730 那 18 筆:加碼次數全部 ≥ 1,且 R數_初始倉 精確等於 加碼後停損R (18/18 吻合,差 < 0.02)。
結論:它們是被加碼調上來的停損掃掉的,不是移動停損。 成因在 shadow_bot.trail_update:出場原因是用 cur_stop 跟 be_stop 比出來的 ——
elif abs(cur_stop - be_stop) < 1e-9: -> 觸及保本停損 else: -> 移動停損(...)
加碼模式=調停損 會把 cur_stop 推高到保本價之上,於是落進 else,被標成移動停損。 giveback_R_eff 這時還是初始值 3.0,所以訊息才會印出「回吐至 3.0R」這個沒發生過的數字。
影響範圍:
正確是 27→2 筆。也就是移動停損在 0.75 幾乎已經不作用了 —— 這讓「完全關掉」的預期更明確:結果應該會非常接近 0.75。
已修(2026-10-01,使用者:「可以修 待辦的」):
shadow_bot.trail_update 加了第四種出場原因(備份 .bak_修出場標籤_20261001):
移停在作用 = bool(be and maxR_now >= trail_start_R) ... elif 移停在作用: -> 移動停損(...) else: -> 加碼後調高停損(停損在%+.1fR)
要不要改其他檔,先查過才動:
標籤修好之後那個篩選自動就只抓到真的移動停損了。
新標籤會自己變成一組,這正是想要的。
「價格跌到停損才出場的,圖上紅線會被碰到」,而這種出場原始停損線全程沒被碰到。 已加分支(備份 .bak_出場說明加碼_20261001),且必須放在 "停損" in 原因 之前。
回測健檢.py 加了一條不變量守住這個修正(備份 .bak_加碼停損不變量_20261001): 「出場原因是『加碼後調高停損』但這筆沒有加碼」。反向測試過 —— 故意把一筆的加碼次數 改成 0,健檢確實叫出來並指名 1000PEPEUSDT。
驗證: 1. 單元測試 trail_update 四個分支(加碼調停損/保本/移動停損/現行9999設定)全部符合預期。 2. 端對端跑 180天/池50 回測(195 筆):「移動停損」0 筆(現行啟動R=9999,符合預期)、 「加碼後調高停損」4 筆且全部 加碼次數=1、R數_初始倉 與 加碼後停損R 4/4 吻合。 被重新標記的正是當初診斷出的那幾檔:1000PEPE、1000SHIB、CL、SOON。 3. 回測健檢.py 通過(結束碼 0)。
注意:舊的回測檔不會變。回測結果_掃描4_*、回測結果_掃描5_* 裡的誤標還在, 那是歷史紀錄。要重算出場原因分布得重跑回測。
原始資料 參數掃描4.csv(14 組,實驗腳本/param_sweep4.py,每組逐筆檔獨立留存)。 起因:使用者提 ALCH/ARK「出場後續的獲利沒吃到」,查出這兩個參數從來沒被掃過。
使用者定的判讀標準(2026-09-27 原話):「可以犧牲獲利換取更大的 R 數。」 所以不只看 總R÷回撤,要一起看大單(最高R >= 10R)最後拿到多少。
| 回吐比例 | 365 每筆R | 365 大單每筆R | 730 每筆R | 730 大單每筆R | 移停筆數 365/730 |
|---|---|---|---|---|---|
| 0.3(現況) | 1.113 | 13.98 | 0.882 | 14.19 | 29 / 45 |
| 0.4 | 1.121 | 14.04 | 0.889 | 14.61 | 23 / 36 |
| 0.5 | 1.200 | 14.90 | 0.920 | 15.01 | 15 / 26 |
| 0.6 | 1.169 | 14.45 | 0.908 | 14.99 | 14 / 24 |
| 0.75 | 1.212 | 15.06 | 0.919 | 15.27 | 10 / 20 |
回撤完全沒變:365 天七組全是 16.4、730 天全是 16.1。 原因很清楚:移動停損要 移動停損啟動R = 10 才啟動,而只有約 5% 的單走得到 10R, 所以放寬它幾乎不影響權益曲線。這推翻了我原本的預期(以為放寬=回撤變大)。
大單每筆R 兩個窗口都單調上升(13.98→15.06、14.19→15.27)—— 正是使用者要的那件事。而且總體每筆R 也變好,不是拿獲利換的,是純賺。
0.75 等於幾乎把移動停損關掉(移停出場 365 天 29→10 筆、730 天 45→20 筆)。 而且 0.3→0.75 的趨勢是單調的,代表曲線可能還沒到頂。
這跟芭樂價R 當初的狀況一樣:12 是測過的最低值,所以第二輪往下補測 6/8/10。 現在 0.75 是測過的最高值,要先補測「完全關掉移動停損」, 才知道 0.75 是真的最佳點,還是只是我們停下來的地方。
另一個佐證:移動停損啟動R 那一輪(2026-09-22)730 天的總R÷回撤 是 4→34.2、5→31.2、6→34.4、8→40.0、10→41.6 —— 越晚啟動越好,同一個方向。 兩輪掃描都在說「移動停損這個機制本身可能是負貢獻」。
| 最大回吐R | 365 每筆R | 730 每筆R |
|---|---|---|
| 3.0(現況) | 1.113 | 0.882 |
| 4.0 | 1.102 | 0.847(比現況差) |
| 5.0 | 1.164 | 0.927 |
5.0 兩個窗口都比現況好,但 4.0 反而比 3.0 差——曲線不單調, 代表這裡的差異有相當部分是雜訊。先不動。
沒有改任何設定。 移動停損回吐比例 維持 0.3、移動停損最大回吐R 維持 3.0。
要套用的話會改變出場語意 → 依 2026-09-22 的 (b) 定義,v5 樣本計數歸零(目前 12 筆)。 在補測「完全關掉」之前不值得付這個代價,因為可能補測完會發現該設的是別的值。
<!-- 核對 檔=回測結果_掃描4_730_回吐比例_0p3.csv 分組=全部 -->
| 730天 回吐比例 0.3(現況) | 筆數 | 總R | 每筆R | 勝率% | 回撤 |
|---|---|---|---|---|---|
| 全部 | 914 | 806.3 | 0.882 | 43.5 | 16.1 |
<!-- 核對 檔=回測結果_掃描4_730_回吐比例_0p75.csv 分組=全部 -->
| 730天 回吐比例 0.75 | 筆數 | 總R | 每筆R | 勝率% | 回撤 |
|---|---|---|---|---|---|
| 全部 | 917 | 842.5 | 0.919 | 43.6 | 16.1 |
原始資料 參數掃描3.csv(8 組,實驗腳本/param_sweep3.py)。 底圖:群組定義/四個位階全開/池100/逐日建池。批次隔離:只跟這一批互比。
| 天數 | 設定 | 筆數 | 每筆R | 回撤 | 總R÷回撤 | vs 現況 |
|---|---|---|---|---|---|---|
| 365 | 現況 | 451 | 1.038 | 21.3 | 22.0 | — |
| 365 | A 早期乾淨 220/35% | 349 | 0.969 | 18.7 | 18.1 | −3.9 |
| 365 | B 突兀量需區間最大 | 450 | 1.043 | 21.3 | 22.0 | ±0.0 |
| 365 | A+B | 349 | 0.969 | 18.7 | 18.1 | −3.9 |
| 730 | 現況 | 910 | 0.827 | 16.8 | 44.8 | — |
| 730 | A 早期乾淨 220/35% | 693 | 0.902 | 12.5 | 50.0 | +5.2 |
| 730 | B 突兀量需區間最大 | 913 | 0.830 | 17.7 | 42.8 | −1.9 |
| 730 | A+B | 703 | 0.910 | 12.5 | 51.2 | +6.4 |
筆數幾乎沒變:365 天 451→450(−0.2%)、730 天 910→913(+0.3%,還變多)。 事前推論的「壞處二」完全成立:趨勢走出去時量一路放大、最大量一直被刷新, 所以「必須是區間最大量」實際上幾乎不擋任何一根。
(筆數會變多是因為它換掉的是「選中哪一根突兀量」→ 停損位置不同 → 出場時間不同 → 影響同時持倉的名額競爭。所以它不是濾網,是洗牌。)
風險調整後 365 持平、730 −1.9。沒有價值,不採用。
兩個窗口方向相反 → 依四窗口穩健標準,矛盾=沒有結論=維持現狀。
而且代價是確定的:兩個窗口都砍掉 23% 的筆數(451→349、910→693)。 確定要付 23% 的樣本,換到的好處只有一個窗口說有。
這跟 2026-09-14 那批六條濾網是同一個型態,但要誠實說一個差別: A 在 730 天不只是隨機減量——它把回撤從 16.8 壓到 12.5(−26%), 每筆 R 還從 0.827 升到 0.902。那個窗口它確實有在篩掉壞單。 但 365 天完全相反(每筆 1.038→0.969),所以站不住。
兩個都維持關閉(早期乾淨回看根數 = 0、突兀量需為區間最大 = 否)。 程式留著,設定檔也留著說明,之後樣本夠了可以再驗。 沒有動任何進場語意 → v5 樣本計數不歸零。
這批是第一次帶 R數_初始倉 欄的回測。現況組: 365 天 吐回(混尺) 16.9% vs 吐回(初始倉) 4.0%;730 天 16.6% vs 3.1%。 跟今天早上用舊檔算的 4.0% / 3.0% 幾乎一樣 —— 在全新資料上獨立重現了那個結論。
<!-- 核對 檔=回測結果_參數掃描3.csv 分組=全部 -->
| A+B 730天(掃描最後一組,逐筆檔留著的那組) | 筆數 | 總R | 每筆R | 勝率% | 回撤 |
|---|---|---|---|---|---|
| 全部 | 703 | 639.6 | 0.910 | 43.4 | 12.5 |
1. 回測健檢.py 的誤判:我昨天把「新檔還出現最高R < R數」寫成硬失敗, 假設是「有了 R數_初始倉 欄混尺就會消失」。那是錯的—— 最高R < R數 是加碼單的本質(兩欄本來就用不同的尺),新欄位只是讓指標 *能正確計算*,不會讓現象消失。真正的不變量「最高R >= R數_初始倉」本來就在驗, 而且通過(0 筆)。這條硬失敗會讓每個新檔都紅燈,正好犯了自己訂的 「誤報比不檢查更糟」。已改回提醒等級。這是三層機制第一天就抓到自己的錯。
2. 掃描的可驗證性缺口:param_sweep3.py 每一組跑完都把逐筆檔覆蓋掉, 所以 8 組裡只有最後一組(A+B 730)的原始資料留著,另外 7 組無法用 核對.py 重算。上面那張表只有最後一組帶核對標註就是這個原因。 下次掃描要改成每組存成獨立檔(8 組約 2MB,成本可忽略)。
使用者:「1、2 可以做;3 可以看看回測或是這樣做的好處跟壞處。」
朋友那頁顯示 passCount/7,看得到「只差一條」的標的。我們的檢核是 「一關不過就跳下一檔」的序列,要真算 passCount 得重構熱路徑。 但因為關卡順序固定,「被擋在第幾關」等價於「通過了前幾關」, 所以純事後統計就能得到同樣的資訊,完全不用動進場程式。
意外發現:SKIP_LOG 每輪都收集了跳過理由,skip_summary() 卻從來沒被呼叫過 ——這份資料一直被丟掉。現在存成 漏斗.json,戰情板新增「進場檢核漏斗」區塊, 顯示每一關擋掉幾檔(長條)與走最遠的 8 檔(過了幾關/共 20 關)。
不改變進場語意,依 (b) 不重數樣本。 備份 shadow_bot.py.bak_加漏斗_20260924、 戰情板.py.bak_加漏斗區_20260924。資料要等下一輪掃盤才會出現。
early_clean_ok():觀察窗之前 look 根的最大回撤超過上限就跳過。 跟既有的 base_drawdown_ok 互補——那個量「現在這個 base 有多深」(最近 30 根), 這個量「更早那段乾不乾淨」(跳過最近 40 根之後的 220 根)。
設定 早期乾淨回看根數 = 0(關)、早期乾淨跳過最近根數 = 40、早期乾淨最大回撤百分比 = 35。 線上與回測都接好了。沒有打開——它會改變進場語意,要先過兩個窗口。
設定 突兀量需為區間最大 = 否。打開後 _anomaly_lows() 會多要求那根是區間內最大量。
事前推論的好處與壞處(等回測驗證,不當結論用):
| 內容 | |
|---|---|
| 好處 | 現在只比「前 20 根均量 ×2.5」,所以一波連續放量的第二、三根也會被當成新訊號。加上「必須是區間最大量」之後,加碼比較不會加在已經追高的位置,也更接近教材「突兀量是明顯突出周圍」的原意 |
| 壞處一 | 突兀量是進場的必要條件(需要突兀量 = 是),變嚴就是直接減少筆數。2026-09-14 那批濾網實驗的教訓:六條濾網砍掉 20~40% 的單之後,平均虧損單、平均獲利單都沒變——它們不是在篩壞單,是在隨機減量 |
| 壞處二 | 趨勢走出去的時候量會一路放大、最大量一直被刷新,最新那根往往自動就是最大量 → 實際擋掉的可能比想像中少,效果不如預期 |
| 壞處三 | 改變進場語意 → 樣本計數歸零,現在 v5 才 12 筆 |
實驗腳本/param_sweep3.py(存在專案裡,不放暫存夾), 4 組 × 2 窗口 = 8 次回測:現況/只開A/只開B/A+B,輸出 參數掃描3.csv。 有斷點續跑。獨立行程,啟動殼 PID 25916、實際工作的子行程 PID 28336。 預估 3.5~4 小時。
這一批跑出來的回測檔會帶 R數_初始倉 欄,所以「高峰吐回%」第一次可以用同一把尺算, CSV 裡混尺與初始倉兩種都會印,可以直接看差多少。
使用者:「朋友網站有新功能,即時強弱那邊有 T桑掃圖,可以學習」,並授權「控制在可控範圍」。
怎麼看的(沒有碰紅線):沒有用瀏覽器開(頁面自己可能會打 /scan/*), 改成只 GET 兩個靜態檔:首頁 HTML 與 /assets/index-BAQQPeY_.js, 完全不執行 JS,所以不可能觸發他的重掃。全部連線 2 次,之後都在本機分析。
他的判定函式 jd()(從 minified JS 還原):資料要 60+220+40 = 至少 320 根。 回傳 7 個檢核 + 型態,setup = 7 條全過 且 型態 != 其他,UI 顯示 passCount/7。
| 檢核 | 他的作法 | 我們的 |
|---|---|---|
| q1 均線不交叉 | 最近 40 根 MA30>MA45>MA60 每根都成立 | 同樣 30/45/60 |
| q2 發散 | 後半平均差距 > 前半 ×1.05(MA30-45 與 MA45-60 都要),且沒有任何一根差距 > 前一根 ×1.6;或變異係數 <0.12(平行)也算過 | 我們有張開幅度,但平行不算過 |
| q3 凹口/平行 | 46 根的「5根斜率」後半平均 > 前半且 >0 | 類似 |
| q4 之前乾淨 | 更早的 220 根最大回撤 < 35% | 我們完全沒有這條 |
| q7 乖離 | 上限 18%、並標記 >=7% | 乖離上限=18、警戒=7 —— 完全一樣 |
| volSpike 突兀量 | 量 > 前一根 ×2.5 且是最近 20 根內最大 | 量 > 前 20 根均量 ×2.5,回看 48 根 |
| tier2 位階2 | 突破前 60 根高點後,回撤低點 >= 高點 ×0.99,且現價 >= 高點 | 位階2守住 = 0.05(5%) |
型態只有兩種(用最近 120 根收盤):
回撤低點不破全區最低 → 現價 >= 高點 ×0.95
值得學的三件事: 1. 顯示 passCount/7,不是只有過/不過。這樣看得到「只差一條」的標的, 也看得出是哪一條最常擋人。純 UI 改善,零風險。 2. 「之前乾淨」濾網(更早 220 根最大回撤 < 35%)——我們沒有。 它在排除「大跌完在反彈」的標的。可以回測驗。 3. 突兀量要求「是最近 20 根內最大量」——我們只比均量 ×2.5,沒有這個條件。他更嚴。
不打算照抄的:位階2 守住門檻他用 1%、我們用 5%。我們是測過的 (2026-09-19:2%/5%/10% 三組,5% 勝出,730 天 0.374→0.679),有數據支撐,不動。
乖離 18%/7% 兩邊完全一樣,大概都是直接取自 T桑教材。這反而是個好消息: 兩套獨立實作在同一個數字上收斂。
沒有套用任何東西。 依紅線第 7 條「不要主動加使用者沒要求的濾網」, 上面三件事都只是候選,要測要等使用者點頭。已列入 覆盤待議.md。
問題(使用者):「要怎麼有機制讓我知道你回測的數據是否正確,避免我以後決策錯誤?」
背景:今天核對抓到的三個錯誤,共同點是沒有任何東西在驗證數字—— 全靠人眼,而人眼在幾百個數字裡看不出「這張表的筆數跟來源檔差 22 筆」。
已做:回測健檢.py(第一層)
驗「邏輯上絕不可能違反」的事,跑完回測就該執行:
| 檢查 | 會抓到什麼 |
|---|---|
| 最高R < 最終R(同一把尺) | 尺用錯、欄位算錯 |
| 最高R < R數(混尺偵測) | 今天的錯誤二、三 |
| 無加碼單的 R數 ≠ (出場−進場)÷風險 | R 數算錯 |
| 觸及停損但 R ≠ −1.00 | 出場價或停損價寫錯 |
| 芭樂價停利但 R ≠ 設定值 | 出場邏輯跟設定不同步 |
| MAE_R 為正 | 不可能發生 |
| 加權R ≠ R數×倉位倍數 | 加權算錯 |
| 同標的同進場時間重複出現 | 重複計入 |
同時印出該檔的權威彙總(筆數/總R/每筆R/勝率/回撤)—— 以後要引用數字就引用它印的,不要自己心算,也不要跨檔拼。
實測:掃過全部 20 個回測檔,只剩「最高R < R數」這個已知的兩把尺問題 (等下次重跑帶 R數_初始倉 欄就會清掉)。其餘全部通過。
一個當場修掉的誤報:回測結果_參數掃描2.csv 被報「芭樂價停利但 R≠12」3 筆—— 那是掃描檔,跑的時候芭樂價R 被覆寫成 6/8/10,拿設定檔的 12 去對一定不合。 已改成掃描/實驗/暫存檔跳過門檻類檢查,只印一行說明。 (誤報比不檢查更糟,healthcheck.py 已經為此踩過兩次。)
已套用:CLAUDE.md 常用指令加入 python 回測健檢.py, 工作方式加入「引用回測數字前先跑健檢,只引用它印的彙總,數字要標來源檔+筆數」。
第二層:核對.py(已做)
決策紀錄的表格前面加一行標註,指定該從哪個檔重算: <!-- 核對 檔=回測結果_全開730.csv 分組=位階 --> 跑 python 核對.py 就會從來源檔重算,跟表格逐格比對。 支援欄名:筆數/每筆R/總R/勝率%/回撤;分組=全部 表示整個檔當一組。
反向測試(確認它真的會抓錯,不是永遠說 OK):把今天那個錯誤數字塞回去, 它精準報出「位階1 每筆R 文件寫 0.931、重算是 0.904」與「位階1.5 筆數 467 vs 457」, 並指出行號。還原後回到全過。
本檔已加 5 張帶標註的權威數字表(730/365 的總體、位階、型態),全部對得上。
第三層:抽查.py(已做)
隨機挑幾筆把算式一步步攤開,讓使用者自己用 Excel 對: 印出進場價/停損價/出場價、風險單位怎麼算、R 怎麼算、跟 CSV 記的對不對得上。 加碼單會說明「R數 是混合成本,跟價格算的不同是設計不是錯」。
數字檢查.bat:三層一次跑完,任一層不過就提示不要拿數字做決策。
一個刻意的設計:舊檔的混尺只提醒、不當失敗。 2026-09-24 之前跑的檔沒有 R數_初始倉 欄,一定會混尺。 如果把它當失敗,健檢就會永遠亮紅燈 —— 然後就沒人看了。 新檔(有新欄位)若還出現混尺才是真的壞掉。 (healthcheck.py 誤報過兩次,誤報比不檢查更糟。)
不做完全獨立的第二套回測:成本高、自己也會有 bug,兩邊不一致時無法判斷誰對。 真正的「雙重」是「機器驗不變量」+「人能一鍵重算」,不是兩套程式互猜。
已套用:CLAUDE.md 寫入固定的七步數字流程,常用指令加入三支工具與 數字檢查.bat。 以後開新對話的我會自動載入,照這個順序走。
問題(使用者):「回測數據 R 數跟績效有沒有錯誤,再重新核對。」 做法:不看既有結論,直接從逐筆 CSV 重算,再跟文件裡寫的數字逐項比對。
芭樂價停利 16 筆 1.8% +17.954/移動停損 35 筆 3.9% +7.577/觸及保本停損 7 筆 0.8% −0.176。 全部對得上,一個字都沒錯。
位階1 0.726(54筆)全部對得上。
2026-09-21 位階掃描 那段寫「四個全開時(730 天,回測結果_全開730.csv)」, 但那些數字不是從那個檔算出來的:
| 位階 | 文件寫的 | 從 回測結果_全開730.csv 實算 |
|---|---|---|
| 位階0 | 99 筆 / 0.608 | 100 筆 / 0.700 |
| 位階1 | 130 筆 / 0.931 | 130 筆 / 0.904 |
| 位階1.5 | 467 筆 / 0.782 | 457 筆 / 0.863 |
| 位階2 | 215 筆 / 0.674 | 202 筆 / 0.740 |
| 合計 | 911 筆 | 889 筆 |
911 是 位階掃描.csv(2026-09-21 06:18 那批)的數字,跟 回測結果_全開730.csv (09-22 02:39)不是同一批 —— 違反自己訂的「只有同一批的數字能互相比較」。 排名順序(位階1 > 1.5 > 2 > 0)沒變,但四個數值全都要換掉。 「位階1 最好(0.931)」正確的值是 0.904。
730 天有 52 筆、365 天有 26 筆出現 最高R < R數 —— 最終比最高還大,邏輯上不可能。 全部是加碼過的單(52/52、26/26)。
原因:R數 用混合成本算(整筆損益÷初倉風險),最高R 用初始倉算。兩把尺。 用初始倉的尺重算最終 R,52 筆與 26 筆全部不再超過最高R。
這正是 2026-09-19 最高R 沒有加碼感知(已修) 那段修過的東西 —— 但那次只改了線上路徑,回測輸出的 最高R 欄從來沒改。 所以線上實單 50 筆一筆都沒有這個問題,回測有 52 筆。
2026-09-22 逐筆盤點 說「142 筆(16.0%)最高走到 2.5~10R、最後收在 0.5R 以下」, 那是拿初始倉尺的最高R 去比混合尺的 R數。用同一把尺重算後拆成兩塊:
| 730 天 | 365 天 | |
|---|---|---|
| (i) 價格真的從 2.5R+ 吐回到 0.5R 以下 | 27 筆 / 3.0% | 17 筆 / 4.0% |
| (ii) 價格守住了,是加碼把整筆拖到 0.5R 以下 | 113 筆 / 12.7% | 49 筆 / 11.4% |
| 合計(=原本報的數字) | 140 筆 / 15.7% | 66 筆 / 15.4% |
(ii) 那群 113 筆全部有加碼,平均最高 3.38R、初始倉尺最終 +1.14R、實際入帳 +0.06R, 每筆被吃掉 1.08R。
所以「每 6 筆有 1 筆從高點吐回去」這個說法是錯的。 價格真的吐回只有 1/33。 真正在發生的是:加碼把「價格守在 +1.14R」的普通單換成打平,發生率 12.7%。
這不是 bug,是設計(加碼後最壞R = 0 就是「加碼後整筆至少保本」)。 整件事的正確描述是:加碼是拿「3R 附近的普通單變打平」去換「大單部位翻倍」。 乾淨 A/B 顯示這筆交易整體是划算的(730 天 0.707 → 0.784), 也解釋了為什麼放寬 加碼後最壞R 沒用 —— 那是在調一個本來就照設計運作的東西。
<!-- 核對 檔=回測結果_全開730.csv 分組=全部 -->
| 全開730 | 筆數 | 總R | 每筆R | 勝率% | 回撤 |
|---|---|---|---|---|---|
| 全部 | 889 | 731.5 | 0.823 | 42.7 | 16.8 |
<!-- 核對 檔=回測結果_全開730.csv 分組=位階 -->
| 位階(730天) | 筆數 | 每筆R |
|---|---|---|
| 位階0 | 100 | 0.700 |
| 位階1 | 130 | 0.904 |
| 位階1.5 | 457 | 0.863 |
| 位階2 | 202 | 0.740 |
<!-- 核對 檔=回測結果_全開730.csv 分組=型態 -->
| 型態(730天) | 筆數 | 每筆R |
|---|---|---|
| 等距發散 | 429 | 0.944 |
| 擴散回碰 | 410 | 0.676 |
| 盤整突破 | 35 | 1.485 |
| 收斂上彎 | 15 | -0.175 |
<!-- 核對 檔=回測結果_全開365.csv 分組=全部 -->
| 全開365 | 筆數 | 總R | 每筆R | 勝率% | 回撤 |
|---|---|---|---|---|---|
| 全部 | 429 | 404.7 | 0.943 | 42.9 | 25.5 |
<!-- 核對 檔=回測結果_全開365.csv 分組=位階 -->
| 位階(365天) | 筆數 | 每筆R |
|---|---|---|
| 位階0 | 57 | 0.985 |
| 位階1 | 54 | 0.726 |
| 位階1.5 | 217 | 1.082 |
| 位階2 | 101 | 0.739 |
回測.py 新增輸出欄 R數_初始倉 = (出場價 − 進場價) ÷ 初始風險。 要算「拿最高R 比最終R」的指標(高峰吐回% 之類)就用這欄配 最高R,兩邊同一把尺。
故意不改 最高R 或 R數:改了會讓所有既有回測檔跟新檔不可比, 而且 R數(混合成本)本來就是正確的績效口徑 —— 它才是真正入帳的錢。 加一欄是可加性的,舊檔只是少一欄,照樣能讀。備份 回測.py.bak_加初始倉R欄_20260924。
這個改動不影響進出場語意(只多寫一欄診斷資料),依 2026-09-22 的 (b) 定義 不重數樣本,v5 維持現有筆數。新欄位要等下次跑回測才會有。
問題(使用者):「為什麼不是合併在 https://wood-shadow-board.pages.dev/?會造成混亂。」
我做錯的事:今天把決策總表做成 claude.ai 的 Artifact,等於多開一個要看的地方。 而且 publish_board.py 開頭早就寫明 2026-09-14 就決定不用 Artifact 發布—— 那會用聊天帳號的額度做網頁託管,跟掃盤/健檢排程搶同一個 5 小時額度(09-14 00:15 撞過一次)。 Artifact 已刪除,內容改成戰情板的一個區塊。
已套用: 1. 戰情板.py 新增 區段_決策紀錄(),直接渲染 決策紀錄.md(17 條,新的排最前、可展開)。 單一事實來源就是這個 .md,網頁只是渲染,不另外維護一份—— 今天才踩過兩份文件對位階1 講相反話的坑。 備份 戰情板.py.bak_加決策紀錄區_20260922。 2. 樣本進度改成只算現行規則版本:顯示「10 / 100(v5)」並列出 「另有舊規則 v1 33 筆、v2 5 筆不列入計數」。戰情板.py 與 看報表.py 都改了。
順手修掉一個沒人發現的 bug:看報表.py 第 666 行用 s 當迴圈變數, 把第 543 行的統計結果 s 蓋掉,導致後面 s["n"] 丟 KeyError、整份報表產不出來。 這個迴圈只有在「持倉加過碼(有子倉)」時才會跑,所以是 BNCUSDT 加碼之後才開始壞的。 改名成 sp。備份 看報表.py.bak_樣本進度分版本_20260922。
這兩個 bug(健檢用錯尺、報表變數覆蓋)都不改變進出場語意,依 (b) 的定義不重數樣本。
問題:47 筆實單橫跨三個規則版本,「累積 100 筆後逐條檢視」到底在數什麼?
使用者選 (b):只有「改變進出場語意」的改動才把計數歸零; 修 bug、修誤報、改顯示、改文件都不重數。
為什麼是這個:它跟同一天訂的「調參數 vs 修錯誤」是同一條線。 今天修的健檢誤報(保本用錯尺)不該讓樣本歸零——它根本沒碰交易邏輯; 但 2026-09-15 的加碼機制重做(門檻 0→2R、改調停損模式)確實換了一個系統,應該歸零。
操作方式:用 交易紀錄.csv 既有的 規則版本 欄位,取開頭的版本號(v1/v2/v5)當計數依據。
判斷「會不會影響語意」的標準:這個改動會不會讓同一段 K 線跑出不同的進場、 不同的出場點、或不同的加碼行為?會 → 升版;不會 → 不升版。
現況:現行版本是 v5 v3+加碼調停損(加100%/門檻2R), 可比較樣本 10 筆(不是 47 筆)。三個版本的每筆 R 分別是 +0.222/−0.502/+2.423。
已套用:看報表.py 與 戰情板.py 的樣本進度改成只算現行版本, 同時把舊版本的筆數列出來,避免「總數看起來快到了」的錯覺。
怎麼查的(使用者:「把大單該加碼的補上,而不是不該加碼的導致停損亂掉」→ 授權重播): 把 13 筆「走到 2.5R 以上卻沒加碼」的線上單,用 shadow_bot.check_add_on 逐根重播 (腳本 實驗腳本/replay_addon.py,只讀不寫)。
第一個更正:上一段推測「線上每小時才檢查一次、回測逐根檢查」是錯的。 shadow_bot.py:2062 每一輪都從進場那根重跑所有 30M K 棒(涵蓋進場 為真時), 跟回測同一套語意。沒有取樣密度問題。
第二個更正(關鍵):47 筆實單橫跨三個規則版本,不能混在一起統計。
| 規則版本 | 筆數 | 每筆R | 走到2.5R | 其中有加碼 |
|---|---|---|---|---|
| v1 舊規則 | 33 | +0.222 | 12 | 3(25%) |
| v2 | 5 | −0.502 | 1 | 0 |
| v5 現行 | 10 | +2.423 | 6 | 3(50%) |
加碼機制是 2026-09-15 才重做的(門檻 0→2R、改調停損模式), 所以 v1 那 33 筆根本不是同一套加碼邏輯。 重播找到的 3 筆「該加卻沒加」(ZECUSDT 09-05、SOLVUSDT 09-07、NEARUSDT 09-14) 全部是舊規則的單——是我拿今天的設定去判昨天的系統,不是漏加。
結論:現行 v5 規則下一筆都沒有漏加。 走到 2.5R 的 6 筆裡 3 筆有加碼; 另外 3 筆(NEARUSDT 12.36R、ALCHUSDT 10.68R、SOLVUSDT 4.73R) 經重播確認整段沒有出現新的突兀量+回測不破,照規則本來就不該加。 這正是設計要的:只在新訊號出現時加,不是價格拉回就攤平。
第三個更正(影響最大):2026-09-22 逐筆盤點 那段與稍早做的 「實單 47 筆 vs 回測」基準對照表(每筆 +0.639 vs 0.808)無效—— 它把三個系統混在一起。可比較的樣本只有 v5 的 10 筆。
這連帶影響「累積 100 筆後逐條檢視」:100 筆是指哪個版本的 100 筆? 用總數算是 47/100,用可比較樣本算只有 10/100。已列入 覆盤待議.md。
問題(使用者):「加碼 2 次這個基準是怎麼來的?加碼頻率是否太高?」
設定.ini 裡它是唯一沒有證據註解的加碼參數。旁邊的 加碼比例 = 1.0、加碼門檻R = 2.0 都附了四窗口同批對照(批次 20260915-1646/1712),只有這行光禿禿。 搜 決策紀錄.md、覆盤待議.md、參數掃描.csv、參數掃描2.csv—— 「最多加碼次數」沒有被掃過、也沒有被記錄過。它是預設值,不是結論。
| 加碼次數 | 730天 889 筆 | 365天 429 筆 |
|---|---|---|
| 0 次 | 526(59.2%) | 258(60.1%) |
| 1 次 | 361(40.6%) | 171(39.9%) |
| 2 次 | 2(0.2%) | 0(0.0%) |
被 加碼總保證金倍數 = 2.0 卡死:加碼比例 = 1.0 表示第一次加碼就讓部位翻倍, 剛好頂到保證金上限,第二次結構上不可能發生。那 2 筆例外是 加碼後最壞R = 0 讓第一次加得比較少才留的縫。要真能加兩次,得先放寬保證金倍數—— 而那條註解寫著「帳戶只有 520U,真倉上線前要確認帳戶吃得下」。
上面 2026-09-22「逐筆盤點」那段寫「142 筆吐回裡有 123 筆有加碼」, 並把機制歸到加碼調停損。那是錯的推論。 控制變因之後(只比都走到過 2.5R 的單):
| 730天 | 365天 | |
|---|---|---|
| 沒加碼 | 45 筆,吐回 42.2%,每筆 +2.831 | 30 筆,吐回 46.7%,每筆 +2.645 |
| 有加碼 | 295 筆,吐回 41.7%,每筆 +3.670 | 137 筆,吐回 39.4%,每筆 +4.031 |
吐回率跟加不加碼無關,大約就是 42%,兩窗口一致。加碼組的每筆 R 還明顯更高。 吐回的單大多有加碼,只是因為走到 2.5R 的單本來就有 87% 會加碼——又是一次 「結果當成原因」的誤讀,跟「加碼1次勝率 96%」是同一個坑。
所以「加碼頻率太高」在回測數據上不成立。 40.8% 的加碼率沒有造成傷害。
只看走到 2.5R 以上的單:
| 有加碼的比例 | |
|---|---|
| 回測 730天 | 295/340 = 86.8% |
| 回測 365天 | 137/167 = 82.0% |
| 線上實單 | 6/19 = 31.6% |
線上走到 2.5R 的單裡,只有三分之一加到碼。NEARUSDT(最高 12.36R)、 ALCHUSDT(10.68R)、ZECUSDT(7.31R)這幾筆大單一次都沒加—— 在回測裡這種單幾乎必定會加。
推測原因(未驗證):線上每小時跑一輪,但進場時框是 30M, 等於每 2 根 K 棒才檢查一次加碼條件;回測是逐根檢查。 加碼要求「新突兀量+回測不破+離上次進場至少 6 根」,窗口可能就這樣錯過。 已列入 覆盤待議.md。這條若成立,屬於「實作跟回測不同步」,不是參數問題。
怎麼發現的:使用者質疑「有問題的應該提早調整,不用等到 100 筆,讓數據更有參考價值」。 為了確認線上到底還有沒有已知問題,跑了 healthcheck.py —— 報出 1 個異常。
異常:幣圈 BNCUSDT 最高到 4.63R 卻沒保本(規則是 >=4.0R)。
查下去是誤報,原因是兩把尺:
這把尺 2026-09-19 就決定故意不動(它是拿初始風險在定停損)。
max(歷史最高, 混合R, maxR)。
(7.024 − 5.836) ÷ 0.3875 = 3.07R,沒到 4.0,照規則本來就不該保本。
已修:健檢的保本檢查改用初始倉的尺重算,訊息同時印出兩個值好對照。 重跑健檢「一切正常」。備份 healthcheck.py.bak_保本兩把尺_20260922。
這是同類誤報的第二次(第一次是 09-19 門檻寫死 2.5、設定卻已改 4.0)。 healthcheck.py 第 56 行本來就留著那次的註解。 健檢的尺只要跟線上不同步,報出來的就不是異常而是雜訊 —— 這種東西比不檢查更糟。
順帶一提:BNCUSDT 本身是「高峰吐回」的線上實例 —— 最高 R 4.63、加碼 2 次、 現在目前R −1.15(混合成本)。回測量到每 6 筆有 1 筆,這是其中一筆正在發生。
參數掃描2.csv,同底圖。新增指標「高峰吐回%」=最高R>=2.5 但收<=0.5R 的佔比(現況 16.0%)。
結果(2026-09-22 18:24 讀檔,B/C 兩組已跑完,芭樂價R 的 730 天還在跑)
| 值 | 365 每筆R/回撤/吐回% | 365 總R÷回撤 | 730 每筆R/回撤/吐回% | 730 總R÷回撤 |
|---|---|---|---|---|
| 0(現況) | 0.974 / 26.5 / 16.6 | 16.2 | 0.808 / 17.3 / 16.0 | 41.6 |
| −0.25 | 0.953 / 28.8 / 16.3 | 14.4 | 0.787 / 19.2 / 16.2 | 36.3 |
| −0.5 | 1.020 / 31.0 / 15.7 | 14.2 | 0.823 / 21.1 / 15.9 | 34.1 |
| −1.0 | 1.018 / 33.7 / 14.8 | 12.9 | 0.828 / 24.8 / 15.1 | 29.0 |
結論:放寬確實有效——高峰吐回兩窗口都被壓下來(365 天 16.6→14.8、730 天 16.0→15.1), 每筆 R 還微升。但回撤同步惡化(365 天 26.5→33.7、730 天 17.3→24.8), 風險調整後兩個窗口都是單調變差(365 天 16.2→12.9、730 天 41.6→29.0)。
少被掃出去換來的是套得更久、賠得更深,划不來。維持 加碼後最壞R = 0。
這條的意義:使用者擔心的「停損被拉太高 → 容易被掃出去」確實存在(每 6 筆有 1 筆), 但放寬最壞R 不是解法。要解高峰吐回,得往別的旋鈕找。
| 啟動R | 365 每筆R/回撤/吐回% | 365 總R÷回撤 | 730 每筆R/回撤/吐回% | 730 總R÷回撤 |
|---|---|---|---|---|
| 4 | 0.750 / 20.9 / 14.0 | 15.9 | 0.638 / 16.8 / 14.5 | 34.2 |
| 5 | 0.782 / 20.9 / 15.4 | 16.5 | 0.640 / 18.4 / 15.3 | 31.2 |
| 6 | 0.859 / 16.7 / 16.2 | 22.6 | 0.704 / 18.4 / 15.8 | 34.4 |
| 8 | 0.919 / 25.6 / 16.6 | 15.8 | 0.772 / 17.3 / 16.2 | 40.0 |
| 10(現況) | 0.967 / 25.6 / 16.9 | 16.6 | 0.808 / 17.3 / 16.0 | 41.6 |
(730 天的 10 那格還在跑,表中用的是同一批的基準列=加碼後最壞R=0,設定完全等同 10R。)
結論:730 天隨啟動R 往上單調變好(34.2/31.2/34.4/40.0/41.6),提早收緊明顯比較差。 365 天除了 6R 那一格之外也是 10 最好。
那格 6R(22.6)是唯一亮點,但它靠的是回撤只有 16.7——同組其他格都是 20.9~25.6, 單一格的回撤跳動不足以支撐決策(位階那題就是這樣栽的)。維持 移動停損啟動R = 10。
使用者原話:「芭樂價不用太在意,只是部分艙位設定一個高價讓插針有機會吃到而已,不用太過調整。」
這句話推翻了這題的問法。 我一直把 芭樂價R 當成主要出場旋鈕在掃, 所以看到 365 天的 6R「回撤少 38%」會以為是重大發現。但那個效果是 「13.0% 的單走到 6R 就整倉收掉」換來的——跟「掛個高價等插針」完全是兩回事。 照使用者的定位,芭樂價根本不該影響回撤曲線。
維持 芭樂價R = 12。理由是定位,不是數據。 730 天三格照常跑完留檔, 但不作為調參依據——這題已經定案。
同時查出一個實作落差:現在的實作是整倉出場(shadow_bot.py 約 1229 行, exit_reason = "芭樂價停利" 後直接平掉整筆),全專案沒有任何「部分平倉/減倉/分批」機制, 線上與回測都沒有。所以「730 天 16 筆芭樂單貢獻 +287.3R=總獲利 39%」這個數字 是建立在整倉出場上的;若改成部分倉位,貢獻會按比例縮水, 其餘倉位改由移動停損處理。已列入 覆盤待議.md。
365 天:6→0.891(回撤 16.4、總R÷回撤 24.2、芭樂出場 13.0%)、8→0.909(25.6/15.7/6.3%)、 10→0.938(25.6/16.1/3.4%)、基準 12→0.974(26.5/16.2/2.3%)。
6 這格的樣子很特別:每筆 R 掉 8.5%,但回撤少掉 38%,風險調整後大勝現況。 它直接砍掉高峰吐回的發生路徑(走到 6R 先落袋)。但 730 天三格一格都還沒跑, 而且提早停利會砍掉大單(730 天走到 10R 以上的 42 筆貢獻 +573.6R)。等 730 天補完再說。
已套用:無。 B、C 兩題的結論都是維持原值,設定.ini 不需要任何修改。
730 天 889 筆(回測結果_全開730.csv):
出場原因:觸及停損 75.7%(每筆 −0.717R)/保本後收盤跌破MA30 17.8%(+4.194R)/ 芭樂價停利 1.8%(+17.954R)/移動停損 3.9%/觸及保本停損 0.8%。
型態:等距發散 429 筆 0.944R、擴散回碰 410 筆 0.676R(合計 94%,兩窗口都正); 盤整突破 35 筆(365天 0.046/730天 1.485,不穩);收斂上彎 15 筆 −0.175R。
分層:889 筆 100% 是 T1(線上 47 筆也有 46 筆 T1)。T2 實際上開不到。
停損來源:889 筆全部是「突兀量低點−0.5ATR」= low,線上 47 筆也一樣。 所以線上與回測在停損口徑上是同步的,覆盤待議.md 原本寫「現在設定 open」是過期資訊。
問題所在:
其中 142 筆(該群 47.7%、全部 16.0%)最後收在 0.5R 以下。
機制(不是 bug,是設計):加碼模式 = 調停損 + 加碼後最壞R = 0 → 加碼後把共用停損反解到「被掃到剛好打平」的位置,實測平均 +1.20R。 加碼量中位數是初倉的 94%(照設計翻倍,沒有失控)。
這正是使用者一直在講的那件事:「小筆加倉去增加獲利的R數, 並且不會讓停損拉到太高影響到被掃出去的機率」——它已經在發生,規模是每 6 筆有 1 筆。
所以真正該掃的旋鈕是 加碼後最壞R,不是 加碼後上調停損—— 前者才是決定停損被拉多高的東西,而且從來沒掃過。
| 加碼比例 | 365天 每筆R/回撤 | 730天 每筆R/回撤 |
|---|---|---|
| 0(完全不加碼) | 0.845 / 18.6 | 0.707 / 17.7 |
| 0.2 | 0.824 / 17.5 | 0.699 / 18.8 |
| 0.3 | 0.866 / 21.4 | 0.723 / 19.0 |
| 0.5 | 0.937 / 25.6 | 0.747 / 18.5 |
| 1.0(現況) | 0.935 / 25.5 | 0.784 / 16.8 |
結論一:加碼有價值,兩窗口一致(+0.090/+0.077 每筆),730 天回撤還更低。
結論二:加碼比例這題沒有答案,不要動。 R 的分母是初始風險, 所以加得多=下注大,期望值自然高,不能直接比。公平指標是 總R÷回撤: 730 天 1.0 最好(41.9),但 365 天 0.2 最好(19.5)、1.0 倒數第二(15.8)。 兩窗口矛盾 → 維持 1.0 不動。
要避免的誤讀:逐筆 CSV 顯示「加碼0次的單勝率 6.1%、每筆 −0.672R; 加碼1次的單勝率 95.8%、每筆 +2.999R」——這不是加碼的功勞。 加碼門檻是 +2R,所以「有加碼」等於「這單已經走到 +2R」。那是結果不是原因。 真正的證據只有上面那張 A/B 表。
原始資料:參數掃描.csv。底圖:群組定義/四個位階全開/池100。
| 芭樂價R | 365天 每筆R | 730天 每筆R | 實際觸發% |
|---|---|---|---|
| 0(完全不掛) | 0.883 | 0.755 | 0.0 |
| 12(現況) | 0.943 | 0.823 | 2.1 / 1.8 |
| 15 | 0.914 | 0.768 | 0.7 / 0.4 |
| 20 | 0.900 | 0.760 | 0.2 / 0.1 |
| 25 | 0.893 | 0.753 | 0.0 |
| 30 | 0.893 | 0.745 | 0.0 |
| 40 | 0.893 | 0.746 | 0.0 |
結論:兩個窗口一致,12 最好,往上單調變差,25 以上觸發率 0.0%—— 等於沒掛停利,數字就退回「不掛」那一排。插針到 +20R 的機率只有 0.1%。
使用者原本的假設是「幣圈上下插針情況大,芭樂價設高一點、數倍都不要緊等著插針」。 數據不支持這個假設:插針確實有,但不會插到 20R 以上。
反過來看這機制本身很重要:730 天 16 筆芭樂單貢獻 +287.3R, 佔總獲利的 39%——1.8% 的單撐起四成。所以不是要拿掉,是點位不能設高。
維持 芭樂價R = 12。 12 是測過的最低值,往下 6/8/10 第二輪在掃。
已完成,結果見下面 2026-09-22 兩段。原始資料 參數掃描.csv。
用 回測結果_全開730.csv 逐筆重新加權算的(倍數只縮放倉位、不改變進出場, 所以不用重跑回測)。公平指標是 總R ÷ 回撤(倍數同乘常數時這個比值不變)。
| 方案 | 總加權R | 回撤 | 總R÷回撤 |
|---|---|---|---|
| 全 1.0(現況) | 691.0 | 27.6 | 25.0 |
| 0=.5 1=1 1.5=.75 2=1 | 569.7 | 22.9 | 24.9 |
| 0=.5 1=1.25 1.5=.75 2=1 | 600.0 | 26.2 | 22.9 |
| 0=.3 1=1 1.5=.5 2=1 | 466.4 | 19.8 | 23.6 |
| 0=0(不做試倉) | 630.9 | 26.0 | 24.3 |
| 0=.5 1=1.5 1.5=.5 2=1 | 539.0 | 27.6 | 19.5 |
結論:縮小位階0/1.5 確實能把回撤從 27.6 壓到 19.8, 但少掉的報酬剛好等比例,風險調整後沒有變好,全 1.0 反而最高。 差距(25.0 vs 24.9 vs 23.6)都在雜訊內。
不套用位階倉位倍數。 要用試倉的話,理由只能是「主觀上不想在沒結構時壓大注」, 不能宣稱它讓績效變好——數據不支持。 365 天窗口(回測結果_全開365.csv,429 筆)同樣的結論,而且更明確:
| 方案 | 總加權R | 回撤 | 總R÷回撤 |
|---|---|---|---|
| 全 1.0(現況) | 404.7 | 18.6 | 21.8 |
| 0=.5 1.5=.75 | 318.0 | 14.9 | 21.3 |
| 0=.3 1.5=.5 | 248.0 | 13.0 | 19.1 |
| 位階0 不做 | 348.6 | 18.6 | 18.7 |
兩個窗口都是「全 1.0 最高」。分級下注這題結案:不做。
另外 365 天四個全開的各位階是 位階1.5 (1.082) > 位階0 (0.985) > 位階2 (0.739) > 位階1 (0.726), 跟 730 天的排序(位階1 最好)不一樣。所以「哪個位階最好」只有 730 天那組站得住, 365 天這組要當成雜訊看待——這也是為什麼要兩個窗口都看。
原始資料:位階掃描.csv(16 組)。倉位倍數全 1.0。
每個位階「單獨跑」:
| 只做 | 365天 筆/每筆R/回撤 | 730天 筆/每筆R/回撤 |
|---|---|---|
| 現行 位階1,2(對照) | 391 / 0.841 / 23.2 | 824 / 0.750 / 16.0 |
| 群組 位階0 | 133 / 0.660 / 17.9 | 293 / 0.442 / 36.6 |
| 群組 位階1 | 82 / 0.588 / 12.7 | 195 / 0.602 / 14.8 |
| 群組 位階1.5 | 348 / 0.912 / 25.0 | 749 / 0.629 / 25.7 |
| 群組 位階2 | 204 / 0.799 / 20.8 | 459 / 0.649 / 25.5 |
| 群組 位階1,2 | 245 / 0.749 / 19.0 | 558 / 0.673 / 17.1 |
| 群組 位階1,1.5,2 | 409 / 0.807 / 25.2 | 869 / 0.722 / 16.7 |
| 群組 四個全開 | 435 / 0.882 / 24.5 | 911 / 0.759 / 16.7 |
> ⚠ 下面那張「全開時」的表數字是錯的(2026-09-24 查出取自別批回測)。 > 正確數值見本檔 2026-09-24 回測 R 數與績效全面核對 那段的權威數字表。 > 保留原表是為了留下更正痕跡,不要引用它。
但是「單獨跑」不等於實際表現。 同標的同時間只能有一個倉位、還有出場冷靜期, 所以先出現的位階會吃掉名額。四個全開時(730 天,回測結果_全開730.csv):
| 位階 | 全開時 筆數/每筆R | 單獨跑時 筆數/每筆R |
|---|---|---|
| 位階0 | 99 / 0.608 | 293 / 0.442 |
| 位階1 | 130 / 0.931 | 195 / 0.602 |
| 位階1.5 | 467 / 0.782 | 749 / 0.629 |
| 位階2 | 215 / 0.674 | 459 / 0.649 |
結論: 1. 730 天實際運作下的排名是 位階1 (0.931) > 位階1.5 > 位階2 > 位階0。 但 365 天的排名完全不同:位階1.5 (1.082) > 位階0 (0.985) > 位階2 (0.739) > 位階1 (0.726), 位階1 反而墊底。兩個窗口不一致 → 「哪個位階最好」目前沒有定論, 不要拿單一窗口的排名去做決策(我 2026-09-21 就是只看 730 天就下了結論,那是錯的)。 2. 群組定義四個全開,兩個窗口都小勝現行對照(0.882 vs 0.841、0.759 vs 0.750), 而且多約 10% 筆數、730 天回撤持平。 3. 只做位階1+位階2 會變差(0.749/0.673),因為丟掉了 1.5 的量。 4. 我事前預測位階0 單獨跑會是負的,猜錯了——兩個窗口都是正的。 但它每筆最低、續抱R 最低(0.799),賺的是「小R、多次、抱不久」, 剛好符合「試倉」的性質。
尚未套用:是否把線上改成「群組定義+四個全開」還沒拍板。
數據:第 1 次再進場 0.640、第 2 次 0.598、第 3 次 −0.176。
結論:再進場沒有價值,越後面越差。不做。
原因:線上每小時從全市場重算 T1(一天會經過 43~53 個不同標的), 回測只在每日收盤重算一次(一天 ≤ 20 個)。池開到 100 之後回測是 3.33 筆/天,跟線上一致。
結論:不是程式錯,是取樣密度不同。之後所有回測一律用池100, 否則跟線上不可比。
問題:使用者說「位階2 應該沒有錯誤,之後要做加碼,不應該捨去」。
驗:原本的位階2 只判「過前高後回撤」,沒有判回撤有沒有守住。 補上 位階2守住(回撤低點要 ≥ 前高×(1−0.05))與 位階2站上倍數 = 1.0。
數據:730 天每筆 R 0.374 → 0.679。
結論:使用者是對的,問題出在條件沒實作完,不是這個球路不能打。
已套用:[參數] 位階2守住 = 0.05、位階2站上倍數 = 1.0。備份 .bak_位階2_20260919。
問題:戰情板出現「最高R(3.09) 比 目前R(3.22) 還小」。
原因:加碼後 目前R 用混合成本算,最高R 還在用初始倉算。
已套用:最高R 改成 max(歷史最高, 混合R, maxR)。 trail_update() 內部的 maxR 故意不動——它是拿初始風險在定停損的尺。 2026-09-21 線上確認正常:KAVAUSDT 最高+3.74R > 目前+2.80R。
同批修掉的還有:健檢重播用預設值而不是設定檔(假警報)、健檢 保本R 寫死 2.5 但設定是 4.0、驗證出場.py 只傳 ma_n=30 導致用的是另一套規則。
問題:風報比門檻 2.5 從來沒擋過任何一單。
數據:回測裡還留著線上 2026-09-07 就拿掉的假項 entry*(1+5*dist), 讓 rr 恆 ≥ 5(實測 44 筆最小值就是 5.00、84% 恰好等於 5.00)。
結論:回測與線上不同步,風報比濾網在回測中是死的。
已套用:回測改呼叫共用的 B.目標價()。另外實測發現把濾網修活反而更差 (前高目標會把創新高的突破單擋掉),所以門檻維持 2.5 不動。
問題:台股從開始以來一筆單都沒有。使用者問「你的空頭判定是否正確?不是糾結也算空頭吧?」
驗:ma_bear_veto() 只看排列。排列是落後事實——3 日線的 MA40 等於 120 天記憶, 分不出「還在跌」和「跌完正在翻」。新增 mode="排列+斜率":空排且最短均線沒上彎才否決。
數據:拿 6414.TW 對使用者自己的圖,新版 2023-11-15 放行、舊版拖到 2024-01-15。
結論:舊判定確實會把糾結/剛翻多當成空頭擋掉。
已套用:設定.ini [台股] 大時區否決方式 = 排列+斜率、日線否決方式 = 排列+斜率、 否決斜率根數 = 3、池大小 = 100。備份 .bak_空頭判定_20260919。