Indicator · Pine Script v6 · On the chart

Bollinger Band Wick Marker with RSI Alerts

by gaopfEditer

An extended version of a Bollinger Band wick marker that labels candles with wicks beyond the bands on the 15-minute timeframe.

View on GitHub

GitHub stars1on the repository
Pine versionv6current
Lines of code611
Settings27inputs
LicenceMIT
Last update6 weeks ago11 Sep 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.

Source Code

611 lines of Pine Script v6 from tradingview-bollinger-wicks.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.

tradingview-bollinger-wicks.pine
//@version=6
indicator("布林带插针标记 - 多时间框架", shorttitle="BB-Wicks", overlay=true, max_bars_back=500)

// ==================== 输入参数 ====================
// 布林带参数
bb_length = input.int(20, title="布林带周期", minval=1)
bb_mult = input.float(2.0, title="布林带倍数", minval=0.1, step=0.1)

// ==================== 时间框架配置(可扩展)====================
// 配置说明:
//   - timeframes_code: 存储时间框架代码(TradingView格式)
//   - timeframes_name: 存储显示名称(对应位置)
// 时间框架代码说明:
//   "15" = 15分钟, "30" = 30分钟, "60" = 1小时
//   "240" = 4小时, "1D" = 1天, "1W" = 1周
// 要添加新时间框架,在两个数组中对应位置添加即可
var timeframes_code = array.new<string>()
var timeframes_name = array.new<string>()
if barstate.isfirst
    // 默认配置:15分钟、1小时、4小时
    array.push(timeframes_code, "15")
    array.push(timeframes_name, "15M")
    // array.push(timeframes_code, "60")
    // array.push(timeframes_name, "1H")
    // array.push(timeframes_code, "240")
    // array.push(timeframes_name, "4H")
    // 要添加新时间框架,取消下面的注释并修改:
    // array.push(timeframes_code, "30")
    // array.push(timeframes_name, "30M")  // 30分钟
    // array.push(timeframes_code, "1D")
    // array.push(timeframes_name, "1D")   // 1天
    // array.push(timeframes_code, "1W")
    // array.push(timeframes_name, "1W")   // 1周

// 插针检测参数
wick_ratio = input.float(0.3, title="插针比例(实体/影线)", minval=0.1, maxval=1.0, step=0.1, tooltip="影线长度与实体长度的比例,值越小越严格")

// 显示选项
show_labels = input.bool(true, title="显示标签", group="显示设置")
show_plots = input.bool(true, title="显示布林带", group="显示设置")
label_size = input.string("small", title="标签大小", options=["tiny", "small", "normal", "large", "huge"], group="显示设置")

// 警报设置
enable_alert = input.bool(true, title="启用警报", tooltip="启用后可在TradingView中设置警报,通过webhook调用API", group="警报设置")
alert_on_realtime = input.bool(true, title="实时K线警报", tooltip="在当前时间框架检测到插针时触发警报", group="警报设置")
alert_on_mtf = input.bool(false, title="多时间框架警报", tooltip="在其他时间框架检测到插针时触发警报", group="警报设置")

// RSI 预警设置
enable_rsi_alert = input.bool(true, title="启用RSI预警", tooltip="启用RSI超买超卖预警", group="RSI预警设置")
rsi_length = input.int(14, title="RSI周期", minval=1, group="RSI预警设置")
rsi_overbought = input.int(70, title="超买阈值", minval=50, maxval=100, group="RSI预警设置")
rsi_oversold = input.int(30, title="超卖阈值", minval=0, maxval=50, group="RSI预警设置")

// RSI 背离设置
enable_rsi_divergence = input.bool(true, title="启用RSI背离预警", tooltip="检测价格与RSI的背离信号", group="RSI背离设置")
divergence_lookback = input.int(9, title="历史K线周期", minval=5, maxval=50, tooltip="用于计算平均K线长度的历史周期", group="RSI背离设置")

// 连续插针检测设置
enable_continuous_wick = input.bool(true, title="启用连续插针预警", tooltip="检测上下轨附近连续插针信号", group="连续插针设置")
continuous_wick_count = input.int(2, title="插针数量", minval=2, maxval=5, tooltip="触发信号所需的连续插针数量", group="连续插针设置")

// K线形态设置(射击之星、吞没)
enable_candle_pattern = input.bool(true, title="启用K线形态预警", tooltip="检测射击之星和吞没形态", group="K线形态设置")
enable_shooting_star = input.bool(true, title="射击之星", tooltip="上影线长、实体小、下影线短,看跌信号", group="K线形态设置")
enable_engulfing = input.bool(true, title="吞没形态", tooltip="当前K线实体完全包住前一根K线实体", group="K线形态设置")
pattern_upper_wick_ratio = input.float(2.0, title="射击之星上影线/实体比", minval=1.5, maxval=5.0, step=0.1, tooltip="上影线至少为实体的倍数", group="K线形态设置")

// 定时日线推送设置
enable_daily_line_push = input.bool(true, title="启用定时日线推送", tooltip="按设定时间推送指定交易对的日线数据", group="定时日线推送")
daily_push_symbol = input.symbol("BINANCE:BTCUSDT", title="推送交易对", group="定时日线推送")
daily_push_hour = input.int(8, title="推送小时(北京时间)", minval=0, maxval=23, group="定时日线推送")
daily_push_minute = input.int(1, title="推送分钟(北京时间)", minval=0, maxval=59, group="定时日线推送")

// 颜色设置
color_upper_wick = input.color(color.new(color.red, 0), title="上插针颜色", group="颜色设置")
color_lower_wick = input.color(color.new(color.green, 0), title="下插针颜色", group="颜色设置")

// ==================== 函数:计算布林带 ====================
calc_bb(tf) =>
    [high_tf, low_tf, close_tf, open_tf] = request.security(syminfo.tickerid, tf, [high, low, close, open], lookahead=barmerge.lookahead_off)
    // 计算布林带
    basis = ta.sma(close_tf, bb_length)
    dev = bb_mult * ta.stdev(close_tf, bb_length)
    upper = basis + dev
    lower = basis - dev
    [upper, lower, basis, high_tf, low_tf, close_tf, open_tf]

// ==================== 函数:检测插针 ====================
detect_wick(upper_band, lower_band, high_price, low_price, open_price, close_price) =>
    body_size = math.abs(close_price - open_price)
    upper_wick = high_price - math.max(open_price, close_price)
    lower_wick = math.min(open_price, close_price) - low_price
    // 上插针:上影线突破上轨,且上影线长度满足条件
    upper_wick_condition = high_price > upper_band and upper_wick > 0 and (body_size == 0 or upper_wick / math.max(body_size, 0.0001) >= wick_ratio)
    // 下插针:下影线突破下轨,且下影线长度满足条件
    lower_wick_condition = low_price < lower_band and lower_wick > 0 and (body_size == 0 or lower_wick / math.max(body_size, 0.0001) >= wick_ratio)
    [upper_wick_condition, lower_wick_condition, upper_wick, lower_wick]

// ==================== 函数:检测射击之星 ====================
// 射击之星:上影线长、实体小,下方可有插针但下影线长度 < 上影线1/3
detect_shooting_star(h_price, l_price, o_price, c_price, ratio) =>
    body = math.abs(c_price - o_price)
    upper_w = h_price - math.max(o_price, c_price)
    lower_w = math.min(o_price, c_price) - l_price
    // 实体不能为0,上影线>=实体*ratio,下影线 < 上影线/3(允许有下影线但须远短于上影线)
    body > 0 and upper_w >= body * ratio and lower_w < upper_w / 3

// ==================== 函数:检测倒锤子(射击之星倒过来的形态)====================
// 倒锤子:下影线长、实体小,上方可有插针但上影线 < 下影线1/3,看涨 reversal 信号
detect_inverted_shooting_star(h_price, l_price, o_price, c_price, ratio) =>
    body = math.abs(c_price - o_price)
    upper_w = h_price - math.max(o_price, c_price)
    lower_w = math.min(o_price, c_price) - l_price
    // 实体不能为0,下影线>=实体*ratio,上影线 < 下影线/3(允许有上影线但须远短于下影线)
    body > 0 and lower_w >= body * ratio and upper_w < lower_w / 3

// ==================== 函数:检测吞没形态 ====================
// 看涨吞没:当前阳线实体包住前一根阴线实体
// 看跌吞没:当前阴线实体包住前一根阳线实体
detect_bullish_engulfing(o1, c1, o0, c0) =>
    prev_bearish = c1 < o1  // 前一根阴线
    curr_bullish = c0 > o0  // 当前阳线
    curr_open_below_prev_close = o0 <= c1
    curr_close_above_prev_open = c0 >= o1
    prev_bearish and curr_bullish and curr_open_below_prev_close and curr_close_above_prev_open

detect_bearish_engulfing(o1, c1, o0, c0) =>
    prev_bullish = c1 > o1  // 前一根阳线
    curr_bearish = c0 < o0  // 当前阴线
    curr_open_above_prev_close = o0 >= c1
    curr_close_below_prev_open = c0 <= o1
    prev_bullish and curr_bearish and curr_open_above_prev_close and curr_close_below_prev_open

// ==================== 辅助函数:获取标签大小 ====================
get_label_size() =>
    switch label_size
        "tiny" => size.tiny
        "small" => size.small
        "normal" => size.normal
        "large" => size.large
        "huge" => size.huge
        => size.small

// ==================== 变量:警报条件(合并后)====================
wick_alert = false  // 合并的上插针和下插针警报
rsi_alert = false  // 合并的RSI超买超卖警报
rsi_divergence_alert = false  // 合并的RSI背离警报
continuous_wick_alert = false  // 连续插针警报
candle_pattern_alert = false  // K线形态警报(射击之星、吞没)

// 警报消息
wick_alert_message = ""
rsi_alert_message = ""
rsi_divergence_alert_message = ""
continuous_wick_alert_message = ""
candle_pattern_alert_message = ""

// 连续插针计数(用于检测连续插针信号)
var int continuous_upper_wick_counter = 0  // 连续上插针计数(上下轨附近)
var int continuous_lower_wick_counter = 0  // 连续下插针计数(上下轨附近)
// 非上下轨附近连续插针检测(用于存储历史插针位置,允许跳过最多2根K线)
var array<int> non_zone_upper_wick_bars = array.new<int>()  // 非上轨附近的上插针K线索引
var array<int> non_zone_lower_wick_bars = array.new<int>()  // 非下轨附近的下插针K线索引

// ==================== 主逻辑 ====================
label_size_value = get_label_size()

// 初始化警报变量
wick_alert := false
wick_alert_message := ""

// 循环处理所有配置的时间框架 - 忠实记录每个插针,不合并不忽略
for i = 0 to array.size(timeframes_code) - 1
    tf_code = array.get(timeframes_code, i)
    tf_name = array.get(timeframes_name, i)
    
    [upper_tf, lower_tf, basis_tf, high_tf, low_tf, close_tf, open_tf] = calc_bb(tf_code)
    [upper_wick_tf, lower_wick_tf, uw_size_tf, lw_size_tf] = detect_wick(upper_tf, lower_tf, high_tf, low_tf, open_tf, close_tf)
    
    // 上插针:直接显示和记录
    if upper_wick_tf
        if show_labels
            label.new(bar_index, high_tf, tf_name + "↑", color=color_upper_wick, textcolor=color.white, style=label.style_label_down, size=label_size_value)
        // 合并警报:上插针和下插针合并
        if enable_alert and alert_on_mtf
            wick_alert := true
            if wick_alert_message == ""
                wick_alert_message := "上插针:" + tf_name + "@" + str.tostring(high_tf)
            else
                wick_alert_message := wick_alert_message + ",上插针:" + tf_name + "@" + str.tostring(high_tf)
    
    // 下插针:直接显示和记录
    if lower_wick_tf
        if show_labels
            label.new(bar_index, low_tf, tf_name + "↓", color=color_lower_wick, textcolor=color.white, style=label.style_label_up, size=label_size_value)
        // 合并警报:上插针和下插针合并
        if enable_alert and alert_on_mtf
            wick_alert := true
            if wick_alert_message == ""
                wick_alert_message := "下插针:" + tf_name + "@" + str.tostring(low_tf)
            else
                wick_alert_message := wick_alert_message + ",下插针:" + tf_name + "@" + str.tostring(low_tf)


// ==================== RSI 计算和预警(合并)====================
rsi_value = ta.rsi(close, rsi_length)

// 初始化RSI警报
rsi_alert := false
rsi_alert_message := ""

// 检测 RSI 超买超卖条件(合并)
if enable_rsi_alert
    rsi_overbought_trigger = rsi_value > rsi_overbought and rsi_value[1] <= rsi_overbought
    rsi_oversold_trigger = rsi_value < rsi_oversold and rsi_value[1] >= rsi_oversold
    
    if rsi_overbought_trigger
        rsi_alert := true
        rsi_alert_message := "RSI超买:" + str.tostring(rsi_value, "#.##")
    else if rsi_oversold_trigger
        rsi_alert := true
        rsi_alert_message := "RSI超卖:" + str.tostring(rsi_value, "#.##")

// ==================== 可选:绘制布林带(当前时间框架) ====================
basis_current = ta.sma(close, bb_length)
dev_current = bb_mult * ta.stdev(close, bb_length)
upper_current = basis_current + dev_current
lower_current = basis_current - dev_current

// ==================== RSI 背离检测(实时,合并)====================
// 初始化背离警报
rsi_divergence_alert := false
rsi_divergence_alert_message := ""

if enable_rsi_divergence and not na(rsi_value)
    // 计算历史9根K线的平均长度(实体长度:|close - open|)
    avg_candle_length = 0.0
    for i = 1 to divergence_lookback
        candle_length = math.abs(close[i] - open[i])
        avg_candle_length := avg_candle_length + candle_length
    avg_candle_length := avg_candle_length / divergence_lookback
    
    // 当前K线的长度
    current_candle_length = math.abs(close - open)
    
    // 价格变化阈值:平均长度的一半
    price_threshold = avg_candle_length / 2.0
    
    // 查找左侧历史最高价和对应的RSI(不包括当前K线)
    // 至少相隔3根K线,所以需要检查索引
    min_distance = 3  // 至少相隔3根K线
    highest_price = ta.highest(high[1], divergence_lookback)
    highest_price_idx = ta.highestbars(high[1], divergence_lookback)
    // highest_price_idx 是负数,表示距离 high[1] 的偏移量
    // 例如:highest_price_idx = -1 表示在 high[2],距离当前K线2根(不满足)
    //      highest_price_idx = -2 表示在 high[3],距离当前K线3根(满足)
    //      highest_price_idx = -3 表示在 high[4],距离当前K线4根(满足)
    // 需要确保至少相隔3根K线,即 highest_price_idx <= -min_distance
    // 计算实际索引:如果 highest_price_idx = -2,实际位置是 high[1-2] = high[-1],但这是无效的
    // 正确理解:highest_price_idx = -2 表示在 high[1+(-2)] = high[-1],但应该理解为 high[3]
    // 实际上:highest_price_idx = -2 时,最高价在 high[3],对应的RSI是 rsi_value[3]
    // 所以:actual_idx = 1 + highest_price_idx + 1 = 2 + highest_price_idx
    // 但更简单:如果 highest_price_idx = -2,那么实际K线位置是 1 + (-2) + 1 = 0,不对
    // 重新理解:highest_price_idx 是相对于 high[1] 的偏移,所以实际位置是 1 + highest_price_idx
    // 如果 highest_price_idx = -2,实际位置是 1 + (-2) = -1,这是无效的
    // 实际上 ta.highestbars 返回的索引:-1 表示在 high[2],-2 表示在 high[3]
    // 所以实际K线位置是 1 + abs(highest_price_idx) = 1 + 2 = 3
    // 对应的RSI是 rsi_value[3]
    actual_highest_bar = 1 + math.abs(highest_price_idx)
    highest_rsi = (highest_price_idx <= -min_distance and actual_highest_bar <= divergence_lookback) ? rsi_value[actual_highest_bar] : na
    
    // 查找左侧历史最低价和对应的RSI(不包括当前K线)
    lowest_price = ta.lowest(low[1], divergence_lookback)
    lowest_price_idx = ta.lowestbars(low[1], divergence_lookback)
    // lowest_price_idx 是负数,表示距离 low[1] 的偏移量
    // 需要确保至少相隔3根K线,即 lowest_price_idx <= -min_distance
    actual_lowest_bar = 1 + math.abs(lowest_price_idx)
    lowest_rsi = (lowest_price_idx <= -min_distance and actual_lowest_bar <= divergence_lookback) ? rsi_value[actual_lowest_bar] : na
    
    // 实时检测看跌背离:价格创新高但RSI未创新高
    bearish_divergence = false
    if not na(highest_price) and not na(highest_rsi)
        price_new_high = high > highest_price
        rsi_not_new_high = rsi_value < highest_rsi
        
        // 条件:价格创新高 + RSI未创新高 + 当前K线长度 > 平均长度的一半 + 至少相隔3根K线
        if price_new_high and rsi_not_new_high and current_candle_length > price_threshold
            bearish_divergence := true
            rsi_divergence_alert := true
            rsi_divergence_alert_message := "看跌背离"
            if show_labels
                label.new(bar_index, high, "看跌背离", color=color.new(color.orange, 0), textcolor=color.white, style=label.style_label_down, size=label_size_value)
    
    // 实时检测看涨背离:价格创新低但RSI未创新低
    bullish_divergence = false
    if not na(lowest_price) and not na(lowest_rsi)
        price_new_low = low < lowest_price
        rsi_not_new_low = rsi_value > lowest_rsi
        
        // 条件:价格创新低 + RSI未创新低 + 当前K线长度 > 平均长度的一半 + 至少相隔3根K线
        if price_new_low and rsi_not_new_low and current_candle_length > price_threshold
            bullish_divergence := true
            rsi_divergence_alert := true
            if rsi_divergence_alert_message == ""
                rsi_divergence_alert_message := "看涨背离"
            else
                rsi_divergence_alert_message := rsi_divergence_alert_message + ",看涨背离"
            if show_labels
                label.new(bar_index, low, "看涨背离", color=color.new(color.aqua, 0), textcolor=color.white, style=label.style_label_up, size=label_size_value)

// ==================== 绘制布林带(当前时间框架) ====================
plot(show_plots ? upper_current : na, "上轨", color=color.new(color.blue, 50), linewidth=1)
plot(show_plots ? lower_current : na, "下轨", color=color.new(color.blue, 50), linewidth=1)
plot(show_plots ? basis_current : na, "中轨", color=color.new(color.blue, 70), linewidth=1)

// ==================== 连续插针检测(上下轨附近)====================
// 初始化连续插针警报
continuous_wick_alert := false
continuous_wick_alert_message := ""

if enable_continuous_wick
    // 使用当前时间框架的数据
    body_size = math.abs(close - open)
    
    // 检测当前K线是否有插针(使用detect_wick函数)
    [upper_wick_current, lower_wick_current, uw_size_current, lw_size_current] = detect_wick(upper_current, lower_current, high, low, open, close)
    
    // ========== 上轨附近连续插针检测 ==========
    // 计算中轨到上轨的距离
    mid_to_upper = upper_current - basis_current
    // 85%位置:中轨 + 85% * (上轨 - 中轨)
    upper_zone_threshold = basis_current + mid_to_upper * 0.85
    
    // 检查当前K线是否在上轨附近(85%以上)
    is_in_upper_zone = high >= upper_zone_threshold
    
    // 计算上影线大小
    upper_wick_size = high - math.max(open, close)
    
    // 检测有效上插针:在上轨附近且插针大于实体
    valid_upper_wick = is_in_upper_zone and upper_wick_size > body_size and upper_wick_size > 0
    
    // 连续上插针计数逻辑(上下轨附近:2次即可报警)
    if valid_upper_wick
        // 检测到有效上插针,增加计数
        continuous_upper_wick_counter := continuous_upper_wick_counter + 1
        
        // 如果达到指定数量,触发信号
        if continuous_upper_wick_counter == continuous_wick_count
            continuous_wick_alert := true
            if continuous_wick_alert_message == ""
                continuous_wick_alert_message := "连续上插针(" + str.tostring(continuous_upper_wick_counter) + "次)"
            else
                continuous_wick_alert_message := continuous_wick_alert_message + ",连续上插针(" + str.tostring(continuous_upper_wick_counter) + "次)"
            if show_labels
                label.new(bar_index, high, "连续上插针", color=color.new(color.purple, 0), textcolor=color.white, style=label.style_label_down, size=label_size_value)
    else
        // 没有检测到上插针,清空计数
        continuous_upper_wick_counter := 0
    
    // ========== 非上轨附近连续插针检测(允许跳过最多2根K线,需要3根以上插针)==========
    // 检测非上轨附近的上插针:突破上轨但不在85%区域
    non_zone_upper_wick = upper_wick_current and not is_in_upper_zone
    if non_zone_upper_wick
        // 记录当前K线索引
        array.push(non_zone_upper_wick_bars, bar_index)
        // 只保留最近20根K线的记录(避免数组过大)
        if array.size(non_zone_upper_wick_bars) > 20
            array.shift(non_zone_upper_wick_bars)
        
        // 检查是否有连续插针(允许跳过最多2根K线,需要至少3根插针)
        if array.size(non_zone_upper_wick_bars) >= 3
            // 从最新的插针开始向前检查
            recent_count = 1  // 当前K线已经有插针
            last_wick_bar = bar_index
            gap_allowed = 2  // 允许跳过的K线数量
            
            // 检查最近的插针序列(从倒数第二个开始向前检查)
            for i = array.size(non_zone_upper_wick_bars) - 2 to 0
                wick_bar = array.get(non_zone_upper_wick_bars, i)
                // 检查与前一个插针的间隔
                gap = last_wick_bar - wick_bar - 1
                if gap <= gap_allowed
                    recent_count := recent_count + 1
                    last_wick_bar := wick_bar
                else
                    // 间隔太大,停止检查
                    break
            
            // 如果找到至少3根连续插针(允许跳过最多2根K线),触发信号
            if recent_count >= 3
                continuous_wick_alert := true
                if continuous_wick_alert_message == ""
                    continuous_wick_alert_message := "非上轨连续上插针(" + str.tostring(recent_count) + "次)"
                else
                    continuous_wick_alert_message := continuous_wick_alert_message + ",非上轨连续上插针(" + str.tostring(recent_count) + "次)"
                if show_labels
                    label.new(bar_index, high, "非上轨连续上插针", color=color.new(color.purple, 0), textcolor=color.white, style=label.style_label_down, size=label_size_value)
    
    // ========== 下轨附近连续插针检测 ==========
    // 计算中轨到下轨的距离
    mid_to_lower = basis_current - lower_current
    // 15%位置:下轨 + 15% * (中轨 - 下轨) = 下轨 + 0.15 * (中轨 - 下轨)
    lower_zone_threshold = lower_current + mid_to_lower * 0.15
    
    // 检查当前K线是否在下轨附近(15%以内)
    is_in_lower_zone = low <= lower_zone_threshold
    
    // 计算下影线大小
    lower_wick_size = math.min(open, close) - low
    
    // 检测有效下插针:在下轨附近且插针大于实体
    valid_lower_wick = is_in_lower_zone and lower_wick_size > body_size and lower_wick_size > 0
    
    // 连续下插针计数逻辑(上下轨附近:2次即可报警)
    if valid_lower_wick
        // 检测到有效下插针,增加计数
        continuous_lower_wick_counter := continuous_lower_wick_counter + 1
        
        // 如果达到指定数量,触发信号
        if continuous_lower_wick_counter == continuous_wick_count
            continuous_wick_alert := true
            if continuous_wick_alert_message == ""
                continuous_wick_alert_message := "连续下插针(" + str.tostring(continuous_lower_wick_counter) + "次)"
            else
                continuous_wick_alert_message := continuous_wick_alert_message + ",连续下插针(" + str.tostring(continuous_lower_wick_counter) + "次)"
            if show_labels
                label.new(bar_index, low, "连续下插针", color=color.new(color.purple, 0), textcolor=color.white, style=label.style_label_up, size=label_size_value)
    else
        // 没有检测到下插针,清空计数
        continuous_lower_wick_counter := 0
    
    // ========== 非下轨附近连续插针检测(允许跳过最多2根K线,需要3根以上插针)==========
    // 检测非下轨附近的下插针:突破下轨但不在15%区域
    non_zone_lower_wick = lower_wick_current and not is_in_lower_zone
    if non_zone_lower_wick
        // 记录当前K线索引
        array.push(non_zone_lower_wick_bars, bar_index)
        // 只保留最近20根K线的记录(避免数组过大)
        if array.size(non_zone_lower_wick_bars) > 20
            array.shift(non_zone_lower_wick_bars)
        
        // 检查是否有连续插针(允许跳过最多2根K线,需要至少3根插针)
        if array.size(non_zone_lower_wick_bars) >= 3
            // 从最新的插针开始向前检查
            recent_count = 1  // 当前K线已经有插针
            last_wick_bar = bar_index
            gap_allowed = 2  // 允许跳过的K线数量
            
            // 检查最近的插针序列(从倒数第二个开始向前检查)
            for i = array.size(non_zone_lower_wick_bars) - 2 to 0
                wick_bar = array.get(non_zone_lower_wick_bars, i)
                // 检查与前一个插针的间隔
                gap = last_wick_bar - wick_bar - 1
                if gap <= gap_allowed
                    recent_count := recent_count + 1
                    last_wick_bar := wick_bar
                else
                    // 间隔太大,停止检查
                    break
            
            // 如果找到至少3根连续插针(允许跳过最多2根K线),触发信号
            if recent_count >= 3
                continuous_wick_alert := true
                if continuous_wick_alert_message == ""
                    continuous_wick_alert_message := "非下轨连续下插针(" + str.tostring(recent_count) + "次)"
                else
                    continuous_wick_alert_message := continuous_wick_alert_message + ",非下轨连续下插针(" + str.tostring(recent_count) + "次)"
                if show_labels
                    label.new(bar_index, low, "非下轨连续下插针", color=color.new(color.purple, 0), textcolor=color.white, style=label.style_label_up, size=label_size_value)

// ==================== K线形态检测(射击之星、吞没,需在布林带上下轨附近)====================
candle_pattern_alert := false
candle_pattern_alert_message := ""

if enable_candle_pattern
    // 布林带位置判断:上轨附近(85%以上)、下轨附近(15%以内)
    mid_to_upper_bb = upper_current - basis_current
    upper_zone_bb = basis_current + mid_to_upper_bb * 0.85
    mid_to_lower_bb = basis_current - lower_current
    lower_zone_bb = lower_current + mid_to_lower_bb * 0.15
    at_upper_band = high >= upper_zone_bb
    at_lower_band = low <= lower_zone_bb
    above_mid_band = high >= basis_current  // 中轨之上
    below_mid_band = low <= basis_current   // 中轨之下

    // 射击之星:看跌信号,需在中轨之上
    if enable_shooting_star and above_mid_band and detect_shooting_star(high, low, open, close, pattern_upper_wick_ratio)
        candle_pattern_alert := true
        candle_pattern_alert_message := "射击之星"
        if show_labels
            label.new(bar_index, high, "射击之星", color=color.new(color.orange, 0), textcolor=color.white, style=label.style_label_down, size=label_size_value)

    // 倒锤子:看涨信号,射击之星倒过来的形态,需在中轨之下,上影线 < 下影线/3
    if enable_shooting_star and below_mid_band and detect_inverted_shooting_star(high, low, open, close, pattern_upper_wick_ratio)
        candle_pattern_alert := true
        if candle_pattern_alert_message != ""
            candle_pattern_alert_message := candle_pattern_alert_message + ",倒锤子"
        else
            candle_pattern_alert_message := "倒锤子"
        if show_labels
            label.new(bar_index, low, "倒锤子", color=color.new(color.aqua, 0), textcolor=color.white, style=label.style_label_up, size=label_size_value)

    // 看涨吞没:当前阳线包住前一根阴线,需在布林带下轨附近
    if enable_engulfing and at_lower_band and detect_bullish_engulfing(open[1], close[1], open, close)
        candle_pattern_alert := true
        if candle_pattern_alert_message != ""
            candle_pattern_alert_message := candle_pattern_alert_message + ",看涨吞没"
        else
            candle_pattern_alert_message := "看涨吞没"
        if show_labels
            label.new(bar_index, low, "看涨吞没", color=color.new(color.green, 0), textcolor=color.white, style=label.style_label_up, size=label_size_value)

    // 看跌吞没:当前阴线包住前一根阳线,需在布林带上轨附近
    if enable_engulfing and at_upper_band and detect_bearish_engulfing(open[1], close[1], open, close)
        candle_pattern_alert := true
        if candle_pattern_alert_message != ""
            candle_pattern_alert_message := candle_pattern_alert_message + ",看跌吞没"
        else
            candle_pattern_alert_message := "看跌吞没"
        if show_labels
            label.new(bar_index, high, "看跌吞没", color=color.new(color.red, 0), textcolor=color.white, style=label.style_label_down, size=label_size_value)

// ==================== 实时检测当前K线的插针 ====================
if barstate.islast
    // 使用当前图表的数据计算布林带
    basis_realtime = ta.sma(close, bb_length)
    dev_realtime = bb_mult * ta.stdev(close, bb_length)
    upper_realtime = basis_realtime + dev_realtime
    lower_realtime = basis_realtime - dev_realtime
    [upper_wick_realtime, lower_wick_realtime, uw_size_realtime, lw_size_realtime] = detect_wick(upper_realtime, lower_realtime, high, low, open, close)
    // 实时标记(仅在最后一根K线)
    if upper_wick_realtime and show_labels
        label.new(bar_index, high, "实时↑", color=color.new(color.red, 20), textcolor=color.white, style=label.style_label_down, size=size.normal)
    if lower_wick_realtime and show_labels
        label.new(bar_index, low, "实时↓", color=color.new(color.green, 20), textcolor=color.white, style=label.style_label_up, size=size.normal)
    
    // 设置实时警报(合并上插针和下插针)
    if enable_alert and alert_on_realtime
        if upper_wick_realtime or lower_wick_realtime
            wick_alert := true
            if upper_wick_realtime and lower_wick_realtime
                wick_alert_message := "实时上插针@" + str.tostring(high) + ",下插针@" + str.tostring(low) + " 价格:" + str.tostring(close)
            else if upper_wick_realtime
                wick_alert_message := "实时上插针@" + str.tostring(high) + " 价格:" + str.tostring(close)
            else
                wick_alert_message := "实时下插针@" + str.tostring(low) + " 价格:" + str.tostring(close)

// ==================== 警报:动态消息携带信号类型(合并为单一日志)====================
// 格式:ticker | 信号中文描述 | time | close | high | low ; 触发信号【周期】
// 插针:仅连续插针预警;K线形态:具体到射击之星/倒锤子/看涨吞没/看跌吞没
get_alert_time() =>
    str.format("{0,date,yyyy-MM-dd'T'HH:mm:ss'Z'}", time)

// 当前图表周期转可读标签(兜底不为空)
get_timeframe_label() =>
    tf = timeframe.period
    // 分钟周期:1/3/5/15/30/45/60/120/240...
    n = str.tonumber(tf)
    if not na(n)
        n >= 60 and n % 60 == 0 ? str.tostring(int(n / 60)) + "h" : str.tostring(int(n)) + "m"
    else
        // 非分钟周期:D/W/M 等
        tf == "D" or tf == "1D" ? "1D" :
         tf == "W" or tf == "1W" ? "1W" :
         tf == "M" or tf == "1M" ? "1M" :
         (str.length(tf) > 0 ? tf : "unknown_tf")

// 生成北京时间日期键,用于限制每天只推送一次
get_bj_day_key() =>
    y = year(time, "Asia/Shanghai")
    m = month(time, "Asia/Shanghai")
    d = dayofmonth(time, "Asia/Shanghai")
    y * 10000 + m * 100 + d

// 记录最近一次日线推送日期
var int last_daily_line_push_day = na

// 定时推送指定交易对上一根完整日线(北京时间)
if enable_daily_line_push and barstate.isconfirmed
    is_push_time = hour(time, "Asia/Shanghai") == daily_push_hour and minute(time, "Asia/Shanghai") == daily_push_minute
    day_key = get_bj_day_key()
    if is_push_time and day_key != last_daily_line_push_day
        d_open = request.security(daily_push_symbol, "1D", open[1], lookahead=barmerge.lookahead_off)
        d_high = request.security(daily_push_symbol, "1D", high[1], lookahead=barmerge.lookahead_off)
        d_low = request.security(daily_push_symbol, "1D", low[1], lookahead=barmerge.lookahead_off)
        d_close = request.security(daily_push_symbol, "1D", close[1], lookahead=barmerge.lookahead_off)
        d_time = request.security(daily_push_symbol, "1D", time[1], lookahead=barmerge.lookahead_off)
        d_time_str = str.format("{0,date,yyyy-MM-dd}", d_time)
        daily_msg = str.format("{0} | 日线播报 | {1} | O:{2} H:{3} L:{4} C:{5}; 定时推送", daily_push_symbol, d_time_str, str.tostring(d_open), str.tostring(d_high), str.tostring(d_low), str.tostring(d_close))
        alert(daily_msg, alert.freq_once_per_bar_close)
        last_daily_line_push_day := day_key

all_signals = continuous_wick_alert or rsi_alert or rsi_divergence_alert or candle_pattern_alert
if all_signals
    sig_desc = ""
    if continuous_wick_alert
        sig_desc := continuous_wick_alert_message != "" ? continuous_wick_alert_message : "连续插针"
    else if rsi_alert
        sig_desc := rsi_alert_message != "" ? rsi_alert_message : "RSI超买超卖"
    else if rsi_divergence_alert
        sig_desc := rsi_divergence_alert_message != "" ? rsi_divergence_alert_message : "RSI背离"
    else if candle_pattern_alert
        sig_desc := candle_pattern_alert_message != "" ? candle_pattern_alert_message : "K线形态"
    else
        sig_desc := "未知信号"
    t_str = get_alert_time()
    tf_label = get_timeframe_label()
    // 触发信号【15m】/【1h】/【4h】等,与警报所选周期一致
    final_msg = str.format("{0} | {1} | {2} | {3} | {4} | {5} | {6}; 触发信号", syminfo.ticker, sig_desc, t_str, str.tostring(close), str.tostring(high), str.tostring(low), tf_label)
    alert(final_msg, alert.freq_once_per_bar_close)

Overview

Bollinger Band Wick Marker with RSI Alerts adds RSI overbought and oversold alerts, an RSI divergence check, a repeated-wick warning, shooting star and engulfing candle detection, and a scheduled daily push for a chosen symbol. Each feature has an on-off input and the alerts are meant for webhook use. It draws on the price chart.

Details

Published by

gaopfEditer on GitHub

Type

Indicator, Pine Script v6

Draws

On the price chart

Category

Volatility & bands, Candlestick patterns, Divergence

Markets

Crypto

Timeframes

M15-H1

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
布林带周期int20bb_length
布林带倍数float2.0bb_mult
插针比例(实体/影线)float0.3wick_ratio
显示标签booltrueshow_labels
显示布林带booltrueshow_plots
标签大小stringsmalllabel_size
启用警报booltrueenable_alert
实时K线警报booltruealert_on_realtime
多时间框架警报boolfalsealert_on_mtf
启用RSI预警booltrueenable_rsi_alert
RSI周期int14rsi_length
超买阈值int70rsi_overbought
Show all 27 settings
SettingTypeDefaultVariable
超卖阈值int30rsi_oversold
启用RSI背离预警booltrueenable_rsi_divergence
历史K线周期int9divergence_lookback
启用连续插针预警booltrueenable_continuous_wick
插针数量int2continuous_wick_count
启用K线形态预警booltrueenable_candle_pattern
射击之星booltrueenable_shooting_star
吞没形态booltrueenable_engulfing
射击之星上影线/实体比float2.0pattern_upper_wick_ratio
启用定时日线推送booltrueenable_daily_line_push
推送交易对symbolBINANCE:BTCUSDTdaily_push_symbol
推送小时(北京时间)int8daily_push_hour
推送分钟(北京时间)int1daily_push_minute
上插针颜色colorcolor.new(color.red, 0)color_upper_wick
下插针颜色colorcolor.new(color.green, 0)color_lower_wick
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

Body Mass Indicator

by harryguiacorn
219 stars

The Body Mass Indicator highlights candles with exceptionally large body ranges relative to recent price movement. It calculates the absolute distance between open and close prices. When enabled, it identifies bars where the body range achieves a new high over

Indicator v5 Volatility & bandsCandlestick patterns
Updated 1 year ago · None stated GitHub repository of Body Mass Indicator

Raschke Patterns

by TradersPost
218 stars

This overlay indicator marks Linda Raschke short-term bar setups on the price chart. It flags Turtle Soup and Turtle Soup plus one false breakouts of a prior extreme, 80-20 bars, inside bars, failed inside-bar breakouts, outside up and down bars, NR4 and NR7 c

Indicator v6 Candlestick patternsBreakout Repaints
Updated 3 months ago · None stated GitHub repository of Raschke Patterns

Five-in-one Strategy

by capissimo
114 stars

Five-in-one Strategy combines five analytical tools into a single price chart overlay: the Dual Thrust Trading Algorithm (DTTA), Semafore, HalfTrend, Nick Rypock Trailing Reverse, and Tweezer or Kangaroo Tail candlestick patterns. It generates trade signals us

Indicator v4 TrendBreakout Repaints
Updated 1 year ago · None stated GitHub repository of Five-in-one Strategy

RSI Div at dVWAP StDev

by cryptorife
75 stars

This indicator marks RSI divergences only when price trades beyond daily VWAP standard-deviation bands. It compares recent RSI extremes with price highs and lows over a lookback window, and it treats a divergence as valid only while RSI stays beyond overbought

Indicator v4 DivergenceOscillators & momentum Repaints
Updated 3 years ago · GPL-3.0 GitHub repository of RSI Div at dVWAP StDev

Force Bar

by milocaetano
48 stars

Force Bar highlights candlesticks directly on the price chart using three distinct body and range criteria: widest range (Biggest), extreme body relative to historical average (Exhaustion), and moderate body relative to historical average (Force). Colors apply

Indicator v5 Candlestick patternsVolatility & bands
Updated 2 days ago · MIT GitHub repository of Force Bar

This indicator builds a momentum score from the rate of change of close, using a lookback that expands or contracts with ATR relative to its standard deviation. It divides that rate of change by price standard deviation, scales the result, and weights it by vo

Indicator v5 Oscillators & momentumVolatility & bands Repaints
Updated 7 weeks ago · None stated GitHub repository of Adaptive Volatility-Adjusted Momentum Score

More indicators

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers