beast-agent 2.63.5 → 2.63.7
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 +468 -0
- package/src/renderer/index.html +1 -1
package/package.json
CHANGED
package/src/main.js
CHANGED
|
@@ -10690,6 +10690,12 @@ function finWakeAgentDm(sid, text) {
|
|
|
10690
10690
|
finTradeHoursBlockedLog('olay uyandırması');
|
|
10691
10691
|
return false;
|
|
10692
10692
|
}
|
|
10693
|
+
/* TYPESAFE-ONLY: LLM turu BAŞLATILMAZ — olay TS turunu öne çeker; prompt/
|
|
10694
|
+
pendingReports hattı (engine.send) bu modda hiç kullanılmaz */
|
|
10695
|
+
if (finTsAgentMode(agent)) {
|
|
10696
|
+
if (!agent.tsBusy) finTypeSafeKick(id, agent);
|
|
10697
|
+
return true;
|
|
10698
|
+
}
|
|
10693
10699
|
try {
|
|
10694
10700
|
const body = agent.role
|
|
10695
10701
|
? String(text || '') + "\n(ROL HATIRLATMASI: işlem AÇMA — durumu analiz et; gerekiyorsa agent_dm ile ANA TRADER'a bildir.)"
|
|
@@ -12863,6 +12869,446 @@ function finTeamWaitTick(sid) {
|
|
|
12863
12869
|
finAgentRound(sid, { noTeamWait: true });
|
|
12864
12870
|
}
|
|
12865
12871
|
|
|
12872
|
+
/* ---------- TYPESAFE-ONLY FİNANS MODU (LLM'SİZ) ----------
|
|
12873
|
+
Rol→Skill eşleştirmesinde "typesafe-ai" seçiliyse ajan LLM HİÇ kullanmaz:
|
|
12874
|
+
tur verisi (fiyat/gösterge/pozisyon/öğrenme geçmişi/ekip yanıtları) YALNIZ
|
|
12875
|
+
TypeSafe System One'a gider; yanıtlar olasılık olarak döner, kararı KOD
|
|
12876
|
+
uygular. Yanıtlar AJAN DM ekip grubuna yazılır — tüm ajanlar birbirinin
|
|
12877
|
+
cevabını görür (son yanıtlar sonraki turların state'ine de girer) ve emirler
|
|
12878
|
+
YALNIZ market buy/sell olarak açılır (bekleyen emir YOK). */
|
|
12879
|
+
const FIN_TS_ACTION_P = 0.6; /* choice: işlem için min olasılık */
|
|
12880
|
+
const FIN_TS_MARGIN_P = 0.12; /* birinci ile ikinci seçenek arası min fark */
|
|
12881
|
+
const FIN_TS_CONFIRM_P = 0.55; /* noul teyit eşiği */
|
|
12882
|
+
const FIN_TS_EXIT_P = 0.62; /* pozisyon kapatma eşiği */
|
|
12883
|
+
const FIN_TS_MAX_SYMBOLS = 3; /* tur başına işlenecek sembol tavanı */
|
|
12884
|
+
const FIN_TS_ROLE_TF = { technic: 'M15', risk: 'H1', macro: 'H4', visual: 'M15' };
|
|
12885
|
+
const FIN_TS_ROLE_CRIT = {
|
|
12886
|
+
technic: {
|
|
12887
|
+
yukari: 'Boğa yapısı — HH/HL, yükseliş trendi, kırılım teyidi',
|
|
12888
|
+
asagi: 'Ayı yapısı — LH/LL, düşüş trendi, kırılım teyidi',
|
|
12889
|
+
yatay: 'Yatay/range — yön teyidi yok',
|
|
12890
|
+
},
|
|
12891
|
+
risk: {
|
|
12892
|
+
uygun: 'Risk limitleri uygun — pozisyon açılabilir',
|
|
12893
|
+
dikkat: 'Sınırda — küçük lot / ek teyit şart',
|
|
12894
|
+
uygundegil: 'Uygun değil — açma, mevcudu küçült',
|
|
12895
|
+
},
|
|
12896
|
+
macro: {
|
|
12897
|
+
pozitif: 'Makro akış pozitif (faiz/veri/jeopolitik destekliyor)',
|
|
12898
|
+
negatif: 'Makro akış negatif (risk iştahı bozuk)',
|
|
12899
|
+
notr: 'Makro etki nötr/belirsiz',
|
|
12900
|
+
},
|
|
12901
|
+
visual: {
|
|
12902
|
+
yukari: 'Grafik yapısı yukarı (formasyon/trend yukarı)',
|
|
12903
|
+
asagi: 'Grafik yapısı aşağı',
|
|
12904
|
+
yatay: 'Yatay/sıkışma — formasyon yok',
|
|
12905
|
+
},
|
|
12906
|
+
};
|
|
12907
|
+
|
|
12908
|
+
function finTsAgentMode(agent) {
|
|
12909
|
+
try {
|
|
12910
|
+
const f = finCfg();
|
|
12911
|
+
const key = agent && agent.main ? 'trader' : String((agent && agent.role) || '');
|
|
12912
|
+
if (!key) return false;
|
|
12913
|
+
const list = f.roleSkills && Array.isArray(f.roleSkills[key]) ? f.roleSkills[key] : [];
|
|
12914
|
+
return list.some((s) => String(s || '').toLowerCase() === 'typesafe-ai');
|
|
12915
|
+
} catch {
|
|
12916
|
+
return false;
|
|
12917
|
+
}
|
|
12918
|
+
}
|
|
12919
|
+
|
|
12920
|
+
function finTsWho(agent, extra) {
|
|
12921
|
+
const role = agent && agent.main ? 'TRADER' : ((finRoleDef(agent && agent.role) || {}).label || 'FİNANS').toUpperCase();
|
|
12922
|
+
return 'TypeSafe · ' + role + (extra ? ' · ' + extra : '');
|
|
12923
|
+
}
|
|
12924
|
+
|
|
12925
|
+
/* TypeSafe yanıtını AJAN DM ekip grubuna yaz (panelde görünür) + state için
|
|
12926
|
+
besleme tamponuna ekle (ajanlar birbirini sonraki turda görür) */
|
|
12927
|
+
function finTsPost(sid, agent, text, topic) {
|
|
12928
|
+
const body = String(text || '').trim();
|
|
12929
|
+
if (!body) return;
|
|
12930
|
+
try {
|
|
12931
|
+
if (engine && typeof engine.agentDmGroupPost === 'function') {
|
|
12932
|
+
engine.agentDmGroupPost({
|
|
12933
|
+
gid: FIN_TEAM_GID,
|
|
12934
|
+
title: FIN_TEAM_TITLE,
|
|
12935
|
+
fromSid: String(sid),
|
|
12936
|
+
fromTitle: finTsWho(agent),
|
|
12937
|
+
topic: String(topic || 'typesafe'),
|
|
12938
|
+
text: body,
|
|
12939
|
+
});
|
|
12940
|
+
}
|
|
12941
|
+
} catch {}
|
|
12942
|
+
try {
|
|
12943
|
+
financeState.tsFeed = Array.isArray(financeState.tsFeed) ? financeState.tsFeed : [];
|
|
12944
|
+
financeState.tsFeed.push({ at: Date.now(), sid: String(sid), who: finTsWho(agent, topic), text: body });
|
|
12945
|
+
while (financeState.tsFeed.length > 30) financeState.tsFeed.shift();
|
|
12946
|
+
} catch {}
|
|
12947
|
+
}
|
|
12948
|
+
|
|
12949
|
+
function finTsFeedText(limit) {
|
|
12950
|
+
const feed = Array.isArray(financeState.tsFeed) ? financeState.tsFeed.slice(-(Math.max(1, Number(limit) || 6))) : [];
|
|
12951
|
+
if (!feed.length) return '(ekip yanıtı yok)';
|
|
12952
|
+
return feed.map((x) => `- ${x.who}: ${String(x.text || '').replace(/\s+/g, ' ').slice(0, 220)}`).join('\n');
|
|
12953
|
+
}
|
|
12954
|
+
|
|
12955
|
+
/* ZAMAN DİLİMİ BOT KARARI: önce öğrenmede en iyi net getiren periyot (>=3
|
|
12956
|
+
işlem), sonra ajanın seçimi, sonra rol varsayılanı */
|
|
12957
|
+
function finTsPickTf(agent, symbol) {
|
|
12958
|
+
try {
|
|
12959
|
+
const sym = String(symbol || '').toUpperCase();
|
|
12960
|
+
const e = finLearnLoad().symbols[sym];
|
|
12961
|
+
const byTf = (e && e.stats && e.stats.byTf) || {};
|
|
12962
|
+
let best = '';
|
|
12963
|
+
let bestNet = -Infinity;
|
|
12964
|
+
for (const [tf, s] of Object.entries(byTf)) {
|
|
12965
|
+
if (!s || Number(s.trades) < 3) continue;
|
|
12966
|
+
const n = Number(s.net) || 0;
|
|
12967
|
+
if (n > bestNet) { bestNet = n; best = tf; }
|
|
12968
|
+
}
|
|
12969
|
+
if (best) return best;
|
|
12970
|
+
} catch {}
|
|
12971
|
+
const role = String((agent && agent.role) || '');
|
|
12972
|
+
return finLearnNormTf(agent && agent.tsTf) || FIN_TS_ROLE_TF[role] || 'M15';
|
|
12973
|
+
}
|
|
12974
|
+
|
|
12975
|
+
function finTsChoice(ans, id) {
|
|
12976
|
+
const a = ans && ans.answers && ans.answers[id];
|
|
12977
|
+
if (!a || a.type !== 'choice') return null;
|
|
12978
|
+
const probs = a.probabilities && typeof a.probabilities === 'object' ? a.probabilities : {};
|
|
12979
|
+
const top = String(a.choice || '');
|
|
12980
|
+
let p = Number(probs[top]);
|
|
12981
|
+
if (!isFinite(p)) { p = 0; for (const v of Object.values(probs)) p = Math.max(p, Number(v) || 0); }
|
|
12982
|
+
let second = 0;
|
|
12983
|
+
for (const [k, v] of Object.entries(probs)) {
|
|
12984
|
+
if (k === top) continue;
|
|
12985
|
+
second = Math.max(second, Number(v) || 0);
|
|
12986
|
+
}
|
|
12987
|
+
return { choice: top, p, second, conf: Number(a.confidence) || 0, probs };
|
|
12988
|
+
}
|
|
12989
|
+
|
|
12990
|
+
function finTsNoul(ans, id) {
|
|
12991
|
+
const a = ans && ans.answers && ans.answers[id];
|
|
12992
|
+
if (!a || a.type !== 'noul') return null;
|
|
12993
|
+
const n = Number(a.noul);
|
|
12994
|
+
return isFinite(n) ? n : null;
|
|
12995
|
+
}
|
|
12996
|
+
|
|
12997
|
+
function finTsScore(ans, id) {
|
|
12998
|
+
const a = ans && ans.answers && ans.answers[id];
|
|
12999
|
+
if (!a || a.type !== 'score') return null;
|
|
13000
|
+
return { score: Number(a.score) || 0, conf: Number(a.confidence) || 0, probs: a.probabilities || {} };
|
|
13001
|
+
}
|
|
13002
|
+
|
|
13003
|
+
/* TypeSafe System One çağrısı — state + tipli sorular; tek giriş noktası */
|
|
13004
|
+
async function finTsAsk(state, questions) {
|
|
13005
|
+
return await typesafeMod.systemOne({ state, questions });
|
|
13006
|
+
}
|
|
13007
|
+
|
|
13008
|
+
function finTsFmtChoice(c) {
|
|
13009
|
+
if (!c) return 'yanıt yok';
|
|
13010
|
+
const probs = Object.entries(c.probs || {}).map(([k, v]) => `${k}=${(Number(v) || 0).toFixed(2)}`).join(' ');
|
|
13011
|
+
return `${c.choice} (p=${c.p.toFixed(2)}, güven=${c.conf.toFixed(2)})` + (probs ? ' [' + probs + ']' : '');
|
|
13012
|
+
}
|
|
13013
|
+
|
|
13014
|
+
function finTsIndLine(ind) {
|
|
13015
|
+
if (!ind || ind.ok !== true) return null;
|
|
13016
|
+
const g = (k) => {
|
|
13017
|
+
const row = ind.indicators && ind.indicators[k];
|
|
13018
|
+
return row && Array.isArray(row.last) ? Number(row.last[row.last.length - 1]) : null;
|
|
13019
|
+
};
|
|
13020
|
+
return {
|
|
13021
|
+
atr14: g('ATR(14)'),
|
|
13022
|
+
ema50: g('EMA(50)'),
|
|
13023
|
+
ema200: g('EMA(200)'),
|
|
13024
|
+
rsi14: g('RSI(14)'),
|
|
13025
|
+
close: Number(ind.close) || null,
|
|
13026
|
+
range20: ind.range20 || null,
|
|
13027
|
+
};
|
|
13028
|
+
}
|
|
13029
|
+
|
|
13030
|
+
function finTsSchedule(sid, agent, sec) {
|
|
13031
|
+
if (!agent || !financeState.agents.has(String(sid))) return;
|
|
13032
|
+
clearTimeout(agent.timer);
|
|
13033
|
+
const s = Math.max(15, Math.min(3600, Math.round(Number(sec) || finPaceSec())));
|
|
13034
|
+
agent.timer = setTimeout(() => { try { finAgentRound(String(sid)); } catch {} }, s * 1000);
|
|
13035
|
+
}
|
|
13036
|
+
|
|
13037
|
+
function finTypeSafeKick(sid, agent) {
|
|
13038
|
+
if (!agent) return;
|
|
13039
|
+
clearTimeout(agent.timer);
|
|
13040
|
+
agent.timer = setTimeout(() => { try { finAgentRound(String(sid)); } catch {} }, 800);
|
|
13041
|
+
}
|
|
13042
|
+
|
|
13043
|
+
/* LLM'siz TypeSafe turu: veri → TypeSafe (noul/choice/score) → kod kararı →
|
|
13044
|
+
AJAN DM yayını. Hata durumunda tur atlanır, LLM'e ASLA düşülmez. */
|
|
13045
|
+
async function finTypeSafeRound(sid, agent) {
|
|
13046
|
+
if (!agent || !engine || agent.tsBusy) return;
|
|
13047
|
+
agent.tsBusy = true;
|
|
13048
|
+
const sidS = String(sid);
|
|
13049
|
+
const isTrader = !!agent.main;
|
|
13050
|
+
const role = String(agent.role || '');
|
|
13051
|
+
const roleLabel = isTrader ? 'TRADER (ana karar verici)' : ((finRoleDef(role) || {}).label || role || 'finans');
|
|
13052
|
+
try {
|
|
13053
|
+
if (!typesafeMod.cfg().apiKey) {
|
|
13054
|
+
const now = Date.now();
|
|
13055
|
+
if (!agent.tsNoKeyAt || now - agent.tsNoKeyAt > 10 * 60 * 1000) {
|
|
13056
|
+
agent.tsNoKeyAt = now;
|
|
13057
|
+
finTsPost(sidS, agent, '⚠ TypeSafe API anahtarı yok — bu rol typesafe-ai modunda ve LLM KULLANILMIYOR; tur atlanıyor. Sahibe söyle: Ayarlar → TypeSafe sekmesinden anahtar girilmeli.', 'anahtar');
|
|
13058
|
+
}
|
|
13059
|
+
return;
|
|
13060
|
+
}
|
|
13061
|
+
if (!mt5bridge.running) {
|
|
13062
|
+
const now = Date.now();
|
|
13063
|
+
if (!agent.tsNoBridgeAt || now - agent.tsNoBridgeAt > 5 * 60 * 1000) {
|
|
13064
|
+
agent.tsNoBridgeAt = now;
|
|
13065
|
+
finTsPost(sidS, agent, '⚠ MT5 köprüsü bağlı değil — TypeSafe turu atlandı.', 'köprü');
|
|
13066
|
+
}
|
|
13067
|
+
return;
|
|
13068
|
+
}
|
|
13069
|
+
const f = finCfg();
|
|
13070
|
+
const symbols = (Array.isArray(agent.symbols) && agent.symbols.length ? agent.symbols : f.symbols || [])
|
|
13071
|
+
.map((x) => String(x || '').trim().toUpperCase()).filter(Boolean).slice(0, FIN_TS_MAX_SYMBOLS);
|
|
13072
|
+
if (!symbols.length) {
|
|
13073
|
+
const now = Date.now();
|
|
13074
|
+
if (!agent.tsNoSymAt || now - agent.tsNoSymAt > 10 * 60 * 1000) {
|
|
13075
|
+
agent.tsNoSymAt = now;
|
|
13076
|
+
finTsPost(sidS, agent, '⚠ İzleme listesi boş — TypeSafe kararı üretilemiyor. Panele sembol ekle.', 'sembol');
|
|
13077
|
+
}
|
|
13078
|
+
return;
|
|
13079
|
+
}
|
|
13080
|
+
agent.round = (Number(agent.round) || 0) + 1;
|
|
13081
|
+
if (isTrader) {
|
|
13082
|
+
financeState.traderRounds = agent.round;
|
|
13083
|
+
finPush('trader', { state: 'running', round: agent.round, mode: 'typesafe' });
|
|
13084
|
+
}
|
|
13085
|
+
/* VERİ: hesap + pozisyonlar + sembol fiyat/gösterge — hepsi KOD ile toplanır,
|
|
13086
|
+
yalnız TypeSafe'e gönderilir; hiçbir LLM çağrısı yapılmaz */
|
|
13087
|
+
const [accR, posR] = await Promise.all([
|
|
13088
|
+
financetools.handlers.mt5_account({}),
|
|
13089
|
+
financetools.handlers.mt5_positions({}),
|
|
13090
|
+
]);
|
|
13091
|
+
const account = (accR && accR.account) || {};
|
|
13092
|
+
const posList = (posR && posR.positions) || [];
|
|
13093
|
+
const market = {};
|
|
13094
|
+
for (const sym of symbols) {
|
|
13095
|
+
const tf = finTsPickTf(agent, sym);
|
|
13096
|
+
const [mktR, indR] = await Promise.all([
|
|
13097
|
+
financetools.handlers.mt5_market({ symbols: [sym] }),
|
|
13098
|
+
financetools.handlers.mt5_indicators({ symbol: sym, timeframe: tf, count: 300, indicators: ['ATR(14)', 'EMA(50)', 'EMA(200)', 'RSI(14)'] }),
|
|
13099
|
+
]);
|
|
13100
|
+
market[sym] = {
|
|
13101
|
+
row: (mktR && mktR.symbols && mktR.symbols[0]) || null,
|
|
13102
|
+
tf,
|
|
13103
|
+
ind: finTsIndLine(indR),
|
|
13104
|
+
};
|
|
13105
|
+
}
|
|
13106
|
+
const state = {
|
|
13107
|
+
rol: roleLabel,
|
|
13108
|
+
yerel_saat: new Date().getHours(),
|
|
13109
|
+
hesap: {
|
|
13110
|
+
balance: Number(account.balance) || 0,
|
|
13111
|
+
equity: Number(account.equity) || 0,
|
|
13112
|
+
margin_free: Number(account.margin_free) || 0,
|
|
13113
|
+
acik_pozisyon: posList.length,
|
|
13114
|
+
},
|
|
13115
|
+
limitler: { max_pozisyon: Number(f.maxPositions) || 3, min_lot: Number(f.minLot) || 0.01, max_lot: Number(f.maxLot) || 0.1 },
|
|
13116
|
+
pozisyonlar: posList.map((p) => ({
|
|
13117
|
+
ticket: p.ticket, sembol: p.symbol, yon: Number(p.type) === 0 ? 'buy' : 'sell',
|
|
13118
|
+
hacim: p.volume, giris: p.price_open, sl: p.sl, tp: p.tp, kar: p.profit,
|
|
13119
|
+
})),
|
|
13120
|
+
piyasa: {},
|
|
13121
|
+
ogrenme: finBuildLearnDigest(symbols),
|
|
13122
|
+
ekip_yanitlari: finTsFeedText(6),
|
|
13123
|
+
};
|
|
13124
|
+
for (const sym of symbols) {
|
|
13125
|
+
const d = market[sym];
|
|
13126
|
+
const row = d.row || {};
|
|
13127
|
+
state.piyasa[sym] = {
|
|
13128
|
+
zaman_dilimi: d.tf,
|
|
13129
|
+
bid: Number(row.bid) || null,
|
|
13130
|
+
ask: Number(row.ask) || null,
|
|
13131
|
+
spread: Number(row.spread) || null,
|
|
13132
|
+
gosterge: d.ind,
|
|
13133
|
+
};
|
|
13134
|
+
}
|
|
13135
|
+
|
|
13136
|
+
/* ---------------- TRADER: yön + teyit + kapat kararı ---------------- */
|
|
13137
|
+
if (isTrader) {
|
|
13138
|
+
const posBySym = {};
|
|
13139
|
+
for (const p of posList) {
|
|
13140
|
+
const s = String(p.symbol || '').toUpperCase();
|
|
13141
|
+
if (symbols.includes(s)) posBySym[s] = p;
|
|
13142
|
+
}
|
|
13143
|
+
const questions = {};
|
|
13144
|
+
symbols.forEach((sym, i) => {
|
|
13145
|
+
questions['yon_' + i] = {
|
|
13146
|
+
type: 'choice',
|
|
13147
|
+
instructions: `${sym} ${market[sym].tf} grafiğinde verilen fiyat, gösterge, pozisyon, öğrenme geçmişi ve ekip yanıtlarına göre kısa vadeli doğru aksiyon nedir? Emin değilsen bekle.`,
|
|
13148
|
+
criteria: {
|
|
13149
|
+
buy: 'LONG aç — yükseliş teyidi var (yapı/momentum/EMA eğimi destekliyor)',
|
|
13150
|
+
sell: 'SHORT aç — düşüş teyidi var',
|
|
13151
|
+
bekle: 'İşlem açma — teyit yok, belirsiz ya da riskli',
|
|
13152
|
+
},
|
|
13153
|
+
};
|
|
13154
|
+
questions['teyit_' + i] = {
|
|
13155
|
+
type: 'noul',
|
|
13156
|
+
instructions: `${sym} fiyat yapısı ve momentum, 'yon_' + ${i} kararını gerçekten destekliyor mu?`,
|
|
13157
|
+
criteria: { true: 'Net destekliyor', false: 'Zayıf/çelişkili' },
|
|
13158
|
+
};
|
|
13159
|
+
if (posBySym[sym]) {
|
|
13160
|
+
const pp = posBySym[sym];
|
|
13161
|
+
questions['kapat_' + i] = {
|
|
13162
|
+
type: 'noul',
|
|
13163
|
+
instructions: `${sym} açık pozisyon (${Number(pp.type) === 0 ? 'buy' : 'sell'}, kâr ${Number(pp.profit) || 0}) ŞİMDİ kapatılmalı mı? Kârı koruma, momentum dönüşü veya SL/TP yakınlığını değerlendir.`,
|
|
13164
|
+
criteria: { true: 'Kapat — risk/kâr koruma', false: 'Açık kalsın — tez sürüyor' },
|
|
13165
|
+
};
|
|
13166
|
+
}
|
|
13167
|
+
});
|
|
13168
|
+
let ans = null;
|
|
13169
|
+
try {
|
|
13170
|
+
ans = await finTsAsk(state, questions);
|
|
13171
|
+
} catch (e) {
|
|
13172
|
+
const now = Date.now();
|
|
13173
|
+
if (!agent.tsErrAt || now - agent.tsErrAt > 2 * 60 * 1000) {
|
|
13174
|
+
agent.tsErrAt = now;
|
|
13175
|
+
finTsPost(sidS, agent, '⚠ TypeSafe çağrısı başarısız: ' + String((e && e.message) || e).slice(0, 200), 'hata');
|
|
13176
|
+
}
|
|
13177
|
+
return;
|
|
13178
|
+
}
|
|
13179
|
+
const lines = [];
|
|
13180
|
+
let opened = 0;
|
|
13181
|
+
for (let i = 0; i < symbols.length; i++) {
|
|
13182
|
+
const sym = symbols[i];
|
|
13183
|
+
if (!financeState.agents.has(sidS)) return;
|
|
13184
|
+
const c = finTsChoice(ans, 'yon_' + i);
|
|
13185
|
+
const conf = finTsNoul(ans, 'teyit_' + i);
|
|
13186
|
+
const pos = posBySym[sym];
|
|
13187
|
+
if (pos) {
|
|
13188
|
+
const ex = finTsNoul(ans, 'kapat_' + i);
|
|
13189
|
+
if (ex != null && ex >= FIN_TS_EXIT_P) {
|
|
13190
|
+
const r = await financetools.handlers.mt5_close(
|
|
13191
|
+
{ ticket: Number(pos.ticket), reason: `TypeSafe: kapat p=${ex.toFixed(2)}` },
|
|
13192
|
+
{ sessionId: sidS }
|
|
13193
|
+
);
|
|
13194
|
+
lines.push(`- ${sym}: KAPAT (p=${ex.toFixed(2)}) ${r && r.ok ? '✓ pozisyon kapatıldı' : '✗ ' + ((r && r.error) || 'hata')}`);
|
|
13195
|
+
} else {
|
|
13196
|
+
lines.push(`- ${sym}: pozisyon açık (kapat=${ex == null ? 'yanıt yok' : ex.toFixed(2)} < ${FIN_TS_EXIT_P}) — tez sürüyor`);
|
|
13197
|
+
}
|
|
13198
|
+
continue;
|
|
13199
|
+
}
|
|
13200
|
+
if (!c || (c.choice !== 'buy' && c.choice !== 'sell')) {
|
|
13201
|
+
lines.push(`- ${sym}: ${finTsFmtChoice(c)} → BEKLE`);
|
|
13202
|
+
continue;
|
|
13203
|
+
}
|
|
13204
|
+
if (!(c.p >= FIN_TS_ACTION_P) || c.p - c.second < FIN_TS_MARGIN_P) {
|
|
13205
|
+
lines.push(`- ${sym}: ${finTsFmtChoice(c)} → eşik/fark altı, BEKLE`);
|
|
13206
|
+
continue;
|
|
13207
|
+
}
|
|
13208
|
+
if (conf == null || conf < FIN_TS_CONFIRM_P) {
|
|
13209
|
+
lines.push(`- ${sym}: ${finTsFmtChoice(c)} · teyit=${conf == null ? 'yok' : conf.toFixed(2)} < ${FIN_TS_CONFIRM_P} → BEKLE`);
|
|
13210
|
+
continue;
|
|
13211
|
+
}
|
|
13212
|
+
if (opened >= 1 || posList.length >= (Number(f.maxPositions) || 3)) {
|
|
13213
|
+
lines.push(`- ${sym}: sinyal güçlü (${c.choice} p=${c.p.toFixed(2)}) ama pozisyon sınırı dolu — bu tur açılmadı`);
|
|
13214
|
+
continue;
|
|
13215
|
+
}
|
|
13216
|
+
/* SL/TP KOD ile: ATR(14) tabanlı — tip ve seviyeler deterministik */
|
|
13217
|
+
const row = market[sym].row || {};
|
|
13218
|
+
const price = c.choice === 'buy' ? Number(row.ask) || Number(row.bid) : Number(row.bid) || Number(row.ask);
|
|
13219
|
+
if (!(price > 0)) { lines.push(`- ${sym}: fiyat okunamadı`); continue; }
|
|
13220
|
+
const atr = Number(market[sym].ind && market[sym].ind.atr14) || 0;
|
|
13221
|
+
const slDist = Math.max(atr > 0 ? atr * 1.5 : price * 0.003, price * 0.0004);
|
|
13222
|
+
const tpDist = Math.max(atr > 0 ? atr * 2.5 : price * 0.006, slDist * 1.2);
|
|
13223
|
+
const digits = Math.max(0, Math.min(8, Number(row.digits) || 2));
|
|
13224
|
+
const rnd = (v) => Number(Number(v).toFixed(digits));
|
|
13225
|
+
const sl = rnd(c.choice === 'buy' ? price - slDist : price + slDist);
|
|
13226
|
+
const tp = rnd(c.choice === 'buy' ? price + tpDist : price - tpDist);
|
|
13227
|
+
const riskPct = Number(f.riskPerTradePct) > 0 ? Number(f.riskPerTradePct) : 0.5;
|
|
13228
|
+
const r = await financetools.handlers.mt5_trade(
|
|
13229
|
+
{
|
|
13230
|
+
symbol: sym,
|
|
13231
|
+
side: c.choice,
|
|
13232
|
+
type: 'market',
|
|
13233
|
+
sl,
|
|
13234
|
+
tp,
|
|
13235
|
+
riskPct,
|
|
13236
|
+
timeframe: market[sym].tf,
|
|
13237
|
+
comment: 'TS',
|
|
13238
|
+
reason: `TypeSafe: yön ${c.choice} p=${c.p.toFixed(2)} fark=${(c.p - c.second).toFixed(2)} teyit=${conf.toFixed(2)}`,
|
|
13239
|
+
},
|
|
13240
|
+
{ sessionId: sidS }
|
|
13241
|
+
);
|
|
13242
|
+
if (r && r.ok) {
|
|
13243
|
+
opened += 1;
|
|
13244
|
+
lines.push(`- ${sym}: ⚡ MARKET ${c.choice.toUpperCase()} açıldı (lot ${r.opened && r.opened.volume}, SL ${sl}, TP ${tp}, risk %${riskPct}) · p=${c.p.toFixed(2)} teyit=${conf.toFixed(2)} · tf=${market[sym].tf}`);
|
|
13245
|
+
} else {
|
|
13246
|
+
lines.push(`- ${sym}: ${c.choice.toUpperCase()} sinyali reddedildi — ${(r && r.error) || 'hata'}`);
|
|
13247
|
+
}
|
|
13248
|
+
}
|
|
13249
|
+
finTsPost(
|
|
13250
|
+
sidS,
|
|
13251
|
+
agent,
|
|
13252
|
+
`🤖 TypeSafe karar turu #${agent.round} (LLM yok — girdi yalnız TypeSafe):\n` +
|
|
13253
|
+
'TF KARARI: ' + symbols.map((s) => `${s}=${market[s].tf}`).join(', ') + '\n' +
|
|
13254
|
+
lines.join('\n') +
|
|
13255
|
+
(opened ? '' : '\nYeni pozisyon açılmadı (eşikler/limitler).'),
|
|
13256
|
+
symbols.join(',')
|
|
13257
|
+
);
|
|
13258
|
+
return;
|
|
13259
|
+
}
|
|
13260
|
+
|
|
13261
|
+
/* ---------------- ROL AJANI: analiz yanıtları (işlem açmaz) ---------------- */
|
|
13262
|
+
const questions = {};
|
|
13263
|
+
const crit = FIN_TS_ROLE_CRIT[role] || FIN_TS_ROLE_CRIT.technic;
|
|
13264
|
+
symbols.forEach((sym, i) => {
|
|
13265
|
+
questions['bias_' + i] = {
|
|
13266
|
+
type: 'choice',
|
|
13267
|
+
instructions: `${sym} ${market[sym].tf} için ${roleLabel} rolünde yön/eğilim değerlendirmen nedir? Verilen fiyat, gösterge, öğrenme geçmişi ve ekip yanıtlarını kullan.`,
|
|
13268
|
+
criteria: crit,
|
|
13269
|
+
};
|
|
13270
|
+
questions['guc_' + i] = {
|
|
13271
|
+
type: 'score',
|
|
13272
|
+
instructions: `${sym} için bu değerlendirmenin gücü nedir? İstatistik ve gösterge teyidi zayıfsa düşük puan ver.`,
|
|
13273
|
+
criteria: ['çok zayıf', 'zayıf', 'orta', 'güçlü', 'çok güçlü'],
|
|
13274
|
+
};
|
|
13275
|
+
questions['risk_' + i] = {
|
|
13276
|
+
type: 'noul',
|
|
13277
|
+
instructions: `${sym} için ${roleLabel} rolünde işlemi engelleyecek bir risk/uygunsuzluk var mı (volatilite, haber, limit, yapı belirsizliği)?`,
|
|
13278
|
+
criteria: { true: 'Risk var — dikkat/engel', false: 'Risk normal' },
|
|
13279
|
+
};
|
|
13280
|
+
});
|
|
13281
|
+
let ans = null;
|
|
13282
|
+
try {
|
|
13283
|
+
ans = await finTsAsk(state, questions);
|
|
13284
|
+
} catch (e) {
|
|
13285
|
+
const now = Date.now();
|
|
13286
|
+
if (!agent.tsErrAt || now - agent.tsErrAt > 2 * 60 * 1000) {
|
|
13287
|
+
agent.tsErrAt = now;
|
|
13288
|
+
finTsPost(sidS, agent, '⚠ TypeSafe çağrısı başarısız: ' + String((e && e.message) || e).slice(0, 200), 'hata');
|
|
13289
|
+
}
|
|
13290
|
+
return;
|
|
13291
|
+
}
|
|
13292
|
+
const lines = symbols.map((sym, i) => {
|
|
13293
|
+
const b = finTsChoice(ans, 'bias_' + i);
|
|
13294
|
+
const g = finTsScore(ans, 'guc_' + i);
|
|
13295
|
+
const rk = finTsNoul(ans, 'risk_' + i);
|
|
13296
|
+
return (
|
|
13297
|
+
`- ${sym} (tf=${market[sym].tf}): ${finTsFmtChoice(b)}` +
|
|
13298
|
+
(g ? ` · güç=${g.score.toFixed(2)}/4 (güven=${g.conf.toFixed(2)})` : '') +
|
|
13299
|
+
(rk == null ? '' : ` · risk=${rk.toFixed(2)}${rk >= 0.55 ? ' ⚠' : ''}`)
|
|
13300
|
+
);
|
|
13301
|
+
});
|
|
13302
|
+
finTsPost(sidS, agent, `🧠 TypeSafe analiz (LLM yok — girdi yalnız TypeSafe):\n` + lines.join('\n'), symbols.join(','));
|
|
13303
|
+
} catch (e) {
|
|
13304
|
+
try { financeLog('[typesafe] tur hatası (' + sidS + '): ' + String((e && e.message) || e)); } catch {}
|
|
13305
|
+
} finally {
|
|
13306
|
+
agent.tsBusy = false;
|
|
13307
|
+
finTsSchedule(sidS, agent, finPaceSec());
|
|
13308
|
+
if (isTrader && financeState.agents.has(sidS)) finPush('trader', { state: 'idle', round: agent.round, mode: 'typesafe' });
|
|
13309
|
+
}
|
|
13310
|
+
}
|
|
13311
|
+
|
|
12866
13312
|
/* Bir ajanın TEK turu: (opsiyonel) ana ajan planı + tur emri */
|
|
12867
13313
|
function finAgentRound(sid, opts) {
|
|
12868
13314
|
const agent = financeState.agents.get(String(sid));
|
|
@@ -12880,6 +13326,13 @@ function finAgentRound(sid, opts) {
|
|
|
12880
13326
|
/* hâlâ çalışıyor — done eventinde tekrar planlanır */
|
|
12881
13327
|
return;
|
|
12882
13328
|
}
|
|
13329
|
+
/* TYPESAFE-ONLY MODU: roleSkills'te typesafe-ai varsa LLM HİÇ kullanılmaz —
|
|
13330
|
+
tur deterministik TypeSafe hattıyla koşar (girdi yalnız TypeSafe'e gider,
|
|
13331
|
+
cevaplar AJAN DM'e düşer, emirler yalnız market buy/sell) */
|
|
13332
|
+
if (finTsAgentMode(agent)) {
|
|
13333
|
+
finTypeSafeRound(String(sid), agent).catch(() => {});
|
|
13334
|
+
return;
|
|
13335
|
+
}
|
|
12883
13336
|
const f = finCfg();
|
|
12884
13337
|
/* EKİP BEKLEMESİ SÜRÜYOR: DM uyandırması vb. turu erkene çekemez — tick açar */
|
|
12885
13338
|
if (agent.main && agent.waitingTeam && !(opts && opts.noTeamWait)) return;
|
|
@@ -13399,6 +13852,15 @@ async function financeTraderStart() {
|
|
|
13399
13852
|
try { engine.setSessionModel(mainSid, f.traderSel || null); } catch {}
|
|
13400
13853
|
financeState.traderOn = true;
|
|
13401
13854
|
try { engine.clearStop(); } catch {}
|
|
13855
|
+
/* TYPESAFE-ONLY: roleSkills.trader'da typesafe-ai varsa LLM'e HİÇ gidilmez */
|
|
13856
|
+
if (finTsAgentMode(mainAgent)) {
|
|
13857
|
+
financeState.lastRoundAt = Date.now();
|
|
13858
|
+
financeLog('[trader] başlatıldı (TYPESAFE-ONLY — LLM kullanılmıyor, girdi yalnız TypeSafe)');
|
|
13859
|
+
finPush('trader', { state: 'running', round: mainAgent.round, mode: 'typesafe' });
|
|
13860
|
+
finTypeSafeKick(mainSid, mainAgent);
|
|
13861
|
+
finTeamStart(f);
|
|
13862
|
+
return { ok: true, sid: mainSid };
|
|
13863
|
+
}
|
|
13402
13864
|
const ok = engine.send(mainSid, finTraderBrief(mainAgent), { userAction: true });
|
|
13403
13865
|
if (!ok) {
|
|
13404
13866
|
financeState.traderOn = false;
|
|
@@ -13431,6 +13893,12 @@ function finTeamStart(f) {
|
|
|
13431
13893
|
try {
|
|
13432
13894
|
const created = finAgentCreate([], false, roleId);
|
|
13433
13895
|
try { engine.setSessionModel(created.s.id, f.traderSel || null); } catch {}
|
|
13896
|
+
/* TYPESAFE-ONLY: bu rolün skill eşleştirmesinde typesafe-ai varsa LLM yok */
|
|
13897
|
+
if (finTsAgentMode(created.agent)) {
|
|
13898
|
+
financeLog('[ekip] ' + roleDef.label + ' başladı (TYPESAFE-ONLY — LLM kullanılmıyor)');
|
|
13899
|
+
finTypeSafeKick(String(created.s.id), created.agent);
|
|
13900
|
+
continue;
|
|
13901
|
+
}
|
|
13434
13902
|
const ok = engine.send(created.s.id, finTraderBrief(created.agent), { userAction: true });
|
|
13435
13903
|
if (!ok) {
|
|
13436
13904
|
finAgentStop(String(created.s.id), 'oturum meşgul — ekip ajanı başlatılamadı');
|
package/src/renderer/index.html
CHANGED
|
@@ -856,7 +856,7 @@
|
|
|
856
856
|
</div>
|
|
857
857
|
<div class="mini-body">
|
|
858
858
|
<div id="finSkillsList" class="mini-list"></div>
|
|
859
|
-
<div class="fin-sym-hint">Her rol için
|
|
859
|
+
<div class="fin-sym-hint">Her rol için EN FAZLA 2 skill seçilir (ör. price-action + typesafe-ai). Seçili skill'i satırın sağ üstündeki çöp ikonuyla kaldırabilirsin; boş bırakırsan ajan skill'i göreve göre SKILLS kataloğundan kendi seçer. Seçim, koşan ajanlar dahil sonraki turdan itibaren geçerli olur.<br><b>typesafe-ai seçilirse:</b> o ajan LLM KULLANMAZ — tur verisi yalnız TypeSafe System One'a gider (tipli kararlar), cevaplar AJAN DM'de tüm ekibe görünür ve ajanlar birbirinin yanıtını görür; emirler YALNIZ market buy/sell olarak açılır (bekleyen emir yok). Ayarlar → TypeSafe'ten API anahtarı gerekir.</div>
|
|
860
860
|
</div>
|
|
861
861
|
</div>
|
|
862
862
|
</div>
|