添加qwen3的optimised,和最早版本结果一样

This commit is contained in:
jackyu66git
2025-10-21 18:55:40 +08:00
parent 415a2695ff
commit f0e10448c6
+239
View File
@@ -0,0 +1,239 @@
//@version=6
indicator("Support/Resistance (Optimized)", overlay=true, max_lines_count=200, max_labels_count=100)
// ————— Inputs —————
leftBars = input.int(3, "Pivot Left", minval=1)
rightBars = input.int(3, "Pivot Right", minval=1)
lookbackBars = input.int(500, "Lookback Bars", minval=50, maxval=5000)
atrLength = input.int(14, "ATR Length", minval=1)
clusterTolATR = input.float(0.25, "Cluster Tolerance (x ATR)", step=0.05, minval=0.05)
minTouches = input.int(2, "Minimum Touches to Validate", minval=1)
maxLevelsStored = input.int(60, "Max Stored Levels", minval=10, maxval=300)
maxVisibleLevels = input.int(10, "Max Visible Levels", minval=1, maxval=50)
lineWidth = input.int(2, "Line Width", minval=1, maxval=5)
resistanceColor = input.color(color.new(color.red, 0), "Resistance Color")
supportColor = input.color(color.new(color.teal, 0), "Support Color")
showPriceLabels = input.bool(true, "Show Price Labels", inline="lbl")
showTouchesInLbl = input.bool(true, "Touches In Label", inline="lbl")
labelSizeOpt = input.string("Tiny", "Label Size", options=["Tiny", "Small", "Normal", "Large", "Huge"], inline="lbl")
labelOffsetBars = input.int(1, "Label Offset (bars to right)", minval=1, maxval=500)
// ————— Calculations —————
atrValue = ta.atr(atrLength)
// Add minimum absolute tolerance to avoid over-clustering in low-volatility assets
minAbsTolerance = syminfo.mintick * 10
clusterTolerance = math.max(atrValue * clusterTolATR, minAbsTolerance)
// ————— Level Storage —————
var float[] levelPrices = array.new_float()
var int[] levelTotalTouches = array.new_int()
var int[] levelLastTouchBarIndex = array.new_int()
var bool[] levelLastTouchIsResistance = array.new_bool() // NEW: track last touch type
var line[] levelLines = array.new_line()
var label[] levelLabels = array.new_label()
// ————— Helper Functions —————
f_label_size(opt) =>
opt == "Tiny" ? size.tiny : opt == "Small" ? size.small : opt == "Normal" ? size.normal : opt == "Large" ? size.large : size.huge
f_find_level_index(price, tolerance) =>
int foundIndex = -1
sz = array.size(levelPrices)
if sz > 0
for i = 0 to sz - 1
existing = array.get(levelPrices, i)
if math.abs(existing - price) <= tolerance
foundIndex := i
break
foundIndex
f_remove_level(idx) =>
ln = array.get(levelLines, idx)
if not na(ln)
line.delete(ln)
lb = array.get(levelLabels, idx)
if not na(lb)
label.delete(lb)
array.remove(levelPrices, idx)
array.remove(levelTotalTouches, idx)
array.remove(levelLastTouchBarIndex, idx)
array.remove(levelLastTouchIsResistance, idx)
array.remove(levelLines, idx)
array.remove(levelLabels, idx)
f_remove_old_levels() =>
sz = array.size(levelPrices)
if sz > 0
for k = 0 to sz - 1
i = sz - 1 - k
if i < 0
break
lastBar = array.get(levelLastTouchBarIndex, i)
if bar_index - lastBar > lookbackBars
f_remove_level(i)
f_ensure_capacity() =>
if array.size(levelPrices) >= maxLevelsStored
oldestIdx = 0
oldestBar = array.get(levelLastTouchBarIndex, 0)
for i = 1 to array.size(levelPrices) - 1
b = array.get(levelLastTouchBarIndex, i)
if b < oldestBar
oldestBar := b
oldestIdx := i
f_remove_level(oldestIdx)
f_add_or_update_level(price, isResistance) =>
idx = f_find_level_index(price, clusterTolerance)
if idx == -1
f_ensure_capacity()
array.push(levelPrices, price)
array.push(levelTotalTouches, 1)
array.push(levelLastTouchBarIndex, bar_index)
array.push(levelLastTouchIsResistance, isResistance)
array.push(levelLines, na)
array.push(levelLabels, na)
else
prevPrice = array.get(levelPrices, idx)
touches = array.get(levelTotalTouches, idx)
newTouches = touches + 1
newPrice = (prevPrice * touches + price) / newTouches
array.set(levelPrices, idx, newPrice)
array.set(levelTotalTouches, idx, newTouches)
array.set(levelLastTouchBarIndex, idx, bar_index)
array.set(levelLastTouchIsResistance, idx, isResistance) // Update last touch type
f_draw_levels() =>
var int[] candidates = array.new_int()
array.clear(candidates)
sz = array.size(levelPrices)
if sz > 0
for i = 0 to sz - 1
touches = array.get(levelTotalTouches, i)
lastBar = array.get(levelLastTouchBarIndex, i)
if touches >= minTouches and (bar_index - lastBar) <= lookbackBars
array.push(candidates, i)
// Select top N closest to close
var int[] chosen = array.new_int()
array.clear(chosen)
candSz = array.size(candidates)
if candSz > 0
chooseCount = math.min(maxVisibleLevels, candSz)
for _ = 0 to chooseCount - 1
if array.size(candidates) == 0
break
bestPos = -1
bestDist = 10e10
curSz = array.size(candidates)
for pos = 0 to curSz - 1
idx = array.get(candidates, pos)
price = array.get(levelPrices, idx)
d = math.abs(close - price)
if d < bestDist
bestDist := d
bestPos := pos
if bestPos != -1
pickedIdx = array.get(candidates, bestPos)
array.push(chosen, pickedIdx)
array.remove(candidates, bestPos)
// Mark chosen levels
var bool[] isChosen = array.new_bool()
array.clear(isChosen)
if sz > 0
for _ = 0 to sz - 1
array.push(isChosen, false)
chosenSz = array.size(chosen)
if chosenSz > 0
for j = 0 to chosenSz - 1
chIdx = array.get(chosen, j)
if chIdx >= 0 and chIdx < sz
array.set(isChosen, chIdx, true)
// Update visuals
desiredSize = f_label_size(labelSizeOpt)
if sz > 0
for i = 0 to sz - 1
price = array.get(levelPrices, i)
isRes = array.get(levelLastTouchIsResistance, i)
col = isRes ? resistanceColor : supportColor
ln = array.get(levelLines, i)
lb = array.get(levelLabels, i)
if array.get(isChosen, i)
xLeft = math.max(0, bar_index - lookbackBars)
xRight = bar_index
if na(ln)
ln := line.new(x1=xLeft, y1=price, x2=xRight, y2=price, extend=extend.none, color=col, width=lineWidth, style=line.style_dotted)
array.set(levelLines, i, ln)
else
line.set_xy1(ln, xLeft, price)
line.set_xy2(ln, xRight, price)
line.set_color(ln, col)
line.set_width(ln, lineWidth)
// ————— Smart label update —————
if showPriceLabels
touches = array.get(levelTotalTouches, i)
newTxt = (isRes ? "R " : "S ") + str.tostring(price, format.price) + (showTouchesInLbl ? " x" + str.tostring(touches) : "")
shouldRecreate = na(lb) or (label.get_text(lb) != newTxt) or (label.get_x(lb) != bar_index + labelOffsetBars)
if shouldRecreate
if not na(lb)
label.delete(lb)
lblX = bar_index + labelOffsetBars
lb := label.new(x=lblX, y=price, text=newTxt, style=label.style_label_left,
color=color.new(col, 85), textcolor=color.white, size=desiredSize)
array.set(levelLabels, i, lb)
else
if not na(lb)
label.delete(lb)
array.set(levelLabels, i, na)
else
if not na(ln)
line.delete(ln)
array.set(levelLines, i, na)
if not na(lb)
label.delete(lb)
array.set(levelLabels, i, na)
// ————— Detect Pivots —————
ph = ta.pivothigh(high, leftBars, rightBars)
pl = ta.pivotlow(low, leftBars, rightBars)
if not na(ph)
f_add_or_update_level(ph, true)
if not na(pl)
f_add_or_update_level(pl, false)
// ————— Maintenance & Drawing —————
f_remove_old_levels()
f_draw_levels()
// ————— Plot Nearest S/R —————
var float nearestSupport = na
var float nearestResistance = na
nearestSupport := na
nearestResistance := na
szAll = array.size(levelPrices)
if szAll > 0
float bestBelow = na
float bestAbove = na
for i = 0 to szAll - 1
touches = array.get(levelTotalTouches, i)
lastBar = array.get(levelLastTouchBarIndex, i)
if touches >= minTouches and (bar_index - lastBar) <= lookbackBars
p = array.get(levelPrices, i)
if p <= close
bestBelow := na(bestBelow) ? p : math.max(bestBelow, p)
if p >= close
bestAbove := na(bestAbove) ? p : math.min(bestAbove, p)
nearestSupport := bestBelow
nearestResistance := bestAbove
plot(nearestSupport, title="Nearest Support", color=color.new(supportColor, 60), linewidth=1, style=plot.style_linebr)
plot(nearestResistance, title="Nearest Resistance", color=color.new(resistanceColor, 60), linewidth=1, style=plot.style_linebr)