INVITE-ONLY SCRIPT
Updated

پنل سود/زیان + چند تارگت R:R

14
//version=6
indicator("پنل سود/زیان + چند تارگت (۴ ورود مستقل) - پنل چپ نزدیک قیمت + میانگین R:R", overlay=true, max_lines_count=500, max_labels_count=500)

// ====== تنظیمات عمومی ======
side = input.string("لانگ", "نوع پوزیشن", options=["لانگ","شورت"])
usd_dp = input.int(2, "تعداد اعشار نمایش دلار", minval=0, maxval=6)

// ====== تنظیمات پنل ======
hud_font = input.string("large", "اندازۀ فونت پنل", options=["tiny","small","normal","large","huge"])
hud_bg = input.color(color.new(color.black, 0), "رنگ پس‌زمینه پنل")
hud_txtc = input.color(color.white, "رنگ متن پنل")

// محل پنل: کمی «چپِ» آخرین کندل + کمی فاصله عمودی از قیمت
hud_off_bars = input.int(3, "فاصلۀ افقی از قیمت به سمت چپ (تعداد کندل، فقط روی آخرین کندل)", minval=0, maxval=50)
hud_off_atr = input.float(0.2, "فاصلۀ عمودی از قیمت (ATR)", step=0.1)
atr_len = input.int(14, "طول ATR برای فاصله عمودی", minval=1)

// نمایش اجباری پنل حتی بدون ورود
force_show_hud = input.bool(true, "🔍 نمایش اجباری پنل حتی بدون ورود")

// ====== حد ضرر و تارگت‌های مشترک ======
stop_inp = input.float(0.0, "حد ضرر (مشترک، اختیاری)", step=0.0001)
use_tp1 = input.bool(false, "فعال‌سازی تارگت ۱")
tp1 = input.float(0.0, "قیمت تارگت ۱", step=0.0001)
use_tp2 = input.bool(false, "فعال‌سازی تارگت ۲")
tp2 = input.float(0.0, "قیمت تارگت ۲", step=0.0001)
use_tp3 = input.bool(false, "فعال‌سازی تارگت ۳")
tp3 = input.float(0.0, "قیمت تارگت ۳", step=0.0001)
use_tp4 = input.bool(false, "فعال‌سازی تارگت ۴")
tp4 = input.float(0.0, "قیمت تارگت ۴", step=0.0001)
use_tp5 = input.bool(false, "فعال‌سازی تارگت ۵")
tp5 = input.float(0.0, "قیمت تارگت ۵", step=0.0001)

// ====== ورودی‌های ۴ ورود مستقل ======
group1 = "ورود ۱"
en1 = input.bool(true, "فعال‌سازی ورود ۱", inline=group1)
lev1 = input.int(10, "لوریج", minval=1, maxval=200, inline=group1)
entry1 = input.float(0.0, "قیمت ورود ۱", step=0.0001)
set_now1 = input.bool(false, "⚡ ثبت ورود۱ = قیمت فعلی")
mode1 = input.string("دلاری (USDT)", "واحد اندازه ۱", options=["دلاری (USDT)","تعداد کوین"])
sem1 = input.string("مارجین (اعمال لوریج)", "تعبیر اندازه ۱", options=["مارجین (اعمال لوریج)","ناتیونال (از قبل لوریج شده)"])
size1 = input.float(0.0, "اندازه پوزیشن ۱", step=0.0001)
baseLev1 = input.bool(false, "اعمال لوریج روی حالت «تعداد کوین» (۱)")

group2 = "ورود ۲"
en2 = input.bool(false, "فعال‌سازی ورود ۲", inline=group2)
lev2 = input.int(10, "لوریج", minval=1, maxval=200, inline=group2)
entry2 = input.float(0.0, "قیمت ورود ۲", step=0.0001)
set_now2 = input.bool(false, "⚡ ثبت ورود۲ = قیمت فعلی")
mode2 = input.string("دلاری (USDT)", "واحد اندازه ۲", options=["دلاری (USDT)","تعداد کوین"])
sem2 = input.string("مارجین (اعمال لوریج)", "تعبیر اندازه ۲", options=["مارجین (اعمال لوریج)","ناتیونال (از قبل لوریج شده)"])
size2 = input.float(0.0, "اندازه پوزیشن ۲", step=0.0001)
baseLev2 = input.bool(false, "اعمال لوریج روی حالت «تعداد کوین» (۲)")

group3 = "ورود ۳"
en3 = input.bool(false, "فعال‌سازی ورود ۳", inline=group3)
lev3 = input.int(10, "لوریج", minval=1, maxval=200, inline=group3)
entry3 = input.float(0.0, "قیمت ورود ۳", step=0.0001)
set_now3 = input.bool(false, "⚡ ثبت ورود۳ = قیمت فعلی")
mode3 = input.string("دلاری (USDT)", "واحد اندازه ۳", options=["دلاری (USDT)","تعداد کوین"])
sem3 = input.string("مارجین (اعمال لوریج)", "تعبیر اندازه ۳", options=["مارجین (اعمال لوریج)","ناتیونال (از قبل لوریج شده)"])
size3 = input.float(0.0, "اندازه پوزیشن ۳", step=0.0001)
baseLev3 = input.bool(false, "اعمال لوریج روی حالت «تعداد کوین» (۳)")

group4 = "ورود ۴"
en4 = input.bool(false, "فعال‌سازی ورود ۴", inline=group4)
lev4 = input.int(10, "لوریج", minval=1, maxval=200, inline=group4)
entry4 = input.float(0.0, "قیمت ورود ۴", step=0.0001)
set_now4 = input.bool(false, "⚡ ثبت ورود۴ = قیمت فعلی")
mode4 = input.string("دلاری (USDT)", "واحد اندازه ۴", options=["دلاری (USDT)","تعداد کوین"])
sem4 = input.string("مارجین (اعمال لوریج)", "تعبیر اندازه ۴", options=["مارجین (اعمال لوریج)","ناتیونال (از قبل لوریج شده)"])
size4 = input.float(0.0, "اندازه پوزیشن ۴", step=0.0001)
baseLev4 = input.bool(false, "اعمال لوریج روی حالت «تعداد کوین» (۴)")

// ثبت سریع ورود = قیمت فعلی
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

// ====== کمک‌تابع‌ها ======
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 == "دلاری (USDT)"
_qty := (size > 0 and entry > 0) ? ((sem == "مارجین (اعمال لوریج)" ? 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 == "دلاری (USDT)"
sem == "مارجین (اعمال لوریج)" ? size * lev : size
else
(baseLev ? size * lev : size) * entry

f_pnl_quote(side, entry, qty) =>
na(qty) or na(entry) ? na : (side=="لانگ" ? (close - entry) : (entry - close)) * qty

f_pct(side, entry) =>
na(entry) ? na : ((close - entry) / entry * 100.0) * (side=="لانگ" ? 1 : -1)

f_roi_pct(side, entry, lev) =>
na(entry) ? na : f_pct(side, entry) * lev

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

// ====== محاسبات ۴ ورود ======
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)

// ====== مجموع و میانگین ورود وزنی ======
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

// ====== نزدیک‌ترین تارگت و 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)

// نزدیک‌ترین تارگت همسو با جهت
if array.size(tps) > 0
for i = 0 to array.size(tps) - 1
_tp = array.get(tps, i)
cond = side=="لانگ" ? (_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=="لانگ" ? (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=="لانگ" ? (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

// ====== «میانگین R:R» روی همه تارگت‌های معتبر ======
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=="لانگ" ? (_tp > wAvgEntry) : (_tp < wAvgEntry)
if validDir
_reward = math.abs((side=="لانگ" ? (_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

// ====== خطوط ورود/SL/TP ======
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

// ====== ساخت متن پنل ======
string txt = ""

// ردیف‌های هر ورود
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") + "📌 ورود " + str.tostring(idx) + ": " + str.tostring(ent, format.mintick)
txt += "\n 📊 لحظه‌ای: " + (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) + "%")

// خلاصه پایانی یا پنل تست
if txt != ""
if totalQty > 0
txt += "\n— — —"
txt += "\n⚖️ میانگین ورود وزنی: " + str.tostring(wAvgEntry, format.mintick)
if not na(stop)
txt += "\n❌ SL: " + str.tostring(stop, format.mintick)

// نزدیک‌ترین تارگت
string tpInfo = "—"
if not na(nearestTP)
tpInfo := str.tostring(nearestTP, format.mintick) + (na(nearestDistPct) ? "" : " (Δ " + str.tostring(nearestDistPct, format.mintick) + "%)")
txt += "\n🎯 نزدیک‌ترین: " + tpInfo

// R:R نزدیک‌ترین
if not na(rr)
txt += "\n📐 R:R نزدیک‌ترین: " + str.tostring(rr, format.mintick)

// میانگین R:R روی همه تارگت‌های معتبر
if not na(rr_avg)
txt += "\n📐 میانگین R:R (همۀ تارگت‌های معتبر): " + str.tostring(rr_avg, format.mintick)

// مجموع‌ها
txt += "\n🧾 مجموع سود/زیان: " + "$" + f_usd_str(totalPnlUSD, usd_dp)
txt += "\n🧮 ROĪ وزنی (بر اساس ناتیونال): " + (na(totalROIweighted) ? "—" : str.tostring(totalROIweighted, format.mintick) + "%")
else if force_show_hud
txt := "🧪 پنل فعال است.\nاز فیلدهای «قیمت ورود» استفاده کن یا تیک‌های ⚡ را بزن.\nبرای دیدن TP/SL خطوط، تیک‌های مربوطه را فعال کن."

// ====== HUD (پنل سمت چپ، نوک اشاره نزدیک قیمت لحظه‌ای) ======
// ====== HUD (پنل سمت راست، نوک اشاره نزدیک قیمت لحظه‌ای) ======
var label hud = na
atr_val = ta.atr(atr_len)

// لنگر عمودی روی قیمت لحظه‌ای با کمی فاصله عمودی
anchor_price = close
y_pos = na(anchor_price) ? na : anchor_price + (atr_val * hud_off_atr)

// فقط روی آخرین کندل، چند بار به «راست» می‌بریم تا نوک پنل نزدیک کندل باشد
x_pos_base = bar_index
x_pos = barstate.islast ? (x_pos_base + hud_off_bars) : x_pos_base

if not na(y_pos) and txt != ""
if na(hud)
// ⚠️ style_label_left = نوک پنل سمت چپ است ⇒ متن به راست باز می‌شود ⇒ کل پنل در «راستِ» قیمت قرار می‌گیرد
hud := label.new(x_pos, y_pos, txt,xloc=xloc.bar_index,style=label.style_label_left, 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_left)
label.set_size(hud, to_size(hud_font))
else
if not na(hud)
label.delete(hud)
hud := na
Release Notes
//version=6
indicator("پنل سود/زیان + چند تارگت (۴ ورود مستقل) - پنل چپ نزدیک قیمت + میانگین R:R + وزن خروج (v1.3.1-minFixed)", overlay=true, max_lines_count=500, max_labels_count=500)

Disclaimer

The information and publications are not meant to be, and do not constitute, financial, investment, trading, or other types of advice or recommendations supplied or endorsed by TradingView. Read more in the Terms of Use.