diff --git a/srbr多时间周期.pine b/srbr多时间周期.pine new file mode 100644 index 0000000..66be564 --- /dev/null +++ b/srbr多时间周期.pine @@ -0,0 +1,638 @@ +// 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) + +// ◆ +// ---------------------------------------------------------------------------------------------------------------------} +// 𝘼𝙇𝙀𝙍𝙏 𝘾𝙊𝙉𝘿𝙄𝙏𝙄𝙊𝙉𝙎 +// ---------------------------------------------------------------------------------------------------------------------{ + +// 支撑位保持警报 +alertcondition(sup_holds, title = '支撑位保持', message = '{"指标名称":"SRBR","交易对":"{{ticker}}","周期":"{{interval}}","支撑位":"{{plot("supportLevel")}}","阻力位":"{{plot("resistanceLevel")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"支撑位保持","位置":"支撑位","信号":"support_holds"}') + +// 阻力位保持警报 +alertcondition(res_holds, title = '阻力位保持', message = '{"指标名称":"SRBR","交易对":"{{ticker}}","周期":"{{interval}}","支撑位":"{{plot("supportLevel")}}","阻力位":"{{plot("resistanceLevel")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"阻力位保持","位置":"阻力位","信号":"resistance_holds"}') + +// 支撑位突破警报 +alertcondition(brekout_sup, title = '支撑位突破', message = '{"指标名称":"SRBR","交易对":"{{ticker}}","周期":"{{interval}}","支撑位":"{{plot("supportLevel")}}","阻力位":"{{plot("resistanceLevel")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"支撑位突破","位置":"支撑位下方","信号":"support_breakout"}') + +// 阻力位突破警报 +alertcondition(brekout_res, title = '阻力位突破', message = '{"指标名称":"SRBR","交易对":"{{ticker}}","周期":"{{interval}}","支撑位":"{{plot("supportLevel")}}","阻力位":"{{plot("resistanceLevel")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"阻力位突破","位置":"阻力位上方","信号":"resistance_breakout"}') + +// 阻力转支撑警报 +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"}') + +// 支撑转阻力警报 +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"}') + +// ---------------------------------------------------------------------------------------------------------------------}