PROTECTED SOURCE SCRIPT

P6●智能资金概念交易系统

33
//version=5
indicator("P6●智能资金概念交易系统", overlay=true, max_boxes_count = 500, max_labels_count = 500)

// === 参数分类标题 ===
// --------------------------
// 1. 基础指标设置
// --------------------------
// 2. 范围过滤器 设置
// --------------------------
// 3. ADX 趋势过滤器 设置
// --------------------------
// 4. 趋势线 设置
// --------------------------
// 5. 支撑与阻力 设置
// --------------------------
// 6. PMA 设置
// --------------------------
// 7. 交易信息表格 设置
// --------------------------
// 8. 顶部规避 设置
// --------------------------
// 9. 底部规避 设置
// --------------------------
// 10. RSI 动量指标 设置
// --------------------------
// 11. 多时间框架 设置
// --------------------------

// === 显示/隐藏选项 ===
showRangeFilter = input.bool(true, title="显示 范围过滤器", group="1. 基础指标设置")
showADXFilter = input.bool(true, title="启用 ADX 趋势过滤器", group="1. 基础指标设置")
showTrendLines = input.bool(false, title="显示 趋势线", group="1. 基础指标设置")
showSupRes = input.bool(true, title="显示 支撑与阻力", group="1. 基础指标设置")
showPMA = input.bool(true, title="显示 多周期移动平均线", group="1. 基础指标设置")
showTable = input.bool(true, title="显示 交易信息表格", group="1. 基础指标设置")
showTopAvoidance = input.bool(false, title="启用 顶部规避系统", group="1. 基础指标设置")
showBottomAvoidance = input.bool(false, title="启用 底部规避系统", group="1. 基础指标设置")
showRSI = input.bool(false, title="启用 RSI 动量指标", group="1. 基础指标设置")
showMTF = input.bool(true, title="启用 多时间框架分析", group="1. 基础指标设置")

// === RSI 动量指标 设置 ===
rsiLength = input.int(14, title="RSI 周期", minval=1, group="10. RSI 动量指标 设置")
rsiOverbought = input.float(70.0, title="超买阈值", minval=50, maxval=90, step=1, group="10. RSI 动量指标 设置")
rsiOversold = input.float(30.0, title="超卖阈值", minval=10, maxval=50, step=1, group="10. RSI 动量指标 设置")
rsiNeutralUpper = input.float(60.0, title="中性区间上沿", minval=50, maxval=70, step=1, group="10. RSI 动量指标 设置")
rsiNeutralLower = input.float(40.0, title="中性区间下沿", minval=30, maxval=50, step=1, group="10. RSI 动量指标 设置")

// === 多时间框架设置 ===
mtfEnable1m = input.bool(true, title="启用 1分钟", group="11. 多时间框架 设置")
mtfEnable5m = input.bool(true, title="启用 5分钟", group="11. 多时间框架 设置")
mtfEnable15m = input.bool(true, title="启用 15分钟", group="11. 多时间框架 设置")
mtfEnable1h = input.bool(true, title="启用 1小时", group="11. 多时间框架 设置")
mtfEnable4h = input.bool(true, title="启用 4小时", group="11. 多时间框架 设置")

// === RSI 计算与状态判断 ===
rsiValue = ta.rsi(close, rsiLength)
rsiPrevious = ta.rsi(close[1], rsiLength)

// RSI 动量状态判断
getRSIStatus() =>
status = "动量中性"

// 动量回落条件:RSI从高位下降或处于下降趋势
fallCondition1 = rsiValue < rsiPrevious and rsiValue > rsiNeutralUpper
fallCondition2 = rsiValue >= rsiOverbought and rsiValue < rsiPrevious
fallCondition3 = rsiPrevious >= rsiOverbought and rsiValue < rsiOverbought and rsiValue < rsiPrevious

if fallCondition1 or fallCondition2 or fallCondition3
status := "动量回落"

// 动量回升条件:RSI从低位上升或处于上升趋势
riseCondition1 = rsiValue > rsiPrevious and rsiValue < rsiNeutralLower
riseCondition2 = rsiValue <= rsiOversold and rsiValue > rsiPrevious
riseCondition3 = rsiPrevious <= rsiOversold and rsiValue > rsiOversold and rsiValue > rsiPrevious

if riseCondition1 or riseCondition2 or riseCondition3
status := "动量回升"

// 动量中性条件:RSI在中性区间或无明确趋势
if rsiValue >= rsiNeutralLower and rsiValue <= rsiNeutralUpper
status := "动量中性"

status

rsiStatus = getRSIStatus()

// RSI 信号与其他指标结合
rsiSupportsBuy = rsiStatus == "动量回升" or (rsiValue <= rsiOversold and rsiValue > rsiPrevious)
rsiSupportssell = rsiStatus == "动量回落" or (rsiValue >= rsiOverbought and rsiValue < rsiPrevious)

// === 多时间框架数据获取 ===
// 简化的多时间框架趋势计算
calcSimpleTrend(src) =>
ema21 = ta.ema(src, 21)
ema50 = ta.ema(src, 50)
trend = src > ema21 and ema21 > ema50 ? 1 : src < ema21 and ema21 < ema50 ? -1 : 0
trend

// 获取各时间框架的趋势数据
trend1m = showMTF and mtfEnable1m ? request.security(syminfo.tickerid, "1", calcSimpleTrend(close)) : 0
trend5m = showMTF and mtfEnable5m ? request.security(syminfo.tickerid, "5", calcSimpleTrend(close)) : 0
trend15m = showMTF and mtfEnable15m ? request.security(syminfo.tickerid, "15", calcSimpleTrend(close)) : 0
trend1h = showMTF and mtfEnable1h ? request.security(syminfo.tickerid, "60", calcSimpleTrend(close)) : 0
trend4h = showMTF and mtfEnable4h ? request.security(syminfo.tickerid, "240", calcSimpleTrend(close)) : 0

// === 多时间框架趋势判断函数 ===
getTrendDirection(trend) =>
if trend > 0
"多头倾向"
else if trend < 0
"空头倾向"
else
"震荡"

// 获取各时间框架趋势方向
trend1mDir = getTrendDirection(trend1m)
trend5mDir = getTrendDirection(trend5m)
trend15mDir = getTrendDirection(trend15m)
trend1hDir = getTrendDirection(trend1h)
trend4hDir = getTrendDirection(trend4h)

// === 顶部规避系统 ===
ma_period_top = input.int(10, 'MA Period (Length)', group='8. 顶部规避 设置')
topThreshold = input.int(85, 'VAR顶部阈值', minval=70, maxval=95, step=1, group='8. 顶部规避 设置')

// 计算VAR指标 - 顶部(检测上涨动能)
pre_price_top = close[1]
VAR_top = ta.sma(math.max(close-pre_price_top,0), ma_period_top) / ta.sma(math.abs(close-pre_price_top), ma_period_top) * 100

// 顶部信号 - 当上涨动能达到高位时
isTop = VAR_top > topThreshold and VAR_top[1] <= topThreshold

// 图表显示顶部标记
plotshape(series=showTopAvoidance and isTop, title="顶", style=shape.labeldown, location=location.abovebar,
color=color.new(color.purple, 0), textcolor=color.white, size=size.normal, text="顶")

// === 底部规避系统 ===
ma_period_bottom = input.int(14, 'MA Period (Length)', group='9. 底部规避 设置')
bottomThreshold = input.int(15, 'VAR底部阈值', minval=5, maxval=30, step=1, group='9. 底部规避 设置')

// 计算VAR指标 - 底部(检测下跌动能)
pre_price_bottom = close[1]
VAR_bottom = ta.sma(math.max(pre_price_bottom-close,0), ma_period_bottom) / ta.sma(math.abs(close-pre_price_bottom), ma_period_bottom) * 100

// 底部信号 - 当下跌动能达到高位时
isBottom = VAR_bottom > bottomThreshold and VAR_bottom[1] <= bottomThreshold

// 图表显示底部标记
plotshape(series=showBottomAvoidance and isBottom, title="底", style=shape.labelup, location=location.belowbar,
color=color.new(color.orange, 0), textcolor=color.white, size=size.normal, text="底")

// === 范围过滤器 部分 ===
upColor = color.white
midColor = #90bff9
downColor = color.blue

src = input(defval=close, title="数据源", group="2. 范围过滤器 设置")
per = input.int(defval=100, minval=1, title="采样周期", group="2. 范围过滤器 设置")
mult = input.float(defval=3.0, minval=0.1, title="区间倍数", group="2. 范围过滤器 设置")

smoothrng(x, t, m) =>
wper = t * 2 - 1
avrng = ta.ema(math.abs(x - x[1]), t)
smoothrng = ta.ema(avrng, wper) * m
smoothrng
smrng = smoothrng(src, per, mult)

rngfilt(x, r) =>
rngfilt = x
rngfilt := x > nz(rngfilt[1]) ? x - r < nz(rngfilt[1]) ? nz(rngfilt[1]) : x - r :
x + r > nz(rngfilt[1]) ? nz(rngfilt[1]) : x + r
rngfilt

filt = rngfilt(src, smrng)

upward = 0.0
upward := filt > filt[1] ? nz(upward[1]) + 1 : filt < filt[1] ? 0 : nz(upward[1])
downward = 0.0
downward := filt < filt[1] ? nz(downward[1]) + 1 : filt > filt[1] ? 0 : nz(downward[1])

hband = filt + smrng
lband = filt - smrng

filtcolor = upward > 0 ? upColor : downward > 0 ? downColor : midColor
barcolor_ = src > filt and src > src[1] and upward > 0 ? upColor :
src > filt and src < src[1] and upward > 0 ? upColor :
src < filt and src < src[1] and downward > 0 ? downColor :
src < filt and src > src[1] and downward > 0 ? downColor : midColor

longCond = bool(na)
shortCond = bool(na)
longCond := src > filt and src > src[1] and upward > 0 or
src > filt and src < src[1] and upward > 0
shortCond := src < filt and src < src[1] and downward > 0 or
src < filt and src > src[1] and downward > 0

CondIni = 0
CondIni := longCond ? 1 : shortCond ? -1 : CondIni[1]
// === ADX 趋势过滤器 部分 ===
adxLength = input.int(defval=14, minval=1, title="ADX 周期", group="3. ADX 趋势过滤器 设置")
adxThreshold = input.float(defval=25.0, minval=0, maxval=100, step=0.5, title="ADX 阈值", tooltip="ADX大于此值才允许交易信号", group="3. ADX 趋势过滤器 设置")

// 简化的ADX计算 - 更准确的方法
calcADX(len) =>
up = ta.change(high)
down = -ta.change(low)
plusDM = na(up) ? na : (up > down and up > 0 ? up : 0)
minusDM = na(down) ? na : (down > up and down > 0 ? down : 0)
truerange = ta.rma(ta.tr, len)
plus = fixnan(100 * ta.rma(plusDM, len) / truerange)
minus = fixnan(100 * ta.rma(minusDM, len) / truerange)
sum = plus + minus
adx = 100 * ta.rma(math.abs(plus - minus) / (sum == 0 ? 1 : sum), len)
[adx, plus, minus]

[adxValue, diPlus, diMinus] = calcADX(adxLength)

// ADX状态判断
adxStrong = adxValue >= adxThreshold
adxTrendUp = diPlus > diMinus
adxTrendDown = diMinus > diPlus

// 修改信号生成逻辑,加入顶部和底部规避以及RSI确认
longCondition = longCond and CondIni[1] == -1 and (not showADXFilter or adxStrong) and (not showTopAvoidance or not isTop) and (not showRSI or rsiSupportsBuy)
shortCondition = shortCond and CondIni[1] == 1 and (not showADXFilter or adxStrong) and (not showBottomAvoidance or not isBottom) and (not showRSI or rsiSupportssell)

// === 记录买卖信号价格 ===
var float entryPrice = na
var string entryType = na
var float entryTime = na

// 当出现买入信号时记录
if longCondition
entryPrice := close
entryType := "多单"
entryTime := time

// 当出现卖出信号时记录
if shortCondition
entryPrice := close
entryType := "空单"
entryTime := time

// === 趋势颜色逻辑 ===
var trendColor = color.gray
if longCondition
trendColor := color.green
else if shortCondition
trendColor := color.red

// ADX线绘制(可选)- 已隐藏显示
adxColor = adxStrong ? (adxTrendUp ? color.green : color.red) : color.gray
// plot(showADXLine and showADXFilter ? adxValue : na, title="平均方向指数", color=adxColor, linewidth=1)
// hline(showADXLine and showADXFilter ? adxThreshold : na, title="ADX阈值线", color=color.yellow, linestyle=hline.style_dashed)

// 绘图部分 - 已隐藏线条显示,保留功能
// filtplot = plot(showRangeFilter ? filt : na, color=trendColor, linewidth=2, title="区间过滤器")
// hbandplot = plot(showRangeFilter ? hband : na, color=color.new(trendColor, 30), title="上轨线", linewidth=1)
// lbandplot = plot(showRangeFilter ? lband : na, color=color.new(trendColor, 30), title="下轨线", linewidth=1)

// barcolor(na) - 已隐藏K线颜色

plotshape(showRangeFilter and longCondition, title="买入信号", text="买", textcolor=color.white, style=shape.labelup, size=size.small, location=location.belowbar, color=color.new(color.green, 20))
plotshape(showRangeFilter and shortCondition, title="卖出信号", text="卖", textcolor=color.white, style=shape.labeldown, size=size.small, location=location.abovebar, color=color.new(color.red, 20))

// === 趋势线 部分 ===
length_tl = input.int(14, '分型回溯长度', group="4. 趋势线 设置")
mult_tl = input.float(1., '斜率系数', minval = 0, step = .1, group="4. 趋势线 设置")
calcMethod = input.string('平均真实波幅', '斜率计算方法', options = ['平均真实波幅','标准差','线性回归'], group="4. 趋势线 设置")
backpaint = input(true, tooltip = '回溯显示:将可视元素向历史偏移,禁用后可查看实时信号。', group="4. 趋势线 设置")

upCss = input.color(color.teal, '上升趋势线颜色', group = "4. 趋势线 设置")
dnCss = input.color(color.red, '下降趋势线颜色', group = "4. 趋势线 设置")
showExt = input(true, '显示延长线', group="4. 趋势线 设置")

var upper_tl = 0.
var lower_tl = 0.
var slope_ph_tl = 0.
var slope_pl_tl = 0.

var offset_tl = backpaint ? length_tl : 0

n = bar_index
src_tl = close

ph = ta.pivothigh(length_tl, length_tl)
pl = ta.pivotlow(length_tl, length_tl)

slope = switch calcMethod
'平均真实波幅' => ta.atr(length_tl) / length_tl * mult_tl
'标准差' => ta.stdev(src_tl, length_tl) / length_tl * mult_tl
'线性回归' => math.abs(ta.sma(src_tl * n, length_tl) - ta.sma(src_tl, length_tl) * ta.sma(n, length_tl)) / ta.variance(n, length_tl) / 2 * mult_tl

slope_ph_tl := ph ? slope : slope_ph_tl
slope_pl_tl := pl ? slope : slope_pl_tl

upper_tl := ph ? ph : upper_tl - slope_ph_tl
lower_tl := pl ? pl : lower_tl + slope_pl_tl

var upos = 0
var dnos = 0
upos := ph ? 0 : close > upper_tl - slope_ph_tl * length_tl ? 1 : upos
dnos := pl ? 0 : close < lower_tl + slope_pl_tl * length_tl ? 1 : dnos

var uptl = line.new(na,na,na,na, color = upCss, style = line.style_dashed, extend = extend.right)
var dntl = line.new(na,na,na,na, color = dnCss, style = line.style_dashed, extend = extend.right)

if ph and showExt and showTrendLines
line.set_xy1(uptl, n-offset_tl, backpaint ? ph : upper_tl - slope_ph_tl * length_tl)
line.set_xy2(uptl, n-offset_tl+1, backpaint ? ph - slope : upper_tl - slope_ph_tl * (length_tl+1))

if pl and showExt and showTrendLines
line.set_xy1(dntl, n-offset_tl, backpaint ? pl : lower_tl + slope_pl_tl * length_tl)
line.set_xy2(dntl, n-offset_tl+1, backpaint ? pl + slope : lower_tl + slope_pl_tl * (length_tl+1))

plot(showTrendLines ? (backpaint ? upper_tl : upper_tl - slope_ph_tl * length_tl) : na, '上升趋势线', color = ph ? na : upCss, offset = -offset_tl)
plot(showTrendLines ? (backpaint ? lower_tl : lower_tl + slope_pl_tl * length_tl) : na, '下降趋势线', color = pl ? na : dnCss, offset = -offset_tl)

// 趋势线突破也需要ADX确认,并加入顶部和底部规避以及RSI确认
trendLineBuySignal = showTrendLines and upos > upos[1] and (not showADXFilter or adxStrong) and (not showTopAvoidance or not isTop) and (not showRSI or rsiSupportsBuy)
trendLineSellSignal = showTrendLines and dnos > dnos[1] and (not showADXFilter or adxStrong) and (not showBottomAvoidance or not isBottom) and (not showRSI or rsiSupportssell)

plotshape(trendLineBuySignal ? low : na, "上轨突破"
, shape.labelup
, location.absolute
, upCss
, text = "突"
, textcolor = color.white
, size = size.tiny)

plotshape(trendLineSellSignal ? high : na, "下轨突破"
, shape.labeldown
, location.absolute
, dnCss
, text = "突"
, textcolor = color.white
, size = size.tiny)

alertcondition(trendLineBuySignal, '上轨突破', '价格向上突破下趋势线')
alertcondition(trendLineSellSignal, '下轨突破', '价格向下突破上趋势线')
// === 支撑与阻力 部分 ===

g_sr = '5. 支撑与阻力'
g_c = '条件'
g_st = '样式'
t_r = 'K线确认:仅在K线收盘时生成警报(延后1根K线)。\n\n高点与低点:默认情况下,突破/回踩系统使用当前收盘价判断,选择高点与低点后将使用高低点判断条件,不再重绘,结果会不同。'
t_rv = '每当检测到潜在回踩时,指标会判断回踩事件即将发生。此输入用于设置在潜在回踩激活时,最大允许检测多少根K线。\n\n例如,出现潜在回踩标签时,该标签允许存在多少根K线以确认回踩?此功能防止回踩警报在10根K线后才触发导致不准确。'

input_lookback = input.int(defval = 20, title = '回溯区间', minval = 1, tooltip = '检测分型事件的K线数量。', group = g_sr)
input_retSince = input.int(defval = 2, title = '突破后K线数', minval = 1, tooltip = '突破后多少根K线内检测回踩。', group = g_sr)
input_retValid = input.int(defval = 2, title = '回踩检测限制', minval = 1, tooltip = t_rv, group = g_sr)
input_breakout = input.bool(defval = true, title = '显示突破', group = g_c)
input_retest = input.bool(defval = true, title = '显示回踩', group = g_c)
input_repType = input.string(defval = '开启', title = '重绘模式', options = ['开启', '关闭:K线确认', '关闭:高低点'], tooltip = t_r, group = g_c)
input_outL = input.string(defval = line.style_dotted, title = '边框样式', group = g_st, options = [line.style_dotted, line.style_dashed, line.style_solid])
input_extend = input.string(defval = extend.none, title = '延长方向', group = g_st, options = [extend.none, extend.right, extend.left, extend.both])

input_labelType = input.string(defval = '详细', title = '标签类型', options = ['详细', '简洁'], group = g_st)
input_labelSize = input.string(defval = size.small, title = '标签大小', options = [size.tiny, size.small, size.normal, size.large, size.huge], group = g_st)
st_break_lb_co1 = input.color(defval = color.lime , title = '空头突破标签颜色' ,inline = 'st_break_lb_co', group = g_st)
st_break_lb_co2 = input.color(defval = color.new(color.lime,40) , title = '' ,inline = 'st_break_lb_co', group = g_st)
lg_break_lb_co1 = input.color(defval = color.red , title = '多头突破标签颜色' ,inline = 'lg_break_lb_co', group = g_st)
lg_break_lb_co2 = input.color(defval = color.new(color.red,40) , title = '' ,inline = 'lg_break_lb_co', group = g_st)
st_retest_lb_co1 = input.color(defval = color.lime , title = '空头回踩标签颜色' ,inline = 'st_retest_lb_col', group = g_st)
st_retest_lb_co2 = input.color(defval = color.new(color.lime,40) , title = '' ,inline = 'st_retest_lb_col', group = g_st)
lg_retest_lb_co1 = input.color(defval = color.red , title = '多头回踩标签颜色' ,inline = 'lg_retest_lb_co', group = g_st)
lg_retest_lb_co2 = input.color(defval = color.new(color.red,40) , title = '' ,inline = 'lg_retest_lb_co', group = g_st)

input_plColor1 = input.color(defval = color.lime, title = '支撑方框颜色', inline = 'pl_Color', group = g_st)
input_plColor2 = input.color(defval = color.new(color.lime,85), title = '', inline = 'pl_Color', group = g_st)
input_phColor1 = input.color(defval = color.red, title = '阻力方框颜色', inline = 'ph_Color', group = g_st)
input_phColor2 = input.color(defval = color.new(color.red,85), title = '', inline = 'ph_Color', group = g_st)

input_override = input.bool(defval = false, title = '自定义文字颜色', inline = '覆盖', group = g_st)
input_textColor = input.color(defval = color.white, title = '', inline = '覆盖', group = g_st)
bb = input_lookback

// 兼容label与英文选项
rTon = input_repType == '开启'
rTcc = input_repType == '关闭:K线确认'
rThv = input_repType == '关闭:高低点'
breakText = input_labelType == '简洁' ? '突' : '突破'

// 分型
rs_pl = fixnan(ta.pivotlow(low, bb, bb))
rs_ph = fixnan(ta.pivothigh(high, bb, bb))

// Box 高度
s_yLoc = low[bb + 1] > low[bb - 1] ? low[bb - 1] : low[bb + 1]
r_yLoc = high[bb + 1] > high[bb - 1] ? high[bb + 1] : high[bb - 1]

//-----------------------------------------------------------------------------
// 函数
//-----------------------------------------------------------------------------
drawBox(condition, y1, y2, color,bgcolor) =>
var box drawBox = na
if condition and showSupRes // 仅在显示开关打开时绘制
box.set_right(drawBox, bar_index - bb)
drawBox.set_extend(extend.none)
drawBox := box.new(bar_index - bb, y1, bar_index, y2, color, bgcolor = bgcolor, border_style = input_outL, extend = input_extend)
[drawBox]

updateBox(box) =>
if barstate.isconfirmed and showSupRes
box.set_right(box, bar_index + 5)

breakLabel(y, txt_col,lb_col, style, textform) =>
if showSupRes
label.new(bar_index, y, textform, textcolor = input_override ? input_textColor : txt_col, style = style, color = lb_col, size = input_labelSize)
retestCondition(breakout, condition) =>
ta.barssince(na(breakout)) > input_retSince and condition
repaint(c1, c2, c3) => rTon ? c1 : rThv ? c2 : rTcc ? c3 : na

//-----------------------------------------------------------------------------
// 绘制与更新区间
//-----------------------------------------------------------------------------
[sBox] = drawBox(ta.change(rs_pl), s_yLoc, rs_pl, input_plColor1,input_plColor2)
[rBox] = drawBox(ta.change(rs_ph), rs_ph, r_yLoc, input_phColor1,input_phColor2)
sTop = box.get_top(sBox), rTop = box.get_top(rBox)
sBot = box.get_bottom(sBox), rBot = box.get_bottom(rBox)

if showSupRes
updateBox(sBox), updateBox(rBox)

//-----------------------------------------------------------------------------
// 突破事件 - 加入顶部和底部规避以及RSI确认
//-----------------------------------------------------------------------------
var bool sBreak = na
var bool rBreak = na
cu = repaint(ta.crossunder(close, box.get_bottom(sBox)), ta.crossunder(low, box.get_bottom(sBox)), ta.crossunder(close, box.get_bottom(sBox)) and barstate.isconfirmed)
co = repaint(ta.crossover(close, box.get_top(rBox)), ta.crossover(high, box.get_top(rBox)), ta.crossover(close, box.get_top(rBox)) and barstate.isconfirmed)

switch
cu and na(sBreak) and showSupRes and (not showADXFilter or adxStrong) and (not showBottomAvoidance or not isBottom) and (not showRSI or rsiSupportssell) =>
sBreak := true
if input_breakout
breakLabel(sBot, st_break_lb_co1,st_break_lb_co2, label.style_label_upper_right, breakText)
co and na(rBreak) and showSupRes and (not showADXFilter or adxStrong) and (not showTopAvoidance or not isTop) and (not showRSI or rsiSupportsBuy) =>
rBreak := true
if input_breakout
breakLabel(rTop, lg_break_lb_co1,lg_break_lb_co2, label.style_label_lower_right, breakText)

if ta.change(rs_pl) and showSupRes
if na(sBreak)
box.delete(sBox[1])
sBreak := na
if ta.change(rs_ph) and showSupRes
if na(rBreak)
box.delete(rBox[1])
rBreak := na

//-----------------------------------------------------------------------------
// 回踩事件
//-----------------------------------------------------------------------------
s1 = retestCondition(sBreak, high >= sTop and close <= sBot)
s2 = retestCondition(sBreak, high >= sTop and close >= sBot and close <= sTop)
s3 = retestCondition(sBreak, high >= sBot and high <= sTop)
s4 = retestCondition(sBreak, high >= sBot and high <= sTop and close < sBot)

r1 = retestCondition(rBreak, low <= rBot and close >= rTop)
r2 = retestCondition(rBreak, low <= rBot and close <= rTop and close >= rBot)
r3 = retestCondition(rBreak, low <= rTop and low >= rBot)
r4 = retestCondition(rBreak, low <= rTop and low >= rBot and close > rTop)

retestEvent(c1, c2, c3, c4, y1, y2, txt_col,lb_col, style, pType) =>
if input_retest and showSupRes
var bool retOccurred = na
retActive = c1 or c2 or c3 or c4
retEvent = retActive and not retActive[1]
retValue = ta.valuewhen(retEvent, y1, 0)

if pType == 'ph' ? y2 < ta.valuewhen(retEvent, y2, 0) : y2 > ta.valuewhen(retEvent, y2, 0)
retEvent := retActive

retValue := ta.valuewhen(retEvent, y1, 0)

retSince = ta.barssince(retEvent)
var retLabel = array.new<label>()

if retEvent
retOccurred := na
array.push(retLabel, label.new(bar_index - retSince, y2[retSince], text = input_labelType == '简洁' ? '潜回' : '潜在回踩', color = lb_col, style = style, textcolor = input_override ? input_textColor : txt_col, size = input_labelSize))

if array.size(retLabel) == 2
label.delete(array.first(retLabel))
array.shift(retLabel)

retConditions = pType == 'ph' ? repaint(close >= retValue, high >= retValue, close >= retValue and barstate.isconfirmed) : repaint(close <= retValue, low <= retValue, close <= retValue and barstate.isconfirmed)
retValid = ta.barssince(retEvent) > 0 and ta.barssince(retEvent) <= input_retValid and retConditions and not retOccurred and (not showADXFilter or adxStrong) and (not showRSI or (pType == 'ph' ? rsiSupportsBuy : rsiSupportssell))

if retValid
label.new(bar_index - retSince, y2[retSince], text = input_labelType == '简洁' ? '回' : '回踩', color = lb_col, style = style, textcolor = input_override ? input_textColor : txt_col, size = input_labelSize)
retOccurred := true

if retValid or ta.barssince(retEvent) > input_retValid
label.delete(array.first(retLabel))

if pType == 'ph' and ta.change(rs_ph) and retOccurred
box.set_right(rBox[1], bar_index - retSince)
retOccurred := na

if pType == 'pl' and ta.change(rs_pl) and retOccurred
box.set_right(sBox[1], bar_index - retSince)
retOccurred := na
[retValid, retEvent, retValue]
else
[na, na, na]

[rRetValid, rRetEvent] = retestEvent(r1, r2, r3, r4, high, low, lg_retest_lb_co1,lg_retest_lb_co2, label.style_label_upper_left, 'ph')
[sRetValid, sRetEvent] = retestEvent(s1, s2, s3, s4, low, high, st_retest_lb_co1,st_retest_lb_co2, label.style_label_lower_left, 'pl')
//-----------------------------------------------------------------------------
// 警报
//-----------------------------------------------------------------------------
// 买卖信号警报条件
buySignal = showTrendLines and trendLineBuySignal
sellSignal = showTrendLines and trendLineSellSignal

// 添加买卖信号的警报条件
alertcondition(buySignal, title='买入信号', message='范围过滤器买入信号:上轨突破')
alertcondition(sellSignal, title='卖出信号', message='范围过滤器卖出信号:下轨突破')
alertcondition((showSupRes and ta.change(rs_pl)), '新支撑位')
alertcondition((showSupRes and ta.change(rs_ph)), '新阻力位')
alertcondition((showSupRes and ta.barssince(na(sBreak)) == 1), '支撑位突破')
alertcondition((showSupRes and ta.barssince(na(rBreak)) == 1), '阻力位突破')
alertcondition((showSupRes and sRetValid), '支撑位回踩')
alertcondition((showSupRes and sRetEvent), '潜在支撑回踩')
alertcondition((showSupRes and rRetValid), '阻力位回踩')
alertcondition((showSupRes and rRetEvent), '潜在阻力回踩')

AllAlerts(condition, message) =>
if condition and showSupRes
alert(message)

AllAlerts(ta.change(rs_pl), '新支撑位')
AllAlerts(ta.change(rs_ph), '新阻力位')
AllAlerts(ta.barssince(na(sBreak)) == 1, '支撑位突破')
AllAlerts(ta.barssince(na(rBreak)) == 1, '阻力位突破')
AllAlerts(sRetValid, '支撑位回踩')
AllAlerts(sRetEvent, '潜在支撑回踩')
AllAlerts(rRetValid, '阻力位回踩')
AllAlerts(rRetEvent, '潜在阻力回踩')

AllAlerts(buySignal, '买入信号:上轨突破')
AllAlerts(sellSignal, '卖出信号:下轨突破')

// === 多周期移动平均线 部分 ===
// === 公共函数 ===
strRoundValue(num) =>
strv = ''
if num >= 100000
strv := str.tostring(num/1000, '#千')
else if (num < 100000) and (num >= 100)
strv := str.tostring(num, '#')
else if (num < 100) and (num >= 1)
strv := str.tostring(num, '#.##')
else if (num < 1) and (num >= 0.01)
strv := str.tostring(num, '#.####')
else if (num < 0.01) and (num >= 0.0001)
strv := str.tostring(num, '#.######')
else if (num < 0.0001) and (num >= 0.000001)
strv := str.tostring(num, '#.########')
(strv)

defaultFunction(func, src, len, alma_offst, alma_sigma) =>
has_len = false
ma = ta.swma(close)
if func == '自适应移动平均'
ma := ta.alma(src, len, alma_offst, alma_sigma)
has_len := true
else if func == '指数移动平均'
ma := ta.ema(src, len)
has_len := true
else if func == '修正移动平均'
ma := ta.rma(src, len)
has_len := true
else if func == '简单移动平均'
ma := ta.sma(src, len)
has_len := true
else if func == '对称加权移动平均'
ma := ta.swma(src)
has_len := false
else if func == '成交量加权平均价'
ma := ta.vwap(src)
has_len := false
else if func == '成交量加权移动平均'
ma := ta.vwma(src, len)
has_len := true
else if func == '加权移动平均'
ma := ta.wma(src, len)
has_len := true
[ma, has_len]

def_fn = input.string(title='默认移动平均线', defval='指数移动平均', options=['自适应移动平均', '指数移动平均', '修正移动平均', '简单移动平均', '对称加权移动平均', '成交量加权平均价', '成交量加权移动平均', '加权移动平均'], group="6. PMA 设置")
ma1_on = input.bool(inline='均线1', title='启用移动平均线1', defval=false, group="6. PMA 设置")
ma2_on = input.bool(inline='均线2', title='启用移动平均线2', defval=true, group="6. PMA 设置")
ma3_on = input.bool(inline='均线3', title='启用移动平均线3', defval=true, group="6. PMA 设置")
ma4_on = input.bool(inline='均线4', title='启用移动平均线4', defval=true, group="6. PMA 设置")
ma5_on = input.bool(inline='均线5', title='启用移动平均线5', defval=true, group="6. PMA 设置")
ma6_on = input.bool(inline='均线6', title='启用移动平均线6', defval=true, group="6. PMA 设置")
ma7_on = input.bool(inline='均线7', title='启用移动平均线7', defval=true, group="6. PMA 设置")
ma1_fn = input.string(inline='均线1', title='', defval='默认', options=['默认', '自适应移动平均', '指数移动平均', '修正移动平均', '简单移动平均', '对称加权移动平均', '成交量加权平均价', '成交量加权移动平均', '加权移动平均'], group="6. PMA 设置")
ma2_fn = input.string(inline='均线2', title='', defval='默认', options=['默认', '自适应移动平均', '指数移动平均', '修正移动平均', '简单移动平均', '对称加权移动平均', '成交量加权平均价', '成交量加权移动平均', '加权移动平均'], group="6. PMA 设置")
ma3_fn = input.string(inline='均线3', title='', defval='默认', options=['默认', '自适应移动平均', '指数移动平均', '修正移动平均', '简单移动平均', '对称加权移动平均', '成交量加权平均价', '成交量加权移动平均', '加权移动平均'], group="6. PMA 设置")
ma4_fn = input.string(inline='均线4', title='', defval='默认', options=['默认', '自适应移动平均', '指数移动平均', '修正移动平均', '简单移动平均', '对称加权移动平均', '成交量加权平均价', '成交量加权移动平均', '加权移动平均'], group="6. PMA 设置")
ma5_fn = input.string(inline='均线5', title='', defval='默认', options=['默认', '自适应移动平均', '指数移动平均', '修正移动平均', '简单移动平均', '对称加权移动平均', '成交量加权平均价', '成交量加权移动平均', '加权移动平均'], group="6. PMA 设置")
ma6_fn = input.string(inline='均线6', title='', defval='默认', options=['默认', '自适应移动平均', '指数移动平均', '修正移动平均', '简单移动平均', '对称加权移动平均', '成交量加权平均价', '成交量加权移动平均', '加权移动平均'], group="6. PMA 设置")
ma7_fn = input.string(inline='均线7', title='', defval='默认', options=['默认', '自适应移动平均', '指数移动平均', '修正移动平均', '简单移动平均', '对称加权移动平均', '成交量加权平均价', '成交量加权移动平均', '加权移动平均'], group="6. PMA 设置")
ma1_len = input.int(inline='均线1', title='', defval=12, minval=1, group="6. PMA 设置")
ma2_len = input.int(inline='均线2', title='', defval=144, minval=1, group="6. PMA 设置")
ma3_len = input.int(inline='均线3', title='', defval=169, minval=1, group="6. PMA 设置")
ma4_len = input.int(inline='均线4', title='', defval=288, minval=1, group="6. PMA 设置")
ma5_len = input.int(inline='均线5', title='', defval=338, minval=1, group="6. PMA 设置")
ma6_len = input.int(inline='均线6', title='', defval=576, minval=1, group="6. PMA 设置")
ma7_len = input.int(inline='均线7', title='', defval=676, minval=1, group="6. PMA 设置")

alma1_offst = input.float(group='均线1其他设置', inline='均线11', title='自适应偏移', defval=0.85, minval=-1, maxval=1, step=0.01)
alma1_sigma = input.float(group='均线1其他设置', inline='均线11', title=', 西格玛', defval=6, minval=0, maxval=100, step=0.01)
ma1_src = input.source(group='均线1其他设置', inline='均线12', title='数据源', defval=close)
ma1_plt_offst = input.int(group='均线1其他设置', inline='均线12', title=', 绘图偏移', defval=0, minval=-500, maxval=500)
alma2_offst = input.float(group='均线2其他设置', inline='均线21', title='自适应偏移', defval=0.85, minval=-1, maxval=1, step=0.01)
alma2_sigma = input.float(group='均线2其他设置', inline='均线21', title='西格玛', defval=6, minval=0, maxval=100, step=0.01)
ma2_src = input.source(group='均线2其他设置', inline='均线22', title='数据源', defval=close)
ma2_plt_offst = input.int(group='均线2其他设置', inline='均线22', title='绘图偏移', defval=0, minval=-500, maxval=500)
alma3_offst = input.float(group='均线3其他设置', inline='均线31', title='自适应偏移', defval=0.85, minval=-1, maxval=1, step=0.01)
alma3_sigma = input.float(group='均线3其他设置', inline='均线31', title='西格玛', defval=6, minval=0, maxval=100, step=0.01)
ma3_src = input.source(group='均线3其他设置', inline='均线32', title='数据源', defval=close)
ma3_plt_offst = input.int(group='均线3其他设置', inline='均线32', title='绘图偏移', defval=0, minval=-500, maxval=500)
alma4_offst = input.float(group='均线4其他设置', inline='均线41', title='自适应偏移', defval=0.85, minval=-1, maxval=1, step=0.01)
alma4_sigma = input.float(group='均线4其他设置', inline='均线41', title='西格玛', defval=6, minval=0, maxval=100, step=0.01)
ma4_src = input.source(group='均线4其他设置', inline='均线42', title='数据源', defval=close)
ma4_plt_offst = input.int(group='均线4其他设置', inline='均线42', title='绘图偏移', defval=0, minval=-500, maxval=500)
alma5_offst = input.float(group='均线5其他设置', inline='均线51', title='自适应偏移', defval=0.85, minval=-1, maxval=1, step=0.01)
alma5_sigma = input.float(group='均线5其他设置', inline='均线51', title='西格玛', defval=6, minval=0, maxval=100, step=0.01)
ma5_src = input.source(group='均线5其他设置', inline='均线52', title='数据源', defval=close)
ma5_plt_offst = input.int(group='均线5其他设置', inline='均线52', title='绘图偏移', defval=0, minval=-500, maxval=500)
alma6_offst = input.float(group='均线6其他设置', inline='均线61', title='自适应偏移', defval=0.85, minval=-1, maxval=1, step=0.01)
alma6_sigma = input.float(group='均线6其他设置', inline='均线61', title='西格玛', defval=6, minval=0, maxval=100, step=0.01)
ma6_src = input.source(group='均线6其他设置', inline='均线62', title='数据源', defval=close)
ma6_plt_offst = input.int(group='均线6其他设置', inline='均线62', title='绘图偏移', defval=0, minval=-500, maxval=500)
alma7_offst = input.float(group='均线7其他设置', inline='均线71', title='自适应偏移', defval=0.85, minval=-1, maxval=1, step=0.01)
alma7_sigma = input.float(group='均线7其他设置', inline='均线71', title='西格玛', defval=6, minval=0, maxval=100, step=0.01)
ma7_src = input.source(group='均线7其他设置', inline='均线72', title='数据源', defval=close)
ma7_plt_offst = input.int(group='均线7其他设置', inline='均线72', title='绘图偏移', defval=0, minval=-500, maxval=500)

fill_12_on = input.bool(title='启用均线1-2填充', defval=false, group="6. PMA 设置")
fill_23_on = input.bool(title='启用均线2-3填充', defval=true, group="6. PMA 设置")
fill_34_on = input.bool(title='启用均线3-4填充', defval=false, group="6. PMA 设置")
fill_45_on = input.bool(title='启用均线4-5填充', defval=true, group="6. PMA 设置")
fill_56_on = input.bool(title='启用均线5-6填充', defval=false, group="6. PMA 设置")
fill_67_on = input.bool(title='启用均线6-7填充', defval=true, group="6. PMA 设置")

// === 计算移动平均线 ===
[ma1, ma1_has_len] = defaultFunction(def_fn, ma1_src, ma1_len, alma1_offst, alma1_sigma)
[ma2, ma2_has_len] = defaultFunction(def_fn, ma2_src, ma2_len, alma2_offst, alma2_sigma)
[ma3, ma3_has_len] = defaultFunction(def_fn, ma3_src, ma3_len, alma3_offst, alma3_sigma)
[ma4, ma4_has_len] = defaultFunction(def_fn, ma4_src, ma4_len, alma4_offst, alma4_sigma)
[ma5, ma5_has_len] = defaultFunction(def_fn, ma5_src, ma5_len, alma5_offst, alma5_sigma)
[ma6, ma6_has_len] = defaultFunction(def_fn, ma6_src, ma6_len, alma6_offst, alma6_sigma)
[ma7, ma7_has_len] = defaultFunction(def_fn, ma7_src, ma7_len, alma7_offst, alma7_sigma)
// === 均线类型切换 ===
if ma1_fn != '默认'
if ma1_fn == '自适应移动平均'
ma1 := ta.alma(ma1_src, ma1_len, alma1_offst, alma1_sigma)
ma1_has_len := true
else if ma1_fn == '指数移动平均'
ma1 := ta.ema(ma1_src, ma1_len)
ma1_has_len := true
else if ma1_fn == '修正移动平均'
ma1 := ta.rma(ma1_src, ma1_len)
ma1_has_len := true
else if ma1_fn == '简单移动平均'
ma1 := ta.sma(ma1_src, ma1_len)
ma1_has_len := true
else if ma1_fn == '对称加权移动平均'
ma1 := ta.swma(ma1_src)
ma1_has_len := false
else if ma1_fn == '成交量加权平均价'
ma1 := ta.vwap(ma1_src)
ma1_has_len := false
else if ma1_fn == '成交量加权移动平均'
ma1 := ta.vwma(ma1_src, ma1_len)
ma1_has_len := true
else if ma1_fn == '加权移动平均'
ma1 := ta.wma(ma1_src, ma1_len)
ma1_has_len := true

if ma2_fn != '默认'
if ma2_fn == '自适应移动平均'
ma2 := ta.alma(ma2_src, ma2_len, alma2_offst, alma2_sigma)
ma2_has_len := true
else if ma2_fn == '指数移动平均'
ma2 := ta.ema(ma2_src, ma2_len)
ma2_has_len := true
else if ma2_fn == '修正移动平均'
ma2 := ta.rma(ma2_src, ma2_len)
ma2_has_len := true
else if ma2_fn == '简单移动平均'
ma2 := ta.sma(ma2_src, ma2_len)
ma2_has_len := true
else if ma2_fn == '对称加权移动平均'
ma2 := ta.swma(ma2_src)
ma2_has_len := false
else if ma2_fn == '成交量加权平均价'
ma2 := ta.vwap(ma2_src)
ma2_has_len := false
else if ma2_fn == '成交量加权移动平均'
ma2 := ta.vwma(ma2_src, ma2_len)
ma2_has_len := true
else if ma2_fn == '加权移动平均'
ma2 := ta.wma(ma2_src, ma2_len)
ma2_has_len := true

if ma3_fn != '默认'
if ma3_fn == '自适应移动平均'
ma3 := ta.alma(ma3_src, ma3_len, alma3_offst, alma3_sigma)
ma3_has_len := true
else if ma3_fn == '指数移动平均'
ma3 := ta.ema(ma3_src, ma3_len)
ma3_has_len := true
else if ma3_fn == '修正移动平均'
ma3 := ta.rma(ma3_src, ma3_len)
ma3_has_len := true
else if ma3_fn == '简单移动平均'
ma3 := ta.sma(ma3_src, ma3_len)
ma3_has_len := true
else if ma3_fn == '对称加权移动平均'
ma3 := ta.swma(ma3_src)
ma3_has_len := false
else if ma3_fn == '成交量加权平均价'
ma3 := ta.vwap(ma3_src)
ma3_has_len := false
else if ma3_fn == '成交量加权移动平均'
ma3 := ta.vwma(ma3_src, ma3_len)
ma3_has_len := true
else if ma3_fn == '加权移动平均'
ma3 := ta.wma(ma3_src, ma3_len)
ma3_has_len := true

if ma4_fn != '默认'
if ma4_fn == '自适应移动平均'
ma4 := ta.alma(ma4_src, ma4_len, alma4_offst, alma4_sigma)
ma4_has_len := true
else if ma4_fn == '指数移动平均'
ma4 := ta.ema(ma4_src, ma4_len)
ma4_has_len := true
else if ma4_fn == '修正移动平均'
ma4 := ta.rma(ma4_src, ma4_len)
ma4_has_len := true
else if ma4_fn == '简单移动平均'
ma4 := ta.sma(ma4_src, ma4_len)
ma4_has_len := true
else if ma4_fn == '对称加权移动平均'
ma4 := ta.swma(ma4_src)
ma4_has_len := false
else if ma4_fn == '成交量加权平均价'
ma4 := ta.vwap(ma4_src)
ma4_has_len := false
else if ma4_fn == '成交量加权移动平均'
ma4 := ta.vwma(ma4_src, ma4_len)
ma4_has_len := true
else if ma4_fn == '加权移动平均'
ma4 := ta.wma(ma4_src, ma4_len)
ma4_has_len := true

if ma5_fn != '默认'
if ma5_fn == '自适应移动平均'
ma5 := ta.alma(ma5_src, ma5_len, alma5_offst, alma5_sigma)
ma5_has_len := true
else if ma5_fn == '指数移动平均'
ma5 := ta.ema(ma5_src, ma5_len)
ma5_has_len := true
else if ma5_fn == '修正移动平均'
ma5 := ta.rma(ma5_src, ma5_len)
ma5_has_len := true
else if ma5_fn == '简单移动平均'
ma5 := ta.sma(ma5_src, ma5_len)
ma5_has_len := true
else if ma5_fn == '对称加权移动平均'
ma5 := ta.swma(ma5_src)
ma5_has_len := false
else if ma5_fn == '成交量加权平均价'
ma5 := ta.vwap(ma5_src)
ma5_has_len := false
else if ma5_fn == '成交量加权移动平均'
ma5 := ta.vwma(ma5_src, ma5_len)
ma5_has_len := true
else if ma5_fn == '加权移动平均'
ma5 := ta.wma(ma5_src, ma5_len)
ma5_has_len := true

if ma6_fn != '默认'
if ma6_fn == '自适应移动平均'
ma6 := ta.alma(ma6_src, ma6_len, alma6_offst, alma6_sigma)
ma6_has_len := true
else if ma6_fn == '指数移动平均'
ma6 := ta.ema(ma6_src, ma6_len)
ma6_has_len := true
else if ma6_fn == '修正移动平均'
ma6 := ta.rma(ma6_src, ma6_len)
ma6_has_len := true
else if ma6_fn == '简单移动平均'
ma6 := ta.sma(ma6_src, ma6_len)
ma6_has_len := true
else if ma6_fn == '对称加权移动平均'
ma6 := ta.swma(ma6_src)
ma6_has_len := false
else if ma6_fn == '成交量加权平均价'
ma6 := ta.vwap(ma6_src)
ma6_has_len := false
else if ma6_fn == '成交量加权移动平均'
ma6 := ta.vwma(ma6_src, ma6_len)
ma6_has_len := true
else if ma6_fn == '加权移动平均'
ma6 := ta.wma(ma6_src, ma6_len)
ma6_has_len := true

if ma7_fn != '默认'
if ma7_fn == '自适应移动平均'
ma7 := ta.alma(ma7_src, ma7_len, alma7_offst, alma7_sigma)
ma7_has_len := true
else if ma7_fn == '指数移动平均'
ma7 := ta.ema(ma7_src, ma7_len)
ma7_has_len := true
else if ma7_fn == '修正移动平均'
ma7 := ta.rma(ma7_src, ma7_len)
ma7_has_len := true
else if ma7_fn == '简单移动平均'
ma7 := ta.sma(ma7_src, ma7_len)
ma7_has_len := true
else if ma7_fn == '对称加权移动平均'
ma7 := ta.swma(ma7_src)
ma7_has_len := false
else if ma7_fn == '成交量加权平均价'
ma7 := ta.vwap(ma7_src)
ma7_has_len := false
else if ma7_fn == '成交量加权移动平均'
ma7 := ta.vwma(ma7_src, ma7_len)
ma7_has_len := true
else if ma7_fn == '加权移动平均'
ma7 := ta.wma(ma7_src, ma7_len)
ma7_has_len := true

// === 均线颜色 ===
ma1_clr = color.new(color.fuchsia, 0)
ma2_clr = color.new(color.aqua, 0)
ma3_clr = color.new(color.yellow, 0)
ma4_clr = color.new(color.blue, 0)
ma5_clr = color.new(color.orange, 0)
ma6_clr = color.new(color.green, 0)
ma7_clr = color.new(color.red, 0)

// === 均线全局绘图 ===
p1 = plot(series=showPMA and ma1_on ? ma1 : na, title="均线1", color=ma1_clr, trackprice=false, offset=ma1_plt_offst, linewidth=2)
p2 = plot(series=showPMA and ma2_on ? ma2 : na, title="均线2", color=ma2_clr, trackprice=false, offset=ma2_plt_offst, linewidth=2)
p3 = plot(series=showPMA and ma3_on ? ma3 : na, title="均线3", color=ma3_clr, trackprice=false, offset=ma3_plt_offst, linewidth=2)
p4 = plot(series=showPMA and ma4_on ? ma4 : na, title="均线4", color=ma4_clr, trackprice=false, offset=ma4_plt_offst, linewidth=2)
p5 = plot(series=showPMA and ma5_on ? ma5 : na, title="均线5", color=ma5_clr, trackprice=false, offset=ma5_plt_offst, linewidth=2)
p6 = plot(series=showPMA and ma6_on ? ma6 : na, title="均线6", color=ma6_clr, trackprice=false, offset=ma6_plt_offst, linewidth=2)
p7 = plot(series=showPMA and ma7_on ? ma7 : na, title="均线7", color=ma7_clr, trackprice=false, offset=ma7_plt_offst, linewidth=2)

// === 多周期移动平均线 填充渲染 ===
fill(p1, p2, color=showPMA and ma1_on and ma2_on and fill_12_on ? color.new(color.purple, 70) : na, title="均线1-2填充")
fill(p2, p3, color=showPMA and ma2_on and ma3_on and fill_23_on ? color.new(color.blue, 70) : na, title="均线2-3填充")
fill(p3, p4, color=showPMA and ma3_on and ma4_on and fill_34_on ? color.new(color.teal, 70) : na, title="均线3-4填充")
fill(p4, p5, color=showPMA and ma4_on and ma5_on and fill_45_on ? color.new(color.green, 70) : na, title="均线4-5填充")
fill(p5, p6, color=showPMA and ma5_on and ma6_on and fill_56_on ? color.new(color.yellow, 70) : na, title="均线5-6填充")
fill(p6, p7, color=showPMA and ma6_on and ma7_on and fill_67_on ? color.new(color.orange, 70) : na, title="均线6-7填充")

// === 交易信息表格 部分 ===

// 表格参数设置 - 修改默认大小为中等
tablePos = input.string("右上角", title="表格位置", options=["右上角", "右下角", "左上角", "左下角"], group="7. 交易信息表格 设置")
tableSize = input.string("中等", title="表格大小", options=["小", "中等", "大"], group="7. 交易信息表格 设置")
showTargets = input.bool(true, title="显示止盈目标", group="7. 交易信息表格 设置")
showRatio = input.bool(true, title="显示盈亏比", group="7. 交易信息表格 设置")

// 辅助函数
getTablePosition() =>
switch tablePos
"右上角" => position.top_right
"右下角" => position.bottom_right
"左上角" => position.top_left
"左下角" => position.bottom_left

getTableSize() =>
switch tableSize
"小" => size.small
"中等" => size.normal
"大" => size.large

formatPrice(price) =>
if na(price)
"N/A"
else
str.tostring(price, "#.####")

calcStopLossPercentage(entryPrice, stopLoss, entryType) =>
if na(entryPrice) or na(stopLoss) or na(entryType)
""
else
pct = 0.0
if entryType == "多单"
pct := (stopLoss - entryPrice) / entryPrice * 100
else if entryType == "空单"
pct := (entryPrice - stopLoss) / entryPrice * 100
" (" + str.tostring(pct, "#.##") + "%)"

calcTakeProfitPercentage(entryPrice, takeProfit, entryType) =>
if na(entryPrice) or na(takeProfit) or na(entryType)
""
else
pct = 0.0
if entryType == "多单"
pct := (takeProfit - entryPrice) / entryPrice * 100
else if entryType == "空单"
pct := (entryPrice - takeProfit) / entryPrice * 100
" (+" + str.tostring(pct, "#.##") + "%)"

calcUnrealizedPnL(entryPrice, currentPrice, entryType) =>
if na(entryPrice) or na(currentPrice) or na(entryType)
""
else
priceDiff = currentPrice - entryPrice
pct = (currentPrice - entryPrice) / entryPrice * 100

if entryType == "多单"
if pct > 0
" (" + formatPrice(priceDiff) + ", +" + str.tostring(pct, "#.##") + "%)"
else
" (" + formatPrice(priceDiff) + ", " + str.tostring(pct, "#.##") + "%)"
else if entryType == "空单"
// 对于空单,价差符号相反
if pct < 0
" (" + formatPrice(-priceDiff) + ", +" + str.tostring(-pct, "#.##") + "%)"
else
" (" + formatPrice(-priceDiff) + ", " + str.tostring(-pct, "#.##") + "%)"
else
""

// RSI状态颜色函数
getRSIStatusColor() =>
switch rsiStatus
"动量回升" => [color.new(#00ff41, 0), color.new(#002600, 0)] // 绿色
"动量回落" => [color.new(#ff0066, 0), color.new(#260013, 0)] // 红色
"动量中性" => [color.new(#ffff00, 0), color.new(#1a1a00, 0)] // 黄色
=> [color.new(#666666, 0), color.new(#1a1a1a, 0)] // 默认灰色

// 多时间框架趋势颜色函数
getTrendColor(trendDirection) =>
switch trendDirection
"多头倾向" => [color.new(#00ff41, 0), color.new(#002600, 0)] // 绿色
"空头倾向" => [color.new(#ff0066, 0), color.new(#260013, 0)] // 红色
"震荡" => [color.new(#ffff00, 0), color.new(#1a1a00, 0)] // 黄色
=> [color.new(#666666, 0), color.new(#1a1a1a, 0)] // 默认灰色
// === 蓝紫科幻风格表格 ===
// 创建蓝紫色主题的表格
var infoTable = table.new(getTablePosition(), columns=2, rows=26,
bgcolor=color.new(#0f0a1a, 5),
border_width=3,
border_color=color.new(#6633ff, 40),
frame_width=2,
frame_color=color.new(#9966ff, 30))

if showTable and barstate.islast
// 确定止盈止损位
var float stopLoss = na
var float takeProfit1 = na
var float takeProfit2 = na

if not na(entryType)
if entryType == "多单"
stopLoss := na(sBot) ? entryPrice * 0.98 : sBot
takeProfit1 := na(rTop) ? entryPrice * 1.02 : rTop
takeProfit2 := entryPrice * 1.05
else if entryType == "空单"
stopLoss := na(rTop) ? entryPrice * 1.02 : rTop
takeProfit1 := na(sBot) ? entryPrice * 0.98 : sBot
takeProfit2 := entryPrice * 0.95

// 计算盈亏比
riskRewardRatio = na(entryPrice) or na(stopLoss) or na(takeProfit1) ? na :
math.abs(takeProfit1 - entryPrice) / math.abs(entryPrice - stopLoss)
riskRewardStr = na(riskRewardRatio) ? "N/A" : "1:" + str.tostring(riskRewardRatio, "#.##")

rowIndex = 0

// === 作者联系信息行 - 最顶部,大字体 ===
table.cell(infoTable, 0, rowIndex, "合作联系作者", text_color=color.new(#ffcc99, 0),
text_size=size.normal, bgcolor=color.new(#1a1a0d, 0))
table.cell(infoTable, 1, rowIndex, "qq2390107445", text_color=color.new(#66ff99, 0),
text_size=size.normal, bgcolor=color.new(#0d2619, 0))
rowIndex += 1

// === 表格标题行 - 蓝紫主题 ===
table.cell(infoTable, 0, rowIndex, "⚡ P6●智能资金概念交易系统", text_color=color.new(#ccccff, 0),
text_size=getTableSize(), bgcolor=color.new(#1a0d33, 0))
table.cell(infoTable, 1, rowIndex, "『" + syminfo.ticker + "』", text_color=color.new(#9966ff, 0),
text_size=size.normal, bgcolor=color.new(#1a0d33, 0))
rowIndex += 1

// === 当前价格与浮盈浮亏行 - 蓝紫主题 ===
unrealizedPnL = calcUnrealizedPnL(entryPrice, close, entryType)

// 浮盈浮亏颜色逻辑
pnlColor = color.new(#ccccff, 0)
pnlBgColor = color.new(#0d0d1a, 0)
if not na(entryPrice)
if entryType == "多单"
if close > entryPrice
pnlColor := color.new(#66ff99, 0)
pnlBgColor := color.new(#0d2619, 0)
else
pnlColor := color.new(#ff6699, 0)
pnlBgColor := color.new(#260d19, 0)
else if entryType == "空单"
if close < entryPrice
pnlColor := color.new(#66ff99, 0)
pnlBgColor := color.new(#0d2619, 0)
else
pnlColor := color.new(#ff6699, 0)
pnlBgColor := color.new(#260d19, 0)

table.cell(infoTable, 0, rowIndex, "当前价格", text_color=color.new(#b3b3ff, 0),
text_size=getTableSize(), bgcolor=color.new(#0d0d1a, 0))
table.cell(infoTable, 1, rowIndex, formatPrice(close) + unrealizedPnL,
text_color=pnlColor,
text_size=getTableSize(), bgcolor=pnlBgColor)
rowIndex += 1

// === 趋势状态与进场价格行 - 蓝紫主题 ===
trendStatus = na(entryType) ? "待机中" : entryType == "多单" ? "多头执行" : "空头执行"
trendIcon = entryType == "多单" ? " ▲" : entryType == "空单" ? " ▼" : " ●"
trendBgColor = entryType == "多单" ? color.new(#1a4d1a, 0) :
entryType == "空单" ? color.new(#4d1a1a, 0) :
color.new(#1a1a4d, 0)
trendTextColor = entryType == "多单" ? color.new(#66ff99, 0) :
entryType == "空单" ? color.new(#ff6699, 0) :
color.new(#9999ff, 0)

table.cell(infoTable, 0, rowIndex, "交易状态", text_color=color.new(#b3b3ff, 0),
text_size=getTableSize(), bgcolor=color.new(#0d0d1a, 0))
table.cell(infoTable, 1, rowIndex, trendStatus + trendIcon, text_color=trendTextColor,
text_size=getTableSize(), bgcolor=trendBgColor)
rowIndex += 1

// === 进场价格行 - 蓝紫主题 ===
table.cell(infoTable, 0, rowIndex, "进场价位", text_color=color.new(#b3b3ff, 0),
text_size=getTableSize(), bgcolor=color.new(#0d0d1a, 0))
table.cell(infoTable, 1, rowIndex, formatPrice(entryPrice),
text_color=color.new(#ffcc99, 0),
text_size=getTableSize(), bgcolor=color.new(#1a1a0d, 0))
rowIndex += 1

// === 多时间框架分析 - 独立行显示 ===
if showMTF
// 多时间框架标题行
table.cell(infoTable, 0, rowIndex, "━━ 多时间框架趋势 ━━", text_color=color.new(#ccccff, 0),
text_size=getTableSize(), bgcolor=color.new(#1a0d33, 0))
table.cell(infoTable, 1, rowIndex, "━━━━━━━━━━━━━━━━━━━━", text_color=color.new(#6633ff, 0),
text_size=getTableSize(), bgcolor=color.new(#1a0d33, 0))
rowIndex += 1

// 1分钟趋势
if mtfEnable1m
[trend1mTextColor, trend1mBgColor] = getTrendColor(trend1mDir)
trend1mIcon = trend1mDir == "多头倾向" ? " ▲" : trend1mDir == "空头倾向" ? " ▼" : " ●"

table.cell(infoTable, 0, rowIndex, "1分钟", text_color=color.new(#b3b3ff, 0),
text_size=getTableSize(), bgcolor=color.new(#0d0d1a, 0))
table.cell(infoTable, 1, rowIndex, trend1mDir + trend1mIcon, text_color=trend1mTextColor,
text_size=getTableSize(), bgcolor=trend1mBgColor)
rowIndex += 1

// 5分钟趋势
if mtfEnable5m
[trend5mTextColor, trend5mBgColor] = getTrendColor(trend5mDir)
trend5mIcon = trend5mDir == "多头倾向" ? " ▲" : trend5mDir == "空头倾向" ? " ▼" : " ●"

table.cell(infoTable, 0, rowIndex, "5分钟", text_color=color.new(#b3b3ff, 0),
text_size=getTableSize(), bgcolor=color.new(#0d0d1a, 0))
table.cell(infoTable, 1, rowIndex, trend5mDir + trend5mIcon, text_color=trend5mTextColor,
text_size=getTableSize(), bgcolor=trend5mBgColor)
rowIndex += 1

// 15分钟趋势
if mtfEnable15m
[trend15mTextColor, trend15mBgColor] = getTrendColor(trend15mDir)
trend15mIcon = trend15mDir == "多头倾向" ? " ▲" : trend15mDir == "空头倾向" ? " ▼" : " ●"

table.cell(infoTable, 0, rowIndex, "15分钟", text_color=color.new(#b3b3ff, 0),
text_size=getTableSize(), bgcolor=color.new(#0d0d1a, 0))
table.cell(infoTable, 1, rowIndex, trend15mDir + trend15mIcon, text_color=trend15mTextColor,
text_size=getTableSize(), bgcolor=trend15mBgColor)
rowIndex += 1

// 1小时趋势
if mtfEnable1h
[trend1hTextColor, trend1hBgColor] = getTrendColor(trend1hDir)
trend1hIcon = trend1hDir == "多头倾向" ? " ▲" : trend1hDir == "空头倾向" ? " ▼" : " ●"

table.cell(infoTable, 0, rowIndex, "1小时", text_color=color.new(#b3b3ff, 0),
text_size=getTableSize(), bgcolor=color.new(#0d0d1a, 0))
table.cell(infoTable, 1, rowIndex, trend1hDir + trend1hIcon, text_color=trend1hTextColor,
text_size=getTableSize(), bgcolor=trend1hBgColor)
rowIndex += 1

// 4小时趋势
if mtfEnable4h
[trend4hTextColor, trend4hBgColor] = getTrendColor(trend4hDir)
trend4hIcon = trend4hDir == "多头倾向" ? " ▲" : trend4hDir == "空头倾向" ? " ▼" : " ●"

table.cell(infoTable, 0, rowIndex, "4小时", text_color=color.new(#b3b3ff, 0),
text_size=getTableSize(), bgcolor=color.new(#0d0d1a, 0))
table.cell(infoTable, 1, rowIndex, trend4hDir + trend4hIcon, text_color=trend4hTextColor,
text_size=getTableSize(), bgcolor=trend4hBgColor)
rowIndex += 1

// === RSI 动量状态行 - 蓝紫主题 ===
rsiTextColor = color.new(#ccccff, 0)
rsiBgColor = color.new(#0d0d1a, 0)

if rsiStatus == "动量回升"
rsiTextColor := color.new(#66ff99, 0)
rsiBgColor := color.new(#0d2619, 0)
else if rsiStatus == "动量回落"
rsiTextColor := color.new(#ff6699, 0)
rsiBgColor := color.new(#260d19, 0)
else
rsiTextColor := color.new(#ffcc99, 0)
rsiBgColor := color.new(#1a1a0d, 0)

rsiIcon = rsiStatus == "动量回升" ? " ▲" : rsiStatus == "动量回落" ? " ▼" : " ●"
rsiDisplayText = rsiStatus + rsiIcon + " (" + str.tostring(rsiValue, "#.#") + ")"

table.cell(infoTable, 0, rowIndex, "RSI动量", text_color=color.new(#b3b3ff, 0),
text_size=getTableSize(), bgcolor=color.new(#0d0d1a, 0))
table.cell(infoTable, 1, rowIndex, rsiDisplayText, text_color=rsiTextColor,
text_size=getTableSize(), bgcolor=rsiBgColor)
rowIndex += 1

// === 风险管理分割线 ===
table.cell(infoTable, 0, rowIndex, "━━ 风险管理 ━━", text_color=color.new(#ccccff, 0),
text_size=getTableSize(), bgcolor=color.new(#1a0d33, 0))
table.cell(infoTable, 1, rowIndex, "━━━━━━━━━━━━━━━━━━━━", text_color=color.new(#6633ff, 0),
text_size=getTableSize(), bgcolor=color.new(#1a0d33, 0))
rowIndex += 1

// === 止损行 - 蓝紫主题 ===
slPct = calcStopLossPercentage(entryPrice, stopLoss, entryType)
table.cell(infoTable, 0, rowIndex, "止损价位", text_color=color.new(#b3b3ff, 0),
text_size=getTableSize(), bgcolor=color.new(#0d0d1a, 0))
table.cell(infoTable, 1, rowIndex, formatPrice(stopLoss) + slPct,
text_color=color.new(#ff6699, 0),
text_size=getTableSize(), bgcolor=color.new(#330d1a, 0))
rowIndex += 1

// 止盈目标行
if showTargets
// === 目标位1 - 蓝紫主题 ===
tp1Pct = calcTakeProfitPercentage(entryPrice, takeProfit1, entryType)
tp1Reached = na(takeProfit1) ? false :
(entryType == "多单" ? high >= takeProfit1 : low <= takeProfit1)
tp1Icon = tp1Reached ? " ✓" : ""
tp1Color = tp1Reached ? color.new(#66ff99, 0) : color.new(#99ccff, 0)
tp1BgColor = tp1Reached ? color.new(#0d2619, 0) : color.new(#0d1a26, 0)

table.cell(infoTable, 0, rowIndex, "止盈目标1", text_color=color.new(#b3b3ff, 0),
text_size=getTableSize(), bgcolor=color.new(#0d0d1a, 0))
table.cell(infoTable, 1, rowIndex, formatPrice(takeProfit1) + tp1Pct + tp1Icon,
text_color=tp1Color,
text_size=getTableSize(), bgcolor=tp1BgColor)
rowIndex += 1

// === 目标2 - 蓝紫主题 ===
tp2Pct = calcTakeProfitPercentage(entryPrice, takeProfit2, entryType)
tp2Reached = na(takeProfit2) ? false :
(entryType == "多单" ? high >= takeProfit2 : low <= takeProfit2)
tp2Icon = tp2Reached ? " ✓" : ""
tp2Color = tp2Reached ? color.new(#66ff99, 0) : color.new(#cc99ff, 0)
tp2BgColor = tp2Reached ? color.new(#0d2619, 0) : color.new(#1a0d26, 0)

table.cell(infoTable, 0, rowIndex, "止盈目标2", text_color=color.new(#b3b3ff, 0),
text_size=getTableSize(), bgcolor=color.new(#0d0d1a, 0))
table.cell(infoTable, 1, rowIndex, formatPrice(takeProfit2) + tp2Pct + tp2Icon,
text_color=tp2Color,
text_size=getTableSize(), bgcolor=tp2BgColor)
rowIndex += 1

// === 盈亏比行 - 蓝紫主题 ===
if showRatio
rrColor = color.new(#9999ff, 0)
rrBgColor = color.new(#0d0d1a, 0)

if not na(riskRewardRatio)
if riskRewardRatio >= 2
rrColor := color.new(#66ff99, 0)
rrBgColor := color.new(#0d2619, 0)
else if riskRewardRatio >= 1
rrColor := color.new(#ffcc99, 0)
rrBgColor := color.new(#1a1a0d, 0)
else
rrColor := color.new(#ff9966, 0)
rrBgColor := color.new(#1a1a0d, 0)

table.cell(infoTable, 0, rowIndex, "盈亏比例", text_color=color.new(#b3b3ff, 0),
text_size=getTableSize(), bgcolor=color.new(#0d0d1a, 0))
table.cell(infoTable, 1, rowIndex, riskRewardStr,
text_color=rrColor,
text_size=getTableSize(), bgcolor=rrBgColor)
rowIndex += 1

// === 免责声明行 - 蓝紫主题 ===
table.cell(infoTable, 0, rowIndex, "⚠ 风险提示", text_color=color.new(#9999ff, 0),
text_size=size.small, bgcolor=color.new(#0d0d1a, 0))
table.cell(infoTable, 1, rowIndex, "仅供参考,不构成投资建议,盈亏自负",
text_color=color.new(#9999ff, 0),
text_size=size.small, bgcolor=color.new(#1a1a4d, 0))

Pernyataan Penyangkalan

Informasi dan publikasi ini tidak dimaksudkan, dan bukan merupakan, saran atau rekomendasi keuangan, investasi, trading, atau jenis lainnya yang diberikan atau didukung oleh TradingView. Baca selengkapnya di Ketentuan Penggunaan.