@raintree-technology/perps 0.1.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 (316) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/LICENSE +21 -0
  3. package/README.md +175 -0
  4. package/dist/adapters/aevo.d.ts +64 -0
  5. package/dist/adapters/aevo.js +899 -0
  6. package/dist/adapters/certification.d.ts +33 -0
  7. package/dist/adapters/certification.js +99 -0
  8. package/dist/adapters/decibel/order-manager.d.ts +45 -0
  9. package/dist/adapters/decibel/order-manager.js +140 -0
  10. package/dist/adapters/decibel/rest-client.d.ts +176 -0
  11. package/dist/adapters/decibel/rest-client.js +155 -0
  12. package/dist/adapters/decibel/ws-feed.d.ts +28 -0
  13. package/dist/adapters/decibel/ws-feed.js +166 -0
  14. package/dist/adapters/decibel.d.ts +108 -0
  15. package/dist/adapters/decibel.js +1377 -0
  16. package/dist/adapters/hyperliquid.d.ts +63 -0
  17. package/dist/adapters/hyperliquid.js +797 -0
  18. package/dist/adapters/index.d.ts +11 -0
  19. package/dist/adapters/index.js +12 -0
  20. package/dist/adapters/interface.d.ts +310 -0
  21. package/dist/adapters/interface.js +15 -0
  22. package/dist/adapters/orderly.d.ts +70 -0
  23. package/dist/adapters/orderly.js +936 -0
  24. package/dist/adapters/paradex.d.ts +69 -0
  25. package/dist/adapters/paradex.js +862 -0
  26. package/dist/adapters/utils.d.ts +17 -0
  27. package/dist/adapters/utils.js +122 -0
  28. package/dist/cli/command-metadata.d.ts +2 -0
  29. package/dist/cli/command-metadata.js +44 -0
  30. package/dist/cli/context.d.ts +14 -0
  31. package/dist/cli/context.js +59 -0
  32. package/dist/cli/experience.d.ts +48 -0
  33. package/dist/cli/experience.js +243 -0
  34. package/dist/cli/ink/app/AppShell.d.ts +12 -0
  35. package/dist/cli/ink/app/AppShell.js +32 -0
  36. package/dist/cli/ink/app/MetricStrip.d.ts +6 -0
  37. package/dist/cli/ink/app/MetricStrip.js +14 -0
  38. package/dist/cli/ink/app/Panel.d.ts +9 -0
  39. package/dist/cli/ink/app/Panel.js +7 -0
  40. package/dist/cli/ink/app/ascii.d.ts +2 -0
  41. package/dist/cli/ink/app/ascii.js +46 -0
  42. package/dist/cli/ink/app/index.d.ts +5 -0
  43. package/dist/cli/ink/app/index.js +4 -0
  44. package/dist/cli/ink/app/types.d.ts +15 -0
  45. package/dist/cli/ink/app/types.js +1 -0
  46. package/dist/cli/ink/components/PnL.d.ts +12 -0
  47. package/dist/cli/ink/components/PnL.js +23 -0
  48. package/dist/cli/ink/components/Spinner.d.ts +13 -0
  49. package/dist/cli/ink/components/Spinner.js +13 -0
  50. package/dist/cli/ink/components/Table.d.ts +14 -0
  51. package/dist/cli/ink/components/Table.js +42 -0
  52. package/dist/cli/ink/components/WatchHeader.d.ts +10 -0
  53. package/dist/cli/ink/components/WatchHeader.js +18 -0
  54. package/dist/cli/ink/components/index.d.ts +4 -0
  55. package/dist/cli/ink/components/index.js +4 -0
  56. package/dist/cli/ink/index.d.ts +4 -0
  57. package/dist/cli/ink/index.js +4 -0
  58. package/dist/cli/ink/render.d.ts +12 -0
  59. package/dist/cli/ink/render.js +21 -0
  60. package/dist/cli/ink/theme.d.ts +29 -0
  61. package/dist/cli/ink/theme.js +40 -0
  62. package/dist/cli/network-defaults.d.ts +10 -0
  63. package/dist/cli/network-defaults.js +35 -0
  64. package/dist/cli/output.d.ts +11 -0
  65. package/dist/cli/output.js +115 -0
  66. package/dist/cli/program.d.ts +18 -0
  67. package/dist/cli/program.js +164 -0
  68. package/dist/cli/watch.d.ts +19 -0
  69. package/dist/cli/watch.js +35 -0
  70. package/dist/client/index.d.ts +55 -0
  71. package/dist/client/index.js +157 -0
  72. package/dist/commands/account/add.d.ts +2 -0
  73. package/dist/commands/account/add.js +510 -0
  74. package/dist/commands/account/balances-simple.d.ts +5 -0
  75. package/dist/commands/account/balances-simple.js +63 -0
  76. package/dist/commands/account/index.d.ts +2 -0
  77. package/dist/commands/account/index.js +17 -0
  78. package/dist/commands/account/ls.d.ts +2 -0
  79. package/dist/commands/account/ls.js +95 -0
  80. package/dist/commands/account/positions-simple.d.ts +5 -0
  81. package/dist/commands/account/positions-simple.js +77 -0
  82. package/dist/commands/account/remove.d.ts +2 -0
  83. package/dist/commands/account/remove.js +47 -0
  84. package/dist/commands/account/set-default.d.ts +2 -0
  85. package/dist/commands/account/set-default.js +47 -0
  86. package/dist/commands/agent/index.d.ts +2 -0
  87. package/dist/commands/agent/index.js +126 -0
  88. package/dist/commands/arb/alert.d.ts +6 -0
  89. package/dist/commands/arb/alert.js +88 -0
  90. package/dist/commands/arb/basis-execute.d.ts +6 -0
  91. package/dist/commands/arb/basis-execute.js +332 -0
  92. package/dist/commands/arb/basis.d.ts +6 -0
  93. package/dist/commands/arb/basis.js +181 -0
  94. package/dist/commands/arb/compare.d.ts +6 -0
  95. package/dist/commands/arb/compare.js +216 -0
  96. package/dist/commands/arb/execute.d.ts +6 -0
  97. package/dist/commands/arb/execute.js +467 -0
  98. package/dist/commands/arb/funding.d.ts +6 -0
  99. package/dist/commands/arb/funding.js +201 -0
  100. package/dist/commands/arb/history.d.ts +6 -0
  101. package/dist/commands/arb/history.js +153 -0
  102. package/dist/commands/arb/index.d.ts +6 -0
  103. package/dist/commands/arb/index.js +29 -0
  104. package/dist/commands/arb/positions.d.ts +6 -0
  105. package/dist/commands/arb/positions.js +158 -0
  106. package/dist/commands/arb/spread.d.ts +6 -0
  107. package/dist/commands/arb/spread.js +253 -0
  108. package/dist/commands/arb/track.d.ts +6 -0
  109. package/dist/commands/arb/track.js +259 -0
  110. package/dist/commands/asset/book-simple.d.ts +5 -0
  111. package/dist/commands/asset/book-simple.js +77 -0
  112. package/dist/commands/asset/index.d.ts +2 -0
  113. package/dist/commands/asset/index.js +5 -0
  114. package/dist/commands/completion.d.ts +2 -0
  115. package/dist/commands/completion.js +161 -0
  116. package/dist/commands/config/index.d.ts +5 -0
  117. package/dist/commands/config/index.js +109 -0
  118. package/dist/commands/data/index.d.ts +31 -0
  119. package/dist/commands/data/index.js +1466 -0
  120. package/dist/commands/doctor.d.ts +2 -0
  121. package/dist/commands/doctor.js +201 -0
  122. package/dist/commands/exchange/index.d.ts +2 -0
  123. package/dist/commands/exchange/index.js +107 -0
  124. package/dist/commands/index.d.ts +2 -0
  125. package/dist/commands/index.js +48 -0
  126. package/dist/commands/markets/index.d.ts +2 -0
  127. package/dist/commands/markets/index.js +5 -0
  128. package/dist/commands/markets/ls-simple.d.ts +7 -0
  129. package/dist/commands/markets/ls-simple.js +277 -0
  130. package/dist/commands/operator/index.d.ts +2 -0
  131. package/dist/commands/operator/index.js +146 -0
  132. package/dist/commands/order/cancel-simple.d.ts +5 -0
  133. package/dist/commands/order/cancel-simple.js +104 -0
  134. package/dist/commands/order/index.d.ts +2 -0
  135. package/dist/commands/order/index.js +13 -0
  136. package/dist/commands/order/limit-simple.d.ts +5 -0
  137. package/dist/commands/order/limit-simple.js +195 -0
  138. package/dist/commands/order/market-simple.d.ts +5 -0
  139. package/dist/commands/order/market-simple.js +190 -0
  140. package/dist/commands/order/shared.d.ts +17 -0
  141. package/dist/commands/order/shared.js +51 -0
  142. package/dist/commands/order/trigger-simple.d.ts +5 -0
  143. package/dist/commands/order/trigger-simple.js +246 -0
  144. package/dist/commands/referral/index.d.ts +2 -0
  145. package/dist/commands/referral/index.js +7 -0
  146. package/dist/commands/referral/set.d.ts +2 -0
  147. package/dist/commands/referral/set.js +26 -0
  148. package/dist/commands/referral/status.d.ts +2 -0
  149. package/dist/commands/referral/status.js +31 -0
  150. package/dist/commands/replay/index.d.ts +2 -0
  151. package/dist/commands/replay/index.js +152 -0
  152. package/dist/commands/risk/analytics.d.ts +2 -0
  153. package/dist/commands/risk/analytics.js +64 -0
  154. package/dist/commands/risk/audit.d.ts +2 -0
  155. package/dist/commands/risk/audit.js +52 -0
  156. package/dist/commands/risk/index.d.ts +2 -0
  157. package/dist/commands/risk/index.js +9 -0
  158. package/dist/commands/risk/rules.d.ts +2 -0
  159. package/dist/commands/risk/rules.js +102 -0
  160. package/dist/commands/server.d.ts +2 -0
  161. package/dist/commands/server.js +208 -0
  162. package/dist/commands/setup/index.d.ts +2 -0
  163. package/dist/commands/setup/index.js +478 -0
  164. package/dist/commands/signal/index.d.ts +2 -0
  165. package/dist/commands/signal/index.js +129 -0
  166. package/dist/commands/state/index.d.ts +2 -0
  167. package/dist/commands/state/index.js +5 -0
  168. package/dist/commands/state/show.d.ts +2 -0
  169. package/dist/commands/state/show.js +105 -0
  170. package/dist/commands/strategy/index.d.ts +4 -0
  171. package/dist/commands/strategy/index.js +73 -0
  172. package/dist/commands/traces/index.d.ts +2 -0
  173. package/dist/commands/traces/index.js +76 -0
  174. package/dist/commands/ui/demo.d.ts +9 -0
  175. package/dist/commands/ui/demo.js +195 -0
  176. package/dist/commands/ui/index.d.ts +2 -0
  177. package/dist/commands/ui/index.js +7 -0
  178. package/dist/commands/ui/terminal.d.ts +2 -0
  179. package/dist/commands/ui/terminal.js +255 -0
  180. package/dist/commands/upgrade.d.ts +2 -0
  181. package/dist/commands/upgrade.js +98 -0
  182. package/dist/index.d.ts +2 -0
  183. package/dist/index.js +4 -0
  184. package/dist/lib/agent/audit.d.ts +12 -0
  185. package/dist/lib/agent/audit.js +13 -0
  186. package/dist/lib/agent/gateway.d.ts +13 -0
  187. package/dist/lib/agent/gateway.js +598 -0
  188. package/dist/lib/agent/metrics.d.ts +33 -0
  189. package/dist/lib/agent/metrics.js +175 -0
  190. package/dist/lib/agent/signature.d.ts +8 -0
  191. package/dist/lib/agent/signature.js +28 -0
  192. package/dist/lib/agent/tools.d.ts +28 -0
  193. package/dist/lib/agent/tools.js +453 -0
  194. package/dist/lib/agent/x402.d.ts +23 -0
  195. package/dist/lib/agent/x402.js +62 -0
  196. package/dist/lib/api-wallet.d.ts +69 -0
  197. package/dist/lib/api-wallet.js +101 -0
  198. package/dist/lib/balance-watcher.d.ts +25 -0
  199. package/dist/lib/balance-watcher.js +83 -0
  200. package/dist/lib/book-watcher.d.ts +25 -0
  201. package/dist/lib/book-watcher.js +48 -0
  202. package/dist/lib/config.d.ts +88 -0
  203. package/dist/lib/config.js +427 -0
  204. package/dist/lib/constants.d.ts +50 -0
  205. package/dist/lib/constants.js +84 -0
  206. package/dist/lib/contracts.d.ts +7 -0
  207. package/dist/lib/contracts.js +8 -0
  208. package/dist/lib/credential-vault.d.ts +22 -0
  209. package/dist/lib/credential-vault.js +109 -0
  210. package/dist/lib/db/accounts.d.ts +83 -0
  211. package/dist/lib/db/accounts.js +203 -0
  212. package/dist/lib/db/funding-history.d.ts +69 -0
  213. package/dist/lib/db/funding-history.js +183 -0
  214. package/dist/lib/db/index.d.ts +11 -0
  215. package/dist/lib/db/index.js +272 -0
  216. package/dist/lib/events/bus.d.ts +10 -0
  217. package/dist/lib/events/bus.js +17 -0
  218. package/dist/lib/events/types.d.ts +51 -0
  219. package/dist/lib/events/types.js +1 -0
  220. package/dist/lib/exchange.d.ts +30 -0
  221. package/dist/lib/exchange.js +84 -0
  222. package/dist/lib/execution/journal.d.ts +25 -0
  223. package/dist/lib/execution/journal.js +158 -0
  224. package/dist/lib/execution/safety.d.ts +34 -0
  225. package/dist/lib/execution/safety.js +197 -0
  226. package/dist/lib/exit-codes.d.ts +18 -0
  227. package/dist/lib/exit-codes.js +60 -0
  228. package/dist/lib/fetch.d.ts +18 -0
  229. package/dist/lib/fetch.js +66 -0
  230. package/dist/lib/fs-security.d.ts +10 -0
  231. package/dist/lib/fs-security.js +26 -0
  232. package/dist/lib/funding-tracker.d.ts +40 -0
  233. package/dist/lib/funding-tracker.js +118 -0
  234. package/dist/lib/logger.d.ts +27 -0
  235. package/dist/lib/logger.js +82 -0
  236. package/dist/lib/network-model.d.ts +13 -0
  237. package/dist/lib/network-model.js +30 -0
  238. package/dist/lib/onboarding.d.ts +133 -0
  239. package/dist/lib/onboarding.js +1459 -0
  240. package/dist/lib/operator-state.d.ts +25 -0
  241. package/dist/lib/operator-state.js +82 -0
  242. package/dist/lib/orders-watcher.d.ts +24 -0
  243. package/dist/lib/orders-watcher.js +74 -0
  244. package/dist/lib/paths.d.ts +20 -0
  245. package/dist/lib/paths.js +23 -0
  246. package/dist/lib/portfolio-watcher.d.ts +33 -0
  247. package/dist/lib/portfolio-watcher.js +95 -0
  248. package/dist/lib/position-watcher.d.ts +16 -0
  249. package/dist/lib/position-watcher.js +44 -0
  250. package/dist/lib/price-watcher.d.ts +15 -0
  251. package/dist/lib/price-watcher.js +84 -0
  252. package/dist/lib/prompts.d.ts +32 -0
  253. package/dist/lib/prompts.js +105 -0
  254. package/dist/lib/rate-limit.d.ts +32 -0
  255. package/dist/lib/rate-limit.js +88 -0
  256. package/dist/lib/risk/analytics.d.ts +39 -0
  257. package/dist/lib/risk/analytics.js +98 -0
  258. package/dist/lib/risk/drawdown.d.ts +18 -0
  259. package/dist/lib/risk/drawdown.js +49 -0
  260. package/dist/lib/risk/evaluation-log.d.ts +29 -0
  261. package/dist/lib/risk/evaluation-log.js +61 -0
  262. package/dist/lib/risk/index.d.ts +4 -0
  263. package/dist/lib/risk/index.js +4 -0
  264. package/dist/lib/risk/limits.d.ts +23 -0
  265. package/dist/lib/risk/limits.js +27 -0
  266. package/dist/lib/risk/manager.d.ts +32 -0
  267. package/dist/lib/risk/manager.js +85 -0
  268. package/dist/lib/risk/policy-middleware.d.ts +33 -0
  269. package/dist/lib/risk/policy-middleware.js +267 -0
  270. package/dist/lib/risk/position-sizer.d.ts +9 -0
  271. package/dist/lib/risk/position-sizer.js +14 -0
  272. package/dist/lib/risk/rules-store.d.ts +16 -0
  273. package/dist/lib/risk/rules-store.js +47 -0
  274. package/dist/lib/schema.d.ts +254 -0
  275. package/dist/lib/schema.js +199 -0
  276. package/dist/lib/secrets.d.ts +3 -0
  277. package/dist/lib/secrets.js +62 -0
  278. package/dist/lib/settings.d.ts +24 -0
  279. package/dist/lib/settings.js +86 -0
  280. package/dist/lib/signals.d.ts +73 -0
  281. package/dist/lib/signals.js +136 -0
  282. package/dist/lib/stable-stringify.d.ts +6 -0
  283. package/dist/lib/stable-stringify.js +17 -0
  284. package/dist/lib/state-context.d.ts +44 -0
  285. package/dist/lib/state-context.js +133 -0
  286. package/dist/lib/strategy/basis-trade.d.ts +2 -0
  287. package/dist/lib/strategy/basis-trade.js +24 -0
  288. package/dist/lib/strategy/funding-arb.d.ts +2 -0
  289. package/dist/lib/strategy/funding-arb.js +23 -0
  290. package/dist/lib/strategy/interface.d.ts +23 -0
  291. package/dist/lib/strategy/interface.js +1 -0
  292. package/dist/lib/strategy/registry.d.ts +4 -0
  293. package/dist/lib/strategy/registry.js +10 -0
  294. package/dist/lib/telemetry.d.ts +25 -0
  295. package/dist/lib/telemetry.js +101 -0
  296. package/dist/lib/trace-queries.d.ts +20 -0
  297. package/dist/lib/trace-queries.js +133 -0
  298. package/dist/lib/trace.d.ts +1 -0
  299. package/dist/lib/trace.js +4 -0
  300. package/dist/lib/trade-reputation.d.ts +6 -0
  301. package/dist/lib/trade-reputation.js +99 -0
  302. package/dist/lib/ui-tokens.d.ts +21 -0
  303. package/dist/lib/ui-tokens.js +26 -0
  304. package/dist/lib/validate.d.ts +39 -0
  305. package/dist/lib/validate.js +108 -0
  306. package/dist/lib/validation.d.ts +9 -0
  307. package/dist/lib/validation.js +64 -0
  308. package/dist/server/cache.d.ts +38 -0
  309. package/dist/server/cache.js +56 -0
  310. package/dist/server/index.d.ts +2 -0
  311. package/dist/server/index.js +89 -0
  312. package/dist/server/ipc.d.ts +18 -0
  313. package/dist/server/ipc.js +159 -0
  314. package/dist/server/subscriptions.d.ts +18 -0
  315. package/dist/server/subscriptions.js +114 -0
  316. package/package.json +124 -0
@@ -0,0 +1,797 @@
1
+ /**
2
+ * Hyperliquid Adapter
3
+ * Implements PerpDEXAdapter interface for Hyperliquid DEX
4
+ */
5
+ import { privateKeyToAccount } from "viem/accounts";
6
+ import { HttpTransport, InfoClient, ExchangeClient, } from "@nktkas/hyperliquid";
7
+ import { registerAdapter, } from "./interface.js";
8
+ export class HyperliquidAdapter {
9
+ info = {
10
+ id: "hyperliquid",
11
+ name: "Hyperliquid",
12
+ type: "dex",
13
+ chains: ["arbitrum"],
14
+ features: {
15
+ spot: true,
16
+ perp: true,
17
+ margin: true,
18
+ crossMargin: true,
19
+ isolatedMargin: true,
20
+ stopOrders: true,
21
+ takeProfitOrders: true,
22
+ postOnly: true,
23
+ reduceOnly: true,
24
+ subaccounts: true,
25
+ modifyOrders: true,
26
+ batchOrders: true,
27
+ cancelAllAfter: true,
28
+ publicTrades: true,
29
+ fundingHistory: false,
30
+ orderHistory: true,
31
+ mmp: false,
32
+ twapOrders: true,
33
+ },
34
+ urls: {
35
+ app: "https://app.hyperliquid.xyz",
36
+ api: "https://api.hyperliquid.xyz",
37
+ docs: "https://hyperliquid.gitbook.io/hyperliquid-docs",
38
+ testnet: "https://app.hyperliquid-testnet.xyz",
39
+ },
40
+ implementation: {
41
+ marketData: "full",
42
+ authenticatedReads: "full",
43
+ orderLifecycle: "full",
44
+ orderCancellation: "full",
45
+ subscriptions: "full",
46
+ advancedTrading: "full",
47
+ },
48
+ };
49
+ httpTransport = null;
50
+ wsTransport = null;
51
+ infoClient = null;
52
+ exchangeClient = null;
53
+ config = null;
54
+ walletAddress = null;
55
+ connected = false;
56
+ meta = null;
57
+ latestMarkPrices = new Map();
58
+ async connect(config) {
59
+ this.config = config;
60
+ const credentialNetwork = config.credentials?.network;
61
+ const isTestnet = credentialNetwork === "testnet"
62
+ ? true
63
+ : credentialNetwork === "mainnet"
64
+ ? false
65
+ : (config.testnet ?? false);
66
+ this.httpTransport = new HttpTransport({ isTestnet });
67
+ this.infoClient = new InfoClient({ transport: this.httpTransport });
68
+ if (config.credentials?.privateKey) {
69
+ const account = privateKeyToAccount(config.credentials.privateKey);
70
+ this.walletAddress = config.credentials.walletAddress || account.address;
71
+ this.exchangeClient = new ExchangeClient({
72
+ transport: this.httpTransport,
73
+ wallet: account,
74
+ });
75
+ }
76
+ else if (config.credentials?.walletAddress) {
77
+ this.walletAddress = config.credentials.walletAddress;
78
+ }
79
+ // Fetch metadata
80
+ this.meta = await this.infoClient.meta();
81
+ this.connected = true;
82
+ }
83
+ async disconnect() {
84
+ if (this.wsTransport) {
85
+ try {
86
+ await this.wsTransport.close();
87
+ }
88
+ catch {
89
+ // Best effort close for transport cleanup.
90
+ }
91
+ this.wsTransport = null;
92
+ }
93
+ this.config = null;
94
+ this.walletAddress = null;
95
+ this.meta = null;
96
+ this.httpTransport = null;
97
+ this.infoClient = null;
98
+ this.exchangeClient = null;
99
+ this.connected = false;
100
+ }
101
+ isConnected() {
102
+ return this.connected;
103
+ }
104
+ // --------------------------------------------------------------------------
105
+ // Public Market Data
106
+ // --------------------------------------------------------------------------
107
+ async getMarkets() {
108
+ this.ensureConnected();
109
+ if (!this.meta) {
110
+ this.meta = await this.infoClient.meta();
111
+ }
112
+ return this.meta.universe.map((asset) => ({
113
+ symbol: `${asset.name}-PERP`,
114
+ baseAsset: asset.name,
115
+ quoteAsset: "USD",
116
+ type: "perp",
117
+ maxLeverage: asset.maxLeverage,
118
+ minSize: Math.pow(10, -asset.szDecimals).toString(),
119
+ tickSize: "0.01", // Hyperliquid uses dynamic tick sizes
120
+ fundingInterval: 1, // Hourly
121
+ isActive: true,
122
+ }));
123
+ }
124
+ async getMarket(symbol) {
125
+ const markets = await this.getMarkets();
126
+ const normalized = symbol.toUpperCase().replace("-PERP", "");
127
+ return markets.find((m) => m.baseAsset === normalized) ?? null;
128
+ }
129
+ async getTicker(market) {
130
+ this.ensureConnected();
131
+ const coin = market.toUpperCase().replace("-PERP", "");
132
+ const ctxs = await this.infoClient.metaAndAssetCtxs();
133
+ const meta = ctxs[0];
134
+ const assetCtxs = ctxs[1];
135
+ const idx = meta.universe.findIndex((u) => u.name === coin);
136
+ if (idx === -1)
137
+ throw new Error(`Market ${market} not found`);
138
+ const ctx = assetCtxs[idx];
139
+ const prevDayPx = parseFloat(ctx.prevDayPx);
140
+ const change = prevDayPx > 0
141
+ ? ((parseFloat(ctx.markPx) - prevDayPx) / prevDayPx) * 100
142
+ : 0;
143
+ // Cache mark price for position enrichment
144
+ this.latestMarkPrices.set(coin, ctx.markPx);
145
+ // Fetch 24h candle for high/low
146
+ let high24h = "0";
147
+ let low24h = "0";
148
+ try {
149
+ const now = Date.now();
150
+ const oneDayAgo = now - 86_400_000;
151
+ const candles = await this.infoClient.candleSnapshot({
152
+ coin,
153
+ interval: "1d",
154
+ startTime: oneDayAgo,
155
+ endTime: now,
156
+ });
157
+ if (candles && candles.length > 0) {
158
+ high24h = candles[candles.length - 1].h;
159
+ low24h = candles[candles.length - 1].l;
160
+ }
161
+ }
162
+ catch {
163
+ // candleSnapshot may not be available for all coins
164
+ }
165
+ return {
166
+ market: `${coin}-PERP`,
167
+ lastPrice: ctx.markPx,
168
+ markPrice: ctx.markPx,
169
+ indexPrice: ctx.oraclePx,
170
+ bid: ctx.impactPxs?.[0] ?? ctx.markPx,
171
+ ask: ctx.impactPxs?.[1] ?? ctx.markPx,
172
+ volume24h: ctx.dayNtlVlm,
173
+ change24h: change.toFixed(2),
174
+ high24h,
175
+ low24h,
176
+ openInterest: ctx.openInterest,
177
+ fundingRate: ctx.funding,
178
+ timestamp: Date.now(),
179
+ };
180
+ }
181
+ async getTickers() {
182
+ this.ensureConnected();
183
+ const ctxs = await this.infoClient.metaAndAssetCtxs();
184
+ const meta = ctxs[0];
185
+ const assetCtxs = ctxs[1];
186
+ return meta.universe.map((asset, idx) => {
187
+ const ctx = assetCtxs[idx];
188
+ const prevDayPx = parseFloat(ctx.prevDayPx);
189
+ const change = prevDayPx > 0
190
+ ? ((parseFloat(ctx.markPx) - prevDayPx) / prevDayPx) * 100
191
+ : 0;
192
+ // Cache mark prices for position enrichment
193
+ this.latestMarkPrices.set(asset.name, ctx.markPx);
194
+ return {
195
+ market: `${asset.name}-PERP`,
196
+ lastPrice: ctx.markPx,
197
+ markPrice: ctx.markPx,
198
+ indexPrice: ctx.oraclePx,
199
+ bid: ctx.impactPxs?.[0] ?? ctx.markPx,
200
+ ask: ctx.impactPxs?.[1] ?? ctx.markPx,
201
+ volume24h: ctx.dayNtlVlm,
202
+ change24h: change.toFixed(2),
203
+ high24h: "0",
204
+ low24h: "0",
205
+ openInterest: ctx.openInterest,
206
+ fundingRate: ctx.funding,
207
+ timestamp: Date.now(),
208
+ };
209
+ });
210
+ }
211
+ async getOrderBook(market, depth = 20) {
212
+ this.ensureConnected();
213
+ const coin = market.toUpperCase().replace("-PERP", "");
214
+ const book = await this.infoClient.l2Book({ coin, nSigFigs: 5 });
215
+ const bids = book?.levels?.[0] ?? [];
216
+ const asks = book?.levels?.[1] ?? [];
217
+ return {
218
+ market: `${coin}-PERP`,
219
+ bids: bids.slice(0, depth).map((l) => ({ price: l.px, size: l.sz })),
220
+ asks: asks.slice(0, depth).map((l) => ({ price: l.px, size: l.sz })),
221
+ timestamp: Date.now(),
222
+ };
223
+ }
224
+ async getFundingRate(market) {
225
+ const ticker = await this.getTicker(market);
226
+ return {
227
+ market: ticker.market,
228
+ rate: ticker.fundingRate,
229
+ nextFundingTime: Date.now() + 3600000, // Approximate
230
+ timestamp: ticker.timestamp,
231
+ };
232
+ }
233
+ async getFundingRates() {
234
+ const tickers = await this.getTickers();
235
+ return tickers.map((t) => ({
236
+ market: t.market,
237
+ rate: t.fundingRate,
238
+ nextFundingTime: Date.now() + 3600000,
239
+ timestamp: t.timestamp,
240
+ }));
241
+ }
242
+ // --------------------------------------------------------------------------
243
+ // Account Data (requires auth)
244
+ // --------------------------------------------------------------------------
245
+ async getPositions() {
246
+ this.ensureAuth();
247
+ // Refresh mark prices from metaAndAssetCtxs for position enrichment
248
+ try {
249
+ const ctxs = await this.infoClient.metaAndAssetCtxs();
250
+ const meta = ctxs[0];
251
+ const assetCtxs = ctxs[1];
252
+ for (let i = 0; i < meta.universe.length; i++) {
253
+ this.latestMarkPrices.set(meta.universe[i].name, assetCtxs[i].markPx);
254
+ }
255
+ }
256
+ catch {
257
+ // Best effort - positions will still work with cached or entry prices
258
+ }
259
+ const state = await this.infoClient.clearinghouseState({ user: this.walletAddress });
260
+ const positions = state.assetPositions;
261
+ return positions
262
+ .filter((p) => parseFloat(p.position.szi) !== 0)
263
+ .map((p) => this.mapPosition(p.position));
264
+ }
265
+ async getPosition(market) {
266
+ const positions = await this.getPositions();
267
+ const coin = market.toUpperCase().replace("-PERP", "");
268
+ return positions.find((p) => p.market === `${coin}-PERP`) ?? null;
269
+ }
270
+ async getOrders(market) {
271
+ this.ensureAuth();
272
+ const orders = await this.infoClient.openOrders({ user: this.walletAddress });
273
+ const mapped = orders.map((o) => this.mapOrder(o));
274
+ if (market) {
275
+ const coin = market.toUpperCase().replace("-PERP", "");
276
+ return mapped.filter((o) => o.market === `${coin}-PERP`);
277
+ }
278
+ return mapped;
279
+ }
280
+ async getOrder(orderId) {
281
+ this.ensureAuth();
282
+ // Try direct orderStatus lookup first
283
+ try {
284
+ const status = await this.infoClient.orderStatus({
285
+ user: this.walletAddress,
286
+ oid: parseInt(orderId),
287
+ });
288
+ if (status.order) {
289
+ return this.mapOrder(status.order);
290
+ }
291
+ }
292
+ catch {
293
+ // Fall through to open orders scan
294
+ }
295
+ const orders = await this.getOrders();
296
+ return orders.find((o) => o.id === orderId) ?? null;
297
+ }
298
+ async getBalances() {
299
+ this.ensureAuth();
300
+ const state = await this.infoClient.clearinghouseState({ user: this.walletAddress });
301
+ // Calculate totals
302
+ const accountValue = parseFloat(state.marginSummary.accountValue);
303
+ const totalMarginUsed = parseFloat(state.marginSummary.totalMarginUsed);
304
+ // Unrealized PnL from positions
305
+ const positions = state.assetPositions;
306
+ const unrealizedPnl = positions.reduce((sum, p) => sum + parseFloat(p.position.unrealizedPnl || "0"), 0);
307
+ return [
308
+ {
309
+ asset: "USD",
310
+ total: accountValue.toString(),
311
+ available: (accountValue - totalMarginUsed).toString(),
312
+ locked: totalMarginUsed.toString(),
313
+ unrealizedPnl: unrealizedPnl.toString(),
314
+ marginUsed: totalMarginUsed.toString(),
315
+ },
316
+ ];
317
+ }
318
+ async getTrades(market, limit = 100) {
319
+ this.ensureAuth();
320
+ const fills = await this.infoClient.userFills({ user: this.walletAddress });
321
+ let mapped = fills.slice(0, limit).map((f) => this.mapFill(f));
322
+ if (market) {
323
+ const coin = market.toUpperCase().replace("-PERP", "");
324
+ mapped = mapped.filter((t) => t.market === `${coin}-PERP`);
325
+ }
326
+ return mapped;
327
+ }
328
+ // --------------------------------------------------------------------------
329
+ // Trading
330
+ // --------------------------------------------------------------------------
331
+ async placeOrder(params) {
332
+ this.ensureExchangeClient();
333
+ const coin = params.market.toUpperCase().replace("-PERP", "");
334
+ const isBuy = params.side === "long";
335
+ const isMarket = params.type === "market";
336
+ let orderType = isMarket
337
+ ? { market: {} }
338
+ : { limit: { tif: params.postOnly ? "Alo" : "Gtc" } };
339
+ if (params.type === "stop" || params.type === "stop_limit") {
340
+ if (!params.triggerPrice) {
341
+ throw new Error("triggerPrice is required for stop orders");
342
+ }
343
+ orderType = {
344
+ trigger: {
345
+ isMarket: params.type === "stop",
346
+ triggerPx: params.triggerPrice,
347
+ tpsl: "sl",
348
+ },
349
+ };
350
+ }
351
+ else if (params.type === "take_profit") {
352
+ if (!params.triggerPrice) {
353
+ throw new Error("triggerPrice is required for take_profit orders");
354
+ }
355
+ orderType = {
356
+ trigger: {
357
+ isMarket: true,
358
+ triggerPx: params.triggerPrice,
359
+ tpsl: "tp",
360
+ },
361
+ };
362
+ }
363
+ const orderRequest = {
364
+ coin,
365
+ is_buy: isBuy,
366
+ sz: parseFloat(params.size),
367
+ limit_px: isMarket ? null : parseFloat(params.price),
368
+ order_type: orderType,
369
+ reduce_only: params.reduceOnly ?? false,
370
+ };
371
+ await this.exchangeClient.order(orderRequest);
372
+ // Return the order (fetch it back for full details)
373
+ const orders = await this.getOrders(params.market);
374
+ return orders[0] || {
375
+ id: "pending",
376
+ market: `${coin}-PERP`,
377
+ side: params.side,
378
+ type: params.type,
379
+ size: params.size,
380
+ price: params.price ?? null,
381
+ filled: "0",
382
+ remaining: params.size,
383
+ status: "open",
384
+ reduceOnly: params.reduceOnly ?? false,
385
+ postOnly: params.postOnly ?? false,
386
+ timestamp: Date.now(),
387
+ };
388
+ }
389
+ async cancelOrder(params) {
390
+ this.ensureExchangeClient();
391
+ if (!params.orderId) {
392
+ throw new Error("orderId is required for Hyperliquid cancelOrder");
393
+ }
394
+ let coin;
395
+ if (params.market) {
396
+ coin = params.market.toUpperCase().replace("-PERP", "");
397
+ }
398
+ else {
399
+ // Look up the order's market from open orders
400
+ const orders = await this.getOrders();
401
+ const match = orders.find((o) => o.id === params.orderId);
402
+ if (match) {
403
+ coin = match.market.replace("-PERP", "");
404
+ }
405
+ }
406
+ if (!coin) {
407
+ throw new Error(`Could not resolve market for order ${params.orderId}`);
408
+ }
409
+ const assetIndex = this.getAssetIndex(coin);
410
+ try {
411
+ await this.exchangeClient.cancel({
412
+ cancels: [{
413
+ a: assetIndex,
414
+ o: parseInt(params.orderId),
415
+ }],
416
+ });
417
+ return true;
418
+ }
419
+ catch {
420
+ return false;
421
+ }
422
+ }
423
+ async cancelAllOrders(market) {
424
+ this.ensureExchangeClient();
425
+ const orders = await this.getOrders(market);
426
+ let cancelled = 0;
427
+ for (const order of orders) {
428
+ const success = await this.cancelOrder({
429
+ orderId: order.id,
430
+ market: order.market,
431
+ });
432
+ if (success)
433
+ cancelled++;
434
+ }
435
+ return cancelled;
436
+ }
437
+ async setLeverage(market, leverage) {
438
+ this.ensureExchangeClient();
439
+ const coin = market.toUpperCase().replace("-PERP", "");
440
+ await this.exchangeClient.updateLeverage({
441
+ asset: this.getAssetIndex(coin),
442
+ isCross: true,
443
+ leverage,
444
+ });
445
+ }
446
+ async setMarginType(market, type) {
447
+ this.ensureExchangeClient();
448
+ const coin = market.toUpperCase().replace("-PERP", "");
449
+ const position = await this.getPosition(market);
450
+ await this.exchangeClient.updateLeverage({
451
+ asset: this.getAssetIndex(coin),
452
+ isCross: type === "cross",
453
+ leverage: position?.leverage ?? 1,
454
+ });
455
+ }
456
+ // --------------------------------------------------------------------------
457
+ // Advanced Trading
458
+ // --------------------------------------------------------------------------
459
+ async modifyOrder(params) {
460
+ this.ensureExchangeClient();
461
+ const coin = params.market.toUpperCase().replace("-PERP", "");
462
+ const oid = parseInt(params.orderId);
463
+ // Fetch existing order to get current values
464
+ const existing = await this.getOrder(params.orderId);
465
+ if (!existing) {
466
+ throw new Error(`Order ${params.orderId} not found`);
467
+ }
468
+ const isBuy = existing.side === "long";
469
+ const newPrice = params.price ? parseFloat(params.price) : parseFloat(existing.price ?? "0");
470
+ const newSize = params.size ? parseFloat(params.size) : parseFloat(existing.size);
471
+ await this.exchangeClient.modify({
472
+ oid,
473
+ order: {
474
+ a: this.getAssetIndex(coin),
475
+ b: isBuy,
476
+ p: newPrice.toString(),
477
+ s: newSize.toString(),
478
+ r: existing.reduceOnly,
479
+ t: { limit: { tif: existing.postOnly ? "Alo" : "Gtc" } },
480
+ },
481
+ });
482
+ // Fetch back the modified order
483
+ const orders = await this.getOrders(params.market);
484
+ return orders[0] || { ...existing, price: newPrice.toString(), size: newSize.toString() };
485
+ }
486
+ async batchPlaceOrders(paramsList) {
487
+ // Sequential: HL's batch endpoint is for modifications, not new orders
488
+ const results = [];
489
+ for (const params of paramsList) {
490
+ results.push(await this.placeOrder(params));
491
+ }
492
+ return results;
493
+ }
494
+ async batchCancelOrders(paramsList) {
495
+ this.ensureExchangeClient();
496
+ // Build batch cancel request
497
+ const cancels = [];
498
+ for (const params of paramsList) {
499
+ if (!params.orderId)
500
+ continue;
501
+ let coin;
502
+ if (params.market) {
503
+ coin = params.market.toUpperCase().replace("-PERP", "");
504
+ }
505
+ else {
506
+ const orders = await this.getOrders();
507
+ const match = orders.find((o) => o.id === params.orderId);
508
+ if (match)
509
+ coin = match.market.replace("-PERP", "");
510
+ }
511
+ if (!coin)
512
+ continue;
513
+ cancels.push({ a: this.getAssetIndex(coin), o: parseInt(params.orderId) });
514
+ }
515
+ if (cancels.length === 0)
516
+ return paramsList.map(() => false);
517
+ try {
518
+ await this.exchangeClient.cancel({ cancels });
519
+ return paramsList.map(() => true);
520
+ }
521
+ catch {
522
+ // Fallback to individual cancels
523
+ const results = [];
524
+ for (const params of paramsList) {
525
+ try {
526
+ results.push(await this.cancelOrder(params));
527
+ }
528
+ catch {
529
+ results.push(false);
530
+ }
531
+ }
532
+ return results;
533
+ }
534
+ }
535
+ async cancelAllAfter(timeoutMs) {
536
+ this.ensureExchangeClient();
537
+ // Hyperliquid scheduleCancel: timeout in seconds
538
+ const timeoutSec = Math.max(0, Math.floor(timeoutMs / 1000));
539
+ await this.exchangeClient.scheduleCancel({
540
+ time: timeoutSec > 0 ? Date.now() + timeoutMs : null,
541
+ });
542
+ }
543
+ async getOrderHistory(_market, limit = 100) {
544
+ this.ensureAuth();
545
+ // Hyperliquid historicalOrders endpoint
546
+ const response = await this.infoClient.historicalOrders({
547
+ user: this.walletAddress,
548
+ });
549
+ let orders = response.slice(0, limit)
550
+ .map((entry) => entry.order ? this.mapOrder(entry.order) : null)
551
+ .filter((o) => o !== null);
552
+ if (_market) {
553
+ const coin = _market.toUpperCase().replace("-PERP", "");
554
+ orders = orders.filter((o) => o.market === `${coin}-PERP`);
555
+ }
556
+ return orders;
557
+ }
558
+ async getFundingHistory(_market, _limit) {
559
+ throw new Error("Hyperliquid does not expose a per-user funding history endpoint");
560
+ }
561
+ async getPublicTrades(market, limit = 100) {
562
+ this.ensureConnected();
563
+ const coin = market.toUpperCase().replace("-PERP", "");
564
+ const trades = await this.infoClient.recentTrades({ coin });
565
+ return trades.slice(0, limit).map((t) => ({
566
+ id: t.tid?.toString() ?? `${t.time}`,
567
+ market: `${coin}-PERP`,
568
+ side: t.side === "B" ? "long" : "short",
569
+ price: t.px,
570
+ size: t.sz,
571
+ timestamp: t.time,
572
+ }));
573
+ }
574
+ // --------------------------------------------------------------------------
575
+ // Market Maker Protection
576
+ // --------------------------------------------------------------------------
577
+ async setMMP(_config) {
578
+ throw new Error("Hyperliquid does not support Market Maker Protection (MMP)");
579
+ }
580
+ async getMMP(_market) {
581
+ throw new Error("Hyperliquid does not support Market Maker Protection (MMP)");
582
+ }
583
+ async resetMMP(_market) {
584
+ throw new Error("Hyperliquid does not support Market Maker Protection (MMP)");
585
+ }
586
+ // --------------------------------------------------------------------------
587
+ // TWAP Orders
588
+ // --------------------------------------------------------------------------
589
+ async placeTWAP(params) {
590
+ this.ensureExchangeClient();
591
+ const coin = params.market.toUpperCase().replace("-PERP", "");
592
+ const isBuy = params.side === "long";
593
+ const durationSec = Math.floor(params.durationMs / 1000);
594
+ await this.exchangeClient.twapOrder({
595
+ coin,
596
+ is_buy: isBuy,
597
+ sz: parseFloat(params.size),
598
+ duration_s: durationSec,
599
+ randomize: params.randomize ?? false,
600
+ });
601
+ return {
602
+ id: `twap-${Date.now()}`,
603
+ market: `${coin}-PERP`,
604
+ side: params.side,
605
+ totalSize: params.size,
606
+ executedSize: "0",
607
+ remainingSize: params.size,
608
+ status: "active",
609
+ startTime: Date.now(),
610
+ endTime: Date.now() + params.durationMs,
611
+ };
612
+ }
613
+ async cancelTWAP(twapId) {
614
+ this.ensureExchangeClient();
615
+ try {
616
+ await this.exchangeClient.twapCancel({
617
+ token_id: parseInt(twapId.replace("twap-", "")),
618
+ });
619
+ return true;
620
+ }
621
+ catch {
622
+ return false;
623
+ }
624
+ }
625
+ async getTWAPStatus(_twapId) {
626
+ throw new Error("Hyperliquid does not expose a TWAP status query endpoint");
627
+ }
628
+ // --------------------------------------------------------------------------
629
+ // Margin Management
630
+ // --------------------------------------------------------------------------
631
+ async updateIsolatedMargin(market, amount) {
632
+ this.ensureExchangeClient();
633
+ const coin = market.toUpperCase().replace("-PERP", "");
634
+ const isBuy = true; // For margin update, direction is based on position side
635
+ await this.exchangeClient.updateIsolatedMargin({
636
+ asset: this.getAssetIndex(coin),
637
+ isBuy,
638
+ ntli: parseFloat(amount),
639
+ });
640
+ }
641
+ subscribe(callbacks) {
642
+ this.ensureConnected();
643
+ let closed = false;
644
+ const emit = async () => {
645
+ if (closed)
646
+ return;
647
+ try {
648
+ if (callbacks.onTicker) {
649
+ const tickers = await this.getTickers();
650
+ for (const ticker of tickers) {
651
+ callbacks.onTicker(ticker);
652
+ }
653
+ }
654
+ if (callbacks.onPositions && this.walletAddress) {
655
+ callbacks.onPositions(await this.getPositions());
656
+ }
657
+ if (callbacks.onOrders && this.walletAddress) {
658
+ callbacks.onOrders(await this.getOrders());
659
+ }
660
+ if (callbacks.onBalances && this.walletAddress) {
661
+ callbacks.onBalances(await this.getBalances());
662
+ }
663
+ }
664
+ catch (err) {
665
+ callbacks.onError?.(err instanceof Error ? err : new Error(String(err)));
666
+ }
667
+ };
668
+ void emit();
669
+ const timer = setInterval(() => {
670
+ void emit();
671
+ }, 1_000);
672
+ return () => {
673
+ closed = true;
674
+ clearInterval(timer);
675
+ };
676
+ }
677
+ subscribeOrderBook(market, callback) {
678
+ this.ensureConnected();
679
+ let closed = false;
680
+ const normalizedMarket = market.toUpperCase().endsWith("-PERP")
681
+ ? market.toUpperCase()
682
+ : `${market.toUpperCase()}-PERP`;
683
+ const emit = async () => {
684
+ if (closed)
685
+ return;
686
+ callback(await this.getOrderBook(normalizedMarket));
687
+ };
688
+ void emit().catch(() => { });
689
+ const timer = setInterval(() => {
690
+ void emit().catch(() => { });
691
+ }, 500);
692
+ return () => {
693
+ closed = true;
694
+ clearInterval(timer);
695
+ };
696
+ }
697
+ subscribeTicker(market, callback) {
698
+ this.ensureConnected();
699
+ let closed = false;
700
+ const normalizedMarket = market.toUpperCase().endsWith("-PERP")
701
+ ? market.toUpperCase()
702
+ : `${market.toUpperCase()}-PERP`;
703
+ const emit = async () => {
704
+ if (closed)
705
+ return;
706
+ callback(await this.getTicker(normalizedMarket));
707
+ };
708
+ void emit().catch(() => { });
709
+ const timer = setInterval(() => {
710
+ void emit().catch(() => { });
711
+ }, 1_000);
712
+ return () => {
713
+ closed = true;
714
+ clearInterval(timer);
715
+ };
716
+ }
717
+ // --------------------------------------------------------------------------
718
+ // Private Helpers
719
+ // --------------------------------------------------------------------------
720
+ ensureConnected() {
721
+ if (!this.connected || !this.infoClient) {
722
+ throw new Error("Not connected. Call connect() first.");
723
+ }
724
+ }
725
+ ensureAuth() {
726
+ this.ensureConnected();
727
+ if (!this.walletAddress) {
728
+ throw new Error("Wallet address required. Provide credentials in connect().");
729
+ }
730
+ }
731
+ ensureExchangeClient() {
732
+ this.ensureConnected();
733
+ if (!this.exchangeClient) {
734
+ throw new Error("Exchange client not available. Provide privateKey in credentials.");
735
+ }
736
+ }
737
+ getAssetIndex(coin) {
738
+ if (!this.meta)
739
+ throw new Error("Meta not loaded");
740
+ const idx = this.meta.universe.findIndex((u) => u.name === coin);
741
+ if (idx === -1)
742
+ throw new Error(`Asset ${coin} not found`);
743
+ return idx;
744
+ }
745
+ mapPosition(p) {
746
+ const size = parseFloat(p.szi);
747
+ const markPrice = this.latestMarkPrices.get(p.coin) ?? p.entryPx;
748
+ return {
749
+ market: `${p.coin}-PERP`,
750
+ side: size > 0 ? "long" : "short",
751
+ size: Math.abs(size).toString(),
752
+ entryPrice: p.entryPx,
753
+ markPrice,
754
+ liquidationPrice: p.liquidationPx,
755
+ unrealizedPnl: p.unrealizedPnl,
756
+ realizedPnl: "0",
757
+ leverage: p.leverage.value,
758
+ marginType: p.leverage.type === "cross" ? "cross" : "isolated",
759
+ margin: p.marginUsed,
760
+ timestamp: Date.now(),
761
+ };
762
+ }
763
+ mapOrder(o) {
764
+ const filled = parseFloat(o.origSz) - parseFloat(o.sz);
765
+ return {
766
+ id: o.oid.toString(),
767
+ market: `${o.coin}-PERP`,
768
+ side: o.side === "B" ? "long" : "short",
769
+ type: o.triggerPx ? "stop" : "limit",
770
+ size: o.origSz,
771
+ price: o.limitPx,
772
+ filled: filled.toString(),
773
+ remaining: o.sz,
774
+ status: "open",
775
+ reduceOnly: o.reduceOnly,
776
+ postOnly: false,
777
+ timestamp: o.timestamp,
778
+ triggerPrice: o.triggerPx,
779
+ };
780
+ }
781
+ mapFill(f) {
782
+ return {
783
+ id: `${f.oid}-${f.time}`,
784
+ market: `${f.coin}-PERP`,
785
+ side: f.side === "B" ? "long" : "short",
786
+ price: f.px,
787
+ size: f.sz,
788
+ fee: f.fee,
789
+ feeAsset: f.feeToken,
790
+ timestamp: f.time,
791
+ orderId: f.oid.toString(),
792
+ };
793
+ }
794
+ }
795
+ // Register the adapter
796
+ registerAdapter("hyperliquid", () => new HyperliquidAdapter());
797
+ export default HyperliquidAdapter;