hyperliquid-prime 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 (119) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +426 -0
  3. package/dist/cli/context.d.ts +12 -0
  4. package/dist/cli/context.d.ts.map +1 -0
  5. package/dist/cli/context.js +27 -0
  6. package/dist/cli/context.js.map +1 -0
  7. package/dist/cli/index.d.ts +3 -0
  8. package/dist/cli/index.d.ts.map +1 -0
  9. package/dist/cli/index.js +5 -0
  10. package/dist/cli/index.js.map +1 -0
  11. package/dist/cli/output.d.ts +7 -0
  12. package/dist/cli/output.d.ts.map +1 -0
  13. package/dist/cli/output.js +29 -0
  14. package/dist/cli/output.js.map +1 -0
  15. package/dist/cli/program.d.ts +3 -0
  16. package/dist/cli/program.d.ts.map +1 -0
  17. package/dist/cli/program.js +232 -0
  18. package/dist/cli/program.js.map +1 -0
  19. package/dist/collateral/manager.d.ts +45 -0
  20. package/dist/collateral/manager.d.ts.map +1 -0
  21. package/dist/collateral/manager.js +252 -0
  22. package/dist/collateral/manager.js.map +1 -0
  23. package/dist/collateral/types.d.ts +26 -0
  24. package/dist/collateral/types.d.ts.map +1 -0
  25. package/dist/collateral/types.js +2 -0
  26. package/dist/collateral/types.js.map +1 -0
  27. package/dist/config.d.ts +31 -0
  28. package/dist/config.d.ts.map +1 -0
  29. package/dist/config.js +6 -0
  30. package/dist/config.js.map +1 -0
  31. package/dist/execution/executor.d.ts +30 -0
  32. package/dist/execution/executor.d.ts.map +1 -0
  33. package/dist/execution/executor.js +291 -0
  34. package/dist/execution/executor.js.map +1 -0
  35. package/dist/execution/monitor.d.ts +26 -0
  36. package/dist/execution/monitor.d.ts.map +1 -0
  37. package/dist/execution/monitor.js +50 -0
  38. package/dist/execution/monitor.js.map +1 -0
  39. package/dist/execution/types.d.ts +26 -0
  40. package/dist/execution/types.d.ts.map +1 -0
  41. package/dist/execution/types.js +2 -0
  42. package/dist/execution/types.js.map +1 -0
  43. package/dist/index.d.ts +87 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +249 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/logging/logger.d.ts +7 -0
  48. package/dist/logging/logger.d.ts.map +1 -0
  49. package/dist/logging/logger.js +10 -0
  50. package/dist/logging/logger.js.map +1 -0
  51. package/dist/market/aggregator.d.ts +28 -0
  52. package/dist/market/aggregator.d.ts.map +1 -0
  53. package/dist/market/aggregator.js +166 -0
  54. package/dist/market/aggregator.js.map +1 -0
  55. package/dist/market/book.d.ts +22 -0
  56. package/dist/market/book.d.ts.map +1 -0
  57. package/dist/market/book.js +34 -0
  58. package/dist/market/book.js.map +1 -0
  59. package/dist/market/registry.d.ts +19 -0
  60. package/dist/market/registry.d.ts.map +1 -0
  61. package/dist/market/registry.js +127 -0
  62. package/dist/market/registry.js.map +1 -0
  63. package/dist/market/types.d.ts +53 -0
  64. package/dist/market/types.d.ts.map +1 -0
  65. package/dist/market/types.js +2 -0
  66. package/dist/market/types.js.map +1 -0
  67. package/dist/position/manager.d.ts +21 -0
  68. package/dist/position/manager.d.ts.map +1 -0
  69. package/dist/position/manager.js +63 -0
  70. package/dist/position/manager.js.map +1 -0
  71. package/dist/position/risk.d.ts +7 -0
  72. package/dist/position/risk.d.ts.map +1 -0
  73. package/dist/position/risk.js +23 -0
  74. package/dist/position/risk.js.map +1 -0
  75. package/dist/position/types.d.ts +28 -0
  76. package/dist/position/types.d.ts.map +1 -0
  77. package/dist/position/types.js +2 -0
  78. package/dist/position/types.js.map +1 -0
  79. package/dist/provider/nktkas.d.ts +63 -0
  80. package/dist/provider/nktkas.d.ts.map +1 -0
  81. package/dist/provider/nktkas.js +277 -0
  82. package/dist/provider/nktkas.js.map +1 -0
  83. package/dist/provider/provider.d.ts +42 -0
  84. package/dist/provider/provider.d.ts.map +1 -0
  85. package/dist/provider/provider.js +2 -0
  86. package/dist/provider/provider.js.map +1 -0
  87. package/dist/provider/types.d.ts +214 -0
  88. package/dist/provider/types.d.ts.map +1 -0
  89. package/dist/provider/types.js +4 -0
  90. package/dist/provider/types.js.map +1 -0
  91. package/dist/router/router.d.ts +30 -0
  92. package/dist/router/router.d.ts.map +1 -0
  93. package/dist/router/router.js +256 -0
  94. package/dist/router/router.js.map +1 -0
  95. package/dist/router/scorer.d.ts +18 -0
  96. package/dist/router/scorer.d.ts.map +1 -0
  97. package/dist/router/scorer.js +43 -0
  98. package/dist/router/scorer.js.map +1 -0
  99. package/dist/router/simulator.d.ts +11 -0
  100. package/dist/router/simulator.d.ts.map +1 -0
  101. package/dist/router/simulator.js +44 -0
  102. package/dist/router/simulator.js.map +1 -0
  103. package/dist/router/splitter.d.ts +26 -0
  104. package/dist/router/splitter.d.ts.map +1 -0
  105. package/dist/router/splitter.js +119 -0
  106. package/dist/router/splitter.js.map +1 -0
  107. package/dist/router/types.d.ts +69 -0
  108. package/dist/router/types.d.ts.map +1 -0
  109. package/dist/router/types.js +4 -0
  110. package/dist/router/types.js.map +1 -0
  111. package/dist/utils/errors.d.ts +28 -0
  112. package/dist/utils/errors.d.ts.map +1 -0
  113. package/dist/utils/errors.js +55 -0
  114. package/dist/utils/errors.js.map +1 -0
  115. package/dist/utils/math.d.ts +24 -0
  116. package/dist/utils/math.d.ts.map +1 -0
  117. package/dist/utils/math.js +43 -0
  118. package/dist/utils/math.js.map +1 -0
  119. package/package.json +59 -0
package/dist/index.js ADDED
@@ -0,0 +1,249 @@
1
+ import { privateKeyToAccount } from "viem/accounts";
2
+ import { DEFAULT_BUILDER } from "./config.js";
3
+ import { NktkasProvider } from "./provider/nktkas.js";
4
+ import { MarketRegistry } from "./market/registry.js";
5
+ import { BookAggregator } from "./market/aggregator.js";
6
+ import { Router } from "./router/router.js";
7
+ import { Executor } from "./execution/executor.js";
8
+ import { CollateralManager } from "./collateral/manager.js";
9
+ import { PositionManager } from "./position/manager.js";
10
+ import { createLogger } from "./logging/logger.js";
11
+ import { HyperliquidPrimeError, NoWalletError, NotConnectedError } from "./utils/errors.js";
12
+ export class HyperliquidPrime {
13
+ provider;
14
+ _registry;
15
+ router;
16
+ executor;
17
+ collateralManager;
18
+ positions;
19
+ aggregator;
20
+ logger;
21
+ _config;
22
+ walletAddress;
23
+ connected = false;
24
+ constructor(config) {
25
+ this._config = config;
26
+ this.logger = createLogger({
27
+ level: config.logLevel ?? "info",
28
+ pretty: config.prettyLogs ?? false,
29
+ });
30
+ this.provider = new NktkasProvider({
31
+ privateKey: config.privateKey,
32
+ testnet: config.testnet ?? false,
33
+ });
34
+ // Derive wallet address if private key is provided
35
+ if (config.privateKey) {
36
+ this.walletAddress =
37
+ config.walletAddress ??
38
+ privateKeyToAccount(config.privateKey).address;
39
+ }
40
+ else {
41
+ this.walletAddress = config.walletAddress;
42
+ }
43
+ this._registry = new MarketRegistry(this.provider, this.logger);
44
+ this.aggregator = new BookAggregator(this.provider, this._registry, this.logger);
45
+ this.collateralManager = new CollateralManager(this.provider, this.logger);
46
+ this.router = new Router(this.provider, this._registry, this.logger, this.aggregator);
47
+ // Resolve builder config: undefined → default, null → disabled, object → custom
48
+ const resolvedBuilder = config.builder === undefined ? DEFAULT_BUILDER
49
+ : config.builder === null ? null
50
+ : config.builder;
51
+ if (resolvedBuilder && (resolvedBuilder.feeBps < 0 || resolvedBuilder.feeBps > 10)) {
52
+ throw new HyperliquidPrimeError(`Builder fee ${resolvedBuilder.feeBps} bps out of range (0-10 bps)`);
53
+ }
54
+ this.executor = new Executor(this.provider, this.logger, resolvedBuilder);
55
+ this.positions = new PositionManager(this.provider, this._registry, this.logger);
56
+ }
57
+ /** Connect to Hyperliquid and discover markets. Must be called before use. */
58
+ async connect() {
59
+ await this.provider.connect();
60
+ await this._registry.discover();
61
+ this.connected = true;
62
+ this.logger.info("Hyperliquid Prime connected");
63
+ }
64
+ ensureConnected() {
65
+ if (!this.connected)
66
+ throw new NotConnectedError();
67
+ }
68
+ ensureWallet() {
69
+ if (!this.walletAddress)
70
+ throw new NoWalletError();
71
+ return this.walletAddress;
72
+ }
73
+ // === Read-Only (no wallet required) ===
74
+ /** Get all HIP-3 markets for an asset. */
75
+ getMarkets(baseAsset) {
76
+ this.ensureConnected();
77
+ return this._registry.getMarkets(baseAsset);
78
+ }
79
+ /** Get all asset groups that have multiple HIP-3 markets. */
80
+ getAggregatedMarkets() {
81
+ this.ensureConnected();
82
+ return this._registry.getGroupsWithAlternatives();
83
+ }
84
+ /** Get a merged orderbook across all markets for an asset. */
85
+ async getAggregatedBook(baseAsset) {
86
+ this.ensureConnected();
87
+ return this.aggregator.aggregate(baseAsset);
88
+ }
89
+ /** Compare funding rates across all markets for an asset. */
90
+ async getFundingComparison(baseAsset) {
91
+ this.ensureConnected();
92
+ const markets = this._registry.getMarkets(baseAsset);
93
+ const comparison = {
94
+ baseAsset,
95
+ markets: markets.map((m) => ({
96
+ coin: m.coin,
97
+ dexName: m.dexName,
98
+ collateral: m.collateral,
99
+ fundingRate: parseFloat(m.funding ?? "0"),
100
+ openInterest: parseFloat(m.openInterest ?? "0"),
101
+ markPrice: parseFloat(m.markPrice ?? "0"),
102
+ })),
103
+ bestForLong: "",
104
+ bestForShort: "",
105
+ };
106
+ // Best for long = lowest (most negative) funding rate
107
+ // (shorts pay longs when funding is negative)
108
+ const sorted = [...comparison.markets].sort((a, b) => a.fundingRate - b.fundingRate);
109
+ comparison.bestForLong = sorted[0]?.coin ?? "";
110
+ comparison.bestForShort = sorted[sorted.length - 1]?.coin ?? "";
111
+ return comparison;
112
+ }
113
+ /** Generate a routing quote. Does NOT execute. */
114
+ async quote(baseAsset, side, size) {
115
+ this.ensureConnected();
116
+ const { collateral, warnings } = await this.resolveUserCollateral();
117
+ const quote = await this.router.quote(baseAsset, side, size, collateral, this._config.defaultSlippage ?? 0.01);
118
+ if (warnings.length > 0) {
119
+ quote.warnings = [...(quote.warnings ?? []), ...warnings];
120
+ }
121
+ return quote;
122
+ }
123
+ // === Trading (wallet required) ===
124
+ /** Execute a previously generated quote. */
125
+ async execute(plan) {
126
+ this.ensureConnected();
127
+ const user = this.ensureWallet();
128
+ return this.executor.execute(plan, user);
129
+ }
130
+ /** Convenience: quote + execute in one call. */
131
+ async long(baseAsset, size) {
132
+ const q = await this.quote(baseAsset, "buy", size);
133
+ return this.execute(q.plan);
134
+ }
135
+ async short(baseAsset, size) {
136
+ const q = await this.quote(baseAsset, "sell", size);
137
+ return this.execute(q.plan);
138
+ }
139
+ /** Generate a split quote across multiple HIP-3 markets. Does NOT execute. */
140
+ async quoteSplit(baseAsset, side, size) {
141
+ this.ensureConnected();
142
+ const { collateral, warnings } = await this.resolveUserCollateral();
143
+ const quote = await this.router.quoteSplit(baseAsset, side, size, collateral, this._config.defaultSlippage ?? 0.01);
144
+ if (warnings.length > 0) {
145
+ quote.warnings = [...(quote.warnings ?? []), ...warnings];
146
+ }
147
+ return quote;
148
+ }
149
+ /** Execute a previously generated split quote. */
150
+ async executeSplit(plan) {
151
+ this.ensureConnected();
152
+ const user = this.ensureWallet();
153
+ return this.executor.executeSplit(plan, this.collateralManager, user);
154
+ }
155
+ /** Convenience: split quote + execute in one call. */
156
+ async longSplit(baseAsset, size) {
157
+ const q = await this.quoteSplit(baseAsset, "buy", size);
158
+ return this.executeSplit(q.splitPlan);
159
+ }
160
+ async shortSplit(baseAsset, size) {
161
+ const q = await this.quoteSplit(baseAsset, "sell", size);
162
+ return this.executeSplit(q.splitPlan);
163
+ }
164
+ async close(baseAsset) {
165
+ this.ensureConnected();
166
+ const user = this.ensureWallet();
167
+ const allPositions = await this.positions.getPositions(user);
168
+ const toClose = allPositions.filter((p) => p.baseAsset.toUpperCase() === baseAsset.toUpperCase() && p.size > 0);
169
+ const receipts = [];
170
+ for (const pos of toClose) {
171
+ const side = pos.side === "long" ? "sell" : "buy";
172
+ const q = await this.quote(pos.coin, side, pos.size);
173
+ const receipt = await this.execute(q.plan);
174
+ receipts.push(receipt);
175
+ }
176
+ return receipts;
177
+ }
178
+ // === Positions ===
179
+ /** Get all positions. */
180
+ async getPositions() {
181
+ this.ensureConnected();
182
+ const user = this.ensureWallet();
183
+ return this.positions.getPositions(user);
184
+ }
185
+ /** Get positions grouped by base asset (unified view). */
186
+ async getGroupedPositions() {
187
+ this.ensureConnected();
188
+ const user = this.ensureWallet();
189
+ return this.positions.getGroupedPositions(user);
190
+ }
191
+ // === Balance ===
192
+ /** Get perp account balance/margin summary. */
193
+ async getBalance() {
194
+ this.ensureConnected();
195
+ const user = this.ensureWallet();
196
+ const state = await this.provider.clearinghouseState(user);
197
+ return state.marginSummary;
198
+ }
199
+ // === Escape Hatches ===
200
+ /** Direct access to the provider for raw HL API calls. */
201
+ get api() {
202
+ return this.provider;
203
+ }
204
+ /** Direct access to the market registry. */
205
+ get markets() {
206
+ return this._registry;
207
+ }
208
+ // === Lifecycle ===
209
+ async disconnect() {
210
+ await this.provider.disconnect();
211
+ this.connected = false;
212
+ this.logger.info("Hyperliquid Prime disconnected");
213
+ }
214
+ async resolveUserCollateral() {
215
+ let collateral = ["USDC"];
216
+ const warnings = [];
217
+ if (!this.walletAddress) {
218
+ return { collateral, warnings };
219
+ }
220
+ try {
221
+ const spotState = await this.provider.spotClearinghouseState(this.walletAddress);
222
+ collateral = spotState.balances
223
+ .filter((b) => parseFloat(b.total) > 0)
224
+ .map((b) => b.coin);
225
+ if (!collateral.includes("USDC")) {
226
+ collateral.push("USDC");
227
+ }
228
+ }
229
+ catch (error) {
230
+ warnings.push("Could not load spot balances for collateral matching; defaulting to USDC");
231
+ this.logger.warn({ error }, "Falling back to default collateral set due to spot balance fetch failure");
232
+ }
233
+ return { collateral, warnings };
234
+ }
235
+ }
236
+ export { isSplitQuote } from "./router/types.js";
237
+ export { MarketRegistry } from "./market/registry.js";
238
+ export { BookAggregator } from "./market/aggregator.js";
239
+ export { Router } from "./router/router.js";
240
+ export { FillSimulator } from "./router/simulator.js";
241
+ export { MarketScorer } from "./router/scorer.js";
242
+ export { SplitOptimizer } from "./router/splitter.js";
243
+ export { CollateralManager } from "./collateral/manager.js";
244
+ export { Executor } from "./execution/executor.js";
245
+ export { PositionManager } from "./position/manager.js";
246
+ export { NktkasProvider } from "./provider/nktkas.js";
247
+ export { createLogger } from "./logging/logger.js";
248
+ export { HyperliquidPrimeError, NoMarketsError, InsufficientLiquidityError, MarketDataUnavailableError, NoWalletError, NotConnectedError, ExecutionError, } from "./utils/errors.js";
249
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import pino from "pino";
2
+ export declare function createLogger(opts?: {
3
+ level?: string;
4
+ pretty?: boolean;
5
+ }): Logger;
6
+ export type Logger = pino.Logger;
7
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/logging/logger.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,wBAAgB,YAAY,CAAC,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,MAAM,CAOpF;AAED,MAAM,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC"}
@@ -0,0 +1,10 @@
1
+ import pino from "pino";
2
+ export function createLogger(opts = {}) {
3
+ return pino({
4
+ level: opts.level ?? "info",
5
+ transport: opts.pretty
6
+ ? { target: "pino-pretty", options: { colorize: true } }
7
+ : undefined,
8
+ });
9
+ }
10
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/logging/logger.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,UAAU,YAAY,CAAC,OAA6C,EAAE;IAC1E,OAAO,IAAI,CAAC;QACV,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,MAAM;QAC3B,SAAS,EAAE,IAAI,CAAC,MAAM;YACpB,CAAC,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE;YACxD,CAAC,CAAC,SAAS;KACd,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,28 @@
1
+ import type { HLProvider } from "../provider/provider.js";
2
+ import type { Logger } from "../logging/logger.js";
3
+ import type { MarketRegistry } from "./registry.js";
4
+ import type { AggregatedBook } from "./types.js";
5
+ export declare class BookAggregator {
6
+ private provider;
7
+ private registry;
8
+ private logger;
9
+ constructor(provider: HLProvider, registry: MarketRegistry, logger: Logger);
10
+ /**
11
+ * Fetch orderbooks from all markets for a given asset and merge them
12
+ * into a single aggregated view.
13
+ */
14
+ aggregate(baseAsset: string): Promise<AggregatedBook>;
15
+ /**
16
+ * Aggregate only enough levels to quote a given size for routing.
17
+ * This avoids building the full merged side when an order only needs shallow depth.
18
+ */
19
+ aggregateForOrder(baseAsset: string, side: "buy" | "sell", size: number): Promise<AggregatedBook>;
20
+ /**
21
+ * Merge price levels from multiple books.
22
+ * Groups by price, sums sizes, tracks which markets contribute.
23
+ */
24
+ private mergeLevels;
25
+ private fetchMarketBooks;
26
+ private withTimeout;
27
+ }
28
+ //# sourceMappingURL=aggregator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aggregator.d.ts","sourceRoot":"","sources":["../../src/market/aggregator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE1D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAA+B,MAAM,YAAY,CAAC;AAU9E,qBAAa,cAAc;IAIvB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,QAAQ;IAJlB,OAAO,CAAC,MAAM,CAAS;gBAGb,QAAQ,EAAE,UAAU,EACpB,QAAQ,EAAE,cAAc,EAChC,MAAM,EAAE,MAAM;IAKhB;;;OAGG;IACG,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IA+C3D;;;OAGG;IACG,iBAAiB,CACrB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,KAAK,GAAG,MAAM,EACpB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,cAAc,CAAC;IA8C1B;;;OAGG;IACH,OAAO,CAAC,WAAW;YA8CL,gBAAgB;IAkD9B,OAAO,CAAC,WAAW;CAmBpB"}
@@ -0,0 +1,166 @@
1
+ const BOOK_FETCH_TIMEOUT_MS = 2_500;
2
+ export class BookAggregator {
3
+ provider;
4
+ registry;
5
+ logger;
6
+ constructor(provider, registry, logger) {
7
+ this.provider = provider;
8
+ this.registry = registry;
9
+ this.logger = logger.child({ module: "aggregator" });
10
+ }
11
+ /**
12
+ * Fetch orderbooks from all markets for a given asset and merge them
13
+ * into a single aggregated view.
14
+ */
15
+ async aggregate(baseAsset) {
16
+ const markets = this.registry.getMarkets(baseAsset);
17
+ if (markets.length === 0) {
18
+ return {
19
+ baseAsset,
20
+ bids: [],
21
+ asks: [],
22
+ marketBooks: [],
23
+ timestamp: Date.now(),
24
+ };
25
+ }
26
+ const books = await this.fetchMarketBooks(markets, baseAsset);
27
+ if (books.length === 0) {
28
+ return {
29
+ baseAsset,
30
+ bids: [],
31
+ asks: [],
32
+ marketBooks: [],
33
+ timestamp: Date.now(),
34
+ };
35
+ }
36
+ this.logger.debug({ baseAsset, marketCount: books.length }, "Aggregating orderbooks");
37
+ const bids = this.mergeLevels(books.map((b) => ({ coin: b.coin, levels: b.bids })), "desc");
38
+ const asks = this.mergeLevels(books.map((b) => ({ coin: b.coin, levels: b.asks })), "asc");
39
+ return {
40
+ baseAsset,
41
+ bids,
42
+ asks,
43
+ marketBooks: books,
44
+ timestamp: Date.now(),
45
+ };
46
+ }
47
+ /**
48
+ * Aggregate only enough levels to quote a given size for routing.
49
+ * This avoids building the full merged side when an order only needs shallow depth.
50
+ */
51
+ async aggregateForOrder(baseAsset, side, size) {
52
+ const markets = this.registry.getMarkets(baseAsset);
53
+ if (markets.length === 0) {
54
+ return {
55
+ baseAsset,
56
+ bids: [],
57
+ asks: [],
58
+ marketBooks: [],
59
+ timestamp: Date.now(),
60
+ };
61
+ }
62
+ const books = await this.fetchMarketBooks(markets, baseAsset);
63
+ if (books.length === 0) {
64
+ return {
65
+ baseAsset,
66
+ bids: [],
67
+ asks: [],
68
+ marketBooks: [],
69
+ timestamp: Date.now(),
70
+ };
71
+ }
72
+ const isBuy = side === "buy";
73
+ const targetDepth = Math.max(0, size);
74
+ const bids = this.mergeLevels(books.map((b) => ({ coin: b.coin, levels: b.bids })), "desc", isBuy ? undefined : targetDepth);
75
+ const asks = this.mergeLevels(books.map((b) => ({ coin: b.coin, levels: b.asks })), "asc", isBuy ? targetDepth : undefined);
76
+ return {
77
+ baseAsset,
78
+ bids,
79
+ asks,
80
+ marketBooks: books,
81
+ timestamp: Date.now(),
82
+ };
83
+ }
84
+ /**
85
+ * Merge price levels from multiple books.
86
+ * Groups by price, sums sizes, tracks which markets contribute.
87
+ */
88
+ mergeLevels(sources, sort, targetDepth) {
89
+ const priceMap = new Map();
90
+ for (const { coin, levels } of sources) {
91
+ for (const level of levels) {
92
+ const px = level.px;
93
+ const sz = parseFloat(level.sz);
94
+ if (!priceMap.has(px)) {
95
+ priceMap.set(px, {
96
+ px: parseFloat(px),
97
+ sz: 0,
98
+ sources: [],
99
+ });
100
+ }
101
+ const entry = priceMap.get(px);
102
+ entry.sz += sz;
103
+ entry.sources.push({ coin, sz });
104
+ }
105
+ }
106
+ const merged = [...priceMap.values()];
107
+ merged.sort((a, b) => sort === "desc" ? b.px - a.px : a.px - b.px);
108
+ if (targetDepth === undefined || targetDepth <= 0) {
109
+ return merged;
110
+ }
111
+ let cumulative = 0;
112
+ const trimmed = [];
113
+ for (const level of merged) {
114
+ trimmed.push(level);
115
+ cumulative += level.sz;
116
+ if (cumulative >= targetDepth)
117
+ break;
118
+ }
119
+ return trimmed;
120
+ }
121
+ async fetchMarketBooks(markets, baseAsset) {
122
+ const settled = await Promise.allSettled(markets.map(async (m) => {
123
+ const book = await this.withTimeout(this.provider.l2Book(m.coin), BOOK_FETCH_TIMEOUT_MS, `l2Book timeout for ${m.coin}`);
124
+ return {
125
+ coin: m.coin,
126
+ bids: book.levels[0],
127
+ asks: book.levels[1],
128
+ };
129
+ }));
130
+ const books = [];
131
+ const failures = [];
132
+ for (let i = 0; i < settled.length; i++) {
133
+ const result = settled[i];
134
+ const market = markets[i];
135
+ if (result.status === "fulfilled") {
136
+ books.push(result.value);
137
+ continue;
138
+ }
139
+ failures.push({
140
+ coin: market?.coin ?? `market_${i}`,
141
+ reason: String(result.reason),
142
+ });
143
+ }
144
+ if (failures.length > 0) {
145
+ this.logger.warn({
146
+ baseAsset,
147
+ failedMarkets: failures.map((f) => f.coin),
148
+ failureCount: failures.length,
149
+ }, "Some market books failed to load; continuing with partial data");
150
+ }
151
+ return books;
152
+ }
153
+ withTimeout(promise, timeoutMs, timeoutMessage) {
154
+ return new Promise((resolve, reject) => {
155
+ const timer = setTimeout(() => reject(new Error(timeoutMessage)), timeoutMs);
156
+ promise.then((value) => {
157
+ clearTimeout(timer);
158
+ resolve(value);
159
+ }, (error) => {
160
+ clearTimeout(timer);
161
+ reject(error);
162
+ });
163
+ });
164
+ }
165
+ }
166
+ //# sourceMappingURL=aggregator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aggregator.js","sourceRoot":"","sources":["../../src/market/aggregator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { L2Book, L2Level } from "../provider/types.js";
2
+ export interface NormalizedBook {
3
+ coin: string;
4
+ bids: L2Level[];
5
+ asks: L2Level[];
6
+ midPrice: number;
7
+ spread: number;
8
+ spreadBps: number;
9
+ timestamp: number;
10
+ }
11
+ /**
12
+ * Normalize a raw L2Book into a simpler shape with computed mid/spread.
13
+ */
14
+ export declare function normalizeBook(raw: L2Book): NormalizedBook;
15
+ /**
16
+ * Get the total depth on one side of the book up to a price distance.
17
+ */
18
+ export declare function getBookDepth(levels: L2Level[], maxLevels?: number): {
19
+ totalSize: number;
20
+ levelCount: number;
21
+ };
22
+ //# sourceMappingURL=book.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"book.d.ts","sourceRoot":"","sources":["../../src/market/book.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAE5D,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAoBzD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,OAAO,EAAE,EACjB,SAAS,CAAC,EAAE,MAAM,GACjB;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAQ3C"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Normalize a raw L2Book into a simpler shape with computed mid/spread.
3
+ */
4
+ export function normalizeBook(raw) {
5
+ const bids = raw.levels[0];
6
+ const asks = raw.levels[1];
7
+ const bestBid = bids.length > 0 ? parseFloat(bids[0].px) : 0;
8
+ const bestAsk = asks.length > 0 ? parseFloat(asks[0].px) : 0;
9
+ const midPrice = bestBid > 0 && bestAsk > 0 ? (bestBid + bestAsk) / 2 : bestBid || bestAsk;
10
+ const spread = bestAsk > 0 && bestBid > 0 ? bestAsk - bestBid : 0;
11
+ const spreadBps = midPrice > 0 ? (spread / midPrice) * 10000 : 0;
12
+ return {
13
+ coin: raw.coin,
14
+ bids,
15
+ asks,
16
+ midPrice,
17
+ spread,
18
+ spreadBps,
19
+ timestamp: raw.time,
20
+ };
21
+ }
22
+ /**
23
+ * Get the total depth on one side of the book up to a price distance.
24
+ */
25
+ export function getBookDepth(levels, maxLevels) {
26
+ const limit = maxLevels ?? levels.length;
27
+ let totalSize = 0;
28
+ const count = Math.min(limit, levels.length);
29
+ for (let i = 0; i < count; i++) {
30
+ totalSize += parseFloat(levels[i].sz);
31
+ }
32
+ return { totalSize, levelCount: count };
33
+ }
34
+ //# sourceMappingURL=book.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"book.js","sourceRoot":"","sources":["../../src/market/book.ts"],"names":[],"mappings":"AAYA;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAC3B,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAE3B,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,MAAM,QAAQ,GACZ,OAAO,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,IAAI,OAAO,CAAC;IAC5E,MAAM,MAAM,GAAG,OAAO,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAClE,MAAM,SAAS,GAAG,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,QAAQ,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAEjE,OAAO;QACL,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,IAAI;QACJ,IAAI;QACJ,QAAQ;QACR,MAAM;QACN,SAAS;QACT,SAAS,EAAE,GAAG,CAAC,IAAI;KACpB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAC1B,MAAiB,EACjB,SAAkB;IAElB,MAAM,KAAK,GAAG,SAAS,IAAI,MAAM,CAAC,MAAM,CAAC;IACzC,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/B,SAAS,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { HLProvider } from "../provider/provider.js";
2
+ import type { Logger } from "../logging/logger.js";
3
+ import type { PerpMarket, MarketGroup } from "./types.js";
4
+ export declare class MarketRegistry {
5
+ private provider;
6
+ private groups;
7
+ private spotTokens;
8
+ private logger;
9
+ constructor(provider: HLProvider, logger: Logger);
10
+ discover(): Promise<void>;
11
+ getMarkets(baseAsset: string): PerpMarket[];
12
+ getGroup(baseAsset: string): MarketGroup | undefined;
13
+ getAllGroups(): MarketGroup[];
14
+ getGroupsWithAlternatives(): MarketGroup[];
15
+ private parseAsset;
16
+ private extractBaseAsset;
17
+ private resolveCollateralToken;
18
+ }
19
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/market/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE1D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE1D,qBAAa,cAAc;IAMvB,OAAO,CAAC,QAAQ;IALlB,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,UAAU,CAAgC;IAClD,OAAO,CAAC,MAAM,CAAS;gBAGb,QAAQ,EAAE,UAAU,EAC5B,MAAM,EAAE,MAAM;IAKV,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAqG/B,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,EAAE;IAI3C,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAIpD,YAAY,IAAI,WAAW,EAAE;IAI7B,yBAAyB,IAAI,WAAW,EAAE;IAI1C,OAAO,CAAC,UAAU;IAyBlB,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,sBAAsB;CAQ/B"}