Support Resistance Channels

Support Resistance Channels

see https://www.tradingview.com/script/Ej53t8Wv-Support-Resistance-Channels/

 

How this script works?
- it finds and keeps Pivot Points
- when it found a new Pivot Point it clears older S/R channels then;
- for each pivot point it searches all pivot points in its own channel with dynamic width
- while creating the S/R channel it calculates its strength
- then sorts all S/R channels by strength
- it shows the strongest S/R channels, before doing this it checks old location in the list and adjust them for better visibility
- if any S/R channel was broken on last move then it gives alert and put shape below/above the candle
- The colors of the S/R channels are adjusted automatically

 

这个脚本是如何工作的?

  • 它会查找并保存关键的转折点(Pivot Points)。
  • 当发现一个新的转折点时,会清除之前生成的支撑/阻力(S/R)通道,然后:
    • 针对每个转折点,搜索其动态宽度通道范围内的所有其他转折点。
    • 在创建支撑/阻力通道的同时,计算该通道的强度。
    • 将所有支撑/阻力通道按强度进行排序。
    • 显示最强的几个支撑/阻力通道。在显示前,会参考通道在列表中的历史位置,进行调整以提升视觉清晰度。
  • 如果最近的价格波动突破了某个支撑或阻力通道,脚本会发出警报,并在K线的下方或上方标记提示形状。
  • 支撑/阻力通道的颜色会根据价格与通道的相对位置自动调整。


You can set/change following settings:
Pivot Period
Source: High/Low or Close/Open can be used
Maximum Channel Width %: this is the maximum channel width rate, this is calculated using Highest/Lowest levels in last 300 bars
Number of S/R to show: this is the number of Strongest S/R to show
Loopback Period: While calculating S/R levels it checks Pivot Points in LoopBack Period
Show S/R on last # Bars: To see S/R levels only on last N bars
Start Date: the script starts calculating Pivot Point from this date, the reason I put this option is for visuality. Explained below
- You can set colors/transparency
- and You can enable/disable shapes for broken S/R levels

 

你可以设置或更改以下参数:

  • 转折点周期(Pivot Period):用于识别转折点的K线周期。
  • 数据源(Source):可选择使用最高价/最低价(High/Low)或收盘价/开盘价(Close/Open)作为计算依据。
  • 最大通道宽度百分比(Maximum Channel Width %):支撑/阻力通道允许的最大宽度比例,基于最近300根K线的最高和最低价计算得出。
  • 显示的S/R数量(Number of S/R to show):显示最强的支撑/阻力通道的数量。
  • 回溯周期(Loopback Period):在计算支撑/阻力位时,用于查找转折点的历史K线数量。
  • 仅在最近N根K线上显示S/R:可选择只在最近若干根K线上显示支撑/阻力通道。
  • 起始日期(Start Date):脚本从该日期开始计算转折点。此选项主要是为了视觉效果更清晰(下文有进一步说明)。
  • 颜色与透明度设置:可自定义支撑/阻力通道的颜色和透明度。
  • 启用/禁用突破标记:可开启或关闭当支撑/阻力被突破时显示的提示形状。

 

image

 

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © LonesomeTheBlue

//@version=6
indicator('My Support Resistance Channels', 'MySRchannel', overlay = true, max_bars_back = 501)
prd = input.int(defval = 10, title = 'Pivot Period', minval = 4, maxval = 30, group = 'Settings 🔨', tooltip = 'Used while calculating Pivot Points, checks left&right bars')
ppsrc = input.string(defval = 'High/Low', title = 'Source', options = ['High/Low', 'Close/Open'], group = 'Settings 🔨', tooltip = 'Source for Pivot Points')
ChannelW = input.int(defval = 5, title = 'Maximum Channel Width %', minval = 1, maxval = 8, group = 'Settings 🔨', tooltip = 'Calculated using Highest/Lowest levels in 300 bars')
minstrength = input.int(defval = 1, title = 'Minimum Strength', minval = 1, group = 'Settings 🔨', tooltip = 'Channel must contain at least 2 Pivot Points')
maxnumsr = input.int(defval = 6, title = 'Maximum Number of S/R', minval = 1, maxval = 10, group = 'Settings 🔨', tooltip = 'Maximum number of Support/Resistance Channels to Show') - 1
loopback = input.int(defval = 180, title = 'Loopback Period', minval = 100, maxval = 400, group = 'Settings 🔨', tooltip = 'While calculating S/R levels it checks Pivots in Loopback Period')
res_col = input.color(defval = color.new(color.red, 75), title = 'Resistance Color', group = 'Colors 🟡🟢🟣')
sup_col = input.color(defval = color.new(color.lime, 75), title = 'Support Color', group = 'Colors 🟡🟢🟣')
inch_col = input.color(defval = color.new(color.gray, 75), title = 'Color When Price in Channel', group = 'Colors 🟡🟢🟣')
showpp = input.bool(defval = false, title = 'Show Pivot Points', group = 'Extras ⏶⏷')
showsrbroken = input.bool(defval = false, title = 'Show Broken Support/Resistance', group = 'Extras ⏶⏷')
showthema1en = input.bool(defval = false, title = 'MA 1', inline = 'ma1')
showthema1len = input.int(defval = 50, title = '', inline = 'ma1')
showthema1type = input.string(defval = 'SMA', title = '', options = ['SMA', 'EMA'], inline = 'ma1')
showthema2en = input.bool(defval = false, title = 'MA 2', inline = 'ma2')
showthema2len = input.int(defval = 200, title = '', inline = 'ma2')
showthema2type = input.string(defval = 'SMA', title = '', options = ['SMA', 'EMA'], inline = 'ma2')

ma1 = showthema1en ? showthema1type == 'SMA' ? ta.sma(close, showthema1len) : ta.ema(close, showthema1len) : na
ma2 = showthema2en ? showthema2type == 'SMA' ? ta.sma(close, showthema2len) : ta.ema(close, showthema2len) : na

plot(ma1, color = not na(ma1) ? color.blue : na)
plot(ma2, color = not na(ma2) ? color.red : na)

// get Pivot High/low
float src1 = ppsrc == 'High/Low' ? high : math.max(close, open)
float src2 = ppsrc == 'High/Low' ? low : math.min(close, open)
float ph = ta.pivothigh(src1, prd, prd)
float pl = ta.pivotlow(src2, prd, prd)

// draw Pivot points
plotshape(bool(ph) and showpp, text = 'H', style = shape.labeldown, color = na, textcolor = color.new(color.red, 0), location = location.abovebar, offset = -prd)
plotshape(bool(pl) and showpp, text = 'L', style = shape.labelup, color = na, textcolor = color.new(color.lime, 0), location = location.belowbar, offset = -prd)

//calculate maximum S/R channel width
prdhighest = ta.highest(300)
prdlowest = ta.lowest(300)
cwidth = (prdhighest - prdlowest) * ChannelW / 100

// get/keep Pivot levels
var pivotvals = array.new_float(0)
var pivotlocs = array.new_float(0)
if bool(ph) or bool(pl)
    array.unshift(pivotvals, bool(ph) ? ph : pl)
    array.unshift(pivotlocs, bar_index)
    for x = array.size(pivotvals) - 1 to 0 by 1
        if bar_index - array.get(pivotlocs, x) > loopback // remove old pivot points
            array.pop(pivotvals)
            array.pop(pivotlocs)
            continue
        break

//find/create SR channel of a pivot point
get_sr_vals(ind) =>
    float lo = array.get(pivotvals, ind)
    float hi = lo
    int numpp = 0
    for y = 0 to array.size(pivotvals) - 1 by 1
        float cpp = array.get(pivotvals, y)
        float wdth = cpp <= hi ? hi - cpp : cpp - lo
        if wdth <= cwidth // fits the max channel width?
            if cpp <= hi
                lo := math.min(lo, cpp)
                lo
            else
                hi := math.max(hi, cpp)
                hi

            numpp := numpp + 20 // each pivot point added as 20
            numpp
    [hi, lo, numpp]

// keep old SR channels and calculate/sort new channels if we met new pivot point
var suportresistance = array.new_float(20, 0) // min/max levels
changeit(x, y) =>
    tmp = array.get(suportresistance, y * 2)
    array.set(suportresistance, y * 2, array.get(suportresistance, x * 2))
    array.set(suportresistance, x * 2, tmp)
    tmp := array.get(suportresistance, y * 2 + 1)
    array.set(suportresistance, y * 2 + 1, array.get(suportresistance, x * 2 + 1))
    array.set(suportresistance, x * 2 + 1, tmp)

if bool(ph) or bool(pl)
    supres = array.new_float(0) // number of pivot, strength, min/max levels
    stren = array.new_float(10, 0)
    // get levels and strengs
    for x = 0 to array.size(pivotvals) - 1 by 1
        [hi, lo, strength] = get_sr_vals(x)
        array.push(supres, strength)
        array.push(supres, hi)
        array.push(supres, lo)

    // add each HL to strengh
    for x = 0 to array.size(pivotvals) - 1 by 1
        h = array.get(supres, x * 3 + 1)
        l = array.get(supres, x * 3 + 2)
        s = 0
        for y = 0 to loopback by 1
            if high[y] <= h and high[y] >= l or low[y] <= h and low[y] >= l
                s := s + 1
                s
        array.set(supres, x * 3, array.get(supres, x * 3) + s)

    //reset SR levels
    array.fill(suportresistance, 0)
    // get strongest SRs
    src = 0
    for x = 0 to array.size(pivotvals) - 1 by 1
        stv = -1. // value
        stl = -1 // location
        for y = 0 to array.size(pivotvals) - 1 by 1
            if array.get(supres, y * 3) > stv and array.get(supres, y * 3) >= minstrength * 20
                stv := array.get(supres, y * 3)
                stl := y
                stl
        if stl >= 0
            //get sr level
            hh = array.get(supres, stl * 3 + 1)
            ll = array.get(supres, stl * 3 + 2)
            array.set(suportresistance, src * 2, hh)
            array.set(suportresistance, src * 2 + 1, ll)
            array.set(stren, src, array.get(supres, stl * 3))

            // make included pivot points' strength zero 
            for y = 0 to array.size(pivotvals) - 1 by 1
                if array.get(supres, y * 3 + 1) <= hh and array.get(supres, y * 3 + 1) >= ll or array.get(supres, y * 3 + 2) <= hh and array.get(supres, y * 3 + 2) >= ll
                    array.set(supres, y * 3, -1)

            src := src + 1
            if src >= 10
                break

    for x = 0 to 8 by 1
        for y = x + 1 to 9 by 1
            if array.get(stren, y) > array.get(stren, x)
                tmp = array.get(stren, y)
                array.set(stren, y, array.get(stren, x))
                changeit(x, y)


get_level(ind) =>
    float ret = na
    if ind < array.size(suportresistance)
        if array.get(suportresistance, ind) != 0
            ret := array.get(suportresistance, ind)
            ret
    ret

get_color(ind) =>
    color ret = na
    if ind < array.size(suportresistance)
        if array.get(suportresistance, ind) != 0
            ret := array.get(suportresistance, ind) > close and array.get(suportresistance, ind + 1) > close ? res_col : array.get(suportresistance, ind) < close and array.get(suportresistance, ind + 1) < close ? sup_col : inch_col
            ret
    ret

var srchannels = array.new_box(10)
for x = 0 to math.min(9, maxnumsr) by 1
    box.delete(array.get(srchannels, x))
    srcol = get_color(x * 2)
    if not na(srcol)
        array.set(srchannels, x, box.new(left = bar_index, top = get_level(x * 2), right = bar_index + 1, bottom = get_level(x * 2 + 1), border_color = srcol, border_width = 1, extend = extend.both, bgcolor = srcol))

resistancebroken = false
supportbroken = false

// check if it's not in a channel
not_in_a_channel = true
for x = 0 to math.min(9, maxnumsr) by 1
    if close <= array.get(suportresistance, x * 2) and close >= array.get(suportresistance, x * 2 + 1)
        not_in_a_channel := false
        not_in_a_channel

// if price is not in a channel then check broken ones
if not_in_a_channel
    for x = 0 to math.min(9, maxnumsr) by 1
        if close[1] <= array.get(suportresistance, x * 2) and close > array.get(suportresistance, x * 2)
            resistancebroken := true
            resistancebroken
        if close[1] >= array.get(suportresistance, x * 2 + 1) and close < array.get(suportresistance, x * 2 + 1)
            supportbroken := true
            supportbroken

alertcondition(resistancebroken, title = 'Resistance Broken', message = 'Resistance Broken')
alertcondition(supportbroken, title = 'Support Broken', message = 'Support Broken')
plotshape(showsrbroken and resistancebroken, style = shape.triangleup, location = location.belowbar, color = color.new(color.lime, 0), size = size.tiny)
plotshape(showsrbroken and supportbroken, style = shape.triangledown, location = location.abovebar, color = color.new(color.red, 0), size = size.tiny)

 

这是一个非常完整且功能强大的 Pine Script 指标脚本,名为 “My Support Resistance Channels”(我的支撑阻力通道),由作者 LonesomeTheBlue 编写,用于在 TradingView 图表上自动识别并绘制支撑位、阻力位和价格通道。


📌 总体功能概述

该脚本的核心目标是:

自动识别历史上的关键高点(Pivot High)和低点(Pivot Low),将它们聚类成“支撑/阻力通道”,并以矩形区域的形式在价格图表上显示出来。

它不仅能显示当前有效的 S/R 通道,还能:

  • 检测通道突破
  • 显示已失效的支撑/阻力
  • 支持自定义颜色、强度、宽度等参数
  • 提供价格是否处于通道内的视觉反馈

🔧 一、基础设置(Inputs)

1. 指标声明

pinescript
深色版本
indicator('My Support Resistance Channels', 'MySRchannel', overlay = true, max_bars_back = 501)
  • 名称:My Support Resistance Channels
  • 缩写:MySRchannel
  • overlay = true:绘制在价格图上(而非子图)
  • max_bars_back = 501:最多回溯 501 根 K 线,确保能处理大量历史数据

2. 用户可调参数(分组为 Settings 和 Colors)

参数说明
prd (Pivot Period) 计算 Pivot 点时左右各看多少根 K 线(默认 10)
ppsrc (Source) Pivot 点使用 High/Low 还是 Close/Open 作为源
ChannelW 支撑/阻力通道的最大允许宽度(占 300 根 K 线极值范围的百分比)
minstrength 通道必须包含至少这么多“强度”的 Pivot 点(强度 ≥ 最小值 × 20)
maxnumsr 最多显示几个支撑/阻力通道(最多 10 个)
loopback 回溯多少根 K 线来查找 Pivot 点(默认 290)

⚠️ 注意:maxnumsr - 1 是因为后面代码中用 math.min(9, maxnumsr),所以实际最大是 9。


3. 颜色设置

pinescript
深色版本
res_col = 阻力颜色(红)
sup_col = 支撑颜色(绿)
inch_col = 价格在通道内时的颜色(灰)

4. 额外功能开关

pinescript
深色版本
showpp = 是否显示 Pivot 点标记(H/L)
showsrbroken = 是否显示支撑/阻力突破信号
showthema1en, showthema2en = 是否显示两条移动平均线(SMA/EMA)

📈 二、移动平均线(MA)绘制(可选)

pinescript
深色版本
ma1 = showthema1en ? (SMA 或 EMA) : na
ma2 = showthema2en ? (SMA 或 EMA) : na
plot(ma1, color.blue)
plot(ma2, color.red)
  • 用户可选择开启两条 MA(如 50 和 200),用于趋势判断。

🔍 三、Pivot 点检测

pinescript
深色版本
float src1 = ppsrc == 'High/Low' ? high : math.max(close, open)
float src2 = ppsrc == 'High/Low' ? low : math.min(close, open)
float ph = ta.pivothigh(src1, prd, prd)
float pl = ta.pivotlow(src2, prd, prd)
  • 使用 ta.pivothigh() 和 ta.pivotlow() 函数检测局部极值。
  • 支持两种源:
    • High/Low:用最高价和最低价
    • Close/Open:用开盘/收盘价中的最大/最小值
pinescript
深色版本
plotshape(showpp and ph, text='H')  // 上方标记 H
plotshape(showpp and pl, text='L')  // 下方标记 L

📏 四、计算最大通道宽度

pinescript
深色版本
prdhighest = ta.highest(300)
prdlowest = ta.lowest(300)
cwidth = (prdhighest - prdlowest) * ChannelW / 100
  • 在最近 300 根 K 线中找最高价和最低价
  • 用它们的差值乘以用户设置的百分比,得到“最大允许通道宽度”

✅ 这是为了避免把跨度太大的价格区域误判为有效通道。


🗃️ 五、存储 Pivot 点数据

pinescript
深色版本
var pivotvals = array.new_float(0)   // 存储 Pivot 价格
var pivotlocs = array.new_float(0)   // 存储 Pivot 所在的 bar_index

if bool(ph) or bool(pl)
    array.unshift(pivotvals, ph 或 pl)
    array.unshift(pivotlocs, bar_index)

    // 删除超过 loopback 期的旧 Pivot 点
    for x = array.size(...) -1 to 0
        if bar_index - loc > loopback → pop()
  • 使用 unshift() 把新 Pivot 插入数组头部
  • 超过 loopback 周期的旧点会被清除

🧩 六、构建支撑/阻力通道(核心逻辑)

函数:get_sr_vals(ind)

目的:以第 ind 个 Pivot 点为中心,尝试将其他相近的 Pivot 点“合并”成一个通道。

pinescript
深色版本
get_sr_vals(ind) =>
    float lo = pivot_price, hi = pivot_price
    int numpp = 0
    for each other pivot:
        if 该点价格在当前通道宽度内(wdth <= cwidth)
            扩展 hi 或 lo
            numpp += 20  // 每个包含的 Pivot 增加 20 强度
    return [hi, lo, numpp]

✅ 这是一个“聚类”过程:相似价格的 Pivot 被归为一组。


🏆 七、筛选最强的支撑/阻力通道

每次出现新 Pivot 时,重新计算所有可能的通道,并按“强度”排序。

步骤:

  1. 对每个 Pivot,调用 get_sr_vals() 得到一个候选通道(hi, lo, strength)
  2. 增强强度:统计过去 loopback 根 K 线中,有多少根价格进入过这个通道(高点在内或低点在内),每进入一次 +1
  3. 从所有候选通道中选出强度最高的 10 个
  4. 为了避免重叠,一旦某个通道被选中,就将其包含的所有 Pivot 的强度设为 -1(防止重复使用)
  5. 按强度从高到低排序,存入 suportresistance 数组(每 2 个元素存一个通道的 [高, 低])

🎨 八、绘制支撑/阻力通道(使用 box

pinescript
深色版本
var srchannels = array.new_box(10)

for x = 0 to maxnumsr
    box.delete(old_box)
    color = get_color(...)  // 根据价格与通道位置决定颜色
    box.new(
        left = bar_index, right = bar_index + 1,
        top = hi, bottom = lo,
        extend = extend.both,  // 向左右无限延伸
        border_color = color,
        bgcolor = color
    )
  • 使用 box 对象绘制矩形通道
  • extend.both:通道向左右无限延伸
  • 颜色逻辑:
    • 价格在通道上方 → 阻力(红色)
    • 价格在通道下方 → 支撑(绿色)
    • 价格在通道内部 → 灰色

🔔 九、突破检测与警报

pinescript
深色版本
// 检查当前价格是否不在任何通道内
not_in_a_channel = true
for 通道 in 所有通道:
    if close 在通道内 → not_in_a_channel = false

// 如果不在通道内,检查是否突破了某个通道
if not_in_a_channel
    for 通道 in 所有通道:
        if 昨日 ≤ 阻力 且 今日 > 阻力 → resistancebroken = true
        if 昨日 ≥ 支撑 且 今日 < 支撑 → supportbroken = true

// 发出警报
alertcondition(resistancebroken, title="Resistance Broken")
alertcondition(supportbroken, title="Support Broken")

// 显示突破信号(小三角)
plotshape(showsrbroken and resistancebroken, ▲ below bar)
plotshape(showsrbroken and supportbroken, ▼ above bar)

✅ 总结:这个脚本做了什么?

功能实现方式
识别关键价格点 使用 ta.pivothigh/low 检测局部极值
聚类成通道 将价格相近的 Pivot 点合并,形成支撑/阻力区域
评估通道强度 基于包含的 Pivot 数量 + 历史测试次数
筛选最强通道 按强度排序,最多保留 10 个
可视化通道 用 box 绘制向两侧延伸的矩形区域
动态颜色反馈 根据价格与通道的相对位置变色
突破检测 检测价格是否突破通道边界
支持警报 可设置“阻力突破”或“支撑跌破”警报

💡 使用建议

  • 适合周期:日线、4H、1H 等中长线周期
  • 搭配使用:可结合 MA 判断趋势方向,在上升趋势中更关注支撑位,在下跌趋势中关注阻力位
  • 通道宽度设置:市场波动大时可调高 ChannelW,震荡市可调低
  • 突破信号:三角形信号可作为入场或止损参考

🚀 总体评价

这是一个非常成熟、逻辑严谨、可视化优秀的支撑阻力识别指标。它超越了简单的水平线,采用了“通道”概念,更符合真实市场的波动特性,是技术分析中非常实用的工具。

 

========== End

 

posted @ 2025-08-28 18:10  lsgxeva  阅读(70)  评论(0)    收藏  举报