beast-agent 2.73.0 → 2.74.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/main.js +255 -20
- package/src/renderer/index.html +14 -4
- package/src/renderer/renderer.js +90 -0
- package/src/renderer/style.css +59 -0
package/package.json
CHANGED
package/src/main.js
CHANGED
|
@@ -10779,17 +10779,36 @@ function finEquitySample(account) {
|
|
|
10779
10779
|
function finDailyLossCheck(point) {
|
|
10780
10780
|
const cfg = finCfg();
|
|
10781
10781
|
const day = finstats.dayKey(point.at);
|
|
10782
|
+
/* TALİMAT: "gün başı bakiye" yazıldıysa taban O'dur; "günlük zarar %X"
|
|
10783
|
+
yazıldıysa limit ayarın yerine talimattan gelir (kullanıcı her gün günceller). */
|
|
10784
|
+
let startBal = 0;
|
|
10785
|
+
let limitPct = Number(cfg.maxDailyLossPct) || 0;
|
|
10786
|
+
try {
|
|
10787
|
+
const ins = finParsedInstr();
|
|
10788
|
+
if (Number(ins.entry.startBalance) > 0) startBal = Number(ins.entry.startBalance);
|
|
10789
|
+
if (Number(ins.entry.dailyLossPct) > 0) limitPct = Number(ins.entry.dailyLossPct);
|
|
10790
|
+
} catch {}
|
|
10782
10791
|
let ds = financeState.dayStart;
|
|
10783
10792
|
if (!ds || ds.day !== day) {
|
|
10784
|
-
financeState.dayStart = ds = {
|
|
10793
|
+
financeState.dayStart = ds = {
|
|
10794
|
+
day,
|
|
10795
|
+
equity: startBal > 0 ? startBal : Number(point.balance) > 0 ? Number(point.balance) : point.equity,
|
|
10796
|
+
warned: false,
|
|
10797
|
+
acted: false,
|
|
10798
|
+
fromNote: startBal > 0,
|
|
10799
|
+
};
|
|
10785
10800
|
}
|
|
10786
|
-
if (
|
|
10801
|
+
if (startBal > 0) {
|
|
10802
|
+
ds.equity = startBal;
|
|
10803
|
+
ds.fromNote = true;
|
|
10804
|
+
}
|
|
10805
|
+
if (ds.warned || !(limitPct > 0) || !(ds.equity > 0)) return;
|
|
10787
10806
|
const dd = ((ds.equity - point.equity) / ds.equity) * 100;
|
|
10788
|
-
if (dd >=
|
|
10807
|
+
if (dd >= limitPct) {
|
|
10789
10808
|
ds.warned = true;
|
|
10790
10809
|
const action = String(cfg.dailyLossAction || 'stop');
|
|
10791
10810
|
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 %${
|
|
10811
|
+
const line = `⚠️ Günlük kayıp %${dd.toFixed(2)} (limit %${limitPct}${ds.fromNote ? ' · talimat gün başı bakiye' : ''})${tail}`;
|
|
10793
10812
|
financeLog('[risk] ' + line);
|
|
10794
10813
|
financeNotify(line, 'drawdown');
|
|
10795
10814
|
finJournal({ kind: 'drawdown', pct: Math.round(dd * 100) / 100, action });
|
|
@@ -13698,6 +13717,115 @@ function finTsStrategyText() {
|
|
|
13698
13717
|
}
|
|
13699
13718
|
}
|
|
13700
13719
|
|
|
13720
|
+
/* ---- TALİMAT AYRIŞTIRICI ----
|
|
13721
|
+
Trade Ajanı + Pozisyon Yöneticisi notlarındaki SAYISAL kuralları koda çevirir:
|
|
13722
|
+
"risk %2" → giriş riski %2
|
|
13723
|
+
"lot x1.5" / "poz başı lot 1.5" / "lotu 2 kat" → lot çarpanı
|
|
13724
|
+
"martingale" / "martingale 1.5" → kayıp serisinde lot katlama (varsayılan ×2)
|
|
13725
|
+
"1R'de %50 kısmi kapat" / "%50 1R" / "kısmi %50" → otomatik kısmi close kuralı
|
|
13726
|
+
Saf metin ayrıştırma; uygulama ilgili turda kodla yapılır (LLM yok). */
|
|
13727
|
+
function finInstrNum(v) {
|
|
13728
|
+
const n = Number(String(v == null ? '' : v).replace(',', '.'));
|
|
13729
|
+
return isFinite(n) ? n : null;
|
|
13730
|
+
}
|
|
13731
|
+
|
|
13732
|
+
/* Para değeri: "10.000" / "10,000" → 10000; "10000,50" / "10000.50" → 10000.5 */
|
|
13733
|
+
function finInstrMoney(v) {
|
|
13734
|
+
const s = String(v == null ? '' : v).replace(/\s+/g, '');
|
|
13735
|
+
if (!s) return null;
|
|
13736
|
+
/* "5.000,50" / "5,000.50" → 5000.50 ; "10.000" → 10000 ; "10000,50" → 10000.5 */
|
|
13737
|
+
const m = s.match(/^(\d{1,3}(?:[.,]\d{3})+)(?:[.,](\d{1,2}))?$/);
|
|
13738
|
+
if (m) {
|
|
13739
|
+
const n = Number(m[1].replace(/[.,]/g, '') + (m[2] ? '.' + m[2] : ''));
|
|
13740
|
+
return isFinite(n) && n > 0 ? n : null;
|
|
13741
|
+
}
|
|
13742
|
+
const n2 = Number(s.replace(',', '.'));
|
|
13743
|
+
return isFinite(n2) && n2 > 0 ? n2 : null;
|
|
13744
|
+
}
|
|
13745
|
+
|
|
13746
|
+
function finParseInstructions(text) {
|
|
13747
|
+
const low = String(text || '').toLowerCase();
|
|
13748
|
+
const out = { riskPct: null, lotMult: null, martingale: null, partial: null, startBalance: null, dailyLossPct: null };
|
|
13749
|
+
if (!low.trim()) return out;
|
|
13750
|
+
/* "risk %2", "%2 risk", "risk yüzde 2", "riski 2 yap" → 2 (ilk sayı) */
|
|
13751
|
+
let m = low.match(
|
|
13752
|
+
/(?:risk\s*%\s*(\d+(?:[.,]\d+)?))|(?:%\s*(\d+(?:[.,]\d+)?)\s*risk)|(?:risk[^0-9]{0,14}(\d+(?:[.,]\d+)?))/
|
|
13753
|
+
);
|
|
13754
|
+
if (m) out.riskPct = finInstrNum(m[1] || m[2] || m[3]);
|
|
13755
|
+
if (out.riskPct != null) out.riskPct = Math.max(0.1, Math.min(10, out.riskPct));
|
|
13756
|
+
/* GÜN BAŞLANGIÇ BAKİYESİ (kullanıcı her gün talimata yazar): "başlangıç bakiye 10.000",
|
|
13757
|
+
"gün başı: 10000", "starting balance 10000" */
|
|
13758
|
+
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]*)/);
|
|
13759
|
+
if (m) out.startBalance = finInstrMoney(m[1]);
|
|
13760
|
+
/* GÜNLÜK ZARAR LİMİTİ: "günlük zarar %3", "max günlük kayıp 3", "daily loss %3" */
|
|
13761
|
+
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+)?)/);
|
|
13762
|
+
if (m) {
|
|
13763
|
+
const v = finInstrNum(m[1]);
|
|
13764
|
+
if (v != null && v > 0) out.dailyLossPct = Math.max(0.1, Math.min(50, v));
|
|
13765
|
+
}
|
|
13766
|
+
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)/);
|
|
13767
|
+
if (m) out.lotMult = finInstrNum(m[1] || m[2] || m[3]);
|
|
13768
|
+
if (out.lotMult != null) out.lotMult = Math.max(1, Math.min(5, out.lotMult));
|
|
13769
|
+
if (/martingale|mart[ıi]ngale/.test(low)) {
|
|
13770
|
+
/* faktör yalnız bitişik yazımdan okunur: "martingale 1.5", "martingale x2",
|
|
13771
|
+
"martingale çarpanı 1.5" — "martingale kullan, 1R..." gibi metinden sayı kapmaz */
|
|
13772
|
+
m = low.match(/mart[ıi]ngale\s*(?:x|×|çarpan[ıi]?|carpan[ıi]?)?\s*(\d+(?:[.,]\d+)?)/);
|
|
13773
|
+
out.martingale = m ? Math.max(1.1, Math.min(5, finInstrNum(m[1]) || 2)) : 2;
|
|
13774
|
+
}
|
|
13775
|
+
/* kısmi kapatma: "1R'de %50" → atR=1, pct=50; "%50 1R" → aynı; "kısmi %50" → atR=1 */
|
|
13776
|
+
m = low.match(/(\d+(?:[.,]\d+)?)\s*r[^%\d]{0,28}%\s*(\d+(?:[.,]\d+)?)/);
|
|
13777
|
+
if (m) out.partial = { atR: finInstrNum(m[1]), pct: finInstrNum(m[2]) };
|
|
13778
|
+
if (!out.partial) {
|
|
13779
|
+
m = low.match(/%\s*(\d+(?:[.,]\d+)?)[^%\d]{0,28}?(\d+(?:[.,]\d+)?)\s*r/);
|
|
13780
|
+
if (m) out.partial = { atR: finInstrNum(m[2]), pct: finInstrNum(m[1]) };
|
|
13781
|
+
}
|
|
13782
|
+
if (!out.partial) {
|
|
13783
|
+
m = low.match(/(?:k[ıi]smi|partial)[^%\d]{0,24}%\s*(\d+(?:[.,]\d+)?)/);
|
|
13784
|
+
if (m) out.partial = { atR: 1, pct: finInstrNum(m[1]) };
|
|
13785
|
+
}
|
|
13786
|
+
if (out.partial) {
|
|
13787
|
+
const p = out.partial;
|
|
13788
|
+
if (!(p.atR > 0)) p.atR = 1;
|
|
13789
|
+
p.atR = Math.min(10, Math.round(p.atR * 100) / 100);
|
|
13790
|
+
if (!(p.pct >= 5 && p.pct <= 90)) out.partial = null;
|
|
13791
|
+
else p.pct = Math.round(p.pct);
|
|
13792
|
+
}
|
|
13793
|
+
return out;
|
|
13794
|
+
}
|
|
13795
|
+
|
|
13796
|
+
/* İki notu birleştir: GİRİŞ kuralları trade notundan, YÖNETİM kuralları
|
|
13797
|
+
pozisyon yöneticisi notundan (yoksa trade notundan) gelir. */
|
|
13798
|
+
function finParsedInstr() {
|
|
13799
|
+
const trade = finParseInstructions(finTsStrategyText());
|
|
13800
|
+
const mgr = finParseInstructions(String(finCfg().posManagerNote || ''));
|
|
13801
|
+
return {
|
|
13802
|
+
entry: {
|
|
13803
|
+
riskPct: trade.riskPct != null ? trade.riskPct : mgr.riskPct,
|
|
13804
|
+
lotMult: trade.lotMult != null ? trade.lotMult : mgr.lotMult,
|
|
13805
|
+
martingale: trade.martingale != null ? trade.martingale : mgr.martingale,
|
|
13806
|
+
startBalance: trade.startBalance != null ? trade.startBalance : mgr.startBalance,
|
|
13807
|
+
dailyLossPct: trade.dailyLossPct != null ? trade.dailyLossPct : mgr.dailyLossPct,
|
|
13808
|
+
},
|
|
13809
|
+
manage: { partial: mgr.partial || trade.partial },
|
|
13810
|
+
};
|
|
13811
|
+
}
|
|
13812
|
+
|
|
13813
|
+
/* Rapor/state için tek satır özet: kod ne uygulayacak */
|
|
13814
|
+
function finInstrSummary(ins) {
|
|
13815
|
+
try {
|
|
13816
|
+
const p = [];
|
|
13817
|
+
if (ins.entry.riskPct != null) p.push(`risk %${ins.entry.riskPct}`);
|
|
13818
|
+
if (ins.entry.lotMult != null) p.push(`lot ×${ins.entry.lotMult}`);
|
|
13819
|
+
if (ins.entry.martingale != null) p.push(`martingale ×${ins.entry.martingale}`);
|
|
13820
|
+
if (ins.entry.startBalance != null) p.push(`gün başı ${ins.entry.startBalance}`);
|
|
13821
|
+
if (ins.entry.dailyLossPct != null) p.push(`günlük zarar limiti %${ins.entry.dailyLossPct}`);
|
|
13822
|
+
if (ins.manage.partial) p.push(`kısmi %${ins.manage.partial.pct} @${ins.manage.partial.atR}R`);
|
|
13823
|
+
return p.join(' · ');
|
|
13824
|
+
} catch {
|
|
13825
|
+
return '';
|
|
13826
|
+
}
|
|
13827
|
+
}
|
|
13828
|
+
|
|
13701
13829
|
/* Talimattan ZAMAN DİLİMİ çıkar: "M15", "1m", "1 dk", "4 saat" → M15/M1/H4 */
|
|
13702
13830
|
function finTsStrategyTf() {
|
|
13703
13831
|
const s = String(finTsStrategyText() || '');
|
|
@@ -14079,6 +14207,9 @@ async function finPosManagerRound(positions, account) {
|
|
|
14079
14207
|
pm.rounds = (Number(pm.rounds) || 0) + 1;
|
|
14080
14208
|
pm.lastAt = Date.now();
|
|
14081
14209
|
const f = finCfg();
|
|
14210
|
+
/* TALİMAT: kısmi close kuralı varsa KOD uygular (Jev'e sorulmaz) */
|
|
14211
|
+
const ins = finParsedInstr();
|
|
14212
|
+
const instrTxt = finInstrSummary(ins);
|
|
14082
14213
|
const lines = [];
|
|
14083
14214
|
try {
|
|
14084
14215
|
/* pozisyon sembolleri: piyasa + gösterge (tur başına tek Jev çağrısı) */
|
|
@@ -14106,6 +14237,18 @@ async function finPosManagerRound(positions, account) {
|
|
|
14106
14237
|
piyasa: {},
|
|
14107
14238
|
alarmlar: (financeState.alerts || []).slice(0, 8).map((a) => ({ sembol: a.symbol, yon: a.direction, fiyat: a.price, mod: a.once ? 'tek' : 'tekrarlı' })),
|
|
14108
14239
|
sahip_talimati: String(f.posManagerNote || '').slice(0, 1500) || '(yok — genel disiplin: kârı koru, zararı sınırla, SL/TP aktif yönet)',
|
|
14240
|
+
talimat_ayarlari: instrTxt || '(sayısal kural yok)',
|
|
14241
|
+
gun_durumu: (() => {
|
|
14242
|
+
try {
|
|
14243
|
+
const sb = Number(ins.entry.startBalance) || 0;
|
|
14244
|
+
const eqNow = Number(account && account.equity) || 0;
|
|
14245
|
+
if (!(sb > 0) || !(eqNow > 0)) return '';
|
|
14246
|
+
const pct = Math.round(((eqNow - sb) / sb) * 10000) / 100;
|
|
14247
|
+
return `Gün başı ${sb} → %${pct >= 0 ? '+' : ''}${pct} (${pct >= 0 ? 'KÂR' : 'ZARAR'})`;
|
|
14248
|
+
} catch {
|
|
14249
|
+
return '';
|
|
14250
|
+
}
|
|
14251
|
+
})(),
|
|
14109
14252
|
ekip_yanitlari: finTsFeedText(6),
|
|
14110
14253
|
};
|
|
14111
14254
|
for (const sym of syms) {
|
|
@@ -14131,16 +14274,19 @@ async function finPosManagerRound(positions, account) {
|
|
|
14131
14274
|
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
14275
|
criteria: { true: 'Kapat — risk/kâr koruma', false: 'Açık kalsın — tez sürüyor' },
|
|
14133
14276
|
};
|
|
14134
|
-
|
|
14135
|
-
|
|
14136
|
-
|
|
14137
|
-
|
|
14138
|
-
|
|
14139
|
-
|
|
14140
|
-
|
|
14141
|
-
|
|
14142
|
-
|
|
14143
|
-
|
|
14277
|
+
/* Talimatta SAYISAL kısmi kuralı varsa Jev'e sorulmaz — kodu uygular */
|
|
14278
|
+
if (!ins.manage.partial) {
|
|
14279
|
+
questions['kismi_' + i] = {
|
|
14280
|
+
type: 'choice',
|
|
14281
|
+
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.'}`,
|
|
14282
|
+
criteria: {
|
|
14283
|
+
yok: 'Kısmi kapatma yok — pozisyon tam kalsın',
|
|
14284
|
+
yuzde25: 'Pozisyonun %25’i kapatılsın',
|
|
14285
|
+
yuzde50: 'Pozisyonun %50’si kapatılsın',
|
|
14286
|
+
yuzde75: 'Pozisyonun %75’i kapatılsın',
|
|
14287
|
+
},
|
|
14288
|
+
};
|
|
14289
|
+
}
|
|
14144
14290
|
questions['sl_' + i] = {
|
|
14145
14291
|
type: 'choice',
|
|
14146
14292
|
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 +14319,39 @@ async function finPosManagerRound(positions, account) {
|
|
|
14173
14319
|
}
|
|
14174
14320
|
const psNow = finTsPosState(pp);
|
|
14175
14321
|
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'}`);
|
|
14322
|
+
/* TALİMAT KISMİ KURALI (kod): "+atR'de %pct kapat" → otomatik uygula */
|
|
14323
|
+
const rule = ins.manage.partial;
|
|
14324
|
+
if (rule) {
|
|
14325
|
+
const stP = financeState.watch.get(String(pp.ticket)) || null;
|
|
14326
|
+
const done = !!(stP && stP.partial) || !!(pm.tsPartials && pm.tsPartials.has(String(pp.ticket)));
|
|
14327
|
+
if (!done && psNow.kz_r != null && psNow.kz_r >= rule.atR) {
|
|
14328
|
+
let rr = null;
|
|
14329
|
+
try {
|
|
14330
|
+
rr = await financetools.handlers.mt5_close(
|
|
14331
|
+
{ 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)` },
|
|
14332
|
+
{ sessionId: FIN_POSMGR_ID }
|
|
14333
|
+
);
|
|
14334
|
+
} catch (e) {
|
|
14335
|
+
rr = { ok: false, error: String((e && e.message) || e) };
|
|
14336
|
+
}
|
|
14337
|
+
if (rr && rr.ok) {
|
|
14338
|
+
if (stP) { stP.partial = true; finWatchSave(); }
|
|
14339
|
+
pm.tsPartials = pm.tsPartials || new Set();
|
|
14340
|
+
pm.tsPartials.add(String(pp.ticket));
|
|
14341
|
+
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' : ''})`);
|
|
14342
|
+
} else {
|
|
14343
|
+
lines.push(`- ${sym} #${pp.ticket}: talimat kısmi reddedildi — ${(rr && rr.error) || 'hata'}`);
|
|
14344
|
+
}
|
|
14345
|
+
}
|
|
14346
|
+
}
|
|
14176
14347
|
try { await finTsManageOpen(FIN_POSMGR_ID, pm, sym, pp, market[sym], ans, i, lines); } catch {}
|
|
14177
14348
|
}
|
|
14178
14349
|
finTsPost(
|
|
14179
14350
|
FIN_POSMGR_ID,
|
|
14180
14351
|
FIN_POSMGR_AGENT,
|
|
14181
|
-
`🛡️ Pozisyon yöneticisi turu #${pm.rounds} (LLM yok — 5 sn):\n` +
|
|
14352
|
+
`🛡️ Pozisyon yöneticisi turu #${pm.rounds} (LLM yok — 5 sn):\n` +
|
|
14353
|
+
(instrTxt ? 'TALİMAT AYARLARI (kod uygular): ' + instrTxt + '\n' : '') +
|
|
14354
|
+
lines.join('\n'),
|
|
14182
14355
|
'yönetim'
|
|
14183
14356
|
);
|
|
14184
14357
|
} catch (e) {
|
|
@@ -14265,6 +14438,25 @@ async function finTypeSafeRound(sid, agent) {
|
|
|
14265
14438
|
const posList = (posR && posR.positions) || [];
|
|
14266
14439
|
/* BEKLEYEN EMİRLER: pozisyon slotunu paylaşır (aşırı birikmeyi önler) */
|
|
14267
14440
|
const pendCount = (ordR && Array.isArray(ordR.orders) ? ordR.orders.length : 0);
|
|
14441
|
+
/* TALİMAT AYARLARI: sayısal kurallar koda çevrildi (risk/lot/martingale/
|
|
14442
|
+
gün başı bakiye/günlük zarar limiti) — state ve giriş kapısı kullanır */
|
|
14443
|
+
const ins = finParsedInstr();
|
|
14444
|
+
/* GÜN BAŞI BAKİYE → günlük K/Z ve limit durumu (hesap anlık değerinden) */
|
|
14445
|
+
let dayPct = null;
|
|
14446
|
+
let dayBlocked = '';
|
|
14447
|
+
try {
|
|
14448
|
+
const sb = Number(ins.entry.startBalance) || 0;
|
|
14449
|
+
const eqNow = Number(account.equity) || 0;
|
|
14450
|
+
const balNow = Number(account.balance) || 0;
|
|
14451
|
+
const refNow = eqNow > 0 ? eqNow : balNow;
|
|
14452
|
+
if (sb > 0 && refNow > 0) {
|
|
14453
|
+
dayPct = Math.round(((refNow - sb) / sb) * 10000) / 100;
|
|
14454
|
+
const lim = Number(ins.entry.dailyLossPct) || 0;
|
|
14455
|
+
if (lim > 0 && dayPct <= -lim) {
|
|
14456
|
+
dayBlocked = `günlük zarar limiti AŞILDI (gün başı ${sb} → ${refNow}, %${dayPct} ≤ -%${lim}) — talimat gereği yeni işlem açılmaz`;
|
|
14457
|
+
}
|
|
14458
|
+
}
|
|
14459
|
+
} catch {}
|
|
14268
14460
|
const market = {};
|
|
14269
14461
|
for (const sym of symbols) {
|
|
14270
14462
|
const tf = finTsPickTf(agent, sym);
|
|
@@ -14305,6 +14497,16 @@ async function finTypeSafeRound(sid, agent) {
|
|
|
14305
14497
|
talimat "zorunlu giriş" içeriyorsa kod eşikleri devre dışı bırakır. */
|
|
14306
14498
|
sahip_talimati: finTsStrategyText() || '(yok — temel teknik okuma)',
|
|
14307
14499
|
talimat_modu: finTsMandatoryEntry() ? 'ZORUNLU GİRİŞ — bu turda işlem açmak zorunlu (bekle yok); yönü sen seç' : '',
|
|
14500
|
+
talimat_ayarlari: finInstrSummary(ins) || '(sayısal kural yok)',
|
|
14501
|
+
/* GÜN BAŞI BAKİYE (talimattan): günlük K/Z — Jev zarar durumunu otomatik görür */
|
|
14502
|
+
gun_baslangic_bakiye: ins.entry.startBalance != null ? ins.entry.startBalance : null,
|
|
14503
|
+
gun_net_yuzde: dayPct,
|
|
14504
|
+
gun_durumu: dayBlocked
|
|
14505
|
+
? dayBlocked
|
|
14506
|
+
: ins.entry.startBalance != null && dayPct != null
|
|
14507
|
+
? `Gün başı ${ins.entry.startBalance} → şimdi %${dayPct >= 0 ? '+' : ''}${dayPct} (${dayPct >= 0 ? 'KÂR' : 'ZARAR'})` +
|
|
14508
|
+
(ins.entry.dailyLossPct != null ? ` · limit -%${ins.entry.dailyLossPct}` : '')
|
|
14509
|
+
: '',
|
|
14308
14510
|
};
|
|
14309
14511
|
for (const sym of symbols) {
|
|
14310
14512
|
const d = market[sym];
|
|
@@ -14329,6 +14531,7 @@ async function finTypeSafeRound(sid, agent) {
|
|
|
14329
14531
|
const talimatZorunlu = finTsMandatoryEntry();
|
|
14330
14532
|
/* Yönetici açıkken açık pozisyon kararları ONA aittir (çift yönetim yok) */
|
|
14331
14533
|
const posManagerOn = f.posManagerEnabled !== false;
|
|
14534
|
+
/* TALİMAT AYARLARI: yukarıda (state kurulmadan) ayrıştırıldı */
|
|
14332
14535
|
symbols.forEach((sym, i) => {
|
|
14333
14536
|
questions['yon_' + i] = {
|
|
14334
14537
|
type: 'choice',
|
|
@@ -14491,8 +14694,16 @@ async function finTypeSafeRound(sid, agent) {
|
|
|
14491
14694
|
continue;
|
|
14492
14695
|
}
|
|
14493
14696
|
}
|
|
14494
|
-
|
|
14495
|
-
|
|
14697
|
+
/* GÜN BAŞI BAKİYE LİMİTİ (talimat): aşıldıysa YENİ İŞLEM AÇILMAZ */
|
|
14698
|
+
if (dayBlocked) {
|
|
14699
|
+
lines.push(`- ${sym}: ${dayBlocked}`);
|
|
14700
|
+
continue;
|
|
14701
|
+
}
|
|
14702
|
+
/* ÇOKLU GİRİŞ: aynı turda birden çok sembol açılabilir — yalnız toplam
|
|
14703
|
+
slot (pozisyon + bekleyen emir + bu turda açılanlar) tavanı korur */
|
|
14704
|
+
const slotsLeft = (Number(f.maxPositions) || 3) - pendCount - posList.length - opened;
|
|
14705
|
+
if (slotsLeft <= 0) {
|
|
14706
|
+
lines.push(`- ${sym}: sinyal güçlü (${c.choice} p=${c.p.toFixed(2)}) ama pozisyon+bekleyen emir sınırı dolu (${posList.length + pendCount}/${Number(f.maxPositions) || 3}) — bu tur açılmadı`);
|
|
14496
14707
|
continue;
|
|
14497
14708
|
}
|
|
14498
14709
|
/* GİRİŞ TİPİ + RİSK PROFİLİ (JEV kararı) — seviyeleri KOD hesaplar */
|
|
@@ -14535,8 +14746,29 @@ async function finTypeSafeRound(sid, agent) {
|
|
|
14535
14746
|
}
|
|
14536
14747
|
const sl = rnd(isBuy ? entry - slDist : entry + slDist);
|
|
14537
14748
|
const tp = rnd(isBuy ? entry + tpDist : entry - tpDist);
|
|
14749
|
+
/* RİSK + LOT: talimatta "risk %2" varsa AYNEN uygulanır; yoksa ayar ×
|
|
14750
|
+
kalibrasyon. Lot çarpanı ve MARTİNGALE (kayıp serisi × kat) burada. */
|
|
14538
14751
|
const riskBase = Number(f.riskPerTradePct) > 0 ? Number(f.riskPerTradePct) : 0.5;
|
|
14539
|
-
|
|
14752
|
+
let riskPct = ins.entry.riskPct != null
|
|
14753
|
+
? ins.entry.riskPct
|
|
14754
|
+
: Math.max(0.1, Math.min(2, Math.round(riskBase * cal.riskMult * 100) / 100));
|
|
14755
|
+
let sizeMult = 1;
|
|
14756
|
+
let martNote = '';
|
|
14757
|
+
if (ins.entry.lotMult != null) sizeMult *= ins.entry.lotMult;
|
|
14758
|
+
if (ins.entry.martingale != null) {
|
|
14759
|
+
let streak = 0;
|
|
14760
|
+
try {
|
|
14761
|
+
const le = finLearnLoad().symbols[sym];
|
|
14762
|
+
streak = Number(le && le.stats && le.stats.streak) || 0;
|
|
14763
|
+
} catch {}
|
|
14764
|
+
const pow = Math.min(3, Math.max(0, Math.round(streak)));
|
|
14765
|
+
if (pow > 0) {
|
|
14766
|
+
sizeMult *= Math.pow(ins.entry.martingale, pow);
|
|
14767
|
+
martNote = ` · martingale ×${ins.entry.martingale}^${pow}`;
|
|
14768
|
+
}
|
|
14769
|
+
}
|
|
14770
|
+
if (sizeMult !== 1) riskPct = Math.max(0.1, Math.min(10, Math.round(riskPct * sizeMult * 100) / 100));
|
|
14771
|
+
const riskNote = ins.entry.riskPct != null ? ' · TALİMAT risk %' + ins.entry.riskPct : '';
|
|
14540
14772
|
const emirLabel =
|
|
14541
14773
|
orderType === 'market' ? 'MARKET' :
|
|
14542
14774
|
isBuy && orderType === 'buy_limit' ? 'BUY LIMIT' :
|
|
@@ -14584,10 +14816,11 @@ async function finTypeSafeRound(sid, agent) {
|
|
|
14584
14816
|
orderType,
|
|
14585
14817
|
});
|
|
14586
14818
|
} catch {}
|
|
14819
|
+
const riskTxt = `risk %${riskPct}${ins.entry.riskPct == null && cal.riskMult !== 1 ? ` ×${cal.riskMult}` : ''}${riskNote}${martNote}`;
|
|
14587
14820
|
lines.push(
|
|
14588
14821
|
(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},
|
|
14822
|
+
? `- ${sym}: ⚡ MARKET ${c.choice.toUpperCase()} açıldı (lot ${r.opened && r.opened.volume}, SL ${sl}, TP ${tp}, ${riskTxt})`
|
|
14823
|
+
: `- ${sym}: ⏳ ${emirLabel} emri kondu @${entry} (${profKey} profil, SL ${sl}, TP ${tp}, ${riskTxt})`) +
|
|
14591
14824
|
` · p=${c.p.toFixed(2)} teyit=${confVal.toFixed(2)} · tf=${market[sym].tf}` +
|
|
14592
14825
|
(talimatZorunlu ? ' · TALİMAT: zorunlu giriş' : '') +
|
|
14593
14826
|
(thAction !== FIN_TS_DEFAULT_TH.action ? ` · öğrenilmiş eşik p≥${thAction.toFixed(2)}` : '')
|
|
@@ -14600,10 +14833,12 @@ async function finTypeSafeRound(sid, agent) {
|
|
|
14600
14833
|
}
|
|
14601
14834
|
/* JEV ARAÇ İSTEĞİ (tur düzeyi): eksik araç varsa TOOL botuna asenkron yazdır */
|
|
14602
14835
|
try { await finTsToolRequest(sidS, agent, ans, lines); } catch {}
|
|
14836
|
+
const insTxt = finInstrSummary(ins);
|
|
14603
14837
|
finTsPost(
|
|
14604
14838
|
sidS,
|
|
14605
14839
|
agent,
|
|
14606
14840
|
`🤖 TypeSafe karar turu #${agent.round} (LLM yok — girdi yalnız TypeSafe):\n` +
|
|
14841
|
+
(insTxt ? 'TALİMAT AYARLARI (kod uygular): ' + insTxt + '\n' : '') +
|
|
14607
14842
|
'TF KARARI: ' + symbols.map((s) => `${s}=${market[s].tf}`).join(', ') + '\n' +
|
|
14608
14843
|
'ÖĞRENİLMİŞ: ' +
|
|
14609
14844
|
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,90 @@ 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.5</code><code>martingale x2</code>',
|
|
10938
|
+
'<b>Kod otomatik uygular.</b> Kayıp serisinde lot katlanır (varsayılan ×2; 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
|
+
];
|
|
10948
|
+
const example = posmgr
|
|
10949
|
+
? `1- 1R'de %50 kısmi kapat\n2- kâr 2R'ye gelince kalanı kapat\n3- zarar -0.5R'yi geçerse kes`
|
|
10950
|
+
: `1- risk yüzde 2\n2- martingale kullan (x2)\n3- her mumda işlem açmak zorundasın\n4- başlangıç bakiye 10.000\n5- günlük zarar %3`;
|
|
10951
|
+
const head = posmgr
|
|
10952
|
+
? 'Pozisyon Yöneticisi (5 sn turu) açık pozisyonları yönetir: kapat / kısmi kapat / SL taşı.'
|
|
10953
|
+
: 'Trade Ajanı girişleri yönetir: yön, emir tipi, risk, lot, martingale ve günlük limitler.';
|
|
10954
|
+
const rows = items
|
|
10955
|
+
.map((it) => '<div class="fin-help-item"><div class="fin-help-code">' + it[0] + '</div><div class="fin-help-desc">' + it[1] + '</div></div>')
|
|
10956
|
+
.join('');
|
|
10957
|
+
return (
|
|
10958
|
+
'<div class="fin-help-head">' + head + '</div>' +
|
|
10959
|
+
'<div class="fin-help-sec">Neler yazabilirsin?</div>' +
|
|
10960
|
+
rows +
|
|
10961
|
+
'<div class="fin-help-sec">Nasıl yazılır?</div>' +
|
|
10962
|
+
'<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>' +
|
|
10963
|
+
'<pre class="fin-help-ex">' + example + '</pre>'
|
|
10964
|
+
);
|
|
10965
|
+
}
|
|
10966
|
+
|
|
10967
|
+
function finHelpOpen(which) {
|
|
10968
|
+
if (!els.finHelpOverlay) return;
|
|
10969
|
+
const posmgr = which === 'posmgr';
|
|
10970
|
+
if (els.finHelpTitle) els.finHelpTitle.textContent = posmgr ? 'POZİSYON YÖNETİCİSİ — TALİMAT KILAVUZU' : 'TRADE AJANI — TALİMAT KILAVUZU';
|
|
10971
|
+
if (els.finHelpBody) els.finHelpBody.innerHTML = finHelpHtml(which);
|
|
10972
|
+
els.finHelpOverlay.hidden = false;
|
|
10973
|
+
}
|
|
10974
|
+
|
|
10975
|
+
function finHelpClose() {
|
|
10976
|
+
if (els.finHelpOverlay) els.finHelpOverlay.hidden = true;
|
|
10977
|
+
}
|
|
10978
|
+
|
|
10889
10979
|
/* POZİSYON YÖNETİCİSİ: 5 sn Jev turu — kendi talimatı + aç/kapa */
|
|
10890
10980
|
if (els.finPosNote) {
|
|
10891
10981
|
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
|
|