// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ // © BackQuant - Optimized Version //@version=6 indicator('Optimized ML RSI Pro', 'ML RSI Pro', overlay = false, max_labels_count = 500) // ===== PARAMETER GROUPS ===== const string rsi_g = 'RSI Settings' const string ml_g = 'Machine Learning' const string opt_g = 'Optimization' const string filter_g = 'Signal Filters' const string ui_g = 'UI & Alerts' const string preset_g = 'Preset Modes' // ===== PRESET MODES ===== string preset_mode = input.string('Custom', 'Preset Mode', options = ['Conservative', 'Balanced', 'Aggressive', 'Custom'], group = preset_g, tooltip = 'Choose a preset or use Custom for manual settings') // ===== RSI SETTINGS ===== series float src = input.source(close, 'Source', group = rsi_g, inline = 'rsi1') simple int rsi_length = input.int(14, 'RSI Length', minval = 2, maxval = 50, group = rsi_g, inline = 'rsi1') simple bool enable_smooth = input.bool(true, 'Enable Smoothing', group = rsi_g, inline = 'smooth1') string ma_type = input.string('EMA', 'MA Type', options = ['SMA', 'EMA', 'RMA', 'WMA', 'HMA'], group = rsi_g, inline = 'smooth1') simple int smooth_length = input.int(3, 'Smooth Length', minval = 2, maxval = 10, group = rsi_g) // ===== MACHINE LEARNING SETTINGS ===== simple int lookback_bars = input.int(500, 'Lookback Period', minval = 100, maxval = 2000, group = ml_g, tooltip = 'Number of bars for ML analysis (reduced from 3000 for better performance)') simple int update_frequency = input.int(5, 'Update Every N Bars', minval = 1, maxval = 20, group = ml_g, tooltip = 'Update ML thresholds every N bars to improve performance') simple int max_iterations = input.int(50, 'Max Iterations', minval = 10, maxval = 200, group = ml_g, tooltip = 'Maximum clustering iterations (reduced from 1000)') simple float convergence_threshold = input.float(0.1, 'Convergence Threshold', minval = 0.01, maxval = 1.0, group = ml_g, tooltip = 'Stop clustering when centroids change less than this value') // ===== OPTIMIZATION SETTINGS ===== simple bool enable_outlier_filter = input.bool(true, 'Filter Outliers', group = opt_g) simple float outlier_threshold = input.float(2.0, 'Outlier Threshold (Std Dev)', minval = 1.0, maxval = 3.0, group = opt_g) simple bool enable_weighted_data = input.bool(true, 'Weight Recent Data', group = opt_g) simple float weight_decay = input.float(0.95, 'Weight Decay Factor', minval = 0.8, maxval = 0.99, group = opt_g) // ===== SIGNAL FILTERS ===== simple bool enable_trend_filter = input.bool(true, 'Enable Trend Filter', group = filter_g) simple int trend_length = input.int(50, 'Trend MA Length', minval = 20, maxval = 200, group = filter_g) simple bool enable_volume_filter = input.bool(false, 'Enable Volume Filter', group = filter_g) simple float volume_threshold = input.float(1.2, 'Volume Threshold (x Average)', minval = 0.5, maxval = 3.0, group = filter_g) // ===== UI & ALERT SETTINGS ===== simple bool show_thresholds = input.bool(true, 'Show Threshold Lines', group = ui_g) simple bool show_signals = input.bool(true, 'Show Signal Markers', group = ui_g) simple bool show_statistics = input.bool(false, 'Show Statistics Table', group = ui_g) simple bool enable_alerts = input.bool(true, 'Enable Alerts', group = ui_g) color bull_color = input.color(#00ff88, 'Bull Color', group = ui_g, inline = 'colors') color bear_color = input.color(#ff4444, 'Bear Color', group = ui_g, inline = 'colors') color neutral_color = input.color(#888888, 'Neutral Color', group = ui_g, inline = 'colors') // ===== PRESET CONFIGURATIONS ===== [preset_lookback, preset_update_freq, preset_max_iter, preset_conv_thresh] = switch preset_mode 'Conservative' => [800, 10, 30, 0.2] 'Balanced' => [500, 5, 50, 0.1] 'Aggressive' => [300, 3, 80, 0.05] => [lookback_bars, update_frequency, max_iterations, convergence_threshold] // Apply preset values if not custom mode final_lookback = preset_mode != 'Custom' ? preset_lookback : lookback_bars final_update_freq = preset_mode != 'Custom' ? preset_update_freq : update_frequency final_max_iter = preset_mode != 'Custom' ? preset_max_iter : max_iterations final_conv_thresh = preset_mode != 'Custom' ? preset_conv_thresh : convergence_threshold // ===== HELPER FUNCTIONS ===== // Enhanced Moving Average Function f_ma(src, length, ma_type) => switch ma_type 'SMA' => ta.sma(src, length) 'EMA' => ta.ema(src, length) 'RMA' => ta.rma(src, length) 'WMA' => ta.wma(src, length) 'HMA' => ta.hma(src, length) => ta.ema(src, length) // Outlier Detection Function f_is_outlier(value, data_array, threshold) => if array.size(data_array) < 10 false else mean_val = array.avg(data_array) std_dev = array.stdev(data_array) math.abs(value - mean_val) > threshold * std_dev // Weighted Average Function f_weighted_avg(data_array, weight_decay) => if array.size(data_array) == 0 na else weighted_sum = 0.0 weight_sum = 0.0 size = array.size(data_array) for i = 0 to size - 1 weight = math.pow(weight_decay, size - 1 - i) weighted_sum := weighted_sum + array.get(data_array, i) * weight weight_sum := weight_sum + weight weighted_sum / weight_sum // Enhanced K-means Clustering Function f_enhanced_kmeans(data_array, max_iter, conv_thresh) => size = array.size(data_array) if size < 10 [na, na, na] else // Initialize centroids using percentiles c1 = array.percentile_linear_interpolation(data_array, 20) c2 = array.percentile_linear_interpolation(data_array, 50) c3 = array.percentile_linear_interpolation(data_array, 80) // Iterative clustering with early convergence for iteration = 0 to max_iter - 1 cluster1 = array.new_float() cluster2 = array.new_float() cluster3 = array.new_float() // Assign points to clusters for i = 0 to size - 1 value = array.get(data_array, i) d1 = math.abs(value - c1) d2 = math.abs(value - c2) d3 = math.abs(value - c3) if d1 <= d2 and d1 <= d3 array.push(cluster1, value) else if d2 <= d3 array.push(cluster2, value) else array.push(cluster3, value) // Calculate new centroids new_c1 = array.size(cluster1) > 0 ? (enable_weighted_data ? f_weighted_avg(cluster1, weight_decay) : array.avg(cluster1)) : c1 new_c2 = array.size(cluster2) > 0 ? (enable_weighted_data ? f_weighted_avg(cluster2, weight_decay) : array.avg(cluster2)) : c2 new_c3 = array.size(cluster3) > 0 ? (enable_weighted_data ? f_weighted_avg(cluster3, weight_decay) : array.avg(cluster3)) : c3 // Check convergence if math.abs(new_c1 - c1) < conv_thresh and math.abs(new_c2 - c2) < conv_thresh and math.abs(new_c3 - c3) < conv_thresh break c1 := new_c1 c2 := new_c2 c3 := new_c3 [c1, c2, c3] // ===== MAIN CALCULATIONS ===== // Calculate RSI rsi_raw = ta.rsi(src, rsi_length) rsi = enable_smooth ? f_ma(rsi_raw, smooth_length, ma_type) : rsi_raw // Data collection with performance optimization var rsi_data = array.new_float() var int last_update_bar = 0 // Update data array periodically if bar_index % final_update_freq == 0 or barstate.islast // Add current RSI value if not na(rsi) // Apply outlier filter if enabled if enable_outlier_filter and f_is_outlier(rsi, rsi_data, outlier_threshold) // Skip outlier na else array.push(rsi_data, rsi) // Maintain data size while array.size(rsi_data) > final_lookback array.shift(rsi_data) last_update_bar := bar_index // Calculate dynamic thresholds using enhanced clustering [oversold_threshold, neutral_center, overbought_threshold] = f_enhanced_kmeans(rsi_data, final_max_iter, final_conv_thresh) // Fallback to traditional levels if clustering fails final_oversold = na(oversold_threshold) ? 30 : oversold_threshold final_overbought = na(overbought_threshold) ? 70 : overbought_threshold // ===== SIGNAL GENERATION ===== // Basic signals rsi_oversold = rsi < final_oversold rsi_overbought = rsi > final_overbought rsi_neutral = not rsi_oversold and not rsi_overbought // ===== RSI SEGMENTATION AND COUNTING LOGIC (from original) ===== 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 var bool oversold_mark2_alert = false // Determine current RSI state current_state = rsi > final_overbought ? 1 : rsi < final_oversold ? -1 : 0 // Track state changes and update counting if current_state != rsi_state and not na(rsi) // Update previous state prev_rsi_state := rsi_state // Reset alert triggers overbought_repeat_alert := false oversold_repeat_alert := false overbought_mark2_alert := false oversold_mark2_alert := false // 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 // Check for specific mark 2 alert if segment_count == 2 overbought_mark2_alert := true // Display count label if show_signals label.new(bar_index, rsi, text = str.tostring(segment_count), style = label.style_label_down, color = bear_color, 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 // Check for specific mark -2 alert if segment_count == -2 oversold_mark2_alert := true // Display count label if show_signals label.new(bar_index, rsi, text = str.tostring(segment_count), style = label.style_label_up, color = bull_color, textcolor = color.white, size = size.small) // Update state rsi_state := current_state // Enhanced signals with filters trend_ma = f_ma(close, trend_length, 'EMA') is_uptrend = enable_trend_filter ? close > trend_ma : true is_downtrend = enable_trend_filter ? close < trend_ma : true volume_avg = ta.sma(volume, 20) is_high_volume = enable_volume_filter ? volume > volume_threshold * volume_avg : true // Final filtered signals buy_signal = ta.crossover(rsi, final_oversold) and is_uptrend and is_high_volume sell_signal = ta.crossunder(rsi, final_overbought) and is_downtrend and is_high_volume // ===== VISUALIZATION ===== // RSI line with dynamic coloring rsi_color = rsi_overbought ? bear_color : rsi_oversold ? bull_color : neutral_color plot(rsi, 'RSI', color = rsi_color, linewidth = 2) // Dynamic threshold lines plot(show_thresholds ? final_overbought : na, 'Overbought', color = bear_color, style = plot.style_line) plot(show_thresholds ? final_oversold : na, 'Oversold', color = bull_color, style = plot.style_line) plot(show_thresholds and not na(neutral_center) ? neutral_center : na, 'Neutral', color = neutral_color, style = plot.style_line) // Signal markers plotshape(show_signals and buy_signal, 'Buy Signal', shape.triangleup, location.bottom, bull_color, size = size.small) plotshape(show_signals and sell_signal, 'Sell Signal', shape.triangledown, location.top, bear_color, size = size.small) // Reference lines hline(50, 'Midline', color = color.gray, linestyle = hline.style_solid) hline(70, 'Traditional OB', color = color.new(color.red, 50), linestyle = hline.style_dotted) hline(30, 'Traditional OS', color = color.new(color.green, 50), linestyle = hline.style_dotted) // ===== STATISTICS TABLE ===== if show_statistics and barstate.islast var table stats_table = table.new(position.top_right, 2, 6, bgcolor = color.white, border_width = 1) table.cell(stats_table, 0, 0, 'Metric', text_color = color.black, bgcolor = color.gray) table.cell(stats_table, 1, 0, 'Value', text_color = color.black, bgcolor = color.gray) table.cell(stats_table, 0, 1, 'Current RSI', text_color = color.black) table.cell(stats_table, 1, 1, str.tostring(rsi, '#.##'), text_color = color.black) table.cell(stats_table, 0, 2, 'Oversold Level', text_color = color.black) table.cell(stats_table, 1, 2, str.tostring(final_oversold, '#.##'), text_color = color.black) table.cell(stats_table, 0, 3, 'Overbought Level', text_color = color.black) table.cell(stats_table, 1, 3, str.tostring(final_overbought, '#.##'), text_color = color.black) table.cell(stats_table, 0, 4, 'Data Points', text_color = color.black) table.cell(stats_table, 1, 4, str.tostring(array.size(rsi_data)), text_color = color.black) table.cell(stats_table, 0, 5, 'Mode', text_color = color.black) table.cell(stats_table, 1, 5, preset_mode, text_color = color.black) // ===== ADVANCED FEATURES (moved before alerts) ===== // Multi-timeframe RSI analysis rsi_htf = request.security(syminfo.tickerid, '1D', rsi, lookahead = barmerge.lookahead_off) htf_trend = rsi_htf > 50 ? 1 : rsi_htf < 50 ? -1 : 0 // Divergence Detection Functions f_find_pivot_high(src, length) => ph = ta.pivothigh(src, length, length) ph f_find_pivot_low(src, length) => pl = ta.pivotlow(src, length, length) pl // Divergence variables var float last_high_price = na var float last_high_rsi = na var float last_low_price = na var float last_low_rsi = na var int last_high_bar = na var int last_low_bar = na // Calculate pivot points on each bar for consistency pivot_high = f_find_pivot_high(close, 5) pivot_low = f_find_pivot_low(close, 5) // Update pivot points if not na(pivot_high) last_high_price := pivot_high last_high_rsi := rsi[5] last_high_bar := bar_index[5] if not na(pivot_low) last_low_price := pivot_low last_low_rsi := rsi[5] last_low_bar := bar_index[5] // Detect divergences bullish_divergence = not na(last_low_price) and not na(last_low_rsi) and close < last_low_price and rsi > last_low_rsi and bar_index - last_low_bar < 50 bearish_divergence = not na(last_high_price) and not na(last_high_rsi) and close > last_high_price and rsi < last_high_rsi and bar_index - last_high_bar < 50 // RSI Momentum and Velocity rsi_momentum = rsi - rsi[1] rsi_velocity = rsi_momentum - rsi_momentum[1] rsi_acceleration = rsi_velocity - rsi_velocity[1] // Dynamic position sizing based on RSI strength rsi_strength = math.abs(rsi - 50) / 50 position_size_factor = rsi_strength > 0.4 ? 1.5 : rsi_strength > 0.2 ? 1.0 : 0.5 // Enhanced signal scoring system signal_score = 0.0 if buy_signal signal_score := signal_score + 3.0 // Base signal signal_score := htf_trend == 1 ? signal_score + 1.0 : signal_score // HTF alignment signal_score := bullish_divergence ? signal_score + 2.0 : signal_score // Divergence signal_score := rsi_momentum > 0 ? signal_score + 0.5 : signal_score // Momentum signal_score := rsi_velocity > 0 ? signal_score + 0.5 : signal_score // Acceleration if sell_signal signal_score := signal_score - 3.0 // Base signal signal_score := htf_trend == -1 ? signal_score - 1.0 : signal_score // HTF alignment signal_score := bearish_divergence ? signal_score - 2.0 : signal_score // Divergence signal_score := rsi_momentum < 0 ? signal_score - 0.5 : signal_score // Momentum signal_score := rsi_velocity < 0 ? signal_score - 0.5 : signal_score // Acceleration // Signal quality classification signal_quality = math.abs(signal_score) > 5 ? 'Strong' : math.abs(signal_score) > 3 ? 'Medium' : math.abs(signal_score) > 1 ? 'Weak' : 'None' // ===== UNIFIED ALERT SYSTEM ===== // 统一警报系统 - 只需添加一次警报即可捕获所有信号 // 警报频率限制 - 每分钟只触发一次 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_high_quality_buy = 0 var int last_alert_high_quality_sell = 0 var int last_alert_bullish_divergence = 0 var int last_alert_bearish_divergence = 0 var int last_alert_rsi_overbought = 0 var int last_alert_rsi_oversold = 0 // 获取当前时间(分钟级别) current_minute = math.floor(timenow / 60000) // 检测所有警报条件并生成对应的JSON消息 alert_message = "" // 基础穿越信号 - 每分钟限制 if ta.crossover(rsi, final_overbought) and enable_alerts and current_minute > last_alert_rsi_buy alert_message := '{"指标名称":"ML_RSI_Pro","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","RSI":"' + str.tostring(rsi, '#.##') + '","Long ML Threshold":"' + str.tostring(final_overbought, '#.##') + '","事件":"RSI 已上穿多头ML阈值 - 潜在买入信号","信号":"buy"}' alert(alert_message, alert.freq_once_per_bar_close) last_alert_rsi_buy := current_minute if ta.crossunder(rsi, final_oversold) and enable_alerts and current_minute > last_alert_rsi_sell alert_message := '{"指标名称":"ML_RSI_Pro","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","RSI":"' + str.tostring(rsi, '#.##') + '","Short ML Threshold":"' + str.tostring(final_oversold, '#.##') + '","事件":"RSI 已下穿空头ML阈值 - 潜在卖出信号","信号":"sell"}' alert(alert_message, alert.freq_once_per_bar_close) last_alert_rsi_sell := current_minute // 区域转换信号 - 每分钟限制 // if ta.crossunder(rsi, final_overbought) and enable_alerts and current_minute > last_alert_rsi_neutral_from_ob // alert_message := '{"指标名称":"ML_RSI_Pro","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","RSI":"' + str.tostring(rsi, '#.##') + '","Long ML Threshold":"' + str.tostring(final_overbought, '#.##') + '","事件":"RSI 已下穿多头ML阈值进入中性区","备注":"进入震荡"}' // alert(alert_message, alert.freq_once_per_bar_close) // last_alert_rsi_neutral_from_ob := current_minute // if ta.crossover(rsi, final_oversold) and enable_alerts and current_minute > last_alert_rsi_neutral_from_os // alert_message := '{"指标名称":"ML_RSI_Pro","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","RSI":"' + str.tostring(rsi, '#.##') + '","Short ML Threshold":"' + str.tostring(final_oversold, '#.##') + '","事件":"RSI 已上穿空头ML阈值进入中性区","备注":"进入震荡"}' // alert(alert_message, alert.freq_once_per_bar_close) // last_alert_rsi_neutral_from_os := current_minute // 重复进入信号 - 每分钟限制 if overbought_repeat_alert and enable_alerts and current_minute > last_alert_overbought_repeat alert_message := '{"指标名称":"ML_RSI_Pro","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","RSI":"' + str.tostring(rsi, '#.##') + '","Long ML Threshold":"' + str.tostring(final_overbought, '#.##') + '","事件":"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 enable_alerts and current_minute > last_alert_oversold_repeat alert_message := '{"指标名称":"ML_RSI_Pro","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","RSI":"' + str.tostring(rsi, '#.##') + '","Short ML Threshold":"' + str.tostring(final_oversold, '#.##') + '","事件":"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 enable_alerts and current_minute > last_alert_overbought_mark2 alert_message := '{"指标名称":"ML_RSI_Pro","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","RSI":"' + str.tostring(rsi, '#.##') + '","Long ML Threshold":"' + str.tostring(final_overbought, '#.##') + '","事件":"RSI 第二次进入超买区","标记":"2","信号":"overbought_mark2","警告":"二次超买信号"}' alert(alert_message, alert.freq_once_per_bar_close) last_alert_overbought_mark2 := current_minute if oversold_mark2_alert and enable_alerts and current_minute > last_alert_oversold_mark2 alert_message := '{"指标名称":"ML_RSI_Pro","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","RSI":"' + str.tostring(rsi, '#.##') + '","Short ML Threshold":"' + str.tostring(final_oversold, '#.##') + '","事件":"RSI 第二次进入超卖区","标记":"-2","信号":"oversold_mark2","警告":"二次超卖信号"}' alert(alert_message, alert.freq_once_per_bar_close) last_alert_oversold_mark2 := current_minute // 高级信号 - 每分钟限制 // if buy_signal and signal_score > 4 and enable_alerts and current_minute > last_alert_high_quality_buy // alert_message := '{"指标名称":"ML_RSI_Pro","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","RSI":"' + str.tostring(rsi, '#.##') + '","事件":"高质量买入信号","信号":"high_quality_buy","评分":"' + str.tostring(signal_score, '#.#') + '","备注":"强烈看涨条件"}' // alert(alert_message, alert.freq_once_per_bar_close) // last_alert_high_quality_buy := current_minute // if sell_signal and signal_score < -4 and enable_alerts and current_minute > last_alert_high_quality_sell // alert_message := '{"指标名称":"ML_RSI_Pro","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","RSI":"' + str.tostring(rsi, '#.##') + '","事件":"高质量卖出信号","信号":"high_quality_sell","评分":"' + str.tostring(signal_score, '#.#') + '","备注":"强烈看跌条件"}' // alert(alert_message, alert.freq_once_per_bar_close) // last_alert_high_quality_sell := current_minute // 背离信号 - 每分钟限制 // if bullish_divergence and enable_alerts and current_minute > last_alert_bullish_divergence // alert_message := '{"指标名称":"ML_RSI_Pro","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","RSI":"' + str.tostring(rsi, '#.##') + '","事件":"牛市背离","信号":"bullish_divergence","备注":"价格新低但RSI更高"}' // alert(alert_message, alert.freq_once_per_bar_close) // last_alert_bullish_divergence := current_minute // if bearish_divergence and enable_alerts and current_minute > last_alert_bearish_divergence // alert_message := '{"指标名称":"ML_RSI_Pro","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","RSI":"' + str.tostring(rsi, '#.##') + '","事件":"熊市背离","信号":"bearish_divergence","备注":"价格新高但RSI更低"}' // alert(alert_message, alert.freq_once_per_bar_close) // last_alert_bearish_divergence := current_minute // RSI状态警报 - 计算RSI变化方向 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, '#.##') // RSI处于超买状态警报 - 每分钟限制 if rsi_overbought and enable_alerts and current_minute > last_alert_rsi_overbought alert_message := '{"指标名称":"ML_RSI_Pro","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","RSI":"' + str.tostring(rsi, '#.##') + '","超买阈值":"' + str.tostring(final_overbought, '#.##') + '","事件":"RSI处于超买状态","RSI变化":"' + rsi_direction + '","RSI变化值":"' + rsi_change_value + '","信号":"rsi_overbought","备注":"RSI高于超买线"}' alert(alert_message, alert.freq_once_per_bar) last_alert_rsi_overbought := current_minute // RSI处于超卖状态警报 - 每分钟限制 if rsi_oversold and enable_alerts and current_minute > last_alert_rsi_oversold alert_message := '{"指标名称":"ML_RSI_Pro","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","RSI":"' + str.tostring(rsi, '#.##') + '","超卖阈值":"' + str.tostring(final_oversold, '#.##') + '","事件":"RSI处于超卖状态","RSI变化":"' + rsi_direction + '","RSI变化值":"' + rsi_change_value + '","信号":"rsi_oversold","备注":"RSI低于超卖线"}' alert(alert_message, alert.freq_once_per_bar) last_alert_rsi_oversold := current_minute // (Advanced features moved above alerts section to avoid duplication) // ===== ENHANCED VISUALIZATION ===== // Divergence markers plotshape(bullish_divergence and show_signals, 'Bullish Divergence', shape.diamond, location.bottom, color.lime, size = size.normal, text = 'BD') plotshape(bearish_divergence and show_signals, 'Bearish Divergence', shape.diamond, location.top, color.orange, size = size.normal, text = 'BD') // RSI momentum histogram plot(rsi_momentum * 10, 'RSI Momentum', color = rsi_momentum > 0 ? color.green : color.red, style = plot.style_histogram, histbase = 0, display = display.none) // Background coloring for trend alignment bgcolor(enable_trend_filter and htf_trend == 1 ? color.new(color.green, 95) : enable_trend_filter and htf_trend == -1 ? color.new(color.red, 95) : na, title = 'HTF Trend Background') // ===== PERFORMANCE METRICS ===== var int total_signals = 0 var int correct_signals = 0 var float total_return = 0.0 var float entry_price = na // Track signal performance (simplified) if buy_signal or sell_signal total_signals := total_signals + 1 entry_price := close // Calculate approximate return after 10 bars if not na(entry_price) and bar_index % 10 == 0 return_pct = (close - entry_price) / entry_price * 100 if (buy_signal[10] and return_pct > 0) or (sell_signal[10] and return_pct < 0) correct_signals := correct_signals + 1 total_return := total_return + math.abs(return_pct) entry_price := na // Calculate success rate success_rate = total_signals > 0 ? correct_signals / total_signals * 100 : 0 // ===== ENHANCED STATISTICS TABLE ===== if show_statistics and barstate.islast var table enhanced_stats = table.new(position.top_left, 2, 10, bgcolor = color.white, border_width = 1) table.cell(enhanced_stats, 0, 0, 'Advanced Metrics', text_color = color.white, bgcolor = color.blue) table.cell(enhanced_stats, 1, 0, 'Value', text_color = color.white, bgcolor = color.blue) table.cell(enhanced_stats, 0, 1, 'Signal Quality', text_color = color.black) table.cell(enhanced_stats, 1, 1, signal_quality, text_color = color.black) table.cell(enhanced_stats, 0, 2, 'Signal Score', text_color = color.black) table.cell(enhanced_stats, 1, 2, str.tostring(signal_score, '#.#'), text_color = color.black) table.cell(enhanced_stats, 0, 3, 'HTF Trend', text_color = color.black) table.cell(enhanced_stats, 1, 3, htf_trend == 1 ? 'Bullish' : htf_trend == -1 ? 'Bearish' : 'Neutral', text_color = color.black) table.cell(enhanced_stats, 0, 4, 'RSI Momentum', text_color = color.black) table.cell(enhanced_stats, 1, 4, str.tostring(rsi_momentum, '#.##'), text_color = color.black) table.cell(enhanced_stats, 0, 5, 'Position Size', text_color = color.black) table.cell(enhanced_stats, 1, 5, str.tostring(position_size_factor, '#.#') + 'x', text_color = color.black) table.cell(enhanced_stats, 0, 6, 'Total Signals', text_color = color.black) table.cell(enhanced_stats, 1, 6, str.tostring(total_signals), text_color = color.black) table.cell(enhanced_stats, 0, 7, 'Success Rate', text_color = color.black) table.cell(enhanced_stats, 1, 7, str.tostring(success_rate, '#.#') + '%', text_color = color.black) table.cell(enhanced_stats, 0, 8, 'Bullish Div', text_color = color.black) table.cell(enhanced_stats, 1, 8, bullish_divergence ? 'YES' : 'NO', text_color = color.black) table.cell(enhanced_stats, 0, 9, 'Bearish Div', text_color = color.black) table.cell(enhanced_stats, 1, 9, bearish_divergence ? 'YES' : 'NO', text_color = color.black) // ===== 传统警报条件(保留兼容性)===== // 注意:使用统一警报系统时,建议只使用上面的alert()函数 // 以下alertcondition保留用于需要单独设置警报的情况 // 基础穿越信号警报 alertcondition(ta.crossover(rsi, final_overbought), title = 'RSI上穿多头ML阈值', message = '{"指标名称":"ML_RSI_Pro","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI")}}","Long ML Threshold":"{{plot("Long ML Threshold")}}","事件":"RSI 已上穿多头ML阈值 - 潜在买入信号","信号":"buy"}') alertcondition(ta.crossunder(rsi, final_oversold), title = 'RSI下穿空头ML阈值', message = '{"指标名称":"ML_RSI_Pro","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI")}}","Short ML Threshold":"{{plot("Short ML Threshold")}}","事件":"RSI 已下穿空头ML阈值 - 潜在卖出信号","信号":"sell"}') // 区域转换信号警报 // alertcondition(ta.crossunder(rsi, final_overbought), title = 'RSI下穿多头ML阈值进入中性区', message = '{"指标名称":"ML_RSI_Pro","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI")}}","Long ML Threshold":"{{plot("Long ML Threshold")}}","事件":"RSI 已下穿多头ML阈值进入中性区","备注":"进入震荡","信号":"neutral_from_overbought"}') // alertcondition(ta.crossover(rsi, final_oversold), title = 'RSI上穿空头ML阈值进入中性区', message = '{"指标名称":"ML_RSI_Pro","交易对":"{{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 = '{"指标名称":"ML_RSI_Pro","交易对":"{{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 = '{"指标名称":"ML_RSI_Pro","交易对":"{{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 = '{"指标名称":"ML_RSI_Pro","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI")}}","Long ML Threshold":"{{plot("Long ML Threshold")}}","事件":"RSI 第二次进入超买区","标记":"2","信号":"overbought_mark2","警告":"二次超买信号"}') alertcondition(oversold_mark2_alert, title = 'RSI第二次进入超卖区', message = '{"指标名称":"ML_RSI_Pro","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI")}}","Short ML Threshold":"{{plot("Short ML Threshold")}}","事件":"RSI 第二次进入超卖区","标记":"-2","信号":"oversold_mark2","警告":"二次超卖信号"}') // 高级信号警报 // alertcondition(buy_signal and signal_score > 4, title = '高质量买入信号', message = '{"指标名称":"ML_RSI_Pro","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI")}}","事件":"高质量买入信号","信号":"high_quality_buy","评分":"{{plot("Signal Score")}}","备注":"强烈看涨条件"}') // alertcondition(sell_signal and signal_score < -4, title = '高质量卖出信号', message = '{"指标名称":"ML_RSI_Pro","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI")}}","事件":"高质量卖出信号","信号":"high_quality_sell","评分":"{{plot("Signal Score")}}","备注":"强烈看跌条件"}') // 背离信号警报 // alertcondition(bullish_divergence, title = '牛市背离', message = '{"指标名称":"ML_RSI_Pro","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI")}}","事件":"牛市背离","信号":"bullish_divergence","备注":"价格新低但RSI更高"}') // alertcondition(bearish_divergence, title = '熊市背离', message = '{"指标名称":"ML_RSI_Pro","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI")}}","事件":"熊市背离","信号":"bearish_divergence","备注":"价格新高但RSI更低"}') // RSI状态警报 alertcondition(rsi_overbought, title = 'RSI处于超买状态', message = '{"指标名称":"ML_RSI_Pro","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI")}}","超买阈值":"{{plot("Long ML Threshold")}}","事件":"RSI处于超买状态","信号":"rsi_overbought","备注":"RSI高于超买线"}') alertcondition(rsi_oversold, title = 'RSI处于超卖状态', message = '{"指标名称":"ML_RSI_Pro","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI")}}","超卖阈值":"{{plot("Short ML Threshold")}}","事件":"RSI处于超卖状态","信号":"rsi_oversold","备注":"RSI低于超卖线"}') // 基础买卖信号警报 // alertcondition(buy_signal, title = '买入信号', message = '{"指标名称":"ML_RSI_Pro","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI")}}","事件":"买入信号","信号":"buy_signal","备注":"过滤后的买入信号"}') // alertcondition(sell_signal, title = '卖出信号', message = '{"指标名称":"ML_RSI_Pro","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI")}}","事件":"卖出信号","信号":"sell_signal","备注":"过滤后的卖出信号"}') // 传统RSI阈值警报(70/30) // alertcondition(ta.crossover(rsi, 70), title = 'RSI上穿70', message = '{"指标名称":"ML_RSI_Pro","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI")}}","阈值":"70","事件":"RSI上穿70","信号":"rsi_70_cross_up","备注":"传统超买信号"}') // alertcondition(ta.crossunder(rsi, 30), title = 'RSI下穿30', message = '{"指标名称":"ML_RSI_Pro","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI")}}","阈值":"30","事件":"RSI下穿30","信号":"rsi_30_cross_down","备注":"传统超卖信号"}') // RSI中线穿越警报(50) // alertcondition(ta.crossover(rsi, 50), title = 'RSI上穿50', message = '{"指标名称":"ML_RSI_Pro","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI")}}","中线":"50","事件":"RSI上穿50","信号":"rsi_50_cross_up","备注":"多头信号"}') // alertcondition(ta.crossunder(rsi, 50), title = 'RSI下穿50', message = '{"指标名称":"ML_RSI_Pro","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","RSI":"{{plot("RSI")}}","中线":"50","事件":"RSI下穿50","信号":"rsi_50_cross_down","备注":"空头信号"}') // ===== PLOTS FOR EXTERNAL ACCESS ===== plot(buy_signal ? 1 : 0, 'Buy Signal Plot', display = display.none) plot(sell_signal ? 1 : 0, 'Sell Signal Plot', display = display.none) plot(final_oversold, 'Short ML Threshold', display = display.none) // For alert reference plot(final_overbought, 'Long ML Threshold', display = display.none) // For alert reference plot(signal_score, 'Signal Score', display = display.none) plot(bullish_divergence ? 1 : 0, 'Bullish Divergence Plot', display = display.none) plot(bearish_divergence ? 1 : 0, 'Bearish Divergence Plot', display = display.none) plot(htf_trend, 'HTF Trend', display = display.none) plot(segment_count, 'Segment Count', display = display.none) // For alert reference 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) plot(oversold_mark2_alert ? 1 : 0, 'Oversold Mark2', display = display.none) plot(rsi_overbought ? 1 : 0, 'RSI Overbought Status', display = display.none) plot(rsi_oversold ? 1 : 0, 'RSI Oversold Status', display = display.none) plot(rsi_change, 'RSI Change', display = display.none)