beast-agent 2.32.0 → 2.33.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/src/preload.js CHANGED
@@ -120,6 +120,7 @@ contextBridge.exposeInMainWorld('beast', {
120
120
  financeCancel: (ticket) => ipcRenderer.invoke('finance:cancel', { ticket }),
121
121
  financeInstall: () => ipcRenderer.invoke('finance:install'),
122
122
  financeSymbolsList: (filter) => ipcRenderer.invoke('finance:symbols:list', filter),
123
+ financeReport: () => ipcRenderer.invoke('finance:report'),
123
124
  clipRead: () => ipcRenderer.invoke('clip:read'),
124
125
  clipWrite: (t) => ipcRenderer.invoke('clip:write', t),
125
126
  thinkSet: (v) => ipcRenderer.invoke('think:set', v),
@@ -150,6 +150,7 @@
150
150
  <span id="finTerm" title="">MT5</span>
151
151
  <span class="file-spacer"></span>
152
152
  <button id="finReconnect" title="MT5'e yeniden bağlan">&#x27F3;</button>
153
+ <button id="finSettings" title="Görünüm ayarları — bölümleri göster/gizle">&#9881;</button>
153
154
  </div>
154
155
  <div id="finBody">
155
156
  <div class="fin-card">
@@ -190,6 +191,59 @@
190
191
  </div>
191
192
  <div id="finTraderStatus">Kapalı</div>
192
193
  </div>
194
+ <div class="fin-card" id="finRiskCard" hidden>
195
+ <div class="fin-card-title">RİSK OTOMASYONU <span id="finWatchDot" class="fin-dot off" title="Koruma döngüsü"></span><span id="finWatchInfo" class="fin-hint"></span></div>
196
+ <div class="fin-field fin-check">
197
+ <label title="5 saniyelik döngü: +R'da SL'yi başabaşa çeker, trailing uygular, kısmi TP alır — ajan turunu beklemez">
198
+ <input id="finWatchdog" type="checkbox" /> Aktif — BE + trailing + kısmi TP
199
+ </label>
200
+ </div>
201
+ <div class="fin-grid2">
202
+ <div class="fin-field"><span>BE (R)</span><input id="finBeOnR" type="number" min="0" max="10" step="0.1" title="Kâr kaç R'ye ulaşınca SL başabaşa çekilsin (0 = kapalı)" /></div>
203
+ <div class="fin-field"><span>Trailing başlangıç (R)</span><input id="finTrailStartR" type="number" min="0" max="10" step="0.1" title="Kaç R kârdan sonra trailing başlasın (0 = kapalı)" /></div>
204
+ <div class="fin-field"><span>Trailing mesafe (R)</span><input id="finTrailR" type="number" min="0" max="5" step="0.1" title="SL fiyattan kaç R geriden gelsin" /></div>
205
+ <div class="fin-field"><span>Kısmi TP (R)</span><input id="finPartialR" type="number" min="0" max="10" step="0.1" title="Kaç R kârda kısmi kapatma yapılsın (0 = kapalı)" /></div>
206
+ <div class="fin-field"><span>Kısmi TP (%)</span><input id="finPartialPct" type="number" min="0" max="90" step="5" title="Kısmi kapatmada kapanacak lot yüzdesi" /></div>
207
+ <div class="fin-field"><span>Günlük kayıp uyarı (%)</span><input id="finMaxDailyLoss" type="number" min="0" max="50" step="0.5" title="Gün içi düşüş bu yüzdeyi geçince aksiyon uygulanır (0 = kapalı)" /></div>
208
+ </div>
209
+ <div class="fin-grid2">
210
+ <div class="fin-field"><span>İşlem riski (%)</span><input id="finRiskPct" type="number" min="0" max="20" step="0.1" title="Pozisyon başına hesap riski — mt5_risksize ve riskPct ile lot bu orandan hesaplanır" /></div>
211
+ <div class="fin-field"><span>Sembol başına max</span><input id="finMaxPerSymbol" type="number" min="0" max="20" step="1" title="Aynı sembolde aynı yönde en fazla kaç pozisyon (0 = sınırsız)" /></div>
212
+ <div class="fin-field"><span>Aynı yön max</span><input id="finMaxSameSide" type="number" min="0" max="20" step="1" title="Toplam aynı yönde (buy ya da sell) en fazla pozisyon (0 = sınırsız)" /></div>
213
+ <div class="fin-field"><span>Min marj seviyesi (%)</span><input id="finMinMarginLevel" type="number" min="0" max="1000" step="10" title="İşlem sonrası marj seviyesi bunun altına düşecekse işlem reddedilir (0 = kapalı)" /></div>
214
+ </div>
215
+ <div class="fin-field">
216
+ <span>Günlük limit aksiyonu</span>
217
+ <select id="finDailyLossAction" title="Günlük kayıp limiti aşılınca ne yapılsın">
218
+ <option value="warn">Yalnız uyar</option>
219
+ <option value="stop">Ajanları durdur</option>
220
+ <option value="flatten">Durdur + hepsini kapat</option>
221
+ </select>
222
+ </div>
223
+ <div class="fin-field">
224
+ <span>Bildirim kanalı</span>
225
+ <select id="finNotifyTarget" title="İşlem/koruma/alarm bildirimleri bu kanala gider; panel ve masaüstü toast her zaman çalışır">
226
+ <option value="auto">Otomatik (bağlı olan kanallar)</option>
227
+ <option value="telegram">Telegram</option>
228
+ <option value="whatsapp">WhatsApp</option>
229
+ <option value="discord">Discord</option>
230
+ <option value="off">Kapalı (yalnız panel)</option>
231
+ </select>
232
+ </div>
233
+ <div id="finAlertList" class="fin-alerts"><div class="fin-empty">Aktif fiyat alarmı yok</div></div>
234
+ </div>
235
+ <div class="fin-card" id="finPerfCard" hidden>
236
+ <div class="fin-card-title">PERFORMANS <span id="finStatsInfo" class="fin-hint"></span><span class="file-spacer"></span><button id="finReportBtn" title="Haftalık rapor üret — istatistik + işlem günlüğü + ajan değerlendirmesi">&#128196; Rapor</button></div>
237
+ <div id="finEquity" class="fin-equity"></div>
238
+ <div class="fin-grid">
239
+ <div class="fin-kv"><span>Bugün</span><b id="finStatToday">—</b></div>
240
+ <div class="fin-kv"><span>Hafta</span><b id="finStatWeek">—</b></div>
241
+ <div class="fin-kv"><span>Win rate</span><b id="finStatWin">—</b></div>
242
+ <div class="fin-kv"><span>Profit factor</span><b id="finStatPf">—</b></div>
243
+ <div class="fin-kv"><span>Max DD</span><b id="finStatDd">—</b></div>
244
+ <div class="fin-kv"><span>İşlem (90g)</span><b id="finStatTrades">—</b></div>
245
+ </div>
246
+ </div>
193
247
  <div class="fin-card">
194
248
  <div class="fin-card-title">POZİSYONLAR <span id="finPosCount"></span></div>
195
249
  <div id="finPosList"><div class="fin-empty">Açık pozisyon yok</div></div>
@@ -205,7 +259,7 @@
205
259
  </div>
206
260
  <div id="finSymList"><div class="fin-empty">—</div></div>
207
261
  </div>
208
- <div class="fin-card fin-grow">
262
+ <div class="fin-card fin-grow" id="finFlowCard" hidden>
209
263
  <div class="fin-card-title">AKIŞ</div>
210
264
  <div id="finLog"></div>
211
265
  </div>
@@ -701,6 +755,31 @@
701
755
  </div>
702
756
  </div>
703
757
 
758
+ <div id="finSettingsOverlay" class="mini-overlay" hidden>
759
+ <div class="mini-dialog fin-settings-dialog">
760
+ <div class="mini-head">
761
+ <span class="mini-title">FINANCE GÖRÜNÜM AYARLARI</span>
762
+ <button class="mini-close" id="finSettingsClose" title="Kapat">&#x00D7;</button>
763
+ </div>
764
+ <div class="mini-body">
765
+ <div class="fin-set-hint">Varsayılan olarak üç bölüm de gizlidir — açmak tamamen isteğe bağlıdır. Seçim bilgisayarda hatırlanır. Risk otomasyonu gizliyken AKTİF OLMAZ.</div>
766
+ <label class="fin-set-row" title="BE + trailing + kısmi TP koruması, günlük limitler, fiyat alarmları bölümü">
767
+ <input id="finShowRisk" type="checkbox" />
768
+ <span class="fsr-main"><b>RİSK OTOMASYONU</b><i>BE + trailing + kısmi TP, günlük limitler, alarmlar</i></span>
769
+ </label>
770
+ <label class="fin-set-row" title="Equity grafiği + günlük/haftalık istatistikler + haftalık rapor bölümü">
771
+ <input id="finShowPerf" type="checkbox" />
772
+ <span class="fsr-main"><b>PERFORMANS</b><i>Equity grafiği, istatistikler, haftalık rapor</i></span>
773
+ </label>
774
+ <label class="fin-set-row" title="Ajan/MT5 işlem günlüğü akışı bölümü">
775
+ <input id="finShowFlow" type="checkbox" />
776
+ <span class="fsr-main"><b>AKIŞ</b><i>Ajan ve MT5 olay günlüğü</i></span>
777
+ </label>
778
+ <div class="fin-set-note">RİSK OTOMASYONU gizliyken koruma döngüsü (watchdog) kapatılır; tekrar gösterdiğinde ilgili kutucuktan açabilirsin.</div>
779
+ </div>
780
+ </div>
781
+ </div>
782
+
704
783
  <div id="cronOverlay" class="mini-overlay" hidden>
705
784
  <div class="mini-dialog">
706
785
  <div class="mini-head">
@@ -165,6 +165,15 @@ const els = {
165
165
  finDot: $('#finDot'),
166
166
  finTerm: $('#finTerm'),
167
167
  finReconnect: $('#finReconnect'),
168
+ finSettings: $('#finSettings'),
169
+ finSettingsOverlay: $('#finSettingsOverlay'),
170
+ finSettingsClose: $('#finSettingsClose'),
171
+ finShowRisk: $('#finShowRisk'),
172
+ finShowPerf: $('#finShowPerf'),
173
+ finShowFlow: $('#finShowFlow'),
174
+ finRiskCard: $('#finRiskCard'),
175
+ finPerfCard: $('#finPerfCard'),
176
+ finFlowCard: $('#finFlowCard'),
168
177
  finBalance: $('#finBalance'),
169
178
  finEquity: $('#finEquity'),
170
179
  finProfit: $('#finProfit'),
@@ -194,6 +203,31 @@ const els = {
194
203
  finSymSearch: $('#finSymSearch'),
195
204
  finSymPick: $('#finSymPick'),
196
205
  finSymCount: $('#finSymCount'),
206
+ finWatchdogCb: $('#finWatchdog'),
207
+ finBeOnR: $('#finBeOnR'),
208
+ finTrailStartR: $('#finTrailStartR'),
209
+ finTrailR: $('#finTrailR'),
210
+ finPartialR: $('#finPartialR'),
211
+ finPartialPct: $('#finPartialPct'),
212
+ finMaxDailyLoss: $('#finMaxDailyLoss'),
213
+ finRiskPct: $('#finRiskPct'),
214
+ finMaxPerSymbol: $('#finMaxPerSymbol'),
215
+ finMaxSameSide: $('#finMaxSameSide'),
216
+ finMinMarginLevel: $('#finMinMarginLevel'),
217
+ finDailyLossAction: $('#finDailyLossAction'),
218
+ finNotifyTarget: $('#finNotifyTarget'),
219
+ finWatchDot: $('#finWatchDot'),
220
+ finWatchInfo: $('#finWatchInfo'),
221
+ finAlertList: $('#finAlertList'),
222
+ finReportBtn: $('#finReportBtn'),
223
+ finStatsInfo: $('#finStatsInfo'),
224
+ finStatToday: $('#finStatToday'),
225
+ finStatWeek: $('#finStatWeek'),
226
+ finStatWin: $('#finStatWin'),
227
+ finStatPf: $('#finStatPf'),
228
+ finStatDd: $('#finStatDd'),
229
+ finStatTrades: $('#finStatTrades'),
230
+ finEquityBox: $('#finEquity'),
197
231
  stVideoEl: $('#stVideoEl'),
198
232
  stVideoName: $('#stVideoName'),
199
233
  stVideoOpen: $('#stVideoOpen'),
@@ -9356,6 +9390,116 @@ function finRenderTrader(trader, cfg) {
9356
9390
  }
9357
9391
  }
9358
9392
 
9393
+ /* ---- RİSK OTOMASYONU + PERFORMANS panosu ---- */
9394
+ function finDayKey(ms) {
9395
+ const d = new Date(Number(ms) || 0);
9396
+ const p = (x) => String(x).padStart(2, '0');
9397
+ return d.getFullYear() + '-' + p(d.getMonth() + 1) + '-' + p(d.getDate());
9398
+ }
9399
+
9400
+ function finRenderAutomation(cfg, watch) {
9401
+ if (!cfg) return;
9402
+ const ae = document.activeElement;
9403
+ if (els.finWatchdogCb) els.finWatchdogCb.checked = finView.risk && cfg.watchdog !== false;
9404
+ const setNum = (el, v) => {
9405
+ if (el && ae !== el) el.value = v;
9406
+ };
9407
+ setNum(els.finBeOnR, cfg.beOnR != null ? cfg.beOnR : 1);
9408
+ setNum(els.finTrailStartR, cfg.trailStartR != null ? cfg.trailStartR : 1.5);
9409
+ setNum(els.finTrailR, cfg.trailR != null ? cfg.trailR : 0.5);
9410
+ setNum(els.finPartialR, cfg.partialR != null ? cfg.partialR : 0);
9411
+ setNum(els.finPartialPct, cfg.partialPct != null ? cfg.partialPct : 50);
9412
+ setNum(els.finMaxDailyLoss, cfg.maxDailyLossPct != null ? cfg.maxDailyLossPct : 3);
9413
+ setNum(els.finRiskPct, cfg.riskPerTradePct != null ? cfg.riskPerTradePct : 1);
9414
+ setNum(els.finMaxPerSymbol, cfg.maxPerSymbol != null ? cfg.maxPerSymbol : 2);
9415
+ setNum(els.finMaxSameSide, cfg.maxSameSide != null ? cfg.maxSameSide : 3);
9416
+ setNum(els.finMinMarginLevel, cfg.minMarginLevel != null ? cfg.minMarginLevel : 150);
9417
+ if (els.finDailyLossAction && ae !== els.finDailyLossAction) els.finDailyLossAction.value = cfg.dailyLossAction || 'stop';
9418
+ if (els.finNotifyTarget && ae !== els.finNotifyTarget) els.finNotifyTarget.value = cfg.notifyTarget || 'auto';
9419
+ if (els.finWatchDot) {
9420
+ els.finWatchDot.classList.remove('on', 'off', 'busy');
9421
+ els.finWatchDot.classList.add(watch && watch.on ? 'on' : 'off');
9422
+ els.finWatchDot.title = watch && watch.on ? 'Koruma döngüsü çalışıyor (5 sn)' : 'Koruma döngüsü kapalı';
9423
+ }
9424
+ if (els.finWatchInfo) {
9425
+ els.finWatchInfo.textContent = watch && watch.on ? '· izlenen ' + (watch.managed || 0) : '';
9426
+ }
9427
+ }
9428
+
9429
+ function finSparkline(points) {
9430
+ const list = (Array.isArray(points) ? points : []).filter((p) => p && isFinite(Number(p.equity)));
9431
+ if (list.length < 2) return '<div class="fin-empty">Equity verisi toplanıyor…</div>';
9432
+ const w = 100;
9433
+ const h = 28;
9434
+ const vals = list.map((p) => Number(p.equity));
9435
+ let min = Math.min(...vals);
9436
+ let max = Math.max(...vals);
9437
+ if (max - min < 1e-9) max = min + 1;
9438
+ const step = w / (list.length - 1);
9439
+ const pts = vals
9440
+ .map((v, i) => (i * step).toFixed(2) + ',' + (h - 2 - ((v - min) / (max - min)) * (h - 4)).toFixed(2))
9441
+ .join(' ');
9442
+ const up = vals[vals.length - 1] >= vals[0];
9443
+ return '<svg viewBox="0 0 ' + w + ' ' + h + '" preserveAspectRatio="none" class="' + (up ? 'up' : 'down') + '">' +
9444
+ '<polyline points="' + pts + '" fill="none" stroke="currentColor" stroke-width="1.4" vector-effect="non-scaling-stroke" /></svg>';
9445
+ }
9446
+
9447
+ function finRenderStats(stats, equity, cur) {
9448
+ const s = stats || null;
9449
+ if (els.finEquityBox) {
9450
+ els.finEquityBox.innerHTML = finSparkline(equity);
9451
+ }
9452
+ if (els.finStatsInfo) {
9453
+ els.finStatsInfo.textContent = s && s.at
9454
+ ? '· son 90 gün · ' + new Date(s.at).toLocaleTimeString('tr-TR', { hour: '2-digit', minute: '2-digit' })
9455
+ : '';
9456
+ }
9457
+ if (!s) {
9458
+ finKvSet(els.finStatToday, '—');
9459
+ finKvSet(els.finStatWeek, '—');
9460
+ finKvSet(els.finStatWin, '—');
9461
+ finKvSet(els.finStatPf, '—');
9462
+ finKvSet(els.finStatDd, '—');
9463
+ finKvSet(els.finStatTrades, '—');
9464
+ return;
9465
+ }
9466
+ const byDay = s.byDay && typeof s.byDay === 'object' ? s.byDay : {};
9467
+ const today = Number(byDay[finDayKey(Date.now())]) || 0;
9468
+ const week = Object.entries(byDay)
9469
+ .filter(([d]) => Date.now() - new Date(d + 'T00:00:00').getTime() < 7 * 86400000)
9470
+ .reduce((a, [, v]) => a + (Number(v) || 0), 0);
9471
+ const fmt = (n) => (n > 0 ? '+' : '') + fmtMoney(n, cur);
9472
+ finKvSet(els.finStatToday, fmt(today), today !== 0 ? (today > 0 ? 'pos' : 'neg') : null);
9473
+ finKvSet(els.finStatWeek, fmt(week), week !== 0 ? (week > 0 ? 'pos' : 'neg') : null);
9474
+ finKvSet(els.finStatWin, '%' + (Number(s.winRate) || 0) + ' (' + (Number(s.wins) || 0) + '/' + (Number(s.losses) || 0) + ')');
9475
+ finKvSet(els.finStatPf, s.profitFactor == null ? '∞' : String(s.profitFactor));
9476
+ const dd = s.drawdown || {};
9477
+ finKvSet(els.finStatDd, '%' + (Number(dd.maxPct) || 0), (Number(dd.maxPct) || 0) > 0 ? 'neg' : null);
9478
+ finKvSet(els.finStatTrades, String(Number(s.trades) || 0));
9479
+ }
9480
+
9481
+ function finRenderAlerts(list) {
9482
+ const box = els.finAlertList;
9483
+ if (!box) return;
9484
+ box.textContent = '';
9485
+ if (!list || !list.length) {
9486
+ const d = document.createElement('div');
9487
+ d.className = 'fin-empty';
9488
+ d.textContent = 'Aktif fiyat alarmı yok';
9489
+ box.appendChild(d);
9490
+ return;
9491
+ }
9492
+ for (const a of list) {
9493
+ const row = document.createElement('div');
9494
+ row.className = 'fin-alert';
9495
+ row.innerHTML =
9496
+ '<span class="fa-sym">' + escapeHtml(String(a.symbol || '?')) + '</span>' +
9497
+ '<span class="fa-cond">' + (a.direction === 'below' ? '≤' : '≥') + ' ' + (Number(a.price) || 0) + '</span>' +
9498
+ (a.note ? '<span class="fa-note">' + escapeHtml(String(a.note)) + '</span>' : '');
9499
+ box.appendChild(row);
9500
+ }
9501
+ }
9502
+
9359
9503
  async function finFillModels() {
9360
9504
  if (!els.finTraderModel) return;
9361
9505
  let models = [];
@@ -9397,6 +9541,11 @@ async function finSnapshot() {
9397
9541
  finTraderInputsSet(r.cfg);
9398
9542
  finRenderRoles(r.cfg);
9399
9543
  finRenderTrader(r.trader, r.cfg);
9544
+ finRenderAutomation(r.cfg, r.watch);
9545
+ /* GİZLİ RİSK OTOMASYONU AKTİF OLAMAZ: sunucu hâlâ açık diyorsa kapat */
9546
+ if (!finView.risk && r.cfg && r.cfg.watchdog !== false) finSaveCfg({ watchdog: false });
9547
+ finRenderStats(r.stats, r.equity, r.account && r.account.currency ? r.account.currency : '');
9548
+ finRenderAlerts(r.alerts);
9400
9549
  }
9401
9550
 
9402
9551
  function finLogLine(line) {
@@ -9414,7 +9563,11 @@ function finLogLine(line) {
9414
9563
  function finOnEvent(ev) {
9415
9564
  if (!ev || ev.type !== 'finance') return;
9416
9565
  if (ev.fn === 'log' && ev.line) finLogLine(ev.line);
9417
- else if (ev.fn === 'trade' && ev.line) {
9566
+ else if (ev.fn === 'notify' && ev.line) {
9567
+ finLogLine(ev.line);
9568
+ toast(ev.line);
9569
+ finSnapshot();
9570
+ } else if (ev.fn === 'trade' && ev.line) {
9418
9571
  finLogLine(ev.line);
9419
9572
  toast(ev.line);
9420
9573
  finSnapshot();
@@ -9488,6 +9641,78 @@ function finSaveCfg(patch) {
9488
9641
  beast.financeSettings(patch).then(() => { finWatchDirty = false; }).catch(() => { finWatchDirty = false; });
9489
9642
  }, 400);
9490
9643
  }
9644
+
9645
+ /* ---------- GÖRÜNÜM AYARLARI (isteğe bağlı bölümler) ----------
9646
+ RİSK OTOMASYONU + PERFORMANS + AKIŞ varsayılan GİZLİ; açmak isteğe bağlı.
9647
+ Seçim localStorage'da hatırlanır. Risk otomasyonu gizliyken watchdog
9648
+ AKTİF OLMAZ — kart yeniden gösterilince kutucuktan açılabilir. */
9649
+ const finViewKey = 'beast.financeView';
9650
+ const finView = { risk: false, perf: false, flow: false };
9651
+ try {
9652
+ const v = JSON.parse(localStorage.getItem(finViewKey) || 'null');
9653
+ if (v && typeof v === 'object') {
9654
+ finView.risk = v.risk === true;
9655
+ finView.perf = v.perf === true;
9656
+ finView.flow = v.flow === true;
9657
+ }
9658
+ } catch {}
9659
+
9660
+ function finViewPaint() {
9661
+ if (els.finRiskCard) els.finRiskCard.hidden = !finView.risk;
9662
+ if (els.finPerfCard) els.finPerfCard.hidden = !finView.perf;
9663
+ if (els.finFlowCard) els.finFlowCard.hidden = !finView.flow;
9664
+ if (els.finShowRisk) els.finShowRisk.checked = finView.risk;
9665
+ if (els.finShowPerf) els.finShowPerf.checked = finView.perf;
9666
+ if (els.finShowFlow) els.finShowFlow.checked = finView.flow;
9667
+ const row = (cb) => cb && cb.closest('.fin-set-row');
9668
+ const r1 = row(els.finShowRisk); if (r1) r1.classList.toggle('on', finView.risk);
9669
+ const r2 = row(els.finShowPerf); if (r2) r2.classList.toggle('on', finView.perf);
9670
+ const r3 = row(els.finShowFlow); if (r3) r3.classList.toggle('on', finView.flow);
9671
+ }
9672
+
9673
+ function finViewApply() {
9674
+ finViewPaint();
9675
+ /* gizli risk otomasyonu aktif kalmaz */
9676
+ if (!finView.risk && els.finWatchdogCb) els.finWatchdogCb.checked = false;
9677
+ try { localStorage.setItem(finViewKey, JSON.stringify(finView)); } catch {}
9678
+ if (!finView.risk) finSaveCfg({ watchdog: false });
9679
+ }
9680
+
9681
+ function finSettingsOpen() {
9682
+ if (els.finSettingsOverlay) els.finSettingsOverlay.hidden = false;
9683
+ }
9684
+ function finSettingsCloseModal() {
9685
+ if (els.finSettingsOverlay) els.finSettingsOverlay.hidden = true;
9686
+ }
9687
+
9688
+ function finViewToggle(key, on) {
9689
+ finView[key] = !!on;
9690
+ finViewApply();
9691
+ if (key === 'risk') {
9692
+ toast(on
9693
+ ? 'RİSK OTOMASYONU gösteriliyor — aktif etmek için karttaki kutucuğu işaretle'
9694
+ : 'RİSK OTOMASYONU gizlendi ve kapatıldı');
9695
+ } else {
9696
+ toast((key === 'perf' ? 'PERFORMANS' : 'AKIŞ') + (on ? ' bölümü gösteriliyor' : ' bölümü gizlendi'));
9697
+ }
9698
+ if (financeModeOn()) finSnapshot();
9699
+ }
9700
+
9701
+ if (els.finSettings) els.finSettings.addEventListener('click', finSettingsOpen);
9702
+ if (els.finSettingsClose) els.finSettingsClose.addEventListener('click', finSettingsCloseModal);
9703
+ if (els.finSettingsOverlay) {
9704
+ els.finSettingsOverlay.addEventListener('click', (e) => {
9705
+ if (e.target === els.finSettingsOverlay) finSettingsCloseModal();
9706
+ });
9707
+ els.finSettingsOverlay.addEventListener('keydown', (e) => {
9708
+ if (e.key === 'Escape') { e.stopPropagation(); finSettingsCloseModal(); }
9709
+ });
9710
+ }
9711
+ if (els.finShowRisk) els.finShowRisk.addEventListener('change', () => finViewToggle('risk', els.finShowRisk.checked));
9712
+ if (els.finShowPerf) els.finShowPerf.addEventListener('change', () => finViewToggle('perf', els.finShowPerf.checked));
9713
+ if (els.finShowFlow) els.finShowFlow.addEventListener('change', () => finViewToggle('flow', els.finShowFlow.checked));
9714
+ finViewApply();
9715
+
9491
9716
  if (els.finInterval) els.finInterval.addEventListener('change', () => {
9492
9717
  const v = Math.max(30, Math.min(3600, Math.round(Number(els.finInterval.value) || 120)));
9493
9718
  els.finInterval.value = v;
@@ -9501,6 +9726,60 @@ if (els.finMaxLot) els.finMaxLot.addEventListener('change', () => {
9501
9726
  toast('Max lot: ' + v + ' — sonraki turdan itibaren geçerli');
9502
9727
  });
9503
9728
  if (els.finSymBtn) els.finSymBtn.addEventListener('click', finSymPickerOpen);
9729
+
9730
+ /* RİSK OTOMASYONU kontrolleri: değişiklik anında kaydedilir (ajan turunu beklemez) */
9731
+ if (els.finWatchdogCb) {
9732
+ els.finWatchdogCb.addEventListener('change', () => {
9733
+ finSaveCfg({ watchdog: els.finWatchdogCb.checked });
9734
+ toast('Risk otomasyonu ' + (els.finWatchdogCb.checked ? 'açık — BE/trailing/kısmi TP 5 sn döngüyle uygulanır' : 'kapalı'));
9735
+ });
9736
+ }
9737
+ const finAutoNum = (el, key, min, max, step) => {
9738
+ if (!el) return;
9739
+ el.addEventListener('change', () => {
9740
+ let v = Number(el.value);
9741
+ if (!isFinite(v)) v = min;
9742
+ v = Math.max(min, Math.min(max, step ? Math.round(v / step) * step : v));
9743
+ el.value = v;
9744
+ finSaveCfg({ [key]: v });
9745
+ });
9746
+ };
9747
+ finAutoNum(els.finBeOnR, 'beOnR', 0, 10);
9748
+ finAutoNum(els.finTrailStartR, 'trailStartR', 0, 10);
9749
+ finAutoNum(els.finTrailR, 'trailR', 0, 5);
9750
+ finAutoNum(els.finPartialR, 'partialR', 0, 10);
9751
+ finAutoNum(els.finPartialPct, 'partialPct', 0, 90, 5);
9752
+ finAutoNum(els.finMaxDailyLoss, 'maxDailyLossPct', 0, 50);
9753
+ finAutoNum(els.finRiskPct, 'riskPerTradePct', 0, 20, 0.1);
9754
+ finAutoNum(els.finMaxPerSymbol, 'maxPerSymbol', 0, 20, 1);
9755
+ finAutoNum(els.finMaxSameSide, 'maxSameSide', 0, 20, 1);
9756
+ finAutoNum(els.finMinMarginLevel, 'minMarginLevel', 0, 1000, 10);
9757
+ if (els.finDailyLossAction) {
9758
+ els.finDailyLossAction.addEventListener('change', () => {
9759
+ finSaveCfg({ dailyLossAction: els.finDailyLossAction.value });
9760
+ const t = els.finDailyLossAction.options[els.finDailyLossAction.selectedIndex].textContent;
9761
+ toast('Günlük limit aksiyonu: ' + t);
9762
+ });
9763
+ }
9764
+ if (els.finNotifyTarget) {
9765
+ els.finNotifyTarget.addEventListener('change', () => {
9766
+ finSaveCfg({ notifyTarget: els.finNotifyTarget.value });
9767
+ toast('Bildirim kanalı: ' + els.finNotifyTarget.options[els.finNotifyTarget.selectedIndex].textContent);
9768
+ });
9769
+ }
9770
+ if (els.finReportBtn) {
9771
+ els.finReportBtn.addEventListener('click', async () => {
9772
+ els.finReportBtn.disabled = true;
9773
+ els.finReportBtn.textContent = '⏳ Rapor…';
9774
+ const r = await beast.financeReport().catch((e) => ({ ok: false, error: String((e && e.message) || e) }));
9775
+ els.finReportBtn.disabled = false;
9776
+ els.finReportBtn.textContent = '📄 Rapor';
9777
+ if (r && r.ok) toast('Rapor hazır: ' + String(r.path || '').split(/[\\/]/).pop());
9778
+ else toast('Rapor üretilemedi: ' + ((r && r.error) || '?'));
9779
+ finSnapshot();
9780
+ });
9781
+ }
9782
+
9504
9783
  /* OTOMATİK İŞLEM onay kutusu KALDIRILDI — trade ajanı daima işlem açabilir */
9505
9784
  if (els.finTraderModel) {
9506
9785
  els.finTraderModel.addEventListener('change', () => {
@@ -4845,6 +4845,29 @@ body.finance-mode #composerWrap { margin-right: var(--finW, 400px); }
4845
4845
  .fin-grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
4846
4846
  .fin-grid2 .fin-field { margin-bottom: 8px; }
4847
4847
  .fin-hint { font-style: normal; opacity: 0.75; }
4848
+ /* RİSK OTOMASYONU + PERFORMANS kartları */
4849
+ .fin-check label { display: flex; align-items: center; gap: 6px; font-size: 11px; color: var(--text); cursor: pointer; }
4850
+ .fin-check input { accent-color: var(--accent); margin: 0; }
4851
+ .fin-kv b.pos { color: #22c55e; }
4852
+ .fin-kv b.neg { color: #ef4444; }
4853
+ .fin-equity { height: 34px; margin-bottom: 8px; color: var(--muted); }
4854
+ .fin-equity svg { width: 100%; height: 100%; display: block; }
4855
+ .fin-equity svg.up { color: #22c55e; }
4856
+ .fin-equity svg.down { color: #ef4444; }
4857
+ .fin-alerts { margin-top: 6px; display: flex; flex-direction: column; gap: 4px; }
4858
+ .fin-alert {
4859
+ display: flex;
4860
+ align-items: center;
4861
+ gap: 6px;
4862
+ font-size: 11px;
4863
+ background: var(--panel2);
4864
+ border-radius: 4px;
4865
+ padding: 3px 6px;
4866
+ min-width: 0;
4867
+ }
4868
+ .fin-alert .fa-sym { font-weight: 700; }
4869
+ .fin-alert .fa-cond { color: #eab308; font-variant-numeric: tabular-nums; }
4870
+ .fin-alert .fa-note { color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
4848
4871
  /* ekib sayısı + otomatik atama özeti */
4849
4872
  .fin-team { display: flex; align-items: center; gap: 8px; min-width: 0; }
4850
4873
  .fin-team-hint {
@@ -5179,3 +5202,32 @@ body.finance-mode #composerWrap { margin-right: var(--finW, 400px); }
5179
5202
  .fin-skill-chip:hover { border-color: var(--accent); }
5180
5203
  .fin-skill-chip.on { border-color: var(--accent); color: var(--accent); background: var(--accent-dim); }
5181
5204
  .fin-skill-chip input { flex: none; width: auto; margin: 0; }
5205
+
5206
+ /* FINANCE GÖRÜNÜM AYARLARI modalı (başlıktaki ⚙) — isteğe bağlı bölümler */
5207
+ .fin-card[hidden] { display: none; }
5208
+ .fin-settings-dialog { width: min(440px, 90vw); height: auto; max-height: min(560px, 84vh); }
5209
+ .fin-set-hint {
5210
+ font-size: 11px;
5211
+ color: var(--muted);
5212
+ line-height: 1.45;
5213
+ margin-bottom: 10px;
5214
+ }
5215
+ .fin-set-row {
5216
+ display: flex;
5217
+ align-items: flex-start;
5218
+ gap: 9px;
5219
+ background: var(--panel);
5220
+ border: 1px solid var(--border);
5221
+ border-radius: 9px;
5222
+ padding: 9px 10px;
5223
+ margin-bottom: 6px;
5224
+ cursor: pointer;
5225
+ user-select: none;
5226
+ }
5227
+ .fin-set-row:hover { border-color: var(--accent); }
5228
+ .fin-set-row.on { border-color: var(--accent); background: var(--accent-dim); }
5229
+ .fin-set-row input { flex: none; width: auto; margin: 2px 0 0; accent-color: var(--accent); }
5230
+ .fin-set-row .fsr-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
5231
+ .fin-set-row .fsr-main b { font-size: 12px; color: var(--text); letter-spacing: 0.4px; }
5232
+ .fin-set-row .fsr-main i { font-style: normal; font-size: 10.5px; color: var(--muted); }
5233
+ .fin-set-note { margin-top: 8px; font-size: 10.5px; color: var(--muted); line-height: 1.4; }