@clawnch/clawtomaton 0.8.0 → 0.8.2
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/README.md +5 -4
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +2 -0
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/prompt.d.ts.map +1 -1
- package/dist/agent/prompt.js +35 -0
- package/dist/agent/prompt.js.map +1 -1
- package/dist/heartbeat/index.d.ts +28 -0
- package/dist/heartbeat/index.d.ts.map +1 -1
- package/dist/heartbeat/index.js +188 -2
- package/dist/heartbeat/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/market/index.d.ts +39 -0
- package/dist/market/index.d.ts.map +1 -1
- package/dist/market/index.js +95 -1
- package/dist/market/index.js.map +1 -1
- package/dist/skills/check-balance.js +1 -1
- package/dist/skills/check-balance.js.map +1 -1
- package/dist/skills/check-price.d.ts.map +1 -1
- package/dist/skills/check-price.js +8 -4
- package/dist/skills/check-price.js.map +1 -1
- package/dist/skills/clawnx.d.ts +20 -4
- package/dist/skills/clawnx.d.ts.map +1 -1
- package/dist/skills/clawnx.js +718 -23
- package/dist/skills/clawnx.js.map +1 -1
- package/dist/skills/deploy.d.ts.map +1 -1
- package/dist/skills/deploy.js +10 -0
- package/dist/skills/deploy.js.map +1 -1
- package/dist/skills/herd.d.ts +23 -0
- package/dist/skills/herd.d.ts.map +1 -0
- package/dist/skills/herd.js +687 -0
- package/dist/skills/herd.js.map +1 -0
- package/dist/skills/hummingbot.d.ts +17 -0
- package/dist/skills/hummingbot.d.ts.map +1 -0
- package/dist/skills/hummingbot.js +1079 -0
- package/dist/skills/hummingbot.js.map +1 -0
- package/dist/skills/index.d.ts +3 -1
- package/dist/skills/index.d.ts.map +1 -1
- package/dist/skills/index.js +9 -1
- package/dist/skills/index.js.map +1 -1
- package/dist/skills/portfolio.js +1 -1
- package/dist/skills/portfolio.js.map +1 -1
- package/dist/state/index.d.ts +16 -0
- package/dist/state/index.d.ts.map +1 -1
- package/dist/state/index.js +67 -0
- package/dist/state/index.js.map +1 -1
- package/package.json +4 -3
|
@@ -0,0 +1,1079 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill: hummingbot — Professional market making via Hummingbot integration.
|
|
3
|
+
*
|
|
4
|
+
* Full-featured integration with the Hummingbot API server covering all 14
|
|
5
|
+
* upstream MCP tool capabilities: connector setup, multi-server config,
|
|
6
|
+
* portfolio, order placement, leverage/position mode, executors (with
|
|
7
|
+
* preferences), market data (all order book query types), controllers,
|
|
8
|
+
* bots, gateway (container/config/swaps/CLMM), and history search.
|
|
9
|
+
*
|
|
10
|
+
* Also includes Clawnch-specific strategy templates.
|
|
11
|
+
*
|
|
12
|
+
* @see https://github.com/hummingbot/hummingbot
|
|
13
|
+
* @see https://github.com/hummingbot/mcp
|
|
14
|
+
*/
|
|
15
|
+
import { HummingbotClient } from '@clawnch/clawncher-sdk';
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Lazy client singleton
|
|
18
|
+
// ============================================================================
|
|
19
|
+
let _client = null;
|
|
20
|
+
function getClient(ctx) {
|
|
21
|
+
if (!_client) {
|
|
22
|
+
const config = {
|
|
23
|
+
apiUrl: process.env.HUMMINGBOT_API_URL ?? 'http://localhost:8000',
|
|
24
|
+
username: process.env.HUMMINGBOT_USERNAME ?? 'admin',
|
|
25
|
+
password: process.env.HUMMINGBOT_PASSWORD ?? 'admin',
|
|
26
|
+
timeout: parseInt(process.env.HUMMINGBOT_TIMEOUT ?? '30000', 10),
|
|
27
|
+
maxRetries: parseInt(process.env.HUMMINGBOT_MAX_RETRIES ?? '3', 10),
|
|
28
|
+
retryDelay: parseInt(process.env.HUMMINGBOT_RETRY_DELAY ?? '2000', 10),
|
|
29
|
+
};
|
|
30
|
+
_client = new HummingbotClient(config);
|
|
31
|
+
}
|
|
32
|
+
return _client;
|
|
33
|
+
}
|
|
34
|
+
/** Helper to split comma-separated strings into arrays */
|
|
35
|
+
function splitCsv(val) {
|
|
36
|
+
if (!val)
|
|
37
|
+
return undefined;
|
|
38
|
+
return String(val).split(',').map(s => s.trim()).filter(Boolean);
|
|
39
|
+
}
|
|
40
|
+
// ============================================================================
|
|
41
|
+
// Skill definition
|
|
42
|
+
// ============================================================================
|
|
43
|
+
export const hummingbotSkill = {
|
|
44
|
+
name: 'hummingbot',
|
|
45
|
+
description: 'Professional market making and trading via Hummingbot. ' +
|
|
46
|
+
'Actions: "status", "portfolio", "order", "leverage", "executor", "market_data", ' +
|
|
47
|
+
'"controller", "bot", "gateway", "history", "templates", "connector", "servers", ' +
|
|
48
|
+
'"backtest", "discovery", "archived", "scripts", "analytics", "accounts". ' +
|
|
49
|
+
'Requires Hummingbot API server (default: localhost:8000).',
|
|
50
|
+
parameters: [
|
|
51
|
+
{
|
|
52
|
+
name: 'action',
|
|
53
|
+
type: 'string',
|
|
54
|
+
description: 'Action: "status", "portfolio", "order", "leverage", "executor", "market_data", ' +
|
|
55
|
+
'"controller", "bot", "gateway", "history", "templates", "connector", "servers", ' +
|
|
56
|
+
'"backtest", "discovery", "archived", "scripts", "analytics", "accounts".',
|
|
57
|
+
required: true,
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: 'sub_action',
|
|
61
|
+
type: 'string',
|
|
62
|
+
description: 'Sub-action for compound actions. ' +
|
|
63
|
+
'executor: create|search|stop|logs|positions|get_preferences|save_preferences|reset_preferences|clear_position|types|type_config|summary|get_by_id. ' +
|
|
64
|
+
'bot: deploy|status|logs|stop|stop_controllers|start_controllers|history|runs|archive. ' +
|
|
65
|
+
'gateway: container_status|container_start|container_stop|container_restart|container_logs|' +
|
|
66
|
+
'config_list|config_get|config_update|config_add|config_delete|' +
|
|
67
|
+
'swap_quote|swap_execute|swap_search|swap_status|' +
|
|
68
|
+
'clmm_list|clmm_info|clmm_open|clmm_close|clmm_fees|clmm_positions. ' +
|
|
69
|
+
'market_data: prices|candles|historical_candles|funding|orderbook|vwap|add_pair|remove_pair. ' +
|
|
70
|
+
'history: orders|perp_positions|clmm_positions. ' +
|
|
71
|
+
'templates: list|describe|build. ' +
|
|
72
|
+
'connector: list|setup|delete. ' +
|
|
73
|
+
'controller: list|describe|upsert|delete. ' +
|
|
74
|
+
'servers: list|add|modify|set_default|remove. ' +
|
|
75
|
+
'discovery: connectors|config_map|trading_rules|order_types. ' +
|
|
76
|
+
'archived: list|summary|performance|trades|orders. ' +
|
|
77
|
+
'scripts: list|get|upsert|delete|configs|get_config|upsert_config|delete_config|template. ' +
|
|
78
|
+
'analytics: history|distribution|accounts_distribution|funding_payments|rates|rate. ' +
|
|
79
|
+
'accounts: list|credentials|create|delete.',
|
|
80
|
+
required: false,
|
|
81
|
+
},
|
|
82
|
+
// --- Shared ---
|
|
83
|
+
{ name: 'connector_name', type: 'string', description: 'Exchange connector name.', required: false },
|
|
84
|
+
{ name: 'trading_pair', type: 'string', description: 'Trading pair (e.g. "ETH-USDT").', required: false },
|
|
85
|
+
{ name: 'trading_pairs', type: 'string', description: 'Comma-separated trading pairs.', required: false },
|
|
86
|
+
{ name: 'account_name', type: 'string', description: 'Account name.', required: false },
|
|
87
|
+
{ name: 'account_names', type: 'string', description: 'Comma-separated account names.', required: false },
|
|
88
|
+
{ name: 'connector_names', type: 'string', description: 'Comma-separated connector names for filtering.', required: false },
|
|
89
|
+
// --- Order ---
|
|
90
|
+
{ name: 'side', type: 'string', description: 'Trade side: "BUY" or "SELL".', required: false },
|
|
91
|
+
{ name: 'amount', type: 'string', description: 'Order amount (base currency, or "$100" for USD value).', required: false },
|
|
92
|
+
{ name: 'order_type', type: 'string', description: 'Order type: "MARKET", "LIMIT", "LIMIT_MAKER".', required: false },
|
|
93
|
+
{ name: 'price', type: 'string', description: 'Price for limit orders.', required: false },
|
|
94
|
+
{ name: 'position_action', type: 'string', description: 'Position action for perps: "OPEN" or "CLOSE".', required: false },
|
|
95
|
+
// --- Leverage ---
|
|
96
|
+
{ name: 'leverage', type: 'number', description: 'Leverage multiplier for perpetuals.', required: false },
|
|
97
|
+
{ name: 'position_mode', type: 'string', description: 'Position mode: "HEDGE" or "ONE-WAY".', required: false },
|
|
98
|
+
// --- Executor ---
|
|
99
|
+
{ name: 'executor_type', type: 'string', description: 'Executor type: grid_executor, dca_executor, position_executor, order_executor.', required: false },
|
|
100
|
+
{ name: 'executor_id', type: 'string', description: 'Executor ID for stop/logs/search.', required: false },
|
|
101
|
+
{ name: 'executor_config', type: 'string', description: 'JSON string of executor/controller configuration.', required: false },
|
|
102
|
+
{ name: 'keep_position', type: 'boolean', description: 'Keep position when stopping executor.', required: false },
|
|
103
|
+
{ name: 'preferences_content', type: 'string', description: 'Markdown content for save_preferences.', required: false },
|
|
104
|
+
// --- Bot ---
|
|
105
|
+
{ name: 'bot_name', type: 'string', description: 'Bot name.', required: false },
|
|
106
|
+
{ name: 'controllers_config', type: 'string', description: 'Comma-separated controller config/names.', required: false },
|
|
107
|
+
// --- Market data ---
|
|
108
|
+
{ name: 'interval', type: 'string', description: 'Candle interval: "1m", "5m", "15m", "30m", "1h", "4h", "1d".', required: false },
|
|
109
|
+
{ name: 'days', type: 'number', description: 'Days of historical data for candles.', required: false },
|
|
110
|
+
{ name: 'query_type', type: 'string', description: 'Order book query type: snapshot, volume_for_price, price_for_volume, quote_volume_for_price, price_for_quote_volume.', required: false },
|
|
111
|
+
{ name: 'query_value', type: 'number', description: 'Query value for order book queries (price or volume).', required: false },
|
|
112
|
+
{ name: 'is_buy', type: 'boolean', description: 'Side for order book queries (default: true).', required: false },
|
|
113
|
+
// --- Controller ---
|
|
114
|
+
{ name: 'target', type: 'string', description: 'Controller target: "controller" or "config".', required: false },
|
|
115
|
+
{ name: 'controller_type', type: 'string', description: 'Controller type: directional_trading, market_making, generic.', required: false },
|
|
116
|
+
{ name: 'controller_name', type: 'string', description: 'Controller name.', required: false },
|
|
117
|
+
{ name: 'controller_code', type: 'string', description: 'Python code for controller upsert.', required: false },
|
|
118
|
+
{ name: 'config_name', type: 'string', description: 'Config name for controller operations.', required: false },
|
|
119
|
+
{ name: 'config_data', type: 'string', description: 'JSON config data for controller upsert.', required: false },
|
|
120
|
+
{ name: 'confirm_override', type: 'boolean', description: 'Confirm overwrite for controller/connector.', required: false },
|
|
121
|
+
// --- Templates ---
|
|
122
|
+
{ name: 'template', type: 'string', description: 'Strategy template name.', required: false },
|
|
123
|
+
// --- History ---
|
|
124
|
+
{ name: 'limit', type: 'number', description: 'Max results.', required: false },
|
|
125
|
+
{ name: 'offset', type: 'number', description: 'Pagination offset.', required: false },
|
|
126
|
+
{ name: 'status', type: 'string', description: 'Status filter (OPEN, CLOSED, FILLED, CANCELED, RUNNING, TERMINATED, etc).', required: false },
|
|
127
|
+
{ name: 'start_time', type: 'number', description: 'Start time (unix seconds) for history.', required: false },
|
|
128
|
+
{ name: 'end_time', type: 'number', description: 'End time (unix seconds) for history.', required: false },
|
|
129
|
+
// --- Gateway ---
|
|
130
|
+
{ name: 'network', type: 'string', description: 'Network for gateway (e.g. "solana-mainnet-beta").', required: false },
|
|
131
|
+
{ name: 'pool_address', type: 'string', description: 'Pool address for CLMM.', required: false },
|
|
132
|
+
{ name: 'position_address', type: 'string', description: 'Position NFT address for CLMM.', required: false },
|
|
133
|
+
{ name: 'wallet_address', type: 'string', description: 'Wallet address for gateway operations.', required: false },
|
|
134
|
+
{ name: 'slippage_pct', type: 'string', description: 'Slippage tolerance percentage (e.g. "1.0").', required: false },
|
|
135
|
+
{ name: 'lower_price', type: 'string', description: 'Lower price bound for CLMM open_position.', required: false },
|
|
136
|
+
{ name: 'upper_price', type: 'string', description: 'Upper price bound for CLMM open_position.', required: false },
|
|
137
|
+
{ name: 'base_token_amount', type: 'string', description: 'Base token amount for CLMM.', required: false },
|
|
138
|
+
{ name: 'quote_token_amount', type: 'string', description: 'Quote token amount for CLMM.', required: false },
|
|
139
|
+
{ name: 'transaction_hash', type: 'string', description: 'Transaction hash for swap status lookup.', required: false },
|
|
140
|
+
// --- Gateway config ---
|
|
141
|
+
{ name: 'resource_type', type: 'string', description: 'Gateway config resource: chains, networks, tokens, connectors, pools, wallets.', required: false },
|
|
142
|
+
{ name: 'chain', type: 'string', description: 'Blockchain chain name.', required: false },
|
|
143
|
+
{ name: 'private_key', type: 'string', description: 'Private key for wallet operations.', required: false },
|
|
144
|
+
{ name: 'token_address', type: 'string', description: 'Token contract address.', required: false },
|
|
145
|
+
{ name: 'token_symbol', type: 'string', description: 'Token symbol.', required: false },
|
|
146
|
+
{ name: 'token_decimals', type: 'number', description: 'Token decimals.', required: false },
|
|
147
|
+
{ name: 'pool_type', type: 'string', description: 'Pool type: CLMM or AMM.', required: false },
|
|
148
|
+
{ name: 'search', type: 'string', description: 'Search/filter term.', required: false },
|
|
149
|
+
// --- Connector setup ---
|
|
150
|
+
{ name: 'credentials', type: 'string', description: 'JSON credentials for connector setup.', required: false },
|
|
151
|
+
// --- Server config ---
|
|
152
|
+
{ name: 'host', type: 'string', description: 'API server host for servers action.', required: false },
|
|
153
|
+
{ name: 'port', type: 'number', description: 'API server port.', required: false },
|
|
154
|
+
{ name: 'server_name', type: 'string', description: 'Server name for servers action.', required: false },
|
|
155
|
+
// --- Backtesting ---
|
|
156
|
+
{ name: 'config', type: 'string', description: 'Config name or JSON for backtesting.', required: false },
|
|
157
|
+
{ name: 'resolution', type: 'string', description: 'Backtesting resolution (1m, 5m, 1h).', required: false },
|
|
158
|
+
{ name: 'trade_cost', type: 'number', description: 'Trade cost as decimal (0.0006 = 0.06%).', required: false },
|
|
159
|
+
// --- Scripts ---
|
|
160
|
+
{ name: 'script_name', type: 'string', description: 'Script name.', required: false },
|
|
161
|
+
{ name: 'script_content', type: 'string', description: 'Python source code for script upsert.', required: false },
|
|
162
|
+
// --- Rate Oracle ---
|
|
163
|
+
{ name: 'db_path', type: 'string', description: 'Archived bot database path.', required: false },
|
|
164
|
+
// --- Active Orders / Trades ---
|
|
165
|
+
{ name: 'client_order_id', type: 'string', description: 'Client order ID for cancellation.', required: false },
|
|
166
|
+
{ name: 'trade_types', type: 'string', description: 'Comma-separated trade types filter.', required: false },
|
|
167
|
+
{ name: 'verbose', type: 'boolean', description: 'Verbose output for bot history.', required: false },
|
|
168
|
+
{ name: 'run_status', type: 'string', description: 'Bot run status filter.', required: false },
|
|
169
|
+
{ name: 'volume', type: 'number', description: 'Volume for VWAP calculation.', required: false },
|
|
170
|
+
// --- Portfolio ---
|
|
171
|
+
{ name: 'refresh', type: 'boolean', description: 'Force refresh portfolio from exchanges.', required: false },
|
|
172
|
+
{ name: 'as_distribution', type: 'boolean', description: 'Show portfolio as distribution percentages.', required: false },
|
|
173
|
+
{ name: 'include_balances', type: 'boolean', description: 'Include token balances in portfolio.', required: false },
|
|
174
|
+
{ name: 'include_perp_positions', type: 'boolean', description: 'Include perp positions in portfolio.', required: false },
|
|
175
|
+
{ name: 'include_lp_positions', type: 'boolean', description: 'Include LP positions in portfolio.', required: false },
|
|
176
|
+
{ name: 'include_active_orders', type: 'boolean', description: 'Include active orders in portfolio.', required: false },
|
|
177
|
+
// --- Gateway container ---
|
|
178
|
+
{ name: 'passphrase', type: 'string', description: 'Gateway container passphrase.', required: false },
|
|
179
|
+
{ name: 'image', type: 'string', description: 'Docker image for gateway/bot.', required: false },
|
|
180
|
+
{ name: 'tail', type: 'number', description: 'Number of log lines.', required: false },
|
|
181
|
+
],
|
|
182
|
+
execute: async (params, ctx) => {
|
|
183
|
+
try {
|
|
184
|
+
const client = getClient(ctx);
|
|
185
|
+
const action = params.action;
|
|
186
|
+
switch (action) {
|
|
187
|
+
// ================================================================
|
|
188
|
+
// Status
|
|
189
|
+
// ================================================================
|
|
190
|
+
case 'status': {
|
|
191
|
+
const prereqs = await client.checkPrerequisites();
|
|
192
|
+
const dockerInstances = prereqs.docker ? await client.listDockerInstances() : [];
|
|
193
|
+
const lines = [
|
|
194
|
+
'Hummingbot Status:',
|
|
195
|
+
` API Server: ${prereqs.api ? `connected at ${process.env.HUMMINGBOT_API_URL ?? 'localhost:8000'}` : 'NOT CONNECTED'}`,
|
|
196
|
+
` Docker: ${prereqs.docker ? 'available' : 'NOT FOUND'}`,
|
|
197
|
+
` HB Image: ${prereqs.image ? 'installed' : 'not found'}`,
|
|
198
|
+
` MCP Server: ${prereqs.mcp ? 'running' : 'not running'}`,
|
|
199
|
+
];
|
|
200
|
+
if (prereqs.api) {
|
|
201
|
+
lines.push('', 'Full capabilities available: portfolio, order, leverage, executor, market_data, controller, bot, gateway, history, templates, connector, servers');
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
lines.push('', 'Set HUMMINGBOT_API_URL, HUMMINGBOT_USERNAME, HUMMINGBOT_PASSWORD to connect.');
|
|
205
|
+
}
|
|
206
|
+
if (dockerInstances.length > 0) {
|
|
207
|
+
lines.push('', `Docker instances (${dockerInstances.length}):`);
|
|
208
|
+
for (const inst of dockerInstances) {
|
|
209
|
+
lines.push(` ${inst.name}: ${inst.status} (created ${inst.created})`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return { callId: '', success: true, result: lines.join('\n') };
|
|
213
|
+
}
|
|
214
|
+
// ================================================================
|
|
215
|
+
// Portfolio
|
|
216
|
+
// ================================================================
|
|
217
|
+
case 'portfolio': {
|
|
218
|
+
const result = await client.getPortfolioOverview({
|
|
219
|
+
accountNames: splitCsv(params.account_names),
|
|
220
|
+
connectorNames: splitCsv(params.connector_names) ?? (params.connector_name ? [params.connector_name] : undefined),
|
|
221
|
+
includeBalances: params.include_balances ?? true,
|
|
222
|
+
includePerpPositions: params.include_perp_positions ?? true,
|
|
223
|
+
includeLPPositions: params.include_lp_positions ?? true,
|
|
224
|
+
includeActiveOrders: params.include_active_orders ?? true,
|
|
225
|
+
asDistribution: params.as_distribution ?? false,
|
|
226
|
+
refresh: params.refresh ?? true,
|
|
227
|
+
});
|
|
228
|
+
return { callId: '', success: true, result };
|
|
229
|
+
}
|
|
230
|
+
// ================================================================
|
|
231
|
+
// Order
|
|
232
|
+
// ================================================================
|
|
233
|
+
case 'order': {
|
|
234
|
+
const connectorName = params.connector_name;
|
|
235
|
+
const tradingPair = params.trading_pair;
|
|
236
|
+
const side = params.side;
|
|
237
|
+
const amount = params.amount;
|
|
238
|
+
if (!connectorName || !tradingPair || !side || !amount) {
|
|
239
|
+
return {
|
|
240
|
+
callId: '', success: false, result: null,
|
|
241
|
+
error: 'Required: connector_name, trading_pair, side (BUY/SELL), amount.',
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
const result = await client.placeOrder({
|
|
245
|
+
connectorName,
|
|
246
|
+
tradingPair,
|
|
247
|
+
tradeType: side.toUpperCase(),
|
|
248
|
+
amount,
|
|
249
|
+
orderType: params.order_type?.toUpperCase() ?? 'MARKET',
|
|
250
|
+
price: params.price,
|
|
251
|
+
positionAction: params.position_action?.toUpperCase() ?? 'OPEN',
|
|
252
|
+
accountName: params.account_name,
|
|
253
|
+
});
|
|
254
|
+
return {
|
|
255
|
+
callId: '', success: result.success, result: result.result,
|
|
256
|
+
error: result.success ? undefined : result.result,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
// ================================================================
|
|
260
|
+
// Leverage / Position Mode
|
|
261
|
+
// ================================================================
|
|
262
|
+
case 'leverage': {
|
|
263
|
+
const accountName = params.account_name ?? 'master_account';
|
|
264
|
+
const connectorName = params.connector_name;
|
|
265
|
+
if (!connectorName) {
|
|
266
|
+
return { callId: '', success: false, result: null, error: 'connector_name required for leverage.' };
|
|
267
|
+
}
|
|
268
|
+
const result = await client.setPositionModeAndLeverage({
|
|
269
|
+
accountName,
|
|
270
|
+
connectorName,
|
|
271
|
+
tradingPair: params.trading_pair,
|
|
272
|
+
positionMode: params.position_mode?.toUpperCase(),
|
|
273
|
+
leverage: params.leverage,
|
|
274
|
+
});
|
|
275
|
+
return { callId: '', success: true, result };
|
|
276
|
+
}
|
|
277
|
+
// ================================================================
|
|
278
|
+
// Executor
|
|
279
|
+
// ================================================================
|
|
280
|
+
case 'executor': {
|
|
281
|
+
const subAction = params.sub_action ?? 'search';
|
|
282
|
+
switch (subAction) {
|
|
283
|
+
case 'create': {
|
|
284
|
+
const configStr = params.executor_config;
|
|
285
|
+
if (!configStr) {
|
|
286
|
+
const executorType = params.executor_type;
|
|
287
|
+
if (executorType) {
|
|
288
|
+
const result = await client.getExecutorTypeConfig(executorType);
|
|
289
|
+
return { callId: '', success: true, result };
|
|
290
|
+
}
|
|
291
|
+
const result = await client.getExecutorTypes();
|
|
292
|
+
return { callId: '', success: true, result };
|
|
293
|
+
}
|
|
294
|
+
let config;
|
|
295
|
+
try {
|
|
296
|
+
config = JSON.parse(configStr);
|
|
297
|
+
}
|
|
298
|
+
catch {
|
|
299
|
+
return { callId: '', success: false, result: null, error: 'executor_config must be valid JSON.' };
|
|
300
|
+
}
|
|
301
|
+
const result = await client.createExecutor(config);
|
|
302
|
+
return { callId: '', success: true, result };
|
|
303
|
+
}
|
|
304
|
+
case 'search': {
|
|
305
|
+
const result = await client.searchExecutors({
|
|
306
|
+
executorId: params.executor_id,
|
|
307
|
+
executorTypes: params.executor_type ? [params.executor_type] : undefined,
|
|
308
|
+
connectorNames: splitCsv(params.connector_names) ?? (params.connector_name ? [params.connector_name] : undefined),
|
|
309
|
+
tradingPairs: splitCsv(params.trading_pairs) ?? (params.trading_pair ? [params.trading_pair] : undefined),
|
|
310
|
+
status: params.status,
|
|
311
|
+
limit: params.limit ?? 50,
|
|
312
|
+
});
|
|
313
|
+
return { callId: '', success: true, result };
|
|
314
|
+
}
|
|
315
|
+
case 'stop': {
|
|
316
|
+
if (!params.executor_id) {
|
|
317
|
+
return { callId: '', success: false, result: null, error: 'executor_id required to stop.' };
|
|
318
|
+
}
|
|
319
|
+
const result = await client.stopExecutor(params.executor_id, params.keep_position ?? false);
|
|
320
|
+
return { callId: '', success: true, result };
|
|
321
|
+
}
|
|
322
|
+
case 'logs': {
|
|
323
|
+
if (!params.executor_id) {
|
|
324
|
+
return { callId: '', success: false, result: null, error: 'executor_id required for logs.' };
|
|
325
|
+
}
|
|
326
|
+
const result = await client.getExecutorLogs(params.executor_id);
|
|
327
|
+
return { callId: '', success: true, result };
|
|
328
|
+
}
|
|
329
|
+
case 'positions': {
|
|
330
|
+
const result = await client.getPositionsSummary(params.connector_name, params.trading_pair);
|
|
331
|
+
return { callId: '', success: true, result };
|
|
332
|
+
}
|
|
333
|
+
case 'clear_position': {
|
|
334
|
+
if (!params.connector_name || !params.trading_pair) {
|
|
335
|
+
return { callId: '', success: false, result: null, error: 'connector_name and trading_pair required.' };
|
|
336
|
+
}
|
|
337
|
+
const result = await client.clearPosition(params.connector_name, params.trading_pair);
|
|
338
|
+
return { callId: '', success: true, result };
|
|
339
|
+
}
|
|
340
|
+
case 'types': {
|
|
341
|
+
const result = await client.getExecutorTypes();
|
|
342
|
+
return { callId: '', success: true, result };
|
|
343
|
+
}
|
|
344
|
+
case 'type_config': {
|
|
345
|
+
if (!params.executor_type)
|
|
346
|
+
return { callId: '', success: false, result: null, error: 'executor_type required.' };
|
|
347
|
+
const result = await client.getExecutorTypeConfig(params.executor_type);
|
|
348
|
+
return { callId: '', success: true, result };
|
|
349
|
+
}
|
|
350
|
+
case 'summary': {
|
|
351
|
+
const result = await client.getExecutorsSummary();
|
|
352
|
+
return { callId: '', success: true, result };
|
|
353
|
+
}
|
|
354
|
+
case 'get_by_id': {
|
|
355
|
+
if (!params.executor_id)
|
|
356
|
+
return { callId: '', success: false, result: null, error: 'executor_id required.' };
|
|
357
|
+
const result = await client.getExecutorById(params.executor_id);
|
|
358
|
+
return { callId: '', success: true, result };
|
|
359
|
+
}
|
|
360
|
+
default:
|
|
361
|
+
return {
|
|
362
|
+
callId: '', success: false, result: null,
|
|
363
|
+
error: `Unknown executor sub_action: "${subAction}". Use: create, search, stop, logs, positions, clear_position, types, type_config, summary, get_by_id.`,
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
// ================================================================
|
|
368
|
+
// Market Data
|
|
369
|
+
// ================================================================
|
|
370
|
+
case 'market_data': {
|
|
371
|
+
const subAction = params.sub_action ?? 'prices';
|
|
372
|
+
const connectorName = params.connector_name;
|
|
373
|
+
if (!connectorName) {
|
|
374
|
+
return { callId: '', success: false, result: null, error: 'connector_name required for market_data.' };
|
|
375
|
+
}
|
|
376
|
+
switch (subAction) {
|
|
377
|
+
case 'prices': {
|
|
378
|
+
const pairs = splitCsv(params.trading_pairs) ?? splitCsv(params.trading_pair) ?? [];
|
|
379
|
+
if (pairs.length === 0) {
|
|
380
|
+
return { callId: '', success: false, result: null, error: 'trading_pairs or trading_pair required.' };
|
|
381
|
+
}
|
|
382
|
+
const result = await client.getPrices(connectorName, pairs);
|
|
383
|
+
return { callId: '', success: true, result };
|
|
384
|
+
}
|
|
385
|
+
case 'candles': {
|
|
386
|
+
if (!params.trading_pair) {
|
|
387
|
+
return { callId: '', success: false, result: null, error: 'trading_pair required for candles.' };
|
|
388
|
+
}
|
|
389
|
+
const result = await client.getCandles(connectorName, params.trading_pair, params.interval ?? '1h', params.days ?? 30);
|
|
390
|
+
return { callId: '', success: true, result };
|
|
391
|
+
}
|
|
392
|
+
case 'funding': {
|
|
393
|
+
if (!params.trading_pair) {
|
|
394
|
+
return { callId: '', success: false, result: null, error: 'trading_pair required for funding.' };
|
|
395
|
+
}
|
|
396
|
+
const result = await client.getFundingRate(connectorName, params.trading_pair);
|
|
397
|
+
return { callId: '', success: true, result };
|
|
398
|
+
}
|
|
399
|
+
case 'orderbook': {
|
|
400
|
+
if (!params.trading_pair) {
|
|
401
|
+
return { callId: '', success: false, result: null, error: 'trading_pair required for orderbook.' };
|
|
402
|
+
}
|
|
403
|
+
const result = await client.getOrderBook(connectorName, params.trading_pair, params.query_type ?? 'snapshot', params.query_value, params.is_buy ?? true);
|
|
404
|
+
return { callId: '', success: true, result };
|
|
405
|
+
}
|
|
406
|
+
case 'historical_candles': {
|
|
407
|
+
if (!params.trading_pair)
|
|
408
|
+
return { callId: '', success: false, result: null, error: 'trading_pair required.' };
|
|
409
|
+
if (!params.start_time || !params.end_time)
|
|
410
|
+
return { callId: '', success: false, result: null, error: 'start_time and end_time required.' };
|
|
411
|
+
const result = await client.getHistoricalCandles({
|
|
412
|
+
connectorName,
|
|
413
|
+
tradingPair: params.trading_pair,
|
|
414
|
+
interval: params.interval ?? '1h',
|
|
415
|
+
startTime: params.start_time,
|
|
416
|
+
endTime: params.end_time,
|
|
417
|
+
});
|
|
418
|
+
return { callId: '', success: true, result };
|
|
419
|
+
}
|
|
420
|
+
case 'vwap': {
|
|
421
|
+
if (!params.trading_pair)
|
|
422
|
+
return { callId: '', success: false, result: null, error: 'trading_pair required.' };
|
|
423
|
+
if (!params.volume)
|
|
424
|
+
return { callId: '', success: false, result: null, error: 'volume required for VWAP.' };
|
|
425
|
+
const result = await client.getVWAP(connectorName, params.trading_pair, params.is_buy ?? true, params.volume);
|
|
426
|
+
return { callId: '', success: true, result };
|
|
427
|
+
}
|
|
428
|
+
case 'add_pair': {
|
|
429
|
+
if (!params.trading_pair)
|
|
430
|
+
return { callId: '', success: false, result: null, error: 'trading_pair required.' };
|
|
431
|
+
const result = await client.addTradingPair(connectorName, params.trading_pair, params.account_name);
|
|
432
|
+
return { callId: '', success: true, result };
|
|
433
|
+
}
|
|
434
|
+
case 'remove_pair': {
|
|
435
|
+
if (!params.trading_pair)
|
|
436
|
+
return { callId: '', success: false, result: null, error: 'trading_pair required.' };
|
|
437
|
+
const result = await client.removeTradingPair(connectorName, params.trading_pair, params.account_name);
|
|
438
|
+
return { callId: '', success: true, result };
|
|
439
|
+
}
|
|
440
|
+
default:
|
|
441
|
+
return {
|
|
442
|
+
callId: '', success: false, result: null,
|
|
443
|
+
error: `Unknown market_data sub_action: "${subAction}". Use: prices, candles, historical_candles, funding, orderbook, vwap, add_pair, remove_pair.`,
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
// ================================================================
|
|
448
|
+
// Controller management
|
|
449
|
+
// ================================================================
|
|
450
|
+
case 'controller': {
|
|
451
|
+
const subAction = params.sub_action ?? 'list';
|
|
452
|
+
const target = params.target ?? 'controller';
|
|
453
|
+
switch (subAction) {
|
|
454
|
+
case 'list': {
|
|
455
|
+
if (target === 'config') {
|
|
456
|
+
const result = await client.listControllerConfigs();
|
|
457
|
+
return { callId: '', success: true, result };
|
|
458
|
+
}
|
|
459
|
+
const result = await client.listControllers(params.controller_type);
|
|
460
|
+
return { callId: '', success: true, result };
|
|
461
|
+
}
|
|
462
|
+
case 'describe': {
|
|
463
|
+
if (target === 'config' && params.config_name) {
|
|
464
|
+
const result = await client.getControllerConfig(params.config_name);
|
|
465
|
+
return { callId: '', success: true, result };
|
|
466
|
+
}
|
|
467
|
+
if (!params.controller_name) {
|
|
468
|
+
return { callId: '', success: false, result: null, error: 'controller_name required.' };
|
|
469
|
+
}
|
|
470
|
+
const result = await client.getController(params.controller_name);
|
|
471
|
+
return { callId: '', success: true, result };
|
|
472
|
+
}
|
|
473
|
+
case 'upsert': {
|
|
474
|
+
if (target === 'config') {
|
|
475
|
+
if (!params.config_name || !params.config_data) {
|
|
476
|
+
return { callId: '', success: false, result: null, error: 'config_name and config_data required.' };
|
|
477
|
+
}
|
|
478
|
+
let configData;
|
|
479
|
+
try {
|
|
480
|
+
configData = JSON.parse(params.config_data);
|
|
481
|
+
}
|
|
482
|
+
catch {
|
|
483
|
+
return { callId: '', success: false, result: null, error: 'config_data must be valid JSON.' };
|
|
484
|
+
}
|
|
485
|
+
const result = await client.upsertControllerConfig(params.config_name, configData);
|
|
486
|
+
return { callId: '', success: true, result };
|
|
487
|
+
}
|
|
488
|
+
if (!params.controller_name) {
|
|
489
|
+
return { callId: '', success: false, result: null, error: 'controller_name required.' };
|
|
490
|
+
}
|
|
491
|
+
const result = await client.upsertController(params.controller_name, {
|
|
492
|
+
controllerType: params.controller_type,
|
|
493
|
+
controllerCode: params.controller_code,
|
|
494
|
+
});
|
|
495
|
+
return { callId: '', success: true, result };
|
|
496
|
+
}
|
|
497
|
+
case 'delete': {
|
|
498
|
+
if (target === 'config' && params.config_name) {
|
|
499
|
+
const result = await client.deleteControllerConfig(params.config_name);
|
|
500
|
+
return { callId: '', success: true, result };
|
|
501
|
+
}
|
|
502
|
+
if (!params.controller_name) {
|
|
503
|
+
return { callId: '', success: false, result: null, error: 'controller_name required.' };
|
|
504
|
+
}
|
|
505
|
+
const result = await client.deleteController(params.controller_name);
|
|
506
|
+
return { callId: '', success: true, result };
|
|
507
|
+
}
|
|
508
|
+
default:
|
|
509
|
+
return { callId: '', success: false, result: null, error: `Unknown controller sub_action: "${subAction}". Use: list, describe, upsert, delete.` };
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
// ================================================================
|
|
513
|
+
// Bot management
|
|
514
|
+
// ================================================================
|
|
515
|
+
case 'bot': {
|
|
516
|
+
const subAction = params.sub_action ?? 'status';
|
|
517
|
+
switch (subAction) {
|
|
518
|
+
case 'deploy': {
|
|
519
|
+
const botName = params.bot_name;
|
|
520
|
+
const configsStr = params.controllers_config;
|
|
521
|
+
if (!botName || !configsStr) {
|
|
522
|
+
return { callId: '', success: false, result: null, error: 'bot_name and controllers_config required.' };
|
|
523
|
+
}
|
|
524
|
+
const result = await client.deployBot({
|
|
525
|
+
botName,
|
|
526
|
+
controllersConfig: configsStr.split(',').map(s => s.trim()),
|
|
527
|
+
accountName: params.account_name,
|
|
528
|
+
image: params.image,
|
|
529
|
+
});
|
|
530
|
+
return { callId: '', success: true, result };
|
|
531
|
+
}
|
|
532
|
+
case 'status': {
|
|
533
|
+
const result = await client.getBotsStatus();
|
|
534
|
+
return { callId: '', success: true, result };
|
|
535
|
+
}
|
|
536
|
+
case 'logs': {
|
|
537
|
+
if (!params.bot_name) {
|
|
538
|
+
return { callId: '', success: false, result: null, error: 'bot_name required.' };
|
|
539
|
+
}
|
|
540
|
+
const result = await client.getBotLogs({
|
|
541
|
+
botName: params.bot_name,
|
|
542
|
+
limit: params.limit ?? 50,
|
|
543
|
+
searchTerm: params.search,
|
|
544
|
+
});
|
|
545
|
+
return { callId: '', success: true, result };
|
|
546
|
+
}
|
|
547
|
+
case 'stop': {
|
|
548
|
+
if (!params.bot_name) {
|
|
549
|
+
return { callId: '', success: false, result: null, error: 'bot_name required.' };
|
|
550
|
+
}
|
|
551
|
+
const result = await client.stopBot(params.bot_name);
|
|
552
|
+
return { callId: '', success: true, result };
|
|
553
|
+
}
|
|
554
|
+
case 'stop_controllers':
|
|
555
|
+
case 'start_controllers': {
|
|
556
|
+
if (!params.bot_name || !params.controllers_config) {
|
|
557
|
+
return { callId: '', success: false, result: null, error: 'bot_name and controllers_config required.' };
|
|
558
|
+
}
|
|
559
|
+
const names = params.controllers_config.split(',').map(s => s.trim());
|
|
560
|
+
const result = subAction === 'stop_controllers'
|
|
561
|
+
? await client.stopControllers(params.bot_name, names)
|
|
562
|
+
: await client.startControllers(params.bot_name, names);
|
|
563
|
+
return { callId: '', success: true, result };
|
|
564
|
+
}
|
|
565
|
+
case 'history': {
|
|
566
|
+
const name = params.bot_name;
|
|
567
|
+
if (!name)
|
|
568
|
+
return { callId: '', success: false, result: null, error: 'bot_name required.' };
|
|
569
|
+
const result = await client.getBotHistory(name, params.days ?? 0, params.verbose ?? false);
|
|
570
|
+
return { callId: '', success: true, result };
|
|
571
|
+
}
|
|
572
|
+
case 'runs': {
|
|
573
|
+
const result = await client.getBotRuns({
|
|
574
|
+
botName: params.bot_name,
|
|
575
|
+
accountName: params.account_name,
|
|
576
|
+
runStatus: params.run_status,
|
|
577
|
+
limit: params.limit,
|
|
578
|
+
offset: params.offset,
|
|
579
|
+
});
|
|
580
|
+
return { callId: '', success: true, result };
|
|
581
|
+
}
|
|
582
|
+
case 'archive': {
|
|
583
|
+
const name = params.bot_name;
|
|
584
|
+
if (!name)
|
|
585
|
+
return { callId: '', success: false, result: null, error: 'bot_name required.' };
|
|
586
|
+
const result = await client.archiveBot(name);
|
|
587
|
+
return { callId: '', success: true, result };
|
|
588
|
+
}
|
|
589
|
+
default:
|
|
590
|
+
return {
|
|
591
|
+
callId: '', success: false, result: null,
|
|
592
|
+
error: `Unknown bot sub_action: "${subAction}". Use: deploy, status, logs, stop, stop_controllers, start_controllers, history, runs, archive.`,
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
// ================================================================
|
|
597
|
+
// Gateway: container, config, swaps, CLMM
|
|
598
|
+
// ================================================================
|
|
599
|
+
case 'gateway': {
|
|
600
|
+
const subAction = params.sub_action ?? 'container_status';
|
|
601
|
+
// --- Container lifecycle ---
|
|
602
|
+
if (subAction === 'container_status') {
|
|
603
|
+
const result = await client.getGatewayStatus();
|
|
604
|
+
return { callId: '', success: true, result };
|
|
605
|
+
}
|
|
606
|
+
if (subAction === 'container_start') {
|
|
607
|
+
const result = await client.startGateway({
|
|
608
|
+
passphrase: params.passphrase ?? 'clawnch',
|
|
609
|
+
image: params.image ?? 'hummingbot/gateway:latest',
|
|
610
|
+
port: params.port,
|
|
611
|
+
environment: undefined,
|
|
612
|
+
});
|
|
613
|
+
return { callId: '', success: true, result };
|
|
614
|
+
}
|
|
615
|
+
if (subAction === 'container_stop') {
|
|
616
|
+
const result = await client.stopGateway();
|
|
617
|
+
return { callId: '', success: true, result };
|
|
618
|
+
}
|
|
619
|
+
if (subAction === 'container_logs') {
|
|
620
|
+
const result = await client.getGatewayLogs(params.tail);
|
|
621
|
+
return { callId: '', success: true, result };
|
|
622
|
+
}
|
|
623
|
+
// --- Gateway config ---
|
|
624
|
+
if (subAction === 'config_chains') {
|
|
625
|
+
const result = await client.listGatewayChains();
|
|
626
|
+
return { callId: '', success: true, result };
|
|
627
|
+
}
|
|
628
|
+
if (subAction === 'config_networks') {
|
|
629
|
+
const result = await client.listGatewayNetworks(params.chain);
|
|
630
|
+
return { callId: '', success: true, result };
|
|
631
|
+
}
|
|
632
|
+
if (subAction === 'config_connectors') {
|
|
633
|
+
const result = await client.listGatewayConnectors();
|
|
634
|
+
return { callId: '', success: true, result };
|
|
635
|
+
}
|
|
636
|
+
if (subAction === 'config_tokens') {
|
|
637
|
+
const result = await client.listGatewayTokens(params.chain, params.network, params.search);
|
|
638
|
+
return { callId: '', success: true, result };
|
|
639
|
+
}
|
|
640
|
+
if (subAction === 'config_wallets') {
|
|
641
|
+
const result = await client.listGatewayWallets(params.chain);
|
|
642
|
+
return { callId: '', success: true, result };
|
|
643
|
+
}
|
|
644
|
+
if (subAction === 'config_add_token') {
|
|
645
|
+
const result = await client.addGatewayToken({
|
|
646
|
+
chain: params.chain,
|
|
647
|
+
network: params.network,
|
|
648
|
+
tokenAddress: params.token_address,
|
|
649
|
+
tokenSymbol: params.token_symbol,
|
|
650
|
+
tokenDecimals: params.token_decimals,
|
|
651
|
+
tokenName: params.token_name,
|
|
652
|
+
});
|
|
653
|
+
return { callId: '', success: true, result };
|
|
654
|
+
}
|
|
655
|
+
if (subAction === 'config_add_wallet') {
|
|
656
|
+
const result = await client.addGatewayWallet(params.chain, params.private_key);
|
|
657
|
+
return { callId: '', success: true, result };
|
|
658
|
+
}
|
|
659
|
+
// --- Swaps ---
|
|
660
|
+
if (subAction === 'swap_quote') {
|
|
661
|
+
const result = await client.getGatewayAmmPrice({
|
|
662
|
+
connector: params.connector_name,
|
|
663
|
+
chain: params.chain,
|
|
664
|
+
network: params.network,
|
|
665
|
+
tradingPair: params.trading_pair,
|
|
666
|
+
side: params.side?.toUpperCase(),
|
|
667
|
+
amount: params.amount,
|
|
668
|
+
});
|
|
669
|
+
return { callId: '', success: true, result };
|
|
670
|
+
}
|
|
671
|
+
if (subAction === 'swap_execute') {
|
|
672
|
+
const result = await client.executeGatewayAmmTrade({
|
|
673
|
+
connector: params.connector_name,
|
|
674
|
+
chain: params.chain,
|
|
675
|
+
network: params.network,
|
|
676
|
+
tradingPair: params.trading_pair,
|
|
677
|
+
side: params.side?.toUpperCase(),
|
|
678
|
+
amount: params.amount,
|
|
679
|
+
slippagePct: params.slippage_pct,
|
|
680
|
+
walletAddress: params.wallet_address ?? ctx.identity.address,
|
|
681
|
+
});
|
|
682
|
+
return { callId: '', success: true, result };
|
|
683
|
+
}
|
|
684
|
+
// --- CLMM ---
|
|
685
|
+
if (subAction === 'clmm_list') {
|
|
686
|
+
const result = await client.listCLMMPools({
|
|
687
|
+
connector: params.connector_name,
|
|
688
|
+
chain: params.chain,
|
|
689
|
+
network: params.network,
|
|
690
|
+
limit: params.limit ?? 50,
|
|
691
|
+
searchTerm: params.search,
|
|
692
|
+
});
|
|
693
|
+
return { callId: '', success: true, result };
|
|
694
|
+
}
|
|
695
|
+
if (subAction === 'clmm_info') {
|
|
696
|
+
const result = await client.getCLMMPoolInfo({
|
|
697
|
+
connector: params.connector_name,
|
|
698
|
+
chain: params.chain,
|
|
699
|
+
network: params.network,
|
|
700
|
+
poolAddress: params.pool_address,
|
|
701
|
+
});
|
|
702
|
+
return { callId: '', success: true, result };
|
|
703
|
+
}
|
|
704
|
+
if (subAction === 'clmm_positions') {
|
|
705
|
+
const result = await client.getCLMMPositions({
|
|
706
|
+
connector: params.connector_name,
|
|
707
|
+
chain: params.chain,
|
|
708
|
+
network: params.network,
|
|
709
|
+
walletAddress: params.wallet_address ?? ctx.identity.address,
|
|
710
|
+
poolAddress: params.pool_address,
|
|
711
|
+
});
|
|
712
|
+
return { callId: '', success: true, result };
|
|
713
|
+
}
|
|
714
|
+
if (subAction === 'clmm_open') {
|
|
715
|
+
const result = await client.addCLMMLiquidity({
|
|
716
|
+
connector: params.connector_name,
|
|
717
|
+
chain: params.chain,
|
|
718
|
+
network: params.network,
|
|
719
|
+
poolAddress: params.pool_address,
|
|
720
|
+
walletAddress: params.wallet_address ?? ctx.identity.address,
|
|
721
|
+
lowerPrice: params.lower_price,
|
|
722
|
+
upperPrice: params.upper_price,
|
|
723
|
+
baseTokenAmount: params.base_token_amount,
|
|
724
|
+
quoteTokenAmount: params.quote_token_amount,
|
|
725
|
+
slippagePct: params.slippage_pct,
|
|
726
|
+
});
|
|
727
|
+
return { callId: '', success: true, result };
|
|
728
|
+
}
|
|
729
|
+
if (subAction === 'clmm_close') {
|
|
730
|
+
const result = await client.removeCLMMLiquidity({
|
|
731
|
+
connector: params.connector_name,
|
|
732
|
+
chain: params.chain,
|
|
733
|
+
network: params.network,
|
|
734
|
+
positionAddress: params.position_address,
|
|
735
|
+
walletAddress: params.wallet_address ?? ctx.identity.address,
|
|
736
|
+
slippagePct: params.slippage_pct,
|
|
737
|
+
});
|
|
738
|
+
return { callId: '', success: true, result };
|
|
739
|
+
}
|
|
740
|
+
return {
|
|
741
|
+
callId: '', success: false, result: null,
|
|
742
|
+
error: `Unknown gateway sub_action: "${subAction}". Prefixes: container_, config_, swap_, clmm_.`,
|
|
743
|
+
};
|
|
744
|
+
}
|
|
745
|
+
// ================================================================
|
|
746
|
+
// History
|
|
747
|
+
// ================================================================
|
|
748
|
+
case 'history': {
|
|
749
|
+
const dataType = params.sub_action ?? 'orders';
|
|
750
|
+
const validTypes = ['orders', 'perp_positions', 'clmm_positions'];
|
|
751
|
+
if (!validTypes.includes(dataType)) {
|
|
752
|
+
return {
|
|
753
|
+
callId: '', success: false, result: null,
|
|
754
|
+
error: `Invalid history sub_action: "${dataType}". Use: orders, perp_positions, clmm_positions.`,
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
const result = await client.searchHistory({
|
|
758
|
+
dataType: dataType,
|
|
759
|
+
accountNames: splitCsv(params.account_names),
|
|
760
|
+
connectorNames: splitCsv(params.connector_names) ?? (params.connector_name ? [params.connector_name] : undefined),
|
|
761
|
+
tradingPairs: splitCsv(params.trading_pairs) ?? (params.trading_pair ? [params.trading_pair] : undefined),
|
|
762
|
+
status: params.status,
|
|
763
|
+
startTime: params.start_time,
|
|
764
|
+
endTime: params.end_time,
|
|
765
|
+
limit: params.limit ?? 50,
|
|
766
|
+
offset: params.offset ?? 0,
|
|
767
|
+
network: params.network,
|
|
768
|
+
walletAddress: params.wallet_address,
|
|
769
|
+
});
|
|
770
|
+
return { callId: '', success: true, result };
|
|
771
|
+
}
|
|
772
|
+
// ================================================================
|
|
773
|
+
// Templates
|
|
774
|
+
// ================================================================
|
|
775
|
+
case 'templates': {
|
|
776
|
+
const subAction = params.sub_action ?? 'list';
|
|
777
|
+
if (subAction === 'list') {
|
|
778
|
+
const templates = client.getStrategyTemplates();
|
|
779
|
+
const clawnchTemplates = templates.filter((t) => t.template.startsWith('clawnch_'));
|
|
780
|
+
const genericTemplates = templates.filter((t) => !t.template.startsWith('clawnch_'));
|
|
781
|
+
const lines = [
|
|
782
|
+
'Clawnch Token Strategy Templates:',
|
|
783
|
+
...clawnchTemplates.map((t) => ` ${t.template}: ${t.description} (executor: ${t.executorType})`),
|
|
784
|
+
'',
|
|
785
|
+
'Generic Strategy Templates:',
|
|
786
|
+
...genericTemplates.map((t) => ` ${t.template}: ${t.description} (executor: ${t.executorType})`),
|
|
787
|
+
'', 'Use sub_action="describe" with template to see details, or sub_action="build" to create.',
|
|
788
|
+
];
|
|
789
|
+
return { callId: '', success: true, result: lines.join('\n') };
|
|
790
|
+
}
|
|
791
|
+
if (subAction === 'describe') {
|
|
792
|
+
if (!params.template) {
|
|
793
|
+
return { callId: '', success: false, result: null, error: 'template parameter required.' };
|
|
794
|
+
}
|
|
795
|
+
const tmpl = client.getStrategyTemplate(params.template);
|
|
796
|
+
if (!tmpl) {
|
|
797
|
+
return { callId: '', success: false, result: null, error: `Unknown template: ${params.template}` };
|
|
798
|
+
}
|
|
799
|
+
return {
|
|
800
|
+
callId: '', success: true,
|
|
801
|
+
result: `Template: ${tmpl.template}\nDescription: ${tmpl.description}\nExecutor Type: ${tmpl.executorType}\nDefaults: ${JSON.stringify(tmpl.defaultConfig, null, 2)}\nRequired: ${tmpl.requiredOverrides.join(', ')}`,
|
|
802
|
+
};
|
|
803
|
+
}
|
|
804
|
+
if (subAction === 'build') {
|
|
805
|
+
if (!params.template)
|
|
806
|
+
return { callId: '', success: false, result: null, error: 'template required.' };
|
|
807
|
+
if (!params.executor_config)
|
|
808
|
+
return { callId: '', success: false, result: null, error: 'executor_config (JSON) required.' };
|
|
809
|
+
let overrides;
|
|
810
|
+
try {
|
|
811
|
+
overrides = JSON.parse(params.executor_config);
|
|
812
|
+
}
|
|
813
|
+
catch {
|
|
814
|
+
return { callId: '', success: false, result: null, error: 'executor_config must be valid JSON.' };
|
|
815
|
+
}
|
|
816
|
+
const config = client.buildFromTemplate(params.template, overrides);
|
|
817
|
+
const result = await client.createExecutor(config);
|
|
818
|
+
return { callId: '', success: true, result };
|
|
819
|
+
}
|
|
820
|
+
return { callId: '', success: false, result: null, error: `Unknown templates sub_action: "${subAction}". Use: list, describe, build.` };
|
|
821
|
+
}
|
|
822
|
+
// ================================================================
|
|
823
|
+
// Connector setup
|
|
824
|
+
// ================================================================
|
|
825
|
+
case 'connector': {
|
|
826
|
+
const subAction = params.sub_action ?? 'list';
|
|
827
|
+
if (subAction === 'list') {
|
|
828
|
+
const result = await client.listConnectors();
|
|
829
|
+
return { callId: '', success: true, result };
|
|
830
|
+
}
|
|
831
|
+
if (subAction === 'config_map') {
|
|
832
|
+
if (!params.connector_name) {
|
|
833
|
+
return { callId: '', success: false, result: null, error: 'connector_name required.' };
|
|
834
|
+
}
|
|
835
|
+
const result = await client.getConnectorConfigMap(params.connector_name);
|
|
836
|
+
return { callId: '', success: true, result };
|
|
837
|
+
}
|
|
838
|
+
if (subAction === 'setup') {
|
|
839
|
+
if (!params.connector_name || !params.credentials) {
|
|
840
|
+
return { callId: '', success: false, result: null, error: 'connector_name and credentials (JSON) required.' };
|
|
841
|
+
}
|
|
842
|
+
let creds;
|
|
843
|
+
try {
|
|
844
|
+
creds = JSON.parse(params.credentials);
|
|
845
|
+
}
|
|
846
|
+
catch {
|
|
847
|
+
return { callId: '', success: false, result: null, error: 'credentials must be valid JSON.' };
|
|
848
|
+
}
|
|
849
|
+
const accountName = params.account_name ?? 'master_account';
|
|
850
|
+
const result = await client.addConnector(accountName, params.connector_name, creds);
|
|
851
|
+
return { callId: '', success: true, result };
|
|
852
|
+
}
|
|
853
|
+
if (subAction === 'trading_rules') {
|
|
854
|
+
if (!params.connector_name) {
|
|
855
|
+
return { callId: '', success: false, result: null, error: 'connector_name required.' };
|
|
856
|
+
}
|
|
857
|
+
const tradingPairs = params.trading_pair ? [params.trading_pair] : undefined;
|
|
858
|
+
const result = await client.getTradingRules(params.connector_name, tradingPairs);
|
|
859
|
+
return { callId: '', success: true, result };
|
|
860
|
+
}
|
|
861
|
+
if (subAction === 'order_types') {
|
|
862
|
+
if (!params.connector_name) {
|
|
863
|
+
return { callId: '', success: false, result: null, error: 'connector_name required.' };
|
|
864
|
+
}
|
|
865
|
+
const result = await client.getOrderTypes(params.connector_name);
|
|
866
|
+
return { callId: '', success: true, result };
|
|
867
|
+
}
|
|
868
|
+
return { callId: '', success: false, result: null, error: `Unknown connector sub_action: "${subAction}". Use: list, config_map, setup, trading_rules, order_types.` };
|
|
869
|
+
}
|
|
870
|
+
// ================================================================
|
|
871
|
+
// Backtesting
|
|
872
|
+
// ================================================================
|
|
873
|
+
case 'backtest': {
|
|
874
|
+
let config = params.config;
|
|
875
|
+
try {
|
|
876
|
+
config = JSON.parse(config);
|
|
877
|
+
}
|
|
878
|
+
catch { /* keep as string (config name) */ }
|
|
879
|
+
const result = await client.runBacktest({
|
|
880
|
+
config,
|
|
881
|
+
startTime: params.start_time,
|
|
882
|
+
endTime: params.end_time,
|
|
883
|
+
resolution: params.resolution,
|
|
884
|
+
tradeCost: params.trade_cost,
|
|
885
|
+
});
|
|
886
|
+
return { callId: '', success: true, result };
|
|
887
|
+
}
|
|
888
|
+
// ================================================================
|
|
889
|
+
// Connector / Market Discovery
|
|
890
|
+
// ================================================================
|
|
891
|
+
case 'discovery': {
|
|
892
|
+
const subAction = params.sub_action;
|
|
893
|
+
if (subAction === 'connectors' || !subAction) {
|
|
894
|
+
const result = await client.listConnectors();
|
|
895
|
+
return { callId: '', success: true, result };
|
|
896
|
+
}
|
|
897
|
+
if (subAction === 'config_map') {
|
|
898
|
+
const result = await client.getConnectorConfigMap(params.connector_name);
|
|
899
|
+
return { callId: '', success: true, result };
|
|
900
|
+
}
|
|
901
|
+
if (subAction === 'trading_rules') {
|
|
902
|
+
const result = await client.getTradingRules(params.connector_name, splitCsv(params.trading_pairs));
|
|
903
|
+
return { callId: '', success: true, result };
|
|
904
|
+
}
|
|
905
|
+
if (subAction === 'order_types') {
|
|
906
|
+
const result = await client.getOrderTypes(params.connector_name);
|
|
907
|
+
return { callId: '', success: true, result };
|
|
908
|
+
}
|
|
909
|
+
return { callId: '', success: false, result: null, error: `Unknown discovery sub_action: "${subAction}". Use: connectors, config_map, trading_rules, order_types.` };
|
|
910
|
+
}
|
|
911
|
+
// ================================================================
|
|
912
|
+
// Archived Bot Analytics
|
|
913
|
+
// ================================================================
|
|
914
|
+
case 'archived': {
|
|
915
|
+
const subAction = params.sub_action;
|
|
916
|
+
if (subAction === 'list' || !subAction) {
|
|
917
|
+
const result = await client.listArchivedBots();
|
|
918
|
+
return { callId: '', success: true, result };
|
|
919
|
+
}
|
|
920
|
+
const dbPath = params.db_path;
|
|
921
|
+
if (!dbPath)
|
|
922
|
+
return { callId: '', success: false, result: null, error: 'db_path required for archived bot queries.' };
|
|
923
|
+
if (subAction === 'summary') {
|
|
924
|
+
const result = await client.getArchivedBotSummary(dbPath);
|
|
925
|
+
return { callId: '', success: true, result };
|
|
926
|
+
}
|
|
927
|
+
if (subAction === 'performance') {
|
|
928
|
+
const result = await client.getArchivedBotPerformance(dbPath);
|
|
929
|
+
return { callId: '', success: true, result };
|
|
930
|
+
}
|
|
931
|
+
if (subAction === 'trades') {
|
|
932
|
+
const result = await client.getArchivedBotTrades(dbPath, params.limit ?? 100, params.offset ?? 0);
|
|
933
|
+
return { callId: '', success: true, result };
|
|
934
|
+
}
|
|
935
|
+
if (subAction === 'orders') {
|
|
936
|
+
const result = await client.getArchivedBotOrders(dbPath, params.limit ?? 100, params.offset ?? 0, params.status);
|
|
937
|
+
return { callId: '', success: true, result };
|
|
938
|
+
}
|
|
939
|
+
return { callId: '', success: false, result: null, error: `Unknown archived sub_action: "${subAction}". Use: list, summary, performance, trades, orders.` };
|
|
940
|
+
}
|
|
941
|
+
// ================================================================
|
|
942
|
+
// Script Management
|
|
943
|
+
// ================================================================
|
|
944
|
+
case 'scripts': {
|
|
945
|
+
const subAction = params.sub_action;
|
|
946
|
+
if (subAction === 'list' || !subAction) {
|
|
947
|
+
const result = await client.listScripts();
|
|
948
|
+
return { callId: '', success: true, result };
|
|
949
|
+
}
|
|
950
|
+
if (subAction === 'get') {
|
|
951
|
+
const result = await client.getScript(params.script_name);
|
|
952
|
+
return { callId: '', success: true, result };
|
|
953
|
+
}
|
|
954
|
+
if (subAction === 'upsert') {
|
|
955
|
+
const result = await client.upsertScript(params.script_name, params.script_content);
|
|
956
|
+
return { callId: '', success: true, result };
|
|
957
|
+
}
|
|
958
|
+
if (subAction === 'delete') {
|
|
959
|
+
const result = await client.deleteScript(params.script_name);
|
|
960
|
+
return { callId: '', success: true, result };
|
|
961
|
+
}
|
|
962
|
+
if (subAction === 'configs') {
|
|
963
|
+
const result = await client.listScriptConfigs();
|
|
964
|
+
return { callId: '', success: true, result };
|
|
965
|
+
}
|
|
966
|
+
if (subAction === 'get_config') {
|
|
967
|
+
const result = await client.getScriptConfig(params.config_name);
|
|
968
|
+
return { callId: '', success: true, result };
|
|
969
|
+
}
|
|
970
|
+
if (subAction === 'upsert_config') {
|
|
971
|
+
let data;
|
|
972
|
+
try {
|
|
973
|
+
data = JSON.parse(params.config_data);
|
|
974
|
+
}
|
|
975
|
+
catch {
|
|
976
|
+
return { callId: '', success: false, result: null, error: 'config_data must be valid JSON.' };
|
|
977
|
+
}
|
|
978
|
+
const result = await client.upsertScriptConfig(params.config_name, data);
|
|
979
|
+
return { callId: '', success: true, result };
|
|
980
|
+
}
|
|
981
|
+
if (subAction === 'delete_config') {
|
|
982
|
+
const result = await client.deleteScriptConfig(params.config_name);
|
|
983
|
+
return { callId: '', success: true, result };
|
|
984
|
+
}
|
|
985
|
+
if (subAction === 'template') {
|
|
986
|
+
const result = await client.getScriptConfigTemplate(params.script_name);
|
|
987
|
+
return { callId: '', success: true, result };
|
|
988
|
+
}
|
|
989
|
+
return { callId: '', success: false, result: null, error: `Unknown scripts sub_action: "${subAction}". Use: list, get, upsert, delete, configs, get_config, upsert_config, delete_config, template.` };
|
|
990
|
+
}
|
|
991
|
+
// ================================================================
|
|
992
|
+
// Portfolio Analytics & Rate Oracle
|
|
993
|
+
// ================================================================
|
|
994
|
+
case 'analytics': {
|
|
995
|
+
const subAction = params.sub_action;
|
|
996
|
+
if (subAction === 'history') {
|
|
997
|
+
const result = await client.getPortfolioHistory({
|
|
998
|
+
accountNames: splitCsv(params.account_names),
|
|
999
|
+
connectorNames: splitCsv(params.connector_names),
|
|
1000
|
+
startTime: params.start_time,
|
|
1001
|
+
endTime: params.end_time,
|
|
1002
|
+
interval: params.interval,
|
|
1003
|
+
limit: params.limit,
|
|
1004
|
+
});
|
|
1005
|
+
return { callId: '', success: true, result };
|
|
1006
|
+
}
|
|
1007
|
+
if (subAction === 'distribution') {
|
|
1008
|
+
const result = await client.getPortfolioDistribution({
|
|
1009
|
+
accountNames: splitCsv(params.account_names),
|
|
1010
|
+
connectorNames: splitCsv(params.connector_names),
|
|
1011
|
+
});
|
|
1012
|
+
return { callId: '', success: true, result };
|
|
1013
|
+
}
|
|
1014
|
+
if (subAction === 'accounts_distribution') {
|
|
1015
|
+
const result = await client.getAccountsDistribution();
|
|
1016
|
+
return { callId: '', success: true, result };
|
|
1017
|
+
}
|
|
1018
|
+
if (subAction === 'funding_payments') {
|
|
1019
|
+
const result = await client.getFundingPayments({
|
|
1020
|
+
accountNames: splitCsv(params.account_names),
|
|
1021
|
+
connectorNames: splitCsv(params.connector_names),
|
|
1022
|
+
tradingPair: params.trading_pair,
|
|
1023
|
+
limit: params.limit,
|
|
1024
|
+
});
|
|
1025
|
+
return { callId: '', success: true, result };
|
|
1026
|
+
}
|
|
1027
|
+
if (subAction === 'rates') {
|
|
1028
|
+
const pairs = splitCsv(params.trading_pairs);
|
|
1029
|
+
if (!pairs?.length)
|
|
1030
|
+
return { callId: '', success: false, result: null, error: 'trading_pairs required.' };
|
|
1031
|
+
const result = await client.getRates(pairs);
|
|
1032
|
+
return { callId: '', success: true, result };
|
|
1033
|
+
}
|
|
1034
|
+
if (subAction === 'rate') {
|
|
1035
|
+
const result = await client.getRate(params.trading_pair);
|
|
1036
|
+
return { callId: '', success: true, result };
|
|
1037
|
+
}
|
|
1038
|
+
return { callId: '', success: false, result: null, error: `Unknown analytics sub_action: "${subAction}". Use: history, distribution, accounts_distribution, funding_payments, rates, rate.` };
|
|
1039
|
+
}
|
|
1040
|
+
// ================================================================
|
|
1041
|
+
// Account Management
|
|
1042
|
+
// ================================================================
|
|
1043
|
+
case 'accounts': {
|
|
1044
|
+
const subAction = params.sub_action;
|
|
1045
|
+
if (subAction === 'list' || !subAction) {
|
|
1046
|
+
const result = await client.listAccounts();
|
|
1047
|
+
return { callId: '', success: true, result };
|
|
1048
|
+
}
|
|
1049
|
+
if (subAction === 'credentials') {
|
|
1050
|
+
const result = await client.getAccountCredentials(params.account_name);
|
|
1051
|
+
return { callId: '', success: true, result };
|
|
1052
|
+
}
|
|
1053
|
+
if (subAction === 'create') {
|
|
1054
|
+
const result = await client.createAccount(params.account_name);
|
|
1055
|
+
return { callId: '', success: true, result };
|
|
1056
|
+
}
|
|
1057
|
+
if (subAction === 'delete') {
|
|
1058
|
+
const result = await client.deleteAccount(params.account_name);
|
|
1059
|
+
return { callId: '', success: true, result };
|
|
1060
|
+
}
|
|
1061
|
+
return { callId: '', success: false, result: null, error: `Unknown accounts sub_action: "${subAction}". Use: list, credentials, create, delete.` };
|
|
1062
|
+
}
|
|
1063
|
+
// ================================================================
|
|
1064
|
+
// Unknown
|
|
1065
|
+
// ================================================================
|
|
1066
|
+
default:
|
|
1067
|
+
return {
|
|
1068
|
+
callId: '', success: false, result: null,
|
|
1069
|
+
error: `Unknown hummingbot action: "${action}". Valid: status, portfolio, order, leverage, executor, market_data, controller, bot, gateway, history, templates, connector, servers, backtest, discovery, archived, scripts, analytics, accounts.`,
|
|
1070
|
+
};
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
catch (err) {
|
|
1074
|
+
const message = err?.code ? `[${err.code}] ${err.message}` : err?.message ?? String(err);
|
|
1075
|
+
return { callId: '', success: false, result: null, error: message };
|
|
1076
|
+
}
|
|
1077
|
+
},
|
|
1078
|
+
};
|
|
1079
|
+
//# sourceMappingURL=hummingbot.js.map
|