本页源码来自 TradingView 公开发布的开源脚本,版权归原作者所有, 请遵循其原始许可(Pine 脚本常见 CC BY-NC-SA / MPL-2.0 / MIT)。 本项目仅用于研究检索与许可范围内的移植。
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © BOSWaves
//@version=6
indicator("Arc VWAP Supertrend [BOSWaves]", overlay = true,
max_lines_count = 500, max_labels_count = 500)
// ┌───────────────────────────── BOSWaves ─ Arc Settings ────────────────────────────┐
// └──────────────────────────────────────────────────────────────────────────────────┘
float accelRate = input.float(0.12, "Arc Speed", step = 0.01, minval = 0.01,
tooltip = "Base acceleration rate of the arc. Higher values make the arc chase price more aggressively. Scales up automatically when price is extended from VWAP.")
float startMult = input.float(2.0, "Start Distance (ATR×)", step = 0.1,
tooltip = "How far the arc is placed from price when a new trend begins, measured in multiples of the slow ATR. Higher = more breathing room before a flip.")
int smooth = input.int(3, "Smoothing", minval = 1, maxval = 10,
tooltip = "Number of bars used to smooth the arc and candle gradient. Higher values reduce noise but add lag.")
bool showLevels = input.bool(true, "Show Flip Levels",
tooltip = "Draw a horizontal level at each trend flip point. Lines extend forward until price closes through them.")
bool showCloud = input.bool(true, "Show Cloud Fill",
tooltip = "Fill the area between the arc and price with a semi-transparent cloud. Color reflects current trend direction.")
bool showCandles = input.bool(true, "Color Candles",
tooltip = "Override candle colors with a gradient based on trend direction and distance from the arc. Brighter = further from arc.")
int maxLevels = input.int(10, "Max Levels", 5, 50,
tooltip = "Maximum number of unbroken flip levels kept on the chart at once. Oldest levels are removed first when the limit is reached.")
color colUp = input.color(#1ac200, "Bull Color", inline = "c",
tooltip = "Color used for bullish trend elements: arc, candles, flip markers, and cloud fill.")
color colDn = input.color(#ff4040, "Bear Color", inline = "c",
tooltip = "Color used for bearish trend elements: arc, candles, flip markers, and cloud fill.")
float arrowOffset = input.float(1.2, "Arrow Offset (ATR×)", step = 0.1, minval = 0.1,
tooltip = "How far the flip arrows are pushed away from the arc, in multiples of ATR. Increase if arrows overlap candle wicks.")
// ┌───────────────────────────── BOSWaves ─ Flip Level Style ────────────────────────┐
// └──────────────────────────────────────────────────────────────────────────────────┘
string levelStyle = input.string("Dashed", "Level Style",
options = ["Solid", "Dashed", "Dotted"],
group = "Flip Levels",
tooltip = "Line style for active flip levels.")
int levelWidth = input.int(1, "Level Width", minval = 1, maxval = 4,
group = "Flip Levels",
tooltip = "Stroke width of active flip level lines.")
int levelTransp = input.int(20, "Level Transparency", minval = 0, maxval = 90,
group = "Flip Levels",
tooltip = "Transparency of active flip level lines. 0 = fully opaque, 90 = nearly invisible.")
bool levelLabel = input.bool(true, "Show Price Label",
group = "Flip Levels",
tooltip = "Show a small price label at the right edge of each active flip level.")
string levelLabelSize = input.string("tiny", "Label Size",
options = ["auto", "tiny", "small", "normal", "large", "huge"],
group = "Flip Levels",
tooltip = "Size of the price label shown at the right edge of each flip level.")
// ┌───────────────────────────── BOSWaves ─ VWAP Settings ───────────────────────────┐
// └──────────────────────────────────────────────────────────────────────────────────┘
string filterPeriod = input.string("Session", "Signal Filter Period",
options = ["Session", "Week", "Month", "Any", "All"],
group = "VWAP",
tooltip = "Which VWAP must agree with the flip direction for a confirmed alert.\n\nSession = daily VWAP\nWeek = rolling weekly VWAP\nMonth = rolling monthly VWAP\nAny = at least one VWAP agrees\nAll = every VWAP must agree")
float vwapAccelBoost = input.float(1.5, "VWAP Distance Speed Boost",
minval = 1.0, maxval = 5.0, step = 0.1,
group = "VWAP",
tooltip = "How much faster the arc accelerates when price is extended from the reference VWAP.\n\n1.0 = no boost (flat acceleration)\n5.0 = up to 5× faster when price is 4+ ATRs from VWAP")
// ┌───────────────────────────── BOSWaves ─ VWAP Calculation ────────────────────────┐
// └──────────────────────────────────────────────────────────────────────────────────┘
bool newSession = timeframe.change("D")
var float cumPvS = 0.0
var float cumVolS = 0.0
if newSession
cumPvS := 0.0
cumVolS := 0.0
cumPvS += hl2 * volume
cumVolS += volume
float vwapSession = cumVolS > 0 ? cumPvS / cumVolS : hl2
bool newWeek = timeframe.change("W")
var float cumPvW = 0.0
var float cumVolW = 0.0
if newWeek
cumPvW := 0.0
cumVolW := 0.0
cumPvW += hl2 * volume
cumVolW += volume
float vwapWeek = cumVolW > 0 ? cumPvW / cumVolW : hl2
bool newMonth = timeframe.change("M")
var float cumPvM = 0.0
var float cumVolM = 0.0
if newMonth
cumPvM := 0.0
cumVolM := 0.0
cumPvM += hl2 * volume
cumVolM += volume
float vwapMonth = cumVolM > 0 ? cumPvM / cumVolM : hl2
// ┌───────────────────────────── BOSWaves ─ VWAP Filter & Speed Logic ───────────────┐
// └──────────────────────────────────────────────────────────────────────────────────┘
vwapAgrees(bool bullish) =>
bool s = bullish ? close >= vwapSession : close <= vwapSession
bool w = bullish ? close >= vwapWeek : close <= vwapWeek
bool m = bullish ? close >= vwapMonth : close <= vwapMonth
switch filterPeriod
"Session" => s
"Week" => w
"Month" => m
"Any" => s or w or m
"All" => s and w and m
=> true
float atr = ta.atr(14)
float atrSlow = ta.sma(ta.tr, 100)
float refVwap = switch filterPeriod
"Session" => vwapSession
"Week" => vwapWeek
"Month" => vwapMonth
=> vwapSession
float vwapDistNorm = nz(atr, 1) > 0 ? math.min(math.abs(close - refVwap) / (nz(atr, 1) * 4), 1.0) : 0.0
float effectiveAccel = accelRate * (1.0 + (vwapAccelBoost - 1.0) * vwapDistNorm)
// ┌───────────────────────────── BOSWaves ─ Core Calculation ────────────────────────┐
// └──────────────────────────────────────────────────────────────────────────────────┘
var bool trend = true
var float arc = na
var float velocity = 0.0
var bool initDone = false
if not initDone and not na(atrSlow) and bar_index > 100
arc := low - atrSlow * startMult
trend := true
initDone := true
if initDone
if close < arc
trend := false
if close > arc
trend := true
bool rawFlipped = initDone and trend != trend[1]
bool flipConfirmed = rawFlipped and vwapAgrees(trend)
bool flipFiltered = rawFlipped and not flipConfirmed
if rawFlipped and trend
arc := low - nz(atrSlow, 1) * startMult
velocity := 0.0
if rawFlipped and not trend
arc := high + nz(atrSlow, 1) * startMult
velocity := 0.0
float stepSize = nz(atrSlow, 1) * 0.15
if initDone and bar_index % smooth == 0
velocity += effectiveAccel
if trend
arc += stepSize * velocity
else
arc -= stepSize * velocity
float arcSmooth = ta.sma(arc, smooth)
float outerRaw = trend ? arc + nz(atrSlow, 1) * 0.4 : arc - nz(atrSlow, 1) * 0.4
float outer = ta.sma(outerRaw, smooth)
color trendClr = trend ? colUp : colDn
// ┌───────────────────────────── BOSWaves ─ Flip Levels ─────────────────────────────┐
// └──────────────────────────────────────────────────────────────────────────────────┘
var flipLines = array.new<line>()
var flipLevels = array.new<float>()
var flipBull = array.new<bool>()
var flipLabels = array.new<label>()
string resolvedLabelSize = levelLabelSize == "auto" ? size.auto :
levelLabelSize == "small" ? size.small :
levelLabelSize == "normal" ? size.normal :
levelLabelSize == "large" ? size.large :
levelLabelSize == "huge" ? size.huge : size.tiny
if rawFlipped and showLevels
float _price = trend ? low : high
color _clr = color.new(trendClr, levelTransp)
_ln = line.new(bar_index, _price, bar_index + 1, _price,
color = _clr,
width = levelWidth,
style = levelStyle == "Dotted" ? line.style_dotted :
levelStyle == "Solid" ? line.style_solid :
line.style_dashed)
string _labelTxt = levelLabel ? str.tostring(_price, format.mintick) : ""
_lbl = label.new(bar_index + 1, _price, _labelTxt,
color = color.new(trendClr, 80),
textcolor = trendClr,
style = label.style_label_left,
size = resolvedLabelSize)
flipLines.push(_ln)
flipLevels.push(_price)
flipBull.push(trend)
flipLabels.push(_lbl)
label.new(bar_index, _price, "◆",
color = color(na),
textcolor = trendClr,
style = trend ? label.style_label_up : label.style_label_down,
size = size.tiny)
if flipLines.size() > 0
for i = flipLines.size() - 1 to 0
if i >= flipLines.size()
break
ln = flipLines.get(i)
if na(ln)
flipLines.remove(i)
if i < flipLevels.size()
flipLevels.remove(i)
if i < flipBull.size()
flipBull.remove(i)
if i < flipLabels.size()
lbl = flipLabels.get(i)
if not na(lbl)
label.delete(lbl)
flipLabels.remove(i)
continue
line.set_x2(ln, bar_index)
float lvl = flipLevels.get(i)
bool isBull = flipBull.get(i)
if i < flipLabels.size()
lbl = flipLabels.get(i)
if not na(lbl)
label.set_x(lbl, bar_index)
bool broken = isBull ? (close < lvl and barstate.isconfirmed) :
(close > lvl and barstate.isconfirmed)
if broken
line.delete(ln)
flipLines.set(i, line(na))
if i < flipLabels.size()
lbl = flipLabels.get(i)
if not na(lbl)
label.delete(lbl)
flipLabels.set(i, label(na))
while flipLines.size() > maxLevels
_old = flipLines.shift()
if not na(_old)
line.delete(_old)
if flipLevels.size() > 0
flipLevels.shift()
if flipBull.size() > 0
flipBull.shift()
if flipLabels.size() > 0
_oldLbl = flipLabels.shift()
if not na(_oldLbl)
label.delete(_oldLbl)
// ┌───────────────────────────── BOSWaves ─ Visualization ───────────────────────────┐
// └──────────────────────────────────────────────────────────────────────────────────┘
float arcPlotVal = initDone and not rawFlipped ? arcSmooth : na
float priceRef = ta.sma(hl2, smooth * 5)
p1 = plot(arcPlotVal, "Arc", color.new(chart.fg_color, 60), 1, plot.style_linebr)
p2 = plot(priceRef, display = display.none, editable = false)
color fillClr = showCloud and initDone ? color.new(trendClr, 65) : na
fill(p1, p2, arcSmooth, priceRef, fillClr, color(na))
float distToArc = not na(arcSmooth) ? math.abs(close - arcSmooth) : 0
float safAtr = nz(atr, 1)
float distNorm = safAtr > 0 ? math.min(distToArc / (safAtr * 3), 1.0) : 0.5
color gradCandle = showCandles ?
color.from_gradient(distNorm, 0, 1, color.new(trendClr, 55), trendClr) : na
plotcandle(open, high, low, close, "Candles",
gradCandle, gradCandle, bordercolor = gradCandle)
float arrowAtr = nz(atr, nz(atrSlow, 1))
float bullArrowY = rawFlipped and trend ? arcSmooth - arrowAtr * arrowOffset : na
float bearArrowY = rawFlipped and not trend ? arcSmooth + arrowAtr * arrowOffset : na
plotshape(bullArrowY, "Bull Flip",
shape.triangleup, location.absolute, colUp, size = size.tiny)
plotshape(bullArrowY, "Bull Glow",
shape.triangleup, location.absolute, color.new(colUp, 60), size = size.small)
plotshape(bearArrowY, "Bear Flip",
shape.triangledown, location.absolute, colDn, size = size.tiny)
plotshape(bearArrowY, "Bear Glow",
shape.triangledown, location.absolute, color.new(colDn, 60), size = size.small)
// ┌───────────────────────────── BOSWaves ─ Alerts ──────────────────────────────────┐
// └──────────────────────────────────────────────────────────────────────────────────┘
alertcondition(flipConfirmed and trend, "Bullish Flip (VWAP Confirmed)", "Arc Supertrend — Bullish flip confirmed by VWAP")
alertcondition(flipConfirmed and not trend, "Bearish Flip (VWAP Confirmed)", "Arc Supertrend — Bearish flip confirmed by VWAP")
alertcondition(flipFiltered and trend, "Bullish Flip (VWAP Filtered)", "Arc Supertrend — Bullish flip, VWAP disagrees")
alertcondition(flipFiltered and not trend, "Bearish Flip (VWAP Filtered)", "Arc Supertrend — Bearish flip, VWAP disagrees")