beast-agent 2.39.0 → 2.40.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/bots.js +2 -2
- package/src/agent/customtools.js +52 -2
- package/src/agent/defaulttools/mt5_barlar2/run.js +188 -0
- package/src/agent/defaulttools/mt5_barlar2/tool.json +23 -0
- package/src/agent/defaulttools/mt5_bekleyen/run.js +100 -0
- package/src/agent/defaulttools/mt5_bekleyen/tool.json +17 -0
- package/src/agent/defaulttools/mt5_durum/run.js +93 -0
- package/src/agent/defaulttools/mt5_durum/tool.json +10 -0
- package/src/agent/defaulttools/mt5_emir/run.js +98 -0
- package/src/agent/defaulttools/mt5_emir/tool.json +17 -0
- package/src/agent/defaulttools/mt5_emir_iptal/run.js +90 -0
- package/src/agent/defaulttools/mt5_emir_iptal/tool.json +12 -0
- package/src/agent/defaulttools/mt5_fiyat/run.js +87 -0
- package/src/agent/defaulttools/mt5_fiyat/tool.json +16 -0
- package/src/agent/defaulttools/mt5_gecmis/run.js +87 -0
- package/src/agent/defaulttools/mt5_gecmis/tool.json +12 -0
- package/src/agent/defaulttools/mt5_kapat/run.js +92 -0
- package/src/agent/defaulttools/mt5_kapat/tool.json +13 -0
- package/src/agent/defaulttools/mt5_m15_m5/m15m5.py +60 -0
- package/src/agent/defaulttools/mt5_m15_m5/run.js +73 -0
- package/src/agent/defaulttools/mt5_m15_m5/tool.json +10 -0
- package/src/agent/defaulttools/mt5_pozisyon_gecmis/run.js +144 -0
- package/src/agent/defaulttools/mt5_pozisyon_gecmis/tool.json +12 -0
- package/src/agent/defaulttools/mt5_shot/run.js +428 -0
- package/src/agent/defaulttools/mt5_shot/tool.json +20 -0
- package/src/agent/defaulttools/mt5_sltp/run.js +92 -0
- package/src/agent/defaulttools/mt5_sltp/tool.json +14 -0
- package/src/agent/engine.js +51 -16
- package/src/agent/financetools.js +1 -1
- package/src/agent/mt5/BeastFinance.mq5 +140 -3
- package/src/agent/mt5/BeastShot.tpl +0 -0
- package/src/agent/mt5setup.js +22 -0
- package/src/agent/seeds/mql5/SKILL.md +4 -2
- package/src/main.js +1 -1
- package/src/renderer/renderer.js +11 -1
- package/src/renderer/style.css +15 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mt5_emir",
|
|
3
|
+
"description": "MT5 köprüsüyle PİYASA EMİRİ açar (işlem açma). symbol (broker adı: GOLD veya BITCOIN — XAUUSD/BTCUSD DEĞİL), side (buy|sell), volume (lot) zorunlu; sl/tp/comment opsiyonel. Başarıda ticket/retcode döner. NOT: Bu tool tüm oturumlarda çalışır — Trader ajanları da işlem açmak için bunu kullanır.",
|
|
4
|
+
"parameters": {
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"symbol": { "type": "string", "description": "Broker sembol adi: GOLD veya BITCOIN (XAUUSD degil)" },
|
|
8
|
+
"side": { "type": "string", "description": "buy | sell" },
|
|
9
|
+
"volume": { "type": "number", "description": "Lot büyüklüğü (0.01-0.1)" },
|
|
10
|
+
"sl": { "type": "number", "description": "Stop loss fiyatı (opsiyonel)" },
|
|
11
|
+
"tp": { "type": "number", "description": "Take profit fiyatı (opsiyonel)" },
|
|
12
|
+
"comment": { "type": "string", "description": "Kısa işlem notu (opsiyonel)" }
|
|
13
|
+
},
|
|
14
|
+
"required": ["symbol", "side", "volume"]
|
|
15
|
+
},
|
|
16
|
+
"updatedAt": "2026-09-09T18:40:00.000Z"
|
|
17
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// MT5 BEKLEYEN EMIR IPTAL — stdin: JSON args · stdout: JSON sonuç
|
|
3
|
+
const { spawn } = require('child_process');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
/* TAŞINABİLİR YOL ÇÖZÜMÜ: Beast gömülü python → sistem python'ları → PATH.
|
|
8
|
+
Köprü dosyası %APPDATA%\beast\finance\mt5_bridge.py'den (veya BEAST_FINANCE_DIR)
|
|
9
|
+
okunur; ortam değişkenleriyle geçersiz kılınabilir. */
|
|
10
|
+
function resolvePython() {
|
|
11
|
+
const cands = [];
|
|
12
|
+
if (process.env.BEAST_PYTHON) cands.push({ exe: String(process.env.BEAST_PYTHON), args: [] });
|
|
13
|
+
if (process.env.APPDATA) cands.push({ exe: path.join(process.env.APPDATA, 'beast', 'py', 'python.exe'), args: [] });
|
|
14
|
+
for (const v of ['314', '313', '312', '311', '310']) cands.push({ exe: 'C:\\Python' + v + '\\python.exe', args: [] });
|
|
15
|
+
cands.push({ exe: 'python', args: [] }, { exe: 'py', args: ['-3'] });
|
|
16
|
+
for (const c of cands) {
|
|
17
|
+
if (c.exe === 'python' || c.exe === 'py') return c;
|
|
18
|
+
try { if (fs.existsSync(c.exe)) return c; } catch (e) {}
|
|
19
|
+
}
|
|
20
|
+
return { exe: 'python', args: [] };
|
|
21
|
+
}
|
|
22
|
+
function resolveBridge() {
|
|
23
|
+
const cands = [];
|
|
24
|
+
if (process.env.BEAST_BRIDGE) cands.push(String(process.env.BEAST_BRIDGE));
|
|
25
|
+
if (process.env.BEAST_FINANCE_DIR) cands.push(path.join(String(process.env.BEAST_FINANCE_DIR), 'mt5_bridge.py'));
|
|
26
|
+
if (process.env.APPDATA) cands.push(path.join(process.env.APPDATA, 'beast', 'finance', 'mt5_bridge.py'));
|
|
27
|
+
for (const p of cands) { try { if (p && fs.existsSync(p)) return p; } catch (e) {} }
|
|
28
|
+
return cands[0] || '';
|
|
29
|
+
}
|
|
30
|
+
const PYSPEC = resolvePython();
|
|
31
|
+
const PY = PYSPEC.exe;
|
|
32
|
+
const PY_ARGS = PYSPEC.args;
|
|
33
|
+
const BRIDGE = resolveBridge();
|
|
34
|
+
|
|
35
|
+
const TIMEOUT = 35000;
|
|
36
|
+
|
|
37
|
+
function call(requests) {
|
|
38
|
+
return new Promise((resolve) => {
|
|
39
|
+
let py;
|
|
40
|
+
try { py = spawn(PY, [...PY_ARGS, BRIDGE], { windowsHide: true, stdio: ['pipe', 'pipe', 'pipe'] }); }
|
|
41
|
+
catch (e) { return resolve({ ok: false, error: 'python baslatilamadi: ' + e.message }); }
|
|
42
|
+
const results = {};
|
|
43
|
+
let buf = '';
|
|
44
|
+
let errTail = '';
|
|
45
|
+
let settled = false;
|
|
46
|
+
const finish = (obj) => { if (!settled) { settled = true; clearTimeout(timer); try { py.kill(); } catch (e) {} resolve(obj); } };
|
|
47
|
+
const timer = setTimeout(() => finish({ ok: false, error: 'zaman asimi: MT5 terminali acik ve yanit veriyor mu?' }), TIMEOUT);
|
|
48
|
+
py.stdout.on('data', (d) => {
|
|
49
|
+
buf += d.toString('utf8');
|
|
50
|
+
let i;
|
|
51
|
+
while ((i = buf.indexOf('\n')) >= 0) {
|
|
52
|
+
const line = buf.slice(0, i).trim(); buf = buf.slice(i + 1);
|
|
53
|
+
if (!line) continue;
|
|
54
|
+
let o = null;
|
|
55
|
+
try { o = JSON.parse(line); } catch (e) { continue; }
|
|
56
|
+
if (o && o.event) continue;
|
|
57
|
+
if (o && typeof o.id === 'number' && Object.prototype.hasOwnProperty.call(o, 'ok')) {
|
|
58
|
+
results[o.id] = o;
|
|
59
|
+
if (Object.keys(results).length >= requests.length) {
|
|
60
|
+
const arr = requests.map((_, k) => results[k + 1]);
|
|
61
|
+
finish(arr.length === 1 ? arr[0] : { ok: true, results: arr });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
py.stderr.on('data', (d) => { errTail = (errTail + d.toString('utf8')).slice(-800); });
|
|
67
|
+
py.on('error', (e) => finish({ ok: false, error: 'python baslatilamadi: ' + e.message }));
|
|
68
|
+
py.on('close', (code) => { if (Object.keys(results).length < requests.length) finish({ ok: false, error: 'bridge erken cikti code=' + code + ' ' + errTail }); });
|
|
69
|
+
requests.forEach((r, k) => py.stdin.write(JSON.stringify({ id: k + 1, method: r.method, params: r.params || {} }) + '\n'));
|
|
70
|
+
py.stdin.end();
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
(async function main() {
|
|
75
|
+
let args = {};
|
|
76
|
+
try { args = JSON.parse(fs.readFileSync(0, 'utf8') || '{}'); } catch (e) {}
|
|
77
|
+
const ticket = Number(args.ticket || 0);
|
|
78
|
+
if (!ticket) return console.log(JSON.stringify({ ok: false, error: 'ticket zorunlu' }));
|
|
79
|
+
const r = await call([{ method: 'cancel', params: { ticket: ticket } }]);
|
|
80
|
+
if (r.ok && r.data && r.data.result) {
|
|
81
|
+
const res = r.data.result;
|
|
82
|
+
console.log(JSON.stringify({ ok: true, retcode: res.retcode, comment: res.comment, detay: r.data }));
|
|
83
|
+
} else {
|
|
84
|
+
console.log(JSON.stringify({ ok: false, error: r.error || 'iptal reddedildi' }));
|
|
85
|
+
}
|
|
86
|
+
})();
|
|
87
|
+
|
|
88
|
+
/* PATCH 2026-09-10b: electron app-mode cocuk prosesi kapanmiyordu (90sn timeout).
|
|
89
|
+
stdout'un boruya bosalmasi icin kisa bekleme, sonra zorla cik. */
|
|
90
|
+
setTimeout(() => process.exit(0), 1500);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mt5_emir_iptal",
|
|
3
|
+
"description": "Bekleyen emri İPTAL eder: ticket zorunlu (mt5_bekleyen veya durum/emir listesinden gelen ticket no).",
|
|
4
|
+
"parameters": {
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"ticket": { "type": "number", "description": "Iptal edilecek bekleyen emrin ticket numarasi" }
|
|
8
|
+
},
|
|
9
|
+
"required": ["ticket"]
|
|
10
|
+
},
|
|
11
|
+
"updatedAt": "2026-09-09T18:50:00.000Z"
|
|
12
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// MT5 CANLI FİYAT — stdin: JSON args · stdout: JSON sonuç
|
|
3
|
+
const { spawn } = require('child_process');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
/* TAŞINABİLİR YOL ÇÖZÜMÜ: Beast gömülü python → sistem python'ları → PATH.
|
|
8
|
+
Köprü dosyası %APPDATA%\beast\finance\mt5_bridge.py'den (veya BEAST_FINANCE_DIR)
|
|
9
|
+
okunur; ortam değişkenleriyle geçersiz kılınabilir. */
|
|
10
|
+
function resolvePython() {
|
|
11
|
+
const cands = [];
|
|
12
|
+
if (process.env.BEAST_PYTHON) cands.push({ exe: String(process.env.BEAST_PYTHON), args: [] });
|
|
13
|
+
if (process.env.APPDATA) cands.push({ exe: path.join(process.env.APPDATA, 'beast', 'py', 'python.exe'), args: [] });
|
|
14
|
+
for (const v of ['314', '313', '312', '311', '310']) cands.push({ exe: 'C:\\Python' + v + '\\python.exe', args: [] });
|
|
15
|
+
cands.push({ exe: 'python', args: [] }, { exe: 'py', args: ['-3'] });
|
|
16
|
+
for (const c of cands) {
|
|
17
|
+
if (c.exe === 'python' || c.exe === 'py') return c;
|
|
18
|
+
try { if (fs.existsSync(c.exe)) return c; } catch (e) {}
|
|
19
|
+
}
|
|
20
|
+
return { exe: 'python', args: [] };
|
|
21
|
+
}
|
|
22
|
+
function resolveBridge() {
|
|
23
|
+
const cands = [];
|
|
24
|
+
if (process.env.BEAST_BRIDGE) cands.push(String(process.env.BEAST_BRIDGE));
|
|
25
|
+
if (process.env.BEAST_FINANCE_DIR) cands.push(path.join(String(process.env.BEAST_FINANCE_DIR), 'mt5_bridge.py'));
|
|
26
|
+
if (process.env.APPDATA) cands.push(path.join(process.env.APPDATA, 'beast', 'finance', 'mt5_bridge.py'));
|
|
27
|
+
for (const p of cands) { try { if (p && fs.existsSync(p)) return p; } catch (e) {} }
|
|
28
|
+
return cands[0] || '';
|
|
29
|
+
}
|
|
30
|
+
const PYSPEC = resolvePython();
|
|
31
|
+
const PY = PYSPEC.exe;
|
|
32
|
+
const PY_ARGS = PYSPEC.args;
|
|
33
|
+
const BRIDGE = resolveBridge();
|
|
34
|
+
|
|
35
|
+
const TIMEOUT = 35000;
|
|
36
|
+
|
|
37
|
+
function call(requests) {
|
|
38
|
+
return new Promise((resolve) => {
|
|
39
|
+
let py;
|
|
40
|
+
try { py = spawn(PY, [...PY_ARGS, BRIDGE], { windowsHide: true, stdio: ['pipe', 'pipe', 'pipe'] }); }
|
|
41
|
+
catch (e) { return resolve({ ok: false, error: 'python baslatilamadi: ' + e.message }); }
|
|
42
|
+
const results = {};
|
|
43
|
+
let buf = '';
|
|
44
|
+
let errTail = '';
|
|
45
|
+
let settled = false;
|
|
46
|
+
const finish = (obj) => { if (!settled) { settled = true; clearTimeout(timer); try { py.kill(); } catch (e) {} resolve(obj); } };
|
|
47
|
+
const timer = setTimeout(() => finish({ ok: false, error: 'zaman asimi: MT5 terminali acik ve yanit veriyor mu?' }), TIMEOUT);
|
|
48
|
+
py.stdout.on('data', (d) => {
|
|
49
|
+
buf += d.toString('utf8');
|
|
50
|
+
let i;
|
|
51
|
+
while ((i = buf.indexOf('\n')) >= 0) {
|
|
52
|
+
const line = buf.slice(0, i).trim(); buf = buf.slice(i + 1);
|
|
53
|
+
if (!line) continue;
|
|
54
|
+
let o = null;
|
|
55
|
+
try { o = JSON.parse(line); } catch (e) { continue; }
|
|
56
|
+
if (o && o.event) continue;
|
|
57
|
+
if (o && typeof o.id === 'number' && Object.prototype.hasOwnProperty.call(o, 'ok')) {
|
|
58
|
+
results[o.id] = o;
|
|
59
|
+
if (Object.keys(results).length >= requests.length) {
|
|
60
|
+
const arr = requests.map((_, k) => results[k + 1]);
|
|
61
|
+
finish(arr.length === 1 ? arr[0] : { ok: true, results: arr });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
py.stderr.on('data', (d) => { errTail = (errTail + d.toString('utf8')).slice(-800); });
|
|
67
|
+
py.on('error', (e) => finish({ ok: false, error: 'python baslatilamadi: ' + e.message }));
|
|
68
|
+
py.on('close', (code) => { if (Object.keys(results).length < requests.length) finish({ ok: false, error: 'bridge erken cikti code=' + code + ' ' + errTail }); });
|
|
69
|
+
requests.forEach((r, k) => py.stdin.write(JSON.stringify({ id: k + 1, method: r.method, params: r.params || {} }) + '\n'));
|
|
70
|
+
py.stdin.end();
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
(async function main() {
|
|
75
|
+
let args = {};
|
|
76
|
+
try { args = JSON.parse(fs.readFileSync(0, 'utf8') || '{}'); } catch (e) {}
|
|
77
|
+
let syms = args.symbols;
|
|
78
|
+
if (typeof syms === 'string') syms = [syms];
|
|
79
|
+
if (!Array.isArray(syms) || syms.length === 0) return console.log(JSON.stringify({ ok: false, error: 'symbols dizisi zorunlu, orn [\"XAUUSD\"]' }));
|
|
80
|
+
const r = await call([{ method: 'symbols', params: { symbols: syms } }]);
|
|
81
|
+
if (r.ok && r.data) return console.log(JSON.stringify({ ok: true, symbols: r.data.symbols }));
|
|
82
|
+
console.log(JSON.stringify({ ok: false, error: r.error || 'fiyat alinamadi' }));
|
|
83
|
+
})();
|
|
84
|
+
|
|
85
|
+
/* PATCH 2026-09-10b: electron app-mode cocuk prosesi kapanmiyordu (90sn timeout).
|
|
86
|
+
stdout'un boruya bosalmasi icin kisa bekleme, sonra zorla cik. */
|
|
87
|
+
setTimeout(() => process.exit(0), 1500);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mt5_fiyat",
|
|
3
|
+
"description": "MT5 canlı fiyat okur: symbols dizisindeki her sembol için bid/ask/spread/digit + sembol bilgisi döner. Broker sembol adlari GOLD ve BITCOIN'dir (XAUUSD/BTCUSD degil — onlar missing doner). Eksik sembol 'missing' işaretlenir. Örn: {\"symbols\":[\"GOLD\",\"BITCOIN\"]}",
|
|
4
|
+
"parameters": {
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"symbols": {
|
|
8
|
+
"type": "array",
|
|
9
|
+
"items": { "type": "string" },
|
|
10
|
+
"description": "Sorgulanacak semboller, örn XAUUSD, BTCUSD"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"required": ["symbols"]
|
|
14
|
+
},
|
|
15
|
+
"updatedAt": "2026-09-09T18:45:00.000Z"
|
|
16
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// MT5 KAPANMIS ISLEM GECMISI — stdin: JSON args · stdout: JSON sonuç
|
|
3
|
+
const { spawn } = require('child_process');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
/* TAŞINABİLİR YOL ÇÖZÜMÜ: Beast gömülü python → sistem python'ları → PATH.
|
|
8
|
+
Köprü dosyası %APPDATA%\beast\finance\mt5_bridge.py'den (veya BEAST_FINANCE_DIR)
|
|
9
|
+
okunur; ortam değişkenleriyle geçersiz kılınabilir. */
|
|
10
|
+
function resolvePython() {
|
|
11
|
+
const cands = [];
|
|
12
|
+
if (process.env.BEAST_PYTHON) cands.push({ exe: String(process.env.BEAST_PYTHON), args: [] });
|
|
13
|
+
if (process.env.APPDATA) cands.push({ exe: path.join(process.env.APPDATA, 'beast', 'py', 'python.exe'), args: [] });
|
|
14
|
+
for (const v of ['314', '313', '312', '311', '310']) cands.push({ exe: 'C:\\Python' + v + '\\python.exe', args: [] });
|
|
15
|
+
cands.push({ exe: 'python', args: [] }, { exe: 'py', args: ['-3'] });
|
|
16
|
+
for (const c of cands) {
|
|
17
|
+
if (c.exe === 'python' || c.exe === 'py') return c;
|
|
18
|
+
try { if (fs.existsSync(c.exe)) return c; } catch (e) {}
|
|
19
|
+
}
|
|
20
|
+
return { exe: 'python', args: [] };
|
|
21
|
+
}
|
|
22
|
+
function resolveBridge() {
|
|
23
|
+
const cands = [];
|
|
24
|
+
if (process.env.BEAST_BRIDGE) cands.push(String(process.env.BEAST_BRIDGE));
|
|
25
|
+
if (process.env.BEAST_FINANCE_DIR) cands.push(path.join(String(process.env.BEAST_FINANCE_DIR), 'mt5_bridge.py'));
|
|
26
|
+
if (process.env.APPDATA) cands.push(path.join(process.env.APPDATA, 'beast', 'finance', 'mt5_bridge.py'));
|
|
27
|
+
for (const p of cands) { try { if (p && fs.existsSync(p)) return p; } catch (e) {} }
|
|
28
|
+
return cands[0] || '';
|
|
29
|
+
}
|
|
30
|
+
const PYSPEC = resolvePython();
|
|
31
|
+
const PY = PYSPEC.exe;
|
|
32
|
+
const PY_ARGS = PYSPEC.args;
|
|
33
|
+
const BRIDGE = resolveBridge();
|
|
34
|
+
|
|
35
|
+
const TIMEOUT = 35000;
|
|
36
|
+
|
|
37
|
+
function call(requests) {
|
|
38
|
+
return new Promise((resolve) => {
|
|
39
|
+
let py;
|
|
40
|
+
try { py = spawn(PY, [...PY_ARGS, BRIDGE], { windowsHide: true, stdio: ['pipe', 'pipe', 'pipe'] }); }
|
|
41
|
+
catch (e) { return resolve({ ok: false, error: 'python baslatilamadi: ' + e.message }); }
|
|
42
|
+
const results = {};
|
|
43
|
+
let buf = '';
|
|
44
|
+
let errTail = '';
|
|
45
|
+
let settled = false;
|
|
46
|
+
const finish = (obj) => { if (!settled) { settled = true; clearTimeout(timer); try { py.kill(); } catch (e) {} resolve(obj); } };
|
|
47
|
+
const timer = setTimeout(() => finish({ ok: false, error: 'zaman asimi: MT5 terminali acik ve yanit veriyor mu?' }), TIMEOUT);
|
|
48
|
+
py.stdout.on('data', (d) => {
|
|
49
|
+
buf += d.toString('utf8');
|
|
50
|
+
let i;
|
|
51
|
+
while ((i = buf.indexOf('\n')) >= 0) {
|
|
52
|
+
const line = buf.slice(0, i).trim(); buf = buf.slice(i + 1);
|
|
53
|
+
if (!line) continue;
|
|
54
|
+
let o = null;
|
|
55
|
+
try { o = JSON.parse(line); } catch (e) { continue; }
|
|
56
|
+
if (o && o.event) continue;
|
|
57
|
+
if (o && typeof o.id === 'number' && Object.prototype.hasOwnProperty.call(o, 'ok')) {
|
|
58
|
+
results[o.id] = o;
|
|
59
|
+
if (Object.keys(results).length >= requests.length) {
|
|
60
|
+
const arr = requests.map((_, k) => results[k + 1]);
|
|
61
|
+
finish(arr.length === 1 ? arr[0] : { ok: true, results: arr });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
py.stderr.on('data', (d) => { errTail = (errTail + d.toString('utf8')).slice(-800); });
|
|
67
|
+
py.on('error', (e) => finish({ ok: false, error: 'python baslatilamadi: ' + e.message }));
|
|
68
|
+
py.on('close', (code) => { if (Object.keys(results).length < requests.length) finish({ ok: false, error: 'bridge erken cikti code=' + code + ' ' + errTail }); });
|
|
69
|
+
requests.forEach((r, k) => py.stdin.write(JSON.stringify({ id: k + 1, method: r.method, params: r.params || {} }) + '\n'));
|
|
70
|
+
py.stdin.end();
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
(async function main() {
|
|
75
|
+
let args = {};
|
|
76
|
+
try { args = JSON.parse(fs.readFileSync(0, 'utf8') || '{}'); } catch (e) {}
|
|
77
|
+
let days = Number(args.days || 1);
|
|
78
|
+
if (!(days > 0)) days = 1;
|
|
79
|
+
days = Math.min(days, 90);
|
|
80
|
+
const r = await call([{ method: 'deals', params: { days: days } }]);
|
|
81
|
+
if (r.ok && r.data) return console.log(JSON.stringify({ ok: true, count: r.data.count, deals: r.data.deals }));
|
|
82
|
+
console.log(JSON.stringify({ ok: false, error: r.error || 'gecmis alinamadi' }));
|
|
83
|
+
})();
|
|
84
|
+
|
|
85
|
+
/* PATCH 2026-09-10b: electron app-mode cocuk prosesi kapanmiyordu (90sn timeout).
|
|
86
|
+
stdout'un boruya bosalmasi icin kisa bekleme, sonra zorla cik. */
|
|
87
|
+
setTimeout(() => process.exit(0), 1500);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mt5_gecmis",
|
|
3
|
+
"description": "Kapanmış işlem geçmişi: son N günde kapatılan pozisyonlar/deals, kar-zarar, komisyon, swap. days verilmezse 1 gün (en fazla 90). Trader ajanları performans ve günlük P&L kontrolünde kullanır.",
|
|
4
|
+
"parameters": {
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"days": { "type": "number", "description": "Kac gun geriye bakilsin (1-90, varsayilan 1)" }
|
|
8
|
+
},
|
|
9
|
+
"required": []
|
|
10
|
+
},
|
|
11
|
+
"updatedAt": "2026-09-09T18:45:00.000Z"
|
|
12
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// MT5 POZISYON KAPAT — stdin: JSON args · stdout: JSON sonuç
|
|
3
|
+
const { spawn } = require('child_process');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
/* TAŞINABİLİR YOL ÇÖZÜMÜ: Beast gömülü python → sistem python'ları → PATH.
|
|
8
|
+
Köprü dosyası %APPDATA%\beast\finance\mt5_bridge.py'den (veya BEAST_FINANCE_DIR)
|
|
9
|
+
okunur; ortam değişkenleriyle geçersiz kılınabilir. */
|
|
10
|
+
function resolvePython() {
|
|
11
|
+
const cands = [];
|
|
12
|
+
if (process.env.BEAST_PYTHON) cands.push({ exe: String(process.env.BEAST_PYTHON), args: [] });
|
|
13
|
+
if (process.env.APPDATA) cands.push({ exe: path.join(process.env.APPDATA, 'beast', 'py', 'python.exe'), args: [] });
|
|
14
|
+
for (const v of ['314', '313', '312', '311', '310']) cands.push({ exe: 'C:\\Python' + v + '\\python.exe', args: [] });
|
|
15
|
+
cands.push({ exe: 'python', args: [] }, { exe: 'py', args: ['-3'] });
|
|
16
|
+
for (const c of cands) {
|
|
17
|
+
if (c.exe === 'python' || c.exe === 'py') return c;
|
|
18
|
+
try { if (fs.existsSync(c.exe)) return c; } catch (e) {}
|
|
19
|
+
}
|
|
20
|
+
return { exe: 'python', args: [] };
|
|
21
|
+
}
|
|
22
|
+
function resolveBridge() {
|
|
23
|
+
const cands = [];
|
|
24
|
+
if (process.env.BEAST_BRIDGE) cands.push(String(process.env.BEAST_BRIDGE));
|
|
25
|
+
if (process.env.BEAST_FINANCE_DIR) cands.push(path.join(String(process.env.BEAST_FINANCE_DIR), 'mt5_bridge.py'));
|
|
26
|
+
if (process.env.APPDATA) cands.push(path.join(process.env.APPDATA, 'beast', 'finance', 'mt5_bridge.py'));
|
|
27
|
+
for (const p of cands) { try { if (p && fs.existsSync(p)) return p; } catch (e) {} }
|
|
28
|
+
return cands[0] || '';
|
|
29
|
+
}
|
|
30
|
+
const PYSPEC = resolvePython();
|
|
31
|
+
const PY = PYSPEC.exe;
|
|
32
|
+
const PY_ARGS = PYSPEC.args;
|
|
33
|
+
const BRIDGE = resolveBridge();
|
|
34
|
+
|
|
35
|
+
const TIMEOUT = 35000;
|
|
36
|
+
|
|
37
|
+
function call(requests) {
|
|
38
|
+
return new Promise((resolve) => {
|
|
39
|
+
let py;
|
|
40
|
+
try { py = spawn(PY, [...PY_ARGS, BRIDGE], { windowsHide: true, stdio: ['pipe', 'pipe', 'pipe'] }); }
|
|
41
|
+
catch (e) { return resolve({ ok: false, error: 'python baslatilamadi: ' + e.message }); }
|
|
42
|
+
const results = {};
|
|
43
|
+
let buf = '';
|
|
44
|
+
let errTail = '';
|
|
45
|
+
let settled = false;
|
|
46
|
+
const finish = (obj) => { if (!settled) { settled = true; clearTimeout(timer); try { py.kill(); } catch (e) {} resolve(obj); } };
|
|
47
|
+
const timer = setTimeout(() => finish({ ok: false, error: 'zaman asimi: MT5 terminali acik ve yanit veriyor mu?' }), TIMEOUT);
|
|
48
|
+
py.stdout.on('data', (d) => {
|
|
49
|
+
buf += d.toString('utf8');
|
|
50
|
+
let i;
|
|
51
|
+
while ((i = buf.indexOf('\n')) >= 0) {
|
|
52
|
+
const line = buf.slice(0, i).trim(); buf = buf.slice(i + 1);
|
|
53
|
+
if (!line) continue;
|
|
54
|
+
let o = null;
|
|
55
|
+
try { o = JSON.parse(line); } catch (e) { continue; }
|
|
56
|
+
if (o && o.event) continue;
|
|
57
|
+
if (o && typeof o.id === 'number' && Object.prototype.hasOwnProperty.call(o, 'ok')) {
|
|
58
|
+
results[o.id] = o;
|
|
59
|
+
if (Object.keys(results).length >= requests.length) {
|
|
60
|
+
const arr = requests.map((_, k) => results[k + 1]);
|
|
61
|
+
finish(arr.length === 1 ? arr[0] : { ok: true, results: arr });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
py.stderr.on('data', (d) => { errTail = (errTail + d.toString('utf8')).slice(-800); });
|
|
67
|
+
py.on('error', (e) => finish({ ok: false, error: 'python baslatilamadi: ' + e.message }));
|
|
68
|
+
py.on('close', (code) => { if (Object.keys(results).length < requests.length) finish({ ok: false, error: 'bridge erken cikti code=' + code + ' ' + errTail }); });
|
|
69
|
+
requests.forEach((r, k) => py.stdin.write(JSON.stringify({ id: k + 1, method: r.method, params: r.params || {} }) + '\n'));
|
|
70
|
+
py.stdin.end();
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
(async function main() {
|
|
75
|
+
let args = {};
|
|
76
|
+
try { args = JSON.parse(fs.readFileSync(0, 'utf8') || '{}'); } catch (e) {}
|
|
77
|
+
const ticket = Number(args.ticket || 0);
|
|
78
|
+
if (!ticket) return console.log(JSON.stringify({ ok: false, error: 'ticket zorunlu' }));
|
|
79
|
+
const params = { ticket: ticket };
|
|
80
|
+
if (args.volume) params.volume = Number(args.volume);
|
|
81
|
+
const r = await call([{ method: 'close', params: params }]);
|
|
82
|
+
if (r.ok && r.data && r.data.result) {
|
|
83
|
+
const res = r.data.result;
|
|
84
|
+
console.log(JSON.stringify({ ok: true, retcode: res.retcode, comment: res.comment, detay: r.data }));
|
|
85
|
+
} else {
|
|
86
|
+
console.log(JSON.stringify({ ok: false, error: r.error || 'kapatma reddedildi' }));
|
|
87
|
+
}
|
|
88
|
+
})();
|
|
89
|
+
|
|
90
|
+
/* PATCH 2026-09-10b: electron app-mode cocuk prosesi kapanmiyordu (90sn timeout).
|
|
91
|
+
stdout'un boruya bosalmasi icin kisa bekleme, sonra zorla cik. */
|
|
92
|
+
setTimeout(() => process.exit(0), 1500);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mt5_kapat",
|
|
3
|
+
"description": "Açık pozisyonu KAPATIR: ticket (pozisyon no) zorunlu. volume verilirse kısmi kapatır. Risk yönetimi için kullanılır. Başarıda kapanış sonucu döner.",
|
|
4
|
+
"parameters": {
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"ticket": { "type": "number", "description": "Kapatilacak pozisyonun ticket numarasi" },
|
|
8
|
+
"volume": { "type": "number", "description": "Kapatilacak lot (bos = tamami)" }
|
|
9
|
+
},
|
|
10
|
+
"required": ["ticket"]
|
|
11
|
+
},
|
|
12
|
+
"updatedAt": "2026-09-09T18:48:00.000Z"
|
|
13
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""mt5_m15_m5 - SALT-OKUNUR yardimci. GOLD M15 + M5 son 12 bar + canli fiyat.
|
|
2
|
+
Arguman ALMAZ. Kopruye (mt5_bridge.py) DOKUNMAZ, ayri surecte calisir.
|
|
3
|
+
hicbir order_send / order_check / positions_close cagrisi YOKTUR.
|
|
4
|
+
Cikti: stdout'a TEK satir JSON, 2000 baytin altinda.
|
|
5
|
+
"""
|
|
6
|
+
import sys, json, datetime
|
|
7
|
+
|
|
8
|
+
SYM = "GOLD"
|
|
9
|
+
TERM = r"C:\Program Files\FxPro - MetaTrader 5\terminal64.exe"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def emit(o, code=0):
|
|
13
|
+
sys.stdout.write(json.dumps(o, separators=(",", ":")))
|
|
14
|
+
sys.stdout.flush()
|
|
15
|
+
sys.exit(code)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
try:
|
|
19
|
+
import MetaTrader5 as mt5
|
|
20
|
+
except Exception as e:
|
|
21
|
+
emit({"ok": False, "error": "modul yuklenemedi: " + type(e).__name__}, 1)
|
|
22
|
+
|
|
23
|
+
if not mt5.initialize(path=TERM):
|
|
24
|
+
if not mt5.initialize():
|
|
25
|
+
emit({"ok": False, "error": "mt5 initialize basarisiz"}, 1)
|
|
26
|
+
|
|
27
|
+
try:
|
|
28
|
+
si = mt5.symbol_info(SYM)
|
|
29
|
+
if si is None:
|
|
30
|
+
emit({"ok": False, "error": "sembol yok: " + SYM}, 1)
|
|
31
|
+
if not si.visible:
|
|
32
|
+
mt5.symbol_select(SYM, True)
|
|
33
|
+
|
|
34
|
+
def bars(tf_const, n=12):
|
|
35
|
+
r = mt5.copy_rates_from_pos(SYM, tf_const, 0, n)
|
|
36
|
+
if r is None or len(r) == 0:
|
|
37
|
+
return []
|
|
38
|
+
return [[int(x["time"]), round(float(x["open"]), 2), round(float(x["high"]), 2),
|
|
39
|
+
round(float(x["low"]), 2), round(float(x["close"]), 2)] for x in r]
|
|
40
|
+
|
|
41
|
+
m15 = bars(mt5.TIMEFRAME_M15, 12)
|
|
42
|
+
m5 = bars(mt5.TIMEFRAME_M5, 12)
|
|
43
|
+
if not m15 and not m5:
|
|
44
|
+
emit({"ok": False, "error": "bar alinamadi: " + SYM}, 1)
|
|
45
|
+
|
|
46
|
+
tk = mt5.symbol_info_tick(SYM)
|
|
47
|
+
if tk is None:
|
|
48
|
+
st, bid, ask, sp = "--:--", 0, 0, 0
|
|
49
|
+
else:
|
|
50
|
+
bid, ask = round(float(tk.bid), 2), round(float(tk.ask), 2)
|
|
51
|
+
sp = round(ask - bid, 2)
|
|
52
|
+
st = datetime.datetime.fromtimestamp(int(tk.time), datetime.timezone.utc).strftime("%H:%M")
|
|
53
|
+
|
|
54
|
+
emit({"ok": True, "server_time": st, "bid": bid, "ask": ask, "spread": sp,
|
|
55
|
+
"m15": m15, "m5": m5}, 0)
|
|
56
|
+
finally:
|
|
57
|
+
try:
|
|
58
|
+
mt5.shutdown()
|
|
59
|
+
except Exception:
|
|
60
|
+
pass
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/* mt5_m15_m5 - PARAMETRE ALMAZ (argumansiz yedek yol).
|
|
3
|
+
C:\Python314\python.exe ile yanindaki m15m5.py dosyasini calistirir,
|
|
4
|
+
stdout'a TEK satir JSON basar. SALT-OKUNUR: hicbir islem/pending/close cagrisi yok.
|
|
5
|
+
Cikti alanlari: ok, server_time, bid, ask, spread, m15[12], m5[12] -> [epoch,o,h,l,c]
|
|
6
|
+
stdout sert sinir: 2000 bayt. */
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const { spawnSync } = require('child_process');
|
|
10
|
+
function resolvePython() {
|
|
11
|
+
const cands = [];
|
|
12
|
+
if (process.env.BEAST_PYTHON) cands.push({ exe: String(process.env.BEAST_PYTHON), args: [] });
|
|
13
|
+
if (process.env.APPDATA) cands.push({ exe: require('path').join(process.env.APPDATA, 'beast', 'py', 'python.exe'), args: [] });
|
|
14
|
+
for (const v of ['314', '313', '312', '311', '310']) cands.push({ exe: 'C:\\Python' + v + '\\python.exe', args: [] });
|
|
15
|
+
cands.push({ exe: 'python', args: [] }, { exe: 'py', args: ['-3'] });
|
|
16
|
+
for (const c of cands) {
|
|
17
|
+
if (c.exe === 'python' || c.exe === 'py') return c;
|
|
18
|
+
try { if (fs.existsSync(c.exe)) return c; } catch (e) {}
|
|
19
|
+
}
|
|
20
|
+
return { exe: 'python', args: [] };
|
|
21
|
+
}
|
|
22
|
+
const PYSPEC = resolvePython();
|
|
23
|
+
const PY = PYSPEC.exe;
|
|
24
|
+
const PY_ARGS = PYSPEC.args;
|
|
25
|
+
|
|
26
|
+
const SCRIPT = path.join(__dirname, 'm15m5.py');
|
|
27
|
+
const LIMIT = 2000;
|
|
28
|
+
|
|
29
|
+
function emit(o, code) {
|
|
30
|
+
process.stdout.write(JSON.stringify(o));
|
|
31
|
+
process.exit(code || 0);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
(function main() {
|
|
35
|
+
// parametre almaz: stdin'i beklemeden sessizce yut, araclar arasi kalmasin
|
|
36
|
+
try {
|
|
37
|
+
process.stdin.on('error', () => {});
|
|
38
|
+
process.stdin.on('data', () => {});
|
|
39
|
+
process.stdin.resume();
|
|
40
|
+
} catch { }
|
|
41
|
+
|
|
42
|
+
if (!fs.existsSync(SCRIPT)) return emit({ ok: false, error: 'm15m5.py yok: ' + SCRIPT }, 1);
|
|
43
|
+
|
|
44
|
+
let r;
|
|
45
|
+
try {
|
|
46
|
+
r = spawnSync(PY, [...PY_ARGS, SCRIPT], { encoding: 'utf8', timeout: 60000, windowsHide: true });
|
|
47
|
+
} catch (e) {
|
|
48
|
+
return emit({ ok: false, error: 'python baslatilamadi: ' + String((e && e.message) || e).slice(0, 140) }, 1);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const out = String((r && r.stdout) || '').trim();
|
|
52
|
+
if (out) {
|
|
53
|
+
let parsed = null;
|
|
54
|
+
try { parsed = JSON.parse(out); } catch { }
|
|
55
|
+
if (parsed && typeof parsed === 'object') {
|
|
56
|
+
const packed = JSON.stringify(parsed);
|
|
57
|
+
const bytes = Buffer.byteLength(packed, 'utf8');
|
|
58
|
+
if (bytes > LIMIT) return emit({ ok: false, error: 'cikti siniri asildi', bytes: bytes, limit: LIMIT }, 1);
|
|
59
|
+
return emit(parsed, parsed.ok ? 0 : 1);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
emit({
|
|
64
|
+
ok: false,
|
|
65
|
+
error: 'python cikti yok/kirik',
|
|
66
|
+
exit_code: r && r.status,
|
|
67
|
+
stderr: String((r && r.stderr) || '').trim().slice(0, 300),
|
|
68
|
+
}, 1);
|
|
69
|
+
})();
|
|
70
|
+
|
|
71
|
+
/* PATCH 2026-09-10b: electron app-mode cocuk prosesi kapanmiyordu (90sn timeout).
|
|
72
|
+
stdout'un boruya bosalmasi icin kisa bekleme, sonra zorla cik. */
|
|
73
|
+
setTimeout(() => process.exit(0), 1500);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mt5_m15_m5",
|
|
3
|
+
"description": "PARAMETRE ALMAZ (argumansiz cagrilir). SALT-OKUNUR, islem acmaz. C:\\Python314\\python.exe ile MetaTrader5 modulunu DOGRUDAN kullanip GOLD icin tek satir JSON dondurur: server_time (HH:MM), bid, ask, spread, m15 (son 12 M15 bari), m5 (son 12 M5 bari) - barlar [epoch,o,h,l,c] biciminde eskiden yeniye. Amac: parametre gecirmeyen runner icin parametresiz yedek yol.",
|
|
4
|
+
"parameters": {
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {},
|
|
7
|
+
"required": []
|
|
8
|
+
},
|
|
9
|
+
"updatedAt": "2026-09-10T10:05:00.000Z"
|
|
10
|
+
}
|