openbroker 1.0.82 → 1.0.87
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.
- package/SKILL.md +79 -7
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/scripts/auto/cli.ts +1 -0
- package/scripts/auto/dashboard-forwarder.ts +77 -0
- package/scripts/auto/loader.ts +4 -2
- package/scripts/auto/report.ts +2 -2
- package/scripts/auto/runtime.ts +42 -14
- package/scripts/auto/types.ts +17 -1
- package/scripts/core/client.ts +167 -23
- package/scripts/core/config.ts +1 -1
- package/scripts/core/types.ts +13 -4
- package/scripts/info/all-markets.ts +51 -24
- package/scripts/info/candles.ts +13 -2
- package/scripts/info/fees.ts +16 -5
- package/scripts/info/funding-history.ts +13 -2
- package/scripts/info/funding-scan.ts +6 -0
- package/scripts/info/funding.ts +7 -1
- package/scripts/info/markets.ts +5 -0
- package/scripts/info/order-status.ts +11 -2
- package/scripts/info/rate-limit.ts +11 -2
- package/scripts/info/search-markets.ts +30 -10
- package/scripts/info/spot.ts +25 -5
- package/scripts/info/trades.ts +13 -2
- package/scripts/operations/limit-order.ts +1 -1
- package/scripts/operations/twap-cancel.ts +4 -2
- package/scripts/operations/twap.ts +8 -10
- package/scripts/plugin/tools.ts +15 -19
- package/scripts/setup/onboard.ts +8 -2
|
@@ -32,6 +32,7 @@ Examples:
|
|
|
32
32
|
|
|
33
33
|
interface FundingScanResult {
|
|
34
34
|
coin: string;
|
|
35
|
+
assetId: number;
|
|
35
36
|
dex: string;
|
|
36
37
|
hourlyRate: number;
|
|
37
38
|
annualizedPct: number;
|
|
@@ -69,9 +70,14 @@ async function scanFunding(client: ReturnType<typeof getClient>, options: {
|
|
|
69
70
|
|
|
70
71
|
// API returns HIP-3 names already prefixed (e.g., "xyz:CL")
|
|
71
72
|
const coin = asset.name;
|
|
73
|
+
let assetId = isMain ? i : -1;
|
|
74
|
+
if (!isMain) {
|
|
75
|
+
try { assetId = client.getAssetIndex(coin); } catch { /* not registered */ }
|
|
76
|
+
}
|
|
72
77
|
|
|
73
78
|
results.push({
|
|
74
79
|
coin,
|
|
80
|
+
assetId,
|
|
75
81
|
dex: dexData.dexName ?? 'main',
|
|
76
82
|
hourlyRate,
|
|
77
83
|
annualizedPct,
|
package/scripts/info/funding.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { formatPercent, annualizeFundingRate, parseArgs } from '../core/utils.js
|
|
|
6
6
|
|
|
7
7
|
interface FundingDisplay {
|
|
8
8
|
coin: string;
|
|
9
|
+
assetId: number;
|
|
9
10
|
hourlyRate: number;
|
|
10
11
|
annualizedRate: number;
|
|
11
12
|
premium: number;
|
|
@@ -38,7 +39,7 @@ async function main() {
|
|
|
38
39
|
|
|
39
40
|
const hourlyRate = parseFloat(ctx.funding);
|
|
40
41
|
const annualizedRate = annualizeFundingRate(hourlyRate);
|
|
41
|
-
const premium = parseFloat(ctx.premium);
|
|
42
|
+
const premium = parseFloat(ctx.premium ?? '0');
|
|
42
43
|
const openInterest = parseFloat(ctx.openInterest);
|
|
43
44
|
const markPx = parseFloat(ctx.markPx);
|
|
44
45
|
|
|
@@ -47,6 +48,7 @@ async function main() {
|
|
|
47
48
|
|
|
48
49
|
fundingData.push({
|
|
49
50
|
coin: asset.name,
|
|
51
|
+
assetId: i,
|
|
50
52
|
hourlyRate,
|
|
51
53
|
annualizedRate,
|
|
52
54
|
premium,
|
|
@@ -84,8 +86,12 @@ async function main() {
|
|
|
84
86
|
|
|
85
87
|
if (!showAll && openInterest < 1000) continue;
|
|
86
88
|
|
|
89
|
+
let assetId = -1;
|
|
90
|
+
try { assetId = client.getAssetIndex(coinName); } catch { /* not registered */ }
|
|
91
|
+
|
|
87
92
|
fundingData.push({
|
|
88
93
|
coin: coinName,
|
|
94
|
+
assetId,
|
|
89
95
|
hourlyRate,
|
|
90
96
|
annualizedRate,
|
|
91
97
|
premium: 0,
|
package/scripts/info/markets.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { formatUsd, parseArgs } from '../core/utils.js';
|
|
|
6
6
|
|
|
7
7
|
interface MarketDisplay {
|
|
8
8
|
coin: string;
|
|
9
|
+
assetId: number;
|
|
9
10
|
markPx: number;
|
|
10
11
|
oraclePx: number;
|
|
11
12
|
prevDayPx: number;
|
|
@@ -47,6 +48,7 @@ async function main() {
|
|
|
47
48
|
|
|
48
49
|
markets.push({
|
|
49
50
|
coin: asset.name,
|
|
51
|
+
assetId: i,
|
|
50
52
|
markPx,
|
|
51
53
|
oraclePx,
|
|
52
54
|
prevDayPx,
|
|
@@ -86,9 +88,12 @@ async function main() {
|
|
|
86
88
|
const volume24h = parseFloat(ctx.dayNtlVlm);
|
|
87
89
|
const openInterest = parseFloat(ctx.openInterest);
|
|
88
90
|
const change24h = prevDayPx > 0 ? (markPx - prevDayPx) / prevDayPx : 0;
|
|
91
|
+
let assetId = -1;
|
|
92
|
+
try { assetId = client.getAssetIndex(coinName); } catch { /* not registered */ }
|
|
89
93
|
|
|
90
94
|
markets.push({
|
|
91
95
|
coin: coinName,
|
|
96
|
+
assetId,
|
|
92
97
|
markPx,
|
|
93
98
|
oraclePx,
|
|
94
99
|
prevDayPx,
|
|
@@ -11,6 +11,7 @@ Usage: openbroker order-status --oid <order-id>
|
|
|
11
11
|
Options:
|
|
12
12
|
--oid <id> Order ID (number) or client order ID (hex string) — required
|
|
13
13
|
--address <0x...> Look up order on another account
|
|
14
|
+
--json Output as JSON (machine-readable)
|
|
14
15
|
--help, -h Show this help
|
|
15
16
|
|
|
16
17
|
Examples:
|
|
@@ -37,15 +38,23 @@ async function main() {
|
|
|
37
38
|
|
|
38
39
|
const oid = oidArg.startsWith('0x') ? oidArg : parseInt(oidArg);
|
|
39
40
|
const targetAddress = args.address as string | undefined;
|
|
41
|
+
const jsonOutput = args.json as boolean;
|
|
40
42
|
const client = getClient();
|
|
41
43
|
const lookupAddress = targetAddress?.toLowerCase();
|
|
42
44
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
if (!jsonOutput) {
|
|
46
|
+
console.log('Open Broker - Order Status');
|
|
47
|
+
console.log('=========================\n');
|
|
48
|
+
}
|
|
45
49
|
|
|
46
50
|
try {
|
|
47
51
|
const result = await client.getOrderStatus(oid, lookupAddress);
|
|
48
52
|
|
|
53
|
+
if (jsonOutput) {
|
|
54
|
+
console.log(JSON.stringify(result, null, 2));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
49
58
|
if (result.status === 'unknownOid') {
|
|
50
59
|
console.log(`Order ${oidArg} not found`);
|
|
51
60
|
return;
|
|
@@ -9,6 +9,7 @@ function printUsage() {
|
|
|
9
9
|
Usage: openbroker rate-limit [options]
|
|
10
10
|
|
|
11
11
|
Options:
|
|
12
|
+
--json Output as JSON (machine-readable)
|
|
12
13
|
--help, -h Show this help
|
|
13
14
|
|
|
14
15
|
Examples:
|
|
@@ -24,14 +25,22 @@ async function main() {
|
|
|
24
25
|
process.exit(0);
|
|
25
26
|
}
|
|
26
27
|
|
|
28
|
+
const jsonOutput = args.json as boolean;
|
|
27
29
|
const client = getClient();
|
|
28
30
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
if (!jsonOutput) {
|
|
32
|
+
console.log('Open Broker - API Rate Limit');
|
|
33
|
+
console.log('===========================\n');
|
|
34
|
+
}
|
|
31
35
|
|
|
32
36
|
try {
|
|
33
37
|
const rl = await client.getUserRateLimit();
|
|
34
38
|
|
|
39
|
+
if (jsonOutput) {
|
|
40
|
+
console.log(JSON.stringify(rl, null, 2));
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
35
44
|
const used = rl.nRequestsUsed;
|
|
36
45
|
const cap = rl.nRequestsCap;
|
|
37
46
|
const surplus = rl.nRequestsSurplus;
|
|
@@ -7,6 +7,7 @@ interface Args {
|
|
|
7
7
|
query: string;
|
|
8
8
|
type?: 'perp' | 'spot' | 'hip3' | 'all';
|
|
9
9
|
verbose?: boolean;
|
|
10
|
+
json?: boolean;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
function parseArgs(): Args {
|
|
@@ -23,6 +24,8 @@ function parseArgs(): Args {
|
|
|
23
24
|
}
|
|
24
25
|
} else if (arg === '--verbose') {
|
|
25
26
|
args.verbose = true;
|
|
27
|
+
} else if (arg === '--json') {
|
|
28
|
+
args.json = true;
|
|
26
29
|
} else if (arg === '--help' || arg === '-h') {
|
|
27
30
|
console.log(`
|
|
28
31
|
Search Markets - Find assets across all Hyperliquid markets
|
|
@@ -32,6 +35,7 @@ Usage: npx tsx scripts/info/search-markets.ts --query <search> [options]
|
|
|
32
35
|
Options:
|
|
33
36
|
--query <search> Search term (required) - matches coin name
|
|
34
37
|
--type <type> Filter by market type: perp, spot, hip3, or all (default: all)
|
|
38
|
+
--json Output as JSON (machine-readable)
|
|
35
39
|
--verbose Show detailed output
|
|
36
40
|
--help Show this help
|
|
37
41
|
|
|
@@ -40,6 +44,7 @@ Examples:
|
|
|
40
44
|
npx tsx scripts/info/search-markets.ts --query BTC # Find all BTC markets
|
|
41
45
|
npx tsx scripts/info/search-markets.ts --query ETH --type perp # ETH perps only
|
|
42
46
|
npx tsx scripts/info/search-markets.ts --query PURR --type spot # PURR spot only
|
|
47
|
+
npx tsx scripts/info/search-markets.ts --query HYPE --json # JSON output
|
|
43
48
|
`);
|
|
44
49
|
process.exit(0);
|
|
45
50
|
} else if (!args.query && !arg.startsWith('-')) {
|
|
@@ -85,18 +90,23 @@ async function main() {
|
|
|
85
90
|
client.verbose = args.verbose ?? false;
|
|
86
91
|
|
|
87
92
|
const query = args.query.toUpperCase();
|
|
88
|
-
|
|
93
|
+
if (!args.json) {
|
|
94
|
+
console.log(`Searching for "${query}" across all markets...\n`);
|
|
95
|
+
}
|
|
89
96
|
|
|
90
|
-
|
|
97
|
+
interface Result {
|
|
91
98
|
type: 'perp' | 'spot' | 'hip3';
|
|
92
99
|
provider: string;
|
|
93
100
|
coin: string;
|
|
101
|
+
assetId: number;
|
|
94
102
|
price: string;
|
|
95
103
|
volume24h: number;
|
|
96
104
|
funding?: string;
|
|
97
105
|
maxLeverage?: number;
|
|
98
106
|
openInterest?: string;
|
|
99
|
-
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const results: Result[] = [];
|
|
100
110
|
|
|
101
111
|
// Search main perps
|
|
102
112
|
if (args.type === 'all' || args.type === 'perp') {
|
|
@@ -110,6 +120,7 @@ async function main() {
|
|
|
110
120
|
type: 'perp',
|
|
111
121
|
provider: 'Hyperliquid',
|
|
112
122
|
coin: asset.name,
|
|
123
|
+
assetId: i,
|
|
113
124
|
price: ctx.markPx,
|
|
114
125
|
volume24h: parseFloat(ctx.dayNtlVlm),
|
|
115
126
|
funding: ctx.funding,
|
|
@@ -126,7 +137,7 @@ async function main() {
|
|
|
126
137
|
// On testnet, load specific dex if query is "dex:COIN" format
|
|
127
138
|
if (args.query.includes(':')) {
|
|
128
139
|
await client.loadSingleHip3Dex(args.query.split(':')[0]);
|
|
129
|
-
} else {
|
|
140
|
+
} else if (!args.json) {
|
|
130
141
|
console.log(' (Testnet: HIP-3 dexes not auto-loaded. Use "dexName:COIN" to search a specific dex.)\n');
|
|
131
142
|
}
|
|
132
143
|
}
|
|
@@ -143,10 +154,13 @@ async function main() {
|
|
|
143
154
|
if (!asset || !ctx) continue;
|
|
144
155
|
|
|
145
156
|
if (asset.name.toUpperCase().includes(query)) {
|
|
157
|
+
let assetId = -1;
|
|
158
|
+
try { assetId = client.getAssetIndex(asset.name); } catch { /* not registered */ }
|
|
146
159
|
results.push({
|
|
147
160
|
type: 'hip3',
|
|
148
161
|
provider: dexData.dexName || `HIP-3 DEX ${dexIdx}`,
|
|
149
162
|
coin: asset.name,
|
|
163
|
+
assetId,
|
|
150
164
|
price: ctx.markPx,
|
|
151
165
|
volume24h: parseFloat(ctx.dayNtlVlm || '0'),
|
|
152
166
|
funding: ctx.funding,
|
|
@@ -199,6 +213,7 @@ async function main() {
|
|
|
199
213
|
type: 'spot',
|
|
200
214
|
provider: 'Spot',
|
|
201
215
|
coin: displayName,
|
|
216
|
+
assetId: 10000 + pair.index,
|
|
202
217
|
price: ctx.markPx,
|
|
203
218
|
volume24h: parseFloat(ctx.dayNtlVlm || '0'),
|
|
204
219
|
});
|
|
@@ -212,20 +227,25 @@ async function main() {
|
|
|
212
227
|
// Sort by volume
|
|
213
228
|
results.sort((a, b) => b.volume24h - a.volume24h);
|
|
214
229
|
|
|
230
|
+
if (args.json) {
|
|
231
|
+
console.log(JSON.stringify(results, null, 2));
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
215
235
|
if (results.length === 0) {
|
|
216
236
|
console.log(`No markets found matching "${query}"`);
|
|
217
237
|
return;
|
|
218
238
|
}
|
|
219
239
|
|
|
220
240
|
console.log(`Found ${results.length} market(s) matching "${query}":\n`);
|
|
221
|
-
console.log('Type Provider Coin Price 24h Volume Funding (Ann.) OI');
|
|
222
|
-
console.log('-'.repeat(
|
|
241
|
+
console.log('Type Provider Coin AssetID Price 24h Volume Funding (Ann.) OI');
|
|
242
|
+
console.log('-'.repeat(112));
|
|
223
243
|
|
|
224
244
|
for (const m of results) {
|
|
225
245
|
const typeStr = m.type === 'hip3' ? 'HIP-3' : m.type.charAt(0).toUpperCase() + m.type.slice(1);
|
|
226
246
|
const oi = m.openInterest ? formatVolume(parseFloat(m.openInterest)) : '-';
|
|
227
247
|
console.log(
|
|
228
|
-
`${typeStr.padEnd(8)} ${m.provider.padEnd(16)} ${m.coin.padEnd(14)} ${formatPrice(m.price).padStart(16)} ${formatVolume(m.volume24h).padStart(13)} ${(m.funding ? formatFunding(m.funding) : '-').padStart(14)} ${oi.padStart(10)}`
|
|
248
|
+
`${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)}`
|
|
229
249
|
);
|
|
230
250
|
}
|
|
231
251
|
|
|
@@ -245,11 +265,11 @@ async function main() {
|
|
|
245
265
|
const perpsWithFunding = markets.filter((m) => m.funding && m.type !== 'spot');
|
|
246
266
|
if (perpsWithFunding.length > 1) {
|
|
247
267
|
console.log(`\n=== ${coin} Funding Comparison ===\n`);
|
|
248
|
-
console.log('Provider Coin Funding (Ann.) Price');
|
|
249
|
-
console.log('-'.repeat(
|
|
268
|
+
console.log('Provider Coin AssetID Funding (Ann.) Price');
|
|
269
|
+
console.log('-'.repeat(78));
|
|
250
270
|
for (const m of perpsWithFunding.sort((a, b) => parseFloat(b.funding!) - parseFloat(a.funding!))) {
|
|
251
271
|
console.log(
|
|
252
|
-
`${m.provider.padEnd(16)} ${m.coin.padEnd(14)} ${formatFunding(m.funding!).padStart(14)} ${formatPrice(m.price)}`
|
|
272
|
+
`${m.provider.padEnd(16)} ${m.coin.padEnd(14)} ${String(m.assetId).padStart(7)} ${formatFunding(m.funding!).padStart(14)} ${formatPrice(m.price)}`
|
|
253
273
|
);
|
|
254
274
|
}
|
|
255
275
|
}
|
package/scripts/info/spot.ts
CHANGED
|
@@ -9,6 +9,7 @@ interface Args {
|
|
|
9
9
|
top?: number;
|
|
10
10
|
verbose?: boolean;
|
|
11
11
|
address?: string;
|
|
12
|
+
json?: boolean;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
function parseArgs(): Args {
|
|
@@ -26,6 +27,8 @@ function parseArgs(): Args {
|
|
|
26
27
|
args.address = process.argv[++i].toLowerCase();
|
|
27
28
|
} else if (arg === '--verbose') {
|
|
28
29
|
args.verbose = true;
|
|
30
|
+
} else if (arg === '--json') {
|
|
31
|
+
args.json = true;
|
|
29
32
|
} else if (arg === '--help' || arg === '-h') {
|
|
30
33
|
console.log(`
|
|
31
34
|
Spot Markets - View Hyperliquid spot markets and balances
|
|
@@ -37,6 +40,7 @@ Options:
|
|
|
37
40
|
--balances Show your spot token balances
|
|
38
41
|
--address <0x...> Look up another account's spot balances (with --balances)
|
|
39
42
|
--top <n> Show only top N markets by volume
|
|
43
|
+
--json Output as JSON (machine-readable)
|
|
40
44
|
--verbose Show detailed output
|
|
41
45
|
--help Show this help
|
|
42
46
|
|
|
@@ -85,10 +89,15 @@ async function main() {
|
|
|
85
89
|
// Show balances
|
|
86
90
|
if (args.balances) {
|
|
87
91
|
const lookupAddress = args.address ?? client.address;
|
|
88
|
-
console.log(`Fetching spot balances for ${lookupAddress}...\n`);
|
|
92
|
+
if (!args.json) console.log(`Fetching spot balances for ${lookupAddress}...\n`);
|
|
89
93
|
|
|
90
94
|
const balances = await client.getSpotBalances(args.address);
|
|
91
95
|
|
|
96
|
+
if (args.json) {
|
|
97
|
+
console.log(JSON.stringify(balances.balances ?? [], null, 2));
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
92
101
|
if (!balances.balances || balances.balances.length === 0) {
|
|
93
102
|
console.log('No spot token balances found.');
|
|
94
103
|
return;
|
|
@@ -112,17 +121,20 @@ async function main() {
|
|
|
112
121
|
}
|
|
113
122
|
|
|
114
123
|
// Show markets
|
|
115
|
-
console.log('Fetching spot market data...\n');
|
|
124
|
+
if (!args.json) console.log('Fetching spot market data...\n');
|
|
116
125
|
|
|
117
126
|
const spotData = await client.getSpotMetaAndAssetCtxs();
|
|
118
127
|
|
|
119
128
|
interface SpotMarket {
|
|
120
129
|
name: string;
|
|
121
130
|
index: number;
|
|
131
|
+
assetId: number;
|
|
122
132
|
price: string;
|
|
123
133
|
volume24h: number;
|
|
124
134
|
change24h: string;
|
|
125
135
|
tokens: [number, number];
|
|
136
|
+
base?: string;
|
|
137
|
+
quote?: string;
|
|
126
138
|
}
|
|
127
139
|
|
|
128
140
|
const markets: SpotMarket[] = [];
|
|
@@ -155,10 +167,13 @@ async function main() {
|
|
|
155
167
|
markets.push({
|
|
156
168
|
name: pair.name,
|
|
157
169
|
index: pair.index,
|
|
170
|
+
assetId: 10000 + pair.index,
|
|
158
171
|
price: ctx.markPx,
|
|
159
172
|
volume24h: parseFloat(ctx.dayNtlVlm || '0'),
|
|
160
173
|
change24h: formatChange(ctx.markPx, ctx.prevDayPx),
|
|
161
174
|
tokens: pair.tokens,
|
|
175
|
+
base: tokenNameMap.get(pair.tokens[0]),
|
|
176
|
+
quote: tokenNameMap.get(pair.tokens[1]),
|
|
162
177
|
});
|
|
163
178
|
}
|
|
164
179
|
|
|
@@ -168,6 +183,11 @@ async function main() {
|
|
|
168
183
|
// Apply top filter
|
|
169
184
|
const displayMarkets = args.top ? markets.slice(0, args.top) : markets;
|
|
170
185
|
|
|
186
|
+
if (args.json) {
|
|
187
|
+
console.log(JSON.stringify(displayMarkets, null, 2));
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
171
191
|
if (displayMarkets.length === 0) {
|
|
172
192
|
console.log(args.coin ? `No spot markets found for "${args.coin}"` : 'No spot markets found');
|
|
173
193
|
return;
|
|
@@ -180,8 +200,8 @@ async function main() {
|
|
|
180
200
|
}
|
|
181
201
|
|
|
182
202
|
console.log(`=== Spot Markets (${displayMarkets.length} total) ===\n`);
|
|
183
|
-
console.log('Pair Price 24h Volume 24h Change Base/Quote');
|
|
184
|
-
console.log('-'.repeat(
|
|
203
|
+
console.log('Pair AssetID Price 24h Volume 24h Change Base/Quote');
|
|
204
|
+
console.log('-'.repeat(92));
|
|
185
205
|
|
|
186
206
|
for (const m of displayMarkets) {
|
|
187
207
|
const baseToken = tokenMap.get(m.tokens[0]);
|
|
@@ -189,7 +209,7 @@ async function main() {
|
|
|
189
209
|
const pairStr = `${baseToken?.name || '?'}/${quoteToken?.name || '?'}`;
|
|
190
210
|
|
|
191
211
|
console.log(
|
|
192
|
-
`${m.name.padEnd(14)} ${formatPrice(m.price).padStart(16)} ${formatVolume(m.volume24h).padStart(13)} ${m.change24h.padStart(11)} ${pairStr}`
|
|
212
|
+
`${m.name.padEnd(14)} ${String(m.assetId).padStart(7)} ${formatPrice(m.price).padStart(16)} ${formatVolume(m.volume24h).padStart(13)} ${m.change24h.padStart(11)} ${pairStr}`
|
|
193
213
|
);
|
|
194
214
|
}
|
|
195
215
|
|
package/scripts/info/trades.ts
CHANGED
|
@@ -11,6 +11,7 @@ Usage: openbroker trades --coin <symbol> [options]
|
|
|
11
11
|
Options:
|
|
12
12
|
--coin <symbol> Asset symbol (required, e.g. ETH, BTC)
|
|
13
13
|
--top <n> Show last N trades (default: 30)
|
|
14
|
+
--json Output as JSON (machine-readable)
|
|
14
15
|
--help, -h Show this help
|
|
15
16
|
|
|
16
17
|
Examples:
|
|
@@ -35,10 +36,13 @@ async function main() {
|
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
const top = parseInt(args.top as string) || 30;
|
|
39
|
+
const jsonOutput = args.json as boolean;
|
|
38
40
|
const client = getClient();
|
|
39
41
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
+
if (!jsonOutput) {
|
|
43
|
+
console.log(`Open Broker - ${normalizeCoin(coin)} Recent Trades`);
|
|
44
|
+
console.log('='.repeat(40) + '\n');
|
|
45
|
+
}
|
|
42
46
|
|
|
43
47
|
try {
|
|
44
48
|
// Load metadata (needed for HIP-3 coin resolution)
|
|
@@ -53,6 +57,13 @@ async function main() {
|
|
|
53
57
|
trades.sort((a, b) => b.time - a.time);
|
|
54
58
|
trades = trades.slice(0, top);
|
|
55
59
|
|
|
60
|
+
if (jsonOutput) {
|
|
61
|
+
let assetId = -1;
|
|
62
|
+
try { assetId = client.getAssetIndex(normalizeCoin(coin)); } catch { /* noop */ }
|
|
63
|
+
console.log(JSON.stringify({ coin: normalizeCoin(coin), assetId, trades }, null, 2));
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
56
67
|
if (trades.length === 0) {
|
|
57
68
|
console.log('No recent trades found');
|
|
58
69
|
return;
|
|
@@ -129,7 +129,7 @@ async function main() {
|
|
|
129
129
|
console.log('\nResult');
|
|
130
130
|
console.log('------');
|
|
131
131
|
|
|
132
|
-
if (response.status === 'ok' && response.response) {
|
|
132
|
+
if (response.status === 'ok' && response.response && typeof response.response !== 'string') {
|
|
133
133
|
const statuses = response.response.data.statuses;
|
|
134
134
|
for (const status of statuses) {
|
|
135
135
|
if (status.filled) {
|
|
@@ -49,11 +49,13 @@ async function main() {
|
|
|
49
49
|
|
|
50
50
|
const response = await client.twapCancel(coin, twapId);
|
|
51
51
|
|
|
52
|
+
// SDK returns a success-only response shape; failures throw and are
|
|
53
|
+
// caught by the surrounding try/catch. `status` is the success literal.
|
|
52
54
|
const status = response.response.data.status;
|
|
53
55
|
if (typeof status === 'string' && status === 'success') {
|
|
54
56
|
console.log(`\nTWAP order ${twapId} cancelled successfully.`);
|
|
55
|
-
} else
|
|
56
|
-
console.error(`\
|
|
57
|
+
} else {
|
|
58
|
+
console.error(`\nUnexpected TWAP cancel response status: ${JSON.stringify(status)}`);
|
|
57
59
|
process.exit(1);
|
|
58
60
|
}
|
|
59
61
|
} catch (error) {
|
|
@@ -123,17 +123,15 @@ async function main() {
|
|
|
123
123
|
leverage,
|
|
124
124
|
);
|
|
125
125
|
|
|
126
|
+
// SDK's TwapOrderSuccessResponse excludes the error variant — the SDK
|
|
127
|
+
// throws on failure and the surrounding try/catch handles that. So
|
|
128
|
+
// `status` only ever carries `{ running }` here.
|
|
126
129
|
const status = response.response.data.status;
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
console.log(`To check status: openbroker twap-status`);
|
|
133
|
-
} else if ('error' in status) {
|
|
134
|
-
console.error(`TWAP order failed: ${status.error}`);
|
|
135
|
-
process.exit(1);
|
|
136
|
-
}
|
|
130
|
+
console.log(`TWAP order placed successfully!`);
|
|
131
|
+
console.log(`TWAP ID: ${status.running.twapId}`);
|
|
132
|
+
console.log(`\nThe exchange is now executing your TWAP order over ${formatDuration(durationMinutes * 60)}.`);
|
|
133
|
+
console.log(`To cancel: openbroker twap-cancel --coin ${coin} --twap-id ${status.running.twapId}`);
|
|
134
|
+
console.log(`To check status: openbroker twap-status`);
|
|
137
135
|
} catch (error) {
|
|
138
136
|
console.error('Error:', error instanceof Error ? error.message : error);
|
|
139
137
|
process.exit(1);
|
package/scripts/plugin/tools.ts
CHANGED
|
@@ -1385,24 +1385,21 @@ export function createTools(watcherOrCtx: PositionWatcher | null | ToolsContext)
|
|
|
1385
1385
|
const midPrice = parseFloat(mids[coin]);
|
|
1386
1386
|
|
|
1387
1387
|
const response = await client.twapOrder(coin, isBuy, size, durationMinutes, randomize, reduceOnly, leverage);
|
|
1388
|
+
// SDK's TwapOrderSuccessResponse excludes errors; they'd throw and
|
|
1389
|
+
// be caught below. Status is always `{ running }` on this branch.
|
|
1388
1390
|
const status = response.response.data.status;
|
|
1389
1391
|
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
});
|
|
1402
|
-
} else if ('error' in status) {
|
|
1403
|
-
return error(status.error);
|
|
1404
|
-
}
|
|
1405
|
-
return error('Unexpected response');
|
|
1392
|
+
return json({
|
|
1393
|
+
twapId: status.running.twapId,
|
|
1394
|
+
coin,
|
|
1395
|
+
side: isBuy ? 'buy' : 'sell',
|
|
1396
|
+
size,
|
|
1397
|
+
durationMinutes,
|
|
1398
|
+
randomize,
|
|
1399
|
+
reduceOnly,
|
|
1400
|
+
estimatedNotional: midPrice ? midPrice * size : undefined,
|
|
1401
|
+
midPrice: midPrice || undefined,
|
|
1402
|
+
});
|
|
1406
1403
|
} catch (err) {
|
|
1407
1404
|
return error(err instanceof Error ? err.message : String(err));
|
|
1408
1405
|
}
|
|
@@ -1428,14 +1425,13 @@ export function createTools(watcherOrCtx: PositionWatcher | null | ToolsContext)
|
|
|
1428
1425
|
try {
|
|
1429
1426
|
const client = getClient();
|
|
1430
1427
|
const response = await client.twapCancel(coin, twapId);
|
|
1428
|
+
// SDK returns the success-only response; failures throw.
|
|
1431
1429
|
const status = response.response.data.status;
|
|
1432
1430
|
|
|
1433
1431
|
if (typeof status === 'string' && status === 'success') {
|
|
1434
1432
|
return json({ cancelled: true, coin, twapId });
|
|
1435
|
-
} else if (typeof status === 'object' && 'error' in status) {
|
|
1436
|
-
return error(status.error);
|
|
1437
1433
|
}
|
|
1438
|
-
return error(
|
|
1434
|
+
return error(`Unexpected TWAP cancel status: ${JSON.stringify(status)}`);
|
|
1439
1435
|
} catch (err) {
|
|
1440
1436
|
return error(err instanceof Error ? err.message : String(err));
|
|
1441
1437
|
}
|
package/scripts/setup/onboard.ts
CHANGED
|
@@ -387,8 +387,10 @@ Examples:
|
|
|
387
387
|
return setupApiWallet();
|
|
388
388
|
}
|
|
389
389
|
|
|
390
|
-
// Options 1 & 2: Master wallet flow
|
|
391
|
-
|
|
390
|
+
// Options 1 & 2: Master wallet flow. Initialised in the branches below —
|
|
391
|
+
// the compiler can't prove the while-loop in option 2 assigns, so we use
|
|
392
|
+
// `| undefined` and narrow at use sites (`assertDefined`).
|
|
393
|
+
let privateKey: `0x${string}` | undefined;
|
|
392
394
|
|
|
393
395
|
if (choice === '2') {
|
|
394
396
|
// User has existing key
|
|
@@ -417,6 +419,10 @@ Examples:
|
|
|
417
419
|
console.log('✅ New wallet created');
|
|
418
420
|
}
|
|
419
421
|
|
|
422
|
+
if (!privateKey) {
|
|
423
|
+
throw new Error('Internal error: privateKey was not set by onboarding flow.');
|
|
424
|
+
}
|
|
425
|
+
|
|
420
426
|
// Derive account from private key
|
|
421
427
|
const account = privateKeyToAccount(privateKey);
|
|
422
428
|
console.log(`\nWallet Address: ${account.address}\n`);
|