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

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
indicator("پنل سود/زیان + چند تارگت (۴ ورود مستقل) - پنل چپ نزدیک قیمت + میانگین R:R + وزن خروج (v1.3.1-minFixed)", overlay=true, max_lines_count=500, max_labels_count=500)
Tập lệnh chỉ hiển thị cho người được mời
Chỉ những người dùng được tác giả đồng ý mới có thể truy cập tập lệnh này. Bạn cần yêu cầu và xin phép sử dụng tập lệnh này. Quyền truy cập thường được cấp sau khi thanh toán. Để biết thêm chi tiết, hãy làm theo hướng dẫn của tác giả bên dưới hoặc liên hệ trực tiếp với hsuyvm.
TradingView KHÔNG khuyến khích trả tiền hoặc sử dụng tập lệnh trừ khi bạn hoàn toàn tin tưởng tác giả và hiểu cách hoạt động của tập lệnh. Bạn cũng có thể tìm thấy các giải pháp thay thế miễn phí, mã nguồn mở trong mục tập lệnh cộng đồng của chúng tôi.
Hướng dẫn của tác giả
Cảnh báo: vui lòng đọc hướng dẫn của chúng tôi về các tập lệnh chỉ dành cho người được mời trước khi yêu cầu quyền truy cập.
Thông báo miễn trừ trách nhiệm
Tập lệnh chỉ hiển thị cho người được mời
Chỉ những người dùng được tác giả đồng ý mới có thể truy cập tập lệnh này. Bạn cần yêu cầu và xin phép sử dụng tập lệnh này. Quyền truy cập thường được cấp sau khi thanh toán. Để biết thêm chi tiết, hãy làm theo hướng dẫn của tác giả bên dưới hoặc liên hệ trực tiếp với hsuyvm.
TradingView KHÔNG khuyến khích trả tiền hoặc sử dụng tập lệnh trừ khi bạn hoàn toàn tin tưởng tác giả và hiểu cách hoạt động của tập lệnh. Bạn cũng có thể tìm thấy các giải pháp thay thế miễn phí, mã nguồn mở trong mục tập lệnh cộng đồng của chúng tôi.
Hướng dẫn của tác giả
Cảnh báo: vui lòng đọc hướng dẫn của chúng tôi về các tập lệnh chỉ dành cho người được mời trước khi yêu cầu quyền truy cập.