P/L Panel + Multi Targets (4 Entries) – HUD near Price + Avg R:R

indicator("P/L Panel + Multi Targets (4 Entries) – HUD near Price + Avg R:R", overlay=true, max_lines_count=500, max_labels_count=500)
// ====== General =====
side = input.string("Long", "Position Side", options=["Long","Short"])
usd_dp = input.int(2, "USD decimals", minval=0, maxval=6)
// ====== HUD Settings ======
hud_font = input.string("large", "HUD font size", options=["tiny","small","normal","large","huge"])
hud_bg = input.color(color.new(color.black, 0), "HUD background color")
hud_txtc = input.color(color.white, "HUD text color")
hud_side = input.string("Right of price", "HUD side", options=["Right of price","Left of price"])
hud_off_bars = input.int(3, "Horizontal offset (bars)", minval=0, maxval=50)
hud_off_atr = input.float(0.2, "Vertical offset from price (ATR)", step=0.1)
atr_len = input.int(14, "ATR length for vertical offset", minval=1)
lock_to_last_bar = input.bool(true, "Lock HUD to the last bar")
// Show HUD even when there are no entries (test text)
force_show_hud = input.bool(true, "🔍 Show HUD even with no entries")
// ====== Shared SL & Targets ======
stop_inp = input.float(0.0, "Stop Loss (shared, optional)", step=0.0001)
use_tp1 = input.bool(false, "Enable Target 1")
tp1 = input.float(0.0, "Target 1 price", step=0.0001)
use_tp2 = input.bool(false, "Enable Target 2")
tp2 = input.float(0.0, "Target 2 price", step=0.0001)
use_tp3 = input.bool(false, "Enable Target 3")
tp3 = input.float(0.0, "Target 3 price", step=0.0001)
use_tp4 = input.bool(false, "Enable Target 4")
tp4 = input.float(0.0, "Target 4 price", step=0.0001)
use_tp5 = input.bool(false, "Enable Target 5")
tp5 = input.float(0.0, "Target 5 price", step=0.0001)
// ====== Four Independent Entries ======
group1 = "Entry 1"
en1 = input.bool(true, "Enable Entry 1", inline=group1)
lev1 = input.int(10, "Leverage", minval=1, maxval=200, inline=group1)
entry1 = input.float(0.0, "Entry 1 price", step=0.0001)
set_now1 = input.bool(false, "⚡ Set Entry1 = Current Price")
mode1 = input.string("USD (USDT)", "Size unit 1", options=["USD (USDT)","Coin Quantity"])
sem1 = input.string("Margin (apply leverage)", "Size meaning 1", options=["Margin (apply leverage)","Notional (already leveraged)"])
size1 = input.float(0.0, "Position size 1", step=0.0001)
baseLev1 = input.bool(false, "Apply leverage to 'Coin Quantity' (1)")
group2 = "Entry 2"
en2 = input.bool(false, "Enable Entry 2", inline=group2)
lev2 = input.int(10, "Leverage", minval=1, maxval=200, inline=group2)
entry2 = input.float(0.0, "Entry 2 price", step=0.0001)
set_now2 = input.bool(false, "⚡ Set Entry2 = Current Price")
mode2 = input.string("USD (USDT)", "Size unit 2", options=["USD (USDT)","Coin Quantity"])
sem2 = input.string("Margin (apply leverage)", "Size meaning 2", options=["Margin (apply leverage)","Notional (already leveraged)"])
size2 = input.float(0.0, "Position size 2", step=0.0001)
baseLev2 = input.bool(false, "Apply leverage to 'Coin Quantity' (2)")
group3 = "Entry 3"
en3 = input.bool(false, "Enable Entry 3", inline=group3)
lev3 = input.int(10, "Leverage", minval=1, maxval=200, inline=group3)
entry3 = input.float(0.0, "Entry 3 price", step=0.0001)
set_now3 = input.bool(false, "⚡ Set Entry3 = Current Price")
mode3 = input.string("USD (USDT)", "Size unit 3", options=["USD (USDT)","Coin Quantity"])
sem3 = input.string("Margin (apply leverage)", "Size meaning 3", options=["Margin (apply leverage)","Notional (already leveraged)"])
size3 = input.float(0.0, "Position size 3", step=0.0001)
baseLev3 = input.bool(false, "Apply leverage to 'Coin Quantity' (3)")
group4 = "Entry 4"
en4 = input.bool(false, "Enable Entry 4", inline=group4)
lev4 = input.int(10, "Leverage", minval=1, maxval=200, inline=group4)
entry4 = input.float(0.0, "Entry 4 price", step=0.0001)
set_now4 = input.bool(false, "⚡ Set Entry4 = Current Price")
mode4 = input.string("USD (USDT)", "Size unit 4", options=["USD (USDT)","Coin Quantity"])
sem4 = input.string("Margin (apply leverage)", "Size meaning 4", options=["Margin (apply leverage)","Notional (already leveraged)"])
size4 = input.float(0.0, "Position size 4", step=0.0001)
baseLev4 = input.bool(false, "Apply leverage to 'Coin Quantity' (4)")
// Quick set entries = current price
entry1 := (en1 and set_now1) ? close : entry1
entry2 := (en2 and set_now2) ? close : entry2
entry3 := (en3 and set_now3) ? close : entry3
entry4 := (en4 and set_now4) ? close : entry4
// ====== Helpers ======
to_size(s) =>
s == "tiny" ? size.tiny : s == "small" ? size.small : s == "normal" ? size.normal : s == "large" ? size.large : size.huge
f_usd_str(_val, _decimals) =>
na(_val) ? "—" : str.tostring(math.round(_val * math.pow(10, _decimals)) / math.pow(10, _decimals))
f_qty_base(mode, sem, size, entry, baseLev, lev) =>
float _qty = na
if mode == "USD (USDT)"
_qty := (size > 0 and entry > 0) ? ((sem == "Margin (apply leverage)" ? size * lev : size) / entry) : na
else
_qty := size > 0 ? (baseLev ? size * lev : size) : na
_qty
f_notional_quote(mode, sem, size, entry, lev, baseLev) =>
if mode == "USD (USDT)"
sem == "Margin (apply leverage)" ? size * lev : size
else
(baseLev ? size * lev : size) * entry
f_pnl_quote(side, entry, qty) =>
na(qty) or na(entry) ? na : (side=="Long" ? (close - entry) : (entry - close)) * qty
f_pct(side, entry) =>
na(entry) ? na : ((close - entry) / entry * 100.0) * (side=="Long" ? 1 : -1)
f_roi_pct(side, entry, lev) =>
na(entry) ? na : f_pct(side, entry) * lev
// NOTE: _lineIn must be a line, not a float
f_stickyHLine(_price, _lineIn, _color, _width) =>
var line _out = na
_out := _lineIn
if na(_out)
_out := line.new(bar_index-1, _price, bar_index+1, _price, xloc=xloc.bar_index, extend=extend.both, width=_width, style=line.style_dashed, color=_color)
else
line.set_xy1(_out, bar_index-1, _price)
line.set_xy2(_out, bar_index+1, _price)
line.set_color(_out, _color)
line.set_width(_out, _width)
_out
// ====== 4 Entries Calculations ======
var color[] entryCols = array.from(color.new(color.yellow, 0), color.new(color.orange, 0), color.new(color.teal, 0), color.new(color.fuchsia, 0))
bool[] ens = array.from(en1, en2, en3, en4)
float[] entries = array.from(entry1, entry2, entry3, entry4)
int[] levs = array.from(lev1, lev2, lev3, lev4)
string[] modes = array.from(mode1, mode2, mode3, mode4)
string[] sems = array.from(sem1, sem2, sem3, sem4)
float[] sizes = array.from(size1, size2, size3, size4)
bool[] baseLevs = array.from(baseLev1, baseLev2, baseLev3, baseLev4)
float[] qtys = array.new_float(4, na)
float[] pnls = array.new_float(4, na)
float[] pcts = array.new_float(4, na)
float[] rois = array.new_float(4, na)
float[] notionals = array.new_float(4, na)
for i = 0 to 3
if array.get(ens, i) and array.get(entries, i) > 0
ent = array.get(entries, i)
levX = array.get(levs, i)
modeX= array.get(modes, i)
semX = array.get(sems, i)
sizeX= array.get(sizes, i)
bLev = array.get(baseLevs, i)
qty = f_qty_base(modeX, semX, sizeX, ent, bLev, levX)
array.set(qtys, i, qty)
pnlq = f_pnl_quote(side, ent, qty)
array.set(pnls, i, pnlq)
pct = f_pct(side, ent)
array.set(pcts, i, pct)
roi = f_roi_pct(side, ent, levX)
array.set(rois, i, roi)
notq = f_notional_quote(modeX, semX, sizeX, ent, levX, bLev)
array.set(notionals, i, notq)
// ====== Totals & Weighted Avg Entry ======
float totalPnlUSD = 0.0
float totalNotional = 0.0
float totalQty = 0.0
float wAvgEntry = na
for i = 0 to 3
if not na(array.get(pnls, i))
totalPnlUSD += array.get(pnls, i)
if not na(array.get(notionals, i))
totalNotional += array.get(notionals, i)
if not na(array.get(qtys, i)) and array.get(entries, i) > 0
totalQty += array.get(qtys, i)
if totalQty > 0
num = 0.0
for i = 0 to 3
qi = array.get(qtys, i)
ei = array.get(entries, i)
if not na(qi) and ei > 0
num += qi * ei
wAvgEntry := num / totalQty
totalROIweighted = totalNotional > 0 ? (totalPnlUSD / totalNotional) * 100.0 : na
// ====== Nearest TP & R:R ======
float nearestTP = na
float nearestDistPrice = na
float nearestDistPct = na
float risk_pct = na
float reward_pct = na
float rr = na
var float[] tps = array.new_float()
array.clear(tps)
if use_tp1 and tp1 > 0
array.push(tps, tp1)
if use_tp2 and tp2 > 0
array.push(tps, tp2)
if use_tp3 and tp3 > 0
array.push(tps, tp3)
if use_tp4 and tp4 > 0
array.push(tps, tp4)
if use_tp5 and tp5 > 0
array.push(tps, tp5)
// nearest target in the trade direction (from current price)
if array.size(tps) > 0
for i = 0 to array.size(tps) - 1
_tp = array.get(tps, i)
cond = side=="Long" ? (_tp > close) : (_tp < close)
if cond
distP = math.abs(_tp - close)
if na(nearestDistPrice) or distP < nearestDistPrice
nearestDistPrice := distP
nearestTP := _tp
if not na(nearestDistPrice) and close != 0
nearestDistPct := (nearestDistPrice / close) * 100.0
float stop = stop_inp > 0 ? stop_inp : na
if not na(wAvgEntry) and not na(stop)
rawRisk = (side=="Long" ? (stop - wAvgEntry) : (wAvgEntry - stop)) / wAvgEntry * 100.0
risk_pct := math.abs(rawRisk)
if not na(wAvgEntry) and not na(nearestTP)
reward_pct := math.abs((side=="Long" ? (nearestTP - wAvgEntry) : (wAvgEntry - nearestTP)) / wAvgEntry * 100.0)
rr := (not na(risk_pct) and not na(reward_pct) and risk_pct != 0) ? reward_pct / risk_pct : na
// ====== Average R:R across all valid targets ======
float rr_avg = na
if not na(wAvgEntry) and not na(stop) and array.size(tps) > 0 and not na(risk_pct) and risk_pct != 0
float sum_rr = 0.0
int cnt_rr = 0
for i = 0 to array.size(tps) - 1
_tp = array.get(tps, i)
bool validDir = side=="Long" ? (_tp > wAvgEntry) : (_tp < wAvgEntry)
if validDir
_reward = math.abs((side=="Long" ? (_tp - wAvgEntry) : (wAvgEntry - _tp)) / wAvgEntry * 100.0)
_rr = _reward / risk_pct
sum_rr += _rr
cnt_rr += 1
rr_avg := cnt_rr > 0 ? (sum_rr / cnt_rr) : na
// ====== Entry/SL/TP Lines ======
var line[] entryLines = array.new_line(4, na)
for i = 0 to 3
ln = array.get(entryLines, i)
if array.get(ens, i) and array.get(entries, i) > 0
col = array.get(entryCols, i)
ent = array.get(entries, i)
ln := f_stickyHLine(ent, ln, col, 2)
array.set(entryLines, i, ln)
else
if not na(ln)
line.delete(ln)
array.set(entryLines, i, na)
var line slLine = na
if not na(stop)
slLine := f_stickyHLine(stop, slLine, color.new(color.red, 0), 1)
else
if not na(slLine)
line.delete(slLine)
slLine := na
var line tpLine1 = na
var line tpLine2 = na
var line tpLine3 = na
var line tpLine4 = na
var line tpLine5 = na
if use_tp1 and tp1 > 0
tpLine1 := f_stickyHLine(tp1, tpLine1, color.new(color.teal, 0), 1)
else
if not na(tpLine1)
line.delete(tpLine1)
tpLine1 := na
if use_tp2 and tp2 > 0
tpLine2 := f_stickyHLine(tp2, tpLine2, color.new(color.teal, 0), 1)
else
if not na(tpLine2)
line.delete(tpLine2)
tpLine2 := na
if use_tp3 and tp3 > 0
tpLine3 := f_stickyHLine(tp3, tpLine3, color.new(color.teal, 0), 1)
else
if not na(tpLine3)
line.delete(tpLine3)
tpLine3 := na
if use_tp4 and tp4 > 0
tpLine4 := f_stickyHLine(tp4, tpLine4, color.new(color.teal, 0), 1)
else
if not na(tpLine4)
line.delete(tpLine4)
tpLine4 := na
if use_tp5 and tp5 > 0
tpLine5 := f_stickyHLine(tp5, tpLine5, color.new(color.teal, 0), 1)
else
if not na(tpLine5)
line.delete(tpLine5)
tpLine5 := na
// ====== Build HUD Text ======
string txt = ""
// Per-entry rows
for i = 0 to 3
if array.get(ens, i) and array.get(entries, i) > 0
idx = i + 1
ent = array.get(entries, i)
pct = array.get(pcts, i)
pnlq = array.get(pnls, i)
roi = array.get(rois, i)
levX = array.get(levs, i)
txt += (txt=="" ? "" : "\n") + "📌 Entry " + str.tostring(idx) + ": " + str.tostring(ent, format.mintick)
txt += "\n 📊 Live: " + (na(pct) ? "—" : str.tostring(pct, format.mintick) + "%") + " | 💵 " + (na(pnlq) ? "—" : "$" + f_usd_str(pnlq, usd_dp))
txt += "\n 🧮 ROI(x" + str.tostring(levX) + "): " + (na(roi) ? "—" : str.tostring(roi, format.mintick) + "%")
// Summary or test HUD
if txt != ""
if totalQty > 0
txt += "\n— — —"
txt += "\n⚖️ Weighted Avg Entry: " + str.tostring(wAvgEntry, format.mintick)
if not na(stop)
txt += "\n❌ SL: " + str.tostring(stop, format.mintick)
// Nearest target (from current price)
string tpInfo = "—"
if not na(nearestTP)
tpInfo := str.tostring(nearestTP, format.mintick) + (na(nearestDistPct) ? "" : " (Δ " + str.tostring(nearestDistPct, format.mintick) + "%)")
txt += "\n🎯 Nearest: " + tpInfo
// R:R (nearest)
if not na(rr)
txt += "\n📐 R:R (nearest): " + str.tostring(rr, format.mintick)
// Avg R:R across all valid TPs (by direction from weighted entry)
if not na(rr_avg)
txt += "\n📐 Avg R:R (all valid TPs): " + str.tostring(rr_avg, format.mintick)
// Totals
txt += "\n🧾 Total P/L: " + "$" + f_usd_str(totalPnlUSD, usd_dp)
txt += "\n🧮 Weighted ROI (by Notional): " + (na(totalROIweighted) ? "—" : str.tostring(totalROIweighted, format.mintick) + "%")
else if force_show_hud
txt := "🧪 HUD is active.\nFill Entry prices or tick ⚡.\nEnable TP/SL to see lines."
// ====== HUD Placement (near live price) ======
var label hud = na
atr_val = nz(ta.atr(atr_len), 0.0)
anchor_price = close
y_pos = na(anchor_price) ? na : anchor_price + (atr_val * hud_off_atr)
x_pos_base = bar_index
off = hud_side == "Right of price" ? hud_off_bars : -hud_off_bars
x_pos = lock_to_last_bar ? (barstate.islast ? (x_pos_base + off) : x_pos_base) : (x_pos_base + off)
// Pick label style by side:
// - Right of price → pointer on LEFT edge → style_label_left
// - Left of price → pointer on RIGHT edge → style_label_right
label_style = hud_side == "Right of price" ? label.style_label_left : label.style_label_right
if not na(y_pos) and txt != ""
if na(hud)
hud := label.new(x_pos, y_pos, txt, xloc=xloc.bar_index, style=label_style, textcolor=hud_txtc, color=hud_bg, size=to_size(hud_font))
else
label.set_x(hud, x_pos)
label.set_y(hud, y_pos)
label.set_text(hud, txt)
label.set_textcolor(hud, hud_txtc)
label.set_color(hud, hud_bg)
label.set_style(hud, label_style)
label.set_size(hud, to_size(hud_font))
else
if not na(hud)
label.delete(hud)
hud := na
Скрипт с ограниченным доступом
Только пользователи, одобренные автором, могут получить доступ к этому скрипту. Вам нужно отправить запрос и получить разрешение на его использование. Обычно доступ предоставляется после оплаты. Для получения подробной информации следуйте инструкциям автора ниже или свяжитесь с hsuyvm напрямую.
TradingView НЕ рекомендует платить за скрипт или использовать его, если вы не доверяете его автору и не понимаете, как скрипт работает. Вы всегда можете найти бесплатные скрипты с открытым исходным кодом в Скриптах сообщества.
Инструкции от автора
Внимание: перед тем как запрашивать доступ, прочитайте наши правила для скриптов с ограниченным доступом.
Отказ от ответственности
Скрипт с ограниченным доступом
Только пользователи, одобренные автором, могут получить доступ к этому скрипту. Вам нужно отправить запрос и получить разрешение на его использование. Обычно доступ предоставляется после оплаты. Для получения подробной информации следуйте инструкциям автора ниже или свяжитесь с hsuyvm напрямую.
TradingView НЕ рекомендует платить за скрипт или использовать его, если вы не доверяете его автору и не понимаете, как скрипт работает. Вы всегда можете найти бесплатные скрипты с открытым исходным кодом в Скриптах сообщества.
Инструкции от автора
Внимание: перед тем как запрашивать доступ, прочитайте наши правила для скриптов с ограниченным доступом.