openbroker 1.0.57 → 1.0.59
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/CHANGELOG.md +18 -0
- package/SKILL.md +29 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/scripts/plugin/tools.ts +182 -64
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to Open Broker will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.0.59] - 2026-03-11
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- **Plugin Tools Parity with CLI**: Reviewed all plugin tools against CLI commands and aligned behavior
|
|
9
|
+
- **`ob_account`**: Now uses `crossMarginSummary` (matches CLI), includes `signingWallet`, `walletType`, `marginRatio`, translates order sides (`B`→`buy`, `A`→`sell`), adds `side` field to positions
|
|
10
|
+
- **`ob_positions`**: Now fetches mark prices (`getAllMids`) and cumulative funding (`getUserFunding`) in parallel — includes `markPrice`, `notional`, `cumulativeFunding`, `liquidationDistance`, `maxLeverage`, `leverageType` fields matching CLI output
|
|
11
|
+
- **`ob_markets`**: Now includes HIP-3 markets (was main dex only), adds `change24h` field, sorts by volume, includes `type` field (`perp`/`hip3`)
|
|
12
|
+
- **`ob_buy`/`ob_sell`**: Fixed default slippage — was using `builderInfo.f` (1 bps) instead of config default (50 bps), causing market orders to fail with price-too-far errors
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- **SKILL.md CLI Fallback Guide**: Added troubleshooting section with plugin tool → CLI command mapping table, so agents can fall back to CLI when plugin tools return errors
|
|
16
|
+
|
|
17
|
+
## [1.0.58] - 2026-03-11
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
- **`ob_funding` HIP-3 Support**: Rewrote plugin tool to use `getMetaAndAssetCtxs()` + `getAllPerpMetas()` instead of `getPredictedFundings()` which only returned main dex data. Now correctly returns funding rates for HIP-3 assets like `xyz:GOLD`. Fixes "Cannot read properties of null" crash.
|
|
21
|
+
- **`ob_search` HIP-3 Filter**: Fixed inverted type filter condition — HIP-3 search was gated behind `typeFilter === 'perp'` instead of `typeFilter === 'hip3'`, causing empty results in some filter combinations. Added `funding` and `openInterest` fields to search results.
|
|
22
|
+
|
|
5
23
|
## [1.0.57] - 2026-03-10
|
|
6
24
|
|
|
7
25
|
### Fixed
|
package/SKILL.md
CHANGED
|
@@ -4,7 +4,7 @@ description: Hyperliquid trading plugin with background position monitoring. Exe
|
|
|
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.0.
|
|
7
|
+
metadata: {"author": "monemetrics", "version": "1.0.59", "openclaw": {"requires": {"bins": ["openbroker"], "env": ["HYPERLIQUID_PRIVATE_KEY"]}, "primaryEnv": "HYPERLIQUID_PRIVATE_KEY", "install": [{"id": "node", "kind": "node", "package": "openbroker", "bins": ["openbroker"], "label": "Install openbroker (npm)"}]}}
|
|
8
8
|
allowed-tools: ob_account ob_positions ob_funding ob_markets ob_search ob_spot ob_fills ob_orders ob_order_status ob_fees ob_candles ob_funding_history ob_trades ob_rate_limit ob_funding_scan ob_buy ob_sell ob_limit ob_trigger ob_tpsl ob_cancel ob_twap ob_bracket ob_chase ob_watcher_status Bash(openbroker:*)
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -46,6 +46,34 @@ Or with the `ob_search` plugin tool: `{ "query": "gold" }` or `{ "query": "oil",
|
|
|
46
46
|
|
|
47
47
|
**HIP-3 assets use `dex:COIN` format** — e.g., `xyz:CL` not just `CL`. If you get an error like "No market data found", search for the asset to find the correct prefixed ticker. Common HIP-3 dexes: `xyz`, `flx`, `km`, `hyna`, `vntl`, `cash`.
|
|
48
48
|
|
|
49
|
+
## Troubleshooting: CLI Fallback
|
|
50
|
+
|
|
51
|
+
If an `ob_*` plugin tool returns unexpected errors, empty results, or crashes, **fall back to the equivalent CLI command** via Bash. The CLI and plugin tools share the same core code, but the CLI has more mature error handling and output.
|
|
52
|
+
|
|
53
|
+
| Plugin Tool | CLI Equivalent |
|
|
54
|
+
|-------------|---------------|
|
|
55
|
+
| `ob_account` | `openbroker account --json` |
|
|
56
|
+
| `ob_positions` | `openbroker positions --json` |
|
|
57
|
+
| `ob_funding` | `openbroker funding --json --include-hip3` |
|
|
58
|
+
| `ob_markets` | `openbroker markets --json --include-hip3` |
|
|
59
|
+
| `ob_search` | `openbroker search --query <QUERY>` |
|
|
60
|
+
| `ob_buy` | `openbroker buy --coin <COIN> --size <SIZE>` |
|
|
61
|
+
| `ob_sell` | `openbroker sell --coin <COIN> --size <SIZE>` |
|
|
62
|
+
| `ob_limit` | `openbroker limit --coin <COIN> --side <SIDE> --size <SIZE> --price <PRICE>` |
|
|
63
|
+
| `ob_tpsl` | `openbroker tpsl --coin <COIN> --tp <PRICE> --sl <PRICE>` |
|
|
64
|
+
| `ob_cancel` | `openbroker cancel --all` or `--coin <COIN>` |
|
|
65
|
+
| `ob_fills` | `openbroker fills --json` |
|
|
66
|
+
| `ob_orders` | `openbroker orders --json` |
|
|
67
|
+
| `ob_funding_scan` | `openbroker funding-scan --json` |
|
|
68
|
+
| `ob_candles` | `openbroker candles --coin <COIN> --json` |
|
|
69
|
+
|
|
70
|
+
**When to use CLI fallback:**
|
|
71
|
+
- Plugin tool returns `null`, empty data, or throws an error
|
|
72
|
+
- You need data the plugin tool doesn't expose (e.g., `--verbose` debug output)
|
|
73
|
+
- Long-running operations (strategies, TWAP) — the CLI handles timeouts and progress better
|
|
74
|
+
|
|
75
|
+
Add `--dry` to any trading CLI command to preview without executing. Add `--json` to info commands for structured output.
|
|
76
|
+
|
|
49
77
|
## Command Reference
|
|
50
78
|
|
|
51
79
|
### Setup
|
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
package/scripts/plugin/tools.ts
CHANGED
|
@@ -37,18 +37,25 @@ export function createTools(watcher: PositionWatcher | null): PluginTool[] {
|
|
|
37
37
|
const state = await client.getUserStateAll();
|
|
38
38
|
const accountMode = await client.getAccountMode();
|
|
39
39
|
|
|
40
|
+
const margin = state.crossMarginSummary;
|
|
41
|
+
const accountValue = parseFloat(margin.accountValue);
|
|
42
|
+
const totalMarginUsed = parseFloat(margin.totalMarginUsed);
|
|
43
|
+
|
|
40
44
|
const result: Record<string, unknown> = {
|
|
41
45
|
address: client.address,
|
|
42
|
-
|
|
46
|
+
signingWallet: client.walletAddress,
|
|
47
|
+
walletType: client.isApiWallet ? 'api' : 'main',
|
|
43
48
|
accountMode,
|
|
44
|
-
equity:
|
|
45
|
-
totalNtlPos:
|
|
46
|
-
totalMarginUsed:
|
|
47
|
-
withdrawable:
|
|
49
|
+
equity: margin.accountValue,
|
|
50
|
+
totalNtlPos: margin.totalNtlPos,
|
|
51
|
+
totalMarginUsed: margin.totalMarginUsed,
|
|
52
|
+
withdrawable: margin.withdrawable,
|
|
53
|
+
marginRatio: totalMarginUsed > 0 && accountValue > 0 ? totalMarginUsed / accountValue : 0,
|
|
48
54
|
positions: state.assetPositions
|
|
49
55
|
.filter(ap => parseFloat(ap.position.szi) !== 0)
|
|
50
56
|
.map(ap => ({
|
|
51
57
|
coin: ap.position.coin,
|
|
58
|
+
side: parseFloat(ap.position.szi) > 0 ? 'long' : 'short',
|
|
52
59
|
size: ap.position.szi,
|
|
53
60
|
entryPrice: ap.position.entryPx,
|
|
54
61
|
positionValue: ap.position.positionValue,
|
|
@@ -63,7 +70,7 @@ export function createTools(watcher: PositionWatcher | null): PluginTool[] {
|
|
|
63
70
|
result.openOrders = orders.map(o => ({
|
|
64
71
|
coin: o.coin,
|
|
65
72
|
oid: o.oid,
|
|
66
|
-
side: o.side,
|
|
73
|
+
side: o.side === 'B' ? 'buy' : 'sell',
|
|
67
74
|
size: o.sz,
|
|
68
75
|
price: o.limitPx,
|
|
69
76
|
orderType: o.orderType,
|
|
@@ -87,22 +94,44 @@ export function createTools(watcher: PositionWatcher | null): PluginTool[] {
|
|
|
87
94
|
async execute(_id, params) {
|
|
88
95
|
const { getClient } = await import('../core/client.js');
|
|
89
96
|
const client = getClient();
|
|
90
|
-
const state = await
|
|
97
|
+
const [state, mids, fundingHistory] = await Promise.all([
|
|
98
|
+
client.getUserStateAll(),
|
|
99
|
+
client.getAllMids(),
|
|
100
|
+
client.getUserFunding(),
|
|
101
|
+
]);
|
|
102
|
+
|
|
103
|
+
// Sum cumulative funding per coin
|
|
104
|
+
const fundingByCoin = new Map<string, number>();
|
|
105
|
+
for (const entry of fundingHistory) {
|
|
106
|
+
const coin = entry.delta.coin;
|
|
107
|
+
const usdc = parseFloat(entry.delta.usdc);
|
|
108
|
+
fundingByCoin.set(coin, (fundingByCoin.get(coin) ?? 0) + usdc);
|
|
109
|
+
}
|
|
91
110
|
|
|
92
111
|
let positions = state.assetPositions
|
|
93
112
|
.filter(ap => parseFloat(ap.position.szi) !== 0)
|
|
94
|
-
.map(ap =>
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
113
|
+
.map(ap => {
|
|
114
|
+
const pos = ap.position;
|
|
115
|
+
const markPx = parseFloat(mids[pos.coin] || '0');
|
|
116
|
+
const liqPx = pos.liquidationPx ? parseFloat(pos.liquidationPx) : null;
|
|
117
|
+
return {
|
|
118
|
+
coin: pos.coin,
|
|
119
|
+
side: parseFloat(pos.szi) > 0 ? 'long' : 'short',
|
|
120
|
+
size: pos.szi,
|
|
121
|
+
entryPrice: pos.entryPx,
|
|
122
|
+
markPrice: markPx,
|
|
123
|
+
notional: Math.abs(parseFloat(pos.positionValue)),
|
|
124
|
+
unrealizedPnl: parseFloat(pos.unrealizedPnl),
|
|
125
|
+
returnOnEquity: parseFloat(pos.returnOnEquity),
|
|
126
|
+
cumulativeFunding: fundingByCoin.get(pos.coin) ?? 0,
|
|
127
|
+
marginUsed: parseFloat(pos.marginUsed),
|
|
128
|
+
leverage: `${pos.leverage.value}x`,
|
|
129
|
+
leverageType: pos.leverage.type,
|
|
130
|
+
liquidationPrice: liqPx,
|
|
131
|
+
liquidationDistance: liqPx && markPx ? Math.abs((markPx - liqPx) / markPx) : null,
|
|
132
|
+
maxLeverage: pos.maxLeverage,
|
|
133
|
+
};
|
|
134
|
+
});
|
|
106
135
|
|
|
107
136
|
if (params.coin) {
|
|
108
137
|
const coin = normalizeCoin(params.coin as string);
|
|
@@ -127,23 +156,59 @@ export function createTools(watcher: PositionWatcher | null): PluginTool[] {
|
|
|
127
156
|
const { getClient } = await import('../core/client.js');
|
|
128
157
|
const { annualizeFundingRate } = await import('../core/utils.js');
|
|
129
158
|
const client = getClient();
|
|
130
|
-
const raw = await client.getPredictedFundings();
|
|
131
159
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
// Use the first venue's funding rate
|
|
135
|
-
const rate = venues.length > 0 ? parseFloat(venues[0][1].fundingRate) : 0;
|
|
136
|
-
return {
|
|
137
|
-
coin,
|
|
138
|
-
fundingRate: rate,
|
|
139
|
-
annualizedRate: annualizeFundingRate(rate),
|
|
140
|
-
venues: venues.map(([venue, data]) => ({ venue, fundingRate: data.fundingRate })),
|
|
141
|
-
};
|
|
142
|
-
});
|
|
160
|
+
const filterCoin = params.coin ? normalizeCoin(params.coin as string) : undefined;
|
|
161
|
+
const includeHip3 = !filterCoin || filterCoin.includes(':');
|
|
143
162
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
163
|
+
let results: Array<{ coin: string; fundingRate: number; annualizedRate: number; openInterest: string; markPx: string; type: string }> = [];
|
|
164
|
+
|
|
165
|
+
// Main dex funding from meta
|
|
166
|
+
try {
|
|
167
|
+
const { meta, assetCtxs } = await client.getMetaAndAssetCtxs();
|
|
168
|
+
for (let i = 0; i < meta.universe.length; i++) {
|
|
169
|
+
const asset = meta.universe[i];
|
|
170
|
+
const ctx = assetCtxs[i];
|
|
171
|
+
if (!ctx) continue;
|
|
172
|
+
if (filterCoin && asset.name !== filterCoin) continue;
|
|
173
|
+
|
|
174
|
+
const rate = parseFloat(ctx.funding);
|
|
175
|
+
results.push({
|
|
176
|
+
coin: asset.name,
|
|
177
|
+
fundingRate: rate,
|
|
178
|
+
annualizedRate: annualizeFundingRate(rate),
|
|
179
|
+
openInterest: ctx.openInterest,
|
|
180
|
+
markPx: ctx.markPx,
|
|
181
|
+
type: 'perp',
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
} catch { /* skip */ }
|
|
185
|
+
|
|
186
|
+
// HIP-3 dex funding
|
|
187
|
+
if (includeHip3) {
|
|
188
|
+
try {
|
|
189
|
+
const allPerps = await client.getAllPerpMetas();
|
|
190
|
+
for (let dexIdx = 1; dexIdx < allPerps.length; dexIdx++) {
|
|
191
|
+
const dexData = allPerps[dexIdx];
|
|
192
|
+
if (!dexData?.meta?.universe) continue;
|
|
193
|
+
|
|
194
|
+
for (let i = 0; i < dexData.meta.universe.length; i++) {
|
|
195
|
+
const asset = dexData.meta.universe[i];
|
|
196
|
+
const ctx = dexData.assetCtxs[i];
|
|
197
|
+
if (!asset || !ctx) continue;
|
|
198
|
+
if (filterCoin && asset.name !== filterCoin) continue;
|
|
199
|
+
|
|
200
|
+
const rate = parseFloat(ctx.funding);
|
|
201
|
+
results.push({
|
|
202
|
+
coin: asset.name,
|
|
203
|
+
fundingRate: rate,
|
|
204
|
+
annualizedRate: annualizeFundingRate(rate),
|
|
205
|
+
openInterest: ctx.openInterest,
|
|
206
|
+
markPx: ctx.markPx,
|
|
207
|
+
type: 'hip3',
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
} catch { /* skip */ }
|
|
147
212
|
}
|
|
148
213
|
|
|
149
214
|
results.sort((a, b) => Math.abs(b.annualizedRate) - Math.abs(a.annualizedRate));
|
|
@@ -157,7 +222,7 @@ export function createTools(watcher: PositionWatcher | null): PluginTool[] {
|
|
|
157
222
|
|
|
158
223
|
{
|
|
159
224
|
name: 'ob_markets',
|
|
160
|
-
description: 'View market data for Hyperliquid perpetuals (price, volume, open interest)',
|
|
225
|
+
description: 'View market data for Hyperliquid perpetuals (price, volume, open interest). Includes HIP-3 markets.',
|
|
161
226
|
parameters: {
|
|
162
227
|
type: 'object',
|
|
163
228
|
properties: {
|
|
@@ -170,28 +235,75 @@ export function createTools(watcher: PositionWatcher | null): PluginTool[] {
|
|
|
170
235
|
const client = getClient();
|
|
171
236
|
const { meta, assetCtxs } = await client.getMetaAndAssetCtxs();
|
|
172
237
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
238
|
+
const filterCoin = params.coin ? normalizeCoin(params.coin as string) : undefined;
|
|
239
|
+
const includeHip3 = !filterCoin || filterCoin.includes(':');
|
|
240
|
+
|
|
241
|
+
interface MarketEntry { coin: string; type: string; markPx: number; oraclePx: number; change24h: number; dayVolume: number; openInterest: number; maxLeverage: number; szDecimals: number; funding: string }
|
|
242
|
+
|
|
243
|
+
const markets: MarketEntry[] = [];
|
|
244
|
+
|
|
245
|
+
// Main dex
|
|
246
|
+
for (let i = 0; i < meta.universe.length; i++) {
|
|
247
|
+
const asset = meta.universe[i];
|
|
248
|
+
const ctx = assetCtxs[i];
|
|
249
|
+
if (!ctx) continue;
|
|
250
|
+
if (filterCoin && asset.name !== filterCoin) continue;
|
|
251
|
+
|
|
252
|
+
const markPx = parseFloat(ctx.markPx);
|
|
253
|
+
const prevDayPx = parseFloat(ctx.prevDayPx);
|
|
254
|
+
markets.push({
|
|
255
|
+
coin: asset.name,
|
|
256
|
+
type: 'perp',
|
|
257
|
+
markPx,
|
|
258
|
+
oraclePx: parseFloat(ctx.oraclePx),
|
|
259
|
+
change24h: prevDayPx > 0 ? (markPx - prevDayPx) / prevDayPx : 0,
|
|
260
|
+
dayVolume: parseFloat(ctx.dayNtlVlm),
|
|
261
|
+
openInterest: parseFloat(ctx.openInterest),
|
|
262
|
+
maxLeverage: asset.maxLeverage,
|
|
263
|
+
szDecimals: asset.szDecimals,
|
|
264
|
+
funding: ctx.funding,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
185
267
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
268
|
+
// HIP-3 dexes
|
|
269
|
+
if (includeHip3) {
|
|
270
|
+
try {
|
|
271
|
+
const allPerps = await client.getAllPerpMetas();
|
|
272
|
+
for (let dexIdx = 1; dexIdx < allPerps.length; dexIdx++) {
|
|
273
|
+
const dexData = allPerps[dexIdx];
|
|
274
|
+
if (!dexData?.meta?.universe) continue;
|
|
275
|
+
for (let i = 0; i < dexData.meta.universe.length; i++) {
|
|
276
|
+
const asset = dexData.meta.universe[i];
|
|
277
|
+
const ctx = dexData.assetCtxs[i];
|
|
278
|
+
if (!asset || !ctx) continue;
|
|
279
|
+
if (filterCoin && asset.name !== filterCoin) continue;
|
|
280
|
+
|
|
281
|
+
const markPx = parseFloat(ctx.markPx);
|
|
282
|
+
const prevDayPx = parseFloat(ctx.prevDayPx);
|
|
283
|
+
markets.push({
|
|
284
|
+
coin: asset.name,
|
|
285
|
+
type: 'hip3',
|
|
286
|
+
markPx,
|
|
287
|
+
oraclePx: parseFloat(ctx.oraclePx),
|
|
288
|
+
change24h: prevDayPx > 0 ? (markPx - prevDayPx) / prevDayPx : 0,
|
|
289
|
+
dayVolume: parseFloat(ctx.dayNtlVlm),
|
|
290
|
+
openInterest: parseFloat(ctx.openInterest),
|
|
291
|
+
maxLeverage: asset.maxLeverage,
|
|
292
|
+
szDecimals: asset.szDecimals,
|
|
293
|
+
funding: ctx.funding,
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
} catch { /* skip */ }
|
|
189
298
|
}
|
|
190
299
|
|
|
300
|
+
// Sort by volume (matches CLI behavior)
|
|
301
|
+
markets.sort((a, b) => b.dayVolume - a.dayVolume);
|
|
302
|
+
|
|
191
303
|
const top = (params.top as number) || 30;
|
|
192
|
-
|
|
304
|
+
const result = filterCoin ? markets : markets.slice(0, top);
|
|
193
305
|
|
|
194
|
-
return json({ markets });
|
|
306
|
+
return json({ markets: result });
|
|
195
307
|
},
|
|
196
308
|
},
|
|
197
309
|
|
|
@@ -228,7 +340,9 @@ export function createTools(watcher: PositionWatcher | null): PluginTool[] {
|
|
|
228
340
|
coin: asset.name,
|
|
229
341
|
type: 'perp',
|
|
230
342
|
markPx: assetCtxs[i]?.markPx,
|
|
343
|
+
funding: assetCtxs[i]?.funding,
|
|
231
344
|
dayVolume: assetCtxs[i]?.dayNtlVlm,
|
|
345
|
+
openInterest: assetCtxs[i]?.openInterest,
|
|
232
346
|
maxLeverage: asset.maxLeverage,
|
|
233
347
|
});
|
|
234
348
|
}
|
|
@@ -236,24 +350,26 @@ export function createTools(watcher: PositionWatcher | null): PluginTool[] {
|
|
|
236
350
|
} catch (e) { errors.push(`perp: ${e instanceof Error ? e.message : String(e)}`); }
|
|
237
351
|
}
|
|
238
352
|
|
|
239
|
-
// Search HIP-3 perps
|
|
240
|
-
if (!typeFilter || typeFilter === 'hip3'
|
|
353
|
+
// Search HIP-3 perps (always included unless filtering to perp-only or spot-only)
|
|
354
|
+
if (!typeFilter || typeFilter === 'hip3') {
|
|
241
355
|
try {
|
|
242
356
|
const allPerps = await client.getAllPerpMetas();
|
|
243
357
|
for (let dexIdx = 1; dexIdx < allPerps.length; dexIdx++) {
|
|
244
358
|
const dexData = allPerps[dexIdx];
|
|
245
|
-
if (!dexData
|
|
359
|
+
if (!dexData?.meta?.universe) continue;
|
|
246
360
|
for (let i = 0; i < dexData.meta.universe.length; i++) {
|
|
247
361
|
const asset = dexData.meta.universe[i];
|
|
362
|
+
const ctx = dexData.assetCtxs[i];
|
|
248
363
|
if (!asset) continue;
|
|
249
364
|
if (asset.name.toUpperCase().includes(query)) {
|
|
250
365
|
results.push({
|
|
251
|
-
// API returns names already prefixed (e.g., "xyz:CL")
|
|
252
366
|
coin: asset.name,
|
|
253
367
|
type: 'hip3',
|
|
254
368
|
dex: dexData.dexName,
|
|
255
|
-
markPx:
|
|
256
|
-
|
|
369
|
+
markPx: ctx?.markPx,
|
|
370
|
+
funding: ctx?.funding,
|
|
371
|
+
dayVolume: ctx?.dayNtlVlm,
|
|
372
|
+
openInterest: ctx?.openInterest,
|
|
257
373
|
maxLeverage: asset.maxLeverage,
|
|
258
374
|
});
|
|
259
375
|
}
|
|
@@ -759,7 +875,7 @@ export function createTools(watcher: PositionWatcher | null): PluginTool[] {
|
|
|
759
875
|
|
|
760
876
|
const coin = normalizeCoin(params.coin as string);
|
|
761
877
|
const size = params.size as number;
|
|
762
|
-
const slippageBps =
|
|
878
|
+
const slippageBps = params.slippage as number | undefined;
|
|
763
879
|
const leverage = params.leverage as number | undefined;
|
|
764
880
|
|
|
765
881
|
const mids = await client.getAllMids();
|
|
@@ -768,7 +884,8 @@ export function createTools(watcher: PositionWatcher | null): PluginTool[] {
|
|
|
768
884
|
|
|
769
885
|
const szDecimals = await client.getSzDecimals(coin);
|
|
770
886
|
const roundedSize = roundSize(size, szDecimals);
|
|
771
|
-
const
|
|
887
|
+
const effectiveSlippage = slippageBps ?? 50;
|
|
888
|
+
const slippagePrice = getSlippagePrice(midPrice, true, effectiveSlippage);
|
|
772
889
|
|
|
773
890
|
if (params.dry) {
|
|
774
891
|
return json({
|
|
@@ -778,7 +895,7 @@ export function createTools(watcher: PositionWatcher | null): PluginTool[] {
|
|
|
778
895
|
size: roundedSize,
|
|
779
896
|
midPrice,
|
|
780
897
|
slippagePrice,
|
|
781
|
-
slippageBps,
|
|
898
|
+
slippageBps: effectiveSlippage,
|
|
782
899
|
leverage,
|
|
783
900
|
});
|
|
784
901
|
}
|
|
@@ -811,7 +928,7 @@ export function createTools(watcher: PositionWatcher | null): PluginTool[] {
|
|
|
811
928
|
|
|
812
929
|
const coin = normalizeCoin(params.coin as string);
|
|
813
930
|
const size = params.size as number;
|
|
814
|
-
const slippageBps =
|
|
931
|
+
const slippageBps = params.slippage as number | undefined;
|
|
815
932
|
const leverage = params.leverage as number | undefined;
|
|
816
933
|
|
|
817
934
|
const mids = await client.getAllMids();
|
|
@@ -820,7 +937,8 @@ export function createTools(watcher: PositionWatcher | null): PluginTool[] {
|
|
|
820
937
|
|
|
821
938
|
const szDecimals = await client.getSzDecimals(coin);
|
|
822
939
|
const roundedSize = roundSize(size, szDecimals);
|
|
823
|
-
const
|
|
940
|
+
const effectiveSlippage = slippageBps ?? 50;
|
|
941
|
+
const slippagePrice = getSlippagePrice(midPrice, false, effectiveSlippage);
|
|
824
942
|
|
|
825
943
|
if (params.dry) {
|
|
826
944
|
return json({
|
|
@@ -830,7 +948,7 @@ export function createTools(watcher: PositionWatcher | null): PluginTool[] {
|
|
|
830
948
|
size: roundedSize,
|
|
831
949
|
midPrice,
|
|
832
950
|
slippagePrice,
|
|
833
|
-
slippageBps,
|
|
951
|
+
slippageBps: effectiveSlippage,
|
|
834
952
|
leverage,
|
|
835
953
|
});
|
|
836
954
|
}
|