OPEN-SOURCE SCRIPT
Confluence AutoEntry (1m/5m/15m) for Alertatron

//version=5
indicator("Confluence AutoEntry (1m/5m/15m) for Alertatron", overlay=true, max_lines_count=500, max_labels_count=500)
// =========================
// 参数
// =========================
tf1 = input.timeframe("1", "周期-1")
tf2 = input.timeframe("5", "周期-2")
tf3 = input.timeframe("15", "周期-3")
ema1 = input.int(10, "EMA1")
ema2 = input.int(30, "EMA2")
ema3 = input.int(60, "EMA3")
rLen = input.int(14, "RSI 长度")
thr1 = input.int(60, "阈值-周期1 (0~100)", minval=0, maxval=100)
thr2 = input.int(60, "阈值-周期2 (0~100)", minval=0, maxval=100)
thr3 = input.int(60, "阈值-周期3 (0~100)", minval=0, maxval=100)
// 下单资金(USDT)
usdtPerTrade = input.float(500, "每次下单金额(USDT)", step=5)
// 下单类型(市价/限价)
orderType = input.string("market", "下单类型", options=["market","limit"], tooltip="market=市价;limit=限价(使用 entry 作为限价)")
// 两步延续触发
useTwoStep = input.bool(true, "启用两步延续触发", tooltip="收盘仅“武装”,下一根或后续“延续突破”才真正发单;关闭=收盘即发一次信号")
bufferPct = input.float(0.08, "延续触发缓冲(%)", step=0.01, tooltip="突破需要超过武装价的百分比")
armBars = input.int(1, "武装有效bar数", minval=1, tooltip="超时未触发则自动取消武装")
// 可选:在 JSON 中附带 token
attachToken = input.bool(false, "在 JSON 中附带 token 字段")
longToken = input.string("", "多头 token(可留空)")
shortToken = input.string("", "空头 token(可留空)")
// 图形显示
showShapes = input.bool(true, "图表显示三角/武装/触发标记")
showTriggerLabel = input.bool(true, "触发时显示【入场/TP/SL/Qty】标签")
// 「平衡」展示用 TP/SL 百分比(仅用于标签展示,不发到 Alertatron)
tpPct = input.float(2.0, "展示用:TP百分比(%)")
slPct = input.float(1.0, "展示用:SL百分比(%)")
// =========================
// 工具函数
// =========================
f_score(tf) =>
_c = request.security(syminfo.tickerid, tf, close, barmerge.gaps_off, barmerge.lookahead_off)
_e1 = request.security(syminfo.tickerid, tf, ta.ema(close, ema1), barmerge.gaps_off, barmerge.lookahead_off)
_e2 = request.security(syminfo.tickerid, tf, ta.ema(close, ema2), barmerge.gaps_off, barmerge.lookahead_off)
_e3 = request.security(syminfo.tickerid, tf, ta.ema(close, ema3), barmerge.gaps_off, barmerge.lookahead_off)
_r = request.security(syminfo.tickerid, tf, ta.rsi(close, rLen), barmerge.gaps_off, barmerge.lookahead_off)
_m = request.security(syminfo.tickerid, tf, ta.sma(ta.change(close), 5), barmerge.gaps_off, barmerge.lookahead_off)
_ok1 = _c > _e1 ? 1 : 0
_ok2 = _e1 >= _e2 ? 1 : 0
_ok3 = _e2 >= _e3 ? 1 : 0
_ok4 = _r > 50 ? 1 : 0
_ok5 = _m >= 0 ? 1 : 0
(_ok1 + _ok2 + _ok3 + _ok4 + _ok5) / 5.0 * 100.0
// 价格按最小跳动取整
tickRound(x) =>
syminfo.mintick > 0 ? math.round(x / syminfo.mintick) * syminfo.mintick : x
// 数字 -> 价格串
sPrice(x) =>
str.tostring(x, format.mintick)
// 小数点四舍五入(用于数量展示)
roundN(x, n) =>
_f = math.pow(10.0, n)
math.round(x * _f) / _f
sQty(x) =>
str.tostring(roundN(x, 6))
// 去掉交易所前缀和 .P 后缀,得到 BASEQUOTE(如 ETHUSDC)
cleanSymbol() =>
_s = syminfo.ticker
_arr = str.split(_s, ":")
_last = array.get(_arr, array.size(_arr) - 1)
str.replace_all(_last, ".P", "")
// =========================
// 多周期评分 -> 一致方向
// =========================
score1 = f_score(tf1)
score2 = f_score(tf2)
score3 = f_score(tf3)
dir1 = score1 >= thr1 ? 1 : -1
dir2 = score2 >= thr2 ? 1 : -1
dir3 = score3 >= thr3 ? 1 : -1
conf_long = dir1 == 1 and dir2 == 1 and dir3 == 1
conf_short = dir1 == -1 and dir2 == -1 and dir3 == -1
// =========================
// 两步法:收盘“武装” + 下一根/后续“延续触发”
// =========================
var bool armLong = false
var float armLongPx = na
var int armLongUntil = na
var bool armShort = false
var float armShortPx = na
var int armShortUntil = na
if barstate.isconfirmed
if conf_long
armLong := true
armLongPx := close
armLongUntil := bar_index + armBars
if conf_short
armShort := true
armShortPx := close
armShortUntil := bar_index + armBars
longTrigPrice = armLong ? armLongPx * (1 + bufferPct/100.0) : na
shortTrigPrice = armShort ? armShortPx * (1 - bufferPct/100.0) : na
triggerLong = useTwoStep ? (armLong and high >= longTrigPrice) : (barstate.isconfirmed and conf_long)
triggerShort = useTwoStep ? (armShort and low <= shortTrigPrice) : (barstate.isconfirmed and conf_short)
// 触发后立刻卸载武装;超时未触发亦卸载
if triggerLong
armLong := false
if triggerShort
armShort := false
if bar_index > armLongUntil
armLong := false
if bar_index > armShortUntil
armShort := false
// =========================
// 发单用价位(在触发时会被使用)
// =========================
float entryL = tickRound(useTwoStep ? longTrigPrice : close)
float entryS = tickRound(useTwoStep ? shortTrigPrice : close)
float tpL = tickRound(entryL * (1 + tpPct/100.0))
float slL = tickRound(entryL * (1 - slPct/100.0))
float tpS = tickRound(entryS * (1 - tpPct/100.0))
float slS = tickRound(entryS * (1 + slPct/100.0))
// —— 展示标签直接使用上面算好的 entryL/entryS/tpL/slL/tpS/slS
if showTriggerLabel and barstate.isconfirmed
if triggerLong
_txt = "LONG Entry: " + sPrice(entryL) + "\nTP: " + sPrice(tpL) + "\nSL: " + sPrice(slL) + "\nEstQty: " + sQty(usdtPerTrade/entryL)
label.new(bar_index, low, text=_txt, style=label.style_label_up, textcolor=color.white, color=color.new(color.lime, 0))
if triggerShort
_txt = "SHORT Entry: " + sPrice(entryS) + "\nTP: " + sPrice(tpS) + "\nSL: " + sPrice(slS) + "\nEstQty: " + sQty(usdtPerTrade/entryS)
label.new(bar_index, high, text=_txt, style=label.style_label_down, textcolor=color.white, color=color.new(color.red, 0))
// ============ 构造 JSON(按方向用不同 signal 名,所有数值写入) ============
buildMsg(_side, _entry, _tp, _sl) =>
_sig = _side == "buy" ? "open_long" : "open_short"
_token = attachToken ? ',"token":"' + (_side == "buy" ? longToken : shortToken) + '"' : ""
_msg = '{"signal":"' + _sig + '"'
_msg := _msg + ',"side":"' + _side + '"'
_msg := _msg + ',"symbol":"' + cleanSymbol() + '"'
_msg := _msg + ',"order_type":"market"'
_msg := _msg + ',"usdt_per_trade":' + str.tostring(usdtPerTrade)
_msg := _msg + ',"entry":' + sPrice(_entry)
_msg := _msg + ',"tp":' + sPrice(_tp)
_msg := _msg + ',"sl":' + sPrice(_sl)
_msg := _msg + _token + "}"
_msg
msgLong = buildMsg("buy", entryL, tpL, slL)
msgShort = buildMsg("sell", entryS, tpS, slS)
// =========================
// 报警 & 发单(在 TradingView 里选择 Any alert() function call;Webhook 填机器人 URL;Message 留空)
// =========================
alertcondition(triggerLong, title="多仓开仓(…)", message="LONG")
alertcondition(triggerShort, title="空仓开仓(…)", message="SHORT")
if barstate.isconfirmed
if triggerLong
alert(message = msgLong, freq = alert.freq_once_per_bar_close)
if triggerShort
alert(message = msgShort, freq = alert.freq_once_per_bar_close)
// =========================
// 可视化:形态+触发线
// =========================
plotshape(showShapes and conf_long and barstate.isconfirmed, title="收盘-多武装", style=shape.triangleup, color=color.new(color.green, 0), size=size.tiny, text="ARM L", location=location.belowbar)
plotshape(showShapes and conf_short and barstate.isconfirmed, title="收盘-空武装", style=shape.triangledown, color=color.new(color.red, 0), size=size.tiny, text="ARM S", location=location.abovebar)
plotshape(showShapes and triggerLong, title="触发-开多", style=shape.labelup, color=color.new(color.lime, 0), text="▶ LONG", location=location.belowbar, size=size.tiny)
plotshape(showShapes and triggerShort, title="触发-开空", style=shape.labeldown, color=color.new(color.maroon,0), text="▶ SHORT", location=location.abovebar, size=size.tiny)
plot(useTwoStep and armLong ? armLongPx : na, "武装价-L", color=color.new(color.green, 70), style=plot.style_circles, linewidth=1)
plot(useTwoStep and armShort ? armShortPx : na, "武装价-S", color=color.new(color.red, 70), style=plot.style_circles, linewidth=1)
plot(useTwoStep ? longTrigPrice : na, "触发线-L", color=color.new(color.lime, 0), style=plot.style_linebr, linewidth=1)
plot(useTwoStep ? shortTrigPrice : na, "触发线-S", color=color.new(color.maroon, 0), style=plot.style_linebr, linewidth=1)
// =========================
// 可视化:触发时弹出【入场/TP/SL/Qty】标签(仅展示用)
// =========================
if showTriggerLabel and barstate.isconfirmed
if triggerLong
_qtyL = usdtPerTrade > 0 and entryL > 0 ? (usdtPerTrade / entryL) : na
_txtL = "LONG Entry: " + sPrice(entryL) + "\nTP: " + sPrice(tpL) + "\nSL: " + sPrice(slL) + "\nEstQty: " + sQty(_qtyL)
label.new(bar_index, low, text=_txtL, style=label.style_label_up, textcolor=color.white, color=color.new(color.lime, 0))
if triggerShort
_qtyS = usdtPerTrade > 0 and entryS > 0 ? (usdtPerTrade / entryS) : na
_txtS = "SHORT Entry: " + sPrice(entryS) + "\nTP: " + sPrice(tpS) + "\nSL: " + sPrice(slS) + "\nEstQty: " + sQty(_qtyS)
label.new(bar_index, high, text=_txtS, style=label.style_label_down, textcolor=color.white, color=color.new(color.red, 0))
indicator("Confluence AutoEntry (1m/5m/15m) for Alertatron", overlay=true, max_lines_count=500, max_labels_count=500)
// =========================
// 参数
// =========================
tf1 = input.timeframe("1", "周期-1")
tf2 = input.timeframe("5", "周期-2")
tf3 = input.timeframe("15", "周期-3")
ema1 = input.int(10, "EMA1")
ema2 = input.int(30, "EMA2")
ema3 = input.int(60, "EMA3")
rLen = input.int(14, "RSI 长度")
thr1 = input.int(60, "阈值-周期1 (0~100)", minval=0, maxval=100)
thr2 = input.int(60, "阈值-周期2 (0~100)", minval=0, maxval=100)
thr3 = input.int(60, "阈值-周期3 (0~100)", minval=0, maxval=100)
// 下单资金(USDT)
usdtPerTrade = input.float(500, "每次下单金额(USDT)", step=5)
// 下单类型(市价/限价)
orderType = input.string("market", "下单类型", options=["market","limit"], tooltip="market=市价;limit=限价(使用 entry 作为限价)")
// 两步延续触发
useTwoStep = input.bool(true, "启用两步延续触发", tooltip="收盘仅“武装”,下一根或后续“延续突破”才真正发单;关闭=收盘即发一次信号")
bufferPct = input.float(0.08, "延续触发缓冲(%)", step=0.01, tooltip="突破需要超过武装价的百分比")
armBars = input.int(1, "武装有效bar数", minval=1, tooltip="超时未触发则自动取消武装")
// 可选:在 JSON 中附带 token
attachToken = input.bool(false, "在 JSON 中附带 token 字段")
longToken = input.string("", "多头 token(可留空)")
shortToken = input.string("", "空头 token(可留空)")
// 图形显示
showShapes = input.bool(true, "图表显示三角/武装/触发标记")
showTriggerLabel = input.bool(true, "触发时显示【入场/TP/SL/Qty】标签")
// 「平衡」展示用 TP/SL 百分比(仅用于标签展示,不发到 Alertatron)
tpPct = input.float(2.0, "展示用:TP百分比(%)")
slPct = input.float(1.0, "展示用:SL百分比(%)")
// =========================
// 工具函数
// =========================
f_score(tf) =>
_c = request.security(syminfo.tickerid, tf, close, barmerge.gaps_off, barmerge.lookahead_off)
_e1 = request.security(syminfo.tickerid, tf, ta.ema(close, ema1), barmerge.gaps_off, barmerge.lookahead_off)
_e2 = request.security(syminfo.tickerid, tf, ta.ema(close, ema2), barmerge.gaps_off, barmerge.lookahead_off)
_e3 = request.security(syminfo.tickerid, tf, ta.ema(close, ema3), barmerge.gaps_off, barmerge.lookahead_off)
_r = request.security(syminfo.tickerid, tf, ta.rsi(close, rLen), barmerge.gaps_off, barmerge.lookahead_off)
_m = request.security(syminfo.tickerid, tf, ta.sma(ta.change(close), 5), barmerge.gaps_off, barmerge.lookahead_off)
_ok1 = _c > _e1 ? 1 : 0
_ok2 = _e1 >= _e2 ? 1 : 0
_ok3 = _e2 >= _e3 ? 1 : 0
_ok4 = _r > 50 ? 1 : 0
_ok5 = _m >= 0 ? 1 : 0
(_ok1 + _ok2 + _ok3 + _ok4 + _ok5) / 5.0 * 100.0
// 价格按最小跳动取整
tickRound(x) =>
syminfo.mintick > 0 ? math.round(x / syminfo.mintick) * syminfo.mintick : x
// 数字 -> 价格串
sPrice(x) =>
str.tostring(x, format.mintick)
// 小数点四舍五入(用于数量展示)
roundN(x, n) =>
_f = math.pow(10.0, n)
math.round(x * _f) / _f
sQty(x) =>
str.tostring(roundN(x, 6))
// 去掉交易所前缀和 .P 后缀,得到 BASEQUOTE(如 ETHUSDC)
cleanSymbol() =>
_s = syminfo.ticker
_arr = str.split(_s, ":")
_last = array.get(_arr, array.size(_arr) - 1)
str.replace_all(_last, ".P", "")
// =========================
// 多周期评分 -> 一致方向
// =========================
score1 = f_score(tf1)
score2 = f_score(tf2)
score3 = f_score(tf3)
dir1 = score1 >= thr1 ? 1 : -1
dir2 = score2 >= thr2 ? 1 : -1
dir3 = score3 >= thr3 ? 1 : -1
conf_long = dir1 == 1 and dir2 == 1 and dir3 == 1
conf_short = dir1 == -1 and dir2 == -1 and dir3 == -1
// =========================
// 两步法:收盘“武装” + 下一根/后续“延续触发”
// =========================
var bool armLong = false
var float armLongPx = na
var int armLongUntil = na
var bool armShort = false
var float armShortPx = na
var int armShortUntil = na
if barstate.isconfirmed
if conf_long
armLong := true
armLongPx := close
armLongUntil := bar_index + armBars
if conf_short
armShort := true
armShortPx := close
armShortUntil := bar_index + armBars
longTrigPrice = armLong ? armLongPx * (1 + bufferPct/100.0) : na
shortTrigPrice = armShort ? armShortPx * (1 - bufferPct/100.0) : na
triggerLong = useTwoStep ? (armLong and high >= longTrigPrice) : (barstate.isconfirmed and conf_long)
triggerShort = useTwoStep ? (armShort and low <= shortTrigPrice) : (barstate.isconfirmed and conf_short)
// 触发后立刻卸载武装;超时未触发亦卸载
if triggerLong
armLong := false
if triggerShort
armShort := false
if bar_index > armLongUntil
armLong := false
if bar_index > armShortUntil
armShort := false
// =========================
// 发单用价位(在触发时会被使用)
// =========================
float entryL = tickRound(useTwoStep ? longTrigPrice : close)
float entryS = tickRound(useTwoStep ? shortTrigPrice : close)
float tpL = tickRound(entryL * (1 + tpPct/100.0))
float slL = tickRound(entryL * (1 - slPct/100.0))
float tpS = tickRound(entryS * (1 - tpPct/100.0))
float slS = tickRound(entryS * (1 + slPct/100.0))
// —— 展示标签直接使用上面算好的 entryL/entryS/tpL/slL/tpS/slS
if showTriggerLabel and barstate.isconfirmed
if triggerLong
_txt = "LONG Entry: " + sPrice(entryL) + "\nTP: " + sPrice(tpL) + "\nSL: " + sPrice(slL) + "\nEstQty: " + sQty(usdtPerTrade/entryL)
label.new(bar_index, low, text=_txt, style=label.style_label_up, textcolor=color.white, color=color.new(color.lime, 0))
if triggerShort
_txt = "SHORT Entry: " + sPrice(entryS) + "\nTP: " + sPrice(tpS) + "\nSL: " + sPrice(slS) + "\nEstQty: " + sQty(usdtPerTrade/entryS)
label.new(bar_index, high, text=_txt, style=label.style_label_down, textcolor=color.white, color=color.new(color.red, 0))
// ============ 构造 JSON(按方向用不同 signal 名,所有数值写入) ============
buildMsg(_side, _entry, _tp, _sl) =>
_sig = _side == "buy" ? "open_long" : "open_short"
_token = attachToken ? ',"token":"' + (_side == "buy" ? longToken : shortToken) + '"' : ""
_msg = '{"signal":"' + _sig + '"'
_msg := _msg + ',"side":"' + _side + '"'
_msg := _msg + ',"symbol":"' + cleanSymbol() + '"'
_msg := _msg + ',"order_type":"market"'
_msg := _msg + ',"usdt_per_trade":' + str.tostring(usdtPerTrade)
_msg := _msg + ',"entry":' + sPrice(_entry)
_msg := _msg + ',"tp":' + sPrice(_tp)
_msg := _msg + ',"sl":' + sPrice(_sl)
_msg := _msg + _token + "}"
_msg
msgLong = buildMsg("buy", entryL, tpL, slL)
msgShort = buildMsg("sell", entryS, tpS, slS)
// =========================
// 报警 & 发单(在 TradingView 里选择 Any alert() function call;Webhook 填机器人 URL;Message 留空)
// =========================
alertcondition(triggerLong, title="多仓开仓(…)", message="LONG")
alertcondition(triggerShort, title="空仓开仓(…)", message="SHORT")
if barstate.isconfirmed
if triggerLong
alert(message = msgLong, freq = alert.freq_once_per_bar_close)
if triggerShort
alert(message = msgShort, freq = alert.freq_once_per_bar_close)
// =========================
// 可视化:形态+触发线
// =========================
plotshape(showShapes and conf_long and barstate.isconfirmed, title="收盘-多武装", style=shape.triangleup, color=color.new(color.green, 0), size=size.tiny, text="ARM L", location=location.belowbar)
plotshape(showShapes and conf_short and barstate.isconfirmed, title="收盘-空武装", style=shape.triangledown, color=color.new(color.red, 0), size=size.tiny, text="ARM S", location=location.abovebar)
plotshape(showShapes and triggerLong, title="触发-开多", style=shape.labelup, color=color.new(color.lime, 0), text="▶ LONG", location=location.belowbar, size=size.tiny)
plotshape(showShapes and triggerShort, title="触发-开空", style=shape.labeldown, color=color.new(color.maroon,0), text="▶ SHORT", location=location.abovebar, size=size.tiny)
plot(useTwoStep and armLong ? armLongPx : na, "武装价-L", color=color.new(color.green, 70), style=plot.style_circles, linewidth=1)
plot(useTwoStep and armShort ? armShortPx : na, "武装价-S", color=color.new(color.red, 70), style=plot.style_circles, linewidth=1)
plot(useTwoStep ? longTrigPrice : na, "触发线-L", color=color.new(color.lime, 0), style=plot.style_linebr, linewidth=1)
plot(useTwoStep ? shortTrigPrice : na, "触发线-S", color=color.new(color.maroon, 0), style=plot.style_linebr, linewidth=1)
// =========================
// 可视化:触发时弹出【入场/TP/SL/Qty】标签(仅展示用)
// =========================
if showTriggerLabel and barstate.isconfirmed
if triggerLong
_qtyL = usdtPerTrade > 0 and entryL > 0 ? (usdtPerTrade / entryL) : na
_txtL = "LONG Entry: " + sPrice(entryL) + "\nTP: " + sPrice(tpL) + "\nSL: " + sPrice(slL) + "\nEstQty: " + sQty(_qtyL)
label.new(bar_index, low, text=_txtL, style=label.style_label_up, textcolor=color.white, color=color.new(color.lime, 0))
if triggerShort
_qtyS = usdtPerTrade > 0 and entryS > 0 ? (usdtPerTrade / entryS) : na
_txtS = "SHORT Entry: " + sPrice(entryS) + "\nTP: " + sPrice(tpS) + "\nSL: " + sPrice(slS) + "\nEstQty: " + sQty(_qtyS)
label.new(bar_index, high, text=_txtS, style=label.style_label_down, textcolor=color.white, color=color.new(color.red, 0))
Скрипт с открытым кодом
В истинном духе TradingView автор этого скрипта опубликовал его с открытым исходным кодом, чтобы трейдеры могли понять, как он работает, и проверить на практике. Вы можете воспользоваться им бесплатно, но повторное использование этого кода в публикации регулируется Правилами поведения.
Отказ от ответственности
Все виды контента, которые вы можете увидеть на TradingView, не являются финансовыми, инвестиционными, торговыми или любыми другими рекомендациями. Мы не предоставляем советы по покупке и продаже активов. Подробнее — в Условиях использования TradingView.
Скрипт с открытым кодом
В истинном духе TradingView автор этого скрипта опубликовал его с открытым исходным кодом, чтобы трейдеры могли понять, как он работает, и проверить на практике. Вы можете воспользоваться им бесплатно, но повторное использование этого кода в публикации регулируется Правилами поведения.
Отказ от ответственности
Все виды контента, которые вы можете увидеть на TradingView, не являются финансовыми, инвестиционными, торговыми или любыми другими рекомендациями. Мы не предоставляем советы по покупке и продаже активов. Подробнее — в Условиях использования TradingView.