Fair Value Gap Profile + Rolling POC [BigBeluga]

BigBeluga · study · 190 行 · 点赞 4,142 · TradingView 原页

本页源码来自 TradingView 公开发布的开源脚本,版权归原作者所有, 请遵循其原始许可(Pine 脚本常见 CC BY-NC-SA / MPL-2.0 / MIT)。 本项目仅用于研究检索与许可范围内的移植。

Pine Script

// This work is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International  
// https://creativecommons.org/licenses/by-nc-sa/4.0/
// © BigBeluga
 
//@version=6
indicator("Fair Value Gap Profile + Rolling POC [BigBeluga]", "FVG Profile + POC [Bigbeluga]", overlay = true, max_boxes_count = 500, max_bars_back = 5000, calc_bars_count = 5000)
 
// INPUTS ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――{
 
period     = input.int(500, "Lookback Period", tooltip = "The number of bars back from the current price to analyze for Fair Value Gaps.")
binSize    = input.int(40, "Profile Resolution (Bins)", tooltip = "The number of rows (price levels) the profile is divided into. Higher values create a more detailed but narrower profile.")
offset     = input.int(10, "Horizontal Offset", tooltip = "Moves the profile further to the right of the current bar to avoid overlapping price action.")
 
displayFVG = input.bool(true, "Show Fair Value Gaps", tooltip = "When enabled, highlights individual FVG boxes directly on the price chart.")
displayPer = input.bool(true, "Show Strength Percentage", tooltip = "Displays the percentage of total gap activity for each price bin.")
showPOC     = input.bool(true, "Show Rolling POC Line", tooltip = "Draws a line tracking the price level with the most FVG activity.")
 
DisplayDelta = input.bool(true, "Show Delta Volume", tooltip = "Shows the net volume difference between bullish and bearish gaps at that level.")
Displayqty   = input.bool(true, "Show Bull / Bear FVG Count", tooltip = "Displays the total count of bullish (▲) and bearish (▼) gaps found in each bin.")
heatMap      = input.bool(false, "Enable Heatmap", tooltip = "Overlays a color gradient on the background based on the density of gap activity.", inline = "hm")
 
bullCol = input.color(color.lime, "Bullish/Bearish Color", tooltip = "Color used for bullish gaps and positive volume delta.", inline = "col")
bearCol = input.color(color.orange, "", tooltip = "Color used for bearish gaps and negative volume delta.", inline = "col")
bgColor = input.color(color.rgb(73, 73, 73, 80), "Background Colorㅤㅤ", tooltip = "The background color of the profile area.", inline = "col1")
 
pocCol  = input.color(color.rgb(255, 102, 0), "POC Color", tooltip = "The color of the Rolling Point of Control line.")
 
topBot  = array.new<float>()
colorNA = color.new(color.black, 100)
// }
 
// ROLLING POC LOGIC ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――{
 
// We need a way to find the POC on every bar for the 'Rolling' effect
// This function finds which bin the current FVG falls into based on the global high/low range
get_poc() =>
    float hi = ta.highest(high, period)
    float lo = ta.lowest(low, period)
    float stp = (hi - lo) / binSize
    
    array<int>   counts = array.new<int>(binSize, 0)
    float pocPrice = na
    
    for i = 0 to period - 1
        // Bull FVG Logic
        if high[i+2] < low[i]
            avg = math.avg(high[i+2], low[i])
            binIdx = math.floor((avg - lo) / stp)
            if binIdx >= 0 and binIdx < binSize
                counts.set(binIdx, counts.get(binIdx) + 1)
        
        // Bear FVG Logic
        if low[i+2] > high[i]
            avg = math.avg(low[i+2], high[i])
            binIdx = math.floor((avg - lo) / stp)
            if binIdx >= 0 and binIdx < binSize
                counts.set(binIdx, counts.get(binIdx) + 1)
    
    // Find index of max activity
    maxAct = counts.max()
    if maxAct > 0
        pocIdx = counts.indexof(maxAct)
        pocPrice := lo + (stp * pocIdx) + (stp / 2)
    pocPrice
 
rollingPoc = showPOC ? get_poc() : na
poc = ta.sma(rollingPoc, 10)
plot(poc, "Rolling POC", color = pocCol, linewidth = 2, show_last = period, style = plot.style_linebr)
if barstate.islast and showPOC
    label.delete(label.new(bar_index, poc, "< PoC", style = label.style_label_left, color = colorNA, textcolor = pocCol)[1])
 
// }
 
// CALCULATIONS (Static Profile for Last Bar) ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――{
 
if barstate.islast
    var boxes = array.new<box>()
    for b in boxes 
        b.delete()
    boxes.clear()
 
    for i = 0 to period - 1
        topBot.push(high[i])
        topBot.push(low[i])
 
    step = (topBot.max() - topBot.min()) / binSize
    bullGaps = array.new<int>(binSize, 0)
    bearGaps = array.new<int>(binSize, 0)
    bullVol  = array.new<float>(binSize, 0.)
    bearVol  = array.new<float>(binSize, 0.)
 
    for i = 0 to period - 1
        avgBull = math.avg(high[i+2], low[i])
        avgBear = math.avg(low[i+2], high[i])
 
        if high[i+2] < low[i] // bullFVG 
            if displayFVG
                boxes.push(box.new(bar_index[i]-2, high[i+2], bar_index[i]+1, low[i], color.new(bullCol, 10), 1, bgcolor = color.new(bullCol, 80)))
 
            for k = 0 to binSize - 1 
                L = topBot.min() + step * k + step / 2
                if math.abs(avgBull - L) < step / 2
                    bullGaps.set(k, bullGaps.get(k) + 1)
                    bullVol.set(k, bullVol.get(k) + volume[i+1])
 
        if low[i+2] > high[i] // bearFVG 
            if displayFVG
                boxes.push(box.new(bar_index[i]-2, low[i+2], bar_index[i]+1, high[i], color.new(bearCol, 10), 1, bgcolor = color.new(bearCol, 80)))
 
            for k = 0 to binSize - 1 
                L = topBot.min() + step * k + step / 2
                if math.abs(avgBear - L) < step / 2
                    bearGaps.set(k, bearGaps.get(k) + 1)
                    bearVol.set(k, bearVol.get(k) + volume[i+1])
 
    max_ = 0.
    for k = 0 to binSize - 1 
        delta = bullVol.get(k) - bearVol.get(k)
        max_ := math.max(math.abs(delta), max_)
 
    // PLOT Profile Bars
    for k = 0 to binSize - 1 
        L = topBot.min() + step * k 
        H = L + step
        bullFVG_w = int(bullGaps.get(k) / math.max(1, bullGaps.max()) * 25) 
        bearFVG_w = int(bearGaps.get(k) / math.max(1, bearGaps.max()) * 25) 
        
        max_act = bullGaps.max() + bearGaps.max()
        tot = (bullGaps.get(k) + bearGaps.get(k)) / math.max(1, max_act) * 100
        delta = bullVol.get(k) - bearVol.get(k)
 
        if bullGaps.get(k) != 0 or bearGaps.get(k) != 0
            if heatMap
                boxes.push(box.new(bar_index-period, H, bar_index+50+offset, L, bgcolor = color.from_gradient(tot, 0, 100, colorNA, color.new(chart.fg_color, 50)), border_color = colorNA))
 
            boxes.push(box.new(bar_index+50+offset, H, bar_index+50+offset-bullFVG_w, L, bgcolor = bullCol, border_color = chart.bg_color, text = Displayqty ?  "▲" + str.tostring(bullGaps.get(k)) : ""))
            boxes.push(box.new(bar_index+50+offset-bullFVG_w, H, bar_index+50+offset-bullFVG_w-bearFVG_w, L, bgcolor = bearCol, border_color = chart.bg_color, text = Displayqty ? "▼" + str.tostring(bearGaps.get(k)) : ""))
 
            if displayPer
                boxes.push(box.new(bar_index+ 50 + offset, H, bar_index+ 60 + offset, L, colorNA, 0, bgcolor = colorNA, text =  str.tostring(tot, format.percent) + " |", text_halign = text.align_left, text_color = delta > 0 ? bullCol : bearCol))
            
            if DisplayDelta
                boxes.push(box.new(bar_index+ (displayPer ? 60 : 50) + offset, H, bar_index+ (displayPer ? 75 : 60) + offset, L, colorNA, 0, bgcolor = colorNA, text =  "Δ " + str.tostring(delta, format.volume), text_halign = text.align_left, text_color = delta > 0 ? bullCol : bearCol))
 
    boxes.push(box.new(bar_index-period, topBot.max(), bar_index+50+offset, topBot.min(), colorNA, 0, bgcolor = bgColor))
 
    line.delete(line.new(bar_index+50+offset, topBot.max(), bar_index+50+offset, topBot.min(), color = chart.fg_color)[1])
 
// }
 
// Smoothing MA inputs
var length = 2
 
if bar_index == last_bar_index - period 
    length := 2
 
length += 1
 
 
GRP = "Moving Average"
maTypeInput = input.string("None", "Type", options = ["None", "SMA", "EMA", "SMMA (RMA)", "WMA", "VWMA"], group = GRP, display = display.none)
maLengthInput = input.int(25, "Length", group = GRP, display = display.none, inline = "len")
autoLength = input.bool(false, "Auto", group = GRP, display = display.none, inline = "len")
src = input(close, title="Source", group = GRP)
 
pine_ema(src, length) =>
    alpha = 2 / (length + 1)
    sum = 0.0
    sum := na(sum[1]) ? src : alpha * src + (1 - alpha) * nz(sum[1])
 
pine_rma(src, length) =>
    alpha = 1/length
    sum = 0.0
    sum := na(sum[1]) ? ta.sma(src, length) : alpha * src + (1 - alpha) * nz(sum[1])
 
// Smoothing MA Calculation
ma(source, length, MAtype) =>
    switch MAtype
        "SMA"                   => ta.sma(source, length)
        "EMA"                   => pine_ema(source, length)
        "SMMA (RMA)"            => pine_rma(source, length)
        "WMA"                   => ta.wma(source, length)
        "VWMA"                  => ta.vwma(source, length)
ma = ma(src, autoLength ? length : maLengthInput, maTypeInput)
plot(ma, color=color.yellow, title="MA", show_last = period, style = plot.style_linebr)
 
if barstate.islast and maTypeInput != "None"
    label.delete(label.new(bar_index, ma, maTypeInput + ": " + str.tostring(autoLength ? length : maLengthInput), style = label.style_label_left, color = colorNA, textcolor = color.yellow)[1])
 
// }

← 返回列表