beast-agent 2.24.5 → 2.30.1
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/engine.js +69 -13
- package/src/main.js +28 -3
- package/src/preload.js +1 -0
- package/src/renderer/index.html +6 -2
- package/src/renderer/renderer.js +55 -0
- package/src/renderer/style.css +25 -3
package/package.json
CHANGED
package/src/agent/engine.js
CHANGED
|
@@ -1894,6 +1894,10 @@ class Engine {
|
|
|
1894
1894
|
macro:
|
|
1895
1895
|
'ROL: MAKRO AJANI 🌍 — büyük resim uzmanısın, İşlem AÇMAZSIN (mt5_trade/mt5_pending/mt5_close KULLANMA). Her turda web_search ile güncel makro manşetleri + ekonomik takvim riskleri (faiz, CPI, jeopolitik); DXY/altın/petrol bağıntılarını odak sembollere çevir; sembol başına yön eğilimi + TEMKİN/BEKLE notu ver.',
|
|
1896
1896
|
})[String((session && session.financeRole) || '')] || '';
|
|
1897
|
+
/* FİNANS EKİBİ: tüm finance ajanları tek DM grubundadır — sohbet grup
|
|
1898
|
+
thread'inde toplanır (ayrı ayrı 1:1 thread'lere dağılmaz) */
|
|
1899
|
+
const finJob = this._bgJobs && this._bgJobs.get(String(session && session.id));
|
|
1900
|
+
const teamLine = finJob && finJob.teamGid ? this._agentTeamPromptLine(finJob.teamGid) : '';
|
|
1897
1901
|
return (
|
|
1898
1902
|
(mem.soul ? mem.soul.trim() + '\n\n' : '') +
|
|
1899
1903
|
'Sen BEAST FİNANS\u2019sın — bilgisayardaki MetaTrader 5 (MT5) terminaline köprüyle bağlı trading ajanı.\n' +
|
|
@@ -1902,6 +1906,7 @@ class Engine {
|
|
|
1902
1906
|
'GÖREV ALANI: piyasa verisi okuma (fiyat/hesap/pozisyon/geçmiş), teknik değerlendirme, pozisyon yönetimi (aç/kapat/SL/TP), risk disiplini ve kısa karar raporları. Kod yazma işi DEĞİLDİR.\n' +
|
|
1903
1907
|
modeBlock2 + '\n' +
|
|
1904
1908
|
(roleBlock ? roleBlock + '\n' : '') +
|
|
1909
|
+
(teamLine || '') +
|
|
1905
1910
|
'MT5 ARAÇLARI: mt5_status (bağlantı), mt5_account (hesap), mt5_market (canlı fiyat), mt5_positions (açık pozisyonlar), mt5_orders (bekleyen emirler), mt5_history (kapanan işlemler), mt5_trade (piyasa emri), mt5_close (kapat), mt5_modify (SL/TP), mt5_pending (bekleyen emir), mt5_cancel (emir iptal).\n' +
|
|
1906
1911
|
'VERİ AKIŞI (her değerlendirmede): mt5_account + mt5_positions + mt5_market çağrılarını AYNI turda PARALEL ver; gerekiyorsa mt5_history ile son işlemleri gör.\n' +
|
|
1907
1912
|
'PARALEL + KOORDİNASYON: uzun araştırma/işleri run_background ile paralel finance işçisine devret (parent finance olduğu için işçi mt5 okuma araçlarını görür); koşan ajanlarla konuşmak için agent_dm (to: ajan başlığındaki anahtar kelime, örn "GOLD"; ortak karar için group: "İSİM" ile grup sohbeti kur — mesaj tüm üyelere düşer). Görevin bitince DM/grup sohbetleri otomatik KAPANIR (geçmiş panelde kalır).\n' +
|
|
@@ -2489,7 +2494,6 @@ class Engine {
|
|
|
2489
2494
|
korunur — sadece içerik temizlenir, önek cache bozulmaz. Döndürür: kazanılan token */
|
|
2490
2495
|
_pruneSession(session) {
|
|
2491
2496
|
try {
|
|
2492
|
-
if (this.ctrls.has(session.id)) return 0;
|
|
2493
2497
|
const msgs = session.messages;
|
|
2494
2498
|
let total = 0, pruned = 0, turns = 0;
|
|
2495
2499
|
const targets = [];
|
|
@@ -2580,7 +2584,10 @@ class Engine {
|
|
|
2580
2584
|
`- kullanıcının hedefleri ve net talepleri\n` +
|
|
2581
2585
|
`- alınan kararlar, önemli bilgi parçaları (isim, sayı, dosya/klasör yolu, hata ve çözümü)\n` +
|
|
2582
2586
|
`- tamamlanan işler ve sonuçları\n` +
|
|
2583
|
-
|
|
2587
|
+
(session.finance
|
|
2588
|
+
? `- FİNANS İŞLEMLERİ (KRİTİK, atlama): açılan/kapatılan/güncellenen pozisyonlar — sembol, yön (AL/SAT), lot, giriş/SL/TP, kâr/zarar ve gerekçe; sonraki turlarda birebir hatırlanmalı\n`
|
|
2589
|
+
: '') +
|
|
2590
|
+
`Madde madde yaz, en fazla ${session.finance ? 180 : 120} kelime, başlık/selamlama yok. Alakasız ayrıntıyı at.\n\n` +
|
|
2584
2591
|
`# SOHBET PARÇASI\n${transcript}`;
|
|
2585
2592
|
const res = await chatOnce(
|
|
2586
2593
|
this.sel,
|
|
@@ -2682,6 +2689,25 @@ class Engine {
|
|
|
2682
2689
|
}
|
|
2683
2690
|
}
|
|
2684
2691
|
|
|
2692
|
+
/* SÜREKLİ ajan DM INBOX (bkz. flushPendingReports): tur aralığında biriken
|
|
2693
|
+
DM'ler yeni tur AÇMAZ; sıradaki planlı turun mesajına tek blok olarak
|
|
2694
|
+
eklenir — ajan-ajan sonsuz DM ping-pong'u ve bağlam şişmesi engellenir. */
|
|
2695
|
+
try {
|
|
2696
|
+
const jobRec = this._bgJobs && this._bgJobs.get(String(sessionId));
|
|
2697
|
+
if (jobRec && Array.isArray(jobRec.dmInbox) && jobRec.dmInbox.length) {
|
|
2698
|
+
const inbox = jobRec.dmInbox.splice(0);
|
|
2699
|
+
const boxText = inbox.join('\n\n').slice(0, 6000);
|
|
2700
|
+
const prefix =
|
|
2701
|
+
`[BEKLEYEN AJAN DM'LERİ — ${inbox.length} mesaj]\n${boxText}\n` +
|
|
2702
|
+
`(Tur aralığında biriken DM'ler. Bu turda değerlendir; yalnızca aksiyon/cevap GEREKİYORSA agent_dm ile TEK kısa cevap ver — teşekkür/onay/ack mesajı YAZMA.)\n\n`;
|
|
2703
|
+
if (typeof msg.content === 'string') {
|
|
2704
|
+
msg.content = prefix + msg.content;
|
|
2705
|
+
} else if (Array.isArray(msg.content) && msg.content[0] && typeof msg.content[0].text === 'string') {
|
|
2706
|
+
msg.content[0] = { ...msg.content[0], text: prefix + msg.content[0].text };
|
|
2707
|
+
}
|
|
2708
|
+
}
|
|
2709
|
+
} catch {}
|
|
2710
|
+
|
|
2685
2711
|
if (!String(typeof msg.content === 'string' ? msg.content : msg.content[0].text || '').trim()) return false;
|
|
2686
2712
|
/* #12 kişilik kalibrasyonu: kullanıcı cümlelerini örnek havuzuna düşür (Beast Code hariç — hız) */
|
|
2687
2713
|
if (!s.bcCode) {
|
|
@@ -3509,10 +3535,22 @@ class Engine {
|
|
|
3509
3535
|
this._pendingReports = [];
|
|
3510
3536
|
return;
|
|
3511
3537
|
}
|
|
3538
|
+
const job = this._bgJobs && this._bgJobs.get(String(sessionId));
|
|
3539
|
+
/* SÜREKLİ ajan (Beast Finance): DM/rapor teslimi YENİ TUR AÇMAZ — aksi
|
|
3540
|
+
halde ajanlar birbirine DM attıkça sonsuz tur döngüsü doğar (bağlam
|
|
3541
|
+
şişer, ajan hiç dinlenmez). Mesaj inbox'a yazılır; bir sonraki PLANLI
|
|
3542
|
+
turda send() tarafından tek blok halinde enjekte edilir. */
|
|
3543
|
+
const continuous = !!(job && job.continuous);
|
|
3512
3544
|
const rest = [];
|
|
3513
3545
|
for (const r of this._pendingReports) {
|
|
3514
3546
|
if (r.parentId !== sessionId) { rest.push(r); continue; }
|
|
3515
3547
|
if (this._deletedSessions && this._deletedSessions.has(sessionId)) continue;
|
|
3548
|
+
if (continuous) {
|
|
3549
|
+
job.dmInbox = job.dmInbox || [];
|
|
3550
|
+
job.dmInbox.push(String(r.text || '').slice(0, 4000));
|
|
3551
|
+
if (job.dmInbox.length > 20) job.dmInbox.splice(0, job.dmInbox.length - 20);
|
|
3552
|
+
continue;
|
|
3553
|
+
}
|
|
3516
3554
|
if (this.isBusy(sessionId)) { rest.push(r); continue; }
|
|
3517
3555
|
let sent = false;
|
|
3518
3556
|
try { sent = !!this.send(sessionId, { text: r.text }); } catch {}
|
|
@@ -3553,8 +3591,10 @@ class Engine {
|
|
|
3553
3591
|
_bgTrim(session) {
|
|
3554
3592
|
const max = Engine.BG_KEEP_MSGS;
|
|
3555
3593
|
const msgs = session.messages;
|
|
3556
|
-
/* bg işleri + Beast Code
|
|
3557
|
-
|
|
3594
|
+
/* bg işleri + Beast Code + SÜREKLİ finance ajanları: uzun geçmiş payload'ı
|
|
3595
|
+
şişirip yavaşlatır — finance ajanları binlerce tur döndüğü için bağlam
|
|
3596
|
+
tavanı onlara da şart */
|
|
3597
|
+
if ((!session.bgJob && !session.bcCode && !session.finance) || msgs.length <= max) return;
|
|
3558
3598
|
let keep = msgs.slice(-max);
|
|
3559
3599
|
/* GÜVENLİ SINIR: kesim bir assistant(tool_calls) + tool sonuç çiftini BÖLMESİN.
|
|
3560
3600
|
Yetim 'tool' mesajı ya da sonuçları pencere dışında kalan tool_calls'lı
|
|
@@ -6389,7 +6429,7 @@ Engine.prototype._agentDmSend = function (fromSid, args) {
|
|
|
6389
6429
|
parentId: m,
|
|
6390
6430
|
text:
|
|
6391
6431
|
`[AJAN DM (grup: "${g.title}") — ${dm.fromTitle} · konu: "${topic}"]\n${text}\n` +
|
|
6392
|
-
`(
|
|
6432
|
+
`(Cevap yalnızca aksiyon/karar GEREKİYORSA ver — agent_dm group: "${g.title}", to: "${dm.fromTitle}", topic: "${topic}"; teşekkür/onay yazma.)`,
|
|
6393
6433
|
});
|
|
6394
6434
|
this.flushPendingReports(m);
|
|
6395
6435
|
}
|
|
@@ -6414,7 +6454,7 @@ Engine.prototype._agentDmSend = function (fromSid, args) {
|
|
|
6414
6454
|
parentId: target,
|
|
6415
6455
|
text:
|
|
6416
6456
|
`[AJAN DM — ${dm.fromTitle} · konu: "${topic}"]\n${text}\n` +
|
|
6417
|
-
`(
|
|
6457
|
+
`(Cevap yalnızca aksiyon/karar GEREKİYORSA ver — agent_dm to: "${dm.fromTitle}", topic: "${topic}"; teşekkür/onay yazma.)`,
|
|
6418
6458
|
});
|
|
6419
6459
|
this.flushPendingReports(target);
|
|
6420
6460
|
}
|
|
@@ -6448,18 +6488,30 @@ Engine.prototype._pushAgentDm = function (dm) {
|
|
|
6448
6488
|
ortak DM grubuna girer — tartışma ZORUNLU (sistem promptuyla). ---------- */
|
|
6449
6489
|
|
|
6450
6490
|
/* İş başlarken çağrılır: aynı parent / bg-gruptan başka ajan varsa (varsa
|
|
6451
|
-
önceden kurulmuştur) hepsini TEK ekip grubuna katar + katılım postu düşer.
|
|
6491
|
+
önceden kurulmuştur) hepsini TEK ekip grubuna katar + katılım postu düşer.
|
|
6492
|
+
dmGroupId verilirse (finans ekibi gibi hazır grup) parent şartı aranmaz —
|
|
6493
|
+
aynı dmGroupId'li TÜM ajanlar tek gruba toplanır. */
|
|
6452
6494
|
Engine.prototype._agentTeamJoin = function (job) {
|
|
6453
6495
|
try {
|
|
6454
6496
|
if (!job || !job.id) return;
|
|
6455
6497
|
const parent = String(job.parentId || '');
|
|
6456
|
-
|
|
6457
|
-
|
|
6498
|
+
const explicit = String(job.dmGroupId || '');
|
|
6499
|
+
if (!parent && !explicit) return;
|
|
6500
|
+
const gid = explicit || 'team:' + (job.groupId || parent);
|
|
6458
6501
|
const base =
|
|
6459
|
-
String(job.task || job.title || 'ortak görev').replace(/\s+/g, ' ').trim().slice(0,
|
|
6502
|
+
String(job.dmGroupTitle || job.task || job.title || 'ortak görev').replace(/\s+/g, ' ').trim().slice(0, 40) ||
|
|
6503
|
+
'ortak görev';
|
|
6460
6504
|
let g = this._agentGroups.get(gid);
|
|
6461
6505
|
if (!g) {
|
|
6462
|
-
g = {
|
|
6506
|
+
g = {
|
|
6507
|
+
id: gid,
|
|
6508
|
+
title: job.dmGroupTitle ? base : base + ' EKİP',
|
|
6509
|
+
members: [],
|
|
6510
|
+
titles: {},
|
|
6511
|
+
createdAt: nowIso(),
|
|
6512
|
+
closed: false,
|
|
6513
|
+
team: true,
|
|
6514
|
+
};
|
|
6463
6515
|
this._agentGroups.set(gid, g);
|
|
6464
6516
|
}
|
|
6465
6517
|
g.closed = false;
|
|
@@ -6470,9 +6522,13 @@ Engine.prototype._agentTeamJoin = function (job) {
|
|
|
6470
6522
|
if (!g.members.includes(id)) g.members.push(id);
|
|
6471
6523
|
if (title) g.titles[id] = String(title);
|
|
6472
6524
|
};
|
|
6473
|
-
/* aynı ortak görevdeki DİĞER ajanlar (aborted
|
|
6525
|
+
/* aynı ortak görevdeki / aynı hazır gruptaki DİĞER ajanlar (aborted hariç) */
|
|
6474
6526
|
const mates = [...this._bgJobs.values()].filter(
|
|
6475
|
-
(j) =>
|
|
6527
|
+
(j) =>
|
|
6528
|
+
j &&
|
|
6529
|
+
String(j.id) !== String(job.id) &&
|
|
6530
|
+
j.status !== 'aborted' &&
|
|
6531
|
+
(explicit ? String(j.dmGroupId || '') === explicit : String(j.parentId) === parent)
|
|
6476
6532
|
);
|
|
6477
6533
|
add(job.id, job.title);
|
|
6478
6534
|
for (const m of mates) add(m.id, m.title);
|
package/src/main.js
CHANGED
|
@@ -8519,7 +8519,7 @@ function finAgentRegisterBg(s, symbols) {
|
|
|
8519
8519
|
const f = finCfg();
|
|
8520
8520
|
const symLabel = symbols && symbols.length ? symbols.join(', ').slice(0, 40) : 'tüm izleme listesi';
|
|
8521
8521
|
const roleDef = finRoleDef(s.financeRole);
|
|
8522
|
-
|
|
8522
|
+
const job = {
|
|
8523
8523
|
id: s.id,
|
|
8524
8524
|
code: s.code,
|
|
8525
8525
|
title: s.bgTitle || 'Finance Ajanı',
|
|
@@ -8529,6 +8529,10 @@ function finAgentRegisterBg(s, symbols) {
|
|
|
8529
8529
|
agent: null,
|
|
8530
8530
|
parentId: '',
|
|
8531
8531
|
groupId: null,
|
|
8532
|
+
/* FİNANS EKİBİ DM GRUBU: trader + analiz ekibi + sembol işçileri TEK
|
|
8533
|
+
gruba girer — mesajlar ayrı ayrı 1:1 thread'lere dağılmaz */
|
|
8534
|
+
dmGroupId: 'team:finance',
|
|
8535
|
+
dmGroupTitle: 'Beast Finance EKİP',
|
|
8532
8536
|
status: 'running',
|
|
8533
8537
|
slot: false, /* eşzamanlılık slotu TÜKETMEZ — ana işleri bloklamaz */
|
|
8534
8538
|
continuous: true, /* tur sonları işi KAPATMAZ (_bgFinish) */
|
|
@@ -8539,8 +8543,12 @@ function finAgentRegisterBg(s, symbols) {
|
|
|
8539
8543
|
fixes: 0,
|
|
8540
8544
|
endedAt: null,
|
|
8541
8545
|
error: null,
|
|
8542
|
-
}
|
|
8546
|
+
};
|
|
8547
|
+
engine._bgJobs.set(String(s.id), job);
|
|
8543
8548
|
engine._bgEmit();
|
|
8549
|
+
/* otomatik ekip grubuna katıl: grup thread'i ilk ajanla kurulur,
|
|
8550
|
+
sonraki her finance ajanı aynı gruba eklenir (katılım postu düşer) */
|
|
8551
|
+
engine._agentTeamJoin(job);
|
|
8544
8552
|
} catch {}
|
|
8545
8553
|
}
|
|
8546
8554
|
|
|
@@ -8758,15 +8766,18 @@ ipcMain.handle('finance:snapshot', async () => {
|
|
|
8758
8766
|
const st = financeEnsureBridge();
|
|
8759
8767
|
let account = st.account || null;
|
|
8760
8768
|
let positions = [];
|
|
8769
|
+
let orders = [];
|
|
8761
8770
|
let symbols = [];
|
|
8762
8771
|
if (st.running) {
|
|
8763
|
-
const [a, p, sy] = await Promise.all([
|
|
8772
|
+
const [a, p, o, sy] = await Promise.all([
|
|
8764
8773
|
mt5bridge.call('account', {}, 8000).catch(() => null),
|
|
8765
8774
|
mt5bridge.call('positions', {}, 8000).catch(() => null),
|
|
8775
|
+
mt5bridge.call('orders', {}, 8000).catch(() => null),
|
|
8766
8776
|
mt5bridge.call('symbols', { symbols: f.symbols || [] }, 10000).catch(() => null),
|
|
8767
8777
|
]);
|
|
8768
8778
|
if (a && a.ok) account = a.data && a.data.account;
|
|
8769
8779
|
if (p && p.ok) positions = (p.data && p.data.positions) || [];
|
|
8780
|
+
if (o && o.ok) orders = (o.data && o.data.orders) || [];
|
|
8770
8781
|
if (sy && sy.ok) symbols = (sy.data && sy.data.symbols) || [];
|
|
8771
8782
|
}
|
|
8772
8783
|
const busy = financeState.traderSid && engine ? engine.isBusy(financeState.traderSid) : false;
|
|
@@ -8775,6 +8786,7 @@ ipcMain.handle('finance:snapshot', async () => {
|
|
|
8775
8786
|
bridge: { running: st.running, connected: st.connected, error: st.error, terminal: st.terminal, python: st.python },
|
|
8776
8787
|
account,
|
|
8777
8788
|
positions,
|
|
8789
|
+
orders,
|
|
8778
8790
|
symbols,
|
|
8779
8791
|
cfg: f,
|
|
8780
8792
|
roles: FIN_ROLES,
|
|
@@ -8999,6 +9011,19 @@ ipcMain.handle('finance:close', async (_e, payload) => {
|
|
|
8999
9011
|
return r;
|
|
9000
9012
|
});
|
|
9001
9013
|
|
|
9014
|
+
/* Bekleyen emri panelden iptal et (ajanın mt5_cancel aracıyla aynı köprü) */
|
|
9015
|
+
ipcMain.handle('finance:cancel', async (_e, payload) => {
|
|
9016
|
+
const ticket = Number(payload && payload.ticket);
|
|
9017
|
+
if (!ticket) return { ok: false, error: 'ticket gerekli' };
|
|
9018
|
+
if (!mt5bridge.running) return { ok: false, error: 'MT5 köprüsü bağlı değil' };
|
|
9019
|
+
const r = await mt5bridge.call('cancel', { ticket }, 20000);
|
|
9020
|
+
if (r && r.ok) {
|
|
9021
|
+
financeLog('[panel] bekleyen emir iptal edildi: ticket ' + ticket);
|
|
9022
|
+
finPush('trade', { line: 'EMİR İPTAL (panel): ticket ' + ticket });
|
|
9023
|
+
}
|
|
9024
|
+
return r;
|
|
9025
|
+
});
|
|
9026
|
+
|
|
9002
9027
|
ipcMain.handle('finance:install', async () => {
|
|
9003
9028
|
financeState.installTried = false;
|
|
9004
9029
|
financeTryInstall();
|
package/src/preload.js
CHANGED
|
@@ -117,6 +117,7 @@ contextBridge.exposeInMainWorld('beast', {
|
|
|
117
117
|
financeAgentSpawn: (symbol) => ipcRenderer.invoke('finance:agent:spawn', { symbol }),
|
|
118
118
|
financeConnect: () => ipcRenderer.invoke('finance:connect'),
|
|
119
119
|
financeClose: (ticket, volume) => ipcRenderer.invoke('finance:close', { ticket, volume }),
|
|
120
|
+
financeCancel: (ticket) => ipcRenderer.invoke('finance:cancel', { ticket }),
|
|
120
121
|
financeInstall: () => ipcRenderer.invoke('finance:install'),
|
|
121
122
|
financeSymbolsList: (filter) => ipcRenderer.invoke('finance:symbols:list', filter),
|
|
122
123
|
clipRead: () => ipcRenderer.invoke('clip:read'),
|
package/src/renderer/index.html
CHANGED
|
@@ -161,7 +161,7 @@
|
|
|
161
161
|
<div class="fin-kv"><span>Serbest Marj</span><b id="finFree">—</b></div>
|
|
162
162
|
</div>
|
|
163
163
|
</div>
|
|
164
|
-
<div class="fin-card">
|
|
164
|
+
<div class="fin-card fin-card-trader">
|
|
165
165
|
<div class="fin-card-title">TRADE AJANI <span id="finTraderDot" class="fin-dot off" title="Trader durumu"></span></div>
|
|
166
166
|
<div class="fin-row"><select id="finTraderModel" title="Trader ajanının modeli — farklı API/model seçilebilir"></select></div>
|
|
167
167
|
<div class="fin-row fin-mini">
|
|
@@ -173,7 +173,7 @@
|
|
|
173
173
|
<label>Analiz ekibi</label>
|
|
174
174
|
<div id="finRoles" class="fin-roles" title="Trader'ın yanında koşacak uzman ajanlar — tüm skill + mt5 erişimli, işlem açmazlar"></div>
|
|
175
175
|
</div>
|
|
176
|
-
<div class="fin-row">
|
|
176
|
+
<div class="fin-row fin-btn-row">
|
|
177
177
|
<button id="finTraderBtn" class="fin-start">▶︎ Ajanı Başlat</button>
|
|
178
178
|
</div>
|
|
179
179
|
<div id="finTraderStatus">Kapalı</div>
|
|
@@ -182,6 +182,10 @@
|
|
|
182
182
|
<div class="fin-card-title">POZİSYONLAR <span id="finPosCount"></span></div>
|
|
183
183
|
<div id="finPosList"><div class="fin-empty">Açık pozisyon yok</div></div>
|
|
184
184
|
</div>
|
|
185
|
+
<div class="fin-card">
|
|
186
|
+
<div class="fin-card-title">BEKLEYEN EMİRLER <span id="finOrdCount"></span></div>
|
|
187
|
+
<div id="finOrdList"><div class="fin-empty">Bekleyen emir yok</div></div>
|
|
188
|
+
</div>
|
|
185
189
|
<div class="fin-card">
|
|
186
190
|
<div class="fin-card-title">
|
|
187
191
|
PİYASA
|
package/src/renderer/renderer.js
CHANGED
|
@@ -180,6 +180,8 @@ const els = {
|
|
|
180
180
|
finTraderStatus: $('#finTraderStatus'),
|
|
181
181
|
finPosList: $('#finPosList'),
|
|
182
182
|
finPosCount: $('#finPosCount'),
|
|
183
|
+
finOrdList: $('#finOrdList'),
|
|
184
|
+
finOrdCount: $('#finOrdCount'),
|
|
183
185
|
finSymList: $('#finSymList'),
|
|
184
186
|
finLog: $('#finLog'),
|
|
185
187
|
finSymAdd: $('#finSymAdd'),
|
|
@@ -8874,6 +8876,56 @@ function finRenderPositions(list) {
|
|
|
8874
8876
|
}
|
|
8875
8877
|
}
|
|
8876
8878
|
|
|
8879
|
+
/* MT5 bekleyen emir tipi → etiket + renk sınıfı (0..7) */
|
|
8880
|
+
const FIN_ORDER_TYPES = {
|
|
8881
|
+
0: { t: 'BUY', c: 'buy' },
|
|
8882
|
+
1: { t: 'SELL', c: 'sell' },
|
|
8883
|
+
2: { t: 'BUY LIMIT', c: 'buy' },
|
|
8884
|
+
3: { t: 'SELL LIMIT', c: 'sell' },
|
|
8885
|
+
4: { t: 'BUY STOP', c: 'buy' },
|
|
8886
|
+
5: { t: 'SELL STOP', c: 'sell' },
|
|
8887
|
+
6: { t: 'BUY STP-LMT', c: 'buy' },
|
|
8888
|
+
7: { t: 'SELL STP-LMT', c: 'sell' },
|
|
8889
|
+
};
|
|
8890
|
+
|
|
8891
|
+
function finRenderOrders(list) {
|
|
8892
|
+
if (!els.finOrdList) return;
|
|
8893
|
+
els.finOrdList.textContent = '';
|
|
8894
|
+
if (els.finOrdCount) els.finOrdCount.textContent = list && list.length ? '(' + list.length + ')' : '';
|
|
8895
|
+
if (!list || !list.length) {
|
|
8896
|
+
const d = document.createElement('div');
|
|
8897
|
+
d.className = 'fin-empty';
|
|
8898
|
+
d.textContent = 'Bekleyen emir yok';
|
|
8899
|
+
els.finOrdList.appendChild(d);
|
|
8900
|
+
return;
|
|
8901
|
+
}
|
|
8902
|
+
for (const o of list) {
|
|
8903
|
+
const row = document.createElement('div');
|
|
8904
|
+
row.className = 'fin-pos fin-ord';
|
|
8905
|
+
const ot = FIN_ORDER_TYPES[Number(o.type)] || { t: String(o.type ?? '?'), c: '' };
|
|
8906
|
+
const vol = Number(o.volume_current) || Number(o.volume_initial) || 0;
|
|
8907
|
+
row.innerHTML =
|
|
8908
|
+
'<span class="fp-sym" title="ticket ' + o.ticket + '">' + escapeHtml(String(o.symbol || '?')) + '</span>' +
|
|
8909
|
+
'<span class="fp-dir ' + ot.c + '">' + ot.t + '</span>' +
|
|
8910
|
+
'<span class="fp-meta">' + vol + ' lot @ ' + (Number(o.price_open) || 0) +
|
|
8911
|
+
(o.sl ? ' · SL ' + o.sl : '') + (o.tp ? ' · TP ' + o.tp : '') + '</span>';
|
|
8912
|
+
const btn = document.createElement('button');
|
|
8913
|
+
btn.className = 'fp-close';
|
|
8914
|
+
btn.title = 'Bekleyen emri iptal et';
|
|
8915
|
+
btn.textContent = '✕';
|
|
8916
|
+
btn.addEventListener('click', async () => {
|
|
8917
|
+
const ok = await uiConfirm((o.symbol || '') + ' bekleyen emri iptal edilsin mi? (ticket ' + o.ticket + ')', 'İptal Et');
|
|
8918
|
+
if (!ok) return;
|
|
8919
|
+
const r = await beast.financeCancel(o.ticket).catch((e) => ({ ok: false, error: String((e && e.message) || e) }));
|
|
8920
|
+
if (r && r.ok) toast('Emir iptal edildi');
|
|
8921
|
+
else toast('İptal edilemedi: ' + ((r && r.error) || '?'));
|
|
8922
|
+
finSnapshot();
|
|
8923
|
+
});
|
|
8924
|
+
row.appendChild(btn);
|
|
8925
|
+
els.finOrdList.appendChild(row);
|
|
8926
|
+
}
|
|
8927
|
+
}
|
|
8928
|
+
|
|
8877
8929
|
function finRenderSymbols(list) {
|
|
8878
8930
|
if (!els.finSymList) return;
|
|
8879
8931
|
els.finSymList.textContent = '';
|
|
@@ -9038,6 +9090,8 @@ function finRenderTrader(trader, cfg) {
|
|
|
9038
9090
|
else els.finTraderDot.classList.add('off');
|
|
9039
9091
|
}
|
|
9040
9092
|
if (els.finTraderStatus) {
|
|
9093
|
+
els.finTraderStatus.classList.toggle('on', on);
|
|
9094
|
+
els.finTraderStatus.classList.toggle('busy', !!(on && trader && trader.busy));
|
|
9041
9095
|
let t = '';
|
|
9042
9096
|
if (trader && trader.lastAt) {
|
|
9043
9097
|
const d = new Date(trader.lastAt);
|
|
@@ -9087,6 +9141,7 @@ async function finSnapshot() {
|
|
|
9087
9141
|
finSetDot(b.connected ? true : b.running ? 'busy' : false, b);
|
|
9088
9142
|
finRenderAccount(r.account);
|
|
9089
9143
|
finRenderPositions(r.positions || []);
|
|
9144
|
+
finRenderOrders(r.orders || []);
|
|
9090
9145
|
finRenderSymbols(r.symbols || []);
|
|
9091
9146
|
if (Array.isArray(r.roles) && r.roles.length) finRolesCatalog = r.roles;
|
|
9092
9147
|
finTraderInputsSet(r.cfg);
|
package/src/renderer/style.css
CHANGED
|
@@ -4919,16 +4919,36 @@ body.finance-mode #composerWrap { margin-right: var(--finW, 400px); }
|
|
|
4919
4919
|
color: #fff; /* kırmızı zeminde beyaz her iki temada da okunur */
|
|
4920
4920
|
}
|
|
4921
4921
|
|
|
4922
|
+
/* TRADE AJANI kartı — vurgulu görünüm (accent çerçeve + yumuşak zemin) */
|
|
4923
|
+
.fin-card-trader {
|
|
4924
|
+
border-color: var(--accent);
|
|
4925
|
+
box-shadow: 0 0 0 1px var(--accent-dim), 0 2px 10px rgba(0, 0, 0, 0.1);
|
|
4926
|
+
background: linear-gradient(180deg, var(--accent-dim), transparent 46%), var(--panel);
|
|
4927
|
+
}
|
|
4928
|
+
.fin-card-trader .fin-card-title { color: var(--text); }
|
|
4929
|
+
.fin-card-trader .fin-row { margin-bottom: 8px; }
|
|
4930
|
+
.fin-card-trader .fin-btn-row { margin-top: 2px; }
|
|
4931
|
+
.fin-btn-row .fin-start { flex: 1; width: 100%; padding: 7px 14px; }
|
|
4932
|
+
|
|
4922
4933
|
#finTraderStatus {
|
|
4923
|
-
margin-top:
|
|
4924
|
-
font-size:
|
|
4934
|
+
margin-top: 8px;
|
|
4935
|
+
font-size: 10.5px;
|
|
4925
4936
|
color: var(--muted);
|
|
4937
|
+
background: var(--panel2);
|
|
4938
|
+
border: 1px solid var(--border);
|
|
4939
|
+
border-radius: 7px;
|
|
4940
|
+
padding: 5px 8px;
|
|
4926
4941
|
white-space: nowrap;
|
|
4927
4942
|
overflow: hidden;
|
|
4928
4943
|
text-overflow: ellipsis;
|
|
4929
4944
|
}
|
|
4945
|
+
#finTraderStatus::before { content: '● '; font-size: 9px; color: var(--muted); }
|
|
4946
|
+
#finTraderStatus.on { color: var(--text); border-color: var(--accent); }
|
|
4947
|
+
#finTraderStatus.on::before { color: #22c55e; }
|
|
4948
|
+
#finTraderStatus.on.busy { color: var(--accent); }
|
|
4949
|
+
#finTraderStatus.on.busy::before { color: #f59e0b; }
|
|
4930
4950
|
|
|
4931
|
-
#finPosList, #finSymList { display: flex; flex-direction: column; gap: 5px; }
|
|
4951
|
+
#finPosList, #finOrdList, #finSymList { display: flex; flex-direction: column; gap: 5px; }
|
|
4932
4952
|
.fin-empty { font-size: 11px; color: var(--muted); padding: 2px 0 4px; }
|
|
4933
4953
|
|
|
4934
4954
|
.fin-pos {
|
|
@@ -4967,6 +4987,8 @@ body.finance-mode #composerWrap { margin-right: var(--finW, 400px); }
|
|
|
4967
4987
|
border-radius: 5px;
|
|
4968
4988
|
}
|
|
4969
4989
|
.fin-pos .fp-close:hover { background: rgba(239, 68, 68, 0.15); color: #ef4444; }
|
|
4990
|
+
/* bekleyen emir satırı: amber sol şerit ile pozisyondan ayrışır */
|
|
4991
|
+
.fin-pos.fin-ord { border-left: 2px solid #f59e0b; }
|
|
4970
4992
|
|
|
4971
4993
|
.fin-sym {
|
|
4972
4994
|
display: flex;
|