beast-agent 2.76.3 → 2.76.5
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 +36 -2
- package/src/main.js +110 -40
- package/src/renderer/index.html +1 -1
- package/src/renderer/renderer.js +5 -1
package/package.json
CHANGED
|
@@ -126,6 +126,20 @@ function lotRange(cfg, symbol) {
|
|
|
126
126
|
return { minLot, maxLot };
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
+
/* LOT ÇARPANI (martingale/kademe): risk lotu hesaplandıktan SONRA hacim
|
|
130
|
+
çarpılır ve broker adımına normalize edilir; maxLot ile kırpılır.
|
|
131
|
+
1. işlem 0.01 lot ise martingale kademesi 0.012'ye çıkar (adıma yuvarlanır)
|
|
132
|
+
— kâra geçince çarpan kalkar, taban lota dönülür. */
|
|
133
|
+
function scaleVolume(info, vol, mult, minLot, maxLot) {
|
|
134
|
+
const m = Number(mult);
|
|
135
|
+
if (!(m > 0) || m === 1) return vol;
|
|
136
|
+
const lo = Number(minLot) > 0 ? Number(minLot) : 0.01;
|
|
137
|
+
const hi = Number(maxLot) > 0 ? Number(maxLot) : vol * m;
|
|
138
|
+
const want = Math.max(lo, Math.min(hi, vol * m));
|
|
139
|
+
const n = finrisk.normalizeVolume(info, want, maxLot, minLot);
|
|
140
|
+
return !n.error && Number(n.volume) > 0 ? Number(n.volume) : vol;
|
|
141
|
+
}
|
|
142
|
+
|
|
129
143
|
/* İşlem öncesi risk katmanı: stops_level + yoğunluk + marj kalkanı.
|
|
130
144
|
Hata metni ya da null döner. positions çağıran tarafından verilir. */
|
|
131
145
|
async function preTradeCheck(cfg, side, symbol, info, price, volume, sl, tp, positions) {
|
|
@@ -792,6 +806,8 @@ const handlers = {
|
|
|
792
806
|
mesafesinden hesaplanır; aksi halde volume broker kuralına normalize edilir */
|
|
793
807
|
const explicitRisk = Number(args.riskPct) > 0 ? Number(args.riskPct) : 0;
|
|
794
808
|
const wantVolume = Number(args.volume);
|
|
809
|
+
/* MARTİNGALE/KADEME ÇARPANI: risk lotu hesaplandıktan sonra hacme uygulanır */
|
|
810
|
+
const sizeMult = Number(args.sizeMult) > 0 ? Math.min(20, Number(args.sizeMult)) : 1;
|
|
795
811
|
let vol = 0;
|
|
796
812
|
let riskInfo = null;
|
|
797
813
|
if (explicitRisk > 0 || (!(wantVolume > 0) && Number(cfg.riskPerTradePct) > 0)) {
|
|
@@ -803,7 +819,15 @@ const handlers = {
|
|
|
803
819
|
const rr = finrisk.calcRiskLot(info, price, sl, riskAmount, range.maxLot, range.minLot);
|
|
804
820
|
if (rr.error) return { ok: false, error: rr.error };
|
|
805
821
|
vol = rr.volume;
|
|
806
|
-
|
|
822
|
+
if (sizeMult !== 1) vol = scaleVolume(info, vol, sizeMult, range.minLot, range.maxLot);
|
|
823
|
+
const perLot = Number(rr.lossPerLot) || 0;
|
|
824
|
+
riskInfo = {
|
|
825
|
+
riskPct,
|
|
826
|
+
riskAmount: Math.round((perLot > 0 ? perLot * vol : riskAmount) * 100) / 100,
|
|
827
|
+
lossPerLot: rr.lossPerLot,
|
|
828
|
+
raised: !!rr.raised,
|
|
829
|
+
sizeMult,
|
|
830
|
+
};
|
|
807
831
|
} else {
|
|
808
832
|
const norm = finrisk.normalizeVolume(info, wantVolume, range.maxLot, range.minLot);
|
|
809
833
|
if (norm.error) return { ok: false, error: norm.error };
|
|
@@ -939,6 +963,8 @@ const handlers = {
|
|
|
939
963
|
/* LOT: riskPct verilirse BEKLEYEN EMİR fiyatı + SL mesafesinden hesaplanır
|
|
940
964
|
(piyasa emriyle aynı risk hattı); volume verilmişse normalize edilir. */
|
|
941
965
|
const explicitRisk = Number(args.riskPct) > 0 ? Number(args.riskPct) : 0;
|
|
966
|
+
/* MARTİNGALE/KADEME ÇARPANI: risk lotu hesaplandıktan sonra hacme uygulanır */
|
|
967
|
+
const sizeMult = Number(args.sizeMult) > 0 ? Math.min(20, Number(args.sizeMult)) : 1;
|
|
942
968
|
let vol = 0;
|
|
943
969
|
let riskInfo = null;
|
|
944
970
|
if (explicitRisk > 0 || (!(Number(args.volume) > 0) && Number(cfg.riskPerTradePct) > 0)) {
|
|
@@ -951,7 +977,15 @@ const handlers = {
|
|
|
951
977
|
const rr = finrisk.calcRiskLot(info, entryPrice, slRef, riskAmount, range.maxLot, range.minLot);
|
|
952
978
|
if (rr.error) return { ok: false, error: rr.error };
|
|
953
979
|
vol = rr.volume;
|
|
954
|
-
|
|
980
|
+
if (sizeMult !== 1) vol = scaleVolume(info, vol, sizeMult, range.minLot, range.maxLot);
|
|
981
|
+
const perLot = Number(rr.lossPerLot) || 0;
|
|
982
|
+
riskInfo = {
|
|
983
|
+
riskPct,
|
|
984
|
+
riskAmount: Math.round((perLot > 0 ? perLot * vol : riskAmount) * 100) / 100,
|
|
985
|
+
lossPerLot: rr.lossPerLot,
|
|
986
|
+
raised: !!rr.raised,
|
|
987
|
+
sizeMult,
|
|
988
|
+
};
|
|
955
989
|
} else {
|
|
956
990
|
const norm = finrisk.normalizeVolume(info, args.volume, range.maxLot, range.minLot);
|
|
957
991
|
if (norm.error) return { ok: false, error: norm.error };
|
package/src/main.js
CHANGED
|
@@ -10006,7 +10006,10 @@ function finCfg() {
|
|
|
10006
10006
|
finNormalizeSymbolLimits(f);
|
|
10007
10007
|
if (f.maxPositions == null) f.maxPositions = 3;
|
|
10008
10008
|
/* KODLA DİSİPLİN (trader kuralları): hepsi 0 = kural kapalı */
|
|
10009
|
-
|
|
10009
|
+
/* GÜNLÜK İŞLEM LİMİTİ TAMAMEN KALDIRILDI: ayar değeri artık uygulanmaz
|
|
10010
|
+
(0'a sabitlenir). Günlük limit YALNIZ talimata "günde en fazla N işlem"
|
|
10011
|
+
yazılırsa (not) devreye girer — varsayılan SINIRSIZ. */
|
|
10012
|
+
f.maxTradesPerDay = 0;
|
|
10010
10013
|
if (!Number.isFinite(Number(f.lossStreakLimit))) f.lossStreakLimit = 2;
|
|
10011
10014
|
if (!Number.isFinite(Number(f.lossStreakPauseMin))) f.lossStreakPauseMin = 30;
|
|
10012
10015
|
/* RE-ENTRY BEKLEME: kural VARSAYILAN KAPALI (0) — isteyen Gelişmiş
|
|
@@ -10413,18 +10416,18 @@ function finTeamDigest() {
|
|
|
10413
10416
|
function finDisciplineError(side, symbol, positions) {
|
|
10414
10417
|
try {
|
|
10415
10418
|
const cfg = finCfg();
|
|
10416
|
-
/* TALİMAT
|
|
10417
|
-
|
|
10418
|
-
|
|
10419
|
-
|
|
10420
|
-
|
|
10421
|
-
|
|
10422
|
-
|
|
10423
|
-
|
|
10424
|
-
|
|
10425
|
-
|
|
10426
|
-
|
|
10427
|
-
|
|
10419
|
+
/* GÜNLÜK İŞLEM LİMİTİ: yalnız TALİMAT notu uygulanır ("günde en fazla N
|
|
10420
|
+
işlem"); ayarlardaki değer KALDIRILDI. Not yoksa kural kapalı = sınırsız
|
|
10421
|
+
(günlük işlem sayısı asla yeni girişi engellemez). */
|
|
10422
|
+
const dayNote = Number(cfg.maxTradesPerDayNote) > 0 ? Number(cfg.maxTradesPerDayNote) : 0;
|
|
10423
|
+
return finrisk.disciplineError(
|
|
10424
|
+
finJournalTail(400),
|
|
10425
|
+
Date.now(),
|
|
10426
|
+
{ ...cfg, maxTradesPerDay: dayNote },
|
|
10427
|
+
side,
|
|
10428
|
+
symbol,
|
|
10429
|
+
positions
|
|
10430
|
+
);
|
|
10428
10431
|
} catch {
|
|
10429
10432
|
return null;
|
|
10430
10433
|
}
|
|
@@ -11333,19 +11336,28 @@ async function finRecordClose(ticket, st) {
|
|
|
11333
11336
|
let net = null;
|
|
11334
11337
|
let symbol = (st && st.symbol) || '';
|
|
11335
11338
|
let closeReason = null; /* kapanışı yapan son deal'in nedeni (4=SL, 5=TP, 6=stop-out) */
|
|
11336
|
-
|
|
11337
|
-
|
|
11338
|
-
|
|
11339
|
-
|
|
11340
|
-
if (
|
|
11341
|
-
|
|
11342
|
-
|
|
11343
|
-
|
|
11344
|
-
|
|
11339
|
+
/* DEAL GECİKMESİ: kapanıştan hemen sonra deal listesi boş dönebilir — kısa
|
|
11340
|
+
gecikmeyle 1 kez daha dene. K/Z kaydı kaçarsa martingale kayıp serisi,
|
|
11341
|
+
öğrenme istatistiği ve kalibrasyon boş kalır (martingale çalışmaz). */
|
|
11342
|
+
for (let attempt = 0; attempt < 2 && net == null; attempt++) {
|
|
11343
|
+
if (attempt > 0) await new Promise((res) => setTimeout(res, 2000));
|
|
11344
|
+
try {
|
|
11345
|
+
const r = await mt5bridge.call('deals', { days: 3 }, 12000);
|
|
11346
|
+
const deals = (r && r.ok && r.data && r.data.deals) || [];
|
|
11347
|
+
const mine = deals.filter((d) => String(d.position_id) === String(ticket));
|
|
11348
|
+
if (mine.length) {
|
|
11349
|
+
net = 0;
|
|
11350
|
+
for (const d of mine) {
|
|
11351
|
+
net += (Number(d.profit) || 0) + (Number(d.swap) || 0) + (Number(d.commission) || 0);
|
|
11352
|
+
if (Number(d.entry) === 1) closeReason = Number(d.reason);
|
|
11353
|
+
}
|
|
11354
|
+
symbol = String(mine[0].symbol || symbol);
|
|
11345
11355
|
}
|
|
11346
|
-
|
|
11347
|
-
|
|
11348
|
-
|
|
11356
|
+
} catch {}
|
|
11357
|
+
}
|
|
11358
|
+
if (net == null) {
|
|
11359
|
+
try { financeLog(`[watchdog] kapanış K/Z okunamadı (ticket ${ticket}, ${symbol || '?'}) — deal kaydı yok`); } catch {}
|
|
11360
|
+
}
|
|
11349
11361
|
const rounded = net == null ? null : Math.round(net * 100) / 100;
|
|
11350
11362
|
/* MAE/MFE: pozisyonun gördüğü en iyi/en kötü seviyeler kapanışa iliştirilir */
|
|
11351
11363
|
const ex = financeState.excursions.get(String(ticket)) || null;
|
|
@@ -13868,7 +13880,7 @@ function finInstrMoney(v) {
|
|
|
13868
13880
|
|
|
13869
13881
|
function finParseInstructions(text) {
|
|
13870
13882
|
const low = String(text || '').toLowerCase();
|
|
13871
|
-
const out = { riskPct: null, lotMult: null, martingale: null, partial: null, startBalance: null, dailyLossPct: null };
|
|
13883
|
+
const out = { riskPct: null, lotMult: null, martingale: null, partial: null, startBalance: null, dailyLossPct: null, noLossClose: false };
|
|
13872
13884
|
if (!low.trim()) return out;
|
|
13873
13885
|
/* "risk %2", "%2 risk", "risk yüzde 2", "riski 2 yap" → 2 (ilk sayı) */
|
|
13874
13886
|
let m = low.match(
|
|
@@ -13898,7 +13910,9 @@ function finParseInstructions(text) {
|
|
|
13898
13910
|
sayılar faktör sayılmaz (varsayılan ×2 kalır). Geçerli aralık 1.01-5. */
|
|
13899
13911
|
const pats = [
|
|
13900
13912
|
/mart[ıi]ngale\s*(?:x|×|çarpan[ıi]?|carpan[ıi]?|oran[ıi]?|fakt[öo]r[üu]?|kat[ıi]?)?\s*(\d+(?:[.,]\d+)?)(?!\s*r\b)/,
|
|
13901
|
-
|
|
13913
|
+
/* "1.2x martingale" — çarpan kelimesi (x/kat) ZORUNLU: yoksa "risk %2
|
|
13914
|
+
martingale" cümlesindeki 2 yanlışlıkla faktör sanılırdı */
|
|
13915
|
+
/(\d+(?:[.,]\d+)?)\s*(?:x|×|kat[ıi]?)\s*mart[ıi]ngale/,
|
|
13902
13916
|
/mart[ıi]ngale[^0-9%\n]{0,24}?(\d+(?:[.,]\d+)?)\s*(?:x|×|kat[ıi]?)/,
|
|
13903
13917
|
/mart[ıi]ngale[^0-9%\n]{0,24}?(\d+[.,]\d+)(?!\s*r\b)/,
|
|
13904
13918
|
];
|
|
@@ -13924,6 +13938,16 @@ function finParseInstructions(text) {
|
|
|
13924
13938
|
m = low.match(/(?:k[ıi]smi|partial)[^%\d]{0,24}%\s*(\d+(?:[.,]\d+)?)/);
|
|
13925
13939
|
if (m) out.partial = { atR: 1, pct: finInstrNum(m[1]) };
|
|
13926
13940
|
}
|
|
13941
|
+
if (!out.partial) {
|
|
13942
|
+
/* "0.5R'de yarısını kapat", "0.5R karda partial close ile yarısını kapat" */
|
|
13943
|
+
m = low.match(/(\d+(?:[.,]\d+)?)\s*r[^.\n]{0,40}?(?:yar[ıi]s[ıi](?:n[ıi])?|half)/);
|
|
13944
|
+
if (m) out.partial = { atR: finInstrNum(m[1]), pct: 50 };
|
|
13945
|
+
}
|
|
13946
|
+
if (!out.partial) {
|
|
13947
|
+
/* R yazılmamış: "partial close ile yarısını kapat" → 1R varsayılan */
|
|
13948
|
+
m = low.match(/(?:k[ıi]smi|partial|yar[ıi]s[ıi](?:n[ıi])?)[^.\n]{0,30}?(?:yar[ıi]s[ıi](?:n[ıi])?|%\s*50)/);
|
|
13949
|
+
if (m) out.partial = { atR: 1, pct: 50 };
|
|
13950
|
+
}
|
|
13927
13951
|
if (out.partial) {
|
|
13928
13952
|
const p = out.partial;
|
|
13929
13953
|
if (!(p.atR > 0)) p.atR = 1;
|
|
@@ -13931,6 +13955,18 @@ function finParseInstructions(text) {
|
|
|
13931
13955
|
if (!(p.pct >= 5 && p.pct <= 90)) out.partial = null;
|
|
13932
13956
|
else p.pct = Math.round(p.pct);
|
|
13933
13957
|
}
|
|
13958
|
+
/* ZARARDA KAPATMA YASAĞI (KOD uygular): "zararda işlem kapatma",
|
|
13959
|
+
"zararına kapatma", "sadece karda kapat", "kârda değilse kapatma" →
|
|
13960
|
+
kapatma kararı zarardayken REDDEDİLİR (SL/TP hariç — stop çalışır). */
|
|
13961
|
+
if (
|
|
13962
|
+
/(?:zarar(?:da|ına|dayken|day[ıi]m)?|eksi(?:de|ye))[^.\n]{0,24}?kapatma/.test(low) ||
|
|
13963
|
+
/kapatma[^.\n]{0,24}?(?:zarar|eksi)/.test(low) ||
|
|
13964
|
+
/(?:sadece|yaln[ıi]z)[^.\n]{0,24}?k[âa]r(?:da|daysa|dayken)?\b/.test(low) ||
|
|
13965
|
+
/k[âa]rda de[ğg]il(?:se)?[^.\n]{0,20}?kapatma/.test(low) ||
|
|
13966
|
+
/k[âa]r olmadan[^.\n]{0,16}?kapatma/.test(low)
|
|
13967
|
+
) {
|
|
13968
|
+
out.noLossClose = true;
|
|
13969
|
+
}
|
|
13934
13970
|
return out;
|
|
13935
13971
|
}
|
|
13936
13972
|
|
|
@@ -13947,7 +13983,11 @@ function finParsedInstr() {
|
|
|
13947
13983
|
startBalance: trade.startBalance != null ? trade.startBalance : mgr.startBalance,
|
|
13948
13984
|
dailyLossPct: trade.dailyLossPct != null ? trade.dailyLossPct : mgr.dailyLossPct,
|
|
13949
13985
|
},
|
|
13950
|
-
manage: {
|
|
13986
|
+
manage: {
|
|
13987
|
+
partial: mgr.partial || trade.partial,
|
|
13988
|
+
/* YÖNETİM KURALI: zararda kapatma yasağı iki nottan birinde varsa geçerli */
|
|
13989
|
+
noLossClose: !!(mgr.noLossClose || trade.noLossClose),
|
|
13990
|
+
},
|
|
13951
13991
|
};
|
|
13952
13992
|
}
|
|
13953
13993
|
|
|
@@ -13960,7 +14000,8 @@ function finInstrSummary(ins) {
|
|
|
13960
14000
|
if (ins.entry.martingale != null) p.push(`martingale ×${ins.entry.martingale}`);
|
|
13961
14001
|
if (ins.entry.startBalance != null) p.push(`gün başı ${ins.entry.startBalance}`);
|
|
13962
14002
|
if (ins.entry.dailyLossPct != null) p.push(`günlük zarar limiti %${ins.entry.dailyLossPct}`);
|
|
13963
|
-
if (ins.manage.partial) p.push(`kısmi %${ins.manage.partial.pct} @${ins.manage.partial.atR}R`);
|
|
14003
|
+
if (ins.manage.partial) p.push(`kısmi %${ins.manage.partial.pct} @${ins.manage.partial.atR}R (yalnız kârda)`);
|
|
14004
|
+
if (ins.manage.noLossClose) p.push('zararda kapatma YOK');
|
|
13964
14005
|
try {
|
|
13965
14006
|
const f = finCfg();
|
|
13966
14007
|
if (Number(f.maxPositionsNote) > 0) p.push(`maks ${f.maxPositionsNote} pozisyon`);
|
|
@@ -14151,8 +14192,10 @@ async function finTsManageOpen(sidS, agent, sym, pos, mkt, ans, qi, lines) {
|
|
|
14151
14192
|
const pct = par && par.p >= FIN_TS_CONFIRM_P && par.p - par.second >= FIN_TS_MARGIN_P
|
|
14152
14193
|
? ({ yuzde25: 25, yuzde50: 50, yuzde75: 75 }[String(par.choice)] || 0)
|
|
14153
14194
|
: 0;
|
|
14154
|
-
if (pct > 0 && !partialDone) {
|
|
14155
|
-
|
|
14195
|
+
if (pct > 0 && profitDist > 0 && !partialDone) {
|
|
14196
|
+
/* YALNIZ KÂRDA: sahip kuralı "kısmi kapatma sadece kardaysa" — zararda
|
|
14197
|
+
kısmi kapatma (partial_sl) UYGULANMAZ; zarar kesme kararı SL'ye aittir. */
|
|
14198
|
+
const kind = 'partial_tp';
|
|
14156
14199
|
let r = null;
|
|
14157
14200
|
try {
|
|
14158
14201
|
r = await financetools.handlers.mt5_close(
|
|
@@ -14160,7 +14203,7 @@ async function finTsManageOpen(sidS, agent, sym, pos, mkt, ans, qi, lines) {
|
|
|
14160
14203
|
ticket: Number(pos.ticket),
|
|
14161
14204
|
percent: pct,
|
|
14162
14205
|
kind,
|
|
14163
|
-
reason: `TypeSafe: kısmi %${pct} p=${par.p.toFixed(2)} (
|
|
14206
|
+
reason: `TypeSafe: kısmi %${pct} p=${par.p.toFixed(2)} (kâr al)`,
|
|
14164
14207
|
},
|
|
14165
14208
|
{ sessionId: sidS }
|
|
14166
14209
|
);
|
|
@@ -14171,12 +14214,14 @@ async function finTsManageOpen(sidS, agent, sym, pos, mkt, ans, qi, lines) {
|
|
|
14171
14214
|
if (st) { st.partial = true; finWatchSave(); }
|
|
14172
14215
|
if (agent) { agent.tsPartials = agent.tsPartials || new Set(); agent.tsPartials.add(String(pos.ticket)); }
|
|
14173
14216
|
lines.push(
|
|
14174
|
-
`- ${sym} #${pos.ticket}: KISMİ %${pct}
|
|
14217
|
+
`- ${sym} #${pos.ticket}: KISMİ %${pct} TP ✓` +
|
|
14175
14218
|
` (p=${par.p.toFixed(2)}${r.remaining != null ? ', kalan ' + r.remaining + ' lot' : ''})`
|
|
14176
14219
|
);
|
|
14177
14220
|
} else {
|
|
14178
14221
|
lines.push(`- ${sym} #${pos.ticket}: kısmi %${pct} reddedildi — ${(r && r.error) || 'hata'}`);
|
|
14179
14222
|
}
|
|
14223
|
+
} else if (pct > 0 && profitDist <= 0) {
|
|
14224
|
+
lines.push(`- ${sym} #${pos.ticket}: kısmi atlandı — kârda değil (talimat: sadece kârda)`);
|
|
14180
14225
|
} else if (pct > 0 && partialDone) {
|
|
14181
14226
|
lines.push(`- ${sym} #${pos.ticket}: kısmi atlandı — daha önce alındı`);
|
|
14182
14227
|
}
|
|
@@ -14459,6 +14504,12 @@ async function finPosManagerRound(positions, account) {
|
|
|
14459
14504
|
piyasa: {},
|
|
14460
14505
|
alarmlar: (financeState.alerts || []).slice(0, 8).map((a) => ({ sembol: a.symbol, yon: a.direction, fiyat: a.price, mod: a.once ? 'tek' : 'tekrarlı' })),
|
|
14461
14506
|
sahip_talimati: String(f.posManagerNote || '').slice(0, 1500) || '(yok — genel disiplin: kârı koru, zararı sınırla, SL/TP aktif yönet)',
|
|
14507
|
+
/* TRADE TALİMATI da yöneticiye görünür: iki kartın kuralları çelişmesin */
|
|
14508
|
+
trader_talimati: finTsStrategyText() ? String(finTsStrategyText()).slice(0, 1000) : '',
|
|
14509
|
+
/* KOD KURALI ÖZETİ: Jev bunları ihlal eden seçim yapmasın */
|
|
14510
|
+
kapatma_kurali: ins.manage.noLossClose
|
|
14511
|
+
? 'ZARARDA KAPATMA YOK (kod uygular): zarardaki pozisyonun kapatma kararı reddedilir — SL/TP kapatması serbest; kısmi kapatma YALNIZ kârda'
|
|
14512
|
+
: 'zararda kapatma serbest',
|
|
14462
14513
|
talimat_ayarlari: instrTxt || '(sayısal kural yok)',
|
|
14463
14514
|
gun_durumu: (() => {
|
|
14464
14515
|
try {
|
|
@@ -14526,7 +14577,16 @@ async function finPosManagerRound(positions, account) {
|
|
|
14526
14577
|
const pp = positions[i];
|
|
14527
14578
|
const sym = String(pp.symbol || '').toUpperCase();
|
|
14528
14579
|
const ex = finTsNoul(ans, 'kapat_' + i);
|
|
14529
|
-
|
|
14580
|
+
const psNow = finTsPosState(pp);
|
|
14581
|
+
/* ZARARDA KAPATMA YASAĞI (talimat — KOD uygular): zarardaki pozisyonun
|
|
14582
|
+
kapatma kararı REDDEDİLİR. SL/TP kapatması bundan etkilenmez. */
|
|
14583
|
+
const inLoss = Number(pp.profit) < 0 || (psNow.kz_r != null && psNow.kz_r < 0);
|
|
14584
|
+
if (ex != null && ex >= FIN_TS_EXIT_P && ins.manage.noLossClose && inLoss) {
|
|
14585
|
+
lines.push(
|
|
14586
|
+
`- ${sym} #${pp.ticket}: KAPATILMADI — talimat "zararda kapatma" ` +
|
|
14587
|
+
`(K/Z ${Math.round((Number(pp.profit) || 0) * 100) / 100}${psNow.kz_r != null ? ' · ' + psNow.kz_r + 'R' : ''})`
|
|
14588
|
+
);
|
|
14589
|
+
} else if (ex != null && ex >= FIN_TS_EXIT_P) {
|
|
14530
14590
|
let r = null;
|
|
14531
14591
|
try {
|
|
14532
14592
|
r = await financetools.handlers.mt5_close(
|
|
@@ -14538,9 +14598,9 @@ async function finPosManagerRound(positions, account) {
|
|
|
14538
14598
|
}
|
|
14539
14599
|
lines.push(`- ${sym} #${pp.ticket}: KAPAT (p=${ex.toFixed(2)}) ${r && r.ok ? '✓ kapatıldı' : '✗ ' + ((r && r.error) || 'hata')}`);
|
|
14540
14600
|
continue;
|
|
14601
|
+
} else {
|
|
14602
|
+
lines.push(`- ${sym} #${pp.ticket}: açık (kapat=${ex == null ? 'yanıt yok' : ex.toFixed(2)} < ${FIN_TS_EXIT_P}) · ${psNow.kz_r == null ? 'kâr ?' : 'kâr ' + psNow.kz_r + 'R'}`);
|
|
14541
14603
|
}
|
|
14542
|
-
const psNow = finTsPosState(pp);
|
|
14543
|
-
lines.push(`- ${sym} #${pp.ticket}: açık (kapat=${ex == null ? 'yanıt yok' : ex.toFixed(2)} < ${FIN_TS_EXIT_P}) · ${psNow.kz_r == null ? 'kâr ?' : 'kâr ' + psNow.kz_r + 'R'}`);
|
|
14544
14604
|
/* TALİMAT KISMİ KURALI (kod): "+atR'de %pct kapat" → otomatik uygula */
|
|
14545
14605
|
const rule = ins.manage.partial;
|
|
14546
14606
|
if (rule) {
|
|
@@ -14889,7 +14949,13 @@ async function finTypeSafeRound(sid, agent) {
|
|
|
14889
14949
|
lines.push(`- ${sym}: pozisyon açık #${pos.ticket} — yönetim Pozisyon Yöneticisi'nde (${finPosMgrSec()} sn Jev turu)`);
|
|
14890
14950
|
} else {
|
|
14891
14951
|
const ex = finTsNoul(ans, 'kapat_' + i);
|
|
14892
|
-
|
|
14952
|
+
const psT = finTsPosState(pos);
|
|
14953
|
+
const inLossT = Number(pos.profit) < 0 || (psT.kz_r != null && psT.kz_r < 0);
|
|
14954
|
+
if (ex != null && ex >= FIN_TS_EXIT_P && ins.manage.noLossClose && inLossT) {
|
|
14955
|
+
lines.push(`- ${sym}: kapat REDDEDİLDİ — talimat "zararda kapatma" (K/Z ${Math.round((Number(pos.profit) || 0) * 100) / 100})`);
|
|
14956
|
+
/* yönetim kararları (kısmi/SL) yine değerlendirilir */
|
|
14957
|
+
try { await finTsManageOpen(sidS, agent, sym, pos, market[sym], ans, i, lines); } catch {}
|
|
14958
|
+
} else if (ex != null && ex >= FIN_TS_EXIT_P) {
|
|
14893
14959
|
const r = await financetools.handlers.mt5_close(
|
|
14894
14960
|
{ ticket: Number(pos.ticket), reason: `TypeSafe: kapat p=${ex.toFixed(2)}` },
|
|
14895
14961
|
{ sessionId: sidS }
|
|
@@ -14999,7 +15065,10 @@ async function finTypeSafeRound(sid, agent) {
|
|
|
14999
15065
|
martNote = ` · martingale ×${ins.entry.martingale}^${pow} (${pow}. ardışık kayıp sonrası)`;
|
|
15000
15066
|
}
|
|
15001
15067
|
}
|
|
15002
|
-
|
|
15068
|
+
/* MARTİNGALE/LOT ÇARPANI: riskPct TABAN kalır; çarpan LOTA uygulanır
|
|
15069
|
+
(araç: risk lotu × sizeMult, broker adımı + maxLot kelepçesi).
|
|
15070
|
+
Gösterim ve karar kaydı için efektif risk yüzdesi hesaplanır. */
|
|
15071
|
+
const effRiskPct = Math.max(0.1, Math.min(30, Math.round(riskPct * sizeMult * 100) / 100));
|
|
15003
15072
|
const riskNote = ins.entry.riskPct != null ? ' · TALİMAT risk %' + ins.entry.riskPct : '';
|
|
15004
15073
|
const emirLabel =
|
|
15005
15074
|
orderType === 'market' ? 'MARKET' :
|
|
@@ -15015,6 +15084,7 @@ async function finTypeSafeRound(sid, agent) {
|
|
|
15015
15084
|
sl,
|
|
15016
15085
|
tp,
|
|
15017
15086
|
riskPct,
|
|
15087
|
+
sizeMult,
|
|
15018
15088
|
timeframe: market[sym].tf,
|
|
15019
15089
|
comment: 'TS',
|
|
15020
15090
|
reason:
|
|
@@ -15051,11 +15121,11 @@ async function finTypeSafeRound(sid, agent) {
|
|
|
15051
15121
|
emaAlign: ind.ema50 != null && ind.ema200 != null ? (ind.ema50 > ind.ema200) === (c.choice === 'buy') : null,
|
|
15052
15122
|
rsi: ind.rsi14,
|
|
15053
15123
|
atrPct: atr > 0 && entryRef > 0 ? atr / entryRef : null,
|
|
15054
|
-
riskPct,
|
|
15124
|
+
riskPct: effRiskPct,
|
|
15055
15125
|
orderType,
|
|
15056
15126
|
});
|
|
15057
15127
|
} catch {}
|
|
15058
|
-
const riskTxt = `risk %${
|
|
15128
|
+
const riskTxt = `risk %${effRiskPct}${ins.entry.riskPct == null && cal.riskMult !== 1 ? ` ×${cal.riskMult}` : ''}${riskNote}${martNote}`;
|
|
15059
15129
|
lines.push(
|
|
15060
15130
|
(orderType === 'market'
|
|
15061
15131
|
? `- ${sym}: ⚡ MARKET ${c.choice.toUpperCase()} açıldı (lot ${r.opened && r.opened.volume}, SL ${sl}, TP ${tp}, ${riskTxt})`
|
package/src/renderer/index.html
CHANGED
|
@@ -200,7 +200,7 @@
|
|
|
200
200
|
<div class="fin-field">
|
|
201
201
|
<span>Disiplin <i class="fin-hint">— kodla zorlanır; 0 = kural kapalı</i></span>
|
|
202
202
|
<div class="fin-grid2">
|
|
203
|
-
<div class="fin-field"><span>Günlük max işlem</span><input id="finMaxTradesDay" type="number" min="0" max="50" step="1" title="
|
|
203
|
+
<div class="fin-field"><span>Günlük max işlem (kapalı)</span><input id="finMaxTradesDay" type="number" min="0" max="50" step="1" disabled title="Kaldırıldı: günlük işlem limiti yalnız talimata "günde en fazla N işlem" yazarsan uygulanır — varsayılan sınırsız" /></div>
|
|
204
204
|
<div class="fin-field"><span>Kayıp serisi limiti</span><input id="finLossStreak" type="number" min="0" max="10" step="1" title="Üst üste bu kadar kayıptan sonra yeni işlem kilidi (0 = kapalı)" /></div>
|
|
205
205
|
<div class="fin-field"><span>Seri molası (dk)</span><input id="finLossStreakPause" type="number" min="0" max="1440" step="5" title="Kayıp serisi limitine ulaşınca kaç dakika yeni işlem açılmaz" /></div>
|
|
206
206
|
<div class="fin-field"><span>Re-entry bekleme (dk)</span><input id="finReentry" type="number" min="0" max="1440" step="5" title="Aynı sembolda bir işlem kapandıktan sonra yeni giriş için beklenecek süre — VARSAYILAN KAPALI (0 = kapalı)" /></div>
|
package/src/renderer/renderer.js
CHANGED
|
@@ -10949,9 +10949,13 @@ function finHelpHtml(which) {
|
|
|
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
|
-
'<b>Kod otomatik uygular.</b>
|
|
10952
|
+
'<b>Kod otomatik uygular.</b> "aynı anda/en fazla pozisyon" = eşzamanlı tavan (pozisyon + bekleyen emir). <b>Günlük işlem limiti kaldırıldı (varsayılan sınırsız)</b>; yalnız "günde en fazla N işlem" yazarsan o gün için devreye girer — Ayarlar\'daki günlük limit alanı artık kullanılmıyor.'],
|
|
10953
10953
|
['<code>sembol başına 5 işlem</code><code>aynı sembolde en fazla 3 pozisyon</code>',
|
|
10954
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.'],
|
|
10955
|
+
['<code>zararda işlem kapatma</code><code>sadece karda kapat</code><code>kârda değilse kapatma</code>',
|
|
10956
|
+
'<b>Kod otomatik uygular.</b> Zarardaki pozisyonun kapatma kararı REDDEDİLİR — SL/TP çalışmaya devam eder (stop = martingale serisinin parçası). Kârdaki/başabaştaki pozisyon normal kapatılır.'],
|
|
10957
|
+
['<code>0.5R karda yarısını kapat</code><code>partial close ile yarısını kapat</code>',
|
|
10958
|
+
'<b>Kod otomatik uygular.</b> Kâr +0.5R\'ye ulaşınca pozisyonun %50\'si kapatılır — <b>yalnız kârdayken</b> uygulanır (zararda kısmi stop yapılmaz).'],
|
|
10955
10959
|
];
|
|
10956
10960
|
const example = posmgr
|
|
10957
10961
|
? `1- 1R'de %50 kısmi kapat\n2- kâr 2R'ye gelince kalanı kapat\n3- zarar -0.5R'yi geçerse kes`
|