beast-agent 2.63.2 → 2.63.4
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 +13 -4
- package/src/agent/financetools.js +50 -17
- package/src/agent/finrisk.js +16 -6
- package/src/agent/seeds/risk-yonetimi/SKILL.md +52 -52
- package/src/main.js +228 -34
- package/src/renderer/index.html +3 -2
- package/src/renderer/renderer.js +36 -4
package/package.json
CHANGED
package/src/agent/engine.js
CHANGED
|
@@ -2032,7 +2032,7 @@ class Engine {
|
|
|
2032
2032
|
modeBlock2 + '\n' +
|
|
2033
2033
|
(roleBlockFull ? roleBlockFull + '\n' : '') +
|
|
2034
2034
|
(teamLine || '') +
|
|
2035
|
-
'MT5 ARAÇLARI: mt5_status (bağlantı), mt5_account (hesap), mt5_market (canlı fiyat), mt5_positions (açık pozisyonlar), mt5_orders (bekleyen emirler), mt5_history (kapanan işlemler), mt5_alerts (fiyat alarmı: kur/listele/sil — modu SEN seçersin: once/repeat), mt5_ogrenme (SEMBOL BAZLI ÖĞRENME: işlem istatistiği + dersler —
|
|
2035
|
+
'MT5 ARAÇLARI: mt5_status (bağlantı), mt5_account (hesap), mt5_market (canlı fiyat), mt5_positions (açık pozisyonlar), mt5_orders (bekleyen emirler), mt5_history (kapanan işlemler), mt5_alerts (fiyat alarmı: kur/listele/sil — modu SEN seçersin: once/repeat), mt5_ogrenme (SEMBOL BAZLI ÖĞRENME: işlem istatistiği + dersler — yalnız gerçekten öğretici kısa içgörüyü yaz, karar öncesi oku), mt5_limits (lot/pozisyon limitlerini gör/GÜNCELLE — yalnız trader; symbol ile SEMBOL BAZLI min/max lot — sembolün karakterine göre karar senin), mt5_ea (BeastFinance grafik panosu: status/ping/chart/note), mt5_trade (⚡PİYASA EMRİ: side:"buy"|"sell" ile ANLIK gir — bekleyen emir ZORUNLU DEĞİL; lot için volume yerine riskPct+sl ver, sistem hesaplar; limit/stop tipleri de kabul eder), mt5_close (TAM ya da KISMİ kapat: percent ile kısmi TP & kısmi stop — karar ajanın), mt5_modify (SL/TP), mt5_pending (BEKLEYEN emir: limit/stop + price — fiyatın seviyeye gelmesini beklemek için; anlık giriş için mt5_trade kullan), mt5_cancel (emir iptal).\n' +
|
|
2036
2036
|
'EMİR TİPLERİ (6 tip — HEPSİ AÇIK): buy_market/sell_market = anlık piyasa emri (fiyat beklenmez), buy_limit/sell_limit = bekleyen limit (price zorunlu), buy_stop/sell_stop = bekleyen stop (price zorunlu). mt5_trade ve mt5_pending İKİSİ DE 6 tipi kabul eder; emir tipini net söyle (ör. type:"sell_limit").\n' +
|
|
2037
2037
|
'⚡HIZLI AKSİYON (ZORUNLU ZİHNİYET): piyasa emri (market buy/sell) HER ZAMAN elinde ve bekleyen emir vermek ZORUNDA DEĞİLSİN. Fırsat anıksa / teyitli kırılım, momentum, haber veya seviye reddi anında mt5_trade {symbol, side:"buy"|"sell", sl, tp, riskPct ya da volume, reason} ile ANINDA market gir — type bile yazmana gerek yok. Bekleyen emir YALNIZ fiyatın seviyeye gelmesini beklemek gerçekten mantıklıysa kurulur (ör. geri çekilme limiti); "emir" diye her şeyi bekleyen emirle yapma. Hızlı girişte tek çağrı yeter: volume yerine riskPct+sl ver → lot otomatik hesaplanır.\n' +
|
|
2038
2038
|
'ALARM KARARI SENDE: mt5_alerts ile alarm kurarken mode ZORUNLU — "once" (tek seferlik; ilk tetiklemede kapanır) ya da "repeat" (tekrarlı; alarm açık kalır, koşul sürdükçe cooldownMin dakikada bir tekrar uyarır + seni uyandırır; cooldownMin varsayılan 5). Tekrarlı mı tek seferlik mi olacağını sen seç, varsayılana bırakma; seviyenin önemine göre cooldownMin belirle (ör. 5/15/60).\n' +
|
|
@@ -2064,17 +2064,26 @@ class Engine {
|
|
|
2064
2064
|
lim.maxLot ? `max lot ${lim.maxLot}` : null,
|
|
2065
2065
|
lim.maxPositions ? `max eşzamanlı pozisyon ${lim.maxPositions}` : null,
|
|
2066
2066
|
].filter(Boolean).join(' · ') +
|
|
2067
|
-
'
|
|
2067
|
+
' (genel).' +
|
|
2068
|
+
(lim.symbolLimits && Object.keys(lim.symbolLimits).length
|
|
2069
|
+
? ' SEMBOL BAZLI: ' +
|
|
2070
|
+
Object.entries(lim.symbolLimits)
|
|
2071
|
+
.map(([s, v]) => `${s} ${Number(v && v.minLot) > 0 ? Number(v.minLot) : lim.minLot}–${Number(v && v.maxLot) > 0 ? Number(v.maxLot) : lim.maxLot}`)
|
|
2072
|
+
.join(' · ') +
|
|
2073
|
+
' — sembol limiti önceliklidir.'
|
|
2074
|
+
: '') +
|
|
2075
|
+
' Bunları aşıp araç kullanma; sistem zaten reddeder (lot min lot altına inemez, max lot üstüne çıkamaz).\n'
|
|
2068
2076
|
: '') +
|
|
2077
|
+
'TUR RİTMİ (yalnız trader kararı): mt5_limits {action:"set", intervalSec, intervalForMin} ile tur aralığını ayarlarsın — sert hareket/haber anında geçici hızlan (ör. 45-60 sn × 10-20 dk), sakinleşince geri çek (ör. 180-300 sn); süre dolunca taban aralığa OTOMATİK dönülür. SÜREKLİ en düşük aralıkta kalma — API/maliyet limitini koru; hız modu sınırları sistemce zorlanır.\n' +
|
|
2069
2078
|
'RİSK DİSİPLİNİ:\n' +
|
|
2070
2079
|
'- SL\u2019siz pozisyon BIRAKMA: açtığın her işlemde mantıklı bir SL koy; SL\u2019siz kalan pozisyonu mt5_modify ile tamamla.\n' +
|
|
2071
2080
|
'- KÂR KORUMA (SİSTEM OTOMATİK): kâr 0.3R\'ye ulaşınca SL, görülen en iyi kârın 0.15R gerisine kilitlenir — kâr eksiye dönmez. Bu yüzden kârı erken koru; hedefe ulaşmayan işlemde bile kârı geri verme.\n' +
|
|
2072
2081
|
'- TP İÇİN RR ≥ 1.5 ŞARTI YOK: scalp/hızlı işlemlerde TP 0.3R-0.5R olabilir. Kısmi kâr alımı SERBEST ve TEŞVİK EDİLİR: 0.3-0.5R\'de pozisyonun bir kısmını mt5_close {percent, kind:"partial_tp"} ile realize et, kalanı korumalı trailing ile taşı. Amaç: sık işlem + hızlı kâr toplama; kârı masada bekletme.\n' +
|
|
2073
2082
|
'- Martingale/kademeli lot artışı YASAK; kaybı geri kovalama (revenge trade) YASAK.\n' +
|
|
2074
2083
|
'- Emin olmadığında İŞLEM YOK — "BEKLE: <sebep>" yaz. Sık işlem tek başına iyi işlem değil; ama onaylı fırsatta HIZLI gir, kârı hızlı topla.\n' +
|
|
2075
|
-
'-
|
|
2084
|
+
'- LOT KORKUSU YOK — önemli olan LOT DEĞİL, STOP YERİ ve risktir: SL yakın ve setup netse yüksek lot NORMALDİR (boyut zaten risk % + SL mesafesinden hesaplanır; sembol tavanı trader kararıdır). Tek işlemde serbest marjın tamamını riske atma; sık işlem için lotu değil, TUR RİTMİNİ (mt5_limits intervalSec) ve kısmi kâr alımını kullan.\n' +
|
|
2076
2085
|
(session && session.financeLearn ? `SEMBOL BAZLI ÖĞRENME HAFIZAN (otomatik istatistik + kendi derslerin — kararlarında kullan):\n${session.financeLearn}\n` : '') +
|
|
2077
|
-
'ÖĞRENME DÖNGÜSÜ (
|
|
2086
|
+
'ÖĞRENME DÖNGÜSÜ (SEÇİCİ — ders çıkarmak zorunlu DEĞİL): yalnız GERÇEKTEN öğrenilmiş, tekrar kullanılabilir, kanıtlı bir içgörü varsa tek KISA cümleyle kaydet: mt5_ogrenme {action:"add", symbol, text, kind}. İyi ders: "XAUUSD M5 EMA50 üstü Londra açılışı momentumu 3/4 işledi" gibi somut, sebep-sonuç içeren, en fazla ~20 kelimelik cümle. YASAK: her kapanışa ders yazmak, günlük/rapor tarzı uzun metin ("bugün şunu yaptım"), genel laf ("dikkatli olmalıyım"), tekrar. Emin değilsen HİÇ ders yazma — hafızayı çöple doldurma; günde en fazla 2-3 ders. Yeni karar öncesi mt5_ogrenme {action:"stats", symbol} ya da list ile o sembolün geçmişini oku (kalıcı özet + son dersler) — aynı hatayı tekrarlama, işleyen deseni kullan. Hafıza kendini sadeleştirir: eski dersler otomatik özetlenir ve süresi geçenler unutulur; gerekirse mt5_ogrenme {action:"compact", symbol} ile hemen özetlet, geçersiz dersi remove/clear ile sil.\n' +
|
|
2078
2087
|
(session && session.financeStrategy ? `SAHİBİNİN STRATEJİ NOTU (önceliklidir):\n${session.financeStrategy}\n` : '') +
|
|
2079
2088
|
(session && session.financeShadow ? 'SHADOW MOD AKTİF: mt5_trade/mt5_pending emir GÖNDERMEZ — kararını teziyle raporla; gerçek işlem açılmaz (karar günlüğe yazılır).\n' : '') +
|
|
2080
2089
|
(session && session.financeDigest ? `İŞLEM PERFORMANS GEÇMİŞİN (kendi kayıtların — kararlarında ders çıkar):\n${session.financeDigest}\n` : '') +
|
|
@@ -101,6 +101,19 @@ function tickPrice(row, side) {
|
|
|
101
101
|
return Number(row && row.bid) || Number(row && row.ask) || 0;
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
/* SEMBOL BAZLI LOT ARALIĞI (trader mt5_limits ile koyar): sembol limiti
|
|
105
|
+
varsa genel aralığın yerine geçer — yoksa genel minLot/maxLot kullanılır.
|
|
106
|
+
İki değer de broker normalizasyonuna girer (adım/min/max sembolden gelir). */
|
|
107
|
+
function lotRange(cfg, symbol) {
|
|
108
|
+
const sym = String(symbol || '').trim().toUpperCase();
|
|
109
|
+
const o = (cfg && cfg.symbolLimits && cfg.symbolLimits[sym]) || null;
|
|
110
|
+
let minLot = Number(o && o.minLot) > 0 ? Number(o.minLot) : Number(cfg && cfg.minLot) || 0.01;
|
|
111
|
+
let maxLot = Number(o && o.maxLot) > 0 ? Number(o.maxLot) : Number(cfg && cfg.maxLot) || 0.1;
|
|
112
|
+
if (minLot > maxLot) minLot = maxLot;
|
|
113
|
+
if (maxLot < minLot) maxLot = minLot;
|
|
114
|
+
return { minLot, maxLot };
|
|
115
|
+
}
|
|
116
|
+
|
|
104
117
|
/* İşlem öncesi risk katmanı: stops_level + yoğunluk + marj kalkanı.
|
|
105
118
|
Hata metni ya da null döner. positions çağıran tarafından verilir. */
|
|
106
119
|
async function preTradeCheck(cfg, side, symbol, info, price, volume, sl, tp, positions) {
|
|
@@ -262,32 +275,37 @@ const definitions = NAMES.map((name) => {
|
|
|
262
275
|
},
|
|
263
276
|
mt5_limits: {
|
|
264
277
|
description:
|
|
265
|
-
'LOT / POZİSYON LİMİTLERİNİ oku ve GÜNCELLE — trader karar mercii: mt5_limits {action:"get"|"set", minLot?, maxLot?, maxPositions?}. get:
|
|
278
|
+
'LOT / POZİSYON / RİTİM LİMİTLERİNİ oku ve GÜNCELLE — trader karar mercii: mt5_limits {action:"get"|"set", symbol?, minLot?, maxLot?, maxPositions?, intervalSec?, intervalForMin?, reset?}. get: genel min lot / max lot / max eşzamanlı pozisyon + SEMBOL BAZLI limitler + efektif tur aralığı + işlem riski %. GENEL set: minLot/maxLot/maxPositions. SEMBOL BAZLI set: symbol ver (ör. {action:"set", symbol:"XAUUSD", minLot:0.02, maxLot:0.5}) — her sembolün min/max lotunu kendi karakterine göre SEN belirle (volatilite, spread, marj); sembol limiti genel aralığın dışına çıkamaz (genel taban/tavan kelepçeler). Sembolü genele döndürmek için {action:"set", symbol:"XAUUSD", reset:true}. TUR RİTMİ: intervalSec (30-3600 sn) + intervalForMin (1-240 dk) → geçici hızlanma; süre bitince taban aralığa OTOMATİK döner (ör. {action:"set", intervalSec:45, intervalForMin:15}). intervalForMin yoksa kalıcı temel aralık değişir. Sert hareket/haber anında hızlan, sakinleşince geri çek — SÜREKLİ en düşük aralıkta kalma (API/maliyet limiti); sınırlar sistemce zorlanır. set: yalnız ana trader (ve finance sohbet copilot\'ı) kullanabilir — rol/işçi ajanları değiştiremez. Değişiklik ANINDA panelde ve sonraki turda geçerli olur. Kural: minLot maxLot\'u aşamaz.',
|
|
266
279
|
parameters: {
|
|
267
280
|
type: 'object',
|
|
268
281
|
properties: {
|
|
269
282
|
action: { type: 'string', enum: ['get', 'set'], description: 'get: mevcut limitler · set: güncelle' },
|
|
283
|
+
symbol: { type: 'string', description: 'set: sembol bazlı lot limiti (ör. XAUUSD) — genel set için boş bırak' },
|
|
270
284
|
minLot: { type: 'number', description: 'set: yeni alt sınır (0.01-100)' },
|
|
271
285
|
maxLot: { type: 'number', description: 'set: yeni üst sınır (0.01-100)' },
|
|
272
|
-
maxPositions: { type: 'number', description: 'set: eşzamanlı pozisyon tavanı (1-20)' },
|
|
286
|
+
maxPositions: { type: 'number', description: 'set: eşzamanlı pozisyon tavanı (1-20) — yalnız GENEL (sembol ile verilemez)' },
|
|
287
|
+
intervalSec: { type: 'number', description: 'set: tur aralığı saniye (30-3600) — intervalForMin ile geçici hız modu, tek başına kalıcı temel aralık' },
|
|
288
|
+
intervalForMin: { type: 'number', description: 'set: hız modu süresi dakika (1-240) — süre bitince taban aralığa otomatik döner' },
|
|
289
|
+
reset: { type: 'boolean', description: 'set + symbol: true → sembol limitini kaldır, genel aralığa dön' },
|
|
273
290
|
},
|
|
274
291
|
required: ['action'],
|
|
275
292
|
},
|
|
276
293
|
},
|
|
277
294
|
mt5_ogrenme: {
|
|
278
295
|
description:
|
|
279
|
-
'SEMBOL BAZLI ÖĞRENME HAFIZASI — Beast Finance sürekli öğrenir: mt5_ogrenme {action:"list"|"add"|"remove"|"clear"|"stats"|"compact"|"forget", symbol?, text?, kind?, tags?, id?, ids?, all?}. Her sembolün KENDİ istatistiği (işlem/kazanç/kayıp, net, kâr yakalama, kâr geri verme) OTOMATİK birikir; ayrıca
|
|
296
|
+
'SEMBOL BAZLI ÖĞRENME HAFIZASI — Beast Finance sürekli öğrenir: mt5_ogrenme {action:"list"|"add"|"remove"|"clear"|"stats"|"compact"|"forget", symbol?, text?, kind?, tags?, id?, ids?, all?, limit?}. Her sembolün KENDİ istatistiği (işlem/kazanç/kayıp, net, kâr yakalama, kâr geri verme) OTOMATİK birikir; ayrıca gerçekten öğrendiğin dersleri sen kaydedersin. DERS KURALLARI (SEÇİCİ): (1) Her kapanışa ders YAZMA — yalnız gerçekten öğrenilmiş, tekrar kullanılabilir, kanıtlı içgörüyü TEK KISA cümleyle kaydet (en fazla ~20 kelime / 200 karakter); ör. "XAUUSD M5 EMA50 üstü Londra açılışı momentumu 3/4 işledi". YASAK: günlük/rapor tarzı uzun metin ("bugün şunu yaptım"), genel laf ("dikkatli olmalıyım"), her turda ders, tekrar. Emin değilsen HİÇ kaydetme. (2) Yeni işlem kararından ÖNCE ilgili sembolün stats (kompakt: istatistik + kalıcı özet + son 3 ders) ya da list (son 8 ders; limit ile artır) çıktısını oku; aynı hatayı tekrarlama, işleyen deseni kullan. (3) Yanlış çıkan/genel geçersiz dersi remove/clear ile sil. Aynı ders tekrar yazılamaz; sembol başına 24 saatte en fazla 3 ders kabul edilir (kalite kapısı: çok kısa/uzun, günlük tarzı ve genel tavsiye metinleri reddedilir). HAFIZA KENDİNİ SADELEŞTİRİR (opencode tarzı compaction): ham dersler birikince (24+) ESKİ dersler OTOMATİK olarak modele özetlettirilir ve tek KALICI ÖZETE sıkıştırılır — ham yalnız son dersler kalır; 30 günden eski dersler, 90 günden eski işlem kayıtları ve 120 gün hareketsiz semboller otomatik unutulur. Gerekirse compact {symbol} ile hemen özetlet, forget ile süresi geçenleri temizle. action:"list" symbol verilmezse tüm sembollerin özetini döner (kalıcı özet dahil).',
|
|
280
297
|
parameters: {
|
|
281
298
|
type: 'object',
|
|
282
299
|
properties: {
|
|
283
300
|
action: { type: 'string', enum: ['list', 'add', 'remove', 'clear', 'stats', 'compact', 'forget'] },
|
|
284
301
|
symbol: { type: 'string', description: 'Sembol (ör. XAUUSD) — öğrenme sembol bazlıdır' },
|
|
285
|
-
text: { type: 'string', description: 'add: öğrenilen ders
|
|
302
|
+
text: { type: 'string', description: 'add: öğrenilen ders — TEK kısa cümle (en fazla ~20 kelime/200 karakter), somut ve tekrar kullanılabilir; günlük/uzun metin kaydetme' },
|
|
286
303
|
kind: { type: 'string', enum: ['pattern', 'mistake', 'rule', 'observation'], description: 'add: kayıt türü (varsayılan observation)' },
|
|
287
304
|
tags: { type: 'array', items: { type: 'string' }, description: 'add: etiketler (ör. ["scalp","london"])' },
|
|
288
305
|
id: { type: 'string', description: 'remove: kayıt id' },
|
|
289
306
|
ids: { type: 'array', items: { type: 'string' }, description: 'clear: silinecek kayıt id listesi' },
|
|
290
307
|
all: { type: 'boolean', description: 'clear: true → tüm öğrenme kayıtları (dikkatli)' },
|
|
308
|
+
limit: { type: 'number', description: 'list: döndürülecek son ders sayısı (varsayılan 8, en fazla 25)' },
|
|
291
309
|
},
|
|
292
310
|
required: ['action'],
|
|
293
311
|
},
|
|
@@ -562,11 +580,17 @@ const handlers = {
|
|
|
562
580
|
}
|
|
563
581
|
if (action === 'set') {
|
|
564
582
|
const patch = {};
|
|
565
|
-
for (const k of ['minLot', 'maxLot', 'maxPositions']) {
|
|
583
|
+
for (const k of ['minLot', 'maxLot', 'maxPositions', 'intervalSec', 'intervalForMin']) {
|
|
566
584
|
if (args[k] !== undefined && args[k] !== null && args[k] !== '') patch[k] = Number(args[k]);
|
|
567
585
|
}
|
|
568
|
-
|
|
569
|
-
|
|
586
|
+
/* SEMBOL BAZLI LOT LİMİTİ: symbol verilirse trader o sembolün min/max
|
|
587
|
+
lotunu ayarlar (reset:true → genel aralığa döndürür) */
|
|
588
|
+
const sym = String(args.symbol || '').trim().toUpperCase();
|
|
589
|
+
if (sym) patch.symbol = sym;
|
|
590
|
+
const reset = args.reset === true || String(args.reset || '').toLowerCase() === 'true';
|
|
591
|
+
if (reset) patch.reset = true;
|
|
592
|
+
if (!Object.keys(patch).length || (sym && patch.minLot === undefined && patch.maxLot === undefined && !reset)) {
|
|
593
|
+
return { ok: false, error: 'set için en az bir alan ver: minLot / maxLot / maxPositions / intervalSec (sembol bazlıda minLot/maxLot ya da reset:true)' };
|
|
570
594
|
}
|
|
571
595
|
return await limitsApi.set(patch, ctx || {});
|
|
572
596
|
}
|
|
@@ -575,7 +599,12 @@ const handlers = {
|
|
|
575
599
|
async mt5_ogrenme(args, ctx) {
|
|
576
600
|
const action = String(args.action || 'list').toLowerCase();
|
|
577
601
|
const symbol = String(args.symbol || '').trim().toUpperCase();
|
|
578
|
-
if (action === 'list')
|
|
602
|
+
if (action === 'list') {
|
|
603
|
+
/* kompakt okuma: varsayılan son 8 ders (limit ile artırılır, max 25) —
|
|
604
|
+
hafızanın tamamı ajana gönderilmez */
|
|
605
|
+
const limit = Math.round(Number(args.limit) || 0);
|
|
606
|
+
return learningApi.list({ symbol, limit: limit > 0 ? limit : 8 });
|
|
607
|
+
}
|
|
579
608
|
if (action === 'stats') return learningApi.stats({ symbol });
|
|
580
609
|
if (action === 'add') {
|
|
581
610
|
const text = String(args.text || '').replace(/\s+/g, ' ').trim();
|
|
@@ -584,9 +613,11 @@ const handlers = {
|
|
|
584
613
|
const kindRaw = String(args.kind || 'observation').toLowerCase();
|
|
585
614
|
const kind = ['pattern', 'mistake', 'rule', 'observation'].includes(kindRaw) ? kindRaw : 'observation';
|
|
586
615
|
const tags = Array.isArray(args.tags) ? args.tags.map((t) => String(t || '').trim()).filter(Boolean).slice(0, 6) : [];
|
|
587
|
-
|
|
616
|
+
/* metin AYNEN geçer: kalite kapısı (kısa+somut) main tarafında çalışır —
|
|
617
|
+
uzun/günlük metin sessizce kırpılmaz, ajan net hata alıp kısaltır */
|
|
618
|
+
const res = learningApi.add({ symbol, text, kind, tags, sid: (ctx && ctx.sessionId) || '' });
|
|
588
619
|
if (res && res.ok) {
|
|
589
|
-
noteTrade('learn', { symbol, text: text.slice(0,
|
|
620
|
+
noteTrade('learn', { symbol, text: text.slice(0, 200), kind }, ctx || {});
|
|
590
621
|
}
|
|
591
622
|
return res;
|
|
592
623
|
}
|
|
@@ -678,7 +709,8 @@ const handlers = {
|
|
|
678
709
|
const balance = Number(acct && acct.account && acct.account.balance) || 0;
|
|
679
710
|
if (!(balance > 0)) return { ok: false, error: 'bakiye okunamadı' };
|
|
680
711
|
const riskAmount = (balance * riskPct) / 100;
|
|
681
|
-
const
|
|
712
|
+
const range = lotRange(cfg, symbol);
|
|
713
|
+
const res = finrisk.calcRiskLot(info, entry, sl, riskAmount, range.maxLot, range.minLot);
|
|
682
714
|
if (res.error) return { ok: false, error: res.error, raw: res.raw, lossPerLot: res.lossPerLot, riskAmount: Math.round(riskAmount * 100) / 100 };
|
|
683
715
|
const digits = Number(info.digits) || 5;
|
|
684
716
|
const dist = Math.abs(entry - sl);
|
|
@@ -699,8 +731,8 @@ const handlers = {
|
|
|
699
731
|
capped: !!res.capped,
|
|
700
732
|
raised: !!res.raised,
|
|
701
733
|
warning: closeErr || undefined,
|
|
702
|
-
minLot:
|
|
703
|
-
maxLot:
|
|
734
|
+
minLot: range.minLot,
|
|
735
|
+
maxLot: range.maxLot,
|
|
704
736
|
};
|
|
705
737
|
},
|
|
706
738
|
async mt5_trade(args, ctx) {
|
|
@@ -720,7 +752,7 @@ const handlers = {
|
|
|
720
752
|
const side = t.side;
|
|
721
753
|
const symbol = String(args.symbol || '').trim().toUpperCase();
|
|
722
754
|
if (!symbol) return { ok: false, error: 'symbol gerekli' };
|
|
723
|
-
const
|
|
755
|
+
const range = lotRange(cfg, symbol);
|
|
724
756
|
const sl = Number(args.sl) || 0;
|
|
725
757
|
const tp = Number(args.tp) || 0;
|
|
726
758
|
const info = await symInfoRow(symbol);
|
|
@@ -738,12 +770,12 @@ const handlers = {
|
|
|
738
770
|
const acct = await bcall('account', {}, 8000);
|
|
739
771
|
const balance = Number(acct && acct.account && acct.account.balance) || 0;
|
|
740
772
|
const riskAmount = (balance * riskPct) / 100;
|
|
741
|
-
const rr = finrisk.calcRiskLot(info, price, sl, riskAmount, maxLot,
|
|
773
|
+
const rr = finrisk.calcRiskLot(info, price, sl, riskAmount, range.maxLot, range.minLot);
|
|
742
774
|
if (rr.error) return { ok: false, error: rr.error };
|
|
743
775
|
vol = rr.volume;
|
|
744
776
|
riskInfo = { riskPct, riskAmount: Math.round(riskAmount * 100) / 100, lossPerLot: rr.lossPerLot, raised: !!rr.raised };
|
|
745
777
|
} else {
|
|
746
|
-
const norm = finrisk.normalizeVolume(info, wantVolume, maxLot,
|
|
778
|
+
const norm = finrisk.normalizeVolume(info, wantVolume, range.maxLot, range.minLot);
|
|
747
779
|
if (norm.error) return { ok: false, error: norm.error };
|
|
748
780
|
vol = norm.volume;
|
|
749
781
|
}
|
|
@@ -860,7 +892,8 @@ const handlers = {
|
|
|
860
892
|
if (!symbol) return { ok: false, error: 'symbol gerekli' };
|
|
861
893
|
const info = await symInfoRow(symbol);
|
|
862
894
|
if (!info) return { ok: false, error: 'sembol bulunamadı: ' + symbol + ' (MT5 Market Watch?)' };
|
|
863
|
-
const
|
|
895
|
+
const range = lotRange(cfg, symbol);
|
|
896
|
+
const norm = finrisk.normalizeVolume(info, args.volume, range.maxLot, range.minLot);
|
|
864
897
|
if (norm.error) return { ok: false, error: norm.error };
|
|
865
898
|
const vol = norm.volume;
|
|
866
899
|
const ptype = t.type;
|
package/src/agent/finrisk.js
CHANGED
|
@@ -24,7 +24,9 @@ function stepCeil(v, step) {
|
|
|
24
24
|
|
|
25
25
|
/* info: MT5 symbol_info satırı. wanted: istenen lot. hardMax: kullanıcı üst
|
|
26
26
|
limiti (max lot). hardMin: kullanıcı alt limiti (min lot) — istenen lot bu
|
|
27
|
-
tabanın altındaysa adıma yukarı yuvarlanır (raised).
|
|
27
|
+
tabanın altındaysa adıma yukarı yuvarlanır (raised). Taban/tavan broker
|
|
28
|
+
adımına OTURMUYORSA (ör. min 0.15–max 0.19, adım 0.1) sessizce limit dışına
|
|
29
|
+
düşmek yerine net hata döner — aralığı mt5_limits ile düzelt. */
|
|
28
30
|
function normalizeVolume(info, wanted, hardMax, hardMin) {
|
|
29
31
|
const vmin = num(info && info.volume_min, 0.01);
|
|
30
32
|
const vmax = num(info && info.volume_max, 100);
|
|
@@ -33,24 +35,32 @@ function normalizeVolume(info, wanted, hardMax, hardMin) {
|
|
|
33
35
|
if (!(v > 0)) return { error: 'volume gerekli (pozitif sayı)' };
|
|
34
36
|
const cap = Math.min(vmax > 0 ? vmax : Infinity, num(hardMax, 0) > 0 ? num(hardMax, 0) : Infinity);
|
|
35
37
|
const floor = num(hardMin, 0) > 0 ? num(hardMin, 0) : 0;
|
|
38
|
+
const align = (x) => Math.round(x * 1e8) / 1e8;
|
|
39
|
+
const mismatch = () => ({
|
|
40
|
+
error: `lot aralığı broker adımıyla uyuşmuyor (min ${floor}, max ${cap === Infinity ? '∞' : cap}, adım ${step}) — mt5_limits ile aralığı düzelt`,
|
|
41
|
+
});
|
|
42
|
+
if (floor > cap + 1e-9) return mismatch();
|
|
36
43
|
let capped = false;
|
|
37
44
|
let raised = false;
|
|
38
45
|
if (v > cap) {
|
|
39
|
-
v = stepFloor(cap, step);
|
|
46
|
+
v = align(stepFloor(cap, step));
|
|
40
47
|
capped = true;
|
|
48
|
+
if (floor > 0 && v < floor - 1e-9) return mismatch();
|
|
41
49
|
}
|
|
42
50
|
if (v < floor - 1e-9) {
|
|
43
|
-
v = stepCeil(floor, step);
|
|
51
|
+
v = align(stepCeil(floor, step));
|
|
44
52
|
raised = true;
|
|
53
|
+
if (v > cap + 1e-9) return mismatch();
|
|
45
54
|
}
|
|
46
|
-
v =
|
|
55
|
+
v = align(stepFloor(v, step));
|
|
56
|
+
if (floor > 0 && v < floor - 1e-9) { v = align(stepCeil(floor, step)); raised = true; }
|
|
47
57
|
if (!(v > 0) || v < vmin - 1e-9) {
|
|
48
58
|
return { error: `hacim broker minimumunun altında (min ${vmin} lot)` };
|
|
49
59
|
}
|
|
50
60
|
if (v > cap + 1e-9) {
|
|
51
|
-
|
|
52
|
-
v = Math.round(stepFloor(cap, step) * 1e8) / 1e8;
|
|
61
|
+
v = align(stepFloor(cap, step));
|
|
53
62
|
capped = true;
|
|
63
|
+
if (floor > 0 && v < floor - 1e-9) return mismatch();
|
|
54
64
|
if (!(v > 0) || v < vmin - 1e-9) {
|
|
55
65
|
return { error: `hacim broker minimumunun altında (min ${vmin} lot)` };
|
|
56
66
|
}
|
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: risk-yonetimi
|
|
3
|
-
description: Pozisyon boyutlandırma ve risk disiplini rehberi — hesap yüzdesiyle lot hesabı, marj/kaldıraç denetimi, max eşzamanlı pozisyon, korelasyon/tek yön birikme, günlük kayıp limiti, SL/BE/trailing kuralları. Risk ajanı veya trader her turda ve her işlemden önce bu skill'e göre kontrol yapar.
|
|
4
|
-
version: 1.0.0
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Risk Yönetimi
|
|
8
|
-
|
|
9
|
-
## TEMEL KURAL
|
|
10
|
-
|
|
11
|
-
Önce kaybı sınırla, kârı piyasa versin. İşlem başına risk sabittir; lot, SL mesafesine göre hesaplanır.
|
|
12
|
-
|
|
13
|
-
## 1) POZİSYON BOYUTU
|
|
14
|
-
|
|
15
|
-
- İşlem başına risk: hesabın **%0.5–1'i** (agresif değilse %0.25–0.5).
|
|
16
|
-
- Lot hesabı: `lot = (bakiye × risk%) / (SL_mesafesi × sembolün pip değeri)`.
|
|
17
|
-
- SL mesafesi ATR/yapıdan gelir; önce SL belirle, sonra lotu küçült — tersini yapma.
|
|
18
|
-
- Broker limitleri: panel `max lot` ve `max eşzamanlı pozisyon` ayarlarına uy; sistem reddederse zorlama.
|
|
19
|
-
|
|
20
|
-
## 2) MARJ / KALDIRAÇ
|
|
21
|
-
|
|
22
|
-
- Serbest marjın tamamını tek işleme bağlama; toplam açık risk serbest marjın küçük bir kısmı olsun.
|
|
23
|
-
- Kaldıraç yüksekse lotu düşür; kaldıraç = risk değil, imkândır.
|
|
24
|
-
- Marj seviyesi düşerken yeni pozisyon AÇMA; önce riski azalt.
|
|
25
|
-
|
|
26
|
-
## 3) PORTFÖY DENETİMİ (her turda)
|
|
27
|
-
|
|
28
|
-
- Açık pozisyonların toplam riskini hesapla (SL'lere göre kayıp potansiyeli).
|
|
29
|
-
- **Tek yön birikme**: aynı yönde üst üste pozisyon = tek işlem gibi davranır; toplam riski tek işlem limiti gibi say.
|
|
30
|
-
- **Korelasyon**: XAUUSD/EURUSD ile DXY ters koreledir; aynı yönde iki korelasyonlu pozisyon riski katlar.
|
|
31
|
-
- SL'siz pozisyon varsa ilk iş: SL tamamla veya kapat.
|
|
32
|
-
- Hedefine ulaşan/kâra geçen pozisyonda BE veya kısmi kâr; trailing ATR bazlı.
|
|
33
|
-
- **Kâr koruma:** +0.3R'de sistem SL'yi en iyi kârın 0.15R gerisine kilitler; +0.3-0.5R'de kısmi TP (ör. %50) ile kârı cebe al, kalanı trailing'e bırak. TP için R:R ≥ 1.5 şartı YOK — hızlı kâr toplama (scalp) serbest; ama kârı kale verme.
|
|
34
|
-
- **Sembol bazlı öğrenme:** her
|
|
35
|
-
|
|
36
|
-
## 4) KAYIP LİMİTLERİ
|
|
37
|
-
|
|
38
|
-
- Günlük kayıp limiti belirle (ör. hesabın %2–3'ü). Limit dolduysa **o gün yeni işlem yok**; raporla.
|
|
39
|
-
- Üst üste 2-3 kayıptan sonra lotu artırma (revenge trade YASAK); aksine küçült veya dur.
|
|
40
|
-
- Drawdown artıyorsa tur sıklığını/agresifliği azalt, sadece A+ setuplara gir.
|
|
41
|
-
|
|
42
|
-
## 5) YASAKLAR
|
|
43
|
-
|
|
44
|
-
- Martingale / kademeli lot artışı.
|
|
45
|
-
- SL taşımayı kaybı büyütecek yönde yapmak (SL genişletme).
|
|
46
|
-
- Marjı zorlayan "son işlem" kumarı.
|
|
47
|
-
- Aynı anda korelasyonlu 3+ pozisyonla tek yön yığmak.
|
|
48
|
-
|
|
49
|
-
## 6) RAPOR FORMATI
|
|
50
|
-
|
|
51
|
-
`Risk: toplam açık R%X | marj kullanımı %Y | en riskli pozisyon: ... | öneri: SL/BE/küçült/kapat`
|
|
52
|
-
Sınır aşımı varsa öncelikli ve net yaz.
|
|
1
|
+
---
|
|
2
|
+
name: risk-yonetimi
|
|
3
|
+
description: Pozisyon boyutlandırma ve risk disiplini rehberi — hesap yüzdesiyle lot hesabı, marj/kaldıraç denetimi, max eşzamanlı pozisyon, korelasyon/tek yön birikme, günlük kayıp limiti, SL/BE/trailing kuralları. Risk ajanı veya trader her turda ve her işlemden önce bu skill'e göre kontrol yapar.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Risk Yönetimi
|
|
8
|
+
|
|
9
|
+
## TEMEL KURAL
|
|
10
|
+
|
|
11
|
+
Önce kaybı sınırla, kârı piyasa versin. İşlem başına risk sabittir; lot, SL mesafesine göre hesaplanır.
|
|
12
|
+
|
|
13
|
+
## 1) POZİSYON BOYUTU
|
|
14
|
+
|
|
15
|
+
- İşlem başına risk: hesabın **%0.5–1'i** (agresif değilse %0.25–0.5).
|
|
16
|
+
- Lot hesabı: `lot = (bakiye × risk%) / (SL_mesafesi × sembolün pip değeri)`.
|
|
17
|
+
- SL mesafesi ATR/yapıdan gelir; önce SL belirle, sonra lotu küçült — tersini yapma.
|
|
18
|
+
- Broker limitleri: panel `max lot` ve `max eşzamanlı pozisyon` ayarlarına uy; sistem reddederse zorlama.
|
|
19
|
+
|
|
20
|
+
## 2) MARJ / KALDIRAÇ
|
|
21
|
+
|
|
22
|
+
- Serbest marjın tamamını tek işleme bağlama; toplam açık risk serbest marjın küçük bir kısmı olsun.
|
|
23
|
+
- Kaldıraç yüksekse lotu düşür; kaldıraç = risk değil, imkândır.
|
|
24
|
+
- Marj seviyesi düşerken yeni pozisyon AÇMA; önce riski azalt.
|
|
25
|
+
|
|
26
|
+
## 3) PORTFÖY DENETİMİ (her turda)
|
|
27
|
+
|
|
28
|
+
- Açık pozisyonların toplam riskini hesapla (SL'lere göre kayıp potansiyeli).
|
|
29
|
+
- **Tek yön birikme**: aynı yönde üst üste pozisyon = tek işlem gibi davranır; toplam riski tek işlem limiti gibi say.
|
|
30
|
+
- **Korelasyon**: XAUUSD/EURUSD ile DXY ters koreledir; aynı yönde iki korelasyonlu pozisyon riski katlar.
|
|
31
|
+
- SL'siz pozisyon varsa ilk iş: SL tamamla veya kapat.
|
|
32
|
+
- Hedefine ulaşan/kâra geçen pozisyonda BE veya kısmi kâr; trailing ATR bazlı.
|
|
33
|
+
- **Kâr koruma:** +0.3R'de sistem SL'yi en iyi kârın 0.15R gerisine kilitler; +0.3-0.5R'de kısmi TP (ör. %50) ile kârı cebe al, kalanı trailing'e bırak. TP için R:R ≥ 1.5 şartı YOK — hızlı kâr toplama (scalp) serbest; ama kârı kale verme.
|
|
34
|
+
- **Sembol bazlı öğrenme (seçici):** her kapanışa ders YAZMA — yalnız gerçekten öğretici, tekrar kullanılabilir içgörüyü TEK kısa cümleyle (≈20 kelime) mt5_ogrenme add ile kaydet; yeni işlem öncesi o sembolün stats/list geçmişini oku — aynı hatayı tekrarlama.
|
|
35
|
+
|
|
36
|
+
## 4) KAYIP LİMİTLERİ
|
|
37
|
+
|
|
38
|
+
- Günlük kayıp limiti belirle (ör. hesabın %2–3'ü). Limit dolduysa **o gün yeni işlem yok**; raporla.
|
|
39
|
+
- Üst üste 2-3 kayıptan sonra lotu artırma (revenge trade YASAK); aksine küçült veya dur.
|
|
40
|
+
- Drawdown artıyorsa tur sıklığını/agresifliği azalt, sadece A+ setuplara gir.
|
|
41
|
+
|
|
42
|
+
## 5) YASAKLAR
|
|
43
|
+
|
|
44
|
+
- Martingale / kademeli lot artışı.
|
|
45
|
+
- SL taşımayı kaybı büyütecek yönde yapmak (SL genişletme).
|
|
46
|
+
- Marjı zorlayan "son işlem" kumarı.
|
|
47
|
+
- Aynı anda korelasyonlu 3+ pozisyonla tek yön yığmak.
|
|
48
|
+
|
|
49
|
+
## 6) RAPOR FORMATI
|
|
50
|
+
|
|
51
|
+
`Risk: toplam açık R%X | marj kullanımı %Y | en riskli pozisyon: ... | öneri: SL/BE/küçült/kapat`
|
|
52
|
+
Sınır aşımı varsa öncelikli ve net yaz.
|
package/src/main.js
CHANGED
|
@@ -9402,6 +9402,11 @@ const financeState = {
|
|
|
9402
9402
|
reportCheckAt: 0,
|
|
9403
9403
|
flattening: false,
|
|
9404
9404
|
breachBusy: false,
|
|
9405
|
+
/* TUR RİTMİ (trader kararı): sert hareket/haber anında geçici hızlanma.
|
|
9406
|
+
pace = { sec, until, base } — süre dolunca otomatik taban aralığa döner;
|
|
9407
|
+
kalıcı değişiklik settings.finance.intervalSec'e yazılır. */
|
|
9408
|
+
pace: { sec: 0, until: 0, base: 0 },
|
|
9409
|
+
paceTimer: null,
|
|
9405
9410
|
};
|
|
9406
9411
|
|
|
9407
9412
|
function financeDir() {
|
|
@@ -9410,6 +9415,33 @@ function financeDir() {
|
|
|
9410
9415
|
return d;
|
|
9411
9416
|
}
|
|
9412
9417
|
|
|
9418
|
+
/* SEMBOL BAZLI LOT LİMİTLERİ: trader mt5_limits symbol ile koyar; anahtar =
|
|
9419
|
+
sembol (XAUUSD…). Genel aralık taban/tavan olarak zorlanır — sembol limiti
|
|
9420
|
+
onun dışına çıkamaz; boş alan genel aralığı kullanır. Her okuma/yazmada
|
|
9421
|
+
normalize edilir (bozuk/eski kayıtlar temizlenir). */
|
|
9422
|
+
function finNormalizeSymbolLimits(f) {
|
|
9423
|
+
const gMin = Number(f.minLot) || 0.01;
|
|
9424
|
+
const gMax = Number(f.maxLot) || 0.1;
|
|
9425
|
+
if (!f.symbolLimits || typeof f.symbolLimits !== 'object') f.symbolLimits = {};
|
|
9426
|
+
const clean = {};
|
|
9427
|
+
for (const [k, v] of Object.entries(f.symbolLimits).slice(0, 40)) {
|
|
9428
|
+
const sym = String(k || '').trim().toUpperCase();
|
|
9429
|
+
const o = v && typeof v === 'object' ? v : {};
|
|
9430
|
+
if (!sym) continue;
|
|
9431
|
+
let mn = Number(o.minLot) > 0 ? Math.round(Math.max(0.01, Math.min(100, Number(o.minLot))) * 100) / 100 : 0;
|
|
9432
|
+
let mx = Number(o.maxLot) > 0 ? Math.round(Math.max(0.01, Math.min(100, Number(o.maxLot))) * 100) / 100 : 0;
|
|
9433
|
+
if (mn && mx && mn > mx) mn = mx;
|
|
9434
|
+
if (mn) mn = Math.min(Math.max(mn, gMin), gMax);
|
|
9435
|
+
if (mx) mx = Math.max(Math.min(mx, gMax), gMin);
|
|
9436
|
+
if (mn && mx && mn > mx) mn = mx;
|
|
9437
|
+
const lim = {};
|
|
9438
|
+
if (mn) lim.minLot = mn;
|
|
9439
|
+
if (mx) lim.maxLot = mx;
|
|
9440
|
+
if (lim.minLot || lim.maxLot) clean[sym] = lim;
|
|
9441
|
+
}
|
|
9442
|
+
f.symbolLimits = clean;
|
|
9443
|
+
}
|
|
9444
|
+
|
|
9413
9445
|
function finCfg() {
|
|
9414
9446
|
if (!settings.finance || typeof settings.finance !== 'object') settings.finance = {};
|
|
9415
9447
|
const f = settings.finance;
|
|
@@ -9448,8 +9480,10 @@ function finCfg() {
|
|
|
9448
9480
|
if (!Number(f.intervalSec)) f.intervalSec = 120;
|
|
9449
9481
|
if (!Number(f.minLot)) f.minLot = 0.01;
|
|
9450
9482
|
if (!Number(f.maxLot)) f.maxLot = 0.1;
|
|
9451
|
-
/* LOT ARALIĞI
|
|
9483
|
+
/* LOT ARALIĞI KİLİDİ: min lot hiçbir zaman max lotu aşamaz */
|
|
9452
9484
|
if (f.minLot > f.maxLot) f.minLot = f.maxLot;
|
|
9485
|
+
/* SEMBOL BAZLI LOT LİMİTLERİ (trader kararı — mt5_limits symbol ile koyar) */
|
|
9486
|
+
finNormalizeSymbolLimits(f);
|
|
9453
9487
|
if (f.maxPositions == null) f.maxPositions = 3;
|
|
9454
9488
|
/* KODLA DİSİPLİN (trader kuralları): hepsi 0 = kural kapalı */
|
|
9455
9489
|
if (!Number.isFinite(Number(f.maxTradesPerDay))) f.maxTradesPerDay = 10;
|
|
@@ -11241,13 +11275,62 @@ try {
|
|
|
11241
11275
|
Ana trader / finance sohbet oturumu min lot-max lot-pozisyon tavanını
|
|
11242
11276
|
güncelleyebilir; rol/işçi ajanları yalnız okur. Değişiklik ayarlara yazılır,
|
|
11243
11277
|
koşan oturumlara ANINDA işlenir ve panele duyurulur. */
|
|
11278
|
+
/* TUR RİTMİ: trader sert harekette geçici hızlanabilir — efektif aralık (sn).
|
|
11279
|
+
Süre dolunca kendiliğinden taban aralığa döner (API/maliyet limiti korunur). */
|
|
11280
|
+
function finPaceSec() {
|
|
11281
|
+
const f = finCfg();
|
|
11282
|
+
const base = Math.max(30, Math.min(3600, Math.round(Number(f.intervalSec) || 120)));
|
|
11283
|
+
const p = financeState.pace;
|
|
11284
|
+
if (p && Number(p.until) > Date.now() && Number(p.sec) >= 30) {
|
|
11285
|
+
return Math.max(30, Math.min(3600, Math.round(Number(p.sec))));
|
|
11286
|
+
}
|
|
11287
|
+
return base;
|
|
11288
|
+
}
|
|
11289
|
+
|
|
11290
|
+
/* Koşan ajan zamanlayıcılarını efektif ritme göre yeniden kur; hız modunun
|
|
11291
|
+
bitişini de zamanla — süre dolunca taban aralığa OTOMATİK dönüş. */
|
|
11292
|
+
function finRescheduleAgents() {
|
|
11293
|
+
const iv = finPaceSec() * 1000;
|
|
11294
|
+
if (financeState.paceTimer) { clearTimeout(financeState.paceTimer); financeState.paceTimer = null; }
|
|
11295
|
+
const p = financeState.pace;
|
|
11296
|
+
if (p && Number(p.until) > Date.now() && Number(p.sec) > 0) {
|
|
11297
|
+
const left = Math.max(1000, Number(p.until) - Date.now() + 1000);
|
|
11298
|
+
financeState.paceTimer = setTimeout(() => {
|
|
11299
|
+
financeState.pace = { sec: 0, until: 0, base: 0 };
|
|
11300
|
+
try { financeLog('[ritim] hız modu bitti — taban tur aralığı ' + finPaceSec() + ' sn'); } catch {}
|
|
11301
|
+
try { finRescheduleAgents(); } catch {}
|
|
11302
|
+
try { finPush('limits', { ...finLimitsSnapshot(), note: 'hız modu bitti — taban tur aralığı ' + finPaceSec() + ' sn' }); } catch {}
|
|
11303
|
+
}, left);
|
|
11304
|
+
}
|
|
11305
|
+
if (!engine || !financeState.agents) return;
|
|
11306
|
+
const hasMain = finTeamHasMain();
|
|
11307
|
+
for (const [sid, a] of financeState.agents) {
|
|
11308
|
+
if (!a) continue;
|
|
11309
|
+
if (a.role && hasMain) continue; /* cycle modu: trader turu başlatır */
|
|
11310
|
+
if (engine.isBusy(sid)) continue; /* tur bitince finFlushOnDone yeni ritmi okur */
|
|
11311
|
+
clearTimeout(a.timer);
|
|
11312
|
+
a.timer = setTimeout(() => { try { finAgentRound(String(sid)); } catch {} }, iv);
|
|
11313
|
+
}
|
|
11314
|
+
if (financeState.traderSid) {
|
|
11315
|
+
const a = financeState.agents.get(String(financeState.traderSid));
|
|
11316
|
+
finPush('trader', { state: 'idle', round: (a && a.round) || 0, nextInSec: iv / 1000 });
|
|
11317
|
+
}
|
|
11318
|
+
}
|
|
11319
|
+
|
|
11244
11320
|
function finLimitsSnapshot() {
|
|
11245
11321
|
const f = finCfg();
|
|
11322
|
+
const paceOn = Number(financeState.pace && financeState.pace.until) > Date.now();
|
|
11246
11323
|
return {
|
|
11247
11324
|
minLot: Number(f.minLot) || 0.01,
|
|
11248
11325
|
maxLot: Number(f.maxLot) || 0.1,
|
|
11249
11326
|
maxPositions: Number(f.maxPositions) || 3,
|
|
11250
11327
|
riskPerTradePct: Number(f.riskPerTradePct) || 0,
|
|
11328
|
+
/* SEMBOL BAZLI LOT LİMİTLERİ (trader kararı) — genel aralığı daraltır */
|
|
11329
|
+
symbols: { ...(f.symbolLimits && typeof f.symbolLimits === 'object' ? f.symbolLimits : {}) },
|
|
11330
|
+
/* TUR RİTMİ: efektif aralık + taban + hız modu bitişi */
|
|
11331
|
+
intervalSec: finPaceSec(),
|
|
11332
|
+
intervalBase: Math.max(30, Math.min(3600, Math.round(Number(f.intervalSec) || 120))),
|
|
11333
|
+
paceUntil: paceOn ? Number(financeState.pace.until) : 0,
|
|
11251
11334
|
};
|
|
11252
11335
|
}
|
|
11253
11336
|
|
|
@@ -11262,21 +11345,22 @@ function finLimitsSessionAllowed(sid) {
|
|
|
11262
11345
|
return true;
|
|
11263
11346
|
}
|
|
11264
11347
|
|
|
11265
|
-
function finSyncLimitsToSessions() {
|
|
11348
|
+
function finSyncLimitsToSessions(extra) {
|
|
11266
11349
|
const lim = finLimitsSnapshot();
|
|
11350
|
+
const apply = { minLot: lim.minLot, maxLot: lim.maxLot, maxPositions: lim.maxPositions, symbolLimits: lim.symbols, intervalSec: lim.intervalSec, intervalBase: lim.intervalBase, paceUntil: lim.paceUntil };
|
|
11267
11351
|
if (engine) {
|
|
11268
11352
|
try {
|
|
11269
11353
|
for (const [sid] of financeState.agents) {
|
|
11270
11354
|
const s = engine.cache.get(String(sid));
|
|
11271
|
-
if (s) s.financeLimits = {
|
|
11355
|
+
if (s) s.financeLimits = { ...apply };
|
|
11272
11356
|
}
|
|
11273
11357
|
for (const [, s] of engine.cache) {
|
|
11274
11358
|
if (!s || !s.finance || s.bgJob || !s.financeLimits) continue;
|
|
11275
|
-
s.financeLimits = {
|
|
11359
|
+
s.financeLimits = { ...apply };
|
|
11276
11360
|
}
|
|
11277
11361
|
} catch {}
|
|
11278
11362
|
}
|
|
11279
|
-
finPush('limits', { ...lim });
|
|
11363
|
+
finPush('limits', { ...lim, ...(extra && typeof extra === 'object' ? extra : {}) });
|
|
11280
11364
|
}
|
|
11281
11365
|
|
|
11282
11366
|
function finLimitsSet(patch, ctx) {
|
|
@@ -11286,6 +11370,54 @@ function finLimitsSet(patch, ctx) {
|
|
|
11286
11370
|
}
|
|
11287
11371
|
const f = finCfg();
|
|
11288
11372
|
const notes = [];
|
|
11373
|
+
/* SEMBOL BAZLI LOT LİMİTİ (symbol verilirse): trader sembole göre min/max lot
|
|
11374
|
+
koyar — genel aralık taban/tavan olarak zorlanır. reset:true (ya da yalnız
|
|
11375
|
+
symbol) → sembol limiti kaldırılır, genel aralık geçerli olur. */
|
|
11376
|
+
const sym = String(patch.symbol || '').trim().toUpperCase();
|
|
11377
|
+
if (sym) {
|
|
11378
|
+
if (patch.maxPositions !== undefined || patch.intervalSec !== undefined || patch.intervalForMin !== undefined) {
|
|
11379
|
+
return { ok: false, error: 'maxPositions ve tur ritmi (intervalSec) sembol bazlı değil — symbol vermeden genel olarak ayarla' };
|
|
11380
|
+
}
|
|
11381
|
+
const hasMin = patch.minLot !== undefined && patch.minLot !== null && patch.minLot !== '';
|
|
11382
|
+
const hasMax = patch.maxLot !== undefined && patch.maxLot !== null && patch.maxLot !== '';
|
|
11383
|
+
const reset = patch.reset === true || String(patch.reset || '').toLowerCase() === 'true';
|
|
11384
|
+
if (!reset && !hasMin && !hasMax) {
|
|
11385
|
+
return { ok: false, error: 'sembol güncellemesi için minLot/maxLot ver ya da reset:true' };
|
|
11386
|
+
}
|
|
11387
|
+
if (!f.symbolLimits || typeof f.symbolLimits !== 'object') f.symbolLimits = {};
|
|
11388
|
+
if (reset) {
|
|
11389
|
+
if (f.symbolLimits[sym]) {
|
|
11390
|
+
delete f.symbolLimits[sym];
|
|
11391
|
+
notes.push('sembol limiti kaldırıldı → genel aralık geçerli');
|
|
11392
|
+
}
|
|
11393
|
+
} else {
|
|
11394
|
+
const cur = { ...(f.symbolLimits[sym] || {}) };
|
|
11395
|
+
if (hasMin) {
|
|
11396
|
+
const v = Number(patch.minLot);
|
|
11397
|
+
if (!(v >= 0.01) || v > 100) return { ok: false, error: 'sembol minLot 0.01-100 arasında olmalı' };
|
|
11398
|
+
cur.minLot = Math.round(v * 100) / 100;
|
|
11399
|
+
}
|
|
11400
|
+
if (hasMax) {
|
|
11401
|
+
const v = Number(patch.maxLot);
|
|
11402
|
+
if (!(v >= 0.01) || v > 100) return { ok: false, error: 'sembol maxLot 0.01-100 arasında olmalı' };
|
|
11403
|
+
cur.maxLot = Math.round(v * 100) / 100;
|
|
11404
|
+
}
|
|
11405
|
+
/* genel aralığa kelepçe: sembol limiti geneli AŞAMAZ/ALTA İNEMEZ */
|
|
11406
|
+
if (cur.minLot !== undefined && cur.minLot < f.minLot) { cur.minLot = f.minLot; notes.push(`minLot genel tabana kelepçelendi (${f.minLot})`); }
|
|
11407
|
+
if (cur.maxLot !== undefined && cur.maxLot > f.maxLot) { cur.maxLot = f.maxLot; notes.push(`maxLot genel tavana kelepçelendi (${f.maxLot})`); }
|
|
11408
|
+
if (cur.minLot !== undefined && cur.maxLot !== undefined && cur.minLot > cur.maxLot) { cur.minLot = cur.maxLot; notes.push(`minLot maxLot'a kelepçelendi (${cur.maxLot})`); }
|
|
11409
|
+
if (cur.minLot === undefined && cur.maxLot === undefined) delete f.symbolLimits[sym];
|
|
11410
|
+
else f.symbolLimits[sym] = cur;
|
|
11411
|
+
}
|
|
11412
|
+
try { saveSettings(); } catch {}
|
|
11413
|
+
const e = f.symbolLimits[sym];
|
|
11414
|
+
const line = `⚙️ SEMBOL LOT LİMİTİ: ${sym} → ${e ? `min ${e.minLot ?? f.minLot} · max ${e.maxLot ?? f.maxLot}` : 'genel aralığa döndü'}${sid ? ' (ajan kararı)' : ''}`;
|
|
11415
|
+
financeLog('[limit] ' + line);
|
|
11416
|
+
finSyncLimitsToSessions({ symbol: sym, note: line });
|
|
11417
|
+
financeNotify(line, 'limit', true);
|
|
11418
|
+
try { finJournal({ kind: 'limits', symbol: sym, minLot: e ? e.minLot : null, maxLot: e ? e.maxLot : null, sid }); } catch {}
|
|
11419
|
+
return { ok: true, symbol: sym, limits: finLimitsSnapshot(), note: notes.length ? notes.join('; ') : undefined };
|
|
11420
|
+
}
|
|
11289
11421
|
if (patch.maxLot !== undefined) {
|
|
11290
11422
|
const v = Number(patch.maxLot);
|
|
11291
11423
|
if (!(v >= 0.01) || v > 100) return { ok: false, error: 'maxLot 0.01-100 arasında olmalı' };
|
|
@@ -11301,16 +11433,39 @@ function finLimitsSet(patch, ctx) {
|
|
|
11301
11433
|
if (!(v >= 1) || v > 20) return { ok: false, error: 'maxPositions 1-20 arasında olmalı' };
|
|
11302
11434
|
f.maxPositions = v;
|
|
11303
11435
|
}
|
|
11436
|
+
/* TUR RİTMİ (trader kararı): sert hareket/haber anında geçici hızlanma.
|
|
11437
|
+
intervalForMin > 0 → geçici (süre dolunca taban aralığa otomatik döner);
|
|
11438
|
+
yoksa kalıcı temel aralık güncellenir. Alt sınır 30 sn, hız modu ≤ 240 dk:
|
|
11439
|
+
API/maliyet limiti bilinçli — sürekli en düşük aralıkta kalmak YASAK. */
|
|
11440
|
+
let intervalChanged = false;
|
|
11441
|
+
if (patch.intervalSec !== undefined) {
|
|
11442
|
+
const base = Math.max(30, Math.min(3600, Math.round(Number(f.intervalSec) || 120)));
|
|
11443
|
+
const sec = Math.max(30, Math.min(3600, Math.round(Number(patch.intervalSec) || base)));
|
|
11444
|
+
const mins = Math.max(0, Math.min(240, Math.round(Number(patch.intervalForMin) || 0)));
|
|
11445
|
+
if (mins > 0 && sec < base) {
|
|
11446
|
+
financeState.pace = { sec, until: Date.now() + mins * 60 * 1000, base };
|
|
11447
|
+
notes.push(`hız modu: ${sec} sn × ${mins} dk (sonra taban ${base} sn'e döner)`);
|
|
11448
|
+
} else {
|
|
11449
|
+
f.intervalSec = sec;
|
|
11450
|
+
if (Number(financeState.pace && financeState.pace.until) > Date.now()) financeState.pace = { sec: 0, until: 0, base: 0 };
|
|
11451
|
+
notes.push(`temel tur aralığı: ${sec} sn`);
|
|
11452
|
+
}
|
|
11453
|
+
intervalChanged = true;
|
|
11454
|
+
} else if (patch.intervalForMin !== undefined) {
|
|
11455
|
+
notes.push('intervalForMin için intervalSec de verilmeli');
|
|
11456
|
+
}
|
|
11304
11457
|
if (f.minLot > f.maxLot) {
|
|
11305
11458
|
notes.push(`minLot (${f.minLot}) maxLot'tan (${f.maxLot}) büyüktü → minLot ${f.maxLot} yapıldı`);
|
|
11306
11459
|
f.minLot = f.maxLot;
|
|
11307
11460
|
}
|
|
11308
11461
|
try { saveSettings(); } catch {}
|
|
11462
|
+
if (intervalChanged) { try { finRescheduleAgents(); } catch {} }
|
|
11309
11463
|
finSyncLimitsToSessions();
|
|
11310
|
-
const
|
|
11464
|
+
const paceOn = Number(financeState.pace && financeState.pace.until) > Date.now();
|
|
11465
|
+
const line = `⚙️ LİMİTLER GÜNCELLENDİ: min lot ${f.minLot} · max lot ${f.maxLot} · max pozisyon ${f.maxPositions}${intervalChanged ? ` · tur ${finPaceSec()} sn${paceOn ? ' (hız modu)' : ''}` : ''}${sid ? ' (ajan kararı)' : ''}`;
|
|
11311
11466
|
financeLog('[limit] ' + line);
|
|
11312
11467
|
financeNotify(line, 'limit', true);
|
|
11313
|
-
try { finJournal({ kind: 'limits', minLot: f.minLot, maxLot: f.maxLot, maxPositions: f.maxPositions, sid }); } catch {}
|
|
11468
|
+
try { finJournal({ kind: 'limits', minLot: f.minLot, maxLot: f.maxLot, maxPositions: f.maxPositions, intervalSec: finPaceSec(), paceUntil: paceOn ? financeState.pace.until : 0, sid }); } catch {}
|
|
11314
11469
|
return { ok: true, limits: finLimitsSnapshot(), note: notes.length ? notes.join('; ') : undefined };
|
|
11315
11470
|
}
|
|
11316
11471
|
|
|
@@ -11322,7 +11477,11 @@ function finLimitsSet(patch, ctx) {
|
|
|
11322
11477
|
const FIN_LEARN_MAX_NOTES = 60; /* sembol başına ders tavanı */
|
|
11323
11478
|
const FIN_LEARN_MAX_TRADES = 60;
|
|
11324
11479
|
const FIN_LEARN_MAX_SYMBOLS = 60; /* toplam sembol tavanı — depo sınırsız büyümesin */
|
|
11325
|
-
const FIN_LEARN_MAX_NOTES_DAY =
|
|
11480
|
+
const FIN_LEARN_MAX_NOTES_DAY = 3; /* sembol başına 24 saatte en fazla ders — ders SELİ depoyu zehirlemesin */
|
|
11481
|
+
/* DERS KALİTESİ: "günlük tutar gibi" uzun/genel metinler ders DEĞİLDİR —
|
|
11482
|
+
yalnız kısa, somut, tekrar kullanılabilir bilgi kaydedilir. */
|
|
11483
|
+
const FIN_LEARN_NOTE_MIN = 12; /* çok kısa/genel laf (ör. "iyi işlem") ders sayılmaz */
|
|
11484
|
+
const FIN_LEARN_NOTE_MAX = 200; /* tek kısa cümle tavanı (karakter) */
|
|
11326
11485
|
/* SÜREKLİ UNUTMA (bellek hijyeni): eski kayıtlar otomatik düşer — depo büyüyüp
|
|
11327
11486
|
zehirlenmez, yalnız GÜNCEL dersler ve son performans kalır. */
|
|
11328
11487
|
const FIN_LEARN_NOTE_TTL_MS = 30 * 24 * 60 * 60 * 1000; /* 30 gün: eski ders unutulur */
|
|
@@ -11354,6 +11513,20 @@ function finLearnNoteKey(text) {
|
|
|
11354
11513
|
.slice(0, 140);
|
|
11355
11514
|
}
|
|
11356
11515
|
|
|
11516
|
+
/* DERS KALİTE KAPISI: gerçekten öğrenilmiş, işe yarar bilgi kısa cümleyle;
|
|
11517
|
+
günlük/özet tarzı metin ya da genel laf kaydedilmez. Hata metni ya da null. */
|
|
11518
|
+
function finLearnNoteQuality(text) {
|
|
11519
|
+
const t = String(text || '').replace(/\s+/g, ' ').trim();
|
|
11520
|
+
if (t.length < FIN_LEARN_NOTE_MIN) return 'ders çok kısa — tek cümlede somut ders yaz (ör. "Londra açılışı M5 EMA50 üstü momentum işledi")';
|
|
11521
|
+
if (t.length > FIN_LEARN_NOTE_MAX) return `ders çok uzun (${t.length} karakter) — en fazla ${FIN_LEARN_NOTE_MAX} karakterlik TEK kısa cümle yaz; günlük/rapor metnini ders diye kaydetme`;
|
|
11522
|
+
if (/^(bug[üu]n|g[üu]nl[üu]k|bu sabah|bu ak[şs]am|sabah|ak[şs]am)\b/i.test(t)) return 'günlük tarzı metin ders değildir — yalnız tekrar kullanılabilir somut ders yaz';
|
|
11523
|
+
/* GENEL LAFLAR: kanıtsız/tavsiye cümleleri ders değildir (somut setup/ölçüm iste) */
|
|
11524
|
+
if (/(dikkatli ol|dikkat et|sab[ıi]rl[ıi] ol|panik yapma|duygular[ıi]na kap[ıi]lma|disiplinli ol|temkinli ol)/i.test(t)) {
|
|
11525
|
+
return 'genel tavsiye ders değildir — hangi setup/koşulda ne olduğunu somut yaz (ör. sembol+periyot+seviye+sonuç)';
|
|
11526
|
+
}
|
|
11527
|
+
return null;
|
|
11528
|
+
}
|
|
11529
|
+
|
|
11357
11530
|
/* sembolün son aktivitesi (kapanış / ders / eski istatistik) — tavan aşımında
|
|
11358
11531
|
EN ESKİ semboller düşürülür; dokunulan (protectSym) sembol asla atılmaz */
|
|
11359
11532
|
function finLearnActivity(e) {
|
|
@@ -11630,9 +11803,10 @@ function finBuildLearnDigest(symbols) {
|
|
|
11630
11803
|
function finLearnApi() {
|
|
11631
11804
|
const norm = (s) => String(s || '').trim().toUpperCase();
|
|
11632
11805
|
return {
|
|
11633
|
-
list: ({ symbol } = {}) => {
|
|
11806
|
+
list: ({ symbol, limit } = {}) => {
|
|
11634
11807
|
const learn = finLearnLoad();
|
|
11635
11808
|
const sym = norm(symbol);
|
|
11809
|
+
const take = Math.max(1, Math.min(25, Math.round(Number(limit) || 8)));
|
|
11636
11810
|
if (sym) {
|
|
11637
11811
|
const e = learn.symbols[sym];
|
|
11638
11812
|
if (!e) return { ok: true, symbol: sym, count: 0, notes: [], trades: [], stats: finLearnEmptyStats(), summary: null };
|
|
@@ -11640,7 +11814,7 @@ function finLearnApi() {
|
|
|
11640
11814
|
ok: true,
|
|
11641
11815
|
symbol: sym,
|
|
11642
11816
|
count: e.notes.length,
|
|
11643
|
-
notes: e.notes.slice(-
|
|
11817
|
+
notes: e.notes.slice(-take),
|
|
11644
11818
|
trades: e.trades.slice(-12),
|
|
11645
11819
|
stats: { ...finLearnEmptyStats(), ...(e.stats || {}) },
|
|
11646
11820
|
summary: e.summary && e.summary.text ? e.summary : null,
|
|
@@ -11658,9 +11832,20 @@ function finLearnApi() {
|
|
|
11658
11832
|
return { ok: true, count: rows.length, symbols: rows.slice(0, FIN_LEARN_MAX_SYMBOLS) };
|
|
11659
11833
|
},
|
|
11660
11834
|
stats: ({ symbol } = {}) => {
|
|
11835
|
+
/* KOMPAKT OKUMA: istatistik + kalıcı özet + son 3 ders — ajan karar
|
|
11836
|
+
öncesi bunu okur (hafızanın TAMAMI değil, sadece güncel öz) */
|
|
11661
11837
|
const learn = finLearnLoad();
|
|
11662
11838
|
const sym = norm(symbol);
|
|
11663
|
-
if (sym)
|
|
11839
|
+
if (sym) {
|
|
11840
|
+
const e = learn.symbols[sym] || {};
|
|
11841
|
+
return {
|
|
11842
|
+
ok: true,
|
|
11843
|
+
symbol: sym,
|
|
11844
|
+
stats: { ...finLearnEmptyStats(), ...(e.stats || {}) },
|
|
11845
|
+
summary: e.summary && e.summary.text ? e.summary : null,
|
|
11846
|
+
notes: Array.isArray(e.notes) ? e.notes.slice(-3) : [],
|
|
11847
|
+
};
|
|
11848
|
+
}
|
|
11664
11849
|
const stats = {};
|
|
11665
11850
|
for (const [s, e] of Object.entries(learn.symbols)) stats[s] = { ...finLearnEmptyStats(), ...(e.stats || {}) };
|
|
11666
11851
|
return { ok: true, count: Object.keys(stats).length, stats };
|
|
@@ -11669,6 +11854,9 @@ function finLearnApi() {
|
|
|
11669
11854
|
const sym = norm(symbol);
|
|
11670
11855
|
const t = String(text || '').replace(/\s+/g, ' ').trim();
|
|
11671
11856
|
if (!sym || !t) return { ok: false, error: 'symbol ve text gerekli' };
|
|
11857
|
+
/* KALİTE KAPISI: kısa + somut + tekrar kullanılabilir — günlük tutma */
|
|
11858
|
+
const q = finLearnNoteQuality(t);
|
|
11859
|
+
if (q) return { ok: false, error: q, symbol: sym };
|
|
11672
11860
|
const learn = finLearnLoad();
|
|
11673
11861
|
const e = finLearnSym(sym);
|
|
11674
11862
|
if (!e) return { ok: false, error: 'sembol yok' };
|
|
@@ -11693,7 +11881,7 @@ function finLearnApi() {
|
|
|
11693
11881
|
const note = {
|
|
11694
11882
|
id: 'l' + Date.now().toString(36) + Math.random().toString(36).slice(2, 6),
|
|
11695
11883
|
at: Date.now(),
|
|
11696
|
-
text: t.slice(0,
|
|
11884
|
+
text: t.slice(0, FIN_LEARN_NOTE_MAX),
|
|
11697
11885
|
kind: ['pattern', 'mistake', 'rule', 'observation'].includes(String(kind || '')) ? String(kind) : 'observation',
|
|
11698
11886
|
tags: Array.isArray(tags) ? tags.map((x) => String(x || '').slice(0, 24)).filter(Boolean).slice(0, 6) : [],
|
|
11699
11887
|
sid: String(sid || ''),
|
|
@@ -12157,7 +12345,13 @@ function finApplyTraderFields(s, symbolsOverride, role, isMain) {
|
|
|
12157
12345
|
s.financeSymbols = Array.isArray(symbolsOverride) && symbolsOverride.length ? symbolsOverride : f.symbols;
|
|
12158
12346
|
s.financeStrategy = String(f.strategy || '');
|
|
12159
12347
|
s.financeShadow = !!f.shadowMode; /* shadow modda işlem araçları emir göndermez */
|
|
12160
|
-
|
|
12348
|
+
{
|
|
12349
|
+
const lim = finLimitsSnapshot();
|
|
12350
|
+
s.financeLimits = {
|
|
12351
|
+
minLot: lim.minLot, maxLot: lim.maxLot, maxPositions: lim.maxPositions,
|
|
12352
|
+
symbolLimits: lim.symbols, intervalSec: lim.intervalSec, intervalBase: lim.intervalBase, paceUntil: lim.paceUntil,
|
|
12353
|
+
};
|
|
12354
|
+
}
|
|
12161
12355
|
/* ZORUNLU TEK skill: rol ajanı → roleSkills[rol], ana trader → roleSkills.trader */
|
|
12162
12356
|
const skillKey = r || (s.financePlaybook ? 'trader' : '');
|
|
12163
12357
|
s.financeRoleSkills = (skillKey && f.roleSkills && f.roleSkills[skillKey]) || [];
|
|
@@ -12235,7 +12429,7 @@ function finAgentStop(sid, reason, opts) {
|
|
|
12235
12429
|
}
|
|
12236
12430
|
/* ANA TRADER DURDU: ekip cycle'sız kaldı — kendi timer'ıyla dönmeye devam etsin */
|
|
12237
12431
|
if (agent.main) {
|
|
12238
|
-
const iv =
|
|
12432
|
+
const iv = finPaceSec() * 1000;
|
|
12239
12433
|
for (const [tsid, ta] of financeState.agents) {
|
|
12240
12434
|
if (!ta || !ta.role) continue;
|
|
12241
12435
|
if (engine && engine.isBusy(tsid)) continue;
|
|
@@ -12258,13 +12452,21 @@ function finTraderBrief(agent) {
|
|
|
12258
12452
|
return [
|
|
12259
12453
|
`Beast Finance ${who} başlatıldı — ilk tur: strateji çerçeveni kur ve piyasa taramasını yap.`,
|
|
12260
12454
|
`Odak semboller: ${syms || '(boş — mt5_status ile terminale bak, mantıklı semboller seç)'}`,
|
|
12261
|
-
`Tur aralığı: ${f.intervalSec} sn · Lot aralığı: ${f.minLot}–${f.maxLot} (
|
|
12455
|
+
`Tur aralığı: ${finPaceSec()} sn${Number(financeState.pace && financeState.pace.until) > Date.now() ? ` (HIZ MODU — taban ${f.intervalSec} sn)` : ''} · Lot aralığı: ${f.minLot}–${f.maxLot} (genel taban/tavan; sembol bazlı limit daraltır) · Max eşzamanlı pozisyon: ${f.maxPositions}`,
|
|
12456
|
+
(() => {
|
|
12457
|
+
const rows = Object.entries(f.symbolLimits || {}).map(([s, v]) => {
|
|
12458
|
+
const mn = Number(v && v.minLot) > 0 ? Number(v.minLot) : Number(f.minLot);
|
|
12459
|
+
const mx = Number(v && v.maxLot) > 0 ? Number(v.maxLot) : Number(f.maxLot);
|
|
12460
|
+
return `${s} ${mn}–${mx}`;
|
|
12461
|
+
});
|
|
12462
|
+
return rows.length ? `SEMBOL LOT LİMİTLERİN (senin kararın): ${rows.join(' · ')}` : '';
|
|
12463
|
+
})(),
|
|
12262
12464
|
agent && agent.main
|
|
12263
|
-
? `LİMİT YETKİN:
|
|
12465
|
+
? `LİMİT+RİTİM YETKİN: mt5_limits ile SEN güncellersin (anında geçerli): genel {action:"set", minLot?, maxLot?, maxPositions?}; SEMBOL BAZLI {action:"set", symbol:"XAUUSD", minLot?, maxLot?} — her sembolün min/max lotunu kendi karakterine göre SEN belirle (volatilite, spread, marj); sembolü genele döndürmek için {action:"set", symbol:"XAUUSD", reset:true}. TUR RİTMİ: {action:"set", intervalSec:45, intervalForMin:15} → sert hareket/haber anında geçici hızlan, süre bitince taban aralığa OTOMATİK döner; sakinleşince geri çek (ör. 180-300 sn) — SÜREKLİ en düşük aralıkta kalma (API/maliyet limiti).`
|
|
12264
12466
|
: '',
|
|
12265
12467
|
roleDef
|
|
12266
12468
|
? `UZMANLIK: ${roleDef.desc} — raporlarını bu çerçevede yaz; İŞLEM AÇMA, yalnız analiz + net öneri üret.`
|
|
12267
|
-
: 'Otomatik işlem AÇIK (daima): 6 emir tipinin HEPSİ açık — buy_market/sell_market (anlık piyasa), buy_limit/sell_limit ve buy_stop/sell_stop (bekleyen; price zorunlu). mt5_trade ya da mt5_pending İKİSİ de tüm tipleri kabul eder; ayrıca mt5_close/mt5_modify/mt5_cancel açık (limitler sistemce zorlanır). KISMİ KAPATMA yetkisi: kısmi TP (kâr al) ve kısmi stop (zarar kes) — mt5_close {percent, kind:"partial_tp"|"partial_sl"}; otomatik DEĞİL, gerek görürsen sen kullan. ALARM: mt5_alerts ile kurarken modu SEN seç — mode:"once" tek seferlik, mode:"repeat" + cooldownMin (dk) tekrarlı. Lot için mt5_risksize hesapla ya da mt5_trade’e riskPct ver; SL/TP broker stops_level mesafesine uymalı.',
|
|
12469
|
+
: 'Otomatik işlem AÇIK (daima): 6 emir tipinin HEPSİ açık — buy_market/sell_market (anlık piyasa), buy_limit/sell_limit ve buy_stop/sell_stop (bekleyen; price zorunlu). mt5_trade ya da mt5_pending İKİSİ de tüm tipleri kabul eder; ayrıca mt5_close/mt5_modify/mt5_cancel açık (limitler sistemce zorlanır). KISMİ KAPATMA yetkisi: kısmi TP (kâr al) ve kısmi stop (zarar kes) — mt5_close {percent, kind:"partial_tp"|"partial_sl"}; otomatik DEĞİL, gerek görürsen sen kullan. ALARM: mt5_alerts ile kurarken modu SEN seç — mode:"once" tek seferlik, mode:"repeat" + cooldownMin (dk) tekrarlı. Lot için mt5_risksize hesapla ya da mt5_trade’e riskPct ver; SL/TP broker stops_level mesafesine uymalı. LOT KORKUSU YOK: önemli olan lot değil SL YERİ ve risk %’sidir — yakın stoplu net setupta yüksek lot NORMALDİR (boyutu risk hesabı verir).',
|
|
12268
12470
|
roleDef
|
|
12269
12471
|
? 'Bulgularını agent_dm ile ANA TRADER\u2019a bildir (to: "Trader" ya da ajan başlığı anahtarı); teknik/öneri çelişkisi varsa gerekçenle yaz.'
|
|
12270
12472
|
: f.strategy ? `Sahibinin strateji notu: ${f.strategy}` : 'Strateji notu yok: trend + destek/direnç + momentum ile temel okuma yap.',
|
|
@@ -12273,7 +12475,7 @@ function finTraderBrief(agent) {
|
|
|
12273
12475
|
f.shadowMode ? 'SHADOW MOD AÇIK: emir gönderilmez — kararlarını gerekçesiyle raporla, gerçek işlem açılmaz.' : '',
|
|
12274
12476
|
'Bu turda: mt5_status → hesap/pozisyon/fiyat verisi → mt5_rates/mt5_indicators ile teknik okuma → değerlendirme → kararlar (veya BEKLE: sebep) → kısa rapor.',
|
|
12275
12477
|
'Önemli kararların gerekçesini mt5_note ile günlüğe yaz (haftalık performans raporu bu notları kullanır).',
|
|
12276
|
-
'ÖĞRENME (
|
|
12478
|
+
'ÖĞRENME (SEÇİCİ): yalnız gerçekten öğrenilmiş, tekrar kullanılabilir içgörüyü tek KISA cümleyle mt5_ogrenme {action:"add", symbol, text, kind} ile kaydet (günde en fazla 2-3); her kapanışa ders yazma, günlük/uzun metin kaydetme; yeni karar öncesi mt5_ogrenme {action:"stats"/"list", symbol} ile geçmişi oku.',
|
|
12277
12479
|
'Risk otomasyonu main süreçte 5 sn döngüyle çalışır (+R BE, trailing, KÂR KORUMA: kâr 0.3R\'de kilitlenir, kısmi TP) — TP için RR ≥ 1.5 şartı YOK; 0.3-0.5R\'de kısmi kâr alıp kalanı korumalı trailing ile taşı (hızlı kâr toplama), SL/TP seviyelerini yine sen aktif yönet.',
|
|
12278
12480
|
'⚡HIZLI AKSİYON: onaylı fırsatta market buy/sell ile ANINDA gir (mt5_trade {symbol, side, sl, tp, riskPct}); bekleyen emir vermek ZORUNLU DEĞİL — limit/stop yalnız seviye beklemede kurulur.',
|
|
12279
12481
|
'Diğer finance/paralel ajanlarla koordinasyon için agent_dm aracı var (to: ajan başlığı anahtar kelimesi).',
|
|
@@ -12359,7 +12561,7 @@ async function finConsultPlan(f, agent, sid) {
|
|
|
12359
12561
|
'Güncel piyasa bağlamı gerekiyorsa web_search kullan; kurulu bir skill konuyla ilgiliyse skill aracıyla oku.';
|
|
12360
12562
|
const ctx = [
|
|
12361
12563
|
`Odak semboller: ${agent && agent.symbols && agent.symbols.length ? agent.symbols.join(', ') : (f.symbols || []).join(', ') || '(boş — ajan kendi bulabilir)'}`,
|
|
12362
|
-
`Otomatik işlem: ${auto} · lot aralığı ${f.minLot}–${f.maxLot} · max eşzamanlı pozisyon ${f.maxPositions}`,
|
|
12564
|
+
`Otomatik işlem: ${auto} · lot aralığı ${f.minLot}–${f.maxLot} (genel; sembol bazlı limitler daraltır) · max eşzamanlı pozisyon ${f.maxPositions}`,
|
|
12363
12565
|
account
|
|
12364
12566
|
? `Hesap: bakiye ${account.balance} ${account.currency} · özkaynak ${account.equity ?? '?'} · serbest marj ${account.margin_free ?? '?'} · kaldıraç 1:${account.leverage ?? '?'}`
|
|
12365
12567
|
: 'Hesap verisi alınamadı.',
|
|
@@ -12411,7 +12613,7 @@ function finTeamHasMain() {
|
|
|
12411
12613
|
|
|
12412
12614
|
/* Takılma valfi: ekip turu bu süreyi aşarsa trader eski raporla başlar */
|
|
12413
12615
|
function finTeamWaitMaxMs() {
|
|
12414
|
-
const iSec =
|
|
12616
|
+
const iSec = finPaceSec();
|
|
12415
12617
|
return Math.max(60, Math.min(300, iSec)) * 1000;
|
|
12416
12618
|
}
|
|
12417
12619
|
|
|
@@ -12500,7 +12702,7 @@ function finAgentRound(sid, opts) {
|
|
|
12500
12702
|
: 'İşlem açabilirsin — limitlere uy, SL\u2019siz pozisyon bırakma.';
|
|
12501
12703
|
const learnTip = roleDef
|
|
12502
12704
|
? ' İlgili sembolün geçmiş derslerini (mt5_ogrenme) oku ve önerine yansıt.'
|
|
12503
|
-
: '
|
|
12705
|
+
: ' Yalnız gerçekten öğretici, tekrar kullanılabilir bir içgörü varsa TEK kısa cümleyle mt5_ogrenme add ile kaydet (her kapanışa ders yazma); karar öncesi mt5_ogrenme stats/list ile o sembolün geçmişini oku' + (agent.main ? '; mt5_limits ile lot/pozisyon limitlerini ve TUR RİTMİNİ (intervalSec+intervalForMin) güncelleyebilirsin.' : '.');
|
|
12504
12706
|
const focus = agent.symbols.length ? `Odak: ${agent.symbols.join(', ')}. ` : '';
|
|
12505
12707
|
const round = `FINANCE TUR #${agent.round}: ${focus}hesap + pozisyonlar + fiyatları çek; ${roleDef ? 'rolüne uygun analiz yap (mt5_rates/mt5_indicators ile) ve öneri ver.' : 'açık pozisyonları yönet (SL/TP güncelle, hedefe ulaşanı kapat); mt5_rates/mt5_indicators ile yeni fırsatları değerlendir. ⚡Onaylı fırsatta market buy/sell ile ANINDA gir (bekleyen emir ZORUNLU DEĞİL); lot için volume yerine riskPct+sl yeter.'} ${auto}${learnTip} Önemli kararların gerekçesini mt5_note ile günlüğe yaz. Kısa rapor ver.`;
|
|
12506
12708
|
const launch = (planBlock) => {
|
|
@@ -12595,8 +12797,7 @@ function finFlushOnDone(ev) {
|
|
|
12595
12797
|
sıradaki turu trader'ın cycle'ı başlatır (rapor tazeliği). Trader yoksa
|
|
12596
12798
|
ekip kendi timer'ıyla dönmeye devam eder. */
|
|
12597
12799
|
if (agent.role && finTeamHasMain()) return;
|
|
12598
|
-
const
|
|
12599
|
-
const iv = Math.max(30, Number(f.intervalSec) || 120) * 1000;
|
|
12800
|
+
const iv = finPaceSec() * 1000;
|
|
12600
12801
|
financeState.lastRoundAt = Date.now();
|
|
12601
12802
|
if (agent.main) {
|
|
12602
12803
|
finPush('trader', { state: 'idle', round: agent.round, nextInSec: iv / 1000 });
|
|
@@ -12791,21 +12992,14 @@ ipcMain.handle('finance:settings', async (_e, patch) => {
|
|
|
12791
12992
|
}
|
|
12792
12993
|
if (p.intervalSec !== undefined) f.intervalSec = Math.max(30, Math.min(3600, Math.round(Number(p.intervalSec) || 120)));
|
|
12793
12994
|
/* TUR ARALIĞI CANLI: bekleyen zamanlayıcılar yeni aralıkla yeniden kurulur —
|
|
12794
|
-
koşan tur bitince zaten finFlushOnDone yeni
|
|
12795
|
-
if (p.intervalSec !== undefined
|
|
12796
|
-
const iv = Math.max(30, Math.round(Number(f.intervalSec) || 120)) * 1000;
|
|
12797
|
-
const hasMain = finTeamHasMain();
|
|
12798
|
-
for (const [sid, a] of financeState.agents) {
|
|
12799
|
-
if (!a || !engine || engine.isBusy(sid)) continue;
|
|
12800
|
-
if (a.role && hasMain) continue; /* cycle modu: ekip turunu trader başlatır */
|
|
12801
|
-
clearTimeout(a.timer);
|
|
12802
|
-
a.timer = setTimeout(() => { try { finAgentRound(String(sid)); } catch {} }, iv);
|
|
12803
|
-
}
|
|
12804
|
-
}
|
|
12995
|
+
koşan tur bitince zaten finFlushOnDone yeni ritmi okur. */
|
|
12996
|
+
if (p.intervalSec !== undefined) { try { finRescheduleAgents(); } catch {} }
|
|
12805
12997
|
if (p.maxLot !== undefined) f.maxLot = Math.max(0.01, Math.min(100, Number(p.maxLot) || 0.1));
|
|
12806
12998
|
if (p.minLot !== undefined) f.minLot = Math.max(0.01, Math.min(100, Number(p.minLot) || 0.01));
|
|
12807
12999
|
/* min lot max lotu aşamaz — hangisi sonra yazıldıysa diğerine kelepçelenir */
|
|
12808
13000
|
if (f.minLot > f.maxLot) f.minLot = f.maxLot;
|
|
13001
|
+
/* genel aralık değişti: sembol bazlı limitler yeni taban/tavana kelepçelenir */
|
|
13002
|
+
if (p.minLot !== undefined || p.maxLot !== undefined) finNormalizeSymbolLimits(f);
|
|
12809
13003
|
if (p.maxPositions !== undefined) f.maxPositions = Math.max(1, Math.min(20, Math.round(Number(p.maxPositions) || 3)));
|
|
12810
13004
|
/* limit değişikliği koşan oturumlara ANINDA işlenir (sonraki turu beklemez) */
|
|
12811
13005
|
if (p.minLot !== undefined || p.maxLot !== undefined || p.maxPositions !== undefined) {
|
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="finLearnBtn" title="MT5 öğrenme hafızası — neler öğrendi: sembol bazlı dersler + otomatik istatistik (görüntüle/sil)"
|
|
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>
|
|
@@ -868,7 +869,7 @@
|
|
|
868
869
|
</div>
|
|
869
870
|
<div class="mini-body">
|
|
870
871
|
<div id="finLearnList" class="mini-list"></div>
|
|
871
|
-
<div class="fin-sym-hint">Trade ajanının çekirdekteki sembol bazlı hafızası: her işlem kapanışı otomatik istatistiğe işlenir
|
|
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>
|
|
872
873
|
</div>
|
|
873
874
|
</div>
|
|
874
875
|
</div>
|
package/src/renderer/renderer.js
CHANGED
|
@@ -226,6 +226,7 @@ const els = {
|
|
|
226
226
|
finInterval: $('#finInterval'),
|
|
227
227
|
finMinLot: $('#finMinLot'),
|
|
228
228
|
finMaxLot: $('#finMaxLot'),
|
|
229
|
+
finSymLimits: $('#finSymLimits'),
|
|
229
230
|
finStrategy: $('#finStrategy'),
|
|
230
231
|
finMaxTradesDay: $('#finMaxTradesDay'),
|
|
231
232
|
finLossStreak: $('#finLossStreak'),
|
|
@@ -9821,6 +9822,30 @@ function finSymBtnUpdate() {
|
|
|
9821
9822
|
}
|
|
9822
9823
|
}
|
|
9823
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
|
+
|
|
9824
9849
|
function finTraderInputsSet(cfg) {
|
|
9825
9850
|
if (!cfg) return;
|
|
9826
9851
|
if (!finWatchDirty) finWatchSet(cfg.symbols);
|
|
@@ -9832,6 +9857,7 @@ function finTraderInputsSet(cfg) {
|
|
|
9832
9857
|
if (els.finInterval && ae !== els.finInterval) els.finInterval.value = cfg.intervalSec || 120;
|
|
9833
9858
|
if (els.finMinLot && ae !== els.finMinLot) els.finMinLot.value = cfg.minLot || 0.01;
|
|
9834
9859
|
if (els.finMaxLot && ae !== els.finMaxLot) els.finMaxLot.value = cfg.maxLot || 0.1;
|
|
9860
|
+
finSymLimitsRender(cfg.symbolLimits);
|
|
9835
9861
|
if (els.finStrategy && ae !== els.finStrategy && !finStrategyDirty) els.finStrategy.value = cfg.strategy || '';
|
|
9836
9862
|
if (els.finMaxTradesDay && ae !== els.finMaxTradesDay) els.finMaxTradesDay.value = Number(cfg.maxTradesPerDay) || 0;
|
|
9837
9863
|
if (els.finLossStreak && ae !== els.finLossStreak) els.finLossStreak.value = Number(cfg.lossStreakLimit) || 0;
|
|
@@ -10204,14 +10230,20 @@ function finOnEvent(ev) {
|
|
|
10204
10230
|
if (ev.minLot !== undefined) finCfgCache.minLot = ev.minLot;
|
|
10205
10231
|
if (ev.maxLot !== undefined) finCfgCache.maxLot = ev.maxLot;
|
|
10206
10232
|
if (ev.maxPositions !== undefined) finCfgCache.maxPositions = ev.maxPositions;
|
|
10233
|
+
if (ev.symbols !== undefined) finCfgCache.symbolLimits = ev.symbols;
|
|
10234
|
+
if (ev.intervalBase !== undefined) finCfgCache.intervalSec = ev.intervalBase;
|
|
10207
10235
|
finTraderInputsSet(finCfgCache);
|
|
10208
10236
|
} else {
|
|
10209
10237
|
const ae2 = document.activeElement;
|
|
10210
10238
|
if (els.finMinLot && ae2 !== els.finMinLot && ev.minLot !== undefined) els.finMinLot.value = ev.minLot;
|
|
10211
10239
|
if (els.finMaxLot && ae2 !== els.finMaxLot && ev.maxLot !== undefined) els.finMaxLot.value = ev.maxLot;
|
|
10240
|
+
if (els.finInterval && ae2 !== els.finInterval && ev.intervalBase !== undefined) els.finInterval.value = ev.intervalBase;
|
|
10241
|
+
if (ev.symbols !== undefined) finSymLimitsRender(ev.symbols);
|
|
10212
10242
|
}
|
|
10213
10243
|
finLogLine('[limit] ' + (ev.note || ('min lot ' + ev.minLot + ' · max lot ' + ev.maxLot + ' · max pozisyon ' + ev.maxPositions)));
|
|
10214
|
-
|
|
10244
|
+
if (ev.symbol) toast('Sembol lot limiti güncellendi: ' + ev.symbol);
|
|
10245
|
+
else if (ev.paceUntil) toast('Trader hız modu: tur ' + ev.intervalSec + ' sn — süre bitince tabana döner');
|
|
10246
|
+
else toast('Trader limitleri güncelledi: min ' + ev.minLot + ' / max ' + ev.maxLot + (ev.intervalSec ? ' · tur ' + ev.intervalSec + ' sn' : ''));
|
|
10215
10247
|
} else if (ev.fn === 'install') {
|
|
10216
10248
|
finLogLine('[MT5] paket kurulumu tamamlandı (kod ' + ev.code + ')');
|
|
10217
10249
|
}
|
|
@@ -11051,7 +11083,7 @@ if (els.finSkillsOverlay) {
|
|
|
11051
11083
|
Çekirdekteki (main process) sembol bazlı öğrenme deposunu gösterir:
|
|
11052
11084
|
otomatik istatistik + ajanın mt5_ogrenme ile yazdığı dersler. Tek ders
|
|
11053
11085
|
silinebilir, sembol kaydı tümden bırakılabilir; depo tavanları
|
|
11054
|
-
(60 sembol /
|
|
11086
|
+
(60 sembol / 60 ders / 60 işlem / günlük 3 ders; ders = kısa+somut) çekirdekte uygulanır. */
|
|
11055
11087
|
const FIN_LEARN_TRASH_SVG =
|
|
11056
11088
|
'<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>';
|
|
11057
11089
|
|
|
@@ -11211,7 +11243,7 @@ function finLearnSymEl(row) {
|
|
|
11211
11243
|
body.hidden = false;
|
|
11212
11244
|
finLearnOpenSym = sym;
|
|
11213
11245
|
body.innerHTML = '<div class="fin-empty">yükleniyor…</div>';
|
|
11214
|
-
const d = await finLearnCall({ action: 'list', symbol: sym });
|
|
11246
|
+
const d = await finLearnCall({ action: 'list', symbol: sym, limit: 25 });
|
|
11215
11247
|
if (!els.finLearnOverlay || els.finLearnOverlay.hidden) { busy = false; return; }
|
|
11216
11248
|
finLearnDetail(body, sym, d);
|
|
11217
11249
|
loaded = true;
|
|
@@ -11266,7 +11298,7 @@ function finLearnDetail(body, sym, d) {
|
|
|
11266
11298
|
if (!notes.length) {
|
|
11267
11299
|
const e = document.createElement('div');
|
|
11268
11300
|
e.className = 'fin-empty';
|
|
11269
|
-
e.textContent = 'Ders yok — ajan
|
|
11301
|
+
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).';
|
|
11270
11302
|
body.appendChild(e);
|
|
11271
11303
|
} else {
|
|
11272
11304
|
for (const n of notes.slice().reverse()) {
|