PROTECTED SOURCE SCRIPT

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

38
//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))

Aviso legal

As informações e publicações não se destinam a ser, e não constituem, conselhos ou recomendações financeiras, de investimento, comerciais ou de outro tipo fornecidos ou endossados pela TradingView. Leia mais nos Termos de Uso.