perp-cli 0.3.3
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/LICENSE +21 -0
- package/README.md +293 -0
- package/dist/__tests__/alert-logic.test.d.ts +1 -0
- package/dist/__tests__/alert-logic.test.js +107 -0
- package/dist/__tests__/arb-auto-3dex.test.d.ts +1 -0
- package/dist/__tests__/arb-auto-3dex.test.js +397 -0
- package/dist/__tests__/arb-history-stats.test.d.ts +1 -0
- package/dist/__tests__/arb-history-stats.test.js +176 -0
- package/dist/__tests__/arb-logic.test.d.ts +1 -0
- package/dist/__tests__/arb-logic.test.js +84 -0
- package/dist/__tests__/arb-manage.test.d.ts +1 -0
- package/dist/__tests__/arb-manage.test.js +253 -0
- package/dist/__tests__/arb-new-features.test.d.ts +1 -0
- package/dist/__tests__/arb-new-features.test.js +457 -0
- package/dist/__tests__/arb-sizing.test.d.ts +1 -0
- package/dist/__tests__/arb-sizing.test.js +48 -0
- package/dist/__tests__/arb-state.test.d.ts +1 -0
- package/dist/__tests__/arb-state.test.js +284 -0
- package/dist/__tests__/arb-userflow.test.d.ts +1 -0
- package/dist/__tests__/arb-userflow.test.js +945 -0
- package/dist/__tests__/arb-utils.test.d.ts +1 -0
- package/dist/__tests__/arb-utils.test.js +264 -0
- package/dist/__tests__/bot-conditions.test.d.ts +1 -0
- package/dist/__tests__/bot-conditions.test.js +341 -0
- package/dist/__tests__/client-id-tracker.test.d.ts +1 -0
- package/dist/__tests__/client-id-tracker.test.js +137 -0
- package/dist/__tests__/commands/new-atomic-commands.test.d.ts +1 -0
- package/dist/__tests__/commands/new-atomic-commands.test.js +502 -0
- package/dist/__tests__/commands/order-intent.test.d.ts +1 -0
- package/dist/__tests__/commands/order-intent.test.js +600 -0
- package/dist/__tests__/commands/trade-commands.test.d.ts +1 -0
- package/dist/__tests__/commands/trade-commands.test.js +821 -0
- package/dist/__tests__/config.test.d.ts +1 -0
- package/dist/__tests__/config.test.js +86 -0
- package/dist/__tests__/cross-chain-margin.test.d.ts +1 -0
- package/dist/__tests__/cross-chain-margin.test.js +287 -0
- package/dist/__tests__/dex-asset-map.test.d.ts +1 -0
- package/dist/__tests__/dex-asset-map.test.js +191 -0
- package/dist/__tests__/errors.test.d.ts +1 -0
- package/dist/__tests__/errors.test.js +110 -0
- package/dist/__tests__/event-stream.test.d.ts +1 -0
- package/dist/__tests__/event-stream.test.js +276 -0
- package/dist/__tests__/exchanges/interface.test.d.ts +1 -0
- package/dist/__tests__/exchanges/interface.test.js +132 -0
- package/dist/__tests__/exchanges/mock-adapter.d.ts +69 -0
- package/dist/__tests__/exchanges/mock-adapter.js +137 -0
- package/dist/__tests__/execution-log.test.d.ts +1 -0
- package/dist/__tests__/execution-log.test.js +106 -0
- package/dist/__tests__/funding-calc.test.d.ts +1 -0
- package/dist/__tests__/funding-calc.test.js +71 -0
- package/dist/__tests__/funding-history.test.d.ts +1 -0
- package/dist/__tests__/funding-history.test.js +343 -0
- package/dist/__tests__/funding-rates.test.d.ts +1 -0
- package/dist/__tests__/funding-rates.test.js +342 -0
- package/dist/__tests__/funding.test.d.ts +1 -0
- package/dist/__tests__/funding.test.js +173 -0
- package/dist/__tests__/gap-logic.test.d.ts +1 -0
- package/dist/__tests__/gap-logic.test.js +43 -0
- package/dist/__tests__/hip3-dex.test.d.ts +1 -0
- package/dist/__tests__/hip3-dex.test.js +234 -0
- package/dist/__tests__/integration/agent-features.integration.test.d.ts +1 -0
- package/dist/__tests__/integration/agent-features.integration.test.js +553 -0
- package/dist/__tests__/integration/atomic-commands.integration.test.d.ts +13 -0
- package/dist/__tests__/integration/atomic-commands.integration.test.js +246 -0
- package/dist/__tests__/integration/bridge-simulation.integration.test.d.ts +1 -0
- package/dist/__tests__/integration/bridge-simulation.integration.test.js +453 -0
- package/dist/__tests__/integration/bridge-strict.integration.test.d.ts +1 -0
- package/dist/__tests__/integration/bridge-strict.integration.test.js +812 -0
- package/dist/__tests__/integration/bridge.integration.test.d.ts +1 -0
- package/dist/__tests__/integration/bridge.integration.test.js +309 -0
- package/dist/__tests__/integration/cli-e2e.integration.test.d.ts +1 -0
- package/dist/__tests__/integration/cli-e2e.integration.test.js +202 -0
- package/dist/__tests__/integration/dex-arb.integration.test.d.ts +1 -0
- package/dist/__tests__/integration/dex-arb.integration.test.js +116 -0
- package/dist/__tests__/integration/envelope-consistency.integration.test.d.ts +13 -0
- package/dist/__tests__/integration/envelope-consistency.integration.test.js +205 -0
- package/dist/__tests__/integration/hip3-dex.integration.test.d.ts +1 -0
- package/dist/__tests__/integration/hip3-dex.integration.test.js +147 -0
- package/dist/__tests__/integration/hyperliquid.integration.test.d.ts +1 -0
- package/dist/__tests__/integration/hyperliquid.integration.test.js +79 -0
- package/dist/__tests__/integration/lighter.integration.test.d.ts +1 -0
- package/dist/__tests__/integration/lighter.integration.test.js +53 -0
- package/dist/__tests__/integration/new-commands-e2e.integration.test.d.ts +9 -0
- package/dist/__tests__/integration/new-commands-e2e.integration.test.js +236 -0
- package/dist/__tests__/integration/order-verification.integration.test.d.ts +1 -0
- package/dist/__tests__/integration/order-verification.integration.test.js +321 -0
- package/dist/__tests__/integration/pacifica.integration.test.d.ts +1 -0
- package/dist/__tests__/integration/pacifica.integration.test.js +75 -0
- package/dist/__tests__/integration/response-shapes.integration.test.d.ts +1 -0
- package/dist/__tests__/integration/response-shapes.integration.test.js +278 -0
- package/dist/__tests__/liquidity.test.d.ts +1 -0
- package/dist/__tests__/liquidity.test.js +225 -0
- package/dist/__tests__/plan-executor.test.d.ts +1 -0
- package/dist/__tests__/plan-executor.test.js +314 -0
- package/dist/__tests__/position-history.test.d.ts +1 -0
- package/dist/__tests__/position-history.test.js +367 -0
- package/dist/__tests__/retry.test.d.ts +1 -0
- package/dist/__tests__/retry.test.js +310 -0
- package/dist/__tests__/risk-assessment.test.d.ts +1 -0
- package/dist/__tests__/risk-assessment.test.js +145 -0
- package/dist/__tests__/security-adversarial.test.d.ts +1 -0
- package/dist/__tests__/security-adversarial.test.js +574 -0
- package/dist/__tests__/strategies.test.d.ts +1 -0
- package/dist/__tests__/strategies.test.js +539 -0
- package/dist/__tests__/trade-execution.test.d.ts +1 -0
- package/dist/__tests__/trade-execution.test.js +129 -0
- package/dist/__tests__/trade-validator.test.d.ts +1 -0
- package/dist/__tests__/trade-validator.test.js +655 -0
- package/dist/__tests__/utils.test.d.ts +1 -0
- package/dist/__tests__/utils.test.js +76 -0
- package/dist/api/public/hyperliquid.d.ts +18 -0
- package/dist/api/public/hyperliquid.js +82 -0
- package/dist/api/public/index.d.ts +8 -0
- package/dist/api/public/index.js +8 -0
- package/dist/api/public/lighter.d.ts +24 -0
- package/dist/api/public/lighter.js +100 -0
- package/dist/api/public/pacifica.d.ts +17 -0
- package/dist/api/public/pacifica.js +54 -0
- package/dist/api/public/urls.d.ts +12 -0
- package/dist/api/public/urls.js +33 -0
- package/dist/arb/history-stats.d.ts +44 -0
- package/dist/arb/history-stats.js +135 -0
- package/dist/arb/index.d.ts +4 -0
- package/dist/arb/index.js +4 -0
- package/dist/arb/sizing.d.ts +23 -0
- package/dist/arb/sizing.js +96 -0
- package/dist/arb/state.d.ts +51 -0
- package/dist/arb/state.js +112 -0
- package/dist/arb/utils.d.ts +81 -0
- package/dist/arb/utils.js +267 -0
- package/dist/arb-history-stats.d.ts +5 -0
- package/dist/arb-history-stats.js +5 -0
- package/dist/arb-sizing.d.ts +5 -0
- package/dist/arb-sizing.js +5 -0
- package/dist/arb-state.d.ts +5 -0
- package/dist/arb-state.js +5 -0
- package/dist/arb-utils.d.ts +5 -0
- package/dist/arb-utils.js +5 -0
- package/dist/bot/conditions.d.ts +32 -0
- package/dist/bot/conditions.js +141 -0
- package/dist/bot/config.d.ts +76 -0
- package/dist/bot/config.js +160 -0
- package/dist/bot/engine.d.ts +8 -0
- package/dist/bot/engine.js +519 -0
- package/dist/bot/presets.d.ts +11 -0
- package/dist/bot/presets.js +296 -0
- package/dist/bridge-engine.d.ts +133 -0
- package/dist/bridge-engine.js +1487 -0
- package/dist/cache.d.ts +25 -0
- package/dist/cache.js +99 -0
- package/dist/cli-spec.d.ts +50 -0
- package/dist/cli-spec.js +75 -0
- package/dist/client-id-tracker.d.ts +25 -0
- package/dist/client-id-tracker.js +76 -0
- package/dist/commands/account.d.ts +3 -0
- package/dist/commands/account.js +425 -0
- package/dist/commands/agent.d.ts +3 -0
- package/dist/commands/agent.js +386 -0
- package/dist/commands/alert.d.ts +2 -0
- package/dist/commands/alert.js +421 -0
- package/dist/commands/analytics.d.ts +3 -0
- package/dist/commands/analytics.js +311 -0
- package/dist/commands/arb/index.d.ts +3 -0
- package/dist/commands/arb/index.js +921 -0
- package/dist/commands/arb-auto.d.ts +54 -0
- package/dist/commands/arb-auto.js +1328 -0
- package/dist/commands/arb-manage.d.ts +5 -0
- package/dist/commands/arb-manage.js +5 -0
- package/dist/commands/arb.d.ts +2 -0
- package/dist/commands/arb.js +347 -0
- package/dist/commands/backtest.d.ts +2 -0
- package/dist/commands/backtest.js +327 -0
- package/dist/commands/bot.d.ts +3 -0
- package/dist/commands/bot.js +412 -0
- package/dist/commands/bridge.d.ts +2 -0
- package/dist/commands/bridge.js +396 -0
- package/dist/commands/dashboard.d.ts +3 -0
- package/dist/commands/dashboard.js +176 -0
- package/dist/commands/deposit.d.ts +4 -0
- package/dist/commands/deposit.js +573 -0
- package/dist/commands/dex.d.ts +3 -0
- package/dist/commands/dex.js +114 -0
- package/dist/commands/env.d.ts +2 -0
- package/dist/commands/env.js +136 -0
- package/dist/commands/funding.d.ts +2 -0
- package/dist/commands/funding.js +347 -0
- package/dist/commands/gap.d.ts +2 -0
- package/dist/commands/gap.js +305 -0
- package/dist/commands/health.d.ts +2 -0
- package/dist/commands/health.js +67 -0
- package/dist/commands/history.d.ts +2 -0
- package/dist/commands/history.js +235 -0
- package/dist/commands/init.d.ts +15 -0
- package/dist/commands/init.js +266 -0
- package/dist/commands/jobs.d.ts +2 -0
- package/dist/commands/jobs.js +133 -0
- package/dist/commands/manage.d.ts +4 -0
- package/dist/commands/manage.js +309 -0
- package/dist/commands/market.d.ts +3 -0
- package/dist/commands/market.js +225 -0
- package/dist/commands/plan.d.ts +3 -0
- package/dist/commands/plan.js +95 -0
- package/dist/commands/portfolio.d.ts +3 -0
- package/dist/commands/portfolio.js +169 -0
- package/dist/commands/rebalance.d.ts +3 -0
- package/dist/commands/rebalance.js +293 -0
- package/dist/commands/risk.d.ts +3 -0
- package/dist/commands/risk.js +169 -0
- package/dist/commands/run.d.ts +3 -0
- package/dist/commands/run.js +202 -0
- package/dist/commands/settings.d.ts +2 -0
- package/dist/commands/settings.js +102 -0
- package/dist/commands/stream.d.ts +5 -0
- package/dist/commands/stream.js +123 -0
- package/dist/commands/trade.d.ts +3 -0
- package/dist/commands/trade.js +1273 -0
- package/dist/commands/wallet.d.ts +14 -0
- package/dist/commands/wallet.js +602 -0
- package/dist/commands/withdraw.d.ts +3 -0
- package/dist/commands/withdraw.js +187 -0
- package/dist/config.d.ts +5 -0
- package/dist/config.js +68 -0
- package/dist/cross-chain-margin.d.ts +46 -0
- package/dist/cross-chain-margin.js +107 -0
- package/dist/dashboard/server.d.ts +80 -0
- package/dist/dashboard/server.js +340 -0
- package/dist/dashboard/ui.d.ts +4 -0
- package/dist/dashboard/ui.js +538 -0
- package/dist/dashboard/ws-feeds.d.ts +29 -0
- package/dist/dashboard/ws-feeds.js +660 -0
- package/dist/dex-asset-map.d.ts +80 -0
- package/dist/dex-asset-map.js +201 -0
- package/dist/errors.d.ts +109 -0
- package/dist/errors.js +84 -0
- package/dist/event-stream.d.ts +25 -0
- package/dist/event-stream.js +168 -0
- package/dist/exchanges/hyperliquid.d.ts +212 -0
- package/dist/exchanges/hyperliquid.js +931 -0
- package/dist/exchanges/interface.d.ts +95 -0
- package/dist/exchanges/interface.js +5 -0
- package/dist/exchanges/lighter.d.ts +159 -0
- package/dist/exchanges/lighter.js +793 -0
- package/dist/exchanges/pacifica.d.ts +51 -0
- package/dist/exchanges/pacifica.js +248 -0
- package/dist/execution-log.d.ts +36 -0
- package/dist/execution-log.js +102 -0
- package/dist/funding/history.d.ts +63 -0
- package/dist/funding/history.js +266 -0
- package/dist/funding/index.d.ts +3 -0
- package/dist/funding/index.js +3 -0
- package/dist/funding/normalize.d.ts +39 -0
- package/dist/funding/normalize.js +66 -0
- package/dist/funding/rates.d.ts +45 -0
- package/dist/funding/rates.js +172 -0
- package/dist/funding-history.d.ts +5 -0
- package/dist/funding-history.js +5 -0
- package/dist/funding-rates.d.ts +5 -0
- package/dist/funding-rates.js +5 -0
- package/dist/funding.d.ts +5 -0
- package/dist/funding.js +5 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +458 -0
- package/dist/jobs.d.ts +37 -0
- package/dist/jobs.js +152 -0
- package/dist/liquidity.d.ts +34 -0
- package/dist/liquidity.js +100 -0
- package/dist/mcp-server.d.ts +9 -0
- package/dist/mcp-server.js +1206 -0
- package/dist/pacifica/client.d.ts +111 -0
- package/dist/pacifica/client.js +310 -0
- package/dist/pacifica/constants.d.ts +27 -0
- package/dist/pacifica/constants.js +47 -0
- package/dist/pacifica/deposit.d.ts +14 -0
- package/dist/pacifica/deposit.js +78 -0
- package/dist/pacifica/index.d.ts +6 -0
- package/dist/pacifica/index.js +11 -0
- package/dist/pacifica/signing.d.ts +49 -0
- package/dist/pacifica/signing.js +97 -0
- package/dist/pacifica/types/account.d.ts +42 -0
- package/dist/pacifica/types/account.js +1 -0
- package/dist/pacifica/types/index.d.ts +6 -0
- package/dist/pacifica/types/index.js +6 -0
- package/dist/pacifica/types/lake.d.ts +18 -0
- package/dist/pacifica/types/lake.js +1 -0
- package/dist/pacifica/types/market.d.ts +64 -0
- package/dist/pacifica/types/market.js +1 -0
- package/dist/pacifica/types/order.d.ts +92 -0
- package/dist/pacifica/types/order.js +1 -0
- package/dist/pacifica/types/position.d.ts +25 -0
- package/dist/pacifica/types/position.js +1 -0
- package/dist/pacifica/types/ws.d.ts +34 -0
- package/dist/pacifica/types/ws.js +41 -0
- package/dist/pacifica/ws-client.d.ts +42 -0
- package/dist/pacifica/ws-client.js +180 -0
- package/dist/plan-executor.d.ts +48 -0
- package/dist/plan-executor.js +280 -0
- package/dist/position-history.d.ts +68 -0
- package/dist/position-history.js +222 -0
- package/dist/rebalance.d.ts +64 -0
- package/dist/rebalance.js +142 -0
- package/dist/retry.d.ts +74 -0
- package/dist/retry.js +129 -0
- package/dist/risk.d.ts +48 -0
- package/dist/risk.js +156 -0
- package/dist/settings.d.ts +19 -0
- package/dist/settings.js +45 -0
- package/dist/shared-api.d.ts +5 -0
- package/dist/shared-api.js +5 -0
- package/dist/strategies/dca.d.ts +25 -0
- package/dist/strategies/dca.js +114 -0
- package/dist/strategies/funding-arb.d.ts +15 -0
- package/dist/strategies/funding-arb.js +281 -0
- package/dist/strategies/grid.d.ts +34 -0
- package/dist/strategies/grid.js +185 -0
- package/dist/strategies/trailing-stop.d.ts +17 -0
- package/dist/strategies/trailing-stop.js +121 -0
- package/dist/strategies/twap.d.ts +20 -0
- package/dist/strategies/twap.js +78 -0
- package/dist/trade-validator.d.ts +39 -0
- package/dist/trade-validator.js +154 -0
- package/dist/utils.d.ts +38 -0
- package/dist/utils.js +110 -0
- package/package.json +63 -0
- package/skills/perp-cli/SKILL.md +149 -0
- package/skills/perp-cli/references/commands.md +143 -0
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import { PacificaAdapter } from "../exchanges/pacifica.js";
|
|
2
|
+
import { printJson, jsonOk } from "../utils.js";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
export function registerManageCommands(program, getAdapter, isJson, getPacificaAdapter) {
|
|
5
|
+
const manage = program.command("manage").description("Account management");
|
|
6
|
+
// Ensure adapter is initialized before accessing PacificaAdapter
|
|
7
|
+
async function pac() {
|
|
8
|
+
const adapter = await getAdapter();
|
|
9
|
+
if (!(adapter instanceof PacificaAdapter)) {
|
|
10
|
+
throw new Error("This command requires --exchange pacifica");
|
|
11
|
+
}
|
|
12
|
+
return adapter;
|
|
13
|
+
}
|
|
14
|
+
manage
|
|
15
|
+
.command("margin <symbol> <mode>")
|
|
16
|
+
.description("Set margin mode (cross/isolated)")
|
|
17
|
+
.action(async (symbol, mode) => {
|
|
18
|
+
const m = mode.toLowerCase();
|
|
19
|
+
if (m !== "cross" && m !== "isolated") {
|
|
20
|
+
console.error(chalk.red("Mode must be cross or isolated"));
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
const a = await pac();
|
|
24
|
+
const result = await a.sdk.updateMarginMode({ symbol: symbol.toUpperCase(), is_isolated: m === "isolated" }, a.publicKey, a.signer);
|
|
25
|
+
if (isJson())
|
|
26
|
+
return printJson(jsonOk(result));
|
|
27
|
+
console.log(chalk.green(`\n Margin mode for ${symbol.toUpperCase()} set to ${m}.\n`));
|
|
28
|
+
});
|
|
29
|
+
manage
|
|
30
|
+
.command("withdraw <amount> <address>")
|
|
31
|
+
.description("Withdraw funds to a Solana address")
|
|
32
|
+
.action(async (amount, address) => {
|
|
33
|
+
const a = await pac();
|
|
34
|
+
const result = await a.sdk.withdraw({ amount, dest_address: address }, a.publicKey, a.signer);
|
|
35
|
+
if (isJson())
|
|
36
|
+
return printJson(jsonOk(result));
|
|
37
|
+
console.log(chalk.green(`\n Withdrawal of $${amount} to ${address} submitted.\n`));
|
|
38
|
+
});
|
|
39
|
+
// Subaccounts
|
|
40
|
+
const sub = manage.command("sub").description("Subaccount management");
|
|
41
|
+
sub
|
|
42
|
+
.command("create <name>")
|
|
43
|
+
.description("Create a subaccount")
|
|
44
|
+
.action(async (name) => {
|
|
45
|
+
const a = await pac();
|
|
46
|
+
const result = await a.sdk.createSubaccount(name, a.publicKey, a.signer);
|
|
47
|
+
if (isJson())
|
|
48
|
+
return printJson(jsonOk(result));
|
|
49
|
+
console.log(chalk.green(`\n Subaccount "${name}" created.\n`));
|
|
50
|
+
});
|
|
51
|
+
sub
|
|
52
|
+
.command("list")
|
|
53
|
+
.description("List subaccounts")
|
|
54
|
+
.action(async () => {
|
|
55
|
+
const a = await pac();
|
|
56
|
+
const result = await a.sdk.listSubaccounts(a.publicKey, a.signer);
|
|
57
|
+
if (isJson())
|
|
58
|
+
return printJson(jsonOk(result));
|
|
59
|
+
printJson(jsonOk(result));
|
|
60
|
+
});
|
|
61
|
+
sub
|
|
62
|
+
.command("transfer <from> <to> <amount>")
|
|
63
|
+
.description("Transfer funds between accounts")
|
|
64
|
+
.action(async (from, to, amount) => {
|
|
65
|
+
const a = await pac();
|
|
66
|
+
const result = await a.sdk.transferFunds({ from_account: from, to_account: to, amount }, a.publicKey, a.signer);
|
|
67
|
+
if (isJson())
|
|
68
|
+
return printJson(jsonOk(result));
|
|
69
|
+
console.log(chalk.green(`\n Transferred $${amount}.\n`));
|
|
70
|
+
});
|
|
71
|
+
// Agent wallets
|
|
72
|
+
const agent = manage.command("agent").description("Agent wallet management");
|
|
73
|
+
agent
|
|
74
|
+
.command("bind <wallet>")
|
|
75
|
+
.description("Bind an agent wallet")
|
|
76
|
+
.action(async (wallet) => {
|
|
77
|
+
const a = await pac();
|
|
78
|
+
const result = await a.sdk.bindAgentWallet(wallet, a.publicKey, a.signer);
|
|
79
|
+
if (isJson())
|
|
80
|
+
return printJson(jsonOk(result));
|
|
81
|
+
console.log(chalk.green(`\n Agent wallet ${wallet} bound.\n`));
|
|
82
|
+
});
|
|
83
|
+
agent
|
|
84
|
+
.command("list")
|
|
85
|
+
.description("List agent wallets")
|
|
86
|
+
.action(async () => {
|
|
87
|
+
const a = await pac();
|
|
88
|
+
const result = await a.sdk.listAgentWallets(a.publicKey, a.signer);
|
|
89
|
+
if (isJson())
|
|
90
|
+
return printJson(jsonOk(result));
|
|
91
|
+
printJson(jsonOk(result));
|
|
92
|
+
});
|
|
93
|
+
agent
|
|
94
|
+
.command("revoke <wallet>")
|
|
95
|
+
.description("Revoke an agent wallet")
|
|
96
|
+
.action(async (wallet) => {
|
|
97
|
+
const a = await pac();
|
|
98
|
+
const result = await a.sdk.revokeAgentWallet(wallet, a.publicKey, a.signer);
|
|
99
|
+
if (isJson())
|
|
100
|
+
return printJson(jsonOk(result));
|
|
101
|
+
console.log(chalk.green(`\n Agent wallet ${wallet} revoked.\n`));
|
|
102
|
+
});
|
|
103
|
+
agent
|
|
104
|
+
.command("revoke-all")
|
|
105
|
+
.description("Revoke all agent wallets")
|
|
106
|
+
.action(async () => {
|
|
107
|
+
const a = await pac();
|
|
108
|
+
const result = await a.sdk.revokeAllAgentWallets(a.publicKey, a.signer);
|
|
109
|
+
if (isJson())
|
|
110
|
+
return printJson(jsonOk(result));
|
|
111
|
+
console.log(chalk.green("\n All agent wallets revoked.\n"));
|
|
112
|
+
});
|
|
113
|
+
// Lake (liquidity vaults)
|
|
114
|
+
const lake = manage.command("lake").description("Lake (liquidity vault) management");
|
|
115
|
+
lake
|
|
116
|
+
.command("create <symbol> <amount>")
|
|
117
|
+
.description("Create a new lake")
|
|
118
|
+
.action(async (symbol, amount) => {
|
|
119
|
+
const a = await pac();
|
|
120
|
+
const result = await a.sdk.createLake({ symbol: symbol.toUpperCase(), amount }, a.publicKey, a.signer);
|
|
121
|
+
if (isJson())
|
|
122
|
+
return printJson(jsonOk(result));
|
|
123
|
+
console.log(chalk.green(`\n Lake created for ${symbol.toUpperCase()} with $${amount}.\n`));
|
|
124
|
+
printJson(jsonOk(result));
|
|
125
|
+
});
|
|
126
|
+
lake
|
|
127
|
+
.command("deposit <lakeId> <amount>")
|
|
128
|
+
.description("Deposit to a lake")
|
|
129
|
+
.action(async (lakeId, amount) => {
|
|
130
|
+
const a = await pac();
|
|
131
|
+
const result = await a.sdk.depositToLake({ lake_id: lakeId, amount }, a.publicKey, a.signer);
|
|
132
|
+
if (isJson())
|
|
133
|
+
return printJson(jsonOk(result));
|
|
134
|
+
console.log(chalk.green(`\n Deposited $${amount} to lake ${lakeId}.\n`));
|
|
135
|
+
});
|
|
136
|
+
lake
|
|
137
|
+
.command("withdraw <lakeId> <amount>")
|
|
138
|
+
.description("Withdraw from a lake")
|
|
139
|
+
.action(async (lakeId, amount) => {
|
|
140
|
+
const a = await pac();
|
|
141
|
+
const result = await a.sdk.withdrawFromLake({ lake_id: lakeId, amount }, a.publicKey, a.signer);
|
|
142
|
+
if (isJson())
|
|
143
|
+
return printJson(jsonOk(result));
|
|
144
|
+
console.log(chalk.green(`\n Withdrew $${amount} from lake ${lakeId}.\n`));
|
|
145
|
+
});
|
|
146
|
+
// Builder Codes
|
|
147
|
+
const builder = manage.command("builder").description("Builder code management (Pacifica)");
|
|
148
|
+
builder
|
|
149
|
+
.command("approve <code> <maxFeeRate>")
|
|
150
|
+
.description("Approve a builder code (e.g. approve MYCODE 0.001)")
|
|
151
|
+
.action(async (code, maxFeeRate) => {
|
|
152
|
+
const a = await pac();
|
|
153
|
+
const result = await a.sdk.approveBuilderCode({ builder_code: code, max_fee_rate: maxFeeRate }, a.publicKey, a.signer);
|
|
154
|
+
if (isJson())
|
|
155
|
+
return printJson(jsonOk(result));
|
|
156
|
+
console.log(chalk.green(`\n Builder code "${code}" approved (max fee: ${maxFeeRate}).\n`));
|
|
157
|
+
});
|
|
158
|
+
builder
|
|
159
|
+
.command("revoke <code>")
|
|
160
|
+
.description("Revoke a builder code")
|
|
161
|
+
.action(async (code) => {
|
|
162
|
+
const a = await pac();
|
|
163
|
+
const result = await a.sdk.revokeBuilderCode({ builder_code: code }, a.publicKey, a.signer);
|
|
164
|
+
if (isJson())
|
|
165
|
+
return printJson(jsonOk(result));
|
|
166
|
+
console.log(chalk.green(`\n Builder code "${code}" revoked.\n`));
|
|
167
|
+
});
|
|
168
|
+
builder
|
|
169
|
+
.command("list")
|
|
170
|
+
.description("List approved builder codes")
|
|
171
|
+
.action(async () => {
|
|
172
|
+
const a = await pac();
|
|
173
|
+
const result = await a.sdk.getBuilderApprovals(a.publicKey);
|
|
174
|
+
if (isJson())
|
|
175
|
+
return printJson(jsonOk(result));
|
|
176
|
+
const approvals = result;
|
|
177
|
+
if (!Array.isArray(approvals) || approvals.length === 0) {
|
|
178
|
+
console.log(chalk.gray("\n No builder codes approved.\n"));
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
console.log(chalk.cyan.bold("\n Approved Builder Codes\n"));
|
|
182
|
+
for (const b of approvals) {
|
|
183
|
+
console.log(` ${chalk.white(b.builder_code.padEnd(16))} max_fee: ${b.max_fee_rate} ${chalk.gray(b.description || "")}`);
|
|
184
|
+
}
|
|
185
|
+
console.log();
|
|
186
|
+
});
|
|
187
|
+
builder
|
|
188
|
+
.command("overview")
|
|
189
|
+
.description("Show your builder code overview (if you are a builder)")
|
|
190
|
+
.action(async () => {
|
|
191
|
+
const a = await pac();
|
|
192
|
+
const result = await a.sdk.getBuilderOverview(a.publicKey);
|
|
193
|
+
if (isJson())
|
|
194
|
+
return printJson(jsonOk(result));
|
|
195
|
+
printJson(jsonOk(result));
|
|
196
|
+
});
|
|
197
|
+
builder
|
|
198
|
+
.command("trades <code>")
|
|
199
|
+
.description("Show trade history for a builder code")
|
|
200
|
+
.action(async (code) => {
|
|
201
|
+
const a = await pac();
|
|
202
|
+
const result = await a.sdk.getBuilderTrades(code);
|
|
203
|
+
if (isJson())
|
|
204
|
+
return printJson(jsonOk(result));
|
|
205
|
+
printJson(jsonOk(result));
|
|
206
|
+
});
|
|
207
|
+
builder
|
|
208
|
+
.command("leaderboard <code>")
|
|
209
|
+
.description("Show user leaderboard for a builder code")
|
|
210
|
+
.action(async (code) => {
|
|
211
|
+
const a = await pac();
|
|
212
|
+
const result = await a.sdk.getBuilderLeaderboard(code);
|
|
213
|
+
if (isJson())
|
|
214
|
+
return printJson(jsonOk(result));
|
|
215
|
+
printJson(jsonOk(result));
|
|
216
|
+
});
|
|
217
|
+
builder
|
|
218
|
+
.command("update-fee <code> <feeRate>")
|
|
219
|
+
.description("Update fee rate for your builder code (builder owners only)")
|
|
220
|
+
.action(async (code, feeRate) => {
|
|
221
|
+
const a = await pac();
|
|
222
|
+
const result = await a.sdk.updateBuilderFeeRate({ builder_code: code, fee_rate: feeRate }, a.publicKey, a.signer);
|
|
223
|
+
if (isJson())
|
|
224
|
+
return printJson(jsonOk(result));
|
|
225
|
+
console.log(chalk.green(`\n Builder code "${code}" fee rate updated to ${feeRate}.\n`));
|
|
226
|
+
});
|
|
227
|
+
// Referral
|
|
228
|
+
const referral = manage.command("referral").description("Referral code management (Pacifica)");
|
|
229
|
+
referral
|
|
230
|
+
.command("claim <code>")
|
|
231
|
+
.description("Claim a referral code")
|
|
232
|
+
.action(async (code) => {
|
|
233
|
+
const a = await pac();
|
|
234
|
+
const result = await a.sdk.claimReferralCode({ code }, a.publicKey, a.signer);
|
|
235
|
+
if (isJson())
|
|
236
|
+
return printJson(jsonOk(result));
|
|
237
|
+
console.log(chalk.green(`\n Referral code "${code}" claimed!\n`));
|
|
238
|
+
});
|
|
239
|
+
// API Keys
|
|
240
|
+
const apikey = manage.command("apikey").description("API key management");
|
|
241
|
+
apikey
|
|
242
|
+
.command("create <name> <maxFeeRate>")
|
|
243
|
+
.description("Create an API key")
|
|
244
|
+
.action(async (name, maxFeeRate) => {
|
|
245
|
+
const a = await pac();
|
|
246
|
+
const result = await a.sdk.createApiKey(name, maxFeeRate, a.publicKey, a.signer);
|
|
247
|
+
if (isJson())
|
|
248
|
+
return printJson(jsonOk(result));
|
|
249
|
+
console.log(chalk.green(`\n API key "${name}" created.\n`));
|
|
250
|
+
printJson(jsonOk(result));
|
|
251
|
+
});
|
|
252
|
+
apikey
|
|
253
|
+
.command("list")
|
|
254
|
+
.description("List API keys")
|
|
255
|
+
.action(async () => {
|
|
256
|
+
const a = await pac();
|
|
257
|
+
const result = await a.sdk.listApiKeys(a.publicKey, a.signer);
|
|
258
|
+
if (isJson())
|
|
259
|
+
return printJson(jsonOk(result));
|
|
260
|
+
printJson(jsonOk(result));
|
|
261
|
+
});
|
|
262
|
+
apikey
|
|
263
|
+
.command("revoke <key>")
|
|
264
|
+
.description("Revoke an API key")
|
|
265
|
+
.action(async (key) => {
|
|
266
|
+
const a = await pac();
|
|
267
|
+
const result = await a.sdk.revokeApiKey(key, a.publicKey, a.signer);
|
|
268
|
+
if (isJson())
|
|
269
|
+
return printJson(jsonOk(result));
|
|
270
|
+
console.log(chalk.green(`\n API key revoked.\n`));
|
|
271
|
+
});
|
|
272
|
+
// === Lighter API Key Setup ===
|
|
273
|
+
manage
|
|
274
|
+
.command("setup-api-key")
|
|
275
|
+
.description("Generate & register a Lighter API key (required for trading)")
|
|
276
|
+
.option("--key-index <n>", "API key index (2-254, default: 2)", "2")
|
|
277
|
+
.action(async (opts) => {
|
|
278
|
+
const adapter = await getAdapter();
|
|
279
|
+
const { LighterAdapter } = await import("../exchanges/lighter.js");
|
|
280
|
+
if (!(adapter instanceof LighterAdapter)) {
|
|
281
|
+
throw new Error("This command requires --exchange lighter");
|
|
282
|
+
}
|
|
283
|
+
const keyIndex = parseInt(opts.keyIndex);
|
|
284
|
+
if (!isJson()) {
|
|
285
|
+
console.log(chalk.cyan.bold("\n Lighter API Key Setup\n"));
|
|
286
|
+
console.log(chalk.gray(` Account: ${adapter.address} (index: ${adapter.accountIndex})`));
|
|
287
|
+
console.log(chalk.gray(` API Key Index: ${keyIndex}\n`));
|
|
288
|
+
console.log(chalk.gray(" Generating key pair + registering on-chain...\n"));
|
|
289
|
+
}
|
|
290
|
+
const { privateKey, publicKey } = await adapter.setupApiKey(keyIndex);
|
|
291
|
+
if (isJson()) {
|
|
292
|
+
return printJson(jsonOk({
|
|
293
|
+
privateKey,
|
|
294
|
+
publicKey,
|
|
295
|
+
address: adapter.address,
|
|
296
|
+
accountIndex: adapter.accountIndex,
|
|
297
|
+
apiKeyIndex: keyIndex,
|
|
298
|
+
}));
|
|
299
|
+
}
|
|
300
|
+
console.log(chalk.green(" API Key Registered!\n"));
|
|
301
|
+
console.log(` ${chalk.bold("Private Key:")} ${privateKey}`);
|
|
302
|
+
console.log(` ${chalk.bold("Public Key:")} ${publicKey}`);
|
|
303
|
+
console.log();
|
|
304
|
+
console.log(chalk.yellow(" Add to your .env file:"));
|
|
305
|
+
console.log(chalk.white(` LIGHTER_API_KEY=${privateKey}`));
|
|
306
|
+
console.log(chalk.white(` LIGHTER_ACCOUNT_INDEX=${adapter.accountIndex}`));
|
|
307
|
+
console.log();
|
|
308
|
+
});
|
|
309
|
+
}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { PacificaAdapter } from "../exchanges/pacifica.js";
|
|
2
|
+
import { makeTable, formatUsd, formatPercent, printJson, jsonOk, jsonError } from "../utils.js";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
export function registerMarketCommands(program, getAdapter, isJson) {
|
|
5
|
+
const market = program.command("market").description("Market data commands");
|
|
6
|
+
market
|
|
7
|
+
.command("list")
|
|
8
|
+
.description("List all available markets")
|
|
9
|
+
.action(async () => {
|
|
10
|
+
const adapter = await getAdapter();
|
|
11
|
+
const markets = await adapter.getMarkets();
|
|
12
|
+
if (isJson())
|
|
13
|
+
return printJson(jsonOk(markets));
|
|
14
|
+
const rows = markets.map((m) => [
|
|
15
|
+
chalk.white.bold(m.symbol),
|
|
16
|
+
`$${formatUsd(m.markPrice)}`,
|
|
17
|
+
`$${formatUsd(m.indexPrice)}`,
|
|
18
|
+
formatPercent(m.fundingRate),
|
|
19
|
+
`$${formatUsd(m.volume24h)}`,
|
|
20
|
+
`$${formatUsd(m.openInterest)}`,
|
|
21
|
+
String(m.maxLeverage) + "x",
|
|
22
|
+
]);
|
|
23
|
+
console.log(makeTable(["Symbol", "Mark", "Index", "Funding", "24h Vol", "OI", "Max Lev"], rows));
|
|
24
|
+
});
|
|
25
|
+
market
|
|
26
|
+
.command("prices")
|
|
27
|
+
.description("Get current prices for all markets")
|
|
28
|
+
.action(async () => {
|
|
29
|
+
const adapter = await getAdapter();
|
|
30
|
+
if (adapter instanceof PacificaAdapter) {
|
|
31
|
+
const prices = await adapter.sdk.getPrices();
|
|
32
|
+
if (isJson())
|
|
33
|
+
return printJson(jsonOk(prices));
|
|
34
|
+
const rows = prices.map((p) => [
|
|
35
|
+
chalk.white.bold(p.symbol),
|
|
36
|
+
`$${formatUsd(p.mark)}`,
|
|
37
|
+
`$${formatUsd(p.mid)}`,
|
|
38
|
+
`$${formatUsd(p.oracle)}`,
|
|
39
|
+
formatPercent(p.funding),
|
|
40
|
+
]);
|
|
41
|
+
console.log(makeTable(["Symbol", "Mark", "Mid", "Oracle", "Funding"], rows));
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
// Generic: use getMarkets as price source
|
|
45
|
+
const markets = await adapter.getMarkets();
|
|
46
|
+
if (isJson())
|
|
47
|
+
return printJson(jsonOk(markets));
|
|
48
|
+
const rows = markets.map((m) => [
|
|
49
|
+
chalk.white.bold(m.symbol),
|
|
50
|
+
`$${formatUsd(m.markPrice)}`,
|
|
51
|
+
`$${formatUsd(m.indexPrice)}`,
|
|
52
|
+
formatPercent(m.fundingRate),
|
|
53
|
+
]);
|
|
54
|
+
console.log(makeTable(["Symbol", "Mark", "Index", "Funding"], rows));
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
market
|
|
58
|
+
.command("info <symbol>")
|
|
59
|
+
.description("Detailed info for a single market")
|
|
60
|
+
.action(async (symbol) => {
|
|
61
|
+
const adapter = await getAdapter();
|
|
62
|
+
const markets = await adapter.getMarkets();
|
|
63
|
+
const sym = symbol.toUpperCase();
|
|
64
|
+
const m = markets.find((mk) => mk.symbol === sym || mk.symbol === `${sym}-PERP` || mk.symbol.replace(/-PERP$/, "") === sym);
|
|
65
|
+
if (!m) {
|
|
66
|
+
if (isJson())
|
|
67
|
+
return printJson(jsonError("SYMBOL_NOT_FOUND", `Market ${sym} not found`));
|
|
68
|
+
console.log(chalk.red(`\n Market "${sym}" not found.\n`));
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (isJson())
|
|
72
|
+
return printJson(jsonOk(m));
|
|
73
|
+
console.log(chalk.cyan.bold(`\n ${m.symbol} on ${adapter.name}\n`));
|
|
74
|
+
console.log(` Mark Price: $${formatUsd(m.markPrice)}`);
|
|
75
|
+
console.log(` Index Price: $${formatUsd(m.indexPrice)}`);
|
|
76
|
+
console.log(` Funding Rate: ${formatPercent(m.fundingRate)}`);
|
|
77
|
+
console.log(` 24h Volume: $${formatUsd(m.volume24h)}`);
|
|
78
|
+
console.log(` Open Interest: $${formatUsd(m.openInterest)}`);
|
|
79
|
+
console.log(` Max Leverage: ${m.maxLeverage}x`);
|
|
80
|
+
console.log();
|
|
81
|
+
});
|
|
82
|
+
market
|
|
83
|
+
.command("book <symbol>")
|
|
84
|
+
.description("Show orderbook for a symbol")
|
|
85
|
+
.option("-d, --depth <n>", "Number of levels", "10")
|
|
86
|
+
.action(async (symbol, opts) => {
|
|
87
|
+
const adapter = await getAdapter();
|
|
88
|
+
const book = await adapter.getOrderbook(symbol.toUpperCase());
|
|
89
|
+
if (isJson())
|
|
90
|
+
return printJson(jsonOk(book));
|
|
91
|
+
const depth = parseInt(opts.depth);
|
|
92
|
+
const asks = book.asks.slice(0, depth).reverse();
|
|
93
|
+
const bids = book.bids.slice(0, depth);
|
|
94
|
+
console.log(chalk.cyan.bold(`\n Orderbook: ${symbol.toUpperCase()} (${adapter.name})\n`));
|
|
95
|
+
console.log(chalk.gray(" Price Size"));
|
|
96
|
+
console.log(chalk.gray(" ─────────────────────"));
|
|
97
|
+
asks.forEach(([p, a]) => {
|
|
98
|
+
console.log(chalk.red(` ${formatUsd(p).padStart(12)} ${a}`));
|
|
99
|
+
});
|
|
100
|
+
console.log(chalk.gray(" ─── spread ───"));
|
|
101
|
+
bids.forEach(([p, a]) => {
|
|
102
|
+
console.log(chalk.green(` ${formatUsd(p).padStart(12)} ${a}`));
|
|
103
|
+
});
|
|
104
|
+
console.log();
|
|
105
|
+
});
|
|
106
|
+
market
|
|
107
|
+
.command("trades <symbol>")
|
|
108
|
+
.description("Recent trades for a symbol")
|
|
109
|
+
.action(async (symbol) => {
|
|
110
|
+
const adapter = await getAdapter();
|
|
111
|
+
const trades = await adapter.getRecentTrades(symbol.toUpperCase(), 20);
|
|
112
|
+
if (isJson())
|
|
113
|
+
return printJson(jsonOk(trades));
|
|
114
|
+
if (trades.length === 0) {
|
|
115
|
+
console.log(chalk.gray("\n No recent trades.\n"));
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const rows = trades.map((t) => [
|
|
119
|
+
new Date(t.time).toLocaleTimeString(),
|
|
120
|
+
t.side === "buy" ? chalk.green("BUY") : chalk.red("SELL"),
|
|
121
|
+
`$${formatUsd(t.price)}`,
|
|
122
|
+
t.size,
|
|
123
|
+
]);
|
|
124
|
+
console.log(makeTable(["Time", "Side", "Price", "Size"], rows));
|
|
125
|
+
});
|
|
126
|
+
market
|
|
127
|
+
.command("funding <symbol>")
|
|
128
|
+
.description("Funding rate history")
|
|
129
|
+
.option("-l, --limit <n>", "Number of records", "10")
|
|
130
|
+
.action(async (symbol, opts) => {
|
|
131
|
+
const adapter = await getAdapter();
|
|
132
|
+
const history = await adapter.getFundingHistory(symbol.toUpperCase(), parseInt(opts.limit));
|
|
133
|
+
if (isJson())
|
|
134
|
+
return printJson(jsonOk(history));
|
|
135
|
+
if (history.length === 0) {
|
|
136
|
+
console.log(chalk.gray("\n No funding history.\n"));
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const rows = history.map((h) => [
|
|
140
|
+
new Date(h.time).toLocaleString(),
|
|
141
|
+
formatPercent(h.rate),
|
|
142
|
+
`$${formatUsd(h.price)}`,
|
|
143
|
+
]);
|
|
144
|
+
console.log(makeTable(["Time", "Funding Rate", "Oracle"], rows));
|
|
145
|
+
});
|
|
146
|
+
market
|
|
147
|
+
.command("mid <symbol>")
|
|
148
|
+
.description("Get mid price for a single symbol (fast)")
|
|
149
|
+
.action(async (symbol) => {
|
|
150
|
+
const sym = symbol.toUpperCase();
|
|
151
|
+
try {
|
|
152
|
+
const adapter = await getAdapter();
|
|
153
|
+
// Try orderbook mid (best bid + best ask) / 2
|
|
154
|
+
const book = await adapter.getOrderbook(sym);
|
|
155
|
+
const bestBid = book.bids[0]?.[0];
|
|
156
|
+
const bestAsk = book.asks[0]?.[0];
|
|
157
|
+
if (!bestBid && !bestAsk) {
|
|
158
|
+
if (isJson())
|
|
159
|
+
return printJson(jsonError("SYMBOL_NOT_FOUND", `No orderbook data for ${sym}`));
|
|
160
|
+
console.log(chalk.red(`\n No orderbook data for ${sym}.\n`));
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const bid = Number(bestBid ?? 0);
|
|
164
|
+
const ask = Number(bestAsk ?? 0);
|
|
165
|
+
const mid = bid && ask ? (bid + ask) / 2 : bid || ask;
|
|
166
|
+
const spread = bid && ask ? ((ask - bid) / mid * 100) : 0;
|
|
167
|
+
if (isJson())
|
|
168
|
+
return printJson(jsonOk({
|
|
169
|
+
symbol: sym,
|
|
170
|
+
mid: mid.toString(),
|
|
171
|
+
bid: bestBid ?? null,
|
|
172
|
+
ask: bestAsk ?? null,
|
|
173
|
+
spread: spread.toFixed(6),
|
|
174
|
+
}));
|
|
175
|
+
console.log(chalk.cyan.bold(`\n ${sym} Mid Price\n`));
|
|
176
|
+
console.log(` Mid: $${formatUsd(mid)}`);
|
|
177
|
+
if (bestBid)
|
|
178
|
+
console.log(` Bid: $${formatUsd(bestBid)}`);
|
|
179
|
+
if (bestAsk)
|
|
180
|
+
console.log(` Ask: $${formatUsd(bestAsk)}`);
|
|
181
|
+
console.log(` Spread: ${spread.toFixed(4)}%`);
|
|
182
|
+
console.log();
|
|
183
|
+
}
|
|
184
|
+
catch (err) {
|
|
185
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
186
|
+
if (isJson()) {
|
|
187
|
+
const { classifyError } = await import("../errors.js");
|
|
188
|
+
const classified = classifyError(err);
|
|
189
|
+
return printJson(jsonError(classified.code, classified.message, {
|
|
190
|
+
status: classified.status,
|
|
191
|
+
retryable: classified.retryable,
|
|
192
|
+
}));
|
|
193
|
+
}
|
|
194
|
+
console.error(chalk.red(`Error: ${msg}`));
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
market
|
|
198
|
+
.command("kline <symbol> <interval>")
|
|
199
|
+
.description("Kline/candlestick data (intervals: 1m,5m,15m,1h,4h,1d,...)")
|
|
200
|
+
.option("--start <ts>", "Start time (unix ms)")
|
|
201
|
+
.option("--end <ts>", "End time (unix ms)")
|
|
202
|
+
.action(async (symbol, interval, opts) => {
|
|
203
|
+
const adapter = await getAdapter();
|
|
204
|
+
const now = Date.now();
|
|
205
|
+
const startTime = opts.start ? parseInt(opts.start) : now - 24 * 60 * 60 * 1000;
|
|
206
|
+
const endTime = opts.end ? parseInt(opts.end) : now;
|
|
207
|
+
const klines = await adapter.getKlines(symbol.toUpperCase(), interval, startTime, endTime);
|
|
208
|
+
if (isJson())
|
|
209
|
+
return printJson(jsonOk(klines));
|
|
210
|
+
if (klines.length === 0) {
|
|
211
|
+
console.log(chalk.gray("\n No kline data.\n"));
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const rows = klines.slice(-20).map((k) => [
|
|
215
|
+
new Date(k.time).toLocaleString(),
|
|
216
|
+
`$${formatUsd(k.open)}`,
|
|
217
|
+
`$${formatUsd(k.high)}`,
|
|
218
|
+
`$${formatUsd(k.low)}`,
|
|
219
|
+
`$${formatUsd(k.close)}`,
|
|
220
|
+
k.volume,
|
|
221
|
+
String(k.trades),
|
|
222
|
+
]);
|
|
223
|
+
console.log(makeTable(["Time", "Open", "High", "Low", "Close", "Volume", "Trades"], rows));
|
|
224
|
+
});
|
|
225
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { readFileSync } from "fs";
|
|
2
|
+
import { printJson, jsonOk, jsonError, withJsonErrors } from "../utils.js";
|
|
3
|
+
import { validatePlan, executePlan } from "../plan-executor.js";
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
export function registerPlanCommands(program, getAdapter, isJson) {
|
|
6
|
+
const plan = program.command("plan").description("Composite execution plans (multi-step atomic operations)");
|
|
7
|
+
// ── plan validate ──
|
|
8
|
+
plan
|
|
9
|
+
.command("validate <file>")
|
|
10
|
+
.description("Validate a JSON execution plan without executing")
|
|
11
|
+
.action(async (file) => {
|
|
12
|
+
await withJsonErrors(isJson(), async () => {
|
|
13
|
+
const raw = file === "-" ? readFileSync(0, "utf-8") : readFileSync(file, "utf-8");
|
|
14
|
+
const planData = JSON.parse(raw);
|
|
15
|
+
const result = validatePlan(planData);
|
|
16
|
+
if (isJson())
|
|
17
|
+
return printJson(jsonOk(result));
|
|
18
|
+
if (result.valid) {
|
|
19
|
+
console.log(chalk.green(`\n Plan is valid (${planData.steps?.length ?? 0} steps).\n`));
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
console.log(chalk.red(`\n Plan validation failed:\n`));
|
|
23
|
+
for (const err of result.errors) {
|
|
24
|
+
console.log(chalk.red(` • ${err}`));
|
|
25
|
+
}
|
|
26
|
+
console.log();
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
// ── plan execute ──
|
|
31
|
+
plan
|
|
32
|
+
.command("execute <file>")
|
|
33
|
+
.description("Execute a JSON plan (use - for stdin)")
|
|
34
|
+
.option("--dry-run", "Simulate without executing trades")
|
|
35
|
+
.action(async (file, opts) => {
|
|
36
|
+
await withJsonErrors(isJson(), async () => {
|
|
37
|
+
const raw = file === "-" ? readFileSync(0, "utf-8") : readFileSync(file, "utf-8");
|
|
38
|
+
const planData = JSON.parse(raw);
|
|
39
|
+
// Validate first
|
|
40
|
+
const validation = validatePlan(planData);
|
|
41
|
+
if (!validation.valid) {
|
|
42
|
+
if (isJson())
|
|
43
|
+
return printJson(jsonError("INVALID_PARAMS", `Plan validation failed: ${validation.errors.join("; ")}`));
|
|
44
|
+
console.error(chalk.red(`\n Plan validation failed:`));
|
|
45
|
+
for (const err of validation.errors)
|
|
46
|
+
console.error(chalk.red(` • ${err}`));
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const adapter = await getAdapter();
|
|
50
|
+
const log = isJson() ? () => { } : (msg) => console.log(chalk.gray(` ${msg}`));
|
|
51
|
+
if (!isJson()) {
|
|
52
|
+
console.log(chalk.cyan.bold(`\n Executing plan (${planData.steps.length} steps)${opts.dryRun ? " [DRY RUN]" : ""}...\n`));
|
|
53
|
+
}
|
|
54
|
+
const result = await executePlan(adapter, planData, {
|
|
55
|
+
dryRun: opts.dryRun,
|
|
56
|
+
log,
|
|
57
|
+
});
|
|
58
|
+
if (isJson())
|
|
59
|
+
return printJson(jsonOk(result));
|
|
60
|
+
// Pretty print results
|
|
61
|
+
for (const step of result.steps) {
|
|
62
|
+
const icon = step.status === "success" ? chalk.green("✓")
|
|
63
|
+
: step.status === "dry_run" ? chalk.blue("○")
|
|
64
|
+
: step.status === "skipped" ? chalk.yellow("–")
|
|
65
|
+
: chalk.red("✗");
|
|
66
|
+
const duration = chalk.gray(`(${step.durationMs}ms)`);
|
|
67
|
+
const err = step.error ? chalk.red(` — ${step.error.message}`) : "";
|
|
68
|
+
console.log(` ${icon} ${step.stepId} (${step.action}) ${duration}${err}`);
|
|
69
|
+
}
|
|
70
|
+
const statusColor = result.status === "completed" ? chalk.green
|
|
71
|
+
: result.status === "dry_run" ? chalk.blue
|
|
72
|
+
: result.status === "partial" ? chalk.yellow
|
|
73
|
+
: chalk.red;
|
|
74
|
+
console.log(`\n Status: ${statusColor(result.status)} | ${result.totalDurationMs}ms\n`);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
// ── plan example ──
|
|
78
|
+
plan
|
|
79
|
+
.command("example")
|
|
80
|
+
.description("Print an example execution plan")
|
|
81
|
+
.action(() => {
|
|
82
|
+
const example = {
|
|
83
|
+
version: "1.0",
|
|
84
|
+
description: "Open hedged position with stop loss",
|
|
85
|
+
steps: [
|
|
86
|
+
{ id: "check", action: "check_balance", params: { minAvailable: 100 }, onFailure: "abort" },
|
|
87
|
+
{ id: "leverage", action: "set_leverage", params: { symbol: "ETH", leverage: 5 }, onFailure: "abort" },
|
|
88
|
+
{ id: "entry", action: "market_order", params: { symbol: "ETH", side: "buy", size: "0.5" }, onFailure: "rollback" },
|
|
89
|
+
{ id: "verify", action: "check_position", params: { symbol: "ETH", mustExist: true }, dependsOn: "entry", onFailure: "rollback" },
|
|
90
|
+
{ id: "stop", action: "stop_order", params: { symbol: "ETH", side: "sell", size: "0.5", triggerPrice: "1800", reduceOnly: true }, dependsOn: "verify", onFailure: "skip" },
|
|
91
|
+
],
|
|
92
|
+
};
|
|
93
|
+
printJson(jsonOk(example));
|
|
94
|
+
});
|
|
95
|
+
}
|