Files
tradingview-pine/BjKeyLevels.pine

1190 lines
90 KiB
Plaintext
Raw Normal View History

2025-08-02 03:44:19 +00:00
// █▀▀▄ ──▀ █▀▀█ █▀▀█ █▀▀▀ █──█ █▀▄▀█
// █▀▀▄ ──█ █──█ █▄▄▀ █─▀█ █──█ █─▀─█
// ▀▀▀─ █▄█ ▀▀▀▀ ▀─▀▀ ▀▀▀▀ ─▀▀▀ ▀───▀
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Bjorgum
//@version=6
indicator('BjorgumKeyLevels', 'BjKeyLevels', overlay = true, max_boxes_count = 500, max_labels_count = 500, max_lines_count = 500)
import Bjorgum/BjCandlePatterns/3 as bj
// ================================== //
// ------------> 提示信息 <-------------- //
// ================================== //
leftTip = '向左查找摆动高低点的K线数量以形成枢轴点。数值越高脚本向左查找最高/最低点的范围越大'
rightTip = '向右查找摆动高低点的K线数量以形成枢轴点。数值越高脚本向右查找最高/最低点的范围越大'
nPivTip = '设置数组大小即同时跟踪的枢轴点数量x个高点和x个低点'
atrLenTip = '平均K线数量。ATR用于标准化不同资产和时间框架之间的区域宽度'
multTip = 'ATR乘数设置区域宽度。默认为从区域底部到顶部的半个ATR'
perTip = '区域大小占价格的最大百分比。某些资产在低价位时可能过于波动,会创建不合理大小的区域'
maxTip = '历史跟踪蜡烛图形态的最大框数。注意:数值越高,由于同时允许的框元素数量限制,回顾时跟踪的枢轴区域越少'
futTip = '价格水平标签的偏移K线数'
srcTip = '枢轴点的源输入。默认跟踪HA蜡烛的最高和最低实体以平均价格行为这可能导致水平位于支撑和阻力重叠区域'
alignZonesTip = '对齐边缘重叠现有区域的重复区域,创建随时间老化并在视觉上增强的区域'
extendTip = '向右延伸当前区域'
lLabTip = '显示从关键水平延伸的价格水平标签'
dhighsTip = '禁用将阻止跟踪高点'
dlowsTip = '禁用将阻止跟踪低点'
detectBOTip = '显示价格突破所有枢轴点的位置。显示来自下方的箭头'
detectBDTip = '显示价格跌破所有枢轴点的位置。显示来自上方的箭头'
breakUpTip = '显示价格突破阻力的位置。显示来自下方的箭头'
breakDnTip = '显示价格跌破支撑的位置。显示来自上方的箭头'
falseBullTip = '显示价格最初跌破支撑后反转的位置。假突破可能导致相反方向的快速移动(空头陷阱)。显示来自下方的大箭头'
falseBearTip = '显示价格最初突破阻力后反转的位置。假突破可能导致相反方向的快速移动(多头陷阱)。显示来自上方的大箭头'
supPushTip = '显示在支撑区域内检测到的上涨蜡烛。可以显示支撑被尊重的点。显示来自下方的三角形'
resPushTip = '显示在阻力区域内检测到的下跌蜡烛。可以显示阻力被尊重的点。显示来自上方的三角形'
curlTip = '当在关键区域范围内检测到蜡烛时显示Bjorgum TSI\'卷曲\'。可以显示关键水平的动量转换。与Bjorgum TSI指标相关'
// 添加标签大小配置的提示信息
labelSizeTip = '设置价格水平标签的字体大小'
repaintTip = '等待蜡烛结束后再检测形态。设为False将在确认前显示潜在形态'
labelsTip = '为检测到的蜡烛形态显示标签'
sBoxTip = '在检测到的蜡烛形态周围显示框'
dTip = '检测十字星蜡烛形态'
beTip = '检测吞没形态'
hsTip = '检测锤子线和流星线形态'
dgTip = '检测蜻蜓十字和墓碑十字形态'
twTip = '检测镊子顶和镊子底形态'
stTip = '检测纺锤顶形态'
pcTip = '检测刺透线和乌云盖顶形态'
bhTip = '检测孕线形态'
lsTip = '检测长上影线和长下影线形态'
ecWickTip = '确定吞没蜡烛是否必须吞没前一根蜡烛的影线或仅吞没实体'
colorMatchTip = '确定锤子线是否必须是阳线,流星线是否必须是阴线'
closeHalfTip = '确定镊子形态是否必须收盘超过前一根蜡烛的中点'
atrMaxTip = '设置蜡烛的最大尺寸作为当前ATR的倍数'
rejectWickTip = '形态解决蜡烛上拒绝影线允许的最大影线尺寸占实体尺寸的百分比。0禁用过滤器'
hammerFibTip = '锤子线和流星线的实体与蜡烛尺寸的关系即实体占总蜡烛尺寸的33%'
hsShadowPercTip = '允许的最大对立影线尺寸占实体尺寸的百分比(例如锤子形态的上影线等)'
hammerSizeTip = '锤子线、流星线或长影线的最小尺寸ATR的倍数用于过滤微小设置'
dojiSizeTip = '实体与蜡烛尺寸的关系即实体占总蜡烛尺寸的5%'
dojiWickSizeTip = '相对于对立影线的最大影线尺寸。例如2 = 下影线必须小于或等于上影线的2倍'
luRatioTip = '上影线与整体蜡烛尺寸的关系,以百分比表示'
lookbackTip = '可包含在假突破信号中的蜡烛数量'
swingTip = '摆动检测用于过滤突破类型信号。数值越高意味着更重要的点,但数量更少'
reflectTip = '过滤以确保设置是重要的摆动点。回顾这么远'
offsetTip = '蜡烛形态高/低点与绝对摆动高/低点的距离。例如0将过滤仅为最高/最低的形态1过滤重要长度内的第二高等'
bullPivotTip = '看涨关键水平的颜色\n边框背景'
bearPivotTip = '看跌关键水平的颜色\n边框背景'
breakoutTip = '突破箭头的颜色\n看涨看跌'
SnRTip = '支撑或阻力突破三角形的颜色\n看涨看跌'
falseBreakTip = '假突破箭头的颜色\n看涨看跌箭头最大高度像素'
moveTip = '在区域内检测到的蜡烛三角形的颜色\n看涨看跌'
patTip = '包围蜡烛图形态的框颜色\n背景看涨中性看跌\n边框看涨中性看跌'
labTip = '标记蜡烛图形态的标签颜色\n文本看涨中性看跌\n标签看涨中性看跌'
stratTip = 'TSI速度控制预设。两种速度都与Bjorgum TSI指标相关'
// ================================== //
// ---------> 用户输入 <----------- //
// ================================== //
left = input.int(20, '向左查找', group = '区域设置', tooltip = leftTip)
right = input.int(15, '向右查找', group = '区域设置', tooltip = rightTip)
nPiv = input.int(4, '枢轴点数量', group = '区域设置', tooltip = nPivTip)
atrLen = input.int(30, 'ATR长度', group = '区域设置', tooltip = atrLenTip)
mult = input.float(0.5, '区域宽度(ATR)', group = '区域设置', tooltip = multTip, step = 0.1)
per = input.float(5, '最大区域百分比', group = '区域设置', tooltip = perTip)
max = input.float(10, '形态最大框数', group = '区域设置', tooltip = maxTip)
fut = input.int(30, '标签偏移量', group = '区域设置', tooltip = futTip)
src = input.string('HA', '枢轴点源', group = '区域设置', tooltip = srcTip, options = ['HA', 'High/Low Body', 'High/Low'])
alignZones = input.bool(true, '对齐区域', group = '区域设置', tooltip = alignZonesTip)
extend = input.bool(false, '向右延伸', group = '区域设置', tooltip = extendTip)
lLab = input.bool(false, '显示水平标签', group = '区域设置', tooltip = lLabTip)
dhighs = input.bool(true, '检测枢轴高点', group = '检测设置', tooltip = dhighsTip)
dlows = input.bool(true, '检测枢轴低点', group = '检测设置', tooltip = dlowsTip)
detectBO = input.bool(false, '检测突破', group = '检测设置', tooltip = detectBOTip)
detectBD = input.bool(false, '检测跌破', group = '检测设置', tooltip = detectBDTip)
breakUp = input.bool(false, '检测阻力突破', group = '检测设置', tooltip = breakUpTip)
breakDn = input.bool(false, '检测支撑跌破', group = '检测设置', tooltip = breakDnTip)
falseBull = input.bool(false, '检测假跌破', group = '检测设置', tooltip = falseBullTip)
falseBear = input.bool(false, '检测假突破', group = '检测设置', tooltip = falseBearTip)
supPush = input.bool(false, '检测支撑反弹', group = '检测设置', tooltip = supPushTip)
resPush = input.bool(false, '检测阻力回落', group = '检测设置', tooltip = resPushTip)
curl = input.bool(false, '检测TSI卷曲', group = '检测设置', tooltip = curlTip)
repaint = input.bool(true, '等待确认K线', group = '蜡烛形态', tooltip = repaintTip)
labels = input.bool(false, '显示标签', group = '蜡烛形态', tooltip = labelsTip)
sBox = input.bool(false, '显示形态框', group = '蜡烛形态', tooltip = sBoxTip)
d_ = input.bool(false, '检测十字星', group = '蜡烛形态', tooltip = dTip)
be_ = input.bool(false, '检测吞没形态', group = '蜡烛形态', tooltip = beTip)
hs_ = input.bool(false, '检测锤子线和流星线', group = '蜡烛形态', tooltip = hsTip)
dg_ = input.bool(false, '检测蜻蜓和墓碑十字', group = '蜡烛形态', tooltip = dgTip)
tw_ = input.bool(false, '检测镊子形态', group = '蜡烛形态', tooltip = twTip)
st_ = input.bool(false, '检测纺锤顶', group = '蜡烛形态', tooltip = stTip)
pc_ = input.bool(false, '检测刺透线和乌云盖顶', group = '蜡烛形态', tooltip = pcTip)
bh_ = input.bool(false, '检测孕线', group = '蜡烛形态', tooltip = bhTip)
ls_ = input.bool(false, '检测长影线', group = '蜡烛形态', tooltip = lsTip)
alertMode = input.string(alert.freq_once_per_bar_close, '警报模式', group = '警报频率', options = [alert.freq_once_per_bar, alert.freq_once_per_bar_close])
ecWick = input.bool(false, '吞没必须包含影线', group = '蜡烛过滤器', tooltip = ecWickTip)
colorMatch = input.bool(false, '锤子线必须匹配颜色', group = '蜡烛过滤器', tooltip = colorMatchTip)
closeHalf = input.bool(false, '镊子收盘超过一半', group = '蜡烛过滤器', tooltip = closeHalfTip)
atrMax = input.float(0.0, '最大蜡烛尺寸(× ATR)', group = '蜡烛过滤器', tooltip = atrMaxTip, step = 0.1)
rejectWickMax = input.float(0.0, '[吞没]最大拒绝影线尺寸', group = '蜡烛过滤器', tooltip = rejectWickTip, step = 1)
hammerFib = input.float(33, '[锤子]锤子线比例(%)', group = '蜡烛过滤器', tooltip = hammerFibTip, step = 1)
hsShadowPerc = input.float(5, '[锤子]对立影线百分比(%)', group = '蜡烛过滤器', tooltip = hsShadowPercTip, step = 1)
hammerSize = input.float(0.1, '[锤子]最小尺寸(× ATR)', group = '蜡烛过滤器', tooltip = hammerSizeTip, step = 0.1)
dojiSize = input.float(5, '[十字]十字星尺寸(%)', group = '蜡烛过滤器', tooltip = dojiSizeTip, step = 1)
dojiWickSize = input.float(2, '[十字]最大影线尺寸', group = '蜡烛过滤器', tooltip = dojiWickSizeTip, step = 1)
luRatio = input.float(75, '[长影]长影线比例(%)', group = '蜡烛过滤器', tooltip = luRatioTip, step = 1)
lookback = input.int(2, '突破回顾期', group = '回顾设置', tooltip = lookbackTip)
swing = input.int(5, '摆动高低点', group = '回顾设置', tooltip = swingTip)
reflect = input.int(10, '重要高低点', group = '回顾设置', tooltip = reflectTip)
offset = input.int(1, '距离高低点K线数', group = '回顾设置', tooltip = offsetTip)
// 添加标签大小配置
labelSize = input.string('small', '标签字体大小', group = '显示设置', tooltip = labelSizeTip, options = ['tiny', 'small', 'normal', 'large', 'huge'])
bullBorder = input.color(color.new(#64b5f6, 60), '', inline = '0', group = '枢轴颜色')
bullBgCol = input.color(color.new(#64b5f6, 95), '', inline = '0', group = '枢轴颜色', tooltip = bullPivotTip)
bearBorder = input.color(color.new(#ffeb3b, 60), '', inline = '1', group = '枢轴颜色')
bearBgCol = input.color(color.new(#ffeb3b, 95), '', inline = '1', group = '枢轴颜色', tooltip = bearPivotTip)
upCol = input.color(color.new(#ff6d00, 25), '', inline = '2', group = '突破颜色')
dnCol = input.color(color.new(#ff00ff, 25), '', inline = '2', group = '突破颜色', tooltip = breakoutTip)
supCol = input.color(color.new(#17ff00, 25), '', inline = '3', group = '支撑阻力突破颜色')
resCol = input.color(color.new(#ff0000, 25), '', inline = '3', group = '支撑阻力突破颜色', tooltip = SnRTip)
fBull = input.color(color.new(#17ff00, 25), '', inline = '4', group = '假突破颜色')
fBear = input.color(color.new(#ff0000, 25), '', inline = '4', group = '假突破颜色')
arrowMax = input.int(75, '', inline = '4', group = '假突破颜色', tooltip = falseBreakTip)
moveBullCol = input.color(color.new(#64b5f6, 25), '', inline = '5', group = '支撑阻力反弹颜色')
moveBearCol = input.color(color.new(#ffeb3b, 25), '', inline = '5', group = '支撑阻力反弹颜色', tooltip = moveTip)
curlBullCol = input.color(color.new(#17ff00, 40), '', inline = '6', group = '动量卷曲颜色')
curlBearCol = input.color(color.new(#f3ff00, 40), '', inline = '6', group = '动量卷曲颜色', tooltip = curlTip)
patBullBg = input.color(color.new(#17ff00, 90), '', inline = '7', group = '形态框颜色')
patNeutBg = input.color(color.new(#b2b5be, 90), '', inline = '7', group = '形态框颜色')
patBearBg = input.color(color.new(#ff0000, 90), '', inline = '7', group = '形态框颜色')
patBullBo = input.color(color.new(#17ff00, 80), '', inline = '8', group = '形态框颜色')
patNeutBo = input.color(color.new(#b2b5be, 80), '', inline = '8', group = '形态框颜色')
patBearBo = input.color(color.new(#ff0000, 80), '', inline = '8', group = '形态框颜色', tooltip = patTip)
textBullCol = input.color(color.new(#17ff00, 0), '', inline = '9', group = '标签颜色(文本/背景)')
textNeutCol = input.color(color.new(#b2b5be, 0), '', inline = '9', group = '标签颜色(文本/背景)')
textBearCol = input.color(color.new(#ff0000, 0), '', inline = '9', group = '标签颜色(文本/背景)')
labBullCol = input.color(color.new(#17ff00, 80), '', inline = '10', group = '标签颜色(文本/背景)')
labNeutCol = input.color(color.new(#b2b5be, 80), '', inline = '10', group = '标签颜色(文本/背景)')
labBearCol = input.color(color.new(#ff0000, 80), '', inline = '10', group = '标签颜色(文本/背景)', tooltip = labTip)
strat = input.string('Fast', '选择速度', group = 'TSI速度控制', tooltip = stratTip, options = ['Fast', 'Slow'])
longf = input.int(25, '长周期长度', group = 'TSI快速设置')
shortf = input.int(5, '短周期长度', group = 'TSI快速设置')
signalf = input.int(14, '信号长度', group = 'TSI快速设置')
longs = input.int(25, '长周期长度', group = 'TSI慢速设置')
shorts = input.int(13, '短周期长度', group = 'TSI慢速设置')
signals = input.int(13, '信号长度', group = 'TSI慢速设置')
// ================================== //
// -----> 不可变常量 <------ //
// ================================== //
sync = bar_index
labUp = label.style_label_up
labDn = label.style_label_down
confirmed = barstate.isconfirmed
extrap = extend ? extend.right : extend.none
// 标签大小常量定义
labelSizeValue = labelSize == 'tiny' ? size.tiny : labelSize == 'small' ? size.small : labelSize == 'normal' ? size.normal : labelSize == 'large' ? size.large : size.huge
var pivotHigh = array.new_box(nPiv)
var pivotLows = array.new_box(nPiv)
var highBull = array.new_bool(nPiv)
var lowsBull = array.new_bool(nPiv)
var boxes = array.new_box()
haSrc = src == 'HA'
hiLoSrc = src == 'High/Low'
tsifast = strat == 'Fast'
tsislow = strat == 'Slow'
// ================================== //
// ---> Functional Declarations <---- //
// ================================== //
atr = ta.atr(atrLen)
perMax = close * 0.02
min = math.min(perMax, atr * 0.3)
_haBody() =>
haClose = (open + high + low + close) / 4
haOpen = float(na)
haOpen := na(haOpen[1]) ? (open + close) / 2 : (nz(haOpen[1]) + nz(haClose[1])) / 2
[haOpen, haClose]
_extend(_x) =>
for i = 0 to array.size(_x) - 1 by 1
box.set_right(array.get(_x, i), sync)
_arrayLoad(_x, _max, _val) =>
array.unshift(_x, _val)
if array.size(_x) > _max
array.pop(_x)
_arrayBox(_x, _max, _val) =>
array.unshift(_x, _val)
if array.size(_x) > _max
_b = array.pop(_x)
if extend
box.set_extend(_b, extend.none)
_arrayWrap(_x, _max, _val) =>
array.unshift(_x, _val)
if array.size(_x) > _max
box.delete(array.pop(_x))
_delLab(_x) =>
if array.size(_x) > 0
label.delete(array.pop(_x))
_delLine(_x) =>
if array.size(_x) > 0
line.delete(array.pop(_x))
_delLevels(_x, _y) =>
for i = 0 to array.size(_x) - 1 by 1
_delLab(_x)
_delLine(_y)
_box(_x1, _t, _r, _b, _boCol, _bgCol, _e) =>
box.new(_x1, _t, _r, _b, xloc = xloc.bar_index, extend = _e, border_color = _boCol, bgcolor = _bgCol)
_wrap(_cond, _x, _bb, _bc, _bgc) =>
_t = ta.highest(high, _bb) + min
_b = ta.lowest(low, _bb) - min
_l = bar_index - _bb
_r = bar_index + 1
if _cond
_arrayWrap(_x, max, _box(_l, _t, _r, _b, _bc, _bgc, extend.none))
_getBox(_x, _i) =>
_box = array.get(_x, _i)
_t = box.get_top(_box)
_b = box.get_bottom(_box)
[_t, _b]
_align(_x, _y) =>
for i = 0 to array.size(_x) - 1 by 1
[_T, _B] = _getBox(_y, 0)
[_t, _b] = _getBox(_x, i)
if _T > _b and _T < _t or _B < _t and _B > _b or _T > _t and _B < _b or _B > _b and _T < _t
box.set_top(array.get(_y, 0), _t)
box.set_bottom(array.get(_y, 0), _b)
_color(_x, _y) =>
var int _track = nPiv
for i = 0 to array.size(_x) - 1 by 1
[t_, b_] = _getBox(_x, i)
_isBull = array.get(_y, i)
if close > t_ and not _isBull
box.set_extend(array.get(_x, i), extend.none)
array.set(_x, i, _box(sync, t_, sync, b_, bullBorder, bullBgCol, extrap))
array.set(_y, i, true)
_track := _track + 1
_track
if close < b_ and _isBull
box.set_extend(array.get(_x, i), extend.none)
array.set(_x, i, _box(sync, t_, sync, b_, bearBorder, bearBgCol, extrap))
array.set(_y, i, false)
_track := _track - 1
_track
_track
_detect(_x, _y) =>
int _i = 0
bool _found = false
bool _isBull = false
while not _found and _i < array.size(_x)
[t_, b_] = _getBox(_x, _i)
if low < t_ and high > b_
_isBull := array.get(_y, _i)
_found := true
_found
_i := _i + 1
_i
[_found, _isBull]
_falseBreak(_l) =>
bool _d = false
bool _u = false
for i = 1 to lookback by 1
if _l[i] < _l and _l[i + 1] >= _l and _l[1] < _l
_d := true
_d
if _l[i] > _l and _l[i + 1] <= _l and _l[1] > _l
_u := true
_u
[_d, _u]
_numLevel(_x, _y) =>
int _above = 0
int _fill = 0
for i = 0 to array.size(_x) - 1 by 1
if i < array.size(_x)
_isBull = array.get(_x, i)
if _isBull == true
_above := _above + 1
_above
if _isBull == true or _isBull == false // Only count if it's a valid boolean (not na)
_fill := _fill + 1
_fill
for i = 0 to array.size(_y) - 1 by 1
if i < array.size(_y)
_isBull = array.get(_y, i)
if _isBull == true
_above := _above + 1
_above
if _isBull == true or _isBull == false // Only count if it's a valid boolean (not na)
_fill := _fill + 1
_fill
[_above, _fill]
_check(_src, _l) =>
bool _check = false
for i = 0 to _l by 1
if _src[i]
_check := true
_check
_check
_count(_src, _l) =>
int _result = 0
for i = 0 to _l by 1
if _src > _src[i]
_result := _result + 1
_result
_result
// 修改 _label 函数
// 添加 x_offset_adjust 参数默认为0
_label(_x, _y, y_price, _s, _col1, _col2, x_offset_adjust = 0) =>
transp = math.min(color.t(_col1), color.t(_col2))
// 将 x_offset_adjust 添加到标签和线的 x 坐标计算中
label_x_position = sync + fut + x_offset_adjust
line_x2_position = sync + fut + x_offset_adjust
array.unshift(_x, label.new(label_x_position, y_price, text = str.tostring(math.round_to_mintick(y_price)), color = color.new(_col1, transp), style = _s, textcolor = color.white, size = labelSizeValue))
if not extend and fut > 0 // 只有当 fut > 0 且不向右无限延长时才绘制连接线
// 线的起点是 sync (当前K线),终点是标签的 x 位置
array.unshift(_y, line.new(sync, y_price, line_x2_position, y_price, color = color.new(_col1, transp)))
// 修改 _level 函数
// 添加 isHighPivotZone 参数 (true 表示是 pivotHigh 区域, false 表示是 pivotLows 区域)
_level(_x, _y, isHighPivotZone) =>
var array<label> lab = array.new_label()
var array<line> lines = array.new_line()
if barstate.islast and lLab
while array.size(lab) > 0
label.delete(array.pop(lab))
while array.size(lines) > 0
line.delete(array.pop(lines))
for i = 0 to array.size(_x) - 1 by 1
current_box_id = array.get(_x, i)
if not na(current_box_id)
[_t, _b] = _getBox(_x, i)
_isBull_val = array.get(_y, i)
bool currentIsBull = _isBull_val != true and _isBull_val != false ? isHighPivotZone ? false : true : _isBull_val // pivotHigh 默认为熊区(false), pivotLows默认为牛区(true)
_col1 = currentIsBull ? bullBgCol : bearBgCol
_col2 = currentIsBull ? bullBorder : bearBorder
// 定义错开的偏移量
// 可以根据需要调整这些值,甚至可以将它们作为输入参数
int top_label_offset_adj = 0
int bottom_label_offset_adj = 0
if isHighPivotZone // 如果是阻力区 (来自 pivotHigh)
// 阻力区的顶线标签稍微向左偏一点 (或不偏),底线标签向右偏一点
top_label_offset_adj := 0 // 例如,顶部标签不额外偏移或轻微向左
bottom_label_offset_adj := 2 // 例如底部标签向右偏移2个单位K线
bottom_label_offset_adj
// 如果是支撑区 (来自 pivotLows)
else // 支撑区的顶线标签稍微向右偏一点,底线标签向左偏一点 (或不偏)
top_label_offset_adj := 2 // 例如顶部标签向右偏移2个单位
bottom_label_offset_adj := 0 // 例如,底部标签不额外偏移或轻微向左
bottom_label_offset_adj
// 另一种错开方式:都向右偏,但偏移量不同
// if isHighPivotZone
// top_label_offset_adj = 0
// bottom_label_offset_adj = 1 // 阻力区底部标签偏移量小
// else
// top_label_offset_adj = 2 // 支撑区顶部标签偏移量大
// bottom_label_offset_adj = 3
// 绘制顶线标签
_label(lab, lines, _t, labDn, _col1, _col2, top_label_offset_adj)
// 绘制底线标签
_label(lab, lines, _b, labUp, _col1, _col2, bottom_label_offset_adj)
_alert(_x, _y) =>
if _x
alert(_y + timeframe.period + ' chart. Price is ' + str.tostring(close), alertMode)
// ================================== //
// ----> Variable Calculations <----- //
// ================================== //
shortvar = tsifast ? shortf : shorts
longvar = tsifast ? longf : longs
signalvar = tsifast ? signalf : signals
tsi = ta.tsi(close, shortvar, longvar)
tsl = ta.ema(tsi, signalvar)
highest = close == ta.highest(close, right)
lowest = close == ta.lowest(close, right)
closeLows = ta.lowest(close, swing)
closeHigh = ta.highest(close, swing)
numLows = _count(low, reflect)
numHigh = _count(high, reflect)
[open_, close_] = _haBody()
hiHaBod = math.max(close_, open_)
loHaBod = math.min(close_, open_)
hiBod = math.max(close, open)
loBod = math.min(close, open)
srcHigh = haSrc ? hiHaBod : hiLoSrc ? high : hiBod
srcLow = haSrc ? loHaBod : hiLoSrc ? low : loBod
pivot_high = ta.pivothigh(srcHigh, left, right)
pivot_low = ta.pivotlow(srcLow, left, right)
perc = close * (per / 100)
band = math.min(atr * mult, perc)[right] / 2
HH = pivot_high + band
HL = pivot_high - band
LH = pivot_low + band
LL = pivot_low - band
coDiff = close - open
// ================================== //
// --------> Logical Order <--------- //
// ================================== //
if not na(pivot_high) and dhighs and confirmed
_arrayLoad(highBull, nPiv, false)
_arrayBox(pivotHigh, nPiv, _box(sync[right], HH, sync, HL, bearBorder, bearBgCol, extrap))
if not na(pivot_low) and dlows and confirmed
_arrayLoad(lowsBull, nPiv, true)
_arrayBox(pivotLows, nPiv, _box(sync[right], LH, sync, LL, bullBorder, bullBgCol, extrap))
if alignZones
_align(pivotHigh, pivotHigh)
_align(pivotHigh, pivotLows)
_align(pivotLows, pivotLows)
_align(pivotLows, pivotHigh)
_extend(pivotHigh)
_extend(pivotLows)
trackHigh = _color(pivotHigh, highBull)
trackLows = _color(pivotLows, lowsBull)
// ================================== //
// ----> Conditional Parameters <---- //
// ================================== //
isLows = closeLows == close
isHigh = closeHigh == close
wasLows = _check(isLows, lookback)
wasHigh = _check(isHigh, lookback)
[above, total] = _numLevel(highBull, lowsBull)
moveAbove = trackHigh > trackHigh[1]
moveBelow = trackLows < trackLows[1]
resBreak = trackLows > trackLows[1] or moveAbove
supBreak = trackHigh < trackHigh[1] or moveBelow
breakOut = moveAbove and highest and above == total
breakDwn = moveBelow and lowest and above == 0
[dh, uh] = _falseBreak(trackHigh)
[dl, ul] = _falseBreak(trackLows)
falseBreakBull = wasLows and (dh or dl)
falseBreakBear = wasHigh and (uh or ul)
[fh, hb] = _detect(pivotHigh, highBull)
[fl, lb] = _detect(pivotLows, lowsBull)
bull = (fh or fl) and (hb or lb)
bear = (fh or fl) and not(hb or lb)
bullCheck = not resBreak and not resBreak[1] and (fh or fl) and close > open and (hb or lb)
bearCheck = not supBreak and not supBreak[1] and (fh or fl) and close < open and not(hb or lb)
highrange = reflect - offset
lowsrange = offset
sigLows = numLows <= lowsrange
sigHigh = numHigh >= highrange
isBull1 = sigLows and bull
isBear1 = sigHigh and bear
isBull2 = (sigLows or sigLows[1]) and (bull or bull[1])
isBear2 = (sigHigh or sigHigh[1]) and (bear or bear[1])
data = tsi > tsi[1] and tsi < tsl
dtat = tsi < tsi[1] and tsi > tsl
hMatch = not colorMatch or close > open
sMatch = not colorMatch or close < open
hsFilter = bj.barRange() >= hammerSize * atr
atrMaxSize = bj.barRange() <= atrMax * atr or atrMax == 0.0
rp = confirmed or not repaint
// ================================== //
// -----> Pattern Recognition <------ //
// ================================== //
dw = isBull1 and rp and d_ and atrMaxSize and bj.doji(dojiSize = dojiSize, dojiWickSize = dojiWickSize)
db = isBear1 and rp and d_ and atrMaxSize and bj.doji(dojiSize = dojiSize, dojiWickSize = dojiWickSize)
bew = isBull2 and rp and be_ and atrMaxSize and bj.bullEngulf(maxRejectWick = rejectWickMax, mustEngulfWick = ecWick)
beb = isBear2 and rp and be_ and atrMaxSize and bj.bearEngulf(maxRejectWick = rejectWickMax, mustEngulfWick = ecWick)
h = isBull1 and rp and hs_ and atrMaxSize and bj.hammer(ratio = hammerFib, shadowPercent = hsShadowPerc) and hsFilter and hMatch
ss = isBear1 and rp and hs_ and atrMaxSize and bj.star(ratio = hammerFib, shadowPercent = hsShadowPerc) and hsFilter and sMatch
dd = isBull1 and rp and dg_ and atrMaxSize and bj.dragonflyDoji()
gd = isBear1 and rp and dg_ and atrMaxSize and bj.gravestoneDoji()
tb = isBull2 and rp and tw_ and atrMaxSize and bj.tweezerBottom(closeUpperHalf = closeHalf)
tt = isBear2 and rp and tw_ and atrMaxSize and bj.tweezerTop(closeLowerHalf = closeHalf)
stw = isBull1 and rp and st_ and atrMaxSize and bj.spinningTop()
stb = isBear1 and rp and st_ and atrMaxSize and bj.spinningTop()
p = isBull1 and rp and pc_ and atrMaxSize and bj.piercing()
dcc = isBear1 and rp and pc_ and atrMaxSize and bj.darkCloudCover()
bhw = isBull1 and rp and bh_ and atrMaxSize and bj.haramiBull()
bhb = isBear1 and rp and bh_ and atrMaxSize and bj.haramiBear()
ll = isBull1 and rp and ls_ and atrMaxSize and bj.lls(ratio = luRatio) and hsFilter
lu = isBear1 and rp and ls_ and atrMaxSize and bj.lus(ratio = luRatio) and hsFilter
// ================================== //
// ------> Graphical Display <------- //
// ================================== //
// 添加显示警报名称的输入选项
showAlertNames = input.bool(true, '显示警报名称', group = '警报标签设置')
alertTextSize = input.string('tiny', '警报名称字体大小', group = '警报标签设置', options = ['tiny', 'small', 'normal'])
plotFalseDn = falseBull and falseBreakBull
plotFalseUp = falseBear and falseBreakBear
falseUpCol = plotFalseUp ? upCol : na
falseDnCol = plotFalseDn ? dnCol : na
plotBreakOut = breakOut and detectBO and not plotFalseDn
plotBreakDn = breakDwn and detectBD and not plotFalseUp
plotResBreak = resBreak and breakUp and not(plotBreakOut or plotFalseDn)
plotSupBreak = supBreak and breakDn and not(plotBreakDn or plotFalseUp)
plotBullCheck = bullCheck and supPush
plotBearCheck = bearCheck and resPush
plotCurlBull = curl and data and bull
plotCurlBear = curl and dtat and bear
// 获取字体大小
textSizeValue = alertTextSize == 'tiny' ? size.tiny : alertTextSize == 'small' ? size.small : size.normal
plotarrow(plotFalseUp ? coDiff : na, colorup = fBull, colordown = fBear, maxheight = arrowMax)
plotarrow(plotFalseDn ? coDiff : na, colorup = fBull, colordown = fBear, maxheight = arrowMax)
plotshape(plotBreakOut, style = shape.arrowup, location = location.belowbar, color = upCol, size = size.small)
plotshape(plotBreakDn, style = shape.arrowdown, location = location.abovebar, color = dnCol, size = size.small)
plotshape(plotResBreak, style = shape.arrowup, location = location.belowbar, color = supCol, size = size.small)
plotshape(plotSupBreak, style = shape.arrowdown, location = location.abovebar, color = resCol, size = size.small)
plotshape(plotBullCheck, style = shape.triangleup, location = location.belowbar, color = moveBullCol)
plotshape(plotBearCheck, style = shape.triangledown, location = location.abovebar, color = moveBearCol)
plotshape(plotCurlBull, style = shape.triangleup, location = location.belowbar, color = curlBullCol)
plotshape(plotCurlBear, style = shape.triangledown, location = location.abovebar, color = curlBearCol)
// 添加警报名称标签
if showAlertNames
// 假突破警报标签
if plotFalseUp
label.new(bar_index, high + atr * 0.3, '假突破↑', style = label.style_none, textcolor = fBull, size = labelSizeValue)
if plotFalseDn
label.new(bar_index, low - atr * 0.3, '假突破↓', style = label.style_none, textcolor = fBear, size = labelSizeValue)
// 突破警报标签
if plotBreakOut
label.new(bar_index, low - atr * 0.2, '突破', style = label.style_none, textcolor = upCol, size = labelSizeValue)
if plotBreakDn
label.new(bar_index, high + atr * 0.2, '跌破', style = label.style_none, textcolor = dnCol, size = labelSizeValue)
// 阻力/支撑突破标签
if plotResBreak
label.new(bar_index, low - atr * 0.2, '阻力突破', style = label.style_none, textcolor = supCol, size = labelSizeValue)
if plotSupBreak
label.new(bar_index, high + atr * 0.2, '支撑跌破', style = label.style_none, textcolor = resCol, size = labelSizeValue)
// 支撑阻力反弹标签
if plotBullCheck
label.new(bar_index, low - atr * 0.15, '支撑反弹', style = label.style_none, textcolor = moveBullCol, size = labelSizeValue)
if plotBearCheck
label.new(bar_index, high + atr * 0.15, '阻力回落', style = label.style_none, textcolor = moveBearCol, size = labelSizeValue)
// TSI动量转向标签
if plotCurlBull
label.new(bar_index, low - atr * 0.1, '动量转多', style = label.style_none, textcolor = curlBullCol, size = labelSizeValue)
if plotCurlBear
label.new(bar_index, high + atr * 0.1, '动量转空', style = label.style_none, textcolor = curlBearCol, size = labelSizeValue)
bj.dLab(dw and labels, labNeutCol, textNeutCol)
_wrap(dw and sBox, boxes, 1, patNeutBo, patNeutBg)
bj.bewLab(bew and labels, labBullCol, textBullCol)
_wrap(bew and sBox, boxes, 2, patBullBo, patBullBg)
bj.hLab(h and labels, labBullCol, textBullCol)
_wrap(h and sBox, boxes, 1, patBullBo, patBullBg)
bj.ddLab(dd and labels, labBullCol, textBullCol)
_wrap(dd and sBox, boxes, 1, patBullBo, patBullBg)
bj.tbLab(tb and labels, labBullCol, textBullCol)
_wrap(tb and sBox, boxes, 2, patBullBo, patBullBg)
bj.stwLab(stw and labels, labNeutCol, textNeutCol)
_wrap(stw and sBox, boxes, 1, patBullBo, patNeutBg)
bj.pLab(p and labels, labBullCol, textBullCol)
_wrap(p and sBox, boxes, 2, patBullBo, patBullBg)
bj.hwLab(bhw and labels, labBullCol, textBullCol)
_wrap(bhw and sBox, boxes, 2, patBullBo, patBullBg)
bj.llsLab(ll and labels, labBullCol, textBullCol)
_wrap(ll and sBox, boxes, 1, patBullBo, patBullBg)
bj.dLab(db and labels, labNeutCol, textNeutCol)
_wrap(db and sBox, boxes, 1, patNeutBo, patNeutBg)
bj.bebLab(beb and labels, labBearCol, textBearCol)
_wrap(beb and sBox, boxes, 2, patBearBo, patBearBg)
bj.ssLab(ss and labels, labBearCol, textBearCol)
_wrap(ss and sBox, boxes, 1, patBearBo, patBearBg)
bj.gdLab(gd and labels, labBearCol, textBearCol)
_wrap(gd and sBox, boxes, 1, patBearBo, patBearBg)
bj.ttLab(tt and labels, labBearCol, textBearCol)
_wrap(tt and sBox, boxes, 2, patBearBo, patBearBg)
bj.stbLab(stb and labels, labNeutCol, textNeutCol)
_wrap(stb and sBox, boxes, 1, patBearBo, patBearBg)
bj.dccLab(dcc and labels, labBearCol, textBearCol)
_wrap(dcc and sBox, boxes, 2, patBearBo, patBearBg)
bj.hbLab(bhb and labels, labBearCol, textBearCol)
_wrap(bhb and sBox, boxes, 2, patBearBo, patBearBg)
bj.lusLab(lu and labels, labBearCol, textBearCol)
_wrap(lu and sBox, boxes, 1, patBearBo, patBearBg)
// 添加蜡烛图形态名称标签
if showAlertNames
// 看涨形态标签
if dw
label.new(bar_index, low - atr * 0.05, '十字星', style = label.style_none, textcolor = textNeutCol, size = labelSizeValue)
if bew
label.new(bar_index, low - atr * 0.05, '看涨吞没', style = label.style_none, textcolor = textBullCol, size = labelSizeValue)
if h
label.new(bar_index, low - atr * 0.05, '锤子线', style = label.style_none, textcolor = textBullCol, size = labelSizeValue)
if dd
label.new(bar_index, low - atr * 0.05, '蜻蜓十字', style = label.style_none, textcolor = textBullCol, size = labelSizeValue)
if tb
label.new(bar_index, low - atr * 0.05, '镊子底', style = label.style_none, textcolor = textBullCol, size = labelSizeValue)
if stw
label.new(bar_index, low - atr * 0.05, '纺锤顶', style = label.style_none, textcolor = textNeutCol, size = labelSizeValue)
if p
label.new(bar_index, low - atr * 0.05, '刺透线', style = label.style_none, textcolor = textBullCol, size = labelSizeValue)
if bhw
label.new(bar_index, low - atr * 0.05, '看涨孕线', style = label.style_none, textcolor = textBullCol, size = labelSizeValue)
if ll
label.new(bar_index, low - atr * 0.05, '长下影', style = label.style_none, textcolor = textBullCol, size = labelSizeValue)
// 看跌形态标签
if db
label.new(bar_index, high + atr * 0.05, '十字星', style = label.style_none, textcolor = textNeutCol, size = labelSizeValue)
if beb
label.new(bar_index, high + atr * 0.05, '看跌吞没', style = label.style_none, textcolor = textBearCol, size = labelSizeValue)
if ss
label.new(bar_index, high + atr * 0.05, '流星线', style = label.style_none, textcolor = textBearCol, size = labelSizeValue)
if gd
label.new(bar_index, high + atr * 0.05, '墓碑十字', style = label.style_none, textcolor = textBearCol, size = labelSizeValue)
if tt
label.new(bar_index, high + atr * 0.05, '镊子顶', style = label.style_none, textcolor = textBearCol, size = labelSizeValue)
if stb
label.new(bar_index, high + atr * 0.05, '纺锤顶', style = label.style_none, textcolor = textNeutCol, size = labelSizeValue)
if dcc
label.new(bar_index, high + atr * 0.05, '乌云盖顶', style = label.style_none, textcolor = textBearCol, size = labelSizeValue)
if bhb
label.new(bar_index, high + atr * 0.05, '看跌孕线', style = label.style_none, textcolor = textBearCol, size = labelSizeValue)
if lu
label.new(bar_index, high + atr * 0.05, '长上影', style = label.style_none, textcolor = textBearCol, size = labelSizeValue)
// ... 其他代码 ...
_level(pivotHigh, highBull, true) // true 表示这是 highPivotZone
_level(pivotLows, lowsBull, false) // false 表示这是 lowPivotZone (即支撑区)
// 添加价格变化的plot用于警报消息中的占位符
plot(close - open, title = '价格变化', display = display.none)
// ... 其他代码 ...
// ================================== //
// -----> Alert Functionality <------ //
// ================================== //
// 获取最近的支撑位和阻力位价格(移动到这里以便在警报中使用)
_getNearestLevels() =>
var float nearestSupport = na
var float nearestResistance = na
var float supportDistance = na
var float resistanceDistance = na
// 初始化最近距离为无穷大
float minSupportDist = 999999.0
float minResistanceDist = 999999.0
// 检查所有支撑区域pivotLows
if array.size(pivotLows) > 0
for i = 0 to array.size(pivotLows) - 1 by 1
current_box = array.get(pivotLows, i)
if not na(current_box)
[top_price, bottom_price] = _getBox(pivotLows, i)
// 计算当前价格到支撑区域的距离
float distToSupport = na
if close > top_price
distToSupport := close - top_price
distToSupport
else if close < bottom_price
distToSupport := bottom_price - close
distToSupport
else
distToSupport := 0.0 // 价格在支撑区域内
distToSupport
// 更新最近的支撑位
if distToSupport < minSupportDist
minSupportDist := distToSupport
nearestSupport := (top_price + bottom_price) / 2
supportDistance := distToSupport
supportDistance
// 检查所有阻力区域pivotHigh
if array.size(pivotHigh) > 0
for i = 0 to array.size(pivotHigh) - 1 by 1
current_box = array.get(pivotHigh, i)
if not na(current_box)
[top_price, bottom_price] = _getBox(pivotHigh, i)
// 计算当前价格到阻力区域的距离
float distToResistance = na
if close > top_price
distToResistance := close - top_price
distToResistance
else if close < bottom_price
distToResistance := bottom_price - close
distToResistance
else
distToResistance := 0.0 // 价格在阻力区域内
distToResistance
// 更新最近的阻力位
if distToResistance < minResistanceDist
minResistanceDist := distToResistance
nearestResistance := (top_price + bottom_price) / 2
resistanceDistance := distToResistance
resistanceDistance
[nearestSupport, nearestResistance, supportDistance, resistanceDistance]
// 为了在警报中包含支撑阻力位信息我们需要创建plot变量
// 因为alertcondition只接受const string不能使用动态函数
// 创建用于警报的plot变量
[nearestSupportPrice, nearestResistancePrice, supportDistance, resistanceDistance] = _getNearestLevels()
// 计算百分比
supportPercent = not na(supportDistance) and not na(nearestSupportPrice) ? supportDistance / close * 100 : na
resistancePercent = not na(resistanceDistance) and not na(nearestResistancePrice) ? resistanceDistance / close * 100 : na
// 创建plot用于在警报中引用
plot(nearestSupportPrice, title = '最近支撑价格', display = display.none)
plot(nearestResistancePrice, title = '最近阻力价格', display = display.none)
plot(supportDistance, title = '支撑距离', display = display.none)
plot(resistanceDistance, title = '阻力距离', display = display.none)
plot(supportPercent, title = '支撑距离百分比', display = display.none)
plot(resistancePercent, title = '阻力距离百分比', display = display.none)
// ===== 统一警报系统 =====
// 统一警报系统 - 只需添加一次警报即可捕获所有信号
// 警报频率限制 - 每分钟只触发一次
var int last_alert_resistance_break = 0
var int last_alert_support_break = 0
var int last_alert_support_found = 0
var int last_alert_resistance_found = 0
var int last_alert_resistance_rejection = 0
var int last_alert_support_bounce = 0
var int last_alert_false_breakdown = 0
var int last_alert_false_breakout = 0
var int last_alert_strong_breakout_up = 0
var int last_alert_strong_breakdown = 0
var int last_alert_bullish_engulfing = 0
var int last_alert_bearish_engulfing = 0
var int last_alert_hammer = 0
var int last_alert_shooting_star = 0
var int last_alert_tsi_bullish = 0
var int last_alert_tsi_bearish = 0
// 获取当前时间(分钟级别)
current_minute = math.floor(timenow / 60000)
// 检测所有警报条件并生成对应的JSON消息
alert_message = ""
// 支撑阻力突破警报 - 每分钟限制
if resBreak and current_minute > last_alert_resistance_break
alert_message := '{"指标名称":"BjorgumKeyLevels","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"阻力突破","位置":"阻力位上方","成交量":"' + str.tostring(volume, '#') + '","价格变化":"' + str.tostring(close - open, '#.####') + '","最近支撑价格":"' + str.tostring(nearestSupportPrice, '#.####') + '","支撑距离":"' + str.tostring(supportDistance, '#.####') + '","支撑距离百分比":"' + str.tostring(supportPercent, '#.##') + '","最近阻力价格":"' + str.tostring(nearestResistancePrice, '#.####') + '","阻力距离":"' + str.tostring(resistanceDistance, '#.####') + '","阻力距离百分比":"' + str.tostring(resistancePercent, '#.##') + '","信号":"resistance_break"}'
alert(alert_message, alert.freq_once_per_bar_close)
last_alert_resistance_break := current_minute
if supBreak and current_minute > last_alert_support_break
alert_message := '{"指标名称":"BjorgumKeyLevels","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"支撑跌破","位置":"支撑位下方","成交量":"' + str.tostring(volume, '#') + '","价格变化":"' + str.tostring(close - open, '#.####') + '","最近支撑价格":"' + str.tostring(nearestSupportPrice, '#.####') + '","支撑距离":"' + str.tostring(supportDistance, '#.####') + '","支撑距离百分比":"' + str.tostring(supportPercent, '#.##') + '","最近阻力价格":"' + str.tostring(nearestResistancePrice, '#.####') + '","阻力距离":"' + str.tostring(resistanceDistance, '#.####') + '","阻力距离百分比":"' + str.tostring(resistancePercent, '#.##') + '","信号":"support_break"}'
alert(alert_message, alert.freq_once_per_bar_close)
last_alert_support_break := current_minute
// 关键位置发现警报 - 每分钟限制
if bullCheck and current_minute > last_alert_support_found
alert_message := '{"指标名称":"BjorgumKeyLevels","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"发现支撑","位置":"关键支撑位","成交量":"' + str.tostring(volume, '#') + '","价格变化":"' + str.tostring(close - open, '#.####') + '","最近支撑价格":"' + str.tostring(nearestSupportPrice, '#.####') + '","支撑距离":"' + str.tostring(supportDistance, '#.####') + '","支撑距离百分比":"' + str.tostring(supportPercent, '#.##') + '","最近阻力价格":"' + str.tostring(nearestResistancePrice, '#.####') + '","阻力距离":"' + str.tostring(resistanceDistance, '#.####') + '","阻力距离百分比":"' + str.tostring(resistancePercent, '#.##') + '","信号":"support_found"}'
alert(alert_message, alert.freq_once_per_bar_close)
last_alert_support_found := current_minute
if bearCheck and current_minute > last_alert_resistance_found
alert_message := '{"指标名称":"BjorgumKeyLevels","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"发现阻力","位置":"关键阻力位","成交量":"' + str.tostring(volume, '#') + '","价格变化":"' + str.tostring(close - open, '#.####') + '","最近支撑价格":"' + str.tostring(nearestSupportPrice, '#.####') + '","支撑距离":"' + str.tostring(supportDistance, '#.####') + '","支撑距离百分比":"' + str.tostring(supportPercent, '#.##') + '","最近阻力价格":"' + str.tostring(nearestResistancePrice, '#.####') + '","阻力距离":"' + str.tostring(resistanceDistance, '#.####') + '","阻力距离百分比":"' + str.tostring(resistancePercent, '#.##') + '","信号":"resistance_found"}'
alert(alert_message, alert.freq_once_per_bar_close)
last_alert_resistance_found := current_minute
// 支撑阻力反弹回落警报 - 每分钟限制
if plotBearCheck and current_minute > last_alert_resistance_rejection
alert_message := '{"指标名称":"BjorgumKeyLevels","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"阻力回落","位置":"阻力区域内","形态类型":"看跌信号","成交量":"' + str.tostring(volume, '#') + '","价格变化":"' + str.tostring(close - open, '#.####') + '","最近支撑价格":"' + str.tostring(nearestSupportPrice, '#.####') + '","支撑距离":"' + str.tostring(supportDistance, '#.####') + '","支撑距离百分比":"' + str.tostring(supportPercent, '#.##') + '","最近阻力价格":"' + str.tostring(nearestResistancePrice, '#.####') + '","阻力距离":"' + str.tostring(resistanceDistance, '#.####') + '","阻力距离百分比":"' + str.tostring(resistancePercent, '#.##') + '","信号":"resistance_rejection"}'
alert(alert_message, alert.freq_once_per_bar_close)
last_alert_resistance_rejection := current_minute
if plotBullCheck and current_minute > last_alert_support_bounce
alert_message := '{"指标名称":"BjorgumKeyLevels","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"支撑反弹","位置":"支撑区域内","形态类型":"看涨信号","成交量":"' + str.tostring(volume, '#') + '","价格变化":"' + str.tostring(close - open, '#.####') + '","最近支撑价格":"' + str.tostring(nearestSupportPrice, '#.####') + '","支撑距离":"' + str.tostring(supportDistance, '#.####') + '","支撑距离百分比":"' + str.tostring(supportPercent, '#.##') + '","最近阻力价格":"' + str.tostring(nearestResistancePrice, '#.####') + '","阻力距离":"' + str.tostring(resistanceDistance, '#.####') + '","阻力距离百分比":"' + str.tostring(resistancePercent, '#.##') + '","信号":"support_bounce"}'
alert(alert_message, alert.freq_once_per_bar_close)
last_alert_support_bounce := current_minute
// 假突破警报 - 每分钟限制
if falseBreakBull and current_minute > last_alert_false_breakdown
alert_message := '{"指标名称":"BjorgumKeyLevels","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"假跌破","位置":"支撑位反弹","成交量":"' + str.tostring(volume, '#') + '","价格变化":"' + str.tostring(close - open, '#.####') + '","最近支撑价格":"' + str.tostring(nearestSupportPrice, '#.####') + '","支撑距离":"' + str.tostring(supportDistance, '#.####') + '","支撑距离百分比":"' + str.tostring(supportPercent, '#.##') + '","最近阻力价格":"' + str.tostring(nearestResistancePrice, '#.####') + '","阻力距离":"' + str.tostring(resistanceDistance, '#.####') + '","阻力距离百分比":"' + str.tostring(resistancePercent, '#.##') + '","信号":"false_breakdown"}'
alert(alert_message, alert.freq_once_per_bar_close)
last_alert_false_breakdown := current_minute
if falseBreakBear and current_minute > last_alert_false_breakout
alert_message := '{"指标名称":"BjorgumKeyLevels","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"假突破","位置":"阻力位回落","成交量":"' + str.tostring(volume, '#') + '","价格变化":"' + str.tostring(close - open, '#.####') + '","最近支撑价格":"' + str.tostring(nearestSupportPrice, '#.####') + '","支撑距离":"' + str.tostring(supportDistance, '#.####') + '","支撑距离百分比":"' + str.tostring(supportPercent, '#.##') + '","最近阻力价格":"' + str.tostring(nearestResistancePrice, '#.####') + '","阻力距离":"' + str.tostring(resistanceDistance, '#.####') + '","阻力距离百分比":"' + str.tostring(resistancePercent, '#.##') + '","信号":"false_breakout"}'
alert(alert_message, alert.freq_once_per_bar_close)
last_alert_false_breakout := current_minute
// 强势突破警报 - 每分钟限制
if breakOut and current_minute > last_alert_strong_breakout_up
alert_message := '{"指标名称":"BjorgumKeyLevels","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"向上突破","位置":"所有阻力位上方","成交量":"' + str.tostring(volume, '#') + '","价格变化":"' + str.tostring(close - open, '#.####') + '","最近支撑价格":"' + str.tostring(nearestSupportPrice, '#.####') + '","支撑距离":"' + str.tostring(supportDistance, '#.####') + '","支撑距离百分比":"' + str.tostring(supportPercent, '#.##') + '","最近阻力价格":"' + str.tostring(nearestResistancePrice, '#.####') + '","阻力距离":"' + str.tostring(resistanceDistance, '#.####') + '","阻力距离百分比":"' + str.tostring(resistancePercent, '#.##') + '","信号":"strong_breakout_up"}'
alert(alert_message, alert.freq_once_per_bar_close)
last_alert_strong_breakout_up := current_minute
if breakDwn and current_minute > last_alert_strong_breakdown
alert_message := '{"指标名称":"BjorgumKeyLevels","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"向下跌破","位置":"所有支撑位下方","成交量":"' + str.tostring(volume, '#') + '","价格变化":"' + str.tostring(close - open, '#.####') + '","最近支撑价格":"' + str.tostring(nearestSupportPrice, '#.####') + '","支撑距离":"' + str.tostring(supportDistance, '#.####') + '","支撑距离百分比":"' + str.tostring(supportPercent, '#.##') + '","最近阻力价格":"' + str.tostring(nearestResistancePrice, '#.####') + '","阻力距离":"' + str.tostring(resistanceDistance, '#.####') + '","阻力距离百分比":"' + str.tostring(resistancePercent, '#.##') + '","信号":"strong_breakdown"}'
alert(alert_message, alert.freq_once_per_bar_close)
last_alert_strong_breakdown := current_minute
// 主要蜡烛图形态警报 - 每分钟限制
// if bew and current_minute > last_alert_bullish_engulfing // 看涨吞没
// alert_message := '{"指标名称":"BjorgumKeyLevels","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"看涨吞没","位置":"关键位置","形态类型":"强烈看涨","成交量":"' + str.tostring(volume, '#') + '","最近支撑价格":"' + str.tostring(nearestSupportPrice, '#.####') + '","支撑距离":"' + str.tostring(supportDistance, '#.####') + '","支撑距离百分比":"' + str.tostring(supportPercent, '#.##') + '","最近阻力价格":"' + str.tostring(nearestResistancePrice, '#.####') + '","阻力距离":"' + str.tostring(resistanceDistance, '#.####') + '","阻力距离百分比":"' + str.tostring(resistancePercent, '#.##') + '","信号":"bullish_engulfing"}'
// alert(alert_message, alert.freq_once_per_bar_close)
// last_alert_bullish_engulfing := current_minute
// if beb and current_minute > last_alert_bearish_engulfing // 看跌吞没
// alert_message := '{"指标名称":"BjorgumKeyLevels","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"看跌吞没","位置":"关键位置","形态类型":"强烈看跌","成交量":"' + str.tostring(volume, '#') + '","最近支撑价格":"' + str.tostring(nearestSupportPrice, '#.####') + '","支撑距离":"' + str.tostring(supportDistance, '#.####') + '","支撑距离百分比":"' + str.tostring(supportPercent, '#.##') + '","最近阻力价格":"' + str.tostring(nearestResistancePrice, '#.####') + '","阻力距离":"' + str.tostring(resistanceDistance, '#.####') + '","阻力距离百分比":"' + str.tostring(resistancePercent, '#.##') + '","信号":"bearish_engulfing"}'
// alert(alert_message, alert.freq_once_per_bar_close)
// last_alert_bearish_engulfing := current_minute
// if h and current_minute > last_alert_hammer // 锤子线
// alert_message := '{"指标名称":"BjorgumKeyLevels","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"锤子线","位置":"支撑位","形态类型":"看涨反转","成交量":"' + str.tostring(volume, '#') + '","最近支撑价格":"' + str.tostring(nearestSupportPrice, '#.####') + '","支撑距离":"' + str.tostring(supportDistance, '#.####') + '","支撑距离百分比":"' + str.tostring(supportPercent, '#.##') + '","最近阻力价格":"' + str.tostring(nearestResistancePrice, '#.####') + '","阻力距离":"' + str.tostring(resistanceDistance, '#.####') + '","阻力距离百分比":"' + str.tostring(resistancePercent, '#.##') + '","信号":"hammer"}'
// alert(alert_message, alert.freq_once_per_bar_close)
// last_alert_hammer := current_minute
// if ss and current_minute > last_alert_shooting_star // 流星线
// alert_message := '{"指标名称":"BjorgumKeyLevels","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"流星线","位置":"阻力位","形态类型":"看跌反转","成交量":"' + str.tostring(volume, '#') + '","最近支撑价格":"' + str.tostring(nearestSupportPrice, '#.####') + '","支撑距离":"' + str.tostring(supportDistance, '#.####') + '","支撑距离百分比":"' + str.tostring(supportPercent, '#.##') + '","最近阻力价格":"' + str.tostring(nearestResistancePrice, '#.####') + '","阻力距离":"' + str.tostring(resistanceDistance, '#.####') + '","阻力距离百分比":"' + str.tostring(resistancePercent, '#.##') + '","信号":"shooting_star"}'
// alert(alert_message, alert.freq_once_per_bar_close)
// last_alert_shooting_star := current_minute
// TSI动量转向警报 - 每分钟限制
// if plotCurlBull and current_minute > last_alert_tsi_bullish
// alert_message := '{"指标名称":"BjorgumKeyLevels","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"TSI动量转多","位置":"关键位置","成交量":"' + str.tostring(volume, '#') + '","最近支撑价格":"' + str.tostring(nearestSupportPrice, '#.####') + '","支撑距离":"' + str.tostring(supportDistance, '#.####') + '","支撑距离百分比":"' + str.tostring(supportPercent, '#.##') + '","最近阻力价格":"' + str.tostring(nearestResistancePrice, '#.####') + '","阻力距离":"' + str.tostring(resistanceDistance, '#.####') + '","阻力距离百分比":"' + str.tostring(resistancePercent, '#.##') + '","信号":"tsi_bullish"}'
// alert(alert_message, alert.freq_once_per_bar_close)
// last_alert_tsi_bullish := current_minute
// if plotCurlBear and current_minute > last_alert_tsi_bearish
// alert_message := '{"指标名称":"BjorgumKeyLevels","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"TSI动量转空","位置":"关键位置","成交量":"' + str.tostring(volume, '#') + '","最近支撑价格":"' + str.tostring(nearestSupportPrice, '#.####') + '","支撑距离":"' + str.tostring(supportDistance, '#.####') + '","支撑距离百分比":"' + str.tostring(supportPercent, '#.##') + '","最近阻力价格":"' + str.tostring(nearestResistancePrice, '#.####') + '","阻力距离":"' + str.tostring(resistanceDistance, '#.####') + '","阻力距离百分比":"' + str.tostring(resistancePercent, '#.##') + '","信号":"tsi_bearish"}'
// alert(alert_message, alert.freq_once_per_bar_close)
// last_alert_tsi_bearish := current_minute
// ===== 传统警报条件(保留兼容性)=====
// 注意使用统一警报系统时建议只使用上面的alert()函数
// 以下alertcondition保留用于需要单独设置警报的情况
// 阻力突破警报
alertcondition(resBreak, title = '阻力突破', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"阻力突破","位置":"阻力位上方","成交量":"{{volume}}","价格变化":"{{plot("价格变化")}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// 支撑跌破警报
alertcondition(supBreak, title = '支撑跌破', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"支撑跌破","位置":"支撑位下方","成交量":"{{volume}}","价格变化":"{{plot("价格变化")}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// 发现支撑警报
alertcondition(bullCheck, title = '发现支撑', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"发现支撑","位置":"关键支撑位","成交量":"{{volume}}","价格变化":"{{plot("价格变化")}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// 发现阻力警报
alertcondition(bearCheck, title = '发现阻力', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"发现阻力","位置":"关键阻力位","成交量":"{{volume}}","价格变化":"{{plot("价格变化")}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// 阻力回落警报
alertcondition(plotBearCheck, title = '阻力回落', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"阻力回落","位置":"阻力区域内","形态类型":"看跌信号","成交量":"{{volume}}","价格变化":"{{plot("价格变化")}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// 支撑反弹警报
alertcondition(plotBullCheck, title = '支撑反弹', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"支撑反弹","位置":"支撑区域内","形态类型":"看涨信号","成交量":"{{volume}}","价格变化":"{{plot("价格变化")}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// 假跌破警报
alertcondition(falseBreakBull, title = '假跌破', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"假跌破","位置":"支撑位反弹","成交量":"{{volume}}","价格变化":"{{plot("价格变化")}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// 假突破警报
alertcondition(falseBreakBear, title = '假突破', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"假突破","位置":"阻力位回落","成交量":"{{volume}}","价格变化":"{{plot("价格变化")}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// 向上突破警报
alertcondition(breakOut, title = '向上突破', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"向上突破","位置":"所有阻力位上方","成交量":"{{volume}}","价格变化":"{{plot("价格变化")}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// 向下跌破警报
alertcondition(breakDwn, title = '向下跌破', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"向下跌破","位置":"所有支撑位下方","成交量":"{{volume}}","价格变化":"{{plot("价格变化")}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// 蜡烛图形态警报 - 看涨形态
// alertcondition(dw, title = '十字星-支撑', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"十字星","位置":"支撑位","形态类型":"中性反转","成交量":"{{volume}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// alertcondition(bew, title = '看涨吞没', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"看涨吞没","位置":"关键位置","形态类型":"强烈看涨","成交量":"{{volume}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// alertcondition(h, title = '锤子线', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"锤子线","位置":"支撑位","形态类型":"看涨反转","成交量":"{{volume}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// alertcondition(dd, title = '蜻蜓十字', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"蜻蜓十字","位置":"支撑位","形态类型":"看涨反转","成交量":"{{volume}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// alertcondition(tb, title = '镊子底', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"镊子底","位置":"关键位置","形态类型":"看涨反转","成交量":"{{volume}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// alertcondition(p, title = '刺透线', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"刺透线","位置":"关键位置","形态类型":"看涨反转","成交量":"{{volume}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// alertcondition(bhw, title = '看涨孕线', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"看涨孕线","位置":"关键位置","形态类型":"看涨反转","成交量":"{{volume}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// alertcondition(ll, title = '长下影线', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"长下影线","位置":"支撑位","形态类型":"看涨信号","成交量":"{{volume}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// // 蜡烛图形态警报 - 看跌形态
// alertcondition(db, title = '十字星-阻力', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"十字星","位置":"阻力位","形态类型":"中性反转","成交量":"{{volume}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// alertcondition(beb, title = '看跌吞没', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"看跌吞没","位置":"关键位置","形态类型":"强烈看跌","成交量":"{{volume}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// alertcondition(ss, title = '流星线', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"流星线","位置":"阻力位","形态类型":"看跌反转","成交量":"{{volume}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// alertcondition(gd, title = '墓碑十字', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"墓碑十字","位置":"阻力位","形态类型":"看跌反转","成交量":"{{volume}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// alertcondition(tt, title = '镊子顶', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"镊子顶","位置":"关键位置","形态类型":"看跌反转","成交量":"{{volume}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// alertcondition(dcc, title = '乌云盖顶', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"乌云盖顶","位置":"关键位置","形态类型":"看跌反转","成交量":"{{volume}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// alertcondition(bhb, title = '看跌孕线', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"看跌孕线","位置":"关键位置","形态类型":"看跌反转","成交量":"{{volume}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// alertcondition(lu, title = '长上影线', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"长上影线","位置":"阻力位","形态类型":"看跌信号","成交量":"{{volume}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// // 纺锤顶形态警报
// alertcondition(stw, title = '白色纺锤顶', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"白色纺锤顶","位置":"关键位置","形态类型":"中性信号","成交量":"{{volume}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// alertcondition(stb, title = '黑色纺锤顶', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"黑色纺锤顶","位置":"关键位置","形态类型":"中性信号","成交量":"{{volume}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// TSI动量转向警报
alertcondition(plotCurlBull, title = 'TSI动量转多', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"TSI动量转多","位置":"关键位置","成交量":"{{volume}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
alertcondition(plotCurlBear, title = 'TSI动量转空', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"TSI动量转空","位置":"关键位置","成交量":"{{volume}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// 综合警报 - 价格在关键位置的行为
alertcondition(close > ta.highest(high, 20), title = '价格创新高', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格创新高","位置":"20周期新高","成交量":"{{volume}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
alertcondition(close < ta.lowest(low, 20), title = '价格创新低', message = '{"指标名称":"BjorgumKeyLevels","交易对":"{{ticker}}","周期":"{{interval}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格创新低","位置":"20周期新低","成交量":"{{volume}}","最近支撑价格":"{{plot("最近支撑价格")}}","支撑距离":"{{plot("支撑距离")}}","支撑距离百分比":"{{plot("支撑距离百分比")}}","最近阻力价格":"{{plot("最近阻力价格")}}","阻力距离":"{{plot("阻力距离")}}","阻力距离百分比":"{{plot("阻力距离百分比")}}"}')
// ===== 统一警报系统说明 =====
// 本指标已经包含了完整的JSON格式警报消息支持统一警报系统
// 所有警报条件都使用了JSON格式的消息包含了详细的市场信息
// 在TradingView中添加警报时选择任意一个警报条件即可获得对应的JSON消息
//
// 主要警报类型:
// 1. 关键位置突破:阻力突破、支撑跌破
// 2. 关键位置发现:发现支撑、发现阻力
// 3. 价格反应:支撑反弹、阻力回落
// 4. 假突破信号:假跌破、假突破
// 5. 趋势突破:向上突破、向下跌破
// 6. 蜡烛图形态:各种看涨看跌形态
// 7. 动量信号TSI动量转向
// 8. 价格极值:创新高、创新低
//
// 所有警报消息都包含:
// - 指标名称、交易对、周期
// - OHLC价格数据
// - 触发时间信息
// - 最近支撑阻力位价格和距离
// - 成交量信息
// - 具体事件描述
// ================================== //
// -----> 仪表盘功能 <------ //
// ================================== //
// 添加仪表盘显示设置
showDashboard = input.bool(true, '显示价格距离仪表盘', group = '仪表盘设置')
dashboardPos = input.string('左下', '仪表盘位置', group = '仪表盘设置', options = ['左上', '右上', '左下', '右下'])
dashboardSize = input.string('small', '仪表盘字体大小', group = '仪表盘设置', options = ['tiny', 'small', 'normal', 'large'])
// 获取仪表盘位置
_getDashboardPosition() =>
switch dashboardPos
'左上' => [position.top_left, position.top_left]
'右上' => [position.top_right, position.top_right]
'左下' => [position.bottom_left, position.bottom_left]
'右下' => [position.bottom_right, position.bottom_right]
=> [position.top_right, position.top_right]
// 获取仪表盘字体大小
_getDashboardSize() =>
switch dashboardSize
'tiny' => size.tiny
'small' => size.small
'normal' => size.normal
'large' => size.large
=> size.normal
// 显示仪表盘
if showDashboard and barstate.islast
[nearestSup, nearestRes, supDist, resDist] = _getNearestLevels()
[dashPos, _] = _getDashboardPosition()
dashSize = _getDashboardSize()
// 创建表格式仪表盘 (4行4列)
var table dashboard = table.new(dashPos, 4, 4, bgcolor = color.new(color.gray, 90), border_width = 1, border_color = color.new(color.white, 70))
// 表格标题行
table.cell(dashboard, 0, 0, '项目', text_color = color.new(color.black, 20), text_size = dashSize, bgcolor = color.new(color.blue, 80))
table.cell(dashboard, 1, 0, '价格', text_color = color.new(color.black, 20), text_size = dashSize, bgcolor = color.new(color.blue, 80))
table.cell(dashboard, 2, 0, '距离', text_color = color.new(color.black, 20), text_size = dashSize, bgcolor = color.new(color.blue, 80))
table.cell(dashboard, 3, 0, '百分比', text_color = color.new(color.black, 20), text_size = dashSize, bgcolor = color.new(color.blue, 80))
// 当前价格行
table.cell(dashboard, 0, 1, '当前价格', text_color = color.new(color.black, 30), text_size = dashSize, bgcolor = color.new(color.white, 85))
table.cell(dashboard, 1, 1, str.tostring(close, '#.####'), text_color = color.new(color.black, 20), text_size = dashSize, bgcolor = color.new(color.white, 85))
table.cell(dashboard, 2, 1, '-', text_color = color.new(color.black, 50), text_size = dashSize, bgcolor = color.new(color.white, 85))
table.cell(dashboard, 3, 1, '-', text_color = color.new(color.black, 50), text_size = dashSize, bgcolor = color.new(color.white, 85))
// 支撑位行
table.cell(dashboard, 0, 2, '最近支撑', text_color = color.new(color.black, 30), text_size = dashSize, bgcolor = color.new(color.green, 85))
var string supPriceText = ''
var string supDistText = ''
var string supPercText = ''
if not na(nearestSup)
supPriceText := str.tostring(nearestSup, '#.####')
if not na(supDist)
supDistPercent = supDist / close * 100
if close >= nearestSup
supDistText := '+' + str.tostring(supDist, '#.####')
supPercText := '+' + str.tostring(supDistPercent, '#.##') + '%'
supPercText
else
supDistText := '-' + str.tostring(supDist, '#.####')
supPercText := '-' + str.tostring(supDistPercent, '#.##') + '%'
supPercText
else
supDistText := '-'
supPercText := '-'
supPercText
else
supPriceText := '未找到'
supDistText := '-'
supPercText := '-'
supPercText
table.cell(dashboard, 1, 2, supPriceText, text_color = color.new(color.black, 20), text_size = dashSize, bgcolor = color.new(color.green, 85))
table.cell(dashboard, 2, 2, supDistText, text_color = color.new(color.black, 20), text_size = dashSize, bgcolor = color.new(color.green, 85))
table.cell(dashboard, 3, 2, supPercText, text_color = color.new(color.black, 20), text_size = dashSize, bgcolor = color.new(color.green, 85))
// 阻力位行
table.cell(dashboard, 0, 3, '最近阻力', text_color = color.new(color.black, 30), text_size = dashSize, bgcolor = color.new(color.red, 85))
var string resPriceText = ''
var string resDistText = ''
var string resPercText = ''
if not na(nearestRes)
resPriceText := str.tostring(nearestRes, '#.####')
if not na(resDist)
resDistPercent = resDist / close * 100
if close >= nearestRes
resDistText := '+' + str.tostring(resDist, '#.####')
resPercText := '+' + str.tostring(resDistPercent, '#.##') + '%'
resPercText
else
resDistText := '-' + str.tostring(resDist, '#.####')
resPercText := '-' + str.tostring(resDistPercent, '#.##') + '%'
resPercText
else
resDistText := '-'
resPercText := '-'
resPercText
else
resPriceText := '未找到'
resDistText := '-'
resPercText := '-'
resPercText
table.cell(dashboard, 1, 3, resPriceText, text_color = color.new(color.black, 20), text_size = dashSize, bgcolor = color.new(color.red, 85))
table.cell(dashboard, 2, 3, resDistText, text_color = color.new(color.black, 20), text_size = dashSize, bgcolor = color.new(color.red, 85))
table.cell(dashboard, 3, 3, resPercText, text_color = color.new(color.black, 20), text_size = dashSize, bgcolor = color.new(color.red, 85))
// ____ __ _ ____
// ( __)( ( \( \
// ) _) / / ) D (
// (____)\_)__)(____/