beast-agent 2.24.5 → 2.30.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/engine.js +28 -7
- 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' +
|
|
@@ -6448,18 +6453,30 @@ Engine.prototype._pushAgentDm = function (dm) {
|
|
|
6448
6453
|
ortak DM grubuna girer — tartışma ZORUNLU (sistem promptuyla). ---------- */
|
|
6449
6454
|
|
|
6450
6455
|
/* İş 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.
|
|
6456
|
+
önceden kurulmuştur) hepsini TEK ekip grubuna katar + katılım postu düşer.
|
|
6457
|
+
dmGroupId verilirse (finans ekibi gibi hazır grup) parent şartı aranmaz —
|
|
6458
|
+
aynı dmGroupId'li TÜM ajanlar tek gruba toplanır. */
|
|
6452
6459
|
Engine.prototype._agentTeamJoin = function (job) {
|
|
6453
6460
|
try {
|
|
6454
6461
|
if (!job || !job.id) return;
|
|
6455
6462
|
const parent = String(job.parentId || '');
|
|
6456
|
-
|
|
6457
|
-
|
|
6463
|
+
const explicit = String(job.dmGroupId || '');
|
|
6464
|
+
if (!parent && !explicit) return;
|
|
6465
|
+
const gid = explicit || 'team:' + (job.groupId || parent);
|
|
6458
6466
|
const base =
|
|
6459
|
-
String(job.task || job.title || 'ortak görev').replace(/\s+/g, ' ').trim().slice(0,
|
|
6467
|
+
String(job.dmGroupTitle || job.task || job.title || 'ortak görev').replace(/\s+/g, ' ').trim().slice(0, 40) ||
|
|
6468
|
+
'ortak görev';
|
|
6460
6469
|
let g = this._agentGroups.get(gid);
|
|
6461
6470
|
if (!g) {
|
|
6462
|
-
g = {
|
|
6471
|
+
g = {
|
|
6472
|
+
id: gid,
|
|
6473
|
+
title: job.dmGroupTitle ? base : base + ' EKİP',
|
|
6474
|
+
members: [],
|
|
6475
|
+
titles: {},
|
|
6476
|
+
createdAt: nowIso(),
|
|
6477
|
+
closed: false,
|
|
6478
|
+
team: true,
|
|
6479
|
+
};
|
|
6463
6480
|
this._agentGroups.set(gid, g);
|
|
6464
6481
|
}
|
|
6465
6482
|
g.closed = false;
|
|
@@ -6470,9 +6487,13 @@ Engine.prototype._agentTeamJoin = function (job) {
|
|
|
6470
6487
|
if (!g.members.includes(id)) g.members.push(id);
|
|
6471
6488
|
if (title) g.titles[id] = String(title);
|
|
6472
6489
|
};
|
|
6473
|
-
/* aynı ortak görevdeki DİĞER ajanlar (aborted
|
|
6490
|
+
/* aynı ortak görevdeki / aynı hazır gruptaki DİĞER ajanlar (aborted hariç) */
|
|
6474
6491
|
const mates = [...this._bgJobs.values()].filter(
|
|
6475
|
-
(j) =>
|
|
6492
|
+
(j) =>
|
|
6493
|
+
j &&
|
|
6494
|
+
String(j.id) !== String(job.id) &&
|
|
6495
|
+
j.status !== 'aborted' &&
|
|
6496
|
+
(explicit ? String(j.dmGroupId || '') === explicit : String(j.parentId) === parent)
|
|
6476
6497
|
);
|
|
6477
6498
|
add(job.id, job.title);
|
|
6478
6499
|
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;
|