beast-agent 2.49.0 → 2.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/agent/defaulttools/mt5_shot/stitch.js +32 -7
- package/src/agent/defaulttools/mt5_shot/tool.json +2 -2
- package/src/agent/mt5/BeastFinance.mq5 +18 -4
- package/src/renderer/index.html +6 -0
- package/src/renderer/renderer.js +71 -3
- package/src/renderer/style.css +35 -0
package/package.json
CHANGED
|
@@ -97,16 +97,41 @@ async function compose(panels, opts) {
|
|
|
97
97
|
if (layout === 'h') ctx.fillRect(x - GAP, 0, GAP, H);
|
|
98
98
|
else ctx.fillRect(0, y - GAP, W, GAP);
|
|
99
99
|
}
|
|
100
|
-
/* etiket:
|
|
100
|
+
/* etiket: SAĞ ÜST köşede BÜYÜK zaman dilimi (üstünde küçük sembol) —
|
|
101
|
+
görsel ajan hangi panelin hangi periyot olduğunu bakışta okur */
|
|
101
102
|
if (p.label) {
|
|
102
103
|
try {
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
104
|
+
const parts = String(p.label).split('·').map((s) => s.trim()).filter(Boolean);
|
|
105
|
+
const tf = parts.length > 1 ? parts[1] : parts[0];
|
|
106
|
+
const sym = parts.length > 1 ? parts[0] : '';
|
|
107
|
+
const fsTf = Math.max(22, Math.round(cellW / 44)); /* 1600 px panel → 36 px */
|
|
108
|
+
const fsSym = Math.max(12, Math.round(fsTf * 0.45));
|
|
109
|
+
const padX = Math.round(fsTf * 0.55);
|
|
110
|
+
const padY = Math.round(fsTf * 0.42);
|
|
111
|
+
const lineGap = Math.round(fsSym * 0.45);
|
|
108
112
|
ctx.textBaseline = 'middle';
|
|
109
|
-
ctx.
|
|
113
|
+
ctx.textAlign = 'right';
|
|
114
|
+
ctx.font = pickFont(fsTf);
|
|
115
|
+
const tw = ctx.measureText(tf).width;
|
|
116
|
+
ctx.font = pickFont(fsSym);
|
|
117
|
+
const sw = sym ? ctx.measureText(sym).width : 0;
|
|
118
|
+
const boxW = Math.ceil(Math.max(tw, sw) + padX * 2);
|
|
119
|
+
const boxH = Math.ceil(padY * 2 + fsTf + (sym ? fsSym + lineGap : 0));
|
|
120
|
+
const bx = x + cellW - boxW - 10;
|
|
121
|
+
const by = y + 10;
|
|
122
|
+
ctx.fillStyle = 'rgba(0,0,0,0.80)';
|
|
123
|
+
ctx.fillRect(bx, by, boxW, boxH);
|
|
124
|
+
ctx.fillStyle = '#00e676';
|
|
125
|
+
ctx.fillRect(bx, by, boxW, 3); /* üst aksan çizgisi */
|
|
126
|
+
if (sym) {
|
|
127
|
+
ctx.font = pickFont(fsSym);
|
|
128
|
+
ctx.fillStyle = '#c9d2d9';
|
|
129
|
+
ctx.fillText(sym, bx + boxW - padX, by + padY + fsSym / 2);
|
|
130
|
+
}
|
|
131
|
+
ctx.font = pickFont(fsTf);
|
|
132
|
+
ctx.fillStyle = '#00e676';
|
|
133
|
+
ctx.fillText(tf, bx + boxW - padX, by + padY + (sym ? fsSym + lineGap : 0) + fsTf / 2);
|
|
134
|
+
ctx.textAlign = 'start';
|
|
110
135
|
} catch (e) {}
|
|
111
136
|
}
|
|
112
137
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mt5_shot",
|
|
3
|
-
"defaultsVersion":
|
|
4
|
-
"description": "MT5 grafiğinin GERÇEK ekran görüntüsünü alır ve GÖRSELİ ÇAĞIRAN AJANA GÖSTERİR: MT5\\MQL5\\Files\\beast_cmd.json üzerinden BeastFinance EA'ya 'shot' komutu yazar, EA ChartScreenShot ile PNG üretir; PNG hem tool klasörüne hem <kullanıcı>\\beast_shots altına kopyalanır (dönen path send_file'a verilebilir) hem de data URL olarak sonuca gömülür — engine bunu sonraki turda ajana görsel olarak enjekte eder (embed:false kapatır). ÇOKLU ZAMAN DİLİMİ: timeframes:[\"M1\",\"M15\"] verirsen aynı sembolün periyotları SIRAYLA çekilip TEK PNG'de birleştirilir (layout:\"h\" soldan sağa — varsayılan; \"v\" üstten alta; 2-3 periyot) ve her panelin
|
|
3
|
+
"defaultsVersion": 3,
|
|
4
|
+
"description": "MT5 grafiğinin GERÇEK ekran görüntüsünü alır ve GÖRSELİ ÇAĞIRAN AJANA GÖSTERİR: MT5\\MQL5\\Files\\beast_cmd.json üzerinden BeastFinance EA'ya 'shot' komutu yazar, EA ChartScreenShot ile PNG üretir; PNG hem tool klasörüne hem <kullanıcı>\\beast_shots altına kopyalanır (dönen path send_file'a verilebilir) hem de data URL olarak sonuca gömülür — engine bunu sonraki turda ajana görsel olarak enjekte eder (embed:false kapatır). ÇOKLU ZAMAN DİLİMİ: timeframes:[\"M1\",\"M15\"] verirsen aynı sembolün periyotları SIRAYLA çekilip TEK PNG'de birleştirilir (layout:\"h\" soldan sağa — varsayılan; \"v\" üstten alta; 2-3 periyot) ve her panelin SAĞ ÜST köşesine BÜYÜK periyot etiketi (üstünde küçük sembol) çizilir — solda/sağda hangi periyot olduğu görüntüden bakışta okunur. Aktif grafik istenen sembol/periyot ile aynıysa ondan çekilir (Beast panosu + seviye çizgileri görünür), değilse EA geçici grafik açar (ChartOpen/ChartSetSymbolPeriod + BeastShot.tpl açık tema). Çekim öncesi grafiğe sağ boşluk payı (chart shift %12) uygulanır — SON MUM sağ kenara yapışmaz; aktif grafikte önceki ayar çekimden sonra geri yazılır. Komut id/ts ile yazılır, ack poll edilir ve PNG MQL5\\Files'ta belirene kadar beklenir; hata halinde gövde şu kodu taşır: err = no_terminal|ea_offline|cmd_write_fail|ea_no_ack|ea_error|png_yok|timeout|stitch_fail (+ cmdId, filesDir, diagnostic, ping). Grafik analizi/raporu ve ekip paylaşımı için birincil screenshot aracıdır.",
|
|
5
5
|
"parameters": {
|
|
6
6
|
"type": "object",
|
|
7
7
|
"properties": {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
//+------------------------------------------------------------------+
|
|
2
|
-
//| BeastFinance.mq5 — Beast Finance köprü EA'sı (v1.
|
|
2
|
+
//| BeastFinance.mq5 — Beast Finance köprü EA'sı (v1.21) |
|
|
3
3
|
//| - Heartbeat: MQL5\Files\beast_ea.json (durum + izinler + equity) |
|
|
4
4
|
//| - Komut köprüsü: beast_cmd.json (Beast yazar) → beast_cmd_ack.json|
|
|
5
5
|
//| - Entegrasyon/Screenshot: grafik üstü pano (Comment) + seviye |
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
//+------------------------------------------------------------------+
|
|
9
9
|
#property copyright "Beast Agent"
|
|
10
10
|
#property link "https://github.com/algokodcom/beast-agent"
|
|
11
|
-
#property version "1.
|
|
11
|
+
#property version "1.21"
|
|
12
12
|
#property description "Beast Finance köprü EA'sı — heartbeat + komut köprüsü + grafik panosu."
|
|
13
13
|
|
|
14
14
|
#include <Trade\Trade.mqh>
|
|
@@ -72,7 +72,7 @@ void WriteBeat(const string stage)
|
|
|
72
72
|
{
|
|
73
73
|
int h = FileOpen(BeatFile, FILE_WRITE|FILE_TXT|FILE_UNICODE);
|
|
74
74
|
if(h == INVALID_HANDLE) return;
|
|
75
|
-
string js = StringFormat("{\"ok\":true,\"ea\":\"BeastFinance\",\"version\":\"1.
|
|
75
|
+
string js = StringFormat("{\"ok\":true,\"ea\":\"BeastFinance\",\"version\":\"1.21\",\"tag\":\"%s\",\"stage\":\"%s\",\"time\":%d,\"server_time\":\"%s\",\"symbol\":\"%s\",\"period\":%d,\"equity\":%.2f,\"balance\":%.2f,\"terminal_trade_allowed\":%s,\"mql_trade_allowed\":%s,\"positions\":%d,\"note\":\"%s\"}",
|
|
76
76
|
JStr(InpTag), stage, (int)TimeCurrent(), TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS),
|
|
77
77
|
_Symbol, (int)Period(),
|
|
78
78
|
AccountInfoDouble(ACCOUNT_EQUITY), AccountInfoDouble(ACCOUNT_BALANCE),
|
|
@@ -93,7 +93,7 @@ void RefreshPanel()
|
|
|
93
93
|
Comment("");
|
|
94
94
|
return;
|
|
95
95
|
}
|
|
96
|
-
string lines = "Beast Finance — BeastFinance v1.
|
|
96
|
+
string lines = "Beast Finance — BeastFinance v1.21\n";
|
|
97
97
|
lines += _Symbol + " · " + EnumToString((ENUM_TIMEFRAMES)Period()) + " · " + TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS) + "\n";
|
|
98
98
|
lines += StringFormat("Equity: %.2f · Balance: %.2f · Acik pozisyon: %d\n",
|
|
99
99
|
AccountInfoDouble(ACCOUNT_EQUITY), AccountInfoDouble(ACCOUNT_BALANCE), PositionsTotal());
|
|
@@ -351,8 +351,16 @@ void ProcessCommands()
|
|
|
351
351
|
}
|
|
352
352
|
}
|
|
353
353
|
|
|
354
|
+
/* SON MUM SAĞ KENARA YAPIŞMASIN: grafik "shift" payı (%12 sağ boşluk).
|
|
355
|
+
Aktif grafikte önceki ayar çekimden SONRA geri yazılır — kullanıcının
|
|
356
|
+
grafiği kalıcı değişmez; geçici grafik zaten kapanır. */
|
|
357
|
+
long shiftPrev = ChartGetInteger(cid, CHART_SHIFT);
|
|
358
|
+
long shiftSizePrev = ChartGetInteger(cid, CHART_SHIFT_SIZE);
|
|
359
|
+
|
|
354
360
|
if(ok)
|
|
355
361
|
{
|
|
362
|
+
ChartSetInteger(cid, CHART_SHIFT, true);
|
|
363
|
+
ChartSetInteger(cid, CHART_SHIFT_SIZE, 12);
|
|
356
364
|
ChartRedraw(cid);
|
|
357
365
|
Sleep(1200); /* mumlar/olcek otursun */
|
|
358
366
|
ChartRedraw(cid);
|
|
@@ -367,6 +375,12 @@ void ProcessCommands()
|
|
|
367
375
|
result = StringFormat("{\"file\":\"%s\",\"width\":%d,\"height\":%d,\"symbol\":\"%s\",\"period\":%d,\"temp_chart\":%s,\"template_applied\":%s,\"theme_ok\":%s,\"bg\":%d}",
|
|
368
376
|
JStr(file), w, hh, symWant, (int)tfUse, (tempChart ? "true" : "false"), (tplApplied ? "true" : "false"), (themeOk ? "true" : "false"), bgNow);
|
|
369
377
|
}
|
|
378
|
+
if(!tempChart)
|
|
379
|
+
{
|
|
380
|
+
ChartSetInteger(cid, CHART_SHIFT, shiftPrev != 0);
|
|
381
|
+
ChartSetInteger(cid, CHART_SHIFT_SIZE, shiftSizePrev);
|
|
382
|
+
ChartRedraw(cid);
|
|
383
|
+
}
|
|
370
384
|
}
|
|
371
385
|
if(tempChart) ChartClose(cid);
|
|
372
386
|
}
|
package/src/renderer/index.html
CHANGED
|
@@ -549,6 +549,12 @@
|
|
|
549
549
|
</div>
|
|
550
550
|
</div>
|
|
551
551
|
|
|
552
|
+
<!-- DM görselleri: tıkla → tam boy görüntüleyici (Esc / tıkla kapat) -->
|
|
553
|
+
<div id="imgOverlay" hidden>
|
|
554
|
+
<img id="imgOverlayImg" alt="görsel" />
|
|
555
|
+
<button id="imgOverlayClose" title="Kapat (Esc)">✕︎</button>
|
|
556
|
+
</div>
|
|
557
|
+
|
|
552
558
|
<div id="toolOverlay" hidden>
|
|
553
559
|
<div id="toolDialog">
|
|
554
560
|
<div id="toolDialogHead">
|
package/src/renderer/renderer.js
CHANGED
|
@@ -53,6 +53,9 @@ const els = {
|
|
|
53
53
|
dmColumnBtn: $('#dmColumnBtn'),
|
|
54
54
|
dmMaxBtn: $('#dmMaxBtn'),
|
|
55
55
|
dmBackBtn: $('#dmBackBtn'),
|
|
56
|
+
imgOverlay: $('#imgOverlay'),
|
|
57
|
+
imgOverlayImg: $('#imgOverlayImg'),
|
|
58
|
+
imgOverlayClose: $('#imgOverlayClose'),
|
|
56
59
|
watchBtn: $('#watchBtn'),
|
|
57
60
|
watchPaneList: $('#watchPaneList'),
|
|
58
61
|
watchPaneOpen: $('#watchPaneOpen'),
|
|
@@ -5549,6 +5552,30 @@ function toggleDmRail(hide) {
|
|
|
5549
5552
|
|
|
5550
5553
|
/* --- modal: SOHBET (yalnız burada tam döküm) --- */
|
|
5551
5554
|
|
|
5555
|
+
/* Yeni mesaj / geç decode olan görsellerde sohbeti otomatik en alta indir:
|
|
5556
|
+
anında + rAF + kısa gecikmeler + görsel load olayları (görsel sonradan
|
|
5557
|
+
yüklenince içerik uzar; tek seferlik scroll yetmez). */
|
|
5558
|
+
function dmStickBottom(box) {
|
|
5559
|
+
if (!box) return;
|
|
5560
|
+
const toBottom = () => {
|
|
5561
|
+
try {
|
|
5562
|
+
box.scrollTop = box.scrollHeight;
|
|
5563
|
+
const p = box.parentElement;
|
|
5564
|
+
if (p && p.scrollHeight > p.clientHeight) p.scrollTop = p.scrollHeight;
|
|
5565
|
+
} catch {}
|
|
5566
|
+
};
|
|
5567
|
+
toBottom();
|
|
5568
|
+
try { requestAnimationFrame(toBottom); } catch {}
|
|
5569
|
+
setTimeout(toBottom, 60);
|
|
5570
|
+
setTimeout(toBottom, 300);
|
|
5571
|
+
for (const img of box.querySelectorAll('img.dmt-img')) {
|
|
5572
|
+
if (img.dataset.dmStick) continue;
|
|
5573
|
+
img.dataset.dmStick = '1';
|
|
5574
|
+
img.addEventListener('load', toBottom, { once: true });
|
|
5575
|
+
img.addEventListener('error', toBottom, { once: true });
|
|
5576
|
+
}
|
|
5577
|
+
}
|
|
5578
|
+
|
|
5552
5579
|
function renderDmModal() {
|
|
5553
5580
|
const list = els.dmDialogList;
|
|
5554
5581
|
if (!list) return;
|
|
@@ -5570,8 +5597,7 @@ function renderDmModal() {
|
|
|
5570
5597
|
if (els.dmBackBtn) els.dmBackBtn.hidden = false;
|
|
5571
5598
|
if (els.dmModalDel) els.dmModalDel.hidden = false;
|
|
5572
5599
|
list.innerHTML = '<div class="dm-thread-msgs">' + msgs.map(dmMsgHtml).join('') + '</div>';
|
|
5573
|
-
|
|
5574
|
-
if (box) box.scrollTop = box.scrollHeight;
|
|
5600
|
+
dmStickBottom(list.querySelector('.dm-thread-msgs'));
|
|
5575
5601
|
return;
|
|
5576
5602
|
}
|
|
5577
5603
|
/* OTURUM LİSTESİ — AKTİF + GEÇMİŞ bölümleri */
|
|
@@ -5665,7 +5691,8 @@ if (els.dmOverlay) {
|
|
|
5665
5691
|
els.dmOverlay.addEventListener('keydown', (e) => {
|
|
5666
5692
|
if (e.key === 'Escape') {
|
|
5667
5693
|
e.stopPropagation();
|
|
5668
|
-
if (els.
|
|
5694
|
+
if (els.imgOverlay && !els.imgOverlay.hidden) closeImgViewer(); /* önce görüntüleyici kapansın */
|
|
5695
|
+
else if (els.dmOverlay.classList.contains('dm-max')) toggleDmMax(false);
|
|
5669
5696
|
else closeDmModal();
|
|
5670
5697
|
}
|
|
5671
5698
|
});
|
|
@@ -5679,6 +5706,47 @@ if (els.dmColumnBtn) {
|
|
|
5679
5706
|
});
|
|
5680
5707
|
}
|
|
5681
5708
|
|
|
5709
|
+
/* --- DM görsel görüntüleyici: görsele tıkla → TAM BOY (tıkla/Esc kapat) --- */
|
|
5710
|
+
function openImgViewer(src) {
|
|
5711
|
+
if (!els.imgOverlay || !els.imgOverlayImg || !src) return;
|
|
5712
|
+
els.imgOverlayImg.src = String(src);
|
|
5713
|
+
els.imgOverlay.hidden = false;
|
|
5714
|
+
}
|
|
5715
|
+
|
|
5716
|
+
function closeImgViewer() {
|
|
5717
|
+
if (els.imgOverlay) els.imgOverlay.hidden = true;
|
|
5718
|
+
if (els.imgOverlayImg) els.imgOverlayImg.src = '';
|
|
5719
|
+
}
|
|
5720
|
+
|
|
5721
|
+
if (els.imgOverlay) {
|
|
5722
|
+
els.imgOverlay.addEventListener('click', () => closeImgViewer());
|
|
5723
|
+
}
|
|
5724
|
+
if (els.imgOverlayClose) {
|
|
5725
|
+
els.imgOverlayClose.addEventListener('click', (e) => {
|
|
5726
|
+
e.stopPropagation();
|
|
5727
|
+
closeImgViewer();
|
|
5728
|
+
});
|
|
5729
|
+
}
|
|
5730
|
+
if (els.dmDialogList) {
|
|
5731
|
+
/* delegasyon: modal her mesajda yeniden çizilir — dinleyici tek yerde kalır */
|
|
5732
|
+
els.dmDialogList.addEventListener('click', (e) => {
|
|
5733
|
+
const img = e.target && e.target.closest ? e.target.closest('img.dmt-img') : null;
|
|
5734
|
+
if (!img || !img.src) return;
|
|
5735
|
+
e.stopPropagation();
|
|
5736
|
+
openImgViewer(img.src);
|
|
5737
|
+
});
|
|
5738
|
+
}
|
|
5739
|
+
document.addEventListener(
|
|
5740
|
+
'keydown',
|
|
5741
|
+
(e) => {
|
|
5742
|
+
if (e.key !== 'Escape' || !els.imgOverlay || els.imgOverlay.hidden) return;
|
|
5743
|
+
e.preventDefault();
|
|
5744
|
+
e.stopPropagation();
|
|
5745
|
+
closeImgViewer();
|
|
5746
|
+
},
|
|
5747
|
+
true
|
|
5748
|
+
);
|
|
5749
|
+
|
|
5682
5750
|
/* ---------------- TOOLS konsolu (kişisel araçlar) ----------------
|
|
5683
5751
|
%APPDATA%\beast\tools\<ad>\tool.json + run.js — kullanıcı kendi araçlarını
|
|
5684
5752
|
yazar; finance dahil TÜM oturumlar tool__<ad> olarak çağırır. Sol panelde
|
package/src/renderer/style.css
CHANGED
|
@@ -2331,6 +2331,7 @@ body.browser-open #settingsDialog { width: min(70vw, calc(100vw - var(--bw, 480p
|
|
|
2331
2331
|
border-radius: 6px;
|
|
2332
2332
|
margin-top: 5px;
|
|
2333
2333
|
border: 1px solid var(--border, rgba(255,255,255,0.12));
|
|
2334
|
+
cursor: zoom-in;
|
|
2334
2335
|
}
|
|
2335
2336
|
.dmt-msg .dmt-img-note {
|
|
2336
2337
|
font-size: 10px;
|
|
@@ -2338,6 +2339,40 @@ body.browser-open #settingsDialog { width: min(70vw, calc(100vw - var(--bw, 480p
|
|
|
2338
2339
|
font-style: italic;
|
|
2339
2340
|
margin-top: 3px;
|
|
2340
2341
|
}
|
|
2342
|
+
/* DM görsel görüntüleyici: tam boy, tıkla/Esc ile kapanır */
|
|
2343
|
+
#imgOverlay {
|
|
2344
|
+
position: fixed;
|
|
2345
|
+
inset: 0;
|
|
2346
|
+
z-index: 400;
|
|
2347
|
+
background: rgba(0, 0, 0, 0.88);
|
|
2348
|
+
display: flex;
|
|
2349
|
+
align-items: center;
|
|
2350
|
+
justify-content: center;
|
|
2351
|
+
cursor: zoom-out;
|
|
2352
|
+
}
|
|
2353
|
+
#imgOverlay[hidden] { display: none; }
|
|
2354
|
+
#imgOverlay img {
|
|
2355
|
+
max-width: 96vw;
|
|
2356
|
+
max-height: 94vh;
|
|
2357
|
+
object-fit: contain;
|
|
2358
|
+
border-radius: 6px;
|
|
2359
|
+
box-shadow: 0 9px 40px rgba(0, 0, 0, 0.55);
|
|
2360
|
+
background: #0b0b0b;
|
|
2361
|
+
}
|
|
2362
|
+
#imgOverlayClose {
|
|
2363
|
+
position: absolute;
|
|
2364
|
+
top: 14px;
|
|
2365
|
+
right: 18px;
|
|
2366
|
+
width: 34px;
|
|
2367
|
+
height: 34px;
|
|
2368
|
+
border: none;
|
|
2369
|
+
border-radius: 8px;
|
|
2370
|
+
background: rgba(255, 255, 255, 0.12);
|
|
2371
|
+
color: #fff;
|
|
2372
|
+
font-size: 17px;
|
|
2373
|
+
cursor: pointer;
|
|
2374
|
+
}
|
|
2375
|
+
#imgOverlayClose:hover { background: rgba(255, 255, 255, 0.26); }
|
|
2341
2376
|
/* ajan adının yanındaki KOD rozeti (oturum id) */
|
|
2342
2377
|
.dm-code {
|
|
2343
2378
|
font-size: 9px; font-weight: 700; letter-spacing: 0.5px;
|