perp-cli 0.14.0 → 0.14.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.
Files changed (75) hide show
  1. package/dist/arb/sizing.js +29 -7
  2. package/dist/bot/conditions.d.ts +5 -1
  3. package/dist/bot/conditions.js +16 -11
  4. package/dist/bot/engine.d.ts +12 -0
  5. package/dist/bot/engine.js +55 -44
  6. package/dist/bot/strategies/claude-agent.js +2 -2
  7. package/dist/bot/strategies/funding-arb-strategy.js +16 -20
  8. package/dist/bot/strategies/funding-arb-utils.d.ts +19 -0
  9. package/dist/bot/strategies/funding-arb-utils.js +44 -0
  10. package/dist/bot/strategies/funding-auto.js +61 -37
  11. package/dist/bot/strategies/grid-strategy.d.ts +2 -0
  12. package/dist/bot/strategies/grid-strategy.js +21 -2
  13. package/dist/bot/strategies/spot-perp-arb-strategy.js +28 -20
  14. package/dist/bot/tui/BotDashboard.d.ts +13 -2
  15. package/dist/bot/tui/BotDashboard.js +8 -3
  16. package/dist/bridge-engine.d.ts +2 -0
  17. package/dist/bridge-engine.js +68 -31
  18. package/dist/cli-program.js +19 -2
  19. package/dist/commands/account.js +2 -2
  20. package/dist/commands/arb/index.d.ts +20 -0
  21. package/dist/commands/arb/index.js +121 -36
  22. package/dist/commands/arb-auto.d.ts +36 -0
  23. package/dist/commands/arb-auto.js +202 -76
  24. package/dist/commands/arb.js +51 -35
  25. package/dist/commands/bot.d.ts +6 -0
  26. package/dist/commands/bot.js +55 -45
  27. package/dist/commands/funds-onchain.d.ts +1 -1
  28. package/dist/commands/funds-onchain.js +12 -49
  29. package/dist/commands/funds.js +51 -52
  30. package/dist/commands/history.js +165 -62
  31. package/dist/commands/portfolio.d.ts +5 -0
  32. package/dist/commands/portfolio.js +58 -20
  33. package/dist/commands/rebalance.js +46 -10
  34. package/dist/commands/settings.js +2 -1
  35. package/dist/commands/trade.js +8 -4
  36. package/dist/commands/wallet.js +74 -155
  37. package/dist/cross-chain-margin.d.ts +29 -2
  38. package/dist/cross-chain-margin.js +30 -4
  39. package/dist/dashboard/server.d.ts +45 -8
  40. package/dist/dashboard/server.js +113 -42
  41. package/dist/dashboard/ui.js +46 -27
  42. package/dist/dashboard/ws-feeds.d.ts +25 -3
  43. package/dist/dashboard/ws-feeds.js +219 -82
  44. package/dist/dex-asset-map.d.ts +23 -4
  45. package/dist/dex-asset-map.js +39 -13
  46. package/dist/exchanges/arcus/adapter.js +33 -6
  47. package/dist/exchanges/arcus/public.d.ts +6 -0
  48. package/dist/exchanges/arcus/public.js +12 -4
  49. package/dist/exchanges/aster.d.ts +33 -0
  50. package/dist/exchanges/aster.js +162 -55
  51. package/dist/exchanges/hyperliquid.d.ts +30 -0
  52. package/dist/exchanges/hyperliquid.js +159 -34
  53. package/dist/exchanges/lighter.d.ts +1 -1
  54. package/dist/exchanges/lighter.js +11 -9
  55. package/dist/exchanges/ondo/adapter.d.ts +4 -18
  56. package/dist/exchanges/ondo/adapter.js +5 -29
  57. package/dist/exchanges/ondo/funds.d.ts +1 -29
  58. package/dist/exchanges/ondo/funds.js +2 -94
  59. package/dist/exchanges/pacifica.d.ts +12 -0
  60. package/dist/exchanges/pacifica.js +78 -35
  61. package/dist/exchanges/qfex/adapter.js +4 -1
  62. package/dist/exchanges/venues/ondo.d.ts +0 -5
  63. package/dist/exchanges/venues/ondo.js +2 -6
  64. package/dist/exchanges/venues/qfex.d.ts +11 -0
  65. package/dist/exchanges/venues/qfex.js +10 -2
  66. package/dist/mcp-server.js +2 -2
  67. package/dist/onchain-balances.d.ts +40 -0
  68. package/dist/onchain-balances.js +173 -0
  69. package/dist/rebalance.d.ts +20 -1
  70. package/dist/rebalance.js +31 -5
  71. package/dist/strategies/funding-arb.js +38 -7
  72. package/package.json +1 -1
  73. package/skills/perp-cli/SKILL.md +20 -3
  74. package/skills/perp-cli/references/agent-operations.md +2 -2
  75. package/skills/perp-cli/references/commands.md +12 -9
@@ -4,7 +4,7 @@ import { symbolMatch, logSettledRejections } from "../utils.js";
4
4
  import { logExecution } from "../execution-log.js";
5
5
  import { updateJobState } from "../jobs.js";
6
6
  import { invalidateCache } from "../cache.js";
7
- import { fetchAllBalances, computeRebalancePlan, hasEnoughBalance, marketLeverageOf, requiredArbMargin } from "../rebalance.js";
7
+ import { fetchBalancesWithFailures, computeRebalancePlan, hasEnoughBalance, marketLeverageOf, requiredArbMargin } from "../rebalance.js";
8
8
  import { checkArbLiquidity } from "../liquidity.js";
9
9
  import { computeAnnualSpread } from "../funding.js";
10
10
  import { fetchPacificaPrices, fetchHyperliquidMeta, fetchLighterOrderBookDetails, fetchLighterFundingRates, } from "../shared-api.js";
@@ -15,6 +15,11 @@ import { isQuarantined, quarantineSymbol } from "../bot/quarantine.js";
15
15
  import { isPositionGone, matchSymbol } from "../bot/strategies/funding-arb-utils.js";
16
16
  /** Quarantine source for `perp strategy funding-arb` (src/bot/quarantine.ts). */
17
17
  const SOURCE = "funding-arb-cli";
18
+ /** The market's published size decimals on `adapter` (null = not published / market not listed). */
19
+ async function sizeDecimalsOf(adapter, symbol) {
20
+ const m = (await adapter.getMarkets()).find((x) => symbolMatch(x.symbol, symbol));
21
+ return m === undefined ? null : m.sizeDecimals;
22
+ }
18
23
  async function fetchAllRates() {
19
24
  // SSOT rule #2: each DEX is independent. allSettled keeps the comparison
20
25
  // alive when one DEX errors out, while rejection reasons get logged to
@@ -147,9 +152,17 @@ export async function runFundingArb(adapters, params, jobId, log = console.log)
147
152
  // ── Phase 2: Max drawdown check ──
148
153
  if (params.maxDrawdown && params.autoExecute && positions.length > 0) {
149
154
  try {
150
- const snapshots = await fetchAllBalances(adapters);
155
+ const { snapshots, failed } = await fetchBalancesWithFailures(adapters);
151
156
  const totalPnl = snapshots.reduce((s, e) => s + e.unrealizedPnl, 0);
152
- if (totalPnl < -params.maxDrawdown) {
157
+ // Only a failed venue that holds one of the bot's legs makes the uPnL sum unknown; a venue
158
+ // without credentials (notConfigured) cannot hold one.
159
+ const legVenues = new Set(positions.flatMap(p => [p.longExchange, p.shortExchange]));
160
+ const failedLegs = failed.filter(f => legVenues.has(f.exchange));
161
+ if (failedLegs.length > 0) {
162
+ // A partial uPnL sum is not the bot's drawdown: never close everything on it.
163
+ log(`[ARB] Drawdown check skipped — balance unavailable on ${failedLegs.map(f => `${f.exchange} (${f.error})`).join(", ")}`);
164
+ }
165
+ else if (totalPnl < -params.maxDrawdown) {
153
166
  log(`[ARB] MAX DRAWDOWN hit: uPnL $${totalPnl.toFixed(2)} < -$${params.maxDrawdown}`);
154
167
  log(`[ARB] Closing all ${positions.length} positions...`);
155
168
  const stillOpen = await closeAllPositions(positions, adapters, log);
@@ -166,7 +179,11 @@ export async function runFundingArb(adapters, params, jobId, log = console.log)
166
179
  const shouldCheckBalance = params.autoRebalance && (Date.now() - lastRebalanceCheck > 300_000); // every 5 min
167
180
  if (shouldCheckBalance || (params.autoExecute && positions.length < maxPos)) {
168
181
  try {
169
- balanceSnapshots = await fetchAllBalances(adapters);
182
+ const read = await fetchBalancesWithFailures(adapters);
183
+ balanceSnapshots = read.snapshots;
184
+ // A venue missing from the snapshots has no balance for entry checks (no entry there).
185
+ for (const f of read.failed)
186
+ log(`[ARB] ${f.exchange} balance unavailable — no entries / rebalance on it this cycle: ${f.error}`);
170
187
  lastRebalanceCheck = Date.now();
171
188
  if (params.autoRebalance) {
172
189
  const threshold = params.rebalanceThreshold ?? 100;
@@ -229,8 +246,22 @@ export async function runFundingArb(adapters, params, jobId, log = console.log)
229
246
  const liq = await checkArbLiquidity(longAdapter, shortAdapter, symbol, requestedUsd, 0.5, log);
230
247
  if (!liq.viable)
231
248
  continue;
232
- // Compute matched size (same for both legs)
233
- let matched = computeMatchedSize(liq.adjustedSizeUsd, highest.markPrice, longEx, shortEx);
249
+ // Compute matched size (same for both legs) at each venue's published size precision —
250
+ // the per-venue defaults (HL 2 decimals) would reject small BTC legs or over-round.
251
+ let longDec;
252
+ let shortDec;
253
+ try {
254
+ [longDec, shortDec] = await Promise.all([sizeDecimalsOf(longAdapter, symbol), sizeDecimalsOf(shortAdapter, symbol)]);
255
+ }
256
+ catch (e) {
257
+ log(`[ARB] Skip ${symbol}: could not read the market size precision (${e instanceof Error ? e.message : String(e)})`);
258
+ continue;
259
+ }
260
+ if (longDec === null || shortDec === null) {
261
+ log(`[ARB] Skip ${symbol}: size precision not published on ${longDec === null ? longEx : shortEx}`);
262
+ continue;
263
+ }
264
+ let matched = computeMatchedSize(liq.adjustedSizeUsd, highest.markPrice, longEx, shortEx, { longSizeDecimals: longDec, shortSizeDecimals: shortDec });
234
265
  if (!matched) {
235
266
  log(`[ARB] Skip ${symbol}: can't compute matched size (min notional or precision issue)`);
236
267
  continue;
@@ -266,7 +297,7 @@ export async function runFundingArb(adapters, params, jobId, log = console.log)
266
297
  // The LONG was definitely rejected for lot size (nothing placed): recompute once.
267
298
  const lotSize = res.lotSize;
268
299
  log(`[ARB] Lot size ${lotSize} on ${longEx} — recalculating (nothing was placed)`);
269
- matched = computeMatchedSize(liq.adjustedSizeUsd, highest.markPrice, longEx, shortEx, { lotSize });
300
+ matched = computeMatchedSize(liq.adjustedSizeUsd, highest.markPrice, longEx, shortEx, { lotSize, longSizeDecimals: longDec, shortSizeDecimals: shortDec });
270
301
  if (!matched) {
271
302
  log(`[ARB] Skip ${symbol}: can't meet lot size ${lotSize}`);
272
303
  continue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "perp-cli",
3
- "version": "0.14.0",
3
+ "version": "0.14.2",
4
4
  "description": "Multi-DEX Perpetual Futures CLI - Pacifica, Hyperliquid, Lighter, Aster, Lighter RH, Ondo Perps, Arcus",
5
5
  "bin": {
6
6
  "perp": "dist/index.js",
@@ -6,7 +6,7 @@ allowed-tools: "Bash(perp:*), Bash(npx -y perp-cli:*), Bash(bash scripts/preflig
6
6
  compatibility: "Requires Node.js 20 or newer and the perp-cli npm package (global install or npx). Network access required for exchange APIs and bridge providers. Mutating commands need a wallet key imported into the OWS vault via 'perp wallet set EXCHANGE' (key on stdin or hidden prompt — never argv). Skill is portable across Claude Code, Claude.ai, Cursor, Codex, and Gemini CLI — no platform-specific features."
7
7
  metadata:
8
8
  author: hypurrquant
9
- version: "0.14.0"
9
+ version: "0.14.2"
10
10
  ---
11
11
 
12
12
  # perp-cli
@@ -46,7 +46,7 @@ Also bundled under `scripts/`: `preflight.sh`, `arb-monitor.sh`, `funding-analys
46
46
  ### Step 1: Verify install + version
47
47
 
48
48
  ```bash
49
- perp --version 2>/dev/null || npx -y perp-cli@latest --version # must be >= 0.14.0
49
+ perp --version 2>/dev/null || npx -y perp-cli@latest --version # must be >= 0.14.2
50
50
  ```
51
51
 
52
52
  If it is missing or older, ask the user before installing/upgrading (`npm install -g perp-cli@latest`) — never install on your own. If `perp` is not on PATH, prefix every command with `npx -y perp-cli@latest`.
@@ -94,7 +94,7 @@ Imported keys trade; `funds deposit|withdraw|transfer|bridge`, `wallet manage re
94
94
  - Limit GTC / ALO returns `status: accepted, finality: pending` after the ACK; `open` only via `perp --json trade status c:<id> --symbol <S> -e qfex`.
95
95
  - `ORDER_PENDING` = outcome unknown: NEVER resubmit; check with the `c:<id>` in the remediation.
96
96
  - Funding rates on QFEX are unverified: excluded everywhere unless `perp --json arb scan --rates --include-unverified` (display only).
97
- - Withdrawals need `settings.withdraw.qfex` (allowlist + limits), which only the user can set in an interactive terminal — an agent cannot set or change it. `perp --json --dry-run funds withdraw qfex <amt> --to <addr>` shows the gate verdict.
97
+ - Withdrawals are disabled in perp-cli for now: `funds withdraw qfex` → `CAPABILITY_UNSUPPORTED` (also under `--dry-run`). Withdraw in the QFEX web app. Ondo Perps has no API withdrawals either.
98
98
 
99
99
  Venue rules for these: `trade limit` defaults to `--tif GTC` on every venue (arcus maps it to GTT; ondo offers GTC|IOC|ALO; FOK is never emulated → `CAPABILITY_UNSUPPORTED` where not offered); market orders on every venue are bounded by `--slippage-bps <n>` → `settings.slippageBps.<venue>` → `settings.defaultSlippageBps` (shipped default 50). Ondo (US, PA) and Arcus (US, CA, GB) print a one-time restricted-region notice on stderr when used with credentials (warn only, never blocks).
100
100
 
@@ -116,6 +116,23 @@ perp --json arb scan --live --interval 60 # continuous monitoring
116
116
 
117
117
  Common knobs: `--min <pct>`, `--top <n>`, `--hold-days <n>`, `--bridge-cost <usd>`, `--size <usd>`.
118
118
 
119
+ #### HIP-3 dexes (part of Hyperliquid, not a separate venue)
120
+
121
+ HIP-3 dexes are selected on the Hyperliquid venue with the root `--dex <name>` flag; every market / account / trade command works the same way. Same account and wallet as native Hyperliquid perps.
122
+
123
+ ```bash
124
+ perp --json -e hyperliquid market hip3 # list deployed dexes (name, markets)
125
+ perp --json -e hyperliquid --dex xyz market list # markets on dex "xyz"
126
+ perp --json -e hyperliquid --dex xyz market info GOLD # symbols WITHOUT the "xyz:" prefix
127
+ perp --json -e hyperliquid --dex xyz account positions # positions on that dex only
128
+ perp --json -e hyperliquid --dex xyz --dry-run trade market GOLD buy 0.01
129
+ ```
130
+
131
+ - `--dex` with any other `-e` venue → `INVALID_PARAMS` (never ignored).
132
+ - A dex symbol without `--dex` (e.g. `-e hyperliquid market mid xyz:GOLD`) → `SYMBOL_NOT_FOUND` with remediation `--dex xyz`; it is never read from the native dex.
133
+ - `portfolio --dexes xyz,…` adds HIP-3 dex balances; builder fees are never attached on HIP-3.
134
+ - MCP tools cover native Hyperliquid perps only — use the CLI for HIP-3.
135
+
119
136
  ### Step 4: Validate before mutating
120
137
 
121
138
  For arb:
@@ -42,7 +42,7 @@ perp --json wallet generate evm # generate EVM wallet
42
42
  perp --json wallet generate solana # generate Solana wallet
43
43
  perp --json wallet show # check configured wallets
44
44
  perp --json wallet list # list named wallets
45
- perp --json wallet balance # on-chain USDC balances
45
+ perp --json wallet balance # gas token + USDC/USDT per chain (Arbitrum, Ethereum, Base, BNB, Robinhood USDG, Solana); failed reads → balance null + error
46
46
  perp --json portfolio -e <EX> # per-exchange balance + positions (account balance was renamed in v0.12)
47
47
  perp --json -e <EX> account positions # open positions
48
48
  perp --json -e <EX> market list # available markets
@@ -148,7 +148,7 @@ Default `-e` = `settings.defaultExchange`, else `pacifica` — always pass `-e`.
148
148
 
149
149
  ### Check On-Chain vs Exchange Balance
150
150
  ```bash
151
- perp --json wallet balance # on-chain USDC in your wallet
151
+ perp --json wallet balance # gas token + USDC/USDT per chain (Arbitrum, Ethereum, Base, BNB, Robinhood USDG, Solana); failed reads → balance null + error
152
152
  perp --json portfolio -e hyperliquid # USDC deposited on exchange
153
153
  ```
154
154
 
@@ -19,12 +19,14 @@ perp --json -e <EX> market book <SYMBOL> # orderbook (bids/asks)
19
19
  perp --json -e <EX> market trades <SYMBOL> # recent trades
20
20
  perp --json -e <EX> market funding <SYMBOL> # funding rate history
21
21
  perp --json -e <EX> market kline <SYM> <INT> # OHLCV candles (1m,5m,15m,1h,4h,1d)
22
- perp --json market hip3 # list HIP-3 deployed perp dexes (Hyperliquid)
22
+ perp --json -e hyperliquid market hip3 # list HIP-3 deployed perp dexes (needs -e hyperliquid; other -e → INVALID_PARAMS)
23
+ perp --json -e hyperliquid --dex <DEX> market list # one HIP-3 dex's markets (e.g. --dex xyz)
24
+ perp --json -e hyperliquid --dex <DEX> market book <SYMBOL> # any market/account/trade command takes --dex the same way
23
25
  ```
24
26
 
25
27
  ## Account (read-only, safe)
26
28
  ```bash
27
- perp --json portfolio -e <VENUE_ID> # perp balance + spot holdings + 24h funding; full venue id only (hl → INVALID_PARAMS)
29
+ perp --json portfolio -e <VENUE_ID> # perp balance + spot holdings + 24h funding; venue id or alias (hl, lt, …)
28
30
  perp --json -e <EX> account positions # open positions
29
31
  perp --json -e <EX> account orders # open/pending orders
30
32
  perp --json -e <EX> account history # order history
@@ -35,6 +37,7 @@ perp --json -e <EX> account margin <SYMBOL> # position margin info
35
37
  perp --json -e <EX> account pnl # realized + unrealized + funding
36
38
  perp --json -e <EX> account twap-orders # active TWAP orders
37
39
  perp --json portfolio # cross-exchange unified view
40
+ # funding24h is null (with fundingError) when a venue's funding history is unreadable; totals.fundingIncomplete = true then
38
41
  perp --json portfolio --arb # full dashboard with arb top 5
39
42
  ```
40
43
 
@@ -195,15 +198,14 @@ perp --json funds withdraw hyperliquid <AMOUNT> [--chain arbitrum|ethereum|base]
195
198
  # --to another address only if it is on settings withdraw.hyperliquid (else POLICY_DENIED).
196
199
  perp --json funds withdraw lighter <AMOUNT> # -e lighter: USDC → Ethereum; -e lighter-rh: USDG → Robinhood Chain
197
200
  perp --json funds deposit lighter-rh <AMOUNT> # USDG on Robinhood Chain (min 1, mainnet only)
198
- perp --json funds withdraw ondo <AMOUNT> --to <ADDRESS> # USDC → Ethereum (address-book destination)
201
+ # Ondo Perps: NO API withdrawals — `funds withdraw ondo` → CAPABILITY_UNSUPPORTED; withdraw in the Ondo web app
199
202
  perp --json funds withdraw arcus <AMOUNT> # USDG → the account owner (min 1)
200
203
  perp --json funds deposit qfex # prints the USDC / Arbitrum One deposit address (sends nothing)
201
- perp --json --dry-run funds withdraw qfex <AMOUNT> --to <0x> # plan + local gate verdict (settings withdraw.qfex; user-only, terminal)
204
+ # QFEX: withdrawals disabled in perp-cli for now — `funds withdraw qfex` → CAPABILITY_UNSUPPORTED; withdraw in the QFEX web app
202
205
  perp --json -e qfex funds transfer <AMOUNT> primary --from <account-uuid> # between your QFEX accounts
203
206
  perp --json funds deposit aster <AMOUNT> [--chain bsc|arbitrum] [--asset USDT|USDC] # vault approve + deposit (mainnet; default BNB Chain USDT)
204
207
  perp --json funds withdraw aster <AMOUNT> [--chain bsc|arbitrum] [--asset USDT|USDC] # → the account's own address (default USDT; mainnet; agent approved with --can-withdraw --ip-whitelist)
205
208
  perp --json funds deposit ondo <AMOUNT> [--chain arbitrum|ethereum] [--probe <AMT>] # USDC transfer to the account's funding address (mainnet)
206
- perp --json funds address-book add ondo <MASTER_ADDRESS> # SIWE challenge → Ondo withdrawal address book (own address only)
207
209
  perp --json funds transfer <AMOUNT> <ADDRESS> # HL internal transfer (instant); destination must be on settings withdraw.hyperliquid
208
210
  # settings withdraw.<venue> (allowlist + limits) is set ONLY by the user in an interactive terminal
209
211
  # (--json / piped → POLICY_DENIED). Agents never set or change it.
@@ -254,7 +256,7 @@ perp --json arb scan --gaps # cross-exchange pri
254
256
  perp --json arb scan --hip3 # HIP-3 cross-dex spreads
255
257
  perp --json arb scan --history [SYMBOL] # historical funding
256
258
  perp --json arb scan --compare <SYMBOL> # compare a symbol across exchanges
257
- perp --json arb scan --positions # position funding impact
259
+ perp --json arb scan --positions # position funding impact; actual24h null + fundingHistoryErrors when a venue's history is unreadable
258
260
  perp --json arb scan --live --interval 60 # continuous monitoring
259
261
  perp --json arb scan --top 10 --hold-days 7 --bridge-cost 0 --size 100 # cost-aware filtering
260
262
  perp --json arb scan --rates --include-unverified # also show QFEX (unverified funding; display only, never ranked)
@@ -280,6 +282,7 @@ perp --json arb close <SYM> --state-only --yes # drop a stale state
280
282
 
281
283
  # Status / history / config / rebalance
282
284
  perp --json arb status # open arb positions + PnL + funding; check unconfirmedPairs, staleStateEntries
285
+ # spot-perp entries: fundingSource actual | partial | estimate | recorded (+ fundingError) — only "actual" is complete settled funding
283
286
  perp --json arb status --period 7 --symbol BTC # filter funding lookback / symbol
284
287
  perp --json arb history # alias: arb log
285
288
  perp --json arb history --period 30 # past arb trade performance
@@ -307,7 +310,7 @@ perp --json wallet list # all named wallets
307
310
  perp --json wallet use <name> # set active wallet
308
311
  perp --json wallet rename <old> <new>
309
312
  perp --json wallet remove <name>
310
- perp --json wallet balance # on-chain USDC balances
313
+ perp --json wallet balance # gas token + USDC/USDT per chain (Arbitrum, Ethereum, Base, BNB, Robinhood USDG, Solana); failed reads → balance null + error
311
314
  perp --json wallet solana <address> # check arbitrary Solana address
312
315
  perp --json wallet arbitrum <address> # check arbitrary Arbitrum address
313
316
  perp --json wallet migrate # migrate legacy ~/.perp/.env config
@@ -423,9 +426,9 @@ perp --json history list # execution audit trail
423
426
  perp --json history positions # position lifetime tracking
424
427
  perp --json history prune # purge old entries
425
428
  perp --json history summary # trading performance summary (replaces former 'stats')
426
- perp --json history pnl # P&L breakdown by exchange
429
+ perp --json history pnl # P&L breakdown by exchange; errors + partial name venues whose reads failed (left out, not 0)
427
430
  perp --json history funding # funding payment aggregation
428
- perp --json history report # full performance report (summary + pnl + funding)
431
+ perp --json history report # full performance report (summary + pnl + funding); errors + partial + venuesRead
429
432
  perp --json history compare # compare strategies / accounts
430
433
  perp --json history snapshot # equity snapshot
431
434
  perp --json history track # PnL tracking helper