// @version=6 indicator("๐Ÿงช Kachky Test Alerts", "๐Ÿงช TEST", overlay=true) // โ”€โ”€โ”€ Signal Mode โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ grpSig = "1) Signal" sigMode = input.string("Price Cross", "Signal Mode", options=["Price Cross", "Manual JSON"], group=grpSig, tooltip="Price Cross = auto signals when price crosses level.\nManual JSON = paste your own alert JSON.") // Price Cross mode crossLevel = input.float(0.0, "Cross Level (0 = SMA20)", group=grpSig, tooltip="Price level for cross signals. Set 0 to use SMA(20) as dynamic level.") smaLen = input.int(20, "SMA Length (if level=0)", minval=2, group=grpSig) // Manual JSON mode manualJson = input.text_area("", "Manual JSON payload", group=grpSig, tooltip='Paste full JSON, e.g.:\n{"action":"OPEN","symbol":"BTCUSDT","side":"LONG","strategy":"TEST","route":"capital","tier":"C"}') // โ”€โ”€โ”€ Direction โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ grpDir = "2) Direction" direction = input.string("Both", "Direction", options=["Long only", "Short only", "Both"], group=grpDir) // โ”€โ”€โ”€ Webhook โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ grpWH = "3) Webhook" useWebhook = input.bool(true, "Send webhook via alert()", group=grpWH) webhookMode = input.string("Both", "Webhook mode", options=["Both", "Open only", "Close only"], group=grpWH) routeOpt = input.string("capital", "Route", options=["auto", "hl", "bybit", "both", "capital", "all"], group=grpWH) scopeOpt = input.string("group", "Scope", options=["group", "individual"], group=grpWH) tierOpt = input.string("TEST", "๐Ÿ’ฐ Position Tier", options=["TEST", "A", "B", "C", "D", "E"], group=grpWH, tooltip="A=$1000 B=$500 C=$200 D=$100 E=$20 TEST=paper only") strategyName = input.string("TEST", "Strategy name", group=grpWH, tooltip="Strategy key sent in alert, e.g. TEST, VBO_1H, DONKEY_1H") kvOpt = input.string("", "Overrides (k=v;...)", group=grpWH) // โ”€โ”€โ”€ Logic โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ float level = crossLevel != 0 ? crossLevel : ta.sma(close, smaLen) // State var int pos = 0 // 0=flat, 1=long, -1=short bool longEntry = ta.crossover(close, level) and pos <= 0 and (direction != "Short only") bool shortEntry = ta.crossunder(close, level) and pos >= 0 and (direction != "Long only") bool longExit = ta.crossunder(close, level) and pos > 0 bool shortExit = ta.crossover(close, level) and pos < 0 if longEntry pos := 1 if shortEntry pos := -1 if longExit or shortExit pos := 0 // โ”€โ”€โ”€ Visuals โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ plot(level, "Level", color.new(color.gray, 40), 1, plot.style_stepline) plotshape(longEntry, "Long Entry", shape.triangleup, location.belowbar, color.lime, size=size.small) plotshape(shortEntry, "Short Entry", shape.triangledown, location.abovebar, color.red, size=size.small) plotshape(longExit, "Long Exit", shape.xcross, location.abovebar, color.orange, size=size.tiny) plotshape(shortExit, "Short Exit", shape.xcross, location.belowbar, color.orange, size=size.tiny) bgcolor(pos > 0 ? color.new(color.lime, 93) : pos < 0 ? color.new(color.red, 93) : na) // โ”€โ”€โ”€ Alert Generation โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ string tfKey = timeframe.period string strategyKey = strategyName string sigAction = "" string sigSide = "" string sigLabel = "" if longExit sigAction := "CLOSE" sigSide := "LONG" sigLabel := "LONG_EXIT" else if shortExit sigAction := "CLOSE" sigSide := "SHORT" sigLabel := "SHORT_EXIT" else if longEntry sigAction := "OPEN" sigSide := "LONG" sigLabel := "LONG_ENTRY" else if shortEntry sigAction := "OPEN" sigSide := "SHORT" sigLabel := "SHORT_ENTRY" bool allowOpen = (webhookMode != "Close only") bool allowClose = (webhookMode != "Open only") bool passMode = sigAction == "OPEN" ? allowOpen : sigAction == "CLOSE" ? allowClose : false if useWebhook and sigMode == "Price Cross" and sigAction != "" and passMode string baseMsg = str.format( "{0}|{1}|{2}|{3}|{4}|{5}|{6}|{7}|{8}", strategyKey, sigAction, sigSide, sigLabel, syminfo.tickerid, timeframe.period, str.tostring(close, format.mintick), routeOpt, scopeOpt ) string msg = baseMsg + "|" + (str.length(kvOpt) > 0 ? ("tier=" + tierOpt + ";" + kvOpt) : ("tier=" + tierOpt)) alert(msg, alert.freq_once_per_bar_close) // โ”€โ”€โ”€ Manual JSON alert (fires every bar close when in this mode) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ if useWebhook and sigMode == "Manual JSON" and str.length(manualJson) > 5 alert(manualJson, alert.freq_once_per_bar_close) // โ”€โ”€โ”€ Alert conditions (for non-webhook use) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ alertcondition(longEntry, title="Long Entry", message="TEST Long Entry") alertcondition(shortEntry, title="Short Entry", message="TEST Short Entry") alertcondition(longExit, title="Long Exit", message="TEST Long Exit") alertcondition(shortExit, title="Short Exit", message="TEST Short Exit")