- //@version=5
- const int maxDistanceToLastBar = 5000
- const int labelCooldown = 8
- const int KDELimit = 300
- strategy("RSI短线", shorttitle = "RSI短线",overlay = true, max_labels_count = 500)
- rsiLengthInput = input.int(14, minval = 1, title="RSI Length", group="RSI Settings")
- rsiSourceInput = input.source(close, "Source", group="RSI Settings")
- highPivotLen = input.int(21, "High Pivot Length", minval = 1, group = "Pivots", display = display.none)
- lowPivotLen = input.int(21, "Low Pivot Length", minval = 1, group = "Pivots", display = display.none)
- activationThresholdStr = input.string("Medium", "Activation Threshold", options = ["High", "Medium", "Low"], group = "KDE", tooltip = "Determines the amount of arrows shown. Higher options will result in more arrows being rendered.")
- string KDEKernel = input.string("Gaussian", "Kernel", options=['Uniform', 'Gaussian', 'Sigmoid'], group = "KDE", tooltip = "The kernel function for KDE calculation. Gaussian is a commonly used kernel and is based on normal distribution.")
- float KDEBandwidth = input.float(2.71828, "Bandwidth", group = "KDE", tooltip = "This setting sets the smoothness of the KDE function output.")
- int KDEStep = input.int(100, "Nº Bins", minval = 1, group = "KDE", tooltip = "The number of elements the KDE Probability array will have. Higher settings will result in greater precision.")
- activationThreshold = (activationThresholdStr == "High" ? 0.4 : activationThresholdStr == "Medium" ? 0.25 : 0.15)
- probMode = "Sum"
- minPadding = false
- bearishColor = input.color(#f23646, "High Pivots", group = "Style", inline = "col", display = display.none)
- neutralColor = input.color(color.gray, "Neutral", group = "Style", inline = "col", display = display.none)
- bullishColor = input.color(#089981, "Low Pivots", group = "Style", inline = "col", display = display.none)
- RSILabelsEnabled = input.bool(true, "RSI Labels", group = "Style")
- KDELabelsEnabled = input.bool(true, "KDE Labels", group = "Style")
- rsi = ta.rsi(rsiSourceInput, rsiLengthInput)
- //#region KDE
- 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))
- uniform (float distance, float bandwidth = 1.0) => (math.abs(distance) > bandwidth) ? 0.0 : 0.5
- sigmoid (float distance, float bandwidth = 1.0) => 2.0 / math.pi * (1.0 / (math.pow(math.e, (distance / bandwidth)) + math.pow(math.e, -(distance / bandwidth))))
- kde (array<float> arr, string kernel, float bandwidth, int steps) =>
- arrSize = arr.size()
- arrRange = arr.range()
- arrMin = arr.min() - (minPadding ? (arrRange / 2.0) : 0)
- stepCount = arrRange / steps
-
- densityRange = array.new<float>(steps * 2)
- for i = 0 to (steps * 2) - 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), 1.0 / bandwidth)
-
- xArr.push(densityRange.get(i))
- yArr.push(1.0 / arrSize * temp)
- [xArr, yArr]
- //#endregion
- //#region Pivots
- prefixSum (array<float> arr, int l, int r) =>
- arr.get(r) - (l == 0 ? 0 : arr.get(l - 1))
- float MidKDEHigh = na
- float MidKDELow = na
- var array<float> KDEHighX = na
- var array<float> KDEHighY = na
- var array<float> KDEHighYSum = array.new<float>()
- var array<float> KDELowX = na
- var array<float> KDELowY = na
- var array<float> KDELowYSum = array.new<float>()
- highPivot = ta.pivothigh(highPivotLen, highPivotLen)
- lowPivot = ta.pivotlow(lowPivotLen, lowPivotLen)
- var highPivotRSIs = array.new<float>()
- var lowPivotRSIs = array.new<float>()
- if not na(highPivot)
- if highPivotRSIs.size() > KDELimit
- highPivotRSIs.remove(0)
- highPivotRSIs.push(rsi[highPivotLen])
- [KDEHighX1, KDEHighY1] = kde(highPivotRSIs, KDEKernel, KDEBandwidth, KDEStep)
- KDEHighX := KDEHighX1
- KDEHighY := KDEHighY1
-
- KDEHighYSum.clear()
- temp = 0.0
- for i = 0 to KDEHighY.size() - 1
- temp += KDEHighY.get(i)
- KDEHighYSum.push(temp)
- MidKDEHigh := array.get(KDEHighX, array.indexof(KDEHighY, array.max(KDEHighY)))
- if not na(lowPivot)
- if lowPivotRSIs.size() > KDELimit
- lowPivotRSIs.remove(0)
- lowPivotRSIs.push(rsi[lowPivotLen])
- [KDELowX1, KDELowY1] = kde(lowPivotRSIs, KDEKernel, KDEBandwidth, KDEStep)
- KDELowX := KDELowX1
- KDELowY := KDELowY1
- KDELowYSum.clear()
- temp = 0.0
- for i = 0 to KDELowY.size() - 1
- temp += KDELowY.get(i)
- KDELowYSum.push(temp)
- MidKDELow := array.get(KDELowX, array.indexof(KDELowY, array.max(KDELowY)))
- //#endregion
- float lowProb = na
- float maxLowProb = na
- float highProb = na
- float maxHighProb = na
- if last_bar_index - maxDistanceToLastBar < bar_index
- if highPivotRSIs.size() > 0
- highXIndexL = array.binary_search_leftmost(KDEHighX, rsi)
- highXIndexR = math.min(array.binary_search_rightmost(KDEHighX, rsi), KDEHighX.size() - 1)
- nearestIndex = (math.abs(rsi - KDEHighX.get(highXIndexL)) < math.abs(rsi - KDEHighX.get(highXIndexR))) ? highXIndexL : highXIndexR
- highProb := prefixSum(KDEHighYSum, 0, nearestIndex)
-
- if lowPivotRSIs.size() > 0
- lowXIndexL = array.binary_search_leftmost(KDELowX, rsi)
- lowXIndexR = math.min(array.binary_search_rightmost(KDELowX, rsi), KDELowX.size() - 1)
- nearestIndex = (math.abs(rsi - KDELowX.get(lowXIndexL)) < math.abs(rsi - KDELowX.get(lowXIndexR))) ? lowXIndexL : lowXIndexR
- lowProb := prefixSum(KDELowYSum, nearestIndex, KDELowYSum.size() - 1)
- //#region Draw Pivots
- color curColor = na
- if (not na(KDELowY)) and (not na(KDEHighY))
- if lowProb > KDELowY.sum() * (1.0 - activationThreshold)
- curColor := bullishColor
- else if highProb > KDEHighY.sum() * (1.0 - activationThreshold)
- curColor := bearishColor
- long = na(curColor) and curColor[1] == bullishColor and barstate.isconfirmed
- short = na(curColor) and curColor[1] == bearishColor and barstate.isconfirmed
- if long
- strategy.entry("Long", strategy.long)
- if short
- strategy.entry("Short", strategy.short)
复制代码