This commit is contained in:
2025-08-02 04:03:35 +00:00
parent 8a8a9e79d4
commit 0242c06d63
11 changed files with 5730 additions and 0 deletions

307
MaxTrendPoints.pine Normal file
View File

@@ -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)
// ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――{
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"}')
// ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――{
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)
// }

399
Swing Failure Pattern.pine Normal file
View File

@@ -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","备注":"突破对立高点确认看涨"}')
//---------------------------------------------------------------------------------------------------------------------}

844
mrc copy.pine Normal file
View File

@@ -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<d<0.5
alpha := gamma - math.sqrt(gamma * gamma - 1)
c0 := (1 + alpha) / 2
b1 := -2 * beta
b2 := 1
a1 := beta * (1 + alpha)
a2 := -alpha
a2
if _type == 'SMA'
c1 := 1 / _length
b0 := 1 / _length
a1 := 1
a1
if _type == 'EMA'
alpha := 2 / (_length + 1)
b0 := alpha
a1 := 1 - alpha
a1
if _type == 'RMA'
alpha := 1 / _length
b0 := alpha
a1 := 1 - alpha
a1
_Input = _src
_Output = 0.0
_Output := c0 * (b0 * _Input + b1 * nz(_Input[1]) + b2 * nz(_Input[2])) + a1 * nz(_Output[1]) + a2 * nz(_Output[2]) - c1 * nz(_Input[_length])
_Output
//-----------------------
// SuperSmoother Function
//-----------------------
supersmoother(_src, _length) =>
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"}')

715
mrc.pine Normal file
View File

@@ -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<d<0.5
alpha := gamma - math.sqrt(gamma * gamma - 1)
c0 := (1 + alpha) / 2
b1 := -2 * beta
b2 := 1
a1 := beta * (1 + alpha)
a2 := -alpha
a2
if _type == 'SMA'
c1 := 1 / _length
b0 := 1 / _length
a1 := 1
a1
if _type == 'EMA'
alpha := 2 / (_length + 1)
b0 := alpha
a1 := 1 - alpha
a1
if _type == 'RMA'
alpha := 1 / _length
b0 := alpha
a1 := 1 - alpha
a1
_Input = _src
_Output = 0.0
_Output := c0 * (b0 * _Input + b1 * nz(_Input[1]) + b2 * nz(_Input[2])) + a1 * nz(_Output[1]) + a2 * nz(_Output[2]) - c1 * nz(_Input[_length])
_Output
//-----------------------
// SuperSmoother Function
//-----------------------
supersmoother(_src, _length) =>
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"}')

441
rsi.pine Normal file
View File

@@ -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","备注":"空头信号"}')

637
rsi2.pine Normal file
View File

@@ -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)

293
rsi_conbinined.pine Normal file
View File

@@ -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)

714
srbr.pine Normal file
View File

@@ -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)
// ◆
// ---------------------------------------------------------------------------------------------------------------------}
// <20>𝙍𝙄𝘾𝙀 𝙎𝙏𝘼𝙏𝙐𝙎 & 𝙈𝘼𝙍𝙆𝙀𝙏 𝙊𝙐𝙏𝙇𝙊𝙊𝙆
// ---------------------------------------------------------------------------------------------------------------------{
// ═════════ 当前图表时间周期价格状态分析 ════════
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()
// ---------------------------------------------------------------------------------------------------------------------}
// <20>𝘼𝙇𝙀𝙍𝙏 𝘾𝙊𝙉𝘿𝙄𝙏𝙄𝙊𝙉𝙎
// ---------------------------------------------------------------------------------------------------------------------{
// 支撑位保持警报
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 + '"}')
// ---------------------------------------------------------------------------------------------------------------------}

316
srbr1.pine Normal file
View File

@@ -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 + '"}')
// ---------------------------------------------------------------------------------------------------------------------}

503
tmfs.pine Normal file
View File

@@ -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看跌"}')

561
tmfs2.pine Normal file
View File

@@ -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+"}')