beast-agent 2.73.0 → 2.75.0
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 +2 -1
- package/src/main.js +305 -21
- package/src/renderer/index.html +14 -4
- package/src/renderer/renderer.js +92 -0
- package/src/renderer/style.css +59 -0
package/package.json
CHANGED
|
@@ -802,7 +802,8 @@ const handlers = {
|
|
|
802
802
|
}
|
|
803
803
|
const pos = await bcall('positions', {}, 8000);
|
|
804
804
|
const list = (pos && pos.positions) || [];
|
|
805
|
-
|
|
805
|
+
/* EFEKTİF TAVAN: talimattaki "en fazla N işlem/pozisyon" ayarı ezer */
|
|
806
|
+
const maxPos = Number(cfg.maxPositionsNote) > 0 ? Number(cfg.maxPositionsNote) : Number(cfg.maxPositions) || 3;
|
|
806
807
|
if (list.length >= maxPos) {
|
|
807
808
|
return { ok: false, error: `max eşzamanlı pozisyon dolu (${list.length}/${maxPos}) — önce bir pozisyon kapat` };
|
|
808
809
|
}
|
package/src/main.js
CHANGED
|
@@ -10018,6 +10018,27 @@ function finCfg() {
|
|
|
10018
10018
|
try { saveSettings(); } catch {}
|
|
10019
10019
|
}
|
|
10020
10020
|
if (!Number.isFinite(Number(f.maxPerCurrency))) f.maxPerCurrency = 3;
|
|
10021
|
+
/* TALİMATTAN ÜST SINIR: "aynı anda en fazla 10 işlem/pozisyon" → eşzamanlı
|
|
10022
|
+
tavan; "günde en fazla 10 işlem" → günlük işlem tavanı. Ayarı KALICI
|
|
10023
|
+
ezmez: not yalnız talimat metninde durdukça geçerlidir (0 = not yok). */
|
|
10024
|
+
f.maxPositionsNote = 0;
|
|
10025
|
+
f.maxTradesPerDayNote = 0;
|
|
10026
|
+
try {
|
|
10027
|
+
const txt = (String(f.strategy || '') + '\n' + String(f.posManagerNote || '')).toLowerCase();
|
|
10028
|
+
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;
|
|
10029
|
+
let mm;
|
|
10030
|
+
while ((mm = re.exec(txt))) {
|
|
10031
|
+
const n = Number(mm[2]);
|
|
10032
|
+
if (!(n >= 1 && n <= 20)) continue;
|
|
10033
|
+
/* GÜNLÜK ayrımı: "günde/günlük/gün içinde ... en fazla N işlem" — cümle
|
|
10034
|
+
sınırı (nokta/virgül) aşılmaz; "günlük zarar %3, maks 4 pozisyon"
|
|
10035
|
+
ifadesindeki "günlük" günlük tavana YAZILMAZ, eşzamanlı sayılır. */
|
|
10036
|
+
const before = txt.slice(0, mm.index);
|
|
10037
|
+
const daily = /(?:g[üu]nde|g[üu]nl[üu]k|g[üu]n\s*i[çc]inde)[^.;,\n]{0,14}$/.test(before);
|
|
10038
|
+
if (daily) f.maxTradesPerDayNote = n;
|
|
10039
|
+
else if (!f.maxPositionsNote) f.maxPositionsNote = n; /* eşzamanlı tavan */
|
|
10040
|
+
}
|
|
10041
|
+
} catch {}
|
|
10021
10042
|
/* SHADOW MOD: emir gönderilmez — kararlar gerekçesiyle günlüğe yazılır */
|
|
10022
10043
|
if (typeof f.shadowMode !== 'boolean') f.shadowMode = false;
|
|
10023
10044
|
/* POZİSYON YÖNETİCİSİ: açık pozisyonları 5 sn'de bir Jev ile yöneten ayrı
|
|
@@ -10379,12 +10400,31 @@ function finTeamDigest() {
|
|
|
10379
10400
|
/* KODLA DİSİPLİN kancası: financetools işlem öncesi bunu çağırır. */
|
|
10380
10401
|
function finDisciplineError(side, symbol, positions) {
|
|
10381
10402
|
try {
|
|
10382
|
-
|
|
10403
|
+
const cfg = finCfg();
|
|
10404
|
+
/* TALİMAT: "günde en fazla N işlem" → günlük işlem tavanını ezer */
|
|
10405
|
+
if (Number(cfg.maxTradesPerDayNote) > 0) {
|
|
10406
|
+
return finrisk.disciplineError(
|
|
10407
|
+
finJournalTail(400),
|
|
10408
|
+
Date.now(),
|
|
10409
|
+
{ ...cfg, maxTradesPerDay: Number(cfg.maxTradesPerDayNote) },
|
|
10410
|
+
side,
|
|
10411
|
+
symbol,
|
|
10412
|
+
positions
|
|
10413
|
+
);
|
|
10414
|
+
}
|
|
10415
|
+
return finrisk.disciplineError(finJournalTail(400), Date.now(), cfg, side, symbol, positions);
|
|
10383
10416
|
} catch {
|
|
10384
10417
|
return null;
|
|
10385
10418
|
}
|
|
10386
10419
|
}
|
|
10387
10420
|
|
|
10421
|
+
/* EFEKTİF POZİSYON TAVANI: talimattaki "en fazla N işlem/pozisyon" ayarı ezer */
|
|
10422
|
+
function finPosCap(f) {
|
|
10423
|
+
const note = Number(f && f.maxPositionsNote) > 0 ? Number(f.maxPositionsNote) : 0;
|
|
10424
|
+
const base = Number(f && f.maxPositions) || 3;
|
|
10425
|
+
return Math.max(1, Math.min(20, note > 0 ? note : base));
|
|
10426
|
+
}
|
|
10427
|
+
|
|
10388
10428
|
/* ---------- MAE/MFE: pozisyonun gördüğü en iyi/en kötü seviye ---------- */
|
|
10389
10429
|
function finExcLoad() {
|
|
10390
10430
|
try {
|
|
@@ -10779,17 +10819,36 @@ function finEquitySample(account) {
|
|
|
10779
10819
|
function finDailyLossCheck(point) {
|
|
10780
10820
|
const cfg = finCfg();
|
|
10781
10821
|
const day = finstats.dayKey(point.at);
|
|
10822
|
+
/* TALİMAT: "gün başı bakiye" yazıldıysa taban O'dur; "günlük zarar %X"
|
|
10823
|
+
yazıldıysa limit ayarın yerine talimattan gelir (kullanıcı her gün günceller). */
|
|
10824
|
+
let startBal = 0;
|
|
10825
|
+
let limitPct = Number(cfg.maxDailyLossPct) || 0;
|
|
10826
|
+
try {
|
|
10827
|
+
const ins = finParsedInstr();
|
|
10828
|
+
if (Number(ins.entry.startBalance) > 0) startBal = Number(ins.entry.startBalance);
|
|
10829
|
+
if (Number(ins.entry.dailyLossPct) > 0) limitPct = Number(ins.entry.dailyLossPct);
|
|
10830
|
+
} catch {}
|
|
10782
10831
|
let ds = financeState.dayStart;
|
|
10783
10832
|
if (!ds || ds.day !== day) {
|
|
10784
|
-
financeState.dayStart = ds = {
|
|
10833
|
+
financeState.dayStart = ds = {
|
|
10834
|
+
day,
|
|
10835
|
+
equity: startBal > 0 ? startBal : Number(point.balance) > 0 ? Number(point.balance) : point.equity,
|
|
10836
|
+
warned: false,
|
|
10837
|
+
acted: false,
|
|
10838
|
+
fromNote: startBal > 0,
|
|
10839
|
+
};
|
|
10785
10840
|
}
|
|
10786
|
-
if (
|
|
10841
|
+
if (startBal > 0) {
|
|
10842
|
+
ds.equity = startBal;
|
|
10843
|
+
ds.fromNote = true;
|
|
10844
|
+
}
|
|
10845
|
+
if (ds.warned || !(limitPct > 0) || !(ds.equity > 0)) return;
|
|
10787
10846
|
const dd = ((ds.equity - point.equity) / ds.equity) * 100;
|
|
10788
|
-
if (dd >=
|
|
10847
|
+
if (dd >= limitPct) {
|
|
10789
10848
|
ds.warned = true;
|
|
10790
10849
|
const action = String(cfg.dailyLossAction || 'stop');
|
|
10791
10850
|
const tail = action === 'flatten' ? ' — ajanlar durduruldu, pozisyonlar kapatılıyor' : action === 'stop' ? ' — ajanlar durduruldu' : '';
|
|
10792
|
-
const line = `⚠️ Günlük kayıp %${dd.toFixed(2)} (limit %${
|
|
10851
|
+
const line = `⚠️ Günlük kayıp %${dd.toFixed(2)} (limit %${limitPct}${ds.fromNote ? ' · talimat gün başı bakiye' : ''})${tail}`;
|
|
10793
10852
|
financeLog('[risk] ' + line);
|
|
10794
10853
|
financeNotify(line, 'drawdown');
|
|
10795
10854
|
finJournal({ kind: 'drawdown', pct: Math.round(dd * 100) / 100, action });
|
|
@@ -13698,6 +13757,123 @@ function finTsStrategyText() {
|
|
|
13698
13757
|
}
|
|
13699
13758
|
}
|
|
13700
13759
|
|
|
13760
|
+
/* ---- TALİMAT AYRIŞTIRICI ----
|
|
13761
|
+
Trade Ajanı + Pozisyon Yöneticisi notlarındaki SAYISAL kuralları koda çevirir:
|
|
13762
|
+
"risk %2" → giriş riski %2
|
|
13763
|
+
"lot x1.5" / "poz başı lot 1.5" / "lotu 2 kat" → lot çarpanı
|
|
13764
|
+
"martingale" / "martingale 1.5" → kayıp serisinde lot katlama (varsayılan ×2)
|
|
13765
|
+
"1R'de %50 kısmi kapat" / "%50 1R" / "kısmi %50" → otomatik kısmi close kuralı
|
|
13766
|
+
Saf metin ayrıştırma; uygulama ilgili turda kodla yapılır (LLM yok). */
|
|
13767
|
+
function finInstrNum(v) {
|
|
13768
|
+
const n = Number(String(v == null ? '' : v).replace(',', '.'));
|
|
13769
|
+
return isFinite(n) ? n : null;
|
|
13770
|
+
}
|
|
13771
|
+
|
|
13772
|
+
/* Para değeri: "10.000" / "10,000" → 10000; "10000,50" / "10000.50" → 10000.5 */
|
|
13773
|
+
function finInstrMoney(v) {
|
|
13774
|
+
const s = String(v == null ? '' : v).replace(/\s+/g, '');
|
|
13775
|
+
if (!s) return null;
|
|
13776
|
+
/* "5.000,50" / "5,000.50" → 5000.50 ; "10.000" → 10000 ; "10000,50" → 10000.5 */
|
|
13777
|
+
const m = s.match(/^(\d{1,3}(?:[.,]\d{3})+)(?:[.,](\d{1,2}))?$/);
|
|
13778
|
+
if (m) {
|
|
13779
|
+
const n = Number(m[1].replace(/[.,]/g, '') + (m[2] ? '.' + m[2] : ''));
|
|
13780
|
+
return isFinite(n) && n > 0 ? n : null;
|
|
13781
|
+
}
|
|
13782
|
+
const n2 = Number(s.replace(',', '.'));
|
|
13783
|
+
return isFinite(n2) && n2 > 0 ? n2 : null;
|
|
13784
|
+
}
|
|
13785
|
+
|
|
13786
|
+
function finParseInstructions(text) {
|
|
13787
|
+
const low = String(text || '').toLowerCase();
|
|
13788
|
+
const out = { riskPct: null, lotMult: null, martingale: null, partial: null, startBalance: null, dailyLossPct: null };
|
|
13789
|
+
if (!low.trim()) return out;
|
|
13790
|
+
/* "risk %2", "%2 risk", "risk yüzde 2", "riski 2 yap" → 2 (ilk sayı) */
|
|
13791
|
+
let m = low.match(
|
|
13792
|
+
/(?:risk\s*%\s*(\d+(?:[.,]\d+)?))|(?:%\s*(\d+(?:[.,]\d+)?)\s*risk)|(?:risk[^0-9]{0,14}(\d+(?:[.,]\d+)?))/
|
|
13793
|
+
);
|
|
13794
|
+
if (m) out.riskPct = finInstrNum(m[1] || m[2] || m[3]);
|
|
13795
|
+
if (out.riskPct != null) out.riskPct = Math.max(0.1, Math.min(10, out.riskPct));
|
|
13796
|
+
/* GÜN BAŞLANGIÇ BAKİYESİ (kullanıcı her gün talimata yazar): "başlangıç bakiye 10.000",
|
|
13797
|
+
"gün başı: 10000", "starting balance 10000" */
|
|
13798
|
+
m = low.match(/(?:ba[şs]lang[ıi][çc]\s*bakiye|g[üu]n\s*ba[şs][ıi](?:\s*bakiye)?|g[üu]nl[üu]k\s*ba[şs]lang[ıi][çc](?:\s*bakiye)?|starting\s*balance|start\s*balance)[^0-9]{0,14}(\d[\d.,\s]*)/);
|
|
13799
|
+
if (m) out.startBalance = finInstrMoney(m[1]);
|
|
13800
|
+
/* GÜNLÜK ZARAR LİMİTİ: "günlük zarar %3", "max günlük kayıp 3", "daily loss %3" */
|
|
13801
|
+
m = low.match(/(?:g[üu]nl[üu]k\s*(?:max(?:imum)?\s*)?(?:zarar|kay[ıi]p)|max\s*g[üu]nl[üu]k\s*kay[ıi]p|g[üu]nl[üu]k\s*limit|daily\s*(?:max\s*)?loss)[^0-9%]{0,12}%?\s*(\d+(?:[.,]\d+)?)/);
|
|
13802
|
+
if (m) {
|
|
13803
|
+
const v = finInstrNum(m[1]);
|
|
13804
|
+
if (v != null && v > 0) out.dailyLossPct = Math.max(0.1, Math.min(50, v));
|
|
13805
|
+
}
|
|
13806
|
+
m = low.match(/(?:lot\s*(?:çarpan[ıi]?|carpan[ıi]?)?\s*(?:x|×|\*)\s*(\d+(?:[.,]\d+)?))|(?:poz\s*ba[şs][ıi]\s*lot[^0-9]{0,12}(\d+(?:[.,]\d+)?))|(?:lot[^0-9]{0,12}(\d+(?:[.,]\d+)?)\s*kat)/);
|
|
13807
|
+
if (m) out.lotMult = finInstrNum(m[1] || m[2] || m[3]);
|
|
13808
|
+
if (out.lotMult != null) out.lotMult = Math.max(1, Math.min(5, out.lotMult));
|
|
13809
|
+
if (/martingale|mart[ıi]ngale/.test(low)) {
|
|
13810
|
+
/* Faktör serbest: "martingale 1.2", "martingale x1.20", "martingale 1,2",
|
|
13811
|
+
"martingale çarpanı 1.2", "1.2x martingale", "1.2 kat martingale".
|
|
13812
|
+
Yalnız bilinen bağlaçlardan sonra sayı okunur — "martingale kullan, 1R..."
|
|
13813
|
+
gibi metinden yanlış sayı kapmaz. Varsayılan ×2 (1.01–5 arası geçerli). */
|
|
13814
|
+
m = low.match(/(?:mart[ıi]ngale\s*(?:x|×|çarpan[ıi]?|carpan[ıi]?|oran[ıi]?|fakt[öo]r[üu]?|kat[ıi]?)?\s*(\d+(?:[.,]\d+)?))|(?:(\d+(?:[.,]\d+)?)\s*(?:x|×|kat[ıi]?)?\s*mart[ıi]ngale)/);
|
|
13815
|
+
const mf = m ? finInstrNum(m[1] || m[2]) : null;
|
|
13816
|
+
out.martingale = Math.max(1.01, Math.min(5, mf != null && mf > 1 ? mf : 2));
|
|
13817
|
+
}
|
|
13818
|
+
/* kısmi kapatma: "1R'de %50" → atR=1, pct=50; "%50 1R" → aynı; "kısmi %50" → atR=1 */
|
|
13819
|
+
m = low.match(/(\d+(?:[.,]\d+)?)\s*r[^%\d]{0,28}%\s*(\d+(?:[.,]\d+)?)/);
|
|
13820
|
+
if (m) out.partial = { atR: finInstrNum(m[1]), pct: finInstrNum(m[2]) };
|
|
13821
|
+
if (!out.partial) {
|
|
13822
|
+
m = low.match(/%\s*(\d+(?:[.,]\d+)?)[^%\d]{0,28}?(\d+(?:[.,]\d+)?)\s*r/);
|
|
13823
|
+
if (m) out.partial = { atR: finInstrNum(m[2]), pct: finInstrNum(m[1]) };
|
|
13824
|
+
}
|
|
13825
|
+
if (!out.partial) {
|
|
13826
|
+
m = low.match(/(?:k[ıi]smi|partial)[^%\d]{0,24}%\s*(\d+(?:[.,]\d+)?)/);
|
|
13827
|
+
if (m) out.partial = { atR: 1, pct: finInstrNum(m[1]) };
|
|
13828
|
+
}
|
|
13829
|
+
if (out.partial) {
|
|
13830
|
+
const p = out.partial;
|
|
13831
|
+
if (!(p.atR > 0)) p.atR = 1;
|
|
13832
|
+
p.atR = Math.min(10, Math.round(p.atR * 100) / 100);
|
|
13833
|
+
if (!(p.pct >= 5 && p.pct <= 90)) out.partial = null;
|
|
13834
|
+
else p.pct = Math.round(p.pct);
|
|
13835
|
+
}
|
|
13836
|
+
return out;
|
|
13837
|
+
}
|
|
13838
|
+
|
|
13839
|
+
/* İki notu birleştir: GİRİŞ kuralları trade notundan, YÖNETİM kuralları
|
|
13840
|
+
pozisyon yöneticisi notundan (yoksa trade notundan) gelir. */
|
|
13841
|
+
function finParsedInstr() {
|
|
13842
|
+
const trade = finParseInstructions(finTsStrategyText());
|
|
13843
|
+
const mgr = finParseInstructions(String(finCfg().posManagerNote || ''));
|
|
13844
|
+
return {
|
|
13845
|
+
entry: {
|
|
13846
|
+
riskPct: trade.riskPct != null ? trade.riskPct : mgr.riskPct,
|
|
13847
|
+
lotMult: trade.lotMult != null ? trade.lotMult : mgr.lotMult,
|
|
13848
|
+
martingale: trade.martingale != null ? trade.martingale : mgr.martingale,
|
|
13849
|
+
startBalance: trade.startBalance != null ? trade.startBalance : mgr.startBalance,
|
|
13850
|
+
dailyLossPct: trade.dailyLossPct != null ? trade.dailyLossPct : mgr.dailyLossPct,
|
|
13851
|
+
},
|
|
13852
|
+
manage: { partial: mgr.partial || trade.partial },
|
|
13853
|
+
};
|
|
13854
|
+
}
|
|
13855
|
+
|
|
13856
|
+
/* Rapor/state için tek satır özet: kod ne uygulayacak */
|
|
13857
|
+
function finInstrSummary(ins) {
|
|
13858
|
+
try {
|
|
13859
|
+
const p = [];
|
|
13860
|
+
if (ins.entry.riskPct != null) p.push(`risk %${ins.entry.riskPct}`);
|
|
13861
|
+
if (ins.entry.lotMult != null) p.push(`lot ×${ins.entry.lotMult}`);
|
|
13862
|
+
if (ins.entry.martingale != null) p.push(`martingale ×${ins.entry.martingale}`);
|
|
13863
|
+
if (ins.entry.startBalance != null) p.push(`gün başı ${ins.entry.startBalance}`);
|
|
13864
|
+
if (ins.entry.dailyLossPct != null) p.push(`günlük zarar limiti %${ins.entry.dailyLossPct}`);
|
|
13865
|
+
if (ins.manage.partial) p.push(`kısmi %${ins.manage.partial.pct} @${ins.manage.partial.atR}R`);
|
|
13866
|
+
try {
|
|
13867
|
+
const f = finCfg();
|
|
13868
|
+
if (Number(f.maxPositionsNote) > 0) p.push(`maks ${f.maxPositionsNote} pozisyon`);
|
|
13869
|
+
if (Number(f.maxTradesPerDayNote) > 0) p.push(`günde maks ${f.maxTradesPerDayNote} işlem`);
|
|
13870
|
+
} catch {}
|
|
13871
|
+
return p.join(' · ');
|
|
13872
|
+
} catch {
|
|
13873
|
+
return '';
|
|
13874
|
+
}
|
|
13875
|
+
}
|
|
13876
|
+
|
|
13701
13877
|
/* Talimattan ZAMAN DİLİMİ çıkar: "M15", "1m", "1 dk", "4 saat" → M15/M1/H4 */
|
|
13702
13878
|
function finTsStrategyTf() {
|
|
13703
13879
|
const s = String(finTsStrategyText() || '');
|
|
@@ -14079,6 +14255,9 @@ async function finPosManagerRound(positions, account) {
|
|
|
14079
14255
|
pm.rounds = (Number(pm.rounds) || 0) + 1;
|
|
14080
14256
|
pm.lastAt = Date.now();
|
|
14081
14257
|
const f = finCfg();
|
|
14258
|
+
/* TALİMAT: kısmi close kuralı varsa KOD uygular (Jev'e sorulmaz) */
|
|
14259
|
+
const ins = finParsedInstr();
|
|
14260
|
+
const instrTxt = finInstrSummary(ins);
|
|
14082
14261
|
const lines = [];
|
|
14083
14262
|
try {
|
|
14084
14263
|
/* pozisyon sembolleri: piyasa + gösterge (tur başına tek Jev çağrısı) */
|
|
@@ -14106,6 +14285,18 @@ async function finPosManagerRound(positions, account) {
|
|
|
14106
14285
|
piyasa: {},
|
|
14107
14286
|
alarmlar: (financeState.alerts || []).slice(0, 8).map((a) => ({ sembol: a.symbol, yon: a.direction, fiyat: a.price, mod: a.once ? 'tek' : 'tekrarlı' })),
|
|
14108
14287
|
sahip_talimati: String(f.posManagerNote || '').slice(0, 1500) || '(yok — genel disiplin: kârı koru, zararı sınırla, SL/TP aktif yönet)',
|
|
14288
|
+
talimat_ayarlari: instrTxt || '(sayısal kural yok)',
|
|
14289
|
+
gun_durumu: (() => {
|
|
14290
|
+
try {
|
|
14291
|
+
const sb = Number(ins.entry.startBalance) || 0;
|
|
14292
|
+
const eqNow = Number(account && account.equity) || 0;
|
|
14293
|
+
if (!(sb > 0) || !(eqNow > 0)) return '';
|
|
14294
|
+
const pct = Math.round(((eqNow - sb) / sb) * 10000) / 100;
|
|
14295
|
+
return `Gün başı ${sb} → %${pct >= 0 ? '+' : ''}${pct} (${pct >= 0 ? 'KÂR' : 'ZARAR'})`;
|
|
14296
|
+
} catch {
|
|
14297
|
+
return '';
|
|
14298
|
+
}
|
|
14299
|
+
})(),
|
|
14109
14300
|
ekip_yanitlari: finTsFeedText(6),
|
|
14110
14301
|
};
|
|
14111
14302
|
for (const sym of syms) {
|
|
@@ -14131,16 +14322,19 @@ async function finPosManagerRound(positions, account) {
|
|
|
14131
14322
|
instructions: `${sym} açık pozisyon #${pp.ticket} (${ps.yon}, kâr ${Number(pp.profit) || 0}, ${kzTxt}${bestTxt}, ${slTxt}) ŞİMDİ kapatılmalı mı? Sahip talimatını, kârı korumayı ve momentum dönüşünü değerlendir.`,
|
|
14132
14323
|
criteria: { true: 'Kapat — risk/kâr koruma', false: 'Açık kalsın — tez sürüyor' },
|
|
14133
14324
|
};
|
|
14134
|
-
|
|
14135
|
-
|
|
14136
|
-
|
|
14137
|
-
|
|
14138
|
-
|
|
14139
|
-
|
|
14140
|
-
|
|
14141
|
-
|
|
14142
|
-
|
|
14143
|
-
|
|
14325
|
+
/* Talimatta SAYISAL kısmi kuralı varsa Jev'e sorulmaz — kodu uygular */
|
|
14326
|
+
if (!ins.manage.partial) {
|
|
14327
|
+
questions['kismi_' + i] = {
|
|
14328
|
+
type: 'choice',
|
|
14329
|
+
instructions: `${sym} #${pp.ticket} (${kzTxt}${bestTxt}${ps.be ? ' · SL takipte' : ''}) için ŞİMDİ kısmi kapatma uygun mu?${ps.kismi_alindi ? ' Bu pozisyonda kısmi kapatma ZATEN yapıldı — yok seç.' : ' Sahip talimatını ve kâr realize etmeyi değerlendir.'}`,
|
|
14330
|
+
criteria: {
|
|
14331
|
+
yok: 'Kısmi kapatma yok — pozisyon tam kalsın',
|
|
14332
|
+
yuzde25: 'Pozisyonun %25’i kapatılsın',
|
|
14333
|
+
yuzde50: 'Pozisyonun %50’si kapatılsın',
|
|
14334
|
+
yuzde75: 'Pozisyonun %75’i kapatılsın',
|
|
14335
|
+
},
|
|
14336
|
+
};
|
|
14337
|
+
}
|
|
14144
14338
|
questions['sl_' + i] = {
|
|
14145
14339
|
type: 'choice',
|
|
14146
14340
|
instructions: `${sym} #${pp.ticket} için SL/koruma aksiyonu: ${ps.yon}, giriş ${Number(pp.price_open) || '?'}, şimdi ${ps.fiyat || '?'}, ${slTxt}, ${kzTxt}. Kâr yoksa ve SL varsa 'birak'; SL yoksa 'koru' ile koruma koy.`,
|
|
@@ -14173,12 +14367,39 @@ async function finPosManagerRound(positions, account) {
|
|
|
14173
14367
|
}
|
|
14174
14368
|
const psNow = finTsPosState(pp);
|
|
14175
14369
|
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'}`);
|
|
14370
|
+
/* TALİMAT KISMİ KURALI (kod): "+atR'de %pct kapat" → otomatik uygula */
|
|
14371
|
+
const rule = ins.manage.partial;
|
|
14372
|
+
if (rule) {
|
|
14373
|
+
const stP = financeState.watch.get(String(pp.ticket)) || null;
|
|
14374
|
+
const done = !!(stP && stP.partial) || !!(pm.tsPartials && pm.tsPartials.has(String(pp.ticket)));
|
|
14375
|
+
if (!done && psNow.kz_r != null && psNow.kz_r >= rule.atR) {
|
|
14376
|
+
let rr = null;
|
|
14377
|
+
try {
|
|
14378
|
+
rr = await financetools.handlers.mt5_close(
|
|
14379
|
+
{ ticket: Number(pp.ticket), percent: rule.pct, kind: 'partial_tp', reason: `TypeSafe yönetici: TALİMAT kısmi %${rule.pct} @${rule.atR}R (kâr ${psNow.kz_r}R)` },
|
|
14380
|
+
{ sessionId: FIN_POSMGR_ID }
|
|
14381
|
+
);
|
|
14382
|
+
} catch (e) {
|
|
14383
|
+
rr = { ok: false, error: String((e && e.message) || e) };
|
|
14384
|
+
}
|
|
14385
|
+
if (rr && rr.ok) {
|
|
14386
|
+
if (stP) { stP.partial = true; finWatchSave(); }
|
|
14387
|
+
pm.tsPartials = pm.tsPartials || new Set();
|
|
14388
|
+
pm.tsPartials.add(String(pp.ticket));
|
|
14389
|
+
lines.push(`- ${sym} #${pp.ticket}: ✂️ TALİMAT kısmi %${rule.pct} TP ✓ (${psNow.kz_r}R ≥ ${rule.atR}R${rr.remaining != null ? ', kalan ' + rr.remaining + ' lot' : ''})`);
|
|
14390
|
+
} else {
|
|
14391
|
+
lines.push(`- ${sym} #${pp.ticket}: talimat kısmi reddedildi — ${(rr && rr.error) || 'hata'}`);
|
|
14392
|
+
}
|
|
14393
|
+
}
|
|
14394
|
+
}
|
|
14176
14395
|
try { await finTsManageOpen(FIN_POSMGR_ID, pm, sym, pp, market[sym], ans, i, lines); } catch {}
|
|
14177
14396
|
}
|
|
14178
14397
|
finTsPost(
|
|
14179
14398
|
FIN_POSMGR_ID,
|
|
14180
14399
|
FIN_POSMGR_AGENT,
|
|
14181
|
-
`🛡️ Pozisyon yöneticisi turu #${pm.rounds} (LLM yok — 5 sn):\n` +
|
|
14400
|
+
`🛡️ Pozisyon yöneticisi turu #${pm.rounds} (LLM yok — 5 sn):\n` +
|
|
14401
|
+
(instrTxt ? 'TALİMAT AYARLARI (kod uygular): ' + instrTxt + '\n' : '') +
|
|
14402
|
+
lines.join('\n'),
|
|
14182
14403
|
'yönetim'
|
|
14183
14404
|
);
|
|
14184
14405
|
} catch (e) {
|
|
@@ -14265,6 +14486,25 @@ async function finTypeSafeRound(sid, agent) {
|
|
|
14265
14486
|
const posList = (posR && posR.positions) || [];
|
|
14266
14487
|
/* BEKLEYEN EMİRLER: pozisyon slotunu paylaşır (aşırı birikmeyi önler) */
|
|
14267
14488
|
const pendCount = (ordR && Array.isArray(ordR.orders) ? ordR.orders.length : 0);
|
|
14489
|
+
/* TALİMAT AYARLARI: sayısal kurallar koda çevrildi (risk/lot/martingale/
|
|
14490
|
+
gün başı bakiye/günlük zarar limiti) — state ve giriş kapısı kullanır */
|
|
14491
|
+
const ins = finParsedInstr();
|
|
14492
|
+
/* GÜN BAŞI BAKİYE → günlük K/Z ve limit durumu (hesap anlık değerinden) */
|
|
14493
|
+
let dayPct = null;
|
|
14494
|
+
let dayBlocked = '';
|
|
14495
|
+
try {
|
|
14496
|
+
const sb = Number(ins.entry.startBalance) || 0;
|
|
14497
|
+
const eqNow = Number(account.equity) || 0;
|
|
14498
|
+
const balNow = Number(account.balance) || 0;
|
|
14499
|
+
const refNow = eqNow > 0 ? eqNow : balNow;
|
|
14500
|
+
if (sb > 0 && refNow > 0) {
|
|
14501
|
+
dayPct = Math.round(((refNow - sb) / sb) * 10000) / 100;
|
|
14502
|
+
const lim = Number(ins.entry.dailyLossPct) || 0;
|
|
14503
|
+
if (lim > 0 && dayPct <= -lim) {
|
|
14504
|
+
dayBlocked = `günlük zarar limiti AŞILDI (gün başı ${sb} → ${refNow}, %${dayPct} ≤ -%${lim}) — talimat gereği yeni işlem açılmaz`;
|
|
14505
|
+
}
|
|
14506
|
+
}
|
|
14507
|
+
} catch {}
|
|
14268
14508
|
const market = {};
|
|
14269
14509
|
for (const sym of symbols) {
|
|
14270
14510
|
const tf = finTsPickTf(agent, sym);
|
|
@@ -14305,6 +14545,16 @@ async function finTypeSafeRound(sid, agent) {
|
|
|
14305
14545
|
talimat "zorunlu giriş" içeriyorsa kod eşikleri devre dışı bırakır. */
|
|
14306
14546
|
sahip_talimati: finTsStrategyText() || '(yok — temel teknik okuma)',
|
|
14307
14547
|
talimat_modu: finTsMandatoryEntry() ? 'ZORUNLU GİRİŞ — bu turda işlem açmak zorunlu (bekle yok); yönü sen seç' : '',
|
|
14548
|
+
talimat_ayarlari: finInstrSummary(ins) || '(sayısal kural yok)',
|
|
14549
|
+
/* GÜN BAŞI BAKİYE (talimattan): günlük K/Z — Jev zarar durumunu otomatik görür */
|
|
14550
|
+
gun_baslangic_bakiye: ins.entry.startBalance != null ? ins.entry.startBalance : null,
|
|
14551
|
+
gun_net_yuzde: dayPct,
|
|
14552
|
+
gun_durumu: dayBlocked
|
|
14553
|
+
? dayBlocked
|
|
14554
|
+
: ins.entry.startBalance != null && dayPct != null
|
|
14555
|
+
? `Gün başı ${ins.entry.startBalance} → şimdi %${dayPct >= 0 ? '+' : ''}${dayPct} (${dayPct >= 0 ? 'KÂR' : 'ZARAR'})` +
|
|
14556
|
+
(ins.entry.dailyLossPct != null ? ` · limit -%${ins.entry.dailyLossPct}` : '')
|
|
14557
|
+
: '',
|
|
14308
14558
|
};
|
|
14309
14559
|
for (const sym of symbols) {
|
|
14310
14560
|
const d = market[sym];
|
|
@@ -14329,6 +14579,7 @@ async function finTypeSafeRound(sid, agent) {
|
|
|
14329
14579
|
const talimatZorunlu = finTsMandatoryEntry();
|
|
14330
14580
|
/* Yönetici açıkken açık pozisyon kararları ONA aittir (çift yönetim yok) */
|
|
14331
14581
|
const posManagerOn = f.posManagerEnabled !== false;
|
|
14582
|
+
/* TALİMAT AYARLARI: yukarıda (state kurulmadan) ayrıştırıldı */
|
|
14332
14583
|
symbols.forEach((sym, i) => {
|
|
14333
14584
|
questions['yon_' + i] = {
|
|
14334
14585
|
type: 'choice',
|
|
@@ -14491,8 +14742,17 @@ async function finTypeSafeRound(sid, agent) {
|
|
|
14491
14742
|
continue;
|
|
14492
14743
|
}
|
|
14493
14744
|
}
|
|
14494
|
-
|
|
14495
|
-
|
|
14745
|
+
/* GÜN BAŞI BAKİYE LİMİTİ (talimat): aşıldıysa YENİ İŞLEM AÇILMAZ */
|
|
14746
|
+
if (dayBlocked) {
|
|
14747
|
+
lines.push(`- ${sym}: ${dayBlocked}`);
|
|
14748
|
+
continue;
|
|
14749
|
+
}
|
|
14750
|
+
/* ÇOKLU GİRİŞ: aynı turda birden çok sembol açılabilir — yalnız toplam
|
|
14751
|
+
slot (pozisyon + bekleyen emir + bu turda açılanlar) tavanı korur */
|
|
14752
|
+
const posCap = finPosCap(f);
|
|
14753
|
+
const slotsLeft = posCap - pendCount - posList.length - opened;
|
|
14754
|
+
if (slotsLeft <= 0) {
|
|
14755
|
+
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ı`);
|
|
14496
14756
|
continue;
|
|
14497
14757
|
}
|
|
14498
14758
|
/* GİRİŞ TİPİ + RİSK PROFİLİ (JEV kararı) — seviyeleri KOD hesaplar */
|
|
@@ -14535,8 +14795,29 @@ async function finTypeSafeRound(sid, agent) {
|
|
|
14535
14795
|
}
|
|
14536
14796
|
const sl = rnd(isBuy ? entry - slDist : entry + slDist);
|
|
14537
14797
|
const tp = rnd(isBuy ? entry + tpDist : entry - tpDist);
|
|
14798
|
+
/* RİSK + LOT: talimatta "risk %2" varsa AYNEN uygulanır; yoksa ayar ×
|
|
14799
|
+
kalibrasyon. Lot çarpanı ve MARTİNGALE (kayıp serisi × kat) burada. */
|
|
14538
14800
|
const riskBase = Number(f.riskPerTradePct) > 0 ? Number(f.riskPerTradePct) : 0.5;
|
|
14539
|
-
|
|
14801
|
+
let riskPct = ins.entry.riskPct != null
|
|
14802
|
+
? ins.entry.riskPct
|
|
14803
|
+
: Math.max(0.1, Math.min(2, Math.round(riskBase * cal.riskMult * 100) / 100));
|
|
14804
|
+
let sizeMult = 1;
|
|
14805
|
+
let martNote = '';
|
|
14806
|
+
if (ins.entry.lotMult != null) sizeMult *= ins.entry.lotMult;
|
|
14807
|
+
if (ins.entry.martingale != null) {
|
|
14808
|
+
let streak = 0;
|
|
14809
|
+
try {
|
|
14810
|
+
const le = finLearnLoad().symbols[sym];
|
|
14811
|
+
streak = Number(le && le.stats && le.stats.streak) || 0;
|
|
14812
|
+
} catch {}
|
|
14813
|
+
const pow = Math.min(3, Math.max(0, Math.round(streak)));
|
|
14814
|
+
if (pow > 0) {
|
|
14815
|
+
sizeMult *= Math.pow(ins.entry.martingale, pow);
|
|
14816
|
+
martNote = ` · martingale ×${ins.entry.martingale}^${pow}`;
|
|
14817
|
+
}
|
|
14818
|
+
}
|
|
14819
|
+
if (sizeMult !== 1) riskPct = Math.max(0.1, Math.min(10, Math.round(riskPct * sizeMult * 100) / 100));
|
|
14820
|
+
const riskNote = ins.entry.riskPct != null ? ' · TALİMAT risk %' + ins.entry.riskPct : '';
|
|
14540
14821
|
const emirLabel =
|
|
14541
14822
|
orderType === 'market' ? 'MARKET' :
|
|
14542
14823
|
isBuy && orderType === 'buy_limit' ? 'BUY LIMIT' :
|
|
@@ -14584,10 +14865,11 @@ async function finTypeSafeRound(sid, agent) {
|
|
|
14584
14865
|
orderType,
|
|
14585
14866
|
});
|
|
14586
14867
|
} catch {}
|
|
14868
|
+
const riskTxt = `risk %${riskPct}${ins.entry.riskPct == null && cal.riskMult !== 1 ? ` ×${cal.riskMult}` : ''}${riskNote}${martNote}`;
|
|
14587
14869
|
lines.push(
|
|
14588
14870
|
(orderType === 'market'
|
|
14589
|
-
? `- ${sym}: ⚡ MARKET ${c.choice.toUpperCase()} açıldı (lot ${r.opened && r.opened.volume}, SL ${sl}, TP ${tp},
|
|
14590
|
-
: `- ${sym}: ⏳ ${emirLabel} emri kondu @${entry} (${profKey} profil, SL ${sl}, TP ${tp},
|
|
14871
|
+
? `- ${sym}: ⚡ MARKET ${c.choice.toUpperCase()} açıldı (lot ${r.opened && r.opened.volume}, SL ${sl}, TP ${tp}, ${riskTxt})`
|
|
14872
|
+
: `- ${sym}: ⏳ ${emirLabel} emri kondu @${entry} (${profKey} profil, SL ${sl}, TP ${tp}, ${riskTxt})`) +
|
|
14591
14873
|
` · p=${c.p.toFixed(2)} teyit=${confVal.toFixed(2)} · tf=${market[sym].tf}` +
|
|
14592
14874
|
(talimatZorunlu ? ' · TALİMAT: zorunlu giriş' : '') +
|
|
14593
14875
|
(thAction !== FIN_TS_DEFAULT_TH.action ? ` · öğrenilmiş eşik p≥${thAction.toFixed(2)}` : '')
|
|
@@ -14600,10 +14882,12 @@ async function finTypeSafeRound(sid, agent) {
|
|
|
14600
14882
|
}
|
|
14601
14883
|
/* JEV ARAÇ İSTEĞİ (tur düzeyi): eksik araç varsa TOOL botuna asenkron yazdır */
|
|
14602
14884
|
try { await finTsToolRequest(sidS, agent, ans, lines); } catch {}
|
|
14885
|
+
const insTxt = finInstrSummary(ins);
|
|
14603
14886
|
finTsPost(
|
|
14604
14887
|
sidS,
|
|
14605
14888
|
agent,
|
|
14606
14889
|
`🤖 TypeSafe karar turu #${agent.round} (LLM yok — girdi yalnız TypeSafe):\n` +
|
|
14890
|
+
(insTxt ? 'TALİMAT AYARLARI (kod uygular): ' + insTxt + '\n' : '') +
|
|
14607
14891
|
'TF KARARI: ' + symbols.map((s) => `${s}=${market[s].tf}`).join(', ') + '\n' +
|
|
14608
14892
|
'ÖĞRENİLMİŞ: ' +
|
|
14609
14893
|
symbols
|
package/src/renderer/index.html
CHANGED
|
@@ -193,8 +193,8 @@
|
|
|
193
193
|
<div id="finRoles" class="fin-roles" title="Trader'ın yanında koşacak uzman ajanları seç — Risk / Teknik / Haber / Görsel; seçilen her rol AYRI sürekli ajan olarak koşar (işlem açmaz)"></div>
|
|
194
194
|
</div>
|
|
195
195
|
<div class="fin-field">
|
|
196
|
-
<span>Ajan talimatı <i class="fin-hint">— 1-2 cümle; trader + tüm paralel ajanlara iletilir</i></span>
|
|
197
|
-
<textarea id="finStrategy" rows="2" maxlength="2000" placeholder="örn.
|
|
196
|
+
<span>Ajan talimatı <i class="fin-hint">— 1-2 cümle; trader + tüm paralel ajanlara iletilir</i><button id="finStrategyHelp" class="fin-help-btn" type="button" title="Neler yazabilirim? Desteklenen talimatlar ve örnekler">?</button></span>
|
|
197
|
+
<textarea id="finStrategy" rows="2" maxlength="2000" placeholder="örn. 1- risk yüzde 2 2- martingale kullan 3- her mumda işlem açmak zorundasın" title="Buraya yazdığın talimat trade ajanına ve koşan tüm paralel ajanlara (ekip + sembol işçileri) sistem promptunda öncelikli strateji notu olarak gider; kaydetmek için alandan çık"></textarea>
|
|
198
198
|
</div>
|
|
199
199
|
<div id="finAdvWrap" hidden>
|
|
200
200
|
<div class="fin-field">
|
|
@@ -227,8 +227,8 @@
|
|
|
227
227
|
</label>
|
|
228
228
|
</div>
|
|
229
229
|
<div class="fin-field">
|
|
230
|
-
<span>Yönetici talimatı <i class="fin-hint">— yalnız bu ajanı bağlar</i></span>
|
|
231
|
-
<textarea id="finPosNote" rows="2" maxlength="1500" placeholder="örn.
|
|
230
|
+
<span>Yönetici talimatı <i class="fin-hint">— yalnız bu ajanı bağlar</i><button id="finPosHelp" class="fin-help-btn" type="button" title="Neler yazabilirim? Desteklenen talimatlar ve örnekler">?</button></span>
|
|
231
|
+
<textarea id="finPosNote" rows="2" maxlength="1500" placeholder="örn. 1- 1R'de %50 kısmi kapat 2- kâr 2R'ye gelince kalanı kapat 3- zarar -0.5R'yi geçerse kes" title="Bu talimat YALNIZ Pozisyon Yöneticisi Jev ajanına gider (5 sn turu, kapat/kısmi/SL kararları); kaydetmek için alandan çık"></textarea>
|
|
232
232
|
</div>
|
|
233
233
|
<div id="finPosStatus">Beklemede — açık pozisyon yok</div>
|
|
234
234
|
</div>
|
|
@@ -889,6 +889,16 @@
|
|
|
889
889
|
</div>
|
|
890
890
|
</div>
|
|
891
891
|
|
|
892
|
+
<div id="finHelpOverlay" class="mini-overlay" hidden>
|
|
893
|
+
<div class="mini-dialog fin-help-dialog">
|
|
894
|
+
<div class="mini-head">
|
|
895
|
+
<span class="mini-title" id="finHelpTitle">TALİMAT KILAVUZU</span>
|
|
896
|
+
<button class="mini-close" id="finHelpClose" title="Kapat">×</button>
|
|
897
|
+
</div>
|
|
898
|
+
<div class="mini-body" id="finHelpBody"></div>
|
|
899
|
+
</div>
|
|
900
|
+
</div>
|
|
901
|
+
|
|
892
902
|
<div id="finTeamOverlay" class="mini-overlay" hidden>
|
|
893
903
|
<div class="mini-dialog fin-sym-dialog">
|
|
894
904
|
<div class="mini-head">
|
package/src/renderer/renderer.js
CHANGED
|
@@ -228,6 +228,12 @@ const els = {
|
|
|
228
228
|
finMaxLot: $('#finMaxLot'),
|
|
229
229
|
finSymLimits: $('#finSymLimits'),
|
|
230
230
|
finStrategy: $('#finStrategy'),
|
|
231
|
+
finStrategyHelp: $('#finStrategyHelp'),
|
|
232
|
+
finPosHelp: $('#finPosHelp'),
|
|
233
|
+
finHelpOverlay: $('#finHelpOverlay'),
|
|
234
|
+
finHelpTitle: $('#finHelpTitle'),
|
|
235
|
+
finHelpBody: $('#finHelpBody'),
|
|
236
|
+
finHelpClose: $('#finHelpClose'),
|
|
231
237
|
finMaxTradesDay: $('#finMaxTradesDay'),
|
|
232
238
|
finLossStreak: $('#finLossStreak'),
|
|
233
239
|
finLossStreakPause: $('#finLossStreakPause'),
|
|
@@ -10886,6 +10892,92 @@ if (els.finStrategy) {
|
|
|
10886
10892
|
toast(v.trim() ? 'Ajan talimatı kaydedildi — tüm ajanlar sonraki turda uygular' : 'Ajan talimatı temizlendi');
|
|
10887
10893
|
});
|
|
10888
10894
|
}
|
|
10895
|
+
/* TALİMAT KILAVUZU (?): her iki talimat alanı için desteklenen kalıplar.
|
|
10896
|
+
"kod" etiketli kalıplar AYRICALIKLI olarak kod tarafından otomatik uygulanır;
|
|
10897
|
+
serbest cümleler Jev'in tur state'ine girer ve Jev ona göre karar verir. */
|
|
10898
|
+
/* BUTONLAR: ? → kılavuz; dışına tıkla / × → kapat */
|
|
10899
|
+
if (els.finStrategyHelp) {
|
|
10900
|
+
els.finStrategyHelp.addEventListener('click', (e) => {
|
|
10901
|
+
e.preventDefault();
|
|
10902
|
+
finHelpOpen('trade');
|
|
10903
|
+
});
|
|
10904
|
+
}
|
|
10905
|
+
if (els.finPosHelp) {
|
|
10906
|
+
els.finPosHelp.addEventListener('click', (e) => {
|
|
10907
|
+
e.preventDefault();
|
|
10908
|
+
finHelpOpen('posmgr');
|
|
10909
|
+
});
|
|
10910
|
+
}
|
|
10911
|
+
if (els.finHelpClose) els.finHelpClose.addEventListener('click', finHelpClose);
|
|
10912
|
+
if (els.finHelpOverlay) {
|
|
10913
|
+
els.finHelpOverlay.addEventListener('click', (e) => {
|
|
10914
|
+
if (e.target === els.finHelpOverlay) finHelpClose();
|
|
10915
|
+
});
|
|
10916
|
+
}
|
|
10917
|
+
function finHelpHtml(which) {
|
|
10918
|
+
const posmgr = which === 'posmgr';
|
|
10919
|
+
const items = posmgr
|
|
10920
|
+
? [
|
|
10921
|
+
['<code>1R\'de %50 kısmi kapat</code><code>%50 1R</code><code>kısmi close %50</code>',
|
|
10922
|
+
'<b>Kod otomatik uygular.</b> Kâr belirtilen R\'ye gelince pozisyonun %50\'si kapatılır (tek sefer). "kısmi %50" tek başına yazılırsa 1R kabul edilir.'],
|
|
10923
|
+
['<code>1.5R\'de %25 kısmi</code><code>3R\'de %75 kapat</code>',
|
|
10924
|
+
'<b>Kod otomatik uygular.</b> R ve yüzdeyi sen seç; yüzde 5-90 arası olmalı.'],
|
|
10925
|
+
['<code>kâr 2R olunca kalanı kapat</code><code>kârı koru</code>',
|
|
10926
|
+
'<b>Jev uygular.</b> Serbest ifade; her 5 sn turunda Jev okur ve kapatma/trailing kararını verir.'],
|
|
10927
|
+
['<code>SL\'yi takip et</code><code>breakeven\'a çek</code><code>zararı -0.5R\'de kes</code>',
|
|
10928
|
+
'<b>Jev uygular.</b> SL/koruma aksiyonu olarak değerlendirilir; kod seviyeyi ATR/R ile hesaplar, SL asla geriye gitmez.'],
|
|
10929
|
+
['<code>başlangıç bakiye 10.000</code><code>gün başı: 10000</code>',
|
|
10930
|
+
'Gün başı bakiyesi — günlük K/Z % otomatik hesaplanır (raporda "Gün başı → %-2.3 ZARAR").'],
|
|
10931
|
+
]
|
|
10932
|
+
: [
|
|
10933
|
+
['<code>risk %2</code><code>%2 risk</code><code>risk yüzde 2</code>',
|
|
10934
|
+
'<b>Kod otomatik uygular.</b> Girişler %2 risk ile açılır (kalibrasyon çarpanı devre dışı, 0.1-10 arası).'],
|
|
10935
|
+
['<code>lot x1.5</code><code>poz başı lot 1.5</code><code>lotu 2 kat yap</code>',
|
|
10936
|
+
'<b>Kod otomatik uygular.</b> Tüm giriş riskine/lotuna çarpan.'],
|
|
10937
|
+
['<code>martingale</code><code>martingale 1.2</code><code>martingale x1.20</code><code>1.2 kat martingale</code>',
|
|
10938
|
+
'<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.'],
|
|
10939
|
+
['<code>her mumda işlem açmak zorundasın</code><code>her barda işlem</code><code>her zaman işlem</code>',
|
|
10940
|
+
'<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.'],
|
|
10941
|
+
['<code>M1</code><code>1m</code><code>5 dk</code><code>4 saat</code>',
|
|
10942
|
+
'İşlem zaman dilimi. M1/M5 yazarsan tur ritmi hızlanır (M1 en hızlı 60 sn).'],
|
|
10943
|
+
['<code>başlangıç bakiye 10.000</code><code>gün başı: 10000</code><code>starting balance 10000</code>',
|
|
10944
|
+
'Gün başı bakiyesi — her turda günlük K/Z otomatik hesaplanır ve Jev\'e durum olarak verilir.'],
|
|
10945
|
+
['<code>günlük zarar %3</code><code>max günlük kayıp 3</code>',
|
|
10946
|
+
'<b>Kod otomatik uygular.</b> Limit aşılırsa yeni işlem açılmaz; günlük kayıp otomasyonunun limiti bu olur.'],
|
|
10947
|
+
['<code>aynı anda en fazla 10 işlem</code><code>en fazla 10 pozisyon</code><code>günde en fazla 10 işlem</code>',
|
|
10948
|
+
'<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.'],
|
|
10949
|
+
];
|
|
10950
|
+
const example = posmgr
|
|
10951
|
+
? `1- 1R'de %50 kısmi kapat\n2- kâr 2R'ye gelince kalanı kapat\n3- zarar -0.5R'yi geçerse kes`
|
|
10952
|
+
: `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`;
|
|
10953
|
+
const head = posmgr
|
|
10954
|
+
? 'Pozisyon Yöneticisi (5 sn turu) açık pozisyonları yönetir: kapat / kısmi kapat / SL taşı.'
|
|
10955
|
+
: 'Trade Ajanı girişleri yönetir: yön, emir tipi, risk, lot, martingale ve günlük limitler.';
|
|
10956
|
+
const rows = items
|
|
10957
|
+
.map((it) => '<div class="fin-help-item"><div class="fin-help-code">' + it[0] + '</div><div class="fin-help-desc">' + it[1] + '</div></div>')
|
|
10958
|
+
.join('');
|
|
10959
|
+
return (
|
|
10960
|
+
'<div class="fin-help-head">' + head + '</div>' +
|
|
10961
|
+
'<div class="fin-help-sec">Neler yazabilirsin?</div>' +
|
|
10962
|
+
rows +
|
|
10963
|
+
'<div class="fin-help-sec">Nasıl yazılır?</div>' +
|
|
10964
|
+
'<div class="fin-help-text">İstediğin gibi düz cümle yazabilirsin; birden çok kuralı <b>1- 2- 3-</b> diye numaralayarak alt alta yazman en kolayı. Kod, yukarıdaki sayısal kalıpları otomatik uygular; kalan serbest ifadeleri Jev her turda okur ve kararına katar. Talimat değişiklikleri <b>sonraki turda</b> geçerli olur.</div>' +
|
|
10965
|
+
'<pre class="fin-help-ex">' + example + '</pre>'
|
|
10966
|
+
);
|
|
10967
|
+
}
|
|
10968
|
+
|
|
10969
|
+
function finHelpOpen(which) {
|
|
10970
|
+
if (!els.finHelpOverlay) return;
|
|
10971
|
+
const posmgr = which === 'posmgr';
|
|
10972
|
+
if (els.finHelpTitle) els.finHelpTitle.textContent = posmgr ? 'POZİSYON YÖNETİCİSİ — TALİMAT KILAVUZU' : 'TRADE AJANI — TALİMAT KILAVUZU';
|
|
10973
|
+
if (els.finHelpBody) els.finHelpBody.innerHTML = finHelpHtml(which);
|
|
10974
|
+
els.finHelpOverlay.hidden = false;
|
|
10975
|
+
}
|
|
10976
|
+
|
|
10977
|
+
function finHelpClose() {
|
|
10978
|
+
if (els.finHelpOverlay) els.finHelpOverlay.hidden = true;
|
|
10979
|
+
}
|
|
10980
|
+
|
|
10889
10981
|
/* POZİSYON YÖNETİCİSİ: 5 sn Jev turu — kendi talimatı + aç/kapa */
|
|
10890
10982
|
if (els.finPosNote) {
|
|
10891
10983
|
els.finPosNote.addEventListener('input', () => {
|
package/src/renderer/style.css
CHANGED
|
@@ -5644,6 +5644,65 @@ body.finance-mode #composerWrap { margin-right: var(--finW, 400px); }
|
|
|
5644
5644
|
#finPosStatus.on.busy { color: var(--accent); }
|
|
5645
5645
|
#finPosStatus.on.busy::before { color: #f59e0b; }
|
|
5646
5646
|
|
|
5647
|
+
/* TALİMAT KILAVUZU (? butonu + modal) */
|
|
5648
|
+
.fin-help-btn {
|
|
5649
|
+
width: 16px;
|
|
5650
|
+
height: 16px;
|
|
5651
|
+
margin-left: 6px;
|
|
5652
|
+
border-radius: 50%;
|
|
5653
|
+
border: 1px solid var(--border);
|
|
5654
|
+
background: var(--panel2);
|
|
5655
|
+
color: var(--muted);
|
|
5656
|
+
font-size: 10px;
|
|
5657
|
+
font-weight: 700;
|
|
5658
|
+
line-height: 1;
|
|
5659
|
+
padding: 0;
|
|
5660
|
+
cursor: pointer;
|
|
5661
|
+
vertical-align: 1px;
|
|
5662
|
+
}
|
|
5663
|
+
.fin-help-btn:hover { color: var(--text); border-color: var(--accent); }
|
|
5664
|
+
.fin-help-dialog { max-width: 620px; }
|
|
5665
|
+
#finHelpBody { max-height: 62vh; overflow: auto; }
|
|
5666
|
+
.fin-help-head { font-size: 11px; color: var(--muted); margin: 2px 0 10px; }
|
|
5667
|
+
.fin-help-sec {
|
|
5668
|
+
font-size: 10.5px;
|
|
5669
|
+
font-weight: 700;
|
|
5670
|
+
letter-spacing: 0.04em;
|
|
5671
|
+
text-transform: uppercase;
|
|
5672
|
+
color: var(--muted);
|
|
5673
|
+
margin: 12px 0 6px;
|
|
5674
|
+
}
|
|
5675
|
+
.fin-help-item {
|
|
5676
|
+
border: 1px solid var(--border);
|
|
5677
|
+
border-radius: 7px;
|
|
5678
|
+
padding: 6px 8px;
|
|
5679
|
+
margin-bottom: 6px;
|
|
5680
|
+
background: var(--panel2);
|
|
5681
|
+
}
|
|
5682
|
+
.fin-help-code { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 4px; }
|
|
5683
|
+
.fin-help-code code {
|
|
5684
|
+
font-size: 10.5px;
|
|
5685
|
+
padding: 1px 5px;
|
|
5686
|
+
border-radius: 4px;
|
|
5687
|
+
background: rgba(127, 127, 127, 0.14);
|
|
5688
|
+
border: 1px solid var(--border);
|
|
5689
|
+
}
|
|
5690
|
+
.fin-help-desc { font-size: 11px; color: var(--muted); line-height: 1.5; }
|
|
5691
|
+
.fin-help-desc b { color: var(--text); }
|
|
5692
|
+
.fin-help-text { font-size: 11px; color: var(--muted); line-height: 1.55; }
|
|
5693
|
+
.fin-help-text b { color: var(--text); }
|
|
5694
|
+
.fin-help-ex {
|
|
5695
|
+
margin: 8px 0 2px;
|
|
5696
|
+
padding: 8px 10px;
|
|
5697
|
+
border-radius: 7px;
|
|
5698
|
+
border: 1px dashed var(--border);
|
|
5699
|
+
background: var(--panel2);
|
|
5700
|
+
font-size: 11px;
|
|
5701
|
+
line-height: 1.6;
|
|
5702
|
+
white-space: pre-wrap;
|
|
5703
|
+
color: var(--text);
|
|
5704
|
+
}
|
|
5705
|
+
|
|
5647
5706
|
#finPosList, #finOrdList, #finSymList { display: flex; flex-direction: column; gap: 5px; }
|
|
5648
5707
|
.fin-empty { font-size: 11px; color: var(--muted); padding: 2px 0 4px; }
|
|
5649
5708
|
|