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/package.json +1 -1
- package/src/agent/engine.js +1 -1
- package/src/agent/financetools.js +316 -45
- package/src/agent/finindicators.js +254 -0
- package/src/agent/finrisk.js +132 -0
- package/src/agent/finstats.js +229 -0
- package/src/agent/finwatch.js +110 -0
- package/src/agent/scripts/mt5_bridge.py +65 -0
- package/src/main.js +678 -8
- package/src/preload.js +1 -0
- package/src/renderer/index.html +80 -1
- package/src/renderer/renderer.js +280 -1
- package/src/renderer/style.css +52 -0
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),
|
package/src/renderer/index.html
CHANGED
|
@@ -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">⟳</button>
|
|
153
|
+
<button id="finSettings" title="Görünüm ayarları — bölümleri göster/gizle">⚙</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">📄 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">×</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">
|
package/src/renderer/renderer.js
CHANGED
|
@@ -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 === '
|
|
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', () => {
|
package/src/renderer/style.css
CHANGED
|
@@ -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; }
|