@timmeck/trading-brain 2.6.0 → 2.7.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/ipc/router.d.ts +18 -0
- package/dist/ipc/router.js +104 -1
- package/dist/ipc/router.js.map +1 -1
- package/dist/mcp/advanced-research-tools.d.ts +7 -0
- package/dist/mcp/advanced-research-tools.js +895 -0
- package/dist/mcp/advanced-research-tools.js.map +1 -0
- package/dist/mcp/http-server.js +7 -1
- package/dist/mcp/http-server.js.map +1 -1
- package/dist/mcp/research-tools.d.ts +7 -0
- package/dist/mcp/research-tools.js +309 -0
- package/dist/mcp/research-tools.js.map +1 -0
- package/dist/mcp/server.js +8 -2
- package/dist/mcp/server.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,895 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
function textResult(data) {
|
|
3
|
+
const text = typeof data === 'string' ? data : JSON.stringify(data, null, 2);
|
|
4
|
+
return { content: [{ type: 'text', text }] };
|
|
5
|
+
}
|
|
6
|
+
/** Register advanced research tools using IPC client (for stdio MCP transport) */
|
|
7
|
+
export function registerAdvancedResearchTools(server, ipc) {
|
|
8
|
+
registerAdvancedResearchToolsWithCaller(server, (method, params) => ipc.request(method, params));
|
|
9
|
+
}
|
|
10
|
+
/** Register advanced research tools using router directly (for HTTP MCP transport inside daemon) */
|
|
11
|
+
export function registerAdvancedResearchToolsDirect(server, router) {
|
|
12
|
+
registerAdvancedResearchToolsWithCaller(server, (method, params) => router.handle(method, params));
|
|
13
|
+
}
|
|
14
|
+
function registerAdvancedResearchToolsWithCaller(server, call) {
|
|
15
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
16
|
+
// Self-Observer (3 tools)
|
|
17
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
18
|
+
server.tool('trading_self_observe', 'Get self-observation statistics for Trading Brain: decision quality scores, bias detection, confidence calibration, and behavioral metrics.', {}, async () => {
|
|
19
|
+
const stats = await call('observer.stats', {});
|
|
20
|
+
if (!stats)
|
|
21
|
+
return textResult('No self-observation data available yet.');
|
|
22
|
+
const lines = [
|
|
23
|
+
'Trading Self-Observation Stats:',
|
|
24
|
+
` Total observations: ${stats.totalObservations ?? 0}`,
|
|
25
|
+
` Decision quality score: ${stats.decisionQuality?.toFixed(2) ?? 'N/A'}`,
|
|
26
|
+
` Confidence calibration: ${stats.confidenceCalibration?.toFixed(2) ?? 'N/A'}`,
|
|
27
|
+
` Bias score: ${stats.biasScore?.toFixed(2) ?? 'N/A'}`,
|
|
28
|
+
];
|
|
29
|
+
if (stats.biases && Object.keys(stats.biases).length > 0) {
|
|
30
|
+
lines.push(' Detected biases:');
|
|
31
|
+
for (const [bias, severity] of Object.entries(stats.biases)) {
|
|
32
|
+
lines.push(` ${bias}: ${severity.toFixed(2)}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (stats.streaks) {
|
|
36
|
+
lines.push(` Current streak: ${stats.streaks.current ?? 'none'}`);
|
|
37
|
+
lines.push(` Best streak: ${stats.streaks.best ?? 0}`);
|
|
38
|
+
lines.push(` Worst streak: ${stats.streaks.worst ?? 0}`);
|
|
39
|
+
}
|
|
40
|
+
return textResult(lines.join('\n'));
|
|
41
|
+
});
|
|
42
|
+
server.tool('trading_self_insights', 'Get self-observer insights about Trading Brain behavior: patterns in decision-making, recurring mistakes, improvement opportunities.', {
|
|
43
|
+
type: z.string().optional().describe('Filter by insight type (e.g., "bias", "improvement", "pattern", "warning")'),
|
|
44
|
+
limit: z.number().optional().describe('Max results (default: 20)'),
|
|
45
|
+
}, async (params) => {
|
|
46
|
+
const insights = await call('observer.insights', {
|
|
47
|
+
type: params.type,
|
|
48
|
+
limit: params.limit ?? 20,
|
|
49
|
+
});
|
|
50
|
+
if (!insights?.length)
|
|
51
|
+
return textResult('No self-observer insights available yet. The brain needs more trading activity to generate insights.');
|
|
52
|
+
const lines = [`Trading Self-Observer Insights (${insights.length}):\n`];
|
|
53
|
+
for (const insight of insights) {
|
|
54
|
+
lines.push(`[${(insight.type ?? 'general').toUpperCase()}] ${insight.title ?? insight.description}`);
|
|
55
|
+
if (insight.description && insight.title)
|
|
56
|
+
lines.push(` ${insight.description}`);
|
|
57
|
+
if (insight.severity)
|
|
58
|
+
lines.push(` Severity: ${insight.severity}`);
|
|
59
|
+
if (insight.actionable)
|
|
60
|
+
lines.push(` Action: ${insight.actionable}`);
|
|
61
|
+
if (insight.created_at)
|
|
62
|
+
lines.push(` Detected: ${new Date(insight.created_at).toLocaleString()}`);
|
|
63
|
+
lines.push('');
|
|
64
|
+
}
|
|
65
|
+
return textResult(lines.join('\n'));
|
|
66
|
+
});
|
|
67
|
+
server.tool('trading_self_improvement_plan', 'Generate a self-improvement plan for Trading Brain based on observed weaknesses, biases, and performance gaps.', {}, async () => {
|
|
68
|
+
const plan = await call('observer.plan', {});
|
|
69
|
+
if (!plan)
|
|
70
|
+
return textResult('No improvement plan available. Need more self-observation data.');
|
|
71
|
+
const lines = [
|
|
72
|
+
'Trading Brain Self-Improvement Plan:',
|
|
73
|
+
` Overall health: ${plan.overallHealth ?? 'unknown'}`,
|
|
74
|
+
` Priority areas: ${plan.priorityAreas?.length ?? 0}`,
|
|
75
|
+
];
|
|
76
|
+
if (plan.priorityAreas?.length > 0) {
|
|
77
|
+
lines.push('\n Priority Areas:');
|
|
78
|
+
for (const area of plan.priorityAreas) {
|
|
79
|
+
lines.push(` ${area.name}: ${area.description ?? ''}`);
|
|
80
|
+
if (area.currentScore !== undefined)
|
|
81
|
+
lines.push(` Current: ${area.currentScore.toFixed(2)} | Target: ${area.targetScore?.toFixed(2) ?? 'N/A'}`);
|
|
82
|
+
if (area.actions?.length > 0) {
|
|
83
|
+
for (const action of area.actions) {
|
|
84
|
+
lines.push(` - ${action}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (plan.timeline) {
|
|
90
|
+
lines.push(`\n Estimated improvement timeline: ${plan.timeline}`);
|
|
91
|
+
}
|
|
92
|
+
return textResult(lines.join('\n'));
|
|
93
|
+
});
|
|
94
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
95
|
+
// Adaptive Strategy (3 tools)
|
|
96
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
97
|
+
server.tool('trading_strategy_status', 'Get current adaptive strategy status for Trading Brain: active strategies, adaptation state, regime detection, and performance under current conditions.', {}, async () => {
|
|
98
|
+
const status = await call('strategy.status', {});
|
|
99
|
+
if (!status)
|
|
100
|
+
return textResult('No adaptive strategy data available.');
|
|
101
|
+
const lines = [
|
|
102
|
+
'Trading Adaptive Strategy Status:',
|
|
103
|
+
` Active strategy: ${status.activeStrategy ?? 'default'}`,
|
|
104
|
+
` Current regime: ${status.currentRegime ?? 'unknown'}`,
|
|
105
|
+
` Adaptation count: ${status.adaptationCount ?? 0}`,
|
|
106
|
+
` Strategy confidence: ${status.confidence?.toFixed(2) ?? 'N/A'}`,
|
|
107
|
+
];
|
|
108
|
+
if (status.performance) {
|
|
109
|
+
lines.push(' Current performance:');
|
|
110
|
+
lines.push(` Win rate: ${(status.performance.winRate * 100).toFixed(1)}%`);
|
|
111
|
+
lines.push(` Avg profit: ${status.performance.avgProfit?.toFixed(2) ?? 'N/A'}%`);
|
|
112
|
+
lines.push(` Sharpe: ${status.performance.sharpe?.toFixed(2) ?? 'N/A'}`);
|
|
113
|
+
}
|
|
114
|
+
if (status.regimeHistory?.length > 0) {
|
|
115
|
+
lines.push(' Recent regime changes:');
|
|
116
|
+
for (const r of status.regimeHistory.slice(0, 5)) {
|
|
117
|
+
lines.push(` ${r.from} → ${r.to} (${new Date(r.timestamp).toLocaleString()})`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return textResult(lines.join('\n'));
|
|
121
|
+
});
|
|
122
|
+
server.tool('trading_strategy_adaptations', 'List past strategy adaptations: parameter changes, regime switches, rule modifications made by the adaptive strategy engine.', {
|
|
123
|
+
strategy: z.string().optional().describe('Filter by strategy name'),
|
|
124
|
+
limit: z.number().optional().describe('Max results (default: 20)'),
|
|
125
|
+
}, async (params) => {
|
|
126
|
+
const adaptations = await call('strategy.adaptations', {
|
|
127
|
+
strategy: params.strategy,
|
|
128
|
+
limit: params.limit ?? 20,
|
|
129
|
+
});
|
|
130
|
+
if (!adaptations?.length)
|
|
131
|
+
return textResult('No strategy adaptations recorded yet.');
|
|
132
|
+
const lines = [`Trading Strategy Adaptations (${adaptations.length}):\n`];
|
|
133
|
+
for (const a of adaptations) {
|
|
134
|
+
lines.push(`#${a.id} [${a.type ?? 'adaptation'}] ${a.description ?? a.summary ?? 'Strategy adapted'}`);
|
|
135
|
+
if (a.strategy)
|
|
136
|
+
lines.push(` Strategy: ${a.strategy}`);
|
|
137
|
+
if (a.trigger)
|
|
138
|
+
lines.push(` Trigger: ${a.trigger}`);
|
|
139
|
+
if (a.changes && Object.keys(a.changes).length > 0) {
|
|
140
|
+
lines.push(' Changes:');
|
|
141
|
+
for (const [param, change] of Object.entries(a.changes)) {
|
|
142
|
+
lines.push(` ${param}: ${change.from ?? '?'} → ${change.to ?? '?'}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (a.created_at)
|
|
146
|
+
lines.push(` When: ${new Date(a.created_at).toLocaleString()}`);
|
|
147
|
+
lines.push('');
|
|
148
|
+
}
|
|
149
|
+
return textResult(lines.join('\n'));
|
|
150
|
+
});
|
|
151
|
+
server.tool('trading_strategy_revert', 'Revert a specific strategy adaptation. Undoes a parameter change or rule modification if it degraded trading performance.', {
|
|
152
|
+
id: z.number().describe('Adaptation ID to revert'),
|
|
153
|
+
reason: z.string().optional().describe('Reason for reverting'),
|
|
154
|
+
}, async (params) => {
|
|
155
|
+
const result = await call('strategy.revert', {
|
|
156
|
+
id: params.id,
|
|
157
|
+
reason: params.reason,
|
|
158
|
+
});
|
|
159
|
+
if (!result)
|
|
160
|
+
return textResult(`Adaptation #${params.id} not found or already reverted.`);
|
|
161
|
+
const lines = [
|
|
162
|
+
`Strategy Adaptation #${params.id} Reverted:`,
|
|
163
|
+
` Status: ${result.status ?? 'reverted'}`,
|
|
164
|
+
];
|
|
165
|
+
if (result.revertedChanges && Object.keys(result.revertedChanges).length > 0) {
|
|
166
|
+
lines.push(' Reverted changes:');
|
|
167
|
+
for (const [param, val] of Object.entries(result.revertedChanges)) {
|
|
168
|
+
lines.push(` ${param}: restored to ${val}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (params.reason)
|
|
172
|
+
lines.push(` Reason: ${params.reason}`);
|
|
173
|
+
return textResult(lines.join('\n'));
|
|
174
|
+
});
|
|
175
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
176
|
+
// Experiment Engine (5 tools)
|
|
177
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
178
|
+
server.tool('trading_experiment_list', 'List trading experiments: A/B tests on signal parameters, strategy variants, risk settings. Shows active, completed, and proposed experiments.', {
|
|
179
|
+
status: z.enum(['proposed', 'running', 'completed', 'aborted']).optional().describe('Filter by experiment status'),
|
|
180
|
+
limit: z.number().optional().describe('Max results (default: 20)'),
|
|
181
|
+
}, async (params) => {
|
|
182
|
+
const experiments = await call('experiment.list', {
|
|
183
|
+
status: params.status,
|
|
184
|
+
limit: params.limit ?? 20,
|
|
185
|
+
});
|
|
186
|
+
if (!experiments?.length)
|
|
187
|
+
return textResult('No trading experiments found.');
|
|
188
|
+
const lines = [`Trading Experiments (${experiments.length}):\n`];
|
|
189
|
+
for (const e of experiments) {
|
|
190
|
+
lines.push(`#${e.id} [${(e.status ?? 'unknown').toUpperCase()}] ${e.name}`);
|
|
191
|
+
if (e.hypothesis)
|
|
192
|
+
lines.push(` Hypothesis: ${e.hypothesis}`);
|
|
193
|
+
lines.push(` Variable: ${e.independent_variable ?? e.independentVariable ?? 'N/A'}`);
|
|
194
|
+
lines.push(` Control: ${e.control_value ?? e.controlValue ?? 'N/A'} | Treatment: ${e.treatment_value ?? e.treatmentValue ?? 'N/A'}`);
|
|
195
|
+
if (e.cycles_completed !== undefined || e.cyclesCompleted !== undefined) {
|
|
196
|
+
lines.push(` Progress: ${e.cycles_completed ?? e.cyclesCompleted ?? 0}/${e.duration_cycles ?? e.durationCycles ?? '?'} cycles`);
|
|
197
|
+
}
|
|
198
|
+
lines.push('');
|
|
199
|
+
}
|
|
200
|
+
return textResult(lines.join('\n'));
|
|
201
|
+
});
|
|
202
|
+
server.tool('trading_experiment_propose', 'Propose a new trading experiment: define a hypothesis, independent/dependent variables, control and treatment values to A/B test.', {
|
|
203
|
+
name: z.string().describe('Experiment name (e.g., "RSI threshold optimization")'),
|
|
204
|
+
hypothesis: z.string().describe('What you expect to happen (e.g., "Lower RSI threshold increases win rate")'),
|
|
205
|
+
independent_variable: z.string().describe('The variable being changed (e.g., "rsi_threshold")'),
|
|
206
|
+
dependent_variable: z.string().describe('The measured outcome (e.g., "win_rate")'),
|
|
207
|
+
control_value: z.string().describe('Control group value (e.g., "30")'),
|
|
208
|
+
treatment_value: z.string().describe('Treatment group value (e.g., "25")'),
|
|
209
|
+
duration_cycles: z.number().optional().describe('Number of cycles to run (default: engine decides)'),
|
|
210
|
+
}, async (params) => {
|
|
211
|
+
const result = await call('experiment.propose', {
|
|
212
|
+
name: params.name,
|
|
213
|
+
hypothesis: params.hypothesis,
|
|
214
|
+
independentVariable: params.independent_variable,
|
|
215
|
+
dependentVariable: params.dependent_variable,
|
|
216
|
+
controlValue: params.control_value,
|
|
217
|
+
treatmentValue: params.treatment_value,
|
|
218
|
+
durationCycles: params.duration_cycles,
|
|
219
|
+
});
|
|
220
|
+
if (!result)
|
|
221
|
+
return textResult('Failed to propose experiment.');
|
|
222
|
+
return textResult(`Trading experiment #${result.id} proposed: "${params.name}"\n Hypothesis: ${params.hypothesis}\n Testing: ${params.independent_variable} = ${params.control_value} vs ${params.treatment_value}\n Measuring: ${params.dependent_variable}\n Status: ${result.status ?? 'proposed'}`);
|
|
223
|
+
});
|
|
224
|
+
server.tool('trading_experiment_status', 'Get detailed status and progress of a specific trading experiment including interim results.', {
|
|
225
|
+
id: z.number().describe('Experiment ID'),
|
|
226
|
+
}, async (params) => {
|
|
227
|
+
const exp = await call('experiment.get', { id: params.id });
|
|
228
|
+
if (!exp)
|
|
229
|
+
return textResult(`Trading experiment #${params.id} not found.`);
|
|
230
|
+
const lines = [
|
|
231
|
+
`Trading Experiment #${exp.id}: ${exp.name}`,
|
|
232
|
+
` Status: ${(exp.status ?? 'unknown').toUpperCase()}`,
|
|
233
|
+
` Hypothesis: ${exp.hypothesis ?? 'N/A'}`,
|
|
234
|
+
` Variable: ${exp.independent_variable ?? exp.independentVariable ?? 'N/A'}`,
|
|
235
|
+
` Control: ${exp.control_value ?? exp.controlValue ?? 'N/A'}`,
|
|
236
|
+
` Treatment: ${exp.treatment_value ?? exp.treatmentValue ?? 'N/A'}`,
|
|
237
|
+
` Measuring: ${exp.dependent_variable ?? exp.dependentVariable ?? 'N/A'}`,
|
|
238
|
+
];
|
|
239
|
+
if (exp.cycles_completed !== undefined || exp.cyclesCompleted !== undefined) {
|
|
240
|
+
lines.push(` Progress: ${exp.cycles_completed ?? exp.cyclesCompleted ?? 0}/${exp.duration_cycles ?? exp.durationCycles ?? '?'} cycles`);
|
|
241
|
+
}
|
|
242
|
+
if (exp.controlResult !== undefined || exp.control_result !== undefined) {
|
|
243
|
+
lines.push(` Control result: ${exp.controlResult ?? exp.control_result}`);
|
|
244
|
+
lines.push(` Treatment result: ${exp.treatmentResult ?? exp.treatment_result}`);
|
|
245
|
+
}
|
|
246
|
+
if (exp.pValue !== undefined || exp.p_value !== undefined) {
|
|
247
|
+
lines.push(` P-value: ${(exp.pValue ?? exp.p_value)?.toFixed(4) ?? 'N/A'}`);
|
|
248
|
+
lines.push(` Significant: ${exp.significant ? 'YES' : 'NO'}`);
|
|
249
|
+
}
|
|
250
|
+
if (exp.conclusion)
|
|
251
|
+
lines.push(` Conclusion: ${exp.conclusion}`);
|
|
252
|
+
if (exp.created_at)
|
|
253
|
+
lines.push(` Created: ${new Date(exp.created_at).toLocaleString()}`);
|
|
254
|
+
return textResult(lines.join('\n'));
|
|
255
|
+
});
|
|
256
|
+
server.tool('trading_experiment_results', 'Get results of completed trading experiments: which variant won, statistical significance, and recommendations.', {
|
|
257
|
+
limit: z.number().optional().describe('Max results (default: 10)'),
|
|
258
|
+
}, async (params) => {
|
|
259
|
+
const results = await call('experiment.results', {
|
|
260
|
+
limit: params.limit ?? 10,
|
|
261
|
+
});
|
|
262
|
+
if (!results?.length)
|
|
263
|
+
return textResult('No completed trading experiment results yet.');
|
|
264
|
+
const lines = [`Trading Experiment Results (${results.length}):\n`];
|
|
265
|
+
for (const r of results) {
|
|
266
|
+
lines.push(`#${r.id} ${r.name}`);
|
|
267
|
+
lines.push(` Winner: ${r.winner ?? 'inconclusive'}`);
|
|
268
|
+
if (r.controlResult !== undefined || r.control_result !== undefined) {
|
|
269
|
+
lines.push(` Control: ${r.controlResult ?? r.control_result} | Treatment: ${r.treatmentResult ?? r.treatment_result}`);
|
|
270
|
+
}
|
|
271
|
+
if (r.pValue !== undefined || r.p_value !== undefined) {
|
|
272
|
+
lines.push(` P-value: ${(r.pValue ?? r.p_value)?.toFixed(4)} | Significant: ${r.significant ? 'YES' : 'NO'}`);
|
|
273
|
+
}
|
|
274
|
+
if (r.recommendation)
|
|
275
|
+
lines.push(` Recommendation: ${r.recommendation}`);
|
|
276
|
+
lines.push('');
|
|
277
|
+
}
|
|
278
|
+
return textResult(lines.join('\n'));
|
|
279
|
+
});
|
|
280
|
+
server.tool('trading_experiment_abort', 'Abort a running trading experiment. Use when an experiment is clearly harmful or no longer relevant.', {
|
|
281
|
+
id: z.number().describe('Experiment ID to abort'),
|
|
282
|
+
}, async (params) => {
|
|
283
|
+
const result = await call('experiment.abort', { id: params.id });
|
|
284
|
+
if (!result)
|
|
285
|
+
return textResult(`Trading experiment #${params.id} not found or not running.`);
|
|
286
|
+
return textResult(`Trading experiment #${params.id} aborted.\n Name: ${result.name ?? 'N/A'}\n Cycles completed: ${result.cycles_completed ?? result.cyclesCompleted ?? 0}\n Status: ${result.status ?? 'aborted'}`);
|
|
287
|
+
});
|
|
288
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
289
|
+
// Cross-Domain (3 tools)
|
|
290
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
291
|
+
server.tool('trading_cross_domain_correlations', 'Find cross-domain correlations between trading and other brain domains (errors, marketing activity). Reveals hidden connections.', {
|
|
292
|
+
limit: z.number().optional().describe('Max correlations to return (default: 20)'),
|
|
293
|
+
}, async (params) => {
|
|
294
|
+
const correlations = await call('crossdomain.correlations', {
|
|
295
|
+
limit: params.limit ?? 20,
|
|
296
|
+
});
|
|
297
|
+
if (!correlations?.length)
|
|
298
|
+
return textResult('No cross-domain correlations found. Need activity across multiple brain domains.');
|
|
299
|
+
const lines = [`Cross-Domain Correlations (${correlations.length}):\n`];
|
|
300
|
+
for (const c of correlations) {
|
|
301
|
+
const strength = typeof c.strength === 'number' ? ` (strength: ${(c.strength * 100).toFixed(0)}%)` : '';
|
|
302
|
+
const confidence = typeof c.confidence === 'number' ? ` confidence: ${(c.confidence * 100).toFixed(0)}%` : '';
|
|
303
|
+
lines.push(`${c.domain_a ?? c.domainA} <-> ${c.domain_b ?? c.domainB}${strength}${confidence}`);
|
|
304
|
+
if (c.description)
|
|
305
|
+
lines.push(` ${c.description}`);
|
|
306
|
+
if (c.pattern)
|
|
307
|
+
lines.push(` Pattern: ${c.pattern}`);
|
|
308
|
+
lines.push('');
|
|
309
|
+
}
|
|
310
|
+
return textResult(lines.join('\n'));
|
|
311
|
+
});
|
|
312
|
+
server.tool('trading_cross_domain_analyze', 'Run a cross-domain analysis: detect how trading performance correlates with error patterns, deployment events, and marketing activity.', {}, async () => {
|
|
313
|
+
const analysis = await call('crossdomain.analyze', {});
|
|
314
|
+
if (!analysis)
|
|
315
|
+
return textResult('Cross-domain analysis produced no results. Need more data across domains.');
|
|
316
|
+
const lines = ['Cross-Domain Analysis for Trading:\n'];
|
|
317
|
+
if (analysis.correlationsFound !== undefined) {
|
|
318
|
+
lines.push(` Correlations found: ${analysis.correlationsFound}`);
|
|
319
|
+
}
|
|
320
|
+
if (analysis.insights?.length > 0) {
|
|
321
|
+
lines.push(' Insights:');
|
|
322
|
+
for (const insight of analysis.insights) {
|
|
323
|
+
lines.push(` - ${insight.description ?? insight}`);
|
|
324
|
+
if (insight.impact)
|
|
325
|
+
lines.push(` Impact: ${insight.impact}`);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
if (analysis.domains?.length > 0) {
|
|
329
|
+
lines.push(` Domains analyzed: ${analysis.domains.join(', ')}`);
|
|
330
|
+
}
|
|
331
|
+
if (analysis.recommendations?.length > 0) {
|
|
332
|
+
lines.push('\n Recommendations:');
|
|
333
|
+
for (const rec of analysis.recommendations) {
|
|
334
|
+
lines.push(` - ${rec}`);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return textResult(lines.join('\n'));
|
|
338
|
+
});
|
|
339
|
+
server.tool('trading_cross_domain_narrative', 'Generate a narrative summary of cross-domain interactions: how trading, errors, and marketing events are connected over time.', {}, async () => {
|
|
340
|
+
const narrative = await call('crossdomain.narrative', {});
|
|
341
|
+
if (!narrative)
|
|
342
|
+
return textResult('No cross-domain narrative available. Need activity across multiple brain domains.');
|
|
343
|
+
if (typeof narrative === 'string')
|
|
344
|
+
return textResult(narrative);
|
|
345
|
+
const lines = ['Cross-Domain Narrative:\n'];
|
|
346
|
+
if (narrative.title)
|
|
347
|
+
lines.push(` ${narrative.title}\n`);
|
|
348
|
+
if (narrative.summary)
|
|
349
|
+
lines.push(` ${narrative.summary}\n`);
|
|
350
|
+
if (narrative.chapters?.length > 0) {
|
|
351
|
+
for (const chapter of narrative.chapters) {
|
|
352
|
+
lines.push(` --- ${chapter.title ?? 'Chapter'} ---`);
|
|
353
|
+
lines.push(` ${chapter.content ?? chapter.description ?? ''}`);
|
|
354
|
+
lines.push('');
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
if (narrative.conclusion)
|
|
358
|
+
lines.push(` Conclusion: ${narrative.conclusion}`);
|
|
359
|
+
return textResult(lines.join('\n'));
|
|
360
|
+
});
|
|
361
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
362
|
+
// Counterfactual (3 tools)
|
|
363
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
364
|
+
server.tool('trading_what_if', 'Run a what-if counterfactual analysis on trading decisions: "What if I had used a different stop-loss?" or "What if I entered earlier?".', {}, async () => {
|
|
365
|
+
const scenarios = await call('counterfactual.whatif', {});
|
|
366
|
+
if (!scenarios)
|
|
367
|
+
return textResult('No what-if scenarios available. Need completed trades for counterfactual analysis.');
|
|
368
|
+
if (Array.isArray(scenarios)) {
|
|
369
|
+
if (!scenarios.length)
|
|
370
|
+
return textResult('No what-if scenarios generated.');
|
|
371
|
+
const lines = [`What-If Scenarios (${scenarios.length}):\n`];
|
|
372
|
+
for (const s of scenarios) {
|
|
373
|
+
lines.push(`[${s.type ?? 'scenario'}] ${s.description ?? s.title ?? 'Scenario'}`);
|
|
374
|
+
if (s.actualOutcome !== undefined)
|
|
375
|
+
lines.push(` Actual outcome: ${s.actualOutcome}`);
|
|
376
|
+
if (s.counterfactualOutcome !== undefined)
|
|
377
|
+
lines.push(` Counterfactual outcome: ${s.counterfactualOutcome}`);
|
|
378
|
+
if (s.difference !== undefined)
|
|
379
|
+
lines.push(` Difference: ${s.difference}`);
|
|
380
|
+
if (s.insight)
|
|
381
|
+
lines.push(` Insight: ${s.insight}`);
|
|
382
|
+
lines.push('');
|
|
383
|
+
}
|
|
384
|
+
return textResult(lines.join('\n'));
|
|
385
|
+
}
|
|
386
|
+
const lines = ['What-If Analysis:\n'];
|
|
387
|
+
if (scenarios.totalScenarios !== undefined)
|
|
388
|
+
lines.push(` Total scenarios: ${scenarios.totalScenarios}`);
|
|
389
|
+
if (scenarios.bestAlternative)
|
|
390
|
+
lines.push(` Best alternative: ${scenarios.bestAlternative}`);
|
|
391
|
+
if (scenarios.potentialImprovement)
|
|
392
|
+
lines.push(` Potential improvement: ${scenarios.potentialImprovement}`);
|
|
393
|
+
if (scenarios.summary)
|
|
394
|
+
lines.push(`\n ${scenarios.summary}`);
|
|
395
|
+
return textResult(lines.join('\n'));
|
|
396
|
+
});
|
|
397
|
+
server.tool('trading_counterfactual_history', 'View history of counterfactual analyses: past what-if explorations and their conclusions about alternative trading decisions.', {}, async () => {
|
|
398
|
+
const history = await call('counterfactual.history', {});
|
|
399
|
+
if (!history?.length)
|
|
400
|
+
return textResult('No counterfactual analysis history. Run what-if analyses first.');
|
|
401
|
+
const lines = [`Counterfactual History (${history.length}):\n`];
|
|
402
|
+
for (const h of history) {
|
|
403
|
+
lines.push(`#${h.id ?? ''} ${h.description ?? h.title ?? 'Analysis'}`);
|
|
404
|
+
if (h.scenario)
|
|
405
|
+
lines.push(` Scenario: ${h.scenario}`);
|
|
406
|
+
if (h.actualOutcome !== undefined)
|
|
407
|
+
lines.push(` Actual: ${h.actualOutcome}`);
|
|
408
|
+
if (h.counterfactualOutcome !== undefined)
|
|
409
|
+
lines.push(` Alternative: ${h.counterfactualOutcome}`);
|
|
410
|
+
if (h.lesson)
|
|
411
|
+
lines.push(` Lesson: ${h.lesson}`);
|
|
412
|
+
if (h.created_at)
|
|
413
|
+
lines.push(` Date: ${new Date(h.created_at).toLocaleString()}`);
|
|
414
|
+
lines.push('');
|
|
415
|
+
}
|
|
416
|
+
return textResult(lines.join('\n'));
|
|
417
|
+
});
|
|
418
|
+
server.tool('trading_intervention_impact', 'Analyze the impact of past trading interventions: parameter changes, strategy switches, rule additions. Did they actually help?', {}, async () => {
|
|
419
|
+
const impact = await call('counterfactual.impact', {});
|
|
420
|
+
if (!impact)
|
|
421
|
+
return textResult('No intervention impact data available.');
|
|
422
|
+
if (Array.isArray(impact)) {
|
|
423
|
+
if (!impact.length)
|
|
424
|
+
return textResult('No interventions recorded yet.');
|
|
425
|
+
const lines = [`Intervention Impact Analysis (${impact.length}):\n`];
|
|
426
|
+
for (const i of impact) {
|
|
427
|
+
lines.push(`${i.intervention ?? i.name ?? 'Intervention'}`);
|
|
428
|
+
if (i.beforePerformance !== undefined)
|
|
429
|
+
lines.push(` Before: ${i.beforePerformance}`);
|
|
430
|
+
if (i.afterPerformance !== undefined)
|
|
431
|
+
lines.push(` After: ${i.afterPerformance}`);
|
|
432
|
+
if (i.impact !== undefined)
|
|
433
|
+
lines.push(` Impact: ${i.impact}`);
|
|
434
|
+
if (i.significant !== undefined)
|
|
435
|
+
lines.push(` Significant: ${i.significant ? 'YES' : 'NO'}`);
|
|
436
|
+
if (i.verdict)
|
|
437
|
+
lines.push(` Verdict: ${i.verdict}`);
|
|
438
|
+
lines.push('');
|
|
439
|
+
}
|
|
440
|
+
return textResult(lines.join('\n'));
|
|
441
|
+
}
|
|
442
|
+
const lines = ['Intervention Impact Summary:\n'];
|
|
443
|
+
if (impact.totalInterventions !== undefined)
|
|
444
|
+
lines.push(` Total interventions: ${impact.totalInterventions}`);
|
|
445
|
+
if (impact.positiveImpact !== undefined)
|
|
446
|
+
lines.push(` Positive impact: ${impact.positiveImpact}`);
|
|
447
|
+
if (impact.negativeImpact !== undefined)
|
|
448
|
+
lines.push(` Negative impact: ${impact.negativeImpact}`);
|
|
449
|
+
if (impact.neutral !== undefined)
|
|
450
|
+
lines.push(` Neutral: ${impact.neutral}`);
|
|
451
|
+
if (impact.summary)
|
|
452
|
+
lines.push(`\n ${impact.summary}`);
|
|
453
|
+
return textResult(lines.join('\n'));
|
|
454
|
+
});
|
|
455
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
456
|
+
// Knowledge Distillation (5 tools)
|
|
457
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
458
|
+
server.tool('trading_knowledge_summary', 'Get a distilled knowledge summary of everything Trading Brain has learned: key patterns, reliable signals, market regime behavior.', {}, async () => {
|
|
459
|
+
const summary = await call('knowledge.summary', {});
|
|
460
|
+
if (!summary)
|
|
461
|
+
return textResult('No distilled knowledge available yet. The brain needs more trading experience.');
|
|
462
|
+
if (typeof summary === 'string')
|
|
463
|
+
return textResult(summary);
|
|
464
|
+
const lines = ['Trading Knowledge Summary:\n'];
|
|
465
|
+
if (summary.totalPatterns !== undefined)
|
|
466
|
+
lines.push(` Patterns learned: ${summary.totalPatterns}`);
|
|
467
|
+
if (summary.totalPrinciples !== undefined)
|
|
468
|
+
lines.push(` Principles extracted: ${summary.totalPrinciples}`);
|
|
469
|
+
if (summary.totalAntiPatterns !== undefined)
|
|
470
|
+
lines.push(` Anti-patterns identified: ${summary.totalAntiPatterns}`);
|
|
471
|
+
if (summary.confidenceLevel !== undefined)
|
|
472
|
+
lines.push(` Overall confidence: ${(summary.confidenceLevel * 100).toFixed(0)}%`);
|
|
473
|
+
if (summary.topInsights?.length > 0) {
|
|
474
|
+
lines.push('\n Top Insights:');
|
|
475
|
+
for (const insight of summary.topInsights) {
|
|
476
|
+
lines.push(` - ${insight.description ?? insight}`);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
if (summary.maturityLevel)
|
|
480
|
+
lines.push(`\n Knowledge maturity: ${summary.maturityLevel}`);
|
|
481
|
+
return textResult(lines.join('\n'));
|
|
482
|
+
});
|
|
483
|
+
server.tool('trading_knowledge_principles', 'Get distilled trading principles: high-confidence rules extracted from patterns, e.g., "Never trade against strong RSI divergence".', {}, async () => {
|
|
484
|
+
const principles = await call('knowledge.principles', {});
|
|
485
|
+
if (!principles?.length)
|
|
486
|
+
return textResult('No trading principles distilled yet. Need more confirmed patterns.');
|
|
487
|
+
const lines = [`Trading Principles (${principles.length}):\n`];
|
|
488
|
+
for (let i = 0; i < principles.length; i++) {
|
|
489
|
+
const p = principles[i];
|
|
490
|
+
lines.push(`${i + 1}. ${p.statement ?? p.description ?? p}`);
|
|
491
|
+
if (p.confidence !== undefined)
|
|
492
|
+
lines.push(` Confidence: ${(p.confidence * 100).toFixed(0)}%`);
|
|
493
|
+
if (p.evidence)
|
|
494
|
+
lines.push(` Evidence: ${p.evidence}`);
|
|
495
|
+
if (p.source)
|
|
496
|
+
lines.push(` Source: ${p.source}`);
|
|
497
|
+
lines.push('');
|
|
498
|
+
}
|
|
499
|
+
return textResult(lines.join('\n'));
|
|
500
|
+
});
|
|
501
|
+
server.tool('trading_knowledge_anti_patterns', 'Get identified trading anti-patterns: things that consistently lead to losses or poor outcomes. Learn from past mistakes.', {}, async () => {
|
|
502
|
+
const antiPatterns = await call('knowledge.antipatterns', {});
|
|
503
|
+
if (!antiPatterns?.length)
|
|
504
|
+
return textResult('No anti-patterns identified yet. Need more trade data to detect recurring mistakes.');
|
|
505
|
+
const lines = [`Trading Anti-Patterns (${antiPatterns.length}):\n`];
|
|
506
|
+
for (let i = 0; i < antiPatterns.length; i++) {
|
|
507
|
+
const ap = antiPatterns[i];
|
|
508
|
+
lines.push(`${i + 1}. ${ap.name ?? ap.description ?? ap}`);
|
|
509
|
+
if (ap.description && ap.name)
|
|
510
|
+
lines.push(` ${ap.description}`);
|
|
511
|
+
if (ap.occurrences !== undefined)
|
|
512
|
+
lines.push(` Occurrences: ${ap.occurrences}`);
|
|
513
|
+
if (ap.avgLoss !== undefined)
|
|
514
|
+
lines.push(` Avg loss when triggered: ${ap.avgLoss.toFixed(2)}%`);
|
|
515
|
+
if (ap.avoidance)
|
|
516
|
+
lines.push(` How to avoid: ${ap.avoidance}`);
|
|
517
|
+
lines.push('');
|
|
518
|
+
}
|
|
519
|
+
return textResult(lines.join('\n'));
|
|
520
|
+
});
|
|
521
|
+
server.tool('trading_knowledge_package', 'Package all distilled trading knowledge into a transferable format: principles, anti-patterns, parameters, and learned rules.', {}, async () => {
|
|
522
|
+
const pkg = await call('knowledge.package', {});
|
|
523
|
+
if (!pkg)
|
|
524
|
+
return textResult('No knowledge available to package.');
|
|
525
|
+
if (typeof pkg === 'string')
|
|
526
|
+
return textResult(pkg);
|
|
527
|
+
const lines = ['Trading Knowledge Package:\n'];
|
|
528
|
+
if (pkg.version)
|
|
529
|
+
lines.push(` Version: ${pkg.version}`);
|
|
530
|
+
if (pkg.created_at)
|
|
531
|
+
lines.push(` Created: ${new Date(pkg.created_at).toLocaleString()}`);
|
|
532
|
+
if (pkg.principles?.length > 0) {
|
|
533
|
+
lines.push(`\n Principles (${pkg.principles.length}):`);
|
|
534
|
+
for (const p of pkg.principles) {
|
|
535
|
+
lines.push(` - ${p.statement ?? p}`);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
if (pkg.antiPatterns?.length > 0) {
|
|
539
|
+
lines.push(`\n Anti-Patterns (${pkg.antiPatterns.length}):`);
|
|
540
|
+
for (const ap of pkg.antiPatterns) {
|
|
541
|
+
lines.push(` - ${ap.name ?? ap}`);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
if (pkg.parameters && Object.keys(pkg.parameters).length > 0) {
|
|
545
|
+
lines.push('\n Optimized Parameters:');
|
|
546
|
+
for (const [name, value] of Object.entries(pkg.parameters)) {
|
|
547
|
+
lines.push(` ${name}: ${value}`);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
if (pkg.rules?.length > 0) {
|
|
551
|
+
lines.push(`\n Learned Rules (${pkg.rules.length}):`);
|
|
552
|
+
for (const r of pkg.rules) {
|
|
553
|
+
lines.push(` - ${r.description ?? r}`);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
return textResult(lines.join('\n'));
|
|
557
|
+
});
|
|
558
|
+
server.tool('trading_knowledge_evolution', 'View how Trading Brain knowledge has evolved over time: when key insights were discovered, confidence changes, paradigm shifts.', {}, async () => {
|
|
559
|
+
const evolution = await call('knowledge.evolution', {});
|
|
560
|
+
if (!evolution)
|
|
561
|
+
return textResult('No knowledge evolution data available.');
|
|
562
|
+
if (Array.isArray(evolution)) {
|
|
563
|
+
if (!evolution.length)
|
|
564
|
+
return textResult('No knowledge evolution events recorded.');
|
|
565
|
+
const lines = [`Knowledge Evolution (${evolution.length} events):\n`];
|
|
566
|
+
for (const e of evolution) {
|
|
567
|
+
const date = e.timestamp ? new Date(e.timestamp).toLocaleString() : 'unknown date';
|
|
568
|
+
lines.push(`[${date}] ${e.type ?? 'event'}: ${e.description ?? e.title ?? ''}`);
|
|
569
|
+
if (e.impact)
|
|
570
|
+
lines.push(` Impact: ${e.impact}`);
|
|
571
|
+
lines.push('');
|
|
572
|
+
}
|
|
573
|
+
return textResult(lines.join('\n'));
|
|
574
|
+
}
|
|
575
|
+
const lines = ['Knowledge Evolution:\n'];
|
|
576
|
+
if (evolution.phases?.length > 0) {
|
|
577
|
+
for (const phase of evolution.phases) {
|
|
578
|
+
lines.push(` Phase: ${phase.name}`);
|
|
579
|
+
if (phase.duration)
|
|
580
|
+
lines.push(` Duration: ${phase.duration}`);
|
|
581
|
+
if (phase.keyInsights?.length > 0) {
|
|
582
|
+
for (const insight of phase.keyInsights) {
|
|
583
|
+
lines.push(` - ${insight}`);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
lines.push('');
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
if (evolution.currentPhase)
|
|
590
|
+
lines.push(` Current phase: ${evolution.currentPhase}`);
|
|
591
|
+
if (evolution.maturity)
|
|
592
|
+
lines.push(` Maturity: ${evolution.maturity}`);
|
|
593
|
+
return textResult(lines.join('\n'));
|
|
594
|
+
});
|
|
595
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
596
|
+
// Research Agenda (4 tools)
|
|
597
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
598
|
+
server.tool('trading_research_agenda', 'View the current trading research agenda: prioritized list of open questions, investigation topics, and research directions.', {}, async () => {
|
|
599
|
+
const agenda = await call('agenda.list', {});
|
|
600
|
+
if (!agenda?.length)
|
|
601
|
+
return textResult('No research agenda items. The brain will generate topics as it learns.');
|
|
602
|
+
const lines = [`Trading Research Agenda (${agenda.length} items):\n`];
|
|
603
|
+
for (const item of agenda) {
|
|
604
|
+
const priority = item.priority !== undefined ? ` [P${item.priority}]` : '';
|
|
605
|
+
const status = item.status ? ` (${item.status})` : '';
|
|
606
|
+
lines.push(`#${item.id ?? ''}${priority} ${item.question ?? item.title ?? item.topic ?? 'Research topic'}${status}`);
|
|
607
|
+
if (item.description)
|
|
608
|
+
lines.push(` ${item.description}`);
|
|
609
|
+
if (item.expectedValue)
|
|
610
|
+
lines.push(` Expected value: ${item.expectedValue}`);
|
|
611
|
+
if (item.estimatedEffort)
|
|
612
|
+
lines.push(` Estimated effort: ${item.estimatedEffort}`);
|
|
613
|
+
lines.push('');
|
|
614
|
+
}
|
|
615
|
+
return textResult(lines.join('\n'));
|
|
616
|
+
});
|
|
617
|
+
server.tool('trading_research_next', 'Get the next highest-priority research question for Trading Brain to investigate.', {}, async () => {
|
|
618
|
+
const next = await call('agenda.next', {});
|
|
619
|
+
if (!next)
|
|
620
|
+
return textResult('No pending research questions on the agenda.');
|
|
621
|
+
const lines = [
|
|
622
|
+
'Next Trading Research Question:',
|
|
623
|
+
` ${next.question ?? next.title ?? next.topic ?? 'Research topic'}`,
|
|
624
|
+
];
|
|
625
|
+
if (next.priority !== undefined)
|
|
626
|
+
lines.push(` Priority: P${next.priority}`);
|
|
627
|
+
if (next.description)
|
|
628
|
+
lines.push(` Description: ${next.description}`);
|
|
629
|
+
if (next.rationale)
|
|
630
|
+
lines.push(` Rationale: ${next.rationale}`);
|
|
631
|
+
if (next.suggestedApproach)
|
|
632
|
+
lines.push(` Suggested approach: ${next.suggestedApproach}`);
|
|
633
|
+
if (next.expectedValue)
|
|
634
|
+
lines.push(` Expected value: ${next.expectedValue}`);
|
|
635
|
+
return textResult(lines.join('\n'));
|
|
636
|
+
});
|
|
637
|
+
server.tool('trading_research_prioritize', 'Re-prioritize the trading research agenda based on current performance gaps, recent discoveries, and potential impact.', {}, async () => {
|
|
638
|
+
const result = await call('agenda.prioritize', {});
|
|
639
|
+
if (!result)
|
|
640
|
+
return textResult('Could not prioritize research agenda.');
|
|
641
|
+
if (Array.isArray(result)) {
|
|
642
|
+
if (!result.length)
|
|
643
|
+
return textResult('Research agenda is empty, nothing to prioritize.');
|
|
644
|
+
const lines = [`Research Agenda Re-prioritized (${result.length} items):\n`];
|
|
645
|
+
for (const item of result) {
|
|
646
|
+
const priority = item.priority !== undefined ? ` [P${item.priority}]` : '';
|
|
647
|
+
lines.push(`#${item.id ?? ''}${priority} ${item.question ?? item.title ?? item.topic ?? 'Topic'}`);
|
|
648
|
+
if (item.reason)
|
|
649
|
+
lines.push(` Reason: ${item.reason}`);
|
|
650
|
+
}
|
|
651
|
+
return textResult(lines.join('\n'));
|
|
652
|
+
}
|
|
653
|
+
const lines = ['Research Agenda Re-prioritized:'];
|
|
654
|
+
if (result.itemsReordered !== undefined)
|
|
655
|
+
lines.push(` Items reordered: ${result.itemsReordered}`);
|
|
656
|
+
if (result.newTopPriority)
|
|
657
|
+
lines.push(` New top priority: ${result.newTopPriority}`);
|
|
658
|
+
if (result.summary)
|
|
659
|
+
lines.push(` ${result.summary}`);
|
|
660
|
+
return textResult(lines.join('\n'));
|
|
661
|
+
});
|
|
662
|
+
server.tool('trading_research_ask', 'Add a new research question to the trading research agenda for future investigation.', {}, async () => {
|
|
663
|
+
const result = await call('agenda.ask', {});
|
|
664
|
+
if (!result)
|
|
665
|
+
return textResult('Could not generate a new research question.');
|
|
666
|
+
if (typeof result === 'string')
|
|
667
|
+
return textResult(`New research question added: ${result}`);
|
|
668
|
+
const lines = ['New Research Question Added:'];
|
|
669
|
+
if (result.question ?? result.title)
|
|
670
|
+
lines.push(` ${result.question ?? result.title}`);
|
|
671
|
+
if (result.priority !== undefined)
|
|
672
|
+
lines.push(` Priority: P${result.priority}`);
|
|
673
|
+
if (result.rationale)
|
|
674
|
+
lines.push(` Rationale: ${result.rationale}`);
|
|
675
|
+
if (result.id)
|
|
676
|
+
lines.push(` ID: #${result.id}`);
|
|
677
|
+
return textResult(lines.join('\n'));
|
|
678
|
+
});
|
|
679
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
680
|
+
// Anomaly Detective (4 tools)
|
|
681
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
682
|
+
server.tool('trading_anomalies', 'List detected anomalies in trading behavior: unusual patterns, outlier trades, unexpected regime shifts, performance deviations.', {}, async () => {
|
|
683
|
+
const anomalies = await call('anomaly.list', {});
|
|
684
|
+
if (!anomalies?.length)
|
|
685
|
+
return textResult('No trading anomalies detected. Performance is within expected bounds.');
|
|
686
|
+
const lines = [`Trading Anomalies (${anomalies.length}):\n`];
|
|
687
|
+
for (const a of anomalies) {
|
|
688
|
+
const severity = a.severity ? ` [${a.severity.toUpperCase()}]` : '';
|
|
689
|
+
lines.push(`#${a.id ?? ''}${severity} ${a.title ?? a.description ?? a.type ?? 'Anomaly'}`);
|
|
690
|
+
if (a.description && a.title)
|
|
691
|
+
lines.push(` ${a.description}`);
|
|
692
|
+
if (a.metric)
|
|
693
|
+
lines.push(` Metric: ${a.metric}`);
|
|
694
|
+
if (a.expectedValue !== undefined && a.actualValue !== undefined) {
|
|
695
|
+
lines.push(` Expected: ${a.expectedValue} | Actual: ${a.actualValue} | Deviation: ${a.deviation ?? 'N/A'}`);
|
|
696
|
+
}
|
|
697
|
+
if (a.detected_at ?? a.detectedAt)
|
|
698
|
+
lines.push(` Detected: ${new Date(a.detected_at ?? a.detectedAt).toLocaleString()}`);
|
|
699
|
+
if (a.status)
|
|
700
|
+
lines.push(` Status: ${a.status}`);
|
|
701
|
+
lines.push('');
|
|
702
|
+
}
|
|
703
|
+
return textResult(lines.join('\n'));
|
|
704
|
+
});
|
|
705
|
+
server.tool('trading_anomaly_investigate', 'Deep investigation of a trading anomaly: root cause analysis, related events, potential explanations, and recommended actions.', {}, async () => {
|
|
706
|
+
const investigation = await call('anomaly.investigate', {});
|
|
707
|
+
if (!investigation)
|
|
708
|
+
return textResult('No anomaly investigation available.');
|
|
709
|
+
if (typeof investigation === 'string')
|
|
710
|
+
return textResult(investigation);
|
|
711
|
+
const lines = ['Anomaly Investigation:\n'];
|
|
712
|
+
if (investigation.anomaly)
|
|
713
|
+
lines.push(` Anomaly: ${investigation.anomaly}`);
|
|
714
|
+
if (investigation.rootCause)
|
|
715
|
+
lines.push(` Root cause: ${investigation.rootCause}`);
|
|
716
|
+
if (investigation.relatedEvents?.length > 0) {
|
|
717
|
+
lines.push(' Related events:');
|
|
718
|
+
for (const e of investigation.relatedEvents) {
|
|
719
|
+
lines.push(` - ${e.description ?? e}`);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
if (investigation.explanations?.length > 0) {
|
|
723
|
+
lines.push(' Possible explanations:');
|
|
724
|
+
for (const exp of investigation.explanations) {
|
|
725
|
+
const prob = exp.probability !== undefined ? ` (${(exp.probability * 100).toFixed(0)}%)` : '';
|
|
726
|
+
lines.push(` - ${exp.description ?? exp}${prob}`);
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
if (investigation.recommendations?.length > 0) {
|
|
730
|
+
lines.push(' Recommendations:');
|
|
731
|
+
for (const rec of investigation.recommendations) {
|
|
732
|
+
lines.push(` - ${rec}`);
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
if (investigation.severity)
|
|
736
|
+
lines.push(`\n Severity: ${investigation.severity}`);
|
|
737
|
+
if (investigation.resolved !== undefined)
|
|
738
|
+
lines.push(` Resolved: ${investigation.resolved ? 'YES' : 'NO'}`);
|
|
739
|
+
return textResult(lines.join('\n'));
|
|
740
|
+
});
|
|
741
|
+
server.tool('trading_anomaly_history', 'View history of past trading anomalies: detected issues, resolutions, and patterns in anomaly occurrence.', {}, async () => {
|
|
742
|
+
const history = await call('anomaly.history', {});
|
|
743
|
+
if (!history?.length)
|
|
744
|
+
return textResult('No anomaly history recorded.');
|
|
745
|
+
const lines = [`Anomaly History (${history.length}):\n`];
|
|
746
|
+
for (const h of history) {
|
|
747
|
+
const status = h.resolved ? 'RESOLVED' : h.status ?? 'OPEN';
|
|
748
|
+
lines.push(`#${h.id ?? ''} [${status}] ${h.title ?? h.description ?? h.type ?? 'Anomaly'}`);
|
|
749
|
+
if (h.description && h.title)
|
|
750
|
+
lines.push(` ${h.description}`);
|
|
751
|
+
if (h.resolution)
|
|
752
|
+
lines.push(` Resolution: ${h.resolution}`);
|
|
753
|
+
if (h.detected_at ?? h.detectedAt)
|
|
754
|
+
lines.push(` Detected: ${new Date(h.detected_at ?? h.detectedAt).toLocaleString()}`);
|
|
755
|
+
if (h.resolved_at ?? h.resolvedAt)
|
|
756
|
+
lines.push(` Resolved: ${new Date(h.resolved_at ?? h.resolvedAt).toLocaleString()}`);
|
|
757
|
+
lines.push('');
|
|
758
|
+
}
|
|
759
|
+
return textResult(lines.join('\n'));
|
|
760
|
+
});
|
|
761
|
+
server.tool('trading_drift_report', 'Get a performance drift report: detect if trading behavior is drifting from historical norms — signal accuracy decay, win rate shifts, risk profile changes.', {}, async () => {
|
|
762
|
+
const drift = await call('anomaly.drift', {});
|
|
763
|
+
if (!drift)
|
|
764
|
+
return textResult('No drift data available. Need sufficient trading history for drift detection.');
|
|
765
|
+
if (typeof drift === 'string')
|
|
766
|
+
return textResult(drift);
|
|
767
|
+
const lines = ['Trading Drift Report:\n'];
|
|
768
|
+
if (drift.overallDrift !== undefined)
|
|
769
|
+
lines.push(` Overall drift: ${drift.overallDrift}`);
|
|
770
|
+
if (drift.driftDetected !== undefined)
|
|
771
|
+
lines.push(` Drift detected: ${drift.driftDetected ? 'YES' : 'NO'}`);
|
|
772
|
+
if (drift.metrics?.length > 0) {
|
|
773
|
+
lines.push(' Metric Drift:');
|
|
774
|
+
for (const m of drift.metrics) {
|
|
775
|
+
const status = m.drifting ? 'DRIFTING' : 'STABLE';
|
|
776
|
+
lines.push(` ${m.name}: ${m.baseline?.toFixed(3) ?? '?'} → ${m.current?.toFixed(3) ?? '?'} [${status}]`);
|
|
777
|
+
if (m.deviation !== undefined)
|
|
778
|
+
lines.push(` Deviation: ${m.deviation.toFixed(3)} (threshold: ${m.threshold?.toFixed(3) ?? 'N/A'})`);
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
if (drift.recommendations?.length > 0) {
|
|
782
|
+
lines.push('\n Recommendations:');
|
|
783
|
+
for (const rec of drift.recommendations) {
|
|
784
|
+
lines.push(` - ${rec}`);
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
if (drift.since)
|
|
788
|
+
lines.push(`\n Analysis period since: ${new Date(drift.since).toLocaleString()}`);
|
|
789
|
+
return textResult(lines.join('\n'));
|
|
790
|
+
});
|
|
791
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
792
|
+
// Research Journal (5 tools)
|
|
793
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
794
|
+
server.tool('trading_journal', 'View trading research journal entries: observations, insights, experiment notes, and decision logs.', {}, async () => {
|
|
795
|
+
const entries = await call('journal.entries', {});
|
|
796
|
+
if (!entries?.length)
|
|
797
|
+
return textResult('Research journal is empty. Entries are created as the brain learns.');
|
|
798
|
+
const lines = [`Trading Research Journal (${entries.length} entries):\n`];
|
|
799
|
+
for (const entry of entries) {
|
|
800
|
+
const date = entry.created_at ? new Date(entry.created_at).toLocaleString() : 'unknown date';
|
|
801
|
+
const tag = entry.type ? `[${entry.type.toUpperCase()}] ` : '';
|
|
802
|
+
lines.push(`${date} — ${tag}${entry.title ?? 'Entry'}`);
|
|
803
|
+
if (entry.content)
|
|
804
|
+
lines.push(` ${entry.content}`);
|
|
805
|
+
if (entry.tags?.length > 0)
|
|
806
|
+
lines.push(` Tags: ${entry.tags.join(', ')}`);
|
|
807
|
+
lines.push('');
|
|
808
|
+
}
|
|
809
|
+
return textResult(lines.join('\n'));
|
|
810
|
+
});
|
|
811
|
+
server.tool('trading_journal_summary', 'Get a summary of the trading research journal: key themes, most active periods, important breakthroughs.', {}, async () => {
|
|
812
|
+
const summary = await call('journal.summary', {});
|
|
813
|
+
if (!summary)
|
|
814
|
+
return textResult('No journal summary available. Need journal entries first.');
|
|
815
|
+
if (typeof summary === 'string')
|
|
816
|
+
return textResult(summary);
|
|
817
|
+
const lines = ['Trading Research Journal Summary:\n'];
|
|
818
|
+
if (summary.totalEntries !== undefined)
|
|
819
|
+
lines.push(` Total entries: ${summary.totalEntries}`);
|
|
820
|
+
if (summary.dateRange)
|
|
821
|
+
lines.push(` Date range: ${summary.dateRange}`);
|
|
822
|
+
if (summary.themes?.length > 0) {
|
|
823
|
+
lines.push(' Key themes:');
|
|
824
|
+
for (const theme of summary.themes) {
|
|
825
|
+
lines.push(` - ${theme.name ?? theme}: ${theme.count ?? ''} entries`);
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
if (summary.breakthroughs?.length > 0) {
|
|
829
|
+
lines.push(' Breakthroughs:');
|
|
830
|
+
for (const b of summary.breakthroughs) {
|
|
831
|
+
lines.push(` - ${b.description ?? b}`);
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
if (summary.openQuestions?.length > 0) {
|
|
835
|
+
lines.push(' Open questions:');
|
|
836
|
+
for (const q of summary.openQuestions) {
|
|
837
|
+
lines.push(` - ${q}`);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
return textResult(lines.join('\n'));
|
|
841
|
+
});
|
|
842
|
+
server.tool('trading_journal_milestones', 'View research milestones in the trading journal: major discoveries, confirmed hypotheses, significant parameter changes.', {}, async () => {
|
|
843
|
+
const milestones = await call('journal.milestones', {});
|
|
844
|
+
if (!milestones?.length)
|
|
845
|
+
return textResult('No research milestones recorded yet.');
|
|
846
|
+
const lines = [`Trading Research Milestones (${milestones.length}):\n`];
|
|
847
|
+
for (const m of milestones) {
|
|
848
|
+
const date = m.date ?? m.created_at ? new Date(m.date ?? m.created_at).toLocaleString() : 'unknown date';
|
|
849
|
+
lines.push(`[${date}] ${m.title ?? m.description ?? 'Milestone'}`);
|
|
850
|
+
if (m.description && m.title)
|
|
851
|
+
lines.push(` ${m.description}`);
|
|
852
|
+
if (m.impact)
|
|
853
|
+
lines.push(` Impact: ${m.impact}`);
|
|
854
|
+
if (m.significance)
|
|
855
|
+
lines.push(` Significance: ${m.significance}`);
|
|
856
|
+
lines.push('');
|
|
857
|
+
}
|
|
858
|
+
return textResult(lines.join('\n'));
|
|
859
|
+
});
|
|
860
|
+
server.tool('trading_journal_write', 'Write a manual entry to the trading research journal: record an observation, insight, decision rationale, or experiment note.', {}, async () => {
|
|
861
|
+
const result = await call('journal.write', {});
|
|
862
|
+
if (!result)
|
|
863
|
+
return textResult('Failed to write journal entry.');
|
|
864
|
+
if (typeof result === 'string')
|
|
865
|
+
return textResult(result);
|
|
866
|
+
const lines = ['Journal Entry Written:'];
|
|
867
|
+
if (result.id)
|
|
868
|
+
lines.push(` ID: #${result.id}`);
|
|
869
|
+
if (result.title)
|
|
870
|
+
lines.push(` Title: ${result.title}`);
|
|
871
|
+
if (result.type)
|
|
872
|
+
lines.push(` Type: ${result.type}`);
|
|
873
|
+
if (result.created_at)
|
|
874
|
+
lines.push(` Date: ${new Date(result.created_at).toLocaleString()}`);
|
|
875
|
+
return textResult(lines.join('\n'));
|
|
876
|
+
});
|
|
877
|
+
server.tool('trading_journal_search', 'Search the trading research journal by keyword, date range, or tag. Find past observations and insights related to a topic.', {}, async () => {
|
|
878
|
+
const results = await call('journal.search', {});
|
|
879
|
+
if (!results?.length)
|
|
880
|
+
return textResult('No matching journal entries found.');
|
|
881
|
+
const lines = [`Journal Search Results (${results.length}):\n`];
|
|
882
|
+
for (const entry of results) {
|
|
883
|
+
const date = entry.created_at ? new Date(entry.created_at).toLocaleString() : 'unknown date';
|
|
884
|
+
const tag = entry.type ? `[${entry.type.toUpperCase()}] ` : '';
|
|
885
|
+
lines.push(`${date} — ${tag}${entry.title ?? 'Entry'}`);
|
|
886
|
+
if (entry.content)
|
|
887
|
+
lines.push(` ${entry.content}`);
|
|
888
|
+
if (entry.relevance !== undefined)
|
|
889
|
+
lines.push(` Relevance: ${(entry.relevance * 100).toFixed(0)}%`);
|
|
890
|
+
lines.push('');
|
|
891
|
+
}
|
|
892
|
+
return textResult(lines.join('\n'));
|
|
893
|
+
});
|
|
894
|
+
}
|
|
895
|
+
//# sourceMappingURL=advanced-research-tools.js.map
|