@timmeck/trading-brain 2.0.3 → 2.2.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/dist/db/migrations/008_backtest_alerts.d.ts +2 -0
- package/dist/db/migrations/008_backtest_alerts.js +32 -0
- package/dist/db/migrations/008_backtest_alerts.js.map +1 -0
- package/dist/db/migrations/index.js +2 -0
- package/dist/db/migrations/index.js.map +1 -1
- package/dist/db/repositories/alert.repository.d.ts +50 -0
- package/dist/db/repositories/alert.repository.js +87 -0
- package/dist/db/repositories/alert.repository.js.map +1 -0
- package/dist/ipc/router.d.ts +8 -0
- package/dist/ipc/router.js +27 -1
- package/dist/ipc/router.js.map +1 -1
- package/dist/mcp/tools.js +211 -0
- package/dist/mcp/tools.js.map +1 -1
- package/dist/services/alert.service.d.ts +33 -0
- package/dist/services/alert.service.js +137 -0
- package/dist/services/alert.service.js.map +1 -0
- package/dist/services/backtest.service.d.ts +96 -0
- package/dist/services/backtest.service.js +242 -0
- package/dist/services/backtest.service.js.map +1 -0
- package/dist/services/import.service.d.ts +24 -0
- package/dist/services/import.service.js +94 -0
- package/dist/services/import.service.js.map +1 -0
- package/dist/services/risk.service.d.ts +52 -0
- package/dist/services/risk.service.js +244 -0
- package/dist/services/risk.service.js.map +1 -0
- package/dist/trading-core.d.ts +1 -0
- package/dist/trading-core.js +36 -9
- package/dist/trading-core.js.map +1 -1
- package/dist/utils/events.d.ts +5 -0
- package/dist/utils/events.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export function up(db) {
|
|
2
|
+
// Add timeframe column to trades
|
|
3
|
+
db.exec(`ALTER TABLE trades ADD COLUMN timeframe TEXT DEFAULT NULL`);
|
|
4
|
+
// Alerts table
|
|
5
|
+
db.exec(`
|
|
6
|
+
CREATE TABLE IF NOT EXISTS alerts (
|
|
7
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
8
|
+
name TEXT NOT NULL,
|
|
9
|
+
condition_type TEXT NOT NULL,
|
|
10
|
+
condition_json TEXT NOT NULL,
|
|
11
|
+
active INTEGER NOT NULL DEFAULT 1,
|
|
12
|
+
webhook_url TEXT DEFAULT NULL,
|
|
13
|
+
last_triggered_at TEXT DEFAULT NULL,
|
|
14
|
+
trigger_count INTEGER NOT NULL DEFAULT 0,
|
|
15
|
+
cooldown_minutes INTEGER NOT NULL DEFAULT 60,
|
|
16
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
17
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
18
|
+
);
|
|
19
|
+
`);
|
|
20
|
+
// Alert history
|
|
21
|
+
db.exec(`
|
|
22
|
+
CREATE TABLE IF NOT EXISTS alert_history (
|
|
23
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
24
|
+
alert_id INTEGER NOT NULL REFERENCES alerts(id),
|
|
25
|
+
trade_id INTEGER DEFAULT NULL,
|
|
26
|
+
message TEXT NOT NULL,
|
|
27
|
+
data_json TEXT DEFAULT NULL,
|
|
28
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
29
|
+
);
|
|
30
|
+
`);
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=008_backtest_alerts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"008_backtest_alerts.js","sourceRoot":"","sources":["../../../src/db/migrations/008_backtest_alerts.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,EAAE,CAAC,EAAqB;IACtC,iCAAiC;IACjC,EAAE,CAAC,IAAI,CAAC,2DAA2D,CAAC,CAAC;IAErE,eAAe;IACf,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;;GAcP,CAAC,CAAC;IAEH,gBAAgB;IAChB,EAAE,CAAC,IAAI,CAAC;;;;;;;;;GASP,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -6,6 +6,7 @@ import { up as researchSchema } from './004_research.js';
|
|
|
6
6
|
import { up as memorySchema } from './005_memory_schema.js';
|
|
7
7
|
import { up as memoryFts } from './006_memory_fts.js';
|
|
8
8
|
import { up as calibrationHistory } from './007_calibration_history.js';
|
|
9
|
+
import { up as backtestAlerts } from './008_backtest_alerts.js';
|
|
9
10
|
const migrations = [
|
|
10
11
|
{ version: 1, name: '001_core', up: coreSchema },
|
|
11
12
|
{ version: 2, name: '002_synapses', up: synapsesSchema },
|
|
@@ -14,6 +15,7 @@ const migrations = [
|
|
|
14
15
|
{ version: 5, name: '005_memory_schema', up: memorySchema },
|
|
15
16
|
{ version: 6, name: '006_memory_fts', up: memoryFts },
|
|
16
17
|
{ version: 7, name: '007_calibration_history', up: calibrationHistory },
|
|
18
|
+
{ version: 8, name: '008_backtest_alerts', up: backtestAlerts },
|
|
17
19
|
];
|
|
18
20
|
function ensureMigrationsTable(db) {
|
|
19
21
|
db.exec(`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/db/migrations/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,EAAE,IAAI,UAAU,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,EAAE,IAAI,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,EAAE,IAAI,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,EAAE,IAAI,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,EAAE,IAAI,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,EAAE,IAAI,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,EAAE,IAAI,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/db/migrations/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type Database from 'better-sqlite3';
|
|
2
|
+
export interface AlertRecord {
|
|
3
|
+
id: number;
|
|
4
|
+
name: string;
|
|
5
|
+
condition_type: string;
|
|
6
|
+
condition_json: string;
|
|
7
|
+
active: number;
|
|
8
|
+
webhook_url: string | null;
|
|
9
|
+
last_triggered_at: string | null;
|
|
10
|
+
trigger_count: number;
|
|
11
|
+
cooldown_minutes: number;
|
|
12
|
+
created_at: string;
|
|
13
|
+
updated_at: string;
|
|
14
|
+
}
|
|
15
|
+
export interface AlertHistoryRecord {
|
|
16
|
+
id: number;
|
|
17
|
+
alert_id: number;
|
|
18
|
+
trade_id: number | null;
|
|
19
|
+
message: string;
|
|
20
|
+
data_json: string | null;
|
|
21
|
+
created_at: string;
|
|
22
|
+
}
|
|
23
|
+
export interface CreateAlertData {
|
|
24
|
+
name: string;
|
|
25
|
+
condition_type: string;
|
|
26
|
+
condition_json: string;
|
|
27
|
+
webhook_url?: string;
|
|
28
|
+
cooldown_minutes?: number;
|
|
29
|
+
}
|
|
30
|
+
export interface UpdateAlertData {
|
|
31
|
+
name?: string;
|
|
32
|
+
condition_type?: string;
|
|
33
|
+
condition_json?: string;
|
|
34
|
+
active?: boolean;
|
|
35
|
+
webhook_url?: string | null;
|
|
36
|
+
cooldown_minutes?: number;
|
|
37
|
+
}
|
|
38
|
+
export declare class AlertRepository {
|
|
39
|
+
private db;
|
|
40
|
+
private stmts;
|
|
41
|
+
constructor(db: Database.Database);
|
|
42
|
+
create(data: CreateAlertData): number;
|
|
43
|
+
getById(id: number): AlertRecord | undefined;
|
|
44
|
+
getAll(): AlertRecord[];
|
|
45
|
+
getActive(): AlertRecord[];
|
|
46
|
+
update(id: number, data: UpdateAlertData): void;
|
|
47
|
+
delete(id: number): void;
|
|
48
|
+
recordTrigger(alertId: number, tradeId: number | null, message: string, data?: unknown): number;
|
|
49
|
+
getHistory(alertId: number, limit?: number): AlertHistoryRecord[];
|
|
50
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
export class AlertRepository {
|
|
2
|
+
db;
|
|
3
|
+
stmts;
|
|
4
|
+
constructor(db) {
|
|
5
|
+
this.db = db;
|
|
6
|
+
this.stmts = {
|
|
7
|
+
create: db.prepare(`
|
|
8
|
+
INSERT INTO alerts (name, condition_type, condition_json, webhook_url, cooldown_minutes)
|
|
9
|
+
VALUES (@name, @condition_type, @condition_json, @webhook_url, @cooldown_minutes)
|
|
10
|
+
`),
|
|
11
|
+
getById: db.prepare('SELECT * FROM alerts WHERE id = ?'),
|
|
12
|
+
getAll: db.prepare('SELECT * FROM alerts ORDER BY created_at DESC'),
|
|
13
|
+
getActive: db.prepare('SELECT * FROM alerts WHERE active = 1 ORDER BY created_at DESC'),
|
|
14
|
+
update: db.prepare(`
|
|
15
|
+
UPDATE alerts
|
|
16
|
+
SET name = COALESCE(@name, name),
|
|
17
|
+
condition_type = COALESCE(@condition_type, condition_type),
|
|
18
|
+
condition_json = COALESCE(@condition_json, condition_json),
|
|
19
|
+
active = COALESCE(@active, active),
|
|
20
|
+
webhook_url = COALESCE(@webhook_url, webhook_url),
|
|
21
|
+
cooldown_minutes = COALESCE(@cooldown_minutes, cooldown_minutes),
|
|
22
|
+
updated_at = datetime('now')
|
|
23
|
+
WHERE id = @id
|
|
24
|
+
`),
|
|
25
|
+
delete: db.prepare('DELETE FROM alerts WHERE id = ?'),
|
|
26
|
+
recordTrigger: db.prepare(`
|
|
27
|
+
INSERT INTO alert_history (alert_id, trade_id, message, data_json)
|
|
28
|
+
VALUES (@alert_id, @trade_id, @message, @data_json)
|
|
29
|
+
`),
|
|
30
|
+
updateTriggerMeta: db.prepare(`
|
|
31
|
+
UPDATE alerts
|
|
32
|
+
SET last_triggered_at = datetime('now'),
|
|
33
|
+
trigger_count = trigger_count + 1,
|
|
34
|
+
updated_at = datetime('now')
|
|
35
|
+
WHERE id = ?
|
|
36
|
+
`),
|
|
37
|
+
getHistory: db.prepare('SELECT * FROM alert_history WHERE alert_id = ? ORDER BY created_at DESC LIMIT ?'),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
create(data) {
|
|
41
|
+
const result = this.stmts['create'].run({
|
|
42
|
+
name: data.name,
|
|
43
|
+
condition_type: data.condition_type,
|
|
44
|
+
condition_json: data.condition_json,
|
|
45
|
+
webhook_url: data.webhook_url ?? null,
|
|
46
|
+
cooldown_minutes: data.cooldown_minutes ?? 0,
|
|
47
|
+
});
|
|
48
|
+
return result.lastInsertRowid;
|
|
49
|
+
}
|
|
50
|
+
getById(id) {
|
|
51
|
+
return this.stmts['getById'].get(id);
|
|
52
|
+
}
|
|
53
|
+
getAll() {
|
|
54
|
+
return this.stmts['getAll'].all();
|
|
55
|
+
}
|
|
56
|
+
getActive() {
|
|
57
|
+
return this.stmts['getActive'].all();
|
|
58
|
+
}
|
|
59
|
+
update(id, data) {
|
|
60
|
+
this.stmts['update'].run({
|
|
61
|
+
id,
|
|
62
|
+
name: data.name ?? null,
|
|
63
|
+
condition_type: data.condition_type ?? null,
|
|
64
|
+
condition_json: data.condition_json ?? null,
|
|
65
|
+
active: data.active !== undefined ? (data.active ? 1 : 0) : null,
|
|
66
|
+
webhook_url: data.webhook_url !== undefined ? data.webhook_url : null,
|
|
67
|
+
cooldown_minutes: data.cooldown_minutes ?? null,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
delete(id) {
|
|
71
|
+
this.stmts['delete'].run(id);
|
|
72
|
+
}
|
|
73
|
+
recordTrigger(alertId, tradeId, message, data) {
|
|
74
|
+
const result = this.stmts['recordTrigger'].run({
|
|
75
|
+
alert_id: alertId,
|
|
76
|
+
trade_id: tradeId,
|
|
77
|
+
message,
|
|
78
|
+
data_json: data ? JSON.stringify(data) : null,
|
|
79
|
+
});
|
|
80
|
+
this.stmts['updateTriggerMeta'].run(alertId);
|
|
81
|
+
return result.lastInsertRowid;
|
|
82
|
+
}
|
|
83
|
+
getHistory(alertId, limit = 50) {
|
|
84
|
+
return this.stmts['getHistory'].all(alertId, limit);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=alert.repository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alert.repository.js","sourceRoot":"","sources":["../../../src/db/repositories/alert.repository.ts"],"names":[],"mappings":"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"}
|
package/dist/ipc/router.d.ts
CHANGED
|
@@ -5,6 +5,10 @@ import type { SynapseService } from '../services/synapse.service.js';
|
|
|
5
5
|
import type { AnalyticsService } from '../services/analytics.service.js';
|
|
6
6
|
import type { InsightService } from '../services/insight.service.js';
|
|
7
7
|
import type { MemoryService } from '../services/memory.service.js';
|
|
8
|
+
import type { BacktestService } from '../services/backtest.service.js';
|
|
9
|
+
import type { RiskService } from '../services/risk.service.js';
|
|
10
|
+
import type { AlertService } from '../services/alert.service.js';
|
|
11
|
+
import type { ImportService } from '../services/import.service.js';
|
|
8
12
|
import type { LearningEngine } from '../learning/learning-engine.js';
|
|
9
13
|
import type { ResearchEngine } from '../research/research-engine.js';
|
|
10
14
|
import type { RuleRepository } from '../db/repositories/rule.repository.js';
|
|
@@ -20,6 +24,10 @@ export interface Services {
|
|
|
20
24
|
analytics: AnalyticsService;
|
|
21
25
|
insight: InsightService;
|
|
22
26
|
memory: MemoryService;
|
|
27
|
+
backtest: BacktestService;
|
|
28
|
+
risk: RiskService;
|
|
29
|
+
alert: AlertService;
|
|
30
|
+
import: ImportService;
|
|
23
31
|
ruleRepo: RuleRepository;
|
|
24
32
|
chainRepo: ChainRepository;
|
|
25
33
|
calRepo: CalibrationRepository;
|
package/dist/ipc/router.js
CHANGED
|
@@ -101,6 +101,32 @@ export class IpcRouter {
|
|
|
101
101
|
['session.history', (params) => s.memory.getSessionHistory(p(params).limit)],
|
|
102
102
|
// ─── Analytics ──────────────────────────────────────
|
|
103
103
|
['analytics.summary', () => s.analytics.getSummary()],
|
|
104
|
+
// ─── Backtest ─────────────────────────────────────
|
|
105
|
+
['backtest.run', (params) => {
|
|
106
|
+
const result = s.backtest.runBacktest(p(params));
|
|
107
|
+
// Convert Maps to plain objects for JSON serialization
|
|
108
|
+
return {
|
|
109
|
+
...result,
|
|
110
|
+
tradesByPair: Object.fromEntries(result.tradesByPair),
|
|
111
|
+
tradesByRegime: Object.fromEntries(result.tradesByRegime),
|
|
112
|
+
};
|
|
113
|
+
}],
|
|
114
|
+
['backtest.compare', (params) => s.backtest.compareSignals(p(params).fingerprint1, p(params).fingerprint2)],
|
|
115
|
+
['backtest.bestSignals', (params) => s.backtest.findBestSignals(p(params))],
|
|
116
|
+
// ─── Risk ─────────────────────────────────────────
|
|
117
|
+
['risk.kelly', (params) => s.risk.getKellyFraction(p(params).pair, p(params).regime)],
|
|
118
|
+
['risk.positionSize', (params) => s.risk.getPositionSize(p(params).capitalPct, p(params).signals, p(params).regime)],
|
|
119
|
+
['risk.metrics', (params) => s.risk.getRiskMetrics(p(params).pair)],
|
|
120
|
+
// ─── Alerts ───────────────────────────────────────
|
|
121
|
+
['alert.create', (params) => s.alert.createAlert(p(params))],
|
|
122
|
+
['alert.list', () => s.alert.getAlerts()],
|
|
123
|
+
['alert.listAll', () => s.alert.getAllAlerts()],
|
|
124
|
+
['alert.delete', (params) => s.alert.deleteAlert(p(params).id)],
|
|
125
|
+
['alert.check', (params) => s.alert.checkAlerts(p(params).trade, p(params).context)],
|
|
126
|
+
['alert.history', (params) => s.alert.getAlertHistory(p(params).alertId, p(params).limit)],
|
|
127
|
+
// ─── Import ───────────────────────────────────────
|
|
128
|
+
['import.trades', (params) => s.import.importTrades(p(params).trades)],
|
|
129
|
+
['import.json', (params) => s.import.importFromJson(p(params).json)],
|
|
104
130
|
// ─── Learning ───────────────────────────────────────
|
|
105
131
|
['learning.run', () => s.learning?.runManual()],
|
|
106
132
|
// ─── Research ───────────────────────────────────────
|
|
@@ -135,7 +161,7 @@ export class IpcRouter {
|
|
|
135
161
|
// ─── Status (cross-brain) ─────────────────────────────
|
|
136
162
|
['status', () => ({
|
|
137
163
|
name: 'trading-brain',
|
|
138
|
-
version: '
|
|
164
|
+
version: '2.2.0',
|
|
139
165
|
uptime: Math.floor(process.uptime()),
|
|
140
166
|
pid: process.pid,
|
|
141
167
|
methods: this.listMethods().length,
|
package/dist/ipc/router.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/ipc/router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/ipc/router.ts"],"names":[],"mappings":"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"}
|
package/dist/mcp/tools.js
CHANGED
|
@@ -206,6 +206,217 @@ function registerToolsWithCaller(server, call) {
|
|
|
206
206
|
}
|
|
207
207
|
return textResult(lines.join('\n'));
|
|
208
208
|
});
|
|
209
|
+
// === Backtesting Tools ===
|
|
210
|
+
server.tool('trading_backtest', 'Run a backtest on historical trades. Computes win rate, profit factor, Sharpe ratio, max drawdown, equity curve, and per-pair/regime breakdowns.', {
|
|
211
|
+
pair: z.string().optional().describe('Filter by trading pair'),
|
|
212
|
+
regime: z.string().optional().describe('Filter by market regime'),
|
|
213
|
+
timeframe: z.string().optional().describe('Filter by timeframe'),
|
|
214
|
+
bot_type: z.string().optional().describe('Filter by bot type'),
|
|
215
|
+
from_date: z.string().optional().describe('Start date (ISO format)'),
|
|
216
|
+
to_date: z.string().optional().describe('End date (ISO format)'),
|
|
217
|
+
signal_filter: z.string().optional().describe('Filter by signal fingerprint similarity'),
|
|
218
|
+
}, async (params) => {
|
|
219
|
+
const result = await call('backtest.run', {
|
|
220
|
+
pair: params.pair,
|
|
221
|
+
regime: params.regime,
|
|
222
|
+
timeframe: params.timeframe,
|
|
223
|
+
botType: params.bot_type,
|
|
224
|
+
fromDate: params.from_date,
|
|
225
|
+
toDate: params.to_date,
|
|
226
|
+
signalFilter: params.signal_filter,
|
|
227
|
+
});
|
|
228
|
+
if (result.totalTrades === 0)
|
|
229
|
+
return textResult('No trades match the given filters.');
|
|
230
|
+
const lines = [
|
|
231
|
+
'── Backtest Results ──',
|
|
232
|
+
` Total trades: ${result.totalTrades}`,
|
|
233
|
+
` Win rate: ${(result.winRate * 100).toFixed(1)}% (${result.wins}W / ${result.losses}L)`,
|
|
234
|
+
` Total profit: ${result.totalProfitPct.toFixed(2)}%`,
|
|
235
|
+
` Avg profit: ${result.avgProfitPct.toFixed(2)}%`,
|
|
236
|
+
` Avg win: ${result.avgWinPct.toFixed(2)}%`,
|
|
237
|
+
` Avg loss: ${result.avgLossPct.toFixed(2)}%`,
|
|
238
|
+
` Best trade: ${result.bestTrade.toFixed(2)}%`,
|
|
239
|
+
` Worst trade: ${result.worstTrade.toFixed(2)}%`,
|
|
240
|
+
` Max drawdown: ${result.maxDrawdownPct.toFixed(2)}%`,
|
|
241
|
+
` Profit factor: ${result.profitFactor === Infinity ? '∞' : result.profitFactor.toFixed(2)}`,
|
|
242
|
+
` Sharpe ratio: ${result.sharpeRatio.toFixed(2)}`,
|
|
243
|
+
];
|
|
244
|
+
if (result.tradesByPair && Object.keys(result.tradesByPair).length > 0) {
|
|
245
|
+
lines.push('', '── By Pair ──');
|
|
246
|
+
for (const [pair, stats] of Object.entries(result.tradesByPair)) {
|
|
247
|
+
const s = stats;
|
|
248
|
+
lines.push(` ${pair}: ${s.wins}W/${s.losses}L, profit: ${s.profitPct.toFixed(2)}%`);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
if (result.tradesByRegime && Object.keys(result.tradesByRegime).length > 0) {
|
|
252
|
+
lines.push('', '── By Regime ──');
|
|
253
|
+
for (const [regime, stats] of Object.entries(result.tradesByRegime)) {
|
|
254
|
+
const s = stats;
|
|
255
|
+
lines.push(` ${regime}: ${s.wins}W/${s.losses}L, profit: ${s.profitPct.toFixed(2)}%`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return textResult(lines.join('\n'));
|
|
259
|
+
});
|
|
260
|
+
server.tool('trading_compare_signals', 'Compare two signal fingerprint patterns head-to-head. Shows win rate, avg profit, sample size, and similarity.', {
|
|
261
|
+
fingerprint1: z.string().describe('First signal fingerprint'),
|
|
262
|
+
fingerprint2: z.string().describe('Second signal fingerprint'),
|
|
263
|
+
}, async (params) => {
|
|
264
|
+
const result = await call('backtest.compare', params);
|
|
265
|
+
const lines = [
|
|
266
|
+
'── Signal Comparison ──',
|
|
267
|
+
'',
|
|
268
|
+
`Signal 1: ${result.fingerprint1}`,
|
|
269
|
+
` Win rate: ${(result.stats1.winRate * 100).toFixed(1)}% (${result.stats1.wins}W / ${result.stats1.losses}L)`,
|
|
270
|
+
` Avg profit: ${result.stats1.avgProfitPct.toFixed(2)}%`,
|
|
271
|
+
` Sample size: ${result.stats1.sampleSize}`,
|
|
272
|
+
'',
|
|
273
|
+
`Signal 2: ${result.fingerprint2}`,
|
|
274
|
+
` Win rate: ${(result.stats2.winRate * 100).toFixed(1)}% (${result.stats2.wins}W / ${result.stats2.losses}L)`,
|
|
275
|
+
` Avg profit: ${result.stats2.avgProfitPct.toFixed(2)}%`,
|
|
276
|
+
` Sample size: ${result.stats2.sampleSize}`,
|
|
277
|
+
'',
|
|
278
|
+
`Similarity: ${(result.similarity * 100).toFixed(0)}%`,
|
|
279
|
+
`Verdict: ${result.verdict}`,
|
|
280
|
+
];
|
|
281
|
+
return textResult(lines.join('\n'));
|
|
282
|
+
});
|
|
283
|
+
server.tool('trading_best_signals', 'Find the top-performing signal patterns ranked by win rate. Requires a minimum sample size for statistical validity.', {
|
|
284
|
+
min_sample_size: z.number().optional().describe('Minimum trades per signal (default 5)'),
|
|
285
|
+
top_n: z.number().optional().describe('Number of top signals to return (default 20)'),
|
|
286
|
+
pair: z.string().optional().describe('Filter by trading pair'),
|
|
287
|
+
regime: z.string().optional().describe('Filter by market regime'),
|
|
288
|
+
}, async (params) => {
|
|
289
|
+
const result = await call('backtest.bestSignals', {
|
|
290
|
+
minSampleSize: params.min_sample_size,
|
|
291
|
+
topN: params.top_n,
|
|
292
|
+
pair: params.pair,
|
|
293
|
+
regime: params.regime,
|
|
294
|
+
});
|
|
295
|
+
if (!Array.isArray(result) || result.length === 0) {
|
|
296
|
+
return textResult('No signals found with enough data. Try lowering min_sample_size.');
|
|
297
|
+
}
|
|
298
|
+
const lines = ['── Top Signals ──'];
|
|
299
|
+
for (let i = 0; i < result.length; i++) {
|
|
300
|
+
const s = result[i];
|
|
301
|
+
lines.push(` ${i + 1}. ${s.fingerprint}`, ` WR: ${(s.winRate * 100).toFixed(1)}% | Avg: ${s.avgProfitPct.toFixed(2)}% | ` +
|
|
302
|
+
`${s.wins}W/${s.losses}L (n=${s.sampleSize}) | ` +
|
|
303
|
+
`synapse: ${s.synapseWeight !== null ? s.synapseWeight.toFixed(3) : 'none'}`);
|
|
304
|
+
}
|
|
305
|
+
return textResult(lines.join('\n'));
|
|
306
|
+
});
|
|
307
|
+
// === Risk Management Tools ===
|
|
308
|
+
server.tool('trading_kelly', 'Calculate Kelly Criterion fraction for position sizing. Returns raw Kelly, half-Kelly, and brain-adjusted values.', {
|
|
309
|
+
pair: z.string().optional().describe('Filter by trading pair'),
|
|
310
|
+
regime: z.string().optional().describe('Filter by market regime'),
|
|
311
|
+
}, async (params) => {
|
|
312
|
+
const result = await call('risk.kelly', params);
|
|
313
|
+
const lines = [
|
|
314
|
+
'── Kelly Criterion ──',
|
|
315
|
+
` Kelly fraction: ${result.kellyFraction.toFixed(3)} (${(result.kellyFraction * 100).toFixed(1)}%)`,
|
|
316
|
+
` Half-Kelly: ${result.halfKelly.toFixed(3)} (${(result.halfKelly * 100).toFixed(1)}%)`,
|
|
317
|
+
` Brain-adjusted: ${result.brainAdjusted.toFixed(3)} (${(result.brainAdjusted * 100).toFixed(1)}%)`,
|
|
318
|
+
'',
|
|
319
|
+
` Win rate: ${(result.winRate * 100).toFixed(1)}%`,
|
|
320
|
+
` Avg win: ${result.avgWin.toFixed(2)}%`,
|
|
321
|
+
` Avg loss: ${result.avgLoss.toFixed(2)}%`,
|
|
322
|
+
` Sample size: ${result.sampleSize}`,
|
|
323
|
+
'',
|
|
324
|
+
` Recommendation: ${result.recommendation}`,
|
|
325
|
+
];
|
|
326
|
+
return textResult(lines.join('\n'));
|
|
327
|
+
});
|
|
328
|
+
server.tool('trading_position_size', 'Get a recommended position size based on Kelly Criterion and signal confidence. Capped at 25% of capital.', {
|
|
329
|
+
capital_pct: z.number().describe('Fraction of total capital available (0-1)'),
|
|
330
|
+
fingerprint: z.string().describe('Signal fingerprint for confidence lookup'),
|
|
331
|
+
confidence: z.number().optional().describe('Override confidence (0-1)'),
|
|
332
|
+
regime: z.string().optional().describe('Market regime'),
|
|
333
|
+
}, async (params) => {
|
|
334
|
+
const result = await call('risk.positionSize', {
|
|
335
|
+
capitalPct: params.capital_pct,
|
|
336
|
+
signals: { fingerprint: params.fingerprint, confidence: params.confidence },
|
|
337
|
+
regime: params.regime,
|
|
338
|
+
});
|
|
339
|
+
const lines = [
|
|
340
|
+
'── Position Size ──',
|
|
341
|
+
` Size: ${result.sizePct.toFixed(1)}%`,
|
|
342
|
+
` Kelly raw: ${result.kellyRaw.toFixed(3)}`,
|
|
343
|
+
` Confidence: ${(result.confidence * 100).toFixed(1)}%`,
|
|
344
|
+
` Reason: ${result.reason}`,
|
|
345
|
+
];
|
|
346
|
+
return textResult(lines.join('\n'));
|
|
347
|
+
});
|
|
348
|
+
server.tool('trading_risk_metrics', 'Get risk metrics: max/current drawdown, consecutive losses, risk-reward ratio, and expectancy.', {
|
|
349
|
+
pair: z.string().optional().describe('Filter by trading pair'),
|
|
350
|
+
}, async (params) => {
|
|
351
|
+
const result = await call('risk.metrics', params);
|
|
352
|
+
const lines = [
|
|
353
|
+
'── Risk Metrics ──',
|
|
354
|
+
` Max drawdown: ${result.maxDrawdownPct.toFixed(2)}%`,
|
|
355
|
+
` Current drawdown: ${result.currentDrawdownPct.toFixed(2)}%`,
|
|
356
|
+
` Consecutive losses: ${result.consecutiveLosses} (max ever: ${result.maxConsecutiveLosses})`,
|
|
357
|
+
` Risk/Reward ratio: ${result.riskRewardRatio === Infinity ? '∞' : result.riskRewardRatio.toFixed(2)}`,
|
|
358
|
+
` Expectancy: ${result.expectancy.toFixed(3)}%`,
|
|
359
|
+
];
|
|
360
|
+
return textResult(lines.join('\n'));
|
|
361
|
+
});
|
|
362
|
+
// === Alert Tools ===
|
|
363
|
+
server.tool('trading_alert_create', 'Create a trading alert. Triggers when conditions are met (confidence thresholds, win/loss streaks, drawdown).', {
|
|
364
|
+
name: z.string().describe('Alert name'),
|
|
365
|
+
condition_type: z.enum(['confidence_above', 'confidence_below', 'win_streak', 'loss_streak', 'drawdown']).describe('Condition type'),
|
|
366
|
+
condition: z.record(z.string(), z.unknown()).describe('Condition parameters (e.g. { threshold: 0.8 } or { minStreak: 3 })'),
|
|
367
|
+
webhook_url: z.string().optional().describe('Webhook URL to POST when triggered'),
|
|
368
|
+
cooldown_minutes: z.number().optional().describe('Cooldown between triggers in minutes (default 60)'),
|
|
369
|
+
}, async (params) => {
|
|
370
|
+
const result = await call('alert.create', {
|
|
371
|
+
name: params.name,
|
|
372
|
+
conditionType: params.condition_type,
|
|
373
|
+
conditionJson: params.condition,
|
|
374
|
+
webhookUrl: params.webhook_url,
|
|
375
|
+
cooldownMinutes: params.cooldown_minutes,
|
|
376
|
+
});
|
|
377
|
+
return textResult(`Alert #${result} created: "${params.name}" (${params.condition_type})`);
|
|
378
|
+
});
|
|
379
|
+
server.tool('trading_alert_list', 'List all active trading alerts.', {}, async () => {
|
|
380
|
+
const alerts = await call('alert.list', {});
|
|
381
|
+
if (!Array.isArray(alerts) || alerts.length === 0)
|
|
382
|
+
return textResult('No active alerts.');
|
|
383
|
+
const lines = alerts.map((a) => `#${a.id} "${a.name}" (${a.condition_type}) — triggered ${a.trigger_count}x${a.webhook_url ? ' [webhook]' : ''}`);
|
|
384
|
+
return textResult(`Active alerts:\n${lines.join('\n')}`);
|
|
385
|
+
});
|
|
386
|
+
server.tool('trading_alert_delete', 'Delete a trading alert by ID.', {
|
|
387
|
+
id: z.number().describe('Alert ID to delete'),
|
|
388
|
+
}, async (params) => {
|
|
389
|
+
await call('alert.delete', { id: params.id });
|
|
390
|
+
return textResult(`Alert #${params.id} deleted.`);
|
|
391
|
+
});
|
|
392
|
+
server.tool('trading_alert_history', 'Get trigger history for an alert.', {
|
|
393
|
+
alert_id: z.number().describe('Alert ID'),
|
|
394
|
+
limit: z.number().optional().describe('Max results (default 50)'),
|
|
395
|
+
}, async (params) => {
|
|
396
|
+
const history = await call('alert.history', { alertId: params.alert_id, limit: params.limit });
|
|
397
|
+
if (!Array.isArray(history) || history.length === 0)
|
|
398
|
+
return textResult('No trigger history for this alert.');
|
|
399
|
+
const lines = history.map((h) => `[${h.created_at}] ${h.message}`);
|
|
400
|
+
return textResult(`Alert #${params.alert_id} history:\n${lines.join('\n')}`);
|
|
401
|
+
});
|
|
402
|
+
// === Import Tools ===
|
|
403
|
+
server.tool('trading_import', 'Import trades from a JSON array. Each trade needs: pair, botType, profitPct, win, signals (with rsi14/macd/trendScore/volatility).', {
|
|
404
|
+
trades_json: z.string().describe('JSON array of trade objects'),
|
|
405
|
+
}, async (params) => {
|
|
406
|
+
const result = await call('import.json', { json: params.trades_json });
|
|
407
|
+
const lines = [
|
|
408
|
+
`Import complete: ${result.imported} imported, ${result.failed} failed`,
|
|
409
|
+
];
|
|
410
|
+
if (result.errors.length > 0) {
|
|
411
|
+
lines.push('Errors:');
|
|
412
|
+
for (const e of result.errors.slice(0, 10)) {
|
|
413
|
+
lines.push(` - ${e}`);
|
|
414
|
+
}
|
|
415
|
+
if (result.errors.length > 10)
|
|
416
|
+
lines.push(` ... and ${result.errors.length - 10} more`);
|
|
417
|
+
}
|
|
418
|
+
return textResult(lines.join('\n'));
|
|
419
|
+
});
|
|
209
420
|
// 14. trading_learn
|
|
210
421
|
server.tool('trading_learn', 'Manually trigger a learning cycle (pattern extraction, calibration, decay).', {}, async () => {
|
|
211
422
|
const result = await call('learning.run', {});
|