// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ // © BackQuant //@version=6 indicator('Machine Learning RSI 13', 'ML RSI [13]', overlay = false, max_labels_count = 500) // Define Groups const string rsi_g = 'Relative Strength Index' const string ml_t = 'Machine Learning Thresholds' const string opt_ = 'ML Optimization' const string ui = 'UI Settings' // User Inputs // RSI Settings series float src = input.source(close, 'Calculation Source', group = rsi_g, inline = 'X') simple int rsiLength = input.int(14, 'RSI Length', minval = 2, group = rsi_g, inline = 'X') simple bool smooth = input.bool(true, 'Smooth RSI?', group = rsi_g, inline = 'smt') string maType = input.string('Ema', 'Moving Average Type', options = ['SMA', 'Hull', 'Ema', 'Wma', 'DEMA', 'RMA', 'LINREG', 'TEMA', 'ALMA', 'T3'], group = rsi_g, inline = 'smt') simple int smoothP = input.int(4, 'Smoothing Period', group = rsi_g) simple int sig = input.int(6, 'Sigma for ALMA', group = rsi_g, tooltip = 'this is only used if the ALMA is choosen in the Moving Average Type Input') // Machine Learning Thresholding Settings simple int minThresh = input.int(10, 'Threshold Range Min', inline = 'thresh', group = ml_t) simple int maxThresh = input.int(90, 'Max', inline = 'thresh', group = ml_t) simple int step = input.int(5, 'Step', inline = 'thresh', group = ml_t) // Optimization Settings simple float perfAlpha = input.float(10, 'Performance Memory', minval = 2, tooltip = 'controls the weighting of past data or the smoothness of calculations.', group = opt_) simple int maxIter = input.int(1000, 'Max Clustering Steps', group = opt_) simple int maxData = input.int(3000, 'Max Data Points', group = opt_) // UI Settings simple bool showthres = input.bool(true, 'Show Threshold Lines?', group = ui) simple bool paintCandles = input.bool(false, 'Color Bars According to Trend?', group = ui) simple bool showSegments = input.bool(true, 'Show RSI Segments?', group = ui) simple bool showCounting = input.bool(true, 'Show Segment Counting?', group = ui) int linew = input.int(3, 'Signal Line Width', 1, 4, 1, group = ui) color longcol = input.color(#00ff00, 'Long Colour', group = ui, inline = 'xxxx') color shortcol = input.color(#ff0000, 'Short Colour', group = ui, inline = 'xxxx') color neucol = input.color(color.gray, 'Neutral Colour', group = ui) color bgCol = input.color(color.new(color.white, 0), 'Pane Background Color', group = ui) bgcolor(bgCol) // Custom DEMA function dema(src, length) => ema1 = ta.ema(src, length) ema2 = ta.ema(ema1, length) 2 * ema1 - ema2 // Custom TEMA function (Triple Exponential Moving Average) tema(src, length) => ema1 = ta.ema(src, length) ema2 = ta.ema(ema1, length) ema3 = ta.ema(ema2, length) 3 * ema1 - 3 * ema2 + ema3 // Custom T3 function (Tim Tillson's T3) t3(src, length, vfactor) => ema1 = ta.ema(src, length) ema2 = ta.ema(ema1, length) ema3 = ta.ema(ema2, length) ema4 = ta.ema(ema3, length) ema5 = ta.ema(ema4, length) ema6 = ta.ema(ema5, length) c1 = -vfactor * vfactor * vfactor c2 = 3 * vfactor * vfactor + 3 * vfactor * vfactor * vfactor c3 = -6 * vfactor * vfactor - 3 * vfactor - 3 * vfactor * vfactor * vfactor c4 = 1 + 3 * vfactor + vfactor * vfactor * vfactor + 3 * vfactor * vfactor c1 * ema6 + c2 * ema5 + c3 * ema4 + c4 * ema3 // MA Function ma(src, len, type, almaSig) => switch type 'SMA' => ta.sma(src, len) 'Hull' => ta.hma(src, len) 'Ema' => ta.ema(src, len) 'Wma' => ta.wma(src, len) 'DEMA' => dema(src, len) 'RMA' => ta.rma(src, len) 'LINREG' => ta.linreg(src, len, 0) 'TEMA' => tema(src, len) 'ALMA' => ta.alma(src, len, 0, almaSig) 'T3' => t3(src, len, 0.7) // Calculate RSI rsi = ta.rsi(src, rsiLength) // Smooth? if smooth == true rsi := ma(rsi, smoothP, maType, sig) rsi // Populate threshold array var factors = array.new_float(0) if barstate.isfirst for i = minThresh to maxThresh by step array.push(factors, i) // Clustering for RSI var rsi_values = array.new_float(0) if last_bar_index - bar_index <= maxData array.push(rsi_values, rsi) var centroids = array.new_float(3) if array.size(rsi_values) > 3 array.set(centroids, 0, array.percentile_linear_interpolation(rsi_values, 25)) array.set(centroids, 1, array.percentile_linear_interpolation(rsi_values, 50)) array.set(centroids, 2, array.percentile_linear_interpolation(rsi_values, 75)) // Initialize clusters var cluster1 = array.new_float(0) var cluster2 = array.new_float(0) var cluster3 = array.new_float(0) // Function to compare two arrays f_arrays_equal(arr1, arr2) => if array.size(arr1) != array.size(arr2) false else all_equal = true for i = 0 to array.size(arr1) - 1 by 1 if array.get(arr1, i) != array.get(arr2, i) all_equal := false break all_equal for _ = 0 to maxIter by 1 // Reset clusters at each iteration cluster1 := array.new_float(0) cluster2 := array.new_float(0) cluster3 := array.new_float(0) for value in rsi_values distances = array.new_float(3) for centroid in centroids array.push(distances, math.abs(value - centroid)) idx = array.indexof(distances, array.min(distances)) if idx == 0 array.push(cluster1, value) else if idx == 1 array.push(cluster2, value) else array.push(cluster3, value) // Update centroids new_centroids = array.new_float(3) array.push(new_centroids, array.avg(cluster1)) array.push(new_centroids, array.avg(cluster2)) array.push(new_centroids, array.avg(cluster3)) if f_arrays_equal(new_centroids, centroids) break centroids := new_centroids centroids // Dynamic thresholds long_S = array.get(centroids, 2) short_S = array.get(centroids, 0) // RSI Segmentation and Counting Logic var int rsi_state = 0 // 0 = neutral, 1 = overbought, -1 = oversold var int prev_rsi_state = 0 // 添加前一个状态的追踪 var int extreme_type = 0 // 1 = overbought type, -1 = oversold type, 0 = no extreme var int segment_count = 0 // current count for the extreme type // Alert trigger variables var bool overbought_repeat_alert = false var bool oversold_repeat_alert = false var bool overbought_mark2_alert = false // NEW: specific alert for mark 2 var bool oversold_mark2_alert = false // NEW: specific alert for mark -2 // Determine current RSI state current_state = rsi > long_S ? 1 : rsi < short_S ? -1 : 0 // Track state changes and update counting if current_state != rsi_state and not na(rsi) // 确定分段线颜色 segment_color = color.black // 默认颜色 if prev_rsi_state == 0 and current_state == 1 segment_color := color.new(color.red, 0) // 从中性区进入超买区 - 红色 else if prev_rsi_state == 0 and current_state == -1 segment_color := color.new(color.blue, 0) // 从中性区进入超卖区 - 蓝色 else if prev_rsi_state == 1 and current_state == 0 segment_color := color.new(color.orange, 0) // 从超买区进入中性区 - 橙色 else if prev_rsi_state == -1 and current_state == 0 segment_color := color.new(color.green, 0) // 从超卖区进入中性区 - 绿色 else if prev_rsi_state == 1 and current_state == -1 segment_color := color.new(color.purple, 0) // 从超买区直接到超卖区 - 紫色 else if prev_rsi_state == -1 and current_state == 1 segment_color := color.new(color.yellow, 0) // 从超卖区直接到超买区 - 黄色 else if prev_rsi_state == 1 and current_state == 1 segment_color := color.new(color.maroon, 0) // 超买区内的重复进入 - 深红色 else if prev_rsi_state == -1 and current_state == -1 segment_color := color.new(color.navy, 0) // 超卖区内的重复进入 - 深蓝色 // Draw vertical line at state transition points with color coding if showSegments line.new(bar_index, 0, bar_index, 100, color = segment_color, width = 2, // 增加线宽以便更好地看到颜色 style = line.style_solid, extend = extend.none) // 更新前一个状态 prev_rsi_state := rsi_state // Reset alert triggers overbought_repeat_alert := false oversold_repeat_alert := false overbought_mark2_alert := false // NEW: reset specific mark alerts oversold_mark2_alert := false // NEW: reset specific mark alerts // Update counting logic if current_state == 1 // Entering overbought if extreme_type != 1 // If previous extreme type was not overbought extreme_type := 1 segment_count := 1 // Reset to 1 else // Same extreme type, increment segment_count := segment_count + 1 // Check for repeat alert trigger (count >= 2) if segment_count >= 2 overbought_repeat_alert := true // NEW: Check for specific mark 2 alert if segment_count == 2 overbought_mark2_alert := true // Display count label if showCounting label.new(bar_index, rsi, text = str.tostring(segment_count), style = label.style_label_down, color = longcol, textcolor = color.white, size = size.small) else if current_state == -1 // Entering oversold if extreme_type != -1 // If previous extreme type was not oversold extreme_type := -1 segment_count := -1 // Reset to -1 else // Same extreme type, decrement segment_count := segment_count - 1 // Check for repeat alert trigger (count <= -2) if segment_count <= -2 oversold_repeat_alert := true // NEW: Check for specific mark -2 alert if segment_count == -2 oversold_mark2_alert := true // Display count label if showCounting label.new(bar_index, rsi, text = str.tostring(segment_count), style = label.style_label_up, color = shortcol, textcolor = color.white, size = size.small) // Update state rsi_state := current_state // RSI变化计算 - 计算RSI相对于前一个K线的变化 rsi_change = not na(rsi[1]) ? rsi - rsi[1] : 0 rsi_direction = rsi_change > 0 ? "升高" : rsi_change < 0 ? "降低" : "持平" rsi_change_value = str.tostring(rsi_change, '#.##') // Create plot outputs for alert messages plot(segment_count, 'Segment Count', display = display.none) plot(overbought_repeat_alert ? 1 : 0, 'Overbought Repeat', display = display.none) plot(oversold_repeat_alert ? 1 : 0, 'Oversold Repeat', display = display.none) plot(overbought_mark2_alert ? 1 : 0, 'Overbought Mark2', display = display.none) // NEW plot(oversold_mark2_alert ? 1 : 0, 'Oversold Mark2', display = display.none) // NEW plot(rsi_change, 'RSI Change', display = display.none) // 添加RSI变化的plot输出 // Cluster plotting arrays var float cluster1_plot = na var float cluster2_plot = na var float cluster3_plot = na if not na(rsi) distances = array.new_float(3) for centroid in centroids array.push(distances, math.abs(rsi - centroid)) idx = array.indexof(distances, array.min(distances)) cluster1_plot := idx == 0 ? rsi : na cluster2_plot := idx == 1 ? rsi : na cluster3_plot := idx == 2 ? rsi : na cluster3_plot // --- Visualization --- col = rsi > long_S ? longcol : rsi < short_S ? shortcol : neucol plot(rsi, 'RSI', color = col, linewidth = math.max(1, linew)) // Main RSI line // Dynamic thresholds via Machine Learning plot(showthres ? long_S : na, 'Long ML Threshold', color = longcol) plot(showthres ? short_S : na, 'Short ML Threshold', color = shortcol) // Plot RSI values in clusters plot(cluster1_plot, 'Cluster 1', color = color.green, linewidth = 2, style = plot.style_circles) plot(cluster2_plot, 'Cluster 2', color = color.orange, linewidth = 2, style = plot.style_circles) plot(cluster3_plot, 'Cluster 3', color = color.red, linewidth = 2, style = plot.style_circles) barcolor(paintCandles ? col : na) // ===== 统一警报系统 ===== // 统一警报系统 - 只需添加一次警报即可捕获所有信号 // 警报频率限制 - 每分钟只触发一次 var int last_alert_rsi_buy = 0 var int last_alert_rsi_sell = 0 var int last_alert_rsi_neutral_from_ob = 0 var int last_alert_rsi_neutral_from_os = 0 var int last_alert_overbought_repeat = 0 var int last_alert_oversold_repeat = 0 var int last_alert_overbought_mark2 = 0 var int last_alert_oversold_mark2 = 0 var int last_alert_rsi_overbought = 0 var int last_alert_rsi_oversold = 0 var int last_alert_rsi_neutral = 0 // 获取当前时间(分钟级别) current_minute = math.floor(timenow / 60000) // 检测所有警报条件并生成对应的JSON消息 alert_message = "" // 基础穿越信号 - 每分钟限制 if ta.crossover(rsi, long_S) and current_minute > last_alert_rsi_buy alert_message := '{"指标名称":"RSI","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","RSI":"' + str.tostring(rsi, '#.##') + '","Long ML Threshold":"' + str.tostring(long_S, '#.##') + '","事件":"RSI 已上穿多头ML阈值 - 潜在买入信号","信号":"buy"}' alert(alert_message, alert.freq_once_per_bar_close) last_alert_rsi_buy := current_minute if ta.crossunder(rsi, short_S) and current_minute > last_alert_rsi_sell alert_message := '{"指标名称":"RSI","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","RSI":"' + str.tostring(rsi, '#.##') + '","Short ML Threshold":"' + str.tostring(short_S, '#.##') + '","事件":"RSI 已下穿空头ML阈值 - 潜在卖出信号","信号":"sell"}' alert(alert_message, alert.freq_once_per_bar_close) last_alert_rsi_sell := current_minute // 区域转换信号 - 每分钟限制 // if ta.crossunder(rsi, long_S) and current_minute > last_alert_rsi_neutral_from_ob // alert_message := '{"指标名称":"RSI","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","RSI":"' + str.tostring(rsi, '#.##') + '","Long ML Threshold":"' + str.tostring(long_S, '#.##') + '","事件":"RSI 已下穿多头ML阈值进入中性区","备注":"进入震荡"}' // alert(alert_message, alert.freq_once_per_bar_close) // last_alert_rsi_neutral_from_ob := current_minute // if ta.crossover(rsi, short_S) and current_minute > last_alert_rsi_neutral_from_os // alert_message := '{"指标名称":"RSI","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","RSI":"' + str.tostring(rsi, '#.##') + '","Short ML Threshold":"' + str.tostring(short_S, '#.##') + '","事件":"RSI 已上穿空头ML阈值进入中性区","备注":"进入震荡"}' // alert(alert_message, alert.freq_once_per_bar_close) // last_alert_rsi_neutral_from_os := current_minute // 重复进入信号 - 每分钟限制 if overbought_repeat_alert and current_minute > last_alert_overbought_repeat alert_message := '{"指标名称":"RSI","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","RSI":"' + str.tostring(rsi, '#.##') + '","Long ML Threshold":"' + str.tostring(long_S, '#.##') + '","事件":"RSI 重复进入超买区","标记":"' + str.tostring(segment_count) + '","信号":"overbought_repeat","警告":"大于和等于2次超买信号"}' alert(alert_message, alert.freq_once_per_bar_close) last_alert_overbought_repeat := current_minute if oversold_repeat_alert and current_minute > last_alert_oversold_repeat alert_message := '{"指标名称":"RSI","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","RSI":"' + str.tostring(rsi, '#.##') + '","Short ML Threshold":"' + str.tostring(short_S, '#.##') + '","事件":"RSI 重复进入超卖区","标记":"' + str.tostring(segment_count) + '","信号":"oversold_repeat","警告":"大于和等于2次超卖信号"}' alert(alert_message, alert.freq_once_per_bar_close) last_alert_oversold_repeat := current_minute // 特定标记信号 - 每分钟限制 if overbought_mark2_alert and current_minute > last_alert_overbought_mark2 alert_message := '{"指标名称":"RSI","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","RSI":"' + str.tostring(rsi, '#.##') + '","Long ML Threshold":"' + str.tostring(long_S, '#.##') + '","事件":"RSI 第二次进入超买区","标记":"2","信号":"overbought_mark2","警告":"二次超买信号"}' alert(alert_message, alert.freq_once_per_bar_close) last_alert_overbought_mark2 := current_minute if oversold_mark2_alert and current_minute > last_alert_oversold_mark2 alert_message := '{"指标名称":"RSI","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","RSI":"' + str.tostring(rsi, '#.##') + '","Short ML Threshold":"' + str.tostring(short_S, '#.##') + '","事件":"RSI 第二次进入超卖区","标记":"-2","信号":"oversold_mark2","警告":"二次超卖信号"}' alert(alert_message, alert.freq_once_per_bar_close) last_alert_oversold_mark2 := current_minute // RSI状态警报 - 每分钟限制 if rsi > long_S and current_minute > last_alert_rsi_overbought alert_message := '{"指标名称":"RSI","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","RSI":"' + str.tostring(rsi, '#.##') + '","超买阈值":"' + str.tostring(long_S, '#.##') + '","事件":"RSI处于超买状态","RSI变化":"' + rsi_direction + '","RSI变化值":"' + rsi_change_value + '","标记":"' + str.tostring(segment_count) + '","信号":"rsi_overbought","备注":"RSI高于超买线"}' alert(alert_message, alert.freq_once_per_bar) last_alert_rsi_overbought := current_minute if rsi < short_S and current_minute > last_alert_rsi_oversold alert_message := '{"指标名称":"RSI","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","RSI":"' + str.tostring(rsi, '#.##') + '","超卖阈值":"' + str.tostring(short_S, '#.##') + '","事件":"RSI处于超卖状态","RSI变化":"' + rsi_direction + '","RSI变化值":"' + rsi_change_value + '","标记":"' + str.tostring(segment_count) + '","信号":"rsi_oversold","备注":"RSI低于超卖线"}' alert(alert_message, alert.freq_once_per_bar) last_alert_rsi_oversold := current_minute // if rsi < long_S and rsi > short_S and current_minute > last_alert_rsi_neutral // alert_message := '{"指标名称":"RSI","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","RSI":"' + str.tostring(rsi, '#.##') + '","Long ML Threshold":"' + str.tostring(long_S, '#.##') + '","Short ML Threshold":"' + str.tostring(short_S, '#.##') + '","事件":"RSI 处于中性区","备注":"震荡"}' // alert(alert_message, alert.freq_once_per_bar) // last_alert_rsi_neutral := current_minute // ===== 传统警报条件(保留兼容性)===== // 注意:使用统一警报系统时,建议只使用上面的alert()函数 // 以下alertcondition保留用于需要单独设置警报的情况 // 创建用于警报的plot变量 plot(rsi, title = 'RSI值', display = display.none) plot(long_S, title = 'Long ML Threshold', display = display.none) plot(short_S, title = 'Short ML Threshold', display = display.none) // 基础穿越信号警报 alertcondition(ta.crossover(rsi, long_S), title = 'RSI上穿多头ML阈值', message = '{"指标名称":"RSI","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI值")}}","Long ML Threshold":"{{plot("Long ML Threshold")}}","事件":"RSI 已上穿多头ML阈值 - 潜在买入信号","信号":"buy"}') alertcondition(ta.crossunder(rsi, short_S), title = 'RSI下穿空头ML阈值', message = '{"指标名称":"RSI","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI值")}}","Short ML Threshold":"{{plot("Short ML Threshold")}}","事件":"RSI 已下穿空头ML阈值 - 潜在卖出信号","信号":"sell"}') // 区域转换信号警报 // alertcondition(ta.crossunder(rsi, long_S), title = 'RSI下穿多头ML阈值进入中性区', message = '{"指标名称":"RSI","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI值")}}","Long ML Threshold":"{{plot("Long ML Threshold")}}","事件":"RSI 已下穿多头ML阈值进入中性区","备注":"进入震荡","信号":"neutral_from_overbought"}') // alertcondition(ta.crossover(rsi, short_S), title = 'RSI上穿空头ML阈值进入中性区', message = '{"指标名称":"RSI","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI值")}}","Short ML Threshold":"{{plot("Short ML Threshold")}}","事件":"RSI 已上穿空头ML阈值进入中性区","备注":"进入震荡","信号":"neutral_from_oversold"}') // 重复进入信号警报 alertcondition(overbought_repeat_alert, title = 'RSI重复进入超买区', message = '{"指标名称":"RSI","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI值")}}","Long ML Threshold":"{{plot("Long ML Threshold")}}","事件":"RSI 重复进入超买区","标记":"{{plot("Segment Count")}}","信号":"overbought_repeat","警告":"大于和等于2次超买信号"}') alertcondition(oversold_repeat_alert, title = 'RSI重复进入超卖区', message = '{"指标名称":"RSI","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI值")}}","Short ML Threshold":"{{plot("Short ML Threshold")}}","事件":"RSI 重复进入超卖区","标记":"{{plot("Segment Count")}}","信号":"oversold_repeat","警告":"大于和等于2次超卖信号"}') // 特定标记信号警报 alertcondition(overbought_mark2_alert, title = 'RSI第二次进入超买区', message = '{"指标名称":"RSI","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI值")}}","Long ML Threshold":"{{plot("Long ML Threshold")}}","事件":"RSI 第二次进入超买区","标记":"2","信号":"overbought_mark2","警告":"二次超买信号"}') alertcondition(oversold_mark2_alert, title = 'RSI第二次进入超卖区', message = '{"指标名称":"RSI","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI值")}}","Short ML Threshold":"{{plot("Short ML Threshold")}}","事件":"RSI 第二次进入超卖区","标记":"-2","信号":"oversold_mark2","警告":"二次超卖信号"}') // RSI状态警报 alertcondition(rsi > long_S, title = 'RSI处于超买状态', message = '{"指标名称":"RSI","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI值")}}","超买阈值":"{{plot("Long ML Threshold")}}","事件":"RSI处于超买状态","标记":"{{plot("Segment Count")}}","信号":"rsi_overbought","备注":"RSI高于超买线"}') alertcondition(rsi < short_S, title = 'RSI处于超卖状态', message = '{"指标名称":"RSI","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI值")}}","超卖阈值":"{{plot("Short ML Threshold")}}","事件":"RSI处于超卖状态","标记":"{{plot("Segment Count")}}","信号":"rsi_oversold","备注":"RSI低于超卖线"}') alertcondition(rsi < long_S and rsi > short_S, title = 'RSI处于中性区', message = '{"指标名称":"RSI","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI值")}}","Long ML Threshold":"{{plot("Long ML Threshold")}}","Short ML Threshold":"{{plot("Short ML Threshold")}}","事件":"RSI 处于中性区","备注":"震荡","信号":"rsi_neutral"}') // 传统RSI阈值警报(70/30) // alertcondition(ta.crossover(rsi, 70), title = 'RSI上穿70', message = '{"指标名称":"RSI","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI值")}}","阈值":"70","事件":"RSI上穿70","信号":"rsi_70_cross_up","备注":"传统超买信号"}') // alertcondition(ta.crossunder(rsi, 30), title = 'RSI下穿30', message = '{"指标名称":"RSI","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI值")}}","阈值":"30","事件":"RSI下穿30","信号":"rsi_30_cross_down","备注":"传统超卖信号"}') // alertcondition(ta.crossunder(rsi, 70), title = 'RSI下穿70', message = '{"指标名称":"RSI","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI值")}}","阈值":"70","事件":"RSI下穿70","信号":"rsi_70_cross_down","备注":"从超买区回落"}') // alertcondition(ta.crossover(rsi, 30), title = 'RSI上穿30', message = '{"指标名称":"RSI","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI值")}}","阈值":"30","事件":"RSI上穿30","信号":"rsi_30_cross_up","备注":"从超卖区反弹"}') // // RSI中线穿越警报(50) // alertcondition(ta.crossover(rsi, 50), title = 'RSI上穿50', message = '{"指标名称":"RSI","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI值")}}","中线":"50","事件":"RSI上穿50","信号":"rsi_50_cross_up","备注":"多头信号"}') // alertcondition(ta.crossunder(rsi, 50), title = 'RSI下穿50', message = '{"指标名称":"RSI","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI值")}}","中线":"50","事件":"RSI下穿50","信号":"rsi_50_cross_down","备注":"空头信号"}')