From 0242c06d634ef96c281df33f15330bede719b4a8 Mon Sep 17 00:00:00 2001 From: admin Date: Sat, 2 Aug 2025 04:03:35 +0000 Subject: [PATCH] up --- MaxTrendPoints.pine | 307 ++++++++++++++ Swing Failure Pattern.pine | 399 ++++++++++++++++++ mrc copy.pine | 844 +++++++++++++++++++++++++++++++++++++ mrc.pine | 715 +++++++++++++++++++++++++++++++ rsi.pine | 441 +++++++++++++++++++ rsi2.pine | 637 ++++++++++++++++++++++++++++ rsi_conbinined.pine | 293 +++++++++++++ srbr.pine | 714 +++++++++++++++++++++++++++++++ srbr1.pine | 316 ++++++++++++++ tmfs.pine | 503 ++++++++++++++++++++++ tmfs2.pine | 561 ++++++++++++++++++++++++ 11 files changed, 5730 insertions(+) create mode 100644 MaxTrendPoints.pine create mode 100644 Swing Failure Pattern.pine create mode 100644 mrc copy.pine create mode 100644 mrc.pine create mode 100644 rsi.pine create mode 100644 rsi2.pine create mode 100644 rsi_conbinined.pine create mode 100644 srbr.pine create mode 100644 srbr1.pine create mode 100644 tmfs.pine create mode 100644 tmfs2.pine diff --git a/MaxTrendPoints.pine b/MaxTrendPoints.pine new file mode 100644 index 0000000..a6bb5e9 --- /dev/null +++ b/MaxTrendPoints.pine @@ -0,0 +1,307 @@ +// This work is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International +// https://creativecommons.org/licenses/by-nc-sa/4.0/ +// © BigBeluga + +//@version=6 +indicator("Max Trend Points [BigBeluga]", overlay = true, max_lines_count = 500, max_labels_count = 500) + +// INPUTS ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――{ +var line_up = line(na) +var line_dn = line(na) +var lbl_up = label(na) +var lbl_dn = label(na) + +var highest = array.new_float(0) +var lowest = array.new_float(0) + +var int start = na +var int last_trend_change = 0 +var float last_trend_price = 0.0 + +// Trend Factor Inputs +factor_default = input.float(2.5, step = 0.1, title="默认趋势因子") +factor_btc = input.float(3.0, step = 0.1, title="BTCUSD 趋势因子") +factor_xau = input.float(2.5, step = 0.1, title="XAUUSD 趋势因子") +factor_eth = input.float(2.8, step = 0.1, title="ETHUSD 趋势因子") +factor_gbp = input.float(2.5, step = 0.1, title="GBPJPY 趋势因子") + +// Consolidation Bars Inputs +consolidation_bars_default = input.int(20, title="默认震荡检测周期", minval=10) +consolidation_bars_btc = input.int(25, title="BTCUSD 震荡检测周期", minval=10) +consolidation_bars_xau = input.int(25, title="XAUUSD 震荡检测周期", minval=10) +consolidation_bars_eth = input.int(20, title="ETHUSD 震荡检测周期", minval=10) +consolidation_bars_gbp = input.int(18, title="GBPJPY 震荡检测周期", minval=10) + +// Consolidation Threshold Inputs +consolidation_threshold_default = input.float(0.1, title="默认震荡阈值(%)", minval=0.1, step=0.02) +consolidation_threshold_btc = input.float(0.2, title="BTCUSD 震荡阈值(%)", minval=0.1, step=0.02) +consolidation_threshold_xau = input.float(0.3, title="XAUUSD 震荡阈值(%)", minval=0.1, step=0.02) +consolidation_threshold_eth = input.float(0.15, title="ETHUSD 震荡阈值(%)", minval=0.1, step=0.02) +consolidation_threshold_gbp = input.float(0.16, title="GBPJPY 震荡阈值(%)", minval=0.1, step=0.02) + +// Activity Period Inputs +activity_period_default = input.int(14, title="默认活跃度检测周期", minval=5) +activity_period_btc = input.int(20, title="BTCUSD 活跃度检测周期", minval=5) +activity_period_xau = input.int(20, title="XAUUSD 活跃度检测周期", minval=5) +activity_period_eth = input.int(20, title="ETHUSD 活跃度检测周期", minval=5) +activity_period_gbp = input.int(12, title="GBPJPY 活跃度检测周期", minval=5) + +// Activity Threshold Inputs +activity_threshold_default = input.float(1.3, title="默认活跃度阈值(ATR倍数)", minval=0.1, step=0.1) +activity_threshold_btc = input.float(1.5, title="BTCUSD 活跃度阈值(ATR倍数)", minval=0.1, step=0.1) +activity_threshold_xau = input.float(1.4, title="XAUUSD 活跃度阈值(ATR倍数)", minval=0.1, step=0.1) +activity_threshold_eth = input.float(1.4, title="ETHUSD 活跃度阈值(ATR倍数)", minval=0.1, step=0.1) +activity_threshold_gbp = input.float(1.3, title="GBPJPY 活跃度阈值(ATR倍数)", minval=0.1, step=0.1) + +// Colors +col_up = input.color(color.rgb(28, 194, 216), "上涨颜色") +col_dn = input.color(color.rgb(228, 144, 19), "下跌颜色") + +// Alert Settings +alert_group = "警报设置" +enable_trend_alert = input.bool(true, "启用趋势变化警报", group=alert_group) +enable_consolidation_alert = input.bool(true, "启用震荡警报", group=alert_group) +enable_activity_alert = input.bool(true, "启用市场活跃度警报", group=alert_group) + +// Select Parameters Based on Trading Pair +sym = syminfo.tickerid +factor = + sym == "TICKMILL:BTCUSD" ? factor_btc : + sym == "TICKMILL:XAUUSD" ? factor_xau : + sym == "TICKMILL:ETHUSD" ? factor_eth : + sym == "TICKMILL:GBPJPY" ? factor_gbp : + factor_default + +consolidation_bars = + sym == "TICKMILL:BTCUSD" ? consolidation_bars_btc : + sym == "TICKMILL:XAUUSD" ? consolidation_bars_xau : + sym == "TICKMILL:ETHUSD" ? consolidation_bars_eth : + sym == "TICKMILL:GBPJPY" ? consolidation_bars_gbp : + consolidation_bars_default + +consolidation_threshold = + sym == "TICKMILL:BTCUSD" ? consolidation_threshold_btc : + sym == "TICKMILL:XAUUSD" ? consolidation_threshold_xau : + sym == "TICKMILL:ETHUSD" ? consolidation_threshold_eth : + sym == "TICKMILL:GBPJPY" ? consolidation_threshold_gbp : + consolidation_threshold_default + +activity_period = + sym == "TICKMILL:BTCUSD" ? activity_period_btc : + sym == "TICKMILL:XAUUSD" ? activity_period_xau : + sym == "TICKMILL:ETHUSD" ? activity_period_eth : + sym == "TICKMILL:GBPJPY" ? activity_period_gbp : + activity_period_default + +activity_threshold = + sym == "TICKMILL:BTCUSD" ? activity_threshold_btc : + sym == "TICKMILL:XAUUSD" ? activity_threshold_xau : + sym == "TICKMILL:ETHUSD" ? activity_threshold_eth : + sym == "TICKMILL:GBPJPY" ? activity_threshold_gbp : + activity_threshold_default +// } + +// CALCULATIONS――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――{ +trend_line(factor)=> + src = hl2 + dist = ta.hma(high-low, 200) + upperBand = src + factor * dist + lowerBand = src - factor * dist + prevLowerBand = nz(lowerBand[1]) + prevUpperBand = nz(upperBand[1]) + + lowerBand := lowerBand > prevLowerBand or close[1] < prevLowerBand ? lowerBand : prevLowerBand + upperBand := upperBand < prevUpperBand or close[1] > prevUpperBand ? upperBand : prevUpperBand + + int _direction = na + float trend_line = na + prevTrendLine = nz(trend_line[1]) + if na(dist[1]) + _direction := 1 + else if prevTrendLine == prevUpperBand + _direction := close > upperBand ? -1 : 1 + else + _direction := close < lowerBand ? 1 : -1 + + trend_line := _direction == -1 ? lowerBand : upperBand + + [trend_line, _direction] + +[trend_line, _direction] = trend_line(factor) + +t_change = ta.cross(_direction, 0) + +// Oscillation Detection +highest_recent = ta.highest(high, consolidation_bars) +lowest_recent = ta.lowest(low, consolidation_bars) +price_range = (highest_recent - lowest_recent) / lowest_recent * 100 +is_consolidating = price_range < consolidation_threshold + +// Market Activity Detection +atr_current = ta.atr(activity_period) +atr_avg = ta.sma(atr_current, activity_period * 2) +is_active = atr_current > atr_avg * activity_threshold + +// Calculate Trend Strength +trend_strength = math.abs(close - trend_line) / trend_line * 100 + +if t_change + array.clear(highest) + array.clear(lowest) + start := bar_index + last_trend_change := bar_index + last_trend_price := close + +if t_change and _direction == 1 + line_dn := line.new(bar_index, close, na, na, color = chart.fg_color, style = line.style_dashed) + lbl_dn := label.new(bar_index, low, color = color.new(col_dn, 50), textcolor = chart.fg_color, size = size.small, style = label.style_label_up) + +if t_change and _direction == -1 + lbl_up := label.new(bar_index, high, color = color.new(col_up, 50), textcolor = chart.fg_color, size = size.small, style = label.style_label_down) + line_up := line.new(bar_index, close, na, na, color = chart.fg_color, style = line.style_dashed) + +if not t_change and _direction == -1 + array.push(highest, high) + label.set_xy(lbl_up, start + array.indexof(highest, array.max(highest))+1, array.max(highest)) + line.set_xy2(line_up, start + array.indexof(highest, array.max(highest))+1, array.max(highest)) + +if not t_change and _direction == 1 + array.push(lowest, low) + label.set_xy(lbl_dn, start + array.indexof(lowest, array.min(lowest))+1, array.min(lowest)) + line.set_xy2(line_dn, start + array.indexof(lowest, array.min(lowest))+1, array.min(lowest)) + +if line.get_y2(line_up) > line.get_y1(line_up) + label.set_text(lbl_up, str.tostring((line.get_y2(line_up) - line.get_y1(line_up)) / line.get_y1(line_up) * 100, format.percent)) +if line.get_y2(line_dn) < line.get_y1(line_dn) + label.set_text(lbl_dn, str.tostring((line.get_y2(line_dn) - line.get_y1(line_dn)) / line.get_y1(line_dn) * 100, format.percent)) + +t_color = _direction == -1 ? col_up : col_dn + +// Track previous states for state change detection +var bool was_consolidating = false +var bool was_active = false +was_consolidating := is_consolidating +was_active := is_active +// } + +// ===== 统一警报系统 ===== +// 统一警报系统 - 只需添加一次警报即可捕获所有信号 + +// 检测所有警报条件并生成对应的JSON消息 +alert_message = "" + +// 趋势变化警报 +if enable_trend_alert and t_change and _direction == -1 + alert_message := '{"指标名称":"MaxTrendPoints","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","趋势线":"' + str.tostring(trend_line, '#.####') + '","趋势强度":"' + str.tostring(trend_strength, '#.##') + '","价格范围":"' + str.tostring(price_range, '#.####') + '","当前ATR":"' + str.tostring(atr_current, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格转为上涨趋势","方向":"上涨趋势","信号":"trend_up"}' + alert(alert_message, alert.freq_once_per_bar_close) + +if enable_trend_alert and t_change and _direction == 1 + alert_message := '{"指标名称":"MaxTrendPoints","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","趋势线":"' + str.tostring(trend_line, '#.####') + '","趋势强度":"' + str.tostring(trend_strength, '#.##') + '","价格范围":"' + str.tostring(price_range, '#.####') + '","当前ATR":"' + str.tostring(atr_current, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格转为下跌趋势","方向":"下跌趋势","信号":"trend_down"}' + alert(alert_message, alert.freq_once_per_bar_close) + +// 震荡状态变化警报 +// if enable_consolidation_alert and is_consolidating and not was_consolidating[1] +// alert_message := '{"指标名称":"MaxTrendPoints","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","趋势线":"' + str.tostring(trend_line, '#.####') + '","趋势强度":"' + str.tostring(trend_strength, '#.##') + '","价格范围":"' + str.tostring(price_range, '#.####') + '","当前ATR":"' + str.tostring(atr_current, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"市场进入震荡状态","状态":"震荡","信号":"consolidation_start"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// if enable_consolidation_alert and not is_consolidating and was_consolidating[1] +// direction_text = _direction == -1 ? "上涨趋势" : "下跌趋势" +// alert_message := '{"指标名称":"MaxTrendPoints","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","趋势线":"' + str.tostring(trend_line, '#.####') + '","趋势强度":"' + str.tostring(trend_strength, '#.##') + '","价格范围":"' + str.tostring(price_range, '#.####') + '","当前ATR":"' + str.tostring(atr_current, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"市场突破震荡状态","方向":"' + direction_text + '","信号":"consolidation_break"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// // 活跃度变化警报 +// if enable_activity_alert and is_active and not was_active[1] +// alert_message := '{"指标名称":"MaxTrendPoints","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","趋势线":"' + str.tostring(trend_line, '#.####') + '","趋势强度":"' + str.tostring(trend_strength, '#.##') + '","价格范围":"' + str.tostring(price_range, '#.####') + '","当前ATR":"' + str.tostring(atr_current, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"市场活跃度增加","活跃状态":"活跃","信号":"activity_increase"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// if enable_activity_alert and not is_active and was_active[1] +// alert_message := '{"指标名称":"MaxTrendPoints","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","趋势线":"' + str.tostring(trend_line, '#.####') + '","趋势强度":"' + str.tostring(trend_strength, '#.##') + '","价格范围":"' + str.tostring(price_range, '#.####') + '","当前ATR":"' + str.tostring(atr_current, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"市场活跃度降低","活跃状态":"不活跃","信号":"activity_decrease"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// 综合市场分析警报 +// if t_change and (enable_trend_alert or enable_consolidation_alert or enable_activity_alert) +// direction_text = _direction == -1 ? "上涨趋势" : "下跌趋势" +// status_text = is_consolidating ? "震荡" : (is_active ? "活跃" : "正常") +// alert_message := '{"指标名称":"MaxTrendPoints","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","趋势线":"' + str.tostring(trend_line, '#.####') + '","趋势强度":"' + str.tostring(trend_strength, '#.##') + '","价格范围":"' + str.tostring(price_range, '#.####') + '","当前ATR":"' + str.tostring(atr_current, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"综合市场分析","方向":"' + direction_text + '","状态":"' + status_text + '","信号":"market_analysis"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// 状态监控警报(频率较低) +if enable_trend_alert and _direction == -1 + alert_message := '{"指标名称":"MaxTrendPoints","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","趋势线":"' + str.tostring(trend_line, '#.####') + '","趋势强度":"' + str.tostring(trend_strength, '#.##') + '","价格范围":"' + str.tostring(price_range, '#.####') + '","当前ATR":"' + str.tostring(atr_current, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于上涨趋势","方向":"上涨趋势","信号":"trend_up_status"}' + alert(alert_message, alert.freq_once_per_bar) + +if enable_trend_alert and _direction == 1 + alert_message := '{"指标名称":"MaxTrendPoints","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","趋势线":"' + str.tostring(trend_line, '#.####') + '","趋势强度":"' + str.tostring(trend_strength, '#.##') + '","价格范围":"' + str.tostring(price_range, '#.####') + '","当前ATR":"' + str.tostring(atr_current, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于下跌趋势","方向":"下跌趋势","信号":"trend_down_status"}' + alert(alert_message, alert.freq_once_per_bar) + +if enable_consolidation_alert and is_consolidating + alert_message := '{"指标名称":"MaxTrendPoints","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","趋势线":"' + str.tostring(trend_line, '#.####') + '","趋势强度":"' + str.tostring(trend_strength, '#.##') + '","价格范围":"' + str.tostring(price_range, '#.####') + '","当前ATR":"' + str.tostring(atr_current, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于震荡状态","状态":"震荡","信号":"consolidation_status"}' + alert(alert_message, alert.freq_once_per_bar) + +if enable_activity_alert and is_active + alert_message := '{"指标名称":"MaxTrendPoints","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","趋势线":"' + str.tostring(trend_line, '#.####') + '","趋势强度":"' + str.tostring(trend_strength, '#.##') + '","价格范围":"' + str.tostring(price_range, '#.####') + '","当前ATR":"' + str.tostring(atr_current, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于活跃状态","活跃状态":"活跃","信号":"activity_status"}' + alert(alert_message, alert.freq_once_per_bar) + +// ===== 传统警报条件(保留兼容性)===== +// 注意:使用统一警报系统时,建议只使用上面的alert()函数 +// 以下alertcondition保留用于需要单独设置警报的情况 + +// 创建用于警报的plot变量 +plot(trend_line, title = '趋势线', display = display.none) +plot(trend_strength, title = '趋势强度', display = display.none) +plot(price_range, title = '价格范围', display = display.none) +plot(atr_current, title = '当前ATR', display = display.none) + +// 趋势变化警报 +alertcondition(enable_trend_alert and t_change and _direction == -1, title = '价格转为上涨趋势', message = '{"指标名称":"MaxTrendPoints","交易对":"{{ticker}}","周期":"{{interval}}","趋势线":"{{plot("趋势线")}}","趋势强度":"{{plot("趋势强度")}}","价格范围":"{{plot("价格范围")}}","当前ATR":"{{plot("当前ATR")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格转为上涨趋势","方向":"上涨趋势","信号":"trend_up"}') + +alertcondition(enable_trend_alert and t_change and _direction == 1, title = '价格转为下跌趋势', message = '{"指标名称":"MaxTrendPoints","交易对":"{{ticker}}","周期":"{{interval}}","趋势线":"{{plot("趋势线")}}","趋势强度":"{{plot("趋势强度")}}","价格范围":"{{plot("价格范围")}}","当前ATR":"{{plot("当前ATR")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格转为下跌趋势","方向":"下跌趋势","信号":"trend_down"}') + +// 震荡状态变化警报 +alertcondition(enable_consolidation_alert and is_consolidating and not was_consolidating[1], title = '市场进入震荡状态', message = '{"指标名称":"MaxTrendPoints","交易对":"{{ticker}}","周期":"{{interval}}","趋势线":"{{plot("趋势线")}}","趋势强度":"{{plot("趋势强度")}}","价格范围":"{{plot("价格范围")}}","当前ATR":"{{plot("当前ATR")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"市场进入震荡状态","状态":"震荡","信号":"consolidation_start"}') + +alertcondition(enable_consolidation_alert and not is_consolidating and was_consolidating[1], title = '市场突破震荡状态', message = '{"指标名称":"MaxTrendPoints","交易对":"{{ticker}}","周期":"{{interval}}","趋势线":"{{plot("趋势线")}}","趋势强度":"{{plot("趋势强度")}}","价格范围":"{{plot("价格范围")}}","当前ATR":"{{plot("当前ATR")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"市场突破震荡状态","信号":"consolidation_break"}') + +// 活跃度变化警报 +alertcondition(enable_activity_alert and is_active and not was_active[1], title = '市场活跃度增加', message = '{"指标名称":"MaxTrendPoints","交易对":"{{ticker}}","周期":"{{interval}}","趋势线":"{{plot("趋势线")}}","趋势强度":"{{plot("趋势强度")}}","价格范围":"{{plot("价格范围")}}","当前ATR":"{{plot("当前ATR")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"市场活跃度增加","活跃状态":"活跃","信号":"activity_increase"}') + +alertcondition(enable_activity_alert and not is_active and was_active[1], title = '市场活跃度降低', message = '{"指标名称":"MaxTrendPoints","交易对":"{{ticker}}","周期":"{{interval}}","趋势线":"{{plot("趋势线")}}","趋势强度":"{{plot("趋势强度")}}","价格范围":"{{plot("价格范围")}}","当前ATR":"{{plot("当前ATR")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"市场活跃度降低","活跃状态":"不活跃","信号":"activity_decrease"}') + +// 综合市场分析警报 +alertcondition(t_change and (enable_trend_alert or enable_consolidation_alert or enable_activity_alert), title = '综合市场分析', message = '{"指标名称":"MaxTrendPoints","交易对":"{{ticker}}","周期":"{{interval}}","趋势线":"{{plot("趋势线")}}","趋势强度":"{{plot("趋势强度")}}","价格范围":"{{plot("价格范围")}}","当前ATR":"{{plot("当前ATR")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"综合市场分析","信号":"market_analysis"}') + +// 状态监控警报 +alertcondition(enable_trend_alert and _direction == -1, title = '价格处于上涨趋势', message = '{"指标名称":"MaxTrendPoints","交易对":"{{ticker}}","周期":"{{interval}}","趋势线":"{{plot("趋势线")}}","趋势强度":"{{plot("趋势强度")}}","价格范围":"{{plot("价格范围")}}","当前ATR":"{{plot("当前ATR")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格处于上涨趋势","方向":"上涨趋势","信号":"trend_up_status"}') + +alertcondition(enable_trend_alert and _direction == 1, title = '价格处于下跌趋势', message = '{"指标名称":"MaxTrendPoints","交易对":"{{ticker}}","周期":"{{interval}}","趋势线":"{{plot("趋势线")}}","趋势强度":"{{plot("趋势强度")}}","价格范围":"{{plot("价格范围")}}","当前ATR":"{{plot("当前ATR")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格处于下跌趋势","方向":"下跌趋势","信号":"trend_down_status"}') + +alertcondition(enable_consolidation_alert and is_consolidating, title = '价格处于震荡状态', message = '{"指标名称":"MaxTrendPoints","交易对":"{{ticker}}","周期":"{{interval}}","趋势线":"{{plot("趋势线")}}","趋势强度":"{{plot("趋势强度")}}","价格范围":"{{plot("价格范围")}}","当前ATR":"{{plot("当前ATR")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格处于震荡状态","状态":"震荡","信号":"consolidation_status"}') + +alertcondition(enable_activity_alert and is_active, title = '价格处于活跃状态', message = '{"指标名称":"MaxTrendPoints","交易对":"{{ticker}}","周期":"{{interval}}","趋势线":"{{plot("趋势线")}}","趋势强度":"{{plot("趋势强度")}}","价格范围":"{{plot("价格范围")}}","当前ATR":"{{plot("当前ATR")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格处于活跃状态","活跃状态":"活跃","信号":"activity_status"}') + +// PLOT ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――{ +plotshape(t_change ? trend_line : na, "趋势变化", style = shape.circle, location = location.absolute, color = t_color, size = size.tiny) + +t_p = plot(trend_line, "趋势线", color = t_change ? color.new(t_color, 100) : t_color, linewidth = 2) +m_p = plot(hl2, color = color.new(color.gray, 100), editable = false) + +fill(t_p, m_p, hl2, trend_line, color.new(t_color, 95), color.new(t_color, 90)) + +// Status Panel +var table panel = table.new(position.top_right, 3, 4, bgcolor=color.new(color.black, 80)) +if barstate.islast + table.cell(panel, 0, 0, "市场状态", text_color=color.white, text_size=size.small) + table.cell(panel, 1, 0, "当前值", text_color=color.white, text_size=size.small) + + table.cell(panel, 0, 1, "趋势方向", text_color=color.gray, text_size=size.small) + table.cell(panel, 1, 1, _direction == -1 ? "↑ 上涨" : "↓ 下跌", + text_color=_direction == -1 ? col_up : col_dn, text_size=size.small) + + table.cell(panel, 0, 2, "市场状态", text_color=color.gray, text_size=size.small) + table.cell(panel, 1, 2, is_consolidating ? "震荡中" : "趋势中", + text_color=is_consolidating ? color.rgb(43, 43, 39) : color.green, text_size=size.small) + + table.cell(panel, 0, 3, "活跃度", text_color=color.gray, text_size=size.small) + table.cell(panel, 1, 3, is_active ? "活跃" : "平静", + text_color=is_active ? color.rgb(60, 60, 60) : color.blue, text_size=size.small) +// } \ No newline at end of file diff --git a/Swing Failure Pattern.pine b/Swing Failure Pattern.pine new file mode 100644 index 0000000..179b0f8 --- /dev/null +++ b/Swing Failure Pattern.pine @@ -0,0 +1,399 @@ +// This work is licensed under a Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) https://creativecommons.org/licenses/by-nc-sa/4.0/ +// © LuxAlgo + +//@version=5 +indicator( 'SwingFailurePattern [LuxAlgo]', 'LuxAlgo - Swing Failure Pattern', max_labels_count = 500, max_lines_count = 500, max_boxes_count = 500, overlay = true) +//---------------------------------------------------------------------------------------------------------------------} +//Settings +//---------------------------------------------------------------------------------------------------------------------{ +sp = '            ' +len = input.int ( 5 , 'Swings' , minval= 1 ) +bull = input.bool ( true , 'Bullish SFP' ) +bear = input.bool ( true , 'Bearish SFP' ) + +iVal = input.string ('None', 'Validation'+sp+ '   ', group='Volume Validation' + , options = ['Volume outside swing < Threshold' ,'Volume outside swing > Threshold','None']) +percent = input.float (25, 'Volume Threshold %' , inline='valy', group='Volume Validation' + , tooltip = '% of Total Volume' , minval= 0 , maxval=100 ) +auto = input.bool (true, '' , inline='auto', group='Volume Validation' ) +mlt = input.int (50 , '      Auto' + sp , inline='auto', group='Volume Validation' ) +res = input.timeframe('1' , sp +'   LTF' + sp +'  ', inline='ltf' , group='Volume Validation' ) +prem = input.bool (false ,'    Premium' , group='Volume Validation' + , tooltip = 'Premium Plan or higher' ) +showDash = input.bool (true , 'Show Dashboard' , group= 'Dashboard' ) +dashLoc = input.string ( 'Top Right' , 'Location' + , options = ['Top Right', 'Bottom Right', 'Bottom Left'] , group= 'Dashboard' ) +textSize = input.string ( 'Normal' , 'Size' + , options = ['Tiny', 'Small', 'Normal'] , group= 'Dashboard' ) +dSwingLine = input.bool (true , 'Swing Lines' , group= 'Style' ) +dOpposLine = input.bool (true , 'Confirmation Lines' , group= 'Style' ) +dSFP_Line = input.bool (true , 'Swing Failure Wick' , group= 'Style' ) +dSFP_Label = input.bool (true , 'Swing Failure Label' , group= 'Style' ) +showAlerts = input.bool (true , 'Show Alert Markers' , group= 'Style' ) +alertSize = input.string ('Normal', 'Alert Marker Size' , group= 'Style' + , options = ['Small', 'Normal', 'Large'] ) +colBl = input.color (#089981 , 'Lines / Labels' , inline='lin' , group= 'Style' ) +colBr = input.color (#f23645 , '' , inline='lin' , group= 'Style' + , tooltip = 'Bullish/Bearish' ) +colBl2 = input.color (#08998180, 'SFP Wicks      ', inline='wic' , group= 'Style' ) +colBr2 = input.color (#f2364580, '' , inline='wic' , group= 'Style' + , tooltip = 'Wick outside Swing, Bullish/Bearish' ) + +//-----------------------------------------------------------------------------} +//UDT +//-----------------------------------------------------------------------------{ +type piv + float swing_prc // price + int swing_bix // bar_index + float oppos_prc // price + int oppos_bix // bar_index + bool active + bool confirmed + line swing_line + line oppos_line + line wicky_line + label wicky_label + +type swing + int bix + float prc + +//-----------------------------------------------------------------------------} +//Variables +//-----------------------------------------------------------------------------{ +n = bar_index +INV = color(na) +FGc = chart.fg_color + +table_position = dashLoc == 'Bottom Left' ? position.bottom_left + : dashLoc == 'Top Right' ? position.top_right + : position.bottom_right + +table_size = textSize == 'Tiny' ? size.tiny + : textSize == 'Small' ? size.small + : size.normal + +alert_marker_size = alertSize == 'Small' ? size.small + : alertSize == 'Large' ? size.large + : size.normal + +var tb = table.new(table_position, 2, 3 + , bgcolor = #1e222d + , border_color = #373a46 + , border_width = 1 + , frame_color = #373a46 + , frame_width = 1) + +var swing swingH = swing.new() +var swing swingL = swing.new() +var piv pivH = piv.new() +var piv pivL = piv.new() + +validate = iVal != 'None' +valHigher= iVal == 'Volume outside swing > Threshold' +valLower = iVal == 'Volume outside swing < Threshold' + +//---------------------------------------------------------------------------------------------------------------------} +//Method +//---------------------------------------------------------------------------------------------------------------------{ +method n(float piv) => bool out = not na(piv) + +//---------------------------------------------------------------------------------------------------------------------} +//Execution +//---------------------------------------------------------------------------------------------------------------------{ +tfS = timeframe.in_seconds( res ) +tfC = timeframe.in_seconds(timeframe.period) +rs = auto ? tfC / mlt : tfS +if not validate + res := timeframe.period +else + rs := prem ? rs : math.max(60, rs) + res := timeframe.from_seconds(math.min(tfC, rs)) + +ph = ta.pivothigh(len, 1) +pl = ta.pivotlow (len, 1) + +[ltf_close, ltf_volume] = request.security_lower_tf(syminfo.tickerid, res, [close, volume]) + +ltf_size = ltf_close.size() + +if validate + if ltf_size > 0 and ltf_size[1] == 0 + line.new(n, close, n, close + syminfo.mintick, color=color.silver, style=line.style_dotted, extend=extend.both) + +//---------------------------------------------------------------------------------------------------------------------} +//Bearish Pattern +//---------------------------------------------------------------------------------------------------------------------{ +if bear + + if ph.n() + swingH.bix := n-1 + swingH.prc := ph + + sw = swingH.prc + bx = swingH.bix + if high > sw + and open < sw + and close < sw + valid = true + if validate + if ltf_close.size() > 0 + outsideVolume = 0. + totalVolume = ltf_volume.sum() + for j = 0 to ltf_close.size() -1 + if ltf_close.get(j) > sw + outsideVolume += ltf_volume.get(j) + if (valHigher ? 100 / totalVolume * outsideVolume < percent + : 100 / totalVolume * outsideVolume > percent + ) + valid := false + + //if valid + // label.new(n, high, text=str.format("Total Volume: {0}\nWick Volume: {1}", totalVolume, outsideVolume)) + + if valid + + opposL = sw + opposB = n + + for i = 1 to n - bx -1 + if low [i] < opposL + opposL := low [i] + opposB := n - i + + if not pivH.confirmed + pivH.swing_line .delete() + pivH.oppos_line .delete() + pivH.wicky_line .delete() + pivH.wicky_label.delete() + + pivH := piv.new(sw, bx, opposL, opposB, true, false) + + if dSwingLine + pivH.swing_line := line.new (bx , sw , n, sw , color=colBr) + if dOpposLine + pivH.oppos_line := line.new (opposB, opposL, n, opposL, color=colBr, style=line.style_dotted) + if dSFP_Line + pivH.wicky_line := line.new (n , high , n, sw , color=colBr2, width=3) + if dSFP_Label + pivH.wicky_label := label.new(n , high + , style=label.style_label_down + , text='SFP', textcolor=colBr + , color=INV, size=size.normal + ) + + if pivH.active and not pivH.confirmed + + pivH.swing_line.set_x2(n) + pivH.oppos_line.set_x2(n) + + if close < pivH.oppos_prc + pivH.confirmed := true + + if pivH.wicky_label.get_x() == n + pivH.wicky_label.set_text('SFP\n▼') + else + label.new(n, high, style=label.style_label_down, text='▼', textcolor=colBr, color=INV, size=size.normal) + + if n - pivH.swing_bix > 500 + or close > pivH.swing_prc + pivH.active := false + if not pivH.confirmed + pivH.swing_line .delete() + pivH.oppos_line .delete() + pivH.wicky_line .delete() + pivH.wicky_label.delete() + +//---------------------------------------------------------------------------------------------------------------------} +//Bullish Pattern +//---------------------------------------------------------------------------------------------------------------------{ +if bull + + if pl.n() + swingL.bix := n-1 + swingL.prc := pl + + sw = swingL.prc + bx = swingL.bix + if low < sw + and open > sw + and close > sw + valid = true + if validate + if ltf_close.size() > 0 + outsideVolume = 0. + totalVolume = ltf_volume.sum() + for j = 0 to ltf_close.size() -1 + if ltf_close.get(j) < sw + outsideVolume += ltf_volume.get(j) + if (valHigher ? 100 / totalVolume * outsideVolume < percent + : 100 / totalVolume * outsideVolume > percent + ) + valid := false + if valid + + opposH = sw + opposB = n + + for i = 1 to n - bx -1 + if high[i] > opposH + opposH := high[i] + opposB := n - i + + if not pivL.confirmed + pivL.swing_line .delete() + pivL.oppos_line .delete() + pivL.wicky_line .delete() + pivL.wicky_label.delete() + + pivL := piv.new(sw, bx, opposH, opposB, true, false) + + if dSwingLine + pivL.swing_line := line.new (bx , sw , n, sw , color=colBl ) + if dOpposLine + pivL.oppos_line := line.new (opposB, opposH, n, opposH, color=colBl , style=line.style_dotted) + if dSFP_Line + pivL.wicky_line := line.new (n , low , n, sw , color=colBl2, width=3) + if dSFP_Label + pivL.wicky_label := label.new(n , low + , style=label.style_label_up + , text='SFP', textcolor=colBl + , color=INV, size=size.normal + ) + + if pivL.active and not pivL.confirmed + + pivL.swing_line.set_x2(n) + pivL.oppos_line.set_x2(n) + + if close > pivL.oppos_prc + pivL.confirmed := true + + if pivL.wicky_label.get_x() == n + pivL.wicky_label.set_text('▲\nSFP') + else + label.new(n, low, style=label.style_label_up, text='▲', textcolor=colBl, color=INV, size=size.normal) + + if n - pivL.swing_bix > 500 + or close < pivL.swing_prc + pivL.active := false + if not pivL.confirmed + pivL.swing_line .delete() + pivL.oppos_line .delete() + pivL.wicky_line .delete() + pivL.wicky_label.delete() + +//---------------------------------------------------------------------------------------------------------------------} +//Dashboard +//---------------------------------------------------------------------------------------------------------------------{ +if barstate.islast and validate and showDash + tb.cell(0, 0, str.format("LTF: {0}", res), text_color=color.white, text_size=table_size) + +//---------------------------------------------------------------------------------------------------------------------} +//Alert System +//---------------------------------------------------------------------------------------------------------------------{ + +// ===== 统一警报系统 ===== +// 统一警报系统 - 只需添加一次警报即可捕获所有信号 + +// 警报频率限制 - 每分钟只触发一次 +var int last_alert_bearish_sfp = 0 +var int last_alert_bullish_sfp = 0 +var int last_alert_bearish_sfp_confirmed = 0 +var int last_alert_bullish_sfp_confirmed = 0 + +// 获取当前时间(分钟级别) +current_minute = math.floor(timenow / 60000) + +// 检测所有警报条件并生成对应的JSON消息 +alert_message = "" + +// 看跌SFP信号检测 - 每分钟限制 +bearish_sfp_signal = bear and high > swingH.prc and open < swingH.prc and close < swingH.prc and not pivH.confirmed +if bearish_sfp_signal and current_minute > last_alert_bearish_sfp + alert_message := '{"指标名称":"SwingFailurePattern","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","摆动高点":"' + str.tostring(swingH.prc, '#.####') + '","事件":"看跌摆动失败模式触发","信号":"bearish_sfp","备注":"突破高点后看跌回落"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_bearish_sfp := current_minute + + // 在K线上绘制看跌SFP信号标记 + if showAlerts + label.new(bar_index, high + (high - low) * 0.1, + text='🔻SFP', + style=label.style_label_down, + color=color.new(color.red, 20), + textcolor=color.white, + size=alert_marker_size, + tooltip='突破高点后看跌回落\n摆动高点: ' + str.tostring(swingH.prc, '#.####')) + +// 看涨SFP信号检测 - 每分钟限制 +bullish_sfp_signal = bull and low < swingL.prc and open > swingL.prc and close > swingL.prc and not pivL.confirmed +if bullish_sfp_signal and current_minute > last_alert_bullish_sfp + alert_message := '{"指标名称":"SwingFailurePattern","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","摆动低点":"' + str.tostring(swingL.prc, '#.####') + '","事件":"看涨摆动失败模式触发","信号":"bullish_sfp","备注":"跌破低点后看涨反弹"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_bullish_sfp := current_minute + + // 在K线上绘制看涨SFP信号标记 + if showAlerts + label.new(bar_index, low - (high - low) * 0.1, + text='🔺SFP', + style=label.style_label_up, + color=color.new(color.green, 20), + textcolor=color.white, + size=alert_marker_size, + tooltip='跌破低点后看涨反弹\n摆动低点: ' + str.tostring(swingL.prc, '#.####')) + +// 看跌SFP确认信号 - 每分钟限制 +bearish_sfp_confirmed = pivH.active and not pivH.confirmed[1] and pivH.confirmed and close < pivH.oppos_prc +if bearish_sfp_confirmed and current_minute > last_alert_bearish_sfp_confirmed + alert_message := '{"指标名称":"SwingFailurePattern","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","摆动高点":"' + str.tostring(pivH.swing_prc, '#.####') + '","对立价格":"' + str.tostring(pivH.oppos_prc, '#.####') + '","事件":"看跌摆动失败模式确认","信号":"bearish_sfp_confirmed","备注":"跌破对立低点确认看跌"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_bearish_sfp_confirmed := current_minute + + // 在K线上绘制看跌SFP确认信号标记 + if showAlerts + label.new(bar_index, high + (high - low) * 0.15, + text='✅🔻', + style=label.style_label_down, + color=color.new(color.maroon, 10), + textcolor=color.white, + size=alert_marker_size, + tooltip='跌破对立低点确认看跌\n摆动高点: ' + str.tostring(pivH.swing_prc, '#.####') + '\n对立价格: ' + str.tostring(pivH.oppos_prc, '#.####')) + +// 看涨SFP确认信号 - 每分钟限制 +bullish_sfp_confirmed = pivL.active and not pivL.confirmed[1] and pivL.confirmed and close > pivL.oppos_prc +if bullish_sfp_confirmed and current_minute > last_alert_bullish_sfp_confirmed + alert_message := '{"指标名称":"SwingFailurePattern","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","摆动低点":"' + str.tostring(pivL.swing_prc, '#.####') + '","对立价格":"' + str.tostring(pivL.oppos_prc, '#.####') + '","事件":"看涨摆动失败模式确认","信号":"bullish_sfp_confirmed","备注":"突破对立高点确认看涨"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_bullish_sfp_confirmed := current_minute + + // 在K线上绘制看涨SFP确认信号标记 + if showAlerts + label.new(bar_index, low - (high - low) * 0.15, + text='✅🔺', + style=label.style_label_up, + color=color.new(color.teal, 10), + textcolor=color.white, + size=alert_marker_size, + tooltip='突破对立高点确认看涨\n摆动低点: ' + str.tostring(pivL.swing_prc, '#.####') + '\n对立价格: ' + str.tostring(pivL.oppos_prc, '#.####')) + +// ===== 传统警报条件(保留兼容性)===== +// 注意:使用统一警报系统时,建议只使用上面的alert()函数 +// 以下alertcondition保留用于需要单独设置警报的情况 + +// 创建用于警报的plot变量 +plot(swingH.prc, title = '摆动高点', display = display.none) +plot(swingL.prc, title = '摆动低点', display = display.none) +plot(pivH.oppos_prc, title = '看跌对立价格', display = display.none) +plot(pivL.oppos_prc, title = '看涨对立价格', display = display.none) + +// SFP信号警报 +alertcondition(bearish_sfp_signal, title = '看跌摆动失败模式', message = '{"指标名称":"SwingFailurePattern","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","摆动高点":"{{plot("摆动高点")}}","事件":"看跌摆动失败模式触发","信号":"bearish_sfp","备注":"突破高点后看跌回落"}') + +alertcondition(bullish_sfp_signal, title = '看涨摆动失败模式', message = '{"指标名称":"SwingFailurePattern","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","摆动低点":"{{plot("摆动低点")}}","事件":"看涨摆动失败模式触发","信号":"bullish_sfp","备注":"跌破低点后看涨反弹"}') + +// SFP确认信号警报 +alertcondition(bearish_sfp_confirmed, title = '看跌摆动失败模式确认', message = '{"指标名称":"SwingFailurePattern","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","摆动高点":"{{plot("摆动高点")}}","对立价格":"{{plot("看跌对立价格")}}","事件":"看跌摆动失败模式确认","信号":"bearish_sfp_confirmed","备注":"跌破对立低点确认看跌"}') + +alertcondition(bullish_sfp_confirmed, title = '看涨摆动失败模式确认', message = '{"指标名称":"SwingFailurePattern","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","摆动低点":"{{plot("摆动低点")}}","对立价格":"{{plot("看涨对立价格")}}","事件":"看涨摆动失败模式确认","信号":"bullish_sfp_confirmed","备注":"突破对立高点确认看涨"}') + +//---------------------------------------------------------------------------------------------------------------------} \ No newline at end of file diff --git a/mrc copy.pine b/mrc copy.pine new file mode 100644 index 0000000..1213f80 --- /dev/null +++ b/mrc copy.pine @@ -0,0 +1,844 @@ +//@version=6 +indicator('Mean Reversion Channel - 带价格标签 -ma200', shorttitle = 'MRC2ma200', overlay = true, format = format.inherit) + +//************************************************************************************************************ +// Parameter +//************************************************************************************************************ + +indiSet = input(false, '═════════ MRC Parameter ════════') +source = input(hlc3, title = 'Price Source') +type = input.string('SuperSmoother', title = 'Filter Type', options = ['SuperSmoother', 'Ehlers EMA', 'Gaussian', 'Butterworth', 'BandStop', 'SMA', 'EMA', 'RMA']) +length = input.int(200, title = 'Lookback Period', minval = 1) +innermult = input.float(1.0, title = 'Inner Channel Size Multiplier', minval = 0.1) +outermult = input.float(2.415, title = 'Outer Channel Size Multiplier', minval = 0.1) + +// ————————————— MA200 参数 ————————————— +maSet = input(false, '═════════ MA200 Parameter ════════') +exponential = input.bool(true, title='使用指数移动平均线 (EMA)') +show_ma_lines = input.bool(true, title='显示MA线条') +show_ma_labels = input.bool(true, title='显示MA价格标签') + +ChartSet = input(false, '═════════ Chart Setting ════════') +drawchannel = input(true, title = 'Draw Channel') +displayzone = input(true, title = 'Draw Zone (With Channel)') +zonetransp = input.int(60, title = 'Zone Transparency', minval = 0, maxval = 100) +displayline = input(true, title = 'Display Line Extension') + +MTFSet = input(false, '═════════ MTF Setting ════════') +enable_mtf = input(true, title = 'Enable Multiple TimeFrame Analysis') +mtf_disp_typ = input.string('On Hover', title = 'MTF Display Type', options = ['Always Display', 'On Hover']) +mtf_typ = input.string('Auto', title = 'Multiple TimeFrame Type', options = ['Auto', 'Custom']) +mtf_lvl1 = input.timeframe('D', title = 'Custom MTF Level 1') +mtf_lvl2 = input.timeframe('W', title = 'Custom MTF Level 2') + +//************************************************************************************************************ +// Functions Start { +//************************************************************************************************************ +var pi = 2 * math.asin(1) +var mult = pi * innermult +var mult2 = pi * outermult +var gradsize = 0.5 +var gradtransp = zonetransp + +//----------------------- +// Ehler SwissArmyKnife Function +//----------------------- +SAK_smoothing(_type, _src, _length) => + c0 = 1.0 + c1 = 0.0 + b0 = 1.0 + b1 = 0.0 + b2 = 0.0 + a1 = 0.0 + a2 = 0.0 + alpha = 0.0 + beta = 0.0 + gamma = 0.0 + cycle = 2 * pi / _length + + if _type == 'Ehlers EMA' + alpha := (math.cos(cycle) + math.sin(cycle) - 1) / math.cos(cycle) + b0 := alpha + a1 := 1 - alpha + a1 + if _type == 'Gaussian' + beta := 2.415 * (1 - math.cos(cycle)) + alpha := -beta + math.sqrt(beta * beta + 2 * beta) + c0 := alpha * alpha + a1 := 2 * (1 - alpha) + a2 := -(1 - alpha) * (1 - alpha) + a2 + if _type == 'Butterworth' + beta := 2.415 * (1 - math.cos(cycle)) + alpha := -beta + math.sqrt(beta * beta + 2 * beta) + c0 := alpha * alpha / 4 + b1 := 2 + b2 := 1 + a1 := 2 * (1 - alpha) + a2 := -(1 - alpha) * (1 - alpha) + a2 + if _type == 'BandStop' + beta := math.cos(cycle) + gamma := 1 / math.cos(cycle * 2 * 0.1) // delta default to 0.1. Acceptable delta -- 0.05 + s_a1 = math.exp(-math.sqrt(2) * pi / _length) + s_b1 = 2 * s_a1 * math.cos(math.sqrt(2) * pi / _length) + s_c3 = -math.pow(s_a1, 2) + s_c2 = s_b1 + s_c1 = 1 - s_c2 - s_c3 + ss = 0.0 + ss := s_c1 * _src + s_c2 * nz(ss[1], _src[1]) + s_c3 * nz(ss[2], _src[2]) + ss + +//----------------------- +// Auto TimeFrame Function +//----------------------- +// ————— Converts current chart resolution into a float minutes value. +f_resInMinutes() => + _resInMinutes = timeframe.multiplier * (timeframe.isseconds ? 1. / 60 : timeframe.isminutes ? 1. : timeframe.isdaily ? 60. * 24 : timeframe.isweekly ? 60. * 24 * 7 : timeframe.ismonthly ? 60. * 24 * 30.4375 : na) + _resInMinutes + +get_tf(_lvl) => + y = f_resInMinutes() + z = timeframe.period + if mtf_typ == 'Auto' + if y < 1 + z := _lvl == 1 ? '1' : _lvl == 2 ? '5' : z + z + else if y <= 3 + z := _lvl == 1 ? '5' : _lvl == 2 ? '15' : z + z + else if y <= 10 + z := _lvl == 1 ? '15' : _lvl == 2 ? '60' : z + z + else if y <= 30 + z := _lvl == 1 ? '60' : _lvl == 2 ? '240' : z + z + else if y <= 120 + z := _lvl == 1 ? '240' : _lvl == 2 ? 'D' : z + z + else if y <= 240 + z := _lvl == 1 ? 'D' : _lvl == 2 ? 'W' : z + z + else if y <= 1440 + z := _lvl == 1 ? 'W' : _lvl == 2 ? 'M' : z + z + else if y <= 10080 + z := _lvl == 1 ? 'M' : z + z + else + z := z + z + else + z := _lvl == 1 ? mtf_lvl1 : _lvl == 2 ? mtf_lvl2 : z + z + + z + +//----------------------- +// Mean Reversion Channel Function +//----------------------- +get_mrc() => + v_condition = 0 + v_meanline = source + v_meanrange = supersmoother(ta.tr, length) + + //-- Get Line value + if type == 'SuperSmoother' + v_meanline := supersmoother(source, length) + v_meanline + + if type != 'SuperSmoother' + v_meanline := SAK_smoothing(type, source, length) + v_meanline + + v_upband1 = v_meanline + v_meanrange * mult + v_loband1 = v_meanline - v_meanrange * mult + v_upband2 = v_meanline + v_meanrange * mult2 + v_loband2 = v_meanline - v_meanrange * mult2 + + //-- Check Condition + if close > v_meanline + v_upband2_1 = v_upband2 + v_meanrange * gradsize * 4 + v_upband2_9 = v_upband2 + v_meanrange * gradsize * -4 + if high >= v_upband2_9 and high < v_upband2 + v_condition := 1 + v_condition + else if high >= v_upband2 and high < v_upband2_1 + v_condition := 2 + v_condition + else if high >= v_upband2_1 + v_condition := 3 + v_condition + else if close <= v_meanline + v_meanrange + v_condition := 4 + v_condition + else + v_condition := 5 + v_condition + + if close < v_meanline + v_loband2_1 = v_loband2 - v_meanrange * gradsize * 4 + v_loband2_9 = v_loband2 - v_meanrange * gradsize * -4 + if low <= v_loband2_9 and low > v_loband2 + v_condition := -1 + v_condition + else if low <= v_loband2 and low > v_loband2_1 + v_condition := -2 + v_condition + else if low <= v_loband2_1 + v_condition := -3 + v_condition + else if close >= v_meanline + v_meanrange + v_condition := -4 + v_condition + else + v_condition := -5 + v_condition + + [v_meanline, v_meanrange, v_upband1, v_loband1, v_upband2, v_loband2, v_condition] + +//----------------------- +// MTF Analysis +//----------------------- + +get_stat(_cond) => + ret = 'Price at Mean Line\n' + if _cond == 1 + ret := 'Overbought (Weak)\n' + ret + else if _cond == 2 + ret := 'Overbought\n' + ret + else if _cond == 3 + ret := 'Overbought (Strong)\n' + ret + else if _cond == 4 + ret := 'Price Near Mean\n' + ret + else if _cond == 5 + ret := 'Price Above Mean\n' + ret + else if _cond == -1 + ret := 'Oversold (Weak)\n' + ret + else if _cond == -2 + ret := 'Oversold\n' + ret + else if _cond == -3 + ret := 'Oversold (Strong)\n' + ret + else if _cond == -4 + ret := 'Price Near Mean\n' + ret + else if _cond == -5 + ret := 'Price Below Mean\n' + ret + ret + +//----------------------- +// Chart Drawing Function +//----------------------- +format_price(x) => + y = str.tostring(x, '0.00000') + if x > 10 + y := str.tostring(x, '0.000') + y + if x > 1000 + y := str.tostring(x, '0.00') + y + y + +f_PriceLine(_ref, linecol) => + line.new(x1 = bar_index, x2 = bar_index - 1, y1 = _ref, y2 = _ref, extend = extend.left, color = linecol) + +f_MTFLabel(_txt, _yloc) => + label.new(x = time + math.round(ta.change(time) * 20), y = _yloc, xloc = xloc.bar_time, text = mtf_disp_typ == 'Always Display' ? _txt : 'Check MTF', tooltip = mtf_disp_typ == 'Always Display' ? '' : _txt, color = color.black, textcolor = color.white, size = size.normal, style = mtf_disp_typ == 'On Hover' and displayline ? label.style_label_lower_left : label.style_label_left, textalign = text.align_left) + +//} Function End + +//************************************************************************************************************ +// Calculate MA200, MA100, MA50 +//************************************************************************************************************ +// ————————————— 计算移动平均线 ————————————— +src = close +ma50 = exponential ? ta.ema(src, 50) : ta.sma(src, 50) +ma100 = exponential ? ta.ema(src, 100) : ta.sma(src, 100) +ma200 = exponential ? ta.ema(src, 200) : ta.sma(src, 200) + +// ————————————— 移动平均线颜色函数 ————————————— +maColor(ma, ref) => ma > ref ? color.lime : color.red + +//************************************************************************************************************ +// Calculate Channel +//************************************************************************************************************ +var tf_0 = timeframe.period +var tf_1 = get_tf(1) +var tf_2 = get_tf(2) + +[meanline, meanrange, upband1, loband1, upband2, loband2, condition] = get_mrc() +[mtf1_meanline, mtf1_meanrange, mtf1_upband1, mtf1_loband1, mtf1_upband2, mtf1_loband2, mtf1_condition] = request.security(syminfo.tickerid, tf_1, get_mrc()) +[mtf2_meanline, mtf2_meanrange, mtf2_upband1, mtf2_loband1, mtf2_upband2, mtf2_loband2, mtf2_condition] = request.security(syminfo.tickerid, tf_2, get_mrc()) + +//************************************************************************************************************ +// Drawing Start { +//************************************************************************************************************ +float p_meanline = drawchannel ? meanline : na +float p_upband1 = drawchannel ? upband1 : na +float p_loband1 = drawchannel ? loband1 : na +float p_upband2 = drawchannel ? upband2 : na +float p_loband2 = drawchannel ? loband2 : na + +// 保留 MEAN、R1、S1 的绘制用于警报,注释掉 R2、S2 +z = plot(p_meanline, color = color.new(color.black, 0), style = plot.style_line, title = ' Mean', linewidth = 2) +x1 = plot(p_upband1, color = color.new(color.black, 0), style = plot.style_line, title = ' R1', linewidth = 2) +x2 = plot(p_loband1, color = color.new(color.black, 0), style = plot.style_line, title = ' S1', linewidth = 2) +// 注释掉 R2、S2 的绘制以减少线条数量 +// y1 = plot(p_upband2, color = color.new(color.red, 50), style = plot.style_line, title = ' R2', linewidth = 1) +// y2 = plot(p_loband2, color = color.new(color.red, 50), style = plot.style_line, title = ' S2', linewidth = 1) + +// ————————————— 绘制 MA50/MA100/MA200 ————————————— +plot(show_ma_lines ? ma50 : na, color=maColor(ma50, ma100), linewidth=2, title='MA50', display=display.all) +plot(show_ma_lines ? ma100 : na, color=maColor(ma100, ma200), linewidth=2, title='MA100', display=display.all) +plot(show_ma_lines ? ma200 : na, color=color.rgb(25, 58, 243), linewidth=4, title='MA200', display=display.all) + +//----------------------- +// Draw zone +//----------------------- +//--- +var color1 = #FF0000 +var color2 = #FF4200 +var color3 = #FF5D00 +var color4 = #FF7400 +var color5 = #FF9700 +var color6 = #FFAE00 +var color7 = #FFC500 +var color8 = #FFCD00 +//--- +float upband2_1 = drawchannel and displayzone ? upband2 + meanrange * gradsize * 4 : na +float loband2_1 = drawchannel and displayzone ? loband2 - meanrange * gradsize * 4 : na +float upband2_2 = drawchannel and displayzone ? upband2 + meanrange * gradsize * 3 : na +float loband2_2 = drawchannel and displayzone ? loband2 - meanrange * gradsize * 3 : na +float upband2_3 = drawchannel and displayzone ? upband2 + meanrange * gradsize * 2 : na +float loband2_3 = drawchannel and displayzone ? loband2 - meanrange * gradsize * 2 : na +float upband2_4 = drawchannel and displayzone ? upband2 + meanrange * gradsize * 1 : na +float loband2_4 = drawchannel and displayzone ? loband2 - meanrange * gradsize * 1 : na +float upband2_5 = drawchannel and displayzone ? upband2 + meanrange * gradsize * 0 : na +float loband2_5 = drawchannel and displayzone ? loband2 - meanrange * gradsize * 0 : na +float upband2_6 = drawchannel and displayzone ? upband2 + meanrange * gradsize * -1 : na +float loband2_6 = drawchannel and displayzone ? loband2 - meanrange * gradsize * -1 : na +float upband2_7 = drawchannel and displayzone ? upband2 + meanrange * gradsize * -2 : na +float loband2_7 = drawchannel and displayzone ? loband2 - meanrange * gradsize * -2 : na +float upband2_8 = drawchannel and displayzone ? upband2 + meanrange * gradsize * -3 : na +float loband2_8 = drawchannel and displayzone ? loband2 - meanrange * gradsize * -3 : na +float upband2_9 = drawchannel and displayzone ? upband2 + meanrange * gradsize * -4 : na +float loband2_9 = drawchannel and displayzone ? loband2 - meanrange * gradsize * -4 : na + +//--- +// 注释掉扩展区域的 plot 以减少线条数量,避免超过 TradingView 64条线限制 +// 保留计算但不绘制,警报仍可使用这些值 +// plot_upband2_1 = plot(upband2_1, color = na, title = 'R2_1') +// plot_loband2_1 = plot(loband2_1, color = na, title = 'S2_1') + +// 注释掉其他隐藏的 plot +// plot_upband2_2 = plot(upband2_2, color = na, display = display.none) +// plot_loband2_2 = plot(loband2_2, color = na, display = display.none) +// plot_upband2_3 = plot(upband2_3, color = na, display = display.none) +// plot_loband2_3 = plot(loband2_3, color = na, display = display.none) +// plot_upband2_4 = plot(upband2_4, color = na, display = display.none) +// plot_loband2_4 = plot(loband2_4, color = na, display = display.none) +// plot_upband2_5 = plot(upband2_5, color = na, display = display.none) +// plot_loband2_5 = plot(loband2_5, color = na, display = display.none) +// plot_upband2_6 = plot(upband2_6, color = na, display = display.none) +// plot_loband2_6 = plot(loband2_6, color = na, display = display.none) +// plot_upband2_7 = plot(upband2_7, color = na, display = display.none) +// plot_loband2_7 = plot(loband2_7, color = na, display = display.none) +// plot_upband2_8 = plot(upband2_8, color = na, display = display.none) +// plot_loband2_8 = plot(loband2_8, color = na, display = display.none) + +// 注释掉 R2_9 和 S2_9 的 plot +// plot_upband2_9 = plot(upband2_9, color = na, title = 'R2_9') +// plot_loband2_9 = plot(loband2_9, color = na, title = 'S2_9') + +//--- +// 注释掉扩展区域的填充,减少绘制元素 +// fill(plot_upband2_1, plot_upband2_2, color = color1) +// fill(plot_loband2_1, plot_loband2_2, color = color1) +// fill(plot_upband2_2, plot_upband2_3, color = color2) +// fill(plot_loband2_2, plot_loband2_3, color = color2) +// fill(plot_upband2_3, plot_upband2_4, color = color3) +// fill(plot_loband2_3, plot_loband2_4, color = color3) +// fill(plot_upband2_4, plot_upband2_5, color = color4) +// fill(plot_loband2_4, plot_loband2_5, color = color4) +// fill(plot_upband2_5, plot_upband2_6, color = color5) +// fill(plot_loband2_5, plot_loband2_6, color = color5) +// fill(plot_upband2_6, plot_upband2_7, color = color6) +// fill(plot_loband2_6, plot_loband2_7, color = color6) +// fill(plot_upband2_7, plot_upband2_8, color = color7) +// fill(plot_loband2_7, plot_loband2_8, color = color7) +// fill(plot_upband2_8, plot_upband2_9, color = color8) +// fill(plot_loband2_8, plot_loband2_9, color = color8) + +//----------------------- +// Plot Extension +//----------------------- +if displayline and enable_mtf and mtf_disp_typ == 'Always Display' + displayline := false + displayline + +var line mean = na +line.delete(mean) +mean := displayline ? f_PriceLine(meanline, #FFCD00) : na +var line res1 = na +line.delete(res1) +res1 := displayline ? f_PriceLine(upband1, color.green) : na +var line sup1 = na +line.delete(sup1) +sup1 := displayline ? f_PriceLine(loband1, color.green) : na +var line res2 = na +line.delete(res2) +res2 := displayline ? f_PriceLine(upband2, color.red) : na +var line sup2 = na +line.delete(sup2) +sup2 := displayline ? f_PriceLine(loband2, color.red) : na + +//-------------- +// Prep MTF Label +//-------------- +var brl = '\n--------------------------------------' +dist_0 = 'Distance from Mean: ' + str.tostring((close - meanline) / close * 100, '#.##') + ' %' +dist_1 = 'Distance from Mean: ' + str.tostring((close - mtf1_meanline) / close * 100, '#.##') + ' %' +dist_2 = 'Distance from Mean: ' + str.tostring((close - mtf2_meanline) / close * 100, '#.##') + ' %' + +var title = 'Mean Reversion Channel\nMultiple TimeFrame Analysis' + brl +tf0 = '\n\nTimeframe: ' + tf_0 + ' (Current)\n\nStatus: ' + get_stat(condition) + dist_0 + brl + +tf1 = not timeframe.ismonthly ? '\n\nTimeframe: ' + tf_1 + '\n\nStatus: ' + get_stat(mtf1_condition) + dist_1 + brl : '' + +tf2 = not timeframe.isweekly and not timeframe.ismonthly ? '\n\nTimeframe: ' + tf_2 + '\n\nStatus: ' + get_stat(mtf2_condition) + dist_2 + brl : '' + +mtf_lbl = title + tf0 + tf1 + tf2 +var label label_mtf = na +label.delete(label_mtf) +label_mtf := enable_mtf ? f_MTFLabel(mtf_lbl, meanline) : na + +//************************************************************************************************************ +// Real-time Price Labels for Extended Lines (Placed on the right side of the last candle) +//************************************************************************************************************ + +// Define persistent label variables so that they update rather than create new labels each bar +var label mean_label = na +var label res1_label = na +var label sup1_label = na +var label res2_label = na +var label sup2_label = na +var label res2_9_label = na // Label for upband2_9 +var label sup2_9_label = na // Label for loband2_9 +var label res2_1_label = na // New label for upband2_1 +var label sup2_1_label = na // New label for loband2_1 + +if displayline and barstate.islast + // MEAN label + if na(mean_label) + mean_label := label.new(bar_index, meanline, "MEAN: " + format_price(meanline), xloc = xloc.bar_index, style = label.style_label_left, color = color.new(color.black, 0), textcolor = color.white) + else + label.set_xy(mean_label, bar_index, meanline) + label.set_text(mean_label, "MEAN: " + format_price(meanline)) + // R1 label + if na(res1_label) + res1_label := label.new(bar_index, upband1, "R1: " + format_price(upband1), xloc = xloc.bar_index, style = label.style_label_left, color = color.new(color.green, 0), textcolor = color.white) + else + label.set_xy(res1_label, bar_index, upband1) + label.set_text(res1_label, "R1: " + format_price(upband1)) + // S1 label + if na(sup1_label) + sup1_label := label.new(bar_index, loband1, "S1: " + format_price(loband1), xloc = xloc.bar_index, style = label.style_label_left, color = color.new(color.green, 0), textcolor = color.white) + else + label.set_xy(sup1_label, bar_index, loband1) + label.set_text(sup1_label, "S1: " + format_price(loband1)) + // R2 label + if na(res2_label) + res2_label := label.new(bar_index, upband2, "R2: " + format_price(upband2), xloc = xloc.bar_index, style = label.style_label_left, color = color.new(color.red, 0), textcolor = color.white) + else + label.set_xy(res2_label, bar_index, upband2) + label.set_text(res2_label, "R2: " + format_price(upband2)) + // S2 label + if na(sup2_label) + sup2_label := label.new(bar_index, loband2, "S2: " + format_price(loband2), xloc = xloc.bar_index, style = label.style_label_left, color = color.new(color.red, 0), textcolor = color.white) + else + label.set_xy(sup2_label, bar_index, loband2) + label.set_text(sup2_label, "S2: " + format_price(loband2)) + // R2_9 label (for upband2_9) + if na(res2_9_label) + res2_9_label := label.new(bar_index, upband2_9, "R2_9: " + format_price(upband2_9), xloc = xloc.bar_index, style = label.style_label_left, color = color.new(color.red, 50), textcolor = color.white) + else + label.set_xy(res2_9_label, bar_index, upband2_9) + label.set_text(res2_9_label, "R2_9: " + format_price(upband2_9)) + // S2_9 label (for loband2_9) + if na(sup2_9_label) + sup2_9_label := label.new(bar_index, loband2_9, "S2_9: " + format_price(loband2_9), xloc = xloc.bar_index, style = label.style_label_left, color = color.new(color.red, 50), textcolor = color.white) + else + label.set_xy(sup2_9_label, bar_index, loband2_9) + label.set_text(sup2_9_label, "S2_9: " + format_price(loband2_9)) + // R2_1 label (New for upband2_1) + if na(res2_1_label) + res2_1_label := label.new(bar_index, upband2_1, "R2_1: " + format_price(upband2_1), xloc = xloc.bar_index, style = label.style_label_left, color = color.new(color.red, 50), textcolor = color.white) + else + label.set_xy(res2_1_label, bar_index, upband2_1) + label.set_text(res2_1_label, "R2_1: " + format_price(upband2_1)) + // S2_1 label (New for loband2_1) + if na(sup2_1_label) + sup2_1_label := label.new(bar_index, loband2_1, "S2_1: " + format_price(loband2_1), xloc = xloc.bar_index, style = label.style_label_left, color = color.new(color.red, 50), textcolor = color.white) + else + label.set_xy(sup2_1_label, bar_index, loband2_1) + label.set_text(sup2_1_label, "S2_1: " + format_price(loband2_1)) + +//************************************************************************************************************ +// MA Price Labels (Placed on the right side of the last candle) +//************************************************************************************************************ +// ————————————— MA价格标签(单行 label.new) ————————————— +var label lbl50 = na +var label lbl100 = na +var label lbl200 = na + +if show_ma_labels and barstate.islast + if na(lbl50) + lbl50 := label.new(x=time, y=ma50, text='MA50: ' + str.tostring(ma50, '#.####'), xloc=xloc.bar_time, yloc=yloc.price, style=label.style_label_left, color=color.lime, textcolor=color.white) + else + label.set_xy(lbl50, x=time, y=ma50), label.set_text(lbl50, 'MA50: ' + str.tostring(ma50, '#.####')) + + if na(lbl100) + lbl100 := label.new(x=time, y=ma100, text='MA100: ' + str.tostring(ma100, '#.####'), xloc=xloc.bar_time, yloc=yloc.price, style=label.style_label_left, color=color.white, textcolor=color.black) + else + label.set_xy(lbl100, x=time, y=ma100), label.set_text(lbl100, 'MA100: ' + str.tostring(ma100, '#.####')) + + if na(lbl200) + lbl200 := label.new(x=time, y=ma200, text='MA200: ' + str.tostring(ma200, '#.####'), xloc=xloc.bar_time, yloc=yloc.price, style=label.style_label_left, color=color.white, textcolor=color.black) + else + label.set_xy(lbl200, x=time, y=ma200), label.set_text(lbl200, 'MA200: ' + str.tostring(ma200, '#.####')) +//************************************************************************************************************ +// ===== 统一警报系统 ===== +// 统一警报系统 - 只需添加一次警报即可捕获所有信号 +//************************************************************************************************************ + +// 警报频率限制 - 每分钟只触发一次 +var int last_alert_r1_breakout_up = 0 +var int last_alert_s1_breakout_down = 0 +var int last_alert_range_r1_s1 = 0 +var int last_alert_above_r1 = 0 +var int last_alert_below_s1 = 0 +var int last_alert_above_mean = 0 +var int last_alert_below_mean = 0 +var int last_alert_mean_above_ma200 = 0 +var int last_alert_mean_below_ma200 = 0 +var int last_alert_mean_above_ma50 = 0 +var int last_alert_mean_below_ma50 = 0 +var int last_alert_mean_above_ma100 = 0 +var int last_alert_mean_below_ma100 = 0 + +// 获取当前时间(分钟级别) +current_minute = math.floor(timenow / 60000) + +// 检测所有警报条件并生成对应的JSON消息 +alert_message = "" + +// 价格触碰关键位置警报 +// if ta.cross(close, meanline) +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow, "yyyy-MM-dd HH:mm:ss") + '","时间":"' + str.tostring(time, "yyyy-MM-dd HH:mm:ss") + '","事件":"碰到MEAN","位置":"MEAN","信号":"mean_touch"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// if ta.cross(close, upband1) +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow, "yyyy-MM-dd HH:mm:ss") + '","时间":"' + str.tostring(time, "yyyy-MM-dd HH:mm:ss") + '","事件":"碰到R1","位置":"R1","信号":"r1_touch"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// if ta.cross(close, loband1) +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow, "yyyy-MM-dd HH:mm:ss") + '","时间":"' + str.tostring(time, "yyyy-MM-dd HH:mm:ss") + '","事件":"碰到S1","位置":"S1","信号":"s1_touch"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// if ta.cross(close, upband2) +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow, "yyyy-MM-dd HH:mm:ss") + '","时间":"' + str.tostring(time, "yyyy-MM-dd HH:mm:ss") + '","事件":"碰到R2","位置":"R2","信号":"r2_touch"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// if ta.cross(close, loband2) +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow, "yyyy-MM-dd HH:mm:ss") + '","时间":"' + str.tostring(time, "yyyy-MM-dd HH:mm:ss") + '","事件":"碰到S2","位置":"S2","信号":"s2_touch"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// 价格区间警报 +// if close > meanline and close < upband1 +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于MEAN和R1之间","位置":"MEAN-R1","信号":"range_mean_r1"}' +// alert(alert_message, alert.freq_once_per_bar) + +// if close < meanline and close > loband1 +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于MEAN和S1之间","位置":"MEAN-S1","信号":"range_mean_s1"}' +// alert(alert_message, alert.freq_once_per_bar) + +// if close > upband1 and close < upband2 +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于R1和R2之间","位置":"R1-R2","信号":"range_r1_r2"}' +// alert(alert_message, alert.freq_once_per_bar) + +// if close < loband1 and close > loband2 +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于S1和S2之间","位置":"S1-S2","信号":"range_s1_s2"}' +// alert(alert_message, alert.freq_once_per_bar) + +// if close > upband1 and close < upband2_9 +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于R1和R2_9之间","位置":"R1-R2_9","信号":"range_r1_r2_9"}' +// alert(alert_message, alert.freq_once_per_bar) + +// if close > upband2_9 and close < upband2_1 +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于R2_9和R2_1之间","位置":"R2_9-R2_1","信号":"range_r2_9_r2_1"}' +// alert(alert_message, alert.freq_once_per_bar) + +// if close < loband1 and close > loband2_9 +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于S1和S2_9之间","位置":"S1-S2_9","信号":"range_s1_s2_9"}' +// alert(alert_message, alert.freq_once_per_bar) + +// if close < loband2_9 and close > loband2_1 +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于S2_9和S2_1之间","位置":"S2_9-S2_1","信号":"range_s2_9_s2_1"}' +// alert(alert_message, alert.freq_once_per_bar) + +// // 价格穿越警报 - 每分钟限制 +// if ta.crossover(close, upband1) and current_minute > last_alert_r1_breakout_up +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格上穿R1","位置":"R1","信号":"r1_breakout_up"}' +// alert(alert_message, alert.freq_once_per_bar_close) +// last_alert_r1_breakout_up := current_minute + +// if ta.crossunder(close, upband1) +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格下穿R1","位置":"R1","信号":"r1_breakout_down"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// if ta.crossunder(close, loband1) and current_minute > last_alert_s1_breakout_down +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格下穿S1","位置":"S1","信号":"s1_breakout_down"}' +// alert(alert_message, alert.freq_once_per_bar_close) +// last_alert_s1_breakout_down := current_minute + +// if ta.crossover(close, loband1) +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格上穿S1","位置":"S1","信号":"s1_breakout_up"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// if ta.crossover(close, meanline) +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格上穿MEAN","位置":"MEAN","信号":"mean_breakout_up"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// if ta.crossunder(close, meanline) +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格下穿MEAN","位置":"MEAN","信号":"mean_breakout_down"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// if ta.crossover(close, loband2_9) +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格上穿S2_9","位置":"S2_9","信号":"s2_9_breakout_up"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// if ta.crossunder(close, loband2_9) +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格下穿S2_9","位置":"S2_9","信号":"s2_9_breakout_down"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// if ta.crossover(close, upband2_9) +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格上穿R2_9","位置":"R2_9","信号":"r2_9_breakout_up"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// if ta.crossunder(close, upband2_9) +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格下穿R2_9","位置":"R2_9","信号":"r2_9_breakout_down"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// ===== 新增的5个警报条件 - 每分钟限制 ===== +// 1. 价格处于R1和S1之间时 +// if close <= upband1 and close >= loband1 and current_minute > last_alert_range_r1_s1 +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于R1和S1之间","位置":"R1-S1区间","信号":"range_r1_s1"}' +// alert(alert_message, alert.freq_once_per_bar) +// last_alert_range_r1_s1 := current_minute + +// // 2. 价格处于R1以上时 +// if close > upband1 and current_minute > last_alert_above_r1 +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于R1以上","位置":"R1以上","信号":"above_r1"}' +// alert(alert_message, alert.freq_once_per_bar) +// last_alert_above_r1 := current_minute + +// // 3. 价格处于S1以下时 +// if close < loband1 and current_minute > last_alert_below_s1 +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于S1以下","位置":"S1以下","信号":"below_s1"}' +// alert(alert_message, alert.freq_once_per_bar) +// last_alert_below_s1 := current_minute + +// // 4. 价格处于MEAN以上时 +// if close > meanline and current_minute > last_alert_above_mean +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于MEAN以上","位置":"MEAN以上","信号":"above_mean"}' +// alert(alert_message, alert.freq_once_per_bar) +// last_alert_above_mean := current_minute + +// // 5. 价格处于MEAN以下时 +// if close < meanline and current_minute > last_alert_below_mean +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于MEAN以下","位置":"MEAN以下","信号":"below_mean"}' +// alert(alert_message, alert.freq_once_per_bar) +// last_alert_below_mean := current_minute + +// ===== 新增的MA相关警报条件 - 每分钟限制 ===== +// 计算MEAN线与各MA的距离 +mean_ma200_distance = math.abs(meanline - ma200) +mean_ma50_distance = math.abs(meanline - ma50) +mean_ma100_distance = math.abs(meanline - ma100) + +// 6. MEAN线价格处于MA200以上时 +if meanline > ma200 and current_minute > last_alert_mean_above_ma200 + alert_message := '{"指标名称":"MA200","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","MA50":"' + str.tostring(ma50, '#.####') + '","MA100":"' + str.tostring(ma100, '#.####') + '","MA200":"' + str.tostring(ma200, '#.####') + '","距离(美元)":"' + str.tostring(mean_ma200_distance, '#.##') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"MEAN线处于MA200以上","位置":"MA200以上"}' + alert(alert_message, alert.freq_once_per_bar) + last_alert_mean_above_ma200 := current_minute + +// 7. MEAN线价格处于MA200以下时 +if meanline < ma200 and current_minute > last_alert_mean_below_ma200 + alert_message := '{"指标名称":"MA200","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","MA50":"' + str.tostring(ma50, '#.####') + '","MA100":"' + str.tostring(ma100, '#.####') + '","MA200":"' + str.tostring(ma200, '#.####') + '","距离(美元)":"' + str.tostring(mean_ma200_distance, '#.##') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"MEAN线处于MA200以下","位置":"MA200以下"}' + alert(alert_message, alert.freq_once_per_bar) + last_alert_mean_below_ma200 := current_minute + +// 8. MEAN线价格处于MA50以上时 +if meanline > ma50 and current_minute > last_alert_mean_above_ma50 + alert_message := '{"指标名称":"MA200","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","MA50":"' + str.tostring(ma50, '#.####') + '","MA100":"' + str.tostring(ma100, '#.####') + '","MA200":"' + str.tostring(ma200, '#.####') + '","距离(美元)":"' + str.tostring(mean_ma50_distance, '#.##') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"MEAN线处于MA50以上","位置":"MA50以上"}' + alert(alert_message, alert.freq_once_per_bar) + last_alert_mean_above_ma50 := current_minute + +// 9. MEAN线价格处于MA50以下时 +if meanline < ma50 and current_minute > last_alert_mean_below_ma50 + alert_message := '{"指标名称":"MA200","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","MA50":"' + str.tostring(ma50, '#.####') + '","MA100":"' + str.tostring(ma100, '#.####') + '","MA200":"' + str.tostring(ma200, '#.####') + '","距离(美元)":"' + str.tostring(mean_ma50_distance, '#.##') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"MEAN线处于MA50以下","位置":"MA50以下"}' + alert(alert_message, alert.freq_once_per_bar) + last_alert_mean_below_ma50 := current_minute + +// 10. MEAN线价格处于MA100以上时 +if meanline > ma100 and current_minute > last_alert_mean_above_ma100 + alert_message := '{"指标名称":"MA200","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","MA50":"' + str.tostring(ma50, '#.####') + '","MA100":"' + str.tostring(ma100, '#.####') + '","MA200":"' + str.tostring(ma200, '#.####') + '","距离(美元)":"' + str.tostring(mean_ma100_distance, '#.##') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"MEAN线处于MA100以上","位置":"MA100以上"}' + alert(alert_message, alert.freq_once_per_bar) + last_alert_mean_above_ma100 := current_minute + +// 11. MEAN线价格处于MA100以下时 +if meanline < ma100 and current_minute > last_alert_mean_below_ma100 + alert_message := '{"指标名称":"MA200","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","MA50":"' + str.tostring(ma50, '#.####') + '","MA100":"' + str.tostring(ma100, '#.####') + '","MA200":"' + str.tostring(ma200, '#.####') + '","距离(美元)":"' + str.tostring(mean_ma100_distance, '#.##') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"MEAN线处于MA100以下","位置":"MA100以下"}' + alert(alert_message, alert.freq_once_per_bar) + last_alert_mean_below_ma100 := current_minute + +// ===== 传统警报条件(保留兼容性)===== +// 注意:使用统一警报系统时,建议只使用上面的alert()函数 +// 以下alertcondition保留用于需要单独设置警报的情况 + +// 创建用于警报的plot变量 +plot(ma50, title = 'MA50值', display = display.none) +plot(ma100, title = 'MA100值', display = display.none) +plot(ma200, title = 'MA200值', display = display.none) +plot(mean_ma200_distance, title = 'MEAN距离MA200', display = display.none) +plot(mean_ma50_distance, title = 'MEAN距离MA50', display = display.none) +plot(mean_ma100_distance, title = 'MEAN距离MA100', display = display.none) + +// 为传统警报创建隐藏的plot变量(不显示但支持警报引用) +plot(upband2, title = ' R2', display = display.none) // R2 隐藏绘制用于警报 +plot(loband2, title = ' S2', display = display.none) // S2 隐藏绘制用于警报 +plot(upband2_1, title = 'R2_1', display = display.none) +plot(loband2_1, title = 'S2_1', display = display.none) +plot(upband2_9, title = 'R2_9', display = display.none) +plot(loband2_9, title = 'S2_9', display = display.none) + +// 价格穿越警报 +alertcondition(ta.crossover(close, upband1), title = '价格上穿R1', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格上穿R1","位置":"R1","信号":"r1_breakout_up"}') + +alertcondition(ta.crossunder(close, upband1), title = '价格下穿R1', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格下穿R1","位置":"R1","信号":"r1_breakout_down"}') + +alertcondition(ta.crossunder(close, loband1), title = '价格下穿S1', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格下穿S1","位置":"S1","信号":"s1_breakout_down"}') + +alertcondition(ta.crossover(close, loband1), title = '价格上穿S1', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格上穿S1","位置":"S1","信号":"s1_breakout_up"}') + +alertcondition(ta.crossover(close, meanline), title = '价格上穿MEAN', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格上穿MEAN","位置":"MEAN","信号":"mean_breakout_up"}') + +alertcondition(ta.crossunder(close, meanline), title = '价格下穿MEAN', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格下穿MEAN","位置":"MEAN","信号":"mean_breakout_down"}') + +// R2和S2穿越警报 +alertcondition(ta.crossover(close, upband2), title = '价格上穿R2', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格上穿R2","位置":"R2","信号":"r2_breakout_up"}') + +alertcondition(ta.crossunder(close, upband2), title = '价格下穿R2', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格下穿R2","位置":"R2","信号":"r2_breakout_down"}') + +alertcondition(ta.crossunder(close, loband2), title = '价格下穿S2', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格下穿S2","位置":"S2","信号":"s2_breakout_down"}') + +alertcondition(ta.crossover(close, loband2), title = '价格上穿S2', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格上穿S2","位置":"S2","信号":"s2_breakout_up"}') + +// 扩展区域穿越警报 +alertcondition(ta.crossover(close, upband2_9), title = '价格上穿R2_9', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格上穿R2_9","位置":"R2_9","信号":"r2_9_breakout_up"}') + +alertcondition(ta.crossunder(close, upband2_9), title = '价格下穿R2_9', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格下穿R2_9","位置":"R2_9","信号":"r2_9_breakout_down"}') + +alertcondition(ta.crossunder(close, loband2_9), title = '价格下穿S2_9', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格下穿S2_9","位置":"S2_9","信号":"s2_9_breakout_down"}') + +alertcondition(ta.crossover(close, loband2_9), title = '价格上穿S2_9', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格上穿S2_9","位置":"S2_9","信号":"s2_9_breakout_up"}') + +alertcondition(ta.crossover(close, upband2_1), title = '价格上穿R2_1', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格上穿R2_1","位置":"R2_1","信号":"r2_1_breakout_up"}') + +alertcondition(ta.crossunder(close, upband2_1), title = '价格下穿R2_1', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格下穿R2_1","位置":"R2_1","信号":"r2_1_breakout_down"}') + +alertcondition(ta.crossunder(close, loband2_1), title = '价格下穿S2_1', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格下穿S2_1","位置":"S2_1","信号":"s2_1_breakout_down"}') + +alertcondition(ta.crossover(close, loband2_1), title = '价格上穿S2_1', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格上穿S2_1","位置":"S2_1","信号":"s2_1_breakout_up"}') + +// 价格区间状态警报 +alertcondition(close <= upband1 and close >= loband1, title = '价格处于R1和S1之间', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格处于R1和S1之间","位置":"R1-S1区间","信号":"range_r1_s1"}') + +alertcondition(close > upband1, title = '价格处于R1以上', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格处于R1以上","位置":"R1以上","信号":"above_r1"}') + +alertcondition(close < loband1, title = '价格处于S1以下', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格处于S1以下","位置":"S1以下","信号":"below_s1"}') + +alertcondition(close > meanline, title = '价格处于MEAN以上', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格处于MEAN以上","位置":"MEAN以上","信号":"above_mean"}') + +alertcondition(close < meanline, title = '价格处于MEAN以下', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格处于MEAN以下","位置":"MEAN以下","信号":"below_mean"}') + +// 区间范围警报 +alertcondition(close > upband1 and close < upband2, title = '价格处于R1和R2之间', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格处于R1和R2之间","位置":"R1-R2","信号":"range_r1_r2"}') + +alertcondition(close < loband1 and close > loband2, title = '价格处于S1和S2之间', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格处于S1和S2之间","位置":"S1-S2","信号":"range_s1_s2"}') + +alertcondition(close > upband2 and close < upband2_1, title = '价格处于R2和R2_1之间', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格处于R2和R2_1之间","位置":"R2-R2_1","信号":"range_r2_r2_1"}') + +alertcondition(close < loband2 and close > loband2_1, title = '价格处于S2和S2_1之间', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格处于S2和S2_1之间","位置":"S2-S2_1","信号":"range_s2_s2_1"}') + +// 极端区域警报 +alertcondition(close > upband2_1, title = '价格处于R2_1以上', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格处于R2_1以上","位置":"R2_1以上","信号":"above_r2_1"}') + +alertcondition(close < loband2_1, title = '价格处于S2_1以下', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格处于S2_1以下","位置":"S2_1以下","信号":"below_s2_1"}') + +// ===== 新增的MA200相关传统警报条件 ===== +// MEAN线与MA200关系警报 +alertcondition(meanline > ma200, title = 'MEAN线处于MA200以上', message = '{"指标名称":"MA200","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","MA50":"{{plot("MA50值")}}","MA100":"{{plot("MA100值")}}","MA200":"{{plot("MA200值")}}","距离(美元)":"{{plot("MEAN距离MA200")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"MEAN线处于MA200以上","位置":"MA200以上","信号":"mean_above_ma200"}') + +alertcondition(meanline < ma200, title = 'MEAN线处于MA200以下', message = '{"指标名称":"MA200","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","MA50":"{{plot("MA50值")}}","MA100":"{{plot("MA100值")}}","MA200":"{{plot("MA200值")}}","距离(美元)":"{{plot("MEAN距离MA200")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"MEAN线处于MA200以下","位置":"MA200以下","信号":"mean_below_ma200"}') + +// MEAN线与MA50关系警报 +alertcondition(meanline > ma50, title = 'MEAN线处于MA50以上', message = '{"指标名称":"MA200","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","MA50":"{{plot("MA50值")}}","MA100":"{{plot("MA100值")}}","MA200":"{{plot("MA200值")}}","距离(美元)":"{{plot("MEAN距离MA50")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"MEAN线处于MA50以上","位置":"MA50以上","信号":"mean_above_ma50"}') + +alertcondition(meanline < ma50, title = 'MEAN线处于MA50以下', message = '{"指标名称":"MA200","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","MA50":"{{plot("MA50值")}}","MA100":"{{plot("MA100值")}}","MA200":"{{plot("MA200值")}}","距离(美元)":"{{plot("MEAN距离MA50")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"MEAN线处于MA50以下","位置":"MA50以下","信号":"mean_below_ma50"}') + +// MEAN线与MA100关系警报 +alertcondition(meanline > ma100, title = 'MEAN线处于MA100以上', message = '{"指标名称":"MA200","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","MA50":"{{plot("MA50值")}}","MA100":"{{plot("MA100值")}}","MA200":"{{plot("MA200值")}}","距离(美元)":"{{plot("MEAN距离MA100")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"MEAN线处于MA100以上","位置":"MA100以上","信号":"mean_above_ma100"}') + +alertcondition(meanline < ma100, title = 'MEAN线处于MA100以下', message = '{"指标名称":"MA200","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","MA50":"{{plot("MA50值")}}","MA100":"{{plot("MA100值")}}","MA200":"{{plot("MA200值")}}","距离(美元)":"{{plot("MEAN距离MA100")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"MEAN线处于MA100以下","位置":"MA100以下","信号":"mean_below_ma100"}') \ No newline at end of file diff --git a/mrc.pine b/mrc.pine new file mode 100644 index 0000000..b33a2a5 --- /dev/null +++ b/mrc.pine @@ -0,0 +1,715 @@ +//@version=6 +indicator('Mean Reversion Channel - 带价格标签', shorttitle = 'MRC2', overlay = true, format = format.inherit) + +//************************************************************************************************************ +// Parameter +//************************************************************************************************************ + +indiSet = input(false, '═════════ MRC Parameter ════════') +source = input(hlc3, title = 'Price Source') +type = input.string('SuperSmoother', title = 'Filter Type', options = ['SuperSmoother', 'Ehlers EMA', 'Gaussian', 'Butterworth', 'BandStop', 'SMA', 'EMA', 'RMA']) +length = input.int(200, title = 'Lookback Period', minval = 1) +innermult = input.float(1.0, title = 'Inner Channel Size Multiplier', minval = 0.1) +outermult = input.float(2.415, title = 'Outer Channel Size Multiplier', minval = 0.1) + +ChartSet = input(false, '═════════ Chart Setting ════════') +drawchannel = input(true, title = 'Draw Channel') +displayzone = input(true, title = 'Draw Zone (With Channel)') +zonetransp = input.int(60, title = 'Zone Transparency', minval = 0, maxval = 100) +displayline = input(true, title = 'Display Line Extension') + +MTFSet = input(false, '═════════ MTF Setting ════════') +enable_mtf = input(true, title = 'Enable Multiple TimeFrame Analysis') +mtf_disp_typ = input.string('On Hover', title = 'MTF Display Type', options = ['Always Display', 'On Hover']) +mtf_typ = input.string('Auto', title = 'Multiple TimeFrame Type', options = ['Auto', 'Custom']) +mtf_lvl1 = input.timeframe('D', title = 'Custom MTF Level 1') +mtf_lvl2 = input.timeframe('W', title = 'Custom MTF Level 2') + +//************************************************************************************************************ +// Functions Start { +//************************************************************************************************************ +var pi = 2 * math.asin(1) +var mult = pi * innermult +var mult2 = pi * outermult +var gradsize = 0.5 +var gradtransp = zonetransp + +//----------------------- +// Ehler SwissArmyKnife Function +//----------------------- +SAK_smoothing(_type, _src, _length) => + c0 = 1.0 + c1 = 0.0 + b0 = 1.0 + b1 = 0.0 + b2 = 0.0 + a1 = 0.0 + a2 = 0.0 + alpha = 0.0 + beta = 0.0 + gamma = 0.0 + cycle = 2 * pi / _length + + if _type == 'Ehlers EMA' + alpha := (math.cos(cycle) + math.sin(cycle) - 1) / math.cos(cycle) + b0 := alpha + a1 := 1 - alpha + a1 + if _type == 'Gaussian' + beta := 2.415 * (1 - math.cos(cycle)) + alpha := -beta + math.sqrt(beta * beta + 2 * beta) + c0 := alpha * alpha + a1 := 2 * (1 - alpha) + a2 := -(1 - alpha) * (1 - alpha) + a2 + if _type == 'Butterworth' + beta := 2.415 * (1 - math.cos(cycle)) + alpha := -beta + math.sqrt(beta * beta + 2 * beta) + c0 := alpha * alpha / 4 + b1 := 2 + b2 := 1 + a1 := 2 * (1 - alpha) + a2 := -(1 - alpha) * (1 - alpha) + a2 + if _type == 'BandStop' + beta := math.cos(cycle) + gamma := 1 / math.cos(cycle * 2 * 0.1) // delta default to 0.1. Acceptable delta -- 0.05 + s_a1 = math.exp(-math.sqrt(2) * pi / _length) + s_b1 = 2 * s_a1 * math.cos(math.sqrt(2) * pi / _length) + s_c3 = -math.pow(s_a1, 2) + s_c2 = s_b1 + s_c1 = 1 - s_c2 - s_c3 + ss = 0.0 + ss := s_c1 * _src + s_c2 * nz(ss[1], _src[1]) + s_c3 * nz(ss[2], _src[2]) + ss + +//----------------------- +// Auto TimeFrame Function +//----------------------- +// ————— Converts current chart resolution into a float minutes value. +f_resInMinutes() => + _resInMinutes = timeframe.multiplier * (timeframe.isseconds ? 1. / 60 : timeframe.isminutes ? 1. : timeframe.isdaily ? 60. * 24 : timeframe.isweekly ? 60. * 24 * 7 : timeframe.ismonthly ? 60. * 24 * 30.4375 : na) + _resInMinutes + +get_tf(_lvl) => + y = f_resInMinutes() + z = timeframe.period + if mtf_typ == 'Auto' + if y < 1 + z := _lvl == 1 ? '1' : _lvl == 2 ? '5' : z + z + else if y <= 3 + z := _lvl == 1 ? '5' : _lvl == 2 ? '15' : z + z + else if y <= 10 + z := _lvl == 1 ? '15' : _lvl == 2 ? '60' : z + z + else if y <= 30 + z := _lvl == 1 ? '60' : _lvl == 2 ? '240' : z + z + else if y <= 120 + z := _lvl == 1 ? '240' : _lvl == 2 ? 'D' : z + z + else if y <= 240 + z := _lvl == 1 ? 'D' : _lvl == 2 ? 'W' : z + z + else if y <= 1440 + z := _lvl == 1 ? 'W' : _lvl == 2 ? 'M' : z + z + else if y <= 10080 + z := _lvl == 1 ? 'M' : z + z + else + z := z + z + else + z := _lvl == 1 ? mtf_lvl1 : _lvl == 2 ? mtf_lvl2 : z + z + + z + +//----------------------- +// Mean Reversion Channel Function +//----------------------- +get_mrc() => + v_condition = 0 + v_meanline = source + v_meanrange = supersmoother(ta.tr, length) + + //-- Get Line value + if type == 'SuperSmoother' + v_meanline := supersmoother(source, length) + v_meanline + + if type != 'SuperSmoother' + v_meanline := SAK_smoothing(type, source, length) + v_meanline + + v_upband1 = v_meanline + v_meanrange * mult + v_loband1 = v_meanline - v_meanrange * mult + v_upband2 = v_meanline + v_meanrange * mult2 + v_loband2 = v_meanline - v_meanrange * mult2 + + //-- Check Condition + if close > v_meanline + v_upband2_1 = v_upband2 + v_meanrange * gradsize * 4 + v_upband2_9 = v_upband2 + v_meanrange * gradsize * -4 + if high >= v_upband2_9 and high < v_upband2 + v_condition := 1 + v_condition + else if high >= v_upband2 and high < v_upband2_1 + v_condition := 2 + v_condition + else if high >= v_upband2_1 + v_condition := 3 + v_condition + else if close <= v_meanline + v_meanrange + v_condition := 4 + v_condition + else + v_condition := 5 + v_condition + + if close < v_meanline + v_loband2_1 = v_loband2 - v_meanrange * gradsize * 4 + v_loband2_9 = v_loband2 - v_meanrange * gradsize * -4 + if low <= v_loband2_9 and low > v_loband2 + v_condition := -1 + v_condition + else if low <= v_loband2 and low > v_loband2_1 + v_condition := -2 + v_condition + else if low <= v_loband2_1 + v_condition := -3 + v_condition + else if close >= v_meanline + v_meanrange + v_condition := -4 + v_condition + else + v_condition := -5 + v_condition + + [v_meanline, v_meanrange, v_upband1, v_loband1, v_upband2, v_loband2, v_condition] + +//----------------------- +// MTF Analysis +//----------------------- + +get_stat(_cond) => + ret = 'Price at Mean Line\n' + if _cond == 1 + ret := 'Overbought (Weak)\n' + ret + else if _cond == 2 + ret := 'Overbought\n' + ret + else if _cond == 3 + ret := 'Overbought (Strong)\n' + ret + else if _cond == 4 + ret := 'Price Near Mean\n' + ret + else if _cond == 5 + ret := 'Price Above Mean\n' + ret + else if _cond == -1 + ret := 'Oversold (Weak)\n' + ret + else if _cond == -2 + ret := 'Oversold\n' + ret + else if _cond == -3 + ret := 'Oversold (Strong)\n' + ret + else if _cond == -4 + ret := 'Price Near Mean\n' + ret + else if _cond == -5 + ret := 'Price Below Mean\n' + ret + ret + +//----------------------- +// Chart Drawing Function +//----------------------- +format_price(x) => + y = str.tostring(x, '0.00000') + if x > 10 + y := str.tostring(x, '0.000') + y + if x > 1000 + y := str.tostring(x, '0.00') + y + y + +f_PriceLine(_ref, linecol) => + line.new(x1 = bar_index, x2 = bar_index - 1, y1 = _ref, y2 = _ref, extend = extend.left, color = linecol) + +f_MTFLabel(_txt, _yloc) => + label.new(x = time + math.round(ta.change(time) * 20), y = _yloc, xloc = xloc.bar_time, text = mtf_disp_typ == 'Always Display' ? _txt : 'Check MTF', tooltip = mtf_disp_typ == 'Always Display' ? '' : _txt, color = color.black, textcolor = color.white, size = size.normal, style = mtf_disp_typ == 'On Hover' and displayline ? label.style_label_lower_left : label.style_label_left, textalign = text.align_left) + +//} Function End + +//************************************************************************************************************ +// Calculate Channel +//************************************************************************************************************ +var tf_0 = timeframe.period +var tf_1 = get_tf(1) +var tf_2 = get_tf(2) + +[meanline, meanrange, upband1, loband1, upband2, loband2, condition] = get_mrc() +[mtf1_meanline, mtf1_meanrange, mtf1_upband1, mtf1_loband1, mtf1_upband2, mtf1_loband2, mtf1_condition] = request.security(syminfo.tickerid, tf_1, get_mrc()) +[mtf2_meanline, mtf2_meanrange, mtf2_upband1, mtf2_loband1, mtf2_upband2, mtf2_loband2, mtf2_condition] = request.security(syminfo.tickerid, tf_2, get_mrc()) + +//************************************************************************************************************ +// Drawing Start { +//************************************************************************************************************ +float p_meanline = drawchannel ? meanline : na +float p_upband1 = drawchannel ? upband1 : na +float p_loband1 = drawchannel ? loband1 : na +float p_upband2 = drawchannel ? upband2 : na +float p_loband2 = drawchannel ? loband2 : na + +z = plot(p_meanline, color = color.new(color.black, 0), style = plot.style_line, title = ' Mean', linewidth = 2) +x1 = plot(p_upband1, color = color.new(color.black, 0), style = plot.style_line, title = ' R1', linewidth = 2) +x2 = plot(p_loband1, color = color.new(color.black, 0), style = plot.style_line, title = ' S1', linewidth = 2) +y1 = plot(p_upband2, color = color.new(color.red, 50), style = plot.style_line, title = ' R2', linewidth = 1) +y2 = plot(p_loband2, color = color.new(color.red, 50), style = plot.style_line, title = ' S2', linewidth = 1) + +//----------------------- +// Draw zone +//----------------------- +//--- +var color1 = #FF0000 +var color2 = #FF4200 +var color3 = #FF5D00 +var color4 = #FF7400 +var color5 = #FF9700 +var color6 = #FFAE00 +var color7 = #FFC500 +var color8 = #FFCD00 +//--- +float upband2_1 = drawchannel and displayzone ? upband2 + meanrange * gradsize * 4 : na +float loband2_1 = drawchannel and displayzone ? loband2 - meanrange * gradsize * 4 : na +float upband2_2 = drawchannel and displayzone ? upband2 + meanrange * gradsize * 3 : na +float loband2_2 = drawchannel and displayzone ? loband2 - meanrange * gradsize * 3 : na +float upband2_3 = drawchannel and displayzone ? upband2 + meanrange * gradsize * 2 : na +float loband2_3 = drawchannel and displayzone ? loband2 - meanrange * gradsize * 2 : na +float upband2_4 = drawchannel and displayzone ? upband2 + meanrange * gradsize * 1 : na +float loband2_4 = drawchannel and displayzone ? loband2 - meanrange * gradsize * 1 : na +float upband2_5 = drawchannel and displayzone ? upband2 + meanrange * gradsize * 0 : na +float loband2_5 = drawchannel and displayzone ? loband2 - meanrange * gradsize * 0 : na +float upband2_6 = drawchannel and displayzone ? upband2 + meanrange * gradsize * -1 : na +float loband2_6 = drawchannel and displayzone ? loband2 - meanrange * gradsize * -1 : na +float upband2_7 = drawchannel and displayzone ? upband2 + meanrange * gradsize * -2 : na +float loband2_7 = drawchannel and displayzone ? loband2 - meanrange * gradsize * -2 : na +float upband2_8 = drawchannel and displayzone ? upband2 + meanrange * gradsize * -3 : na +float loband2_8 = drawchannel and displayzone ? loband2 - meanrange * gradsize * -3 : na +float upband2_9 = drawchannel and displayzone ? upband2 + meanrange * gradsize * -4 : na +float loband2_9 = drawchannel and displayzone ? loband2 - meanrange * gradsize * -4 : na + +//--- +// 为了让警报消息能正确引用这些值,我们需要创建可见的 plot +// R2_1 和 S2_1 (plot_5 和 plot_6) +plot_upband2_1 = plot(upband2_1, color = na, title = 'R2_1') +plot_loband2_1 = plot(loband2_1, color = na, title = 'S2_1') + +// 其他隐藏的 plot 用于填充 +plot_upband2_2 = plot(upband2_2, color = na, display = display.none) +plot_loband2_2 = plot(loband2_2, color = na, display = display.none) +plot_upband2_3 = plot(upband2_3, color = na, display = display.none) +plot_loband2_3 = plot(loband2_3, color = na, display = display.none) +plot_upband2_4 = plot(upband2_4, color = na, display = display.none) +plot_loband2_4 = plot(loband2_4, color = na, display = display.none) +plot_upband2_5 = plot(upband2_5, color = na, display = display.none) +plot_loband2_5 = plot(loband2_5, color = na, display = display.none) +plot_upband2_6 = plot(upband2_6, color = na, display = display.none) +plot_loband2_6 = plot(loband2_6, color = na, display = display.none) +plot_upband2_7 = plot(upband2_7, color = na, display = display.none) +plot_loband2_7 = plot(loband2_7, color = na, display = display.none) +plot_upband2_8 = plot(upband2_8, color = na, display = display.none) +plot_loband2_8 = plot(loband2_8, color = na, display = display.none) + +// 在这里添加 R2_9 和 S2_9 的 plot,确保它们在正确的位置 +// 这些将成为 plot_19 和 plot_20 +plot_upband2_9 = plot(upband2_9, color = na, title = 'R2_9') +plot_loband2_9 = plot(loband2_9, color = na, title = 'S2_9') + +//--- +fill(plot_upband2_1, plot_upband2_2, color = color1) +fill(plot_loband2_1, plot_loband2_2, color = color1) +fill(plot_upband2_2, plot_upband2_3, color = color2) +fill(plot_loband2_2, plot_loband2_3, color = color2) +fill(plot_upband2_3, plot_upband2_4, color = color3) +fill(plot_loband2_3, plot_loband2_4, color = color3) +fill(plot_upband2_4, plot_upband2_5, color = color4) +fill(plot_loband2_4, plot_loband2_5, color = color4) +fill(plot_upband2_5, plot_upband2_6, color = color5) +fill(plot_loband2_5, plot_loband2_6, color = color5) +fill(plot_upband2_6, plot_upband2_7, color = color6) +fill(plot_loband2_6, plot_loband2_7, color = color6) +fill(plot_upband2_7, plot_upband2_8, color = color7) +fill(plot_loband2_7, plot_loband2_8, color = color7) +fill(plot_upband2_8, plot_upband2_9, color = color8) +fill(plot_loband2_8, plot_loband2_9, color = color8) + +//----------------------- +// Plot Extension +//----------------------- +if displayline and enable_mtf and mtf_disp_typ == 'Always Display' + displayline := false + displayline + +var line mean = na +line.delete(mean) +mean := displayline ? f_PriceLine(meanline, #FFCD00) : na +var line res1 = na +line.delete(res1) +res1 := displayline ? f_PriceLine(upband1, color.green) : na +var line sup1 = na +line.delete(sup1) +sup1 := displayline ? f_PriceLine(loband1, color.green) : na +var line res2 = na +line.delete(res2) +res2 := displayline ? f_PriceLine(upband2, color.red) : na +var line sup2 = na +line.delete(sup2) +sup2 := displayline ? f_PriceLine(loband2, color.red) : na + +//-------------- +// Prep MTF Label +//-------------- +var brl = '\n--------------------------------------' +dist_0 = 'Distance from Mean: ' + str.tostring((close - meanline) / close * 100, '#.##') + ' %' +dist_1 = 'Distance from Mean: ' + str.tostring((close - mtf1_meanline) / close * 100, '#.##') + ' %' +dist_2 = 'Distance from Mean: ' + str.tostring((close - mtf2_meanline) / close * 100, '#.##') + ' %' + +var title = 'Mean Reversion Channel\nMultiple TimeFrame Analysis' + brl +tf0 = '\n\nTimeframe: ' + tf_0 + ' (Current)\n\nStatus: ' + get_stat(condition) + dist_0 + brl + +tf1 = not timeframe.ismonthly ? '\n\nTimeframe: ' + tf_1 + '\n\nStatus: ' + get_stat(mtf1_condition) + dist_1 + brl : '' + +tf2 = not timeframe.isweekly and not timeframe.ismonthly ? '\n\nTimeframe: ' + tf_2 + '\n\nStatus: ' + get_stat(mtf2_condition) + dist_2 + brl : '' + +mtf_lbl = title + tf0 + tf1 + tf2 +var label label_mtf = na +label.delete(label_mtf) +label_mtf := enable_mtf ? f_MTFLabel(mtf_lbl, meanline) : na + +//************************************************************************************************************ +// Real-time Price Labels for Extended Lines (Placed on the right side of the last candle) +//************************************************************************************************************ + +// Define persistent label variables so that they update rather than create new labels each bar +var label mean_label = na +var label res1_label = na +var label sup1_label = na +var label res2_label = na +var label sup2_label = na +var label res2_9_label = na // Label for upband2_9 +var label sup2_9_label = na // Label for loband2_9 +var label res2_1_label = na // New label for upband2_1 +var label sup2_1_label = na // New label for loband2_1 + +if displayline and barstate.islast + // MEAN label + if na(mean_label) + mean_label := label.new(bar_index, meanline, "MEAN: " + format_price(meanline), xloc = xloc.bar_index, style = label.style_label_left, color = color.new(color.black, 0), textcolor = color.white) + else + label.set_xy(mean_label, bar_index, meanline) + label.set_text(mean_label, "MEAN: " + format_price(meanline)) + // R1 label + if na(res1_label) + res1_label := label.new(bar_index, upband1, "R1: " + format_price(upband1), xloc = xloc.bar_index, style = label.style_label_left, color = color.new(color.green, 0), textcolor = color.white) + else + label.set_xy(res1_label, bar_index, upband1) + label.set_text(res1_label, "R1: " + format_price(upband1)) + // S1 label + if na(sup1_label) + sup1_label := label.new(bar_index, loband1, "S1: " + format_price(loband1), xloc = xloc.bar_index, style = label.style_label_left, color = color.new(color.green, 0), textcolor = color.white) + else + label.set_xy(sup1_label, bar_index, loband1) + label.set_text(sup1_label, "S1: " + format_price(loband1)) + // R2 label + if na(res2_label) + res2_label := label.new(bar_index, upband2, "R2: " + format_price(upband2), xloc = xloc.bar_index, style = label.style_label_left, color = color.new(color.red, 0), textcolor = color.white) + else + label.set_xy(res2_label, bar_index, upband2) + label.set_text(res2_label, "R2: " + format_price(upband2)) + // S2 label + if na(sup2_label) + sup2_label := label.new(bar_index, loband2, "S2: " + format_price(loband2), xloc = xloc.bar_index, style = label.style_label_left, color = color.new(color.red, 0), textcolor = color.white) + else + label.set_xy(sup2_label, bar_index, loband2) + label.set_text(sup2_label, "S2: " + format_price(loband2)) + // R2_9 label (for upband2_9) + if na(res2_9_label) + res2_9_label := label.new(bar_index, upband2_9, "R2_9: " + format_price(upband2_9), xloc = xloc.bar_index, style = label.style_label_left, color = color.new(color.red, 50), textcolor = color.white) + else + label.set_xy(res2_9_label, bar_index, upband2_9) + label.set_text(res2_9_label, "R2_9: " + format_price(upband2_9)) + // S2_9 label (for loband2_9) + if na(sup2_9_label) + sup2_9_label := label.new(bar_index, loband2_9, "S2_9: " + format_price(loband2_9), xloc = xloc.bar_index, style = label.style_label_left, color = color.new(color.red, 50), textcolor = color.white) + else + label.set_xy(sup2_9_label, bar_index, loband2_9) + label.set_text(sup2_9_label, "S2_9: " + format_price(loband2_9)) + // R2_1 label (New for upband2_1) + if na(res2_1_label) + res2_1_label := label.new(bar_index, upband2_1, "R2_1: " + format_price(upband2_1), xloc = xloc.bar_index, style = label.style_label_left, color = color.new(color.red, 50), textcolor = color.white) + else + label.set_xy(res2_1_label, bar_index, upband2_1) + label.set_text(res2_1_label, "R2_1: " + format_price(upband2_1)) + // S2_1 label (New for loband2_1) + if na(sup2_1_label) + sup2_1_label := label.new(bar_index, loband2_1, "S2_1: " + format_price(loband2_1), xloc = xloc.bar_index, style = label.style_label_left, color = color.new(color.red, 50), textcolor = color.white) + else + label.set_xy(sup2_1_label, bar_index, loband2_1) + label.set_text(sup2_1_label, "S2_1: " + format_price(loband2_1)) +//************************************************************************************************************ +// ===== 统一警报系统 ===== +// 统一警报系统 - 只需添加一次警报即可捕获所有信号 +//************************************************************************************************************ + +// 警报频率限制 - 每分钟只触发一次 +var int last_alert_r1_breakout_up = 0 +var int last_alert_s1_breakout_down = 0 +var int last_alert_range_r1_s1 = 0 +var int last_alert_above_r1 = 0 +var int last_alert_below_s1 = 0 +var int last_alert_above_mean = 0 +var int last_alert_below_mean = 0 + +// 获取当前时间(分钟级别) +current_minute = math.floor(timenow / 60000) + +// 检测所有警报条件并生成对应的JSON消息 +alert_message = "" + +// 价格触碰关键位置警报 +// if ta.cross(close, meanline) +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow, "yyyy-MM-dd HH:mm:ss") + '","时间":"' + str.tostring(time, "yyyy-MM-dd HH:mm:ss") + '","事件":"碰到MEAN","位置":"MEAN","信号":"mean_touch"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// if ta.cross(close, upband1) +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow, "yyyy-MM-dd HH:mm:ss") + '","时间":"' + str.tostring(time, "yyyy-MM-dd HH:mm:ss") + '","事件":"碰到R1","位置":"R1","信号":"r1_touch"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// if ta.cross(close, loband1) +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow, "yyyy-MM-dd HH:mm:ss") + '","时间":"' + str.tostring(time, "yyyy-MM-dd HH:mm:ss") + '","事件":"碰到S1","位置":"S1","信号":"s1_touch"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// if ta.cross(close, upband2) +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow, "yyyy-MM-dd HH:mm:ss") + '","时间":"' + str.tostring(time, "yyyy-MM-dd HH:mm:ss") + '","事件":"碰到R2","位置":"R2","信号":"r2_touch"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// if ta.cross(close, loband2) +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow, "yyyy-MM-dd HH:mm:ss") + '","时间":"' + str.tostring(time, "yyyy-MM-dd HH:mm:ss") + '","事件":"碰到S2","位置":"S2","信号":"s2_touch"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// 价格区间警报 +// if close > meanline and close < upband1 +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于MEAN和R1之间","位置":"MEAN-R1","信号":"range_mean_r1"}' +// alert(alert_message, alert.freq_once_per_bar) + +// if close < meanline and close > loband1 +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于MEAN和S1之间","位置":"MEAN-S1","信号":"range_mean_s1"}' +// alert(alert_message, alert.freq_once_per_bar) + +// if close > upband1 and close < upband2 +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于R1和R2之间","位置":"R1-R2","信号":"range_r1_r2"}' +// alert(alert_message, alert.freq_once_per_bar) + +// if close < loband1 and close > loband2 +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于S1和S2之间","位置":"S1-S2","信号":"range_s1_s2"}' +// alert(alert_message, alert.freq_once_per_bar) + +// if close > upband1 and close < upband2_9 +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于R1和R2_9之间","位置":"R1-R2_9","信号":"range_r1_r2_9"}' +// alert(alert_message, alert.freq_once_per_bar) + +// if close > upband2_9 and close < upband2_1 +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于R2_9和R2_1之间","位置":"R2_9-R2_1","信号":"range_r2_9_r2_1"}' +// alert(alert_message, alert.freq_once_per_bar) + +// if close < loband1 and close > loband2_9 +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于S1和S2_9之间","位置":"S1-S2_9","信号":"range_s1_s2_9"}' +// alert(alert_message, alert.freq_once_per_bar) + +// if close < loband2_9 and close > loband2_1 +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于S2_9和S2_1之间","位置":"S2_9-S2_1","信号":"range_s2_9_s2_1"}' +// alert(alert_message, alert.freq_once_per_bar) + +// 价格穿越警报 - 每分钟限制 +if ta.crossover(close, upband1) and current_minute > last_alert_r1_breakout_up + alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格上穿R1","位置":"R1","信号":"r1_breakout_up"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_r1_breakout_up := current_minute + +// if ta.crossunder(close, upband1) +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格下穿R1","位置":"R1","信号":"r1_breakout_down"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +if ta.crossunder(close, loband1) and current_minute > last_alert_s1_breakout_down + alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格下穿S1","位置":"S1","信号":"s1_breakout_down"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_s1_breakout_down := current_minute + +// if ta.crossover(close, loband1) +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格上穿S1","位置":"S1","信号":"s1_breakout_up"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// if ta.crossover(close, meanline) +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格上穿MEAN","位置":"MEAN","信号":"mean_breakout_up"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// if ta.crossunder(close, meanline) +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格下穿MEAN","位置":"MEAN","信号":"mean_breakout_down"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// if ta.crossover(close, loband2_9) +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格上穿S2_9","位置":"S2_9","信号":"s2_9_breakout_up"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// if ta.crossunder(close, loband2_9) +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格下穿S2_9","位置":"S2_9","信号":"s2_9_breakout_down"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// if ta.crossover(close, upband2_9) +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格上穿R2_9","位置":"R2_9","信号":"r2_9_breakout_up"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// if ta.crossunder(close, upband2_9) +// alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格下穿R2_9","位置":"R2_9","信号":"r2_9_breakout_down"}' +// alert(alert_message, alert.freq_once_per_bar_close) + +// ===== 新增的5个警报条件 - 每分钟限制 ===== +// 1. 价格处于R1和S1之间时 +if close <= upband1 and close >= loband1 and current_minute > last_alert_range_r1_s1 + alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于R1和S1之间","位置":"R1-S1区间","信号":"range_r1_s1"}' + alert(alert_message, alert.freq_once_per_bar) + last_alert_range_r1_s1 := current_minute + +// 2. 价格处于R1以上时 +if close > upband1 and current_minute > last_alert_above_r1 + alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于R1以上","位置":"R1以上","信号":"above_r1"}' + alert(alert_message, alert.freq_once_per_bar) + last_alert_above_r1 := current_minute + +// 3. 价格处于S1以下时 +if close < loband1 and current_minute > last_alert_below_s1 + alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于S1以下","位置":"S1以下","信号":"below_s1"}' + alert(alert_message, alert.freq_once_per_bar) + last_alert_below_s1 := current_minute + +// 4. 价格处于MEAN以上时 +if close > meanline and current_minute > last_alert_above_mean + alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于MEAN以上","位置":"MEAN以上","信号":"above_mean"}' + alert(alert_message, alert.freq_once_per_bar) + last_alert_above_mean := current_minute + +// 5. 价格处于MEAN以下时 +if close < meanline and current_minute > last_alert_below_mean + alert_message := '{"指标名称":"MRC","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MEAN":"' + str.tostring(meanline, '#.####') + '","R1":"' + str.tostring(upband1, '#.####') + '","S1":"' + str.tostring(loband1, '#.####') + '","R2":"' + str.tostring(upband2, '#.####') + '","S2":"' + str.tostring(loband2, '#.####') + '","R2_9":"' + str.tostring(upband2_9, '#.####') + '","S2_9":"' + str.tostring(loband2_9, '#.####') + '","R2_1":"' + str.tostring(upband2_1, '#.####') + '","S2_1":"' + str.tostring(loband2_1, '#.####') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格处于MEAN以下","位置":"MEAN以下","信号":"below_mean"}' + alert(alert_message, alert.freq_once_per_bar) + last_alert_below_mean := current_minute + +// ===== 传统警报条件(保留兼容性)===== +// 注意:使用统一警报系统时,建议只使用上面的alert()函数 +// 以下alertcondition保留用于需要单独设置警报的情况 + +// 价格穿越警报 +alertcondition(ta.crossover(close, upband1), title = '价格上穿R1', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格上穿R1","位置":"R1","信号":"r1_breakout_up"}') + +alertcondition(ta.crossunder(close, upband1), title = '价格下穿R1', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格下穿R1","位置":"R1","信号":"r1_breakout_down"}') + +alertcondition(ta.crossunder(close, loband1), title = '价格下穿S1', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格下穿S1","位置":"S1","信号":"s1_breakout_down"}') + +alertcondition(ta.crossover(close, loband1), title = '价格上穿S1', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格上穿S1","位置":"S1","信号":"s1_breakout_up"}') + +alertcondition(ta.crossover(close, meanline), title = '价格上穿MEAN', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格上穿MEAN","位置":"MEAN","信号":"mean_breakout_up"}') + +alertcondition(ta.crossunder(close, meanline), title = '价格下穿MEAN', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格下穿MEAN","位置":"MEAN","信号":"mean_breakout_down"}') + +// R2和S2穿越警报 +alertcondition(ta.crossover(close, upband2), title = '价格上穿R2', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格上穿R2","位置":"R2","信号":"r2_breakout_up"}') + +alertcondition(ta.crossunder(close, upband2), title = '价格下穿R2', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格下穿R2","位置":"R2","信号":"r2_breakout_down"}') + +alertcondition(ta.crossunder(close, loband2), title = '价格下穿S2', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格下穿S2","位置":"S2","信号":"s2_breakout_down"}') + +alertcondition(ta.crossover(close, loband2), title = '价格上穿S2', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格上穿S2","位置":"S2","信号":"s2_breakout_up"}') + +// 扩展区域穿越警报 +alertcondition(ta.crossover(close, upband2_9), title = '价格上穿R2_9', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格上穿R2_9","位置":"R2_9","信号":"r2_9_breakout_up"}') + +alertcondition(ta.crossunder(close, upband2_9), title = '价格下穿R2_9', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格下穿R2_9","位置":"R2_9","信号":"r2_9_breakout_down"}') + +alertcondition(ta.crossunder(close, loband2_9), title = '价格下穿S2_9', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格下穿S2_9","位置":"S2_9","信号":"s2_9_breakout_down"}') + +alertcondition(ta.crossover(close, loband2_9), title = '价格上穿S2_9', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格上穿S2_9","位置":"S2_9","信号":"s2_9_breakout_up"}') + +alertcondition(ta.crossover(close, upband2_1), title = '价格上穿R2_1', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格上穿R2_1","位置":"R2_1","信号":"r2_1_breakout_up"}') + +alertcondition(ta.crossunder(close, upband2_1), title = '价格下穿R2_1', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格下穿R2_1","位置":"R2_1","信号":"r2_1_breakout_down"}') + +alertcondition(ta.crossunder(close, loband2_1), title = '价格下穿S2_1', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格下穿S2_1","位置":"S2_1","信号":"s2_1_breakout_down"}') + +alertcondition(ta.crossover(close, loband2_1), title = '价格上穿S2_1', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格上穿S2_1","位置":"S2_1","信号":"s2_1_breakout_up"}') + +// 价格区间状态警报 +alertcondition(close <= upband1 and close >= loband1, title = '价格处于R1和S1之间', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格处于R1和S1之间","位置":"R1-S1区间","信号":"range_r1_s1"}') + +alertcondition(close > upband1, title = '价格处于R1以上', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格处于R1以上","位置":"R1以上","信号":"above_r1"}') + +alertcondition(close < loband1, title = '价格处于S1以下', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格处于S1以下","位置":"S1以下","信号":"below_s1"}') + +alertcondition(close > meanline, title = '价格处于MEAN以上', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格处于MEAN以上","位置":"MEAN以上","信号":"above_mean"}') + +alertcondition(close < meanline, title = '价格处于MEAN以下', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格处于MEAN以下","位置":"MEAN以下","信号":"below_mean"}') + +// 区间范围警报 +alertcondition(close > upband1 and close < upband2, title = '价格处于R1和R2之间', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格处于R1和R2之间","位置":"R1-R2","信号":"range_r1_r2"}') + +alertcondition(close < loband1 and close > loband2, title = '价格处于S1和S2之间', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格处于S1和S2之间","位置":"S1-S2","信号":"range_s1_s2"}') + +alertcondition(close > upband2 and close < upband2_1, title = '价格处于R2和R2_1之间', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格处于R2和R2_1之间","位置":"R2-R2_1","信号":"range_r2_r2_1"}') + +alertcondition(close < loband2 and close > loband2_1, title = '价格处于S2和S2_1之间', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格处于S2和S2_1之间","位置":"S2-S2_1","信号":"range_s2_s2_1"}') + +// 极端区域警报 +alertcondition(close > upband2_1, title = '价格处于R2_1以上', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格处于R2_1以上","位置":"R2_1以上","信号":"above_r2_1"}') + +alertcondition(close < loband2_1, title = '价格处于S2_1以下', message = '{"指标名称":"MRC","交易对":"{{ticker}}","周期":"{{interval}}","MEAN":"{{plot(" Mean")}}","R1":"{{plot(" R1")}}","S1":"{{plot(" S1")}}","R2":"{{plot(" R2")}}","S2":"{{plot(" S2")}}","R2_9":"{{plot("R2_9")}}","S2_9":"{{plot("S2_9")}}","R2_1":"{{plot("R2_1")}}","S2_1":"{{plot("S2_1")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格处于S2_1以下","位置":"S2_1以下","信号":"below_s2_1"}') \ No newline at end of file diff --git a/rsi.pine b/rsi.pine new file mode 100644 index 0000000..d6330f4 --- /dev/null +++ b/rsi.pine @@ -0,0 +1,441 @@ +// 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","备注":"空头信号"}') \ No newline at end of file diff --git a/rsi2.pine b/rsi2.pine new file mode 100644 index 0000000..db7fbec --- /dev/null +++ b/rsi2.pine @@ -0,0 +1,637 @@ +// 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) diff --git a/rsi_conbinined.pine b/rsi_conbinined.pine new file mode 100644 index 0000000..d244e00 --- /dev/null +++ b/rsi_conbinined.pine @@ -0,0 +1,293 @@ +//@version=6 +indicator('RSI 窗口二显示', shorttitle='RSI-W2', overlay=false, max_labels_count=500) + +//************************************************************************************************************ +// RSI 参数设置 +//************************************************************************************************************ + +// RSI 参数组 +rsi_src = input.source(close, 'RSI Calculation Source', group='RSI') +rsiLength = input.int(14, 'RSI Length', minval=2, group='RSI') +smooth = input.bool(true, 'Smooth RSI?', group='RSI') +maType = input.string('Ema', 'Moving Average Type', options=['SMA', 'Hull', 'Ema', 'Wma', 'DEMA', 'RMA', 'LINREG', 'TEMA', 'ALMA', 'T3'], group='RSI') +smoothP = input.int(4, 'Smoothing Period', group='RSI') +sig = input.int(6, 'Sigma for ALMA', group='RSI') + +// 显示设置 +show_segments = input.bool(true, 'Show RSI Segments?', group='Display') +show_counting = input.bool(true, 'Show Segment Counting?', group='Display') +show_rsi_table = input.bool(true, 'Show RSI Info Table?', group='Display') +show_price_labels = input.bool(true, 'Show Price Labels?', group='Display') + +//************************************************************************************************************ +// RSI 辅助函数 +//************************************************************************************************************ + +// 自定义移动平均函数 +dema(src, length) => + ema1 = ta.ema(src, length) + ema2 = ta.ema(ema1, length) + 2 * ema1 - ema2 + +tema(src, length) => + ema1 = ta.ema(src, length) + ema2 = ta.ema(ema1, length) + ema3 = ta.ema(ema2, length) + 3 * ema1 - 3 * ema2 + ema3 + +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(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) + +//************************************************************************************************************ +// RSI 计算 +//************************************************************************************************************ + +// 计算RSI +rsi = ta.rsi(rsi_src, rsiLength) +if smooth + rsi := ma(rsi, smoothP, maType, sig) + +// RSI 机器学习阈值计算 +var rsi_values = array.new_float(0) +if last_bar_index - bar_index <= 1000 + 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)) + +long_S = array.get(centroids, 2) +short_S = array.get(centroids, 0) + +// RSI 状态和计数逻辑 +var int rsi_state = 0 +var int prev_rsi_state = 0 +var int extreme_type = 0 +var int segment_count = 0 + +// 计数标签变量 - 不再使用全局变量,每次状态变化时创建新标签以保留历史 + +current_state = rsi > long_S ? 1 : rsi < short_S ? -1 : 0 + +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) // 超卖区内的重复进入 + + // 绘制分段线 + if show_segments + line.new(bar_index, 0, bar_index, 100, + color = segment_color, + width = 2, + style = line.style_solid, + extend = extend.none) + + // 更新计数逻辑 + if current_state == 1 + if extreme_type != 1 + extreme_type := 1 + segment_count := 1 + else + segment_count := segment_count + 1 + + // 显示超买计数标签(保留历史标签) + if show_counting + label.new(bar_index, rsi, + text = str.tostring(segment_count), + style = label.style_label_down, + color = color.red, + textcolor = color.white, + size = size.small) + + else if current_state == -1 + if extreme_type != -1 + extreme_type := -1 + segment_count := -1 + else + segment_count := segment_count - 1 + + // 显示超卖计数标签(保留历史标签) + if show_counting + label.new(bar_index, rsi, + text = str.tostring(segment_count), + style = label.style_label_up, + color = color.blue, + textcolor = color.white, + size = size.small) + + // 更新前一个状态 + prev_rsi_state := rsi_state + rsi_state := current_state + +//************************************************************************************************************ +// RSI 绘图 +//************************************************************************************************************ + +// RSI 主线 +rsi_color = rsi > long_S ? color.red : rsi < short_S ? color.blue : color.gray +plot(rsi, 'RSI', color=rsi_color, linewidth=2) + +// 动态阈值线 +plot(long_S, 'Long ML Threshold', color=color.red, linewidth=1) +plot(short_S, 'Short ML Threshold', color=color.blue, linewidth=1) + +// 50中线 +hline(50, 'RSI 50', color=color.gray, linestyle=hline.style_dashed) + +//************************************************************************************************************ +// RSI 变化方向计算 +//************************************************************************************************************ + +// 计算RSI变化 +rsi_change = not na(rsi[1]) ? rsi - rsi[1] : 0 +rsi_direction = rsi_change > 0.1 ? "↗" : rsi_change < -0.1 ? "↘" : "→" +rsi_direction_text = rsi_change > 0.1 ? "上升" : rsi_change < -0.1 ? "下降" : "平稳" +rsi_change_value = str.tostring(math.abs(rsi_change), '#.##') + +//************************************************************************************************************ +// RSI 价格标签显示(参考MRC原始实现) +//************************************************************************************************************ + +// 价格格式化函数 +format_rsi_value(value) => + str.tostring(value, '#.##') + +// 声明RSI标签变量 +var label rsi_label = na +var label long_threshold_label = na +var label short_threshold_label = na +var label midline_label = na + +if show_price_labels and barstate.islast + // RSI 主线标签(包含变化方向) + rsi_label_text = "RSI: " + format_rsi_value(rsi) + " " + rsi_direction + " (" + rsi_direction_text + " " + rsi_change_value + ")" + if na(rsi_label) + rsi_label := label.new(bar_index, rsi, rsi_label_text, xloc=xloc.bar_index, style=label.style_label_left, color=rsi_color, textcolor=color.white) + else + label.set_xy(rsi_label, bar_index, rsi) + label.set_text(rsi_label, rsi_label_text) + label.set_color(rsi_label, rsi_color) + + // 超买阈值标签 + if na(long_threshold_label) + long_threshold_label := label.new(bar_index, long_S, "超买: " + format_rsi_value(long_S), xloc=xloc.bar_index, style=label.style_label_left, color=color.red, textcolor=color.white) + else + label.set_xy(long_threshold_label, bar_index, long_S) + label.set_text(long_threshold_label, "超买: " + format_rsi_value(long_S)) + + // 超卖阈值标签 + if na(short_threshold_label) + short_threshold_label := label.new(bar_index, short_S, "超卖: " + format_rsi_value(short_S), xloc=xloc.bar_index, style=label.style_label_left, color=color.blue, textcolor=color.white) + else + label.set_xy(short_threshold_label, bar_index, short_S) + label.set_text(short_threshold_label, "超卖: " + format_rsi_value(short_S)) + + // 50中线标签 + if na(midline_label) + midline_label := label.new(bar_index, 50, "中线: 50.00", xloc=xloc.bar_index, style=label.style_label_left, color=color.gray, textcolor=color.white) + else + label.set_xy(midline_label, bar_index, 50) + label.set_text(midline_label, "中线: 50.00") + +//************************************************************************************************************ +// RSI 信息表格 +//************************************************************************************************************ + +if show_rsi_table and barstate.islast + // RSI 状态 + rsi_position = rsi > long_S ? "超买区" : rsi < short_S ? "超卖区" : "中性区" + rsi_cross_count = math.abs(segment_count) + cross_type = segment_count > 0 ? "超买穿越" : segment_count < 0 ? "超卖穿越" : "无穿越" + + // 创建RSI表格(扩展为10行) + var table rsi_table = table.new( + position = position.bottom_right, + columns = 2, + rows = 10, + bgcolor = color.new(color.yellow, 80), + border_width = 1) + + // 清空表格 + table.clear(rsi_table, 0, 0, 1, 9) + + // 添加RSI标题 + table.cell(rsi_table, 0, 0, "RSI指标", text_color=color.black, bgcolor=color.new(color.orange, 70), text_size=size.small) + table.cell(rsi_table, 1, 0, "实时数值", text_color=color.black, bgcolor=color.new(color.orange, 70), text_size=size.small) + + // RSI 值 + table.cell(rsi_table, 0, 1, "RSI值", text_color=color.black, text_size=size.tiny) + table.cell(rsi_table, 1, 1, str.tostring(rsi, '#.##'), text_color=color.black, text_size=size.tiny) + + // RSI 位置 + table.cell(rsi_table, 0, 2, "RSI位置", text_color=color.black, text_size=size.tiny) + table.cell(rsi_table, 1, 2, rsi_position, text_color=color.black, text_size=size.tiny) + + // RSI 阈值 + table.cell(rsi_table, 0, 3, "超买阈值", text_color=color.black, text_size=size.tiny) + table.cell(rsi_table, 1, 3, str.tostring(long_S, '#.##'), text_color=color.black, text_size=size.tiny) + + table.cell(rsi_table, 0, 4, "超卖阈值", text_color=color.black, text_size=size.tiny) + table.cell(rsi_table, 1, 4, str.tostring(short_S, '#.##'), text_color=color.black, text_size=size.tiny) + + // RSI 穿越次数 + table.cell(rsi_table, 0, 5, "穿越次数", text_color=color.black, text_size=size.tiny) + table.cell(rsi_table, 1, 5, str.tostring(rsi_cross_count), text_color=color.black, text_size=size.tiny) + + // RSI 穿越类型 + table.cell(rsi_table, 0, 6, "穿越类型", text_color=color.black, text_size=size.tiny) + table.cell(rsi_table, 1, 6, cross_type, text_color=color.black, text_size=size.tiny) + + // RSI 状态标记 + table.cell(rsi_table, 0, 7, "状态标记", text_color=color.black, text_size=size.tiny) + table.cell(rsi_table, 1, 7, str.tostring(segment_count), text_color=color.black, text_size=size.tiny) + + // RSI 变化方向 + table.cell(rsi_table, 0, 8, "变化方向", text_color=color.black, text_size=size.tiny) + table.cell(rsi_table, 1, 8, rsi_direction_text + " " + rsi_direction, text_color=color.black, text_size=size.tiny) + + // RSI 变化幅度 + table.cell(rsi_table, 0, 9, "变化幅度", text_color=color.black, text_size=size.tiny) + table.cell(rsi_table, 1, 9, rsi_change_value, text_color=color.black, text_size=size.tiny) diff --git a/srbr.pine b/srbr.pine new file mode 100644 index 0000000..6f72b48 --- /dev/null +++ b/srbr.pine @@ -0,0 +1,714 @@ +// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ +// © ChartPrime + +//@version=6 +indicator('SRBR 支撑阻力突破回测 [多时间周期表格]', shorttitle = 'SRBR MTF', overlay = true, max_boxes_count = 50) + + +// ---------------------------------------------------------------------------------------------------------------------} +// 𝙐𝙎𝙀𝙍 𝙄𝙉𝙋𝙐𝙏𝙎 +// ---------------------------------------------------------------------------------------------------------------------{ +int lookbackPeriod = input.int(20, 'Lookback Period', minval = 1, group = 'Settings') +int vol_len = input.int(2, 'Delta Volume Filter Length', tooltip = 'Higher input, will filter low volume boxes', group = 'Settings') +float box_withd = input.float(1, 'Adjust Box Width', maxval = 1000, minval = 0, step = 0.1, group = 'Settings') + +// ═════════ 多时间周期表格设置 ════════ +mtfSet = input(false, '═════════ 多时间周期表格设置 ════════') +show_mtf_table = input.bool(true, title='显示多时间周期表格', group='MTF Table') +mtf_1m = input.bool(true, title='显示1分钟数据', group='MTF Table') +mtf_5m = input.bool(true, title='显示5分钟数据', group='MTF Table') +mtf_15m = input.bool(true, title='显示15分钟数据', group='MTF Table') +mtf_30m = input.bool(true, title='显示30分钟数据', group='MTF Table') +mtf_45m = input.bool(true, title='显示45分钟数据', group='MTF Table') +mtf_1h = input.bool(true, title='显示1小时数据', group='MTF Table') +mtf_4h = input.bool(true, title='显示4小时数据', group='MTF Table') + +// ═════════ 表格显示设置 ════════ +tableSet = input(false, '═════════ 表格显示设置 ════════') +table_position = input.string('bottom_right', title='表格位置', options=['top_left', 'top_center', 'top_right', 'middle_left', 'middle_center', 'middle_right', 'bottom_left', 'bottom_center', 'bottom_right'], group='Table Display') +table_text_size = input.string('small', title='表格文字大小', options=['auto', 'tiny', 'small', 'normal', 'large', 'huge'], group='Table Display') +mtf_table_rows = input.int(9, title='多时间框架表格行数', minval=6, maxval=12, group='Table Display') +mtf_table_columns = input.int(8, title='多时间框架表格列数', minval=6, maxval=10, group='Table Display') + + +//************************************************************************************************************ +// 辅助函数定义 +//************************************************************************************************************ + +// ═════════ 表格文字大小转换 ════════ +get_text_size() => + switch table_text_size + 'auto' => size.auto + 'tiny' => size.tiny + 'small' => size.small + 'normal' => size.normal + 'large' => size.large + 'huge' => size.huge + => size.small + +// ═════════ 表格位置转换 ════════ +get_table_position() => + switch table_position + 'top_left' => position.top_left + 'top_center' => position.top_center + 'top_right' => position.top_right + 'middle_left' => position.middle_left + 'middle_center' => position.middle_center + 'middle_right' => position.middle_right + 'bottom_left' => position.bottom_left + 'bottom_center' => position.bottom_center + 'bottom_right' => position.bottom_right + => position.bottom_left + +// ═════════ 价格状态判断函数 ════════ +get_price_status(price_val, support_val, resistance_val) => + if na(price_val) or na(support_val) or na(resistance_val) + "N/A" + else if price_val > resistance_val + "看多" + else if price_val < support_val + "看空" + else + "震荡" + +// ═════════ 价格状态颜色函数 ════════ +get_price_status_color(price_val, support_val, resistance_val) => + if na(price_val) or na(support_val) or na(resistance_val) + color.new(color.gray, 60) + else if price_val > resistance_val + color.new(color.green, 40) // 看多 - 绿色 + else if price_val < support_val + color.new(color.red, 40) // 看空 - 红色 + else + color.new(color.orange, 40) // 震荡 - 橙色 + +// ═════════ 距离计算函数 ════════ +get_distance_to_levels(price_val, support_val, resistance_val) => + if na(price_val) or na(support_val) or na(resistance_val) + [na, na] + else + distance_to_support = math.abs(price_val - support_val) + distance_to_resistance = math.abs(price_val - resistance_val) + [distance_to_support, distance_to_resistance] + +// ---------------------------------------------------------------------------------------------------------------------} +// 𝙄𝙉𝘿𝙄𝘾𝘼𝙏𝙊𝙍 𝘾𝘼𝙇𝘾𝙐𝙇𝘼𝙏𝙄𝙊𝙉𝙎 +// ---------------------------------------------------------------------------------------------------------------------{ +// Delta Volume Function +upAndDownVolume() => + posVol = 0.0 + negVol = 0.0 + + var isBuyVolume = true + + switch + close > open => + isBuyVolume := true + isBuyVolume + close < open => + isBuyVolume := false + isBuyVolume + + if isBuyVolume + posVol := posVol + volume + posVol + else + negVol := negVol - volume + negVol + + posVol + negVol + + +// Function to identify support and resistance boxes +calcSupportResistance(src, lookbackPeriod) => + // Volume + Vol = upAndDownVolume() + vol_hi = ta.highest(Vol / 2.5, vol_len) + vol_lo = ta.lowest(Vol / 2.5, vol_len) + + var float supportLevel = na + var float supportLevel_1 = na + var float resistanceLevel = na + var float resistanceLevel_1 = na + var box sup = na + var box res = na + var color res_color = na + var color sup_color = na + var float multi = na + + var bool brekout_res = false + var bool brekout_sup = false + var bool res_holds = false + var bool sup_holds = false + + // Find pivot points + pivotHigh = ta.pivothigh(src, lookbackPeriod, lookbackPeriod) + pivotLow = ta.pivotlow(src, lookbackPeriod, lookbackPeriod) + // Box width + atr = ta.atr(200) + withd = atr * box_withd + + // Volume range for color gradient + vol_highest = ta.highest(Vol, 25) + vol_lowest = ta.lowest(Vol, 25) + + // Find support levels with Positive Volume + if not na(pivotLow) and Vol > vol_hi + + supportLevel := pivotLow + supportLevel_1 := supportLevel - withd + + topLeft = chart.point.from_index(bar_index - lookbackPeriod, supportLevel) + bottomRight = chart.point.from_index(bar_index, supportLevel_1) + + sup_color := color.from_gradient(Vol, 0, vol_highest, color(na), color.new(color.green, 30)) + + // 注释掉支撑位box绘图,保留计算逻辑 + // sup := box.new(top_left = topLeft, bottom_right = bottomRight, border_color = color.green, border_width = 1, bgcolor = sup_color, text = 'Vol: ' + str.tostring(math.round(Vol, 2)), text_color = chart.fg_color, text_size = size.small) + // sup + na + + + // Find resistance levels with Negative Volume + if not na(pivotHigh) and Vol < vol_lo + + resistanceLevel := pivotHigh + resistanceLevel_1 := resistanceLevel + withd + + topLeft = chart.point.from_index(bar_index - lookbackPeriod, resistanceLevel) + bottomRight = chart.point.from_index(bar_index, resistanceLevel_1) + + res_color := color.from_gradient(Vol, vol_lowest, 0, color.new(color.red, 30), color(na)) + + // 注释掉阻力位box绘图,保留计算逻辑 + // res := box.new(top_left = topLeft, bottom_right = bottomRight, border_color = color.red, border_width = 1, bgcolor = res_color, text = 'Vol: ' + str.tostring(math.round(Vol, 2)), text_color = chart.fg_color, text_size = size.small) + // res + na + + // Adaptive Box Len - 已注释掉box操作 + // sup.set_right(bar_index + 1) + // res.set_right(bar_index + 1) + + // Break of support or resistance conditions + brekout_res := ta.crossover(low, resistanceLevel_1) + res_holds := ta.crossunder(high, resistanceLevel) + + sup_holds := ta.crossover(low, supportLevel) + brekout_sup := ta.crossunder(high, supportLevel_1) + + // Change Color of Support to red if it was break, change color of resistance to green if it was break - 已注释掉box操作 + // if brekout_sup + // sup.set_bgcolor(color.new(color.red, 80)) + // sup.set_border_color(color.red) + // sup.set_border_style(line.style_dashed) + + // if sup_holds + // sup.set_bgcolor(sup_color) + // sup.set_border_color(color.green) + // sup.set_border_style(line.style_solid) + + // if brekout_res + // res.set_bgcolor(color.new(color.green, 80)) + // res.set_border_color(color.new(color.green, 0)) + // res.set_border_style(line.style_dashed) + + // if res_holds + // res.set_bgcolor(res_color) + // res.set_border_color(color.new(color.red, 0)) + // res.set_border_style(line.style_solid) + + [supportLevel, resistanceLevel, brekout_res, res_holds, sup_holds, brekout_sup] + + +// Calculate support and resistance levels and their breakouts +[supportLevel, resistanceLevel, brekout_res, res_holds, sup_holds, brekout_sup] = calcSupportResistance(close, lookbackPeriod) + + +// Check if Resistance become Support or Support Become Resistance +var bool res_is_sup = false +var bool sup_is_res = false + +switch + brekout_res => + res_is_sup := true + res_is_sup + res_holds => + res_is_sup := false + res_is_sup + +switch + brekout_sup => + sup_is_res := true + sup_is_res + sup_holds => + sup_is_res := false + sup_is_res + + +// ---------------------------------------------------------------------------------------------------------------------} +// 𝙑𝙄𝙎𝙐𝘼𝙇𝙄𝙕𝘼𝙏𝙄𝙊𝙉 +// ---------------------------------------------------------------------------------------------------------------------{ +// Plot Res and Sup breakouts and holds - 已注释掉图形显示 +// plotchar(res_holds, 'Resistance Holds', '◆', color = #e92929, size = size.tiny, location = location.abovebar, offset = -1) +// plotchar(sup_holds, 'Support Holds', '◆', color = #20ca26, size = size.tiny, location = location.belowbar, offset = -1) + +// plotchar(brekout_res and res_is_sup[1], 'Resistance as Support Holds', '◆', color = #20ca26, size = size.tiny, location = location.belowbar, offset = -1) +// plotchar(brekout_sup and sup_is_res[1], 'Support as Resistance Holds', '◆', color = #e92929, size = size.tiny, location = location.abovebar, offset = -1) + +// Break Out Labels - 已注释掉图形显示 +// if brekout_sup and not sup_is_res[1] +// label.new(bar_index[1], supportLevel[1], text = 'Break Sup', style = label.style_label_down, color = #7e1e1e, textcolor = chart.fg_color, size = size.small) + +// if brekout_res and not res_is_sup[1] +// label.new(bar_index[1], resistanceLevel[1], text = 'Break Res', style = label.style_label_up, color = #2b6d2d, textcolor = chart.fg_color, size = size.small) + +// 警报标记 - 醒目的视觉提示 - 已注释掉图形显示 +// 支撑位保持警报标记 +// if sup_holds +// label.new(bar_index, low, text = '🔔SUP', style = label.style_label_down, color = color.new(color.lime, 0), textcolor = color.black, size = size.large, tooltip = '支撑位保持警报') + +// 阻力位保持警报标记 +// if res_holds +// label.new(bar_index, high, text = '🔔RES', style = label.style_label_up, color = color.new(color.red, 0), textcolor = color.white, size = size.large, tooltip = '阻力位保持警报') + +// 支撑位突破警报标记 +// if brekout_sup +// label.new(bar_index[1], supportLevel[1], text = '🚨SUP⬇', style = label.style_label_down, color = color.new(color.orange, 0), textcolor = color.black, size = size.large, tooltip = '支撑位突破警报') + +// 阻力位突破警报标记 +// if brekout_res +// label.new(bar_index[1], resistanceLevel[1], text = '🚨RES⬆', style = label.style_label_up, color = color.new(color.aqua, 0), textcolor = color.black, size = size.large, tooltip = '阻力位突破警报') + +// 阻力转支撑警报标记 +// if brekout_res and res_is_sup[1] +// label.new(bar_index[1], resistanceLevel[1], text = '⭐R→S', style = label.style_label_down, color = color.new(color.purple, 0), textcolor = color.white, size = size.large, tooltip = '阻力转支撑保持警报') + +// 支撑转阻力警报标记 +// if brekout_sup and sup_is_res[1] +// label.new(bar_index[1], supportLevel[1], text = '⭐S→R', style = label.style_label_up, color = color.new(color.maroon, 0), textcolor = color.white, size = size.large, tooltip = '支撑转阻力保持警报') + +// 全局作用域的plotshape - 警报形状标记 - 已注释掉图形显示 +// plotshape(sup_holds, title = '支撑保持警报', style = shape.triangleup, location = location.belowbar, color = color.new(color.lime, 0), size = size.large) +// plotshape(res_holds, title = '阻力保持警报', style = shape.triangledown, location = location.abovebar, color = color.new(color.red, 0), size = size.large) +// plotshape(brekout_sup, title = '支撑突破警报', style = shape.xcross, location = location.belowbar, color = color.new(color.orange, 0), size = size.large) +// plotshape(brekout_res, title = '阻力突破警报', style = shape.xcross, location = location.abovebar, color = color.new(color.aqua, 0), size = size.large) +// plotshape(brekout_res and res_is_sup[1], title = '阻力转支撑警报', style = shape.diamond, location = location.belowbar, color = color.new(color.purple, 0), size = size.large) +// plotshape(brekout_sup and sup_is_res[1], title = '支撑转阻力警报', style = shape.diamond, location = location.abovebar, color = color.new(color.maroon, 0), size = size.large) + + +//************************************************************************************************************ +// 多时间周期计算 +//************************************************************************************************************ + +// ═════════ 多时间周期专用计算函数(无绘图操作) ════════ +// 为了避免request.security()中的绘图函数错误,创建简化版本 +calcSRForMTF(src, lookback) => + // 使用简化的支撑阻力计算,基于pivot点但无绘图 + pivotHigh = ta.pivothigh(src, lookback, lookback) + pivotLow = ta.pivotlow(src, lookback, lookback) + + // 简化的支撑阻力位识别 + var float mtf_support = na + var float mtf_resistance = na + + if not na(pivotLow) + mtf_support := pivotLow + if not na(pivotHigh) + mtf_resistance := pivotHigh + + // 简化的突破判断 + mtf_brekout_res = src > mtf_resistance + mtf_res_holds = src <= mtf_resistance and src >= mtf_resistance * 0.995 + mtf_sup_holds = src >= mtf_support and src <= mtf_support * 1.005 + mtf_brekout_sup = src < mtf_support + + [mtf_support, mtf_resistance, mtf_brekout_res, mtf_res_holds, mtf_sup_holds, mtf_brekout_sup] + +// ═════════ 多时间周期数据获取函数 ════════ +get_mtf_data(tf) => + request.security(syminfo.tickerid, tf, calcSRForMTF(close, lookbackPeriod), lookahead=barmerge.lookahead_off) + +get_mtf_close(tf) => + request.security(syminfo.tickerid, tf, close, lookahead=barmerge.lookahead_off) + +// ═════════ 多时间周期数据获取 ═════════ +// 1分钟数据 +var float supportLevel_1m = na +var float resistanceLevel_1m = na +var bool brekout_res_1m = false +var bool res_holds_1m = false +var bool sup_holds_1m = false +var bool brekout_sup_1m = false +var float close_1m = na + +if mtf_1m + [sup_1m, res_1m, br_res_1m, r_holds_1m, s_holds_1m, br_sup_1m] = get_mtf_data("1") + supportLevel_1m := sup_1m + resistanceLevel_1m := res_1m + brekout_res_1m := br_res_1m + res_holds_1m := r_holds_1m + sup_holds_1m := s_holds_1m + brekout_sup_1m := br_sup_1m + close_1m := get_mtf_close("1") + +// 5分钟数据 +var float supportLevel_5m = na +var float resistanceLevel_5m = na +var bool brekout_res_5m = false +var bool res_holds_5m = false +var bool sup_holds_5m = false +var bool brekout_sup_5m = false +var float close_5m = na + +if mtf_5m + [sup_5m, res_5m, br_res_5m, r_holds_5m, s_holds_5m, br_sup_5m] = get_mtf_data("5") + supportLevel_5m := sup_5m + resistanceLevel_5m := res_5m + brekout_res_5m := br_res_5m + res_holds_5m := r_holds_5m + sup_holds_5m := s_holds_5m + brekout_sup_5m := br_sup_5m + close_5m := get_mtf_close("5") + +// 15分钟数据 +var float supportLevel_15m = na +var float resistanceLevel_15m = na +var bool brekout_res_15m = false +var bool res_holds_15m = false +var bool sup_holds_15m = false +var bool brekout_sup_15m = false +var float close_15m = na + +if mtf_15m + [sup_15m, res_15m, br_res_15m, r_holds_15m, s_holds_15m, br_sup_15m] = get_mtf_data("15") + supportLevel_15m := sup_15m + resistanceLevel_15m := res_15m + brekout_res_15m := br_res_15m + res_holds_15m := r_holds_15m + sup_holds_15m := s_holds_15m + brekout_sup_15m := br_sup_15m + close_15m := get_mtf_close("15") + +// 30分钟数据 +var float supportLevel_30m = na +var float resistanceLevel_30m = na +var bool brekout_res_30m = false +var bool res_holds_30m = false +var bool sup_holds_30m = false +var bool brekout_sup_30m = false +var float close_30m = na + +if mtf_30m + [sup_30m, res_30m, br_res_30m, r_holds_30m, s_holds_30m, br_sup_30m] = get_mtf_data("30") + supportLevel_30m := sup_30m + resistanceLevel_30m := res_30m + brekout_res_30m := br_res_30m + res_holds_30m := r_holds_30m + sup_holds_30m := s_holds_30m + brekout_sup_30m := br_sup_30m + close_30m := get_mtf_close("30") + +// 45分钟数据 +var float supportLevel_45m = na +var float resistanceLevel_45m = na +var bool brekout_res_45m = false +var bool res_holds_45m = false +var bool sup_holds_45m = false +var bool brekout_sup_45m = false +var float close_45m = na + +if mtf_45m + [sup_45m, res_45m, br_res_45m, r_holds_45m, s_holds_45m, br_sup_45m] = get_mtf_data("45") + supportLevel_45m := sup_45m + resistanceLevel_45m := res_45m + brekout_res_45m := br_res_45m + res_holds_45m := r_holds_45m + sup_holds_45m := s_holds_45m + brekout_sup_45m := br_sup_45m + close_45m := get_mtf_close("45") + +// 1小时数据 +var float supportLevel_1h = na +var float resistanceLevel_1h = na +var bool brekout_res_1h = false +var bool res_holds_1h = false +var bool sup_holds_1h = false +var bool brekout_sup_1h = false +var float close_1h = na + +if mtf_1h + [sup_1h, res_1h, br_res_1h, r_holds_1h, s_holds_1h, br_sup_1h] = get_mtf_data("60") + supportLevel_1h := sup_1h + resistanceLevel_1h := res_1h + brekout_res_1h := br_res_1h + res_holds_1h := r_holds_1h + sup_holds_1h := s_holds_1h + brekout_sup_1h := br_sup_1h + close_1h := get_mtf_close("60") + +// 4小时数据 +var float supportLevel_4h = na +var float resistanceLevel_4h = na +var bool brekout_res_4h = false +var bool res_holds_4h = false +var bool sup_holds_4h = false +var bool brekout_sup_4h = false +var float close_4h = na + +if mtf_4h + [sup_4h, res_4h, br_res_4h, r_holds_4h, s_holds_4h, br_sup_4h] = get_mtf_data("240") + supportLevel_4h := sup_4h + resistanceLevel_4h := res_4h + brekout_res_4h := br_res_4h + res_holds_4h := r_holds_4h + sup_holds_4h := s_holds_4h + brekout_sup_4h := br_sup_4h + close_4h := get_mtf_close("240") + +//************************************************************************************************************ +// 多时间周期表格显示 +//************************************************************************************************************ + +if show_mtf_table and barstate.islast + // 创建多时间周期表格 + var table mtf_table = table.new( + position = get_table_position(), + columns = mtf_table_columns, + rows = mtf_table_rows, + bgcolor = color.new(color.white, 85), + border_width = 1) + + // 清空表格 + table.clear(mtf_table, 0, 0, mtf_table_columns-1, mtf_table_rows-1) + + // 获取配置的文字大小 + text_size = get_text_size() + + // ═════════ 表格标题行 ═════════ + table.cell(mtf_table, 0, 0, "时间周期", text_color=color.white, bgcolor=color.new(color.purple, 30), text_size=text_size) + table.cell(mtf_table, 1, 0, "当前价格", text_color=color.white, bgcolor=color.new(color.purple, 30), text_size=text_size) + table.cell(mtf_table, 2, 0, "支撑位", text_color=color.white, bgcolor=color.new(color.green, 30), text_size=text_size) + table.cell(mtf_table, 3, 0, "阻力位", text_color=color.white, bgcolor=color.new(color.red, 30), text_size=text_size) + table.cell(mtf_table, 4, 0, "距支撑", text_color=color.white, bgcolor=color.new(color.green, 30), text_size=text_size) + table.cell(mtf_table, 5, 0, "距阻力", text_color=color.white, bgcolor=color.new(color.red, 30), text_size=text_size) + table.cell(mtf_table, 6, 0, "价格状态", text_color=color.white, bgcolor=color.new(color.blue, 30), text_size=text_size) + table.cell(mtf_table, 7, 0, "市场观点", text_color=color.white, bgcolor=color.new(color.orange, 30), text_size=text_size) + + // ═════════ 数据行 ═════════ + row = 1 + + // 1分钟数据行 + if mtf_1m and row < mtf_table_rows + [dist_to_sup_1m, dist_to_res_1m] = get_distance_to_levels(close_1m, supportLevel_1m, resistanceLevel_1m) + status_1m = get_price_status(close_1m, supportLevel_1m, resistanceLevel_1m) + status_color_1m = get_price_status_color(close_1m, supportLevel_1m, resistanceLevel_1m) + + table.cell(mtf_table, 0, row, "1分钟", text_color=color.black, bgcolor=color.new(color.gray, 80), text_size=text_size) + table.cell(mtf_table, 1, row, str.tostring(close_1m, '#.##'), text_color=color.black, bgcolor=color.white, text_size=text_size) + table.cell(mtf_table, 2, row, str.tostring(supportLevel_1m, '#.##'), text_color=color.white, bgcolor=color.new(color.green, 60), text_size=text_size) + table.cell(mtf_table, 3, row, str.tostring(resistanceLevel_1m, '#.##'), text_color=color.white, bgcolor=color.new(color.red, 60), text_size=text_size) + table.cell(mtf_table, 4, row, str.tostring(dist_to_sup_1m, '#.##'), text_color=color.black, bgcolor=color.new(color.green, 80), text_size=text_size) + table.cell(mtf_table, 5, row, str.tostring(dist_to_res_1m, '#.##'), text_color=color.black, bgcolor=color.new(color.red, 80), text_size=text_size) + table.cell(mtf_table, 6, row, status_1m, text_color=color.white, bgcolor=status_color_1m, text_size=text_size) + table.cell(mtf_table, 7, row, status_1m, text_color=color.white, bgcolor=status_color_1m, text_size=text_size) + row := row + 1 + + // 5分钟数据行 + if mtf_5m and row < mtf_table_rows + [dist_to_sup_5m, dist_to_res_5m] = get_distance_to_levels(close_5m, supportLevel_5m, resistanceLevel_5m) + status_5m = get_price_status(close_5m, supportLevel_5m, resistanceLevel_5m) + status_color_5m = get_price_status_color(close_5m, supportLevel_5m, resistanceLevel_5m) + + table.cell(mtf_table, 0, row, "5分钟", text_color=color.black, bgcolor=color.new(color.gray, 80), text_size=text_size) + table.cell(mtf_table, 1, row, str.tostring(close_5m, '#.##'), text_color=color.black, bgcolor=color.white, text_size=text_size) + table.cell(mtf_table, 2, row, str.tostring(supportLevel_5m, '#.##'), text_color=color.white, bgcolor=color.new(color.green, 60), text_size=text_size) + table.cell(mtf_table, 3, row, str.tostring(resistanceLevel_5m, '#.##'), text_color=color.white, bgcolor=color.new(color.red, 60), text_size=text_size) + table.cell(mtf_table, 4, row, str.tostring(dist_to_sup_5m, '#.##'), text_color=color.black, bgcolor=color.new(color.green, 80), text_size=text_size) + table.cell(mtf_table, 5, row, str.tostring(dist_to_res_5m, '#.##'), text_color=color.black, bgcolor=color.new(color.red, 80), text_size=text_size) + table.cell(mtf_table, 6, row, status_5m, text_color=color.white, bgcolor=status_color_5m, text_size=text_size) + table.cell(mtf_table, 7, row, status_5m, text_color=color.white, bgcolor=status_color_5m, text_size=text_size) + row := row + 1 + + // 15分钟数据行 + if mtf_15m and row < mtf_table_rows + [dist_to_sup_15m, dist_to_res_15m] = get_distance_to_levels(close_15m, supportLevel_15m, resistanceLevel_15m) + status_15m = get_price_status(close_15m, supportLevel_15m, resistanceLevel_15m) + status_color_15m = get_price_status_color(close_15m, supportLevel_15m, resistanceLevel_15m) + + table.cell(mtf_table, 0, row, "15分钟", text_color=color.black, bgcolor=color.new(color.gray, 80), text_size=text_size) + table.cell(mtf_table, 1, row, str.tostring(close_15m, '#.##'), text_color=color.black, bgcolor=color.white, text_size=text_size) + table.cell(mtf_table, 2, row, str.tostring(supportLevel_15m, '#.##'), text_color=color.white, bgcolor=color.new(color.green, 60), text_size=text_size) + table.cell(mtf_table, 3, row, str.tostring(resistanceLevel_15m, '#.##'), text_color=color.white, bgcolor=color.new(color.red, 60), text_size=text_size) + table.cell(mtf_table, 4, row, str.tostring(dist_to_sup_15m, '#.##'), text_color=color.black, bgcolor=color.new(color.green, 80), text_size=text_size) + table.cell(mtf_table, 5, row, str.tostring(dist_to_res_15m, '#.##'), text_color=color.black, bgcolor=color.new(color.red, 80), text_size=text_size) + table.cell(mtf_table, 6, row, status_15m, text_color=color.white, bgcolor=status_color_15m, text_size=text_size) + table.cell(mtf_table, 7, row, status_15m, text_color=color.white, bgcolor=status_color_15m, text_size=text_size) + row := row + 1 + + // 30分钟数据行 + if mtf_30m and row < mtf_table_rows + [dist_to_sup_30m, dist_to_res_30m] = get_distance_to_levels(close_30m, supportLevel_30m, resistanceLevel_30m) + status_30m = get_price_status(close_30m, supportLevel_30m, resistanceLevel_30m) + status_color_30m = get_price_status_color(close_30m, supportLevel_30m, resistanceLevel_30m) + + table.cell(mtf_table, 0, row, "30分钟", text_color=color.black, bgcolor=color.new(color.gray, 80), text_size=text_size) + table.cell(mtf_table, 1, row, str.tostring(close_30m, '#.##'), text_color=color.black, bgcolor=color.white, text_size=text_size) + table.cell(mtf_table, 2, row, str.tostring(supportLevel_30m, '#.##'), text_color=color.white, bgcolor=color.new(color.green, 60), text_size=text_size) + table.cell(mtf_table, 3, row, str.tostring(resistanceLevel_30m, '#.##'), text_color=color.white, bgcolor=color.new(color.red, 60), text_size=text_size) + table.cell(mtf_table, 4, row, str.tostring(dist_to_sup_30m, '#.##'), text_color=color.black, bgcolor=color.new(color.green, 80), text_size=text_size) + table.cell(mtf_table, 5, row, str.tostring(dist_to_res_30m, '#.##'), text_color=color.black, bgcolor=color.new(color.red, 80), text_size=text_size) + table.cell(mtf_table, 6, row, status_30m, text_color=color.white, bgcolor=status_color_30m, text_size=text_size) + table.cell(mtf_table, 7, row, status_30m, text_color=color.white, bgcolor=status_color_30m, text_size=text_size) + row := row + 1 + + // 45分钟数据行 + if mtf_45m and row < mtf_table_rows + [dist_to_sup_45m, dist_to_res_45m] = get_distance_to_levels(close_45m, supportLevel_45m, resistanceLevel_45m) + status_45m = get_price_status(close_45m, supportLevel_45m, resistanceLevel_45m) + status_color_45m = get_price_status_color(close_45m, supportLevel_45m, resistanceLevel_45m) + + table.cell(mtf_table, 0, row, "45分钟", text_color=color.black, bgcolor=color.new(color.gray, 80), text_size=text_size) + table.cell(mtf_table, 1, row, str.tostring(close_45m, '#.##'), text_color=color.black, bgcolor=color.white, text_size=text_size) + table.cell(mtf_table, 2, row, str.tostring(supportLevel_45m, '#.##'), text_color=color.white, bgcolor=color.new(color.green, 60), text_size=text_size) + table.cell(mtf_table, 3, row, str.tostring(resistanceLevel_45m, '#.##'), text_color=color.white, bgcolor=color.new(color.red, 60), text_size=text_size) + table.cell(mtf_table, 4, row, str.tostring(dist_to_sup_45m, '#.##'), text_color=color.black, bgcolor=color.new(color.green, 80), text_size=text_size) + table.cell(mtf_table, 5, row, str.tostring(dist_to_res_45m, '#.##'), text_color=color.black, bgcolor=color.new(color.red, 80), text_size=text_size) + table.cell(mtf_table, 6, row, status_45m, text_color=color.white, bgcolor=status_color_45m, text_size=text_size) + table.cell(mtf_table, 7, row, status_45m, text_color=color.white, bgcolor=status_color_45m, text_size=text_size) + row := row + 1 + + // 1小时数据行 + if mtf_1h and row < mtf_table_rows + [dist_to_sup_1h, dist_to_res_1h] = get_distance_to_levels(close_1h, supportLevel_1h, resistanceLevel_1h) + status_1h = get_price_status(close_1h, supportLevel_1h, resistanceLevel_1h) + status_color_1h = get_price_status_color(close_1h, supportLevel_1h, resistanceLevel_1h) + + table.cell(mtf_table, 0, row, "1小时", text_color=color.black, bgcolor=color.new(color.gray, 80), text_size=text_size) + table.cell(mtf_table, 1, row, str.tostring(close_1h, '#.##'), text_color=color.black, bgcolor=color.white, text_size=text_size) + table.cell(mtf_table, 2, row, str.tostring(supportLevel_1h, '#.##'), text_color=color.white, bgcolor=color.new(color.green, 60), text_size=text_size) + table.cell(mtf_table, 3, row, str.tostring(resistanceLevel_1h, '#.##'), text_color=color.white, bgcolor=color.new(color.red, 60), text_size=text_size) + table.cell(mtf_table, 4, row, str.tostring(dist_to_sup_1h, '#.##'), text_color=color.black, bgcolor=color.new(color.green, 80), text_size=text_size) + table.cell(mtf_table, 5, row, str.tostring(dist_to_res_1h, '#.##'), text_color=color.black, bgcolor=color.new(color.red, 80), text_size=text_size) + table.cell(mtf_table, 6, row, status_1h, text_color=color.white, bgcolor=status_color_1h, text_size=text_size) + table.cell(mtf_table, 7, row, status_1h, text_color=color.white, bgcolor=status_color_1h, text_size=text_size) + row := row + 1 + + // 4小时数据行 + if mtf_4h and row < mtf_table_rows + [dist_to_sup_4h, dist_to_res_4h] = get_distance_to_levels(close_4h, supportLevel_4h, resistanceLevel_4h) + status_4h = get_price_status(close_4h, supportLevel_4h, resistanceLevel_4h) + status_color_4h = get_price_status_color(close_4h, supportLevel_4h, resistanceLevel_4h) + + table.cell(mtf_table, 0, row, "4小时", text_color=color.black, bgcolor=color.new(color.gray, 80), text_size=text_size) + table.cell(mtf_table, 1, row, str.tostring(close_4h, '#.##'), text_color=color.black, bgcolor=color.white, text_size=text_size) + table.cell(mtf_table, 2, row, str.tostring(supportLevel_4h, '#.##'), text_color=color.white, bgcolor=color.new(color.green, 60), text_size=text_size) + table.cell(mtf_table, 3, row, str.tostring(resistanceLevel_4h, '#.##'), text_color=color.white, bgcolor=color.new(color.red, 60), text_size=text_size) + table.cell(mtf_table, 4, row, str.tostring(dist_to_sup_4h, '#.##'), text_color=color.black, bgcolor=color.new(color.green, 80), text_size=text_size) + table.cell(mtf_table, 5, row, str.tostring(dist_to_res_4h, '#.##'), text_color=color.black, bgcolor=color.new(color.red, 80), text_size=text_size) + table.cell(mtf_table, 6, row, status_4h, text_color=color.white, bgcolor=status_color_4h, text_size=text_size) + table.cell(mtf_table, 7, row, status_4h, text_color=color.white, bgcolor=status_color_4h, text_size=text_size) + +// ═════════ 输出支撑阻力位数据供webhook使用 ════════ +plot(supportLevel, title="supportLevel", display=display.none) +plot(resistanceLevel, title="resistanceLevel", display=display.none) + +// ◆ +// ---------------------------------------------------------------------------------------------------------------------} +// �𝙍𝙄𝘾𝙀 𝙎𝙏𝘼𝙏𝙐𝙎 & 𝙈𝘼𝙍𝙆𝙀𝙏 𝙊𝙐𝙏𝙇𝙊𝙊𝙆 +// ---------------------------------------------------------------------------------------------------------------------{ + +// ═════════ 当前图表时间周期价格状态分析 ════════ +get_current_price_status() => + current_price = close + support_level = supportLevel + resistance_level = resistanceLevel + + // 计算价格相对位置 + if na(support_level) and na(resistance_level) + "无明确支撑阻力" + else if na(support_level) + if current_price > resistance_level + "突破阻力位上方" + else if current_price >= resistance_level * 0.995 + "接近阻力位" + else + "阻力位下方" + else if na(resistance_level) + if current_price < support_level + "跌破支撑位下方" + else if current_price <= support_level * 1.005 + "接近支撑位" + else + "支撑位上方" + else + range_size = resistance_level - support_level + price_position = (current_price - support_level) / range_size + + if current_price > resistance_level + "突破阻力位上方" + else if current_price < support_level + "跌破支撑位下方" + else if price_position >= 0.8 + "接近阻力位" + else if price_position <= 0.2 + "接近支撑位" + else + "区间中部运行" + +// ═════════ 市场观点生成 ════════ +get_market_outlook() => + current_status = get_current_price_status() + + // 基于价格状态和突破情况生成观点 + if brekout_res and res_is_sup[1] + "看涨:阻力转支撑确认,建议关注回调买入机会" + else if brekout_sup and sup_is_res[1] + "看跌:支撑转阻力确认,建议关注反弹卖出机会" + else if brekout_res + "看涨:突破阻力位,建议关注回踩确认后的追涨机会" + else if brekout_sup + "看跌:跌破支撑位,建议关注反弹确认后的追跌机会" + else if res_holds + "中性偏空:阻力位有效,短期上涨受阻" + else if sup_holds + "中性偏多:支撑位有效,短期下跌受限" + else if current_status == "接近阻力位" + "谨慎:接近关键阻力位,注意突破或回落" + else if current_status == "接近支撑位" + "谨慎:接近关键支撑位,注意反弹或破位" + else if current_status == "区间中部运行" + "中性:价格在支撑阻力区间内震荡" + else if current_status == "突破阻力位上方" + "看涨:已突破阻力位,关注持续性" + else if current_status == "跌破支撑位下方" + "看跌:已跌破支撑位,关注反弹力度" + else + "观望:等待明确的支撑阻力信号" + +// 获取当前价格状态和市场观点 +current_price_status = get_current_price_status() +market_outlook = get_market_outlook() + +// ---------------------------------------------------------------------------------------------------------------------} +// �𝘼𝙇𝙀𝙍𝙏 𝘾𝙊𝙉𝘿𝙄𝙏𝙄𝙊𝙉𝙎 +// ---------------------------------------------------------------------------------------------------------------------{ + +// 支撑位保持警报 +alertcondition(sup_holds, title = '支撑位保持', message = '{"指标名称":"SRBR","交易对":"{{ticker}}","周期":"{{interval}}","支撑位":"{{plot("supportLevel")}}","阻力位":"{{plot("resistanceLevel")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"支撑位保持","位置":"支撑位","信号":"support_holds","价格状态":"' + current_price_status + '","市场观点":"' + market_outlook + '"}') + +// 阻力位保持警报 +alertcondition(res_holds, title = '阻力位保持', message = '{"指标名称":"SRBR","交易对":"{{ticker}}","周期":"{{interval}}","支撑位":"{{plot("supportLevel")}}","阻力位":"{{plot("resistanceLevel")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"阻力位保持","位置":"阻力位","信号":"resistance_holds","价格状态":"' + current_price_status + '","市场观点":"' + market_outlook + '"}') + +// 支撑位突破警报 +alertcondition(brekout_sup, title = '支撑位突破', message = '{"指标名称":"SRBR","交易对":"{{ticker}}","周期":"{{interval}}","支撑位":"{{plot("supportLevel")}}","阻力位":"{{plot("resistanceLevel")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"支撑位突破","位置":"支撑位下方","信号":"support_breakout","价格状态":"' + current_price_status + '","市场观点":"' + market_outlook + '"}') + +// 阻力位突破警报 +alertcondition(brekout_res, title = '阻力位突破', message = '{"指标名称":"SRBR","交易对":"{{ticker}}","周期":"{{interval}}","支撑位":"{{plot("supportLevel")}}","阻力位":"{{plot("resistanceLevel")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"阻力位突破","位置":"阻力位上方","信号":"resistance_breakout","价格状态":"' + current_price_status + '","市场观点":"' + market_outlook + '"}') + +// 阻力转支撑警报 +alertcondition(brekout_res and res_is_sup[1], title = '阻力转支撑保持', message = '{"指标名称":"SRBR","交易对":"{{ticker}}","周期":"{{interval}}","支撑位":"{{plot("supportLevel")}}","阻力位":"{{plot("resistanceLevel")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"阻力转支撑保持","位置":"前阻力位","信号":"resistance_as_support","价格状态":"' + current_price_status + '","市场观点":"' + market_outlook + '"}') + +// 支撑转阻力警报 +alertcondition(brekout_sup and sup_is_res[1], title = '支撑转阻力保持', message = '{"指标名称":"SRBR","交易对":"{{ticker}}","周期":"{{interval}}","支撑位":"{{plot("supportLevel")}}","阻力位":"{{plot("resistanceLevel")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"支撑转阻力保持","位置":"前支撑位","信号":"support_as_resistance","价格状态":"' + current_price_status + '","市场观点":"' + market_outlook + '"}') + +// ---------------------------------------------------------------------------------------------------------------------} diff --git a/srbr1.pine b/srbr1.pine new file mode 100644 index 0000000..b8ce7c3 --- /dev/null +++ b/srbr1.pine @@ -0,0 +1,316 @@ +// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ +// © ChartPrime + +//@version=6 +indicator('Support and Resistance (High Volume Boxes) [ChartPrime]2', shorttitle = 'SR Breaks and Retests [ChartPrime]2', overlay = true, max_boxes_count = 50) + + +// ---------------------------------------------------------------------------------------------------------------------} +// 𝙐𝙎𝙀𝙍 𝙄𝙉𝙋𝙐𝙏𝙎 +// ---------------------------------------------------------------------------------------------------------------------{ +int lookbackPeriod = input.int(20, 'Lookback Period', minval = 1, group = 'Settings') +int vol_len = input.int(2, 'Delta Volume Filter Length', tooltip = 'Higher input, will filter low volume boxes', group = 'Settings') +float box_withd = input.float(1, 'Adjust Box Width', maxval = 1000, minval = 0, step = 0.1) + + +// ---------------------------------------------------------------------------------------------------------------------} +// 𝙄𝙉𝘿𝙄𝘾𝘼𝙏𝙊𝙍 𝘾𝘼𝙇𝘾𝙐𝙇𝘼𝙏𝙄𝙊𝙉𝙎 +// ---------------------------------------------------------------------------------------------------------------------{ +// Delta Volume Function +upAndDownVolume() => + posVol = 0.0 + negVol = 0.0 + + var isBuyVolume = true + + switch + close > open => + isBuyVolume := true + isBuyVolume + close < open => + isBuyVolume := false + isBuyVolume + + if isBuyVolume + posVol := posVol + volume + posVol + else + negVol := negVol - volume + negVol + + posVol + negVol + + +// Function to identify support and resistance boxes +calcSupportResistance(src, lookbackPeriod) => + // Volume + Vol = upAndDownVolume() + vol_hi = ta.highest(Vol / 2.5, vol_len) + vol_lo = ta.lowest(Vol / 2.5, vol_len) + + var float supportLevel = na + var float supportLevel_1 = na + var float resistanceLevel = na + var float resistanceLevel_1 = na + var box sup = na + var box res = na + var color res_color = na + var color sup_color = na + var float multi = na + + var bool brekout_res = false + var bool brekout_sup = false + var bool res_holds = false + var bool sup_holds = false + + // Find pivot points + pivotHigh = ta.pivothigh(src, lookbackPeriod, lookbackPeriod) + pivotLow = ta.pivotlow(src, lookbackPeriod, lookbackPeriod) + // Box width + atr = ta.atr(200) + withd = atr * box_withd + + // Volume range for color gradient + vol_highest = ta.highest(Vol, 25) + vol_lowest = ta.lowest(Vol, 25) + + // Find support levels with Positive Volume + if not na(pivotLow) and Vol > vol_hi + + supportLevel := pivotLow + supportLevel_1 := supportLevel - withd + + topLeft = chart.point.from_index(bar_index - lookbackPeriod, supportLevel) + bottomRight = chart.point.from_index(bar_index, supportLevel_1) + + sup_color := color.from_gradient(Vol, 0, vol_highest, color(na), color.new(color.green, 30)) + + sup := box.new(top_left = topLeft, bottom_right = bottomRight, border_color = color.green, border_width = 1, bgcolor = sup_color, text = 'Vol: ' + str.tostring(math.round(Vol, 2)), text_color = chart.fg_color, text_size = size.small) + sup + + + // Find resistance levels with Negative Volume + if not na(pivotHigh) and Vol < vol_lo + + resistanceLevel := pivotHigh + resistanceLevel_1 := resistanceLevel + withd + + topLeft = chart.point.from_index(bar_index - lookbackPeriod, resistanceLevel) + bottomRight = chart.point.from_index(bar_index, resistanceLevel_1) + + res_color := color.from_gradient(Vol, vol_lowest, 0, color.new(color.red, 30), color(na)) + + res := box.new(top_left = topLeft, bottom_right = bottomRight, border_color = color.red, border_width = 1, bgcolor = res_color, text = 'Vol: ' + str.tostring(math.round(Vol, 2)), text_color = chart.fg_color, text_size = size.small) + res + + // Adaptive Box Len + sup.set_right(bar_index + 1) + res.set_right(bar_index + 1) + + // Break of support or resistance conditions + brekout_res := ta.crossover(low, resistanceLevel_1) + res_holds := ta.crossunder(high, resistanceLevel) + + sup_holds := ta.crossover(low, supportLevel) + brekout_sup := ta.crossunder(high, supportLevel_1) + + // Change Color of Support to red if it was break, change color of resistance to green if it was break + if brekout_sup + sup.set_bgcolor(color.new(color.red, 80)) + sup.set_border_color(color.red) + sup.set_border_style(line.style_dashed) + + if sup_holds + sup.set_bgcolor(sup_color) + sup.set_border_color(color.green) + sup.set_border_style(line.style_solid) + + if brekout_res + res.set_bgcolor(color.new(color.green, 80)) + res.set_border_color(color.new(color.green, 0)) + res.set_border_style(line.style_dashed) + + if res_holds + res.set_bgcolor(res_color) + res.set_border_color(color.new(color.red, 0)) + res.set_border_style(line.style_solid) + + [supportLevel, resistanceLevel, brekout_res, res_holds, sup_holds, brekout_sup] + + +// Calculate support and resistance levels and their breakouts +[supportLevel, resistanceLevel, brekout_res, res_holds, sup_holds, brekout_sup] = calcSupportResistance(close, lookbackPeriod) + + +// Check if Resistance become Support or Support Become Resistance +var bool res_is_sup = false +var bool sup_is_res = false + +switch + brekout_res => + res_is_sup := true + res_is_sup + res_holds => + res_is_sup := false + res_is_sup + +switch + brekout_sup => + sup_is_res := true + sup_is_res + sup_holds => + sup_is_res := false + sup_is_res + + +// ---------------------------------------------------------------------------------------------------------------------} +// 𝙑𝙄𝙎𝙐𝘼𝙇𝙄𝙕𝘼𝙏𝙄𝙊𝙉 +// ---------------------------------------------------------------------------------------------------------------------{ +// Plot Res and Sup breakouts and holds +plotchar(res_holds, 'Resistance Holds', '◆', color = #e92929, size = size.tiny, location = location.abovebar, offset = -1) +plotchar(sup_holds, 'Support Holds', '◆', color = #20ca26, size = size.tiny, location = location.belowbar, offset = -1) + +plotchar(brekout_res and res_is_sup[1], 'Resistance as Support Holds', '◆', color = #20ca26, size = size.tiny, location = location.belowbar, offset = -1) +plotchar(brekout_sup and sup_is_res[1], 'Support as Resistance Holds', '◆', color = #e92929, size = size.tiny, location = location.abovebar, offset = -1) + +// Break Out Labels +if brekout_sup and not sup_is_res[1] + label.new(bar_index[1], supportLevel[1], text = 'Break Sup', style = label.style_label_down, color = #7e1e1e, textcolor = chart.fg_color, size = size.small) + +if brekout_res and not res_is_sup[1] + label.new(bar_index[1], resistanceLevel[1], text = 'Break Res', style = label.style_label_up, color = #2b6d2d, textcolor = chart.fg_color, size = size.small) + +// 警报标记 - 醒目的视觉提示 +// 支撑位保持警报标记 +if sup_holds + label.new(bar_index, low, text = '🔔SUP', style = label.style_label_down, color = color.new(color.lime, 0), textcolor = color.black, size = size.large, tooltip = '支撑位保持警报') + +// 阻力位保持警报标记 +if res_holds + label.new(bar_index, high, text = '🔔RES', style = label.style_label_up, color = color.new(color.red, 0), textcolor = color.white, size = size.large, tooltip = '阻力位保持警报') + +// 支撑位突破警报标记 +if brekout_sup + label.new(bar_index[1], supportLevel[1], text = '🚨SUP⬇', style = label.style_label_down, color = color.new(color.orange, 0), textcolor = color.black, size = size.large, tooltip = '支撑位突破警报') + +// 阻力位突破警报标记 +if brekout_res + label.new(bar_index[1], resistanceLevel[1], text = '🚨RES⬆', style = label.style_label_up, color = color.new(color.aqua, 0), textcolor = color.black, size = size.large, tooltip = '阻力位突破警报') + +// 阻力转支撑警报标记 +if brekout_res and res_is_sup[1] + label.new(bar_index[1], resistanceLevel[1], text = '⭐R→S', style = label.style_label_down, color = color.new(color.purple, 0), textcolor = color.white, size = size.large, tooltip = '阻力转支撑保持警报') + +// 支撑转阻力警报标记 +if brekout_sup and sup_is_res[1] + label.new(bar_index[1], supportLevel[1], text = '⭐S→R', style = label.style_label_up, color = color.new(color.maroon, 0), textcolor = color.white, size = size.large, tooltip = '支撑转阻力保持警报') + +// 全局作用域的plotshape - 警报形状标记 +plotshape(sup_holds, title = '支撑保持警报', style = shape.triangleup, location = location.belowbar, color = color.new(color.lime, 0), size = size.large) +plotshape(res_holds, title = '阻力保持警报', style = shape.triangledown, location = location.abovebar, color = color.new(color.red, 0), size = size.large) +plotshape(brekout_sup, title = '支撑突破警报', style = shape.xcross, location = location.belowbar, color = color.new(color.orange, 0), size = size.large) +plotshape(brekout_res, title = '阻力突破警报', style = shape.xcross, location = location.abovebar, color = color.new(color.aqua, 0), size = size.large) +plotshape(brekout_res and res_is_sup[1], title = '阻力转支撑警报', style = shape.diamond, location = location.belowbar, color = color.new(color.purple, 0), size = size.large) +plotshape(brekout_sup and sup_is_res[1], title = '支撑转阻力警报', style = shape.diamond, location = location.abovebar, color = color.new(color.maroon, 0), size = size.large) + + +// ◆ +// ---------------------------------------------------------------------------------------------------------------------} +// 𝙋𝙍𝙄𝘾𝙀 𝙎𝙏𝘼𝙏𝙐𝙎 & 𝙈𝘼𝙍𝙆𝙀𝙏 𝙊𝙐𝙏𝙇𝙊𝙊𝙆 +// ---------------------------------------------------------------------------------------------------------------------{ + +// ═════════ 当前图表时间周期价格状态分析 ════════ +get_current_price_status() => + current_price = close + support_level = supportLevel + resistance_level = resistanceLevel + + // 计算价格相对位置 + if na(support_level) and na(resistance_level) + "无明确支撑阻力" + else if na(support_level) + if current_price > resistance_level + "突破阻力位上方" + else if current_price >= resistance_level * 0.995 + "接近阻力位" + else + "阻力位下方" + else if na(resistance_level) + if current_price < support_level + "跌破支撑位下方" + else if current_price <= support_level * 1.005 + "接近支撑位" + else + "支撑位上方" + else + range_size = resistance_level - support_level + price_position = (current_price - support_level) / range_size + + if current_price > resistance_level + "突破阻力位上方" + else if current_price < support_level + "跌破支撑位下方" + else if price_position >= 0.8 + "接近阻力位" + else if price_position <= 0.2 + "接近支撑位" + else + "区间中部运行" + +// ═════════ 市场观点生成 ════════ +get_market_outlook() => + current_status = get_current_price_status() + + // 基于价格状态和突破情况生成观点 + if brekout_res and res_is_sup[1] + "看涨:阻力转支撑确认,建议关注回调买入机会" + else if brekout_sup and sup_is_res[1] + "看跌:支撑转阻力确认,建议关注反弹卖出机会" + else if brekout_res + "看涨:突破阻力位,建议关注回踩确认后的追涨机会" + else if brekout_sup + "看跌:跌破支撑位,建议关注反弹确认后的追跌机会" + else if res_holds + "中性偏空:阻力位有效,短期上涨受阻" + else if sup_holds + "中性偏多:支撑位有效,短期下跌受限" + else if current_status == "接近阻力位" + "谨慎:接近关键阻力位,注意突破或回落" + else if current_status == "接近支撑位" + "谨慎:接近关键支撑位,注意反弹或破位" + else if current_status == "区间中部运行" + "中性:价格在支撑阻力区间内震荡" + else if current_status == "突破阻力位上方" + "看涨:已突破阻力位,关注持续性" + else if current_status == "跌破支撑位下方" + "看跌:已跌破支撑位,关注反弹力度" + else + "观望:等待明确的支撑阻力信号" + +// 获取当前价格状态和市场观点 +current_price_status = get_current_price_status() +market_outlook = get_market_outlook() + +// ---------------------------------------------------------------------------------------------------------------------} +// 𝘼𝙇𝙀𝙍𝙏 𝘾𝙊𝙉𝘿𝙄𝙏𝙄𝙊𝙉𝙎 +// ---------------------------------------------------------------------------------------------------------------------{ + +// 支撑位保持警报 +alertcondition(sup_holds, title = '支撑位保持', message = '{"指标名称":"SRBR","交易对":"{{ticker}}","周期":"{{interval}}","支撑位":"{{plot("supportLevel")}}","阻力位":"{{plot("resistanceLevel")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"支撑位保持","位置":"支撑位","信号":"support_holds","价格状态":"' + current_price_status + '","市场观点":"' + market_outlook + '"}') + +// 阻力位保持警报 +alertcondition(res_holds, title = '阻力位保持', message = '{"指标名称":"SRBR","交易对":"{{ticker}}","周期":"{{interval}}","支撑位":"{{plot("supportLevel")}}","阻力位":"{{plot("resistanceLevel")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"阻力位保持","位置":"阻力位","信号":"resistance_holds","价格状态":"' + current_price_status + '","市场观点":"' + market_outlook + '"}') + +// 支撑位突破警报 +alertcondition(brekout_sup, title = '支撑位突破', message = '{"指标名称":"SRBR","交易对":"{{ticker}}","周期":"{{interval}}","支撑位":"{{plot("supportLevel")}}","阻力位":"{{plot("resistanceLevel")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"支撑位突破","位置":"支撑位下方","信号":"support_breakout","价格状态":"' + current_price_status + '","市场观点":"' + market_outlook + '"}') + +// 阻力位突破警报 +alertcondition(brekout_res, title = '阻力位突破', message = '{"指标名称":"SRBR","交易对":"{{ticker}}","周期":"{{interval}}","支撑位":"{{plot("supportLevel")}}","阻力位":"{{plot("resistanceLevel")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"阻力位突破","位置":"阻力位上方","信号":"resistance_breakout","价格状态":"' + current_price_status + '","市场观点":"' + market_outlook + '"}') + +// 阻力转支撑警报 +alertcondition(brekout_res and res_is_sup[1], title = '阻力转支撑保持', message = '{"指标名称":"SRBR","交易对":"{{ticker}}","周期":"{{interval}}","支撑位":"{{plot("supportLevel")}}","阻力位":"{{plot("resistanceLevel")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"阻力转支撑保持","位置":"前阻力位","信号":"resistance_as_support","价格状态":"' + current_price_status + '","市场观点":"' + market_outlook + '"}') + +// 支撑转阻力警报 +alertcondition(brekout_sup and sup_is_res[1], title = '支撑转阻力保持', message = '{"指标名称":"SRBR","交易对":"{{ticker}}","周期":"{{interval}}","支撑位":"{{plot("supportLevel")}}","阻力位":"{{plot("resistanceLevel")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"支撑转阻力保持","位置":"前支撑位","信号":"support_as_resistance","价格状态":"' + current_price_status + '","市场观点":"' + market_outlook + '"}') + +// ---------------------------------------------------------------------------------------------------------------------} diff --git a/tmfs.pine b/tmfs.pine new file mode 100644 index 0000000..9508dab --- /dev/null +++ b/tmfs.pine @@ -0,0 +1,503 @@ +// This work is licensed under a Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) +// https://creativecommons.org/licenses/by-nc-sa/4.0/ +// Original concepts by FibonacciFlux, rewritten for clarity and functionality + +//@version=6 +indicator('Trendline Breaks 带警报', shorttitle = "TMFS Indicator alerts", overlay = true) + +//---------------------------------------------------------- +// SECTION 1: FIBONACCI SUPERTREND CONFIGURATION +//---------------------------------------------------------- + +// Common ATR period for all supertrend calculations +atrPeriod = input.int(13, 'ATR Length', minval = 1, tooltip="ATR period used for volatility calculation") + +// Fibonacci-based supertrend factor inputs +factor1 = input.float(0.618, 'Factor 1 (Weak/Fibonacci)', minval = 0.01, step = 0.01, tooltip="First Fibonacci factor (0.618)") +factor2 = input.float(1.618, 'Factor 2 (Medium/Golden Ratio)', minval = 0.01, step = 0.01, tooltip="Second Fibonacci factor (1.618)") +factor3 = input.float(2.618, 'Factor 3 (Strong/Extended Fib)', minval = 0.01, step = 0.01, tooltip="Third Fibonacci factor (2.618)") + +// Calculate the three Supertrend lines with different sensitivity levels +[supertrend1, direction1] = ta.supertrend(factor1, atrPeriod) +[supertrend2, direction2] = ta.supertrend(factor2, atrPeriod) +[supertrend3, direction3] = ta.supertrend(factor3, atrPeriod) + +// Handle initial values (first bar) +supertrend1 := barstate.isfirst ? na : supertrend1 +supertrend2 := barstate.isfirst ? na : supertrend2 +supertrend3 := barstate.isfirst ? na : supertrend3 + +// Calculate average of the three supertends and a smoothed version +superlength = input.int(21, "Smoothing Length", tooltip="EMA length for smoothing the average supertrend") +average_trend = (supertrend1 + supertrend2 + supertrend3) / 3 +smoothed_trend = ta.ema(average_trend, superlength) + +// Plot the supertrend lines and fill the area between them +trend_plot = plot(average_trend, color = average_trend > average_trend[1] ? color.green : color.red, title="Average Supertrend") +smoothed_plot = plot(smoothed_trend, linewidth = 2, color = smoothed_trend > smoothed_trend[1] ? color.green : color.red, title="Smoothed Supertrend") +fill(trend_plot, smoothed_plot, color = average_trend > smoothed_trend ? color.new(color.green, 50) : color.new(color.red, 50), title="Trend Direction Fill") + +//---------------------------------------------------------- +// SECTION 2: TRENDLINE DETECTION AND DRAWING +//---------------------------------------------------------- + +// User settings for Swing Trend Lines +swing_length = input.int(8, 'Swing Lookback Period', tooltip="Number of bars to look back for pivot points") +atr_multiplier = input.float(1.0, 'ATR Slope Multiplier', minval = 0.0, step = 0.1, tooltip="Multiplier for ATR to control trendline slope") +show_extended_lines = input.bool(true, 'Show Extended Lines', tooltip="Display dashed extensions for trendlines") +enable_backpainting = input.bool(true, 'Use Backpainting', tooltip="Enable backpainting to move indicators to pivot point") + +// Color settings for trendlines +uptrend_color = color.new(color.teal, 0) +downtrend_color = color.new(color.red, 0) + +// Variable initialization for trendlines +var float upper_trendline = na +var float lower_trendline = na +var float upper_slope = na +var float lower_slope = na +var line upline_extension = na +var line downline_extension = na + +// Offset for backpainting +offset = enable_backpainting ? swing_length : 0 +bar_idx = bar_index + +// Get pivot high and low points +pivot_high = ta.pivothigh(swing_length, swing_length) +pivot_low = ta.pivotlow(swing_length, swing_length) + +// Calculate ATR for slope +atr_value = ta.atr(swing_length) +slope = atr_value / swing_length * atr_multiplier + +// Update upper trendline when pivot high is detected or extend existing trendline +if bool(pivot_high) + upper_slope := slope + upper_trendline := pivot_high +else + upper_trendline := nz(upper_trendline) - nz(upper_slope) + +// Update lower trendline when pivot low is detected or extend existing trendline +if bool(pivot_low) + lower_slope := slope + lower_trendline := pivot_low +else + lower_trendline := nz(lower_trendline) + nz(lower_slope) + +// Create and update extended visualization lines if enabled +if show_extended_lines + // Initialize line objects if not already created + if na(upline_extension) + upline_extension := line.new(na, na, na, na, extend = extend.right, style = line.style_dashed, color = uptrend_color) + + if na(downline_extension) + downline_extension := line.new(na, na, na, na, extend = extend.right, style = line.style_dashed, color = downtrend_color) + + // Update upper trendline extension when a new pivot high is confirmed + if bool(pivot_high) + line.set_xy1(upline_extension, bar_idx - offset, enable_backpainting ? pivot_high : upper_trendline) + line.set_xy2(upline_extension, bar_idx - offset + 1, enable_backpainting ? pivot_high - slope : upper_trendline - slope) + + // Update lower trendline extension when a new pivot low is confirmed + if bool(pivot_low) + line.set_xy1(downline_extension, bar_idx - offset, enable_backpainting ? pivot_low : lower_trendline) + line.set_xy2(downline_extension, bar_idx - offset + 1, enable_backpainting ? pivot_low + slope : lower_trendline + slope) + +//---------------------------------------------------------- +// SECTION 3: BREAKOUT DETECTION +//---------------------------------------------------------- + +// Track breakouts above upper trendline and below lower trendline +// Initialize tracking variables for breakout conditions +var int upper_breakout_state = 0 // State variable to track upper breakout condition +var int lower_breakout_state = 0 // State variable to track lower breakout condition + +// Detect breakouts +bool upper_breakout = close > upper_trendline +bool lower_breakout = close < lower_trendline + +// Update state variables to track when breakouts occur +upper_breakout_state := bool(pivot_high) ? 0 : upper_breakout ? 1 : upper_breakout_state +lower_breakout_state := bool(pivot_low) ? 0 : lower_breakout ? 1 : lower_breakout_state + +// Plot trendlines with appropriate offsets +plot(enable_backpainting ? upper_trendline : upper_trendline, color = bool(pivot_high) ? na : uptrend_color, linewidth = 2, offset = -offset, title = 'Upper Trendline') +plot(enable_backpainting ? lower_trendline : lower_trendline, color = bool(pivot_low) ? na : downtrend_color, linewidth = 2, offset = -offset, title = 'Lower Trendline') + +//---------------------------------------------------------- +// SECTION 4: DIRECTIONAL MOVEMENT INDEX (DMI) CALCULATION +//---------------------------------------------------------- + +// DMI Length parameter +dmi_length = input.int(13, "DMI Length", tooltip="Length for DMI calculation") + +// True Range calculation +true_range = math.max(math.max(high - low, math.abs(high - nz(close[1]))), math.abs(low - nz(close[1]))) + +// Directional Movement calculations +directional_movement_plus = high - nz(high[1]) > nz(low[1]) - low ? math.max(high - nz(high[1]), 0) : 0 +directional_movement_minus = nz(low[1]) - low > high - nz(high[1]) ? math.max(nz(low[1]) - low, 0) : 0 + +// Smoothed calculations for DMI +var float smoothed_true_range = 0.0 +smoothed_true_range := nz(smoothed_true_range[1]) - nz(smoothed_true_range[1]) / dmi_length + true_range + +var float smoothed_directional_plus = 0.0 +smoothed_directional_plus := nz(smoothed_directional_plus[1]) - nz(smoothed_directional_plus[1]) / dmi_length + directional_movement_plus + +var float smoothed_directional_minus = 0.0 +smoothed_directional_minus := nz(smoothed_directional_minus[1]) - nz(smoothed_directional_minus[1]) / dmi_length + directional_movement_minus + +// Calculate DI+ and DI- values +di_plus = smoothed_directional_plus / smoothed_true_range * 100 +di_minus = smoothed_directional_minus / smoothed_true_range * 100 + +//---------------------------------------------------------- +// SECTION 5: SIGNAL DEFINITION +//---------------------------------------------------------- + +// SMA settings for trend confirmation +fast_sma_length = input.int(defval = 2, title = 'Fast SMA Length', minval = 1, group = 'Signal Settings') +slow_sma_length = input.int(defval = 3, title = 'Slow SMA Length', minval = 1, group = 'Signal Settings') + +// Calculate SMA crossovers +fast_sma = ta.sma(close, fast_sma_length) +slow_sma = ta.sma(close, slow_sma_length) + +// Detect SMA crossovers +sma_cross_up = ta.crossover(fast_sma, slow_sma) +sma_cross_down = ta.crossunder(fast_sma, slow_sma) + +//---------------------------------------------------------- +// SECTION 6: ENTRY AND EXIT CONDITIONS +//---------------------------------------------------------- + +// Define entry conditions +long_entry_condition = upper_breakout_state > upper_breakout_state[1] and di_plus > di_minus and close > smoothed_trend +short_entry_condition = lower_breakout_state > lower_breakout_state[1] and di_minus > di_plus and close < smoothed_trend + +// Define exit conditions +long_exit_condition = ta.crossunder(close[1], smoothed_trend) +short_exit_condition = ta.crossover(close[1], smoothed_trend) + +// @function Display BUY/SELL labels on chart +plotshape(long_entry_condition, title='BUY', text='BUY', location=location.belowbar, + style=shape.labelup, size=size.tiny, color=color.new(color.green, 0), textcolor=color.new(color.white, 0)) +plotshape(short_entry_condition, title='SELL', text='SELL', location=location.abovebar, + style=shape.labeldown, size=size.tiny, color=color.new(color.red, 0), textcolor=color.new(color.white, 0)) + +//---------------------------------------------------------- +// SECTION 7: STOP LOSS AND TAKE PROFIT SETTINGS +//---------------------------------------------------------- + +// Common settings +atr_length = input.int(13, 'ATR Length for SL/TP', minval = 1, group = 'Risk Management') + +// Variable to track if stop loss is triggered +var bool long_trailing_tp_executed = false +var bool short_trailing_tp_executed = false + +// Store ATR at position entry +float entry_atr = ta.valuewhen(long_entry_condition or short_entry_condition, ta.atr(atr_length), 0) + +// Stop Loss settings +stop_loss_method = input.string(defval = 'ATR', title = 'Stop Loss Method', options = ['PERC', 'ATR'], group = 'Stop Loss') +long_stop_loss_percent = input.float(defval = 0.75, title = 'Long Position Stop Loss %', minval = 0.05, maxval = 100, step = 0.05, group = 'Stop Loss') / 100 +short_stop_loss_percent = input.float(defval = 0.75, title = 'Short Position Stop Loss %', minval = 0.05, maxval = 100, step = 0.05, group = 'Stop Loss') / 100 +long_stop_loss_atr_multiplier = input.float(defval = 8.0, title = 'Long Position ATR Multiplier', minval = 0.1, step = 0.1, group = 'Stop Loss') +short_stop_loss_atr_multiplier = input.float(defval = 8.0, title = 'Short Position ATR Multiplier', minval = 0.1, step = 0.1, group = 'Stop Loss') +stop_loss_trailing_mode = input.string(defval = 'ON', title = 'Trailing Stop Loss Mode', options = ['TP', 'ON', 'OFF'], tooltip = 'ON: Always trail, TP: Trail after Take Profit hit, OFF: Fixed stop', group = 'Stop Loss') +break_even_enabled = input.bool(defval = true, title = 'Move to Break Even After TP', group = 'Stop Loss') + +// Take Profit settings +take_profit_quantity_percent = input.float(defval = 100, title = 'Take Profit Quantity %', minval = 0.0, maxval = 100, step = 1.0, group = 'Take Profit') +take_profit_method = input.string(defval = 'PERC', title = 'Take Profit Method', options = ['PERC', 'ATR', 'RR'], group = 'Take Profit') +long_take_profit_percent = input.float(defval = 1, title = 'Long Position Take Profit %', minval = 0.05, step = 0.05, group = 'Take Profit') / 100 +short_take_profit_percent = input.float(defval = 1, title = 'Short Position Take Profit %', minval = 0.05, step = 0.05, group = 'Take Profit') / 100 +long_take_profit_atr_multiplier = input.float(defval = 1.5, title = 'Long Position TP ATR Multiplier', minval = 0.1, step = 0.1, group = 'Take Profit') +short_take_profit_atr_multiplier = input.float(defval = 2, title = 'Short Position TP ATR Multiplier', minval = 0.1, step = 0.1, group = 'Take Profit') +long_risk_reward_ratio = input.float(defval = 0.6, title = 'Long Position Risk/Reward Ratio', minval = 0.1, step = 0.1, group = 'Take Profit') +short_risk_reward_ratio = input.float(defval = 1, title = 'Short Position Risk/Reward Ratio', minval = 0.1, step = 0.1, group = 'Take Profit') +trailing_take_profit_enabled = input.bool(defval = true, title = 'Enable Trailing Take Profit', group = 'Take Profit') +deviation_method = input.string(defval = 'PERC', title = 'Trailing Deviation Method', options = ['PERC', 'ATR'], group = 'Take Profit') +deviation_percent = input.float(defval = 0.01, title = 'Trailing Deviation %', minval = 0.01, maxval = 100, step = 0.05, group = 'Take Profit') / 100 +deviation_atr_multiplier = input.float(defval = 1.0, title = 'Trailing Deviation ATR Multiplier', minval = 0.01, step = 0.05, group = 'Take Profit') + +//---------------------------------------------------------- +// SECTION 9: CALCULATE STOP LOSS LEVELS +//---------------------------------------------------------- + +// Calculate long position stop loss price based on selected method +get_long_stop_loss_price(base_price) => + switch stop_loss_method + 'PERC' => base_price * (1 - long_stop_loss_percent) + 'ATR' => base_price - long_stop_loss_atr_multiplier * entry_atr + => na + +// Determine if trailing should be active for long position +long_tp_trailing_enabled = stop_loss_trailing_mode == 'ON' or (stop_loss_trailing_mode == 'TP' and long_trailing_tp_executed) + +// Calculate and maintain stop loss price for long positions +var float long_stop_loss_price = na +long_stop_loss_price := if strategy.position_size > 0 + if long_entry_condition + get_long_stop_loss_price(close) + else + stop_price = get_long_stop_loss_price(long_tp_trailing_enabled ? high : strategy.position_avg_price) + stop_price := break_even_enabled and long_trailing_tp_executed ? math.max(stop_price, strategy.position_avg_price) : stop_price + math.max(stop_price, nz(long_stop_loss_price[1])) +else + na + +// Calculate short position stop loss price based on selected method +get_short_stop_loss_price(base_price) => + switch stop_loss_method + 'PERC' => base_price * (1 + short_stop_loss_percent) + 'ATR' => base_price + short_stop_loss_atr_multiplier * entry_atr + => na + +// Determine if trailing should be active for short position +short_tp_trailing_enabled = stop_loss_trailing_mode == 'ON' or (stop_loss_trailing_mode == 'TP' and short_trailing_tp_executed) + +// Calculate and maintain stop loss price for short positions +var float short_stop_loss_price = na +short_stop_loss_price := if strategy.position_size < 0 + if short_entry_condition + get_short_stop_loss_price(close) + else + var float stop_price = get_short_stop_loss_price(short_tp_trailing_enabled ? low : strategy.position_avg_price) // stop_price を var float で宣言 + if break_even_enabled and short_trailing_tp_executed + stop_price := math.min(stop_price, strategy.position_avg_price) + short_stop_loss_price := math.min(stop_price, nz(short_stop_loss_price[1], 999999.9)) +else + na + +//---------------------------------------------------------- +// SECTION 9: CALCULATE TAKE PROFIT LEVELS +//---------------------------------------------------------- + +// Calculate long position take profit price based on selected method +get_long_take_profit_price() => + switch take_profit_method + 'PERC' => close * (1 + long_take_profit_percent) + 'ATR' => close + long_take_profit_atr_multiplier * entry_atr + 'RR' => close + long_risk_reward_ratio * (close - get_long_stop_loss_price(close)) + => na + +// Calculate and maintain take profit price for long positions +var float long_take_profit_price = na +long_take_profit_price := if strategy.position_size > 0 and not long_trailing_tp_executed + if long_entry_condition + get_long_take_profit_price() + else + nz(long_take_profit_price[1], get_long_take_profit_price()) +else + na + +// Update trailing take profit execution flag for long positions +long_trailing_tp_executed := strategy.position_size > 0 and (long_trailing_tp_executed[1] or strategy.position_size < strategy.position_size[1] or (strategy.position_size[1] == 0 and high >= long_take_profit_price)) + +// Calculate trailing step size in ticks for long positions +long_trailing_tp_step_ticks = switch deviation_method + 'PERC' => long_take_profit_price * deviation_percent / syminfo.mintick + 'ATR' => deviation_atr_multiplier * entry_atr / syminfo.mintick + => na + +// Calculate short position take profit price based on selected method +get_short_take_profit_price() => + switch take_profit_method + 'PERC' => close * (1 - short_take_profit_percent) + 'ATR' => close - short_take_profit_atr_multiplier * entry_atr + 'RR' => close - short_risk_reward_ratio * (get_short_stop_loss_price(close) - close) + => na + +// Calculate and maintain take profit price for short positions +var float short_take_profit_price = na +short_take_profit_price := if strategy.position_size < 0 and not short_trailing_tp_executed + if short_entry_condition + get_short_take_profit_price() + else + nz(short_take_profit_price[1], get_short_take_profit_price()) +else + na + +// Update trailing take profit execution flag for short positions +short_trailing_tp_executed := strategy.position_size < 0 and (short_trailing_tp_executed[1] or strategy.position_size > strategy.position_size[1] or (strategy.position_size[1] == 0 and low <= short_take_profit_price)) + +// Calculate trailing step size in ticks for short positions +short_trailing_tp_step_ticks = switch deviation_method + 'PERC' => short_take_profit_price * deviation_percent / syminfo.mintick + 'ATR' => deviation_atr_multiplier * entry_atr / syminfo.mintick + => na + +//---------------------------------------------------------- +// SECTION 11: STRATEGY EXECUTION +//---------------------------------------------------------- + +// Enter long position when conditions are met +if long_entry_condition + strategy.entry('L', strategy.long, comment = "LONG") + +// Enter short position when conditions are met +if short_entry_condition + strategy.entry('S', strategy.short, comment = "SHORT") + +// Exit long position when exit conditions are met +if long_exit_condition + strategy.close('L', comment = "SL Triggered") + +// Exit short position when exit conditions are met +if short_exit_condition + strategy.close('S', comment = "SL Triggered") + +// Set up take profit and stop loss for long positions +strategy.exit(id = 'Long Take Profit / Stop Loss', from_entry = 'L', qty_percent = take_profit_quantity_percent, limit = trailing_take_profit_enabled ? na : long_take_profit_price, stop = long_stop_loss_price, trail_price = trailing_take_profit_enabled ? long_take_profit_price : na, trail_offset = trailing_take_profit_enabled ? long_trailing_tp_step_ticks : na, comment = "TP/SL Triggered") +strategy.exit(id = 'Long Stop Loss', from_entry = 'L', stop = long_stop_loss_price, comment = "SL Triggered") + +// Set up take profit and stop loss for short positions +strategy.exit(id = 'Short Take Profit / Stop Loss', from_entry = 'S', qty_percent = take_profit_quantity_percent, limit = trailing_take_profit_enabled ? na : short_take_profit_price, stop = short_stop_loss_price, trail_price = trailing_take_profit_enabled ? short_take_profit_price : na, trail_offset = trailing_take_profit_enabled ? short_trailing_tp_step_ticks : na, comment = "TP/SL Triggered") +strategy.exit(id = 'Short Stop Loss', from_entry = 'S', stop = short_stop_loss_price, comment = "SL Triggered") + +// ===== 统一警报系统 ===== +// 统一警报系统 - 只需添加一次警报即可捕获所有信号 + +// 警报频率限制 - 每分钟只触发一次 +var int last_alert_long_entry = 0 +var int last_alert_short_entry = 0 +var int last_alert_long_exit = 0 +var int last_alert_short_exit = 0 +var int last_alert_upper_breakout = 0 +var int last_alert_lower_breakout = 0 +var int last_alert_sma_cross_up = 0 +var int last_alert_sma_cross_down = 0 +var int last_alert_dmi_bullish = 0 +var int last_alert_dmi_bearish = 0 +var int last_alert_trend_bullish = 0 +var int last_alert_trend_bearish = 0 + +// 获取当前时间(分钟级别) +current_minute = math.floor(timenow / 60000) + +// 检测所有警报条件并生成对应的JSON消息 +alert_message = "" + +// 入场信号警报 - 每分钟限制 +if long_entry_condition and current_minute > last_alert_long_entry + alert_message := '{"指标名称":"TMFS","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","价格":"' + str.tostring(close, '#.####') + '","平滑超趋势":"' + str.tostring(smoothed_trend, '#.####') + '","DI+":"' + str.tostring(di_plus, '#.##') + '","DI-":"' + str.tostring(di_minus, '#.##') + '","事件":"多头入场信号触发","信号":"buy","备注":"趋势线突破+DMI确认"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_long_entry := current_minute + +if short_entry_condition and current_minute > last_alert_short_entry + alert_message := '{"指标名称":"TMFS","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","价格":"' + str.tostring(close, '#.####') + '","平滑超趋势":"' + str.tostring(smoothed_trend, '#.####') + '","DI+":"' + str.tostring(di_plus, '#.##') + '","DI-":"' + str.tostring(di_minus, '#.##') + '","事件":"空头入场信号触发","信号":"sell","备注":"趋势线突破+DMI确认"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_short_entry := current_minute + +// 出场信号警报 - 每分钟限制 +if long_exit_condition and current_minute > last_alert_long_exit + alert_message := '{"指标名称":"TMFS","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","价格":"' + str.tostring(close, '#.####') + '","平滑超趋势":"' + str.tostring(smoothed_trend, '#.####') + '","事件":"多头出场信号触发","信号":"exit_long","备注":"价格跌破平滑超趋势"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_long_exit := current_minute + +if short_exit_condition and current_minute > last_alert_short_exit + alert_message := '{"指标名称":"TMFS","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","价格":"' + str.tostring(close, '#.####') + '","平滑超趋势":"' + str.tostring(smoothed_trend, '#.####') + '","事件":"空头出场信号触发","信号":"exit_short","备注":"价格突破平滑超趋势"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_short_exit := current_minute + +// 趋势线突破警报 - 每分钟限制 +if upper_breakout and not upper_breakout[1] and current_minute > last_alert_upper_breakout + alert_message := '{"指标名称":"TMFS","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","价格":"' + str.tostring(close, '#.####') + '","上趋势线":"' + str.tostring(upper_trendline, '#.####') + '","事件":"价格突破上趋势线","信号":"upper_breakout","备注":"潜在看涨信号"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_upper_breakout := current_minute + +if lower_breakout and not lower_breakout[1] and current_minute > last_alert_lower_breakout + alert_message := '{"指标名称":"TMFS","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","价格":"' + str.tostring(close, '#.####') + '","下趋势线":"' + str.tostring(lower_trendline, '#.####') + '","事件":"价格跌破下趋势线","信号":"lower_breakout","备注":"潜在看跌信号"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_lower_breakout := current_minute + +// SMA交叉警报 - 每分钟限制 +if sma_cross_up and current_minute > last_alert_sma_cross_up + alert_message := '{"指标名称":"TMFS","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","价格":"' + str.tostring(close, '#.####') + '","快速SMA":"' + str.tostring(fast_sma, '#.####') + '","慢速SMA":"' + str.tostring(slow_sma, '#.####') + '","事件":"快速SMA上穿慢速SMA","信号":"sma_cross_up","备注":"短期趋势转多"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_sma_cross_up := current_minute + +if sma_cross_down and current_minute > last_alert_sma_cross_down + alert_message := '{"指标名称":"TMFS","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","价格":"' + str.tostring(close, '#.####') + '","快速SMA":"' + str.tostring(fast_sma, '#.####') + '","慢速SMA":"' + str.tostring(slow_sma, '#.####') + '","事件":"快速SMA下穿慢速SMA","信号":"sma_cross_down","备注":"短期趋势转空"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_sma_cross_down := current_minute + +// DMI信号警报 - 每分钟限制 +if ta.crossover(di_plus, di_minus) and current_minute > last_alert_dmi_bullish + alert_message := '{"指标名称":"TMFS","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","价格":"' + str.tostring(close, '#.####') + '","DI+":"' + str.tostring(di_plus, '#.##') + '","DI-":"' + str.tostring(di_minus, '#.##') + '","事件":"DI+上穿DI-","信号":"dmi_bullish","备注":"动量转向看涨"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_dmi_bullish := current_minute + +if ta.crossunder(di_plus, di_minus) and current_minute > last_alert_dmi_bearish + alert_message := '{"指标名称":"TMFS","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","价格":"' + str.tostring(close, '#.####') + '","DI+":"' + str.tostring(di_plus, '#.##') + '","DI-":"' + str.tostring(di_minus, '#.##') + '","事件":"DI+下穿DI-","信号":"dmi_bearish","备注":"动量转向看跌"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_dmi_bearish := current_minute + +// 超趋势方向变化警报 - 每分钟限制 +if ta.crossover(close, smoothed_trend) and current_minute > last_alert_trend_bullish + alert_message := '{"指标名称":"TMFS","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","价格":"' + str.tostring(close, '#.####') + '","平滑超趋势":"' + str.tostring(smoothed_trend, '#.####') + '","事件":"价格上穿平滑超趋势","信号":"trend_bullish","备注":"趋势转向看涨"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_trend_bullish := current_minute + +if ta.crossunder(close, smoothed_trend) and current_minute > last_alert_trend_bearish + alert_message := '{"指标名称":"TMFS","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","价格":"' + str.tostring(close, '#.####') + '","平滑超趋势":"' + str.tostring(smoothed_trend, '#.####') + '","事件":"价格下穿平滑超趋势","信号":"trend_bearish","备注":"趋势转向看跌"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_trend_bearish := current_minute + +// ===== 传统警报条件(保留兼容性)===== +// 注意:使用统一警报系统时,建议只使用上面的alert()函数 +// 以下alertcondition保留用于需要单独设置警报的情况 + +// 创建用于警报的plot变量 +plot(smoothed_trend, title = '平滑超趋势', display = display.none) +plot(di_plus, title = 'DI+', display = display.none) +plot(di_minus, title = 'DI-', display = display.none) +plot(fast_sma, title = '快速SMA', display = display.none) +plot(slow_sma, title = '慢速SMA', display = display.none) +plot(upper_trendline, title = '上趋势线', display = display.none) +plot(lower_trendline, title = '下趋势线', display = display.none) + +// 入场信号警报 +alertcondition(long_entry_condition, title = 'TMFS多头入场', message = '{"指标名称":"TMFS","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","平滑超趋势":"{{plot("平滑超趋势")}}","DI+":"{{plot("DI+")}}","DI-":"{{plot("DI-")}}","事件":"多头入场信号触发","信号":"buy","备注":"趋势线突破+DMI确认"}') + +alertcondition(short_entry_condition, title = 'TMFS空头入场', message = '{"指标名称":"TMFS","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","平滑超趋势":"{{plot("平滑超趋势")}}","DI+":"{{plot("DI+")}}","DI-":"{{plot("DI-")}}","事件":"空头入场信号触发","信号":"sell","备注":"趋势线突破+DMI确认"}') + +// 出场信号警报 +alertcondition(long_exit_condition, title = 'TMFS多头出场', message = '{"指标名称":"TMFS","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","平滑超趋势":"{{plot("平滑超趋势")}}","事件":"多头出场信号触发","信号":"exit_long","备注":"价格跌破平滑超趋势"}') + +alertcondition(short_exit_condition, title = 'TMFS空头出场', message = '{"指标名称":"TMFS","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","平滑超趋势":"{{plot("平滑超趋势")}}","事件":"空头出场信号触发","信号":"exit_short","备注":"价格突破平滑超趋势"}') + +// 趋势线突破警报 +alertcondition(upper_breakout and not upper_breakout[1], title = '价格突破上趋势线', message = '{"指标名称":"TMFS","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","上趋势线":"{{plot("上趋势线")}}","事件":"价格突破上趋势线","信号":"upper_breakout","备注":"潜在看涨信号"}') + +alertcondition(lower_breakout and not lower_breakout[1], title = '价格跌破下趋势线', message = '{"指标名称":"TMFS","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","下趋势线":"{{plot("下趋势线")}}","事件":"价格跌破下趋势线","信号":"lower_breakout","备注":"潜在看跌信号"}') + +// SMA交叉警报 +alertcondition(sma_cross_up, title = '快速SMA上穿慢速SMA', message = '{"指标名称":"TMFS","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","快速SMA":"{{plot("快速SMA")}}","慢速SMA":"{{plot("慢速SMA")}}","事件":"快速SMA上穿慢速SMA","信号":"sma_cross_up","备注":"短期趋势转多"}') + +alertcondition(sma_cross_down, title = '快速SMA下穿慢速SMA', message = '{"指标名称":"TMFS","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","快速SMA":"{{plot("快速SMA")}}","慢速SMA":"{{plot("慢速SMA")}}","事件":"快速SMA下穿慢速SMA","信号":"sma_cross_down","备注":"短期趋势转空"}') + +// DMI信号警报 +alertcondition(ta.crossover(di_plus, di_minus), title = 'DI+上穿DI-', message = '{"指标名称":"TMFS","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","DI+":"{{plot("DI+")}}","DI-":"{{plot("DI-")}}","事件":"DI+上穿DI-","信号":"dmi_bullish","备注":"动量转向看涨"}') + +alertcondition(ta.crossunder(di_plus, di_minus), title = 'DI+下穿DI-', message = '{"指标名称":"TMFS","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","DI+":"{{plot("DI+")}}","DI-":"{{plot("DI-")}}","事件":"DI+下穿DI-","信号":"dmi_bearish","备注":"动量转向看跌"}') + +// 超趋势方向变化警报 +alertcondition(ta.crossover(close, smoothed_trend), title = '价格上穿平滑超趋势', message = '{"指标名称":"TMFS","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","平滑超趋势":"{{plot("平滑超趋势")}}","事件":"价格上穿平滑超趋势","信号":"trend_bullish","备注":"趋势转向看涨"}') + +alertcondition(ta.crossunder(close, smoothed_trend), title = '价格下穿平滑超趋势', message = '{"指标名称":"TMFS","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","平滑超趋势":"{{plot("平滑超趋势")}}","事件":"价格下穿平滑超趋势","信号":"trend_bearish","备注":"趋势转向看跌"}') + +// 综合信号警报 +alertcondition(upper_breakout and di_plus > di_minus, title = '强势看涨信号', message = '{"指标名称":"TMFS","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","事件":"强势看涨信号","信号":"strong_bullish","备注":"趋势线突破+DMI看涨"}') + +alertcondition(lower_breakout and di_minus > di_plus, title = '强势看跌信号', message = '{"指标名称":"TMFS","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","事件":"强势看跌信号","信号":"strong_bearish","备注":"趋势线跌破+DMI看跌"}') + +// 趋势确认警报 +alertcondition(close > smoothed_trend and di_plus > di_minus, title = '多头趋势确认', message = '{"指标名称":"TMFS","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","平滑超趋势":"{{plot("平滑超趋势")}}","DI+":"{{plot("DI+")}}","DI-":"{{plot("DI-")}}","事件":"多头趋势确认","信号":"bullish_trend_confirmed","备注":"价格在超趋势上方且DMI看涨"}') + +alertcondition(close < smoothed_trend and di_minus > di_plus, title = '空头趋势确认', message = '{"指标名称":"TMFS","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","平滑超趋势":"{{plot("平滑超趋势")}}","DI+":"{{plot("DI+")}}","DI-":"{{plot("DI-")}}","事件":"空头趋势确认","信号":"bearish_trend_confirmed","备注":"价格在超趋势下方且DMI看跌"}') + diff --git a/tmfs2.pine b/tmfs2.pine new file mode 100644 index 0000000..9a45781 --- /dev/null +++ b/tmfs2.pine @@ -0,0 +1,561 @@ +// This work is licensed under a Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) +// https://creativecommons.org/licenses/by-nc-sa/4.0/ +// Original concepts by FibonacciFlux, rewritten for clarity and functionality + +//@version=6 +strategy('Trendline Breaks 带警报2', shorttitle = "TMFS Strategy alerts2", overlay = true, initial_capital = 10000, default_qty_type = strategy.percent_of_equity, default_qty_value = 4,commission_type = strategy.commission.percent, commission_value = 0.03, pyramiding = 2 ) + +//---------------------------------------------------------- +// SECTION 1: FIBONACCI SUPERTREND CONFIGURATION +//---------------------------------------------------------- + +// Common ATR period for all supertrend calculations +atrPeriod = input.int(13, 'ATR Length', minval = 1, tooltip="ATR period used for volatility calculation") + +// Fibonacci-based supertrend factor inputs +factor1 = input.float(0.618, 'Factor 1 (Weak/Fibonacci)', minval = 0.01, step = 0.01, tooltip="First Fibonacci factor (0.618)") +factor2 = input.float(1.618, 'Factor 2 (Medium/Golden Ratio)', minval = 0.01, step = 0.01, tooltip="Second Fibonacci factor (1.618)") +factor3 = input.float(2.618, 'Factor 3 (Strong/Extended Fib)', minval = 0.01, step = 0.01, tooltip="Third Fibonacci factor (2.618)") + +// Calculate the three Supertrend lines with different sensitivity levels +[supertrend1, direction1] = ta.supertrend(factor1, atrPeriod) +[supertrend2, direction2] = ta.supertrend(factor2, atrPeriod) +[supertrend3, direction3] = ta.supertrend(factor3, atrPeriod) + +// Handle initial values (first bar) +supertrend1 := barstate.isfirst ? na : supertrend1 +supertrend2 := barstate.isfirst ? na : supertrend2 +supertrend3 := barstate.isfirst ? na : supertrend3 + +// Calculate average of the three supertends and a smoothed version +superlength = input.int(21, "Smoothing Length", tooltip="EMA length for smoothing the average supertrend") +average_trend = (supertrend1 + supertrend2 + supertrend3) / 3 +smoothed_trend = ta.ema(average_trend, superlength) + +// Plot the supertrend lines and fill the area between them +trend_plot = plot(average_trend, color = average_trend > average_trend[1] ? color.green : color.red, title="Average Supertrend") +smoothed_plot = plot(smoothed_trend, linewidth = 2, color = smoothed_trend > smoothed_trend[1] ? color.green : color.red, title="Smoothed Supertrend") +fill(trend_plot, smoothed_plot, color = average_trend > smoothed_trend ? color.new(color.green, 50) : color.new(color.red, 50), title="Trend Direction Fill") + +//---------------------------------------------------------- +// SECTION 2: TRENDLINE DETECTION AND DRAWING +//---------------------------------------------------------- + +// User settings for Swing Trend Lines +swing_length = input.int(8, 'Swing Lookback Period', tooltip="Number of bars to look back for pivot points") +atr_multiplier = input.float(1.0, 'ATR Slope Multiplier', minval = 0.0, step = 0.1, tooltip="Multiplier for ATR to control trendline slope") +show_extended_lines = input.bool(true, 'Show Extended Lines', tooltip="Display dashed extensions for trendlines") +enable_backpainting = input.bool(true, 'Use Backpainting', tooltip="Enable backpainting to move indicators to pivot point") + +// Color settings for trendlines +uptrend_color = color.new(color.teal, 0) +downtrend_color = color.new(color.red, 0) + +// Variable initialization for trendlines +var float upper_trendline = na +var float lower_trendline = na +var float upper_slope = na +var float lower_slope = na +var line upline_extension = na +var line downline_extension = na + +// Offset for backpainting +offset = enable_backpainting ? swing_length : 0 +bar_idx = bar_index + +// Get pivot high and low points +pivot_high = ta.pivothigh(swing_length, swing_length) +pivot_low = ta.pivotlow(swing_length, swing_length) + +// Calculate ATR for slope +atr_value = ta.atr(swing_length) +slope = atr_value / swing_length * atr_multiplier + +// Update upper trendline when pivot high is detected or extend existing trendline +if bool(pivot_high) + upper_slope := slope + upper_trendline := pivot_high +else + upper_trendline := nz(upper_trendline) - nz(upper_slope) + +// Update lower trendline when pivot low is detected or extend existing trendline +if bool(pivot_low) + lower_slope := slope + lower_trendline := pivot_low +else + lower_trendline := nz(lower_trendline) + nz(lower_slope) + +// Create and update extended visualization lines if enabled +if show_extended_lines + // Initialize line objects if not already created + if na(upline_extension) + upline_extension := line.new(na, na, na, na, extend = extend.right, style = line.style_dashed, color = uptrend_color) + + if na(downline_extension) + downline_extension := line.new(na, na, na, na, extend = extend.right, style = line.style_dashed, color = downtrend_color) + + // Update upper trendline extension when a new pivot high is confirmed + if bool(pivot_high) + line.set_xy1(upline_extension, bar_idx - offset, enable_backpainting ? pivot_high : upper_trendline) + line.set_xy2(upline_extension, bar_idx - offset + 1, enable_backpainting ? pivot_high - slope : upper_trendline - slope) + + // Update lower trendline extension when a new pivot low is confirmed + if bool(pivot_low) + line.set_xy1(downline_extension, bar_idx - offset, enable_backpainting ? pivot_low : lower_trendline) + line.set_xy2(downline_extension, bar_idx - offset + 1, enable_backpainting ? pivot_low + slope : lower_trendline + slope) + +//---------------------------------------------------------- +// SECTION 3: BREAKOUT DETECTION +//---------------------------------------------------------- + +// Track breakouts above upper trendline and below lower trendline +// Initialize tracking variables for breakout conditions +var int upper_breakout_state = 0 // State variable to track upper breakout condition +var int lower_breakout_state = 0 // State variable to track lower breakout condition + +// 优化的突破检测 - 添加多K线确认机制,避免假突破 +bool upper_breakout = close > upper_trendline and close[1] > upper_trendline[1] and close[2] > upper_trendline[2] +bool lower_breakout = close < lower_trendline and close[1] < lower_trendline[1] and close[2] < lower_trendline[2] + +// Update state variables to track when breakouts occur +upper_breakout_state := bool(pivot_high) ? 0 : upper_breakout ? 1 : upper_breakout_state +lower_breakout_state := bool(pivot_low) ? 0 : lower_breakout ? 1 : lower_breakout_state + +// Plot trendlines with appropriate offsets +plot(enable_backpainting ? upper_trendline : upper_trendline, color = bool(pivot_high) ? na : uptrend_color, linewidth = 2, offset = -offset, title = 'Upper Trendline') +plot(enable_backpainting ? lower_trendline : lower_trendline, color = bool(pivot_low) ? na : downtrend_color, linewidth = 2, offset = -offset, title = 'Lower Trendline') + +//---------------------------------------------------------- +// SECTION 4: DIRECTIONAL MOVEMENT INDEX (DMI) CALCULATION +//---------------------------------------------------------- + +// DMI Length parameter +dmi_length = input.int(13, "DMI Length", tooltip="Length for DMI calculation") + +// True Range calculation +true_range = math.max(math.max(high - low, math.abs(high - nz(close[1]))), math.abs(low - nz(close[1]))) + +// Directional Movement calculations +directional_movement_plus = high - nz(high[1]) > nz(low[1]) - low ? math.max(high - nz(high[1]), 0) : 0 +directional_movement_minus = nz(low[1]) - low > high - nz(high[1]) ? math.max(nz(low[1]) - low, 0) : 0 + +// Smoothed calculations for DMI +var float smoothed_true_range = 0.0 +smoothed_true_range := nz(smoothed_true_range[1]) - nz(smoothed_true_range[1]) / dmi_length + true_range + +var float smoothed_directional_plus = 0.0 +smoothed_directional_plus := nz(smoothed_directional_plus[1]) - nz(smoothed_directional_plus[1]) / dmi_length + directional_movement_plus + +var float smoothed_directional_minus = 0.0 +smoothed_directional_minus := nz(smoothed_directional_minus[1]) - nz(smoothed_directional_minus[1]) / dmi_length + directional_movement_minus + +// Calculate DI+ and DI- values +di_plus = smoothed_directional_plus / smoothed_true_range * 100 +di_minus = smoothed_directional_minus / smoothed_true_range * 100 + +//---------------------------------------------------------- +// SECTION 4.5: 准确性优化设置 +//---------------------------------------------------------- + +// 根据用户偏好使用第10根K线确认,减少误报 +confirmation_lookback = input.int(10, "确认回看期间", minval=1, maxval=20, tooltip="使用第N根K线确认交叉信号,减少误报", group="准确性优化") +dmi_threshold = input.float(20.0, "DMI最小阈值", minval=10.0, maxval=50.0, tooltip="DMI值必须超过此阈值才触发信号", group="准确性优化") +volume_confirmation = input.bool(true, "启用成交量确认", tooltip="要求成交量高于平均值才触发信号", group="准确性优化") +volume_multiplier = input.float(1.2, "成交量倍数", minval=1.0, maxval=3.0, step=0.1, tooltip="成交量必须是平均成交量的倍数", group="准确性优化") +min_alert_interval = input.int(5, "最小警报间隔", minval=1, maxval=20, tooltip="两次警报之间的最小K线间隔", group="准确性优化") + +// 警报去重机制 +var int last_alert_bar = 0 + +//---------------------------------------------------------- +// SECTION 5: STRATEGY DEFINITION +//---------------------------------------------------------- + +// Enable/disable long and short positions +enable_long_positions = input.bool(defval = true, title = 'Enable Long Positions', group = 'Strategy Settings') +enable_short_positions = input.bool(defval = true, title = 'Enable Short Positions', group = 'Strategy Settings') + +// 优化的SMA设置 - 增加周期以减少噪音 +fast_sma_length = input.int(defval = 5, title = 'Fast SMA Length', minval = 1, group = 'Strategy Settings') +slow_sma_length = input.int(defval = 10, title = 'Slow SMA Length', minval = 1, group = 'Strategy Settings') +sma_distance_threshold = input.float(0.001, "SMA距离阈值", minval=0.0001, step=0.0001, tooltip="SMA之间的最小距离阈值", group = 'Strategy Settings') + +// Calculate SMA crossovers +fast_sma = ta.sma(close, fast_sma_length) +slow_sma = ta.sma(close, slow_sma_length) + +// 优化的SMA交叉检测 - 添加距离过滤 +sma_cross_up = ta.crossover(fast_sma, slow_sma) and math.abs(fast_sma - slow_sma) > close * sma_distance_threshold +sma_cross_down = ta.crossunder(fast_sma, slow_sma) and math.abs(fast_sma - slow_sma) > close * sma_distance_threshold + +//---------------------------------------------------------- +// SECTION 6: ENTRY AND EXIT CONDITIONS +//---------------------------------------------------------- + +// 成交量确认 +volume_avg = ta.sma(volume, 20) +volume_confirmed = not volume_confirmation or volume > volume_avg * volume_multiplier + +// 多重确认机制 +trend_confirmed_bullish = true +trend_confirmed_bearish = true +for i = 0 to 2 + trend_confirmed_bullish := trend_confirmed_bullish and close[i] > smoothed_trend[i] + trend_confirmed_bearish := trend_confirmed_bearish and close[i] < smoothed_trend[i] + +// 优化的DMI信号 - 添加强度过滤 +strong_dmi_bullish = di_plus > di_minus and di_plus > dmi_threshold +strong_dmi_bearish = di_minus > di_plus and di_minus > dmi_threshold + +// 优化的入场条件 - 添加多重确认 +long_entry_condition = enable_long_positions and + upper_breakout_state > upper_breakout_state[1] and + strong_dmi_bullish and + trend_confirmed_bullish and + volume_confirmed + +short_entry_condition = enable_short_positions and + lower_breakout_state > lower_breakout_state[1] and + strong_dmi_bearish and + trend_confirmed_bearish and + volume_confirmed + + + +// 优化后的出场条件 - 使用第10根K线确认 +long_exit_condition = ta.crossunder(close[confirmation_lookback], smoothed_trend[confirmation_lookback]) +short_exit_condition = ta.crossover(close[confirmation_lookback], smoothed_trend[confirmation_lookback]) + +// @function Display BUY/SELL labels on chart +plotshape(long_entry_condition, title='BUY', text='BUY', location=location.belowbar, + style=shape.labelup, size=size.tiny, color=color.new(color.green, 0), textcolor=color.new(color.white, 0)) +plotshape(short_entry_condition, title='SELL', text='SELL', location=location.abovebar, + style=shape.labeldown, size=size.tiny, color=color.new(color.red, 0), textcolor=color.new(color.white, 0)) + +//---------------------------------------------------------- +// SECTION 7: STOP LOSS AND TAKE PROFIT SETTINGS +//---------------------------------------------------------- + +// Common settings +atr_length = input.int(13, 'ATR Length for SL/TP', minval = 1, group = 'Risk Management') + +// Variable to track if stop loss is triggered +var bool long_trailing_tp_executed = false +var bool short_trailing_tp_executed = false + +// Store ATR at position entry +float entry_atr = ta.valuewhen(long_entry_condition or short_entry_condition, ta.atr(atr_length), 0) + +// Stop Loss settings +stop_loss_method = input.string(defval = 'ATR', title = 'Stop Loss Method', options = ['PERC', 'ATR'], group = 'Stop Loss') +long_stop_loss_percent = input.float(defval = 0.75, title = 'Long Position Stop Loss %', minval = 0.05, maxval = 100, step = 0.05, group = 'Stop Loss') / 100 +short_stop_loss_percent = input.float(defval = 0.75, title = 'Short Position Stop Loss %', minval = 0.05, maxval = 100, step = 0.05, group = 'Stop Loss') / 100 +long_stop_loss_atr_multiplier = input.float(defval = 8.0, title = 'Long Position ATR Multiplier', minval = 0.1, step = 0.1, group = 'Stop Loss') +short_stop_loss_atr_multiplier = input.float(defval = 8.0, title = 'Short Position ATR Multiplier', minval = 0.1, step = 0.1, group = 'Stop Loss') +stop_loss_trailing_mode = input.string(defval = 'ON', title = 'Trailing Stop Loss Mode', options = ['TP', 'ON', 'OFF'], tooltip = 'ON: Always trail, TP: Trail after Take Profit hit, OFF: Fixed stop', group = 'Stop Loss') +break_even_enabled = input.bool(defval = true, title = 'Move to Break Even After TP', group = 'Stop Loss') + +// Take Profit settings +take_profit_quantity_percent = input.float(defval = 100, title = 'Take Profit Quantity %', minval = 0.0, maxval = 100, step = 1.0, group = 'Take Profit') +take_profit_method = input.string(defval = 'PERC', title = 'Take Profit Method', options = ['PERC', 'ATR', 'RR'], group = 'Take Profit') +long_take_profit_percent = input.float(defval = 1, title = 'Long Position Take Profit %', minval = 0.05, step = 0.05, group = 'Take Profit') / 100 +short_take_profit_percent = input.float(defval = 1, title = 'Short Position Take Profit %', minval = 0.05, step = 0.05, group = 'Take Profit') / 100 +long_take_profit_atr_multiplier = input.float(defval = 1.5, title = 'Long Position TP ATR Multiplier', minval = 0.1, step = 0.1, group = 'Take Profit') +short_take_profit_atr_multiplier = input.float(defval = 2, title = 'Short Position TP ATR Multiplier', minval = 0.1, step = 0.1, group = 'Take Profit') +long_risk_reward_ratio = input.float(defval = 0.6, title = 'Long Position Risk/Reward Ratio', minval = 0.1, step = 0.1, group = 'Take Profit') +short_risk_reward_ratio = input.float(defval = 1, title = 'Short Position Risk/Reward Ratio', minval = 0.1, step = 0.1, group = 'Take Profit') +trailing_take_profit_enabled = input.bool(defval = true, title = 'Enable Trailing Take Profit', group = 'Take Profit') +deviation_method = input.string(defval = 'PERC', title = 'Trailing Deviation Method', options = ['PERC', 'ATR'], group = 'Take Profit') +deviation_percent = input.float(defval = 0.01, title = 'Trailing Deviation %', minval = 0.01, maxval = 100, step = 0.05, group = 'Take Profit') / 100 +deviation_atr_multiplier = input.float(defval = 1.0, title = 'Trailing Deviation ATR Multiplier', minval = 0.01, step = 0.05, group = 'Take Profit') + +//---------------------------------------------------------- +// SECTION 9: CALCULATE STOP LOSS LEVELS +//---------------------------------------------------------- + +// Calculate long position stop loss price based on selected method +get_long_stop_loss_price(base_price) => + switch stop_loss_method + 'PERC' => base_price * (1 - long_stop_loss_percent) + 'ATR' => base_price - long_stop_loss_atr_multiplier * entry_atr + => na + +// Determine if trailing should be active for long position +long_tp_trailing_enabled = stop_loss_trailing_mode == 'ON' or (stop_loss_trailing_mode == 'TP' and long_trailing_tp_executed) + +// Calculate and maintain stop loss price for long positions +var float long_stop_loss_price = na +long_stop_loss_price := if strategy.position_size > 0 + if long_entry_condition + get_long_stop_loss_price(close) + else + stop_price = get_long_stop_loss_price(long_tp_trailing_enabled ? high : strategy.position_avg_price) + stop_price := break_even_enabled and long_trailing_tp_executed ? math.max(stop_price, strategy.position_avg_price) : stop_price + math.max(stop_price, nz(long_stop_loss_price[1])) +else + na + +// Calculate short position stop loss price based on selected method +get_short_stop_loss_price(base_price) => + switch stop_loss_method + 'PERC' => base_price * (1 + short_stop_loss_percent) + 'ATR' => base_price + short_stop_loss_atr_multiplier * entry_atr + => na + +// Determine if trailing should be active for short position +short_tp_trailing_enabled = stop_loss_trailing_mode == 'ON' or (stop_loss_trailing_mode == 'TP' and short_trailing_tp_executed) + +// Calculate and maintain stop loss price for short positions +var float short_stop_loss_price = na +short_stop_loss_price := if strategy.position_size < 0 + if short_entry_condition + get_short_stop_loss_price(close) + else + var float stop_price = get_short_stop_loss_price(short_tp_trailing_enabled ? low : strategy.position_avg_price) // stop_price を var float で宣言 + if break_even_enabled and short_trailing_tp_executed + stop_price := math.min(stop_price, strategy.position_avg_price) + short_stop_loss_price := math.min(stop_price, nz(short_stop_loss_price[1], 999999.9)) +else + na + +//---------------------------------------------------------- +// SECTION 9: CALCULATE TAKE PROFIT LEVELS +//---------------------------------------------------------- + +// Calculate long position take profit price based on selected method +get_long_take_profit_price() => + switch take_profit_method + 'PERC' => close * (1 + long_take_profit_percent) + 'ATR' => close + long_take_profit_atr_multiplier * entry_atr + 'RR' => close + long_risk_reward_ratio * (close - get_long_stop_loss_price(close)) + => na + +// Calculate and maintain take profit price for long positions +var float long_take_profit_price = na +long_take_profit_price := if strategy.position_size > 0 and not long_trailing_tp_executed + if long_entry_condition + get_long_take_profit_price() + else + nz(long_take_profit_price[1], get_long_take_profit_price()) +else + na + +// Update trailing take profit execution flag for long positions +long_trailing_tp_executed := strategy.position_size > 0 and (long_trailing_tp_executed[1] or strategy.position_size < strategy.position_size[1] or (strategy.position_size[1] == 0 and high >= long_take_profit_price)) + +// Calculate trailing step size in ticks for long positions +long_trailing_tp_step_ticks = switch deviation_method + 'PERC' => long_take_profit_price * deviation_percent / syminfo.mintick + 'ATR' => deviation_atr_multiplier * entry_atr / syminfo.mintick + => na + +// Calculate short position take profit price based on selected method +get_short_take_profit_price() => + switch take_profit_method + 'PERC' => close * (1 - short_take_profit_percent) + 'ATR' => close - short_take_profit_atr_multiplier * entry_atr + 'RR' => close - short_risk_reward_ratio * (get_short_stop_loss_price(close) - close) + => na + +// Calculate and maintain take profit price for short positions +var float short_take_profit_price = na +short_take_profit_price := if strategy.position_size < 0 and not short_trailing_tp_executed + if short_entry_condition + get_short_take_profit_price() + else + nz(short_take_profit_price[1], get_short_take_profit_price()) +else + na + +// Update trailing take profit execution flag for short positions +short_trailing_tp_executed := strategy.position_size < 0 and (short_trailing_tp_executed[1] or strategy.position_size > strategy.position_size[1] or (strategy.position_size[1] == 0 and low <= short_take_profit_price)) + +// Calculate trailing step size in ticks for short positions +short_trailing_tp_step_ticks = switch deviation_method + 'PERC' => short_take_profit_price * deviation_percent / syminfo.mintick + 'ATR' => deviation_atr_multiplier * entry_atr / syminfo.mintick + => na + +//---------------------------------------------------------- +// SECTION 11: STRATEGY EXECUTION +//---------------------------------------------------------- + +// Enter long position when conditions are met +if long_entry_condition + strategy.entry('L', strategy.long, comment = "LONG") + +// Enter short position when conditions are met +if short_entry_condition + strategy.entry('S', strategy.short, comment = "SHORT") + +// Exit long position when exit conditions are met +if long_exit_condition + strategy.close('L', comment = "SL Triggered") + +// Exit short position when exit conditions are met +if short_exit_condition + strategy.close('S', comment = "SL Triggered") + +// Set up take profit and stop loss for long positions +strategy.exit(id = 'Long Take Profit / Stop Loss', from_entry = 'L', qty_percent = take_profit_quantity_percent, limit = trailing_take_profit_enabled ? na : long_take_profit_price, stop = long_stop_loss_price, trail_price = trailing_take_profit_enabled ? long_take_profit_price : na, trail_offset = trailing_take_profit_enabled ? long_trailing_tp_step_ticks : na, comment = "TP/SL Triggered") +strategy.exit(id = 'Long Stop Loss', from_entry = 'L', stop = long_stop_loss_price, comment = "SL Triggered") + +// Set up take profit and stop loss for short positions +strategy.exit(id = 'Short Take Profit / Stop Loss', from_entry = 'S', qty_percent = take_profit_quantity_percent, limit = trailing_take_profit_enabled ? na : short_take_profit_price, stop = short_stop_loss_price, trail_price = trailing_take_profit_enabled ? short_take_profit_price : na, trail_offset = trailing_take_profit_enabled ? short_trailing_tp_step_ticks : na, comment = "TP/SL Triggered") +strategy.exit(id = 'Short Stop Loss', from_entry = 'S', stop = short_stop_loss_price, comment = "SL Triggered") + +// ===== 统一警报系统 ===== +// 统一警报系统 - 只需添加一次警报即可捕获所有信号 + +// 警报频率限制 - 每分钟只触发一次 +var int last_alert_long_entry = 0 +var int last_alert_short_entry = 0 +var int last_alert_long_exit = 0 +var int last_alert_short_exit = 0 +var int last_alert_upper_breakout = 0 +var int last_alert_lower_breakout = 0 +var int last_alert_sma_cross_up = 0 +var int last_alert_sma_cross_down = 0 +var int last_alert_dmi_bullish = 0 +var int last_alert_dmi_bearish = 0 +var int last_alert_trend_bullish = 0 +var int last_alert_trend_bearish = 0 + +// 获取当前时间(分钟级别) +current_minute = math.floor(timenow / 60000) + +// 检测所有警报条件并生成对应的JSON消息 +alert_message = "" + +// 入场信号警报 - 每分钟限制 +if long_entry_condition and current_minute > last_alert_long_entry + alert_message := '{"指标名称":"TMFS_V2","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","价格":"' + str.tostring(close, '#.####') + '","平滑超趋势":"' + str.tostring(smoothed_trend, '#.####') + '","DI+":"' + str.tostring(di_plus, '#.##') + '","DI-":"' + str.tostring(di_minus, '#.##') + '","成交量倍数":"' + str.tostring(volume/volume_avg, '#.##') + '","事件":"多头入场信号触发","信号":"buy","备注":"多重确认+成交量验证"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_long_entry := current_minute + +if short_entry_condition and current_minute > last_alert_short_entry + alert_message := '{"指标名称":"TMFS_V2","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","价格":"' + str.tostring(close, '#.####') + '","平滑超趋势":"' + str.tostring(smoothed_trend, '#.####') + '","DI+":"' + str.tostring(di_plus, '#.##') + '","DI-":"' + str.tostring(di_minus, '#.##') + '","成交量倍数":"' + str.tostring(volume/volume_avg, '#.##') + '","事件":"空头入场信号触发","信号":"sell","备注":"多重确认+成交量验证"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_short_entry := current_minute + +// 出场信号警报 - 每分钟限制 +if long_exit_condition and current_minute > last_alert_long_exit + alert_message := '{"指标名称":"TMFS_V2","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","价格":"' + str.tostring(close, '#.####') + '","平滑超趋势":"' + str.tostring(smoothed_trend, '#.####') + '","确认期间":"' + str.tostring(confirmation_lookback) + '","事件":"多头出场信号触发","信号":"exit_long","备注":"第' + str.tostring(confirmation_lookback) + '根K线确认跌破"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_long_exit := current_minute + +if short_exit_condition and current_minute > last_alert_short_exit + alert_message := '{"指标名称":"TMFS_V2","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","价格":"' + str.tostring(close, '#.####') + '","平滑超趋势":"' + str.tostring(smoothed_trend, '#.####') + '","确认期间":"' + str.tostring(confirmation_lookback) + '","事件":"空头出场信号触发","信号":"exit_short","备注":"第' + str.tostring(confirmation_lookback) + '根K线确认突破"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_short_exit := current_minute + +// 优化的趋势线突破警报 - 每分钟限制 +if upper_breakout and not upper_breakout[1] and current_minute > last_alert_upper_breakout + alert_message := '{"指标名称":"TMFS_V2","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","价格":"' + str.tostring(close, '#.####') + '","上趋势线":"' + str.tostring(upper_trendline, '#.####') + '","突破强度":"连续3K线","事件":"价格确认突破上趋势线","信号":"upper_breakout","备注":"3K线确认突破,过滤假突破"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_upper_breakout := current_minute + +if lower_breakout and not lower_breakout[1] and current_minute > last_alert_lower_breakout + alert_message := '{"指标名称":"TMFS_V2","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","价格":"' + str.tostring(close, '#.####') + '","下趋势线":"' + str.tostring(lower_trendline, '#.####') + '","突破强度":"连续3K线","事件":"价格确认跌破下趋势线","信号":"lower_breakout","备注":"3K线确认跌破,过滤假突破"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_lower_breakout := current_minute + +// 优化的SMA交叉警报 - 每分钟限制 +if sma_cross_up and current_minute > last_alert_sma_cross_up + sma_distance = math.abs(fast_sma - slow_sma) / close * 100 + alert_message := '{"指标名称":"TMFS_V2","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","价格":"' + str.tostring(close, '#.####') + '","快速SMA":"' + str.tostring(fast_sma, '#.####') + '","慢速SMA":"' + str.tostring(slow_sma, '#.####') + '","SMA距离":"' + str.tostring(sma_distance, '#.###') + '%","事件":"SMA金叉确认","信号":"sma_cross_up","备注":"5/10周期+距离过滤"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_sma_cross_up := current_minute + +if sma_cross_down and current_minute > last_alert_sma_cross_down + sma_distance = math.abs(fast_sma - slow_sma) / close * 100 + alert_message := '{"指标名称":"TMFS_V2","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","价格":"' + str.tostring(close, '#.####') + '","快速SMA":"' + str.tostring(fast_sma, '#.####') + '","慢速SMA":"' + str.tostring(slow_sma, '#.####') + '","SMA距离":"' + str.tostring(sma_distance, '#.###') + '%","事件":"SMA死叉确认","信号":"sma_cross_down","备注":"5/10周期+距离过滤"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_sma_cross_down := current_minute + +// 优化的DMI信号警报 - 每分钟限制 +if ta.crossover(di_plus, di_minus) and di_plus > dmi_threshold and current_minute > last_alert_dmi_bullish + alert_message := '{"指标名称":"TMFS_V2","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","价格":"' + str.tostring(close, '#.####') + '","DI+":"' + str.tostring(di_plus, '#.##') + '","DI-":"' + str.tostring(di_minus, '#.##') + '","DMI阈值":"' + str.tostring(dmi_threshold, '#.##') + '","事件":"强势DI+上穿DI-","信号":"dmi_bullish","备注":"动量转向看涨(已过滤弱信号)"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_dmi_bullish := current_minute + +if ta.crossunder(di_plus, di_minus) and di_minus > dmi_threshold and current_minute > last_alert_dmi_bearish + alert_message := '{"指标名称":"TMFS_V2","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","价格":"' + str.tostring(close, '#.####') + '","DI+":"' + str.tostring(di_plus, '#.##') + '","DI-":"' + str.tostring(di_minus, '#.##') + '","DMI阈值":"' + str.tostring(dmi_threshold, '#.##') + '","事件":"强势DI+下穿DI-","信号":"dmi_bearish","备注":"动量转向看跌(已过滤弱信号)"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_dmi_bearish := current_minute + +// 超趋势方向变化警报 - 每分钟限制 +if ta.crossover(close, smoothed_trend) and current_minute > last_alert_trend_bullish + trend_strength = math.abs(close - smoothed_trend) / close * 100 + alert_message := '{"指标名称":"TMFS_V2","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","价格":"' + str.tostring(close, '#.####') + '","平滑超趋势":"' + str.tostring(smoothed_trend, '#.####') + '","趋势强度":"' + str.tostring(trend_strength, '#.###') + '%","事件":"价格上穿平滑超趋势","信号":"trend_bullish","备注":"趋势转向看涨"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_trend_bullish := current_minute + +if ta.crossunder(close, smoothed_trend) and current_minute > last_alert_trend_bearish + trend_strength = math.abs(close - smoothed_trend) / close * 100 + alert_message := '{"指标名称":"TMFS_V2","交易对":"' + syminfo.ticker + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","价格":"' + str.tostring(close, '#.####') + '","平滑超趋势":"' + str.tostring(smoothed_trend, '#.####') + '","趋势强度":"' + str.tostring(trend_strength, '#.###') + '%","事件":"价格下穿平滑超趋势","信号":"trend_bearish","备注":"趋势转向看跌"}' + alert(alert_message, alert.freq_once_per_bar_close) + last_alert_trend_bearish := current_minute + +// ===== 传统警报条件(保留兼容性)===== +// 注意:使用统一警报系统时,建议只使用上面的alert()函数 +// 以下alertcondition保留用于需要单独设置警报的情况 + +// 创建用于警报的plot变量 +plot(smoothed_trend, title = '平滑超趋势', display = display.none) +plot(di_plus, title = 'DI+', display = display.none) +plot(di_minus, title = 'DI-', display = display.none) +plot(fast_sma, title = '快速SMA', display = display.none) +plot(slow_sma, title = '慢速SMA', display = display.none) +plot(upper_trendline, title = '上趋势线', display = display.none) +plot(lower_trendline, title = '下趋势线', display = display.none) +plot(volume/volume_avg, title = '成交量倍数', display = display.none) + +// 入场信号警报 +alertcondition(long_entry_condition, title = 'TMFS_V2多头入场', message = '{"指标名称":"TMFS_V2","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","平滑超趋势":"{{plot("平滑超趋势")}}","DI+":"{{plot("DI+")}}","DI-":"{{plot("DI-")}}","成交量倍数":"{{plot("成交量倍数")}}","事件":"多头入场信号触发","信号":"buy","备注":"多重确认+成交量验证"}') + +alertcondition(short_entry_condition, title = 'TMFS_V2空头入场', message = '{"指标名称":"TMFS_V2","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","平滑超趋势":"{{plot("平滑超趋势")}}","DI+":"{{plot("DI+")}}","DI-":"{{plot("DI-")}}","成交量倍数":"{{plot("成交量倍数")}}","事件":"空头入场信号触发","信号":"sell","备注":"多重确认+成交量验证"}') + +// 出场信号警报 +alertcondition(long_exit_condition, title = 'TMFS_V2多头出场', message = '{"指标名称":"TMFS_V2","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","平滑超趋势":"{{plot("平滑超趋势")}}","事件":"多头出场信号触发","信号":"exit_long","备注":"第10根K线确认跌破"}') + +alertcondition(short_exit_condition, title = 'TMFS_V2空头出场', message = '{"指标名称":"TMFS_V2","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","平滑超趋势":"{{plot("平滑超趋势")}}","事件":"空头出场信号触发","信号":"exit_short","备注":"第10根K线确认突破"}') + +// 优化的趋势线突破警报 +alertcondition(upper_breakout and not upper_breakout[1], title = '价格确认突破上趋势线', message = '{"指标名称":"TMFS_V2","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","上趋势线":"{{plot("上趋势线")}}","事件":"价格确认突破上趋势线","信号":"upper_breakout","备注":"3K线确认突破,过滤假突破"}') + +alertcondition(lower_breakout and not lower_breakout[1], title = '价格确认跌破下趋势线', message = '{"指标名称":"TMFS_V2","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","下趋势线":"{{plot("下趋势线")}}","事件":"价格确认跌破下趋势线","信号":"lower_breakout","备注":"3K线确认跌破,过滤假突破"}') + +// 优化的SMA交叉警报 +alertcondition(sma_cross_up, title = 'SMA金叉确认', message = '{"指标名称":"TMFS_V2","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","快速SMA":"{{plot("快速SMA")}}","慢速SMA":"{{plot("慢速SMA")}}","事件":"SMA金叉确认","信号":"sma_cross_up","备注":"5/10周期+距离过滤"}') + +alertcondition(sma_cross_down, title = 'SMA死叉确认', message = '{"指标名称":"TMFS_V2","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","快速SMA":"{{plot("快速SMA")}}","慢速SMA":"{{plot("慢速SMA")}}","事件":"SMA死叉确认","信号":"sma_cross_down","备注":"5/10周期+距离过滤"}') + +// 优化的DMI信号警报 +alertcondition(ta.crossover(di_plus, di_minus) and di_plus > dmi_threshold, title = '强势DI+上穿DI-', message = '{"指标名称":"TMFS_V2","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","DI+":"{{plot("DI+")}}","DI-":"{{plot("DI-")}}","事件":"强势DI+上穿DI-","信号":"dmi_bullish","备注":"动量转向看涨(已过滤弱信号)"}') + +alertcondition(ta.crossunder(di_plus, di_minus) and di_minus > dmi_threshold, title = '强势DI+下穿DI-', message = '{"指标名称":"TMFS_V2","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","DI+":"{{plot("DI+")}}","DI-":"{{plot("DI-")}}","事件":"强势DI+下穿DI-","信号":"dmi_bearish","备注":"动量转向看跌(已过滤弱信号)"}') + +// 超趋势方向变化警报 +alertcondition(ta.crossover(close, smoothed_trend), title = '价格上穿平滑超趋势', message = '{"指标名称":"TMFS_V2","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","平滑超趋势":"{{plot("平滑超趋势")}}","事件":"价格上穿平滑超趋势","信号":"trend_bullish","备注":"趋势转向看涨"}') + +alertcondition(ta.crossunder(close, smoothed_trend), title = '价格下穿平滑超趋势', message = '{"指标名称":"TMFS_V2","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","平滑超趋势":"{{plot("平滑超趋势")}}","事件":"价格下穿平滑超趋势","信号":"trend_bearish","备注":"趋势转向看跌"}') + +// 综合强势信号警报 +alertcondition(upper_breakout and strong_dmi_bullish and volume_confirmed, title = '强势看涨信号', message = '{"指标名称":"TMFS_V2","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","成交量倍数":"{{plot("成交量倍数")}}","事件":"强势看涨信号","信号":"strong_bullish","备注":"趋势线突破+强势DMI+成交量确认"}') + +alertcondition(lower_breakout and strong_dmi_bearish and volume_confirmed, title = '强势看跌信号', message = '{"指标名称":"TMFS_V2","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","成交量倍数":"{{plot("成交量倍数")}}","事件":"强势看跌信号","信号":"strong_bearish","备注":"趋势线跌破+强势DMI+成交量确认"}') + +// 趋势确认警报 +alertcondition(trend_confirmed_bullish and strong_dmi_bullish, title = '多头趋势确认', message = '{"指标名称":"TMFS_V2","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","平滑超趋势":"{{plot("平滑超趋势")}}","DI+":"{{plot("DI+")}}","DI-":"{{plot("DI-")}}","事件":"多头趋势确认","信号":"bullish_trend_confirmed","备注":"3K线确认在超趋势上方且强势DMI看涨"}') + +alertcondition(trend_confirmed_bearish and strong_dmi_bearish, title = '空头趋势确认', message = '{"指标名称":"TMFS_V2","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","平滑超趋势":"{{plot("平滑超趋势")}}","DI+":"{{plot("DI+")}}","DI-":"{{plot("DI-")}}","事件":"空头趋势确认","信号":"bearish_trend_confirmed","备注":"3K线确认在超趋势下方且强势DMI看跌"}') + +// 成交量异常警报 +alertcondition(volume > volume_avg * volume_multiplier * 2, title = '成交量异常放大', message = '{"指标名称":"TMFS_V2","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","成交量倍数":"{{plot("成交量倍数")}}","事件":"成交量异常放大","信号":"volume_spike","备注":"成交量超过平均值2倍以上"}') + +// 基础DMI状态警报 +alertcondition(di_plus > dmi_threshold and di_plus > di_minus, title = 'DI+强势状态', message = '{"指标名称":"TMFS_V2","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","DI+":"{{plot("DI+")}}","DI-":"{{plot("DI-")}}","事件":"DI+强势状态","信号":"dmi_plus_strong","备注":"DI+高于阈值且大于DI-"}') + +alertcondition(di_minus > dmi_threshold and di_minus > di_plus, title = 'DI-强势状态', message = '{"指标名称":"TMFS_V2","交易对":"{{ticker}}","触发时间":"{{timenow}}","时间":"{{time}}","价格":"{{close}}","DI+":"{{plot("DI+")}}","DI-":"{{plot("DI-")}}","事件":"DI-强势状态","信号":"dmi_minus_strong","备注":"DI-高于阈值且大于DI+"}') +