perp-cli 0.9.8 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (254) hide show
  1. package/README.md +30 -25
  2. package/dist/_stderr-filter.d.ts +0 -0
  3. package/dist/_stderr-filter.js +30 -0
  4. package/dist/agent-wallet/expiry.d.ts +15 -0
  5. package/dist/agent-wallet/expiry.js +26 -0
  6. package/dist/agent-wallet/lighter-keystore.d.ts +34 -0
  7. package/dist/agent-wallet/lighter-keystore.js +232 -0
  8. package/dist/agent-wallet/passphrase.d.ts +13 -0
  9. package/dist/agent-wallet/passphrase.js +54 -0
  10. package/dist/agent-wallet/signing-strategy.d.ts +67 -0
  11. package/dist/agent-wallet/signing-strategy.js +51 -0
  12. package/dist/agent-wallet/store.d.ts +37 -0
  13. package/dist/agent-wallet/store.js +172 -0
  14. package/dist/api/public/_http.d.ts +15 -0
  15. package/dist/api/public/_http.js +24 -0
  16. package/dist/api/public/hyperliquid.js +36 -24
  17. package/dist/api/public/lighter.d.ts +7 -1
  18. package/dist/api/public/lighter.js +85 -37
  19. package/dist/api/public/pacifica.js +47 -18
  20. package/dist/bot/engine.js +23 -4
  21. package/dist/bot/presets.js +3 -3
  22. package/dist/bot/strategies/funding-arb-strategy.d.ts +0 -23
  23. package/dist/bot/strategies/funding-arb-strategy.js +41 -176
  24. package/dist/bot/strategies/funding-auto.js +2 -2
  25. package/dist/bridge-engine.js +102 -49
  26. package/dist/cli-spec.js +1 -2
  27. package/dist/commands/account.js +2 -500
  28. package/dist/commands/agent.d.ts +8 -2
  29. package/dist/commands/agent.js +1903 -366
  30. package/dist/commands/alerts.js +3 -1
  31. package/dist/commands/arb/index.js +37 -7
  32. package/dist/commands/arb-auto.js +44 -11
  33. package/dist/commands/arb.js +83 -34
  34. package/dist/commands/bot.d.ts +1 -1
  35. package/dist/commands/bot.js +20 -16
  36. package/dist/commands/bridge.d.ts +1 -1
  37. package/dist/commands/bridge.js +4 -4
  38. package/dist/commands/funds.d.ts +1 -1
  39. package/dist/commands/funds.js +18 -68
  40. package/dist/commands/jobs.d.ts +1 -1
  41. package/dist/commands/jobs.js +2 -2
  42. package/dist/commands/manage.d.ts +1 -1
  43. package/dist/commands/manage.js +12 -84
  44. package/dist/commands/plan.d.ts +1 -1
  45. package/dist/commands/plan.js +2 -2
  46. package/dist/commands/portfolio.d.ts +19 -3
  47. package/dist/commands/portfolio.js +747 -163
  48. package/dist/commands/rebalance.d.ts +1 -1
  49. package/dist/commands/rebalance.js +18 -12
  50. package/dist/commands/risk.js +2 -6
  51. package/dist/commands/settings.js +30 -53
  52. package/dist/commands/trade.js +16 -15
  53. package/dist/commands/wallet.d.ts +2 -1
  54. package/dist/commands/wallet.js +1122 -176
  55. package/dist/config.d.ts +9 -0
  56. package/dist/config.js +55 -9
  57. package/dist/errors.d.ts +64 -0
  58. package/dist/errors.js +82 -2
  59. package/dist/event-stream.js +12 -1
  60. package/dist/exchanges/aster-typed-data.d.ts +156 -0
  61. package/dist/exchanges/aster-typed-data.js +189 -0
  62. package/dist/exchanges/aster.d.ts +60 -11
  63. package/dist/exchanges/aster.js +278 -136
  64. package/dist/exchanges/hyperliquid.d.ts +14 -0
  65. package/dist/exchanges/hyperliquid.js +88 -34
  66. package/dist/exchanges/lighter-spot.js +19 -5
  67. package/dist/exchanges/lighter.d.ts +66 -0
  68. package/dist/exchanges/lighter.js +213 -31
  69. package/dist/exchanges/pacifica-typed-data.d.ts +75 -0
  70. package/dist/exchanges/pacifica-typed-data.js +74 -0
  71. package/dist/exchanges/pacifica.d.ts +29 -1
  72. package/dist/exchanges/pacifica.js +94 -6
  73. package/dist/funding/rates.js +59 -21
  74. package/dist/guardrail/contracts.d.ts +14 -0
  75. package/dist/guardrail/contracts.js +72 -0
  76. package/dist/guardrail/perp-guardrail.d.ts +21 -0
  77. package/dist/guardrail/perp-guardrail.js +145 -0
  78. package/dist/index.d.ts +1 -1
  79. package/dist/index.js +307 -362
  80. package/dist/jobs.js +3 -1
  81. package/dist/mcp-server.js +92 -88
  82. package/dist/position-history.js +47 -4
  83. package/dist/settings.d.ts +69 -3
  84. package/dist/settings.js +3 -2
  85. package/dist/signer/index.d.ts +2 -0
  86. package/dist/signer/index.js +2 -0
  87. package/dist/signer/ows-evm.d.ts +32 -0
  88. package/dist/signer/ows-evm.js +86 -0
  89. package/dist/signer/ows-loader.d.ts +2 -0
  90. package/dist/signer/ows-loader.js +6 -0
  91. package/dist/signer/ows-solana.d.ts +25 -0
  92. package/dist/signer/ows-solana.js +56 -0
  93. package/dist/smart-order.d.ts +8 -2
  94. package/dist/smart-order.js +46 -11
  95. package/dist/strategies/funding-arb.js +29 -8
  96. package/dist/trade-validator.js +30 -5
  97. package/dist/utils.d.ts +10 -0
  98. package/dist/utils.js +19 -0
  99. package/package.json +4 -2
  100. package/skills/perp-cli/SKILL.md +23 -14
  101. package/skills/perp-cli/references/agent-operations.md +6 -4
  102. package/skills/perp-cli/references/commands.md +55 -34
  103. package/skills/perp-cli/scripts/preflight.sh +4 -4
  104. package/skills/perp-cli/scripts/spot-perp-scan.sh +2 -2
  105. package/dist/__tests__/alert-logic.test.d.ts +0 -1
  106. package/dist/__tests__/alert-logic.test.js +0 -107
  107. package/dist/__tests__/arb-auto-3dex.test.d.ts +0 -1
  108. package/dist/__tests__/arb-auto-3dex.test.js +0 -397
  109. package/dist/__tests__/arb-history-stats.test.d.ts +0 -1
  110. package/dist/__tests__/arb-history-stats.test.js +0 -176
  111. package/dist/__tests__/arb-logic.test.d.ts +0 -1
  112. package/dist/__tests__/arb-logic.test.js +0 -84
  113. package/dist/__tests__/arb-manage.test.d.ts +0 -1
  114. package/dist/__tests__/arb-manage.test.js +0 -253
  115. package/dist/__tests__/arb-new-features.test.d.ts +0 -1
  116. package/dist/__tests__/arb-new-features.test.js +0 -457
  117. package/dist/__tests__/arb-sizing.test.d.ts +0 -1
  118. package/dist/__tests__/arb-sizing.test.js +0 -48
  119. package/dist/__tests__/arb-state.test.d.ts +0 -1
  120. package/dist/__tests__/arb-state.test.js +0 -284
  121. package/dist/__tests__/arb-userflow.test.d.ts +0 -1
  122. package/dist/__tests__/arb-userflow.test.js +0 -945
  123. package/dist/__tests__/arb-utils.test.d.ts +0 -1
  124. package/dist/__tests__/arb-utils.test.js +0 -264
  125. package/dist/__tests__/bot-conditions.test.d.ts +0 -1
  126. package/dist/__tests__/bot-conditions.test.js +0 -341
  127. package/dist/__tests__/client-id-tracker.test.d.ts +0 -1
  128. package/dist/__tests__/client-id-tracker.test.js +0 -137
  129. package/dist/__tests__/commands/new-atomic-commands.test.d.ts +0 -1
  130. package/dist/__tests__/commands/new-atomic-commands.test.js +0 -502
  131. package/dist/__tests__/commands/order-intent.test.d.ts +0 -1
  132. package/dist/__tests__/commands/order-intent.test.js +0 -600
  133. package/dist/__tests__/commands/trade-commands.test.d.ts +0 -1
  134. package/dist/__tests__/commands/trade-commands.test.js +0 -821
  135. package/dist/__tests__/config.test.d.ts +0 -1
  136. package/dist/__tests__/config.test.js +0 -86
  137. package/dist/__tests__/cross-chain-margin.test.d.ts +0 -1
  138. package/dist/__tests__/cross-chain-margin.test.js +0 -287
  139. package/dist/__tests__/dex-asset-map.test.d.ts +0 -1
  140. package/dist/__tests__/dex-asset-map.test.js +0 -191
  141. package/dist/__tests__/errors.test.d.ts +0 -1
  142. package/dist/__tests__/errors.test.js +0 -110
  143. package/dist/__tests__/event-stream.test.d.ts +0 -1
  144. package/dist/__tests__/event-stream.test.js +0 -276
  145. package/dist/__tests__/exchanges/interface.test.d.ts +0 -1
  146. package/dist/__tests__/exchanges/interface.test.js +0 -132
  147. package/dist/__tests__/exchanges/mock-adapter.d.ts +0 -69
  148. package/dist/__tests__/exchanges/mock-adapter.js +0 -137
  149. package/dist/__tests__/execution-log.test.d.ts +0 -1
  150. package/dist/__tests__/execution-log.test.js +0 -106
  151. package/dist/__tests__/funding-calc.test.d.ts +0 -1
  152. package/dist/__tests__/funding-calc.test.js +0 -71
  153. package/dist/__tests__/funding-history.test.d.ts +0 -1
  154. package/dist/__tests__/funding-history.test.js +0 -343
  155. package/dist/__tests__/funding-rates.test.d.ts +0 -1
  156. package/dist/__tests__/funding-rates.test.js +0 -342
  157. package/dist/__tests__/funding.test.d.ts +0 -1
  158. package/dist/__tests__/funding.test.js +0 -173
  159. package/dist/__tests__/gap-logic.test.d.ts +0 -1
  160. package/dist/__tests__/gap-logic.test.js +0 -43
  161. package/dist/__tests__/hip3-dex.test.d.ts +0 -1
  162. package/dist/__tests__/hip3-dex.test.js +0 -234
  163. package/dist/__tests__/integration/agent-features.integration.test.d.ts +0 -1
  164. package/dist/__tests__/integration/agent-features.integration.test.js +0 -553
  165. package/dist/__tests__/integration/atomic-commands.integration.test.d.ts +0 -13
  166. package/dist/__tests__/integration/atomic-commands.integration.test.js +0 -246
  167. package/dist/__tests__/integration/bridge-simulation.integration.test.d.ts +0 -1
  168. package/dist/__tests__/integration/bridge-simulation.integration.test.js +0 -453
  169. package/dist/__tests__/integration/bridge-strict.integration.test.d.ts +0 -1
  170. package/dist/__tests__/integration/bridge-strict.integration.test.js +0 -812
  171. package/dist/__tests__/integration/bridge.integration.test.d.ts +0 -1
  172. package/dist/__tests__/integration/bridge.integration.test.js +0 -309
  173. package/dist/__tests__/integration/cli-e2e.integration.test.d.ts +0 -1
  174. package/dist/__tests__/integration/cli-e2e.integration.test.js +0 -202
  175. package/dist/__tests__/integration/dex-arb.integration.test.d.ts +0 -1
  176. package/dist/__tests__/integration/dex-arb.integration.test.js +0 -116
  177. package/dist/__tests__/integration/envelope-consistency.integration.test.d.ts +0 -13
  178. package/dist/__tests__/integration/envelope-consistency.integration.test.js +0 -205
  179. package/dist/__tests__/integration/hip3-dex.integration.test.d.ts +0 -1
  180. package/dist/__tests__/integration/hip3-dex.integration.test.js +0 -147
  181. package/dist/__tests__/integration/hyperliquid.integration.test.d.ts +0 -1
  182. package/dist/__tests__/integration/hyperliquid.integration.test.js +0 -79
  183. package/dist/__tests__/integration/lighter.integration.test.d.ts +0 -1
  184. package/dist/__tests__/integration/lighter.integration.test.js +0 -53
  185. package/dist/__tests__/integration/new-commands-e2e.integration.test.d.ts +0 -9
  186. package/dist/__tests__/integration/new-commands-e2e.integration.test.js +0 -236
  187. package/dist/__tests__/integration/order-verification.integration.test.d.ts +0 -1
  188. package/dist/__tests__/integration/order-verification.integration.test.js +0 -321
  189. package/dist/__tests__/integration/pacifica.integration.test.d.ts +0 -1
  190. package/dist/__tests__/integration/pacifica.integration.test.js +0 -75
  191. package/dist/__tests__/integration/response-shapes.integration.test.d.ts +0 -1
  192. package/dist/__tests__/integration/response-shapes.integration.test.js +0 -278
  193. package/dist/__tests__/liquidity.test.d.ts +0 -1
  194. package/dist/__tests__/liquidity.test.js +0 -225
  195. package/dist/__tests__/plan-executor.test.d.ts +0 -1
  196. package/dist/__tests__/plan-executor.test.js +0 -314
  197. package/dist/__tests__/position-history.test.d.ts +0 -1
  198. package/dist/__tests__/position-history.test.js +0 -367
  199. package/dist/__tests__/retry.test.d.ts +0 -1
  200. package/dist/__tests__/retry.test.js +0 -310
  201. package/dist/__tests__/risk-assessment.test.d.ts +0 -1
  202. package/dist/__tests__/risk-assessment.test.js +0 -288
  203. package/dist/__tests__/security-adversarial.test.d.ts +0 -1
  204. package/dist/__tests__/security-adversarial.test.js +0 -574
  205. package/dist/__tests__/strategies.test.d.ts +0 -1
  206. package/dist/__tests__/strategies.test.js +0 -539
  207. package/dist/__tests__/trade-execution.test.d.ts +0 -1
  208. package/dist/__tests__/trade-execution.test.js +0 -129
  209. package/dist/__tests__/trade-validator.test.d.ts +0 -1
  210. package/dist/__tests__/trade-validator.test.js +0 -655
  211. package/dist/__tests__/utils.test.d.ts +0 -1
  212. package/dist/__tests__/utils.test.js +0 -76
  213. package/dist/arb/reconcile.d.ts +0 -28
  214. package/dist/arb/reconcile.js +0 -162
  215. package/dist/commands/alert.d.ts +0 -2
  216. package/dist/commands/alert.js +0 -421
  217. package/dist/commands/analytics.d.ts +0 -3
  218. package/dist/commands/analytics.js +0 -311
  219. package/dist/commands/arb-manage.d.ts +0 -5
  220. package/dist/commands/arb-manage.js +0 -5
  221. package/dist/commands/dashboard.d.ts +0 -3
  222. package/dist/commands/dashboard.js +0 -176
  223. package/dist/commands/deposit.d.ts +0 -4
  224. package/dist/commands/deposit.js +0 -573
  225. package/dist/commands/dex.d.ts +0 -3
  226. package/dist/commands/dex.js +0 -120
  227. package/dist/commands/env.d.ts +0 -2
  228. package/dist/commands/env.js +0 -136
  229. package/dist/commands/funding.d.ts +0 -3
  230. package/dist/commands/funding.js +0 -554
  231. package/dist/commands/gap.d.ts +0 -2
  232. package/dist/commands/gap.js +0 -305
  233. package/dist/commands/health.d.ts +0 -2
  234. package/dist/commands/health.js +0 -67
  235. package/dist/commands/multileg.d.ts +0 -16
  236. package/dist/commands/multileg.js +0 -174
  237. package/dist/commands/pnl.d.ts +0 -12
  238. package/dist/commands/pnl.js +0 -243
  239. package/dist/commands/run.d.ts +0 -3
  240. package/dist/commands/run.js +0 -202
  241. package/dist/commands/stream.d.ts +0 -5
  242. package/dist/commands/stream.js +0 -200
  243. package/dist/commands/withdraw.d.ts +0 -3
  244. package/dist/commands/withdraw.js +0 -187
  245. package/dist/exchanges/edgex.d.ts +0 -62
  246. package/dist/exchanges/edgex.js +0 -552
  247. package/dist/exchanges/nado.d.ts +0 -52
  248. package/dist/exchanges/nado.js +0 -223
  249. package/dist/funding/index.d.ts +0 -3
  250. package/dist/funding/index.js +0 -3
  251. package/dist/retry.d.ts +0 -74
  252. package/dist/retry.js +0 -129
  253. package/dist/ws/market-feed.d.ts +0 -74
  254. package/dist/ws/market-feed.js +0 -227
@@ -1,246 +0,0 @@
1
- /**
2
- * Integration tests for new atomic commands against Hyperliquid mainnet (read-only).
3
- *
4
- * Tests:
5
- * - market mid: real orderbook mid price
6
- * - account margin: position-not-found for dummy/real account
7
- * - trade status: order-not-found for dummy order
8
- * - trade fills: empty fills for dummy account / real fills if any
9
- * - Error response shapes and classification
10
- *
11
- * Requires: HYPERLIQUID_PRIVATE_KEY or HL_PRIVATE_KEY env var
12
- */
13
- import "dotenv/config";
14
- import { describe, it, expect, beforeAll } from "vitest";
15
- import { HyperliquidAdapter } from "../../exchanges/hyperliquid.js";
16
- const HL_KEY = process.env.HYPERLIQUID_PRIVATE_KEY || process.env.HL_PRIVATE_KEY;
17
- const SKIP = !HL_KEY;
18
- describe.skipIf(SKIP)("Atomic Commands — Hyperliquid Mainnet", { timeout: 30000 }, () => {
19
- let adapter;
20
- beforeAll(async () => {
21
- const pk = HL_KEY;
22
- adapter = new HyperliquidAdapter(pk, false); // mainnet
23
- await adapter.init();
24
- });
25
- // ══════════════════════════════════════════════════════════
26
- // market mid: orderbook-based mid price
27
- // ══════════════════════════════════════════════════════════
28
- describe("market mid (orderbook mid price)", () => {
29
- it("BTC orderbook has valid bids, asks, and computable mid", async () => {
30
- const book = await adapter.getOrderbook("BTC");
31
- expect(book.bids.length).toBeGreaterThan(0);
32
- expect(book.asks.length).toBeGreaterThan(0);
33
- const bestBid = parseFloat(book.bids[0][0]);
34
- const bestAsk = parseFloat(book.asks[0][0]);
35
- const mid = (bestBid + bestAsk) / 2;
36
- expect(bestBid).toBeGreaterThan(0);
37
- expect(bestAsk).toBeGreaterThan(bestBid);
38
- expect(mid).toBeGreaterThan(100); // BTC is > $100
39
- // Spread should be tiny for BTC
40
- const spreadPct = ((bestAsk - bestBid) / mid) * 100;
41
- expect(spreadPct).toBeLessThan(0.1); // < 0.1%
42
- });
43
- it("ETH orderbook has valid mid price", async () => {
44
- const book = await adapter.getOrderbook("ETH");
45
- const bestBid = parseFloat(book.bids[0][0]);
46
- const bestAsk = parseFloat(book.asks[0][0]);
47
- const mid = (bestBid + bestAsk) / 2;
48
- expect(mid).toBeGreaterThan(10); // ETH > $10
49
- expect(bestAsk).toBeGreaterThan(bestBid);
50
- });
51
- it("SOL orderbook has valid mid price", async () => {
52
- const book = await adapter.getOrderbook("SOL");
53
- const bestBid = parseFloat(book.bids[0][0]);
54
- const bestAsk = parseFloat(book.asks[0][0]);
55
- expect(bestBid).toBeGreaterThan(0);
56
- expect(bestAsk).toBeGreaterThan(bestBid);
57
- });
58
- it("orderbook sizes are positive numbers", async () => {
59
- const book = await adapter.getOrderbook("BTC");
60
- for (const [price, size] of book.bids.slice(0, 5)) {
61
- expect(parseFloat(price)).toBeGreaterThan(0);
62
- expect(parseFloat(size)).toBeGreaterThan(0);
63
- }
64
- for (const [price, size] of book.asks.slice(0, 5)) {
65
- expect(parseFloat(price)).toBeGreaterThan(0);
66
- expect(parseFloat(size)).toBeGreaterThan(0);
67
- }
68
- });
69
- it("bids are sorted descending, asks are sorted ascending", async () => {
70
- const book = await adapter.getOrderbook("BTC");
71
- for (let i = 1; i < Math.min(book.bids.length, 5); i++) {
72
- expect(parseFloat(book.bids[i - 1][0])).toBeGreaterThanOrEqual(parseFloat(book.bids[i][0]));
73
- }
74
- for (let i = 1; i < Math.min(book.asks.length, 5); i++) {
75
- expect(parseFloat(book.asks[i - 1][0])).toBeLessThanOrEqual(parseFloat(book.asks[i][0]));
76
- }
77
- });
78
- });
79
- // ══════════════════════════════════════════════════════════
80
- // account margin: position margin details
81
- // ══════════════════════════════════════════════════════════
82
- describe("account margin (position margin details)", () => {
83
- it("getBalance returns all required fields as strings", async () => {
84
- const balance = await adapter.getBalance();
85
- expect(typeof balance.equity).toBe("string");
86
- expect(typeof balance.available).toBe("string");
87
- expect(typeof balance.marginUsed).toBe("string");
88
- expect(typeof balance.unrealizedPnl).toBe("string");
89
- // Numbers should be parseable
90
- expect(isNaN(parseFloat(balance.equity))).toBe(false);
91
- expect(isNaN(parseFloat(balance.available))).toBe(false);
92
- });
93
- it("getPositions returns array with valid position shapes", async () => {
94
- const positions = await adapter.getPositions();
95
- expect(Array.isArray(positions)).toBe(true);
96
- for (const pos of positions) {
97
- expect(typeof pos.symbol).toBe("string");
98
- expect(["long", "short"]).toContain(pos.side);
99
- expect(typeof pos.size).toBe("string");
100
- expect(parseFloat(pos.size)).toBeGreaterThan(0);
101
- expect(typeof pos.entryPrice).toBe("string");
102
- expect(typeof pos.markPrice).toBe("string");
103
- expect(typeof pos.liquidationPrice).toBe("string");
104
- expect(typeof pos.unrealizedPnl).toBe("string");
105
- expect(typeof pos.leverage).toBe("number");
106
- expect(pos.leverage).toBeGreaterThan(0);
107
- }
108
- });
109
- it("margin calculation is correct for any open position", async () => {
110
- const [balance, positions] = await Promise.all([
111
- adapter.getBalance(),
112
- adapter.getPositions(),
113
- ]);
114
- if (positions.length === 0) {
115
- // No positions — margin used should be 0 or very small
116
- expect(parseFloat(balance.marginUsed)).toBeLessThanOrEqual(1);
117
- return;
118
- }
119
- // For each position, verify margin math
120
- for (const pos of positions) {
121
- const notional = Math.abs(parseFloat(pos.size) * parseFloat(pos.markPrice));
122
- const marginRequired = pos.leverage > 0 ? notional / pos.leverage : 0;
123
- // Sanity: margin should be less than equity
124
- expect(marginRequired).toBeLessThan(parseFloat(balance.equity) * 10); // allow for extreme leverage
125
- expect(notional).toBeGreaterThan(0);
126
- }
127
- });
128
- });
129
- // ══════════════════════════════════════════════════════════
130
- // trade status: order lookup
131
- // ══════════════════════════════════════════════════════════
132
- describe("trade status (order status query)", () => {
133
- it("queryOrder returns result for non-existent order", async () => {
134
- // HL returns a result object even for non-existent orders
135
- const result = await adapter.queryOrder(999999999);
136
- expect(result).toBeDefined();
137
- // The order field should be absent or status should indicate not found
138
- const status = result?.status;
139
- const order = result?.order;
140
- // HL returns { status: "order", order: { order: {...}, status: "unknownOid", statusTimestamp: ... } }
141
- // or similar structure
142
- expect(result).not.toBeNull();
143
- });
144
- it("open orders all have valid orderId for status lookup", async () => {
145
- const orders = await adapter.getOpenOrders();
146
- for (const order of orders) {
147
- expect(typeof order.orderId).toBe("string");
148
- expect(order.orderId.length).toBeGreaterThan(0);
149
- // If we have open orders, try querying one
150
- const result = await adapter.queryOrder(Number(order.orderId));
151
- expect(result).toBeDefined();
152
- }
153
- });
154
- });
155
- // ══════════════════════════════════════════════════════════
156
- // trade fills: recent fills
157
- // ══════════════════════════════════════════════════════════
158
- describe("trade fills (recent trade history)", () => {
159
- it("getTradeHistory returns array", async () => {
160
- const trades = await adapter.getTradeHistory(10);
161
- expect(Array.isArray(trades)).toBe(true);
162
- });
163
- it("each fill has correct shape if any exist", async () => {
164
- const trades = await adapter.getTradeHistory(10);
165
- for (const trade of trades) {
166
- expect(typeof trade.time).toBe("number");
167
- expect(trade.time).toBeGreaterThan(1600000000000); // after 2020
168
- expect(typeof trade.symbol).toBe("string");
169
- expect(trade.symbol.length).toBeGreaterThan(0);
170
- expect(["buy", "sell"]).toContain(trade.side);
171
- expect(typeof trade.price).toBe("string");
172
- expect(parseFloat(trade.price)).toBeGreaterThan(0);
173
- expect(typeof trade.size).toBe("string");
174
- expect(parseFloat(trade.size)).toBeGreaterThan(0);
175
- expect(typeof trade.fee).toBe("string");
176
- }
177
- });
178
- it("fills are returned in chronological order if multiple", async () => {
179
- const trades = await adapter.getTradeHistory(20);
180
- if (trades.length < 2)
181
- return; // skip if not enough fills
182
- for (let i = 1; i < trades.length; i++) {
183
- // HL returns newest first, so time should be descending
184
- expect(trades[i - 1].time).toBeGreaterThanOrEqual(trades[i].time);
185
- }
186
- });
187
- });
188
- // ══════════════════════════════════════════════════════════
189
- // Error classification on real errors
190
- // ══════════════════════════════════════════════════════════
191
- describe("error classification", () => {
192
- it("classifyError properly handles network-like errors", async () => {
193
- const { classifyError } = await import("../../errors.js");
194
- const timeout = classifyError(new Error("Request timed out"));
195
- expect(timeout.code).toBe("TIMEOUT");
196
- expect(timeout.retryable).toBe(true);
197
- const network = classifyError(new Error("ECONNREFUSED"));
198
- expect(network.code).toBe("EXCHANGE_UNREACHABLE");
199
- expect(network.retryable).toBe(true);
200
- const rateLimit = classifyError(new Error("429 Too Many Requests"));
201
- expect(rateLimit.code).toBe("RATE_LIMITED");
202
- expect(rateLimit.retryable).toBe(true);
203
- });
204
- it("classifyError properly handles trading errors", async () => {
205
- const { classifyError } = await import("../../errors.js");
206
- const balance = classifyError(new Error("Insufficient balance"));
207
- expect(balance.code).toBe("INSUFFICIENT_BALANCE");
208
- expect(balance.retryable).toBe(false);
209
- const margin = classifyError(new Error("Not enough margin"));
210
- expect(margin.code).toBe("MARGIN_INSUFFICIENT");
211
- expect(margin.retryable).toBe(false);
212
- });
213
- });
214
- // ══════════════════════════════════════════════════════════
215
- // Cross-cutting: response consistency
216
- // ══════════════════════════════════════════════════════════
217
- describe("response consistency across adapter methods", () => {
218
- it("all market data methods return consistent string-typed numbers", async () => {
219
- const markets = await adapter.getMarkets();
220
- expect(markets.length).toBeGreaterThan(0);
221
- // Check first 5 markets
222
- for (const m of markets.slice(0, 5)) {
223
- expect(typeof m.markPrice).toBe("string");
224
- expect(typeof m.indexPrice).toBe("string");
225
- expect(typeof m.fundingRate).toBe("string");
226
- expect(typeof m.volume24h).toBe("string");
227
- expect(typeof m.openInterest).toBe("string");
228
- expect(typeof m.maxLeverage).toBe("number");
229
- // All parseable
230
- expect(isNaN(parseFloat(m.markPrice))).toBe(false);
231
- expect(isNaN(parseFloat(m.fundingRate))).toBe(false);
232
- }
233
- });
234
- it("balance, positions, orders all return at the same time without errors", async () => {
235
- // This is what the status command does
236
- const [balance, positions, orders] = await Promise.all([
237
- adapter.getBalance(),
238
- adapter.getPositions(),
239
- adapter.getOpenOrders(),
240
- ]);
241
- expect(balance).toBeDefined();
242
- expect(Array.isArray(positions)).toBe(true);
243
- expect(Array.isArray(orders)).toBe(true);
244
- });
245
- });
246
- });