From f0e10448c6c9d907d302cbd9a7f3b281a409803f Mon Sep 17 00:00:00 2001 From: jackyu66git Date: Tue, 21 Oct 2025 18:55:40 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0qwen3=E7=9A=84optimised?= =?UTF-8?q?=EF=BC=8C=E5=92=8C=E6=9C=80=E6=97=A9=E7=89=88=E6=9C=AC=E7=BB=93?= =?UTF-8?q?=E6=9E=9C=E4=B8=80=E6=A0=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 支撑压力位QwenMax.pine | 239 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 239 insertions(+) create mode 100644 支撑压力位QwenMax.pine diff --git a/支撑压力位QwenMax.pine b/支撑压力位QwenMax.pine new file mode 100644 index 0000000..b6528e0 --- /dev/null +++ b/支撑压力位QwenMax.pine @@ -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) \ No newline at end of file