跨標的與多時間框架
request.security() 在不同標的和/或時間框架的上下文中對表達式求值,並將結果對齊到當前圖表 bar。它是 Navi 中存取多時間框架(MTF)資料和其他標的資料的主要方式。
基本語法
request.security(symbol, timeframe, expression, gaps, lookahead, ignore_invalid_symbol, currency, calc_bars_count)| 參數 | 類型 | 說明 |
|---|---|---|
symbol | string | 標的識別符,如 "AAPL.US" 或 syminfo.tickerid |
timeframe | string | 時間框架字串,如 "D"、"W"、"60" |
expression | 任意 series | 在請求的標的/時間框架上求值的表達式 |
gaps | BarmergeGaps | BarmergeGaps.Off(預設):延續最後值;BarmergeGaps.On:無新值時發出 na |
lookahead | BarmergeLookahead | BarmergeLookahead.Off(預設)或 BarmergeLookahead.On |
ignore_invalid_symbol | bool | 若為 true,未知標的返回 na 而不報錯 |
currency | string | 價格轉換的目標貨幣 |
calc_bars_count | int | 可選的正整數,用於限制請求流載入的最近歷史視窗大小 |
基礎示例
高時間框架收盤價
indicator("日線圖上的週線收盤價", overlay: true);
let weekly_close = request.security(syminfo.tickerid, "W", close);
plot(weekly_close, "週線收盤", color: color.BLUE);其他標的
indicator("AAPL 圖上的 SPY", overlay: false);
let spy_close = request.security("SPY.US", "D", close);
plot(spy_close);高時間框架指標
indicator("週線 RSI");
let weekly_rsi = request.security(syminfo.tickerid, "W", ta.rsi(close, 14));
plot(weekly_rsi);
hline(70);
hline(30);時間框架字串
| 字串 | 含義 |
|---|---|
"1"、"5"、"15"、"60" | 分鐘 |
"D" | 日線 |
"W" | 週線 |
"M" | 月線 |
"3M"、"6M" | 多月 |
使用 timeframe.period 引用圖表自身的時間框架。
預熱
被請求的表達式本身就是一條序列:它在被請求的週期上逐 bar 求值,擁有自己的歷史。 所以週線請求裡的 ta.rsi(close, 14) 需要十四根週線才有意義 —— 而這些 bar 通常比圖表的第一根還要早。
引擎會去要它們。週線流的請求含義是「覆蓋圖表首根 bar 之後,並且可以往前多取」, 同時附帶該表達式讀多深,因此遵守這一點的 provider 會把更早的週線一併返回, plot 從圖表第一根 bar 起就有穩定的值。
是否真的如此取決於你的資料來源。只返回圖表首根 bar 之後資料的 provider 依然是正確的 —— 表達式只是自己慢慢預熱,plot 會 na 到它讀滿為止。在日線圖上,一個沒有預熱的 週線 ta.sma(close, 10) 大約要十週才出第一個值。看到這種現象,就說明資料流在圖表 邊界處被截斷了。
內建 provider、playground 和 navi-chart 都會往前多取。
calc_bars_count
當請求只需要最近一小段歷史時,可以使用 calc_bars_count。
- 傳入正整數後,provider 最多為該請求流載入這麼多最近 bar。
na表示不設定上限:請求錨定在圖表上,provider 可以按上文所述往前多取用於預熱。
calc_bars_count 是一個上限,因此它會繞開上文的預熱 —— 請求含義變成「最近 N 根」, 不含更早的。設得過小時,表達式裡的指標可能沒有足夠的 bar 來收斂。
let recent_weekly = request.security(syminfo.tickerid, "W", close, calc_bars_count: 2);gaps(空缺填充)
當請求的時間框架高於圖表時間框架時,高時間框架 bar 收盤的頻率低於圖表 bar 推進的頻率。
BarmergeGaps.Off(預設):最後已知值向前延續——序列中不會出現na。BarmergeGaps.On:每個高時間框架 bar 尚未收盤的圖表 bar 都會發出na。
// Off(預設):weekly_close 始終有值
let weekly_close = request.security(syminfo.tickerid, "W", close);
// On:除週五(週線 bar 收盤)外的所有交易日均為 na
let weekly_close_gaps = request.security(syminfo.tickerid, "W", close, gaps: BarmergeGaps.On);lookahead(超前讀取)
BarmergeLookahead.On 使表達式在週期內的第一個圖表 bar 就能看到高時間框架 bar 的最終值,而不是正在形成中的值。這會在歷史 bar 中引入未來資料洩漏——僅在明確需要時使用。
// 預設:看到正在形成的週線開盤價(本週內持續更新)
let weekly_open = request.security(syminfo.tickerid, "W", open);
// 使用 lookahead:週一即可看到已確認的週線開盤價
let weekly_open_confirmed = request.security(syminfo.tickerid, "W", open, lookahead: BarmergeLookahead.On);var 和 varip 變量
var 和 varip 變量需在腳本頂層宣告,不能在 expression 參數內部宣告。子實例會在請求的標的/時間框架上執行完整程式體,因此頂層的 var 狀態會在請求的時間框架的各個 bar 之間獨立累積:
indicator("累計成交量(週線)");
// 在頂層宣告——子實例在週線 bar 上累積此變量
var cum: float = 0.0;
cum += volume;
let weekly_cum_vol = request.security(syminfo.tickerid, "W", cum);
plot(weekly_cum_vol);每個 request.security 呼叫點都有獨立的子實例——其 var 狀態與主腳本及其他 request.security 呼叫互相獨立。
元組
表達式可以以元組形式返回多個值:
indicator("週線 OHLC");
let (w_open, w_high, w_low, w_close) =
request.security(syminfo.tickerid, "W", (open, high, low, close));
plot_candle(w_open, w_high, w_low, w_close);ignore_invalid_symbol
當標的可能不存在於資料提供者中時使用此參數:
let price = request.security("SOME.US", "D", close, ignore_invalid_symbol: true);
// 標的未識別時 price 為 na,不會觸發執行時錯誤不使用此參數時,未識別的標的會觸發執行時錯誤並中止執行。
request.security_lower_tf
獲取低時間框架資料時,使用 request.security_lower_tf。它返回一個 Array<T>,包含當前圖表 bar 內所有子 bar 的值,按升序排列:
indicator("日線圖上的分鐘級最高價");
// 返回每根日線 bar 內所有 1 分鐘 bar 的最高價
let minute_highs = request.security_lower_tf(syminfo.tickerid, "1", high);
// 當前日線 bar 內的最高 1 分鐘最高價
let intraday_high = minute_highs.max();
plot(intraday_high);當某個 bar 內沒有子 bar 資料時,陣列為空(minute_highs.size() == 0)。
Ticker 表達式
Ticker 表達式是一個將多個標的透過算術運算子組合的字串。Navi 會將其分解為獨立的 DataProvider 請求,逐 bar 對表達式求值,並將結果作為單一序列返回。
支援的運算子
| 運算子 | 示例 | 結果 |
|---|---|---|
* | "AAPL*2" | 標的值 × 純量 |
/ | "AAPL/SPY" | 兩個標的的比值 |
+ | "AAPL+MSFT" | 兩個標的之和 |
- | "AAPL-MSFT" | 兩個標的之差 |
運算元可以是標的字串("TICKER.MARKET")或數字字面量。運算子優先順序與標準數學一致,必要時可使用括號。
示例
加權組合(50/50 投資組合)
let blend = request.security("AAPL.US*0.5+SPY.US*0.5", "D", close);相對表現(比值)
// AAPL 相對於 SPY 的價格——買一股 AAPL 需要多少股 SPY?
let ratio = request.security("AAPL.US/SPY.US", "D", close);
plot(ratio);價差(差值)
// 黃金/白銀價差
let spread = request.security("GC1!.US/SI1!.US", "D", close);
plot(spread);多標的等權指數
// 四隻科技股等權平均
let tech = request.security(
"AAPL.US*0.25+MSFT.US*0.25+GOOGL.US*0.25+AMZN.US*0.25",
"D",
close
);
plot(tech);執行原理
對於 "AAPL*0.5+SPY*0.5" 這樣的表達式,Navi 的處理步驟:
- 提取各個標的(
AAPL、SPY),透過DataProvider獲取對應的 K 線資料。 - 每個 bar 上,使用各標的子實例中請求的
expression欄位(如close)對算術表達式求值。 - 將計算得到的純量結果對齊到圖表 bar 後返回。
表達式中的每個標的都計入 max_security_calls 限制,與一般 request.security 呼叫相同。
限制
嵌套:
request.security的表達式內部可以再呼叫request.security,深度不限。沒有單獨的深度限制;約束它的是下面的子實例上限,因為每一層至少會建一個子實例。循環依賴會被拒絕:如果一串請求繞回了已經經過的呼叫點,這個過程不會結束。執行會以一條指明成環的錯誤停止,而不是耗盡記憶體。
子實例上限:
ExecutionLimits::max_security_calls(預設 40)限制一次執行最多可以建多少個子實例。子實例是一個完整的實例 —— 有自己的狀態、序列緩衝和bar_index—— 而一個呼叫點可能不止花掉一個:- 後續 bar 上換了
symbol或timeframe,就會為那條序列另開一個子實例,並保留原來的以備該呼叫點回到它; - 表達式讀了另一個請求的結果,那個請求就成為本子實例要求值的一部分,並且是在它自己的序列上求值 —— 所以四個互相讀取的請求組成的鏈條要花十個子實例,而不是四個。
指名同一
(symbol, timeframe)的呼叫點共用取得的資料,但不共用計數 —— 同一標的的四個欄位算四次。- 後續 bar 上換了

