Volume Profile POC/VAH/VAL 是什麼?Pine v6 直接拿
你盯著 K 線發現蠟燭穿到某個看不見的價位就掉頭,回頭把 Volume Profile 疊上去,才知道剛好卡在昨天的 POC——這個 Volume Profile POC 你其實一直看得到,只是每次都事後諸葛。
以前把它自動化的方式只有兩種:拿 request.security_lower_tf() 抓分秒級 tick 再自己湊出成交分佈、或是換去 volume footprint 那張特殊 chart 用肉眼判讀。Pine Script(也就是 TradingView 內建的策略腳本語言)v6 加了第三種——request.footprint() 讓 POC、VAH、VAL 直接變成腳本裡可以用的一個數字。
這篇不打算把 Volume Profile 的所有玄學都討論一遍——像 HVN/LVN 的策略含義、Market Profile 的字母編碼、Composite Profile 怎麼疊,這篇都跳過。要處理的是三件比較窄的事:POC/VAH/VAL 分別代表什麼、request.footprint() 這個 v6 新函式的參數到底是什麼意思、以及開始用之前你會撞到的三個坑。
va_percent(預設 70%)為止的最高/最低價格格。Pine v6 的 request.footprint() 讓你在腳本裡直接呼叫 footprint.poc()、footprint.vah()、footprint.val() 拿到這三個 volume_row——但只有 Premium 與 Ultimate plan 拿得到,而且整支腳本只能呼叫一次。先把 Volume Profile POC 講清楚:POC、VAH、VAL 各自標的是什麼
Volume Profile 這張圖把時間軸上的成交量重新排列成沿著價格軸的橫向長條——每一個價格格(row)長多長,代表這個格子內累積了多少成交量。三個縮寫都是從這張直方圖抽出來的。
| POC | VAH | VAL | ||
|---|---|---|---|---|
| 全名 | Point of Control | Value Area High | Value Area Low | |
| 定義 | 範圍內成交量最大的那一格 | 從 POC 往兩邊收攏、到 va_percent(預設 70%)為止的最高價格格 | 同上但取最低價格格 | |
| 用途 | 最多人成交的價位、心理錨點 | Value Area 上沿 | Value Area 下沿 |
Value Area 的算法在文件裡的說法是「similar to the algorithm used by our Volume Profile indicators」——這是由官方定義推導出的結論,不是 TradingView 白紙黑字寫出來的一句話:官方沒有明講「這是 Market Profile 那套一 sigma 的 70% 規則」,只講預設是 70% 且可以改。看到別的地方寫 68% 或 68.27% 那多半是把統計上的一個 sigma 直接套進來——那不是官方數字,能不能對得起實際成交要自己驗。
為什麼一根蠟燭裡就有 POC——footprint 跟 Volume Profile 不是同一張圖
一般人講 Volume Profile 的時候,腦裡的圖多半是 TradingView 的「Fixed Range Volume Profile」或「Session Volume Profile」——一段時間(一天、一個 session、你選的區間)裡累積的分佈(Volume Profile 的一般用法在這篇有整理過)。footprint 不是那樣:它把「一根蠟燭」自己拆成一個小型的 Volume Profile,這根蠟燭橫跨的價格範圍被切成一格一格 row,每一格記著這根 K 棒內部的 buy/sell 成交量。
這件事對你自動化的影響是:你在 Pine v6 用 request.footprint() 拿到的 POC,是「這根 K 棒」的 POC,不是「整個交易日」的 POC。要拿日 POC 就把腳本掛在日線上;要拿週 POC 就掛在週線上——換句話說,你要哪個時間範圍的 profile,就把腳本掛在哪個時間範圍上。這是這一版 API(也就是 Application Programming Interface,官方對外開放的函式集)目前的限制。
request.footprint() 一個「跨 N 根 K 棒累積」的參數;要自己疊,就得逐根 K 棒把 reqFootprint.rows() 展開、把同一個價格 row 的 buy/sell 加總——這件事這一版 API 沒幫你做。或者直接在圖上疊 Fixed Range Volume Profile 那個指標,把數字目測抄下來當常數餵給腳本(不夠精細但立刻能跑)。request.footprint 的三個參數:ticks_per_row、va_percent、imbalance_percent
函式簽名很短:
request.footprint(ticks_per_row, va_percent, imbalance_percent) → series footprint三個參數都是 simple——也就是必須在 script 一開始就決定的常數,不能用 series 值動態塞進來。這個限制在文件裡明講,違反會編譯不過。
| 參數 | 型別 | 預設 | 解釋 |
|---|---|---|---|
ticks_per_row | simple int(必填) | 無 | row 寬度=ticks_per_row × syminfo.mintick。mintick=0.1 且給 100 就是每格 10 美元寬 |
va_percent | simple float | 70 | 要蒐集多少百分比的總成交量才算進 Value Area |
imbalance_percent | simple float | 300 | 相鄰兩格 buy 對 sell 差幾倍才算 imbalance,預設 3 倍 |
request.footprint 的參數。來源:TradingView Pine Script v6「Requesting data from other timeframes and contexts」頁的 request.footprint 段(查證日期 2026 年 8 月)。
imbalance 的判定公式官方寫得很直白:max(buy, sell) ≥ (imbalance_percent / 100) × min(buy, sell)——預設 300 代表「多數那一邊要至少是少數那一邊的三倍」。所以把 imbalance_percent 調小(例如 150)會抓到更多 imbalance;調大(例如 500)只會留下最極端的那些。
拿 POC / VAH / VAL 的最小可跑腳本
以下是把三個價位畫在圖上的最小骨架,跟 Pine Script v6 官方 concept 頁的 request.footprint 範例對得起來:
//@version=6
indicator("POC / VAH / VAL demo", overlay = true)
int ticksInput = input.int(100, "Ticks per row", minval = 1)
footprint fp = request.footprint(ticksInput)
bool hasData = not na(fp)
// footprint.poc / vah / val 回的是 volume_row ID,還要再過一層拿價格
float pocMid = hasData
? (volume_row.up_price(footprint.poc(fp)) + volume_row.down_price(footprint.poc(fp))) / 2
: na
float vahTop = hasData ? volume_row.up_price(footprint.vah(fp)) : na
float valBot = hasData ? volume_row.down_price(footprint.val(fp)) : na
plot(pocMid, "POC", color.new(color.orange, 0), 2, plot.style_circles)
plot(vahTop, "VAH", color.new(color.aqua, 0))
plot(valBot, "VAL", color.new(color.aqua, 0))關鍵是 footprint.poc()、footprint.vah()、footprint.val() 回的都是 volume_row ID 而不是價格——真正的價格要再過一層 volume_row.up_price()(該格的上沿)或 volume_row.down_price()(該格的下沿)才拿得到。POC 通常用 mid(上下沿平均)當代表;VAH/VAL 用外側(VAH 用 up_price、VAL 用 down_price)比較符合「上下邊界」的直覺。
先檢查 na:request.footprint() 在沒 footprint 資料的 K 棒回 na,而 footprint.*() 的 id 參數不接受 na。省掉這個檢查會拿到 runtime error 而不是 na——腳本會直接停在那根 K 棒。
三個一開始就要知道的坑
坑一:需要 Premium 或 Ultimate plan
這是硬條件。官方原文:「Volume footprints are available exclusively to users who have a Premium or Ultimate plan.」 你把腳本發給訂閱者,如果他不在這兩個檔位裡,圖表就是空的——Pine 不會提示為什麼,訂閱者只會覺得腳本壞了。發布之前把這個限制寫進腳本描述。
坑二:整支腳本只能呼叫一次 request.footprint
多呼叫一次就是 runtime error。想比較「不同 ticks_per_row 下 POC 會不會跑」這種問題,只能改參數、重跑腳本,一次比不到兩組。把 footprint ID 存進 var/varip 也繞不過去——限制在函式呼叫這一層,不是在 ID 的儲存上(var/varip 的機制在 Pine Script 的 Alert 沒有記憶那篇有拆過)。
坑三:1D 以上時 total_volume 可能跟 volume 對不上
這個坑很容易安靜地壞掉。官方明講:「On timeframes higher than or equal to '1D', a footprint's total volume might differ significantly from the value of the volume variable.」——原因是 EOD(收盤後)資料可能包含 block trade 與 OTC 成交,而 intraday feed 沒有。footprint 走 intraday feed、volume 內建變數走 EOD feed,兩邊本來就在描述不完全一樣的東西。你的策略在小時線/分鐘線用得爽,一升到日線可能突然對不上——這種錯不會吵,它會安靜地壞掉。
拿 POC 當支撐阻力之前,先過一次這個決策
兩件事要先想清楚:這個訊號代表什麼、以及訂閱者拿不拿得到。
request.footprint() 的 POC/VAH/VAL 就對了,這是它擅長的事footprint.rows() 展開自己疊,或直接在圖上疊 Fixed Range Volume Profile 目測數字餵回腳本。這一版 API 沒幫你做一個實務上比較安全的用法:拿 footprint.vah()/footprint.val() 當訊號濾網而不是進場點——上一根 K 棒的收盤在 VAH 之上、且 delta 是正的,這根才允許做多。這種用法不押「POC 就是絕對支撐」的強斷言,只在 Value Area 邊界確認完再讓進場條件通過。真要拿 POC 當支撐阻力,記得回測時要把 slippage 拉大——被最多人成交過的價位通常也是最擠的地方,你的單不是第一個到。
誠實的一段:這條資料的上限在哪
request.footprint() 給你的是「這根 K 棒的 footprint」——它不是完整的 order flow 工具鏈。真正的 order flow 資料,例如逐筆 tick 級的 buy/sell 分類、跨 session 累積的成交分佈、market delta 的即時曲線變化,這個 API 都不給。想做這一類分析要嘛回 request.security_lower_tf() 抓分秒級 K 棒自己拼、要嘛換到專門的 order flow 平台。TradingView 沒有承諾 request.footprint() 會擴充到那個程度,這是本人依據 v6 目前 API 表面積推論的現狀,不是官方白紙黑字的說法。
另一層限制是逐棒 delta 的準確度取決於 volume categorization——TradingView 分類的方式是看每一根 intrabar(也就是這根 K 棒內部的更短時距,例如 1s/1min/60min,隨圖表 timeframe 而變)的收盤價相對於開盤價:收盤高於開盤視為 buy、低於視為 sell;只有兩者相等時,才會 fallback 去比對前一根 intrabar 的收盤價。真實的 order flow 需要 order book 深度才能完全分對,這個近似對大部分 timeframe 夠用,但在極快速的行情或流動性不足的標的上會出現分類偏差。這是所有基於 TradingView tape 的 delta 分析共通的天花板。
常見問題
配置與相容性
我用 Basic/Pro 版試會拿到什麼?
request.footprint() 回 na,下游計算全部變 na,圖上什麼線都畫不出來。footprint 的 POC 跟 Session Volume Profile 指標畫出來的 POC 一樣嗎?
接進 TVSBot
TVSBot 這一端要做什麼配合才能收到 POC 訊號?
alert() 送一份 JSON 過來。TVSBot 目前的 webhook schema 必填是 secret、strategy(後台建的策略 slot)、action(也接受 side 別名,也就是 Pine 慣用的名字)、symbol、exchange,非 close 動作再帶 qty;其他欄位(market_type/order_type/qty_type 等)有預設值可省略。Pine 端算的具體價位(POC 那個數字本身)不進 payload——TVSBot 只根據觸發判定要不要送單,價位邏輯留在 Pine 那一側,這是設計上的分工不是暫時沒接。訊號解讀
把 va_percent 從 70 改成 100 會怎麼樣?
va_percent = 100 代表整根 K 棒的成交量都算進 Value Area——VAH 就等於這根 K 棒的最高價、VAL 等於最低價,等於 high/low,訊號就沒意義了。反過來調到 30 會讓 VA 太窄,只框住 POC 附近幾格,通常無法作為區間邊界。delta 為什麼有時候是正的但價格反而下跌?
Get started
把 Pine 算出來的 POC/VAH/VAL 訊號 webhook 給 TVSBot——用你自己的 API key(也就是交易所給你的存取憑證),先 dry-run,帳戶層級風控自己設。
免費開始使用