@exagent/sdk 0.1.21 → 0.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/.turbo/turbo-build.log +14 -0
- package/dist/index.d.ts +440 -2082
- package/dist/index.js +67 -2147
- package/package.json +7 -20
- package/src/client.ts +79 -0
- package/src/index.ts +48 -0
- package/src/types.ts +468 -0
- package/tsconfig.json +8 -0
- package/dist/index.d.mts +0 -2131
- package/dist/index.mjs +0 -2136
package/package.json
CHANGED
|
@@ -1,37 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exagent/sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
|
-
"module": "dist/index.mjs",
|
|
7
6
|
"types": "dist/index.d.ts",
|
|
8
7
|
"exports": {
|
|
9
8
|
".": {
|
|
10
|
-
"import": "./dist/index.
|
|
11
|
-
"require": "./dist/index.js",
|
|
9
|
+
"import": "./dist/index.js",
|
|
12
10
|
"types": "./dist/index.d.ts"
|
|
13
11
|
}
|
|
14
12
|
},
|
|
15
|
-
"files": [
|
|
16
|
-
"dist"
|
|
17
|
-
],
|
|
18
13
|
"scripts": {
|
|
19
|
-
"build": "tsup src/index.ts --format
|
|
20
|
-
"dev": "tsup src/index.ts --format
|
|
21
|
-
"test": "vitest",
|
|
22
|
-
"lint": "eslint src/",
|
|
23
|
-
"clean": "rm -rf dist"
|
|
14
|
+
"build": "tsup src/index.ts --format esm --dts",
|
|
15
|
+
"dev": "tsup src/index.ts --format esm --dts --watch"
|
|
24
16
|
},
|
|
25
17
|
"dependencies": {
|
|
26
|
-
"
|
|
18
|
+
"zod": "^3.22.0"
|
|
27
19
|
},
|
|
28
20
|
"devDependencies": {
|
|
29
|
-
"@types/node": "^20.0.0",
|
|
30
21
|
"tsup": "^8.0.0",
|
|
31
|
-
"typescript": "^5.
|
|
32
|
-
"vitest": "^2.0.0"
|
|
33
|
-
},
|
|
34
|
-
"peerDependencies": {
|
|
35
|
-
"viem": "^2.0.0"
|
|
22
|
+
"typescript": "^5.6.0"
|
|
36
23
|
}
|
|
37
24
|
}
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { AgentProfile, TradeSignal } from './types.js';
|
|
2
|
+
|
|
3
|
+
export interface ExagentClientConfig {
|
|
4
|
+
baseUrl: string;
|
|
5
|
+
token: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export class ExagentClient {
|
|
9
|
+
private baseUrl: string;
|
|
10
|
+
private token: string;
|
|
11
|
+
|
|
12
|
+
constructor(config: ExagentClientConfig) {
|
|
13
|
+
this.baseUrl = config.baseUrl.replace(/\/$/, '');
|
|
14
|
+
this.token = config.token;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
private async request<T>(path: string, options: RequestInit = {}): Promise<T> {
|
|
18
|
+
const url = `${this.baseUrl}${path}`;
|
|
19
|
+
const res = await fetch(url, {
|
|
20
|
+
...options,
|
|
21
|
+
headers: {
|
|
22
|
+
'Content-Type': 'application/json',
|
|
23
|
+
Authorization: `Bearer ${this.token}`,
|
|
24
|
+
...options.headers,
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
if (!res.ok) {
|
|
29
|
+
const body = await res.text();
|
|
30
|
+
throw new Error(`API error ${res.status}: ${body}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return res.json() as Promise<T>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async getMe(): Promise<Record<string, unknown>> {
|
|
37
|
+
return this.request('/v1/auth/me');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async listAgents(): Promise<AgentProfile[]> {
|
|
41
|
+
return this.request('/v1/agents');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async getAgent(agentId: string): Promise<AgentProfile> {
|
|
45
|
+
return this.request(`/v1/agents/${agentId}`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async createAgent(data: {
|
|
49
|
+
name: string;
|
|
50
|
+
description?: string;
|
|
51
|
+
config: Record<string, unknown>;
|
|
52
|
+
}): Promise<AgentProfile> {
|
|
53
|
+
return this.request('/v1/agents', {
|
|
54
|
+
method: 'POST',
|
|
55
|
+
body: JSON.stringify(data),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async reportTradeSignal(agentId: string, signal: TradeSignal): Promise<void> {
|
|
60
|
+
await this.request(`/v1/agents/${agentId}/signals`, {
|
|
61
|
+
method: 'POST',
|
|
62
|
+
body: JSON.stringify(signal),
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
getWebSocketUrl(): string {
|
|
67
|
+
const wsBase = this.baseUrl
|
|
68
|
+
.replace(/^http:/, 'ws:')
|
|
69
|
+
.replace(/^https:/, 'wss:');
|
|
70
|
+
return `${wsBase}/ws/agent`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
getDashboardWebSocketUrl(): string {
|
|
74
|
+
const wsBase = this.baseUrl
|
|
75
|
+
.replace(/^http:/, 'ws:')
|
|
76
|
+
.replace(/^https:/, 'wss:');
|
|
77
|
+
return `${wsBase}/ws/dashboard`;
|
|
78
|
+
}
|
|
79
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export { ExagentClient } from './client.js';
|
|
2
|
+
export type { ExagentClientConfig } from './client.js';
|
|
3
|
+
|
|
4
|
+
export type {
|
|
5
|
+
AgentProfile,
|
|
6
|
+
AgentStatus,
|
|
7
|
+
AgentConfig,
|
|
8
|
+
LLMConfig,
|
|
9
|
+
LLMProvider,
|
|
10
|
+
LLMMessage,
|
|
11
|
+
LLMResponse,
|
|
12
|
+
LLMAdapter,
|
|
13
|
+
LLMMetadata,
|
|
14
|
+
StrategyConfig,
|
|
15
|
+
StrategyContext,
|
|
16
|
+
StrategyFunction,
|
|
17
|
+
StrategyStore,
|
|
18
|
+
StrategyTemplate,
|
|
19
|
+
TradingConfig,
|
|
20
|
+
RelayConfig,
|
|
21
|
+
VenueConfig,
|
|
22
|
+
TradeSignal,
|
|
23
|
+
PerpTradeSignal,
|
|
24
|
+
PredictionTradeSignal,
|
|
25
|
+
MarketData,
|
|
26
|
+
OHLCV,
|
|
27
|
+
TrackedPosition,
|
|
28
|
+
TradeRecord,
|
|
29
|
+
PositionSummary,
|
|
30
|
+
RiskParams,
|
|
31
|
+
PaperTrade,
|
|
32
|
+
PaperPortfolio,
|
|
33
|
+
PaperMetrics,
|
|
34
|
+
AgentMode,
|
|
35
|
+
CommandType,
|
|
36
|
+
MessageType,
|
|
37
|
+
MessageLevel,
|
|
38
|
+
RelayCommand,
|
|
39
|
+
AgentStatusPayload,
|
|
40
|
+
AgentRelayMessage,
|
|
41
|
+
HeartbeatMessage,
|
|
42
|
+
TradeSignalMessage,
|
|
43
|
+
AgentToAPIMessage,
|
|
44
|
+
APIToAgentMessage,
|
|
45
|
+
APIToDashboardMessage,
|
|
46
|
+
} from './types.js';
|
|
47
|
+
|
|
48
|
+
export { tradeSignalSchema, tradingConfigSchema } from './types.js';
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
// ─── Agent Identity ──────────────────────────────────────────────
|
|
4
|
+
|
|
5
|
+
export interface AgentProfile {
|
|
6
|
+
id: string;
|
|
7
|
+
userId: string;
|
|
8
|
+
name: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
status: AgentStatus;
|
|
11
|
+
config: AgentConfig;
|
|
12
|
+
createdAt: string;
|
|
13
|
+
updatedAt: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type AgentStatus = 'online' | 'idle' | 'trading' | 'error' | 'offline';
|
|
17
|
+
|
|
18
|
+
// ─── Agent Configuration ─────────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
export interface AgentConfig {
|
|
21
|
+
llm: LLMConfig;
|
|
22
|
+
strategy: StrategyConfig;
|
|
23
|
+
trading: TradingConfig;
|
|
24
|
+
relay: RelayConfig;
|
|
25
|
+
venues?: VenueConfig;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface LLMConfig {
|
|
29
|
+
provider: LLMProvider;
|
|
30
|
+
model?: string;
|
|
31
|
+
apiKey?: string;
|
|
32
|
+
endpoint?: string;
|
|
33
|
+
temperature?: number;
|
|
34
|
+
maxTokens?: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export type LLMProvider =
|
|
38
|
+
| 'openai'
|
|
39
|
+
| 'anthropic'
|
|
40
|
+
| 'google'
|
|
41
|
+
| 'deepseek'
|
|
42
|
+
| 'mistral'
|
|
43
|
+
| 'groq'
|
|
44
|
+
| 'together'
|
|
45
|
+
| 'ollama';
|
|
46
|
+
|
|
47
|
+
export interface StrategyConfig {
|
|
48
|
+
file?: string;
|
|
49
|
+
template?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface TradingConfig {
|
|
53
|
+
mode: 'live' | 'paper';
|
|
54
|
+
timeHorizon: 'intraday' | 'swing' | 'position';
|
|
55
|
+
maxPositionSizeBps: number;
|
|
56
|
+
maxDailyLossBps: number;
|
|
57
|
+
maxConcurrentPositions: number;
|
|
58
|
+
tradingIntervalMs: number;
|
|
59
|
+
maxSlippageBps: number;
|
|
60
|
+
minTradeValueUSD: number;
|
|
61
|
+
initialCapitalUSD?: number;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface RelayConfig {
|
|
65
|
+
url: string;
|
|
66
|
+
heartbeatIntervalMs?: number;
|
|
67
|
+
reconnectMaxAttempts?: number;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface VenueConfig {
|
|
71
|
+
hyperliquid?: {
|
|
72
|
+
enabled: boolean;
|
|
73
|
+
maxLeverage?: number;
|
|
74
|
+
maxNotionalUSD?: number;
|
|
75
|
+
};
|
|
76
|
+
polymarket?: {
|
|
77
|
+
enabled: boolean;
|
|
78
|
+
maxNotionalUSD?: number;
|
|
79
|
+
maxExposureUSD?: number;
|
|
80
|
+
};
|
|
81
|
+
spot?: {
|
|
82
|
+
enabled: boolean;
|
|
83
|
+
chains?: string[];
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// ─── Trade Signals ───────────────────────────────────────────────
|
|
88
|
+
|
|
89
|
+
export interface TradeSignal {
|
|
90
|
+
venue: string;
|
|
91
|
+
chain?: string;
|
|
92
|
+
symbol: string;
|
|
93
|
+
side: 'long' | 'short' | 'buy' | 'sell';
|
|
94
|
+
size: number;
|
|
95
|
+
price: number;
|
|
96
|
+
fee: number;
|
|
97
|
+
venueFillId: string;
|
|
98
|
+
venueTimestamp: string;
|
|
99
|
+
leverage?: number;
|
|
100
|
+
orderType?: string;
|
|
101
|
+
confidence?: number;
|
|
102
|
+
reasoning?: string;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export interface PerpTradeSignal {
|
|
106
|
+
action: 'open_long' | 'open_short' | 'close_long' | 'close_short' | 'hold';
|
|
107
|
+
instrument: string;
|
|
108
|
+
size: number;
|
|
109
|
+
price: number;
|
|
110
|
+
leverage: number;
|
|
111
|
+
orderType: 'limit' | 'market';
|
|
112
|
+
reduceOnly: boolean;
|
|
113
|
+
confidence: number;
|
|
114
|
+
reasoning?: string;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export interface PredictionTradeSignal {
|
|
118
|
+
action: 'buy_yes' | 'buy_no' | 'sell_yes' | 'sell_no' | 'hold';
|
|
119
|
+
marketConditionId: string;
|
|
120
|
+
marketQuestion: string;
|
|
121
|
+
outcomeIndex: number;
|
|
122
|
+
amount: number;
|
|
123
|
+
limitPrice: number;
|
|
124
|
+
confidence: number;
|
|
125
|
+
reasoning?: string;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ─── LLM Types ───────────────────────────────────────────────────
|
|
129
|
+
|
|
130
|
+
export interface LLMMessage {
|
|
131
|
+
role: 'user' | 'assistant' | 'system';
|
|
132
|
+
content: string;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export interface LLMResponse {
|
|
136
|
+
content: string;
|
|
137
|
+
tokens?: { input: number; output: number };
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export interface LLMAdapter {
|
|
141
|
+
chat(messages: LLMMessage[]): Promise<LLMResponse>;
|
|
142
|
+
getMetadata(): LLMMetadata;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export interface LLMMetadata {
|
|
146
|
+
provider: string;
|
|
147
|
+
model: string;
|
|
148
|
+
maxTokens?: number;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// ─── Strategy Types ──────────────────────────────────────────────
|
|
152
|
+
|
|
153
|
+
export interface StrategyContext {
|
|
154
|
+
llm: LLMAdapter;
|
|
155
|
+
market: MarketData;
|
|
156
|
+
position: PositionSummary;
|
|
157
|
+
store: StrategyStore;
|
|
158
|
+
config: TradingConfig;
|
|
159
|
+
log: (message: string) => void;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export type StrategyFunction = (context: StrategyContext) => Promise<TradeSignal[]>;
|
|
163
|
+
|
|
164
|
+
export interface StrategyStore {
|
|
165
|
+
get<T>(key: string): T | undefined;
|
|
166
|
+
set<T>(key: string, value: T): void;
|
|
167
|
+
delete(key: string): void;
|
|
168
|
+
keys(): string[];
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export interface StrategyTemplate {
|
|
172
|
+
id: string;
|
|
173
|
+
name: string;
|
|
174
|
+
description: string;
|
|
175
|
+
category: 'momentum' | 'value' | 'arbitrage' | 'market_making' | 'custom';
|
|
176
|
+
venues: string[];
|
|
177
|
+
riskLevel: 'conservative' | 'moderate' | 'aggressive';
|
|
178
|
+
code: string;
|
|
179
|
+
systemPrompt: string;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// ─── Market Data ─────────────────────────────────────────────────
|
|
183
|
+
|
|
184
|
+
export interface MarketData {
|
|
185
|
+
getPrice(symbol: string): number | undefined;
|
|
186
|
+
getPrices(): Record<string, number>;
|
|
187
|
+
getOHLCV(symbol: string, timeframe: string): OHLCV[];
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export interface OHLCV {
|
|
191
|
+
timestamp: number;
|
|
192
|
+
open: number;
|
|
193
|
+
high: number;
|
|
194
|
+
low: number;
|
|
195
|
+
close: number;
|
|
196
|
+
volume: number;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// ─── Position Tracking ──────────────────────────────────────────
|
|
200
|
+
|
|
201
|
+
export interface TrackedPosition {
|
|
202
|
+
token: string;
|
|
203
|
+
quantity: number;
|
|
204
|
+
costBasisPerUnit: number;
|
|
205
|
+
entryTimestamp: number;
|
|
206
|
+
venue?: string;
|
|
207
|
+
chain?: string;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export interface TradeRecord {
|
|
211
|
+
token: string;
|
|
212
|
+
action: 'buy' | 'sell';
|
|
213
|
+
quantity: number;
|
|
214
|
+
price: number;
|
|
215
|
+
fee: number;
|
|
216
|
+
timestamp: number;
|
|
217
|
+
venue?: string;
|
|
218
|
+
chain?: string;
|
|
219
|
+
venueFillId?: string;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export interface PositionSummary {
|
|
223
|
+
openPositions: TrackedPosition[];
|
|
224
|
+
totalUnrealizedPnL: number;
|
|
225
|
+
totalRealizedPnL: number;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// ─── Risk ────────────────────────────────────────────────────────
|
|
229
|
+
|
|
230
|
+
export interface RiskParams {
|
|
231
|
+
maxPositionSizeBps: number;
|
|
232
|
+
maxDailyLossBps: number;
|
|
233
|
+
maxConcurrentPositions: number;
|
|
234
|
+
maxSlippageBps: number;
|
|
235
|
+
minTradeValueUSD: number;
|
|
236
|
+
confidenceThreshold?: number;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// ─── Paper Trading ───────────────────────────────────────────────
|
|
240
|
+
|
|
241
|
+
export interface PaperTrade {
|
|
242
|
+
id: string;
|
|
243
|
+
symbol: string;
|
|
244
|
+
side: 'buy' | 'sell';
|
|
245
|
+
size: number;
|
|
246
|
+
entryPrice: number;
|
|
247
|
+
exitPrice?: number;
|
|
248
|
+
fee: number;
|
|
249
|
+
pnl?: number;
|
|
250
|
+
timestamp: number;
|
|
251
|
+
venue: string;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export interface PaperPortfolio {
|
|
255
|
+
cash: number;
|
|
256
|
+
positions: Map<string, { quantity: number; avgPrice: number }>;
|
|
257
|
+
equity: number;
|
|
258
|
+
trades: PaperTrade[];
|
|
259
|
+
equityCurve: { timestamp: number; equity: number }[];
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export interface PaperMetrics {
|
|
263
|
+
totalReturn: number;
|
|
264
|
+
sharpeRatio: number;
|
|
265
|
+
maxDrawdown: number;
|
|
266
|
+
winRate: number;
|
|
267
|
+
profitFactor: number;
|
|
268
|
+
totalTrades: number;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// ─── Relay Protocol ──────────────────────────────────────────────
|
|
272
|
+
|
|
273
|
+
export type AgentMode = 'idle' | 'trading' | 'paper' | 'paused';
|
|
274
|
+
|
|
275
|
+
export type CommandType =
|
|
276
|
+
| 'start_trading'
|
|
277
|
+
| 'stop_trading'
|
|
278
|
+
| 'pause_trading'
|
|
279
|
+
| 'update_risk_params'
|
|
280
|
+
| 'update_strategy'
|
|
281
|
+
| 'reload_config'
|
|
282
|
+
| 'get_status'
|
|
283
|
+
| 'close_all_positions'
|
|
284
|
+
| 'shutdown';
|
|
285
|
+
|
|
286
|
+
export type MessageType =
|
|
287
|
+
| 'trade_executed'
|
|
288
|
+
| 'perp_fill'
|
|
289
|
+
| 'prediction_fill'
|
|
290
|
+
| 'spot_fill'
|
|
291
|
+
| 'bridge_fill'
|
|
292
|
+
| 'strategy_decision'
|
|
293
|
+
| 'risk_blocked'
|
|
294
|
+
| 'error'
|
|
295
|
+
| 'info'
|
|
296
|
+
| 'funds_low'
|
|
297
|
+
| 'daily_limit_hit'
|
|
298
|
+
| 'started'
|
|
299
|
+
| 'stopped';
|
|
300
|
+
|
|
301
|
+
export type MessageLevel = 'info' | 'warning' | 'error' | 'success';
|
|
302
|
+
|
|
303
|
+
export interface RelayCommand {
|
|
304
|
+
id: string;
|
|
305
|
+
type: CommandType;
|
|
306
|
+
params?: Record<string, unknown>;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
export interface AgentStatusPayload {
|
|
310
|
+
mode: AgentMode;
|
|
311
|
+
agentId: string;
|
|
312
|
+
walletAddress?: string;
|
|
313
|
+
sdkVersion?: string;
|
|
314
|
+
cycleCount?: number;
|
|
315
|
+
lastCycleAt?: number;
|
|
316
|
+
tradingIntervalMs?: number;
|
|
317
|
+
portfolioValue?: number;
|
|
318
|
+
llm?: {
|
|
319
|
+
provider: string;
|
|
320
|
+
model: string;
|
|
321
|
+
dailyTokens?: number;
|
|
322
|
+
totalTokens?: number;
|
|
323
|
+
dailyCalls?: number;
|
|
324
|
+
totalCalls?: number;
|
|
325
|
+
dailyBudgetExceeded?: boolean;
|
|
326
|
+
};
|
|
327
|
+
risk?: {
|
|
328
|
+
dailyPnL: number;
|
|
329
|
+
dailyLossLimit: number;
|
|
330
|
+
isLimitHit: boolean;
|
|
331
|
+
};
|
|
332
|
+
positions?: {
|
|
333
|
+
openPositions: number;
|
|
334
|
+
totalUnrealizedPnL: number;
|
|
335
|
+
totalRealizedPnL: number;
|
|
336
|
+
};
|
|
337
|
+
paper?: {
|
|
338
|
+
active: boolean;
|
|
339
|
+
simulatedValue: number;
|
|
340
|
+
simulatedPnLPct: number;
|
|
341
|
+
};
|
|
342
|
+
venues?: {
|
|
343
|
+
hyperliquid?: { enabled: boolean; trading: boolean };
|
|
344
|
+
polymarket?: { enabled: boolean; trading: boolean };
|
|
345
|
+
spot?: { enabled: boolean; trading: boolean };
|
|
346
|
+
bridge?: { enabled: boolean };
|
|
347
|
+
};
|
|
348
|
+
diagnostics?: {
|
|
349
|
+
uptime?: number;
|
|
350
|
+
uptimeHuman?: string;
|
|
351
|
+
memoryMB?: number;
|
|
352
|
+
cycleStats?: {
|
|
353
|
+
total: number;
|
|
354
|
+
succeeded: number;
|
|
355
|
+
failed: number;
|
|
356
|
+
successRate: number;
|
|
357
|
+
avgCycleMs: number;
|
|
358
|
+
lastCycleMs: number;
|
|
359
|
+
};
|
|
360
|
+
lastCycleTimings?: {
|
|
361
|
+
totalMs: number;
|
|
362
|
+
priceRefreshMs: number;
|
|
363
|
+
strategyMs: number;
|
|
364
|
+
riskFilterMs: number;
|
|
365
|
+
executionMs: number;
|
|
366
|
+
};
|
|
367
|
+
errorCounts?: Record<string, number>;
|
|
368
|
+
recentErrors?: Array<{ category: string; message: string; timestamp: number }>;
|
|
369
|
+
llmStats?: {
|
|
370
|
+
totalCalls: number;
|
|
371
|
+
avgLatencyMs: number;
|
|
372
|
+
errorRate: number;
|
|
373
|
+
recentCalls: number;
|
|
374
|
+
};
|
|
375
|
+
signalQueue?: {
|
|
376
|
+
pending: number;
|
|
377
|
+
flushedTotal: number;
|
|
378
|
+
};
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
export interface AgentRelayMessage {
|
|
383
|
+
type: 'message';
|
|
384
|
+
agentId: string;
|
|
385
|
+
messageType: MessageType;
|
|
386
|
+
level: MessageLevel;
|
|
387
|
+
title: string;
|
|
388
|
+
body: string;
|
|
389
|
+
data?: Record<string, unknown>;
|
|
390
|
+
timestamp: number;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
export interface HeartbeatMessage {
|
|
394
|
+
type: 'heartbeat';
|
|
395
|
+
agentId: string;
|
|
396
|
+
status: AgentStatusPayload;
|
|
397
|
+
timestamp: number;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
export interface TradeSignalMessage {
|
|
401
|
+
type: 'trade_signal';
|
|
402
|
+
agentId: string;
|
|
403
|
+
signal: TradeSignal;
|
|
404
|
+
timestamp: number;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
export interface CommandAckMessage {
|
|
408
|
+
type: 'command_ack';
|
|
409
|
+
agentId: string;
|
|
410
|
+
commandId: string;
|
|
411
|
+
success: boolean;
|
|
412
|
+
message?: string;
|
|
413
|
+
timestamp: number;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// WebSocket message union (agent → API)
|
|
417
|
+
export type AgentToAPIMessage =
|
|
418
|
+
| { type: 'auth'; agentId: string; token: string }
|
|
419
|
+
| HeartbeatMessage
|
|
420
|
+
| AgentRelayMessage
|
|
421
|
+
| TradeSignalMessage
|
|
422
|
+
| CommandAckMessage;
|
|
423
|
+
|
|
424
|
+
// WebSocket message union (API → agent)
|
|
425
|
+
export type APIToAgentMessage =
|
|
426
|
+
| { type: 'auth_success'; agentId: string }
|
|
427
|
+
| { type: 'auth_error'; error: string }
|
|
428
|
+
| { type: 'command'; command: RelayCommand }
|
|
429
|
+
| { type: 'pong' };
|
|
430
|
+
|
|
431
|
+
// WebSocket message union (API → dashboard)
|
|
432
|
+
export type APIToDashboardMessage =
|
|
433
|
+
| { type: 'agent_status'; agentId: string; status: AgentStatusPayload }
|
|
434
|
+
| { type: 'agent_message'; message: AgentRelayMessage }
|
|
435
|
+
| { type: 'agent_connected'; agentId: string }
|
|
436
|
+
| { type: 'agent_disconnected'; agentId: string }
|
|
437
|
+
| { type: 'trade_signal'; agentId: string; signal: TradeSignal }
|
|
438
|
+
| { type: 'command_ack'; agentId: string; commandId: string; success: boolean; message?: string };
|
|
439
|
+
|
|
440
|
+
// ─── Validation Schemas ──────────────────────────────────────────
|
|
441
|
+
|
|
442
|
+
export const tradeSignalSchema = z.object({
|
|
443
|
+
venue: z.string(),
|
|
444
|
+
chain: z.string().optional(),
|
|
445
|
+
symbol: z.string(),
|
|
446
|
+
side: z.enum(['long', 'short', 'buy', 'sell']),
|
|
447
|
+
size: z.number().positive(),
|
|
448
|
+
price: z.number().positive(),
|
|
449
|
+
fee: z.number().min(0),
|
|
450
|
+
venueFillId: z.string(),
|
|
451
|
+
venueTimestamp: z.string(),
|
|
452
|
+
leverage: z.number().optional(),
|
|
453
|
+
orderType: z.string().optional(),
|
|
454
|
+
confidence: z.number().min(0).max(1).optional(),
|
|
455
|
+
reasoning: z.string().optional(),
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
export const tradingConfigSchema = z.object({
|
|
459
|
+
mode: z.enum(['live', 'paper']).default('paper'),
|
|
460
|
+
timeHorizon: z.enum(['intraday', 'swing', 'position']).default('swing'),
|
|
461
|
+
maxPositionSizeBps: z.number().min(100).max(10000).default(2000),
|
|
462
|
+
maxDailyLossBps: z.number().min(0).max(10000).default(500),
|
|
463
|
+
maxConcurrentPositions: z.number().min(1).max(100).default(5),
|
|
464
|
+
tradingIntervalMs: z.number().min(1000).default(60000),
|
|
465
|
+
maxSlippageBps: z.number().min(10).max(1000).default(100),
|
|
466
|
+
minTradeValueUSD: z.number().min(0).default(10),
|
|
467
|
+
initialCapitalUSD: z.number().optional(),
|
|
468
|
+
});
|