在一個市場交易、卻拿另一個市場當濾網的策略,需要第二個市場的 K 線,而你圖表的 CSV 裡沒有這些資料。本文說明 PineForge 引擎執行這種腳本需要什麼、缺少 K 線時怎麼處理,以及 Docker 映像與 MCP 伺服器提供了什麼。
2026-10-04 更新:自 1.1.0 版起,pineforge-release 映像檔會依
PINEFORGE_SYMBOL_FEEDS指定的 JSON 索引檔,為request.security載入其他商品的 K 線;每個請求的時間週期各對應一個資料源,不做任何彙總(引擎 #327、pineforge-release #23;詳見引擎的 1.1.0 變更紀錄)。本文其餘內容仍維持 2026-10-02 發表時的原樣,以 1.0.1 版為準。
你的策略交易一檔股票,但只在那斯達克處於上升趨勢時才買進。在 TradingView 上,這只要一行,而且跑得起來,因為 TradingView 有每個標的的 K 線。在你的 CSV 上執行的回測工具,手上卻只有圖表本身的 K 線。跟它要 QQQ,它只有三條路可走:拒絕、中止,或是默默拿錯的市場來算濾網。
PineForge 走的是第二條路,而且只在不得已時才這麼做:把 QQQ 自己的 K 線交給引擎,腳本就能執行。
需要第二個市場的那一行
像這樣的腳本,只在 QQQ 站上 50 日均線時做多:
//@version=6
strategy("QQQ regime filter", overlay=true)
qqqUp = request.security("NASDAQ:QQQ", "D", close > ta.sma(close, 50))
fast = ta.sma(close, 20)
if ta.crossover(close, fast) and qqqUp
strategy.entry("L", strategy.long)
if ta.crossunder(close, fast)
strategy.close("L")
問題出在第 3 行。它的運算式 close > ta.sma(close, 50),是在 QQQ 自己的日 K 線上計算:QQQ 的收盤價、QQQ 的 50 日均線。圖表的 K 線再怎麼彙總,也算不出這些值。直到不久之前,PineForge 都會直接拒絕這支腳本。現在它可以執行了,前提是執行引擎的人得把 QQQ 的 K 線交給它。
引擎需要什麼
引擎公開的 C 標頭檔裡,有一個專門做這件事的呼叫(pineforge.h):
PF_API int strategy_set_symbol_feed(pf_strategy_t s, const char* key, const char* timeframe,
const pf_bar_t* bars, const int64_t* close_ms, int n);
可以把它看成三項要求。key 必須和腳本傳入的字串完全相同,也就是 NASDAQ:QQQ,K 線才會對應到要它們的那個呼叫。timeframe 必須是請求的那個時間週期:請求日線,就得給日 K 線;同一個標的、其他時間週期的資料不算數。還有 close_ms,它替每根 K 線提供各自的收盤時間,因為「不會替這個標的猜測交易日曆」:除非 K 線本身說了,否則引擎不知道那斯達克幾點收盤。至於標的的交易時段、幣別和 tick 大小這類資訊,則可以選擇透過另一個同系列的呼叫提供。
照誰的時鐘
收盤時間之所以重要,是因為兩個市場收盤的時刻不同。在圖表的每一根 K 線上,引擎交給這個請求的,是另一個標的在這根圖表 K 線收盤時已經收盤的最後一根 K 線;如果開啟了 lookahead,則是在它開盤時已經開盤的最後一根(pineforge.h)。所以「收盤時間晚於圖表交易時段收盤的日 K 線,會晚一個圖表交易日才被看到,和 TradingView 看到的一樣」(MTF 指南)。
這是 TradingView 的規則,不是 PineForge 圖省事的捷徑。引擎的測試裡保留了一份 TradingView 匯出檔:一張請求美元指數的黃金日線圖。黃金在週日晚間開盤的那根日 K 線,在週一 17:00 ET 收盤;美元指數的週一 K 線則在 19:00 ET 收盤,晚了兩個小時。所以在 TradingView 上,那根黃金 K 線讀到的是週五的美元指數 K 線,週一那根要等到下一根黃金 K 線才會出現(fixture 說明)。回測工具如果在另一個市場的 K 線收盤之前,就把它交給圖表 K 線,那就是在偷看未來。
缺少 K 線的時候
腳本仍然可以轉譯,但會附上一則警告:這個請求讀的是「另一個標的的 K 線」,而且「如果沒有安裝任何資料,執行到讀取它的值時,就會以錯誤中止」(codegen)。第一次讀值時,回測就會中止,並印出一則指名這個呼叫的訊息(原始碼):
request.security("NASDAQ:QQQ", "D", ...) at line 3: no data is pinned for this request, and its value was read
它絕對不會做的,是拿圖表的 K 線頂替 QQQ(變更紀錄)。用錯的市場算出來的濾網,會畫出一條看似合理、其實毫無意義的權益曲線,所以中止是比較安全的失敗方式。有兩種情況不會中止:一是值從來沒被讀到的請求(例如藏在一個關閉的輸入參數後面);二是值只會流向繪圖、警報或表格的請求,它會變成 na,並附上「交易不受影響」的警告(codegen)。
Docker 映像與 MCP 伺服器提供什麼
它們都只回測一個市場的 K 線:圖表本身的那一個。
- Docker 映像接收
strategy.pine和一份ohlcv.csv(README),它的執行腳本不會安裝其他標的的 K 線。QQQ 那支腳本在這裡會印出上面那則訊息並中止,映像則以結束碼 4 退出。 - 本機 MCP 伺服器建立在這個映像之上,回測的也是一份 CSV。它的 README 寫得很清楚:它「不會安裝其他標的的 K 線……例如對其他標的的
request.security,引擎本身支援,但在這裡,只要請求的值可能影響到交易,回測就會中止」(README)。 - 託管 MCP 伺服器接收標的、時間週期和交易所,自己去抓那一個市場的 K 線:而且只支援加密貨幣,所以像 QQQ 範例這種股票策略,在那裡根本無法執行(同一份 README)。
這裡有個常讓人踩到的陷阱:Docker 映像和本機伺服器從來不會告訴引擎圖表是哪個市場,所以用字串寫出來的標的,一律算作其他標的,即使它寫的就是圖表本身的市場(支援範圍說明)。要引用圖表本身的標的,請寫 syminfo.tickerid。對它發出更高時間週期的請求,不需要額外資料,因為引擎會用圖表的 K 線組出那些 K 線(MTF 指南)。但有一個限制:在美股或 CME 期貨的盤中圖表上,TradingView 的日 K 線是交易所自己的日 K,用的是官方收盤價,任何彙總方式都重現不出來(pineforge.h)。
這對你代表什麼
- 用圖表本身的市場當濾網? 改用
syminfo.tickerid,腳本只靠你的 CSV 就能執行。 - 用其他市場當濾網? 自己執行引擎,並在回測開始前,安裝那個市場的 K 線和它們的收盤時間。引擎 repo 的測試執行腳本就是現成的範例:它從每支腳本各自的請求清單安裝這些資料,清單的欄位由
scripts/run_strategy.py定義。 - 要和 TradingView 比對? 在
lookahead維持預設關閉的情況下,如果另一個市場收盤比你的晚,它的日 K 線會晚一天才到。這是 TradingView 的行為,引擎也照樣對齊。
2026-10-02 以當天發行的 PineForge 引擎與 codegen 1.0.1 驗證;這項行為最早在 1.0.0 推出。
下一步
- 從 Claude 或 Cursor 回測:兩個 MCP 伺服器的逐步教學。
- 離線執行 PineForge:在你自己的資料上跑 Docker 映像。
- Pine v6 的型別系統:實務筆記:包括
request.security的 lookahead 預設值在各個 Pine 版本間的變化。