beast-agent 2.76.1 → 2.76.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "beast-agent",
3
3
  "productName": "Beast Agent",
4
- "version": "2.76.1",
4
+ "version": "2.76.3",
5
5
  "description": "Ultra-fast local agent shell for Windows.",
6
6
  "author": "algokodcom (AlgoKod)",
7
7
  "license": "MIT",
@@ -131,7 +131,16 @@ function lotRange(cfg, symbol) {
131
131
  async function preTradeCheck(cfg, side, symbol, info, price, volume, sl, tp, positions) {
132
132
  const closeErr = finrisk.stopsTooClose(info, price, sl, tp);
133
133
  if (closeErr) return closeErr;
134
- const expErr = finrisk.exposureCheck(positions || [], side, symbol, cfg.maxPerSymbol, cfg.maxSameSide);
134
+ /* SEMBOL/YÖN TAVANI: main'in efektif değeri (talimat "sembol başına N" ya da
135
+ "aynı anda en fazla N işlem" notu) ayarı ve toplam tavanı KELEPÇELER */
136
+ let maxSym = Number(cfg.maxPerSymbol) || 0;
137
+ let maxSide = Number(cfg.maxSameSide) || 0;
138
+ try {
139
+ const lim = limitsApi.get();
140
+ if (Number(lim && lim.maxPerSymbol) > 0) maxSym = Number(lim.maxPerSymbol);
141
+ if (Number(lim && lim.maxSameSide) > 0) maxSide = Number(lim.maxSameSide);
142
+ } catch {}
143
+ const expErr = finrisk.exposureCheck(positions || [], side, symbol, maxSym, maxSide);
135
144
  if (expErr) return expErr;
136
145
  /* KODLA DİSİPLİN: günlük limit / kayıp serisi molası / re-entry / kur maruziyeti */
137
146
  let discErr = null;
@@ -219,7 +219,22 @@ function disciplineError(entries, now, cfg, side, symbol, positions) {
219
219
  const dayStart = (() => { const d = new Date(t); d.setHours(0, 0, 0, 0); return d.getTime(); })();
220
220
  const maxDay = num(f.maxTradesPerDay, 0);
221
221
  if (maxDay > 0) {
222
- const opens = list.filter((e) => e.kind === 'open' && Number(e.at) >= dayStart).length;
222
+ /* TEK İŞLEM = AÇILIŞ + KAPANIŞ: gün içindeki açılışlar TICKET bazında
223
+ sayılır; aynı pozisyonun kapanış kaydı AYRICA sayılmaz (çift sayım yok,
224
+ watchdog yeniden açılış yazsa bile ticket tekrarı düşülür). Ticket'sız
225
+ eski kayıtlar tek tek sayılır (geriye dönük uyum). */
226
+ const seen = new Set();
227
+ let opens = 0;
228
+ for (const e of list) {
229
+ if (Number(e.at) < dayStart) continue;
230
+ if (e.kind !== 'open') continue;
231
+ const tk = e.ticket != null ? String(e.ticket) : '';
232
+ if (tk && tk !== '0') {
233
+ if (seen.has(tk)) continue;
234
+ seen.add(tk);
235
+ }
236
+ opens += 1;
237
+ }
223
238
  if (opens >= maxDay) {
224
239
  return `günlük işlem limiti dolu (${opens}/${maxDay}) — bugün yeni işlem açma`;
225
240
  }
package/src/main.js CHANGED
@@ -10024,6 +10024,7 @@ function finCfg() {
10024
10024
  ezmez: not yalnız talimat metninde durdukça geçerlidir (0 = not yok). */
10025
10025
  f.maxPositionsNote = 0;
10026
10026
  f.maxTradesPerDayNote = 0;
10027
+ f.maxPerSymbolNote = 0;
10027
10028
  try {
10028
10029
  const txt = (String(f.strategy || '') + '\n' + String(f.posManagerNote || '')).toLowerCase();
10029
10030
  const re = /(en\s*fazla|en\s*[çc]ok|max(?:imum)?|maks(?:imum)?)\s*(\d{1,2})\s*(?:i[şs]lem|islem|trade|emir|pozisyon|poz)/g;
@@ -10039,6 +10040,13 @@ function finCfg() {
10039
10040
  if (daily) f.maxTradesPerDayNote = n;
10040
10041
  else if (!f.maxPositionsNote) f.maxPositionsNote = n; /* eşzamanlı tavan */
10041
10042
  }
10043
+ /* SEMBOL BAŞINA TAVAN: "sembol başına 5 işlem", "aynı sembolde en fazla 3
10044
+ pozisyon" → aynı sembolde çoklu işlem tavanı (toplam tavanı ezmez) */
10045
+ const msym = txt.match(/(?:sembol\s*ba[şs][ıi]na|ayn[ıi]\s*sembolde|her\s*sembolde)[^0-9]{0,16}(\d{1,2})/);
10046
+ if (msym) {
10047
+ const n = Number(msym[1]);
10048
+ if (n >= 1 && n <= 20) f.maxPerSymbolNote = n;
10049
+ }
10042
10050
  } catch {}
10043
10051
  /* SHADOW MOD: emir gönderilmez — kararlar gerekçesiyle günlüğe yazılır */
10044
10052
  if (typeof f.shadowMode !== 'boolean') f.shadowMode = false;
@@ -10429,6 +10437,31 @@ function finPosCap(f) {
10429
10437
  return Math.max(1, Math.min(20, note > 0 ? note : base));
10430
10438
  }
10431
10439
 
10440
+ /* SEMBOL BAŞINA POZİSYON TAVANI (aynı sembolde çoklu işlem):
10441
+ 1) talimatta "sembol başına N" varsa o,
10442
+ 2) talimatta toplam tavan varsa ("aynı anda en fazla N işlem") aynı sembolde
10443
+ de o tavana kadar izin verilir — sahip 10 istiyorsa GOLD'da 10'a kadar,
10444
+ 3) zorunlu giriş modunda toplam tavan,
10445
+ 4) yoksa ayarlardaki maxPerSymbol (varsayılan 2). Toplam tavanı asla aşmaz. */
10446
+ function finPerSymbolCap(f) {
10447
+ const ff = f || {};
10448
+ const cap = finPosCap(ff);
10449
+ const note = Number(ff.maxPerSymbolNote) > 0 ? Number(ff.maxPerSymbolNote) : 0;
10450
+ if (note > 0) return Math.max(1, Math.min(cap, note));
10451
+ if (Number(ff.maxPositionsNote) > 0) return cap;
10452
+ if (finTsMandatoryEntry()) return cap;
10453
+ const base = Number(ff.maxPerSymbol) > 0 ? Number(ff.maxPerSymbol) : 1;
10454
+ return Math.max(1, Math.min(cap, base));
10455
+ }
10456
+
10457
+ /* AYNI YÖN TAVANI: sembol başına tavandan küçük olamaz (tek sembollü stratejide
10458
+ ardışık martingale kademeleri aynı yöndedir); ayar değeri taban kalır. */
10459
+ function finSameSideCap(f) {
10460
+ const ff = f || {};
10461
+ const base = Number(ff.maxSameSide) > 0 ? Number(ff.maxSameSide) : 3;
10462
+ return Math.max(base, finPerSymbolCap(ff));
10463
+ }
10464
+
10432
10465
  /* ---------- MAE/MFE: pozisyonun gördüğü en iyi/en kötü seviye ---------- */
10433
10466
  function finExcLoad() {
10434
10467
  try {
@@ -11330,7 +11363,7 @@ async function finRecordClose(ticket, st) {
11330
11363
  /* TYPESAFE KARAR GÜNLÜĞÜ: kapanış kararla eşleştirilir (kalibrasyon verisi)
11331
11364
  ve TypeSafe'e hata/desen sınıflandırması sorulup otomatik ders yazılır */
11332
11365
  try {
11333
- const dec = finTsDecClose({ symbol, side: (st && st.side) || '', net: rounded, mfe, mae, reason: kind || '' });
11366
+ const dec = finTsDecClose({ symbol, side: (st && st.side) || '', net: rounded, mfe, mae, reason: kind || '', ticket });
11334
11367
  if (dec) finTsAutoLesson(dec).catch(() => {});
11335
11368
  } catch {}
11336
11369
  const pl = rounded == null ? '' : ` · K/Z ${rounded >= 0 ? '+' : ''}${rounded.toFixed(2)}`;
@@ -11954,6 +11987,10 @@ function finLimitsSnapshot() {
11954
11987
  minLot: Number(f.minLot) || 0.01,
11955
11988
  maxLot: Number(f.maxLot) || 0.1,
11956
11989
  maxPositions: Number(f.maxPositions) || 3,
11990
+ /* EFEKTİF SEMBOL/YÖN TAVANI: talimat notu + toplam tavan kelepçesi
11991
+ (aynı sembolde çoklu işlem buradan geçer) */
11992
+ maxPerSymbol: finPerSymbolCap(f),
11993
+ maxSameSide: finSameSideCap(f),
11957
11994
  riskPerTradePct: Number(f.riskPerTradePct) || 0,
11958
11995
  /* SEMBOL BAZLI LOT LİMİTLERİ (trader kararı) — genel aralığı daraltır */
11959
11996
  symbols: { ...(f.symbolLimits && typeof f.symbolLimits === 'object' ? f.symbolLimits : {}) },
@@ -12500,6 +12537,34 @@ function finLearnRecordClose({ symbol, side, net, mfe, mae, reason, timeframe })
12500
12537
  } catch {}
12501
12538
  }
12502
12539
 
12540
+ /* MARTİNGALE KAYIP SERİSİ: sembol + periyot bazında SON KAPANAN işlemlerden
12541
+ ardışık zarar sayısı. Her işlem (açılış+kapanış) öğrenmede TEK kayıttır →
12542
+ aç+kapa ayrı sayılmaz. Zarar → seri +1 (martingale kademesi büyür), kâr/başabaş
12543
+ → seri 0 (martingale kapanır, taban lota dönülür). */
12544
+ function finLossStreak(symbol, tf) {
12545
+ try {
12546
+ const sym = String(symbol || '').trim().toUpperCase();
12547
+ if (!sym) return 0;
12548
+ const e = finLearnLoad().symbols[sym];
12549
+ const trades = Array.isArray(e && e.trades) ? e.trades : [];
12550
+ const want = finLearnNormTf(tf) || '';
12551
+ let n = 0;
12552
+ for (let i = trades.length - 1; i >= 0; i--) {
12553
+ const t = trades[i] || {};
12554
+ const ttf = finLearnNormTf(t.tf) || '';
12555
+ /* başka periyodun işlemleri bu seriye karışmaz (M15 kararı M1 kayıplarını saymaz) */
12556
+ if (want && ttf && ttf !== want) continue;
12557
+ const v = Number(t.net);
12558
+ if (!isFinite(v)) continue;
12559
+ if (v < 0) n += 1;
12560
+ else break;
12561
+ }
12562
+ return n;
12563
+ } catch {
12564
+ return 0;
12565
+ }
12566
+ }
12567
+
12503
12568
  /* Tur girişine gömülen öğrenme özeti: sembol + PERİYOT istatistiği, son
12504
12569
  hatalar ve dersler. Ajanın "her şeye öğrendiğiyle karar vermesi" için
12505
12570
  karar anında önüne konur; en iyi/en kötü periyot ve tekrar eden hata
@@ -12807,6 +12872,8 @@ function finTsDecRecord(rec) {
12807
12872
  sid: String((rec && rec.sid) || ''),
12808
12873
  role: String((rec && rec.role) || ''),
12809
12874
  symbol: String((rec && rec.symbol) || '').toUpperCase(),
12875
+ /* pozisyon ticket'ı (varsa): kapanışta TAM eşleşme için */
12876
+ ticket: Number(rec && rec.ticket) || 0,
12810
12877
  tf: finLearnNormTf(rec && rec.tf),
12811
12878
  action: String((rec && rec.action) || ''),
12812
12879
  p: Number(rec && rec.p) || 0,
@@ -12830,20 +12897,25 @@ function finTsDecRecord(rec) {
12830
12897
  }
12831
12898
 
12832
12899
  /* Kapanışta karar kaydını sonuçla eşleştir (en yeni eşleşmeyen kayıt) */
12833
- function finTsDecClose({ symbol, side, net, mfe, mae, reason }) {
12900
+ function finTsDecClose({ symbol, side, net, mfe, mae, reason, ticket }) {
12834
12901
  try {
12835
12902
  const sym = String(symbol || '').toUpperCase();
12836
12903
  const act = String(side || '').toLowerCase();
12837
12904
  if (!sym || !act || net == null) return null;
12838
12905
  const d = finTsDecLoad();
12839
12906
  const now = Date.now();
12907
+ const fresh = (x) => !x.closedAt && now - Number(x.at) <= 24 * 60 * 60 * 1000;
12840
12908
  let hit = null;
12841
- for (let i = d.decisions.length - 1; i >= 0; i--) {
12842
- const x = d.decisions[i];
12843
- if (x.closedAt || x.symbol !== sym || x.action !== act) continue;
12844
- if (now - Number(x.at) > 24 * 60 * 60 * 1000) continue;
12845
- hit = x;
12846
- break;
12909
+ /* 1) TICKET TAM EŞLEŞMESİ (çoklu pozisyonda kalibrasyon karışmaz) */
12910
+ const tk = Number(ticket) || 0;
12911
+ if (tk > 0) {
12912
+ hit = d.decisions.find((x) => fresh(x) && Number(x.ticket) === tk) || null;
12913
+ }
12914
+ /* 2) TICKET YOKSA: aynı sembol+yönün EN ESKİ eşleşmemiş kararı (FIFO) */
12915
+ if (!hit) {
12916
+ for (const x of d.decisions) {
12917
+ if (fresh(x) && x.symbol === sym && x.action === act) { hit = x; break; }
12918
+ }
12847
12919
  }
12848
12920
  if (!hit) return null;
12849
12921
  hit.closedAt = now;
@@ -13892,6 +13964,7 @@ function finInstrSummary(ins) {
13892
13964
  try {
13893
13965
  const f = finCfg();
13894
13966
  if (Number(f.maxPositionsNote) > 0) p.push(`maks ${f.maxPositionsNote} pozisyon`);
13967
+ if (Number(f.maxPerSymbolNote) > 0) p.push(`sembol başına maks ${f.maxPerSymbolNote}`);
13895
13968
  if (Number(f.maxTradesPerDayNote) > 0) p.push(`günde maks ${f.maxTradesPerDayNote} işlem`);
13896
13969
  } catch {}
13897
13970
  return p.join(' · ');
@@ -13913,12 +13986,25 @@ function finTsStrategyTf() {
13913
13986
  }
13914
13987
 
13915
13988
  /* Talimat "zorunlu giriş" istiyor mu? ("her mumda işlem açmak zorundasın" gibi)
13916
- Olumsuz yazım ("zorunlu değil") modu AÇMAZ. */
13989
+ SADECE açık emir cümleleri modu açar; teyit cümleleri ("her mum kapanışını
13990
+ bekle", "her mumda alarm kur") modu AÇMAZ → girişler İSTEĞE BAĞLI kalır
13991
+ (eşik + teyit kapıları çalışır). Olumsuz yazım ("zorunlu değil / zorunda
13992
+ değil / mecbur değil") modu kapatır. */
13917
13993
  function finTsMandatoryEntry() {
13918
- const s = String(finTsStrategyText() || '').toLowerCase();
13994
+ const s = String(finTsStrategyText() || '')
13995
+ .toLocaleLowerCase('tr')
13996
+ .replace(/\u0307/g, ''); /* İ → i̇ (birleşik nokta) temizliği */
13919
13997
  if (!s) return false;
13920
13998
  if (/zorunlu değil|mecbur değil|zorunda değil/.test(s)) return false;
13921
- return /her mum|her barda?|her mumda|işlem açmak zorunda|her zaman işlem|sürekli işlem|durmadan işlem|zorunlu (?:olarak )?(?:işlem|giriş|al|sat)|mecbur/.test(s);
13999
+ const trade = '(?:i[şs]lem|trade|giri[şs]|pozisyon|emir|al\\b|sat\\b|a[çc]\\b)';
14000
+ return (
14001
+ new RegExp('her\\s*(?:mum(?:da|de)?|bar(?:da|de)?)[^.\\n]{0,24}?' + trade).test(s) ||
14002
+ new RegExp('(?:i[şs]lem|giri[şs]|pozisyon|emir)\\s*(?:a[çc]mak|a[çc]ma)?\\s*zorunda').test(s) ||
14003
+ new RegExp('her\\s*zaman\\s*' + trade).test(s) ||
14004
+ new RegExp('(?:s[üu]rekli|durmadan)\\s*' + trade).test(s) ||
14005
+ new RegExp('zorunlu\\s*(?:olarak\\s*)?' + trade).test(s) ||
14006
+ /\bmecbur\b/.test(s)
14007
+ );
13922
14008
  }
13923
14009
 
13924
14010
  /* Ritim: talimatta M1 → işlem ajanı turları en hızlı 60 sn, M5 → 300 sn
@@ -14781,6 +14867,7 @@ async function finTypeSafeRound(sid, agent) {
14781
14867
  }
14782
14868
  const lines = [];
14783
14869
  let opened = 0;
14870
+ const openedBySym = new Map(); /* bu turda açılanlar — sembol tavanı sayar */
14784
14871
  for (let i = 0; i < symbols.length; i++) {
14785
14872
  const sym = symbols[i];
14786
14873
  if (!financeState.agents.has(sidS)) return;
@@ -14795,24 +14882,26 @@ async function finTypeSafeRound(sid, agent) {
14795
14882
  const cal = finTsCalibration(sym, market[sym].tf);
14796
14883
  const thAction = cal.action;
14797
14884
  if (pos) {
14798
- /* POZİSYON YÖNETİCİSİ açık: kapat/kısmi/SL kararları onun turunda */
14885
+ /* POZİSYON YÖNETİCİSİ açık: kapat/kısmi/SL kararları onun turunda.
14886
+ GİRİŞ DEĞERLENDİRMESİ DURMAZ: aynı sembolde çoklu işlem açılabilir
14887
+ (toplam slot + sembol başına tavan + eşikler korur). */
14799
14888
  if (posManagerOn) {
14800
14889
  lines.push(`- ${sym}: pozisyon açık #${pos.ticket} — yönetim Pozisyon Yöneticisi'nde (${finPosMgrSec()} sn Jev turu)`);
14801
- continue;
14802
- }
14803
- const ex = finTsNoul(ans, 'kapat_' + i);
14804
- if (ex != null && ex >= FIN_TS_EXIT_P) {
14805
- const r = await financetools.handlers.mt5_close(
14806
- { ticket: Number(pos.ticket), reason: `TypeSafe: kapat p=${ex.toFixed(2)}` },
14807
- { sessionId: sidS }
14808
- );
14809
- lines.push(`- ${sym}: KAPAT (p=${ex.toFixed(2)}) ${r && r.ok ? '✓ pozisyon kapatıldı' : '✗ ' + ((r && r.error) || 'hata')}`);
14810
14890
  } else {
14811
- lines.push(`- ${sym}: pozisyon açık (kapat=${ex == null ? 'yanıt yok' : ex.toFixed(2)} < ${FIN_TS_EXIT_P}) — tez sürüyor`);
14812
- /* JEV POZİSYON YÖNETİMİ: kısmi kapatma + SL/koruma kararları */
14813
- try { await finTsManageOpen(sidS, agent, sym, pos, market[sym], ans, i, lines); } catch {}
14891
+ const ex = finTsNoul(ans, 'kapat_' + i);
14892
+ if (ex != null && ex >= FIN_TS_EXIT_P) {
14893
+ const r = await financetools.handlers.mt5_close(
14894
+ { ticket: Number(pos.ticket), reason: `TypeSafe: kapat p=${ex.toFixed(2)}` },
14895
+ { sessionId: sidS }
14896
+ );
14897
+ lines.push(`- ${sym}: KAPAT (p=${ex.toFixed(2)}) ${r && r.ok ? '✓ pozisyon kapatıldı' : '✗ ' + ((r && r.error) || 'hata')}`);
14898
+ } else {
14899
+ lines.push(`- ${sym}: pozisyon açık (kapat=${ex == null ? 'yanıt yok' : ex.toFixed(2)} < ${FIN_TS_EXIT_P}) — tez sürüyor`);
14900
+ /* JEV POZİSYON YÖNETİMİ: kısmi kapatma + SL/koruma kararları */
14901
+ try { await finTsManageOpen(sidS, agent, sym, pos, market[sym], ans, i, lines); } catch {}
14902
+ }
14903
+ continue;
14814
14904
  }
14815
- continue;
14816
14905
  }
14817
14906
  if (!c || (c.choice !== 'buy' && c.choice !== 'sell')) {
14818
14907
  lines.push(`- ${sym}: ${finTsFmtChoice(c)} → BEKLE`);
@@ -14843,6 +14932,13 @@ async function finTypeSafeRound(sid, agent) {
14843
14932
  lines.push(`- ${sym}: sinyal güçlü (${c.choice} p=${c.p.toFixed(2)}) ama pozisyon+bekleyen emir sınırı dolu (${posList.length + pendCount}/${posCap}) — bu tur açılmadı`);
14844
14933
  continue;
14845
14934
  }
14935
+ /* SEMBOL BAŞINA TAVAN: aynı sembolde çoklu işlem (bu turda açılanlar dahil) */
14936
+ const symCap = finPerSymbolCap(f);
14937
+ const symCount = posList.filter((p) => String((p && p.symbol) || '').toUpperCase() === sym).length + (openedBySym.get(sym) || 0);
14938
+ if (symCount >= symCap) {
14939
+ lines.push(`- ${sym}: sembol başına pozisyon tavanı dolu (${symCount}/${symCap}) — bu tur açılmadı`);
14940
+ continue;
14941
+ }
14846
14942
  /* GİRİŞ TİPİ + RİSK PROFİLİ (JEV kararı) — seviyeleri KOD hesaplar */
14847
14943
  const row = market[sym].row || {};
14848
14944
  const entryRef = c.choice === 'buy' ? Number(row.ask) || Number(row.bid) : Number(row.bid) || Number(row.ask);
@@ -14893,15 +14989,14 @@ async function finTypeSafeRound(sid, agent) {
14893
14989
  let martNote = '';
14894
14990
  if (ins.entry.lotMult != null) sizeMult *= ins.entry.lotMult;
14895
14991
  if (ins.entry.martingale != null) {
14896
- let streak = 0;
14897
- try {
14898
- const le = finLearnLoad().symbols[sym];
14899
- streak = Number(le && le.stats && le.stats.streak) || 0;
14900
- } catch {}
14901
- const pow = Math.min(3, Math.max(0, Math.round(streak)));
14992
+ /* KAYIP SERİSİ SAYACI: kapanan her işlem TEK sayılır (aç+kapa=1).
14993
+ 1. işlem stop → seri 1 (×1.2), 2. stop → seri 2 (×1.44)…
14994
+ kâra geçince seri 0 → martingale kapanır, taban lota dönülür. */
14995
+ const streak = finLossStreak(sym, market[sym].tf);
14996
+ const pow = Math.min(3, Math.max(0, streak));
14902
14997
  if (pow > 0) {
14903
14998
  sizeMult *= Math.pow(ins.entry.martingale, pow);
14904
- martNote = ` · martingale ×${ins.entry.martingale}^${pow}`;
14999
+ martNote = ` · martingale ×${ins.entry.martingale}^${pow} (${pow}. ardışık kayıp sonrası)`;
14905
15000
  }
14906
15001
  }
14907
15002
  if (sizeMult !== 1) riskPct = Math.max(0.1, Math.min(10, Math.round(riskPct * sizeMult * 100) / 100));
@@ -14932,14 +15027,21 @@ async function finTypeSafeRound(sid, agent) {
14932
15027
  );
14933
15028
  if (r && r.ok && !r.shadow) {
14934
15029
  opened += 1;
15030
+ openedBySym.set(sym, (openedBySym.get(sym) || 0) + 1);
14935
15031
  /* KARAR KAYDI: özellikler + karar diske yazılır; kapanışta sonuçla
14936
15032
  eşleşir → kalibrasyon/eşik/risk öğrenmesi bu veriyle çalışır */
14937
15033
  try {
14938
15034
  const ind = market[sym].ind || {};
15035
+ /* TICKET: kapanışta karar-sonuç eşleşmesi TICKET ile yapılır —
15036
+ aynı sembolde çoklu işlemde kalibrasyon karışmaz */
15037
+ const decTicket = Number(
15038
+ r && r.result && (r.result.order || r.result.position || r.result.deal || 0)
15039
+ ) || 0;
14939
15040
  finTsDecRecord({
14940
15041
  sid: sidS,
14941
15042
  role: 'trader',
14942
15043
  symbol: sym,
15044
+ ticket: decTicket,
14943
15045
  tf: market[sym].tf,
14944
15046
  action: c.choice,
14945
15047
  p: c.p,
@@ -14983,6 +15085,11 @@ async function finTypeSafeRound(sid, agent) {
14983
15085
  agent,
14984
15086
  `🤖 TypeSafe karar turu #${agent.round} (LLM yok — girdi yalnız TypeSafe):\n` +
14985
15087
  (insTxt ? 'TALİMAT AYARLARI (kod uygular): ' + insTxt + '\n' : '') +
15088
+ /* giriş serbestliği görünür olsun: zorunlu mod yalnız talimat açıkça
15089
+ isterse; yoksa girişler eşik/teyit kapılı (isteğe bağlı) */
15090
+ (talimatZorunlu
15091
+ ? 'TALİMAT MODU: ZORUNLU GİRİŞ — talimat gereği bu turda giriş zorunlu\n'
15092
+ : 'GİRİŞ MODU: İSTEĞE BAĞLI — yalnız eşik/teyit geçen sinyalde işlem açılır\n') +
14986
15093
  'TF KARARI: ' + symbols.map((s) => `${s}=${market[s].tf}`).join(', ') + '\n' +
14987
15094
  'ÖĞRENİLMİŞ: ' +
14988
15095
  symbols
@@ -10939,21 +10939,23 @@ function finHelpHtml(which) {
10939
10939
  ['<code>lot x1.5</code><code>poz başı lot 1.5</code><code>lotu 2 kat yap</code>',
10940
10940
  '<b>Kod otomatik uygular.</b> Tüm giriş riskine/lotuna çarpan.'],
10941
10941
  ['<code>martingale</code><code>martingale 1.2</code><code>martingale x1.20</code><code>1.2 kat martingale</code>',
10942
- '<b>Kod otomatik uygular.</b> Kayıp serisinde lot katlanır — faktör serbest (ör. 1.2). Varsayılan ×2; 1.01–5 arası geçerli, seri en çok ×3, toplam risk tavanı %10 ve max lot kilidi geçerli.'],
10942
+ '<b>Kod otomatik uygular.</b> Kayıp serisi KAPANAN işlemlerden sayılır (aç+kapa = 1 işlem): 1. işlem stop → 2. işlem ×1.2, o da stop → ×1.44… Kâra geçen ilk işlemde seri sıfırlanır ve taban lota dönülür. Faktör serbest (ör. 1.2); varsayılan ×2, 1.01–5 arası geçerli, seri en çok ×3, toplam risk tavanı %10 ve max lot kilidi geçerli.'],
10943
10943
  ['<code>her mumda işlem açmak zorundasın</code><code>her barda işlem</code><code>her zaman işlem</code>',
10944
- '<b>ZORUNLU GİRİŞ modu.</b> "bekle" seçeneği kaldırılır, eşik/teyit kapıları atlanır, emir market olur. "zorunlu değil" yazarsan mod açılmaz.'],
10945
- ['<code>M1</code><code>1m</code><code>5 dk</code><code>4 saat</code>',
10946
- 'İşlem zaman dilimi. M1/M5 yazarsan tur ritmi hızlanır (M1 en hızlı 60 sn).'],
10944
+ '<b>ZORUNLU GİRİŞ modu (isteğe bağlı).</b> Bu ifadeyi <b>yazmazsan girişler isteğe bağlıdır</b>: yalnız eşik + teyit geçen sinyalde işlem açılır. Yazarsan "bekle" kaldırılır, eşik/teyit atlanır, emir market olur. Teyit cümleleri ("her mum kapanışını bekle") modu açmaz; "zorunlu değil" yazarsan kapanır.'],
10945
+ ['<code>M1</code><code>1m</code><code>M15</code><code>5 dk</code><code>4 saat</code>',
10946
+ 'İşlem zaman dilimi. Yazdığın TF (ör. <b>M15</b>) tüm girişlerde birincil kuraldır: analiz, bildirim ve pozisyon yorumu o periyodu kullanır — talimatta M1 yazmadıkça M1\'de işlem açılmaz. M1/M5 yazarsan tur ritmi hızlanır (M1 en hızlı 60 sn).'],
10947
10947
  ['<code>başlangıç bakiye 10.000</code><code>gün başı: 10000</code><code>starting balance 10000</code>',
10948
10948
  'Gün başı bakiyesi — her turda günlük K/Z otomatik hesaplanır ve Jev\'e durum olarak verilir.'],
10949
10949
  ['<code>günlük zarar %3</code><code>max günlük kayıp 3</code>',
10950
10950
  '<b>Kod otomatik uygular.</b> Limit aşılırsa yeni işlem açılmaz; günlük kayıp otomasyonunun limiti bu olur.'],
10951
10951
  ['<code>aynı anda en fazla 10 işlem</code><code>en fazla 10 pozisyon</code><code>günde en fazla 10 işlem</code>',
10952
10952
  '<b>Kod otomatik uygular.</b> Eşzamanlı tavan (pozisyon + bekleyen emir) ya da günlük işlem tavanı. Talimatta yazdığın sürece Ayarlar\'daki değeri ezer; metinden kaldırınca ayar geçerli olur.'],
10953
+ ['<code>sembol başına 5 işlem</code><code>aynı sembolde en fazla 3 pozisyon</code>',
10954
+ '<b>Kod otomatik uygular.</b> Aynı sembolde çoklu işlem tavanı (toplam tavanı aşamaz). Toplam tavan yazarsan ("aynı anda en fazla 10 işlem") aynı sembolde de o tavana kadar işlem açılabilir; yazmazsan Ayarlar → maks/pay değeri geçerlidir.'],
10953
10955
  ];
10954
10956
  const example = posmgr
10955
10957
  ? `1- 1R'de %50 kısmi kapat\n2- kâr 2R'ye gelince kalanı kapat\n3- zarar -0.5R'yi geçerse kes`
10956
- : `1- risk yüzde 2\n2- martingale kullan (x1.2)\n3- her mumda işlem açmak zorundasın\n4- aynı anda en fazla 10 işlem\n5- başlangıç bakiye 10.000\n6- günlük zarar %3`;
10958
+ : `1- zaman dilimi M15\n2- risk yüzde 2\n3- martingale kullan (x1.2)\n4- sadece uygun sinyalde işlem aç (isteğe bağlı)\n5- aynı anda en fazla 10 işlem\n6- başlangıç bakiye 10.000\n7- günlük zarar %3`;
10957
10959
  const head = posmgr
10958
10960
  ? 'Pozisyon Yöneticisi (ayarlı sıklık — varsayılan 5 sn) açık pozisyonları yönetir: kapat / kısmi kapat / SL taşı. Trade Ajanı pozisyon açıkken de tur atmaya devam eder ve yeni girişleri değerlendirir.'
10959
10961
  : 'Trade Ajanı girişleri yönetir: yön, emir tipi, risk, lot, martingale ve günlük limitler.';