beast-agent 2.61.0 → 2.62.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/engine.js +9 -1
- package/src/agent/financetools.js +9 -7
- package/src/agent/finrisk.js +28 -5
- package/src/main.js +9 -3
- package/src/renderer/index.html +6 -2
- package/src/renderer/renderer.js +15 -0
- package/src/renderer/style.css +2 -0
package/package.json
CHANGED
package/src/agent/engine.js
CHANGED
|
@@ -2057,7 +2057,15 @@ class Engine {
|
|
|
2057
2057
|
'VERİ AKIŞI (her değerlendirmede): mt5_account + mt5_positions + mt5_market çağrılarını AYNI turda PARALEL ver; gerekiyorsa mt5_history ile son işlemleri gör.\n' +
|
|
2058
2058
|
'PARALEL + KOORDİNASYON: uzun araştırma/işleri run_background ile paralel finance işçisine devret (parent finance olduğu için işçi mt5 okuma araçlarını görür); koşan ajanlarla konuşmak için agent_dm (to: ajan başlığındaki anahtar kelime, örn "GOLD"; ortak karar için group: "İSİM" ile grup sohbeti kur — mesaj tüm üyelere düşer). Görevin bitince DM/grup sohbetleri otomatik KAPANIR (geçmiş panelde kalır).\n' +
|
|
2059
2059
|
(symbols ? `İZLEME LİSTESİ: ${symbols}\n` : '') +
|
|
2060
|
-
(lim.
|
|
2060
|
+
(lim.minLot || lim.maxLot
|
|
2061
|
+
? 'LİMİTLER: ' +
|
|
2062
|
+
[
|
|
2063
|
+
lim.minLot ? `min lot ${lim.minLot}` : null,
|
|
2064
|
+
lim.maxLot ? `max lot ${lim.maxLot}` : null,
|
|
2065
|
+
lim.maxPositions ? `max eşzamanlı pozisyon ${lim.maxPositions}` : null,
|
|
2066
|
+
].filter(Boolean).join(' · ') +
|
|
2067
|
+
' — bunları aşıp araç kullanma; sistem zaten reddeder (lot min lot altına inemez, max lot üstüne çıkamaz).\n'
|
|
2068
|
+
: '') +
|
|
2061
2069
|
'RİSK DİSİPLİNİ:\n' +
|
|
2062
2070
|
'- SL\u2019siz pozisyon BIRAKMA: açtığın her işlemde mantıklı bir SL koy; SL\u2019siz kalan pozisyonu mt5_modify ile tamamla.\n' +
|
|
2063
2071
|
'- Martingale/kademeli lot artışı YASAK; kaybı geri kovalama (revenge trade) YASAK.\n' +
|
|
@@ -31,7 +31,7 @@ const NAMES = [
|
|
|
31
31
|
'mt5_cancel',
|
|
32
32
|
];
|
|
33
33
|
|
|
34
|
-
let getCfg = () => ({ allowTrading: false, maxLot: 0.1, maxPositions: 3, symbols: [] });
|
|
34
|
+
let getCfg = () => ({ allowTrading: false, minLot: 0.01, maxLot: 0.1, maxPositions: 3, symbols: [] });
|
|
35
35
|
let notify = () => {};
|
|
36
36
|
/* DİSİPLİN KANCASI (main enjekte eder): kodla zorlanan kurallar — günlük işlem
|
|
37
37
|
limiti, kayıp serisi molası, re-entry beklemesi, kur maruziyeti.
|
|
@@ -273,7 +273,7 @@ const definitions = NAMES.map((name) => {
|
|
|
273
273
|
enum: ['market', 'buy_market', 'sell_market', 'buy_limit', 'sell_limit', 'buy_stop', 'sell_stop'],
|
|
274
274
|
description: 'Emir tipi. Boş/side verilirse piyasa (anlık); limit/stop verilirse bekleyen emir (price zorunlu olur).',
|
|
275
275
|
},
|
|
276
|
-
volume: { type: 'number', description: 'Lot (max lot sınırına tabi) — boşsa riskPct + sl ile OTOMATİK hesaplanır' },
|
|
276
|
+
volume: { type: 'number', description: 'Lot (min/max lot sınırına tabi) — boşsa riskPct + sl ile OTOMATİK hesaplanır' },
|
|
277
277
|
riskPct: { type: 'number', description: 'İşlem riski % (ör. 0.5-2) — volume yerine ver: SL mesafesinden lot hesaplanır (sl zorunlu)' },
|
|
278
278
|
price: { type: 'number', description: 'Limit/stop emirlerinde tetik fiyatı (piyasa emrinde gerekmez)' },
|
|
279
279
|
sl: { type: 'number', description: 'Stop loss fiyatı (0 = yok) — şiddetle önerilir' },
|
|
@@ -565,7 +565,7 @@ const handlers = {
|
|
|
565
565
|
const balance = Number(acct && acct.account && acct.account.balance) || 0;
|
|
566
566
|
if (!(balance > 0)) return { ok: false, error: 'bakiye okunamadı' };
|
|
567
567
|
const riskAmount = (balance * riskPct) / 100;
|
|
568
|
-
const res = finrisk.calcRiskLot(info, entry, sl, riskAmount, cfg.maxLot);
|
|
568
|
+
const res = finrisk.calcRiskLot(info, entry, sl, riskAmount, cfg.maxLot, cfg.minLot);
|
|
569
569
|
if (res.error) return { ok: false, error: res.error, raw: res.raw, lossPerLot: res.lossPerLot, riskAmount: Math.round(riskAmount * 100) / 100 };
|
|
570
570
|
const digits = Number(info.digits) || 5;
|
|
571
571
|
const dist = Math.abs(entry - sl);
|
|
@@ -584,7 +584,9 @@ const handlers = {
|
|
|
584
584
|
atr: atr != null ? Math.round(atr * 1e6) / 1e6 : null,
|
|
585
585
|
timeframe: timeframe || null,
|
|
586
586
|
capped: !!res.capped,
|
|
587
|
+
raised: !!res.raised,
|
|
587
588
|
warning: closeErr || undefined,
|
|
589
|
+
minLot: Number(cfg.minLot) || 0.01,
|
|
588
590
|
maxLot: Number(cfg.maxLot) || 0.1,
|
|
589
591
|
};
|
|
590
592
|
},
|
|
@@ -623,12 +625,12 @@ const handlers = {
|
|
|
623
625
|
const acct = await bcall('account', {}, 8000);
|
|
624
626
|
const balance = Number(acct && acct.account && acct.account.balance) || 0;
|
|
625
627
|
const riskAmount = (balance * riskPct) / 100;
|
|
626
|
-
const rr = finrisk.calcRiskLot(info, price, sl, riskAmount, maxLot);
|
|
628
|
+
const rr = finrisk.calcRiskLot(info, price, sl, riskAmount, maxLot, cfg.minLot);
|
|
627
629
|
if (rr.error) return { ok: false, error: rr.error };
|
|
628
630
|
vol = rr.volume;
|
|
629
|
-
riskInfo = { riskPct, riskAmount: Math.round(riskAmount * 100) / 100, lossPerLot: rr.lossPerLot };
|
|
631
|
+
riskInfo = { riskPct, riskAmount: Math.round(riskAmount * 100) / 100, lossPerLot: rr.lossPerLot, raised: !!rr.raised };
|
|
630
632
|
} else {
|
|
631
|
-
const norm = finrisk.normalizeVolume(info, wantVolume, maxLot);
|
|
633
|
+
const norm = finrisk.normalizeVolume(info, wantVolume, maxLot, cfg.minLot);
|
|
632
634
|
if (norm.error) return { ok: false, error: norm.error };
|
|
633
635
|
vol = norm.volume;
|
|
634
636
|
}
|
|
@@ -745,7 +747,7 @@ const handlers = {
|
|
|
745
747
|
if (!symbol) return { ok: false, error: 'symbol gerekli' };
|
|
746
748
|
const info = await symInfoRow(symbol);
|
|
747
749
|
if (!info) return { ok: false, error: 'sembol bulunamadı: ' + symbol + ' (MT5 Market Watch?)' };
|
|
748
|
-
const norm = finrisk.normalizeVolume(info, args.volume, Number(cfg.maxLot) || 0.1);
|
|
750
|
+
const norm = finrisk.normalizeVolume(info, args.volume, Number(cfg.maxLot) || 0.1, cfg.minLot);
|
|
749
751
|
if (norm.error) return { ok: false, error: norm.error };
|
|
750
752
|
const vol = norm.volume;
|
|
751
753
|
const ptype = t.type;
|
package/src/agent/finrisk.js
CHANGED
|
@@ -16,24 +16,46 @@ function stepFloor(v, step) {
|
|
|
16
16
|
return Math.floor(v / s + 1e-9) * s;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
function stepCeil(v, step) {
|
|
20
|
+
const s = num(step, 0.01);
|
|
21
|
+
if (!(s > 0)) return v;
|
|
22
|
+
return Math.ceil(v / s - 1e-9) * s;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* info: MT5 symbol_info satırı. wanted: istenen lot. hardMax: kullanıcı üst
|
|
26
|
+
limiti (max lot). hardMin: kullanıcı alt limiti (min lot) — istenen lot bu
|
|
27
|
+
tabanın altındaysa adıma yukarı yuvarlanır (raised). */
|
|
28
|
+
function normalizeVolume(info, wanted, hardMax, hardMin) {
|
|
21
29
|
const vmin = num(info && info.volume_min, 0.01);
|
|
22
30
|
const vmax = num(info && info.volume_max, 100);
|
|
23
31
|
const step = num(info && info.volume_step, 0.01);
|
|
24
32
|
let v = num(wanted, 0);
|
|
25
33
|
if (!(v > 0)) return { error: 'volume gerekli (pozitif sayı)' };
|
|
26
34
|
const cap = Math.min(vmax > 0 ? vmax : Infinity, num(hardMax, 0) > 0 ? num(hardMax, 0) : Infinity);
|
|
35
|
+
const floor = num(hardMin, 0) > 0 ? num(hardMin, 0) : 0;
|
|
27
36
|
let capped = false;
|
|
37
|
+
let raised = false;
|
|
28
38
|
if (v > cap) {
|
|
29
39
|
v = stepFloor(cap, step);
|
|
30
40
|
capped = true;
|
|
31
41
|
}
|
|
42
|
+
if (v < floor - 1e-9) {
|
|
43
|
+
v = stepCeil(floor, step);
|
|
44
|
+
raised = true;
|
|
45
|
+
}
|
|
32
46
|
v = Math.round(stepFloor(v, step) * 1e8) / 1e8;
|
|
33
47
|
if (!(v > 0) || v < vmin - 1e-9) {
|
|
34
48
|
return { error: `hacim broker minimumunun altında (min ${vmin} lot)` };
|
|
35
49
|
}
|
|
36
|
-
|
|
50
|
+
if (v > cap + 1e-9) {
|
|
51
|
+
/* min lot tabanı broker adımıyla üst limite sığmadı — üst limitte kal */
|
|
52
|
+
v = Math.round(stepFloor(cap, step) * 1e8) / 1e8;
|
|
53
|
+
capped = true;
|
|
54
|
+
if (!(v > 0) || v < vmin - 1e-9) {
|
|
55
|
+
return { error: `hacim broker minimumunun altında (min ${vmin} lot)` };
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return { volume: v, capped, raised };
|
|
37
59
|
}
|
|
38
60
|
|
|
39
61
|
/* 1 lot için SL mesafesi kaybı (hesap para birimi): tick değeri, yoksa kontrat */
|
|
@@ -49,11 +71,11 @@ function lossPerLot(info, entry, sl) {
|
|
|
49
71
|
}
|
|
50
72
|
|
|
51
73
|
/* riskAmount: hesap para birimi cinsinden kaybedilecek tutar */
|
|
52
|
-
function calcRiskLot(info, entry, sl, riskAmount, hardMax) {
|
|
74
|
+
function calcRiskLot(info, entry, sl, riskAmount, hardMax, hardMin) {
|
|
53
75
|
const lpl = lossPerLot(info, entry, sl);
|
|
54
76
|
if (!(lpl > 0)) return { error: 'risk hesaplanamadı (tick değeri/kontrat bilgisi yok)' };
|
|
55
77
|
const raw = num(riskAmount, 0) / lpl;
|
|
56
|
-
const norm = normalizeVolume(info, raw, hardMax);
|
|
78
|
+
const norm = normalizeVolume(info, raw, hardMax, hardMin);
|
|
57
79
|
if (norm.error) return { error: norm.error, raw, lossPerLot: lpl };
|
|
58
80
|
return {
|
|
59
81
|
volume: norm.volume,
|
|
@@ -61,6 +83,7 @@ function calcRiskLot(info, entry, sl, riskAmount, hardMax) {
|
|
|
61
83
|
lossPerLot: Math.round(lpl * 100) / 100,
|
|
62
84
|
riskAmount: Math.round(raw * lpl * 100) / 100,
|
|
63
85
|
capped: !!norm.capped,
|
|
86
|
+
raised: !!norm.raised,
|
|
64
87
|
};
|
|
65
88
|
}
|
|
66
89
|
|
package/src/main.js
CHANGED
|
@@ -9387,7 +9387,10 @@ function finCfg() {
|
|
|
9387
9387
|
f.roleSkills.trader = cur.map((s) => String(s || '').trim()).filter(Boolean).slice(0, 1);
|
|
9388
9388
|
}
|
|
9389
9389
|
if (!Number(f.intervalSec)) f.intervalSec = 120;
|
|
9390
|
+
if (!Number(f.minLot)) f.minLot = 0.01;
|
|
9390
9391
|
if (!Number(f.maxLot)) f.maxLot = 0.1;
|
|
9392
|
+
/* LOT ARALIĞI KILİDİ: min lot hiçbir zaman max lotu aşamaz */
|
|
9393
|
+
if (f.minLot > f.maxLot) f.minLot = f.maxLot;
|
|
9391
9394
|
if (f.maxPositions == null) f.maxPositions = 3;
|
|
9392
9395
|
/* KODLA DİSİPLİN (trader kuralları): hepsi 0 = kural kapalı */
|
|
9393
9396
|
if (!Number.isFinite(Number(f.maxTradesPerDay))) f.maxTradesPerDay = 10;
|
|
@@ -11403,7 +11406,7 @@ function finApplyTraderFields(s, symbolsOverride, role, isMain) {
|
|
|
11403
11406
|
s.financeSymbols = Array.isArray(symbolsOverride) && symbolsOverride.length ? symbolsOverride : f.symbols;
|
|
11404
11407
|
s.financeStrategy = String(f.strategy || '');
|
|
11405
11408
|
s.financeShadow = !!f.shadowMode; /* shadow modda işlem araçları emir göndermez */
|
|
11406
|
-
s.financeLimits = { maxLot: f.maxLot, maxPositions: f.maxPositions };
|
|
11409
|
+
s.financeLimits = { minLot: f.minLot, maxLot: f.maxLot, maxPositions: f.maxPositions };
|
|
11407
11410
|
/* ZORUNLU TEK skill: rol ajanı → roleSkills[rol], ana trader → roleSkills.trader */
|
|
11408
11411
|
const skillKey = r || (s.financePlaybook ? 'trader' : '');
|
|
11409
11412
|
s.financeRoleSkills = (skillKey && f.roleSkills && f.roleSkills[skillKey]) || [];
|
|
@@ -11499,7 +11502,7 @@ function finTraderBrief(agent) {
|
|
|
11499
11502
|
return [
|
|
11500
11503
|
`Beast Finance ${who} başlatıldı — ilk tur: strateji çerçeveni kur ve piyasa taramasını yap.`,
|
|
11501
11504
|
`Odak semboller: ${syms || '(boş — mt5_status ile terminale bak, mantıklı semboller seç)'}`,
|
|
11502
|
-
`Tur aralığı: ${f.intervalSec} sn ·
|
|
11505
|
+
`Tur aralığı: ${f.intervalSec} sn · Lot aralığı: ${f.minLot}–${f.maxLot} (min lot tabanı zorlanır, max lot tavanı aşılamaz) · Max eşzamanlı pozisyon: ${f.maxPositions}`,
|
|
11503
11506
|
roleDef
|
|
11504
11507
|
? `UZMANLIK: ${roleDef.desc} — raporlarını bu çerçevede yaz; İŞLEM AÇMA, yalnız analiz + net öneri üret.`
|
|
11505
11508
|
: 'Otomatik işlem AÇIK (daima): 6 emir tipinin HEPSİ açık — buy_market/sell_market (anlık piyasa), buy_limit/sell_limit ve buy_stop/sell_stop (bekleyen; price zorunlu). mt5_trade ya da mt5_pending İKİSİ de tüm tipleri kabul eder; ayrıca mt5_close/mt5_modify/mt5_cancel açık (limitler sistemce zorlanır). KISMİ KAPATMA yetkisi: kısmi TP (kâr al) ve kısmi stop (zarar kes) — mt5_close {percent, kind:"partial_tp"|"partial_sl"}; otomatik DEĞİL, gerek görürsen sen kullan. ALARM: mt5_alerts ile kurarken modu SEN seç — mode:"once" tek seferlik, mode:"repeat" + cooldownMin (dk) tekrarlı. Lot için mt5_risksize hesapla ya da mt5_trade’e riskPct ver; SL/TP broker stops_level mesafesine uymalı.',
|
|
@@ -11596,7 +11599,7 @@ async function finConsultPlan(f, agent, sid) {
|
|
|
11596
11599
|
'Güncel piyasa bağlamı gerekiyorsa web_search kullan; kurulu bir skill konuyla ilgiliyse skill aracıyla oku.';
|
|
11597
11600
|
const ctx = [
|
|
11598
11601
|
`Odak semboller: ${agent && agent.symbols && agent.symbols.length ? agent.symbols.join(', ') : (f.symbols || []).join(', ') || '(boş — ajan kendi bulabilir)'}`,
|
|
11599
|
-
`Otomatik işlem: ${auto} ·
|
|
11602
|
+
`Otomatik işlem: ${auto} · lot aralığı ${f.minLot}–${f.maxLot} · max eşzamanlı pozisyon ${f.maxPositions}`,
|
|
11600
11603
|
account
|
|
11601
11604
|
? `Hesap: bakiye ${account.balance} ${account.currency} · özkaynak ${account.equity ?? '?'} · serbest marj ${account.margin_free ?? '?'} · kaldıraç 1:${account.leverage ?? '?'}`
|
|
11602
11605
|
: 'Hesap verisi alınamadı.',
|
|
@@ -12007,6 +12010,9 @@ ipcMain.handle('finance:settings', async (_e, patch) => {
|
|
|
12007
12010
|
}
|
|
12008
12011
|
}
|
|
12009
12012
|
if (p.maxLot !== undefined) f.maxLot = Math.max(0.01, Math.min(100, Number(p.maxLot) || 0.1));
|
|
12013
|
+
if (p.minLot !== undefined) f.minLot = Math.max(0.01, Math.min(100, Number(p.minLot) || 0.01));
|
|
12014
|
+
/* min lot max lotu aşamaz — hangisi sonra yazıldıysa diğerine kelepçelenir */
|
|
12015
|
+
if (f.minLot > f.maxLot) f.minLot = f.maxLot;
|
|
12010
12016
|
if (p.maxPositions !== undefined) f.maxPositions = Math.max(1, Math.min(20, Math.round(Number(p.maxPositions) || 3)));
|
|
12011
12017
|
/* RİSK OTOMASYONU + BİLDİRİM ayarları */
|
|
12012
12018
|
if (p.watchdog !== undefined) f.watchdog = !!p.watchdog;
|
package/src/renderer/index.html
CHANGED
|
@@ -169,14 +169,18 @@
|
|
|
169
169
|
<span>Model</span>
|
|
170
170
|
<select id="finTraderModel" title="Trader ajanının modeli — farklı API/model seçilebilir"></select>
|
|
171
171
|
</div>
|
|
172
|
-
<div class="fin-
|
|
172
|
+
<div class="fin-grid3" title="Değişiklik anında kaydedilir — ajanı DURDURMADAN sonraki tura uygulanır">
|
|
173
173
|
<div class="fin-field">
|
|
174
174
|
<span>Tur (sn)</span>
|
|
175
175
|
<input id="finInterval" type="number" min="30" max="3600" step="10" />
|
|
176
176
|
</div>
|
|
177
|
+
<div class="fin-field">
|
|
178
|
+
<span>Min lot</span>
|
|
179
|
+
<input id="finMinLot" type="number" min="0.01" max="100" step="0.01" title="Alt sınır: lot hesapları bu tabanın altına inemez — taban altındaki lotlar adıma yukarı yuvarlanır (broker minimumunun üzerinde bir taban koyar)" />
|
|
180
|
+
</div>
|
|
177
181
|
<div class="fin-field">
|
|
178
182
|
<span>Max lot</span>
|
|
179
|
-
<input id="finMaxLot" type="number" min="0.01" max="100" step="0.01" />
|
|
183
|
+
<input id="finMaxLot" type="number" min="0.01" max="100" step="0.01" title="Üst sınır: lot hesapları bu tavanın üzerine çıkamaz (min lotun altına inemez)" />
|
|
180
184
|
</div>
|
|
181
185
|
</div>
|
|
182
186
|
<div class="fin-field">
|
package/src/renderer/renderer.js
CHANGED
|
@@ -223,6 +223,7 @@ const els = {
|
|
|
223
223
|
finTraderModel: $('#finTraderModel'),
|
|
224
224
|
finModelRefreshBtn: $('#finModelRefreshBtn'),
|
|
225
225
|
finInterval: $('#finInterval'),
|
|
226
|
+
finMinLot: $('#finMinLot'),
|
|
226
227
|
finMaxLot: $('#finMaxLot'),
|
|
227
228
|
finStrategy: $('#finStrategy'),
|
|
228
229
|
finMaxTradesDay: $('#finMaxTradesDay'),
|
|
@@ -9803,6 +9804,7 @@ function finTraderInputsSet(cfg) {
|
|
|
9803
9804
|
: [];
|
|
9804
9805
|
const ae = document.activeElement;
|
|
9805
9806
|
if (els.finInterval && ae !== els.finInterval) els.finInterval.value = cfg.intervalSec || 120;
|
|
9807
|
+
if (els.finMinLot && ae !== els.finMinLot) els.finMinLot.value = cfg.minLot || 0.01;
|
|
9806
9808
|
if (els.finMaxLot && ae !== els.finMaxLot) els.finMaxLot.value = cfg.maxLot || 0.1;
|
|
9807
9809
|
if (els.finStrategy && ae !== els.finStrategy && !finStrategyDirty) els.finStrategy.value = cfg.strategy || '';
|
|
9808
9810
|
if (els.finMaxTradesDay && ae !== els.finMaxTradesDay) els.finMaxTradesDay.value = Number(cfg.maxTradesPerDay) || 0;
|
|
@@ -10529,9 +10531,22 @@ if (els.finInterval) els.finInterval.addEventListener('change', () => {
|
|
|
10529
10531
|
if (els.finMaxLot) els.finMaxLot.addEventListener('change', () => {
|
|
10530
10532
|
const v = Math.max(0.01, Math.min(100, Number(els.finMaxLot.value) || 0.1));
|
|
10531
10533
|
els.finMaxLot.value = v;
|
|
10534
|
+
/* min lot max lotu aşamaz — görünürde de kelepçele (sunucu ayrıca zorlar) */
|
|
10535
|
+
if (els.finMinLot && Number(els.finMinLot.value) > v) els.finMinLot.value = v;
|
|
10532
10536
|
finSaveCfg({ maxLot: v });
|
|
10533
10537
|
toast('Max lot: ' + v + ' — sonraki turdan itibaren geçerli');
|
|
10534
10538
|
});
|
|
10539
|
+
if (els.finMinLot) els.finMinLot.addEventListener('change', () => {
|
|
10540
|
+
const maxV = Math.max(0.01, Math.min(100, Number(els.finMaxLot && els.finMaxLot.value) || 0.1));
|
|
10541
|
+
let v = Math.max(0.01, Math.min(100, Number(els.finMinLot.value) || 0.01));
|
|
10542
|
+
if (v > maxV) {
|
|
10543
|
+
v = maxV;
|
|
10544
|
+
toast('Min lot max lotu aşamaz — ' + v + ' olarak ayarlandı');
|
|
10545
|
+
}
|
|
10546
|
+
els.finMinLot.value = v;
|
|
10547
|
+
finSaveCfg({ minLot: v });
|
|
10548
|
+
toast('Min lot: ' + v + ' — lot hesapları bu tabanın altına inmez');
|
|
10549
|
+
});
|
|
10535
10550
|
if (els.finSymBtn) els.finSymBtn.addEventListener('click', finSymPickerOpen);
|
|
10536
10551
|
|
|
10537
10552
|
/* RİSK OTOMASYONU kontrolleri: değişiklik anında kaydedilir (ajan turunu beklemez) */
|
package/src/renderer/style.css
CHANGED
|
@@ -5447,6 +5447,8 @@ body.finance-mode #composerWrap { margin-right: var(--finW, 400px); }
|
|
|
5447
5447
|
.fin-field .fin-sym-select { width: 100%; }
|
|
5448
5448
|
.fin-grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
|
|
5449
5449
|
.fin-grid2 .fin-field { margin-bottom: 8px; }
|
|
5450
|
+
.fin-grid3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
|
|
5451
|
+
.fin-grid3 .fin-field { margin-bottom: 8px; }
|
|
5450
5452
|
.fin-hint { font-style: normal; opacity: 0.75; }
|
|
5451
5453
|
/* RİSK OTOMASYONU + PERFORMANS kartları */
|
|
5452
5454
|
.fin-check label { display: flex; align-items: center; gap: 6px; font-size: 11px; color: var(--text); cursor: pointer; }
|