添加新的支撑和压力位显示
This commit is contained in:
+150
@@ -0,0 +1,150 @@
|
||||
//@version=6
|
||||
indicator(title="趋势/震荡行情判定 (BTC 1H)", shorttitle="Trend/Range Regime", overlay=true, max_labels_count=500)
|
||||
|
||||
// ========================= 输入参数 =========================
|
||||
// 基础
|
||||
symbolTitle = input.string(defval="BTCUSD/USDT 1H", title="使用说明 (默认为 1 小时 BTC)", inline="hdr")
|
||||
showEma = input.bool(true, "显示EMA", inline="ema")
|
||||
emaLen = input.int(52, "长度", minval=1, inline="ema")
|
||||
|
||||
// 趋势强度/震荡指标参数
|
||||
adxLen = input.int(14, "ADX长度", minval=2, inline="adx")
|
||||
adxTrendThresh = input.float(22.0, "趋势阈值", minval=5, inline="adx")
|
||||
adxRangeThresh = input.float(18.0, "震荡阈值", minval=5, inline="adx")
|
||||
|
||||
chopLen = input.int(14, "CHOP长度", minval=2, inline="chop")
|
||||
chopTrendMax = input.float(45.0, "趋势上限(越小越趋势)", minval=10, maxval=100, inline="chop")
|
||||
chopRangeMin = input.float(55.0, "震荡下限(越大越震荡)", minval=10, maxval=100, inline="chop")
|
||||
|
||||
// 方向与确认
|
||||
slopePctThresh = input.float(0.05, "EMA斜率阈值(%/bar)", minval=0.0, step=0.01)
|
||||
distancePctThresh = input.float(0.10, "价格偏离EMA阈值(%)", minval=0.0, step=0.01)
|
||||
enterConfirmBars = input.int(2, "进入确认根数", minval=1)
|
||||
exitConfirmBars = input.int(2, "退出确认根数", minval=1)
|
||||
|
||||
// 灵敏度:>1 更灵敏,<1 更稳健
|
||||
sensitivity = input.float(1.2, "灵敏度(>1更灵敏,<1更稳健)", minval=0.5, maxval=2.0, step=0.05)
|
||||
|
||||
// 可视化与告警
|
||||
showBackground = input.bool(true, "背景着色")
|
||||
showLabels = input.bool(true, "标记切换点")
|
||||
|
||||
// 颜色
|
||||
colUp = color.new(color.teal, 80)
|
||||
colDn = color.new(color.red, 80)
|
||||
colRg = color.new(color.gray, 85)
|
||||
|
||||
// ========================= 指标计算 =========================
|
||||
ema = ta.ema(close, emaLen)
|
||||
plot(showEma ? ema : na, color=color.new(color.yellow, 0), linewidth=2, title="EMA")
|
||||
|
||||
// EMA 斜率(百分比/每根)
|
||||
emaSlopePct = ema != 0.0 and ema[1] != 0.0 ? 100.0 * (ema - ema[1]) / ema[1] : 0.0
|
||||
priceDistPct = ema != 0.0 ? 100.0 * (close - ema) / ema : 0.0
|
||||
|
||||
// ADX(手动实现,避免环境不支持 ta.adx)
|
||||
upMove = ta.change(high)
|
||||
downMove = -ta.change(low)
|
||||
plusDM = (upMove > downMove and upMove > 0) ? upMove : 0.0
|
||||
minusDM = (downMove > upMove and downMove > 0) ? downMove : 0.0
|
||||
trAdx = ta.tr(true)
|
||||
plusDI = 100.0 * ta.rma(plusDM, adxLen) / ta.rma(trAdx, adxLen)
|
||||
minusDI = 100.0 * ta.rma(minusDM, adxLen) / ta.rma(trAdx, adxLen)
|
||||
dx = (plusDI + minusDI > 0) ? 100.0 * math.abs(plusDI - minusDI) / (plusDI + minusDI) : 0.0
|
||||
adx = ta.rma(dx, adxLen)
|
||||
|
||||
// CHOP (Choppiness Index)
|
||||
var float log10 = math.log(10.0)
|
||||
tr = ta.tr(true)
|
||||
sumTr = ta.sma(tr, chopLen) * chopLen
|
||||
hh = ta.highest(high, chopLen)
|
||||
ll = ta.lowest(low, chopLen)
|
||||
rangeHL = math.max(hh - ll, 1e-10)
|
||||
chop = 100.0 * (math.log(sumTr / rangeHL) / log10) / (math.log(chopLen) / log10)
|
||||
|
||||
// ========================= 阈值动态调整(按灵敏度) =========================
|
||||
sens = sensitivity
|
||||
adxTrendThreshAdj = adxTrendThresh / sens
|
||||
adxRangeThreshAdj = adxRangeThresh * sens
|
||||
chopTrendMaxAdj = math.min(100.0, chopTrendMax * sens)
|
||||
chopRangeMinAdj = math.max(10.0, chopRangeMin / sens)
|
||||
slopePctThreshAdj = slopePctThresh / sens
|
||||
distancePctThreshAdj = distancePctThresh / sens
|
||||
enterConfirmAdj = math.max(1, int(math.round(enterConfirmBars / sens)))
|
||||
exitConfirmAdj = math.max(1, int(math.round(exitConfirmBars / sens)))
|
||||
|
||||
// 条件
|
||||
isTrendStrength = adx > adxTrendThreshAdj and chop < chopTrendMaxAdj
|
||||
isRangeWeak = adx < adxRangeThreshAdj or chop > chopRangeMinAdj
|
||||
|
||||
dirUpRaw = emaSlopePct > slopePctThreshAdj and priceDistPct > distancePctThreshAdj
|
||||
dirDnRaw = emaSlopePct < -slopePctThreshAdj and priceDistPct < -distancePctThreshAdj
|
||||
|
||||
upReady = isTrendStrength and dirUpRaw
|
||||
dnReady = isTrendStrength and dirDnRaw
|
||||
|
||||
// 连续确认
|
||||
upConsec = ta.barssince(not upReady)
|
||||
dnConsec = ta.barssince(not dnReady)
|
||||
upConfirmed = upConsec >= enterConfirmAdj - 1
|
||||
dnConfirmed = dnConsec >= enterConfirmAdj - 1
|
||||
|
||||
// 退出确认(从趋势转入震荡或反向)
|
||||
exitWeak = isRangeWeak or (not isTrendStrength)
|
||||
exitUpConsec = ta.barssince(not exitWeak) >= exitConfirmAdj - 1
|
||||
exitDnConsec = ta.barssince(not exitWeak) >= exitConfirmAdj - 1
|
||||
|
||||
// ========================= 状态机 =========================
|
||||
// 0: 震荡, 1: 上涨趋势, -1: 下跌趋势
|
||||
var int regime = 0
|
||||
prevRegime = nz(regime[1], 0)
|
||||
|
||||
// 选择方向时的冲突消解:优先单边确认,避免同根双向
|
||||
chooseUp = upConfirmed and not dnConfirmed
|
||||
chooseDn = dnConfirmed and not upConfirmed
|
||||
|
||||
// 状态更新(仅在收盘确认时变更)
|
||||
calcRegime = prevRegime == 0 ? (chooseUp ? 1 : (chooseDn ? -1 : 0)) :
|
||||
prevRegime == 1 ? ((exitWeak and not upReady) ? 0 : ((dnConfirmed and isTrendStrength) ? -1 : 1)) :
|
||||
((exitWeak and not dnReady) ? 0 : ((upConfirmed and isTrendStrength) ? 1 : -1))
|
||||
|
||||
regime := barstate.isconfirmed ? calcRegime : nz(regime[1], prevRegime)
|
||||
|
||||
// ========================= 可视化 =========================
|
||||
bgcolor(showBackground ? (regime == 1 ? colUp : regime == -1 ? colDn : colRg) : na, title="背景")
|
||||
|
||||
// 切换点标记
|
||||
enteredUp = barstate.isconfirmed and regime == 1 and prevRegime != 1
|
||||
enteredDn = barstate.isconfirmed and regime == -1 and prevRegime != -1
|
||||
enteredRg = barstate.isconfirmed and regime == 0 and prevRegime != 0
|
||||
|
||||
// 离开点(结束点)
|
||||
leftUp = barstate.isconfirmed and prevRegime == 1 and regime != 1
|
||||
leftDn = barstate.isconfirmed and prevRegime == -1 and regime != -1
|
||||
leftRg = barstate.isconfirmed and prevRegime == 0 and regime != 0
|
||||
|
||||
plotchar(showLabels and enteredUp, title="↑ Up开始", char="↑", location=location.belowbar, color=color.new(color.teal, 0), size=size.tiny)
|
||||
plotchar(showLabels and leftUp, title="↓ Up结束", char="↓", location=location.abovebar, color=color.new(color.gray, 0), size=size.tiny)
|
||||
plotchar(showLabels and enteredDn, title="↓ Down开始", char="↓", location=location.abovebar, color=color.new(color.red, 0), size=size.tiny)
|
||||
plotchar(showLabels and leftDn, title="↑ Down结束", char="↑", location=location.belowbar, color=color.new(color.gray, 0), size=size.tiny)
|
||||
plotchar(showLabels and enteredRg, title="≈ Range开始",char="≈", location=location.top, color=color.new(color.silver, 0), size=size.tiny)
|
||||
plotchar(showLabels and leftRg, title="≠ Range结束",char="≠", location=location.top, color=color.new(color.silver, 0), size=size.tiny)
|
||||
|
||||
// 辅助输出
|
||||
plotchar(regime == 1, title="UpTrend", char="U", location=location.top, color=color.teal, size=size.tiny)
|
||||
plotchar(regime == -1, title="DownTrend", char="D", location=location.top, color=color.red, size=size.tiny)
|
||||
plotchar(regime == 0, title="Range", char="R", location=location.top, color=color.gray, size=size.tiny)
|
||||
|
||||
// ========================= 告警 =========================
|
||||
alertcondition(enteredUp, title="上涨趋势开始", message="上涨趋势开始 (BTC 1H)")
|
||||
alertcondition(leftUp, title="上涨趋势结束", message="上涨趋势结束 (BTC 1H)")
|
||||
alertcondition(enteredDn, title="下跌趋势开始", message="下跌趋势开始 (BTC 1H)")
|
||||
alertcondition(leftDn, title="下跌趋势结束", message="下跌趋势结束 (BTC 1H)")
|
||||
alertcondition(enteredRg, title="震荡开始", message="震荡开始 (BTC 1H)")
|
||||
alertcondition(leftRg, title="震荡结束", message="震荡结束 (BTC 1H)")
|
||||
|
||||
// ========================= 说明 =========================
|
||||
// 建议用于 1 小时 BTC;参数已做温和默认值以区分趋势/震荡。
|
||||
// 如需更敏感:降低 adxTrendThresh、chopTrendMax,降低 slopePctThresh/confirm;反之亦然。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user