Attachments forums

Re: TradingView Indicators to MT4 Indicators

Tsar, Sun Mar 15, 2026 5:32 am

Dear Coders.
Need your Help convert this TV Script indicator to MT4 please... 🙏

There is the Swing High and Swing Low based Volume Profile with build Zag Zag of BigBeluga concept's.




This Script indicator is Now featured in Editors' picks of TradingViewers.


Swing Profile [BigBeluga]


Swing Profile [BigBeluga] is a dynamic swing-based volume profiling tool that builds a complete volume profile for each completed market swing.
Instead of using fixed sessions or time ranges, the indicator anchors its profile strictly between confirmed swing highs and swing lows, allowing traders to analyze where volume accumulated inside each directional leg.

The profile updates in real time while a swing is still forming and finalizes once the swing direction flips, giving both historical and live insight into volume behavior.



Code: Select all

// 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("Swing Profile [BigBeluga]", overlay = true, max_labels_count = 500, max_boxes_count = 500, calc_bars_count = 2000, max_bars_back = 5000)


// INPUTS ---------------------------------------------------------------------

swingLen = input.int(50, "Swing Length", minval = 10)

swingColorUp = input.color(color.lime, "▲", inline = "colors")
swingColorDown = input.color(color.orange, "▼", inline = "colors")

showProfile = input.bool(true, "Profile", group = "Swing Volume Profile")
showHeatMap = input.bool(false, "HeatMap", group = "Swing Volume Profile")

showZigZag = input.bool(true, "ZigZag", inline = "Zz")
zigZagStyleInput = input.string("Dotted", "", ["Dotted", "Dashed", "Solid"], inline = "Zz")

showPOC = input.bool(true, "PoC", "", inline = "Poc", group = "Point of Control")
pocWidthInput = input.int(2, "", inline = "Poc", group = "Point of Control")
pocColor = input.color(color.red, "", inline = "Poc", group = "Point of Control")

transparentNA = color.new(color.black, 100)

string dataSizeInput = input.string("Small", title = "Data Size", options = ["Tiny", "Small", "Normal", "Large", "Huge"])

// Size switcher for labels
getLabelSize() =>
    switch dataSizeInput
        "Small"  => size.small
        "Normal" => size.normal
        "Large"  => size.large
        "Huge"   => size.huge
        => size.tiny

getZigZagLineStyle() =>
    switch zigZagStyleInput
        "Dotted" => line.style_dotted
        "Dashed" => line.style_dashed
        "Solid"  => line.style_solid


// Persistent storage containers
var polyline profilePoly = na
var dataLabel = label(na)
var pocLineHandle = line(na)
var profileBoxes = array.new<box>()

// Structs for swing points
type SwingData
    float price
    int index

var highSwing = SwingData.new(na, na)
var lowSwing  = SwingData.new(na, na)

// Direction flag: true = down move, false = up move
var isDownMove = false

// CALCULATIONS ---------------------------------------------------------------

// Detect swing highs and lows
highestSwingHigh = ta.highest(swingLen)
lowestSwingLow   = ta.lowest(swingLen)

if high == highestSwingHigh
    isDownMove := true
if low == lowestSwingLow
    isDownMove := false

// Store completed swing high
if high[1] == highestSwingHigh[1] and high < highestSwingHigh
    highSwing.index := bar_index[1]
    highSwing.price := high[1]

// Store completed swing low
if low[1] == lowestSwingLow[1] and low > lowestSwingLow
    lowSwing.index := bar_index[1]
    lowSwing.price := low[1]

// Default bin size based on ATR
priceBinSize = ta.atr(200) * 0.5

// HISTORICAL SWING LEG -------------------------------------------------------

// When direction flips we finalize previous swing leg and build full profile
if isDownMove != isDownMove[1]

    // Clear previous drawings
    profilePoly.delete()
    dataLabel.delete()
    for b in profileBoxes
        b.delete()
    profileBoxes.clear()

    swingMainColor = isDownMove ? swingColorDown : swingColorUp

    // Draw zigzag connector
    if showZigZag
        line.new(highSwing.index, highSwing.price, lowSwing.index, lowSwing.price, color = swingMainColor, style = getZigZagLineStyle())

    // Determine swing boundaries
    swingBottom = math.min(highSwing.price, lowSwing.price)
    swingTop    = math.max(highSwing.price, lowSwing.price)

    // Number of volume bins
    binCount = int(math.abs(highSwing.price - lowSwing.price) / priceBinSize)
    binStep  = math.abs(highSwing.price - lowSwing.price) / binCount

    lastSwingIndex = math.max(highSwing.index, lowSwing.index)
    prevSwingIndex = math.min(highSwing.index, lowSwing.index)

    // Arrays for volume accumulation
    volumeBins = array.new<float>(binCount, 0.)
    profilePoints = array.new<chart.point>()
    buyVolumeBins = array.new<float>(binCount, 0.)
    sellVolumeBins = array.new<float>(binCount, 0.)

    barOffset = bar_index - lastSwingIndex

    // Accumulate volume per price bin
    for i = barOffset to (lastSwingIndex - prevSwingIndex) + barOffset

        candleClose = close[i]
        candleOpen  = open[i]
        candleVol   = volume[i]

        for k = 0 to binCount - 1
            binMidPrice = swingBottom + (k * binStep) + (binStep / 2)

            if math.abs(binMidPrice - candleClose) < binStep

                volumeBins.set(k, volumeBins.get(k) + candleVol)

                if candleClose > candleOpen
                    buyVolumeBins.set(k, buyVolumeBins.get(k) + candleVol)
                else
                    sellVolumeBins.set(k, sellVolumeBins.get(k) + candleVol)

    // Draw boxes and build profile outline
    for k = 0 to binCount - 1

        binLow  = swingBottom + (k * binStep)
        binHigh = binLow + binStep

        volumeRatio = volumeBins.get(k) / volumeBins.max()
        profileWidth = int(volumeRatio * ((lastSwingIndex - prevSwingIndex) / 2))

        // Draw POC line
        if volumeRatio == 1 and showPOC
            line.new(showProfile ? prevSwingIndex + profileWidth : prevSwingIndex, math.avg(binLow, binHigh), lastSwingIndex, math.avg(binLow, binHigh), color = pocColor, width = pocWidthInput)

        // Create volume box
        box.new(
            showProfile ? prevSwingIndex + profileWidth : prevSwingIndex,
            binHigh,
            showHeatMap ? lastSwingIndex : prevSwingIndex,
            binLow,
            transparentNA,
            0,
            bgcolor = showProfile or showHeatMap ? color.from_gradient(volumeRatio, 0, 1, color.new(swingMainColor, 90), color.new(volumeRatio == 1 and showPOC ? pocColor : swingMainColor, 50)) : transparentNA,
            text = showHeatMap ? "" : volumeRatio == 1 ? str.tostring(volumeBins.max(), format.volume) : ""
        )

        // Build polygon outline
        if k == 0
            profilePoints.push(chart.point.from_index(prevSwingIndex, binLow))
        profilePoints.push(chart.point.from_index(prevSwingIndex + profileWidth, binLow))
        profilePoints.push(chart.point.from_index(prevSwingIndex + profileWidth, binHigh))
        if k == binCount - 1
            profilePoints.push(chart.point.from_index(prevSwingIndex, binHigh))

    // Draw outer polyline
    if showProfile
        polyline.new(profilePoints, false, true, line_color = showHeatMap ? color.new(swingMainColor, 50) : swingMainColor)

    // Summary label for historical swing
    swingArrowText = isDownMove ? "▼" : "▲"

    swingTooltip =
          "Total Volume: " + str.tostring(volumeBins.sum(), format.volume)
         + "\nBuy Volume: " + str.tostring(buyVolumeBins.sum(), format.volume)
         + "\nSell Volume: " + str.tostring(sellVolumeBins.sum(), format.volume)
         + "\nDelta Volume: " + str.tostring((buyVolumeBins.sum() - sellVolumeBins.sum()) / volumeBins.sum() * 100, format.percent)

    label.new(prevSwingIndex, isDownMove ? swingTop : swingBottom, swingArrowText,
         style = isDownMove ? label.style_label_down : label.style_label_up,
         color = transparentNA,
         textcolor = swingMainColor,
         size = getLabelSize(),
         tooltip = swingTooltip)


// REAL-TIME SWING LEG --------------------------------------------------------

// Real-time profile rebuilding while swing is still forming
if not isDownMove

    // Clear boxes on every update
    for b in profileBoxes
        b.delete()
    profileBoxes.clear()

    if barstate.islast

        swingMainColor = chart.fg_color

        // Remove previous zigzag preview line
        line.delete(line.new(highSwing.index, highSwing.price, lowSwing.index, lowSwing.price, color = swingMainColor, style = line.style_dashed)[1])

        swingBottom = math.min(highSwing.price, lowSwing.price)
        swingTop    = math.max(highSwing.price, lowSwing.price)

        binCount = int(math.abs(highSwing.price - lowSwing.price) / priceBinSize)
        binStep  = math.abs(highSwing.price - lowSwing.price) / binCount

        lastSwingIndex = math.max(highSwing.index, lowSwing.index)
        prevSwingIndex = math.min(highSwing.index, lowSwing.index)

        volumeBins = array.new<float>(binCount, 0.)
        profilePoints = array.new<chart.point>()
        buyVolumeBins = array.new<float>(binCount, 0.)
        sellVolumeBins = array.new<float>(binCount, 0.)

        barOffset = bar_index - lastSwingIndex

        // Accumulate volume in real time
        for i = barOffset to (lastSwingIndex - prevSwingIndex) + barOffset

            candleClose = close[i]
            candleOpen  = open[i]
            candleVol   = volume[i]

            for k = 0 to binCount - 1
                binMidPrice = swingBottom + (k * binStep) + (binStep / 2)

                if math.abs(binMidPrice - candleClose) < binStep

                    volumeBins.set(k, volumeBins.get(k) + candleVol)
                    if candleClose > candleOpen
                        buyVolumeBins.set(k, buyVolumeBins.get(k) + candleVol)
                    else
                        sellVolumeBins.set(k, sellVolumeBins.get(k) + candleVol)

        // Draw real-time boxes
        for k = 0 to binCount - 1

            binLow  = swingBottom + (k * binStep)
            binHigh = binLow + binStep

            volumeRatio = volumeBins.get(k) / volumeBins.max()
            profileWidth = int(volumeRatio * ((lastSwingIndex - prevSwingIndex) / 2))

            if volumeRatio == 1 and showPOC
                pocLineHandle := line.new(showProfile ? prevSwingIndex + profileWidth : prevSwingIndex, math.avg(binLow, binHigh), lastSwingIndex, math.avg(binLow, binHigh), color = pocColor, width = pocWidthInput)
                line.delete(pocLineHandle[1])

            profileBoxes.push(box.new(
                 showProfile ? prevSwingIndex + profileWidth : prevSwingIndex,
                 binHigh,
                 showHeatMap ? lastSwingIndex : prevSwingIndex,
                 binLow,
                 transparentNA,
                 0,
                 bgcolor = showProfile or showHeatMap ? color.from_gradient(volumeRatio, 0, 1, color.new(swingMainColor, 90), color.new(volumeRatio == 1 and showPOC ? pocColor : swingMainColor, 50)) : transparentNA,
                 text = showHeatMap ? "" : volumeRatio == 1 ? str.tostring(volumeBins.max(), format.volume) : ""
            ))

            if k == 0
                profilePoints.push(chart.point.from_index(prevSwingIndex, binLow))
            profilePoints.push(chart.point.from_index(prevSwingIndex + profileWidth, binLow))
            profilePoints.push(chart.point.from_index(prevSwingIndex + profileWidth, binHigh))
            if k == binCount - 1
                profilePoints.push(chart.point.from_index(prevSwingIndex, binHigh))

        // Update polyline in real time
        if showProfile
            polyline.delete(profilePoly[1])
            profilePoly := polyline.new(profilePoints, false, true, line_color = showHeatMap ? color.new(swingMainColor, 50) : swingMainColor)

        // Label with summary data
        swingTooltip = "T - Total Volume\nB - Buy Volume\nS - Sell Volume\nD - Delta Volume"

        swingDataText =
              "T: " + str.tostring(volumeBins.sum(), format.volume)
             + "\nB: " + str.tostring(buyVolumeBins.sum(), format.volume)
             + "\nS: " + str.tostring(sellVolumeBins.sum(), format.volume)
             + "\nD: " + str.tostring((buyVolumeBins.sum() - sellVolumeBins.sum()) / volumeBins.sum() * 100, format.percent)

        dataLabel := label.new(prevSwingIndex, not isDownMove ? swingTop : swingBottom, swingDataText,
             style = not isDownMove ? label.style_label_down : label.style_label_up,
             color = transparentNA,
             textcolor = swingMainColor,
             size = getLabelSize(),
             tooltip = swingTooltip,
             textalign = text.align_left)

        label.delete(dataLabel[1])


// MIRROR OF ABOVE FOR isDownMove == true ------------------------------------------

// Mirror logic for bullish direction
else

    for b in profileBoxes
        b.delete()
    profileBoxes.clear()

    if barstate.islast

        swingMainColor = chart.fg_color

        line.delete(line.new(highSwing.index, highSwing.price, lowSwing.index, lowSwing.price, color = swingMainColor, style = line.style_dashed)[1])

        swingBottom = math.min(highSwing.price, lowSwing.price)
        swingTop    = math.max(highSwing.price, lowSwing.price)

        binCount = int(math.abs(highSwing.price - lowSwing.price) / priceBinSize)
        binStep  = math.abs(highSwing.price - lowSwing.price) / binCount

        lastSwingIndex = math.max(highSwing.index, lowSwing.index)
        prevSwingIndex = math.min(highSwing.index, lowSwing.index)

        volumeBins = array.new<float>(binCount, 0.)
        profilePoints = array.new<chart.point>()
        buyVolumeBins = array.new<float>(binCount, 0.)
        sellVolumeBins = array.new<float>(binCount, 0.)

        barOffset = bar_index - lastSwingIndex

        for i = barOffset to (lastSwingIndex - prevSwingIndex) + barOffset

            candleClose = close[i]
            candleOpen  = open[i]
            candleVol   = volume[i]

            for k = 0 to binCount - 1

                binMidPrice = swingBottom + (k * binStep) + (binStep / 2)

                if math.abs(binMidPrice - candleClose) < binStep

                    volumeBins.set(k, volumeBins.get(k) + candleVol)
                    if candleClose > candleOpen
                        buyVolumeBins.set(k, buyVolumeBins.get(k) + candleVol)
                    else
                        sellVolumeBins.set(k, sellVolumeBins.get(k) + candleVol)

        for k = 0 to binCount - 1

            binLow  = swingBottom + (k * binStep)
            binHigh = binLow + binStep

            volumeRatio = volumeBins.get(k) / volumeBins.max()
            profileWidth = int(volumeRatio * ((lastSwingIndex - prevSwingIndex) / 2))

            if volumeRatio == 1 and showPOC
                pocLineHandle := line.new(showProfile ? prevSwingIndex + profileWidth : prevSwingIndex, math.avg(binLow, binHigh), lastSwingIndex, math.avg(binLow, binHigh), color = pocColor, width = pocWidthInput)
                line.delete(pocLineHandle[1])

            profileBoxes.push(box.new(
                 showProfile ? prevSwingIndex + profileWidth : prevSwingIndex,
                 binHigh,
                 showHeatMap ? lastSwingIndex : prevSwingIndex,
                 binLow,
                 transparentNA,
                 0,
                 bgcolor = showProfile or showHeatMap ? color.from_gradient(volumeRatio, 0, 1, color.new(swingMainColor, 90), color.new(volumeRatio == 1 and showPOC ? pocColor : swingMainColor, 50)) : transparentNA,
                 text = showHeatMap ? "" : volumeRatio == 1 ? str.tostring(volumeBins.max(), format.volume) : ""
             ))

            if k == 0
                profilePoints.push(chart.point.from_index(prevSwingIndex, binLow))
            profilePoints.push(chart.point.from_index(prevSwingIndex + profileWidth, binLow))
            profilePoints.push(chart.point.from_index(prevSwingIndex + profileWidth, binHigh))
            if k == binCount - 1
                profilePoints.push(chart.point.from_index(prevSwingIndex, binHigh))

        if showProfile
            polyline.delete(profilePoly[1])
            profilePoly := polyline.new(profilePoints, false, true, line_color = showHeatMap ? color.new(swingMainColor, 50) : swingMainColor)

        swingTooltip = "T - Total Volume\nB - Buy Volume\nS - Sell Volume\nD - Delta Volume"

        swingDataText =
              "T: " + str.tostring(volumeBins.sum(), format.volume)
             + "\nB: " + str.tostring(buyVolumeBins.sum(), format.volume)
             + "\nS: " + str.tostring(sellVolumeBins.sum(), format.volume)
             + "\nD: " + str.tostring((buyVolumeBins.sum() - sellVolumeBins.sum()) / volumeBins.sum() * 100, format.percent)

        dataLabel := label.new(prevSwingIndex, not isDownMove ? swingTop : swingBottom, swingDataText,
             style = not isDownMove ? label.style_label_down : label.style_label_up,
             color = transparentNA,
             textcolor = swingMainColor,
             size = getLabelSize(),
             tooltip = swingTooltip,
             textalign = text.align_left)

        label.delete(dataLabel[1])




// Smoothing MA inputs
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, active = maTypeInput != "None")
src = input(close, title="Source", group = GRP, active = maTypeInput != "None")


// Smoothing MA Calculation
ma(source, length, MAtype) =>
    switch MAtype
        "SMA"                   => ta.sma(source, length)
        "EMA"                   => ta.ema(source, length)
        "SMMA (RMA)"            => ta.rma(source, length)
        "WMA"                   => ta.wma(source, length)
        "VWMA"                  => ta.vwma(source, length)

plot(ma(src, maLengthInput, maTypeInput), color=color.yellow, title="MA")

INFO in :
https://www.tradingview.com/script/gFlv ... BigBeluga/
All files in topic