同一支 Pine 腳本的兩份回測,很少能對到分毫不差,所以「和 TradingView 一致」這句話,要先講清楚比的是什麼、多接近才算夠接近,才有意義。本文說明一次受評的回測是什麼、它的交易如何和 TradingView 的配對、五個等級各自的要求,以及一次程式碼變更如何評判。
很多回測工具都說自己和 TradingView 一致。但同一支 Pine 腳本的兩份回測,幾乎不可能對到分毫不差,所以在知道比的是什麼、多接近才算接近之前,這句話其實沒什麼意義。我們的成績表替 7,989 次回測各標上五個詞之一,其中 7,905 次是「excellent」。本文說明這個詞和另外四個詞各代表什麼。
一次回測,一份交易清單
評分的單位是探針:「一支從 TradingView 匯出、附上交易清單,並在相同 K 線上逐筆重播的策略」(codegen README)。腳本沿用自己的輸入參數與預設值,等級比較的是兩份交易清單:TradingView 的,以及 PineForge 在相同 K 線上產生的那一份。
同一支腳本,可以在好幾個市場上各當一支探針。這 7,989 次回測,包括開放語料庫 312 支策略中的 309 支,以及 741 支 TradingView 腳本的 7,680 支探針,分布在九個市場(加密貨幣、美國期貨與股票、一個印度指數、一個貨幣對,以及黃金),每個市場都跑 15 分鐘 K 線和日 K 線(成績表)。
交易怎麼配對
評分程式是一支公開的腳本:verify_corpus.py。對每一筆 TradingView 交易,它會在方向相同、還沒被配對、進場時間相差一小時以內、進場價相差 3.00 以內(以該市場自己的價格單位計)的 PineForge 交易中,挑出最接近的一筆來配對(配對、門檻)。接著量兩件事:TradingView 的清單重現了多少,以及重現出來的交易有多接近。
第一項叫涵蓋率,分母是 TradingView 所有已平倉的交易,而不只是兩份清單重疊的那一段。程式碼裡寫了原因:其他指標都是在配對結果自己界定的區間內計算,「所以少了這道關卡,一次幾乎什麼都沒重現的執行,也可能憑著碰巧重現的那一小段拿到最高等級(正式環境中實際發生過:實際涵蓋率只有 0.9%,卻評為『excellent』)」(評分程式)。涵蓋率成為關卡之後,有兩支語料庫策略掉到「moderate」:它們分別只重現了 TradingView 224 筆交易中的 209 筆,以及 241 筆中的 228 筆,這些缺口原本都被舊的區間藏住了。
五個詞
| 等級 | 重現的 TradingView 交易 | 交易筆數 | 進場價、出場價(p90) | P&L(p90) |
|---|---|---|---|---|
| excellent | ≥ 99% | 完全相同,且當 TradingView 在完全相同的時間、價格和方向上顯示兩個或以上不同的進場 Signals 時,引擎也在該處顯示相同數量的獨立進場(獨立進場識別) | 0.01% 以內 | 1% 以內 |
| strong | ≥ 95% | 6% 以內 | 0.1%、0.5% | 100% 以內 |
| moderate | ≥ 75%,且重疊區間內 ≥ 90% | |||
| weak | 至少一筆 | |||
| minimal | 零筆 |
「p90」的意思是每十筆交易中,有九筆至少這麼接近(門檻、等級階梯)。只要 TradingView 的交易最多只有一筆沒配對上,就能通過「excellent」與「strong」的涵蓋率門檻,所以短匯出檔邊緣的一筆交易,不會害策略丟掉等級。「excellent」完全不容許交易筆數有任何差異,程式碼給的理由是:「在大型策略裡,百分比門檻可能藏住幾十筆缺少或多出的交易」(評分程式)。出場使用移動停損的策略,門檻比較寬:出場價 0.05% 以內、P&L 100% 以內,因為移動停損在一根 K 線內的哪個價位成交,取決於 TradingView 的 K 線內價格路徑(評分程式)。
最差的那筆交易:印出來,但不評分
等級看的是第 90 百分位數,不是最差的那筆交易。有一支公開策略正好說明原因;以下是評分程式跑 order-harbor-stop-limit-01 的輸出(有刪節):
Matched: 471 (100.0% of TV)
Count delta: 0.0000% (OK; abs=0)
PnL p90 delta: 0.0381% (OK)
-- report-only (not gated; MAE/MFE are intrabar-path-limited) --
Entry/Exit/PnL p100: 0.0011% / 0.0084% / 4.9658%
-> excellent
看等級前面的最後一個數字:有一筆交易的 P&L 差了將近 5%。要求評分程式列出最差的幾筆交易(--show-diffs 3),可以看到這一筆 TradingView 的進場價是 1,970.36,PineForge 是 1,970.35,而這筆交易大約虧了 51 美分。一美分乘上約 2.5 單位是 2.5 美分,而 2.5 美分正是 51 美分虧損的 5%。如果以最差的交易來評等級,這支策略會因為一次進場差了一美分,就拿不到「excellent」;看百分位數則讓它通過,報告裡也照樣列出這個離群值。
怎麼評判一次變更
等級描述的是程式碼現在的樣子。一次變更則要看它讓什麼動了:同一批探針在變更前後各評一次分。規則要求 hard surface 不得有任何迴歸。至於其他所有市場與時間週期,則看「excellent」與「excellent+strong」兩個級距合併計算的得分:得分大於零就通過,前提是沒有任何探針一次掉出級距超過一個等級;得分剛好為零,則在沒有任何地方變差時通過(README)。
之所以看兩個級距,是因為各自都看得到對方漏掉的變動。策略從「strong」升到「excellent」,只會改變第一個級距的數量;從「moderate」升到「strong」,只會改變第二個。九月有一次變更讓 32 支探針升上「excellent」;其中兩支原本在「strong」以下,兩個級距都算到它們,所以這次變更的得分是 +34,而且沒有任何探針降級。所謂 hard surface,就是 15 分鐘 ETH 測試組:共 1,009 支探針,開放語料庫的 309 支策略也在其中。不管變更在其他地方進步多少,這裡的探針一支都不能降級。
什麼都沒動的時候
很多好的變更其實什麼都不會動:一次重構、一個新的 API,或是修掉一個測試集裡沒有任何策略會走到的情況。只改文件的變更,不需要重跑掃描(範例)。沒有讓任何探針進出級距的程式碼變更,得分就是零;依照 README 的規則,只要沒有任何地方變差就能通過:沒有任何等級改變時,標上「no-improve-no-regression」(沒有改善,也沒有迴歸);有東西在兩個級距看不到的地方改善時,例如某支策略從「weak」升到「moderate」,則標上「improved」。不過,得分為零也可能藏著迴歸,這時變更就不通過:例如一支探針在兩個級距之下從「moderate」掉到「minimal」,或是一支探針的降級正好抵銷了另一支的升級。
對這類變更來說,零變動是預期中的結果,但這證明不了其他東西都沒變,因為五個詞的刻度很粗。所以引擎的 CI 還會釘住引擎在開放語料庫上產生的每一份交易清單的雜湊值:某支策略的滑價只改動一個 tick,就會「讓它的交易和基準雜湊值改變,而 verify_corpus.py 仍回報 excellent=311, strong=0, anomaly=1」(CI 文件)。
這對你代表什麼
- 在畫廊頁面上,「excellent」代表:交易筆數和 TradingView 相同,TradingView 的交易至少重現 99%,而且每十筆交易中有九筆的價格與 P&L 落在上表的門檻內。對於「excellent」,當 TradingView 在完全相同的時間、價格和方向上顯示兩個或以上不同的進場 Signals 時,引擎也在該處顯示相同數量的獨立進場(獨立進場識別)。除了一支已註明、問題出在 TradingView 端的異常策略之外,畫廊裡每支策略都是「excellent」;「strong」只出現在非公開測試裡。
- 如果你要拿自己的回測工具和 TradingView 比對,也用同樣的方式:依進場配對交易、以 TradingView 的全部交易計算涵蓋率,並且看百分位數,而不是最差的那筆。
- 公開的部分可以自己重跑:照 README 裡的指令,就能建置、執行語料庫的 312 支策略並評分。非公開測試則是我們自己對未公開腳本的量測,其中大多是依 TradingView 的條款不能公開的社群腳本。
等級於 2026-09-29 量測,所用的引擎與 codegen 程式碼都已收錄在 1.0.0 版中。2026-10-02 發行的引擎與 codegen 1.0.1,也在同樣的 7,989 支探針上評過分,沒有任何一支探針的等級改變。
下一步
- 我們如何衡量對齊:目前的結果與資料來源。
- 瀏覽畫廊:每支語料庫策略的等級,以及兩邊的交易清單。
- 一則保證金對齊的故事:策略沒有達到「excellent」時,評分程式的輸出長什麼樣子,以及我們如何把其中一支追查到根本原因。