perp-cli 0.6.3 → 0.7.1

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.
Files changed (177) hide show
  1. package/README.md +7 -2
  2. package/dist/api/public/hyperliquid.d.ts +2 -2
  3. package/dist/api/public/hyperliquid.js +0 -10
  4. package/dist/api/public/lighter.d.ts +2 -1
  5. package/dist/api/public/pacifica.d.ts +2 -1
  6. package/dist/arb/index.d.ts +7 -4
  7. package/dist/arb/index.js +5 -4
  8. package/dist/arb/sizing.d.ts +1 -1
  9. package/dist/arb/state.d.ts +1 -1
  10. package/dist/arb/state.js +4 -3
  11. package/dist/arb/utils.d.ts +0 -10
  12. package/dist/arb/utils.js +0 -42
  13. package/dist/bot/apex/guard.d.ts +26 -0
  14. package/dist/bot/apex/guard.js +86 -0
  15. package/dist/bot/apex/index.d.ts +6 -0
  16. package/dist/bot/apex/index.js +4 -0
  17. package/dist/bot/apex/pulse.d.ts +22 -0
  18. package/dist/bot/apex/pulse.js +107 -0
  19. package/dist/bot/apex/radar.d.ts +17 -0
  20. package/dist/bot/apex/radar.js +150 -0
  21. package/dist/bot/conditions.d.ts +1 -1
  22. package/dist/bot/config.d.ts +5 -1
  23. package/dist/bot/config.js +1 -1
  24. package/dist/bot/engine.d.ts +23 -2
  25. package/dist/bot/engine.js +296 -351
  26. package/dist/bot/index.d.ts +16 -0
  27. package/dist/bot/index.js +10 -0
  28. package/dist/bot/indicators.d.ts +29 -0
  29. package/dist/bot/indicators.js +144 -0
  30. package/dist/bot/reflect.d.ts +34 -0
  31. package/dist/bot/reflect.js +155 -0
  32. package/dist/bot/strategies/aggressive-taker.d.ts +36 -0
  33. package/dist/bot/strategies/aggressive-taker.js +125 -0
  34. package/dist/bot/strategies/apex-strategy.d.ts +36 -0
  35. package/dist/bot/strategies/apex-strategy.js +185 -0
  36. package/dist/bot/strategies/avellaneda-mm.d.ts +27 -0
  37. package/dist/bot/strategies/avellaneda-mm.js +111 -0
  38. package/dist/bot/strategies/basis-arb.d.ts +27 -0
  39. package/dist/bot/strategies/basis-arb.js +97 -0
  40. package/dist/bot/strategies/claude-agent.d.ts +31 -0
  41. package/dist/bot/strategies/claude-agent.js +155 -0
  42. package/dist/bot/strategies/dca-strategy.d.ts +25 -0
  43. package/dist/bot/strategies/dca-strategy.js +59 -0
  44. package/dist/bot/strategies/engine-mm.d.ts +29 -0
  45. package/dist/bot/strategies/engine-mm.js +141 -0
  46. package/dist/bot/strategies/funding-arb-strategy.d.ts +32 -0
  47. package/dist/bot/strategies/funding-arb-strategy.js +168 -0
  48. package/dist/bot/strategies/funding-arb-v2.d.ts +32 -0
  49. package/dist/bot/strategies/funding-arb-v2.js +222 -0
  50. package/dist/bot/strategies/funding-auto.d.ts +1 -0
  51. package/dist/bot/strategies/funding-auto.js +572 -0
  52. package/dist/bot/strategies/grid-mm.d.ts +25 -0
  53. package/dist/bot/strategies/grid-mm.js +99 -0
  54. package/dist/bot/strategies/grid-strategy.d.ts +39 -0
  55. package/dist/bot/strategies/grid-strategy.js +176 -0
  56. package/dist/bot/strategies/hedge-agent.d.ts +25 -0
  57. package/dist/bot/strategies/hedge-agent.js +79 -0
  58. package/dist/bot/strategies/liquidation-mm.d.ts +25 -0
  59. package/dist/bot/strategies/liquidation-mm.js +108 -0
  60. package/dist/bot/strategies/mean-reversion.d.ts +35 -0
  61. package/dist/bot/strategies/mean-reversion.js +118 -0
  62. package/dist/bot/strategies/momentum-breakout.d.ts +36 -0
  63. package/dist/bot/strategies/momentum-breakout.js +159 -0
  64. package/dist/bot/strategies/regime-mm.d.ts +25 -0
  65. package/dist/bot/strategies/regime-mm.js +111 -0
  66. package/dist/bot/strategies/rfq-agent.d.ts +25 -0
  67. package/dist/bot/strategies/rfq-agent.js +71 -0
  68. package/dist/bot/strategies/simple-mm.d.ts +25 -0
  69. package/dist/bot/strategies/simple-mm.js +76 -0
  70. package/dist/bot/strategy-registry.d.ts +9 -0
  71. package/dist/bot/strategy-registry.js +14 -0
  72. package/dist/bot/strategy-types.d.ts +64 -0
  73. package/dist/bot/strategy-types.js +5 -0
  74. package/dist/bot/trade-journal.d.ts +27 -0
  75. package/dist/bot/trade-journal.js +53 -0
  76. package/dist/bot/tui/BotDashboard.d.ts +49 -0
  77. package/dist/bot/tui/BotDashboard.js +93 -0
  78. package/dist/bot/tui/index.d.ts +6 -0
  79. package/dist/bot/tui/index.js +8 -0
  80. package/dist/bridge-engine.d.ts +0 -1
  81. package/dist/bridge-engine.js +0 -1
  82. package/dist/cache.d.ts +0 -1
  83. package/dist/cache.js +0 -1
  84. package/dist/commands/account.d.ts +1 -1
  85. package/dist/commands/account.js +106 -75
  86. package/dist/commands/agent.d.ts +1 -1
  87. package/dist/commands/arb/index.d.ts +1 -1
  88. package/dist/commands/arb/index.js +1 -1
  89. package/dist/commands/arb-auto.d.ts +1 -1
  90. package/dist/commands/arb-auto.js +1 -1
  91. package/dist/commands/arb.d.ts +1 -1
  92. package/dist/commands/bot.d.ts +1 -1
  93. package/dist/commands/bot.js +198 -14
  94. package/dist/commands/dashboard.d.ts +1 -1
  95. package/dist/commands/dashboard.js +1 -1
  96. package/dist/commands/funds.d.ts +1 -1
  97. package/dist/commands/funds.js +33 -20
  98. package/dist/commands/history.d.ts +1 -1
  99. package/dist/commands/history.js +5 -4
  100. package/dist/commands/manage.d.ts +2 -3
  101. package/dist/commands/manage.js +11 -18
  102. package/dist/commands/market.d.ts +1 -1
  103. package/dist/commands/market.js +7 -7
  104. package/dist/commands/plan.d.ts +1 -1
  105. package/dist/commands/rebalance.d.ts +1 -1
  106. package/dist/commands/rebalance.js +8 -9
  107. package/dist/commands/risk.d.ts +1 -1
  108. package/dist/commands/settings.d.ts +1 -1
  109. package/dist/commands/settings.js +3 -1
  110. package/dist/commands/trade.d.ts +1 -1
  111. package/dist/commands/trade.js +39 -52
  112. package/dist/commands/wallet.d.ts +0 -2
  113. package/dist/commands/wallet.js +0 -5
  114. package/dist/constants.d.ts +0 -3
  115. package/dist/constants.js +0 -4
  116. package/dist/cross-chain-margin.d.ts +1 -1
  117. package/dist/dashboard/index.d.ts +4 -0
  118. package/dist/dashboard/index.js +3 -0
  119. package/dist/dashboard/server.d.ts +1 -1
  120. package/dist/dashboard/server.js +1 -1
  121. package/dist/dashboard/ws-feeds.d.ts +1 -1
  122. package/dist/event-stream.d.ts +1 -1
  123. package/dist/exchanges/aster.d.ts +58 -0
  124. package/dist/exchanges/aster.js +409 -0
  125. package/dist/exchanges/capabilities.d.ts +74 -0
  126. package/dist/exchanges/capabilities.js +44 -0
  127. package/dist/exchanges/hyperliquid-spot.d.ts +1 -1
  128. package/dist/exchanges/hyperliquid-spot.js +20 -12
  129. package/dist/exchanges/hyperliquid.d.ts +8 -2
  130. package/dist/exchanges/hyperliquid.js +21 -6
  131. package/dist/exchanges/index.d.ts +11 -0
  132. package/dist/exchanges/index.js +10 -0
  133. package/dist/exchanges/interface.d.ts +3 -0
  134. package/dist/exchanges/lighter-spot.d.ts +13 -0
  135. package/dist/exchanges/lighter-spot.js +98 -26
  136. package/dist/exchanges/lighter.d.ts +9 -3
  137. package/dist/exchanges/lighter.js +18 -8
  138. package/dist/exchanges/nado.d.ts +52 -0
  139. package/dist/exchanges/nado.js +223 -0
  140. package/dist/exchanges/pacifica.d.ts +7 -1
  141. package/dist/exchanges/pacifica.js +17 -2
  142. package/dist/exchanges/registry.d.ts +13 -0
  143. package/dist/exchanges/registry.js +37 -0
  144. package/dist/exchanges/spot-interface.d.ts +9 -0
  145. package/dist/funding/rates.js +1 -1
  146. package/dist/index.js +2 -6
  147. package/dist/jobs.js +1 -1
  148. package/dist/liquidity.d.ts +1 -2
  149. package/dist/liquidity.js +12 -5
  150. package/dist/mcp-server.js +4 -2
  151. package/dist/pacifica/constants.d.ts +0 -3
  152. package/dist/pacifica/constants.js +0 -4
  153. package/dist/pacifica/types/account.d.ts +0 -8
  154. package/dist/pacifica/types/lake.d.ts +0 -6
  155. package/dist/pacifica/types/position.d.ts +0 -12
  156. package/dist/pacifica/types/ws.d.ts +0 -24
  157. package/dist/pacifica/types/ws.js +1 -41
  158. package/dist/plan-executor.d.ts +1 -1
  159. package/dist/rebalance.d.ts +1 -7
  160. package/dist/rebalance.js +0 -6
  161. package/dist/risk.d.ts +1 -1
  162. package/dist/risk.js +3 -1
  163. package/dist/smart-order.d.ts +1 -1
  164. package/dist/strategies/dca.d.ts +1 -1
  165. package/dist/strategies/funding-arb.d.ts +1 -1
  166. package/dist/strategies/funding-arb.js +193 -181
  167. package/dist/strategies/grid.d.ts +1 -1
  168. package/dist/strategies/grid.js +1 -1
  169. package/dist/strategies/index.d.ts +12 -0
  170. package/dist/strategies/index.js +7 -0
  171. package/dist/strategies/split-order.d.ts +1 -1
  172. package/dist/strategies/trailing-stop.d.ts +1 -1
  173. package/dist/strategies/twap.d.ts +1 -1
  174. package/dist/trade-validator.d.ts +1 -1
  175. package/package.json +7 -1
  176. package/skills/perp-cli/SKILL.md +20 -0
  177. package/skills/perp-cli/references/commands.md +22 -8
@@ -1,14 +1,8 @@
1
1
  import chalk from "chalk";
2
2
  import { printJson, jsonOk } from "../utils.js";
3
- import { loadBotConfig, quickGridConfig, quickDCAConfig } from "../bot/config.js";
4
- import { runBot } from "../bot/engine.js";
5
- import { PRESETS, getPreset, getPresetsByStrategy } from "../bot/presets.js";
3
+ import { loadBotConfig, quickGridConfig, quickDCAConfig, runBot, PRESETS, getPreset, getPresetsByStrategy } from "../bot/index.js";
6
4
  import { updateJobState } from "../jobs.js";
7
- import { runTWAP } from "../strategies/twap.js";
8
- import { runFundingArb } from "../strategies/funding-arb.js";
9
- import { runGrid } from "../strategies/grid.js";
10
- import { runDCA } from "../strategies/dca.js";
11
- import { runTrailingStop } from "../strategies/trailing-stop.js";
5
+ import { runTWAP, runFundingArb, runGrid, runDCA, runTrailingStop } from "../strategies/index.js";
12
6
  export function registerBotCommands(program, getAdapter, getAdapterFor, isJson) {
13
7
  const bot = program.command("bot").description("Automated trading bots with condition monitoring & risk management");
14
8
  // ── bot start <config> ──
@@ -16,6 +10,7 @@ export function registerBotCommands(program, getAdapter, getAdapterFor, isJson)
16
10
  .command("start <config>")
17
11
  .description("Start a bot from a YAML/JSON config file")
18
12
  .option("--background", "Run in background (tmux)")
13
+ .option("--headless", "Run without TUI dashboard")
19
14
  .option("--job-id <id>", "Job ID (set by background runner)")
20
15
  .action(async (configPath, opts) => {
21
16
  const config = loadBotConfig(configPath);
@@ -35,8 +30,9 @@ export function registerBotCommands(program, getAdapter, getAdapterFor, isJson)
35
30
  const adapter = config.strategy.type === "funding-arb"
36
31
  ? await getAdapterFor(config.exchange)
37
32
  : await getAdapter();
33
+ const mode = resolveOutputMode(isJson, opts.headless);
38
34
  const log = makeLog();
39
- await runBot(adapter, config, opts.jobId, log);
35
+ await runBot(adapter, config, opts.jobId, log, undefined, mode);
40
36
  });
41
37
  // ── bot quick grid ──
42
38
  bot
@@ -50,6 +46,7 @@ export function registerBotCommands(program, getAdapter, getAdapterFor, isJson)
50
46
  .option("--max-drawdown <usd>", "Stop if drawdown exceeds ($)", "100")
51
47
  .option("--max-runtime <sec>", "Max runtime in seconds", "0")
52
48
  .option("--background", "Run in background (tmux)")
49
+ .option("--headless", "Run without TUI dashboard")
53
50
  .option("--job-id <id>", "Job ID")
54
51
  .action(async (symbol, opts) => {
55
52
  const adapter = await getAdapter();
@@ -84,8 +81,9 @@ export function registerBotCommands(program, getAdapter, getAdapterFor, isJson)
84
81
  printBotJobStarted(config.name, job.id);
85
82
  return;
86
83
  }
84
+ const mode = resolveOutputMode(isJson, opts.headless);
87
85
  const log = makeLog();
88
- await runBot(adapter, config, opts.jobId, log);
86
+ await runBot(adapter, config, opts.jobId, log, undefined, mode);
89
87
  });
90
88
  // ── bot quick dca ──
91
89
  bot
@@ -96,6 +94,7 @@ export function registerBotCommands(program, getAdapter, getAdapterFor, isJson)
96
94
  .option("--trigger-drop <pct>", "Only buy when price drops X% from recent high")
97
95
  .option("--max-drawdown <usd>", "Stop if drawdown exceeds ($)", "100")
98
96
  .option("--background", "Run in background (tmux)")
97
+ .option("--headless", "Run without TUI dashboard")
99
98
  .option("--job-id <id>", "Job ID")
100
99
  .action(async (symbol, side, amount, interval, opts) => {
101
100
  const adapter = await getAdapter();
@@ -129,8 +128,9 @@ export function registerBotCommands(program, getAdapter, getAdapterFor, isJson)
129
128
  printBotJobStarted(config.name, job.id);
130
129
  return;
131
130
  }
131
+ const mode = resolveOutputMode(isJson, opts.headless);
132
132
  const log = makeLog();
133
- await runBot(adapter, config, opts.jobId, log);
133
+ await runBot(adapter, config, opts.jobId, log, undefined, mode);
134
134
  });
135
135
  // ── bot quick arb ──
136
136
  bot
@@ -144,6 +144,7 @@ export function registerBotCommands(program, getAdapter, getAdapterFor, isJson)
144
144
  .option("--interval <sec>", "Check interval in seconds", "60")
145
145
  .option("--max-drawdown <usd>", "Stop if drawdown exceeds ($)", "200")
146
146
  .option("--background", "Run in background (tmux)")
147
+ .option("--headless", "Run without TUI dashboard")
147
148
  .option("--job-id <id>", "Job ID")
148
149
  .action(async (opts) => {
149
150
  const exchangeNames = opts.exchanges.split(",").map(e => e.trim());
@@ -204,8 +205,9 @@ export function registerBotCommands(program, getAdapter, getAdapterFor, isJson)
204
205
  printBotJobStarted(config.name, job.id);
205
206
  return;
206
207
  }
208
+ const mode = resolveOutputMode(isJson, opts.headless);
207
209
  const log = makeLog();
208
- await runBot(primaryAdapter, config, opts.jobId, log, adapters);
210
+ await runBot(primaryAdapter, config, opts.jobId, log, adapters, mode);
209
211
  });
210
212
  // ── bot preset list ──
211
213
  bot
@@ -240,6 +242,7 @@ export function registerBotCommands(program, getAdapter, getAdapterFor, isJson)
240
242
  .command("preset <name> [symbol]")
241
243
  .description("Start a bot from a preset (use 'preset-list' to see options)")
242
244
  .option("--background", "Run in background (tmux)")
245
+ .option("--headless", "Run without TUI dashboard")
243
246
  .option("--job-id <id>", "Job ID")
244
247
  .action(async (name, symbol, opts) => {
245
248
  const preset = getPreset(name);
@@ -287,7 +290,8 @@ export function registerBotCommands(program, getAdapter, getAdapterFor, isJson)
287
290
  console.log(chalk.cyan.bold(`\n Starting preset: ${chalk.white(preset.name)}`));
288
291
  console.log(chalk.gray(` ${preset.description}\n`));
289
292
  }
290
- await runBot(primaryAdapter, config, opts.jobId, log, adapters);
293
+ const mode = resolveOutputMode(isJson, opts.headless);
294
+ await runBot(primaryAdapter, config, opts.jobId, log, adapters, mode);
291
295
  return;
292
296
  }
293
297
  // Grid / DCA presets
@@ -312,7 +316,180 @@ export function registerBotCommands(program, getAdapter, getAdapterFor, isJson)
312
316
  console.log(chalk.cyan.bold(`\n Starting preset: ${chalk.white(preset.name)}`));
313
317
  console.log(chalk.gray(` ${preset.description}\n`));
314
318
  }
315
- await runBot(adapter, config, opts.jobId, log);
319
+ const mode = resolveOutputMode(isJson, opts.headless);
320
+ await runBot(adapter, config, opts.jobId, log, undefined, mode);
321
+ });
322
+ // ── bot list-strategies ──
323
+ bot
324
+ .command("list-strategies")
325
+ .description("List all available trading strategies")
326
+ .action(async () => {
327
+ await import("../bot/engine.js");
328
+ const { listStrategies } = await import("../bot/strategy-registry.js");
329
+ const strategies = listStrategies();
330
+ if (isJson())
331
+ return printJson(jsonOk({ strategies }));
332
+ console.log(chalk.cyan.bold("\n Available Strategies:\n"));
333
+ for (const s of strategies) {
334
+ console.log(` ${chalk.white(s)}`);
335
+ }
336
+ console.log();
337
+ });
338
+ // ── bot apex ──
339
+ bot
340
+ .command("apex [symbol]")
341
+ .description("Start APEX autonomous orchestrator")
342
+ .option("--preset <preset>", "Preset: default, conservative, aggressive", "default")
343
+ .option("--max-slots <n>", "Max concurrent positions", "3")
344
+ .option("--daily-limit <usd>", "Daily loss limit in USD", "250")
345
+ .option("--headless", "Run without TUI dashboard")
346
+ .action(async (symbol, opts) => {
347
+ const adapter = await getAdapter();
348
+ const sym = (symbol ?? "ETH").toUpperCase();
349
+ const config = {
350
+ name: `apex-${sym.toLowerCase()}-${Date.now().toString(36)}`,
351
+ exchange: adapter.name,
352
+ symbol: sym,
353
+ strategy: {
354
+ type: "apex",
355
+ preset: opts.preset,
356
+ max_slots: parseInt(opts.maxSlots),
357
+ },
358
+ entry_conditions: [{ type: "always", value: 0 }],
359
+ exit_conditions: [],
360
+ risk: {
361
+ max_position_usd: 1000,
362
+ max_daily_loss: parseFloat(opts.dailyLimit),
363
+ max_drawdown: parseFloat(opts.dailyLimit) * 2,
364
+ pause_after_loss_sec: 300,
365
+ max_open_bots: 1,
366
+ },
367
+ monitor_interval_sec: 10,
368
+ };
369
+ const mode = resolveOutputMode(isJson, opts.headless);
370
+ const log = makeLog();
371
+ await runBot(adapter, config, undefined, log, undefined, mode);
372
+ });
373
+ // ── bot reflect ──
374
+ bot
375
+ .command("reflect")
376
+ .description("Analyze trading performance")
377
+ .option("--period <days>", "Analysis period in days", "7")
378
+ .action(async (opts) => {
379
+ const { readJournal } = await import("../bot/trade-journal.js");
380
+ const { analyzePerformance } = await import("../bot/reflect.js");
381
+ const periodDays = Number(opts.period);
382
+ const entries = readJournal({ from: Date.now() - periodDays * 86400000 });
383
+ const report = analyzePerformance(entries, periodDays);
384
+ if (isJson())
385
+ return printJson(jsonOk(report));
386
+ console.log(chalk.cyan.bold("\n Performance Report\n"));
387
+ console.log(` Period: ${chalk.white(`${report.period.days}d`)} (${new Date(report.period.from).toLocaleDateString()} – ${new Date(report.period.to).toLocaleDateString()})`);
388
+ console.log(` Total trades: ${chalk.white(report.totalTrades)}`);
389
+ if (report.totalTrades === 0) {
390
+ console.log(chalk.gray("\n No trades in the selected period.\n"));
391
+ return;
392
+ }
393
+ const wrColor = report.winRate >= 0.5 ? chalk.green : chalk.red;
394
+ console.log(` Win rate: ${wrColor((report.winRate * 100).toFixed(1) + "%")}`);
395
+ console.log(` Avg win: ${chalk.green(`$${report.avgWin.toFixed(2)}`)}`);
396
+ console.log(` Avg loss: ${chalk.red(`$${report.avgLoss.toFixed(2)}`)}`);
397
+ const pfColor = report.profitFactor >= 1.0 ? chalk.green : chalk.red;
398
+ console.log(` Profit factor: ${pfColor(report.profitFactor === Infinity ? "∞" : report.profitFactor.toFixed(2))}`);
399
+ console.log(` Fee drag: ${chalk.yellow((report.feeDragRatio * 100).toFixed(1) + "%")}`);
400
+ console.log(` Direction: ${chalk.gray(`long ${(report.directionSplit.long * 100).toFixed(0)}% / short ${(report.directionSplit.short * 100).toFixed(0)}%`)}`);
401
+ if (report.bestStrategy)
402
+ console.log(` Best strategy: ${chalk.green(report.bestStrategy)}`);
403
+ if (report.worstStrategy && report.worstStrategy !== report.bestStrategy)
404
+ console.log(` Worst strategy:${chalk.red(report.worstStrategy)}`);
405
+ console.log(chalk.cyan.bold("\n Suggestions:\n"));
406
+ for (const s of report.suggestions) {
407
+ console.log(` ${chalk.white("•")} ${chalk.gray(s)}`);
408
+ }
409
+ console.log();
410
+ });
411
+ // ── bot run <strategy> <symbol> ──
412
+ bot
413
+ .command("run <strategy> [symbol]")
414
+ .description("Run any registered strategy (symbol optional for multi-symbol strategies like funding-auto)")
415
+ .option("--config <path>", "YAML/JSON config file")
416
+ .option("--headless", "Run without TUI dashboard")
417
+ .option("--param <key=value>", "Strategy parameter (repeatable)", (val, acc) => [...acc, val], [])
418
+ .action(async (strategyName, symbol, opts) => {
419
+ const sym = symbol?.toUpperCase() || "ALL";
420
+ // Load or build config
421
+ let config;
422
+ if (opts.config) {
423
+ config = loadBotConfig(opts.config);
424
+ // Override strategy type and symbol from CLI args
425
+ config.strategy = { ...config.strategy, type: strategyName };
426
+ config.symbol = sym;
427
+ }
428
+ else {
429
+ // Parse --param key=value pairs
430
+ const params = { type: strategyName };
431
+ for (const kv of opts.param) {
432
+ const eq = kv.indexOf("=");
433
+ if (eq === -1)
434
+ continue;
435
+ const key = kv.slice(0, eq);
436
+ const raw = kv.slice(eq + 1);
437
+ // Try to coerce numbers and booleans
438
+ if (raw === "true")
439
+ params[key] = true;
440
+ else if (raw === "false")
441
+ params[key] = false;
442
+ else if (!isNaN(Number(raw)) && raw !== "")
443
+ params[key] = Number(raw);
444
+ else
445
+ params[key] = raw;
446
+ }
447
+ const adapter = await getAdapter();
448
+ config = {
449
+ name: `${strategyName}-${sym.toLowerCase()}-${Date.now().toString(36)}`,
450
+ exchange: adapter.name,
451
+ symbol: sym,
452
+ strategy: params,
453
+ entry_conditions: [{ type: "always", value: 0 }],
454
+ exit_conditions: [],
455
+ risk: {
456
+ max_position_usd: 1000,
457
+ max_daily_loss: 100,
458
+ max_drawdown: 200,
459
+ pause_after_loss_sec: 300,
460
+ max_open_bots: 5,
461
+ },
462
+ monitor_interval_sec: 10,
463
+ };
464
+ }
465
+ // Verify strategy is registered
466
+ await import("../bot/engine.js");
467
+ const { getStrategy } = await import("../bot/strategy-registry.js");
468
+ if (!getStrategy(strategyName)) {
469
+ console.error(chalk.red(`\n Unknown strategy: "${strategyName}"`));
470
+ console.error(chalk.gray(` Run 'perp bot list-strategies' to see available strategies.\n`));
471
+ return;
472
+ }
473
+ const adapter = await getAdapter();
474
+ config.exchange = adapter.name;
475
+ const mode = resolveOutputMode(isJson, opts.headless);
476
+ const log = makeLog();
477
+ // Multi-exchange strategies need all adapters
478
+ let extraAdapters;
479
+ const multiExchangeStrategies = ["funding-auto", "funding-arb", "funding-arb-v2", "basis-arb", "hedge-agent"];
480
+ if (multiExchangeStrategies.includes(strategyName) && getAdapterFor) {
481
+ extraAdapters = new Map();
482
+ for (const ex of ["pacifica", "hyperliquid", "lighter"]) {
483
+ if (ex === adapter.name)
484
+ continue;
485
+ try {
486
+ const a = await getAdapterFor(ex);
487
+ extraAdapters.set(ex, a);
488
+ }
489
+ catch { /* skip unavailable exchanges */ }
490
+ }
491
+ }
492
+ await runBot(adapter, config, undefined, log, extraAdapters, mode);
316
493
  });
317
494
  // ── bot example ──
318
495
  bot
@@ -341,6 +518,13 @@ function makeLog() {
341
518
  console.log(`${chalk.gray(ts)} ${msg}`);
342
519
  };
343
520
  }
521
+ function resolveOutputMode(isJson, headless) {
522
+ if (isJson())
523
+ return "json";
524
+ if (headless)
525
+ return "headless";
526
+ return process.stdout.isTTY ? "tui" : "headless";
527
+ }
344
528
  function printBotJobStarted(name, jobId) {
345
529
  console.log(chalk.green(`\n Bot "${name}" started in background.`));
346
530
  console.log(` Job ID: ${chalk.white.bold(jobId)}`);
@@ -1,3 +1,3 @@
1
1
  import { Command } from "commander";
2
- import type { ExchangeAdapter } from "../exchanges/interface.js";
2
+ import type { ExchangeAdapter } from "../exchanges/index.js";
3
3
  export declare function registerDashboardCommands(program: Command, getAdapterForExchange: (exchange: string) => Promise<ExchangeAdapter>, isJson: () => boolean, getHLAdapterForDex?: (dex: string) => Promise<ExchangeAdapter>): void;
@@ -1,5 +1,5 @@
1
1
  import chalk from "chalk";
2
- import { startDashboard } from "../dashboard/server.js";
2
+ import { startDashboard } from "../dashboard/index.js";
3
3
  const KNOWN_HIP3_DEXES = ["xyz", "flx", "hyna", "km", "cash", "vntl"];
4
4
  const HL_INFO_URL = "https://api.hyperliquid.xyz/info";
5
5
  /** Lightweight check: query HL info API directly for dex positions (no SDK/WebSocket needed) */
@@ -1,4 +1,4 @@
1
1
  import { Command } from "commander";
2
- import type { ExchangeAdapter } from "../exchanges/interface.js";
2
+ import type { ExchangeAdapter } from "../exchanges/index.js";
3
3
  import type { Network } from "../pacifica/index.js";
4
4
  export declare function registerFundsCommands(program: Command, getAdapter: () => Promise<ExchangeAdapter>, isJson: () => boolean, getNetwork: () => Network): void;
@@ -1,8 +1,7 @@
1
1
  import chalk from "chalk";
2
- import { printJson, formatUsd, jsonOk } from "../utils.js";
3
- import { PacificaAdapter } from "../exchanges/pacifica.js";
4
- import { HyperliquidAdapter } from "../exchanges/hyperliquid.js";
2
+ import { printJson, formatUsd, jsonOk, jsonError } from "../utils.js";
5
3
  import { logExecution } from "../execution-log.js";
4
+ import { hasPacificaSdk, hasEvmAddress, isWithdrawCapable, isUsdTransferCapable, hasLighterAccount } from "../exchanges/capabilities.js";
6
5
  const DEFAULT_RELAYER = "http://localhost:3100";
7
6
  function getRelayerUrl() {
8
7
  return process.env.PERP_RELAYER_URL || DEFAULT_RELAYER;
@@ -38,14 +37,16 @@ export function registerFundsCommands(program, getAdapter, isJson, getNetwork) {
38
37
  if (!isJson())
39
38
  console.log(chalk.cyan(`\n Depositing $${formatUsd(amountNum)} via relayer (gasless)...\n`));
40
39
  const adapter = await getAdapter();
41
- if (!(adapter instanceof PacificaAdapter))
40
+ if (adapter.name !== "pacifica")
42
41
  throw new Error("Requires --exchange pacifica");
42
+ const { PacificaAdapter } = await import("../exchanges/pacifica.js");
43
+ const pacAdapter = adapter;
43
44
  try {
44
45
  const buildRes = await fetch(`${getRelayerUrl()}/deposit/pacifica/build`, {
45
46
  method: "POST",
46
47
  headers: { "Content-Type": "application/json" },
47
48
  body: JSON.stringify({
48
- userPubkey: adapter.keypair.publicKey.toBase58(),
49
+ userPubkey: pacAdapter.keypair.publicKey.toBase58(),
49
50
  amount: amountNum,
50
51
  testnet: getNetwork() === "testnet",
51
52
  }),
@@ -61,7 +62,7 @@ export function registerFundsCommands(program, getAdapter, isJson, getNetwork) {
61
62
  }
62
63
  const { Transaction } = await import("@solana/web3.js");
63
64
  const tx = Transaction.from(Buffer.from(transaction, "base64"));
64
- tx.partialSign(adapter.keypair);
65
+ tx.partialSign(pacAdapter.keypair);
65
66
  const signed = tx.serialize().toString("base64");
66
67
  const submitRes = await fetch(`${getRelayerUrl()}/deposit/pacifica/submit`, {
67
68
  method: "POST",
@@ -104,15 +105,17 @@ export function registerFundsCommands(program, getAdapter, isJson, getNetwork) {
104
105
  console.log(chalk.gray(" Requires: SOL for gas (~0.005 SOL) + USDC on Solana\n"));
105
106
  }
106
107
  const adapter = await getAdapter();
107
- if (!(adapter instanceof PacificaAdapter))
108
+ if (adapter.name !== "pacifica")
108
109
  throw new Error("Requires --exchange pacifica");
110
+ const { PacificaAdapter: PacAdapterCls } = await import("../exchanges/pacifica.js");
111
+ const pacDirect = adapter;
109
112
  try {
110
113
  const { Connection, Transaction } = await import("@solana/web3.js");
111
114
  const { buildDepositInstruction } = await import("../pacifica/deposit.js");
112
115
  const network = getNetwork();
113
116
  const rpcUrl = network === "testnet" ? "https://api.devnet.solana.com" : "https://api.mainnet-beta.solana.com";
114
117
  const connection = new Connection(rpcUrl, "confirmed");
115
- const solBalance = await connection.getBalance(adapter.keypair.publicKey);
118
+ const solBalance = await connection.getBalance(pacDirect.keypair.publicKey);
116
119
  if (solBalance < 5_000_000) {
117
120
  console.error(chalk.red(" Insufficient SOL for gas. Need ~0.005 SOL."));
118
121
  console.error(chalk.gray(" Tip: Use relayer for gasless deposits (start relayer server)\n"));
@@ -120,7 +123,7 @@ export function registerFundsCommands(program, getAdapter, isJson, getNetwork) {
120
123
  }
121
124
  const { PublicKey } = await import("@solana/web3.js");
122
125
  const USDC_MINT = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
123
- const tokenAccounts = await connection.getParsedTokenAccountsByOwner(adapter.keypair.publicKey, { mint: USDC_MINT });
126
+ const tokenAccounts = await connection.getParsedTokenAccountsByOwner(pacDirect.keypair.publicKey, { mint: USDC_MINT });
124
127
  const usdcBalance = tokenAccounts.value.length > 0
125
128
  ? tokenAccounts.value[0].account.data.parsed.info.tokenAmount.uiAmount ?? 0
126
129
  : 0;
@@ -128,11 +131,11 @@ export function registerFundsCommands(program, getAdapter, isJson, getNetwork) {
128
131
  console.error(chalk.red(` Insufficient USDC on Solana. Have: $${formatUsd(usdcBalance)}, need: $${formatUsd(amountNum)}`));
129
132
  process.exit(1);
130
133
  }
131
- const ix = await buildDepositInstruction(adapter.keypair.publicKey, amountNum, network);
134
+ const ix = await buildDepositInstruction(pacDirect.keypair.publicKey, amountNum, network);
132
135
  const tx = new Transaction().add(ix);
133
- tx.feePayer = adapter.keypair.publicKey;
136
+ tx.feePayer = pacDirect.keypair.publicKey;
134
137
  tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
135
- tx.sign(adapter.keypair);
138
+ tx.sign(pacDirect.keypair);
136
139
  const sig = await connection.sendRawTransaction(tx.serialize());
137
140
  await connection.confirmTransaction(sig, "confirmed");
138
141
  logExecution({
@@ -173,7 +176,13 @@ export function registerFundsCommands(program, getAdapter, isJson, getNetwork) {
173
176
  console.log(chalk.cyan(`\n Depositing $${formatUsd(amountNum)} via relayer (gasless)...\n`));
174
177
  const { ethers } = await import("ethers");
175
178
  const { loadPrivateKey } = await import("../config.js");
176
- const pk = await loadPrivateKey("hyperliquid");
179
+ let pk;
180
+ try {
181
+ pk = await loadPrivateKey("hyperliquid");
182
+ }
183
+ catch (err) {
184
+ throw new Error(`Private key not configured for Hyperliquid. Run: perp init`);
185
+ }
177
186
  const wallet = new ethers.Wallet(pk);
178
187
  try {
179
188
  const res = await fetch(`${getRelayerUrl()}/deposit/hyperliquid`, {
@@ -475,7 +484,7 @@ export function registerFundsCommands(program, getAdapter, isJson, getNetwork) {
475
484
  if (isNaN(amountNum) || amountNum <= 0)
476
485
  throw new Error("Invalid amount");
477
486
  const adapter = await getAdapter();
478
- if (!(adapter instanceof PacificaAdapter))
487
+ if (!hasPacificaSdk(adapter) || !isWithdrawCapable(adapter))
479
488
  throw new Error("Requires --exchange pacifica");
480
489
  const dest = opts.to || adapter.publicKey;
481
490
  if (!isJson()) {
@@ -483,7 +492,7 @@ export function registerFundsCommands(program, getAdapter, isJson, getNetwork) {
483
492
  console.log(` Destination: ${dest}`);
484
493
  }
485
494
  try {
486
- const result = await adapter.sdk.withdraw({ amount: String(amountNum), dest_address: dest }, adapter.publicKey, adapter.signer);
495
+ const result = await adapter.withdraw(String(amountNum), dest);
487
496
  logExecution({
488
497
  type: "bridge", exchange: "pacifica", symbol: "USDC", side: "withdraw",
489
498
  size: String(amountNum), status: "success", dryRun: false,
@@ -515,7 +524,7 @@ export function registerFundsCommands(program, getAdapter, isJson, getNetwork) {
515
524
  if (isNaN(amountNum) || amountNum <= 0)
516
525
  throw new Error("Invalid amount");
517
526
  const adapter = await getAdapter();
518
- if (!(adapter instanceof HyperliquidAdapter))
527
+ if (adapter.name !== "hyperliquid" || !hasEvmAddress(adapter) || !isWithdrawCapable(adapter))
519
528
  throw new Error("Requires --exchange hyperliquid");
520
529
  const dest = opts.to || adapter.address;
521
530
  if (!isJson()) {
@@ -562,8 +571,7 @@ export function registerFundsCommands(program, getAdapter, isJson, getNetwork) {
562
571
  if (isNaN(amountNum) || amountNum <= 0)
563
572
  throw new Error("Invalid amount");
564
573
  const adapter = await getAdapter();
565
- const { LighterAdapter } = await import("../exchanges/lighter.js");
566
- if (!(adapter instanceof LighterAdapter))
574
+ if (!hasLighterAccount(adapter) || !isWithdrawCapable(adapter))
567
575
  throw new Error("Requires --exchange lighter");
568
576
  if (!isJson()) {
569
577
  console.log(chalk.cyan(`\n Withdrawing $${formatUsd(amountNum)} USDC from Lighter...\n`));
@@ -571,7 +579,7 @@ export function registerFundsCommands(program, getAdapter, isJson, getNetwork) {
571
579
  console.log(` Address: ${adapter.address}`);
572
580
  }
573
581
  try {
574
- const result = await adapter.withdraw(amountNum, parseInt(opts.assetId), parseInt(opts.route));
582
+ const result = await adapter.withdraw(String(amountNum), "", { assetId: parseInt(opts.assetId), routeType: parseInt(opts.route) });
575
583
  logExecution({
576
584
  type: "bridge", exchange: "lighter", symbol: "USDC", side: "withdraw",
577
585
  size: String(amountNum), status: "success", dryRun: false,
@@ -604,7 +612,7 @@ export function registerFundsCommands(program, getAdapter, isJson, getNetwork) {
604
612
  if (isNaN(amountNum) || amountNum <= 0)
605
613
  throw new Error("Invalid amount");
606
614
  const adapter = await getAdapter();
607
- if (!(adapter instanceof HyperliquidAdapter))
615
+ if (!isUsdTransferCapable(adapter))
608
616
  throw new Error("Requires --exchange hyperliquid");
609
617
  if (!isJson())
610
618
  console.log(chalk.cyan(`\n Transferring $${formatUsd(amountNum)} USDC to ${destination}...\n`));
@@ -654,8 +662,13 @@ export function registerFundsCommands(program, getAdapter, isJson, getNetwork) {
654
662
  console.log(chalk.gray(` Check: perp funds bridge-status --hash ${result.messageHash}\n`));
655
663
  }
656
664
  else {
665
+ if (isJson()) {
666
+ printJson(jsonError("RELAYER_UNAVAILABLE", "CCTP bridge requires relayer server. Start: cd packages/relayer && pnpm start"));
667
+ process.exit(1);
668
+ }
657
669
  console.error(chalk.red("\n CCTP bridge requires relayer server."));
658
670
  console.error(chalk.gray(" Start: cd packages/relayer && pnpm start\n"));
671
+ process.exit(1);
659
672
  }
660
673
  });
661
674
  funds
@@ -1,3 +1,3 @@
1
1
  import { Command } from "commander";
2
- import type { ExchangeAdapter } from "../exchanges/interface.js";
2
+ import type { ExchangeAdapter } from "../exchanges/index.js";
3
3
  export declare function registerHistoryCommands(program: Command, isJson: () => boolean, getAdapterForExchange?: (exchange: string) => Promise<ExchangeAdapter>): void;
@@ -1,7 +1,7 @@
1
1
  import chalk from "chalk";
2
2
  import { printJson, jsonOk, jsonError, makeTable, formatUsd, formatPnl, withJsonErrors } from "../utils.js";
3
3
  import { readExecutionLog, getExecutionStats, pruneExecutionLog } from "../execution-log.js";
4
- import { loadArbState } from "../arb/state.js";
4
+ import { loadArbState } from "../arb/index.js";
5
5
  import { readPositionHistory, getPositionStats } from "../position-history.js";
6
6
  import { saveEquitySnapshot, readEquityHistory, computePnlMetrics, computeDailyPnl, aggregateWeekly, } from "../equity-tracker.js";
7
7
  const EXCHANGES = ["pacifica", "hyperliquid", "lighter"];
@@ -899,8 +899,8 @@ function registerPnlSubcommands(parent, getAdapterForExchange, isJson) {
899
899
  process.on("SIGINT", () => controller.abort());
900
900
  // Initial snapshot
901
901
  const snaps = await takeSnapshot(getAdapterForExchange, exchanges);
902
- const total = snaps.reduce((s, sn) => s + sn.equity, 0);
903
- console.log(`${chalk.gray(new Date().toLocaleTimeString())} Total equity: $${formatUsd(total)}`);
902
+ let prevTotal = snaps.reduce((s, sn) => s + sn.equity, 0);
903
+ console.log(`${chalk.gray(new Date().toLocaleTimeString())} Total equity: $${formatUsd(prevTotal)}`);
904
904
  while (!controller.signal.aborted) {
905
905
  await new Promise((resolve) => {
906
906
  const timer = setTimeout(resolve, intervalMs);
@@ -911,9 +911,10 @@ function registerPnlSubcommands(parent, getAdapterForExchange, isJson) {
911
911
  try {
912
912
  const s = await takeSnapshot(getAdapterForExchange, exchanges);
913
913
  const t = s.reduce((sum, sn) => sum + sn.equity, 0);
914
- const delta = t - total;
914
+ const delta = t - prevTotal;
915
915
  console.log(`${chalk.gray(new Date().toLocaleTimeString())} ` +
916
916
  `Total: $${formatUsd(t)} ${formatPnl(delta)}`);
917
+ prevTotal = t;
917
918
  }
918
919
  catch (err) {
919
920
  console.error(chalk.red(`Snapshot error: ${err instanceof Error ? err.message : err}`));
@@ -1,4 +1,3 @@
1
1
  import { Command } from "commander";
2
- import type { ExchangeAdapter } from "../exchanges/interface.js";
3
- import { PacificaAdapter } from "../exchanges/pacifica.js";
4
- export declare function registerManageCommands(program: Command, getAdapter: () => Promise<ExchangeAdapter>, isJson: () => boolean, getPacificaAdapter: () => PacificaAdapter): void;
2
+ import type { ExchangeAdapter } from "../exchanges/index.js";
3
+ export declare function registerManageCommands(program: Command, getAdapter: () => Promise<ExchangeAdapter>, isJson: () => boolean, getPacificaAdapter: () => unknown): void;
@@ -1,15 +1,16 @@
1
- import { PacificaAdapter } from "../exchanges/pacifica.js";
2
1
  import { printJson, jsonOk } from "../utils.js";
3
2
  import { setEnvVar } from "./init.js";
4
3
  import chalk from "chalk";
4
+ import { hasPacificaSdk, hasLighterAccount } from "../exchanges/capabilities.js";
5
5
  export function registerManageCommands(program, getAdapter, isJson, getPacificaAdapter) {
6
6
  const manage = program.command("manage").description("Exchange account settings (margin, subaccount, API keys, builder)");
7
7
  // Ensure adapter is initialized before accessing PacificaAdapter
8
8
  async function pac() {
9
9
  const adapter = await getAdapter();
10
- if (!(adapter instanceof PacificaAdapter)) {
10
+ if (!hasPacificaSdk(adapter)) {
11
11
  throw new Error("This command requires --exchange pacifica");
12
12
  }
13
+ // Cast sdk to any to allow calling Pacifica SDK methods without importing the concrete type
13
14
  return adapter;
14
15
  }
15
16
  manage
@@ -30,13 +31,8 @@ export function registerManageCommands(program, getAdapter, isJson, getPacificaA
30
31
  const withdrawCmd = manage
31
32
  .command("withdraw <amount> <address>")
32
33
  .description("Use 'perp withdraw pacifica <amount>'")
33
- .action(async (amount, address) => {
34
+ .action(async (_amount, _address) => {
34
35
  console.log(chalk.yellow("\n Use 'perp withdraw pacifica <amount>' instead.\n"));
35
- const a = await pac();
36
- const result = await a.sdk.withdraw({ amount, dest_address: address }, a.publicKey, a.signer);
37
- if (isJson())
38
- return printJson(jsonOk(result));
39
- console.log(chalk.green(`\n Withdrawal of $${amount} to ${address} submitted.\n`));
40
36
  });
41
37
  withdrawCmd._hidden = true;
42
38
  // Subaccounts
@@ -59,7 +55,7 @@ export function registerManageCommands(program, getAdapter, isJson, getPacificaA
59
55
  const result = await a.sdk.listSubaccounts(a.publicKey, a.signer);
60
56
  if (isJson())
61
57
  return printJson(jsonOk(result));
62
- printJson(jsonOk(result));
58
+ console.log(JSON.stringify(result, null, 2));
63
59
  });
64
60
  sub
65
61
  .command("transfer <from> <to> <amount>")
@@ -91,7 +87,7 @@ export function registerManageCommands(program, getAdapter, isJson, getPacificaA
91
87
  const result = await a.sdk.listAgentWallets(a.publicKey, a.signer);
92
88
  if (isJson())
93
89
  return printJson(jsonOk(result));
94
- printJson(jsonOk(result));
90
+ console.log(JSON.stringify(result, null, 2));
95
91
  });
96
92
  agent
97
93
  .command("revoke <wallet>")
@@ -124,7 +120,6 @@ export function registerManageCommands(program, getAdapter, isJson, getPacificaA
124
120
  if (isJson())
125
121
  return printJson(jsonOk(result));
126
122
  console.log(chalk.green(`\n Lake created for ${symbol.toUpperCase()} with $${amount}.\n`));
127
- printJson(jsonOk(result));
128
123
  });
129
124
  lake
130
125
  .command("deposit <lakeId> <amount>")
@@ -195,7 +190,7 @@ export function registerManageCommands(program, getAdapter, isJson, getPacificaA
195
190
  const result = await a.sdk.getBuilderOverview(a.publicKey);
196
191
  if (isJson())
197
192
  return printJson(jsonOk(result));
198
- printJson(jsonOk(result));
193
+ console.log(JSON.stringify(result, null, 2));
199
194
  });
200
195
  builder
201
196
  .command("trades <code>")
@@ -205,7 +200,7 @@ export function registerManageCommands(program, getAdapter, isJson, getPacificaA
205
200
  const result = await a.sdk.getBuilderTrades(code);
206
201
  if (isJson())
207
202
  return printJson(jsonOk(result));
208
- printJson(jsonOk(result));
203
+ console.log(JSON.stringify(result, null, 2));
209
204
  });
210
205
  builder
211
206
  .command("leaderboard <code>")
@@ -215,7 +210,7 @@ export function registerManageCommands(program, getAdapter, isJson, getPacificaA
215
210
  const result = await a.sdk.getBuilderLeaderboard(code);
216
211
  if (isJson())
217
212
  return printJson(jsonOk(result));
218
- printJson(jsonOk(result));
213
+ console.log(JSON.stringify(result, null, 2));
219
214
  });
220
215
  builder
221
216
  .command("update-fee <code> <feeRate>")
@@ -250,7 +245,6 @@ export function registerManageCommands(program, getAdapter, isJson, getPacificaA
250
245
  if (isJson())
251
246
  return printJson(jsonOk(result));
252
247
  console.log(chalk.green(`\n API key "${name}" created.\n`));
253
- printJson(jsonOk(result));
254
248
  });
255
249
  apikey
256
250
  .command("list")
@@ -260,7 +254,7 @@ export function registerManageCommands(program, getAdapter, isJson, getPacificaA
260
254
  const result = await a.sdk.listApiKeys(a.publicKey, a.signer);
261
255
  if (isJson())
262
256
  return printJson(jsonOk(result));
263
- printJson(jsonOk(result));
257
+ console.log(JSON.stringify(result, null, 2));
264
258
  });
265
259
  apikey
266
260
  .command("revoke <key>")
@@ -279,8 +273,7 @@ export function registerManageCommands(program, getAdapter, isJson, getPacificaA
279
273
  .option("--key-index <n>", "API key index (4-254, default: 4)", "4")
280
274
  .action(async (opts) => {
281
275
  const adapter = await getAdapter();
282
- const { LighterAdapter } = await import("../exchanges/lighter.js");
283
- if (!(adapter instanceof LighterAdapter)) {
276
+ if (!hasLighterAccount(adapter)) {
284
277
  throw new Error("This command requires --exchange lighter");
285
278
  }
286
279
  const keyIndex = parseInt(opts.keyIndex);
@@ -1,3 +1,3 @@
1
1
  import { Command } from "commander";
2
- import type { ExchangeAdapter } from "../exchanges/interface.js";
2
+ import type { ExchangeAdapter } from "../exchanges/index.js";
3
3
  export declare function registerMarketCommands(program: Command, getAdapter: () => Promise<ExchangeAdapter>, isJson: () => boolean, getAdapterForExchange?: (exchange: string) => Promise<ExchangeAdapter>): void;