perp-cli 0.4.2 → 0.4.9

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 (89) hide show
  1. package/README.md +46 -5
  2. package/dist/arb/reconcile.d.ts +28 -0
  3. package/dist/arb/reconcile.js +162 -0
  4. package/dist/arb/sizing.d.ts +12 -1
  5. package/dist/arb/sizing.js +38 -5
  6. package/dist/arb/state.d.ts +6 -0
  7. package/dist/cli-spec.d.ts +0 -4
  8. package/dist/cli-spec.js +8 -1
  9. package/dist/commands/account.d.ts +1 -1
  10. package/dist/commands/account.js +300 -63
  11. package/dist/commands/agent.js +16 -9
  12. package/dist/commands/arb/index.js +243 -49
  13. package/dist/commands/arb-auto.js +696 -9
  14. package/dist/commands/arb.d.ts +2 -1
  15. package/dist/commands/arb.js +535 -131
  16. package/dist/commands/bot.js +207 -0
  17. package/dist/commands/dex.js +7 -1
  18. package/dist/commands/funding.d.ts +2 -1
  19. package/dist/commands/funding.js +211 -4
  20. package/dist/commands/funds.d.ts +4 -0
  21. package/dist/commands/funds.js +741 -0
  22. package/dist/commands/history.d.ts +2 -1
  23. package/dist/commands/history.js +508 -5
  24. package/dist/commands/manage.js +6 -4
  25. package/dist/commands/market.js +35 -2
  26. package/dist/commands/multileg.d.ts +16 -0
  27. package/dist/commands/multileg.js +174 -0
  28. package/dist/commands/pnl.d.ts +12 -0
  29. package/dist/commands/pnl.js +243 -0
  30. package/dist/commands/risk.d.ts +2 -0
  31. package/dist/commands/risk.js +56 -0
  32. package/dist/commands/settings.js +147 -0
  33. package/dist/commands/stream.js +132 -55
  34. package/dist/commands/trade.d.ts +1 -1
  35. package/dist/commands/trade.js +270 -267
  36. package/dist/commands/wallet.d.ts +4 -0
  37. package/dist/commands/wallet.js +11 -1
  38. package/dist/config.d.ts +6 -1
  39. package/dist/config.js +21 -1
  40. package/dist/dashboard/ws-feeds.js +1 -1
  41. package/dist/equity-tracker.d.ts +57 -0
  42. package/dist/equity-tracker.js +209 -0
  43. package/dist/exchanges/hyperliquid-spot.d.ts +69 -0
  44. package/dist/exchanges/hyperliquid-spot.js +309 -0
  45. package/dist/exchanges/hyperliquid.d.ts +26 -5
  46. package/dist/exchanges/hyperliquid.js +171 -73
  47. package/dist/exchanges/interface.d.ts +1 -1
  48. package/dist/exchanges/lighter-spot.d.ts +55 -0
  49. package/dist/exchanges/lighter-spot.js +415 -0
  50. package/dist/exchanges/lighter.d.ts +10 -2
  51. package/dist/exchanges/lighter.js +210 -56
  52. package/dist/exchanges/pacifica.d.ts +11 -4
  53. package/dist/exchanges/pacifica.js +64 -37
  54. package/dist/exchanges/spot-interface.d.ts +45 -0
  55. package/dist/exchanges/spot-interface.js +22 -0
  56. package/dist/execution-log.d.ts +2 -2
  57. package/dist/funding/rates.d.ts +36 -0
  58. package/dist/funding/rates.js +146 -0
  59. package/dist/index.js +126 -161
  60. package/dist/liquidity.d.ts +12 -0
  61. package/dist/liquidity.js +43 -0
  62. package/dist/mcp-server.js +43 -96
  63. package/dist/signer/evm-local.d.ts +12 -0
  64. package/dist/signer/evm-local.js +19 -0
  65. package/dist/signer/index.d.ts +3 -0
  66. package/dist/signer/index.js +2 -0
  67. package/dist/signer/interface.d.ts +31 -0
  68. package/dist/signer/interface.js +7 -0
  69. package/dist/signer/solana-local.d.ts +13 -0
  70. package/dist/signer/solana-local.js +19 -0
  71. package/dist/smart-order.js +14 -3
  72. package/dist/strategies/split-order.d.ts +49 -0
  73. package/dist/strategies/split-order.js +138 -0
  74. package/dist/utils.js +7 -1
  75. package/dist/ws/market-feed.d.ts +74 -0
  76. package/dist/ws/market-feed.js +227 -0
  77. package/package.json +1 -1
  78. package/skills/perp-cli/SKILL.md +80 -4
  79. package/skills/perp-cli/references/agent-operations.md +19 -9
  80. package/skills/perp-cli/references/commands.md +54 -32
  81. package/skills/perp-cli/references/strategies.md +27 -17
  82. package/skills/perp-cli/scripts/arb-monitor.sh +74 -0
  83. package/skills/perp-cli/scripts/funding-analysis.sh +85 -0
  84. package/skills/perp-cli/scripts/preflight.sh +98 -0
  85. package/skills/perp-cli/scripts/spot-perp-scan.sh +83 -0
  86. package/skills/perp-cli/scripts/validate-arb.sh +112 -0
  87. package/skills/perp-cli/templates/arb-scan.sh +0 -15
  88. package/skills/perp-cli/templates/open-position.sh +0 -38
  89. package/skills/perp-cli/templates/wallet-setup.sh +0 -17
@@ -1,93 +1,170 @@
1
1
  import { PacificaWSClient } from "../pacifica/index.js";
2
2
  import chalk from "chalk";
3
3
  import { formatUsd, formatPercent } from "../utils.js";
4
+ /** Create an HL or Lighter market feed, connected and ready. */
5
+ async function getMarketFeed(exchange) {
6
+ const { createMarketFeed } = await import("../ws/market-feed.js");
7
+ const feed = createMarketFeed(exchange);
8
+ await feed.connect();
9
+ process.on("SIGINT", () => { feed.close(); process.exit(0); });
10
+ return feed;
11
+ }
4
12
  export function registerStreamCommands(program, getNetwork, getExchange, getAdapter) {
5
13
  const stream = program.command("stream").description("Live WebSocket streams (Ctrl+C to stop)");
14
+ // ── stream prices ──
6
15
  stream
7
16
  .command("prices")
8
17
  .description("Stream live prices")
9
18
  .action(async () => {
10
- const ws = new PacificaWSClient({ network: getNetwork() });
11
- await ws.connect();
12
- ws.subscribe("prices");
13
- ws.on("prices", (msg) => {
14
- const data = msg;
15
- const d = data.data ?? data;
16
- if (Array.isArray(d)) {
17
- d.forEach((p) => {
18
- const mark = Number(p.mark ?? p.m ?? 0);
19
- const funding = Number(p.funding ?? p.f ?? 0);
20
- const sym = String(p.symbol ?? p.s ?? "").padEnd(10);
21
- console.log(`${chalk.white.bold(sym)} $${formatUsd(mark)} ${formatPercent(funding)}`);
22
- });
23
- }
24
- });
25
- console.log(chalk.cyan("Streaming prices... (Ctrl+C to stop)\n"));
19
+ const exchange = getExchange();
20
+ if (exchange === "pacifica") {
21
+ const ws = new PacificaWSClient({ network: getNetwork() });
22
+ await ws.connect();
23
+ ws.subscribe("prices");
24
+ ws.on("prices", (msg) => {
25
+ const data = msg;
26
+ const d = data.data ?? data;
27
+ if (Array.isArray(d)) {
28
+ d.forEach((p) => {
29
+ const mark = Number(p.mark ?? p.m ?? 0);
30
+ const funding = Number(p.funding ?? p.f ?? 0);
31
+ const sym = String(p.symbol ?? p.s ?? "").padEnd(10);
32
+ console.log(`${chalk.white.bold(sym)} $${formatUsd(mark)} ${formatPercent(funding)}`);
33
+ });
34
+ }
35
+ });
36
+ console.log(chalk.cyan("Streaming pacifica prices... (Ctrl+C to stop)\n"));
37
+ }
38
+ else {
39
+ const feed = await getMarketFeed(exchange);
40
+ feed.subscribePrices();
41
+ feed.on("prices", (updates) => {
42
+ for (const p of updates) {
43
+ const sym = p.symbol.padEnd(10);
44
+ console.log(`${chalk.white.bold(sym)} $${formatUsd(p.mid)}`);
45
+ }
46
+ });
47
+ console.log(chalk.cyan(`Streaming ${exchange} prices... (Ctrl+C to stop)\n`));
48
+ }
26
49
  await new Promise(() => { }); // keep alive
27
50
  });
51
+ // ── stream book ──
28
52
  stream
29
53
  .command("book <symbol>")
30
54
  .description("Stream orderbook updates")
31
55
  .action(async (symbol) => {
32
- const ws = new PacificaWSClient({ network: getNetwork() });
33
- await ws.connect();
34
- ws.subscribe("book", { symbol: symbol.toUpperCase() });
35
- ws.on("book", (msg) => {
36
- const data = msg;
37
- console.log(`${chalk.cyan(new Date().toLocaleTimeString())} ${JSON.stringify(data.data ?? data)}`);
38
- });
39
- console.log(chalk.cyan(`Streaming ${symbol.toUpperCase()} orderbook... (Ctrl+C to stop)\n`));
56
+ const exchange = getExchange();
57
+ const sym = symbol.toUpperCase();
58
+ if (exchange === "pacifica") {
59
+ const ws = new PacificaWSClient({ network: getNetwork() });
60
+ await ws.connect();
61
+ ws.subscribe("book", { symbol: sym });
62
+ ws.on("book", (msg) => {
63
+ const data = msg;
64
+ console.log(`${chalk.cyan(new Date().toLocaleTimeString())} ${JSON.stringify(data.data ?? data)}`);
65
+ });
66
+ }
67
+ else {
68
+ const feed = await getMarketFeed(exchange);
69
+ feed.subscribeBook(sym);
70
+ feed.on("book", (data) => {
71
+ const topBids = data.bids.slice(0, 5).map(([p, s]) => `${p}x${s}`).join(" ");
72
+ const topAsks = data.asks.slice(0, 5).map(([p, s]) => `${p}x${s}`).join(" ");
73
+ console.log(`${chalk.cyan(new Date().toLocaleTimeString())} ${chalk.green("BID")} ${topBids} ${chalk.red("ASK")} ${topAsks}`);
74
+ });
75
+ }
76
+ console.log(chalk.cyan(`Streaming ${sym} orderbook on ${exchange}... (Ctrl+C to stop)\n`));
40
77
  await new Promise(() => { });
41
78
  });
79
+ // ── stream trades ──
42
80
  stream
43
81
  .command("trades <symbol>")
44
82
  .description("Stream live trades")
45
83
  .action(async (symbol) => {
46
- const ws = new PacificaWSClient({ network: getNetwork() });
47
- await ws.connect();
48
- ws.subscribe("trades", { symbol: symbol.toUpperCase() });
49
- ws.on("trades", (msg) => {
50
- const data = msg;
51
- const d = (data.data ?? data);
52
- const side = String(d.side ?? d.d ?? "");
53
- const price = String(d.price ?? d.p ?? "");
54
- const amount = String(d.amount ?? d.a ?? "");
55
- const color = side === "bid" || side === "buy" ? chalk.green : chalk.red;
56
- console.log(`${chalk.gray(new Date().toLocaleTimeString())} ${color(side === "bid" ? "BUY " : "SELL")} $${formatUsd(price)} x ${amount}`);
57
- });
58
- console.log(chalk.cyan(`Streaming ${symbol.toUpperCase()} trades... (Ctrl+C to stop)\n`));
84
+ const exchange = getExchange();
85
+ const sym = symbol.toUpperCase();
86
+ if (exchange === "pacifica") {
87
+ const ws = new PacificaWSClient({ network: getNetwork() });
88
+ await ws.connect();
89
+ ws.subscribe("trades", { symbol: sym });
90
+ ws.on("trades", (msg) => {
91
+ const data = msg;
92
+ const d = (data.data ?? data);
93
+ const side = String(d.side ?? d.d ?? "");
94
+ const price = String(d.price ?? d.p ?? "");
95
+ const amount = String(d.amount ?? d.a ?? "");
96
+ const color = side === "bid" || side === "buy" ? chalk.green : chalk.red;
97
+ console.log(`${chalk.gray(new Date().toLocaleTimeString())} ${color(side === "bid" ? "BUY " : "SELL")} $${formatUsd(price)} x ${amount}`);
98
+ });
99
+ }
100
+ else {
101
+ const feed = await getMarketFeed(exchange);
102
+ feed.subscribeTrades(sym);
103
+ feed.on("trade", (t) => {
104
+ const color = t.side === "buy" ? chalk.green : chalk.red;
105
+ console.log(`${chalk.gray(new Date().toLocaleTimeString())} ${color(t.side === "buy" ? "BUY " : "SELL")} $${formatUsd(t.price)} x ${t.size}`);
106
+ });
107
+ }
108
+ console.log(chalk.cyan(`Streaming ${sym} trades on ${exchange}... (Ctrl+C to stop)\n`));
59
109
  await new Promise(() => { });
60
110
  });
111
+ // ── stream bbo ──
61
112
  stream
62
113
  .command("bbo <symbol>")
63
114
  .description("Stream best bid/offer")
64
115
  .action(async (symbol) => {
65
- const ws = new PacificaWSClient({ network: getNetwork() });
66
- await ws.connect();
67
- ws.subscribe("bbo", { symbol: symbol.toUpperCase() });
68
- ws.on("bbo", (msg) => {
69
- const data = msg.data ?? msg;
70
- console.log(`${chalk.gray(new Date().toLocaleTimeString())} ${JSON.stringify(data)}`);
71
- });
72
- console.log(chalk.cyan(`Streaming ${symbol.toUpperCase()} BBO... (Ctrl+C to stop)\n`));
116
+ const exchange = getExchange();
117
+ const sym = symbol.toUpperCase();
118
+ if (exchange === "pacifica") {
119
+ const ws = new PacificaWSClient({ network: getNetwork() });
120
+ await ws.connect();
121
+ ws.subscribe("bbo", { symbol: sym });
122
+ ws.on("bbo", (msg) => {
123
+ const data = msg.data ?? msg;
124
+ console.log(`${chalk.gray(new Date().toLocaleTimeString())} ${JSON.stringify(data)}`);
125
+ });
126
+ }
127
+ else {
128
+ // BBO derived from orderbook (HL/Lighter don't have dedicated BBO channel)
129
+ const feed = await getMarketFeed(exchange);
130
+ feed.subscribeBook(sym);
131
+ feed.on("book", (data) => {
132
+ const bid = data.bids[0] ?? ["—", "—"];
133
+ const ask = data.asks[0] ?? ["—", "—"];
134
+ console.log(`${chalk.gray(new Date().toLocaleTimeString())} ${chalk.green("bid")} ${bid[0]} (${bid[1]}) ${chalk.red("ask")} ${ask[0]} (${ask[1]})`);
135
+ });
136
+ }
137
+ console.log(chalk.cyan(`Streaming ${sym} BBO on ${exchange}... (Ctrl+C to stop)\n`));
73
138
  await new Promise(() => { });
74
139
  });
140
+ // ── stream candle ──
75
141
  stream
76
142
  .command("candle <symbol> <interval>")
77
143
  .description("Stream candlestick data")
78
144
  .action(async (symbol, interval) => {
79
- const ws = new PacificaWSClient({ network: getNetwork() });
80
- await ws.connect();
81
- ws.subscribe("candle", { symbol: symbol.toUpperCase(), interval });
82
- ws.on("candle", (msg) => {
83
- const data = msg.data ?? msg;
84
- const d = data;
85
- console.log(`${chalk.gray(new Date().toLocaleTimeString())} O:$${formatUsd(String(d.o ?? ""))} H:$${formatUsd(String(d.h ?? ""))} L:$${formatUsd(String(d.l ?? ""))} C:$${formatUsd(String(d.c ?? ""))} V:${d.v ?? ""}`);
86
- });
87
- console.log(chalk.cyan(`Streaming ${symbol.toUpperCase()} ${interval} candles... (Ctrl+C to stop)\n`));
145
+ const exchange = getExchange();
146
+ const sym = symbol.toUpperCase();
147
+ if (exchange === "pacifica") {
148
+ const ws = new PacificaWSClient({ network: getNetwork() });
149
+ await ws.connect();
150
+ ws.subscribe("candle", { symbol: sym, interval });
151
+ ws.on("candle", (msg) => {
152
+ const data = msg.data ?? msg;
153
+ const d = data;
154
+ console.log(`${chalk.gray(new Date().toLocaleTimeString())} O:$${formatUsd(String(d.o ?? ""))} H:$${formatUsd(String(d.h ?? ""))} L:$${formatUsd(String(d.l ?? ""))} C:$${formatUsd(String(d.c ?? ""))} V:${d.v ?? ""}`);
155
+ });
156
+ }
157
+ else {
158
+ const feed = await getMarketFeed(exchange);
159
+ feed.subscribeCandle(sym, interval);
160
+ feed.on("candle", (d) => {
161
+ console.log(`${chalk.gray(new Date().toLocaleTimeString())} O:$${formatUsd(d.o)} H:$${formatUsd(d.h)} L:$${formatUsd(d.l)} C:$${formatUsd(d.c)} V:${d.v}`);
162
+ });
163
+ }
164
+ console.log(chalk.cyan(`Streaming ${sym} ${interval} candles on ${exchange}... (Ctrl+C to stop)\n`));
88
165
  await new Promise(() => { });
89
166
  });
90
- // ── stream events ── (unified account events as NDJSON)
167
+ // ── stream events ── (unified account events as NDJSON, already exchange-agnostic)
91
168
  if (getAdapter) {
92
169
  stream
93
170
  .command("events")
@@ -1,3 +1,3 @@
1
1
  import { Command } from "commander";
2
2
  import type { ExchangeAdapter } from "../exchanges/interface.js";
3
- export declare function registerTradeCommands(program: Command, getAdapter: () => Promise<ExchangeAdapter>, isJson: () => boolean, isDryRun?: () => boolean): void;
3
+ export declare function registerTradeCommands(program: Command, getAdapter: () => Promise<ExchangeAdapter>, isJson: () => boolean, isDryRun?: () => boolean, getAdapterForExchange?: (exchange: string) => Promise<ExchangeAdapter>): void;