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,98 @@
1
+ #!/usr/bin/env npx tsx
2
+ // View historical funding rates for an asset on Hyperliquid
3
+ import { getClient } from '../core/client.js';
4
+ import { formatPercent, annualizeFundingRate, parseArgs, normalizeCoin } from '../core/utils.js';
5
+ function printUsage() {
6
+ console.log(`
7
+ Usage: openbroker funding-history --coin <symbol> [options]
8
+
9
+ Options:
10
+ --coin <symbol> Asset symbol (required, e.g. ETH, BTC)
11
+ --hours <n> Hours of history to fetch (default: 24)
12
+ --json Output as JSON (machine-readable)
13
+ --help, -h Show this help
14
+
15
+ Examples:
16
+ openbroker funding-history --coin ETH
17
+ openbroker funding-history --coin BTC --hours 168
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 hours = parseInt(args.hours) || 24;
33
+ const jsonOutput = args.json;
34
+ const client = getClient();
35
+ if (!jsonOutput) {
36
+ console.log(`Open Broker - ${normalizeCoin(coin)} Funding History (${hours}h)`);
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
+ const now = Date.now();
46
+ const startTime = now - (hours * 3_600_000);
47
+ const history = await client.getFundingHistory(normalizeCoin(coin), startTime);
48
+ if (jsonOutput) {
49
+ let assetId = -1;
50
+ try {
51
+ assetId = client.getAssetIndex(normalizeCoin(coin));
52
+ }
53
+ catch { /* noop */ }
54
+ console.log(JSON.stringify({ coin: normalizeCoin(coin), assetId, history }, null, 2));
55
+ return;
56
+ }
57
+ if (history.length === 0) {
58
+ console.log('No funding history found');
59
+ return;
60
+ }
61
+ // Table header
62
+ console.log('Time'.padEnd(20) +
63
+ 'Funding Rate'.padEnd(16) +
64
+ 'Annualized'.padEnd(14) +
65
+ 'Premium');
66
+ console.log('─'.repeat(60));
67
+ let totalRate = 0;
68
+ for (const entry of history) {
69
+ const time = new Date(entry.time).toLocaleString();
70
+ const rate = parseFloat(entry.fundingRate);
71
+ const annualized = annualizeFundingRate(rate);
72
+ const premium = parseFloat(entry.premium);
73
+ totalRate += rate;
74
+ console.log(time.padEnd(20) +
75
+ formatPercent(rate, 6).padEnd(16) +
76
+ formatPercent(annualized).padEnd(14) +
77
+ formatPercent(premium, 4));
78
+ }
79
+ // Summary
80
+ const avgRate = totalRate / history.length;
81
+ const avgAnnualized = annualizeFundingRate(avgRate);
82
+ console.log('─'.repeat(60));
83
+ console.log(`Samples: ${history.length}`);
84
+ console.log(`Avg Hourly Rate: ${formatPercent(avgRate, 6)}`);
85
+ console.log(`Avg Annualized: ${formatPercent(avgAnnualized)}`);
86
+ if (avgRate > 0) {
87
+ console.log('Longs pay shorts');
88
+ }
89
+ else if (avgRate < 0) {
90
+ console.log('Shorts pay longs');
91
+ }
92
+ }
93
+ catch (error) {
94
+ console.error('Error fetching funding history:', error);
95
+ process.exit(1);
96
+ }
97
+ }
98
+ main();
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env npx tsx
2
+ export {};
3
+ //# sourceMappingURL=funding-scan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"funding-scan.d.ts","sourceRoot":"","sources":["../../scripts/info/funding-scan.ts"],"names":[],"mappings":""}
@@ -0,0 +1,178 @@
1
+ #!/usr/bin/env npx tsx
2
+ // Cross-dex funding rate scanner - scan all assets (main + HIP-3) for funding opportunities
3
+ import { getClient } from '../core/client.js';
4
+ import { formatUsd, annualizeFundingRate, parseArgs, sleep } from '../core/utils.js';
5
+ function printUsage() {
6
+ console.log(`
7
+ Usage: openbroker funding-scan [options]
8
+
9
+ Scan funding rates across all dexes (main perps + HIP-3) and find opportunities.
10
+
11
+ Options:
12
+ --threshold <n> Min annualized funding rate % to show (default: 25)
13
+ --include-hip3 Include HIP-3 dex assets (default: true)
14
+ --main-only Only scan main perps
15
+ --hip3-only Only scan HIP-3 perps
16
+ --top <n> Show top N results (default: 30)
17
+ --pairs Show correlated pairs with opposing funding
18
+ --json Output as JSON
19
+ --watch Re-scan periodically
20
+ --interval <n> Watch interval in seconds (default: 60)
21
+ --help, -h Show this help
22
+
23
+ Examples:
24
+ openbroker funding-scan
25
+ openbroker funding-scan --threshold 50 --pairs
26
+ openbroker funding-scan --hip3-only --top 20
27
+ openbroker funding-scan --watch --interval 120
28
+ `);
29
+ }
30
+ async function scanFunding(client, options) {
31
+ const allPerps = await client.getAllPerpMetas();
32
+ const results = [];
33
+ for (const dexData of allPerps) {
34
+ const isMain = !dexData.dexName;
35
+ if (options.mainOnly && !isMain)
36
+ continue;
37
+ if (options.hip3Only && isMain)
38
+ continue;
39
+ for (let i = 0; i < dexData.meta.universe.length; i++) {
40
+ const asset = dexData.meta.universe[i];
41
+ const ctx = dexData.assetCtxs[i];
42
+ if (!ctx)
43
+ continue;
44
+ const hourlyRate = parseFloat(ctx.funding);
45
+ const annualizedPct = annualizeFundingRate(hourlyRate) * 100;
46
+ const openInterest = parseFloat(ctx.openInterest);
47
+ const markPx = parseFloat(ctx.markPx);
48
+ if (Math.abs(annualizedPct) < options.threshold)
49
+ continue;
50
+ if (openInterest < 100)
51
+ continue;
52
+ // API returns HIP-3 names already prefixed (e.g., "xyz:CL")
53
+ const coin = asset.name;
54
+ let assetId = isMain ? i : -1;
55
+ if (!isMain) {
56
+ try {
57
+ assetId = client.getAssetIndex(coin);
58
+ }
59
+ catch { /* not registered */ }
60
+ }
61
+ results.push({
62
+ coin,
63
+ assetId,
64
+ dex: dexData.dexName ?? 'main',
65
+ hourlyRate,
66
+ annualizedPct,
67
+ direction: hourlyRate > 0 ? 'longs pay' : 'shorts pay',
68
+ openInterest,
69
+ markPx,
70
+ });
71
+ }
72
+ }
73
+ // Sort by absolute annualized rate
74
+ results.sort((a, b) => Math.abs(b.annualizedPct) - Math.abs(a.annualizedPct));
75
+ return results.slice(0, options.topN);
76
+ }
77
+ function printResults(results, showPairs) {
78
+ if (results.length === 0) {
79
+ console.log('No assets above threshold');
80
+ return;
81
+ }
82
+ // Table header
83
+ console.log('Coin'.padEnd(16) +
84
+ 'Dex'.padEnd(8) +
85
+ 'Annualized'.padEnd(14) +
86
+ 'Direction'.padEnd(14) +
87
+ 'OI'.padEnd(14) +
88
+ 'Mark');
89
+ console.log('─'.repeat(75));
90
+ for (const r of results) {
91
+ const annStr = `${r.annualizedPct >= 0 ? '+' : ''}${r.annualizedPct.toFixed(1)}%`;
92
+ const oiStr = formatOI(r.openInterest);
93
+ console.log(r.coin.padEnd(16) +
94
+ r.dex.padEnd(8) +
95
+ annStr.padStart(12).padEnd(14) +
96
+ r.direction.padEnd(14) +
97
+ oiStr.padStart(12).padEnd(14) +
98
+ formatUsd(r.markPx));
99
+ }
100
+ // Show opposing pairs
101
+ if (showPairs) {
102
+ console.log('\nOpposing Funding Pairs:');
103
+ console.log('─'.repeat(75));
104
+ const longs = results.filter(r => r.annualizedPct > 0); // longs pay shorts
105
+ const shorts = results.filter(r => r.annualizedPct < 0); // shorts pay longs
106
+ const pairs = [];
107
+ for (const l of longs) {
108
+ for (const s of shorts) {
109
+ // Only pair across different dexes or correlated assets
110
+ const spread = l.annualizedPct + Math.abs(s.annualizedPct);
111
+ if (spread > 20) {
112
+ pairs.push({ long: l, short: s, spread });
113
+ }
114
+ }
115
+ }
116
+ pairs.sort((a, b) => b.spread - a.spread);
117
+ for (const p of pairs.slice(0, 10)) {
118
+ console.log(` SHORT ${p.long.coin.padEnd(14)} (${p.long.annualizedPct.toFixed(1)}%) ` +
119
+ `+ LONG ${p.short.coin.padEnd(14)} (${p.short.annualizedPct.toFixed(1)}%) ` +
120
+ `= ${p.spread.toFixed(1)}% spread`);
121
+ }
122
+ if (pairs.length === 0) {
123
+ console.log(' No strong opposing pairs found');
124
+ }
125
+ }
126
+ }
127
+ function formatOI(oi) {
128
+ if (oi >= 1_000_000)
129
+ return `$${(oi / 1_000_000).toFixed(2)}M`;
130
+ if (oi >= 1_000)
131
+ return `$${(oi / 1_000).toFixed(1)}K`;
132
+ return `$${oi.toFixed(0)}`;
133
+ }
134
+ async function main() {
135
+ const args = parseArgs(process.argv.slice(2));
136
+ if (args.help || args.h) {
137
+ printUsage();
138
+ process.exit(0);
139
+ }
140
+ const threshold = args.threshold ? parseFloat(args.threshold) : 25;
141
+ const mainOnly = args['main-only'] ?? false;
142
+ const hip3Only = args['hip3-only'] ?? false;
143
+ const topN = parseInt(args.top) || 30;
144
+ const showPairs = args.pairs ?? false;
145
+ const outputJson = args.json ?? false;
146
+ const watch = args.watch ?? false;
147
+ const intervalSec = args.interval ? parseInt(args.interval) : 60;
148
+ const client = getClient();
149
+ if (args.verbose)
150
+ client.verbose = true;
151
+ console.log('Open Broker - Funding Rate Scanner');
152
+ console.log('==================================\n');
153
+ console.log(`Threshold: ${threshold}% annualized | Scope: ${mainOnly ? 'main only' : hip3Only ? 'HIP-3 only' : 'all dexes'}\n`);
154
+ if (client.isTestnet && !mainOnly) {
155
+ console.log('Note: Testnet — HIP-3 dexes not auto-loaded. Only main perps will be scanned.\n');
156
+ }
157
+ const options = { threshold, mainOnly, hip3Only, topN };
158
+ const runScan = async () => {
159
+ const results = await scanFunding(client, options);
160
+ if (outputJson) {
161
+ console.log(JSON.stringify(results, null, 2));
162
+ }
163
+ else {
164
+ printResults(results, showPairs);
165
+ }
166
+ return results;
167
+ };
168
+ await runScan();
169
+ if (watch) {
170
+ console.log(`\nWatching every ${intervalSec}s... (Ctrl+C to stop)\n`);
171
+ while (true) {
172
+ await sleep(intervalSec * 1000);
173
+ console.log(`\n[${new Date().toLocaleTimeString()}] Rescanning...\n`);
174
+ await runScan();
175
+ }
176
+ }
177
+ }
178
+ main().catch(err => { console.error(err); process.exit(1); });
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env npx tsx
2
+ export {};
3
+ //# sourceMappingURL=funding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"funding.d.ts","sourceRoot":"","sources":["../../scripts/info/funding.ts"],"names":[],"mappings":""}
@@ -0,0 +1,158 @@
1
+ #!/usr/bin/env npx tsx
2
+ // Get funding rates from Hyperliquid
3
+ import { getClient } from '../core/client.js';
4
+ import { annualizeFundingRate, parseArgs } from '../core/utils.js';
5
+ async function main() {
6
+ const args = parseArgs(process.argv.slice(2));
7
+ const topN = parseInt(args.top) || 20;
8
+ const filterCoin = args.coin;
9
+ const sortBy = args.sort || 'annualized'; // annualized, hourly, oi
10
+ const showAll = args.all;
11
+ const jsonOutput = args.json;
12
+ const client = getClient();
13
+ const includeHip3 = args['include-hip3'] || args['hip3'] || (filterCoin?.includes(':') ?? false);
14
+ try {
15
+ const meta = await client.getMetaAndAssetCtxs();
16
+ const fundingData = [];
17
+ // Main dex assets
18
+ for (let i = 0; i < meta.meta.universe.length; i++) {
19
+ const asset = meta.meta.universe[i];
20
+ const ctx = meta.assetCtxs[i];
21
+ if (filterCoin && asset.name !== filterCoin)
22
+ continue;
23
+ const hourlyRate = parseFloat(ctx.funding);
24
+ const annualizedRate = annualizeFundingRate(hourlyRate);
25
+ const premium = parseFloat(ctx.premium ?? '0');
26
+ const openInterest = parseFloat(ctx.openInterest);
27
+ const markPx = parseFloat(ctx.markPx);
28
+ // Skip if OI is very low (unless showing all)
29
+ if (!showAll && openInterest < 10000)
30
+ continue;
31
+ fundingData.push({
32
+ coin: asset.name,
33
+ assetId: i,
34
+ hourlyRate,
35
+ annualizedRate,
36
+ premium,
37
+ openInterest,
38
+ markPx,
39
+ });
40
+ }
41
+ // Include HIP-3 dex assets
42
+ if (client.isTestnet && (includeHip3 || showAll) && !(filterCoin?.includes(':'))) {
43
+ console.log('Note: Testnet — HIP-3 dexes not auto-loaded. Use --coin dexName:COIN to view a specific HIP-3 asset.\n');
44
+ }
45
+ if (includeHip3 || showAll || (filterCoin && filterCoin.includes(':'))) {
46
+ // On testnet, load the specific dex on demand if user specified dex:COIN
47
+ if (client.isTestnet && filterCoin?.includes(':')) {
48
+ await client.loadSingleHip3Dex(filterCoin.split(':')[0]);
49
+ }
50
+ const allPerps = await client.getAllPerpMetas();
51
+ for (const dexData of allPerps) {
52
+ if (!dexData.dexName)
53
+ continue; // Skip main dex (already loaded)
54
+ for (let i = 0; i < dexData.meta.universe.length; i++) {
55
+ const asset = dexData.meta.universe[i];
56
+ const ctx = dexData.assetCtxs[i];
57
+ if (!ctx)
58
+ continue;
59
+ // API returns names already prefixed (e.g., "xyz:CL")
60
+ const coinName = asset.name;
61
+ if (filterCoin && coinName !== filterCoin)
62
+ continue;
63
+ const hourlyRate = parseFloat(ctx.funding);
64
+ const annualizedRate = annualizeFundingRate(hourlyRate);
65
+ const openInterest = parseFloat(ctx.openInterest);
66
+ const markPx = parseFloat(ctx.markPx);
67
+ if (!showAll && openInterest < 1000)
68
+ continue;
69
+ let assetId = -1;
70
+ try {
71
+ assetId = client.getAssetIndex(coinName);
72
+ }
73
+ catch { /* not registered */ }
74
+ fundingData.push({
75
+ coin: coinName,
76
+ assetId,
77
+ hourlyRate,
78
+ annualizedRate,
79
+ premium: 0,
80
+ openInterest,
81
+ markPx,
82
+ });
83
+ }
84
+ }
85
+ }
86
+ // Sort
87
+ if (sortBy === 'hourly' || sortBy === 'annualized') {
88
+ fundingData.sort((a, b) => Math.abs(b.annualizedRate) - Math.abs(a.annualizedRate));
89
+ }
90
+ else if (sortBy === 'oi') {
91
+ fundingData.sort((a, b) => b.openInterest - a.openInterest);
92
+ }
93
+ // Limit
94
+ const displayData = filterCoin ? fundingData : fundingData.slice(0, topN);
95
+ if (jsonOutput) {
96
+ console.log(JSON.stringify(displayData, null, 2));
97
+ return;
98
+ }
99
+ if (displayData.length === 0) {
100
+ console.log(filterCoin ? `No data for ${filterCoin}` : 'No funding data available');
101
+ return;
102
+ }
103
+ console.log('Open Broker - Funding Rates');
104
+ console.log('===========================\n');
105
+ // Table header
106
+ console.log('Coin | Hourly Rate | Annualized | Premium | Open Interest | Mark');
107
+ console.log('---------|-------------|------------|-------------|---------------|----------');
108
+ for (const data of displayData) {
109
+ const hourlyStr = formatRate(data.hourlyRate * 100, 6);
110
+ const annualStr = formatRate(data.annualizedRate * 100, 2);
111
+ const premiumStr = formatRate(data.premium * 100, 4);
112
+ const oiStr = formatOI(data.openInterest);
113
+ const markStr = formatMark(data.markPx);
114
+ console.log(`${data.coin.padEnd(8)} | ${hourlyStr.padStart(11)} | ${annualStr.padStart(10)} | ` +
115
+ `${premiumStr.padStart(11)} | ${oiStr.padStart(13)} | ${markStr.padStart(8)}`);
116
+ }
117
+ // Legend
118
+ console.log('\nLegend:');
119
+ console.log(' Hourly Rate: Funding rate per hour');
120
+ console.log(' Annualized: Hourly × 8760 hours');
121
+ console.log(' Premium: (Mark - Oracle) / Oracle');
122
+ console.log(' OI: Open Interest in contracts');
123
+ // Highlight high funding opportunities
124
+ const highFunding = fundingData.filter(d => Math.abs(d.annualizedRate) > 0.25);
125
+ if (highFunding.length > 0 && !filterCoin) {
126
+ console.log('\n💰 High Funding Opportunities (>25% annualized):');
127
+ for (const data of highFunding.slice(0, 5)) {
128
+ const direction = data.annualizedRate > 0 ? 'SHORT pays LONG' : 'LONG pays SHORT';
129
+ console.log(` ${data.coin}: ${formatRate(data.annualizedRate * 100, 1)}% - ${direction}`);
130
+ }
131
+ }
132
+ }
133
+ catch (error) {
134
+ console.error('Error fetching funding rates:', error);
135
+ process.exit(1);
136
+ }
137
+ }
138
+ function formatRate(rate, decimals) {
139
+ const sign = rate >= 0 ? '+' : '';
140
+ return `${sign}${rate.toFixed(decimals)}%`;
141
+ }
142
+ function formatOI(oi) {
143
+ if (oi >= 1_000_000)
144
+ return `${(oi / 1_000_000).toFixed(2)}M`;
145
+ if (oi >= 1_000)
146
+ return `${(oi / 1_000).toFixed(1)}K`;
147
+ return oi.toFixed(0);
148
+ }
149
+ function formatMark(price) {
150
+ if (price >= 10000)
151
+ return `$${(price / 1000).toFixed(1)}K`;
152
+ if (price >= 100)
153
+ return `$${price.toFixed(0)}`;
154
+ if (price >= 1)
155
+ return `$${price.toFixed(2)}`;
156
+ return `$${price.toFixed(4)}`;
157
+ }
158
+ main();
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env npx tsx
2
+ export {};
3
+ //# sourceMappingURL=markets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markets.d.ts","sourceRoot":"","sources":["../../scripts/info/markets.ts"],"names":[],"mappings":""}
@@ -0,0 +1,178 @@
1
+ #!/usr/bin/env npx tsx
2
+ // Get market info from Hyperliquid
3
+ import { getClient } from '../core/client.js';
4
+ import { formatUsd, parseArgs } from '../core/utils.js';
5
+ async function main() {
6
+ const args = parseArgs(process.argv.slice(2));
7
+ const filterCoin = args.coin;
8
+ const topN = parseInt(args.top) || 30;
9
+ const sortBy = args.sort || 'volume'; // volume, oi, change
10
+ const jsonOutput = args.json;
11
+ const client = getClient();
12
+ const includeHip3 = args['include-hip3'] || args['hip3'] || (filterCoin?.includes(':') ?? false);
13
+ try {
14
+ const meta = await client.getMetaAndAssetCtxs();
15
+ const markets = [];
16
+ for (let i = 0; i < meta.meta.universe.length; i++) {
17
+ const asset = meta.meta.universe[i];
18
+ const ctx = meta.assetCtxs[i];
19
+ if (filterCoin && asset.name !== filterCoin)
20
+ continue;
21
+ const markPx = parseFloat(ctx.markPx);
22
+ const oraclePx = parseFloat(ctx.oraclePx);
23
+ const prevDayPx = parseFloat(ctx.prevDayPx);
24
+ const volume24h = parseFloat(ctx.dayNtlVlm);
25
+ const openInterest = parseFloat(ctx.openInterest);
26
+ const change24h = prevDayPx > 0 ? (markPx - prevDayPx) / prevDayPx : 0;
27
+ markets.push({
28
+ coin: asset.name,
29
+ assetId: i,
30
+ markPx,
31
+ oraclePx,
32
+ prevDayPx,
33
+ change24h,
34
+ volume24h,
35
+ openInterest,
36
+ maxLeverage: asset.maxLeverage,
37
+ szDecimals: asset.szDecimals,
38
+ });
39
+ }
40
+ // Include HIP-3 markets
41
+ if (client.isTestnet && includeHip3 && !(filterCoin?.includes(':'))) {
42
+ console.log('Note: Testnet — HIP-3 dexes not auto-loaded. Use --coin dexName:COIN to view a specific HIP-3 asset.\n');
43
+ }
44
+ if (includeHip3 || (filterCoin && filterCoin.includes(':'))) {
45
+ // On testnet, load the specific dex on demand if user specified dex:COIN
46
+ if (client.isTestnet && filterCoin?.includes(':')) {
47
+ await client.loadSingleHip3Dex(filterCoin.split(':')[0]);
48
+ }
49
+ const allPerps = await client.getAllPerpMetas();
50
+ for (const dexData of allPerps) {
51
+ if (!dexData.dexName)
52
+ continue;
53
+ for (let i = 0; i < dexData.meta.universe.length; i++) {
54
+ const asset = dexData.meta.universe[i];
55
+ const ctx = dexData.assetCtxs[i];
56
+ if (!ctx)
57
+ continue;
58
+ // API returns names already prefixed (e.g., "xyz:CL")
59
+ const coinName = asset.name;
60
+ if (filterCoin && coinName !== filterCoin)
61
+ continue;
62
+ const markPx = parseFloat(ctx.markPx);
63
+ const oraclePx = parseFloat(ctx.oraclePx);
64
+ const prevDayPx = parseFloat(ctx.prevDayPx);
65
+ const volume24h = parseFloat(ctx.dayNtlVlm);
66
+ const openInterest = parseFloat(ctx.openInterest);
67
+ const change24h = prevDayPx > 0 ? (markPx - prevDayPx) / prevDayPx : 0;
68
+ let assetId = -1;
69
+ try {
70
+ assetId = client.getAssetIndex(coinName);
71
+ }
72
+ catch { /* not registered */ }
73
+ markets.push({
74
+ coin: coinName,
75
+ assetId,
76
+ markPx,
77
+ oraclePx,
78
+ prevDayPx,
79
+ change24h,
80
+ volume24h,
81
+ openInterest,
82
+ maxLeverage: asset.maxLeverage,
83
+ szDecimals: asset.szDecimals,
84
+ });
85
+ }
86
+ }
87
+ }
88
+ // Sort
89
+ if (sortBy === 'volume') {
90
+ markets.sort((a, b) => b.volume24h - a.volume24h);
91
+ }
92
+ else if (sortBy === 'oi') {
93
+ markets.sort((a, b) => b.openInterest - a.openInterest);
94
+ }
95
+ else if (sortBy === 'change') {
96
+ markets.sort((a, b) => Math.abs(b.change24h) - Math.abs(a.change24h));
97
+ }
98
+ // Limit
99
+ const displayData = filterCoin ? markets : markets.slice(0, topN);
100
+ if (jsonOutput) {
101
+ console.log(JSON.stringify(displayData, null, 2));
102
+ return;
103
+ }
104
+ console.log('Open Broker - Markets');
105
+ console.log('=====================\n');
106
+ if (displayData.length === 0) {
107
+ console.log(filterCoin ? `No data for ${filterCoin}` : 'No market data available');
108
+ return;
109
+ }
110
+ if (filterCoin && displayData.length === 1) {
111
+ // Detailed view for single coin
112
+ const m = displayData[0];
113
+ console.log(`${m.coin}`);
114
+ console.log('─'.repeat(40));
115
+ console.log(`Mark Price: ${formatUsd(m.markPx)}`);
116
+ console.log(`Oracle Price: ${formatUsd(m.oraclePx)}`);
117
+ console.log(`24h Change: ${formatChange(m.change24h)}`);
118
+ console.log(`24h Volume: ${formatVolume(m.volume24h)}`);
119
+ console.log(`Open Interest: ${formatVolume(m.openInterest * m.markPx)} (${formatOI(m.openInterest)} contracts)`);
120
+ console.log(`Max Leverage: ${m.maxLeverage}x`);
121
+ console.log(`Size Decimals: ${m.szDecimals}`);
122
+ console.log(`Min Size: ${(10 ** -m.szDecimals).toFixed(m.szDecimals)}`);
123
+ return;
124
+ }
125
+ // Table view
126
+ console.log('Coin | Mark | 24h Chg | 24h Volume | OI | Lev');
127
+ console.log('---------|--------------|------------|---------------|---------------|-----');
128
+ for (const m of displayData) {
129
+ console.log(`${m.coin.padEnd(8)} | ${formatUsd(m.markPx).padStart(12)} | ` +
130
+ `${formatChange(m.change24h).padStart(10)} | ` +
131
+ `${formatVolume(m.volume24h).padStart(13)} | ` +
132
+ `${formatVolume(m.openInterest * m.markPx).padStart(13)} | ` +
133
+ `${m.maxLeverage}x`);
134
+ }
135
+ // Top movers
136
+ if (!filterCoin) {
137
+ const gainers = [...markets].sort((a, b) => b.change24h - a.change24h).slice(0, 3);
138
+ const losers = [...markets].sort((a, b) => a.change24h - b.change24h).slice(0, 3);
139
+ console.log('\n📈 Top Gainers:');
140
+ for (const m of gainers) {
141
+ if (m.change24h <= 0)
142
+ break;
143
+ console.log(` ${m.coin}: ${formatChange(m.change24h)}`);
144
+ }
145
+ console.log('\n📉 Top Losers:');
146
+ for (const m of losers) {
147
+ if (m.change24h >= 0)
148
+ break;
149
+ console.log(` ${m.coin}: ${formatChange(m.change24h)}`);
150
+ }
151
+ }
152
+ }
153
+ catch (error) {
154
+ console.error('Error fetching market data:', error);
155
+ process.exit(1);
156
+ }
157
+ }
158
+ function formatChange(change) {
159
+ const sign = change >= 0 ? '+' : '';
160
+ return `${sign}${(change * 100).toFixed(2)}%`;
161
+ }
162
+ function formatVolume(volume) {
163
+ if (volume >= 1_000_000_000)
164
+ return `$${(volume / 1_000_000_000).toFixed(2)}B`;
165
+ if (volume >= 1_000_000)
166
+ return `$${(volume / 1_000_000).toFixed(2)}M`;
167
+ if (volume >= 1_000)
168
+ return `$${(volume / 1_000).toFixed(1)}K`;
169
+ return `$${volume.toFixed(0)}`;
170
+ }
171
+ function formatOI(oi) {
172
+ if (oi >= 1_000_000)
173
+ return `${(oi / 1_000_000).toFixed(2)}M`;
174
+ if (oi >= 1_000)
175
+ return `${(oi / 1_000).toFixed(1)}K`;
176
+ return oi.toFixed(0);
177
+ }
178
+ main();
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env npx tsx
2
+ export {};
3
+ //# sourceMappingURL=order-status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"order-status.d.ts","sourceRoot":"","sources":["../../scripts/info/order-status.ts"],"names":[],"mappings":""}