SuperTrend + Relative Volume (Kernel Optimized) | Flux Charts

fluxchart · study · 177 行 · 点赞 11,832 · TradingView 原页

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

Pine Script

// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © fluxchart
 
//@version=6
indicator("SuperTrend KDE", max_labels_count = 500, overlay = true)
import TradingView/ta/9 as ta
 
//constants
const bool DEBUG = false
const int KDELimit = 300
 
//Supertrend Inputs
atrLength = input.int(10, title = "ATR Length", group = "SuperTrend")
atrMultiplier = input.int(3, title = "ATR Multiplier", group = "SuperTrend")
supertrend_max_opacity = input.int(99, minval = 0, maxval = 100, title = "SuperTrend Max Opacity", group = "SuperTrend", tooltip = "This setting sets the opacity of supertrend based on the KDE%. A higher value will increase the transparency.")
supertrend_min_opacity = input.int(53, minval = 0, maxval = 100, title = "SuperTrend Min Opacity", group = "SuperTrend", tooltip = "This setting sets the opacity of supertrend based on the KDE%. A lower value will decrease the transparency.")
 
//KDE inputs
string KDEKernel = "Gaussian"           //common kernel for normal distribution
float KDEBandwidth = input.float(0.10, "Bandwidth", minval = 0.01, group = "KDE", tooltip = "This setting sets the smoothness of the KDE function output.")
int KDEStep = input.int(200, "Nº Bins", minval = 1, group = "KDE", tooltip = "The number of elements the KDE Probability array will have. Higher settings will result in greater precision.")
float activationThreshold = input.float(30, "KDE Threshold %", minval = 0, maxval = 100, step = 2.50, group = "KDE", tooltip = "This setting sets the KDE% threshold that must be exceeeded to indicate buy or sell signals.")
int barLength = input.int(5, "Relative Volume Length", minval = 1, group = "KDE", tooltip = "This setting sets the number of candles back to calculate Relative Breakout Volume")
string probMode = "Sum"    
activationThreshold:= activationThreshold/100     
activationThresholdEnabled = input.bool(true, "Enable Activation Threshold", group = "KDE")
 
//Style Inputs
bearishColor = input.color(#f23646, "Bullish Break", group = "Style", inline = "col")
bullishColor = input.color(color.rgb(9, 209, 66), "Bearish Break", group = "Style", inline = "col")
textColor = input.color(color.white, 'Text', group = 'Style', inline = "col", display = display.none)
KDELabelsEnabled = input.bool(true, "KDE Labels", group = "Style")
 
//Gaussian Kernel Function
gaussian (float distance, float bandwidth = 1.0) => 1.0 / math.sqrt(2.0 * math.pi) * math.pow(math.e, -0.5 * math.pow(distance / bandwidth, 2.0))
 
//KDE Probability
var float volumeProb = na      
float maxVolumeProb = na        
 
kde (array<float> arr, string kernel, float bandwidth, int steps) =>
    arrSize = arr.size()
    arrMax = 3  //99.7% of values fall between -3 and 3
    arrMin = -3
    arrRange = arrMax - arrMin 
    stepCount = arrRange / steps
    
    densityRange = array.new<float>(steps)          //calculate values to apply the kernel estimate
    for i = 0 to (steps) - 1
        densityRange.set(i, arrMin + i * stepCount)
    
    xArr = array.new<float>()
    yArr = array.new<float>()
    for i = 0 to densityRange.size() - 1
        float temp = 0
        for j = 0 to arr.size() - 1
            temp += gaussian(densityRange.get(i) - arr.get(j), bandwidth)
        xArr.push(densityRange.get(i))
        yArr.push(temp)
    totalDensity = array.sum(yArr)
    for k= 0 to yArr.size() - 1
        yArr.set(k, yArr.get(k) / totalDensity)  // Normalize each density value
    [xArr, yArr]
//#endregion
 
//Supertrend
[Pine_Supertrend, pineDirection] = ta.supertrend(atrMultiplier, atrLength)
 
//Breaks in Trend
bullishBreak = ta.crossover(close, Pine_Supertrend) 
bearishBreak = ta.crossunder(close, Pine_Supertrend)
 
//Candle Data
var volumeOnBreak = array.new<float>()
var normalizedVolumeOnBreak = array.new<float>()
 
//KDE variables
float MidKDEVol = na
var array<float> KDEVolX = na   //array of volume points
var array<float> KDEVolY = na   //density estimate at the corresponding volume point
var array<float> KDEVolYSum = array.new<float>()
 
//Calculate Relative Volume
getRelativeVolume(cur) =>
    float temp = 0
    int count = 0
    for i = 1 to barLength
        if(not na(volume[i]))
            temp += volume[i]
            count += 1
    temp := count > 0 ? temp / count : na 
    rvol = temp > 0 ? cur / temp : na
    rvol   
 
//Updates KDE Array and density points
if(not na(volume) and (bullishBreak or bearishBreak) and bar_index<(5000-barLength))
    if(volumeOnBreak.size() > KDELimit)
        volumeOnBreak.remove(0)
    volumeOnBreak.push(getRelativeVolume(volume))
 
    normalizedVolumeOnBreak := array.standardize(volumeOnBreak) //normalized array
    [KDEVolX1, KDEVolY1] = kde(normalizedVolumeOnBreak, KDEKernel, KDEBandwidth, KDEStep)
    KDEVolX := KDEVolX1     
    KDEVolY := KDEVolY1
    KDEVolYSum.clear()
 
    temp = 0.0
    for i = 0 to KDEVolY.size() - 1
        temp += KDEVolY.get(i)
        KDEVolYSum.push(temp)
    MidKDEVol := array.get(KDEVolX, array.indexof(KDEVolY, array.max(KDEVolY)))
 
prefixSum (array<float> arr, int l, int r) =>
    arr.get(r) - (l == 0 ? 0 : arr.get(l - 1))
 
//Standardize param: val based on param arr
standardize(float val, array<float> arr) =>    
    meanValue = array.avg(arr)        
    stdDevArr = array.stdev(arr)   
    stdVal = (val-meanValue)/stdDevArr
    stdVal                                     
 
getSupertrendTransparency(KDEProb) =>
    newValue = (KDEProb*(supertrend_max_opacity - supertrend_min_opacity)) + supertrend_min_opacity
    newValue := supertrend_max_opacity - newValue + supertrend_min_opacity
    newValue
 
//Finds Estimated Density Value
//if ((bearishBreak or bullishBreak) and not na(volume))
if(not na(volume))
    vol = standardize(getRelativeVolume(volume), volumeOnBreak)
    if volumeOnBreak.size() > 0
        volXIndexL = array.binary_search_leftmost(KDEVolX, vol )
        volXIndexR = math.min(array.binary_search_rightmost(KDEVolX, vol), KDEVolX.size() - 1)
        nearestIndex = (math.abs(vol - KDEVolX.get(volXIndexL)) < math.abs(vol - KDEVolX.get(volXIndexR))) ? volXIndexL : volXIndexR
        if probMode == "Nearest"
            volumeProb := KDEVolY.get(nearestIndex)
            maxVolumeProb := array.max(KDEVolY)
        else if probMode == "Sum"
            volumeProb := prefixSum(KDEVolYSum, 0, nearestIndex)
//#endregion   
 
overKDEThreshold(KDEprob) =>
    if(activationThresholdEnabled == false)
        true
    else if((KDEprob >= activationThreshold))
        true
    else if((KDEprob < activationThreshold))
        false
    
//Table
var table table = table.new(position=position.top_right, columns=1, rows=1)
if (na(volume) or volume == 0)
    table.cell(table, row=0, column=0, text="⚠️ No Volume Data Available for " + syminfo.tickerid, text_color=color.white, bgcolor=color.red)
else
    //table.cell(table, row=0, column=0, text = "Relative Volume KDE: "+ str.tostring(volumeProb * 100, "#.#") + "%", text_color = color.white, bgcolor = color.new(color.blue, 60))
    table.clear(table, 0, 0) 
 
upTrend = plot(pineDirection < 0 ? Pine_Supertrend : na, "Up direction", color.new(bullishColor, getSupertrendTransparency(volumeProb)), style=plot.style_linebr)
downTrend = plot(pineDirection > 0 ? Pine_Supertrend : na, "Down direction", color.new(bearishColor, getSupertrendTransparency(volumeProb)), style=plot.style_linebr)
bodyMiddle = plot(barstate.isfirst ? na : (open + close) / 2, "Body Middle",display = display.none)
fill(bodyMiddle, upTrend, color.new(bullishColor, getSupertrendTransparency(volumeProb)), fillgaps = false)
fill(bodyMiddle, downTrend, color.new(bearishColor, getSupertrendTransparency(volumeProb)), fillgaps = false)
 
plotshape((bullishBreak and not na(volume) and overKDEThreshold(volumeProb)) ? Pine_Supertrend*0.999 : na, "Bullish Arrows", style = shape.arrowup, size = size.normal, location = location.absolute, color = bullishColor, force_overlay = true)
plotshape((bearishBreak and not na(volume) and overKDEThreshold(volumeProb)) ? Pine_Supertrend*1.001 : na, "Bearish Arrows", style = shape.arrowdown, size = size.normal, location = location.absolute, color = bearishColor, force_overlay = true)
 
alertcondition(not na(volume) and bullishBreak and overKDEThreshold(volumeProb) and barstate.isconfirmed, "Possible Bullish Trend")
alertcondition(not na(volume) and bearishBreak and overKDEThreshold(volumeProb) and barstate.isconfirmed, "Possible Bearish Trend")
 
if not na(volume) and overKDEThreshold(volumeProb) and KDELabelsEnabled 
    txt = ""
    txt := "Vol: " + str.tostring(volumeProb * 100, "#.#") + "%"
    if bullishBreak
        label.new(bar_index, y = Pine_Supertrend*0.9980, text = txt, yloc = yloc.price, color = color.new(color.blue, 100), style = label.style_label_up, textcolor = textColor, force_overlay = true)
    if bearishBreak
        label.new(bar_index, y = Pine_Supertrend*1.002, text = txt, yloc = yloc.price, color = color.new(color.blue, 100), style = label.style_label_down, textcolor = textColor, force_overlay = true)

← 返回列表