beast-agent 2.63.1 → 2.63.3
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/bots.js +19 -1
- package/src/agent/engine.js +74 -14
- package/src/agent/financetools.js +60 -18
- package/src/agent/finrisk.js +16 -6
- package/src/agent/seeds/risk-yonetimi/SKILL.md +52 -52
- package/src/main.js +442 -22
- package/src/preload.js +1 -0
- package/src/renderer/i18n.js +2 -0
- package/src/renderer/index.html +18 -1
- package/src/renderer/renderer.js +344 -1
- package/src/renderer/style.css +115 -0
package/src/preload.js
CHANGED
|
@@ -131,6 +131,7 @@ contextBridge.exposeInMainWorld('beast', {
|
|
|
131
131
|
financeMt5Setup: () => ipcRenderer.invoke('finance:mt5:setup'),
|
|
132
132
|
financeSymbolsList: (filter) => ipcRenderer.invoke('finance:symbols:list', filter),
|
|
133
133
|
financeReport: () => ipcRenderer.invoke('finance:report'),
|
|
134
|
+
financeLearn: (payload) => ipcRenderer.invoke('finance:learn', payload),
|
|
134
135
|
clipRead: () => ipcRenderer.invoke('clip:read'),
|
|
135
136
|
clipWrite: (t) => ipcRenderer.invoke('clip:write', t),
|
|
136
137
|
thinkSet: (v) => ipcRenderer.invoke('think:set', v),
|
package/src/renderer/i18n.js
CHANGED
|
@@ -427,6 +427,7 @@
|
|
|
427
427
|
tip_bb_mobile: 'Mobil önizleme — telefon siluetinde canlı uygulama (Expo/Metro dev server)',
|
|
428
428
|
tip_bb_fwd: 'İleri',
|
|
429
429
|
tip_bb_reload: 'Yenile',
|
|
430
|
+
tip_bb_restart: 'Yeniden başlat — takılan sayfayı sıfırdan açar (oturum korunur)',
|
|
430
431
|
tip_bb_shot: 'Ekran görüntüsünü sohbete ekle',
|
|
431
432
|
tip_bb_open: 'Tarayıcıda aç',
|
|
432
433
|
tip_bb_close: 'Kapat',
|
|
@@ -1250,6 +1251,7 @@
|
|
|
1250
1251
|
tip_bb_mobile: 'Mobile preview — live app in a phone frame (Expo/Metro dev server)',
|
|
1251
1252
|
tip_bb_fwd: 'Forward',
|
|
1252
1253
|
tip_bb_reload: 'Reload',
|
|
1254
|
+
tip_bb_restart: 'Restart — reopens the stuck page from scratch (session kept)',
|
|
1253
1255
|
tip_bb_shot: 'Add screenshot to chat',
|
|
1254
1256
|
tip_bb_open: 'Open in browser',
|
|
1255
1257
|
tip_bb_close: 'Close',
|
package/src/renderer/index.html
CHANGED
|
@@ -164,7 +164,7 @@
|
|
|
164
164
|
</div>
|
|
165
165
|
</div>
|
|
166
166
|
<div class="fin-card fin-card-trader" data-fin-card="trader">
|
|
167
|
-
<div class="fin-card-title">TRADE AJANI <span id="finTraderDot" class="fin-dot off" title="Trader durumu"></span><span class="file-spacer"></span><button id="finSetupBtn" title="MT5 kurulumunu uygula — BeastFinance.mq5 derle + AutoTrading izni + grafiğe ekle">🛠</button><button id="finModelRefreshBtn" title="Modelleri yeniden çek — eksik/güncel modelleri tazeler">⟳</button><button id="finSkillsBtn" title="Rol → skill eşleştirmesi — rol başına tek skill (çöp ikonuyla kaldırılır; boş = ajan kendi seçer)">⚙</button><button id="finAdvToggle" type="button" aria-expanded="false" title="Gelişmiş — disiplin kuralları + shadow mod"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px"><path d="M4 6h9"/><circle cx="16.5" cy="6" r="2.5"/><path d="M20 6h0.01"/><path d="M4 12h3"/><circle cx="10.5" cy="12" r="2.5"/><path d="M15 12h5"/><path d="M4 18h11"/><circle cx="18.5" cy="18" r="2.5"/></svg></button></div>
|
|
167
|
+
<div class="fin-card-title">TRADE AJANI <span id="finTraderDot" class="fin-dot off" title="Trader durumu"></span><span class="file-spacer"></span><button id="finSetupBtn" title="MT5 kurulumunu uygula — BeastFinance.mq5 derle + AutoTrading izni + grafiğe ekle">🛠</button><button id="finModelRefreshBtn" title="Modelleri yeniden çek — eksik/güncel modelleri tazeler">⟳</button><button id="finLearnBtn" title="MT5 öğrenme hafızası — neler öğrendi: sembol bazlı dersler + otomatik istatistik (görüntüle/sil)"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px"><path d="M12 5a3 3 0 1 0-5.997.125 4 4 0 0 0-2.526 5.77 4 4 0 0 0 .556 6.588A4 4 0 1 0 12 18Z"/><path d="M12 5a3 3 0 1 1 5.997.125 4 4 0 0 1 2.526 5.77 4 4 0 0 1-.556 6.588A4 4 0 1 1 12 18Z"/><path d="M15 13a4.5 4.5 0 0 1-3-4 4.5 4.5 0 0 1-3 4"/><path d="M17.599 6.5a3 3 0 0 0 .399-1.375"/><path d="M6.003 5.125A3 3 0 0 0 6.401 6.5"/><path d="M3.477 10.896a4 4 0 0 1 .585-.396"/><path d="M19.938 10.5a4 4 0 0 1 .585.396"/><path d="M6 18a4 4 0 0 1-1.967-.516"/><path d="M19.967 17.484A4 4 0 0 1 18 18"/></svg></button><button id="finSkillsBtn" title="Rol → skill eşleştirmesi — rol başına tek skill (çöp ikonuyla kaldırılır; boş = ajan kendi seçer)">⚙</button><button id="finAdvToggle" type="button" aria-expanded="false" title="Gelişmiş — disiplin kuralları + shadow mod"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px"><path d="M4 6h9"/><circle cx="16.5" cy="6" r="2.5"/><path d="M20 6h0.01"/><path d="M4 12h3"/><circle cx="10.5" cy="12" r="2.5"/><path d="M15 12h5"/><path d="M4 18h11"/><circle cx="18.5" cy="18" r="2.5"/></svg></button></div>
|
|
168
168
|
<div class="fin-field">
|
|
169
169
|
<span>Model</span>
|
|
170
170
|
<select id="finTraderModel" title="Trader ajanının modeli — farklı API/model seçilebilir"></select>
|
|
@@ -183,6 +183,7 @@
|
|
|
183
183
|
<input id="finMaxLot" type="number" min="0.01" max="100" step="0.01" title="Üst sınır: lot hesapları bu tavanın üzerine çıkamaz (min lotun altına inemez)" />
|
|
184
184
|
</div>
|
|
185
185
|
</div>
|
|
186
|
+
<div id="finSymLimits" class="fin-hint" hidden title="Trader'ın mt5_limits ile sembole özel koyduğu lot aralıkları — sembol limiti genel aralığı aşamaz; trader sembolü sıfırlarsa genel aralık geçerli olur"></div>
|
|
186
187
|
<div class="fin-field">
|
|
187
188
|
<span>Semboller</span>
|
|
188
189
|
<button id="finSymBtn" class="fin-sym-select" title="MT5 sembol listesinden seç — tıkla">…</button>
|
|
@@ -858,6 +859,21 @@
|
|
|
858
859
|
</div>
|
|
859
860
|
</div>
|
|
860
861
|
|
|
862
|
+
<div id="finLearnOverlay" class="mini-overlay" hidden>
|
|
863
|
+
<div class="mini-dialog fin-learn-dialog">
|
|
864
|
+
<div class="mini-head">
|
|
865
|
+
<span class="mini-title">MT5 ÖĞRENME HAFIZASI</span>
|
|
866
|
+
<span id="finLearnCount" class="fin-sym-count"></span>
|
|
867
|
+
<button id="finLearnClear" title="TÜM sembollerin derslerini sil — otomatik istatistikler korunur (depo şişmesi/zehirlenmesi önlenir)">Tüm dersleri sil</button>
|
|
868
|
+
<button class="mini-close" id="finLearnClose" title="Kapat">×</button>
|
|
869
|
+
</div>
|
|
870
|
+
<div class="mini-body">
|
|
871
|
+
<div id="finLearnList" class="mini-list"></div>
|
|
872
|
+
<div class="fin-sym-hint">Trade ajanının çekirdekteki sembol bazlı hafızası: her işlem kapanışı otomatik istatistiğe işlenir; ajan yalnız gerçekten öğretici, kısa bir içgörü olunca ders yazar (her kapanışa ders YAZMAZ — günlük en fazla 3, tek kısa cümle). Sembol satırına tıkla → kalıcı özeti, dersleri ve son işlemleri gör; ÖZET ile eski dersleri modele sıkıştırt (24+ ders birikince otomatik), tek dersi çöp ikonuyla sil, sembol kaydını tümden bırak. Hafıza sürekli sadeleşir: 30 günden eski dersler, 90 günden eski işlem kayıtları ve 120 gün hareketsiz semboller otomatik unutulur.</div>
|
|
873
|
+
</div>
|
|
874
|
+
</div>
|
|
875
|
+
</div>
|
|
876
|
+
|
|
861
877
|
<div id="finTeamOverlay" class="mini-overlay" hidden>
|
|
862
878
|
<div class="mini-dialog fin-sym-dialog">
|
|
863
879
|
<div class="mini-head">
|
|
@@ -942,6 +958,7 @@
|
|
|
942
958
|
<button id="bbBack" title="Geri" data-i18n-title="tip_bb_back">←</button>
|
|
943
959
|
<button id="bbFwd" title="İleri" data-i18n-title="tip_bb_fwd">→</button>
|
|
944
960
|
<button id="bbReload" title="Yenile" data-i18n-title="tip_bb_reload">↻</button>
|
|
961
|
+
<button id="bbRestart" title="Yeniden başlat — takılan sayfayı sıfırdan açar (oturum korunur)" data-i18n-title="tip_bb_restart">⟳</button>
|
|
945
962
|
<input id="bbUrl" placeholder="adres yaz veya ara…" autocomplete="off" spellcheck="false" data-i18n-ph="bb_ph" />
|
|
946
963
|
<button id="bbPhone" title="Telefon modu — mobil versiyon / web versiyonu" data-i18n-title="tip_bb_phone"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="7" y="2" width="10" height="20" rx="2.5"/><line x1="11" y1="18" x2="13" y2="18"/></svg></button>
|
|
947
964
|
<button id="bbOpenExt" title="Tarayıcıda aç" data-i18n-title="tip_bb_open">↗</button>
|
package/src/renderer/renderer.js
CHANGED
|
@@ -92,6 +92,7 @@ const els = {
|
|
|
92
92
|
bbBack: $('#bbBack'),
|
|
93
93
|
bbFwd: $('#bbFwd'),
|
|
94
94
|
bbReload: $('#bbReload'),
|
|
95
|
+
bbRestart: $('#bbRestart'),
|
|
95
96
|
bbUrl: $('#bbUrl'),
|
|
96
97
|
bbOpenExt: $('#bbOpenExt'),
|
|
97
98
|
bbClose: $('#bbClose'),
|
|
@@ -225,6 +226,7 @@ const els = {
|
|
|
225
226
|
finInterval: $('#finInterval'),
|
|
226
227
|
finMinLot: $('#finMinLot'),
|
|
227
228
|
finMaxLot: $('#finMaxLot'),
|
|
229
|
+
finSymLimits: $('#finSymLimits'),
|
|
228
230
|
finStrategy: $('#finStrategy'),
|
|
229
231
|
finMaxTradesDay: $('#finMaxTradesDay'),
|
|
230
232
|
finLossStreak: $('#finLossStreak'),
|
|
@@ -260,6 +262,12 @@ const els = {
|
|
|
260
262
|
finSkillsOverlay: $('#finSkillsOverlay'),
|
|
261
263
|
finSkillsClose: $('#finSkillsClose'),
|
|
262
264
|
finSkillsList: $('#finSkillsList'),
|
|
265
|
+
finLearnBtn: $('#finLearnBtn'),
|
|
266
|
+
finLearnOverlay: $('#finLearnOverlay'),
|
|
267
|
+
finLearnClose: $('#finLearnClose'),
|
|
268
|
+
finLearnList: $('#finLearnList'),
|
|
269
|
+
finLearnCount: $('#finLearnCount'),
|
|
270
|
+
finLearnClear: $('#finLearnClear'),
|
|
263
271
|
finSymSearch: $('#finSymSearch'),
|
|
264
272
|
finSymPick: $('#finSymPick'),
|
|
265
273
|
finSymCount: $('#finSymCount'),
|
|
@@ -7813,6 +7821,16 @@ async function init() {
|
|
|
7813
7821
|
els.bbBack.addEventListener('click', () => beast.browserCtrl('back'));
|
|
7814
7822
|
els.bbFwd.addEventListener('click', () => beast.browserCtrl('forward'));
|
|
7815
7823
|
els.bbReload.addEventListener('click', () => beast.browserCtrl('reload'));
|
|
7824
|
+
if (els.bbRestart) {
|
|
7825
|
+
els.bbRestart.addEventListener('click', async () => {
|
|
7826
|
+
try {
|
|
7827
|
+
const r = await beast.browserCtrl('restart');
|
|
7828
|
+
toast(r && r.ok ? 'Tarayıcı yeniden başlatıldı' : 'Tarayıcı yeniden başlatılamadı');
|
|
7829
|
+
} catch (e) {
|
|
7830
|
+
toast('Tarayıcı yeniden başlatılamadı');
|
|
7831
|
+
}
|
|
7832
|
+
});
|
|
7833
|
+
}
|
|
7816
7834
|
if (els.bbPhone) {
|
|
7817
7835
|
els.bbPhone.addEventListener('click', () => {
|
|
7818
7836
|
/* web ↔ mobil: aynı sitenin iki versiyonu arasındaki anahtar */
|
|
@@ -9804,6 +9822,30 @@ function finSymBtnUpdate() {
|
|
|
9804
9822
|
}
|
|
9805
9823
|
}
|
|
9806
9824
|
|
|
9825
|
+
/* SEMBOL BAZLI LOT LİMİTLERİ (trader kararı — mt5_limits symbol ile):
|
|
9826
|
+
genel min/max'tan sapmalar tek satırda gösterilir; trader sıfırlarsa satır kaybolur */
|
|
9827
|
+
function finSymLimitsRender(map) {
|
|
9828
|
+
const box = els.finSymLimits;
|
|
9829
|
+
if (!box) return;
|
|
9830
|
+
const rows = Object.entries(map && typeof map === 'object' ? map : {})
|
|
9831
|
+
.map(([sym, v]) => {
|
|
9832
|
+
const o = v && typeof v === 'object' ? v : {};
|
|
9833
|
+
const min = Number(o.minLot) > 0 ? Number(o.minLot) : 0;
|
|
9834
|
+
const max = Number(o.maxLot) > 0 ? Number(o.maxLot) : 0;
|
|
9835
|
+
if (!min && !max) return '';
|
|
9836
|
+
if (min && max) return sym + ' ' + min + '–' + max;
|
|
9837
|
+
return sym + (min ? ' ≥' + min : ' ≤' + max);
|
|
9838
|
+
})
|
|
9839
|
+
.filter(Boolean);
|
|
9840
|
+
if (!rows.length) {
|
|
9841
|
+
box.hidden = true;
|
|
9842
|
+
box.textContent = '';
|
|
9843
|
+
return;
|
|
9844
|
+
}
|
|
9845
|
+
box.hidden = false;
|
|
9846
|
+
box.textContent = 'Sembol lot limitleri (trader): ' + rows.join(' · ');
|
|
9847
|
+
}
|
|
9848
|
+
|
|
9807
9849
|
function finTraderInputsSet(cfg) {
|
|
9808
9850
|
if (!cfg) return;
|
|
9809
9851
|
if (!finWatchDirty) finWatchSet(cfg.symbols);
|
|
@@ -9815,6 +9857,7 @@ function finTraderInputsSet(cfg) {
|
|
|
9815
9857
|
if (els.finInterval && ae !== els.finInterval) els.finInterval.value = cfg.intervalSec || 120;
|
|
9816
9858
|
if (els.finMinLot && ae !== els.finMinLot) els.finMinLot.value = cfg.minLot || 0.01;
|
|
9817
9859
|
if (els.finMaxLot && ae !== els.finMaxLot) els.finMaxLot.value = cfg.maxLot || 0.1;
|
|
9860
|
+
finSymLimitsRender(cfg.symbolLimits);
|
|
9818
9861
|
if (els.finStrategy && ae !== els.finStrategy && !finStrategyDirty) els.finStrategy.value = cfg.strategy || '';
|
|
9819
9862
|
if (els.finMaxTradesDay && ae !== els.finMaxTradesDay) els.finMaxTradesDay.value = Number(cfg.maxTradesPerDay) || 0;
|
|
9820
9863
|
if (els.finLossStreak && ae !== els.finLossStreak) els.finLossStreak.value = Number(cfg.lossStreakLimit) || 0;
|
|
@@ -10187,14 +10230,17 @@ function finOnEvent(ev) {
|
|
|
10187
10230
|
if (ev.minLot !== undefined) finCfgCache.minLot = ev.minLot;
|
|
10188
10231
|
if (ev.maxLot !== undefined) finCfgCache.maxLot = ev.maxLot;
|
|
10189
10232
|
if (ev.maxPositions !== undefined) finCfgCache.maxPositions = ev.maxPositions;
|
|
10233
|
+
if (ev.symbols !== undefined) finCfgCache.symbolLimits = ev.symbols;
|
|
10190
10234
|
finTraderInputsSet(finCfgCache);
|
|
10191
10235
|
} else {
|
|
10192
10236
|
const ae2 = document.activeElement;
|
|
10193
10237
|
if (els.finMinLot && ae2 !== els.finMinLot && ev.minLot !== undefined) els.finMinLot.value = ev.minLot;
|
|
10194
10238
|
if (els.finMaxLot && ae2 !== els.finMaxLot && ev.maxLot !== undefined) els.finMaxLot.value = ev.maxLot;
|
|
10239
|
+
if (ev.symbols !== undefined) finSymLimitsRender(ev.symbols);
|
|
10195
10240
|
}
|
|
10196
10241
|
finLogLine('[limit] ' + (ev.note || ('min lot ' + ev.minLot + ' · max lot ' + ev.maxLot + ' · max pozisyon ' + ev.maxPositions)));
|
|
10197
|
-
|
|
10242
|
+
if (ev.symbol) toast('Sembol lot limiti güncellendi: ' + ev.symbol);
|
|
10243
|
+
else toast('Trader limitleri güncelledi: min ' + ev.minLot + ' / max ' + ev.maxLot);
|
|
10198
10244
|
} else if (ev.fn === 'install') {
|
|
10199
10245
|
finLogLine('[MT5] paket kurulumu tamamlandı (kod ' + ev.code + ')');
|
|
10200
10246
|
}
|
|
@@ -11030,6 +11076,303 @@ if (els.finSkillsOverlay) {
|
|
|
11030
11076
|
});
|
|
11031
11077
|
}
|
|
11032
11078
|
|
|
11079
|
+
/* ---------- MT5 ÖĞRENME HAFIZASI modalı (TRADE AJANI 🧠) ----------
|
|
11080
|
+
Çekirdekteki (main process) sembol bazlı öğrenme deposunu gösterir:
|
|
11081
|
+
otomatik istatistik + ajanın mt5_ogrenme ile yazdığı dersler. Tek ders
|
|
11082
|
+
silinebilir, sembol kaydı tümden bırakılabilir; depo tavanları
|
|
11083
|
+
(60 sembol / 60 ders / 60 işlem / günlük 3 ders; ders = kısa+somut) çekirdekte uygulanır. */
|
|
11084
|
+
const FIN_LEARN_TRASH_SVG =
|
|
11085
|
+
'<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px"><path d="M3 6h18"/><path d="M8 6V4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v2"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/><path d="M10 11v6"/><path d="M14 11v6"/></svg>';
|
|
11086
|
+
|
|
11087
|
+
let finLearnRows = [];
|
|
11088
|
+
let finLearnOpenSym = '';
|
|
11089
|
+
let finLearnBusy = false;
|
|
11090
|
+
|
|
11091
|
+
function finLearnCall(payload) {
|
|
11092
|
+
return beast.financeLearn(payload).catch(() => ({ ok: false }));
|
|
11093
|
+
}
|
|
11094
|
+
|
|
11095
|
+
function finLearnSign(v) {
|
|
11096
|
+
const n = Math.round((Number(v) || 0) * 100) / 100;
|
|
11097
|
+
return (n >= 0 ? '+' : '') + n;
|
|
11098
|
+
}
|
|
11099
|
+
|
|
11100
|
+
function finLearnTime(ts) {
|
|
11101
|
+
const t = Number(ts) || 0;
|
|
11102
|
+
if (!t) return '';
|
|
11103
|
+
const d = new Date(t);
|
|
11104
|
+
const p = (x) => String(x).padStart(2, '0');
|
|
11105
|
+
return p(d.getDate()) + '.' + p(d.getMonth() + 1) + ' ' + p(d.getHours()) + ':' + p(d.getMinutes());
|
|
11106
|
+
}
|
|
11107
|
+
|
|
11108
|
+
function finLearnKindLabel(kind) {
|
|
11109
|
+
return ({ pattern: 'desen', mistake: 'hata', rule: 'kural', observation: 'gözlem' })[String(kind || '')] || 'gözlem';
|
|
11110
|
+
}
|
|
11111
|
+
|
|
11112
|
+
function finLearnStatsText(st) {
|
|
11113
|
+
const trades = Number(st && st.trades) || 0;
|
|
11114
|
+
if (!trades) return '';
|
|
11115
|
+
const parts = [
|
|
11116
|
+
trades + ' işlem',
|
|
11117
|
+
'%' + Math.round(((Number(st.wins) || 0) / trades) * 100) + ' kazanç',
|
|
11118
|
+
'net ' + finLearnSign(st.net),
|
|
11119
|
+
];
|
|
11120
|
+
if (Number(st.streak) >= 2) parts.push(Number(st.streak) + ' ardışık kayıp');
|
|
11121
|
+
if (Number(st.givebacks) > 0) parts.push(Number(st.givebacks) + ' kez kâr geri verildi');
|
|
11122
|
+
if (st.lastAt) parts.push('son ' + finLearnSign(st.lastNet));
|
|
11123
|
+
return parts.join(' · ');
|
|
11124
|
+
}
|
|
11125
|
+
|
|
11126
|
+
async function finLearnOpen() {
|
|
11127
|
+
if (!els.finLearnOverlay) return;
|
|
11128
|
+
finLearnOpenSym = '';
|
|
11129
|
+
els.finLearnOverlay.hidden = false;
|
|
11130
|
+
await finLearnRefresh();
|
|
11131
|
+
}
|
|
11132
|
+
|
|
11133
|
+
function finLearnCloseModal() {
|
|
11134
|
+
if (els.finLearnOverlay) els.finLearnOverlay.hidden = true;
|
|
11135
|
+
}
|
|
11136
|
+
|
|
11137
|
+
async function finLearnRefresh() {
|
|
11138
|
+
const box = els.finLearnList;
|
|
11139
|
+
if (!box || finLearnBusy) return;
|
|
11140
|
+
finLearnBusy = true;
|
|
11141
|
+
box.innerHTML = '<div class="fin-empty">Öğrenme kayıtları yükleniyor…</div>';
|
|
11142
|
+
const r = await finLearnCall({ action: 'list' });
|
|
11143
|
+
finLearnBusy = false;
|
|
11144
|
+
finLearnRows = (r && Array.isArray(r.symbols)) ? r.symbols : [];
|
|
11145
|
+
finLearnRender();
|
|
11146
|
+
}
|
|
11147
|
+
|
|
11148
|
+
function finLearnRender() {
|
|
11149
|
+
const box = els.finLearnList;
|
|
11150
|
+
if (!box) return;
|
|
11151
|
+
box.textContent = '';
|
|
11152
|
+
if (els.finLearnCount) els.finLearnCount.textContent = finLearnRows.length ? finLearnRows.length + ' sembol' : '';
|
|
11153
|
+
if (!finLearnRows.length) {
|
|
11154
|
+
box.innerHTML = '<div class="fin-empty">Henüz öğrenilmiş bir şey yok — işlem kapandıkça istatistik, ajan ders yazdıkça kayıt burada birikir.</div>';
|
|
11155
|
+
return;
|
|
11156
|
+
}
|
|
11157
|
+
for (const row of finLearnRows) box.appendChild(finLearnSymEl(row));
|
|
11158
|
+
/* silme sonrası yeniden çizimde açık sembol detayı açık kalsın */
|
|
11159
|
+
if (finLearnOpenSym) {
|
|
11160
|
+
const el = [...box.children].find((c) => c.dataset && c.dataset.sym === finLearnOpenSym);
|
|
11161
|
+
if (el && el._finToggle) el._finToggle();
|
|
11162
|
+
}
|
|
11163
|
+
}
|
|
11164
|
+
|
|
11165
|
+
function finLearnSymEl(row) {
|
|
11166
|
+
const sym = String(row.symbol || '');
|
|
11167
|
+
const el = document.createElement('div');
|
|
11168
|
+
el.className = 'fin-learn-sym';
|
|
11169
|
+
el.dataset.sym = sym;
|
|
11170
|
+
const head = document.createElement('div');
|
|
11171
|
+
head.className = 'fin-learn-sym-head';
|
|
11172
|
+
const name = document.createElement('b');
|
|
11173
|
+
name.textContent = sym;
|
|
11174
|
+
const stats = document.createElement('span');
|
|
11175
|
+
stats.className = 'fin-learn-sym-stats';
|
|
11176
|
+
stats.textContent = finLearnStatsText(row.stats) || 'henüz kapanan işlem yok';
|
|
11177
|
+
const noteCount = document.createElement('span');
|
|
11178
|
+
noteCount.className = 'fin-learn-sym-notes';
|
|
11179
|
+
noteCount.textContent = (Number(row.notes) || 0) + ' ders' + (row.hasSummary ? ' · özet' : '');
|
|
11180
|
+
/* ÖZETLE (opencode tarzı compaction): eski dersler modele özetlettirilir */
|
|
11181
|
+
const sum = document.createElement('button');
|
|
11182
|
+
sum.type = 'button';
|
|
11183
|
+
sum.className = 'fin-learn-sum-btn';
|
|
11184
|
+
sum.title = 'Eski dersleri modele özetlet — hafıza sadeleşir (24+ ders birikince otomatik de çalışır)';
|
|
11185
|
+
sum.textContent = 'ÖZET';
|
|
11186
|
+
sum.addEventListener('click', async (e) => {
|
|
11187
|
+
e.stopPropagation();
|
|
11188
|
+
sum.disabled = true;
|
|
11189
|
+
sum.textContent = '…';
|
|
11190
|
+
const r = await finLearnCall({ action: 'compact', symbol: sym });
|
|
11191
|
+
sum.disabled = false;
|
|
11192
|
+
sum.textContent = 'ÖZET';
|
|
11193
|
+
if (r && r.ok) {
|
|
11194
|
+
toast(sym + ' özetlendi: ' + (Number(r.covered) || 0) + ' eski ders kalıcı özete sıkıştı');
|
|
11195
|
+
await finLearnRefresh();
|
|
11196
|
+
} else {
|
|
11197
|
+
toast('Özetlenemedi: ' + ((r && r.error) || '?'));
|
|
11198
|
+
}
|
|
11199
|
+
});
|
|
11200
|
+
const drop = document.createElement('button');
|
|
11201
|
+
drop.type = 'button';
|
|
11202
|
+
drop.className = 'fin-learn-drop';
|
|
11203
|
+
drop.title = sym + ' kaydını TÜMDEN sil (dersler + otomatik istatistik)';
|
|
11204
|
+
drop.innerHTML = FIN_LEARN_TRASH_SVG;
|
|
11205
|
+
drop.addEventListener('click', async (e) => {
|
|
11206
|
+
e.stopPropagation();
|
|
11207
|
+
const ok = await uiConfirm(sym + ' için TÜM öğrenme kaydı (dersler + istatistik) silinsin mi?', 'Sil', 'Vazgeç');
|
|
11208
|
+
if (!ok) return;
|
|
11209
|
+
await finLearnCall({ action: 'drop', symbol: sym });
|
|
11210
|
+
if (finLearnOpenSym === sym) finLearnOpenSym = '';
|
|
11211
|
+
toast(sym + ' öğrenme kaydı silindi');
|
|
11212
|
+
await finLearnRefresh();
|
|
11213
|
+
});
|
|
11214
|
+
head.appendChild(name);
|
|
11215
|
+
head.appendChild(stats);
|
|
11216
|
+
head.appendChild(noteCount);
|
|
11217
|
+
head.appendChild(sum);
|
|
11218
|
+
head.appendChild(drop);
|
|
11219
|
+
el.appendChild(head);
|
|
11220
|
+
|
|
11221
|
+
const body = document.createElement('div');
|
|
11222
|
+
body.className = 'fin-learn-body';
|
|
11223
|
+
body.hidden = true;
|
|
11224
|
+
el.appendChild(body);
|
|
11225
|
+
let loaded = false;
|
|
11226
|
+
let busy = false;
|
|
11227
|
+
el._finToggle = async () => {
|
|
11228
|
+
if (busy) return;
|
|
11229
|
+
if (loaded && !body.hidden) {
|
|
11230
|
+
body.hidden = true;
|
|
11231
|
+
if (finLearnOpenSym === sym) finLearnOpenSym = '';
|
|
11232
|
+
return;
|
|
11233
|
+
}
|
|
11234
|
+
if (loaded) {
|
|
11235
|
+
body.hidden = false;
|
|
11236
|
+
finLearnOpenSym = sym;
|
|
11237
|
+
return;
|
|
11238
|
+
}
|
|
11239
|
+
busy = true;
|
|
11240
|
+
body.hidden = false;
|
|
11241
|
+
finLearnOpenSym = sym;
|
|
11242
|
+
body.innerHTML = '<div class="fin-empty">yükleniyor…</div>';
|
|
11243
|
+
const d = await finLearnCall({ action: 'list', symbol: sym, limit: 25 });
|
|
11244
|
+
if (!els.finLearnOverlay || els.finLearnOverlay.hidden) { busy = false; return; }
|
|
11245
|
+
finLearnDetail(body, sym, d);
|
|
11246
|
+
loaded = true;
|
|
11247
|
+
busy = false;
|
|
11248
|
+
};
|
|
11249
|
+
head.addEventListener('click', () => { el._finToggle(); });
|
|
11250
|
+
return el;
|
|
11251
|
+
}
|
|
11252
|
+
|
|
11253
|
+
function finLearnDetail(body, sym, d) {
|
|
11254
|
+
body.textContent = '';
|
|
11255
|
+
const st = (d && d.stats) || {};
|
|
11256
|
+
const info = document.createElement('div');
|
|
11257
|
+
info.className = 'fin-learn-detail-stats';
|
|
11258
|
+
const trades = Number(st.trades) || 0;
|
|
11259
|
+
const bits = [];
|
|
11260
|
+
if (trades) {
|
|
11261
|
+
bits.push(`${trades} işlem · ${Number(st.wins) || 0} kazanç · ${Number(st.losses) || 0} kayıp`);
|
|
11262
|
+
bits.push(`net ${finLearnSign(st.net)} · en iyi ${finLearnSign(st.bestNet)} · en kötü ${finLearnSign(st.worstNet)}`);
|
|
11263
|
+
bits.push(`MFE toplam ${finLearnSign(st.mfe)} · MAE toplam ${finLearnSign(st.mae)}`);
|
|
11264
|
+
if (Number(st.givebacks) > 0) bits.push(`${Number(st.givebacks)} kez kâr geri verildi (${finLearnSign(st.givebackAmount)})`);
|
|
11265
|
+
} else {
|
|
11266
|
+
bits.push('Bu sembolde henüz kapanan işlem yok — istatistik ilk kapanışta oluşur.');
|
|
11267
|
+
}
|
|
11268
|
+
info.textContent = bits.join(' — ');
|
|
11269
|
+
body.appendChild(info);
|
|
11270
|
+
|
|
11271
|
+
/* KALICI ÖZET (opencode tarzı compaction): eski derslerin modele
|
|
11272
|
+
özetlettirilmiş hâli — ham dersler silinse de bilgi burada kalır */
|
|
11273
|
+
const summ = d && d.summary && d.summary.text ? d.summary : null;
|
|
11274
|
+
if (summ) {
|
|
11275
|
+
const sHead = document.createElement('div');
|
|
11276
|
+
sHead.className = 'fin-learn-sec';
|
|
11277
|
+
sHead.textContent = 'KALICI ÖZET (opencode tarzı sıkıştırma' +
|
|
11278
|
+
(Number(summ.covered) ? ' · ' + Number(summ.covered) + ' eski ders' : '') + ')';
|
|
11279
|
+
body.appendChild(sHead);
|
|
11280
|
+
const sBox = document.createElement('div');
|
|
11281
|
+
sBox.className = 'fin-learn-summary';
|
|
11282
|
+
sBox.textContent = String(summ.text || '');
|
|
11283
|
+
body.appendChild(sBox);
|
|
11284
|
+
const sAt = document.createElement('div');
|
|
11285
|
+
sAt.className = 'fin-learn-summary-at';
|
|
11286
|
+
sAt.textContent = 'güncelleme: ' + finLearnTime(summ.at);
|
|
11287
|
+
body.appendChild(sAt);
|
|
11288
|
+
}
|
|
11289
|
+
|
|
11290
|
+
const notes = (d && Array.isArray(d.notes)) ? d.notes : [];
|
|
11291
|
+
const nHead = document.createElement('div');
|
|
11292
|
+
nHead.className = 'fin-learn-sec';
|
|
11293
|
+
nHead.textContent = 'DERSLER (' + notes.length + ')';
|
|
11294
|
+
body.appendChild(nHead);
|
|
11295
|
+
if (!notes.length) {
|
|
11296
|
+
const e = document.createElement('div');
|
|
11297
|
+
e.className = 'fin-empty';
|
|
11298
|
+
e.textContent = 'Ders yok — ajan yalnız gerçekten öğretici, kısa bir içgörü olunca mt5_ogrenme ile buraya yazar (her kapanışa ders yazmaz).';
|
|
11299
|
+
body.appendChild(e);
|
|
11300
|
+
} else {
|
|
11301
|
+
for (const n of notes.slice().reverse()) {
|
|
11302
|
+
const rowEl = document.createElement('div');
|
|
11303
|
+
rowEl.className = 'fin-learn-note';
|
|
11304
|
+
const kind = document.createElement('span');
|
|
11305
|
+
kind.className = 'fin-learn-kind k-' + String(n.kind || 'observation');
|
|
11306
|
+
kind.textContent = finLearnKindLabel(n.kind);
|
|
11307
|
+
const txt = document.createElement('span');
|
|
11308
|
+
txt.className = 'fin-learn-note-text';
|
|
11309
|
+
txt.textContent = String(n.text || '');
|
|
11310
|
+
txt.title = txt.textContent;
|
|
11311
|
+
const at = document.createElement('span');
|
|
11312
|
+
at.className = 'fin-learn-note-at';
|
|
11313
|
+
at.textContent = finLearnTime(n.at);
|
|
11314
|
+
const del = document.createElement('button');
|
|
11315
|
+
del.type = 'button';
|
|
11316
|
+
del.className = 'fin-learn-note-del';
|
|
11317
|
+
del.title = 'Bu dersi sil — yanlış/geçersiz ders hafızayı zehirlemesin';
|
|
11318
|
+
del.innerHTML = FIN_LEARN_TRASH_SVG;
|
|
11319
|
+
del.addEventListener('click', async () => {
|
|
11320
|
+
const r = await finLearnCall({ action: 'remove', id: n.id, symbol: sym });
|
|
11321
|
+
if (r && r.ok) {
|
|
11322
|
+
toast('Ders silindi');
|
|
11323
|
+
await finLearnRefresh();
|
|
11324
|
+
} else {
|
|
11325
|
+
toast('Ders silinemedi');
|
|
11326
|
+
}
|
|
11327
|
+
});
|
|
11328
|
+
rowEl.appendChild(kind);
|
|
11329
|
+
rowEl.appendChild(txt);
|
|
11330
|
+
rowEl.appendChild(at);
|
|
11331
|
+
rowEl.appendChild(del);
|
|
11332
|
+
body.appendChild(rowEl);
|
|
11333
|
+
}
|
|
11334
|
+
}
|
|
11335
|
+
|
|
11336
|
+
const tradeRows = (d && Array.isArray(d.trades)) ? d.trades : [];
|
|
11337
|
+
if (tradeRows.length) {
|
|
11338
|
+
const tHead = document.createElement('div');
|
|
11339
|
+
tHead.className = 'fin-learn-sec';
|
|
11340
|
+
tHead.textContent = 'SON İŞLEMLER (otomatik)';
|
|
11341
|
+
body.appendChild(tHead);
|
|
11342
|
+
for (const t of tradeRows.slice().reverse()) {
|
|
11343
|
+
const tr = document.createElement('div');
|
|
11344
|
+
tr.className = 'fin-learn-trade ' + (Number(t.net) < 0 ? 'loss' : 'win');
|
|
11345
|
+
const side = String(t.side || '').toLowerCase();
|
|
11346
|
+
const sideTxt = side === 'buy' ? 'AL' : side === 'sell' ? 'SAT' : (side || '?');
|
|
11347
|
+
tr.textContent = `${finLearnTime(t.at)} · ${sideTxt} · ${finLearnSign(t.net)}` +
|
|
11348
|
+
(t.mfe != null ? ` · MFE ${finLearnSign(t.mfe)}` : '') +
|
|
11349
|
+
(t.mae != null ? ` · MAE ${finLearnSign(t.mae)}` : '') +
|
|
11350
|
+
(t.reason ? ` · ${String(t.reason)}` : '');
|
|
11351
|
+
body.appendChild(tr);
|
|
11352
|
+
}
|
|
11353
|
+
}
|
|
11354
|
+
}
|
|
11355
|
+
|
|
11356
|
+
if (els.finLearnBtn) els.finLearnBtn.addEventListener('click', () => { finLearnOpen(); });
|
|
11357
|
+
if (els.finLearnClose) els.finLearnClose.addEventListener('click', finLearnCloseModal);
|
|
11358
|
+
if (els.finLearnOverlay) {
|
|
11359
|
+
els.finLearnOverlay.addEventListener('click', (e) => {
|
|
11360
|
+
if (e.target === els.finLearnOverlay) finLearnCloseModal();
|
|
11361
|
+
});
|
|
11362
|
+
els.finLearnOverlay.addEventListener('keydown', (e) => {
|
|
11363
|
+
if (e.key === 'Escape') { e.stopPropagation(); finLearnCloseModal(); }
|
|
11364
|
+
});
|
|
11365
|
+
}
|
|
11366
|
+
if (els.finLearnClear) {
|
|
11367
|
+
els.finLearnClear.addEventListener('click', async () => {
|
|
11368
|
+
const ok = await uiConfirm('TÜM sembollerin öğrenme DERSLERİ silinsin mi? Otomatik istatistikler korunur; işlem geri alınamaz.', 'Tümünü sil', 'Vazgeç');
|
|
11369
|
+
if (!ok) return;
|
|
11370
|
+
const r = await finLearnCall({ action: 'clear', all: true });
|
|
11371
|
+
toast(r && r.ok ? ('Dersler temizlendi' + (r.removed ? ' (' + r.removed + ' kayıt)' : '')) : 'Dersler temizlenemedi');
|
|
11372
|
+
await finLearnRefresh();
|
|
11373
|
+
});
|
|
11374
|
+
}
|
|
11375
|
+
|
|
11033
11376
|
if (els.finSymAdd) els.finSymAdd.addEventListener('click', finSymPickerOpen);
|
|
11034
11377
|
if (els.finWatchClear) {
|
|
11035
11378
|
els.finWatchClear.addEventListener('click', async () => {
|
package/src/renderer/style.css
CHANGED
|
@@ -5843,6 +5843,121 @@ body.finance-mode #composerWrap { margin-right: var(--finW, 400px); }
|
|
|
5843
5843
|
.fin-skill-chip.on { border-color: var(--accent); color: var(--accent); background: var(--accent-dim); }
|
|
5844
5844
|
.fin-skill-chip input { flex: none; width: auto; margin: 0; }
|
|
5845
5845
|
|
|
5846
|
+
/* MT5 ÖĞRENME HAFIZASI modalı (TRADE AJANI 🧠) */
|
|
5847
|
+
.fin-learn-dialog { width: 580px; max-width: calc(100vw - 40px); }
|
|
5848
|
+
.fin-learn-dialog .mini-body {
|
|
5849
|
+
flex: 1;
|
|
5850
|
+
min-height: 0;
|
|
5851
|
+
display: flex;
|
|
5852
|
+
flex-direction: column;
|
|
5853
|
+
overflow: hidden;
|
|
5854
|
+
}
|
|
5855
|
+
#finLearnList {
|
|
5856
|
+
flex: 1;
|
|
5857
|
+
min-height: 0;
|
|
5858
|
+
overflow-y: auto;
|
|
5859
|
+
display: flex;
|
|
5860
|
+
flex-direction: column;
|
|
5861
|
+
gap: 8px;
|
|
5862
|
+
}
|
|
5863
|
+
#finLearnClear {
|
|
5864
|
+
flex: none;
|
|
5865
|
+
border: 1px solid var(--border);
|
|
5866
|
+
background: var(--panel2);
|
|
5867
|
+
color: var(--muted);
|
|
5868
|
+
font-size: 10.5px;
|
|
5869
|
+
font-weight: 700;
|
|
5870
|
+
border-radius: 7px;
|
|
5871
|
+
padding: 4px 8px;
|
|
5872
|
+
cursor: pointer;
|
|
5873
|
+
margin-right: 6px;
|
|
5874
|
+
}
|
|
5875
|
+
#finLearnClear:hover { color: #ef4444; border-color: #ef4444; }
|
|
5876
|
+
.fin-learn-sym { border: 1px solid var(--border); border-radius: 8px; padding: 7px 9px; background: var(--panel2); }
|
|
5877
|
+
.fin-learn-sym-head { display: flex; align-items: center; gap: 7px; cursor: pointer; }
|
|
5878
|
+
.fin-learn-sym-head b { flex: none; font-size: 12px; color: var(--accent); }
|
|
5879
|
+
.fin-learn-sym-stats {
|
|
5880
|
+
flex: 1;
|
|
5881
|
+
min-width: 0;
|
|
5882
|
+
font-size: 10px;
|
|
5883
|
+
color: var(--muted);
|
|
5884
|
+
overflow: hidden;
|
|
5885
|
+
text-overflow: ellipsis;
|
|
5886
|
+
white-space: nowrap;
|
|
5887
|
+
}
|
|
5888
|
+
.fin-learn-sym-notes { flex: none; font-size: 9.5px; font-weight: 800; letter-spacing: 0.4px; color: var(--muted); }
|
|
5889
|
+
.fin-learn-sum-btn {
|
|
5890
|
+
flex: none;
|
|
5891
|
+
border: 1px solid var(--border);
|
|
5892
|
+
background: var(--panel);
|
|
5893
|
+
color: var(--muted);
|
|
5894
|
+
font-size: 9px;
|
|
5895
|
+
font-weight: 800;
|
|
5896
|
+
letter-spacing: 0.4px;
|
|
5897
|
+
border-radius: 5px;
|
|
5898
|
+
padding: 2px 6px;
|
|
5899
|
+
cursor: pointer;
|
|
5900
|
+
}
|
|
5901
|
+
.fin-learn-sum-btn:hover { color: var(--accent); border-color: var(--accent); }
|
|
5902
|
+
.fin-learn-sum-btn:disabled { opacity: 0.5; cursor: default; }
|
|
5903
|
+
.fin-learn-summary {
|
|
5904
|
+
border: 1px solid var(--border);
|
|
5905
|
+
border-left: 3px solid var(--accent);
|
|
5906
|
+
border-radius: 6px;
|
|
5907
|
+
background: var(--panel);
|
|
5908
|
+
padding: 6px 8px;
|
|
5909
|
+
font-size: 10.5px;
|
|
5910
|
+
color: var(--text);
|
|
5911
|
+
line-height: 1.45;
|
|
5912
|
+
word-break: break-word;
|
|
5913
|
+
}
|
|
5914
|
+
.fin-learn-summary-at { font-size: 9px; color: var(--muted); margin: 3px 0 2px; }
|
|
5915
|
+
.fin-learn-drop,
|
|
5916
|
+
.fin-learn-note-del {
|
|
5917
|
+
flex: none;
|
|
5918
|
+
border: none;
|
|
5919
|
+
background: none;
|
|
5920
|
+
color: var(--muted);
|
|
5921
|
+
line-height: 0;
|
|
5922
|
+
padding: 3px 4px;
|
|
5923
|
+
border-radius: 6px;
|
|
5924
|
+
cursor: pointer;
|
|
5925
|
+
}
|
|
5926
|
+
.fin-learn-drop:hover,
|
|
5927
|
+
.fin-learn-note-del:hover { color: #ef4444; background: var(--accent-dim); }
|
|
5928
|
+
.fin-learn-body { margin-top: 6px; border-top: 1px dashed var(--border); padding-top: 6px; }
|
|
5929
|
+
.fin-learn-detail-stats { font-size: 10px; color: var(--muted); margin-bottom: 6px; }
|
|
5930
|
+
.fin-learn-sec { font-size: 9.5px; font-weight: 800; letter-spacing: 0.5px; color: var(--muted); margin: 6px 0 4px; }
|
|
5931
|
+
.fin-learn-note {
|
|
5932
|
+
display: flex;
|
|
5933
|
+
align-items: flex-start;
|
|
5934
|
+
gap: 6px;
|
|
5935
|
+
padding: 4px 5px;
|
|
5936
|
+
border-radius: 6px;
|
|
5937
|
+
background: var(--panel);
|
|
5938
|
+
border: 1px solid var(--border);
|
|
5939
|
+
margin-bottom: 4px;
|
|
5940
|
+
}
|
|
5941
|
+
.fin-learn-kind {
|
|
5942
|
+
flex: none;
|
|
5943
|
+
font-size: 9px;
|
|
5944
|
+
font-weight: 800;
|
|
5945
|
+
letter-spacing: 0.4px;
|
|
5946
|
+
border-radius: 5px;
|
|
5947
|
+
padding: 2px 5px;
|
|
5948
|
+
border: 1px solid var(--border);
|
|
5949
|
+
color: var(--muted);
|
|
5950
|
+
text-transform: uppercase;
|
|
5951
|
+
}
|
|
5952
|
+
.fin-learn-kind.k-pattern { color: #22c55e; border-color: #22c55e; }
|
|
5953
|
+
.fin-learn-kind.k-mistake { color: #ef4444; border-color: #ef4444; }
|
|
5954
|
+
.fin-learn-kind.k-rule { color: #e6a117; border-color: #e6a117; }
|
|
5955
|
+
.fin-learn-note-text { flex: 1; min-width: 0; font-size: 10.5px; color: var(--text); word-break: break-word; }
|
|
5956
|
+
.fin-learn-note-at { flex: none; font-size: 9px; color: var(--muted); }
|
|
5957
|
+
.fin-learn-trade { font-size: 10px; color: var(--muted); padding: 2px 4px; border-radius: 5px; }
|
|
5958
|
+
.fin-learn-trade.win { color: #22c55e; }
|
|
5959
|
+
.fin-learn-trade.loss { color: #ef4444; }
|
|
5960
|
+
|
|
5846
5961
|
/* FINANCE GÖRÜNÜM AYARLARI modalı (başlıktaki ⚙) — isteğe bağlı bölümler */
|
|
5847
5962
|
.fin-card[hidden] { display: none; }
|
|
5848
5963
|
.fin-settings-dialog { width: min(440px, 90vw); height: auto; max-height: min(560px, 84vh); }
|