openbroker 1.3.1 → 1.3.2

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 CHANGED
@@ -4,7 +4,7 @@ description: Hyperliquid trading CLI skill for agents. Use when an agent needs t
4
4
  license: MIT
5
5
  compatibility: Requires Node.js 22+, network access to api.hyperliquid.xyz
6
6
  homepage: https://www.npmjs.com/package/openbroker
7
- metadata: {"author": "monemetrics", "version": "1.3.1"}
7
+ metadata: {"author": "monemetrics", "version": "1.3.2"}
8
8
  allowed-tools: Bash(openbroker:*)
9
9
  ---
10
10
 
@@ -52,12 +52,15 @@ Common globals:
52
52
  openbroker search --query GOLD --json
53
53
  openbroker search --query BTC --type perp --json
54
54
  openbroker all-markets --type hip3 --json
55
+ openbroker all-markets --type outcome --json
55
56
  openbroker outcomes --query BTC --json
56
57
  ```
57
58
 
58
59
  - HIP-3 perps use `dex:COIN`, e.g. `xyz:CL`, not bare `CL`.
59
60
  - `assetId` is the canonical identifier for comparisons and persisted agent state; order placement still uses `--coin`.
60
- - HIP-4 outcome orders use `--outcome <id|#encoding|+encoding>` plus `--outcome-side yes|no` when the reference is a plain ID.
61
+ - For HIP-4 discovery, use `outcomes --json` for grouped market metadata and `all-markets --type outcome --json` for flattened side rows.
62
+ - HIP-4 outcome orders use `--outcome <id|#encoding|+encoding>` plus `--outcome-side yes|no` when the reference is a plain ID. Encoded sides use `encoding = 10 * outcomeId + side`, where side `0` is the first side and side `1` is the second side.
63
+ - HIP-4 order books use `#<encoding>` coins; spot balances may show `+<encoding>` token names.
61
64
  - On testnet, HIP-3 metadata may need an explicit prefixed coin such as `dex:COIN`.
62
65
 
63
66
  ## CLI command map
@@ -72,7 +75,7 @@ Most info commands accept `--json`. Use `--coin`, `--top`, and `--address` where
72
75
  | `positions` | Open perp positions and liquidation distance | `--coin`, `--address` |
73
76
  | `funding` | Funding rates | `--coin`, `--top`, `--sort annualized|hourly|oi`, `--all`, `--include-hip3` |
74
77
  | `markets` | Perp market data | `--coin`, `--top`, `--sort volume|oi|change`, `--include-hip3` |
75
- | `all-markets` | Browse every venue type | `--type perp|hip3|spot|outcome|all`, `--top` |
78
+ | `all-markets` | Browse every venue type | `--type perp|hip3|spot|outcome|all`, `--top`, `--json` |
76
79
  | `search` | Find markets across providers | `--query`, `--type` |
77
80
  | `spot` | Spot markets or balances | `--coin`, `--balances`, `--address`, `--top` |
78
81
  | `fills` | Recent fills | `--coin`, `--side buy|sell`, `--top`, `--address` |
@@ -84,7 +87,7 @@ Most info commands accept `--json`. Use `--coin`, `--top`, and `--address` where
84
87
  | `trades` | Recent tape | `--coin`, `--top` |
85
88
  | `rate-limit` | API usage | — |
86
89
  | `funding-scan` | Cross-dex scan | `--threshold`, `--main-only`, `--hip3-only`, `--pairs`, `--watch`, `--interval`, `--top` |
87
- | `outcomes` | HIP-4 discovery/balances | `--query`, `--outcome`, `--side`, `--balances`, `--top` |
90
+ | `outcomes` | HIP-4 discovery/balances | `--query`, `--outcome`, `--side`, `--balances`, `--top`, `--json` |
88
91
 
89
92
  ### Perp trading
90
93
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openbroker",
3
- "version": "1.3.1",
3
+ "version": "1.3.2",
4
4
  "description": "Hyperliquid trading CLI - execute orders, manage positions, and run trading strategies",
5
5
  "type": "module",
6
6
  "bin": {
@@ -668,9 +668,19 @@ export class HyperliquidClient {
668
668
  private parseOutcomeDescription(description: string): Record<string, string> {
669
669
  const parsed: Record<string, string> = {};
670
670
  for (const part of description.split('|')) {
671
- const idx = part.indexOf(':');
672
- if (idx <= 0) continue;
673
- parsed[part.slice(0, idx)] = part.slice(idx + 1);
671
+ const rawSegment = part.trim();
672
+ const metadataIdx = rawSegment.indexOf('metadata=');
673
+ const segments = metadataIdx >= 0
674
+ ? [rawSegment, rawSegment.slice(metadataIdx + 'metadata='.length)]
675
+ : [rawSegment];
676
+
677
+ for (const segment of segments) {
678
+ const idx = segment.indexOf(':');
679
+ if (idx <= 0) continue;
680
+ const key = segment.slice(0, idx).trim();
681
+ if (!/^[A-Za-z][A-Za-z0-9_]*$/.test(key)) continue;
682
+ parsed[key] = segment.slice(idx + 1).trim();
683
+ }
674
684
  }
675
685
  return parsed;
676
686
  }
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env tsx
2
- // All Markets - View all available markets across perps, spot, and HIP-3 dexs
2
+ // All Markets - View all available markets across perps, HIP-3, spot, and HIP-4 outcomes
3
3
 
4
4
  import { getClient } from '../core/client.js';
5
5
 
@@ -88,9 +88,22 @@ interface MarketRow {
88
88
  maxLeverage?: number;
89
89
  outcome?: number;
90
90
  outcomeSide?: string;
91
+ outcomeName?: string;
92
+ tokenName?: string;
93
+ parsedDescription?: Record<string, string>;
91
94
  description?: string;
92
95
  }
93
96
 
97
+ function handleMarketFetchError(kind: NonNullable<Args['type']>, error: unknown, requestedType: Args['type'], verbose?: boolean): void {
98
+ const message = error instanceof Error ? error.message : String(error);
99
+ if (requestedType === kind) {
100
+ throw new Error(`Failed to fetch ${kind} markets: ${message}`);
101
+ }
102
+ if (verbose) {
103
+ console.error(`Failed to fetch ${kind} markets:`, error);
104
+ }
105
+ }
106
+
94
107
  async function main() {
95
108
  const args = parseArgs();
96
109
  const client = getClient();
@@ -202,12 +215,15 @@ async function main() {
202
215
  volume24h: parseFloat(side.dayNtlVlm || '0'),
203
216
  outcome: market.outcome,
204
217
  outcomeSide: side.name,
218
+ outcomeName: market.name,
219
+ tokenName: side.tokenName,
220
+ parsedDescription: market.parsedDescription,
205
221
  description: market.description,
206
222
  });
207
223
  }
208
224
  }
209
225
  } catch (e) {
210
- if (args.verbose) console.error('Failed to fetch HIP-4 outcomes:', e);
226
+ handleMarketFetchError('outcome', e, args.type, args.verbose);
211
227
  }
212
228
  }
213
229
 
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env tsx
2
- // Search Markets - Find specific assets across all providers (perps, HIP-3, spot)
2
+ // Search Markets - Find specific assets across all providers (perps, HIP-3, spot, HIP-4)
3
3
 
4
4
  import { getClient } from '../core/client.js';
5
5
 
@@ -85,6 +85,16 @@ function formatFunding(rate: string): string {
85
85
  return `${sign}${annualized.toFixed(2)}%`;
86
86
  }
87
87
 
88
+ function handleMarketFetchError(kind: NonNullable<Args['type']>, error: unknown, requestedType: Args['type'], verbose?: boolean): void {
89
+ const message = error instanceof Error ? error.message : String(error);
90
+ if (requestedType === kind) {
91
+ throw new Error(`Failed to fetch ${kind} markets: ${message}`);
92
+ }
93
+ if (verbose) {
94
+ console.error(`Failed to fetch ${kind} markets:`, error);
95
+ }
96
+ }
97
+
88
98
  async function main() {
89
99
  const args = parseArgs();
90
100
  const client = getClient();
@@ -107,6 +117,9 @@ async function main() {
107
117
  openInterest?: string;
108
118
  outcome?: number;
109
119
  outcomeSide?: string;
120
+ outcomeName?: string;
121
+ tokenName?: string;
122
+ parsedDescription?: Record<string, string>;
110
123
  description?: string;
111
124
  }
112
125
 
@@ -247,12 +260,15 @@ async function main() {
247
260
  volume24h: parseFloat(side.dayNtlVlm || '0'),
248
261
  outcome: market.outcome,
249
262
  outcomeSide: side.name,
263
+ outcomeName: market.name,
264
+ tokenName: side.tokenName,
265
+ parsedDescription: market.parsedDescription,
250
266
  description: market.description,
251
267
  });
252
268
  }
253
269
  }
254
270
  } catch (e) {
255
- if (args.verbose) console.error('Failed to fetch HIP-4 outcomes:', e);
271
+ handleMarketFetchError('outcome', e, args.type, args.verbose);
256
272
  }
257
273
  }
258
274