beast-agent 2.30.2 → 2.30.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "beast-agent",
3
3
  "productName": "Beast Agent",
4
- "version": "2.30.2",
4
+ "version": "2.30.4",
5
5
  "description": "Ultra-fast local agent shell for Windows.",
6
6
  "author": "algokodcom (AlgoKod)",
7
7
  "license": "MIT",
@@ -1894,6 +1894,18 @@ class Engine {
1894
1894
  macro:
1895
1895
  'ROL: MAKRO AJANI 🌍 — büyük resim uzmanısın, İşlem AÇMAZSIN (mt5_trade/mt5_pending/mt5_close KULLANMA). Her turda web_search ile güncel makro manşetleri + ekonomik takvim riskleri (faiz, CPI, jeopolitik); DXY/altın/petrol bağıntılarını odak sembollere çevir; sembol başına yön eğilimi + TEMKİN/BEKLE notu ver.',
1896
1896
  })[String((session && session.financeRole) || '')] || '';
1897
+ /* ROL → SKILL eşleştirmesi (ayarlar modalı): rolün okuması gereken skill'ler
1898
+ prompta gömülür; ayar boşsa satır eklenmez. Skill adları kurulu katalogdan
1899
+ seçilir — yeni skill eklendiğinde modalda görünür ve buraya yansır. */
1900
+ const roleSkills = Array.isArray(session && session.financeRoleSkills)
1901
+ ? session.financeRoleSkills.map((s) => String(s || '').trim()).filter(Boolean).slice(0, 8)
1902
+ : [];
1903
+ const roleBlockFull = roleBlock
1904
+ ? roleBlock +
1905
+ (roleSkills.length
1906
+ ? ` ÖNCE şu skill'leri skill aracıyla oku ve prosedürüne göre uygula: ${roleSkills.map((n) => `skill("${n}")`).join(', ')}.`
1907
+ : '')
1908
+ : '';
1897
1909
  /* FİNANS EKİBİ: tüm finance ajanları tek DM grubundadır — sohbet grup
1898
1910
  thread'inde toplanır (ayrı ayrı 1:1 thread'lere dağılmaz) */
1899
1911
  const finJob = this._bgJobs && this._bgJobs.get(String(session && session.id));
@@ -1903,11 +1915,16 @@ class Engine {
1903
1915
  'Sen BEAST FİNANS\u2019sın — bilgisayardaki MetaTrader 5 (MT5) terminaline köprüyle bağlı trading ajanı.\n' +
1904
1916
  'ORTAM: Beast Finance uygulamasındasın — solda sohbet geçmişi + izleyiciler, ortada bu sohbet, SAĞ panelde MT5 işlem panosu (hesap, pozisyonlar, piyasa, AKIŞ) var.\n' +
1905
1917
  'KÖPRÜ: MT5 terminaline Python stdio köprüsüyle bağlısın; panel 3 saniyede bir hesap/pozisyon/piyasa verisini tazeler. mt5_* araç çağrıların ve işlem hareketlerin (açılan/kapanan pozisyonlar) SAĞ paneldeki AKIŞ akışına canlı düşer — panelin orayı izlediğini bil.\n' +
1906
- 'GÖREV ALANI: piyasa verisi okuma (fiyat/hesap/pozisyon/geçmiş), teknik değerlendirme, pozisyon yönetimi (aç/kapat/SL/TP), risk disiplini ve kısa karar raporları. Kod yazma işi DEĞİLDİR.\n' +
1918
+ 'GÖREV ALANI: piyasa verisi okuma (fiyat/hesap/pozisyon/geçmiş), teknik değerlendirme, pozisyon yönetimi (aç/kapat/SL/TP), risk disiplini ve kısa karar raporları. GEREKTİĞİNDE kendi araçlarını üretirsin — kişisel tool yazımı ve MQL5 script/EA geliştirme bu görev alanının parçasıdır.\n' +
1907
1919
  modeBlock2 + '\n' +
1908
- (roleBlock ? roleBlock + '\n' : '') +
1920
+ (roleBlockFull ? roleBlockFull + '\n' : '') +
1909
1921
  (teamLine || '') +
1910
1922
  'MT5 ARAÇLARI: mt5_status (bağlantı), mt5_account (hesap), mt5_market (canlı fiyat), mt5_positions (açık pozisyonlar), mt5_orders (bekleyen emirler), mt5_history (kapanan işlemler), mt5_trade (piyasa emri), mt5_close (kapat), mt5_modify (SL/TP), mt5_pending (bekleyen emir), mt5_cancel (emir iptal).\n' +
1923
+ 'YETKİLERİN (AÇIK — çekinmeden kullan):\n' +
1924
+ '- skill: kurulu SKILL.md kataloğunu oku ve uygula — tool yazmadan ÖNCE skill("tool-yazma"), MT5 tarafı işlerden ÖNCE skill("mql5") oku ve prosedürüne birebir uy.\n' +
1925
+ '- Kişisel tool yazma: %APPDATA%\\beast\\tools\\<slug>\\ içine tool.json + run.js yaz (write_file/edit_file); run_command ile çıktısını (JSON, ok alanlı) doğrula → tool__<slug> ANINDA tüm finance ajanlarında çağrılabilir olur.\n' +
1926
+ '- MQL5: MT5 tarafında script/gösterge/EA yaz (write_file), metaeditor64.exe /compile ile derle, MQL5\\Files dosya köprüsüyle veriyi Beast\'e taşı; kullanıcıya çalıştırma adımını açıkça söyle.\n' +
1927
+ '- Yerleşik araçlar: run_command, python_run, read_file/write_file/edit_file, web_search/deep_search, browser_* — hepsi açık.\n' +
1911
1928
  'VERİ AKIŞI (her değerlendirmede): mt5_account + mt5_positions + mt5_market çağrılarını AYNI turda PARALEL ver; gerekiyorsa mt5_history ile son işlemleri gör.\n' +
1912
1929
  'PARALEL + KOORDİNASYON: uzun araştırma/işleri run_background ile paralel finance işçisine devret (parent finance olduğu için işçi mt5 okuma araçlarını görür); koşan ajanlarla konuşmak için agent_dm (to: ajan başlığındaki anahtar kelime, örn "GOLD"; ortak karar için group: "İSİM" ile grup sohbeti kur — mesaj tüm üyelere düşer). Görevin bitince DM/grup sohbetleri otomatik KAPANIR (geçmiş panelde kalır).\n' +
1913
1930
  (symbols ? `İZLEME LİSTESİ: ${symbols}\n` : '') +
@@ -1921,7 +1938,7 @@ class Engine {
1921
1938
  (mem.user ? `# USER\n${mem.user}\n` : '') +
1922
1939
  (rules.length ? `# KURALLAR (sahibinin kalıcı talimatları — daima uy)\n${rules.map((r) => '- ' + r).join('\n')}\n` : '') +
1923
1940
  (skList.length
1924
- ? '# SKILLS\nKurulu skill kataloğu: görev bir skill\u2019in tanımına uyarsa skill aracıyla gövdesini (SKILL.md) yükleyip uygula — tekerleği yeniden icat etme. Analysis/rapor/PDF gibi işlerde skill\u2019in prosedürüne uy.\n' +
1941
+ ? '# SKILLS\nKurulu skill kataloğu: görev bir skill\u2019in tanımına uyarsa skill aracıyla gövdesini (SKILL.md) yükleyip uygula — tekerleği yeniden icat etme. Analysis/rapor/PDF gibi işlerde skill\u2019in prosedürüne uy. Tool yazımı → "tool-yazma", MT5 tarafı geliştirme → "mql5" skill\u2019i önceliklidir.\n' +
1925
1942
  skList.map((s) => `- ${s.name}: ${s.description} [${s.path}]`).join('\n') + '\n'
1926
1943
  : '') +
1927
1944
  'RAPOR DİSİPLİNİ: kısa ve sayısal — sembol, yön, lot, giriş, SL/TP, sebep tek satırda. Uzun fal açma; tablo/liste kullanabilirsin.\n' +
@@ -6372,34 +6389,37 @@ Engine.prototype._agentDmSend = function (fromSid, args) {
6372
6389
  groupName verilmemişse ama iki taraf da AYNI AÇIK grubun üyesiyse mesaj
6373
6390
  YİNE GRUBA düşer — üye üyeye 1:1 thread'lere ayrı ayrı dağılmaz; ekibin
6374
6391
  tüm iç trafiği TEK grup sohbetinde canlı toplanır. */
6375
- const shared = groupName || !target ? null : this._agentDmSharedGroup(fromSid, target);
6392
+ /* TEK İŞ = TEK GRUP: taraflar AÇIK bir ekip/grup üyesiyse mesaj HER ZAMAN o
6393
+ gruba düşer — group: verilse bile yeni grup AÇILMAZ. Ayrıca group adı
6394
+ mevcut bir grubun başlığıyla eşleşiyorsa (ör. "Beast Finance EKİP" →
6395
+ team:finance) o grup kullanılır; aynı iş için ikinci grup oluşmaz. */
6396
+ const shared = target ? this._agentDmSharedGroup(fromSid, target) : null;
6376
6397
  let gid = '';
6377
- if (groupName || shared) {
6378
- let g;
6379
- if (groupName) {
6380
- /* gid Türkçe-kararsız normalize: ALTIN/Altın/altın aynı grup */
6381
- gid =
6382
- 'grp:' +
6383
- groupName
6384
- .toLowerCase()
6385
- .replace(/\u0307/g, '')
6386
- .replace(/ı/g, 'i')
6387
- .replace(/ğ/g, 'g')
6388
- .replace(/ü/g, 'u')
6389
- .replace(/ş/g, 's')
6390
- .replace(/ö/g, 'o')
6391
- .replace(/ç/g, 'c');
6392
- g = this._agentGroups.get(gid);
6393
- if (!g) {
6394
- if (!target) return { ok: false, error: 'yeni grup için to ile en az bir ajan belirt' };
6395
- g = { id: gid, title: groupName, members: [], titles: {}, createdAt: at, closed: false };
6396
- this._agentGroups.set(gid, g);
6398
+ let g = null;
6399
+ if (shared) {
6400
+ g = shared;
6401
+ gid = String(g.id || '');
6402
+ } else if (groupName) {
6403
+ gid = 'grp:' + this._agentGroupKey(groupName);
6404
+ g = this._agentGroups.get(gid) || null;
6405
+ if (!g) {
6406
+ const want = this._agentGroupKey(groupName);
6407
+ for (const [, cand] of this._agentGroups || new Map()) {
6408
+ if (!cand || cand.closed) continue;
6409
+ if (this._agentGroupKey(cand.title) === want) {
6410
+ g = cand;
6411
+ gid = String(cand.id || '');
6412
+ break;
6413
+ }
6397
6414
  }
6398
- } else {
6399
- g = shared;
6400
- gid = String(g.id || '');
6401
6415
  }
6402
- g.titles = g.titles || {};
6416
+ if (!g) {
6417
+ if (!target) return { ok: false, error: 'yeni grup için to ile en az bir ajan belirt' };
6418
+ g = { id: gid, title: groupName, members: [], titles: {}, createdAt: at, closed: false };
6419
+ this._agentGroups.set(gid, g);
6420
+ }
6421
+ }
6422
+ if (g) { g.titles = g.titles || {};
6403
6423
  const addMember = (sid, title) => {
6404
6424
  sid = String(sid);
6405
6425
  if (!g.members.includes(sid)) g.members.push(sid);
@@ -6478,6 +6498,20 @@ Engine.prototype._agentDmSharedGroup = function (a, b) {
6478
6498
  return null;
6479
6499
  };
6480
6500
 
6501
+ /* Grup adı anahtarı: Türkçe-kararsız normalize — ALTIN/Altın/altın aynı gruba
6502
+ iner; başlık eşleştirmede de kullanılır (ör. "Beast Finance EKİP"). */
6503
+ Engine.prototype._agentGroupKey = function (name) {
6504
+ return String(name || '')
6505
+ .toLowerCase()
6506
+ .replace(/\u0307/g, '')
6507
+ .replace(/ı/g, 'i')
6508
+ .replace(/ğ/g, 'g')
6509
+ .replace(/ü/g, 'u')
6510
+ .replace(/ş/g, 's')
6511
+ .replace(/ö/g, 'o')
6512
+ .replace(/ç/g, 'c');
6513
+ };
6514
+
6481
6515
  Engine.prototype._pushAgentDm = function (dm) {
6482
6516
  this._agentDms = this._agentDms || [];
6483
6517
  this._agentDms.push(dm);
@@ -6517,6 +6551,12 @@ Engine.prototype._agentTeamJoin = function (job) {
6517
6551
  g.closed = false;
6518
6552
  delete g.closedAt;
6519
6553
  g.titles = g.titles || {};
6554
+ /* durdurulmuş eski üyeler aktif kadrodan düşer — yeniden başlayan ekipte
6555
+ kapanmış ajanlar üye listesinde görünmez (geçmiş mesajlar korunur) */
6556
+ g.members = (g.members || []).filter((m) => {
6557
+ const j = this._bgJobs && this._bgJobs.get(String(m));
6558
+ return !j || j.status === 'running';
6559
+ });
6520
6560
  const add = (id, title) => {
6521
6561
  id = String(id);
6522
6562
  if (!g.members.includes(id)) g.members.push(id);
@@ -0,0 +1,49 @@
1
+ ---
2
+ name: haber-duygu
3
+ description: Haber ve piyasa duyarlılığı rehberi — ekonomik takvim riskleri (NFP/CPI/FOMC/faiz), haber öncesi-sonrası pozisyon disiplini, DXY/faiz/VIX/Fear&Greed okuma, risk-on/risk-off ve emtia bağıntıları. Makro/haber ajanı veya trader haber etkisi değerlendirirken ÖNCE bu skill'i okur.
4
+ version: 1.0.0
5
+ ---
6
+
7
+ # Haber & Piyasa Duyarlılığı
8
+
9
+ ## TEMEL İLKE
10
+
11
+ Haber yön tahmini için değil, **risk zamanlaması** için kullanılır. Yüksek etkili veri saatinde piyasa spreadi genişler ve yön belirsizdir; çoğu zaman en iyi işlem beklemektir.
12
+
13
+ ## 1) EKONOMİK TAKVİM
14
+
15
+ - Yüksek etkili: FOMC/faiz kararları, NFP (tarım dışı istihdam), CPI/PPI, GDP, işsizlik, ECB/BOE/BOJ kararları, jeopolitik başlıklar.
16
+ - Kural: yüksek etkili veriden **15–30 dk önce yeni pozisyon açma**; mevcut pozisyonu gözden geçir (SL sabit, panik kapatma yok).
17
+ - Veri sonrası: ilk 5–15 dk fitil/spike olur; kapanış teyidi gelmeden işlem açma.
18
+ - Takvimi `web_search`/`deep_search` ile teyit et; tarih/saati yerel saatle yaz (sunucu saati farkını belirt).
19
+
20
+ ## 2) DUYGU GÖSTERGELERİ
21
+
22
+ - **DXY**: dolar gücü — yükselirse altın ve EURUSD genelde baskılanır (ters korelasyon).
23
+ - **ABD 10Y tahvil faizi**: faiz yükseliyorsa risk iştahı azalabilir, altın baskılanabilir.
24
+ - **VIX**: yükseliyorsa risk-off; düşüyorsa risk-on.
25
+ - **Kripto Fear & Greed**: yalnız BTC/ETH gibi kripto pozisyonlarında; hisse/emtia için ana referans değil.
26
+ - Aşırı iyimserlik (greed) ve aşırı korku (fear) uçlarda dönüş riskidir; trend takipçisi için tek başına sinyal değildir.
27
+
28
+ ## 3) RİSK-ON / RİSK-OFF
29
+
30
+ - Risk-on: hisse ↑, emtia ↑, dolar/altın baskılı olabilir.
31
+ - Risk-off: DXY/altın/tahvil ↑, hisse/kripto ↓.
32
+ - Makro başlık bölgeyi tersine çevirdiyse mevcut teknik planı **güncelle**, körlemesine uygulama.
33
+
34
+ ## 4) HABER DOĞRULAMA
35
+
36
+ - Tek kaynağa güvenme; 2+ bağımsız kaynak teyidi ara.
37
+ - Manşet ile içerik çelişirse içeriği esas al; tarih/saat eski haberi taze sanma.
38
+ - Söylenti (rumor) ve resmi açıklamayı ayır; söylentiye işlem açma.
39
+
40
+ ## 5) BAĞINTI NOTLARI
41
+
42
+ - XAUUSD ile DXY ters korele; aynı yönde iki korelasyonlu pozisyon açma (bkz. risk-yonetimi).
43
+ - Petrol haberleri (OPEC, arz kesintisi) enerji sembollerini ve genel risk iştahını etkiler.
44
+ - Emtia sembollerinde broker sembol adını kullan (ör. "GOLD", "XAUUSD" değil) — `mt5_market` ile doğrula.
45
+
46
+ ## 6) RAPOR FORMATI
47
+
48
+ `Takvim: <saat> <veri> (yüksek) | duygu: risk-on/off | DXY yön | sembol etkisi: <yön/temkin> | aksiyon: bekle/azalt/normal`
49
+ Veri saatine 30 dk'dan az varsa bunu raporda AÇIKÇA belirt.
@@ -0,0 +1,129 @@
1
+ ---
2
+ name: mql5
3
+ description: MetaTrader 5 tarafında MQL5 (script / indicator / Expert Advisor) yazma-derleme rehberi — mt5_* araçlarının yapamadığı işleri (özel hesap, olay yakalama, EA ile otomatik yürütme, dosya köprüsü) MQL5 ile çözmek gerektiğinde ÖNCE bu skill'i oku. Veri klasörünü bulma, MetaEditor ile derleme, MQL5\Files köprüsü ve hazır kod iskeletleri burada.
4
+ version: 1.0.0
5
+ ---
6
+
7
+ # MQL5 Tool Yazma (MetaTrader 5)
8
+
9
+ ## NE ZAMAN KULLANILIR
10
+
11
+ - `mt5_*` araçları yetmiyorsa: tick/olay anında tepki, çok koşullu emir yönetimi, özel gösterge hesabı, hesap istatistiği, broker'a özel alanlar.
12
+ - Beast tarafında tekrarlı bir rutini MQL5 ile terminalin İÇİNDE çalıştırmak gerekiyorsa.
13
+ - Basit işi Python/Node ile yapabiliyorsan ÖNCE `python_run` / `run_command` / `mt5_*` dene — MQL5 son çare değil ama en ağır seçenektir.
14
+
15
+ ## 1) VERİ KLASÖRÜNÜ BUL (ilk adım)
16
+
17
+ 1. `mt5_status` çağır → dönen `terminal.data_path` = MT5 veri klasörü (en güvenilir yol).
18
+ 2. Bulamazsan `%APPDATA%\MetaQuotes\Terminal\<hash>\` altındaki klasörlerde `MQL5` dizinini ara; hash'i `origin.txt` içeriğiyle (kurulum yolu) eşleştir.
19
+ 3. Klasör düzeni:
20
+
21
+ | Klasör | Ne konur |
22
+ |---|---|
23
+ | `<data_path>\MQL5\Experts\` | Expert Advisor (EA) — chart'a iliştirilir |
24
+ | `<data_path>\MQL5\Indicators\` | Özel gösterge |
25
+ | `<data_path>\MQL5\Scripts\` | Tek seferlik script — elle bir kez çalıştırılır |
26
+ | `<data_path>\MQL5\Include\` | Paylaşılan `.mqh` başlıkları |
27
+ | `<data_path>\MQL5\Files\` | MQL5 program sandbox'ı — Beast buradan `read_file` ile okur |
28
+
29
+ ## 2) YAZMA
30
+
31
+ - Kod `write_file` ile `.mq5` olarak yazılır (UTF-8). `edit_file`, `read_file`, `run_command`, `python_run` yetkilerin açık.
32
+ - MQL5 C++ benzeridir; Python paketi yoktur, yalnız MetaTrader standart kütüphanesi vardır.
33
+ - Hazır sınıflar: `#include <Trade\Trade.mqh>` (CTrade), `#include <Trade\PositionInfo.mqh>`, `#include <Trade\SymbolInfo.mqh>`.
34
+ - Türkçe karakteri yalnız string/yorum içinde kullan; değişken adlarında kullanma.
35
+
36
+ ## 3) DERLEME (MetaEditor)
37
+
38
+ `metaeditor64.exe`, `terminal64.exe` ile aynı klasördedir (genelde `C:\Program Files\MetaTrader 5\` veya broker kurulum klasörü).
39
+
40
+ ```powershell
41
+ & "C:\Program Files\MetaTrader 5\metaeditor64.exe" /compile:"<data_path>\MQL5\Scripts\beast_script.mq5" /log:"<data_path>\MQL5\Scripts\beast_script.log"
42
+ ```
43
+
44
+ - Derleme logu **UTF-16**'dır:
45
+ ```powershell
46
+ Get-Content -Encoding Unicode "<log>" | Select-String "error|warning"
47
+ ```
48
+ - "0 errors" görmeden işi bitti sayma. Hata varsa kodu düzelt, yeniden derle.
49
+ - Terminalin açık olması derleme için gerekmez; metaeditor yolunu bulamazsan `Get-Command metaeditor64.exe` veya `Get-ChildItem "C:\Program Files" -Recurse -Filter metaeditor64.exe` ile ara.
50
+
51
+ ## 4) ÇALIŞTIRMA + BEAST KÖPRÜSÜ
52
+
53
+ - **Script**: MT5 → Navigator → Scripts → çift tık (kullanıcı) — Python API'den MQL5 tetiklenemez.
54
+ - **EA**: chart'a iliştirilir; AutoTrading düğmesi açık olmalıdır.
55
+ - **Dosya köprüsü (önerilen)**:
56
+ - MQL5 → Beast: program `MQL5\Files\beast_signal.json` yazar; ajan `read_file` ile `<data_path>\MQL5\Files\beast_signal.json` okur.
57
+ - Beast → MQL5: ajan `beast_cmd.json` yazar; EA `FileRead` ile komutu çeker (polling).
58
+ - Kullanıcıya EA/script'i nasıl iliştireceğini net söyle; "otomatik çalışıyor" varsayma.
59
+
60
+ ## 5) KOD İSKELETLERİ
61
+
62
+ ### Script → dosyaya veri yaz (Beast okur)
63
+
64
+ ```mql5
65
+ #property version "1.00"
66
+ #property script_show_inputs
67
+ input string OutFile = "beast_signal.json";
68
+
69
+ void OnStart()
70
+ {
71
+ double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
72
+ double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
73
+ int h = FileOpen(OutFile, FILE_WRITE | FILE_TXT | FILE_ANSI);
74
+ if(h == INVALID_HANDLE)
75
+ {
76
+ Print("dosya acilamadi: ", GetLastError());
77
+ return;
78
+ }
79
+ FileWriteString(h, StringFormat("{\"symbol\":\"%s\",\"bid\":%.5f,\"ask\":%.5f,\"time\":\"%s\"}",
80
+ _Symbol, bid, ask, TimeToString(TimeCurrent(), TIME_DATE | TIME_SECONDS)));
81
+ FileClose(h);
82
+ Print("beast_signal yazildi: ", bid, " / ", ask);
83
+ }
84
+ ```
85
+
86
+ ### EA iskeleti (CTrade)
87
+
88
+ ```mql5
89
+ #property version "1.00"
90
+ #include <Trade\Trade.mqh>
91
+ CTrade trade;
92
+
93
+ int OnInit()
94
+ {
95
+ trade.SetExpertMagicNumber(20260910);
96
+ return INIT_SUCCEEDED;
97
+ }
98
+
99
+ void OnTick()
100
+ {
101
+ /* sinyal + risk: lot hesabı, SL/TP zorunlu; martingale YOK */
102
+ /* trade.Buy(lot, _Symbol, 0.0, sl, tp, "beast"); */
103
+ }
104
+
105
+ void OnDeinit(const int reason) {}
106
+ ```
107
+
108
+ ### Ters yön: komut dosyası oku
109
+
110
+ ```mql5
111
+ bool ReadCmd(string &out)
112
+ {
113
+ if(!FileIsExist("beast_cmd.json")) return false;
114
+ int h = FileOpen("beast_cmd.json", FILE_READ | FILE_TXT | FILE_ANSI);
115
+ if(h == INVALID_HANDLE) return false;
116
+ out = FileReadString(h);
117
+ FileClose(h);
118
+ return true;
119
+ }
120
+ ```
121
+
122
+ ## 6) KURALLAR
123
+
124
+ - SL'siz işlem/EA yazma; martingale/kademeli lot artışı YASAK.
125
+ - Sembol adını `mt5_market` ile doğrula — broker'da neyse o (örn "GOLD", "XAUUSD" değil).
126
+ - `TimeCurrent()` broker sunucu saatidir; raporda saat dilimini belirt.
127
+ - Ağ/DLL kullanacaksan kullanıcıdan onay iste (`#import` varsayılan kapalıdır).
128
+ - Şifre/API anahtarını koda, loga, rapora YAZMA.
129
+ - Derlenmemiş/çalıştırılmamış kodu "bitti" diye raporlama; kullanıcıya çalıştırma adımını açıkça söyle.
@@ -0,0 +1,59 @@
1
+ ---
2
+ name: price-action
3
+ description: Fiyat yapısı / price action analiz rehberi — market structure (HH/LL, BOS, CHoCH), destek-direnç bölgeleri, likidite süpürme, çoklu zaman dilimi teyidi, giriş/SL/TP yerleşimi. Teknik analiz ajanı veya trader bir sembolde yön/giriş kararı verirken ÖNCE bu skill'i okur.
4
+ version: 1.0.0
5
+ ---
6
+
7
+ # Price Action / Fiyat Yapısı
8
+
9
+ ## TEMEL İLKE
10
+
11
+ Yön kararı YAPIDAN gelir, göstergeden değil. MA kesişimi tek başına gürültüdür; teyit yoksa işlem yok.
12
+
13
+ ## 1) MARKET STRUCTURE (önce bu)
14
+
15
+ - Swing high / swing low'ları işaretle (lookback: son 50-100 mum yeterli).
16
+ - Yükseliş yapısı: **HH + HL** (higher high, higher low). Düşüş: **LH + LL**.
17
+ - **BOS (Break of Structure)**: trend yönündeki son swing seviyesinin kapanışla kırılması = trend devam teyidi.
18
+ - **CHoCH (Change of Character)**: karşı yöndeki ilk yapı kırılması = olası dönüş sinyali; BOS ile karıştırma.
19
+ - Yapı belirsizse (range) → BEKLE; range'de sadece sınırlardan işlem düşünülür.
20
+
21
+ ## 2) DESTEK / DİRENÇ + LİKİDİTE
22
+
23
+ - Bölgeyi çizgi değil **alan** olarak al (mum gövdeleri + fitiller).
24
+ - Önem sırası: HTF (H4/D1) > LTF (M15/M5). HTF seviyesi LTF'de daha güçlüdür.
25
+ - Eşit tepeler/dipler likidite havuzudur; fitil ile "süpürülme" (stop hunt) sık olur — kırılımda **kapanış teyidi** ara.
26
+ - Yuvarlak rakamlar (2400, 1.1000) ve önceki günün high/low'u doğal seviyedir.
27
+
28
+ ## 3) ÇOKLU ZAMAN DİLİMİ (MTF)
29
+
30
+ 1. HTF (H4/D1): yön ve ana bölge.
31
+ 2. MTF (H1/M15): yapı + BOS/CHoCH.
32
+ 3. LTF (M5/M1): giriş tetiği (retest, engulfing, iğne).
33
+ Kural: LTF sinyali HTF yönüne tersse işlem açma.
34
+
35
+ ## 4) MOMENTUM / VOLATİLİTE
36
+
37
+ - ATR: SL mesafesi ve pozisyon boyutu için (sabit pip değil, ATR bazlı).
38
+ - RSI divergence sadece **teyit** olarak kullanılır; tek başına giriş sebebi değildir.
39
+ - Hacim/range daralması sıkışma (squeeze) → kırılım yaklaşıyor; yön teyidi bekle.
40
+
41
+ ## 5) GİRİŞ / SL / TP
42
+
43
+ - Giriş: BOS sonrası geri çekilme (pullback) + retest teyidi; kovalama yok.
44
+ - SL: yapının arkasına (son swing low/high'ın ötesi) + spread/ATR payı. Yapının İÇİNE SL koyma.
45
+ - Geniş SL tercih ediliyorsa: ~4×ATR SL, ~2×ATR'de BE (break-even) taşıma.
46
+ - TP: bir sonraki HTF bölgesi; R:R en az 1.5–2. Kısmi kâr alımı serbest.
47
+ - BE'e çekmeden SL'siz/işlemsiz kalma; her pozisyonun SL'si olsun.
48
+
49
+ ## 6) YASAKLAR
50
+
51
+ - Teyitsiz (BOS/CHoCH olmadan) giriş.
52
+ - Zarara ekleme (averaging down) ve martingale.
53
+ - Haber anında spread genişken piyasa emri (bkz. haber-duygu skill'i).
54
+ - Yapıya ters, sırf "ucuz/pahalı" diye işlem.
55
+
56
+ ## 7) RAPOR FORMATI
57
+
58
+ Tek satır: `SEMBOL | yön | giriş | SL | TP | yapı gerekçesi (BOS/CHoCH/bölge) | R:R`
59
+ Belirsizse net yaz: `BEKLE: <sebep>`.
@@ -0,0 +1,50 @@
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
+
34
+ ## 4) KAYIP LİMİTLERİ
35
+
36
+ - Günlük kayıp limiti belirle (ör. hesabın %2–3'ü). Limit dolduysa **o gün yeni işlem yok**; raporla.
37
+ - Üst üste 2-3 kayıptan sonra lotu artırma (revenge trade YASAK); aksine küçült veya dur.
38
+ - Drawdown artıyorsa tur sıklığını/agresifliği azalt, sadece A+ setuplara gir.
39
+
40
+ ## 5) YASAKLAR
41
+
42
+ - Martingale / kademeli lot artışı.
43
+ - SL taşımayı kaybı büyütecek yönde yapmak (SL genişletme).
44
+ - Marjı zorlayan "son işlem" kumarı.
45
+ - Aynı anda korelasyonlu 3+ pozisyonla tek yön yığmak.
46
+
47
+ ## 6) RAPOR FORMATI
48
+
49
+ `Risk: toplam açık R%X | marj kullanımı %Y | en riskli pozisyon: ... | öneri: SL/BE/küçült/kapat`
50
+ Sınır aşımı varsa öncelikli ve net yaz.
@@ -0,0 +1,77 @@
1
+ ---
2
+ name: tool-yazma
3
+ description: Kişisel TOOL yazma/düzenleme rehberi — %APPDATA%\beast\tools\<ad>\ altına tool.json + run.js yazılacak veya mevcut bir tool editlenecekse ÖNCE bu skill'i oku. Tool'un sözleşmesi: stdin JSON argüman → stdout JSON sonuç; ajan tool__<ad> olarak çağırır (Beast Finance dahil tüm oturumlarda çalışır).
4
+ version: 1.0.0
5
+ ---
6
+
7
+ # Kişisel TOOL Yazma
8
+
9
+ ## TOOL NEDİR / NE ZAMAN YAZILIR
10
+
11
+ Kişisel tool = modelin alet çantasına GİREN gerçek bir araçtır: %APPDATA%\beast\tools\<slug>\ klasöründe **tool.json** (tanım) + **run.js** (kod) bulunur. Tüm oturumlarda — Beast Finance chat/trader/işçiler dahil — `tool__<slug>` adıyla çağrılır.
12
+
13
+ Yaz ZAMAN: mevcut araçlar işi görmüyorsa (örn. broker sembol adlandırması mt5_trade'i düşürüyorsa), özel bir API'ye bağlanman, tekrarlı bir hesap/işlem rutini gerekiyorsa. Basit işler için YAZMA — önce yerleşik araçları (mt5_*, web_search, python_run, run_command) dene.
14
+
15
+ ## SÖZLEŞME (birebir uygula)
16
+
17
+ - **stdin**: JSON argümanlar (tek satırda, güvenli parse)
18
+ - **stdout**: SADECE JSON sonuç — son satır JSON'a çevrilmeye çalışılır; günlük/metin yazarsan JSON bozulur, `console.error` kullan
19
+ - **çalışma klasörü**: tool'un kendi klasörü (yanına dosya yazabilirsin)
20
+ - **zaman aşımı**: 90 sn — uzun işleri kendin parçalama, `run_background`'a devret
21
+ - **sonuç biçimi**: `{ "ok": true, ... }` ya da `{ "ok": false, "error": "sebep" }` — ok alanı ZORUNLU
22
+
23
+ ## YENİ TOOL OLUŞTURMA (2 dosya, write_file ile)
24
+
25
+ `%APPDATA%\beast\tools\<slug>\tool.json`:
26
+ ```json
27
+ {
28
+ "name": "gold_emir",
29
+ "description": "GOLD için özel emir açar — side (buy/sell), lot, sl, tp alır; sonucu ticket ile döndürür.",
30
+ "parameters": {
31
+ "type": "object",
32
+ "properties": {
33
+ "side": { "type": "string", "description": "buy | sell" },
34
+ "lot": { "type": "number", "description": "0.01-1.0" },
35
+ "sl": { "type": "number" },
36
+ "tp": { "type": "number" }
37
+ },
38
+ "required": ["side", "lot"]
39
+ },
40
+ "updatedAt": "2026-09-09T00:00:00.000Z"
41
+ }
42
+ ```
43
+
44
+ `%APPDATA%\beast\tools\<slug>\run.js`:
45
+ ```javascript
46
+ 'use strict';
47
+ // stdin: JSON args · stdout: JSON sonuç (SADECE JSON yaz!)
48
+ const fs = require('fs');
49
+ let args = {};
50
+ try { args = JSON.parse(fs.readFileSync(0, 'utf8') || '{}'); } catch {}
51
+ (function main() {
52
+ const { side, lot, sl, tp } = args;
53
+ if (!side || !lot) {
54
+ console.log(JSON.stringify({ ok: false, error: 'side ve lot zorunlu' }));
55
+ return;
56
+ }
57
+ // --- kendi işin burada: HTTP çağrısı, MT5 köprüsü, dosya, hesap... ---
58
+ // Örn: https modülüyle özel endpoint'e istek at, sonucu ok alanıyla sar.
59
+ console.log(JSON.stringify({ ok: true, side, lot, sl: sl || 0, tp: tp || 0, ticket: 0 }));
60
+ })();
61
+ ```
62
+
63
+ Slug kuralları: a-z, 0-9, alt çizgi, tire — 2-24 karakter (örn: gold_emir, haber_ozet). Hazır taslak: %APPDATA%\beast\tools\ornek_echo klasörünü referans al; yeni tool'u o biçimle yaz.
64
+
65
+ ## DÜZENLEME / DOĞRULAMA
66
+
67
+ 1. Mevcut toolu değiştirme: `edit_file` ile tool.json / run.js düzenle — ASLA tüm klasörü silip baştan yazma.
68
+ 2. Kayıttan sonra tool ANINDA aktifleşir (yeniden başlatma gerekmez) — bir sonraki turda `tool__<slug>` çağrılabilir.
69
+ 3. Doğrula: `run_command` ile `echo "{\"mesaj\":\"test\"}" | node "%APPDATA%\beast\tools\<slug>\run.js"` — çıktı JSON olmalı ve `ok` alanı içermeli.
70
+ 4. Hata çıktısı `ok:false + error` olsun — model hatayı okuyup düzeltir; çıplak stack yasak.
71
+
72
+ ## GÜVENLİK + STİL
73
+
74
+ - Şifre/API anahtarını ASLA stdout'a, log'a, skill'e yazma.
75
+ - Ağ çağrılarında timeout kullan (`https` modülü + `req.setTimeout` veya fetch); sonsuz bekleyen script yazma.
76
+ - Tek sorumluluk: bir tool = bir iş. Çok işli dev tool yazma — parçala.
77
+ - Kullanıcıya tool'u nasıl yöneteceğini söyle: sol panelde TOOLLAR kutusunda test/düzenle/sil + 📂 klasör.
package/src/main.js CHANGED
@@ -8329,6 +8329,12 @@ function finCfg() {
8329
8329
  f.analysisAuto = true;
8330
8330
  if (!Number.isFinite(Number(f.analysisCount))) f.analysisCount = 2;
8331
8331
  f.analysisCount = Math.max(0, Math.min(FIN_ROLES_AUTO.length, Math.round(Number(f.analysisCount) || 0)));
8332
+ /* ROL → SKILL eşleştirmesi: rol başına en fazla 8 skill adı */
8333
+ if (!f.roleSkills || typeof f.roleSkills !== 'object') f.roleSkills = {};
8334
+ for (const d of FIN_ROLES) {
8335
+ const cur = Array.isArray(f.roleSkills[d.id]) ? f.roleSkills[d.id] : ROLE_SKILL_DEFAULTS[d.id] || [];
8336
+ f.roleSkills[d.id] = cur.map((s) => String(s || '').trim()).filter(Boolean).slice(0, 8);
8337
+ }
8332
8338
  if (!Number(f.intervalSec)) f.intervalSec = 120;
8333
8339
  if (!Number(f.maxLot)) f.maxLot = 0.1;
8334
8340
  if (f.maxPositions == null) f.maxPositions = 3;
@@ -8345,6 +8351,14 @@ const FIN_ROLES = [
8345
8351
  { id: 'macro', label: 'Haber / Makro', desc: 'haber akışı + ekonomik takvim, DXY/emtia bağıntıları, yön eğilimi' },
8346
8352
  ];
8347
8353
  const FIN_ROLES_AUTO = ['technic', 'risk', 'macro'];
8354
+ /* ROL → SKILL varsayılanları: her rolün tur başında okuması gereken skill'ler.
8355
+ TRADE AJANI kartındaki ⚙ modalından değiştirilebilir; liste kurulu skill
8356
+ kataloğundan beslenir, yeni skill eklenince modalda otomatik görünür. */
8357
+ const ROLE_SKILL_DEFAULTS = {
8358
+ technic: ['price-action'],
8359
+ risk: ['risk-yonetimi'],
8360
+ macro: ['haber-duygu'],
8361
+ };
8348
8362
  function finRolesValid(list) {
8349
8363
  return (Array.isArray(list) ? list : [])
8350
8364
  .map((r) => String(r || '').trim())
@@ -8567,6 +8581,8 @@ function finApplyTraderFields(s, symbolsOverride, role) {
8567
8581
  s.financeSymbols = Array.isArray(symbolsOverride) && symbolsOverride.length ? symbolsOverride : f.symbols;
8568
8582
  s.financeStrategy = String(f.strategy || '');
8569
8583
  s.financeLimits = { maxLot: f.maxLot, maxPositions: f.maxPositions };
8584
+ /* rolün okuması gereken skill'ler (modal eşleştirmesi) — promptta role eklenir */
8585
+ s.financeRoleSkills = (f.roleSkills && f.roleSkills[r]) || [];
8570
8586
  engine.cache.set(String(s.id), s);
8571
8587
  }
8572
8588
 
@@ -8609,6 +8625,9 @@ function finAgentStop(sid, reason) {
8609
8625
  engine._bgEmit();
8610
8626
  }
8611
8627
  } catch {}
8628
+ /* AJAN DM: duran ajanın birebir sohbetleri kapanır; grupta KOŞAN üye
8629
+ kalmadıysa ekip sohbeti de GEÇMİŞE düşer (aktif listede kalmaz) */
8630
+ try { if (engine && engine._agentDmClose) engine._agentDmClose(sid); } catch {}
8612
8631
  finPush('trader', { state: 'idle', rounds: financeState.traderRounds });
8613
8632
  return true;
8614
8633
  }
@@ -8856,8 +8875,24 @@ ipcMain.handle('finance:settings', async (_e, patch) => {
8856
8875
  }
8857
8876
  f.symbolHistory = hist.slice(-40);
8858
8877
  f.symbols = next;
8878
+ /* KOŞAN ajanlar DURDURULMADAN yeni listeyi alır: ana trader + analiz ekibi
8879
+ sonraki turda güncel sembollere odaklanır (sembol işçileri kendi
8880
+ sembolünde kalır — onlar tek sembole özeldir). */
8881
+ for (const [, a] of financeState.agents) {
8882
+ if (a && (a.main || a.role)) a.symbols = next.slice(0, 20);
8883
+ }
8859
8884
  }
8860
8885
  if (p.intervalSec !== undefined) f.intervalSec = Math.max(30, Math.min(3600, Math.round(Number(p.intervalSec) || 120)));
8886
+ /* TUR ARALIĞI CANLI: bekleyen zamanlayıcılar yeni aralıkla yeniden kurulur —
8887
+ koşan tur bitince zaten finFlushOnDone yeni aralığı okur. */
8888
+ if (p.intervalSec !== undefined && financeState.agents) {
8889
+ const iv = Math.max(30, Math.round(Number(f.intervalSec) || 120)) * 1000;
8890
+ for (const [sid, a] of financeState.agents) {
8891
+ if (!a || !engine || engine.isBusy(sid)) continue;
8892
+ clearTimeout(a.timer);
8893
+ a.timer = setTimeout(() => { try { finAgentRound(String(sid)); } catch {} }, iv);
8894
+ }
8895
+ }
8861
8896
  if (p.maxLot !== undefined) f.maxLot = Math.max(0.01, Math.min(100, Number(p.maxLot) || 0.1));
8862
8897
  if (p.maxPositions !== undefined) f.maxPositions = Math.max(1, Math.min(20, Math.round(Number(p.maxPositions) || 3)));
8863
8898
  /* allowTrading artık AYARLANMAZ — daima true (finCfg zorlar) */
@@ -8865,6 +8900,14 @@ ipcMain.handle('finance:settings', async (_e, patch) => {
8865
8900
  if (p.analysisTeam !== undefined) f.analysisTeam = finRolesValid(p.analysisTeam);
8866
8901
  if (p.analysisAuto !== undefined) f.analysisAuto = !!p.analysisAuto;
8867
8902
  if (p.analysisCount !== undefined) f.analysisCount = Math.max(0, Math.min(FIN_ROLES_AUTO.length, Math.round(Number(p.analysisCount) || 0)));
8903
+ /* ROL → SKILL eşleştirmesi güncellemesi (modal) */
8904
+ if (p.roleSkills !== undefined && p.roleSkills && typeof p.roleSkills === 'object') {
8905
+ for (const d of FIN_ROLES) {
8906
+ if (p.roleSkills[d.id] === undefined) continue;
8907
+ f.roleSkills[d.id] = (Array.isArray(p.roleSkills[d.id]) ? p.roleSkills[d.id] : [])
8908
+ .map((s) => String(s || '').trim()).filter(Boolean).slice(0, 8);
8909
+ }
8910
+ }
8868
8911
  if (p.pythonPath !== undefined) f.pythonPath = String(p.pythonPath || '').trim();
8869
8912
  if (p.terminalPath !== undefined) f.terminalPath = String(p.terminalPath || '').trim();
8870
8913
  if (p.traderSel !== undefined) {
@@ -162,12 +162,12 @@
162
162
  </div>
163
163
  </div>
164
164
  <div class="fin-card fin-card-trader">
165
- <div class="fin-card-title">TRADE AJANI <span id="finTraderDot" class="fin-dot off" title="Trader durumu"></span></div>
165
+ <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="finSkillsBtn" title="Rol → skill eşleştirmesi — hangi rol hangi skill'i okur">&#9881;</button></div>
166
166
  <div class="fin-field">
167
167
  <span>Model</span>
168
168
  <select id="finTraderModel" title="Trader ajanının modeli — farklı API/model seçilebilir"></select>
169
169
  </div>
170
- <div class="fin-grid2">
170
+ <div class="fin-grid2" title="Değişiklik anında kaydedilir — ajanı DURDURMADAN sonraki tura uygulanır">
171
171
  <div class="fin-field">
172
172
  <span>Tur (sn)</span>
173
173
  <input id="finInterval" type="number" min="30" max="3600" step="10" />
@@ -648,6 +648,19 @@
648
648
  </div>
649
649
  </div>
650
650
 
651
+ <div id="finSkillsOverlay" class="mini-overlay" hidden>
652
+ <div class="mini-dialog fin-skills-dialog">
653
+ <div class="mini-head">
654
+ <span class="mini-title">ROL → SKILL EŞLEŞTİRME</span>
655
+ <button class="mini-close" id="finSkillsClose" title="Kapat">&#x00D7;</button>
656
+ </div>
657
+ <div class="mini-body">
658
+ <div id="finSkillsList" class="mini-list"></div>
659
+ <div class="fin-sym-hint">Her rolün okuması gereken skill'leri seç — liste kurulu katalogdan gelir; yeni skill eklersen burada otomatik görünür.</div>
660
+ </div>
661
+ </div>
662
+ </div>
663
+
651
664
  <div id="cronOverlay" class="mini-overlay" hidden>
652
665
  <div class="mini-dialog">
653
666
  <div class="mini-head">
@@ -187,6 +187,10 @@ const els = {
187
187
  finSymAdd: $('#finSymAdd'),
188
188
  finSymOverlay: $('#finSymOverlay'),
189
189
  finSymClose: $('#finSymClose'),
190
+ finSkillsBtn: $('#finSkillsBtn'),
191
+ finSkillsOverlay: $('#finSkillsOverlay'),
192
+ finSkillsClose: $('#finSkillsClose'),
193
+ finSkillsList: $('#finSkillsList'),
190
194
  finSymSearch: $('#finSymSearch'),
191
195
  finSymPick: $('#finSymPick'),
192
196
  finSymCount: $('#finSymCount'),
@@ -8792,6 +8796,7 @@ function financeModeOn() {
8792
8796
  let finPollTimer = null;
8793
8797
  let finModelsFilled = false;
8794
8798
  let finLastPrices = new Map(); /* sembol → son bid (renk için) */
8799
+ let finCfgCache = null; /* son snapshot cfg — rol→skill modalı bundan okur */
8795
8800
  const FIN_COLOR_UP = 'fs-up';
8796
8801
  const FIN_COLOR_DOWN = 'fs-down';
8797
8802
 
@@ -8949,17 +8954,7 @@ function finRenderSymbols(list) {
8949
8954
  row.innerHTML =
8950
8955
  '<span class="fs-name">' + (s.symbol || '?') + '</span>' +
8951
8956
  '<span class="fs-price ' + cls + '">' + bid.toFixed(digits) + '</span>' +
8952
- '<span class="fs-spread">sp ' + (s.spread != null ? s.spread : '—') + '</span>' +
8953
- '<button class="fs-agent" title="' + escapeHtml(s.symbol || '') + ' için AYRI finance ajanı başlat (paralel koşar)">&#9654;&#xFE0E;</button>';
8954
- const spawnBtn = row.querySelector('.fs-agent');
8955
- if (spawnBtn) {
8956
- spawnBtn.addEventListener('click', async (e) => {
8957
- e.stopPropagation();
8958
- const r = await beast.financeAgentSpawn(s.symbol).catch((err) => ({ ok: false, error: String((err && err.message) || err) }));
8959
- if (r && r.ok) toast(s.symbol + ' için ajan başladı — Paralel Ajanlar panelinde izle');
8960
- else toast((r && r.error) || 'Ajan başlatılamadı');
8961
- });
8962
- }
8957
+ '<span class="fs-spread">sp ' + (s.spread != null ? s.spread : '—') + '</span>';
8963
8958
  els.finSymList.appendChild(row);
8964
8959
  }
8965
8960
  }
@@ -9109,6 +9104,7 @@ async function finSnapshot() {
9109
9104
  return;
9110
9105
  }
9111
9106
  const b = r.bridge || {};
9107
+ finCfgCache = r.cfg || null;
9112
9108
  finSetDot(b.connected ? true : b.running ? 'busy' : false, b);
9113
9109
  finRenderAccount(r.account);
9114
9110
  finRenderPositions(r.positions || []);
@@ -9210,8 +9206,18 @@ function finSaveCfg(patch) {
9210
9206
  beast.financeSettings(patch).then(() => { finWatchDirty = false; }).catch(() => { finWatchDirty = false; });
9211
9207
  }, 400);
9212
9208
  }
9213
- if (els.finInterval) els.finInterval.addEventListener('change', () => finSaveCfg({ intervalSec: Number(els.finInterval.value) || 120 }));
9214
- if (els.finMaxLot) els.finMaxLot.addEventListener('change', () => finSaveCfg({ maxLot: Number(els.finMaxLot.value) || 0.1 }));
9209
+ if (els.finInterval) els.finInterval.addEventListener('change', () => {
9210
+ const v = Math.max(30, Math.min(3600, Math.round(Number(els.finInterval.value) || 120)));
9211
+ els.finInterval.value = v;
9212
+ finSaveCfg({ intervalSec: v });
9213
+ toast('Tur aralığı: ' + v + ' sn — durdurmadan sonraki tura uygulanır');
9214
+ });
9215
+ if (els.finMaxLot) els.finMaxLot.addEventListener('change', () => {
9216
+ const v = Math.max(0.01, Math.min(100, Number(els.finMaxLot.value) || 0.1));
9217
+ els.finMaxLot.value = v;
9218
+ finSaveCfg({ maxLot: v });
9219
+ toast('Max lot: ' + v + ' — sonraki turdan itibaren geçerli');
9220
+ });
9215
9221
  if (els.finSymBtn) els.finSymBtn.addEventListener('click', finSymPickerOpen);
9216
9222
  /* OTOMATİK İŞLEM onay kutusu KALDIRILDI — trade ajanı daima işlem açabilir */
9217
9223
  if (els.finTraderModel) {
@@ -9256,11 +9262,18 @@ function finToggleWatch(sym) {
9256
9262
  const i = finWatch.indexOf(s);
9257
9263
  if (i >= 0) finWatch.splice(i, 1);
9258
9264
  else finWatch.push(s);
9265
+ const added = i < 0; /* true = eklendi */
9259
9266
  finSaveCfg({ symbols: [...finWatch] });
9260
9267
  finSymBtnUpdate(); /* TRADE AJANI düğmesi anında güncellensin */
9261
9268
  clearTimeout(finSymRefreshTimer);
9262
9269
  finSymRefreshTimer = setTimeout(() => finSnapshot(), 700); /* PİYASA kartı tazelensin */
9263
- return i < 0; /* true = eklendi */
9270
+ /* canlı geri bildirim: değişiklik koşan ajanı DURDURMADAN sonraki tura girer */
9271
+ toast(
9272
+ added
9273
+ ? s + ' izleme listesine eklendi — koşan ajan sonraki turda kullanır'
9274
+ : s + ' izleme listesinden çıkarıldı — koşan ajan sonraki turda görmez'
9275
+ );
9276
+ return added;
9264
9277
  }
9265
9278
 
9266
9279
  function finRenderPickRows(rows, q) {
@@ -9365,6 +9378,97 @@ function finSymPickerClose() {
9365
9378
  if (els.finSymOverlay) els.finSymOverlay.hidden = true;
9366
9379
  }
9367
9380
 
9381
+ /* ---------- ROL → SKILL eşleştirme modalı ----------
9382
+ Roller sunucudan (snapshot.roles), skill listesi KURULU katalogdan gelir —
9383
+ yeni skill eklendiğinde modalda otomatik görünür. Seçim finance ayarına
9384
+ (roleSkills) yazılır; rol ajanı her turda o skill'leri okumakla yükümlüdür. */
9385
+ let finSkillNames = [];
9386
+
9387
+ async function finSkillsOpen() {
9388
+ if (!els.finSkillsOverlay) return;
9389
+ els.finSkillsOverlay.hidden = false;
9390
+ if (els.finSkillsList) els.finSkillsList.innerHTML = '<div class="fin-empty">Skill kataloğu yükleniyor…</div>';
9391
+ let list = [];
9392
+ try { list = (await beast.listSkills()) || []; } catch {}
9393
+ finSkillNames = (Array.isArray(list) ? list : [])
9394
+ .map((s) => ({ name: String((s && s.name) || ''), description: String((s && s.description) || '') }))
9395
+ .filter((s) => s.name);
9396
+ try { await finSnapshot(); } catch {}
9397
+ finRenderSkills();
9398
+ }
9399
+
9400
+ function finRenderSkills() {
9401
+ const box = els.finSkillsList;
9402
+ if (!box) return;
9403
+ const cfg = finCfgCache || {};
9404
+ const map = cfg.roleSkills && typeof cfg.roleSkills === 'object' ? cfg.roleSkills : {};
9405
+ const roles = Array.isArray(finRolesCatalog) ? finRolesCatalog : [];
9406
+ box.innerHTML = '';
9407
+ if (!roles.length) {
9408
+ box.innerHTML = '<div class="fin-empty">Rol kataloğu yok</div>';
9409
+ return;
9410
+ }
9411
+ if (!finSkillNames.length) {
9412
+ box.innerHTML = '<div class="fin-empty">Kurulu skill bulunamadı — %APPDATA%\\beast\\skills klasörüne SKILL.md ekle</div>';
9413
+ return;
9414
+ }
9415
+ for (const r of roles) {
9416
+ const row = document.createElement('div');
9417
+ row.className = 'fin-skill-role';
9418
+ const head = document.createElement('div');
9419
+ head.className = 'fin-skill-role-head';
9420
+ head.innerHTML =
9421
+ '<b>' + escapeHtml(String(r.label || r.id)) + '</b>' +
9422
+ '<span>' + escapeHtml(String(r.desc || '').slice(0, 110)) + '</span>';
9423
+ row.appendChild(head);
9424
+ const chips = document.createElement('div');
9425
+ chips.className = 'fin-skill-chips';
9426
+ for (const s of finSkillNames) {
9427
+ const cur = Array.isArray(map[r.id]) ? map[r.id] : [];
9428
+ const chip = document.createElement('label');
9429
+ chip.className = 'fin-skill-chip' + (cur.includes(s.name) ? ' on' : '');
9430
+ chip.title = s.description || s.name;
9431
+ const cb = document.createElement('input');
9432
+ cb.type = 'checkbox';
9433
+ cb.checked = cur.includes(s.name);
9434
+ cb.addEventListener('change', () => {
9435
+ const liveBase = finCfgCache && finCfgCache.roleSkills && Array.isArray(finCfgCache.roleSkills[r.id])
9436
+ ? finCfgCache.roleSkills[r.id]
9437
+ : [];
9438
+ const set = new Set(liveBase);
9439
+ if (cb.checked) set.add(s.name); else set.delete(s.name);
9440
+ const next = [...set];
9441
+ /* yerel önbelleğe anında yaz — 3 sn'lik snapshot eski değeri geri getirmesin */
9442
+ finCfgCache = finCfgCache || {};
9443
+ finCfgCache.roleSkills = finCfgCache.roleSkills || {};
9444
+ finCfgCache.roleSkills[r.id] = next;
9445
+ chip.classList.toggle('on', cb.checked);
9446
+ finSaveCfg({ roleSkills: { [r.id]: next } });
9447
+ toast((r.label || r.id) + ' → ' + (next.length ? next.join(', ') : 'skill kapalı'));
9448
+ });
9449
+ chip.appendChild(cb);
9450
+ chip.appendChild(document.createTextNode(s.name));
9451
+ chips.appendChild(chip);
9452
+ }
9453
+ row.appendChild(chips);
9454
+ box.appendChild(row);
9455
+ }
9456
+ }
9457
+
9458
+ function finSkillsCloseModal() {
9459
+ if (els.finSkillsOverlay) els.finSkillsOverlay.hidden = true;
9460
+ }
9461
+ if (els.finSkillsBtn) els.finSkillsBtn.addEventListener('click', () => { finSkillsOpen(); });
9462
+ if (els.finSkillsClose) els.finSkillsClose.addEventListener('click', finSkillsCloseModal);
9463
+ if (els.finSkillsOverlay) {
9464
+ els.finSkillsOverlay.addEventListener('click', (e) => {
9465
+ if (e.target === els.finSkillsOverlay) finSkillsCloseModal();
9466
+ });
9467
+ els.finSkillsOverlay.addEventListener('keydown', (e) => {
9468
+ if (e.key === 'Escape') { e.stopPropagation(); finSkillsCloseModal(); }
9469
+ });
9470
+ }
9471
+
9368
9472
  if (els.finSymAdd) els.finSymAdd.addEventListener('click', finSymPickerOpen);
9369
9473
  if (els.finWatchClear) {
9370
9474
  els.finWatchClear.addEventListener('click', async () => {
@@ -2290,25 +2290,6 @@ body.browser-open #settingsDialog { width: min(70vw, calc(100vw - var(--bw, 480p
2290
2290
  letter-spacing: 0.4px;
2291
2291
  }
2292
2292
 
2293
- /* PİYASA satırındaki ▶ ajan butonu */
2294
- .fin-sym { position: relative; }
2295
- .fin-sym .fs-agent {
2296
- position: absolute;
2297
- right: 4px;
2298
- top: 50%;
2299
- transform: translateY(-50%);
2300
- border: none;
2301
- background: none;
2302
- color: var(--muted);
2303
- cursor: pointer;
2304
- font-size: 11px;
2305
- padding: 2px 4px;
2306
- border-radius: 4px;
2307
- visibility: hidden;
2308
- }
2309
- .fin-sym:hover .fs-agent { visibility: visible; color: var(--accent); }
2310
- .fin-sym .fs-agent:hover { background: var(--accent-dim); }
2311
-
2312
2293
  /* sembol seçicide bölüm başlıkları (geçmiş / tüm semboller) */
2313
2294
  .fin-sym-sec {
2314
2295
  font-size: 10px;
@@ -5141,3 +5122,47 @@ body.finance-mode #composerWrap { margin-right: var(--finW, 400px); }
5141
5122
  color: var(--muted);
5142
5123
  text-align: center;
5143
5124
  }
5125
+
5126
+ /* ROL → SKILL eşleştirme modalı (TRADE AJANI ⚙) */
5127
+ .fin-skills-dialog { width: 540px; max-width: calc(100vw - 40px); }
5128
+ .fin-skills-dialog .mini-body {
5129
+ flex: 1;
5130
+ min-height: 0;
5131
+ display: flex;
5132
+ flex-direction: column;
5133
+ overflow: hidden;
5134
+ }
5135
+ #finSkillsList {
5136
+ flex: 1;
5137
+ min-height: 0;
5138
+ overflow-y: auto;
5139
+ display: flex;
5140
+ flex-direction: column;
5141
+ gap: 10px;
5142
+ }
5143
+ .fin-skill-role {
5144
+ border: 1px solid var(--border);
5145
+ border-radius: 8px;
5146
+ padding: 8px 9px;
5147
+ background: var(--panel2);
5148
+ }
5149
+ .fin-skill-role-head { display: flex; flex-direction: column; gap: 1px; margin-bottom: 7px; }
5150
+ .fin-skill-role-head b { font-size: 11.5px; color: var(--text); }
5151
+ .fin-skill-role-head span { font-size: 10px; color: var(--muted); }
5152
+ .fin-skill-chips { display: flex; flex-wrap: wrap; gap: 4px; }
5153
+ .fin-skill-chip {
5154
+ display: inline-flex;
5155
+ align-items: center;
5156
+ gap: 4px;
5157
+ font-size: 10.5px;
5158
+ color: var(--text);
5159
+ background: var(--panel);
5160
+ border: 1px solid var(--border);
5161
+ border-radius: 8px;
5162
+ padding: 2px 8px 2px 5px;
5163
+ cursor: pointer;
5164
+ user-select: none;
5165
+ }
5166
+ .fin-skill-chip:hover { border-color: var(--accent); }
5167
+ .fin-skill-chip.on { border-color: var(--accent); color: var(--accent); background: var(--accent-dim); }
5168
+ .fin-skill-chip input { flex: none; width: auto; margin: 0; }