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 +1 -1
- package/src/agent/financetools.js +10 -1
- package/src/agent/finrisk.js +16 -1
- package/src/main.js +139 -32
- package/src/renderer/renderer.js +7 -5
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;
|
|
@@ -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
|
-
|
|
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() || '')
|
|
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
|
-
|
|
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
|
-
|
|
14812
|
-
|
|
14813
|
-
|
|
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
|
-
|
|
14897
|
-
|
|
14898
|
-
|
|
14899
|
-
|
|
14900
|
-
|
|
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
|
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
|
-
'<b>ZORUNLU GİRİŞ modu.</b> "bekle"
|
|
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\
|
|
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.';
|