什麼是重繪(Repainting)
每一套量化交易的軟體或平台都有其需要注意的事項,有時候我們在使用 TradingView 的策略腳本或是指標的時候會發現重新整理之後訊號或是進出場點會不一樣。這種重新讀取圖表資料後指標或是策略進出場點不一致的現象我們就稱為重繪(Repainting)。
官方將重繪定義為:導致歷史與即時計算或繪圖表現不同的腳本行為。
重繪其實很常發生,有多種因素可能導致重繪。根據TradingView官方的統計,超過 95% 的現有指標都表現出某種形式的重繪行為。例如,MACD 和 RSI 等常用指標在歷史柱上顯示已確認的值,但會在即時、未經確認的圖表柱上波動,直到收盤。因此,它們在歷史狀態和實時狀態下的行為有所不同。
更直觀的例子便是成交量,成交量隨時隨地都在變化,並非所有重繪都是無用或具有誤導性的,重繪也不是BUG,此類行為也不會阻止交易者使用具有此類行為的指標。
簡單來說,在K線價格還沒有收盤之前,指標的時會隨著市場價格及時變動,這就是最常見的一種重繪樣態。只是這種類型的重繪是正常無害的,我們真正要避免的是在策略上使用這種無法回溯浮動的指標值。
常見的K棒歷史數據不包括價格在intra-bar變動的記錄,K棒僅記錄了開、高、低、收 (OHLC)四個點位。這導致腳本有時在歷史數據和即時數據上有不同的工作方式,其中只知道開盤價,並且在即時K棒關閉之前,K棒裡的高、低價格會移動很多次;在K棒關閉後,相關價格才會確定。
什麼場景會發生TradingView重繪
使用calc_on_every_tick=true
若策略使用calc_on_every_tick=true,策略將在即時運行時會在每次tick進來時即時更新時運算,不過該策略在回測時卻只會在K棒收盤時才計算。
這將會導致策略在回測與即時運作時產生極大的誤差。
發生這種情況時,回測結果也會失效,因為它們不能即時代表策略的行為。
一般來說策略腳本應該要盡量避免使用此語法。
使用request.security導致重繪
request.security () 函數在歷史回測和實時運行上的行為不同。
在歷史回測上,它僅從其請求的上下文中傳回”已確認”的值,而在即時行情運算上,它可以傳回”未確認”的值。
如果request.security()傳回的值在沒有確認的情況下在即時即時行情上波動,則腳本將在重新啟動執行時重新繪製它們。
使用security以低於主圖的周期來請求數據
某些腳本使用request.security() 來請求低於主圖時間範圍的資料。雖然當專門設計用於處理較低時間範圍內的K棒函數在時間範圍內發送時是有效的,但當這種類型的使用者定義函數需要檢測柱內的第一個柱時(大多數情況都是如此),該技術將僅適用於歷史K棒。這是因為即時資料的K棒尚未排序。
其影響是此類腳本無法即時重現其在歷史K棒上的行為。
例如,任何產生警報的邏輯都會有缺陷,並且需要不斷刷新才能將經過的即時柱重新計算為歷史K棒。
//@version=5
indicator("Lower timeframe security demo", overlay = true)
//@variable The valid timeframe closest to 1/4 the size of the chart timeframe.
string lowerTimeframe = timeframe.from_seconds(int(timeframe.in_seconds() / 4))
//@variable The `close` value on the `lowerTimeframe`. Represents the first intrabar value on each chart bar.
float firstLTFClose = request.security(syminfo.tickerid, lowerTimeframe, close, lookahead = barmerge.lookahead_on)
//@variable The `close` value on the `lowerTimeframe`. Represents the last intrabar value on each chart bar.
float lastLTFClose = request.security(syminfo.tickerid, lowerTimeframe, close)
// Plot the values.
plot(firstLTFClose, "First intrabar close", color.teal, 3)
plot(lastLTFClose, "Last intrabar close", color.purple, 3)
// Highlight the background on realtime bars.
bgcolor(barstate.isrealtime ? color.new(color.orange, 70) : na, title = "Realtime background highlight")
使用timenow語法
使用內建的timenow語法會呼叫目前時間。但使用此變數的腳本無法顯示一致的歷史和即時行為,因此它們必須重新繪製。
資料起始點變化
一般來說腳本會從圖表的第一根K棒上執行,然後按順序在每個K棒上運算。但如果第一個K棒發生變化,則腳本有可能會發生重繪。
以下因素會影響圖表上看到的K棒數量及其起點:
- 你的帳戶類型或訂閱方案
- 數據供應商提供的歷史數據
- 由於歷史資料的對齊要求,因此重繪了K棒起點
TradingView的不同方案對於K棒的顯示限制:
- Premium 方案可以顯示 20,000 個歷史K棒。
- Essential 和 Plus 有 10,000 個歷史K棒。
- 免費方案有 5,000 個歷史K棒。
K棒起點是使用以下規則確定的,這些規則取決於圖表的時間範圍:
- 1、5、10、15、30 秒:與一天的開始對齊。
- 1 – 14 分鐘:與一週的開始對齊。
- 15 – 29 分鐘:與月初對齊。
- 30 – 1439 分鐘:與年初對齊。
- 1440 分鐘以上:與第一個可用歷史資料點對齊。
隨著時間的推移,這些因素會導致圖表的歷史記錄在不同的時間點開始。這通常會對您的腳本計算產生影響,因為早期柱中計算結果的變化可能會波及資料集中的所有其他柱。例如,使用ta.valuewhen()、 ta.barssince()或 ta.ema()等函數將產生隨早期歷史而變化的結果。
歷史數據的改變
歷史和即時K棒是使用交易所/經紀商提供的兩種不同的資料來源建立的。當即時數據過去時,交易所/經紀商有時會對K棒價格進行較小的調整,然後將其寫入其歷史資料。當刷新圖表或在那些已過去的即時K棒上重新執行腳本時,將使用歷史數據構建和計算它們,其中將包含那些通常較小的價格修正。
歷史資料也可能因其他原因而被修改,例如股票分割。
有可能造成重繪的變數
- barstate.isconfirmed, barstate.isfirst, barstate.ishistory, barstate.islast, barstate.isnew, barstate.isrealtime
- timenow
- bar_index
如何避免TradingView重繪
謹慎使用request.security
pine script內建函數很多有Repainting的問題,request.security函數就是一個,所以在用時要小心!!但以上這個程式碼也是有解法,就是將request.security內的close改成=>close[1],使用前一根已經確定收盤的K棒,這樣就不會有Repainting的問題了。
在判斷式增加barstate.isconfirmed
就是在寫策略時,切記要再判斷式內多加一個條件函數『barstate.isconfirmed』,這樣就能輕鬆避免重繪問題啦
在腳本中開啟process_orders_on_close
直接在Strategy內,把『process_orders_on_close』開啟。
結語
並非所有重繪行為都是錯誤需要不惜一切代價避免的。在許多情況下,某些形式的重繪可能正是腳本所需要的。重要的是要知道什麼時候的重繪行為並不是我們想要的。為了避免不可接受的重繪,了解工具的工作原理或應該如何設計工具非常重要。
量化通粉絲社群,一起討論程式交易!