Code: Select all
//@version=5
indicator("Event Risk & 1H Reaction Tracker [Workflow]", overlay=true, max_labels_count=50, max_boxes_count=50)
// =========================================================================
// INPUTS: Weekend Event Configuration
// =========================================================================
grp1 = "Event 1 Setup"
ev1_on = input.bool(true, "Enable Event 1", group=grp1)
ev1_name = input.string("US CPI", "Event Name", group=grp1)
ev1_time = input.time(timestamp("2026-10-08 08:30"), "Event Time", group=grp1)
grp2 = "Event 2 Setup"
ev2_on = input.bool(true, "Enable Event 2", group=grp2)
ev2_name = input.string("FOMC Rate Decision", "Event Name", group=grp2)
ev2_time = input.time(timestamp("2026-10-08 14:00"), "Event Time", group=grp2)
grp3 = "Event 3 Setup"
ev3_on = input.bool(true, "Enable Event 3", group=grp3)
ev3_name = input.string("ECB Press Conf", "Event Name", group=grp3)
ev3_time = input.time(timestamp("2026-10-09 08:30"), "Event Time", group=grp3)
grp4 = "Event 4 Setup"
ev4_on = input.bool(false, "Enable Event 4", group=grp4)
ev4_name = input.string("US Non-Farm Payrolls", "Event Name", group=grp4)
ev4_time = input.time(timestamp("2026-10-09 10:00"), "Event Time", group=grp4)
grpPolicy = "Policy & Display Options"
minsBefore = input.int(30, "No-Trade Window Before (Mins)", group=grpPolicy)
minsAfter = input.int(30, "No-Trade Window After (Mins)", group=grpPolicy)
alertMins = input.int(10, "Early Warning Alert (Mins)", group=grpPolicy)
reactionMins = input.int(60, "Post-Event Reaction Window (Mins)", minval=15, group=grpPolicy)
showTable = input.bool(true, "Show Weekly Summary Table", group=grpPolicy)
// =========================================================================
// HELPER CALCULATIONS
// =========================================================================
// Converts price difference to pips for Forex, or raw points for indices/commodities
toPips(float priceDelta) =>
pipUnit = syminfo.type == "forex" ? syminfo.mintick * 10 : syminfo.mintick
priceDelta / pipUnit
unitLabel = syminfo.type == "forex" ? " pips" : " pts"
// Check if current bar overlaps with the No-Trade Policy Window
inNoTradeZone(int evTime, bool active) =>
if not active
false
else
startT = evTime - (minsBefore * 60000)
endT = evTime + (minsAfter * 60000)
time <= endT and time_close >= startT
// Check if 10-minute warning alert should fire
isAlertCandidate(int evTime, bool active) =>
if not active
false
else
alertT = evTime - (alertMins * 60000)
time <= alertT and time_close > alertT
// =========================================================================
// DATA STRUCTURE FOR EVENT TRACKING
// =========================================================================
type EventTracker
string name
int startTime
int endTime
bool enabled
bool started
bool completed
float basePrice
float maxHigh
float minLow
float endPrice
// Initialize event trackers once
var EventTracker[] events = array.new<EventTracker>()
if barstate.isfirst
if ev1_on
array.push(events, EventTracker.new(ev1_name, ev1_time, ev1_time + (reactionMins * 60000), ev1_on, false, false, na, na, na, na))
if ev2_on
array.push(events, EventTracker.new(ev2_name, ev2_time, ev2_time + (reactionMins * 60000), ev2_on, false, false, na, na, na, na))
if ev3_on
array.push(events, EventTracker.new(ev3_name, ev3_time, ev3_time + (reactionMins * 60000), ev3_on, false, false, na, na, na, na))
if ev4_on
array.push(events, EventTracker.new(ev4_name, ev4_time, ev4_time + (reactionMins * 60000), ev4_on, false, false, na, na, na, na))
// Table initialization
var table summaryTable = table.new(position.top_right, 4, 6, bgcolor=color.new(#1e222d, 10), border_width=1, border_color=color.gray)
if barstate.isfirst and showTable
table.cell(summaryTable, 0, 0, "Event", bgcolor=color.new(color.blue, 40), text_color=color.white, text_size=size.small)
table.cell(summaryTable, 1, 0, "1H Net Move", bgcolor=color.new(color.blue, 40), text_color=color.white, text_size=size.small)
table.cell(summaryTable, 2, 0, "1H Range (Vol)", bgcolor=color.new(color.blue, 40), text_color=color.white, text_size=size.small)
table.cell(summaryTable, 3, 0, "Direction", bgcolor=color.new(color.blue, 40), text_color=color.white, text_size=size.small)
// =========================================================================
// MAIN EXECUTION LOOP (BAR-BY-BAR)
// =========================================================================
bool anyNoTradeZone = false
bool anyAlertTrigger = false
if array.size(events) > 0
for i = 0 to array.size(events) - 1
EventTracker item = array.get(events, i)
// 1. Evaluate risk window & alerts
if inNoTradeZone(item.startTime, item.enabled)
anyNoTradeZone := true
if isAlertCandidate(item.startTime, item.enabled)
anyAlertTrigger := true
// 2. Track 1-Hour Post-Event Reaction
if item.enabled and not item.completed
// Detect event start
if time_close >= item.startTime and not item.started
item.started := true
item.basePrice := open
item.maxHigh := high
item.minLow := low
// During the 1-hour window
if item.started
item.maxHigh := math.max(nz(item.maxHigh, high), high)
item.minLow := math.min(nz(item.minLow, low), low)
// Detect completion of the 1-hour window
if time_close >= item.endTime or (time <= item.endTime and time_close > item.endTime)
item.completed := true
item.endPrice := close
// Metric Calculations
netDelta = item.endPrice - item.basePrice
netPips = toPips(netDelta)
rangePips = toPips(item.maxHigh - item.minLow)
pctDelta = (netDelta / item.basePrice) * 100
isBullish = netDelta >= 0
dirColor = isBullish ? color.green : color.red
dirSymbol = isBullish ? "▲ BULLISH" : "▼ BEARISH"
// Draw 1-Hour Reaction Highlight Box
box.new(left=item.startTime, top=item.maxHigh, right=item.endTime, bottom=item.minLow,
xloc=xloc.bar_time, border_color=dirColor, border_width=1,
bgcolor=color.new(dirColor, 90))
// Draw Detailed Reaction Label on Chart
labelText = item.name + " (1-Hour Reaction)\n" +
"Direction: " + dirSymbol + "\n" +
"Net: " + (isBullish ? "+" : "") + str.tostring(netPips, "#.#") + unitLabel + " (" + str.tostring(pctDelta, "#.##") + "%)\n" +
"Total Range: " + str.tostring(rangePips, "#.#") + unitLabel
label.new(x=time, y=item.endPrice, text=labelText, xloc=xloc.bar_time,
color=color.new(#1e222d, 10), textcolor=color.white,
style=isBullish ? label.style_label_down : label.style_label_up,
size=size.normal)
// Update HUD Table Row
if showTable
row = i + 1
table.cell(summaryTable, 0, row, item.name, text_color=color.white, text_size=size.small)
table.cell(summaryTable, 1, row, (isBullish ? "+" : "") + str.tostring(netPips, "#.#") + unitLabel, text_color=dirColor, text_size=size.small)
table.cell(summaryTable, 2, row, str.tostring(rangePips, "#.#") + unitLabel, text_color=color.yellow, text_size=size.small)
table.cell(summaryTable, 3, row, isBullish ? "Bullish" : "Bearish", text_color=dirColor, text_size=size.small)
// =========================================================================
// VISUALS & ALERTS
// =========================================================================
// Shade the background during your defined No-Trade policy window
bgcolor(anyNoTradeZone ? color.new(color.red, 88) : na, title="No-Trade Risk Zone")
// Audio/Push Notification
if anyAlertTrigger
alert("⚠️️ EVENT WARNING: Tier-1 event in " + str.tostring(alertMins) + " minutes. Follow your policy!", alert.freq_once_per_bar)