@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,259 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect, useMemo, useState } from "react";
3
+ import { Box, Text, render, useApp, useInput } from "ink";
4
+ import { getContext } from "../../cli/program.js";
5
+ import { AppShell, MetricStrip, Panel, Table, colors, toBar, toSparkline, } from "../../cli/ink/index.js";
6
+ import { pollFundingRates } from "../../lib/funding-tracker.js";
7
+ import { getSpreadStats, getRecordCount, cleanupOldRecords } from "../../lib/db/funding-history.js";
8
+ import { getAvailableExchanges } from "../../lib/exchange.js";
9
+ import { COMMON_ASSETS, FUNDING_HISTORY_RETENTION_DAYS } from "../../lib/constants.js";
10
+ import { parseAssetList, parsePositiveInt } from "../../lib/validate.js";
11
+ function formatRatePct(rate) {
12
+ const sign = rate >= 0 ? "+" : "";
13
+ return `${sign}${(rate * 100).toFixed(4)}%`;
14
+ }
15
+ function findExchangeRecord(assetRecords, exchange) {
16
+ return assetRecords.find((record) => record.exchange.toLowerCase().includes(exchange.toLowerCase()));
17
+ }
18
+ function edgeToSignal(edgeAnnualized, avg24h) {
19
+ if (edgeAnnualized >= 30 && (avg24h ?? 0) >= 10)
20
+ return "HUNT";
21
+ if (edgeAnnualized >= 10)
22
+ return "WATCH";
23
+ return "IDLE";
24
+ }
25
+ function signalColor(signal) {
26
+ if (signal === "HUNT")
27
+ return colors.profit;
28
+ if (signal === "WATCH")
29
+ return colors.warning;
30
+ return colors.muted;
31
+ }
32
+ function edgeColor(edgeAnnualized) {
33
+ if (edgeAnnualized >= 30)
34
+ return colors.profit;
35
+ if (edgeAnnualized >= 10)
36
+ return colors.warning;
37
+ return colors.muted;
38
+ }
39
+ function buildAssetSummaryRows(assets, exchanges, records, stats) {
40
+ const baseRows = assets.map((asset) => {
41
+ const market = `${asset}-PERP`;
42
+ const assetRecords = records.filter((record) => record.market === market);
43
+ const sorted = [...assetRecords].sort((left, right) => right.rate - left.rate);
44
+ const high = sorted[0];
45
+ const low = sorted[sorted.length - 1];
46
+ const edge = high && low ? (high.rate - low.rate) * 100 * 24 * 365 : 0;
47
+ const stat = stats.get(asset);
48
+ const rates = exchanges
49
+ .map((exchange) => {
50
+ const record = findExchangeRecord(assetRecords, exchange);
51
+ return record ? `${exchange}:${formatRatePct(record.rate)}` : `${exchange}:--`;
52
+ })
53
+ .join(" ");
54
+ return {
55
+ asset,
56
+ rates,
57
+ trend: toSparkline(assetRecords.map((record) => record.rate * 100), 10),
58
+ edge,
59
+ edgeBar: "",
60
+ avg24h: stat?.avg ?? null,
61
+ signal: edgeToSignal(edge, stat?.avg ?? null),
62
+ };
63
+ });
64
+ const maxEdge = Math.max(1, ...baseRows.map((row) => row.edge));
65
+ return baseRows.map((row) => ({
66
+ ...row,
67
+ edgeBar: toBar(row.edge, maxEdge, 10, "#", "."),
68
+ }));
69
+ }
70
+ function buildOpportunityRows(assets, records) {
71
+ const rows = [];
72
+ for (const asset of assets) {
73
+ const market = `${asset}-PERP`;
74
+ const assetRecords = records.filter((record) => record.market === market);
75
+ if (assetRecords.length < 2)
76
+ continue;
77
+ const sorted = [...assetRecords].sort((left, right) => right.rate - left.rate);
78
+ const high = sorted[0];
79
+ const low = sorted[sorted.length - 1];
80
+ const edge = (high.rate - low.rate) * 100 * 24 * 365;
81
+ rows.push({
82
+ market,
83
+ pair: `${high.exchange} -> ${low.exchange}`,
84
+ edge,
85
+ rates: `${formatRatePct(high.rate)} / ${formatRatePct(low.rate)}`,
86
+ });
87
+ }
88
+ return rows.sort((left, right) => right.edge - left.edge).slice(0, 8);
89
+ }
90
+ function TrackerUI({ assets, exchanges, intervalMin, testnet }) {
91
+ const [records, setRecords] = useState([]);
92
+ const [pollCount, setPollCount] = useState(0);
93
+ const [lastUpdate, setLastUpdate] = useState(null);
94
+ const [errors, setErrors] = useState(new Map());
95
+ const [stats, setStats] = useState(new Map());
96
+ const [pollMs, setPollMs] = useState(0);
97
+ const { exit } = useApp();
98
+ useInput((input, key) => {
99
+ if (input.toLowerCase() === "q" || key.escape || (key.ctrl && input.toLowerCase() === "c")) {
100
+ exit();
101
+ }
102
+ });
103
+ useEffect(() => {
104
+ let cancelled = false;
105
+ const doPoll = async () => {
106
+ const start = performance.now();
107
+ const pollErrors = new Map();
108
+ try {
109
+ const newRecords = await pollFundingRates(assets, exchanges, (err, exchange) => {
110
+ pollErrors.set(exchange, err.message);
111
+ }, testnet);
112
+ if (cancelled)
113
+ return;
114
+ setRecords(newRecords);
115
+ setLastUpdate(new Date());
116
+ setPollCount((count) => count + 1);
117
+ setPollMs(Math.round(performance.now() - start));
118
+ setErrors(pollErrors);
119
+ const newStats = new Map();
120
+ for (const asset of assets) {
121
+ const s = getSpreadStats(`${asset}-PERP`, 24);
122
+ if (s.samples > 0) {
123
+ newStats.set(asset, { avg: s.avgAnnualized, consistency: s.consistency });
124
+ }
125
+ }
126
+ setStats(newStats);
127
+ }
128
+ catch (err) {
129
+ if (cancelled)
130
+ return;
131
+ pollErrors.set("tracker", err instanceof Error ? err.message : String(err));
132
+ setErrors(pollErrors);
133
+ }
134
+ };
135
+ void doPoll();
136
+ const interval = setInterval(() => {
137
+ void doPoll();
138
+ }, intervalMin * 60 * 1000);
139
+ return () => {
140
+ cancelled = true;
141
+ clearInterval(interval);
142
+ };
143
+ }, [assets, exchanges, intervalMin, testnet]);
144
+ const assetRows = useMemo(() => buildAssetSummaryRows(assets, exchanges, records, stats), [assets, exchanges, records, stats]);
145
+ const opportunityRows = useMemo(() => buildOpportunityRows(assets, records), [assets, records]);
146
+ const assetColumns = useMemo(() => [
147
+ { key: "asset", header: "Asset", width: 8 },
148
+ { key: "rates", header: "Rates", width: Math.max(24, exchanges.length * 14) },
149
+ { key: "trend", header: "Trend", width: 10 },
150
+ {
151
+ key: "edge",
152
+ header: "Edge",
153
+ align: "right",
154
+ width: 24,
155
+ render: (value, row) => {
156
+ const edge = value;
157
+ return (_jsxs(Text, { color: edgeColor(edge), children: [row.edgeBar, " ", edge.toFixed(1), "%/yr"] }));
158
+ },
159
+ },
160
+ {
161
+ key: "avg24h",
162
+ header: "24h Avg",
163
+ align: "right",
164
+ width: 11,
165
+ render: (value) => {
166
+ const average = value;
167
+ if (average === null)
168
+ return _jsx(Text, { color: colors.muted, children: "--" });
169
+ return _jsxs(Text, { color: edgeColor(average), children: [average.toFixed(1), "%/yr"] });
170
+ },
171
+ },
172
+ {
173
+ key: "signal",
174
+ header: "Signal",
175
+ align: "right",
176
+ width: 6,
177
+ render: (value) => {
178
+ const signal = value;
179
+ return _jsx(Text, { color: signalColor(signal), children: signal });
180
+ },
181
+ },
182
+ ], [exchanges.length]);
183
+ const opportunityColumns = [
184
+ { key: "market", header: "Market", width: 10 },
185
+ { key: "pair", header: "Pair", width: 40 },
186
+ {
187
+ key: "edge",
188
+ header: "Edge",
189
+ align: "right",
190
+ width: 12,
191
+ render: (value) => {
192
+ const edge = value;
193
+ return _jsxs(Text, { color: edgeColor(edge), children: [edge.toFixed(1), "%/yr"] });
194
+ },
195
+ },
196
+ { key: "rates", header: "Rates", width: 24 },
197
+ ];
198
+ const totalRecords = getRecordCount();
199
+ const activeSignals = assetRows.filter((row) => row.signal !== "IDLE").length;
200
+ const metrics = [
201
+ { label: "Polls", value: String(pollCount), tone: "neutral" },
202
+ { label: "Rows", value: String(records.length), tone: "neutral" },
203
+ { label: "Stored", value: String(totalRecords), tone: "neutral" },
204
+ {
205
+ label: "Latency",
206
+ value: pollMs > 0 ? `${pollMs}ms` : "--",
207
+ tone: pollMs > 2_000 ? "danger" : pollMs > 1_000 ? "warning" : "success",
208
+ },
209
+ { label: "Signals", value: String(activeSignals), tone: activeSignals > 0 ? "info" : "neutral" },
210
+ ];
211
+ return (_jsxs(AppShell, { title: "Funding Rate Tracker", subtitle: `${testnet ? "testnet" : "mainnet"} • poll interval ${intervalMin}m`, status: [
212
+ { label: "LIVE", tone: "success" },
213
+ { label: `${errors.size} ERR`, tone: errors.size > 0 ? "danger" : "neutral" },
214
+ ], lastUpdated: lastUpdate ?? undefined, shortcuts: [
215
+ { key: "q", label: "quit" },
216
+ { key: "esc", label: "quit" },
217
+ { key: "ctrl+c", label: "quit" },
218
+ ], children: [_jsx(MetricStrip, { metrics: metrics }), _jsx(Box, { flexDirection: "column", marginBottom: 1, children: _jsx(Panel, { title: "Asset Matrix", subtitle: "Cross-exchange rates, edge bars, and 24h signal quality", tone: "info", children: assetRows.length === 0 ? (_jsx(Text, { color: colors.muted, children: "Waiting for first poll..." })) : (_jsx(Table, { data: assetRows, columns: assetColumns })) }) }), _jsx(Box, { flexDirection: "column", marginBottom: errors.size > 0 ? 1 : 0, children: _jsx(Panel, { title: "Top Opportunities", subtitle: "Best spread by asset from latest poll", children: opportunityRows.length === 0 ? (_jsx(Text, { color: colors.muted, children: "Need at least 2 exchange quotes per asset." })) : (_jsx(Table, { data: opportunityRows, columns: opportunityColumns })) }) }), errors.size > 0 && (_jsx(Panel, { title: "Errors", subtitle: "Latest polling errors by exchange", tone: "danger", children: _jsx(Box, { flexDirection: "column", children: Array.from(errors.entries()).map(([exchange, message]) => (_jsxs(Text, { color: colors.loss, children: [exchange, ": ", message] }, exchange))) }) }))] }));
219
+ }
220
+ export function registerArbTrackCommand(arb) {
221
+ arb
222
+ .command("track")
223
+ .description("Start live funding rate tracking")
224
+ .option("-a, --assets <assets>", "Comma-separated assets to track", COMMON_ASSETS.join(","))
225
+ .option("-i, --interval <minutes>", "Poll interval in minutes", "5")
226
+ .option("--once", "Poll once and exit (no live tracking)")
227
+ .option("--cleanup", `Clean up old records (>${FUNDING_HISTORY_RETENTION_DAYS} days)`)
228
+ .action(async function () {
229
+ const ctx = getContext(this);
230
+ const opts = this.opts();
231
+ const assets = parseAssetList(opts.assets, COMMON_ASSETS);
232
+ const intervalMin = parsePositiveInt(opts.interval, "interval", 5);
233
+ const exchanges = getAvailableExchanges();
234
+ const isTestnet = ctx.config.testnet;
235
+ if (opts.cleanup) {
236
+ const deleted = cleanupOldRecords(FUNDING_HISTORY_RETENTION_DAYS);
237
+ console.log(`Cleaned up ${deleted} old records`);
238
+ return;
239
+ }
240
+ if (opts.once) {
241
+ console.log(`\nPolling funding rates for ${assets.join(", ")}...\n`);
242
+ const records = await pollFundingRates(assets, exchanges, undefined, isTestnet);
243
+ console.log("Exchange".padEnd(16) + "Market".padEnd(12) + "Rate".padEnd(14) + "Annualized");
244
+ console.log("─".repeat(55));
245
+ for (const r of records.sort((a, b) => a.market.localeCompare(b.market) || b.rate - a.rate)) {
246
+ const sign = r.rate >= 0 ? "+" : "";
247
+ console.log(`${r.exchange.padEnd(14)}` +
248
+ `${r.market.padEnd(12)}` +
249
+ `${sign}${(r.rate * 100).toFixed(4)}%`.padEnd(14) +
250
+ `${sign}${r.annualized.toFixed(2)}%`);
251
+ }
252
+ console.log(`\nStored ${records.length} records`);
253
+ return;
254
+ }
255
+ // Live tracking UI
256
+ const { waitUntilExit } = render(_jsx(TrackerUI, { assets: assets, exchanges: exchanges, intervalMin: intervalMin, testnet: isTestnet }));
257
+ await waitUntilExit();
258
+ });
259
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Simple order book command using the adapter interface
3
+ */
4
+ import { Command } from "commander";
5
+ export declare function registerBookSimpleCommand(asset: Command): void;
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Simple order book command using the adapter interface
3
+ */
4
+ import { getContext, getOutputOptions } from "../../cli/program.js";
5
+ import { output, outputError } from "../../cli/output.js";
6
+ import { getExchangeAdapter } from "../../lib/exchange.js";
7
+ export function registerBookSimpleCommand(asset) {
8
+ asset
9
+ .command("book <symbol>")
10
+ .description("Show order book for an asset")
11
+ .option("-d, --depth <number>", "Order book depth", "10")
12
+ .action(async function (symbol) {
13
+ const ctx = getContext(this);
14
+ const outputOpts = getOutputOptions(this);
15
+ const opts = this.opts();
16
+ const depth = parseInt(opts.depth, 10);
17
+ const adapter = getExchangeAdapter();
18
+ let connected = false;
19
+ try {
20
+ await adapter.connect({ testnet: ctx.config.testnet });
21
+ connected = true;
22
+ // Normalize symbol (accept BTC, BTC-PERP, btc, etc.)
23
+ let market = symbol.toUpperCase();
24
+ if (!market.includes("-")) {
25
+ market = `${market}-PERP`;
26
+ }
27
+ const book = await adapter.getOrderBook(market, depth);
28
+ if (outputOpts.json) {
29
+ output(book, outputOpts);
30
+ }
31
+ else {
32
+ console.log(`\n${adapter.info.name} Order Book: ${book.market}\n`);
33
+ // Calculate max sizes for formatting
34
+ const maxBidSize = Math.max(...book.bids.map(b => parseFloat(b.size)));
35
+ const maxAskSize = Math.max(...book.asks.map(a => parseFloat(a.size)));
36
+ const maxSize = Math.max(maxBidSize, maxAskSize);
37
+ // Header
38
+ console.log(" " + "Price".padEnd(14) + "Size".padEnd(14) + "│".padEnd(3) + "Price".padEnd(14) + "Size");
39
+ console.log(" " + "─".repeat(14) + "─".repeat(14) + "│" + "─".repeat(14) + "─".repeat(14));
40
+ // Asks (reversed so lowest ask is at bottom)
41
+ const asks = [...book.asks].reverse();
42
+ for (const ask of asks) {
43
+ const bar = "█".repeat(Math.ceil((parseFloat(ask.size) / maxSize) * 10));
44
+ console.log(" " + " ".repeat(28) + "│ " +
45
+ `\x1b[31m${parseFloat(ask.price).toFixed(2).padEnd(13)}\x1b[0m` +
46
+ parseFloat(ask.size).toFixed(4).padEnd(10) +
47
+ `\x1b[31m${bar}\x1b[0m`);
48
+ }
49
+ // Spread
50
+ const bestBid = book.bids[0] ? parseFloat(book.bids[0].price) : 0;
51
+ const bestAsk = book.asks[0] ? parseFloat(book.asks[0].price) : 0;
52
+ const spread = bestAsk - bestBid;
53
+ const spreadPct = bestBid > 0 ? ((spread / bestBid) * 100).toFixed(4) : "0";
54
+ console.log(" " + " ".repeat(28) + "│ " + `Spread: $${spread.toFixed(2)} (${spreadPct}%)`);
55
+ // Bids
56
+ for (const bid of book.bids) {
57
+ const bar = "█".repeat(Math.ceil((parseFloat(bid.size) / maxSize) * 10));
58
+ console.log(" " +
59
+ `\x1b[32m${parseFloat(bid.price).toFixed(2).padEnd(13)}\x1b[0m` +
60
+ parseFloat(bid.size).toFixed(4).padEnd(10) +
61
+ `\x1b[32m${bar}\x1b[0m` +
62
+ " ".repeat(5) + "│");
63
+ }
64
+ console.log("");
65
+ }
66
+ }
67
+ catch (err) {
68
+ outputError(err instanceof Error ? err.message : String(err));
69
+ process.exitCode = 1;
70
+ }
71
+ finally {
72
+ if (connected) {
73
+ await adapter.disconnect().catch(() => undefined);
74
+ }
75
+ }
76
+ });
77
+ }
@@ -0,0 +1,2 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerAssetCommands(program: Command): void;
@@ -0,0 +1,5 @@
1
+ import { registerBookSimpleCommand } from "./book-simple.js";
2
+ export function registerAssetCommands(program) {
3
+ const asset = program.command("asset").description("Asset-specific information");
4
+ registerBookSimpleCommand(asset);
5
+ }
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function registerCompletionCommand(program: Command): void;
@@ -0,0 +1,161 @@
1
+ import { getAvailableExchanges } from "../lib/exchange.js";
2
+ /**
3
+ * Walk the Commander command tree to collect all command paths
4
+ */
5
+ function collectCommandPaths(cmd, prefix = []) {
6
+ const paths = [];
7
+ for (const sub of cmd.commands) {
8
+ const current = [...prefix, sub.name()];
9
+ paths.push(current);
10
+ paths.push(...collectCommandPaths(sub, current));
11
+ }
12
+ return paths;
13
+ }
14
+ function generateBashCompletion(program) {
15
+ const paths = collectCommandPaths(program);
16
+ const exchanges = getAvailableExchanges();
17
+ // Build subcommand map: "perps" -> ["account", "markets", ...], "perps account" -> ["ls", "add", ...]
18
+ const subcommandMap = new Map();
19
+ subcommandMap.set("perps", new Set(program.commands.map((c) => c.name())));
20
+ for (const path of paths) {
21
+ const key = ["perps", ...path.slice(0, -1)].join(" ");
22
+ const child = path[path.length - 1];
23
+ if (!subcommandMap.has(key))
24
+ subcommandMap.set(key, new Set());
25
+ subcommandMap.get(key).add(child);
26
+ }
27
+ const cases = Array.from(subcommandMap.entries())
28
+ .map(([key, children]) => {
29
+ const words = Array.from(children).sort().join(" ");
30
+ return ` "${key}") COMPREPLY=( $(compgen -W "${words}" -- "\${cur}") ) ;;`;
31
+ })
32
+ .join("\n");
33
+ return `# bash completion for perps
34
+ # Add to ~/.bashrc: eval "$(perps completion bash)"
35
+ _perps_completions() {
36
+ local cur prev words
37
+ COMPREPLY=()
38
+ cur="\${COMP_WORDS[COMP_CWORD]}"
39
+ prev="\${COMP_WORDS[COMP_CWORD-1]}"
40
+
41
+ # Global flags
42
+ if [[ "\${cur}" == -* ]]; then
43
+ COMPREPLY=( $(compgen -W "--json --human --no-banner --testnet --mainnet --exchange --help --version" -- "\${cur}") )
44
+ return
45
+ fi
46
+
47
+ # Exchange names for --exchange / -e
48
+ if [[ "\${prev}" == "--exchange" || "\${prev}" == "-e" ]]; then
49
+ COMPREPLY=( $(compgen -W "${exchanges.join(" ")}" -- "\${cur}") )
50
+ return
51
+ fi
52
+
53
+ # Subcommands
54
+ local cmd_path="\${COMP_WORDS[*]:0:COMP_CWORD}"
55
+ case "\${cmd_path}" in
56
+ ${cases}
57
+ esac
58
+ }
59
+ complete -F _perps_completions perps
60
+ `;
61
+ }
62
+ function generateZshCompletion(program) {
63
+ const paths = collectCommandPaths(program);
64
+ const exchanges = getAvailableExchanges();
65
+ const subcommandMap = new Map();
66
+ subcommandMap.set("perps", new Set(program.commands.map((c) => c.name())));
67
+ for (const path of paths) {
68
+ const key = ["perps", ...path.slice(0, -1)].join(" ");
69
+ const child = path[path.length - 1];
70
+ if (!subcommandMap.has(key))
71
+ subcommandMap.set(key, new Set());
72
+ subcommandMap.get(key).add(child);
73
+ }
74
+ const cases = Array.from(subcommandMap.entries())
75
+ .map(([key, children]) => {
76
+ const words = Array.from(children).sort().join(" ");
77
+ return ` ${key}) compadd ${words} ;;`;
78
+ })
79
+ .join("\n");
80
+ return `# zsh completion for perps
81
+ # Add to ~/.zshrc: eval "$(perps completion zsh)"
82
+ _perps() {
83
+ local -a exchanges=(${exchanges.join(" ")})
84
+
85
+ # Global flags
86
+ if [[ "\${words[\${CURRENT}]}" == -* ]]; then
87
+ compadd -- --json --human --no-banner --testnet --mainnet --exchange --help --version
88
+ return
89
+ fi
90
+
91
+ # Exchange names for --exchange / -e
92
+ if [[ "\${words[\${CURRENT}-1]}" == "--exchange" || "\${words[\${CURRENT}-1]}" == "-e" ]]; then
93
+ compadd -- \${exchanges[@]}
94
+ return
95
+ fi
96
+
97
+ # Subcommands
98
+ local cmd_path="\${words[1,\${CURRENT}-1]}"
99
+ case "\${cmd_path}" in
100
+ ${cases}
101
+ esac
102
+ }
103
+ compdef _perps perps
104
+ `;
105
+ }
106
+ function generateFishCompletion(program) {
107
+ const paths = collectCommandPaths(program);
108
+ const exchanges = getAvailableExchanges();
109
+ const lines = [
110
+ "# fish completion for perps",
111
+ '# Save to ~/.config/fish/completions/perps.fish or run: perps completion fish | source',
112
+ "",
113
+ "# Global flags",
114
+ "complete -c perps -l json -d 'Output in JSON format'",
115
+ "complete -c perps -l human -d 'Enable human-first output UX'",
116
+ "complete -c perps -l no-banner -d 'Disable session header'",
117
+ "complete -c perps -l testnet -d 'Force testnet network'",
118
+ "complete -c perps -l mainnet -d 'Force mainnet network'",
119
+ `complete -c perps -s e -l exchange -xa '${exchanges.join(" ")}' -d 'Exchange to use'`,
120
+ "",
121
+ ];
122
+ // Top-level subcommands
123
+ for (const cmd of program.commands) {
124
+ const desc = cmd.description() || cmd.name();
125
+ lines.push(`complete -c perps -n '__fish_use_subcommand' -a '${cmd.name()}' -d '${desc.replace(/'/g, "\\'")}'`);
126
+ }
127
+ // Nested subcommands
128
+ for (const path of paths) {
129
+ if (path.length < 2)
130
+ continue;
131
+ const parent = path.slice(0, -1);
132
+ const child = path[path.length - 1];
133
+ const condition = parent
134
+ .map((p, _i) => `__fish_seen_subcommand_from ${p}`)
135
+ .join("; and ");
136
+ lines.push(`complete -c perps -n '${condition}' -a '${child}'`);
137
+ }
138
+ return lines.join("\n") + "\n";
139
+ }
140
+ export function registerCompletionCommand(program) {
141
+ program
142
+ .command("completion")
143
+ .description("Generate shell completion scripts")
144
+ .argument("[shell]", "Shell type: bash, zsh, or fish", "bash")
145
+ .action((shell) => {
146
+ switch (shell.toLowerCase()) {
147
+ case "bash":
148
+ console.log(generateBashCompletion(program));
149
+ break;
150
+ case "zsh":
151
+ console.log(generateZshCompletion(program));
152
+ break;
153
+ case "fish":
154
+ console.log(generateFishCompletion(program));
155
+ break;
156
+ default:
157
+ console.error(`Unknown shell: ${shell}. Supported: bash, zsh, fish`);
158
+ process.exit(1);
159
+ }
160
+ });
161
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Config commands for managing settings
3
+ */
4
+ import { Command } from "commander";
5
+ export declare function registerConfigCommands(program: Command): void;
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Config commands for managing settings
3
+ */
4
+ import { getOutputOptions } from "../../cli/program.js";
5
+ import { output, outputSuccess, outputError } from "../../cli/output.js";
6
+ import { getSetting, setSetting, getAllSettings, resetSettings } from "../../lib/settings.js";
7
+ import { getAvailableExchanges, isExchangeSupported } from "../../lib/exchange.js";
8
+ const VALID_SETTING_KEYS = ["defaultExchange", "testnetByDefault"];
9
+ function isConfigKey(key) {
10
+ return VALID_SETTING_KEYS.includes(key);
11
+ }
12
+ export function registerConfigCommands(program) {
13
+ const config = program
14
+ .command("config")
15
+ .description("Manage CLI configuration");
16
+ // Show all settings
17
+ config
18
+ .command("show")
19
+ .description("Show current configuration")
20
+ .action(function () {
21
+ const outputOpts = getOutputOptions(this);
22
+ const settings = getAllSettings();
23
+ if (outputOpts.json) {
24
+ output(settings, outputOpts);
25
+ }
26
+ else {
27
+ console.log("\nCurrent Configuration:\n");
28
+ console.log(` Default Exchange: ${settings.defaultExchange}`);
29
+ console.log(` Testnet Fallback: ${settings.testnetByDefault}`);
30
+ console.log(" Network Rules: data=mainnet, execution=testnet (unless overridden)");
31
+ console.log(`\nAvailable Exchanges: ${getAvailableExchanges().join(", ")}`);
32
+ console.log("");
33
+ }
34
+ });
35
+ // Get a specific setting
36
+ config
37
+ .command("get <key>")
38
+ .description("Get a configuration value")
39
+ .action(function (key) {
40
+ const outputOpts = getOutputOptions(this);
41
+ if (!isConfigKey(key)) {
42
+ outputError(`Unknown setting: ${key}`);
43
+ console.error(`Valid settings: ${VALID_SETTING_KEYS.join(", ")}`);
44
+ process.exit(1);
45
+ }
46
+ const value = getSetting(key);
47
+ if (outputOpts.json) {
48
+ output({ [key]: value }, outputOpts);
49
+ }
50
+ else {
51
+ console.log(value);
52
+ }
53
+ });
54
+ // Set a specific setting
55
+ config
56
+ .command("set <key> <value>")
57
+ .description("Set a configuration value")
58
+ .action(function (key, value) {
59
+ const outputOpts = getOutputOptions(this);
60
+ // Validate key
61
+ if (!isConfigKey(key)) {
62
+ outputError(`Unknown setting: ${key}`);
63
+ console.error(`Valid settings: ${VALID_SETTING_KEYS.join(", ")}`);
64
+ process.exit(1);
65
+ }
66
+ if (key === "defaultExchange") {
67
+ if (!isExchangeSupported(value)) {
68
+ outputError(`Unknown exchange: ${value}`);
69
+ console.error(`Available exchanges: ${getAvailableExchanges().join(", ")}`);
70
+ process.exit(1);
71
+ }
72
+ const finalValue = value.toLowerCase();
73
+ setSetting(key, finalValue);
74
+ if (outputOpts.json) {
75
+ output({ [key]: finalValue, success: true }, outputOpts);
76
+ }
77
+ else {
78
+ outputSuccess(`Set ${key} = ${finalValue}`);
79
+ }
80
+ return;
81
+ }
82
+ if (!["true", "false"].includes(value.toLowerCase())) {
83
+ outputError("Value must be 'true' or 'false'");
84
+ process.exit(1);
85
+ }
86
+ const finalValue = value.toLowerCase() === "true";
87
+ setSetting(key, finalValue);
88
+ if (outputOpts.json) {
89
+ output({ [key]: finalValue, success: true }, outputOpts);
90
+ }
91
+ else {
92
+ outputSuccess(`Set ${key} = ${finalValue}`);
93
+ }
94
+ });
95
+ // Reset all settings
96
+ config
97
+ .command("reset")
98
+ .description("Reset all settings to defaults")
99
+ .action(function () {
100
+ const outputOpts = getOutputOptions(this);
101
+ resetSettings();
102
+ if (outputOpts.json) {
103
+ output({ success: true, message: "Settings reset to defaults" }, outputOpts);
104
+ }
105
+ else {
106
+ outputSuccess("Settings reset to defaults");
107
+ }
108
+ });
109
+ }
@@ -0,0 +1,31 @@
1
+ import type { Command } from "commander";
2
+ export type JsonObject = Record<string, unknown>;
3
+ type DynamicClient = Record<string, unknown> & {
4
+ close?: () => Promise<unknown> | unknown;
5
+ setSandboxMode?: (enabled: boolean) => void;
6
+ };
7
+ interface CcxtFuturesOperationOptions {
8
+ symbol?: string;
9
+ symbols?: string[];
10
+ id?: string;
11
+ side?: string;
12
+ orderType?: string;
13
+ amount?: number;
14
+ price?: number;
15
+ since?: number;
16
+ limit?: number;
17
+ leverage?: number;
18
+ marginMode?: string;
19
+ positionMode?: string;
20
+ code?: string;
21
+ from?: string;
22
+ to?: string;
23
+ params: JsonObject;
24
+ rawMethod?: string;
25
+ rawArgs: unknown[];
26
+ }
27
+ export declare function parseJsonArray(raw: string): unknown[];
28
+ export declare function parseJsonObject(raw: string, label?: string): JsonObject;
29
+ export declare function executeCcxtFuturesOperation(instance: DynamicClient, operationRaw: string, input: CcxtFuturesOperationOptions): Promise<unknown>;
30
+ export declare function registerDataCommands(program: Command): void;
31
+ export {};