beast-agent 2.76.0 → 2.76.2
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/financetools.js +10 -1
- package/src/agent/finrisk.js +16 -1
- package/src/main.js +140 -36
- package/src/renderer/renderer.js +6 -4
package/package.json
CHANGED
|
@@ -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
|
-
|
|
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;
|
package/src/agent/finrisk.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
12842
|
-
|
|
12843
|
-
|
|
12844
|
-
|
|
12845
|
-
|
|
12846
|
-
|
|
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;
|
|
@@ -13818,13 +13890,28 @@ function finParseInstructions(text) {
|
|
|
13818
13890
|
if (m) out.lotMult = finInstrNum(m[1] || m[2] || m[3]);
|
|
13819
13891
|
if (out.lotMult != null) out.lotMult = Math.max(1, Math.min(5, out.lotMult));
|
|
13820
13892
|
if (/martingale|mart[ıi]ngale/.test(low)) {
|
|
13821
|
-
/*
|
|
13822
|
-
|
|
13823
|
-
|
|
13824
|
-
|
|
13825
|
-
|
|
13826
|
-
|
|
13827
|
-
|
|
13893
|
+
/* FAKTÖR SERBEST — doğal yazımların hepsi denenir:
|
|
13894
|
+
"martingale 1.2" "martingale x1.20" "martingale 1,2"
|
|
13895
|
+
"martingale çarpanı 1.2" "1.2x martingale" "1.2 kat martingale"
|
|
13896
|
+
"martingale kullan, 1.2 kat" "martingale kullan (x1.2)" "martingale e 1.2x"
|
|
13897
|
+
Yanlış sayı kapmamak için: "1R de %50" gibi R-yüzdeleri ve 1 ve altı
|
|
13898
|
+
sayılar faktör sayılmaz (varsayılan ×2 kalır). Geçerli aralık 1.01-5. */
|
|
13899
|
+
const pats = [
|
|
13900
|
+
/mart[ıi]ngale\s*(?:x|×|çarpan[ıi]?|carpan[ıi]?|oran[ıi]?|fakt[öo]r[üu]?|kat[ıi]?)?\s*(\d+(?:[.,]\d+)?)(?!\s*r\b)/,
|
|
13901
|
+
/(\d+(?:[.,]\d+)?)\s*(?:x|×|kat[ıi]?)?\s*mart[ıi]ngale/,
|
|
13902
|
+
/mart[ıi]ngale[^0-9%\n]{0,24}?(\d+(?:[.,]\d+)?)\s*(?:x|×|kat[ıi]?)/,
|
|
13903
|
+
/mart[ıi]ngale[^0-9%\n]{0,24}?(\d+[.,]\d+)(?!\s*r\b)/,
|
|
13904
|
+
];
|
|
13905
|
+
let mf = null;
|
|
13906
|
+
for (const p of pats) {
|
|
13907
|
+
m = low.match(p);
|
|
13908
|
+
const v = m ? finInstrNum(m[1]) : null;
|
|
13909
|
+
if (v != null && v > 1 && v <= 5) {
|
|
13910
|
+
mf = v;
|
|
13911
|
+
break;
|
|
13912
|
+
}
|
|
13913
|
+
}
|
|
13914
|
+
out.martingale = Math.max(1.01, Math.min(5, mf != null ? mf : 2));
|
|
13828
13915
|
}
|
|
13829
13916
|
/* kısmi kapatma: "1R'de %50" → atR=1, pct=50; "%50 1R" → aynı; "kısmi %50" → atR=1 */
|
|
13830
13917
|
m = low.match(/(\d+(?:[.,]\d+)?)\s*r[^%\d]{0,28}%\s*(\d+(?:[.,]\d+)?)/);
|
|
@@ -13877,6 +13964,7 @@ function finInstrSummary(ins) {
|
|
|
13877
13964
|
try {
|
|
13878
13965
|
const f = finCfg();
|
|
13879
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}`);
|
|
13880
13968
|
if (Number(f.maxTradesPerDayNote) > 0) p.push(`günde maks ${f.maxTradesPerDayNote} işlem`);
|
|
13881
13969
|
} catch {}
|
|
13882
13970
|
return p.join(' · ');
|
|
@@ -14766,6 +14854,7 @@ async function finTypeSafeRound(sid, agent) {
|
|
|
14766
14854
|
}
|
|
14767
14855
|
const lines = [];
|
|
14768
14856
|
let opened = 0;
|
|
14857
|
+
const openedBySym = new Map(); /* bu turda açılanlar — sembol tavanı sayar */
|
|
14769
14858
|
for (let i = 0; i < symbols.length; i++) {
|
|
14770
14859
|
const sym = symbols[i];
|
|
14771
14860
|
if (!financeState.agents.has(sidS)) return;
|
|
@@ -14780,24 +14869,26 @@ async function finTypeSafeRound(sid, agent) {
|
|
|
14780
14869
|
const cal = finTsCalibration(sym, market[sym].tf);
|
|
14781
14870
|
const thAction = cal.action;
|
|
14782
14871
|
if (pos) {
|
|
14783
|
-
/* POZİSYON YÖNETİCİSİ açık: kapat/kısmi/SL kararları onun turunda
|
|
14872
|
+
/* POZİSYON YÖNETİCİSİ açık: kapat/kısmi/SL kararları onun turunda.
|
|
14873
|
+
GİRİŞ DEĞERLENDİRMESİ DURMAZ: aynı sembolde çoklu işlem açılabilir
|
|
14874
|
+
(toplam slot + sembol başına tavan + eşikler korur). */
|
|
14784
14875
|
if (posManagerOn) {
|
|
14785
14876
|
lines.push(`- ${sym}: pozisyon açık #${pos.ticket} — yönetim Pozisyon Yöneticisi'nde (${finPosMgrSec()} sn Jev turu)`);
|
|
14786
|
-
continue;
|
|
14787
|
-
}
|
|
14788
|
-
const ex = finTsNoul(ans, 'kapat_' + i);
|
|
14789
|
-
if (ex != null && ex >= FIN_TS_EXIT_P) {
|
|
14790
|
-
const r = await financetools.handlers.mt5_close(
|
|
14791
|
-
{ ticket: Number(pos.ticket), reason: `TypeSafe: kapat p=${ex.toFixed(2)}` },
|
|
14792
|
-
{ sessionId: sidS }
|
|
14793
|
-
);
|
|
14794
|
-
lines.push(`- ${sym}: KAPAT (p=${ex.toFixed(2)}) ${r && r.ok ? '✓ pozisyon kapatıldı' : '✗ ' + ((r && r.error) || 'hata')}`);
|
|
14795
14877
|
} else {
|
|
14796
|
-
|
|
14797
|
-
|
|
14798
|
-
|
|
14878
|
+
const ex = finTsNoul(ans, 'kapat_' + i);
|
|
14879
|
+
if (ex != null && ex >= FIN_TS_EXIT_P) {
|
|
14880
|
+
const r = await financetools.handlers.mt5_close(
|
|
14881
|
+
{ ticket: Number(pos.ticket), reason: `TypeSafe: kapat p=${ex.toFixed(2)}` },
|
|
14882
|
+
{ sessionId: sidS }
|
|
14883
|
+
);
|
|
14884
|
+
lines.push(`- ${sym}: KAPAT (p=${ex.toFixed(2)}) ${r && r.ok ? '✓ pozisyon kapatıldı' : '✗ ' + ((r && r.error) || 'hata')}`);
|
|
14885
|
+
} else {
|
|
14886
|
+
lines.push(`- ${sym}: pozisyon açık (kapat=${ex == null ? 'yanıt yok' : ex.toFixed(2)} < ${FIN_TS_EXIT_P}) — tez sürüyor`);
|
|
14887
|
+
/* JEV POZİSYON YÖNETİMİ: kısmi kapatma + SL/koruma kararları */
|
|
14888
|
+
try { await finTsManageOpen(sidS, agent, sym, pos, market[sym], ans, i, lines); } catch {}
|
|
14889
|
+
}
|
|
14890
|
+
continue;
|
|
14799
14891
|
}
|
|
14800
|
-
continue;
|
|
14801
14892
|
}
|
|
14802
14893
|
if (!c || (c.choice !== 'buy' && c.choice !== 'sell')) {
|
|
14803
14894
|
lines.push(`- ${sym}: ${finTsFmtChoice(c)} → BEKLE`);
|
|
@@ -14828,6 +14919,13 @@ async function finTypeSafeRound(sid, agent) {
|
|
|
14828
14919
|
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ı`);
|
|
14829
14920
|
continue;
|
|
14830
14921
|
}
|
|
14922
|
+
/* SEMBOL BAŞINA TAVAN: aynı sembolde çoklu işlem (bu turda açılanlar dahil) */
|
|
14923
|
+
const symCap = finPerSymbolCap(f);
|
|
14924
|
+
const symCount = posList.filter((p) => String((p && p.symbol) || '').toUpperCase() === sym).length + (openedBySym.get(sym) || 0);
|
|
14925
|
+
if (symCount >= symCap) {
|
|
14926
|
+
lines.push(`- ${sym}: sembol başına pozisyon tavanı dolu (${symCount}/${symCap}) — bu tur açılmadı`);
|
|
14927
|
+
continue;
|
|
14928
|
+
}
|
|
14831
14929
|
/* GİRİŞ TİPİ + RİSK PROFİLİ (JEV kararı) — seviyeleri KOD hesaplar */
|
|
14832
14930
|
const row = market[sym].row || {};
|
|
14833
14931
|
const entryRef = c.choice === 'buy' ? Number(row.ask) || Number(row.bid) : Number(row.bid) || Number(row.ask);
|
|
@@ -14878,15 +14976,14 @@ async function finTypeSafeRound(sid, agent) {
|
|
|
14878
14976
|
let martNote = '';
|
|
14879
14977
|
if (ins.entry.lotMult != null) sizeMult *= ins.entry.lotMult;
|
|
14880
14978
|
if (ins.entry.martingale != null) {
|
|
14881
|
-
|
|
14882
|
-
|
|
14883
|
-
|
|
14884
|
-
|
|
14885
|
-
|
|
14886
|
-
const pow = Math.min(3, Math.max(0, Math.round(streak)));
|
|
14979
|
+
/* KAYIP SERİSİ SAYACI: kapanan her işlem TEK sayılır (aç+kapa=1).
|
|
14980
|
+
1. işlem stop → seri 1 (×1.2), 2. stop → seri 2 (×1.44)…
|
|
14981
|
+
kâra geçince seri 0 → martingale kapanır, taban lota dönülür. */
|
|
14982
|
+
const streak = finLossStreak(sym, market[sym].tf);
|
|
14983
|
+
const pow = Math.min(3, Math.max(0, streak));
|
|
14887
14984
|
if (pow > 0) {
|
|
14888
14985
|
sizeMult *= Math.pow(ins.entry.martingale, pow);
|
|
14889
|
-
martNote = ` · martingale ×${ins.entry.martingale}^${pow}`;
|
|
14986
|
+
martNote = ` · martingale ×${ins.entry.martingale}^${pow} (${pow}. ardışık kayıp sonrası)`;
|
|
14890
14987
|
}
|
|
14891
14988
|
}
|
|
14892
14989
|
if (sizeMult !== 1) riskPct = Math.max(0.1, Math.min(10, Math.round(riskPct * sizeMult * 100) / 100));
|
|
@@ -14917,14 +15014,21 @@ async function finTypeSafeRound(sid, agent) {
|
|
|
14917
15014
|
);
|
|
14918
15015
|
if (r && r.ok && !r.shadow) {
|
|
14919
15016
|
opened += 1;
|
|
15017
|
+
openedBySym.set(sym, (openedBySym.get(sym) || 0) + 1);
|
|
14920
15018
|
/* KARAR KAYDI: özellikler + karar diske yazılır; kapanışta sonuçla
|
|
14921
15019
|
eşleşir → kalibrasyon/eşik/risk öğrenmesi bu veriyle çalışır */
|
|
14922
15020
|
try {
|
|
14923
15021
|
const ind = market[sym].ind || {};
|
|
15022
|
+
/* TICKET: kapanışta karar-sonuç eşleşmesi TICKET ile yapılır —
|
|
15023
|
+
aynı sembolde çoklu işlemde kalibrasyon karışmaz */
|
|
15024
|
+
const decTicket = Number(
|
|
15025
|
+
r && r.result && (r.result.order || r.result.position || r.result.deal || 0)
|
|
15026
|
+
) || 0;
|
|
14924
15027
|
finTsDecRecord({
|
|
14925
15028
|
sid: sidS,
|
|
14926
15029
|
role: 'trader',
|
|
14927
15030
|
symbol: sym,
|
|
15031
|
+
ticket: decTicket,
|
|
14928
15032
|
tf: market[sym].tf,
|
|
14929
15033
|
action: c.choice,
|
|
14930
15034
|
p: c.p,
|
package/src/renderer/renderer.js
CHANGED
|
@@ -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
|
|
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
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).'],
|
|
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\
|
|
10958
|
+
: `1- M15'te işlem aç\n2- risk yüzde 2\n3- martingale kullan (x1.2)\n4- her mumda işlem açmak zorundasın\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.';
|