perp-cli 0.14.2 → 0.15.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.md +152 -13
- package/dist/agent-wallet/store.d.ts +3 -2
- package/dist/agent-wallet/store.js +2 -2
- package/dist/api/public/hyperliquid.js +4 -0
- package/dist/api/public/pacifica.js +83 -13
- package/dist/api/public/urls.d.ts +2 -0
- package/dist/api/public/urls.js +3 -0
- package/dist/arb/utils.d.ts +1 -2
- package/dist/arb/utils.js +1 -2
- package/dist/bot/apex/pulse.js +3 -0
- package/dist/bot/apex/radar.js +2 -1
- package/dist/bot/engine.d.ts +10 -1
- package/dist/bot/engine.js +14 -6
- package/dist/bot/indicators.d.ts +7 -0
- package/dist/bot/indicators.js +16 -0
- package/dist/bot/perp-order.d.ts +4 -4
- package/dist/bot/perp-order.js +5 -5
- package/dist/bot/quarantine.d.ts +1 -1
- package/dist/bot/quarantine.js +1 -1
- package/dist/bot/strategies/apex-strategy.js +3 -2
- package/dist/bot/strategies/engine-mm.js +6 -5
- package/dist/bot/strategies/funding-arb-strategy.js +9 -9
- package/dist/bot/strategies/funding-arb-utils.d.ts +15 -2
- package/dist/bot/strategies/funding-arb-utils.js +43 -24
- package/dist/bot/strategies/funding-auto.js +2 -2
- package/dist/bot/strategies/liquidation-mm.d.ts +1 -0
- package/dist/bot/strategies/liquidation-mm.js +8 -2
- package/dist/bot/strategies/momentum-breakout.d.ts +1 -0
- package/dist/bot/strategies/momentum-breakout.js +11 -3
- package/dist/bot/strategies/spot-perp-arb-strategy.js +23 -12
- package/dist/bot/strategies/spot-perp-executor.d.ts +1 -1
- package/dist/bot/strategies/spot-perp-executor.js +1 -1
- package/dist/bot/strategy-types.d.ts +2 -1
- package/dist/bot/tui/BotDashboard.d.ts +1 -1
- package/dist/bot/tui/BotDashboard.js +1 -1
- package/dist/cache.js +12 -6
- package/dist/cli-program.d.ts +15 -0
- package/dist/cli-program.js +125 -5
- package/dist/commands/agent-import.d.ts +7 -0
- package/dist/commands/agent-import.js +30 -1
- package/dist/commands/agent.d.ts +6 -3
- package/dist/commands/agent.js +160 -12
- package/dist/commands/arb/index.js +4 -4
- package/dist/commands/arb-auto.js +21 -17
- package/dist/commands/arb.d.ts +12 -0
- package/dist/commands/arb.js +61 -143
- package/dist/commands/bot.js +1 -1
- package/dist/commands/builder.js +1 -1
- package/dist/commands/funds.js +113 -3
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.js +27 -7
- package/dist/commands/manage.js +23 -21
- package/dist/commands/market.js +168 -36
- package/dist/commands/options.d.ts +9 -0
- package/dist/commands/options.js +134 -0
- package/dist/commands/pacifica-earn.d.ts +5 -0
- package/dist/commands/pacifica-earn.js +468 -0
- package/dist/commands/pacifica-orders.d.ts +14 -0
- package/dist/commands/pacifica-orders.js +142 -0
- package/dist/commands/portfolio.js +32 -47
- package/dist/commands/rebalance.d.ts +1 -0
- package/dist/commands/rebalance.js +15 -0
- package/dist/commands/risk.d.ts +11 -2
- package/dist/commands/risk.js +39 -44
- package/dist/commands/trade.d.ts +1 -0
- package/dist/commands/trade.js +63 -58
- package/dist/commands/wallet.js +1 -1
- package/dist/config.d.ts +2 -2
- package/dist/config.js +15 -4
- package/dist/constants.js +6 -0
- package/dist/dashboard/server.js +1 -1
- package/dist/dashboard/ui.js +1 -1
- package/dist/errors.d.ts +24 -1
- package/dist/errors.js +25 -3
- package/dist/exchanges/arcus/adapter.d.ts +7 -7
- package/dist/exchanges/arcus/adapter.js +12 -12
- package/dist/exchanges/arcus/agent.d.ts +1 -1
- package/dist/exchanges/arcus/agent.js +1 -1
- package/dist/exchanges/arcus/client.js +1 -1
- package/dist/exchanges/arcus/signing.d.ts +2 -3
- package/dist/exchanges/arcus/signing.js +1 -1
- package/dist/exchanges/arcus/spot-chain.d.ts +1 -1
- package/dist/exchanges/arcus/spot-chain.js +1 -1
- package/dist/exchanges/arcus/spot-router.d.ts +1 -1
- package/dist/exchanges/arcus/spot-router.js +2 -2
- package/dist/exchanges/arcus/spot.d.ts +2 -3
- package/dist/exchanges/arcus/spot.js +2 -3
- package/dist/exchanges/aster-spot.d.ts +3 -3
- package/dist/exchanges/aster-spot.js +6 -9
- package/dist/exchanges/aster-typed-data.d.ts +1 -1
- package/dist/exchanges/aster-typed-data.js +1 -1
- package/dist/exchanges/aster.d.ts +9 -4
- package/dist/exchanges/aster.js +125 -55
- package/dist/exchanges/builder-fee.d.ts +1 -1
- package/dist/exchanges/builder-fee.js +13 -2
- package/dist/exchanges/canonical-symbols.d.ts +1 -2
- package/dist/exchanges/canonical-symbols.js +26 -2
- package/dist/exchanges/derive/client.d.ts +37 -0
- package/dist/exchanges/derive/client.js +135 -0
- package/dist/exchanges/derive/options.d.ts +68 -0
- package/dist/exchanges/derive/options.js +360 -0
- package/dist/exchanges/extended/adapter.d.ts +82 -0
- package/dist/exchanges/extended/adapter.js +179 -0
- package/dist/exchanges/extended/client.d.ts +38 -0
- package/dist/exchanges/extended/client.js +88 -0
- package/dist/exchanges/extended/public.d.ts +130 -0
- package/dist/exchanges/extended/public.js +429 -0
- package/dist/exchanges/grvt/adapter.d.ts +86 -0
- package/dist/exchanges/grvt/adapter.js +206 -0
- package/dist/exchanges/grvt/client.d.ts +25 -0
- package/dist/exchanges/grvt/client.js +86 -0
- package/dist/exchanges/grvt/public.d.ts +151 -0
- package/dist/exchanges/grvt/public.js +438 -0
- package/dist/exchanges/hyperliquid-spot.d.ts +1 -1
- package/dist/exchanges/hyperliquid-spot.js +5 -5
- package/dist/exchanges/hyperliquid.d.ts +22 -16
- package/dist/exchanges/hyperliquid.js +80 -55
- package/dist/exchanges/index.d.ts +1 -1
- package/dist/exchanges/index.js +1 -1
- package/dist/exchanges/interface.d.ts +97 -8
- package/dist/exchanges/interface.js +19 -2
- package/dist/exchanges/ioc-outcome.d.ts +1 -1
- package/dist/exchanges/ioc-outcome.js +1 -1
- package/dist/exchanges/legacy-trading-v2.d.ts +2 -2
- package/dist/exchanges/legacy-trading-v2.js +7 -2
- package/dist/exchanges/lighter-public.d.ts +2 -2
- package/dist/exchanges/lighter-public.js +2 -2
- package/dist/exchanges/lighter-signer.d.ts +1 -1
- package/dist/exchanges/lighter-signer.js +1 -1
- package/dist/exchanges/lighter-spot.d.ts +3 -4
- package/dist/exchanges/lighter-spot.js +6 -7
- package/dist/exchanges/lighter.d.ts +11 -11
- package/dist/exchanges/lighter.js +28 -14
- package/dist/exchanges/ondo/adapter.d.ts +5 -6
- package/dist/exchanges/ondo/adapter.js +16 -14
- package/dist/exchanges/ondo/agent.d.ts +1 -1
- package/dist/exchanges/ondo/agent.js +1 -1
- package/dist/exchanges/ondo/client.d.ts +1 -1
- package/dist/exchanges/ondo/client.js +2 -2
- package/dist/exchanges/ondo/public.d.ts +8 -1
- package/dist/exchanges/ondo/public.js +13 -2
- package/dist/exchanges/ondo/spot.d.ts +2 -2
- package/dist/exchanges/ondo/spot.js +3 -3
- package/dist/exchanges/options-interface.d.ts +158 -0
- package/dist/exchanges/options-interface.js +17 -0
- package/dist/exchanges/options-venues.d.ts +12 -0
- package/dist/exchanges/options-venues.js +35 -0
- package/dist/exchanges/pacifica-atomic.d.ts +211 -0
- package/dist/exchanges/pacifica-atomic.js +440 -0
- package/dist/exchanges/pacifica-decimal.d.ts +10 -0
- package/dist/exchanges/pacifica-decimal.js +51 -0
- package/dist/exchanges/pacifica-presigned.d.ts +53 -0
- package/dist/exchanges/pacifica-presigned.js +141 -0
- package/dist/exchanges/pacifica-print.d.ts +200 -0
- package/dist/exchanges/pacifica-print.js +417 -0
- package/dist/exchanges/pacifica-spot.d.ts +2 -2
- package/dist/exchanges/pacifica-spot.js +3 -3
- package/dist/exchanges/pacifica-typed-data.d.ts +1 -1
- package/dist/exchanges/pacifica-typed-data.js +1 -1
- package/dist/exchanges/pacifica-vaults.d.ts +121 -0
- package/dist/exchanges/pacifica-vaults.js +264 -0
- package/dist/exchanges/pacifica.d.ts +32 -5
- package/dist/exchanges/pacifica.js +114 -48
- package/dist/exchanges/precision.d.ts +3 -1
- package/dist/exchanges/precision.js +9 -2
- package/dist/exchanges/qfex/adapter.d.ts +18 -5
- package/dist/exchanges/qfex/adapter.js +32 -12
- package/dist/exchanges/qfex/agent.d.ts +1 -1
- package/dist/exchanges/qfex/agent.js +1 -1
- package/dist/exchanges/qfex/client.d.ts +1 -1
- package/dist/exchanges/qfex/client.js +1 -1
- package/dist/exchanges/qfex/errors.d.ts +1 -1
- package/dist/exchanges/qfex/errors.js +2 -2
- package/dist/exchanges/qfex/public.d.ts +3 -3
- package/dist/exchanges/qfex/public.js +3 -3
- package/dist/exchanges/qfex/signing.d.ts +2 -2
- package/dist/exchanges/qfex/signing.js +4 -5
- package/dist/exchanges/qfex/ws-transport.d.ts +2 -2
- package/dist/exchanges/qfex/ws-transport.js +3 -3
- package/dist/exchanges/rate-limiter.d.ts +1 -1
- package/dist/exchanges/rate-limiter.js +5 -2
- package/dist/exchanges/registry.d.ts +1 -1
- package/dist/exchanges/registry.js +1 -1
- package/dist/exchanges/risex/adapter.d.ts +148 -0
- package/dist/exchanges/risex/adapter.js +796 -0
- package/dist/exchanges/risex/agent.d.ts +154 -0
- package/dist/exchanges/risex/agent.js +384 -0
- package/dist/exchanges/risex/client.d.ts +47 -0
- package/dist/exchanges/risex/client.js +174 -0
- package/dist/exchanges/risex/nonce.d.ts +43 -0
- package/dist/exchanges/risex/nonce.js +212 -0
- package/dist/exchanges/risex/public.d.ts +64 -0
- package/dist/exchanges/risex/public.js +150 -0
- package/dist/exchanges/risex/session.d.ts +71 -0
- package/dist/exchanges/risex/session.js +171 -0
- package/dist/exchanges/risex/typed-data.d.ts +173 -0
- package/dist/exchanges/risex/typed-data.js +240 -0
- package/dist/exchanges/risex/units.d.ts +29 -0
- package/dist/exchanges/risex/units.js +104 -0
- package/dist/exchanges/slippage.d.ts +1 -1
- package/dist/exchanges/slippage.js +1 -1
- package/dist/exchanges/spot-factory.d.ts +3 -3
- package/dist/exchanges/spot-factory.js +7 -7
- package/dist/exchanges/spot-interface.d.ts +5 -5
- package/dist/exchanges/spot-interface.js +2 -2
- package/dist/exchanges/spot-result.d.ts +3 -3
- package/dist/exchanges/spot-result.js +3 -3
- package/dist/exchanges/trading-v2.d.ts +3 -3
- package/dist/exchanges/trading-v2.js +9 -6
- package/dist/exchanges/txflow/adapter.d.ts +54 -0
- package/dist/exchanges/txflow/adapter.js +118 -0
- package/dist/exchanges/txflow/client.d.ts +47 -0
- package/dist/exchanges/txflow/client.js +153 -0
- package/dist/exchanges/txflow/public.d.ts +76 -0
- package/dist/exchanges/txflow/public.js +284 -0
- package/dist/exchanges/unknown-symbol.d.ts +29 -0
- package/dist/exchanges/unknown-symbol.js +51 -0
- package/dist/exchanges/variational/adapter.d.ts +71 -0
- package/dist/exchanges/variational/adapter.js +137 -0
- package/dist/exchanges/variational/client.d.ts +21 -0
- package/dist/exchanges/variational/client.js +66 -0
- package/dist/exchanges/variational/public.d.ts +126 -0
- package/dist/exchanges/variational/public.js +430 -0
- package/dist/exchanges/venue-types.d.ts +6 -7
- package/dist/exchanges/venue-types.js +2 -2
- package/dist/exchanges/venue.d.ts +51 -8
- package/dist/exchanges/venue.js +54 -4
- package/dist/exchanges/venues/arcus.d.ts +1 -2
- package/dist/exchanges/venues/arcus.js +5 -4
- package/dist/exchanges/venues/aster.d.ts +2 -2
- package/dist/exchanges/venues/aster.js +6 -4
- package/dist/exchanges/venues/create-helpers.d.ts +1 -1
- package/dist/exchanges/venues/create-helpers.js +3 -3
- package/dist/exchanges/venues/extended.d.ts +21 -0
- package/dist/exchanges/venues/extended.js +96 -0
- package/dist/exchanges/venues/grvt.d.ts +30 -0
- package/dist/exchanges/venues/grvt.js +98 -0
- package/dist/exchanges/venues/hyperliquid.d.ts +2 -2
- package/dist/exchanges/venues/hyperliquid.js +10 -8
- package/dist/exchanges/venues/index.d.ts +7 -2
- package/dist/exchanges/venues/index.js +8 -2
- package/dist/exchanges/venues/lighter-family.d.ts +7 -9
- package/dist/exchanges/venues/lighter-family.js +9 -11
- package/dist/exchanges/venues/lighter-rh.d.ts +2 -2
- package/dist/exchanges/venues/lighter-rh.js +7 -5
- package/dist/exchanges/venues/lighter.d.ts +1 -1
- package/dist/exchanges/venues/lighter.js +5 -3
- package/dist/exchanges/venues/ondo.d.ts +1 -1
- package/dist/exchanges/venues/ondo.js +5 -3
- package/dist/exchanges/venues/pacifica.d.ts +2 -2
- package/dist/exchanges/venues/pacifica.js +6 -4
- package/dist/exchanges/venues/qfex.d.ts +1 -1
- package/dist/exchanges/venues/qfex.js +4 -2
- package/dist/exchanges/venues/risex-release.d.ts +14 -0
- package/dist/exchanges/venues/risex-release.js +14 -0
- package/dist/exchanges/venues/risex.d.ts +31 -0
- package/dist/exchanges/venues/risex.js +116 -0
- package/dist/exchanges/venues/txflow.d.ts +18 -0
- package/dist/exchanges/venues/txflow.js +77 -0
- package/dist/exchanges/venues/variational.d.ts +21 -0
- package/dist/exchanges/venues/variational.js +85 -0
- package/dist/execution-log.d.ts +1 -1
- package/dist/funding/legacy-public.d.ts +1 -1
- package/dist/funding/legacy-public.js +9 -4
- package/dist/funding/normalize.d.ts +1 -1
- package/dist/funding/normalize.js +1 -1
- package/dist/funding/rates.d.ts +44 -4
- package/dist/funding/rates.js +56 -12
- package/dist/index.js +7 -6
- package/dist/jobs.d.ts +1 -0
- package/dist/jobs.js +25 -1
- package/dist/landing.d.ts +2 -0
- package/dist/landing.js +1 -1
- package/dist/mcp-pacifica-earn.d.ts +9 -0
- package/dist/mcp-pacifica-earn.js +58 -0
- package/dist/mcp-server.js +113 -59
- package/dist/pacifica/client.d.ts +67 -4
- package/dist/pacifica/client.js +170 -8
- package/dist/pacifica/rate-limit.d.ts +144 -0
- package/dist/pacifica/rate-limit.js +267 -0
- package/dist/pacifica/types/order.d.ts +2 -1
- package/dist/plan-executor.js +7 -2
- package/dist/rebalance.js +1 -1
- package/dist/risk.d.ts +2 -1
- package/dist/risk.js +2 -4
- package/dist/settings.d.ts +32 -3
- package/dist/signer/ows-evm.d.ts +1 -1
- package/dist/signer/ows-evm.js +1 -1
- package/dist/smart-order.d.ts +1 -1
- package/dist/smart-order.js +1 -1
- package/dist/strategies/funding-arb.d.ts +1 -1
- package/dist/strategies/funding-arb.js +1 -1
- package/dist/trade-validator.d.ts +1 -1
- package/dist/trade-validator.js +9 -4
- package/dist/utils.d.ts +12 -3
- package/dist/utils.js +11 -3
- package/dist/venue-health.d.ts +40 -0
- package/dist/venue-health.js +75 -0
- package/dist/withdraw-gate.d.ts +1 -1
- package/dist/withdraw-gate.js +1 -1
- package/dist/ws/index.d.ts +959 -0
- package/dist/ws/index.js +4295 -0
- package/dist/ws/node.d.ts +975 -0
- package/dist/ws/node.js +4366 -0
- package/dist/ws/pacifica-instrument.d.ts +8 -0
- package/dist/ws/pacifica-instrument.js +8 -0
- package/dist/ws-cli/credentials.d.ts +62 -0
- package/dist/ws-cli/credentials.js +126 -0
- package/package.json +58 -10
- package/skills/perp-cli/SKILL.md +62 -9
- package/skills/perp-cli/references/agent-operations.md +7 -0
- package/skills/perp-cli/references/commands.md +76 -5
- package/skills/perp-cli/references/ws-library.md +492 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pacifica GET /info `instrument_type` (docs.pacifica.fi get-market-info; live: "perpetual" / "spot").
|
|
3
|
+
* The one perp rule for every Pacifica surface (WS directory, CLI adapter, funding, arb): only
|
|
4
|
+
* "perpetual" rows are perps — spot (SOL-USDC) and any other / future type are not.
|
|
5
|
+
*/
|
|
6
|
+
export declare function isPacificaPerpetual(row: {
|
|
7
|
+
instrument_type?: unknown;
|
|
8
|
+
}): boolean;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pacifica GET /info `instrument_type` (docs.pacifica.fi get-market-info; live: "perpetual" / "spot").
|
|
3
|
+
* The one perp rule for every Pacifica surface (WS directory, CLI adapter, funding, arb): only
|
|
4
|
+
* "perpetual" rows are perps — spot (SOL-USDC) and any other / future type are not.
|
|
5
|
+
*/
|
|
6
|
+
export function isPacificaPerpetual(row) {
|
|
7
|
+
return row.instrument_type === "perpetual";
|
|
8
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CredentialProvider for perp-cli/ws backed by the CLI's existing stores (plan ws-0.14.4 §5.1).
|
|
3
|
+
* Node only (not part of perp-cli/ws). Identifiers come from the active OWS wallet and the registered
|
|
4
|
+
* venue agents in ~/.perp/settings.json; the Lighter auth token is created in memory by the same path
|
|
5
|
+
* the CLI uses (agent keystore → WASM signer). Never reads argv or env, never prompts: a keystore that
|
|
6
|
+
* needs a passphrase → PASSPHRASE_REQUIRED (the stream reports WS_AUTH_FAILED). Keys never leave this
|
|
7
|
+
* module; only the short-lived token is handed to the stream.
|
|
8
|
+
*/
|
|
9
|
+
import { getAgentForNetwork } from "../agent-wallet/store.js";
|
|
10
|
+
type Network = "mainnet" | "testnet";
|
|
11
|
+
type UserRef = {
|
|
12
|
+
venue: "hyperliquid";
|
|
13
|
+
address: `0x${string}`;
|
|
14
|
+
} | {
|
|
15
|
+
venue: "pacifica";
|
|
16
|
+
account: string;
|
|
17
|
+
} | {
|
|
18
|
+
venue: "lighter" | "lighter-rh";
|
|
19
|
+
accountIndex: number;
|
|
20
|
+
} | {
|
|
21
|
+
venue: "arcus";
|
|
22
|
+
address: `0x${string}`;
|
|
23
|
+
subaccount: number | null;
|
|
24
|
+
};
|
|
25
|
+
export interface CliCredentialProvider {
|
|
26
|
+
/** Non-fatal notes about the resolved identity (e.g. Arcus all-subaccounts agent → subaccount 0). */
|
|
27
|
+
readonly warnings: string[];
|
|
28
|
+
user(): Promise<UserRef>;
|
|
29
|
+
authToken?(req: {
|
|
30
|
+
purpose: string;
|
|
31
|
+
maxTtlSec: number;
|
|
32
|
+
}): Promise<{
|
|
33
|
+
token: string;
|
|
34
|
+
expiresAt: number;
|
|
35
|
+
}>;
|
|
36
|
+
}
|
|
37
|
+
export type CliWsVenue = "hyperliquid" | "pacifica" | "lighter" | "lighter-rh" | "arcus";
|
|
38
|
+
type LighterAgentMeta = NonNullable<ReturnType<typeof getAgentForNetwork>> & {
|
|
39
|
+
accountIndex: number;
|
|
40
|
+
apiKeyIndex: number;
|
|
41
|
+
};
|
|
42
|
+
/** Mints Lighter auth tokens; holds the agent key inside its WASM signer for the provider's lifetime. */
|
|
43
|
+
export interface LighterTokenSigner {
|
|
44
|
+
createAuthToken(deadlineSec: number): Promise<string>;
|
|
45
|
+
}
|
|
46
|
+
/** Injectable for tests; the defaults are the CLI's own stores and signer. */
|
|
47
|
+
export interface CliCredentialDeps {
|
|
48
|
+
owsAddresses(): {
|
|
49
|
+
evm: string;
|
|
50
|
+
solana: string;
|
|
51
|
+
};
|
|
52
|
+
lighterAgent(venue: "lighter" | "lighter-rh", network: Network): LighterAgentMeta;
|
|
53
|
+
arcusAgent(network: Network): {
|
|
54
|
+
ownerAddress: `0x${string}`;
|
|
55
|
+
accountIndex: number;
|
|
56
|
+
} | null;
|
|
57
|
+
/** Decrypt the agent key with the empty passphrase (never prompts). */
|
|
58
|
+
loadLighterKey(venue: "lighter" | "lighter-rh", network: Network, meta: LighterAgentMeta): Promise<string>;
|
|
59
|
+
makeLighterSigner(venue: "lighter" | "lighter-rh", network: Network, meta: LighterAgentMeta, key: string): Promise<LighterTokenSigner>;
|
|
60
|
+
}
|
|
61
|
+
export declare function createCliCredentialProvider(venue: CliWsVenue, network: Network, deps?: Partial<CliCredentialDeps>): CliCredentialProvider;
|
|
62
|
+
export {};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CredentialProvider for perp-cli/ws backed by the CLI's existing stores (plan ws-0.14.4 §5.1).
|
|
3
|
+
* Node only (not part of perp-cli/ws). Identifiers come from the active OWS wallet and the registered
|
|
4
|
+
* venue agents in ~/.perp/settings.json; the Lighter auth token is created in memory by the same path
|
|
5
|
+
* the CLI uses (agent keystore → WASM signer). Never reads argv or env, never prompts: a keystore that
|
|
6
|
+
* needs a passphrase → PASSPHRASE_REQUIRED (the stream reports WS_AUTH_FAILED). Keys never leave this
|
|
7
|
+
* module; only the short-lived token is handed to the stream.
|
|
8
|
+
*/
|
|
9
|
+
import { PerpError } from "../errors.js";
|
|
10
|
+
import { loadSettings } from "../settings.js";
|
|
11
|
+
import { loadOws } from "../signer/ows-loader.js";
|
|
12
|
+
import { getAgentForNetwork, getVenueAgentForNetwork } from "../agent-wallet/store.js";
|
|
13
|
+
function activeOwsAddresses() {
|
|
14
|
+
const name = loadSettings().owsActiveWallet;
|
|
15
|
+
if (!name) {
|
|
16
|
+
throw new PerpError("NO_SIGNER_AVAILABLE", "No active OWS wallet", { remediation: "Run: perp wallet use <name>" });
|
|
17
|
+
}
|
|
18
|
+
const w = loadOws().getWallet(name);
|
|
19
|
+
const evm = w.accounts.find(a => a.chainId.startsWith("eip155:"))?.address;
|
|
20
|
+
const solana = w.accounts.find(a => a.chainId.startsWith("solana:"))?.address;
|
|
21
|
+
if (evm === undefined || solana === undefined) {
|
|
22
|
+
throw new PerpError("NO_SIGNER_AVAILABLE", `OWS wallet "${name}" has no EVM or Solana account`, { remediation: "Run: perp wallet show" });
|
|
23
|
+
}
|
|
24
|
+
return { evm, solana };
|
|
25
|
+
}
|
|
26
|
+
function lighterAgent(venue, network) {
|
|
27
|
+
const meta = getAgentForNetwork(venue, network);
|
|
28
|
+
if (!meta || typeof meta.accountIndex !== "number" || typeof meta.apiKeyIndex !== "number") {
|
|
29
|
+
throw new PerpError("AGENT_NOT_REGISTERED", `No ${venue} agent registered on ${network}`, { remediation: `Run: perp -e ${venue} wallet agent approve` });
|
|
30
|
+
}
|
|
31
|
+
return meta;
|
|
32
|
+
}
|
|
33
|
+
const DEFAULT_DEPS = {
|
|
34
|
+
owsAddresses: activeOwsAddresses,
|
|
35
|
+
lighterAgent,
|
|
36
|
+
arcusAgent: (network) => getVenueAgentForNetwork("arcus", network),
|
|
37
|
+
async loadLighterKey(venue, network, meta) {
|
|
38
|
+
const { loadLighterFamilyKey } = await import("../agent-wallet/lighter-keystore.js");
|
|
39
|
+
return loadLighterFamilyKey(venue, network, meta.accountIndex, meta.apiKeyIndex, "");
|
|
40
|
+
},
|
|
41
|
+
async makeLighterSigner(venue, network, meta, key) {
|
|
42
|
+
const { LighterAdapter } = await import("../exchanges/lighter.js");
|
|
43
|
+
const adapter = LighterAdapter.forVenue(venue, "", network === "testnet");
|
|
44
|
+
adapter.setAgentSigner(meta, key);
|
|
45
|
+
if (meta.userEvmAddress)
|
|
46
|
+
adapter.setAddress(meta.userEvmAddress);
|
|
47
|
+
await adapter.init();
|
|
48
|
+
return { createAuthToken: async (deadlineSec) => (await adapter.signer.createAuthToken(deadlineSec)).authToken };
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Keystore decrypt failures with the empty passphrase mean "this keystore has a passphrase" →
|
|
53
|
+
* PASSPHRASE_REQUIRED. Every other keystore error keeps its code with a generic message (no path,
|
|
54
|
+
* no crypto detail, no key material).
|
|
55
|
+
*/
|
|
56
|
+
function keystoreError(venue, e) {
|
|
57
|
+
const code = e instanceof PerpError ? e.structured.code : "UNKNOWN";
|
|
58
|
+
const msg = e instanceof Error ? e.message : "";
|
|
59
|
+
if (code === "SIGNATURE_FAILED" && /LIGHTER_KEYSTORE_DECRYPT_FAILED: (?!corrupt JSON|unsupported)|Keystore decrypt failed/.test(msg)) {
|
|
60
|
+
return new PerpError("PASSPHRASE_REQUIRED", `${venue} agent keystore needs a passphrase (not prompted for a stream)`, {
|
|
61
|
+
remediation: "Use a keystore without a passphrase for streaming, or pass your own CredentialProvider.authToken",
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
const remediation = e instanceof PerpError ? e.structured.remediation : undefined;
|
|
65
|
+
return new PerpError(code, `${venue} agent keystore could not be read (${code})`, remediation === undefined ? undefined : { remediation });
|
|
66
|
+
}
|
|
67
|
+
export function createCliCredentialProvider(venue, network, deps = {}) {
|
|
68
|
+
const d = { ...DEFAULT_DEPS, ...deps };
|
|
69
|
+
const warnings = [];
|
|
70
|
+
let signer = null;
|
|
71
|
+
const provider = {
|
|
72
|
+
warnings,
|
|
73
|
+
async user() {
|
|
74
|
+
switch (venue) {
|
|
75
|
+
case "hyperliquid":
|
|
76
|
+
return { venue, address: d.owsAddresses().evm };
|
|
77
|
+
case "pacifica":
|
|
78
|
+
return { venue, account: d.owsAddresses().solana };
|
|
79
|
+
case "lighter":
|
|
80
|
+
case "lighter-rh":
|
|
81
|
+
return { venue, accountIndex: d.lighterAgent(venue, network).accountIndex };
|
|
82
|
+
case "arcus": {
|
|
83
|
+
const a = d.arcusAgent(network);
|
|
84
|
+
if (a === null)
|
|
85
|
+
throw new PerpError("AGENT_NOT_REGISTERED", `No arcus agent registered on ${network}`, { remediation: "Run: perp -e arcus wallet agent approve" });
|
|
86
|
+
if (a.accountIndex === 255) {
|
|
87
|
+
// 255 = an API key for ALL subaccounts; a stream follows one account → the venue default (0).
|
|
88
|
+
const w = "arcus agent covers all subaccounts (255): streaming subaccount 0 (the venue default); pass your own CredentialProvider.user() for another subaccount";
|
|
89
|
+
if (!warnings.includes(w))
|
|
90
|
+
warnings.push(w);
|
|
91
|
+
return { venue, address: a.ownerAddress, subaccount: null };
|
|
92
|
+
}
|
|
93
|
+
return { venue, address: a.ownerAddress, subaccount: a.accountIndex };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
if (venue === "lighter" || venue === "lighter-rh") {
|
|
99
|
+
// One signer per provider: the agent key is decrypted once and lives only inside the WASM signer
|
|
100
|
+
// until the provider is dropped. A failed creation is not cached (the next call retries).
|
|
101
|
+
const getSigner = () => {
|
|
102
|
+
if (signer === null) {
|
|
103
|
+
signer = (async () => {
|
|
104
|
+
const meta = d.lighterAgent(venue, network);
|
|
105
|
+
let key;
|
|
106
|
+
try {
|
|
107
|
+
key = await d.loadLighterKey(venue, network, meta);
|
|
108
|
+
}
|
|
109
|
+
catch (e) {
|
|
110
|
+
throw keystoreError(venue, e);
|
|
111
|
+
}
|
|
112
|
+
return d.makeLighterSigner(venue, network, meta, key);
|
|
113
|
+
})();
|
|
114
|
+
signer.catch(() => { signer = null; });
|
|
115
|
+
}
|
|
116
|
+
return signer;
|
|
117
|
+
};
|
|
118
|
+
provider.authToken = async ({ maxTtlSec }) => {
|
|
119
|
+
const s = await getSigner();
|
|
120
|
+
const deadlineSec = Math.floor(Date.now() / 1000) + maxTtlSec;
|
|
121
|
+
const token = await s.createAuthToken(deadlineSec);
|
|
122
|
+
return { token, expiresAt: deadlineSec * 1000 };
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
return provider;
|
|
126
|
+
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,40 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "perp-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Multi-DEX Perpetual Futures CLI - Pacifica, Hyperliquid, Lighter, Aster, Lighter RH, Ondo Perps, Arcus",
|
|
3
|
+
"version": "0.15.0",
|
|
4
|
+
"description": "Multi-DEX Perpetual Futures CLI - Pacifica, Hyperliquid, Lighter, Aster, Lighter RH, Ondo Perps, Arcus, QFEX, RISEx (read-only), TxFlow (market data, unofficial API)",
|
|
5
5
|
"bin": {
|
|
6
6
|
"perp": "dist/index.js",
|
|
7
7
|
"perp-mcp": "dist/mcp-server.js",
|
|
8
8
|
"perp-guardrail": "dist/guardrail/perp-guardrail.js"
|
|
9
9
|
},
|
|
10
|
+
"exports": {
|
|
11
|
+
"./ws": {
|
|
12
|
+
"types": "./dist/ws/index.d.ts",
|
|
13
|
+
"import": "./dist/ws/index.js",
|
|
14
|
+
"default": "./dist/ws/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./ws/node": {
|
|
17
|
+
"types": "./dist/ws/node.d.ts",
|
|
18
|
+
"import": "./dist/ws/node.js",
|
|
19
|
+
"default": "./dist/ws/node.js"
|
|
20
|
+
},
|
|
21
|
+
"./package.json": "./package.json"
|
|
22
|
+
},
|
|
23
|
+
"typesVersions": {
|
|
24
|
+
"*": {
|
|
25
|
+
"ws": [
|
|
26
|
+
"dist/ws/index.d.ts"
|
|
27
|
+
],
|
|
28
|
+
"ws/node": [
|
|
29
|
+
"dist/ws/node.d.ts"
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"sideEffects": [
|
|
34
|
+
"./dist/index.js",
|
|
35
|
+
"./dist/mcp-server.js",
|
|
36
|
+
"./dist/guardrail/perp-guardrail.js"
|
|
37
|
+
],
|
|
10
38
|
"files": [
|
|
11
39
|
"dist",
|
|
12
40
|
"skills",
|
|
@@ -14,7 +42,7 @@
|
|
|
14
42
|
],
|
|
15
43
|
"type": "module",
|
|
16
44
|
"scripts": {
|
|
17
|
-
"build": "tsc",
|
|
45
|
+
"build": "tsc && tsup --config tsup.ws.config.ts && tsup --config tsup.perp-ws.config.ts",
|
|
18
46
|
"dev": "tsc --watch",
|
|
19
47
|
"test": "vitest run --exclude '**/integration/**'",
|
|
20
48
|
"test:integration": "vitest run -c vitest.integration.config.ts",
|
|
@@ -23,7 +51,7 @@
|
|
|
23
51
|
"e2e:typecheck": "tsc -p scripts/e2e/tsconfig.json",
|
|
24
52
|
"typecheck:test": "tsc -p tsconfig.test.json",
|
|
25
53
|
"sync-skill-version": "node scripts/sync-skill-version.mjs",
|
|
26
|
-
"prepublishOnly": "node scripts/sync-skill-version.mjs && pnpm run build"
|
|
54
|
+
"prepublishOnly": "node scripts/sync-skill-version.mjs --check && node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && pnpm run build"
|
|
27
55
|
},
|
|
28
56
|
"keywords": [
|
|
29
57
|
"pacifica",
|
|
@@ -35,6 +63,12 @@
|
|
|
35
63
|
"ondo",
|
|
36
64
|
"ondo-perps",
|
|
37
65
|
"arcus",
|
|
66
|
+
"qfex",
|
|
67
|
+
"risex",
|
|
68
|
+
"rise-chain",
|
|
69
|
+
"txflow",
|
|
70
|
+
"variational",
|
|
71
|
+
"grvt",
|
|
38
72
|
"solana",
|
|
39
73
|
"perps",
|
|
40
74
|
"dex",
|
|
@@ -55,28 +89,28 @@
|
|
|
55
89
|
"node": "^20.0.0 || ^22.0.0 || ^24.0.0"
|
|
56
90
|
},
|
|
57
91
|
"dependencies": {
|
|
58
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
92
|
+
"@modelcontextprotocol/sdk": "^1.32.1",
|
|
59
93
|
"@msgpack/msgpack": "^3.1.3",
|
|
60
94
|
"@open-wallet-standard/core": "1.3.2",
|
|
61
|
-
"@solana/web3.js": "^1.
|
|
62
|
-
"@types/react": "^19.2.14",
|
|
95
|
+
"@solana/web3.js": "^1.99.0",
|
|
63
96
|
"bs58": "^6.0.0",
|
|
64
97
|
"chalk": "^5.4.1",
|
|
65
98
|
"cli-table3": "^0.6.5",
|
|
66
99
|
"commander": "^13.1.0",
|
|
67
100
|
"dotenv": "^16.5.0",
|
|
68
|
-
"ethers": "^6.
|
|
101
|
+
"ethers": "^6.17.0",
|
|
69
102
|
"ink": "^6.8.0",
|
|
70
103
|
"ink-spinner": "^5.0.0",
|
|
71
104
|
"ink-table": "^3.1.0",
|
|
72
105
|
"react": "^19.2.4",
|
|
73
106
|
"tweetnacl": "^1.0.3",
|
|
74
|
-
"ws": "^8.
|
|
75
|
-
"yaml": "^2.
|
|
107
|
+
"ws": "^8.22.0",
|
|
108
|
+
"yaml": "^2.9.1",
|
|
76
109
|
"zod": "^4.3.6"
|
|
77
110
|
},
|
|
78
111
|
"devDependencies": {
|
|
79
112
|
"@types/node": "^25.3.3",
|
|
113
|
+
"@types/react": "^19.2.14",
|
|
80
114
|
"@types/ws": "^8.18.1",
|
|
81
115
|
"@vitest/coverage-v8": "^4.1.6",
|
|
82
116
|
"ts-morph": "^27.0.2",
|
|
@@ -84,5 +118,19 @@
|
|
|
84
118
|
"tsx": "^4.21.0",
|
|
85
119
|
"typescript": "^5.7.0",
|
|
86
120
|
"vitest": "^4.1.6"
|
|
121
|
+
},
|
|
122
|
+
"pnpm": {
|
|
123
|
+
"overrides": {
|
|
124
|
+
"hono@<4.13.7": "^4.13.13",
|
|
125
|
+
"@hono/node-server@<1.19.15": "^1.19.15",
|
|
126
|
+
"fast-uri@<3.1.8": "^3.1.8",
|
|
127
|
+
"proxy-addr@<2.0.8": "^2.0.8",
|
|
128
|
+
"path-to-regexp@>=8.0.0 <8.4.0": "^8.4.2",
|
|
129
|
+
"ip-address@<=10.7.0": "^10.7.4",
|
|
130
|
+
"qs@<6.16.0": "^6.16.0",
|
|
131
|
+
"body-parser@>=2.0.0 <2.3.0": "^2.3.0",
|
|
132
|
+
"ws@>=7.0.0 <7.5.11": "^7.5.13",
|
|
133
|
+
"uuid@>=11.0.0 <11.1.1": "^11.1.1"
|
|
134
|
+
}
|
|
87
135
|
}
|
|
88
136
|
}
|
package/skills/perp-cli/SKILL.md
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: perp-cli
|
|
3
|
-
description: "Multi-DEX perpetual futures trading via the perp-cli command-line tool. Use when user asks to: trade perps, check funding rates, scan/execute arbitrage (perp-perp or spot-perp), run delta-neutral strategies, bridge USDC across chains, manage positions/orders/leverage, deposit/withdraw, hedge spot+perp, trade HIP-3 DEXes, or mentions perp-cli, hypurrquant, Pacifica, Hyperliquid, Lighter, Aster, Lighter RH, Ondo Perps, Arcus, HyperEVM, funding arb, or U-tokens (UBTC/UETH/USOL). Covers Pacifica (Solana), Hyperliquid (HyperEVM), Lighter (Ethereum), Aster (BNB Chain), Lighter RH and Arcus (Robinhood chain)
|
|
3
|
+
description: "Multi-DEX perpetual futures trading via the perp-cli command-line tool. Use when user asks to: trade perps, check funding rates, scan/execute arbitrage (perp-perp or spot-perp), run delta-neutral strategies, bridge USDC across chains, manage positions/orders/leverage, deposit/withdraw, hedge spot+perp, trade HIP-3 DEXes, or mentions perp-cli, hypurrquant, Pacifica, Hyperliquid, Lighter, Aster, Lighter RH, Ondo Perps, Arcus, QFEX, RISEx, TxFlow, Variational, GRVT, HyperEVM, funding arb, or U-tokens (UBTC/UETH/USOL). Covers Pacifica (Solana), Hyperliquid (HyperEVM), Lighter (Ethereum), Aster (BNB Chain), Lighter RH and Arcus (Robinhood chain), Ondo Perps and QFEX (off-chain), RISEx (RISE chain), TxFlow (market data only, UNOFFICIAL API) Variational Omni (market data only, official API) and GRVT (market data only for now, official API)."
|
|
4
4
|
license: MIT
|
|
5
5
|
allowed-tools: "Bash(perp:*), Bash(npx -y perp-cli:*), Bash(bash scripts/preflight.sh:*), Bash(bash scripts/arb-monitor.sh:*), Bash(bash scripts/funding-analysis.sh:*), Bash(bash scripts/spot-perp-scan.sh:*), Bash(bash scripts/validate-arb.sh:*)"
|
|
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.
|
|
9
|
+
version: "0.15.0"
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
# perp-cli
|
|
13
13
|
|
|
14
|
-
Multi-DEX perpetual futures CLI + MCP server for Pacifica (Solana), Hyperliquid (HyperEVM), Lighter (Ethereum), Aster (BNB Chain), Lighter RH (`lighter-rh`, Robinhood chain, USDG), Ondo Perps (`ondo`), QFEX (`qfex`, custodial TradFi perps — import-only API key; resting reduce-only limits and automation are refused for now, see "QFEX" below), Arcus (`arcus`, Robinhood chain, USDG). v0.13.0+ also supports Hyperliquid Outcome markets (HIP-4) — fully-collateralized binary/range contracts; each outcome's quote token comes from `outcomeMeta.quoteToken` (USDC on every listed outcome as of 2026-10-12), minimum order value 10 quote tokens.
|
|
14
|
+
Multi-DEX perpetual futures CLI + MCP server for Pacifica (Solana), Hyperliquid (HyperEVM), Lighter (Ethereum), Aster (BNB Chain), Lighter RH (`lighter-rh`, Robinhood chain, USDG), Ondo Perps (`ondo`), QFEX (`qfex`, custodial TradFi perps — import-only API key; resting reduce-only limits and automation are refused for now, see "QFEX" below), Arcus (`arcus`, Robinhood chain, USDG), RISEx (`risex|rise`, RISE chain, USDC — READ-ONLY in this release: market data + account reads; trading is planned for a later perp-cli release, see "RISEx" below), TxFlow (`txflow|txf`, MARKET DATA ONLY through an UNOFFICIAL API — no official API exists; it may break without notice, see "TxFlow" below), Variational Omni (`variational|var|omni`, MARKET DATA ONLY through its official read-only API — RFQ venue, no public trading API yet, see "Variational" below), GRVT (`grvt|grv`, MARKET DATA ONLY in this version through its official API — trading is planned for a later release, see "GRVT" below), Extended (`extended|ext|x10`, Starknet, formerly X10 — MARKET DATA ONLY in this version through its official public API, see "Extended" below). v0.13.0+ also supports Hyperliquid Outcome markets (HIP-4) — fully-collateralized binary/range contracts; each outcome's quote token comes from `outcomeMeta.quoteToken` (USDC on every listed outcome as of 2026-10-12), minimum order value 10 quote tokens.
|
|
15
15
|
|
|
16
16
|
## Instructions
|
|
17
17
|
|
|
@@ -25,9 +25,10 @@ Activate whenever the user wants to do anything against perp-cli, including: sca
|
|
|
25
25
|
|
|
26
26
|
This skill uses progressive disclosure. Read these on demand:
|
|
27
27
|
|
|
28
|
-
- `references/commands.md` — full command tree for every group (market, account, trade, outcome, arb, funds, wallet, risk, history, strategy, background, alerts, settings, backtest)
|
|
28
|
+
- `references/commands.md` — full command tree for every group (market, account, trade, outcome, options, print, vault, arb, funds, wallet, risk, history, strategy, background, alerts, settings, backtest)
|
|
29
29
|
- `references/agent-operations.md` — non-interactive setup flows, idempotency rules, error codes, common mistakes
|
|
30
30
|
- `references/strategies.md` — funding-arb decision framework + risk-management playbook (read before designing arb strategy)
|
|
31
|
+
- `references/ws-library.md` — WebSocket library (0.15.0, @experimental), published standalone as **`@hypurrquant/perp-ws`** (zero dependencies; recommended for integrators — `npm install @hypurrquant/perp-ws`) and inside perp-cli as `perp-cli/ws` (same code, use it when perp-cli is already installed): build a live dashboard / funding comparison / account feed in the browser or Node (streams, events, nullability, comparator, user channels, errors, capability matrix). Cross-venue subscriptions use `canonicals` (e.g. `{ kind: "allMarkets", canonicals: ["BTC"] }`), never `symbols` (those are per-venue directory symbols); always surface `ready` rejections — an `idle` venue is not "fine"
|
|
31
32
|
|
|
32
33
|
Also bundled under `scripts/`: `preflight.sh`, `arb-monitor.sh`, `funding-analysis.sh`, `spot-perp-scan.sh`, `validate-arb.sh`. Use these for repeatable multi-step diagnostics.
|
|
33
34
|
|
|
@@ -46,7 +47,7 @@ Also bundled under `scripts/`: `preflight.sh`, `arb-monitor.sh`, `funding-analys
|
|
|
46
47
|
### Step 1: Verify install + version
|
|
47
48
|
|
|
48
49
|
```bash
|
|
49
|
-
perp --version 2>/dev/null || npx -y perp-cli@latest --version # must be >= 0.
|
|
50
|
+
perp --version 2>/dev/null || npx -y perp-cli@latest --version # must be >= 0.15.0
|
|
50
51
|
```
|
|
51
52
|
|
|
52
53
|
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`.
|
|
@@ -96,6 +97,37 @@ Imported keys trade; `funds deposit|withdraw|transfer|bridge`, `wallet manage re
|
|
|
96
97
|
- Funding rates on QFEX are unverified: excluded everywhere unless `perp --json arb scan --rates --include-unverified` (display only).
|
|
97
98
|
- 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
99
|
|
|
100
|
+
**RISEx** (`-e risex`, testnet = `-n testnet`, official API): **READ-ONLY in this perp-cli release** — RISEx trading is planned for a later release. Rules an agent must follow:
|
|
101
|
+
- Works: market data (`market list|prices|info|book|trades|kline|funding -e risex`), `perp health`, RISEx rows in `perp --json arb scan` / `arb scan --rates` (funding is hourly and verified), MCP market-data tools, and account reads with only the master address selected (`portfolio`, `account positions|orders|history|trades|funding-history -e risex` — public by address, nothing is signed). `wallet agent verify risex` (read-only) still checks a signer registered by an earlier build.
|
|
102
|
+
- Refused with `CAPABILITY_UNSUPPORTED` ("RISEx trading is planned for a later perp-cli release; in this version RISEx is read-only") before any key is read or request is sent — also under `--dry-run`: every `trade …` write (market / buy / sell / limit / cancel / cancel-all / leverage / close / stop / tpsl / edit / twap / …), `trade multi` legs, `arb exec|auto` legs, every `strategy …` command (bots, plans, TWAP / grid / DCA, `--exchanges` legs), `wallet agent approve|import|revoke|rotate risex` (`revoke --force` only clears the local record), `perp setup --venues risex`, `funds faucet risex`, and the MCP `trade_preview` / `trade_execute` / `trade_close` tools. Never try to trade RISEx through perp-cli — the user trades in app.rise.trade. `arb scan --basis` lists trading venues only, so RISEx is not in it; in `arb scan` a pair with a RISEx leg is `executable: false` (`readOnlyLegs`) — data only.
|
|
103
|
+
- Deposits and withdrawals are app-only: `funds deposit|withdraw risex` → `CAPABILITY_UNSUPPORTED` (also under `--dry-run`), remediation app.rise.trade.
|
|
104
|
+
- Funding: hourly, `current_funding_rate` = the last settled hourly print (verified against funding payments).
|
|
105
|
+
|
|
106
|
+
**TxFlow** (`-e txflow`): UNOFFICIAL — TxFlow has no official API; perp-cli reads the undocumented API its web app uses, READ-ONLY. It may change or be blocked at any time; every JSON row says `venueApi: "unofficial"` (`apiStatus` in mixed tables, MCP meta), human output carries a footnote. Rules an agent must follow:
|
|
107
|
+
- Works: `market list|prices|info|book|trades|kline -e txflow`, and TxFlow rows in `perp --json arb scan --rates --include-unverified` (display only). Funding is percent per hour on the venue, shown as a FRACTION per hour, and is UNVERIFIED (a live estimate) — never rank or trade on it.
|
|
108
|
+
- Refused with `CAPABILITY_UNSUPPORTED` before any request: every trade / account / portfolio / funds / agent / builder / bot command, and funding history (`market funding`). Never try to trade TxFlow through perp-cli; the user trades on the TxFlow website.
|
|
109
|
+
- A blocked read (`EXCHANGE_ERROR` "unofficial API refused …") is not retried and has no fallback; there is no testnet.
|
|
110
|
+
|
|
111
|
+
**Variational** (`-e variational`, aliases `var`, `omni`): Variational Omni, read-only (market data) in perp-cli through its OFFICIAL documented API (`GET /metadata/v2/stats`, one call for all ~575 markets, cached ~5 s; venue limit 10 requests / 10 s per IP). Variational has no public trading API yet. It is an RFQ venue: one market maker (the OLP) quotes every trade — there is no order book.
|
|
112
|
+
- Works: `market list|prices|info|funding|book -e variational`, `perp health` (official), and Variational rows in `perp --json arb scan --rates --include-unverified` / `--compare <sym> --include-unverified` only — display only, never ranked or traded: funding is UNVERIFIED (a moving predicted rate, not checked against settled payments). `US500-PERP` is the SPDR S&P 500 ETF, compared as `SPY`; SPX (SPX6900) and QNT (Quant) are never matched.
|
|
113
|
+
- `market book` shows the OLP's INDICATIVE RFQ quotes at fixed notionals (min order, $1k, $100k, $1M when published; `kind: "rfqQuotes"`), never order-book levels; they may be up to 600 s old (`updatedAt`). `market mid|trades|kline` are refused (`CAPABILITY_UNSUPPORTED`).
|
|
114
|
+
- Funding: the interval is PER MARKET (1h / 4h / 8h perps; `fundingHours` on each row), positive = longs pay. `fundingRate` is the fraction for one interval; `market funding <sym>` shows the current terms (`kind: "currentFunding"`: per interval, hourly, APR %, next time) — there is no funding history. `rateKind` is `predicted`: the rate for the window ending at `nextFundingTime`, recomputed during the window.
|
|
115
|
+
- Perp symbols are the base (`BTC`); swaps keep their suffix (`XAU-SWAP`): daily-funded TradFi swaps with separate long / short rates, `fundingRate` null and never matched across venues. Open interest is published in USD, single-sided (`openInterestUsd`); base-unit `openInterest` is null. No index price, tick, lot or leverage is published (null).
|
|
116
|
+
- Refused with `CAPABILITY_UNSUPPORTED` before any request: every trade / account / portfolio / funds / agent / builder / bot command (also with `--dry-run`). The user trades on omni.variational.io. No testnet. Variational's terms exclude US / Canada persons and sanctioned regions (perp-cli only warns).
|
|
117
|
+
|
|
118
|
+
**GRVT** (`-e grvt`, testnet = `-n testnet`): official Market Data API (api-docs.grvt.io), READ-ONLY in this version. Rules an agent must follow:
|
|
119
|
+
- Works: `market list|prices|info|book|trades|funding|kline -e grvt`, `perp health` (counted among the official venues), and GRVT rows in `perp --json arb scan --rates --include-unverified` (display only).
|
|
120
|
+
- Symbols are the base ticker (`BTC`, `KPEPE`, `XAU`, `AAPL`; `BTC_USDT_Perp` also accepted); `venueSymbol` is GRVT's instrument name. Unknown symbols → `SYMBOL_NOT_FOUND`. Pre-IPO markets (OPENAI, ANTHROPIC, SPACEX) are never matched across venues.
|
|
121
|
+
- Funding interval is PER MARKET (8 h or 4 h — `fundingHours`); rates are fractions per that interval (GRVT publishes percent). `market list|prices|info` rows carry the INDICATIVE rate of the running interval (`fundingRateKind: "predicted"`, moves until `nextFundingTime`); `market funding` is the settled history (`rateKind: "lastSettled"`, `intervalHours` per row). Funding is UNVERIFIED (not yet checked against settled payments) — never rank or trade on it.
|
|
122
|
+
- `stepSize` is null (GRVT publishes a minimum size, `minSize`, but no lot step); `maxLeverage` / `marginTiers` come from GRVT's margin rules and are filled by `market list|prices|info` only (cached up to 6 h — `leverageAsOf` says when they were read) — MCP `get_markets` / `get_prices` rows have them null (price-only path). Equities match other venues only when reviewed; an unreviewed new GRVT equity has `canonical: null`.
|
|
123
|
+
- Refused with `CAPABILITY_UNSUPPORTED` before any request (also under `--dry-run`): every trade / account / portfolio / funds / agent / builder / bot command and `setup` venue selection — remediation "GRVT is read-only (market data) in this version; trading is planned for a later release". GRVT trading needs KYC and is banned in restricted jurisdictions (US, CA, SG, HK, …) — relevant once trading lands.
|
|
124
|
+
|
|
125
|
+
**Extended** (`-e extended`, aliases `ext` / `x10`; testnet = Sepolia via `-n testnet`): official public API (api.docs.extended.exchange), READ-ONLY in this version — counted as an official venue in `perp health`. Rules an agent must follow:
|
|
126
|
+
- Works: `market list|prices|info|book|trades|funding|kline -e extended`, and Extended rows in `perp --json arb scan --rates --include-unverified` (display only — funding is UNVERIFIED: never rank or trade on it). `market list` rows carry `assetClass` (crypto / equity / etf / index / commodity / fx / preIpo; human table "Class" column), `venueSymbol` (wire name, e.g. `TSLA_24_5-USD`), `tickSize`, `minSize`, `tradable` (false while `REDUCE_ONLY` or `isOffHours`), `isRfq`, `tradingHours`.
|
|
127
|
+
- Symbols: `assetName` without the `_24_5` suffix (`TSLA_24_5-USD` → `TSLA`, `SPX500m-USD` → `SPX500M`); `-e extended market book TSLA-USD` and the wire name also resolve. The crypto `SPX` market is SPX6900, not the S&P 500 (index = `SPX500M`). RWA tickers that are also crypto tickers (PURR = Hyperliquid Strategies Inc., QNT, BB, ON, ADI, BOT), XIAOMI and the crypto SPX are never matched across venues.
|
|
128
|
+
- Funding: applied hourly; `fundingRate` in market rows = the current hour's ACCRUING rate (fraction per hour, recomputed every minute, rounded to 6 decimals; `fundingRateKind: "accruing"`, `nextFundingTime`), `market funding` = applied hourly prints (`rateKind: "lastSettled"`, `annualizedPct`). `_24_5` equities print 0 while their underlying is closed (weekends / holidays), so an annualized rate overstates them.
|
|
129
|
+
- Refused with `CAPABILITY_UNSUPPORTED` before any request ("Extended is read-only (market data) in this version; trading is planned for a later release"): every trade / account / portfolio / funds / agent / builder / bot command, also under `--dry-run`. RFQ markets' REST order book is the indicative book.
|
|
130
|
+
|
|
99
131
|
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
132
|
|
|
101
133
|
### Step 3: Discover (read-only)
|
|
@@ -133,6 +165,18 @@ perp --json -e hyperliquid --dex xyz --dry-run trade market GOLD buy 0.01
|
|
|
133
165
|
- `portfolio --dexes xyz,…` adds HIP-3 dex balances; builder fees are never attached on HIP-3.
|
|
134
166
|
- MCP tools cover native Hyperliquid perps only — use the CLI for HIP-3.
|
|
135
167
|
|
|
168
|
+
#### Options market data (Derive, read-only)
|
|
169
|
+
|
|
170
|
+
Derive (derive.xyz) options via the official public API — keyless, never trades. Not a perp venue (`-e derive` works only with `perp options`).
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
perp --json -e derive options expiries ETH # active expiries
|
|
174
|
+
perp --json -e derive options chain ETH --expiry 2026-12-25 --strikes 10 # calls/puts per strike: bid/ask, mark, IV, greeks, OI
|
|
175
|
+
perp --json -e derive options quote ETH-20261225-3500-P # one option
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
`schema: 1`; decimals are strings; `null` = unknown (empty side, uncomputable IV). Unknown underlying / expiry / instrument → `SYMBOL_NOT_FOUND`. Full reference: `references/commands.md` → "Options market data".
|
|
179
|
+
|
|
136
180
|
### Step 4: Validate before mutating
|
|
137
181
|
|
|
138
182
|
For arb:
|
|
@@ -153,6 +197,8 @@ perp --json --dry-run -e <ex> trade buy <SYM> <SIZE> --smart
|
|
|
153
197
|
> `trade check` does NOT read exchange-set leverage. Always pass `--leverage` explicitly.
|
|
154
198
|
>
|
|
155
199
|
> `--smart` (IOC at best bid/ask ± 1 tick) exists only on pacifica / hyperliquid / lighter / aster, and is refused (`CAPABILITY_UNSUPPORTED`) together with `--tp`/`--sl` or `--client-id`/`--auto-id`.
|
|
200
|
+
>
|
|
201
|
+
> Pacifica basket (pair trade): `perp --json --dry-run -e pacifica trade atomic --long BTC:50 --short ETH:50 --usd 1000` — one batch of market orders, NOT all-or-nothing (a leg can fill while another is refused → `ORDER_PARTIAL`; an unconfirmed leg → `ORDER_PENDING` + quarantine). A batch failure other than HTTP 400 / 429 quarantines every leg. Pacifica's Chase / OCO / Trailing Stop / Swarm / Trigger Swarm / Conditional orders have no documented API / SDK path (as of 2026-10-19); nearest here: `trade twap` (≈ Swarm) and `trade tpsl` (≈ OCO bracket exit).
|
|
156
202
|
|
|
157
203
|
Show the dry-run output to the user. Wait for confirmation.
|
|
158
204
|
|
|
@@ -207,6 +253,13 @@ perp --json -e <ex> trade close-all # close all posi
|
|
|
207
253
|
perp --json -e <ex> trade flatten # close ALL + cancel ALL orders
|
|
208
254
|
```
|
|
209
255
|
|
|
256
|
+
### Pacifica Print and vaults (`perp print`, `perp vault`)
|
|
257
|
+
|
|
258
|
+
Pacifica-only, details in `references/commands.md`. Reads first (`print games`, `print quote`, `print positions`, `vault list|info|positions`); every write is `--dry-run` first and needs the user's confirmation:
|
|
259
|
+
- **Print** (`print deposit <game> long|short <usd> --strike <px> --leverage <n> [--cycles 1-1000]`) locks the deposit until a fill or until a cancel settles at the END of the running cycle (up to 30 days on `BTC_1M`). Before asking, show the user: cycle length, `--cycles`, leverage, `maxLoss` (deposit + premiums), and that `docsLiquidationPrice` is only an outer bound (a liquidation was observed earlier in one live case; the venue trigger is unpublished). Checkpoint-only evaluation applies while resting; after a fill it is an ordinary position in the main account (continuous liquidation, nets with an existing position) — `account positions`. The premium is not quoted by perp-cli. `print cancel` uses an UNOFFICIAL endpoint: live runs need `--unverified-endpoint`.
|
|
260
|
+
- **Vaults** (`vault deposit <vault> <usd>`, `vault withdraw <vault> <shares>|--all`): third-party trading pools (can lose the whole deposit); every deposit restarts the lock-up for the whole balance; withdrawals only go to the own account, inside the vault's window. **`vault deposit` is master-only** (never an agent key). Pass the vault ADDRESS and confirm the shown manager with the user — nicknames are not unique (an ambiguous one is refused with the candidates).
|
|
261
|
+
- `ORDER_PENDING` on any of them → NEVER resubmit with a new key; check `print positions` / `vault positions` against `error.details.before`. The only safe retry is the same command with `--idempotency-key <reported key>` (dedupe window unverified).
|
|
262
|
+
|
|
210
263
|
### Funds workflow (deposit / withdraw / transfer / bridge / rebalance)
|
|
211
264
|
|
|
212
265
|
All money movement lives under `perp funds`:
|
|
@@ -367,7 +420,7 @@ Every response is `{ "ok": true, "data": ... }` or `{ "ok": false, "error": { "c
|
|
|
367
420
|
| `PASSPHRASE_REQUIRED` | Vault passphrase needed | Ask the user to provide `OWS_PASSPHRASE` (or stdin); never put it on argv. |
|
|
368
421
|
| `LOCK_HELD` | Another perp process holds a state lock | Wait ~5s and retry once; check `background list`. |
|
|
369
422
|
| `NO_BRIDGE_ROUTE` | No supported bridge route (e.g. deBridge from Solana, HyperCore → Solana) | Use the route in `remediation` (e.g. `--provider cctp`). |
|
|
370
|
-
| `RATE_LIMITED` / `EXCHANGE_UNREACHABLE` | Throttled / API down (reads) | Wait 5–10s, retry once; then skip that venue. |
|
|
423
|
+
| `RATE_LIMITED` / `EXCHANGE_UNREACHABLE` | Throttled / API down (reads) | Wait 5–10s (or `retryAfterMs` when present — Pacifica sets it from its credit headers), retry once; then skip that venue. |
|
|
371
424
|
| `INSUFFICIENT_BALANCE` | Not enough collateral on that venue | Reduce size or move funds first (user-confirmed). |
|
|
372
425
|
| `SYMBOL_NOT_FOUND` | Not listed on this venue | `market list`. Don't add `-PERP`. |
|
|
373
426
|
| `SIZE_TOO_SMALL` | Below venue minimum (HL TWAP: $100 total) | Compute `size × price`; raise size. |
|
|
@@ -377,8 +430,8 @@ Every response is `{ "ok": true, "data": ... }` or `{ "ok": false, "error": { "c
|
|
|
377
430
|
## Safety rules
|
|
378
431
|
|
|
379
432
|
- **Unknown outcome (`ORDER_PENDING`) on ANY write** — orders, cancels, edits, leverage, withdraw / deposit / bridge / transfer: do NOT resubmit. Check `perp --json -e <ex> trade status c:<id> --symbol <S>` (the id in `remediation`), `account orders` / `account positions` / `portfolio`, and the tx hash / request id in `error.details` (`funds bridge status <id>` for bridges). Report to the user.
|
|
380
|
-
- **Quarantine**: an unknown or unhedged outcome (arb, bots, `trade close`, `trade multi`) quarantines the symbol — global per symbol, scoped by network. It blocks opening orders, `arb exec`, `arb auto` and bots (`RISK_VIOLATION`); reduce-only orders pass. List: `perp --json strategy quarantine`. Clear only after the USER has verified the positions on the venues: `perp --json strategy quarantine-clear <SYM>`. `arb close` on a quarantined symbol needs `--force`.
|
|
381
|
-
- **Risk gate**: `trade market / buy / sell / limit / split / market --split / scale-in / twap / multi / stop --no-reduce-only` check `~/.perp/risk.json` (`perp risk limits ...`); reduce-only is exempt. `--force` bypasses the limits (never quarantine) — only with explicit user consent.
|
|
433
|
+
- **Quarantine**: an unknown or unhedged outcome (arb, bots, `trade close`, `trade multi`, `trade atomic`) quarantines the symbol — global per symbol, scoped by network. It blocks opening orders, `arb exec`, `arb auto` and bots (`RISK_VIOLATION`); reduce-only orders pass. List: `perp --json strategy quarantine`. Clear only after the USER has verified the positions on the venues: `perp --json strategy quarantine-clear <SYM>`. `arb close` on a quarantined symbol needs `--force`.
|
|
434
|
+
- **Risk gate**: `trade market / buy / sell / limit / split / market --split / scale-in / twap / multi / atomic / stop --no-reduce-only` check `~/.perp/risk.json` (`perp risk limits ...`); reduce-only is exempt. `--force` bypasses the limits (never quarantine) — only with explicit user consent.
|
|
382
435
|
- **Stops** (`trade stop`, `tpsl`) are reduce-only by default; `--no-reduce-only` is refused on ondo and qfex. `trade tpsl <SYM> long|short` = the OPEN position's side; legs are sized to the live position.
|
|
383
436
|
- **Dry-run is default-deny**: commands that cannot simulate refuse `--dry-run` with `INVALID_PARAMS` (e.g. `trade twap`, `trade multi`, `trade cancel-stop`, `trade cancel-twap`, `strategy start / preset / grid / dca / quick-* / funding-arb`, `wallet agent approve`, `wallet rotate`). Simulate bots with `perp --json --dry-run strategy run <strategy>` / `perp --json --dry-run arb auto`.
|
|
384
437
|
- **A dry-run is not a full venue check**: it validates arguments, the risk gate and quarantine, but some venue rules are enforced only on the live send — e.g. an off-grid limit price (`INVALID_TICK`) or `--no-reduce-only` on ondo / qfex (`CAPABILITY_UNSUPPORTED`). Those refusals happen before anything is sent.
|
|
@@ -422,7 +475,7 @@ qfex: `builder.qfex <uuid>` is a fee share (no extra fee, no approval; mainnet o
|
|
|
422
475
|
|
|
423
476
|
## MCP Server
|
|
424
477
|
|
|
425
|
-
The package also ships a
|
|
478
|
+
The package also ships a 29-tool MCP server (no API keys required for read-only market data — `get_markets`, `get_orderbook`, `get_funding_rates`, `get_prices`, `get_outcome_markets`, `get_outcome_view`, `get_outcome_book`, `get_option_expiries`, `get_option_chain`, `get_option_quote` (Derive options), the read-only Pacifica Print / vault tools `pacifica_print_products`, `pacifica_print_quote`, `pacifica_print_positions`, `pacifica_vaults`, plus 15 account/advisor tools):
|
|
426
479
|
|
|
427
480
|
MCP network: `PERP_NETWORK=mainnet|testnet` (validated; unset = mainnet); every result's `meta.network` says which. The only write tools, `trade_execute` / `trade_close`, run the same local risk gate as `perp trade` (no override over MCP), refuse non-reduce-only orders on quarantined symbols, and log every order.
|
|
428
481
|
|
|
@@ -141,6 +141,11 @@ printf '%s' "$KEY" | OWS_PASSPHRASE=<pp> perp --json wallet set hl
|
|
|
141
141
|
| `ondo` \| `ondo-perps` | off-chain (USDC deposits from Arbitrum / Ethereum) | API key id + secret (stdin) |
|
|
142
142
|
| `arcus` | Robinhood Chain (USDG) | Ed25519 API key (`wallet agent approve arcus --master <w>` / `import`) |
|
|
143
143
|
| `qfex` \| `qf` | custodial (USDC on Arbitrum One) | website key, imported by the user only (`wallet agent import qfex`) |
|
|
144
|
+
| `risex` \| `rise` | RISE chain (USDC; deposit / withdraw in the RISEx app only) | none for market data; master address only for account reads. READ-ONLY in this release: trading is planned for a later release — every trade / agent / bot write → `CAPABILITY_UNSUPPORTED` |
|
|
145
|
+
| `txflow` \| `txf` | — | none: MARKET DATA ONLY through an UNOFFICIAL API (every write → `CAPABILITY_UNSUPPORTED`) |
|
|
146
|
+
| `variational` \| `var` \| `omni` | — | none: MARKET DATA ONLY through the official read-only API; no public trading API yet (every write → `CAPABILITY_UNSUPPORTED`) |
|
|
147
|
+
| `grvt` \| `grv` | — (USDT; off-chain matching) | none: MARKET DATA ONLY in this version, official API (every write → `CAPABILITY_UNSUPPORTED`; trading planned) |
|
|
148
|
+
| `extended` \| `ext` \| `x10` | Starknet | none: MARKET DATA ONLY in this version, official API (every write → `CAPABILITY_UNSUPPORTED`; trading planned) |
|
|
144
149
|
|
|
145
150
|
Default `-e` = `settings.defaultExchange`, else `pacifica` — always pass `-e`.
|
|
146
151
|
|
|
@@ -168,6 +173,8 @@ perp --json funds deposit lighter ethereum 100 # L1 direct (min 1 USDC)
|
|
|
168
173
|
perp --json funds deposit lighter cctp arbitrum 100 # via CCTP from Arbitrum (min 5 USDC)
|
|
169
174
|
```
|
|
170
175
|
|
|
176
|
+
RISEx: deposits are app-only (`funds deposit risex` → `CAPABILITY_UNSUPPORTED`, remediation app.rise.trade). RISEx is read-only in this release (trading in a later release), so `funds faucet risex` is refused too.
|
|
177
|
+
|
|
171
178
|
### Withdraw from Exchange (`funds withdraw`)
|
|
172
179
|
```bash
|
|
173
180
|
perp --json --dry-run funds withdraw hyperliquid 100 # plan first (every withdraw supports --dry-run)
|