@raintree-technology/perps 0.1.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.
Files changed (316) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/LICENSE +21 -0
  3. package/README.md +175 -0
  4. package/dist/adapters/aevo.d.ts +64 -0
  5. package/dist/adapters/aevo.js +899 -0
  6. package/dist/adapters/certification.d.ts +33 -0
  7. package/dist/adapters/certification.js +99 -0
  8. package/dist/adapters/decibel/order-manager.d.ts +45 -0
  9. package/dist/adapters/decibel/order-manager.js +140 -0
  10. package/dist/adapters/decibel/rest-client.d.ts +176 -0
  11. package/dist/adapters/decibel/rest-client.js +155 -0
  12. package/dist/adapters/decibel/ws-feed.d.ts +28 -0
  13. package/dist/adapters/decibel/ws-feed.js +166 -0
  14. package/dist/adapters/decibel.d.ts +108 -0
  15. package/dist/adapters/decibel.js +1377 -0
  16. package/dist/adapters/hyperliquid.d.ts +63 -0
  17. package/dist/adapters/hyperliquid.js +797 -0
  18. package/dist/adapters/index.d.ts +11 -0
  19. package/dist/adapters/index.js +12 -0
  20. package/dist/adapters/interface.d.ts +310 -0
  21. package/dist/adapters/interface.js +15 -0
  22. package/dist/adapters/orderly.d.ts +70 -0
  23. package/dist/adapters/orderly.js +936 -0
  24. package/dist/adapters/paradex.d.ts +69 -0
  25. package/dist/adapters/paradex.js +862 -0
  26. package/dist/adapters/utils.d.ts +17 -0
  27. package/dist/adapters/utils.js +122 -0
  28. package/dist/cli/command-metadata.d.ts +2 -0
  29. package/dist/cli/command-metadata.js +44 -0
  30. package/dist/cli/context.d.ts +14 -0
  31. package/dist/cli/context.js +59 -0
  32. package/dist/cli/experience.d.ts +48 -0
  33. package/dist/cli/experience.js +243 -0
  34. package/dist/cli/ink/app/AppShell.d.ts +12 -0
  35. package/dist/cli/ink/app/AppShell.js +32 -0
  36. package/dist/cli/ink/app/MetricStrip.d.ts +6 -0
  37. package/dist/cli/ink/app/MetricStrip.js +14 -0
  38. package/dist/cli/ink/app/Panel.d.ts +9 -0
  39. package/dist/cli/ink/app/Panel.js +7 -0
  40. package/dist/cli/ink/app/ascii.d.ts +2 -0
  41. package/dist/cli/ink/app/ascii.js +46 -0
  42. package/dist/cli/ink/app/index.d.ts +5 -0
  43. package/dist/cli/ink/app/index.js +4 -0
  44. package/dist/cli/ink/app/types.d.ts +15 -0
  45. package/dist/cli/ink/app/types.js +1 -0
  46. package/dist/cli/ink/components/PnL.d.ts +12 -0
  47. package/dist/cli/ink/components/PnL.js +23 -0
  48. package/dist/cli/ink/components/Spinner.d.ts +13 -0
  49. package/dist/cli/ink/components/Spinner.js +13 -0
  50. package/dist/cli/ink/components/Table.d.ts +14 -0
  51. package/dist/cli/ink/components/Table.js +42 -0
  52. package/dist/cli/ink/components/WatchHeader.d.ts +10 -0
  53. package/dist/cli/ink/components/WatchHeader.js +18 -0
  54. package/dist/cli/ink/components/index.d.ts +4 -0
  55. package/dist/cli/ink/components/index.js +4 -0
  56. package/dist/cli/ink/index.d.ts +4 -0
  57. package/dist/cli/ink/index.js +4 -0
  58. package/dist/cli/ink/render.d.ts +12 -0
  59. package/dist/cli/ink/render.js +21 -0
  60. package/dist/cli/ink/theme.d.ts +29 -0
  61. package/dist/cli/ink/theme.js +40 -0
  62. package/dist/cli/network-defaults.d.ts +10 -0
  63. package/dist/cli/network-defaults.js +35 -0
  64. package/dist/cli/output.d.ts +11 -0
  65. package/dist/cli/output.js +115 -0
  66. package/dist/cli/program.d.ts +18 -0
  67. package/dist/cli/program.js +164 -0
  68. package/dist/cli/watch.d.ts +19 -0
  69. package/dist/cli/watch.js +35 -0
  70. package/dist/client/index.d.ts +55 -0
  71. package/dist/client/index.js +157 -0
  72. package/dist/commands/account/add.d.ts +2 -0
  73. package/dist/commands/account/add.js +510 -0
  74. package/dist/commands/account/balances-simple.d.ts +5 -0
  75. package/dist/commands/account/balances-simple.js +63 -0
  76. package/dist/commands/account/index.d.ts +2 -0
  77. package/dist/commands/account/index.js +17 -0
  78. package/dist/commands/account/ls.d.ts +2 -0
  79. package/dist/commands/account/ls.js +95 -0
  80. package/dist/commands/account/positions-simple.d.ts +5 -0
  81. package/dist/commands/account/positions-simple.js +77 -0
  82. package/dist/commands/account/remove.d.ts +2 -0
  83. package/dist/commands/account/remove.js +47 -0
  84. package/dist/commands/account/set-default.d.ts +2 -0
  85. package/dist/commands/account/set-default.js +47 -0
  86. package/dist/commands/agent/index.d.ts +2 -0
  87. package/dist/commands/agent/index.js +126 -0
  88. package/dist/commands/arb/alert.d.ts +6 -0
  89. package/dist/commands/arb/alert.js +88 -0
  90. package/dist/commands/arb/basis-execute.d.ts +6 -0
  91. package/dist/commands/arb/basis-execute.js +332 -0
  92. package/dist/commands/arb/basis.d.ts +6 -0
  93. package/dist/commands/arb/basis.js +181 -0
  94. package/dist/commands/arb/compare.d.ts +6 -0
  95. package/dist/commands/arb/compare.js +216 -0
  96. package/dist/commands/arb/execute.d.ts +6 -0
  97. package/dist/commands/arb/execute.js +467 -0
  98. package/dist/commands/arb/funding.d.ts +6 -0
  99. package/dist/commands/arb/funding.js +201 -0
  100. package/dist/commands/arb/history.d.ts +6 -0
  101. package/dist/commands/arb/history.js +153 -0
  102. package/dist/commands/arb/index.d.ts +6 -0
  103. package/dist/commands/arb/index.js +29 -0
  104. package/dist/commands/arb/positions.d.ts +6 -0
  105. package/dist/commands/arb/positions.js +158 -0
  106. package/dist/commands/arb/spread.d.ts +6 -0
  107. package/dist/commands/arb/spread.js +253 -0
  108. package/dist/commands/arb/track.d.ts +6 -0
  109. package/dist/commands/arb/track.js +259 -0
  110. package/dist/commands/asset/book-simple.d.ts +5 -0
  111. package/dist/commands/asset/book-simple.js +77 -0
  112. package/dist/commands/asset/index.d.ts +2 -0
  113. package/dist/commands/asset/index.js +5 -0
  114. package/dist/commands/completion.d.ts +2 -0
  115. package/dist/commands/completion.js +161 -0
  116. package/dist/commands/config/index.d.ts +5 -0
  117. package/dist/commands/config/index.js +109 -0
  118. package/dist/commands/data/index.d.ts +31 -0
  119. package/dist/commands/data/index.js +1466 -0
  120. package/dist/commands/doctor.d.ts +2 -0
  121. package/dist/commands/doctor.js +201 -0
  122. package/dist/commands/exchange/index.d.ts +2 -0
  123. package/dist/commands/exchange/index.js +107 -0
  124. package/dist/commands/index.d.ts +2 -0
  125. package/dist/commands/index.js +48 -0
  126. package/dist/commands/markets/index.d.ts +2 -0
  127. package/dist/commands/markets/index.js +5 -0
  128. package/dist/commands/markets/ls-simple.d.ts +7 -0
  129. package/dist/commands/markets/ls-simple.js +277 -0
  130. package/dist/commands/operator/index.d.ts +2 -0
  131. package/dist/commands/operator/index.js +146 -0
  132. package/dist/commands/order/cancel-simple.d.ts +5 -0
  133. package/dist/commands/order/cancel-simple.js +104 -0
  134. package/dist/commands/order/index.d.ts +2 -0
  135. package/dist/commands/order/index.js +13 -0
  136. package/dist/commands/order/limit-simple.d.ts +5 -0
  137. package/dist/commands/order/limit-simple.js +195 -0
  138. package/dist/commands/order/market-simple.d.ts +5 -0
  139. package/dist/commands/order/market-simple.js +190 -0
  140. package/dist/commands/order/shared.d.ts +17 -0
  141. package/dist/commands/order/shared.js +51 -0
  142. package/dist/commands/order/trigger-simple.d.ts +5 -0
  143. package/dist/commands/order/trigger-simple.js +246 -0
  144. package/dist/commands/referral/index.d.ts +2 -0
  145. package/dist/commands/referral/index.js +7 -0
  146. package/dist/commands/referral/set.d.ts +2 -0
  147. package/dist/commands/referral/set.js +26 -0
  148. package/dist/commands/referral/status.d.ts +2 -0
  149. package/dist/commands/referral/status.js +31 -0
  150. package/dist/commands/replay/index.d.ts +2 -0
  151. package/dist/commands/replay/index.js +152 -0
  152. package/dist/commands/risk/analytics.d.ts +2 -0
  153. package/dist/commands/risk/analytics.js +64 -0
  154. package/dist/commands/risk/audit.d.ts +2 -0
  155. package/dist/commands/risk/audit.js +52 -0
  156. package/dist/commands/risk/index.d.ts +2 -0
  157. package/dist/commands/risk/index.js +9 -0
  158. package/dist/commands/risk/rules.d.ts +2 -0
  159. package/dist/commands/risk/rules.js +102 -0
  160. package/dist/commands/server.d.ts +2 -0
  161. package/dist/commands/server.js +208 -0
  162. package/dist/commands/setup/index.d.ts +2 -0
  163. package/dist/commands/setup/index.js +478 -0
  164. package/dist/commands/signal/index.d.ts +2 -0
  165. package/dist/commands/signal/index.js +129 -0
  166. package/dist/commands/state/index.d.ts +2 -0
  167. package/dist/commands/state/index.js +5 -0
  168. package/dist/commands/state/show.d.ts +2 -0
  169. package/dist/commands/state/show.js +105 -0
  170. package/dist/commands/strategy/index.d.ts +4 -0
  171. package/dist/commands/strategy/index.js +73 -0
  172. package/dist/commands/traces/index.d.ts +2 -0
  173. package/dist/commands/traces/index.js +76 -0
  174. package/dist/commands/ui/demo.d.ts +9 -0
  175. package/dist/commands/ui/demo.js +195 -0
  176. package/dist/commands/ui/index.d.ts +2 -0
  177. package/dist/commands/ui/index.js +7 -0
  178. package/dist/commands/ui/terminal.d.ts +2 -0
  179. package/dist/commands/ui/terminal.js +255 -0
  180. package/dist/commands/upgrade.d.ts +2 -0
  181. package/dist/commands/upgrade.js +98 -0
  182. package/dist/index.d.ts +2 -0
  183. package/dist/index.js +4 -0
  184. package/dist/lib/agent/audit.d.ts +12 -0
  185. package/dist/lib/agent/audit.js +13 -0
  186. package/dist/lib/agent/gateway.d.ts +13 -0
  187. package/dist/lib/agent/gateway.js +598 -0
  188. package/dist/lib/agent/metrics.d.ts +33 -0
  189. package/dist/lib/agent/metrics.js +175 -0
  190. package/dist/lib/agent/signature.d.ts +8 -0
  191. package/dist/lib/agent/signature.js +28 -0
  192. package/dist/lib/agent/tools.d.ts +28 -0
  193. package/dist/lib/agent/tools.js +453 -0
  194. package/dist/lib/agent/x402.d.ts +23 -0
  195. package/dist/lib/agent/x402.js +62 -0
  196. package/dist/lib/api-wallet.d.ts +69 -0
  197. package/dist/lib/api-wallet.js +101 -0
  198. package/dist/lib/balance-watcher.d.ts +25 -0
  199. package/dist/lib/balance-watcher.js +83 -0
  200. package/dist/lib/book-watcher.d.ts +25 -0
  201. package/dist/lib/book-watcher.js +48 -0
  202. package/dist/lib/config.d.ts +88 -0
  203. package/dist/lib/config.js +427 -0
  204. package/dist/lib/constants.d.ts +50 -0
  205. package/dist/lib/constants.js +84 -0
  206. package/dist/lib/contracts.d.ts +7 -0
  207. package/dist/lib/contracts.js +8 -0
  208. package/dist/lib/credential-vault.d.ts +22 -0
  209. package/dist/lib/credential-vault.js +109 -0
  210. package/dist/lib/db/accounts.d.ts +83 -0
  211. package/dist/lib/db/accounts.js +203 -0
  212. package/dist/lib/db/funding-history.d.ts +69 -0
  213. package/dist/lib/db/funding-history.js +183 -0
  214. package/dist/lib/db/index.d.ts +11 -0
  215. package/dist/lib/db/index.js +272 -0
  216. package/dist/lib/events/bus.d.ts +10 -0
  217. package/dist/lib/events/bus.js +17 -0
  218. package/dist/lib/events/types.d.ts +51 -0
  219. package/dist/lib/events/types.js +1 -0
  220. package/dist/lib/exchange.d.ts +30 -0
  221. package/dist/lib/exchange.js +84 -0
  222. package/dist/lib/execution/journal.d.ts +25 -0
  223. package/dist/lib/execution/journal.js +158 -0
  224. package/dist/lib/execution/safety.d.ts +34 -0
  225. package/dist/lib/execution/safety.js +197 -0
  226. package/dist/lib/exit-codes.d.ts +18 -0
  227. package/dist/lib/exit-codes.js +60 -0
  228. package/dist/lib/fetch.d.ts +18 -0
  229. package/dist/lib/fetch.js +66 -0
  230. package/dist/lib/fs-security.d.ts +10 -0
  231. package/dist/lib/fs-security.js +26 -0
  232. package/dist/lib/funding-tracker.d.ts +40 -0
  233. package/dist/lib/funding-tracker.js +118 -0
  234. package/dist/lib/logger.d.ts +27 -0
  235. package/dist/lib/logger.js +82 -0
  236. package/dist/lib/network-model.d.ts +13 -0
  237. package/dist/lib/network-model.js +30 -0
  238. package/dist/lib/onboarding.d.ts +133 -0
  239. package/dist/lib/onboarding.js +1459 -0
  240. package/dist/lib/operator-state.d.ts +25 -0
  241. package/dist/lib/operator-state.js +82 -0
  242. package/dist/lib/orders-watcher.d.ts +24 -0
  243. package/dist/lib/orders-watcher.js +74 -0
  244. package/dist/lib/paths.d.ts +20 -0
  245. package/dist/lib/paths.js +23 -0
  246. package/dist/lib/portfolio-watcher.d.ts +33 -0
  247. package/dist/lib/portfolio-watcher.js +95 -0
  248. package/dist/lib/position-watcher.d.ts +16 -0
  249. package/dist/lib/position-watcher.js +44 -0
  250. package/dist/lib/price-watcher.d.ts +15 -0
  251. package/dist/lib/price-watcher.js +84 -0
  252. package/dist/lib/prompts.d.ts +32 -0
  253. package/dist/lib/prompts.js +105 -0
  254. package/dist/lib/rate-limit.d.ts +32 -0
  255. package/dist/lib/rate-limit.js +88 -0
  256. package/dist/lib/risk/analytics.d.ts +39 -0
  257. package/dist/lib/risk/analytics.js +98 -0
  258. package/dist/lib/risk/drawdown.d.ts +18 -0
  259. package/dist/lib/risk/drawdown.js +49 -0
  260. package/dist/lib/risk/evaluation-log.d.ts +29 -0
  261. package/dist/lib/risk/evaluation-log.js +61 -0
  262. package/dist/lib/risk/index.d.ts +4 -0
  263. package/dist/lib/risk/index.js +4 -0
  264. package/dist/lib/risk/limits.d.ts +23 -0
  265. package/dist/lib/risk/limits.js +27 -0
  266. package/dist/lib/risk/manager.d.ts +32 -0
  267. package/dist/lib/risk/manager.js +85 -0
  268. package/dist/lib/risk/policy-middleware.d.ts +33 -0
  269. package/dist/lib/risk/policy-middleware.js +267 -0
  270. package/dist/lib/risk/position-sizer.d.ts +9 -0
  271. package/dist/lib/risk/position-sizer.js +14 -0
  272. package/dist/lib/risk/rules-store.d.ts +16 -0
  273. package/dist/lib/risk/rules-store.js +47 -0
  274. package/dist/lib/schema.d.ts +254 -0
  275. package/dist/lib/schema.js +199 -0
  276. package/dist/lib/secrets.d.ts +3 -0
  277. package/dist/lib/secrets.js +62 -0
  278. package/dist/lib/settings.d.ts +24 -0
  279. package/dist/lib/settings.js +86 -0
  280. package/dist/lib/signals.d.ts +73 -0
  281. package/dist/lib/signals.js +136 -0
  282. package/dist/lib/stable-stringify.d.ts +6 -0
  283. package/dist/lib/stable-stringify.js +17 -0
  284. package/dist/lib/state-context.d.ts +44 -0
  285. package/dist/lib/state-context.js +133 -0
  286. package/dist/lib/strategy/basis-trade.d.ts +2 -0
  287. package/dist/lib/strategy/basis-trade.js +24 -0
  288. package/dist/lib/strategy/funding-arb.d.ts +2 -0
  289. package/dist/lib/strategy/funding-arb.js +23 -0
  290. package/dist/lib/strategy/interface.d.ts +23 -0
  291. package/dist/lib/strategy/interface.js +1 -0
  292. package/dist/lib/strategy/registry.d.ts +4 -0
  293. package/dist/lib/strategy/registry.js +10 -0
  294. package/dist/lib/telemetry.d.ts +25 -0
  295. package/dist/lib/telemetry.js +101 -0
  296. package/dist/lib/trace-queries.d.ts +20 -0
  297. package/dist/lib/trace-queries.js +133 -0
  298. package/dist/lib/trace.d.ts +1 -0
  299. package/dist/lib/trace.js +4 -0
  300. package/dist/lib/trade-reputation.d.ts +6 -0
  301. package/dist/lib/trade-reputation.js +99 -0
  302. package/dist/lib/ui-tokens.d.ts +21 -0
  303. package/dist/lib/ui-tokens.js +26 -0
  304. package/dist/lib/validate.d.ts +39 -0
  305. package/dist/lib/validate.js +108 -0
  306. package/dist/lib/validation.d.ts +9 -0
  307. package/dist/lib/validation.js +64 -0
  308. package/dist/server/cache.d.ts +38 -0
  309. package/dist/server/cache.js +56 -0
  310. package/dist/server/index.d.ts +2 -0
  311. package/dist/server/index.js +89 -0
  312. package/dist/server/ipc.d.ts +18 -0
  313. package/dist/server/ipc.js +159 -0
  314. package/dist/server/subscriptions.d.ts +18 -0
  315. package/dist/server/subscriptions.js +114 -0
  316. package/package.json +124 -0
@@ -0,0 +1,478 @@
1
+ import { existsSync, writeFileSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { getOutputOptions } from "../../cli/program.js";
4
+ import { output, outputError, outputSuccess } from "../../cli/output.js";
5
+ import { withJsonContract } from "../../lib/contracts.js";
6
+ import { createAccount, getAccountByAliasForExchange, } from "../../lib/db/index.js";
7
+ import { privateKeyToAccount } from "viem/accounts";
8
+ import { getCredentialVaultSummary, saveOnboardingProfileToVault, } from "../../lib/credential-vault.js";
9
+ import { ALL_SETUP_CHAINS, ALL_SETUP_EXCHANGES, buildOnboardingEnvFile, parseSetupChains, parseSetupExchanges, parseSetupMode, resolveExchangesFromChains, runOnboardingStateMachine, } from "../../lib/onboarding.js";
10
+ import { confirm, multiSelect, select } from "../../lib/prompts.js";
11
+ import { hardenPrivateFile, PRIVATE_FILE_MODE } from "../../lib/fs-security.js";
12
+ const MODE_DESCRIPTIONS = {
13
+ "mainnet-data": "No credentials. Use real mainnet data immediately.",
14
+ "testnet-execution": "Force selected exchanges to testnet for all commands.",
15
+ both: "Keep defaults: data=mainnet, execution=testnet (recommended).",
16
+ };
17
+ const CHAIN_DESCRIPTIONS = {
18
+ evm: "Hyperliquid, Aevo, Orderly",
19
+ aptos: "Decibel",
20
+ starknet: "Paradex",
21
+ };
22
+ function normalizeFundingOptions(opts) {
23
+ const orderlyBrokerId = opts.orderlyBrokerId ??
24
+ process.env.ORDERLY_TESTNET_FAUCET_BROKER_ID ??
25
+ process.env.ORDERLY_BROKER_ID;
26
+ const orderlyChainId = opts.orderlyChainId ?? process.env.ORDERLY_TESTNET_FAUCET_CHAIN_ID;
27
+ const aptosFaucetJwt = opts.aptosFaucetJwt ?? process.env.APTOS_TESTNET_FAUCET_JWT;
28
+ const aptosFaucetAmount = opts.aptosFaucetAmount ?? process.env.APTOS_TESTNET_FAUCET_AMOUNT;
29
+ return {
30
+ orderlyBrokerId,
31
+ orderlyChainId: orderlyChainId ? Number.parseInt(orderlyChainId, 10) : undefined,
32
+ aptosFaucetJwt,
33
+ aptosFaucetAmount: aptosFaucetAmount ? Number.parseInt(aptosFaucetAmount, 10) : undefined,
34
+ };
35
+ }
36
+ function normalizeAuthOptions(opts) {
37
+ const orderlyChainId = opts.orderlyChainId ??
38
+ process.env.ORDERLY_CHAIN_ID ??
39
+ process.env.ORDERLY_TESTNET_FAUCET_CHAIN_ID;
40
+ return {
41
+ decibelBearerToken: opts.decibelBearerToken ?? process.env.DECIBEL_API_BEARER_TOKEN,
42
+ aevoApiKey: opts.aevoApiKey ?? process.env.AEVO_API_KEY,
43
+ aevoApiSecret: opts.aevoApiSecret ?? process.env.AEVO_API_SECRET,
44
+ aevoAccountPrivateKey: (opts.aevoAccountPrivateKey ??
45
+ process.env.AEVO_ACCOUNT_PRIVATE_KEY),
46
+ aevoRestUrl: opts.aevoRestUrl ?? process.env.AEVO_REST_URL,
47
+ orderlyBrokerId: opts.orderlyBrokerId ??
48
+ process.env.ORDERLY_BROKER_ID ??
49
+ process.env.ORDERLY_TESTNET_FAUCET_BROKER_ID,
50
+ orderlyChainId: orderlyChainId ? Number.parseInt(orderlyChainId, 10) : undefined,
51
+ orderlyRestUrl: opts.orderlyRestUrl ?? process.env.ORDERLY_REST_URL,
52
+ orderlyAccountId: opts.orderlyAccountId ?? process.env.ORDERLY_ACCOUNT_ID,
53
+ orderlyKey: opts.orderlyKey ?? process.env.ORDERLY_KEY,
54
+ orderlySecret: opts.orderlySecret ?? process.env.ORDERLY_SECRET,
55
+ paradexApiBearerToken: opts.paradexBearerToken ?? process.env.PARADEX_API_BEARER_TOKEN,
56
+ paradexAccountAddress: opts.paradexAccountAddress ?? process.env.PARADEX_ACCOUNT_ADDRESS,
57
+ paradexEthereumAccount: opts.paradexEthereumAccount ?? process.env.PARADEX_ETHEREUM_ACCOUNT,
58
+ paradexRestUrl: opts.paradexRestUrl ?? process.env.PARADEX_REST_URL,
59
+ };
60
+ }
61
+ function syncGeneratedAccounts(profile) {
62
+ const alias = "setup";
63
+ const results = [];
64
+ const create = (args) => {
65
+ const { exchange, userAddress, privateKey, publicKey } = args;
66
+ if (!userAddress || !privateKey) {
67
+ results.push({
68
+ exchange,
69
+ alias,
70
+ status: "skipped",
71
+ detail: "missing address/private key",
72
+ });
73
+ return;
74
+ }
75
+ try {
76
+ const existing = getAccountByAliasForExchange(alias, exchange);
77
+ if (existing) {
78
+ results.push({
79
+ exchange,
80
+ alias,
81
+ status: "skipped",
82
+ detail: `alias "${alias}" already exists`,
83
+ });
84
+ return;
85
+ }
86
+ createAccount({
87
+ alias,
88
+ exchange,
89
+ userAddress: userAddress,
90
+ type: "api_wallet",
91
+ source: "cli_import",
92
+ apiWalletPrivateKey: privateKey,
93
+ apiWalletPublicKey: (publicKey ?? userAddress),
94
+ setAsDefault: false,
95
+ });
96
+ results.push({
97
+ exchange,
98
+ alias,
99
+ status: "created",
100
+ detail: `created "${alias}" profile`,
101
+ });
102
+ }
103
+ catch (err) {
104
+ results.push({
105
+ exchange,
106
+ alias,
107
+ status: "error",
108
+ detail: err instanceof Error ? err.message : String(err),
109
+ });
110
+ }
111
+ };
112
+ for (const exchange of profile.exchanges) {
113
+ if (exchange === "hyperliquid" && profile.credentials.hyperliquid) {
114
+ create({
115
+ exchange,
116
+ userAddress: profile.credentials.hyperliquid.walletAddress,
117
+ privateKey: profile.credentials.hyperliquid.privateKey,
118
+ publicKey: profile.credentials.hyperliquid.walletAddress,
119
+ });
120
+ continue;
121
+ }
122
+ if (exchange === "decibel" && profile.credentials.decibel) {
123
+ create({
124
+ exchange,
125
+ userAddress: profile.credentials.decibel.apiWalletAddress,
126
+ privateKey: profile.credentials.decibel.apiWalletPrivateKey,
127
+ publicKey: profile.credentials.decibel.apiWalletAddress,
128
+ });
129
+ continue;
130
+ }
131
+ if (exchange === "aevo" && profile.credentials.aevo) {
132
+ const signingKey = profile.credentials.aevo.signingKey;
133
+ const address = privateKeyToAccount(signingKey).address;
134
+ create({
135
+ exchange,
136
+ userAddress: address,
137
+ privateKey: signingKey,
138
+ publicKey: address,
139
+ });
140
+ continue;
141
+ }
142
+ if (exchange === "orderly" && profile.credentials.orderly) {
143
+ create({
144
+ exchange,
145
+ userAddress: profile.credentials.orderly.accountId ?? profile.wallets.evmAddress,
146
+ privateKey: profile.credentials.orderly.tradingSecret,
147
+ publicKey: profile.wallets.evmAddress,
148
+ });
149
+ continue;
150
+ }
151
+ if (exchange === "paradex" && profile.credentials.paradex) {
152
+ create({
153
+ exchange,
154
+ userAddress: profile.credentials.paradex.accountAddress,
155
+ privateKey: profile.credentials.paradex.privateKey,
156
+ publicKey: profile.credentials.paradex.starkPublicKey,
157
+ });
158
+ continue;
159
+ }
160
+ results.push({
161
+ exchange,
162
+ alias,
163
+ status: "skipped",
164
+ detail: "no generated credentials available",
165
+ });
166
+ }
167
+ return results;
168
+ }
169
+ async function resolveMode(opts, assumeDefaults) {
170
+ if (opts.mode) {
171
+ return parseSetupMode(opts.mode);
172
+ }
173
+ if (assumeDefaults) {
174
+ return "both";
175
+ }
176
+ return select("Choose onboarding mode", [
177
+ {
178
+ value: "both",
179
+ label: "Mainnet data + testnet execution (recommended)",
180
+ description: MODE_DESCRIPTIONS.both,
181
+ },
182
+ {
183
+ value: "mainnet-data",
184
+ label: "Mainnet data only",
185
+ description: MODE_DESCRIPTIONS["mainnet-data"],
186
+ },
187
+ {
188
+ value: "testnet-execution",
189
+ label: "Testnet everywhere",
190
+ description: MODE_DESCRIPTIONS["testnet-execution"],
191
+ },
192
+ ]);
193
+ }
194
+ async function resolveExchanges(opts, assumeDefaults) {
195
+ if (opts.exchanges) {
196
+ return parseSetupExchanges(opts.exchanges);
197
+ }
198
+ if (opts.chains) {
199
+ return resolveExchangesFromChains(parseSetupChains(opts.chains));
200
+ }
201
+ if (assumeDefaults) {
202
+ return [...ALL_SETUP_EXCHANGES];
203
+ }
204
+ const selectedChains = await multiSelect("Select chains for automated testnet onboarding", ALL_SETUP_CHAINS.map((chain) => ({
205
+ value: chain,
206
+ label: chain.toUpperCase(),
207
+ description: CHAIN_DESCRIPTIONS[chain],
208
+ })));
209
+ if (selectedChains.length === 0) {
210
+ throw new Error("At least one chain must be selected");
211
+ }
212
+ const chainExchanges = resolveExchangesFromChains(selectedChains);
213
+ const customize = await confirm("Customize exchanges inside selected chains?", false);
214
+ if (!customize) {
215
+ return chainExchanges;
216
+ }
217
+ const selectedExchanges = await multiSelect("Select exchanges", chainExchanges.map((exchange) => ({
218
+ value: exchange,
219
+ label: exchange,
220
+ description: CHAIN_DESCRIPTIONS[exchange === "decibel" ? "aptos" : exchange === "paradex" ? "starknet" : "evm"],
221
+ })));
222
+ if (selectedExchanges.length === 0) {
223
+ throw new Error("At least one exchange must be selected");
224
+ }
225
+ return selectedExchanges;
226
+ }
227
+ function printMainnetOnlySummary() {
228
+ outputSuccess("Mainnet data mode is already ready out-of-the-box.");
229
+ console.log("");
230
+ console.log("Try:");
231
+ console.log(" perps markets ls");
232
+ console.log(" perps -e aevo markets ls");
233
+ console.log(" perps -e paradex markets ls");
234
+ console.log("");
235
+ }
236
+ function printWizardSummary(args) {
237
+ outputSuccess("Onboarding state machine completed");
238
+ console.log("");
239
+ console.log(`Mode: ${args.mode}`);
240
+ console.log(`Exchanges: ${args.exchanges.join(", ")}`);
241
+ console.log(`State file: ${args.stateFile}`);
242
+ if (args.vault) {
243
+ console.log(`Vault entry: ${args.vault.id}`);
244
+ console.log(`Vault path: ${args.vault.path}`);
245
+ }
246
+ if (args.exportedEnvFile) {
247
+ console.log(`Env export: ${args.exportedEnvFile}`);
248
+ }
249
+ if (args.wallets.evmAddress) {
250
+ console.log(`EVM wallet: ${args.wallets.evmAddress}`);
251
+ }
252
+ if (args.wallets.aptosAddress) {
253
+ console.log(`Aptos wallet: ${args.wallets.aptosAddress}`);
254
+ }
255
+ if (args.wallets.starkPublicKey) {
256
+ console.log(`Stark pubkey: ${args.wallets.starkPublicKey}`);
257
+ }
258
+ if (args.authResults.length > 0) {
259
+ console.log("");
260
+ console.log("Auth bootstrap:");
261
+ for (const result of args.authResults) {
262
+ console.log(` [${result.status}] ${result.service}: ${result.detail}`);
263
+ }
264
+ }
265
+ if (args.fundingResults.length > 0) {
266
+ console.log("");
267
+ console.log("Funding:");
268
+ for (const result of args.fundingResults) {
269
+ console.log(` [${result.status}] ${result.service}: ${result.detail}`);
270
+ }
271
+ }
272
+ if (args.accountSync.length > 0) {
273
+ console.log("");
274
+ console.log("Account sync:");
275
+ for (const result of args.accountSync) {
276
+ console.log(` [${result.status}] ${result.exchange}/${result.alias}: ${result.detail}`);
277
+ }
278
+ }
279
+ if (args.manualFollowUps.length > 0) {
280
+ console.log("");
281
+ console.log("Manual follow-ups:");
282
+ for (const item of args.manualFollowUps) {
283
+ const envKeys = item.env.length > 0 ? ` (${item.env.join(", ")})` : "";
284
+ console.log(` - ${item.exchange}${envKeys}: ${item.detail}`);
285
+ }
286
+ }
287
+ console.log("");
288
+ console.log("Next steps:");
289
+ if (args.exportedEnvFile) {
290
+ console.log(`1) source ${args.exportedEnvFile}`);
291
+ console.log("2) perps doctor --network");
292
+ console.log("3) perps markets ls");
293
+ console.log("4) perps order market buy BTC 0.001 --idempotency-key setup-smoke-001");
294
+ }
295
+ else {
296
+ console.log("1) Re-run with --export-env if you want a source-able env file");
297
+ console.log("2) perps doctor --network");
298
+ console.log("3) perps markets ls");
299
+ console.log("4) perps order market buy BTC 0.001 --idempotency-key setup-smoke-001");
300
+ }
301
+ console.log("");
302
+ }
303
+ export function registerSetupCommands(program) {
304
+ const setup = program.command("setup").description("Onboarding and environment setup");
305
+ setup
306
+ .command("wizard")
307
+ .description("Interactive setup for mainnet data defaults and testnet onboarding")
308
+ .option("--mode <mode>", `Onboarding mode (${["mainnet-data", "testnet-execution", "both"].join(", ")})`)
309
+ .option("--chains <chains>", "Comma-separated chains (evm,aptos,starknet)")
310
+ .option("--exchanges <exchanges>", "Comma-separated exchanges (overrides --chains)")
311
+ .option("--fund", "Attempt automated faucet requests where available")
312
+ .option("--orderly-broker-id <id>", "Orderly broker id (used for auth bootstrap + faucet)")
313
+ .option("--orderly-chain-id <id>", "Orderly chain id for auth/faucet bootstrap (default: 421614)")
314
+ .option("--aptos-faucet-jwt <jwt>", "Aptos faucet JWT for automated mint requests")
315
+ .option("--aptos-faucet-amount <amount>", "Aptos faucet amount in Octas")
316
+ .option("--no-bootstrap-auth", "Skip best-effort auth bootstrap")
317
+ .option("--decibel-bearer-token <token>", "Decibel bearer token override for bootstrap")
318
+ .option("--aevo-api-key <key>", "Aevo API key override for bootstrap")
319
+ .option("--aevo-api-secret <secret>", "Aevo API secret override for bootstrap")
320
+ .option("--aevo-account-private-key <key>", "Aevo account private key for auto-generating API creds")
321
+ .option("--aevo-rest-url <url>", "Aevo REST URL override for bootstrap auth")
322
+ .option("--orderly-account-id <id>", "Orderly account id override for bootstrap")
323
+ .option("--orderly-key <key>", "Orderly API key override for bootstrap")
324
+ .option("--orderly-secret <secret>", "Orderly API secret override for bootstrap")
325
+ .option("--orderly-rest-url <url>", "Orderly REST URL override for bootstrap auth")
326
+ .option("--paradex-bearer-token <token>", "Paradex bearer token override for bootstrap")
327
+ .option("--paradex-account-address <address>", "Paradex account address override for bootstrap")
328
+ .option("--paradex-ethereum-account <address>", "Paradex parent Ethereum account for onboarding bootstrap")
329
+ .option("--paradex-rest-url <url>", "Paradex REST URL override for bootstrap auth")
330
+ .option("--no-sync-accounts", "Skip syncing generated credentials to local account profiles")
331
+ .option("--file <path>", "Output file path", ".env.testnet.local")
332
+ .option("--export-env", "Export a source-able env file in addition to encrypted vault storage")
333
+ .option("--dry-run", "Show onboarding contract without writing state or files")
334
+ .option("--resume", "Resume from an existing onboarding state file")
335
+ .option("--state-file <path>", "Override onboarding state file path")
336
+ .option("--funding-retries <count>", "Retry failed automated funding tasks")
337
+ .option("--force", "Overwrite output file if it already exists")
338
+ .option("--yes", "Skip interactive prompts and use defaults")
339
+ .action(async function () {
340
+ const outputOpts = getOutputOptions(this);
341
+ const opts = this.opts();
342
+ const hasInteractiveTty = process.stdin.isTTY && process.stdout.isTTY;
343
+ const assumeDefaults = Boolean(opts.yes) || !hasInteractiveTty;
344
+ try {
345
+ const mode = await resolveMode(opts, assumeDefaults);
346
+ const networkDefaults = mode === "testnet-execution"
347
+ ? { data: "testnet", execution: "testnet" }
348
+ : { data: "mainnet", execution: "testnet" };
349
+ if (mode === "mainnet-data") {
350
+ const contract = withJsonContract("setup.wizard.result", {
351
+ mode,
352
+ ready: true,
353
+ networkDefaults,
354
+ message: "Public data commands work immediately with mainnet defaults.",
355
+ commands: ["perps markets ls", "perps -e aevo markets ls", "perps -e paradex markets ls"],
356
+ });
357
+ if (outputOpts.json) {
358
+ output(contract, outputOpts);
359
+ }
360
+ else {
361
+ printMainnetOnlySummary();
362
+ }
363
+ return;
364
+ }
365
+ const exchanges = await resolveExchanges(opts, assumeDefaults);
366
+ let shouldFund = Boolean(opts.fund);
367
+ if (!opts.fund && !assumeDefaults) {
368
+ shouldFund = await confirm("Attempt automated faucet funding now (best effort)?", true);
369
+ }
370
+ let shouldExportEnv = Boolean(opts.exportEnv);
371
+ if (!opts.exportEnv && !assumeDefaults) {
372
+ shouldExportEnv = await confirm("Also export a plaintext env file (credentials are always saved encrypted)?", false);
373
+ }
374
+ const fundingOptions = normalizeFundingOptions(opts);
375
+ const authOptions = normalizeAuthOptions(opts);
376
+ const shouldBootstrapAuth = opts.bootstrapAuth ?? true;
377
+ const shouldSyncAccounts = opts.syncAccounts ?? true;
378
+ const targetFile = resolve((opts.file ?? ".env.testnet.local").trim());
379
+ const stateFile = opts.stateFile ? resolve(opts.stateFile) : undefined;
380
+ const runResult = await runOnboardingStateMachine({
381
+ mode,
382
+ exchanges,
383
+ shouldFund,
384
+ fundingOptions,
385
+ shouldBootstrapAuth,
386
+ authOptions,
387
+ statePath: stateFile,
388
+ resume: Boolean(opts.resume),
389
+ fundingRetries: opts.fundingRetries ? Number.parseInt(opts.fundingRetries, 10) : undefined,
390
+ });
391
+ const profile = runResult.profile;
392
+ const authResults = runResult.authResults;
393
+ let vaultRef = null;
394
+ if (!opts.dryRun) {
395
+ vaultRef = saveOnboardingProfileToVault(profile);
396
+ }
397
+ const accountSync = !opts.dryRun && shouldSyncAccounts ? syncGeneratedAccounts(profile) : [];
398
+ let exportedEnvFile;
399
+ if (shouldExportEnv) {
400
+ const envFile = buildOnboardingEnvFile(profile);
401
+ const fileExists = existsSync(targetFile);
402
+ if (fileExists && !opts.force) {
403
+ if (assumeDefaults) {
404
+ throw new Error(`Refusing to overwrite existing file: ${targetFile}. Re-run with --force to replace it.`);
405
+ }
406
+ const overwrite = await confirm(`File exists (${targetFile}). Overwrite it?`, false);
407
+ if (!overwrite) {
408
+ throw new Error("Cancelled by user (file overwrite declined)");
409
+ }
410
+ }
411
+ if (!opts.dryRun) {
412
+ writeFileSync(targetFile, envFile, { mode: PRIVATE_FILE_MODE });
413
+ hardenPrivateFile(targetFile);
414
+ }
415
+ exportedEnvFile = targetFile;
416
+ }
417
+ const payload = withJsonContract("setup.wizard.result", {
418
+ mode,
419
+ dryRun: Boolean(opts.dryRun),
420
+ networkDefaults,
421
+ stateFile: runResult.statePath,
422
+ idempotencyKey: runResult.state.idempotencyKey,
423
+ chains: profile.chains,
424
+ exchanges: profile.exchanges,
425
+ wallets: profile.wallets,
426
+ vault: vaultRef,
427
+ vaultSummary: getCredentialVaultSummary(),
428
+ file: exportedEnvFile,
429
+ auth: authResults,
430
+ funding: runResult.fundingResults,
431
+ accountsSynced: accountSync,
432
+ manualFollowUps: profile.manualFollowUps,
433
+ nextSteps: exportedEnvFile
434
+ ? [
435
+ `source ${exportedEnvFile}`,
436
+ "perps doctor --network",
437
+ "perps markets ls",
438
+ "perps order market buy BTC 0.001 --idempotency-key setup-smoke-001",
439
+ ]
440
+ : [
441
+ "perps setup wizard --export-env",
442
+ "perps doctor --network",
443
+ "perps markets ls",
444
+ "perps order market buy BTC 0.001 --idempotency-key setup-smoke-001",
445
+ ],
446
+ stateNotes: runResult.state.notes,
447
+ stateStatus: runResult.state.statusByStep,
448
+ });
449
+ if (opts.dryRun) {
450
+ if (outputOpts.json) {
451
+ output(payload, outputOpts);
452
+ return;
453
+ }
454
+ outputSuccess("Dry-run only: no vault/env files were written.");
455
+ }
456
+ if (outputOpts.json) {
457
+ output(payload, outputOpts);
458
+ return;
459
+ }
460
+ printWizardSummary({
461
+ mode,
462
+ exchanges: profile.exchanges,
463
+ stateFile: runResult.statePath,
464
+ vault: vaultRef,
465
+ exportedEnvFile,
466
+ wallets: profile.wallets,
467
+ authResults,
468
+ fundingResults: runResult.fundingResults,
469
+ accountSync,
470
+ manualFollowUps: profile.manualFollowUps,
471
+ });
472
+ }
473
+ catch (err) {
474
+ outputError(err instanceof Error ? err.message : String(err));
475
+ process.exit(1);
476
+ }
477
+ });
478
+ }
@@ -0,0 +1,2 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerSignalCommands(program: Command): void;
@@ -0,0 +1,129 @@
1
+ import { getOutputOptions } from "../../cli/program.js";
2
+ import { output, outputSuccess } from "../../cli/output.js";
3
+ import { withJsonContract } from "../../lib/contracts.js";
4
+ import { addSignal, querySignals, getSignalSummary, } from "../../lib/signals.js";
5
+ export function registerSignalCommands(program) {
6
+ const signal = program.command("signal").description("Trade signal tracking (thumbs up/down feedback)");
7
+ signal
8
+ .command("add")
9
+ .description("Log a trade signal")
10
+ .requiredOption("--exchange <id>", "Exchange identifier")
11
+ .requiredOption("--signal <up|down>", "Signal value (up or down)")
12
+ .option("--trace <traceId>", "Trace ID to correlate with")
13
+ .option("--market <symbol>", "Market symbol (e.g. BTC-PERP)")
14
+ .option("--strategy <name>", "Strategy name")
15
+ .option("--reason <text>", "Reason for signal")
16
+ .option("--pnl <usd>", "Realized P&L in USD", Number.parseFloat)
17
+ .action(function () {
18
+ const opts = this.opts();
19
+ const signalValue = opts.signal.toLowerCase();
20
+ if (signalValue !== "up" && signalValue !== "down") {
21
+ console.error('Error: --signal must be "up" or "down"');
22
+ process.exitCode = 1;
23
+ return;
24
+ }
25
+ const id = addSignal({
26
+ traceId: opts.trace,
27
+ exchange: opts.exchange,
28
+ market: opts.market,
29
+ strategy: opts.strategy,
30
+ signal: signalValue,
31
+ reason: opts.reason,
32
+ pnlUsd: opts.pnl,
33
+ });
34
+ const outputOpts = getOutputOptions(this);
35
+ if (outputOpts.json) {
36
+ output(withJsonContract("signal.recorded", { id }), outputOpts);
37
+ }
38
+ else {
39
+ outputSuccess(`Signal recorded (id: ${id})`);
40
+ }
41
+ });
42
+ signal
43
+ .command("ls")
44
+ .description("List recent signals")
45
+ .option("--exchange <id>", "Filter by exchange")
46
+ .option("--market <symbol>", "Filter by market")
47
+ .option("--strategy <name>", "Filter by strategy")
48
+ .option("--signal <up|down>", "Filter by signal value")
49
+ .option("--last <minutes>", "Show signals from last N minutes", Number.parseFloat)
50
+ .option("--limit <n>", "Max results to return", Number.parseFloat)
51
+ .action(function () {
52
+ const outputOpts = getOutputOptions(this);
53
+ const opts = this.opts();
54
+ const signalFilter = opts.signal?.toLowerCase();
55
+ if (signalFilter && signalFilter !== "up" && signalFilter !== "down") {
56
+ console.error('Error: --signal must be "up" or "down"');
57
+ process.exitCode = 1;
58
+ return;
59
+ }
60
+ const signals = querySignals({
61
+ exchange: opts.exchange,
62
+ market: opts.market,
63
+ strategy: opts.strategy,
64
+ signal: signalFilter,
65
+ minutes: opts.last,
66
+ limit: opts.limit,
67
+ });
68
+ if (outputOpts.json) {
69
+ output(withJsonContract("signal.list", { signals }), outputOpts);
70
+ return;
71
+ }
72
+ if (signals.length === 0) {
73
+ console.log("\nNo signals found.\n");
74
+ return;
75
+ }
76
+ const rows = signals.map((s) => ({
77
+ ID: s.id,
78
+ Signal: s.signal,
79
+ Exchange: s.exchange,
80
+ Market: s.market ?? "",
81
+ Strategy: s.strategy ?? "",
82
+ "P&L": s.pnlUsd != null ? `$${s.pnlUsd.toFixed(2)}` : "",
83
+ Reason: s.reason ?? "",
84
+ Time: new Date(s.createdAt).toISOString(),
85
+ }));
86
+ output(rows, outputOpts);
87
+ });
88
+ signal
89
+ .command("summary")
90
+ .description("Show win rate and P&L summary")
91
+ .option("--last <minutes>", "Time window in minutes (default: 1440 = 24h)", Number.parseFloat, 1440)
92
+ .option("--exchange <id>", "Filter by exchange")
93
+ .option("--strategy <name>", "Filter by strategy")
94
+ .action(function () {
95
+ const outputOpts = getOutputOptions(this);
96
+ const opts = this.opts();
97
+ const summary = getSignalSummary({
98
+ minutes: opts.last,
99
+ exchange: opts.exchange,
100
+ strategy: opts.strategy,
101
+ });
102
+ if (outputOpts.json) {
103
+ output(withJsonContract("signal.summary", summary), outputOpts);
104
+ return;
105
+ }
106
+ console.log(`\n Signal Summary (last ${opts.last} min)`);
107
+ console.log(` ${"─".repeat(40)}`);
108
+ console.log(` Total signals: ${summary.total}`);
109
+ console.log(` Up / Down: ${summary.up} / ${summary.down}`);
110
+ console.log(` Win rate: ${(summary.winRate * 100).toFixed(1)}%`);
111
+ console.log(` Total P&L: $${summary.totalPnlUsd.toFixed(2)}`);
112
+ console.log(` Avg P&L: $${summary.avgPnlUsd.toFixed(2)}`);
113
+ if (summary.byStrategy.length > 0) {
114
+ console.log(`\n By Strategy`);
115
+ console.log(` ${"─".repeat(40)}`);
116
+ for (const s of summary.byStrategy) {
117
+ console.log(` ${s.strategy}: ${s.up}/${s.total} (${(s.winRate * 100).toFixed(1)}%) P&L: $${s.totalPnlUsd.toFixed(2)}`);
118
+ }
119
+ }
120
+ if (summary.byMarket.length > 0) {
121
+ console.log(`\n By Market`);
122
+ console.log(` ${"─".repeat(40)}`);
123
+ for (const m of summary.byMarket) {
124
+ console.log(` ${m.market}: ${m.up}/${m.total} (${(m.winRate * 100).toFixed(1)}%) P&L: $${m.totalPnlUsd.toFixed(2)}`);
125
+ }
126
+ }
127
+ console.log("");
128
+ });
129
+ }
@@ -0,0 +1,2 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerStateCommands(program: Command): void;
@@ -0,0 +1,5 @@
1
+ import { registerStateShowCommand } from "./show.js";
2
+ export function registerStateCommands(program) {
3
+ const state = program.command("state").description("Portfolio state and agent context");
4
+ registerStateShowCommand(state);
5
+ }
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function registerStateShowCommand(state: Command): void;