openbroker 1.3.1 → 1.4.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 (171) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/SKILL.md +7 -4
  3. package/dist/auto/audit.d.ts +57 -0
  4. package/dist/auto/audit.d.ts.map +1 -0
  5. package/dist/auto/audit.js +407 -0
  6. package/dist/auto/cli.d.ts +2 -0
  7. package/dist/auto/cli.d.ts.map +1 -0
  8. package/dist/auto/cli.js +423 -0
  9. package/dist/auto/events.d.ts +11 -0
  10. package/dist/auto/events.d.ts.map +1 -0
  11. package/dist/auto/events.js +36 -0
  12. package/dist/auto/examples/dca.d.ts +4 -0
  13. package/dist/auto/examples/dca.d.ts.map +1 -0
  14. package/dist/auto/examples/dca.js +60 -0
  15. package/dist/auto/examples/funding-arb.d.ts +4 -0
  16. package/dist/auto/examples/funding-arb.d.ts.map +1 -0
  17. package/dist/auto/examples/funding-arb.js +81 -0
  18. package/dist/auto/examples/grid.d.ts +4 -0
  19. package/dist/auto/examples/grid.d.ts.map +1 -0
  20. package/dist/auto/examples/grid.js +114 -0
  21. package/dist/auto/examples/mm-maker.d.ts +4 -0
  22. package/dist/auto/examples/mm-maker.d.ts.map +1 -0
  23. package/dist/auto/examples/mm-maker.js +131 -0
  24. package/dist/auto/examples/mm-spread.d.ts +4 -0
  25. package/dist/auto/examples/mm-spread.d.ts.map +1 -0
  26. package/dist/auto/examples/mm-spread.js +119 -0
  27. package/dist/auto/examples/price-alert.d.ts +4 -0
  28. package/dist/auto/examples/price-alert.d.ts.map +1 -0
  29. package/dist/auto/examples/price-alert.js +85 -0
  30. package/dist/auto/keep-awake.d.ts +11 -0
  31. package/dist/auto/keep-awake.d.ts.map +1 -0
  32. package/dist/auto/keep-awake.js +70 -0
  33. package/dist/auto/loader.d.ts +22 -0
  34. package/dist/auto/loader.d.ts.map +1 -0
  35. package/dist/auto/loader.js +127 -0
  36. package/dist/auto/prune.d.ts +40 -0
  37. package/dist/auto/prune.d.ts.map +1 -0
  38. package/dist/auto/prune.js +204 -0
  39. package/dist/auto/registry.d.ts +24 -0
  40. package/dist/auto/registry.d.ts.map +1 -0
  41. package/dist/auto/registry.js +93 -0
  42. package/dist/auto/report.d.ts +3 -0
  43. package/dist/auto/report.d.ts.map +1 -0
  44. package/dist/auto/report.js +385 -0
  45. package/dist/auto/runtime.d.ts +33 -0
  46. package/dist/auto/runtime.d.ts.map +1 -0
  47. package/dist/auto/runtime.js +844 -0
  48. package/dist/auto/types.d.ts +236 -0
  49. package/dist/auto/types.d.ts.map +1 -0
  50. package/dist/auto/types.js +3 -0
  51. package/dist/core/client.d.ts +684 -0
  52. package/dist/core/client.d.ts.map +1 -0
  53. package/dist/core/client.js +2040 -0
  54. package/dist/core/config.d.ts +22 -0
  55. package/dist/core/config.d.ts.map +1 -0
  56. package/dist/core/config.js +143 -0
  57. package/dist/core/types.d.ts +221 -0
  58. package/dist/core/types.d.ts.map +1 -0
  59. package/dist/core/types.js +2 -0
  60. package/dist/core/utils.d.ts +61 -0
  61. package/dist/core/utils.d.ts.map +1 -0
  62. package/dist/core/utils.js +142 -0
  63. package/dist/core/ws.d.ts +121 -0
  64. package/dist/core/ws.d.ts.map +1 -0
  65. package/dist/core/ws.js +222 -0
  66. package/dist/info/account.d.ts +3 -0
  67. package/dist/info/account.d.ts.map +1 -0
  68. package/dist/info/account.js +198 -0
  69. package/dist/info/all-markets.d.ts +3 -0
  70. package/dist/info/all-markets.d.ts.map +1 -0
  71. package/dist/info/all-markets.js +272 -0
  72. package/dist/info/candles.d.ts +3 -0
  73. package/dist/info/candles.d.ts.map +1 -0
  74. package/dist/info/candles.js +120 -0
  75. package/dist/info/fees.d.ts +3 -0
  76. package/dist/info/fees.d.ts.map +1 -0
  77. package/dist/info/fees.js +87 -0
  78. package/dist/info/fills.d.ts +3 -0
  79. package/dist/info/fills.d.ts.map +1 -0
  80. package/dist/info/fills.js +105 -0
  81. package/dist/info/funding-history.d.ts +3 -0
  82. package/dist/info/funding-history.d.ts.map +1 -0
  83. package/dist/info/funding-history.js +98 -0
  84. package/dist/info/funding-scan.d.ts +3 -0
  85. package/dist/info/funding-scan.d.ts.map +1 -0
  86. package/dist/info/funding-scan.js +178 -0
  87. package/dist/info/funding.d.ts +3 -0
  88. package/dist/info/funding.d.ts.map +1 -0
  89. package/dist/info/funding.js +158 -0
  90. package/dist/info/markets.d.ts +3 -0
  91. package/dist/info/markets.d.ts.map +1 -0
  92. package/dist/info/markets.js +178 -0
  93. package/dist/info/order-status.d.ts +3 -0
  94. package/dist/info/order-status.d.ts.map +1 -0
  95. package/dist/info/order-status.js +85 -0
  96. package/dist/info/orders.d.ts +3 -0
  97. package/dist/info/orders.d.ts.map +1 -0
  98. package/dist/info/orders.js +162 -0
  99. package/dist/info/outcomes.d.ts +3 -0
  100. package/dist/info/outcomes.d.ts.map +1 -0
  101. package/dist/info/outcomes.js +175 -0
  102. package/dist/info/positions.d.ts +3 -0
  103. package/dist/info/positions.d.ts.map +1 -0
  104. package/dist/info/positions.js +127 -0
  105. package/dist/info/rate-limit.d.ts +3 -0
  106. package/dist/info/rate-limit.d.ts.map +1 -0
  107. package/dist/info/rate-limit.js +58 -0
  108. package/dist/info/search-markets.d.ts +3 -0
  109. package/dist/info/search-markets.d.ts.map +1 -0
  110. package/dist/info/search-markets.js +296 -0
  111. package/dist/info/spot.d.ts +3 -0
  112. package/dist/info/spot.d.ts.map +1 -0
  113. package/dist/info/spot.js +192 -0
  114. package/dist/info/trades.d.ts +3 -0
  115. package/dist/info/trades.d.ts.map +1 -0
  116. package/dist/info/trades.js +97 -0
  117. package/dist/lib.d.ts +14 -0
  118. package/dist/lib.d.ts.map +1 -0
  119. package/dist/lib.js +17 -0
  120. package/dist/operations/bracket.d.ts +28 -0
  121. package/dist/operations/bracket.d.ts.map +1 -0
  122. package/dist/operations/bracket.js +266 -0
  123. package/dist/operations/cancel.d.ts +3 -0
  124. package/dist/operations/cancel.d.ts.map +1 -0
  125. package/dist/operations/cancel.js +107 -0
  126. package/dist/operations/chase.d.ts +25 -0
  127. package/dist/operations/chase.d.ts.map +1 -0
  128. package/dist/operations/chase.js +215 -0
  129. package/dist/operations/limit-order.d.ts +3 -0
  130. package/dist/operations/limit-order.d.ts.map +1 -0
  131. package/dist/operations/limit-order.js +144 -0
  132. package/dist/operations/market-order.d.ts +3 -0
  133. package/dist/operations/market-order.d.ts.map +1 -0
  134. package/dist/operations/market-order.js +153 -0
  135. package/dist/operations/outcome-order.d.ts +3 -0
  136. package/dist/operations/outcome-order.d.ts.map +1 -0
  137. package/dist/operations/outcome-order.js +171 -0
  138. package/dist/operations/scale.d.ts +3 -0
  139. package/dist/operations/scale.d.ts.map +1 -0
  140. package/dist/operations/scale.js +212 -0
  141. package/dist/operations/set-tpsl.d.ts +3 -0
  142. package/dist/operations/set-tpsl.d.ts.map +1 -0
  143. package/dist/operations/set-tpsl.js +277 -0
  144. package/dist/operations/spot-order.d.ts +3 -0
  145. package/dist/operations/spot-order.d.ts.map +1 -0
  146. package/dist/operations/spot-order.js +173 -0
  147. package/dist/operations/trigger-order.d.ts +3 -0
  148. package/dist/operations/trigger-order.d.ts.map +1 -0
  149. package/dist/operations/trigger-order.js +177 -0
  150. package/dist/operations/twap-cancel.d.ts +3 -0
  151. package/dist/operations/twap-cancel.d.ts.map +1 -0
  152. package/dist/operations/twap-cancel.js +57 -0
  153. package/dist/operations/twap-status.d.ts +3 -0
  154. package/dist/operations/twap-status.d.ts.map +1 -0
  155. package/dist/operations/twap-status.js +81 -0
  156. package/dist/operations/twap.d.ts +3 -0
  157. package/dist/operations/twap.d.ts.map +1 -0
  158. package/dist/operations/twap.js +124 -0
  159. package/dist/setup/approve-builder.d.ts +3 -0
  160. package/dist/setup/approve-builder.d.ts.map +1 -0
  161. package/dist/setup/approve-builder.js +155 -0
  162. package/dist/setup/env.d.ts +4 -0
  163. package/dist/setup/env.d.ts.map +1 -0
  164. package/dist/setup/env.js +8 -0
  165. package/dist/setup/onboard.d.ts +10 -0
  166. package/dist/setup/onboard.d.ts.map +1 -0
  167. package/dist/setup/onboard.js +462 -0
  168. package/package.json +10 -4
  169. package/scripts/core/client.ts +13 -3
  170. package/scripts/info/all-markets.ts +18 -2
  171. package/scripts/info/search-markets.ts +18 -2
@@ -0,0 +1,296 @@
1
+ #!/usr/bin/env tsx
2
+ // Search Markets - Find specific assets across all providers (perps, HIP-3, spot, HIP-4)
3
+ import { getClient } from '../core/client.js';
4
+ function parseArgs() {
5
+ const args = { query: '', type: 'all' };
6
+ for (let i = 2; i < process.argv.length; i++) {
7
+ const arg = process.argv[i];
8
+ if (arg === '--query' && process.argv[i + 1]) {
9
+ args.query = process.argv[++i];
10
+ }
11
+ else if (arg === '--type' && process.argv[i + 1]) {
12
+ const val = process.argv[++i].toLowerCase();
13
+ if (['perp', 'spot', 'hip3', 'outcome', 'all'].includes(val)) {
14
+ args.type = val;
15
+ }
16
+ }
17
+ else if (arg === '--verbose') {
18
+ args.verbose = true;
19
+ }
20
+ else if (arg === '--json') {
21
+ args.json = true;
22
+ }
23
+ else if (arg === '--help' || arg === '-h') {
24
+ console.log(`
25
+ Search Markets - Find assets across all Hyperliquid markets
26
+
27
+ Usage: npx tsx scripts/info/search-markets.ts --query <search> [options]
28
+
29
+ Options:
30
+ --query <search> Search term (required) - matches coin name
31
+ --type <type> Filter by market type: perp, spot, hip3, outcome, or all (default: all)
32
+ --json Output as JSON (machine-readable)
33
+ --verbose Show detailed output
34
+ --help Show this help
35
+
36
+ Examples:
37
+ npx tsx scripts/info/search-markets.ts --query GOLD # Find all GOLD markets
38
+ npx tsx scripts/info/search-markets.ts --query BTC # Find all BTC markets
39
+ npx tsx scripts/info/search-markets.ts --query ETH --type perp # ETH perps only
40
+ npx tsx scripts/info/search-markets.ts --query PURR --type spot # PURR spot only
41
+ npx tsx scripts/info/search-markets.ts --query BTC --type outcome # HIP-4 outcomes only
42
+ npx tsx scripts/info/search-markets.ts --query HYPE --json # JSON output
43
+ `);
44
+ process.exit(0);
45
+ }
46
+ else if (!args.query && !arg.startsWith('-')) {
47
+ // Allow query as positional arg
48
+ args.query = arg;
49
+ }
50
+ }
51
+ if (!args.query) {
52
+ console.error('Error: --query is required');
53
+ console.log('Usage: npx tsx scripts/info/search-markets.ts --query <search>');
54
+ process.exit(1);
55
+ }
56
+ return args;
57
+ }
58
+ function formatVolume(vol) {
59
+ if (vol >= 1_000_000_000)
60
+ return `$${(vol / 1_000_000_000).toFixed(2)}B`;
61
+ if (vol >= 1_000_000)
62
+ return `$${(vol / 1_000_000).toFixed(2)}M`;
63
+ if (vol >= 1_000)
64
+ return `$${(vol / 1_000).toFixed(2)}K`;
65
+ return `$${vol.toFixed(2)}`;
66
+ }
67
+ function formatPrice(price) {
68
+ const p = typeof price === 'string' ? parseFloat(price) : price;
69
+ if (p >= 1000)
70
+ return p.toFixed(2);
71
+ if (p >= 1)
72
+ return p.toFixed(4);
73
+ if (p >= 0.01)
74
+ return p.toFixed(6);
75
+ return p.toFixed(8);
76
+ }
77
+ function formatFunding(rate) {
78
+ const r = parseFloat(rate);
79
+ const annualized = r * 24 * 365 * 100;
80
+ const sign = annualized >= 0 ? '+' : '';
81
+ return `${sign}${annualized.toFixed(2)}%`;
82
+ }
83
+ function handleMarketFetchError(kind, error, requestedType, verbose) {
84
+ const message = error instanceof Error ? error.message : String(error);
85
+ if (requestedType === kind) {
86
+ throw new Error(`Failed to fetch ${kind} markets: ${message}`);
87
+ }
88
+ if (verbose) {
89
+ console.error(`Failed to fetch ${kind} markets:`, error);
90
+ }
91
+ }
92
+ async function main() {
93
+ const args = parseArgs();
94
+ const client = getClient();
95
+ client.verbose = args.verbose ?? false;
96
+ const query = args.query.toUpperCase();
97
+ if (!args.json) {
98
+ console.log(`Searching for "${query}" across all markets...\n`);
99
+ }
100
+ const results = [];
101
+ // Search main perps
102
+ if (args.type === 'all' || args.type === 'perp') {
103
+ const meta = await client.getMetaAndAssetCtxs();
104
+ for (let i = 0; i < meta.meta.universe.length; i++) {
105
+ const asset = meta.meta.universe[i];
106
+ const ctx = meta.assetCtxs[i];
107
+ if (asset.name.toUpperCase().includes(query)) {
108
+ results.push({
109
+ type: 'perp',
110
+ provider: 'Hyperliquid',
111
+ coin: asset.name,
112
+ assetId: i,
113
+ price: ctx.markPx,
114
+ volume24h: parseFloat(ctx.dayNtlVlm),
115
+ funding: ctx.funding,
116
+ maxLeverage: asset.maxLeverage,
117
+ openInterest: ctx.openInterest,
118
+ });
119
+ }
120
+ }
121
+ }
122
+ // Search HIP-3 perps
123
+ if (args.type === 'all' || args.type === 'hip3') {
124
+ if (client.isTestnet) {
125
+ // On testnet, load specific dex if query is "dex:COIN" format
126
+ if (args.query.includes(':')) {
127
+ await client.loadSingleHip3Dex(args.query.split(':')[0]);
128
+ }
129
+ else if (!args.json) {
130
+ console.log(' (Testnet: HIP-3 dexes not auto-loaded. Use "dexName:COIN" to search a specific dex.)\n');
131
+ }
132
+ }
133
+ try {
134
+ const allPerpMetas = await client.getAllPerpMetas();
135
+ // Skip index 0 (main dex), process HIP-3 dexs
136
+ for (let dexIdx = 1; dexIdx < allPerpMetas.length; dexIdx++) {
137
+ const dexData = allPerpMetas[dexIdx];
138
+ if (!dexData || !dexData.meta?.universe)
139
+ continue;
140
+ for (let i = 0; i < dexData.meta.universe.length; i++) {
141
+ const asset = dexData.meta.universe[i];
142
+ const ctx = dexData.assetCtxs[i];
143
+ if (!asset || !ctx)
144
+ continue;
145
+ if (asset.name.toUpperCase().includes(query)) {
146
+ let assetId = -1;
147
+ try {
148
+ assetId = client.getAssetIndex(asset.name);
149
+ }
150
+ catch { /* not registered */ }
151
+ results.push({
152
+ type: 'hip3',
153
+ provider: dexData.dexName || `HIP-3 DEX ${dexIdx}`,
154
+ coin: asset.name,
155
+ assetId,
156
+ price: ctx.markPx,
157
+ volume24h: parseFloat(ctx.dayNtlVlm || '0'),
158
+ funding: ctx.funding,
159
+ maxLeverage: asset.maxLeverage,
160
+ openInterest: ctx.openInterest,
161
+ });
162
+ }
163
+ }
164
+ }
165
+ }
166
+ catch (e) {
167
+ if (args.verbose)
168
+ console.error('Failed to fetch HIP-3 markets:', e);
169
+ }
170
+ }
171
+ // Search spot markets
172
+ if (args.type === 'all' || args.type === 'spot') {
173
+ try {
174
+ const spotData = await client.getSpotMetaAndAssetCtxs();
175
+ // Build token index → name lookup for matching by base token name
176
+ const tokenNameMap = new Map();
177
+ for (const token of spotData.meta.tokens) {
178
+ tokenNameMap.set(token.index, token.name);
179
+ }
180
+ // Build ctx map by coin name (contexts have a 'coin' field that matches pair.name).
181
+ // The contexts array can be longer than universe and is NOT aligned by index.
182
+ const ctxMap = new Map();
183
+ for (const ctx of spotData.assetCtxs) {
184
+ if (ctx.coin) {
185
+ ctxMap.set(ctx.coin, ctx);
186
+ }
187
+ }
188
+ for (const pair of spotData.meta.universe) {
189
+ if (!pair)
190
+ continue;
191
+ const ctx = ctxMap.get(pair.name);
192
+ if (!ctx)
193
+ continue;
194
+ // Match against pair name, base token name, and quote token name
195
+ const baseTokenName = tokenNameMap.get(pair.tokens[0]) ?? '';
196
+ const quoteTokenName = tokenNameMap.get(pair.tokens[1]) ?? '';
197
+ const searchable = `${pair.name} ${baseTokenName} ${quoteTokenName}`.toUpperCase();
198
+ if (searchable.includes(query)) {
199
+ const displayName = baseTokenName && quoteTokenName
200
+ ? `${baseTokenName}/${quoteTokenName}`
201
+ : pair.name;
202
+ results.push({
203
+ type: 'spot',
204
+ provider: 'Spot',
205
+ coin: displayName,
206
+ assetId: 10000 + pair.index,
207
+ price: ctx.markPx,
208
+ volume24h: parseFloat(ctx.dayNtlVlm || '0'),
209
+ });
210
+ }
211
+ }
212
+ }
213
+ catch (e) {
214
+ if (args.verbose)
215
+ console.error('Failed to fetch spot markets:', e);
216
+ }
217
+ }
218
+ // Search HIP-4 outcome markets
219
+ if (args.type === 'all' || args.type === 'outcome') {
220
+ try {
221
+ const outcomes = await client.getOutcomeMarkets();
222
+ for (const market of outcomes) {
223
+ const parsed = Object.values(market.parsedDescription).join(' ');
224
+ const searchable = `${market.name} ${market.description} ${parsed}`.toUpperCase();
225
+ if (!searchable.includes(query))
226
+ continue;
227
+ for (const side of market.sides) {
228
+ results.push({
229
+ type: 'outcome',
230
+ provider: 'HIP-4',
231
+ coin: side.coin,
232
+ assetId: side.assetId,
233
+ price: side.midPx ?? side.markPx ?? '0',
234
+ volume24h: parseFloat(side.dayNtlVlm || '0'),
235
+ outcome: market.outcome,
236
+ outcomeSide: side.name,
237
+ outcomeName: market.name,
238
+ tokenName: side.tokenName,
239
+ parsedDescription: market.parsedDescription,
240
+ description: market.description,
241
+ });
242
+ }
243
+ }
244
+ }
245
+ catch (e) {
246
+ handleMarketFetchError('outcome', e, args.type, args.verbose);
247
+ }
248
+ }
249
+ // Sort by volume
250
+ results.sort((a, b) => b.volume24h - a.volume24h);
251
+ if (args.json) {
252
+ console.log(JSON.stringify(results, null, 2));
253
+ return;
254
+ }
255
+ if (results.length === 0) {
256
+ console.log(`No markets found matching "${query}"`);
257
+ return;
258
+ }
259
+ console.log(`Found ${results.length} market(s) matching "${query}":\n`);
260
+ console.log('Type Provider Coin AssetID Price 24h Volume Funding (Ann.) OI');
261
+ console.log('-'.repeat(112));
262
+ for (const m of results) {
263
+ const typeStr = m.type === 'hip3' ? 'HIP-3' : m.type === 'outcome' ? 'HIP-4' : m.type.charAt(0).toUpperCase() + m.type.slice(1);
264
+ const oi = m.openInterest ? formatVolume(parseFloat(m.openInterest)) : '-';
265
+ console.log(`${typeStr.padEnd(8)} ${m.provider.padEnd(16)} ${m.coin.padEnd(14)} ${String(m.assetId).padStart(7)} ${formatPrice(m.price).padStart(16)} ${formatVolume(m.volume24h).padStart(13)} ${(m.funding ? formatFunding(m.funding) : '-').padStart(14)} ${oi.padStart(10)}`);
266
+ if (m.type === 'outcome' && args.verbose) {
267
+ console.log(` Outcome ${m.outcome} ${m.outcomeSide}: ${m.description}`);
268
+ }
269
+ }
270
+ // Show comparison if same asset on multiple providers
271
+ const coinGroups = new Map();
272
+ for (const r of results) {
273
+ // Extract base asset name (strip /USDC, -PERP, etc.)
274
+ const baseCoin = r.coin.replace(/[-\/].*/, '').toUpperCase();
275
+ if (!coinGroups.has(baseCoin)) {
276
+ coinGroups.set(baseCoin, []);
277
+ }
278
+ coinGroups.get(baseCoin).push(r);
279
+ }
280
+ // Show funding comparison for assets with multiple providers
281
+ for (const [coin, markets] of coinGroups) {
282
+ const perpsWithFunding = markets.filter((m) => m.funding && m.type !== 'spot');
283
+ if (perpsWithFunding.length > 1) {
284
+ console.log(`\n=== ${coin} Funding Comparison ===\n`);
285
+ console.log('Provider Coin AssetID Funding (Ann.) Price');
286
+ console.log('-'.repeat(78));
287
+ for (const m of perpsWithFunding.sort((a, b) => parseFloat(b.funding) - parseFloat(a.funding))) {
288
+ console.log(`${m.provider.padEnd(16)} ${m.coin.padEnd(14)} ${String(m.assetId).padStart(7)} ${formatFunding(m.funding).padStart(14)} ${formatPrice(m.price)}`);
289
+ }
290
+ }
291
+ }
292
+ }
293
+ main().catch((e) => {
294
+ console.error('Error:', e.message);
295
+ process.exit(1);
296
+ });
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env tsx
2
+ export {};
3
+ //# sourceMappingURL=spot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spot.d.ts","sourceRoot":"","sources":["../../scripts/info/spot.ts"],"names":[],"mappings":""}
@@ -0,0 +1,192 @@
1
+ #!/usr/bin/env tsx
2
+ // Spot Markets - View spot markets and balances
3
+ import { getClient } from '../core/client.js';
4
+ function parseArgs() {
5
+ const args = {};
6
+ for (let i = 2; i < process.argv.length; i++) {
7
+ const arg = process.argv[i];
8
+ if (arg === '--coin' && process.argv[i + 1]) {
9
+ args.coin = process.argv[++i].toUpperCase();
10
+ }
11
+ else if (arg === '--balances') {
12
+ args.balances = true;
13
+ }
14
+ else if (arg === '--top' && process.argv[i + 1]) {
15
+ args.top = parseInt(process.argv[++i], 10);
16
+ }
17
+ else if (arg === '--address' && process.argv[i + 1]) {
18
+ args.address = process.argv[++i].toLowerCase();
19
+ }
20
+ else if (arg === '--verbose') {
21
+ args.verbose = true;
22
+ }
23
+ else if (arg === '--json') {
24
+ args.json = true;
25
+ }
26
+ else if (arg === '--help' || arg === '-h') {
27
+ console.log(`
28
+ Spot Markets - View Hyperliquid spot markets and balances
29
+
30
+ Usage: npx tsx scripts/info/spot.ts [options]
31
+
32
+ Options:
33
+ --coin <symbol> Filter by coin symbol
34
+ --balances Show your spot token balances
35
+ --address <0x...> Look up another account's spot balances (with --balances)
36
+ --top <n> Show only top N markets by volume
37
+ --json Output as JSON (machine-readable)
38
+ --verbose Show detailed output
39
+ --help Show this help
40
+
41
+ Examples:
42
+ npx tsx scripts/info/spot.ts # Show all spot markets
43
+ npx tsx scripts/info/spot.ts --coin PURR # Show PURR market info
44
+ npx tsx scripts/info/spot.ts --balances # Show your spot balances
45
+ npx tsx scripts/info/spot.ts --top 20 # Show top 20 by volume
46
+ `);
47
+ process.exit(0);
48
+ }
49
+ }
50
+ return args;
51
+ }
52
+ function formatVolume(vol) {
53
+ if (vol >= 1_000_000_000)
54
+ return `$${(vol / 1_000_000_000).toFixed(2)}B`;
55
+ if (vol >= 1_000_000)
56
+ return `$${(vol / 1_000_000).toFixed(2)}M`;
57
+ if (vol >= 1_000)
58
+ return `$${(vol / 1_000).toFixed(2)}K`;
59
+ return `$${vol.toFixed(2)}`;
60
+ }
61
+ function formatPrice(price) {
62
+ const p = typeof price === 'string' ? parseFloat(price) : price;
63
+ if (p >= 1000)
64
+ return p.toFixed(2);
65
+ if (p >= 1)
66
+ return p.toFixed(4);
67
+ if (p >= 0.01)
68
+ return p.toFixed(6);
69
+ return p.toFixed(8);
70
+ }
71
+ function formatChange(current, prev) {
72
+ const c = parseFloat(current);
73
+ const p = parseFloat(prev);
74
+ if (p === 0)
75
+ return '-';
76
+ const change = ((c - p) / p) * 100;
77
+ const sign = change >= 0 ? '+' : '';
78
+ return `${sign}${change.toFixed(2)}%`;
79
+ }
80
+ async function main() {
81
+ const args = parseArgs();
82
+ const client = getClient();
83
+ client.verbose = args.verbose ?? false;
84
+ // Show balances
85
+ if (args.balances) {
86
+ const lookupAddress = args.address ?? client.address;
87
+ if (!args.json)
88
+ console.log(`Fetching spot balances for ${lookupAddress}...\n`);
89
+ const balances = await client.getSpotBalances(args.address);
90
+ if (args.json) {
91
+ console.log(JSON.stringify(balances.balances ?? [], null, 2));
92
+ return;
93
+ }
94
+ if (!balances.balances || balances.balances.length === 0) {
95
+ console.log('No spot token balances found.');
96
+ return;
97
+ }
98
+ console.log('=== Spot Balances ===\n');
99
+ console.log('Token Total Hold Entry Value');
100
+ console.log('-'.repeat(70));
101
+ for (const b of balances.balances) {
102
+ const total = parseFloat(b.total);
103
+ const hold = parseFloat(b.hold);
104
+ const entry = parseFloat(b.entryNtl);
105
+ if (total === 0)
106
+ continue;
107
+ console.log(`${b.coin.padEnd(14)} ${total.toFixed(6).padStart(18)} ${hold.toFixed(6).padStart(18)} ${formatVolume(entry).padStart(15)}`);
108
+ }
109
+ return;
110
+ }
111
+ // Show markets
112
+ if (!args.json)
113
+ console.log('Fetching spot market data...\n');
114
+ const spotData = await client.getSpotMetaAndAssetCtxs();
115
+ const markets = [];
116
+ // Build ctx map by coin name — the contexts array is NOT aligned with universe by index.
117
+ // Each context has a 'coin' field matching pair.name.
118
+ const ctxMap = new Map();
119
+ for (const ctx of spotData.assetCtxs) {
120
+ if (ctx.coin)
121
+ ctxMap.set(ctx.coin, ctx);
122
+ }
123
+ // Build token name map for filtering by base token name
124
+ const tokenNameMap = new Map();
125
+ for (const token of spotData.meta.tokens) {
126
+ tokenNameMap.set(token.index, token.name);
127
+ }
128
+ for (const pair of spotData.meta.universe) {
129
+ if (!pair)
130
+ continue;
131
+ const ctx = ctxMap.get(pair.name);
132
+ if (!ctx)
133
+ continue;
134
+ // Filter by coin — match pair name or base token name
135
+ if (args.coin) {
136
+ const baseTokenName = tokenNameMap.get(pair.tokens[0]) ?? '';
137
+ const searchable = `${pair.name} ${baseTokenName}`.toUpperCase();
138
+ if (!searchable.includes(args.coin))
139
+ continue;
140
+ }
141
+ markets.push({
142
+ name: pair.name,
143
+ index: pair.index,
144
+ assetId: 10000 + pair.index,
145
+ price: ctx.markPx,
146
+ volume24h: parseFloat(ctx.dayNtlVlm || '0'),
147
+ change24h: formatChange(ctx.markPx, ctx.prevDayPx),
148
+ tokens: pair.tokens,
149
+ base: tokenNameMap.get(pair.tokens[0]),
150
+ quote: tokenNameMap.get(pair.tokens[1]),
151
+ });
152
+ }
153
+ // Sort by volume
154
+ markets.sort((a, b) => b.volume24h - a.volume24h);
155
+ // Apply top filter
156
+ const displayMarkets = args.top ? markets.slice(0, args.top) : markets;
157
+ if (args.json) {
158
+ console.log(JSON.stringify(displayMarkets, null, 2));
159
+ return;
160
+ }
161
+ if (displayMarkets.length === 0) {
162
+ console.log(args.coin ? `No spot markets found for "${args.coin}"` : 'No spot markets found');
163
+ return;
164
+ }
165
+ // Get token info for detailed display
166
+ const tokenMap = new Map();
167
+ for (const token of spotData.meta.tokens) {
168
+ tokenMap.set(token.index, { name: token.name, tokenId: token.tokenId });
169
+ }
170
+ console.log(`=== Spot Markets (${displayMarkets.length} total) ===\n`);
171
+ console.log('Pair AssetID Price 24h Volume 24h Change Base/Quote');
172
+ console.log('-'.repeat(92));
173
+ for (const m of displayMarkets) {
174
+ const baseToken = tokenMap.get(m.tokens[0]);
175
+ const quoteToken = tokenMap.get(m.tokens[1]);
176
+ const pairStr = `${baseToken?.name || '?'}/${quoteToken?.name || '?'}`;
177
+ console.log(`${m.name.padEnd(14)} ${String(m.assetId).padStart(7)} ${formatPrice(m.price).padStart(16)} ${formatVolume(m.volume24h).padStart(13)} ${m.change24h.padStart(11)} ${pairStr}`);
178
+ }
179
+ // Show tokens if verbose
180
+ if (args.verbose) {
181
+ console.log('\n=== Tokens ===\n');
182
+ console.log('Name Token ID Decimals');
183
+ console.log('-'.repeat(50));
184
+ for (const token of spotData.meta.tokens) {
185
+ console.log(`${token.name.padEnd(14)} ${token.tokenId.padEnd(16)} sz=${token.szDecimals}, wei=${token.weiDecimals}`);
186
+ }
187
+ }
188
+ }
189
+ main().catch((e) => {
190
+ console.error('Error:', e.message);
191
+ process.exit(1);
192
+ });
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env npx tsx
2
+ export {};
3
+ //# sourceMappingURL=trades.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trades.d.ts","sourceRoot":"","sources":["../../scripts/info/trades.ts"],"names":[],"mappings":""}
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env npx tsx
2
+ // View recent trades (tape) for an asset on Hyperliquid
3
+ import { getClient } from '../core/client.js';
4
+ import { formatUsd, parseArgs, normalizeCoin } from '../core/utils.js';
5
+ function printUsage() {
6
+ console.log(`
7
+ Usage: openbroker trades --coin <symbol> [options]
8
+
9
+ Options:
10
+ --coin <symbol> Asset symbol (required, e.g. ETH, BTC)
11
+ --top <n> Show last N trades (default: 30)
12
+ --json Output as JSON (machine-readable)
13
+ --help, -h Show this help
14
+
15
+ Examples:
16
+ openbroker trades --coin ETH
17
+ openbroker trades --coin BTC --top 50
18
+ `);
19
+ }
20
+ async function main() {
21
+ const args = parseArgs(process.argv.slice(2));
22
+ if (args.help || args.h) {
23
+ printUsage();
24
+ process.exit(0);
25
+ }
26
+ const coin = args.coin;
27
+ if (!coin) {
28
+ console.error('Error: --coin is required');
29
+ printUsage();
30
+ process.exit(1);
31
+ }
32
+ const top = parseInt(args.top) || 30;
33
+ const jsonOutput = args.json;
34
+ const client = getClient();
35
+ if (!jsonOutput) {
36
+ console.log(`Open Broker - ${normalizeCoin(coin)} Recent Trades`);
37
+ console.log('='.repeat(40) + '\n');
38
+ }
39
+ try {
40
+ // Load metadata (needed for HIP-3 coin resolution)
41
+ await client.getMetaAndAssetCtxs();
42
+ if (client.isTestnet && coin.includes(':')) {
43
+ await client.loadSingleHip3Dex(coin.split(':')[0]);
44
+ }
45
+ let trades = await client.getRecentTrades(normalizeCoin(coin));
46
+ // Most recent first
47
+ trades.sort((a, b) => b.time - a.time);
48
+ trades = trades.slice(0, top);
49
+ if (jsonOutput) {
50
+ let assetId = -1;
51
+ try {
52
+ assetId = client.getAssetIndex(normalizeCoin(coin));
53
+ }
54
+ catch { /* noop */ }
55
+ console.log(JSON.stringify({ coin: normalizeCoin(coin), assetId, trades }, null, 2));
56
+ return;
57
+ }
58
+ if (trades.length === 0) {
59
+ console.log('No recent trades found');
60
+ return;
61
+ }
62
+ // Table header
63
+ console.log('Time'.padEnd(20) +
64
+ 'Side'.padEnd(6) +
65
+ 'Size'.padEnd(14) +
66
+ 'Price');
67
+ console.log('─'.repeat(55));
68
+ let totalVol = 0;
69
+ let buyVol = 0;
70
+ let sellVol = 0;
71
+ for (const trade of trades) {
72
+ const time = new Date(trade.time).toLocaleString();
73
+ const side = trade.side === 'B' ? 'BUY' : 'SELL';
74
+ const notional = parseFloat(trade.px) * parseFloat(trade.sz);
75
+ totalVol += notional;
76
+ if (trade.side === 'B')
77
+ buyVol += notional;
78
+ else
79
+ sellVol += notional;
80
+ console.log(time.padEnd(20) +
81
+ side.padEnd(6) +
82
+ trade.sz.padEnd(14) +
83
+ formatUsd(parseFloat(trade.px)));
84
+ }
85
+ // Summary
86
+ console.log('─'.repeat(55));
87
+ console.log(`Trades: ${trades.length} | Volume: ${formatUsd(totalVol)}`);
88
+ const buyPct = totalVol > 0 ? (buyVol / totalVol * 100).toFixed(1) : '0';
89
+ const sellPct = totalVol > 0 ? (sellVol / totalVol * 100).toFixed(1) : '0';
90
+ console.log(`Buy: ${buyPct}% | Sell: ${sellPct}%`);
91
+ }
92
+ catch (error) {
93
+ console.error('Error fetching trades:', error);
94
+ process.exit(1);
95
+ }
96
+ }
97
+ main();
package/dist/lib.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ export { HyperliquidClient, getClient, } from './core/client.js';
2
+ export { loadConfig, isConfigured, getNetwork, isMainnet, ensureConfigDir, getConfigPath, GLOBAL_CONFIG_DIR, GLOBAL_ENV_PATH, OPEN_BROKER_BUILDER_ADDRESS, } from './core/config.js';
3
+ export { roundPrice, roundSize, sleep, normalizeCoin, formatUsd, formatPercent, annualizeFundingRate, parseArgs, getSlippagePrice, getTimestampMs, generateCloid, orderToWire, checkBuilderFeeApproval, } from './core/utils.js';
4
+ export type * from './core/types.js';
5
+ export { runBracket } from './operations/bracket.js';
6
+ export type { BracketOptions, BracketResult } from './operations/bracket.js';
7
+ export { runChase } from './operations/chase.js';
8
+ export type { ChaseOptions, ChaseResult } from './operations/chase.js';
9
+ export { startAutomation, getRunningAutomations, getAutomation, getRegisteredAutomations, } from './auto/runtime.js';
10
+ export type { RuntimeOptions } from './auto/runtime.js';
11
+ export { resolveScriptPath, resolveExamplePath, listAutomations, listExamples, loadExampleConfigs, ensureAutomationsDir, loadAutomation, } from './auto/loader.js';
12
+ export { registerAutomation, unregisterAutomation, cleanRegistry, getAutomationsToRestart, markAutomationError, } from './auto/registry.js';
13
+ export type * from './auto/types.js';
14
+ //# sourceMappingURL=lib.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../scripts/lib.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,iBAAiB,EACjB,SAAS,GACV,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,UAAU,EACV,YAAY,EACZ,UAAU,EACV,SAAS,EACT,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,2BAA2B,GAC5B,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,UAAU,EACV,SAAS,EACT,KAAK,EACL,aAAa,EACb,SAAS,EACT,aAAa,EACb,oBAAoB,EACpB,SAAS,EACT,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,WAAW,EACX,uBAAuB,GACxB,MAAM,iBAAiB,CAAC;AAEzB,mBAAmB,iBAAiB,CAAC;AAIrC,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE7E,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAIvE,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,aAAa,EACb,wBAAwB,GACzB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,oBAAoB,EACpB,cAAc,GACf,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,aAAa,EACb,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,oBAAoB,CAAC;AAE5B,mBAAmB,iBAAiB,CAAC"}
package/dist/lib.js ADDED
@@ -0,0 +1,17 @@
1
+ // Public library API for `openbroker`.
2
+ //
3
+ // External packages — notably `openbroker-plugin` — import from here to
4
+ // drive the CLI's functionality in-process (no `child_process` dispatch).
5
+ //
6
+ // Stability: every symbol re-exported here is a public API. Renames or
7
+ // removals are breaking changes and require a major version bump.
8
+ export { HyperliquidClient, getClient, } from './core/client.js';
9
+ export { loadConfig, isConfigured, getNetwork, isMainnet, ensureConfigDir, getConfigPath, GLOBAL_CONFIG_DIR, GLOBAL_ENV_PATH, OPEN_BROKER_BUILDER_ADDRESS, } from './core/config.js';
10
+ export { roundPrice, roundSize, sleep, normalizeCoin, formatUsd, formatPercent, annualizeFundingRate, parseArgs, getSlippagePrice, getTimestampMs, generateCloid, orderToWire, checkBuilderFeeApproval, } from './core/utils.js';
11
+ // ── Operations (in-process callable) ────────────────────────────────
12
+ export { runBracket } from './operations/bracket.js';
13
+ export { runChase } from './operations/chase.js';
14
+ // ── Automation runtime ──────────────────────────────────────────────
15
+ export { startAutomation, getRunningAutomations, getAutomation, getRegisteredAutomations, } from './auto/runtime.js';
16
+ export { resolveScriptPath, resolveExamplePath, listAutomations, listExamples, loadExampleConfigs, ensureAutomationsDir, loadAutomation, } from './auto/loader.js';
17
+ export { registerAutomation, unregisterAutomation, cleanRegistry, getAutomationsToRestart, markAutomationError, } from './auto/registry.js';
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env npx tsx
2
+ export interface BracketOptions {
3
+ coin: string;
4
+ side: 'buy' | 'sell';
5
+ size: number;
6
+ tpPct: number;
7
+ slPct: number;
8
+ entryType?: 'market' | 'limit';
9
+ entryPrice?: number;
10
+ slippage?: number;
11
+ leverage?: number;
12
+ dryRun?: boolean;
13
+ verbose?: boolean;
14
+ /** Receives each output line. Defaults to console.log. */
15
+ output?: (line: string) => void;
16
+ }
17
+ export interface BracketResult {
18
+ status: 'dry' | 'limit_resting' | 'complete' | 'entry_failed' | 'partial';
19
+ entryPrice?: number;
20
+ tpPrice?: number;
21
+ slPrice?: number;
22
+ tpOid?: number | null;
23
+ slOid?: number | null;
24
+ entryOid?: number | null;
25
+ reason?: string;
26
+ }
27
+ export declare function runBracket(opts: BracketOptions): Promise<BracketResult>;
28
+ //# sourceMappingURL=bracket.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bracket.d.ts","sourceRoot":"","sources":["../../scripts/operations/bracket.ts"],"names":[],"mappings":";AA8CA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,KAAK,GAAG,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,KAAK,GAAG,eAAe,GAAG,UAAU,GAAG,cAAc,GAAG,SAAS,CAAC;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAsL7E"}