perp-cli 0.15.0 → 0.16.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.
- package/README.ja.md +243 -0
- package/README.ko.md +243 -0
- package/README.md +129 -535
- package/README.zh.md +243 -0
- package/dist/api/public/lighter.d.ts +5 -0
- package/dist/api/public/lighter.js +5 -0
- package/dist/api/public/pacifica.js +2 -2
- package/dist/arb/sizing.js +4 -2
- package/dist/arb/state.d.ts +6 -0
- package/dist/balance-by-address.d.ts +39 -0
- package/dist/balance-by-address.js +44 -0
- package/dist/bot/quote-rules.js +1 -1
- package/dist/bot/strategies/funding-arb-strategy.js +10 -3
- package/dist/bot/strategies/funding-arb-utils.d.ts +14 -2
- package/dist/bot/strategies/funding-arb-utils.js +48 -15
- package/dist/bot/strategies/spot-perp-arb-strategy.d.ts +1 -1
- package/dist/bot/strategies/spot-perp-arb-strategy.js +4 -2
- package/dist/bot/strategies/spot-perp-executor.js +2 -2
- package/dist/cli-program.js +1 -1
- package/dist/commands/account.js +168 -24
- package/dist/commands/arb/index.js +19 -77
- package/dist/commands/arb-auto.d.ts +24 -0
- package/dist/commands/arb-auto.js +155 -81
- package/dist/commands/arb.d.ts +8 -0
- package/dist/commands/arb.js +49 -23
- package/dist/commands/backtest.js +23 -21
- package/dist/commands/market.d.ts +48 -0
- package/dist/commands/market.js +241 -78
- package/dist/commands/options.d.ts +5 -0
- package/dist/commands/options.js +20 -3
- package/dist/commands/pacifica-earn.js +8 -21
- package/dist/commands/portfolio.d.ts +16 -0
- package/dist/commands/portfolio.js +51 -8
- package/dist/commands/trade.js +4 -4
- package/dist/cross-chain-margin.d.ts +3 -1
- package/dist/cross-chain-margin.js +4 -2
- package/dist/dashboard/server.js +2 -2
- package/dist/dashboard/ui.js +9 -6
- package/dist/errors.d.ts +5 -0
- package/dist/errors.js +10 -0
- package/dist/exchanges/address.d.ts +8 -0
- package/dist/exchanges/address.js +47 -0
- package/dist/exchanges/arcus/adapter.d.ts +10 -6
- package/dist/exchanges/arcus/adapter.js +33 -6
- package/dist/exchanges/arcus/public.js +3 -2
- package/dist/exchanges/aster.d.ts +27 -7
- package/dist/exchanges/aster.js +124 -42
- package/dist/exchanges/canonical-symbols.d.ts +7 -0
- package/dist/exchanges/canonical-symbols.js +20 -0
- package/dist/exchanges/capabilities.d.ts +2 -0
- package/dist/exchanges/capabilities.js +2 -1
- package/dist/exchanges/derive/options.d.ts +5 -0
- package/dist/exchanges/derive/options.js +20 -1
- package/dist/exchanges/extended/adapter.d.ts +16 -2
- package/dist/exchanges/extended/adapter.js +96 -34
- package/dist/exchanges/extended/public.d.ts +3 -0
- package/dist/exchanges/extended/public.js +9 -2
- package/dist/exchanges/grvt/adapter.d.ts +16 -2
- package/dist/exchanges/grvt/adapter.js +98 -21
- package/dist/exchanges/hyperliquid-outcome.d.ts +2 -0
- package/dist/exchanges/hyperliquid-outcome.js +29 -1
- package/dist/exchanges/hyperliquid-spot.d.ts +8 -0
- package/dist/exchanges/hyperliquid-spot.js +20 -12
- package/dist/exchanges/hyperliquid.d.ts +180 -13
- package/dist/exchanges/hyperliquid.js +487 -185
- package/dist/exchanges/interface.d.ts +64 -8
- package/dist/exchanges/interface.js +31 -0
- package/dist/exchanges/lighter-public.d.ts +66 -11
- package/dist/exchanges/lighter-public.js +249 -81
- package/dist/exchanges/lighter-spot.d.ts +7 -1
- package/dist/exchanges/lighter-spot.js +99 -90
- package/dist/exchanges/lighter.d.ts +70 -11
- package/dist/exchanges/lighter.js +285 -92
- package/dist/exchanges/ondo/adapter.d.ts +34 -8
- package/dist/exchanges/ondo/adapter.js +73 -16
- package/dist/exchanges/ondo/public.d.ts +27 -2
- package/dist/exchanges/ondo/public.js +63 -31
- package/dist/exchanges/outcome-interface.d.ts +4 -0
- package/dist/exchanges/pacifica-spot.d.ts +6 -0
- package/dist/exchanges/pacifica-spot.js +23 -15
- package/dist/exchanges/pacifica-vaults.d.ts +9 -0
- package/dist/exchanges/pacifica-vaults.js +14 -1
- package/dist/exchanges/pacifica.d.ts +77 -6
- package/dist/exchanges/pacifica.js +321 -130
- package/dist/exchanges/public-balances.d.ts +25 -0
- package/dist/exchanges/public-balances.js +158 -0
- package/dist/exchanges/public-positions.d.ts +43 -0
- package/dist/exchanges/public-positions.js +154 -0
- package/dist/exchanges/qfex/adapter.d.ts +52 -9
- package/dist/exchanges/qfex/adapter.js +74 -9
- package/dist/exchanges/qfex/public.d.ts +62 -9
- package/dist/exchanges/qfex/public.js +128 -22
- package/dist/exchanges/qfex/ws-transport.d.ts +1 -1
- package/dist/exchanges/risex/adapter.d.ts +19 -7
- package/dist/exchanges/risex/adapter.js +58 -12
- package/dist/exchanges/spot-factory.js +1 -1
- package/dist/exchanges/txflow/adapter.d.ts +14 -7
- package/dist/exchanges/txflow/adapter.js +51 -19
- package/dist/exchanges/txflow/client.js +3 -1
- package/dist/exchanges/txflow/public.d.ts +12 -1
- package/dist/exchanges/txflow/public.js +82 -11
- package/dist/exchanges/unknown-symbol.d.ts +6 -1
- package/dist/exchanges/unknown-symbol.js +7 -2
- package/dist/exchanges/variational/adapter.d.ts +2 -6
- package/dist/exchanges/venue-types.d.ts +46 -3
- package/dist/exchanges/venue-types.js +80 -9
- package/dist/exchanges/venue.d.ts +99 -3
- package/dist/exchanges/venue.js +72 -0
- package/dist/exchanges/venues/hyperliquid.js +9 -0
- package/dist/exchanges/venues/lighter-rh.js +13 -3
- package/dist/exchanges/venues/lighter.js +13 -3
- package/dist/exchanges/venues/pacifica.js +9 -0
- package/dist/exchanges/venues/risex.js +15 -0
- package/dist/funding/legacy-public.d.ts +5 -3
- package/dist/funding/legacy-public.js +33 -37
- package/dist/funding/rates.d.ts +54 -5
- package/dist/funding/rates.js +49 -13
- package/dist/liquidity.d.ts +3 -1
- package/dist/liquidity.js +8 -4
- package/dist/mcp-pacifica-earn.js +11 -5
- package/dist/mcp-server.js +104 -15
- package/dist/pacifica/client.d.ts +2 -1
- package/dist/pacifica/client.js +11 -0
- package/dist/positions-by-address.d.ts +34 -0
- package/dist/positions-by-address.js +46 -0
- package/dist/strategies/funding-arb.js +35 -62
- package/dist/utils.d.ts +11 -1
- package/dist/venue-health.js +1 -1
- package/dist/ws/arcus-market.d.ts +9 -0
- package/dist/ws/arcus-market.js +9 -0
- package/dist/ws/aster-market.d.ts +33 -0
- package/dist/ws/aster-market.js +30 -0
- package/dist/ws/index.d.ts +30 -9
- package/dist/ws/index.js +180 -15
- package/dist/ws/lighter-market.d.ts +14 -0
- package/dist/ws/lighter-market.js +13 -0
- package/dist/ws/node.d.ts +30 -9
- package/dist/ws/node.js +204 -16
- package/dist/ws/unclassified.d.ts +16 -0
- package/dist/ws/unclassified.js +43 -0
- package/package.json +15 -2
- package/skills/perp-cli/SKILL.md +97 -33
- package/skills/perp-cli/package.json +15 -2
- package/skills/perp-cli/references/agent-operations.md +15 -12
- package/skills/perp-cli/references/commands.md +67 -12
- package/skills/perp-cli/references/strategies.md +38 -3
- package/skills/perp-cli/references/ws-library.md +55 -24
- package/skills/perp-cli/scripts/arb-monitor.sh +13 -10
- package/skills/perp-cli/scripts/funding-analysis.sh +57 -29
- package/skills/perp-cli/scripts/preflight.sh +27 -19
- package/skills/perp-cli/scripts/spot-perp-scan.sh +58 -38
- package/skills/perp-cli/scripts/validate-arb.sh +56 -39
- package/dist/cli-spec.d.ts +0 -46
- package/dist/cli-spec.js +0 -81
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { printJson, jsonOk, jsonError, makeTable, formatUsd } from "../utils.js";
|
|
2
2
|
import { getHistoricalRates } from "../funding-history.js";
|
|
3
|
+
import { HyperliquidAdapter, hlEarliestCandleStart } from "../exchanges/hyperliquid.js";
|
|
3
4
|
import chalk from "chalk";
|
|
4
5
|
export function registerBacktestCommands(program, isJson) {
|
|
5
6
|
const backtest = program.command("backtest").description("Backtest trading strategies on historical data");
|
|
@@ -32,10 +33,13 @@ export function registerBacktestCommands(program, isJson) {
|
|
|
32
33
|
const ratesA = getHistoricalRates(sym, exchA, startTime, endTime);
|
|
33
34
|
const ratesB = getHistoricalRates(sym, exchB, startTime, endTime);
|
|
34
35
|
if (ratesA.length === 0 && ratesB.length === 0) {
|
|
36
|
+
// The funding history is written by `arb scan --rates` (saveFundingSnapshot; verified venues
|
|
37
|
+
// only). There is no `perp funding snapshot` command (0.15.0 named one).
|
|
38
|
+
const collect = `perp arb scan --rates --symbol ${sym}`;
|
|
35
39
|
if (isJson())
|
|
36
|
-
return printJson(jsonError("NO_DATA", `No historical funding data for ${sym}. Run '
|
|
40
|
+
return printJson(jsonError("NO_DATA", `No historical funding data for ${sym}. Run '${collect}' periodically to collect data first.`));
|
|
37
41
|
console.log(chalk.yellow(`\n No historical funding data for ${sym} on ${exchA}/${exchB}.`));
|
|
38
|
-
console.log(chalk.yellow(` Run '
|
|
42
|
+
console.log(chalk.yellow(` Run '${collect}' periodically to collect data first.\n`));
|
|
39
43
|
return;
|
|
40
44
|
}
|
|
41
45
|
// Build time-aligned rate pairs
|
|
@@ -180,31 +184,25 @@ export function registerBacktestCommands(program, isJson) {
|
|
|
180
184
|
console.error(chalk.red("Error: Need at least 2 grid lines"));
|
|
181
185
|
process.exit(1);
|
|
182
186
|
}
|
|
187
|
+
// Hyperliquid serves only the most recent 5000 candles per interval (docs "Candle snapshot");
|
|
188
|
+
// with 1h candles a --days above ~208 cannot be read. The start is clamped to the available
|
|
189
|
+
// window (one hour inside it) and the result says so — never presented as the full period.
|
|
190
|
+
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
183
191
|
const endTime = Date.now();
|
|
184
|
-
const
|
|
185
|
-
|
|
192
|
+
const requestedStart = endTime - days * DAY_MS;
|
|
193
|
+
const earliest = hlEarliestCandleStart("1h", endTime) + 60 * 60 * 1000;
|
|
194
|
+
const truncated = requestedStart < earliest;
|
|
195
|
+
const startTime = truncated ? earliest : requestedStart;
|
|
196
|
+
const dataFrom = startTime;
|
|
197
|
+
const coveredDays = (endTime - startTime) / DAY_MS;
|
|
198
|
+
// Fetch historical klines from Hyperliquid (adapter: symbol resolution, interval / window checks)
|
|
186
199
|
if (!isJson()) {
|
|
187
200
|
console.log(chalk.gray(`\n Fetching ${days}d of 1h klines for ${sym}...`));
|
|
188
201
|
}
|
|
189
202
|
let klines;
|
|
190
203
|
try {
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
headers: { "Content-Type": "application/json" },
|
|
194
|
-
body: JSON.stringify({
|
|
195
|
-
type: "candleSnapshot",
|
|
196
|
-
req: {
|
|
197
|
-
coin: sym,
|
|
198
|
-
interval: "1h",
|
|
199
|
-
startTime,
|
|
200
|
-
endTime,
|
|
201
|
-
},
|
|
202
|
-
}),
|
|
203
|
-
});
|
|
204
|
-
if (!resp.ok)
|
|
205
|
-
throw new Error(`HTTP ${resp.status}`);
|
|
206
|
-
const data = await resp.json();
|
|
207
|
-
klines = data.map(k => ({ t: k.t, o: k.o, h: k.h, l: k.l, c: k.c }));
|
|
204
|
+
const rows = await new HyperliquidAdapter(undefined, false).getKlines(sym, "1h", startTime, endTime);
|
|
205
|
+
klines = rows.map(k => ({ t: k.time, o: k.open, h: k.high, l: k.low, c: k.close }));
|
|
208
206
|
}
|
|
209
207
|
catch (err) {
|
|
210
208
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -291,6 +289,8 @@ export function registerBacktestCommands(program, isJson) {
|
|
|
291
289
|
symbol: sym,
|
|
292
290
|
period: `${days} days`,
|
|
293
291
|
klines: klines.length,
|
|
292
|
+
dataFrom: new Date(dataFrom).toISOString(),
|
|
293
|
+
truncated,
|
|
294
294
|
priceRange,
|
|
295
295
|
gridRange: `$${formatUsd(String(lowerPrice))} - $${formatUsd(String(upperPrice))}`,
|
|
296
296
|
grids,
|
|
@@ -307,6 +307,8 @@ export function registerBacktestCommands(program, isJson) {
|
|
|
307
307
|
return printJson(jsonOk(summary));
|
|
308
308
|
console.log(chalk.cyan.bold(`\n Grid Backtest — ${sym}\n`));
|
|
309
309
|
console.log(` Period: ${days} days (${klines.length} candles)`);
|
|
310
|
+
if (truncated)
|
|
311
|
+
console.log(chalk.yellow(` Truncated: Hyperliquid serves only the most recent 5000 1h candles — start clamped to ${new Date(dataFrom).toISOString()} (${coveredDays.toFixed(1)} of ${days} days)`));
|
|
310
312
|
console.log(` Price range: ${priceRange}`);
|
|
311
313
|
console.log(` Grid range: $${formatUsd(String(lowerPrice))} - $${formatUsd(String(upperPrice))}`);
|
|
312
314
|
console.log(` Grid lines: ${grids} (step: $${step.toFixed(2)})`);
|
|
@@ -1,6 +1,54 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
2
|
import type { ExchangeAdapter } from "../exchanges/index.js";
|
|
3
3
|
import "../exchanges/venues/index.js";
|
|
4
|
+
/**
|
|
5
|
+
* Venues of the multi-venue `market list|prices` (no -e): every venue with the marketData role
|
|
6
|
+
* and a (public) adapter — market-data-only venues (TxFlow, Variational, GRVT, Extended) included.
|
|
7
|
+
* They were left out in 0.15.0 because the list was the account-role venues.
|
|
8
|
+
*/
|
|
9
|
+
export declare const MARKET_DATA_VENUES: import("../exchanges/venue-types.js").VenueId[];
|
|
10
|
+
/**
|
|
11
|
+
* `--limit` / `-l` / `--depth`: a positive integer, the same rule on every venue (parseInt took
|
|
12
|
+
* "abc" as NaN and "-5" as a negative slice). Anything else → INVALID_PARAMS before any request.
|
|
13
|
+
*/
|
|
14
|
+
export declare function parsePositiveIntArg(raw: string, flag: string): number;
|
|
15
|
+
/**
|
|
16
|
+
* Most order-book levels per side each venue serves (measured live 2026-10-19; the request size
|
|
17
|
+
* where the venue takes one): one rule for every venue — `--depth` above it is INVALID_PARAMS
|
|
18
|
+
* naming the max, never clamped or silently short. Absent = the full book (Extended).
|
|
19
|
+
*/
|
|
20
|
+
export declare const BOOK_DEPTH_MAX: Readonly<Record<string, number>>;
|
|
21
|
+
export declare function assertBookDepth(venue: string, depth: number): void;
|
|
22
|
+
/**
|
|
23
|
+
* `--start` / `--end`: unix ms (digits) or an ISO-8601 date / time (`Date.parse`; "2026-10-18" is
|
|
24
|
+
* UTC midnight). parseInt("2026-10-18") read 2026 ms. Non-finite → INVALID_PARAMS.
|
|
25
|
+
*/
|
|
26
|
+
export declare function parseTimeArg(raw: string, flag: string): number;
|
|
27
|
+
/**
|
|
28
|
+
* Bare market symbol of a CLI argument as `market info` matches it against getMarkets() rows:
|
|
29
|
+
* "btc-perp" → "BTC", Extended "BTC-USD" / "TSLA_24_5-USD" → "BTC" / "TSLA", TxFlow "BTC-USDC" → "BTC"
|
|
30
|
+
* (book / funding resolve these through the venue; info read the raw argument and missed them).
|
|
31
|
+
* HIP-3 "xyz:XYZ100" keeps its prefix.
|
|
32
|
+
*/
|
|
33
|
+
export declare function bareSymbolOf(arg: string): string;
|
|
34
|
+
/**
|
|
35
|
+
* History order, one rule for every venue: trades and funding history newest first, candles
|
|
36
|
+
* oldest first (Aster / QFEX answered funding oldest first, GRVT trades oldest first). A stable
|
|
37
|
+
* copy — the adapter's array (and its non-enumerable tape metadata) is left as is.
|
|
38
|
+
*/
|
|
39
|
+
export declare function newestFirst<T extends {
|
|
40
|
+
time: number;
|
|
41
|
+
}>(rows: readonly T[]): T[];
|
|
42
|
+
export declare function notTradableReason(m: {
|
|
43
|
+
tradable?: boolean;
|
|
44
|
+
status?: string | null;
|
|
45
|
+
}): string | null;
|
|
4
46
|
export declare function registerMarketCommands(program: Command, getAdapter: () => Promise<ExchangeAdapter>, isJson: () => boolean, getAdapterForExchange?: (exchange: string) => Promise<ExchangeAdapter>,
|
|
5
47
|
/** Credentialed adapter of the selected venue — for market data the venue serves only to an authenticated account. */
|
|
6
48
|
getAccountAdapter?: () => Promise<ExchangeAdapter>): void;
|
|
49
|
+
/**
|
|
50
|
+
* Why a listed market is not tradable, from the row's `status` when the venue states it (QFEX
|
|
51
|
+
* "nonUsdQuote", Ondo "closed" / "reduceOnly"); the generic off-hours text only when it does not.
|
|
52
|
+
* null = tradable or no tradability flag.
|
|
53
|
+
*/
|
|
54
|
+
export declare function notTradableNote(m: object): string | null;
|