@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.
- package/CHANGELOG.md +33 -0
- package/LICENSE +21 -0
- package/README.md +175 -0
- package/dist/adapters/aevo.d.ts +64 -0
- package/dist/adapters/aevo.js +899 -0
- package/dist/adapters/certification.d.ts +33 -0
- package/dist/adapters/certification.js +99 -0
- package/dist/adapters/decibel/order-manager.d.ts +45 -0
- package/dist/adapters/decibel/order-manager.js +140 -0
- package/dist/adapters/decibel/rest-client.d.ts +176 -0
- package/dist/adapters/decibel/rest-client.js +155 -0
- package/dist/adapters/decibel/ws-feed.d.ts +28 -0
- package/dist/adapters/decibel/ws-feed.js +166 -0
- package/dist/adapters/decibel.d.ts +108 -0
- package/dist/adapters/decibel.js +1377 -0
- package/dist/adapters/hyperliquid.d.ts +63 -0
- package/dist/adapters/hyperliquid.js +797 -0
- package/dist/adapters/index.d.ts +11 -0
- package/dist/adapters/index.js +12 -0
- package/dist/adapters/interface.d.ts +310 -0
- package/dist/adapters/interface.js +15 -0
- package/dist/adapters/orderly.d.ts +70 -0
- package/dist/adapters/orderly.js +936 -0
- package/dist/adapters/paradex.d.ts +69 -0
- package/dist/adapters/paradex.js +862 -0
- package/dist/adapters/utils.d.ts +17 -0
- package/dist/adapters/utils.js +122 -0
- package/dist/cli/command-metadata.d.ts +2 -0
- package/dist/cli/command-metadata.js +44 -0
- package/dist/cli/context.d.ts +14 -0
- package/dist/cli/context.js +59 -0
- package/dist/cli/experience.d.ts +48 -0
- package/dist/cli/experience.js +243 -0
- package/dist/cli/ink/app/AppShell.d.ts +12 -0
- package/dist/cli/ink/app/AppShell.js +32 -0
- package/dist/cli/ink/app/MetricStrip.d.ts +6 -0
- package/dist/cli/ink/app/MetricStrip.js +14 -0
- package/dist/cli/ink/app/Panel.d.ts +9 -0
- package/dist/cli/ink/app/Panel.js +7 -0
- package/dist/cli/ink/app/ascii.d.ts +2 -0
- package/dist/cli/ink/app/ascii.js +46 -0
- package/dist/cli/ink/app/index.d.ts +5 -0
- package/dist/cli/ink/app/index.js +4 -0
- package/dist/cli/ink/app/types.d.ts +15 -0
- package/dist/cli/ink/app/types.js +1 -0
- package/dist/cli/ink/components/PnL.d.ts +12 -0
- package/dist/cli/ink/components/PnL.js +23 -0
- package/dist/cli/ink/components/Spinner.d.ts +13 -0
- package/dist/cli/ink/components/Spinner.js +13 -0
- package/dist/cli/ink/components/Table.d.ts +14 -0
- package/dist/cli/ink/components/Table.js +42 -0
- package/dist/cli/ink/components/WatchHeader.d.ts +10 -0
- package/dist/cli/ink/components/WatchHeader.js +18 -0
- package/dist/cli/ink/components/index.d.ts +4 -0
- package/dist/cli/ink/components/index.js +4 -0
- package/dist/cli/ink/index.d.ts +4 -0
- package/dist/cli/ink/index.js +4 -0
- package/dist/cli/ink/render.d.ts +12 -0
- package/dist/cli/ink/render.js +21 -0
- package/dist/cli/ink/theme.d.ts +29 -0
- package/dist/cli/ink/theme.js +40 -0
- package/dist/cli/network-defaults.d.ts +10 -0
- package/dist/cli/network-defaults.js +35 -0
- package/dist/cli/output.d.ts +11 -0
- package/dist/cli/output.js +115 -0
- package/dist/cli/program.d.ts +18 -0
- package/dist/cli/program.js +164 -0
- package/dist/cli/watch.d.ts +19 -0
- package/dist/cli/watch.js +35 -0
- package/dist/client/index.d.ts +55 -0
- package/dist/client/index.js +157 -0
- package/dist/commands/account/add.d.ts +2 -0
- package/dist/commands/account/add.js +510 -0
- package/dist/commands/account/balances-simple.d.ts +5 -0
- package/dist/commands/account/balances-simple.js +63 -0
- package/dist/commands/account/index.d.ts +2 -0
- package/dist/commands/account/index.js +17 -0
- package/dist/commands/account/ls.d.ts +2 -0
- package/dist/commands/account/ls.js +95 -0
- package/dist/commands/account/positions-simple.d.ts +5 -0
- package/dist/commands/account/positions-simple.js +77 -0
- package/dist/commands/account/remove.d.ts +2 -0
- package/dist/commands/account/remove.js +47 -0
- package/dist/commands/account/set-default.d.ts +2 -0
- package/dist/commands/account/set-default.js +47 -0
- package/dist/commands/agent/index.d.ts +2 -0
- package/dist/commands/agent/index.js +126 -0
- package/dist/commands/arb/alert.d.ts +6 -0
- package/dist/commands/arb/alert.js +88 -0
- package/dist/commands/arb/basis-execute.d.ts +6 -0
- package/dist/commands/arb/basis-execute.js +332 -0
- package/dist/commands/arb/basis.d.ts +6 -0
- package/dist/commands/arb/basis.js +181 -0
- package/dist/commands/arb/compare.d.ts +6 -0
- package/dist/commands/arb/compare.js +216 -0
- package/dist/commands/arb/execute.d.ts +6 -0
- package/dist/commands/arb/execute.js +467 -0
- package/dist/commands/arb/funding.d.ts +6 -0
- package/dist/commands/arb/funding.js +201 -0
- package/dist/commands/arb/history.d.ts +6 -0
- package/dist/commands/arb/history.js +153 -0
- package/dist/commands/arb/index.d.ts +6 -0
- package/dist/commands/arb/index.js +29 -0
- package/dist/commands/arb/positions.d.ts +6 -0
- package/dist/commands/arb/positions.js +158 -0
- package/dist/commands/arb/spread.d.ts +6 -0
- package/dist/commands/arb/spread.js +253 -0
- package/dist/commands/arb/track.d.ts +6 -0
- package/dist/commands/arb/track.js +259 -0
- package/dist/commands/asset/book-simple.d.ts +5 -0
- package/dist/commands/asset/book-simple.js +77 -0
- package/dist/commands/asset/index.d.ts +2 -0
- package/dist/commands/asset/index.js +5 -0
- package/dist/commands/completion.d.ts +2 -0
- package/dist/commands/completion.js +161 -0
- package/dist/commands/config/index.d.ts +5 -0
- package/dist/commands/config/index.js +109 -0
- package/dist/commands/data/index.d.ts +31 -0
- package/dist/commands/data/index.js +1466 -0
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.js +201 -0
- package/dist/commands/exchange/index.d.ts +2 -0
- package/dist/commands/exchange/index.js +107 -0
- package/dist/commands/index.d.ts +2 -0
- package/dist/commands/index.js +48 -0
- package/dist/commands/markets/index.d.ts +2 -0
- package/dist/commands/markets/index.js +5 -0
- package/dist/commands/markets/ls-simple.d.ts +7 -0
- package/dist/commands/markets/ls-simple.js +277 -0
- package/dist/commands/operator/index.d.ts +2 -0
- package/dist/commands/operator/index.js +146 -0
- package/dist/commands/order/cancel-simple.d.ts +5 -0
- package/dist/commands/order/cancel-simple.js +104 -0
- package/dist/commands/order/index.d.ts +2 -0
- package/dist/commands/order/index.js +13 -0
- package/dist/commands/order/limit-simple.d.ts +5 -0
- package/dist/commands/order/limit-simple.js +195 -0
- package/dist/commands/order/market-simple.d.ts +5 -0
- package/dist/commands/order/market-simple.js +190 -0
- package/dist/commands/order/shared.d.ts +17 -0
- package/dist/commands/order/shared.js +51 -0
- package/dist/commands/order/trigger-simple.d.ts +5 -0
- package/dist/commands/order/trigger-simple.js +246 -0
- package/dist/commands/referral/index.d.ts +2 -0
- package/dist/commands/referral/index.js +7 -0
- package/dist/commands/referral/set.d.ts +2 -0
- package/dist/commands/referral/set.js +26 -0
- package/dist/commands/referral/status.d.ts +2 -0
- package/dist/commands/referral/status.js +31 -0
- package/dist/commands/replay/index.d.ts +2 -0
- package/dist/commands/replay/index.js +152 -0
- package/dist/commands/risk/analytics.d.ts +2 -0
- package/dist/commands/risk/analytics.js +64 -0
- package/dist/commands/risk/audit.d.ts +2 -0
- package/dist/commands/risk/audit.js +52 -0
- package/dist/commands/risk/index.d.ts +2 -0
- package/dist/commands/risk/index.js +9 -0
- package/dist/commands/risk/rules.d.ts +2 -0
- package/dist/commands/risk/rules.js +102 -0
- package/dist/commands/server.d.ts +2 -0
- package/dist/commands/server.js +208 -0
- package/dist/commands/setup/index.d.ts +2 -0
- package/dist/commands/setup/index.js +478 -0
- package/dist/commands/signal/index.d.ts +2 -0
- package/dist/commands/signal/index.js +129 -0
- package/dist/commands/state/index.d.ts +2 -0
- package/dist/commands/state/index.js +5 -0
- package/dist/commands/state/show.d.ts +2 -0
- package/dist/commands/state/show.js +105 -0
- package/dist/commands/strategy/index.d.ts +4 -0
- package/dist/commands/strategy/index.js +73 -0
- package/dist/commands/traces/index.d.ts +2 -0
- package/dist/commands/traces/index.js +76 -0
- package/dist/commands/ui/demo.d.ts +9 -0
- package/dist/commands/ui/demo.js +195 -0
- package/dist/commands/ui/index.d.ts +2 -0
- package/dist/commands/ui/index.js +7 -0
- package/dist/commands/ui/terminal.d.ts +2 -0
- package/dist/commands/ui/terminal.js +255 -0
- package/dist/commands/upgrade.d.ts +2 -0
- package/dist/commands/upgrade.js +98 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +4 -0
- package/dist/lib/agent/audit.d.ts +12 -0
- package/dist/lib/agent/audit.js +13 -0
- package/dist/lib/agent/gateway.d.ts +13 -0
- package/dist/lib/agent/gateway.js +598 -0
- package/dist/lib/agent/metrics.d.ts +33 -0
- package/dist/lib/agent/metrics.js +175 -0
- package/dist/lib/agent/signature.d.ts +8 -0
- package/dist/lib/agent/signature.js +28 -0
- package/dist/lib/agent/tools.d.ts +28 -0
- package/dist/lib/agent/tools.js +453 -0
- package/dist/lib/agent/x402.d.ts +23 -0
- package/dist/lib/agent/x402.js +62 -0
- package/dist/lib/api-wallet.d.ts +69 -0
- package/dist/lib/api-wallet.js +101 -0
- package/dist/lib/balance-watcher.d.ts +25 -0
- package/dist/lib/balance-watcher.js +83 -0
- package/dist/lib/book-watcher.d.ts +25 -0
- package/dist/lib/book-watcher.js +48 -0
- package/dist/lib/config.d.ts +88 -0
- package/dist/lib/config.js +427 -0
- package/dist/lib/constants.d.ts +50 -0
- package/dist/lib/constants.js +84 -0
- package/dist/lib/contracts.d.ts +7 -0
- package/dist/lib/contracts.js +8 -0
- package/dist/lib/credential-vault.d.ts +22 -0
- package/dist/lib/credential-vault.js +109 -0
- package/dist/lib/db/accounts.d.ts +83 -0
- package/dist/lib/db/accounts.js +203 -0
- package/dist/lib/db/funding-history.d.ts +69 -0
- package/dist/lib/db/funding-history.js +183 -0
- package/dist/lib/db/index.d.ts +11 -0
- package/dist/lib/db/index.js +272 -0
- package/dist/lib/events/bus.d.ts +10 -0
- package/dist/lib/events/bus.js +17 -0
- package/dist/lib/events/types.d.ts +51 -0
- package/dist/lib/events/types.js +1 -0
- package/dist/lib/exchange.d.ts +30 -0
- package/dist/lib/exchange.js +84 -0
- package/dist/lib/execution/journal.d.ts +25 -0
- package/dist/lib/execution/journal.js +158 -0
- package/dist/lib/execution/safety.d.ts +34 -0
- package/dist/lib/execution/safety.js +197 -0
- package/dist/lib/exit-codes.d.ts +18 -0
- package/dist/lib/exit-codes.js +60 -0
- package/dist/lib/fetch.d.ts +18 -0
- package/dist/lib/fetch.js +66 -0
- package/dist/lib/fs-security.d.ts +10 -0
- package/dist/lib/fs-security.js +26 -0
- package/dist/lib/funding-tracker.d.ts +40 -0
- package/dist/lib/funding-tracker.js +118 -0
- package/dist/lib/logger.d.ts +27 -0
- package/dist/lib/logger.js +82 -0
- package/dist/lib/network-model.d.ts +13 -0
- package/dist/lib/network-model.js +30 -0
- package/dist/lib/onboarding.d.ts +133 -0
- package/dist/lib/onboarding.js +1459 -0
- package/dist/lib/operator-state.d.ts +25 -0
- package/dist/lib/operator-state.js +82 -0
- package/dist/lib/orders-watcher.d.ts +24 -0
- package/dist/lib/orders-watcher.js +74 -0
- package/dist/lib/paths.d.ts +20 -0
- package/dist/lib/paths.js +23 -0
- package/dist/lib/portfolio-watcher.d.ts +33 -0
- package/dist/lib/portfolio-watcher.js +95 -0
- package/dist/lib/position-watcher.d.ts +16 -0
- package/dist/lib/position-watcher.js +44 -0
- package/dist/lib/price-watcher.d.ts +15 -0
- package/dist/lib/price-watcher.js +84 -0
- package/dist/lib/prompts.d.ts +32 -0
- package/dist/lib/prompts.js +105 -0
- package/dist/lib/rate-limit.d.ts +32 -0
- package/dist/lib/rate-limit.js +88 -0
- package/dist/lib/risk/analytics.d.ts +39 -0
- package/dist/lib/risk/analytics.js +98 -0
- package/dist/lib/risk/drawdown.d.ts +18 -0
- package/dist/lib/risk/drawdown.js +49 -0
- package/dist/lib/risk/evaluation-log.d.ts +29 -0
- package/dist/lib/risk/evaluation-log.js +61 -0
- package/dist/lib/risk/index.d.ts +4 -0
- package/dist/lib/risk/index.js +4 -0
- package/dist/lib/risk/limits.d.ts +23 -0
- package/dist/lib/risk/limits.js +27 -0
- package/dist/lib/risk/manager.d.ts +32 -0
- package/dist/lib/risk/manager.js +85 -0
- package/dist/lib/risk/policy-middleware.d.ts +33 -0
- package/dist/lib/risk/policy-middleware.js +267 -0
- package/dist/lib/risk/position-sizer.d.ts +9 -0
- package/dist/lib/risk/position-sizer.js +14 -0
- package/dist/lib/risk/rules-store.d.ts +16 -0
- package/dist/lib/risk/rules-store.js +47 -0
- package/dist/lib/schema.d.ts +254 -0
- package/dist/lib/schema.js +199 -0
- package/dist/lib/secrets.d.ts +3 -0
- package/dist/lib/secrets.js +62 -0
- package/dist/lib/settings.d.ts +24 -0
- package/dist/lib/settings.js +86 -0
- package/dist/lib/signals.d.ts +73 -0
- package/dist/lib/signals.js +136 -0
- package/dist/lib/stable-stringify.d.ts +6 -0
- package/dist/lib/stable-stringify.js +17 -0
- package/dist/lib/state-context.d.ts +44 -0
- package/dist/lib/state-context.js +133 -0
- package/dist/lib/strategy/basis-trade.d.ts +2 -0
- package/dist/lib/strategy/basis-trade.js +24 -0
- package/dist/lib/strategy/funding-arb.d.ts +2 -0
- package/dist/lib/strategy/funding-arb.js +23 -0
- package/dist/lib/strategy/interface.d.ts +23 -0
- package/dist/lib/strategy/interface.js +1 -0
- package/dist/lib/strategy/registry.d.ts +4 -0
- package/dist/lib/strategy/registry.js +10 -0
- package/dist/lib/telemetry.d.ts +25 -0
- package/dist/lib/telemetry.js +101 -0
- package/dist/lib/trace-queries.d.ts +20 -0
- package/dist/lib/trace-queries.js +133 -0
- package/dist/lib/trace.d.ts +1 -0
- package/dist/lib/trace.js +4 -0
- package/dist/lib/trade-reputation.d.ts +6 -0
- package/dist/lib/trade-reputation.js +99 -0
- package/dist/lib/ui-tokens.d.ts +21 -0
- package/dist/lib/ui-tokens.js +26 -0
- package/dist/lib/validate.d.ts +39 -0
- package/dist/lib/validate.js +108 -0
- package/dist/lib/validation.d.ts +9 -0
- package/dist/lib/validation.js +64 -0
- package/dist/server/cache.d.ts +38 -0
- package/dist/server/cache.js +56 -0
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.js +89 -0
- package/dist/server/ipc.d.ts +18 -0
- package/dist/server/ipc.js +159 -0
- package/dist/server/subscriptions.d.ts +18 -0
- package/dist/server/subscriptions.js +114 -0
- package/package.json +124 -0
|
@@ -0,0 +1,1466 @@
|
|
|
1
|
+
import ccxt from "ccxt";
|
|
2
|
+
import pmxt from "pmxtjs";
|
|
3
|
+
import { getOutputOptions } from "../../cli/program.js";
|
|
4
|
+
import { output, outputError } from "../../cli/output.js";
|
|
5
|
+
const PMXT_EXCHANGES = {
|
|
6
|
+
polymarket: "Polymarket",
|
|
7
|
+
kalshi: "Kalshi",
|
|
8
|
+
limitless: "Limitless",
|
|
9
|
+
};
|
|
10
|
+
const BOOLEAN_TRUE_VALUES = new Set(["1", "true", "yes", "on"]);
|
|
11
|
+
const BOOLEAN_FALSE_VALUES = new Set(["0", "false", "no", "off"]);
|
|
12
|
+
const FUTURES_METHOD_PATTERN = /(?:future|futures|swap|contract|perp|position|funding|openinterest|open_interest|leverage|margin|order|transfer|liquidation|settlement|trigger|takeprofit|take_profit|stop|hedge|adl|insurance|risk|borrow|repay)/i;
|
|
13
|
+
const LIKELY_ONCHAIN_EXCHANGE_IDS = new Set([
|
|
14
|
+
"aevo",
|
|
15
|
+
"dydx",
|
|
16
|
+
"dydxv3",
|
|
17
|
+
"dydxv4",
|
|
18
|
+
"drift",
|
|
19
|
+
"gmx",
|
|
20
|
+
"gmxv2",
|
|
21
|
+
"hyperliquid",
|
|
22
|
+
"injective",
|
|
23
|
+
"jupiter",
|
|
24
|
+
"kwenta",
|
|
25
|
+
"mango",
|
|
26
|
+
"paradex",
|
|
27
|
+
"perpetual-protocol",
|
|
28
|
+
"polkadex",
|
|
29
|
+
"synthetix",
|
|
30
|
+
"uniswap",
|
|
31
|
+
"vertex",
|
|
32
|
+
"zeta",
|
|
33
|
+
]);
|
|
34
|
+
const FUTURES_OPERATION_ALIASES = {
|
|
35
|
+
book: "orderbook",
|
|
36
|
+
"order-book": "orderbook",
|
|
37
|
+
funding: "funding-rate",
|
|
38
|
+
fundingrate: "funding-rate",
|
|
39
|
+
fundingrates: "funding-rates",
|
|
40
|
+
"funding-history": "funding-history",
|
|
41
|
+
"funding-rate-history": "funding-rate-history",
|
|
42
|
+
openinterest: "open-interest",
|
|
43
|
+
openinterests: "open-interests",
|
|
44
|
+
"open-interest-history": "open-interest-history",
|
|
45
|
+
"open-orders": "orders-open",
|
|
46
|
+
"closed-orders": "orders-closed",
|
|
47
|
+
"canceled-orders": "orders-canceled",
|
|
48
|
+
trades: "my-trades",
|
|
49
|
+
trade: "my-trades",
|
|
50
|
+
methods: "futures-methods",
|
|
51
|
+
leverageinfo: "leverage",
|
|
52
|
+
leveragetiers: "leverage-tiers",
|
|
53
|
+
"market-leverage": "market-leverage-tiers",
|
|
54
|
+
"set-margin": "set-margin-mode",
|
|
55
|
+
"set-position": "set-position-mode",
|
|
56
|
+
"position-history": "position-history",
|
|
57
|
+
"positions-history": "positions-history",
|
|
58
|
+
"positions-risk": "positions-risk",
|
|
59
|
+
"public-trades": "trades-public",
|
|
60
|
+
transferin: "transfer-in",
|
|
61
|
+
transferout: "transfer-out",
|
|
62
|
+
"add-collateral": "add-margin",
|
|
63
|
+
"reduce-collateral": "reduce-margin",
|
|
64
|
+
borrow: "borrow-margin",
|
|
65
|
+
repay: "repay-margin",
|
|
66
|
+
closeposition: "close-position",
|
|
67
|
+
closeallpositions: "close-all-positions",
|
|
68
|
+
};
|
|
69
|
+
const SUPPORTED_FUTURES_OPERATIONS = [
|
|
70
|
+
"markets",
|
|
71
|
+
"ticker",
|
|
72
|
+
"tickers",
|
|
73
|
+
"orderbook",
|
|
74
|
+
"funding-rate",
|
|
75
|
+
"funding-rates",
|
|
76
|
+
"funding-rate-history",
|
|
77
|
+
"funding-history",
|
|
78
|
+
"open-interest",
|
|
79
|
+
"open-interests",
|
|
80
|
+
"open-interest-history",
|
|
81
|
+
"balance",
|
|
82
|
+
"positions",
|
|
83
|
+
"position",
|
|
84
|
+
"positions-history",
|
|
85
|
+
"position-history",
|
|
86
|
+
"positions-risk",
|
|
87
|
+
"account-positions",
|
|
88
|
+
"option-positions",
|
|
89
|
+
"orders-open",
|
|
90
|
+
"orders",
|
|
91
|
+
"orders-closed",
|
|
92
|
+
"orders-canceled",
|
|
93
|
+
"order",
|
|
94
|
+
"order-trades",
|
|
95
|
+
"my-trades",
|
|
96
|
+
"trades-public",
|
|
97
|
+
"create-order",
|
|
98
|
+
"cancel-order",
|
|
99
|
+
"cancel-all",
|
|
100
|
+
"set-leverage",
|
|
101
|
+
"set-margin-mode",
|
|
102
|
+
"set-position-mode",
|
|
103
|
+
"leverage",
|
|
104
|
+
"leverage-tiers",
|
|
105
|
+
"market-leverage-tiers",
|
|
106
|
+
"margin-mode",
|
|
107
|
+
"position-mode",
|
|
108
|
+
"margin-adjustment-history",
|
|
109
|
+
"transfers",
|
|
110
|
+
"transfer",
|
|
111
|
+
"transfer-in",
|
|
112
|
+
"transfer-out",
|
|
113
|
+
"add-margin",
|
|
114
|
+
"reduce-margin",
|
|
115
|
+
"borrow-margin",
|
|
116
|
+
"repay-margin",
|
|
117
|
+
"close-position",
|
|
118
|
+
"close-all-positions",
|
|
119
|
+
"snapshot",
|
|
120
|
+
"futures-methods",
|
|
121
|
+
"raw",
|
|
122
|
+
];
|
|
123
|
+
const FUTURES_OPERATION_METHOD_HINTS = {
|
|
124
|
+
markets: ["fetchMarkets"],
|
|
125
|
+
ticker: ["fetchTicker"],
|
|
126
|
+
tickers: ["fetchTickers"],
|
|
127
|
+
orderbook: ["fetchOrderBook"],
|
|
128
|
+
"funding-rate": ["fetchFundingRate"],
|
|
129
|
+
"funding-rates": ["fetchFundingRates", "fetchFundingRate"],
|
|
130
|
+
"funding-rate-history": ["fetchFundingRateHistory"],
|
|
131
|
+
"funding-history": ["fetchFundingHistory"],
|
|
132
|
+
"open-interest": ["fetchOpenInterest"],
|
|
133
|
+
"open-interests": ["fetchOpenInterests", "fetchOpenInterest"],
|
|
134
|
+
"open-interest-history": ["fetchOpenInterestHistory"],
|
|
135
|
+
balance: ["fetchBalance"],
|
|
136
|
+
positions: ["fetchPositions", "fetchPosition", "fetchAccountPositions", "fetchPositionsRisk"],
|
|
137
|
+
position: ["fetchPosition", "fetchPositions", "fetchPositionsForSymbol"],
|
|
138
|
+
"positions-history": ["fetchPositionsHistory", "fetchPositionHistory"],
|
|
139
|
+
"position-history": ["fetchPositionHistory"],
|
|
140
|
+
"positions-risk": ["fetchPositionsRisk", "fetchPositions"],
|
|
141
|
+
"account-positions": ["fetchAccountPositions", "fetchPositions"],
|
|
142
|
+
"option-positions": ["fetchOptionPositions"],
|
|
143
|
+
"orders-open": ["fetchOpenOrders"],
|
|
144
|
+
orders: ["fetchOrders"],
|
|
145
|
+
"orders-closed": ["fetchClosedOrders"],
|
|
146
|
+
"orders-canceled": ["fetchCanceledOrders"],
|
|
147
|
+
order: ["fetchOrder"],
|
|
148
|
+
"order-trades": ["fetchOrderTrades"],
|
|
149
|
+
"my-trades": ["fetchMyTrades"],
|
|
150
|
+
"trades-public": ["fetchTrades"],
|
|
151
|
+
"create-order": ["createOrder"],
|
|
152
|
+
"cancel-order": ["cancelOrder"],
|
|
153
|
+
"cancel-all": ["cancelAllOrders"],
|
|
154
|
+
"set-leverage": ["setLeverage"],
|
|
155
|
+
"set-margin-mode": ["setMarginMode"],
|
|
156
|
+
"set-position-mode": ["setPositionMode"],
|
|
157
|
+
leverage: ["fetchLeverage", "fetchLeverages"],
|
|
158
|
+
"leverage-tiers": ["fetchLeverageTiers", "fetchMarketLeverageTiers"],
|
|
159
|
+
"market-leverage-tiers": ["fetchMarketLeverageTiers"],
|
|
160
|
+
"margin-mode": ["fetchMarginMode", "fetchMarginModes"],
|
|
161
|
+
"position-mode": ["fetchPositionMode"],
|
|
162
|
+
"margin-adjustment-history": ["fetchMarginAdjustmentHistory"],
|
|
163
|
+
transfers: ["fetchTransfers"],
|
|
164
|
+
transfer: ["transfer"],
|
|
165
|
+
"transfer-in": ["transferIn", "transfer"],
|
|
166
|
+
"transfer-out": ["transferOut", "transfer"],
|
|
167
|
+
"add-margin": ["addMargin"],
|
|
168
|
+
"reduce-margin": ["reduceMargin"],
|
|
169
|
+
"borrow-margin": ["borrowMargin"],
|
|
170
|
+
"repay-margin": ["repayMargin"],
|
|
171
|
+
"close-position": ["closePosition"],
|
|
172
|
+
"close-all-positions": ["closeAllPositions"],
|
|
173
|
+
snapshot: ["fetchMarkets", "fetchPositions", "fetchBalance", "fetchOpenOrders"],
|
|
174
|
+
"futures-methods": [],
|
|
175
|
+
raw: [],
|
|
176
|
+
};
|
|
177
|
+
function asRecord(value) {
|
|
178
|
+
if (typeof value !== "object" || value === null)
|
|
179
|
+
return null;
|
|
180
|
+
return value;
|
|
181
|
+
}
|
|
182
|
+
function parseBooleanLike(raw, label) {
|
|
183
|
+
if (raw === undefined)
|
|
184
|
+
return undefined;
|
|
185
|
+
const normalized = raw.trim().toLowerCase();
|
|
186
|
+
if (normalized.length === 0)
|
|
187
|
+
return undefined;
|
|
188
|
+
if (BOOLEAN_TRUE_VALUES.has(normalized))
|
|
189
|
+
return true;
|
|
190
|
+
if (BOOLEAN_FALSE_VALUES.has(normalized))
|
|
191
|
+
return false;
|
|
192
|
+
throw new Error(`${label} must be one of: ${Array.from(BOOLEAN_TRUE_VALUES).join(", ")} or ${Array.from(BOOLEAN_FALSE_VALUES).join(", ")}`);
|
|
193
|
+
}
|
|
194
|
+
function parseNumber(raw, label) {
|
|
195
|
+
const value = Number(raw);
|
|
196
|
+
if (!Number.isFinite(value)) {
|
|
197
|
+
throw new Error(`${label} must be a finite number`);
|
|
198
|
+
}
|
|
199
|
+
return value;
|
|
200
|
+
}
|
|
201
|
+
function parseOptionalNumber(raw, label) {
|
|
202
|
+
if (!raw)
|
|
203
|
+
return undefined;
|
|
204
|
+
return parseNumber(raw, label);
|
|
205
|
+
}
|
|
206
|
+
function parseOptionalPositiveNumber(raw, label) {
|
|
207
|
+
const value = parseOptionalNumber(raw, label);
|
|
208
|
+
if (value === undefined)
|
|
209
|
+
return undefined;
|
|
210
|
+
if (value <= 0) {
|
|
211
|
+
throw new Error(`${label} must be a positive number`);
|
|
212
|
+
}
|
|
213
|
+
return value;
|
|
214
|
+
}
|
|
215
|
+
function parseOptionalInteger(raw, label) {
|
|
216
|
+
const value = parseOptionalNumber(raw, label);
|
|
217
|
+
if (value === undefined)
|
|
218
|
+
return undefined;
|
|
219
|
+
if (!Number.isInteger(value)) {
|
|
220
|
+
throw new Error(`${label} must be an integer`);
|
|
221
|
+
}
|
|
222
|
+
return value;
|
|
223
|
+
}
|
|
224
|
+
function normalizeOptionalString(value) {
|
|
225
|
+
if (value === undefined)
|
|
226
|
+
return undefined;
|
|
227
|
+
const normalized = value.trim();
|
|
228
|
+
return normalized.length > 0 ? normalized : undefined;
|
|
229
|
+
}
|
|
230
|
+
export function parseJsonArray(raw) {
|
|
231
|
+
try {
|
|
232
|
+
const parsed = JSON.parse(raw);
|
|
233
|
+
if (!Array.isArray(parsed)) {
|
|
234
|
+
throw new Error("must be a JSON array");
|
|
235
|
+
}
|
|
236
|
+
return parsed;
|
|
237
|
+
}
|
|
238
|
+
catch (err) {
|
|
239
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
240
|
+
throw new Error(`Invalid --args JSON: ${reason}. Example: --args '["BTC/USDT"]'`);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
export function parseJsonObject(raw, label = "--params") {
|
|
244
|
+
try {
|
|
245
|
+
const parsed = JSON.parse(raw);
|
|
246
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
247
|
+
throw new Error("must be a JSON object");
|
|
248
|
+
}
|
|
249
|
+
return parsed;
|
|
250
|
+
}
|
|
251
|
+
catch (err) {
|
|
252
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
253
|
+
throw new Error(`Invalid ${label} JSON: ${reason}. Example: ${label} '{"recvWindow":5000}'`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
function parseJsonStringArray(raw, label) {
|
|
257
|
+
const values = parseJsonArray(raw);
|
|
258
|
+
const invalid = values.find((item) => typeof item !== "string");
|
|
259
|
+
if (invalid !== undefined) {
|
|
260
|
+
throw new Error(`${label} must be a JSON array of strings`);
|
|
261
|
+
}
|
|
262
|
+
return values;
|
|
263
|
+
}
|
|
264
|
+
function parseEnvJsonObject(name) {
|
|
265
|
+
const raw = process.env[name];
|
|
266
|
+
if (!raw || raw.trim().length === 0)
|
|
267
|
+
return undefined;
|
|
268
|
+
return parseJsonObject(raw, `env ${name}`);
|
|
269
|
+
}
|
|
270
|
+
function parseEnvInt(name) {
|
|
271
|
+
const raw = process.env[name];
|
|
272
|
+
if (!raw || raw.trim().length === 0)
|
|
273
|
+
return undefined;
|
|
274
|
+
const value = Number(raw);
|
|
275
|
+
if (!Number.isInteger(value) || value <= 0) {
|
|
276
|
+
throw new Error(`${name} must be a positive integer`);
|
|
277
|
+
}
|
|
278
|
+
return value;
|
|
279
|
+
}
|
|
280
|
+
function isEmptyObject(value) {
|
|
281
|
+
return !value || Object.keys(value).length === 0;
|
|
282
|
+
}
|
|
283
|
+
function mergeObjects(...objects) {
|
|
284
|
+
const out = {};
|
|
285
|
+
for (const item of objects) {
|
|
286
|
+
if (!item)
|
|
287
|
+
continue;
|
|
288
|
+
for (const [key, value] of Object.entries(item)) {
|
|
289
|
+
out[key] = value;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return out;
|
|
293
|
+
}
|
|
294
|
+
function trimTrailingUndefined(args) {
|
|
295
|
+
const values = [...args];
|
|
296
|
+
while (values.length > 0 && values[values.length - 1] === undefined) {
|
|
297
|
+
values.pop();
|
|
298
|
+
}
|
|
299
|
+
return values;
|
|
300
|
+
}
|
|
301
|
+
function isCcxtMethodAvailable(instance, method) {
|
|
302
|
+
return typeof instance[method] === "function";
|
|
303
|
+
}
|
|
304
|
+
function listFuturesMethods(instance) {
|
|
305
|
+
return listCallableMethods(instance).filter((method) => FUTURES_METHOD_PATTERN.test(method));
|
|
306
|
+
}
|
|
307
|
+
function listCcxtExchangeIds() {
|
|
308
|
+
const exchangeList = ccxt.exchanges;
|
|
309
|
+
if (Array.isArray(exchangeList) && exchangeList.length > 0) {
|
|
310
|
+
return [...exchangeList].sort();
|
|
311
|
+
}
|
|
312
|
+
const constructors = ccxt;
|
|
313
|
+
return Object.keys(constructors)
|
|
314
|
+
.filter((name) => !name.startsWith("_") && /^[a-z0-9]+$/.test(name) && typeof constructors[name] === "function" && constructors[name].prototype?.id !== undefined)
|
|
315
|
+
.sort();
|
|
316
|
+
}
|
|
317
|
+
function resolveOperation(operationRaw) {
|
|
318
|
+
const operation = operationRaw.toLowerCase().replace(/_/g, "-");
|
|
319
|
+
return FUTURES_OPERATION_ALIASES[operation] ?? operation;
|
|
320
|
+
}
|
|
321
|
+
function requireString(value, label) {
|
|
322
|
+
const normalized = normalizeOptionalString(value);
|
|
323
|
+
if (!normalized) {
|
|
324
|
+
throw new Error(`${label} is required`);
|
|
325
|
+
}
|
|
326
|
+
return normalized;
|
|
327
|
+
}
|
|
328
|
+
function requireNumber(value, label) {
|
|
329
|
+
if (value === undefined) {
|
|
330
|
+
throw new Error(`${label} is required`);
|
|
331
|
+
}
|
|
332
|
+
return value;
|
|
333
|
+
}
|
|
334
|
+
function parsePositionMode(value) {
|
|
335
|
+
const normalized = requireString(value, "--position-mode").toLowerCase();
|
|
336
|
+
if (["hedged", "hedge", "true", "on", "1"].includes(normalized)) {
|
|
337
|
+
return true;
|
|
338
|
+
}
|
|
339
|
+
if (["oneway", "one-way", "false", "off", "0"].includes(normalized)) {
|
|
340
|
+
return false;
|
|
341
|
+
}
|
|
342
|
+
throw new Error("--position-mode must be one of: hedged, oneway");
|
|
343
|
+
}
|
|
344
|
+
function isNotSupportedError(err) {
|
|
345
|
+
if (!(err instanceof Error))
|
|
346
|
+
return false;
|
|
347
|
+
const text = `${err.name} ${err.message}`.toLowerCase();
|
|
348
|
+
return text.includes("not supported") || text.includes("unsupported") || text.includes("not implemented");
|
|
349
|
+
}
|
|
350
|
+
async function callWithFallback(instance, attempts, context) {
|
|
351
|
+
const available = attempts.filter((attempt) => isCcxtMethodAvailable(instance, attempt.method));
|
|
352
|
+
if (available.length === 0) {
|
|
353
|
+
throw new Error(`No supported method for ${context}. None of these methods are available: ${attempts
|
|
354
|
+
.map((attempt) => attempt.method)
|
|
355
|
+
.join(", ")}`);
|
|
356
|
+
}
|
|
357
|
+
let lastUnsupportedError = null;
|
|
358
|
+
for (const attempt of available) {
|
|
359
|
+
try {
|
|
360
|
+
return await callMethod(instance, attempt.method, trimTrailingUndefined(attempt.args));
|
|
361
|
+
}
|
|
362
|
+
catch (err) {
|
|
363
|
+
if (isNotSupportedError(err)) {
|
|
364
|
+
lastUnsupportedError = err instanceof Error ? err : new Error(String(err));
|
|
365
|
+
continue;
|
|
366
|
+
}
|
|
367
|
+
throw err;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
if (lastUnsupportedError) {
|
|
371
|
+
throw new Error(`No supported method for ${context}. Tried: ${available.map((attempt) => attempt.method).join(", ")}. Last error: ${lastUnsupportedError.message}`);
|
|
372
|
+
}
|
|
373
|
+
throw new Error(`No supported method for ${context}. Tried: ${available.map((attempt) => attempt.method).join(", ")}`);
|
|
374
|
+
}
|
|
375
|
+
function normalizeToObjectArray(data) {
|
|
376
|
+
if (!Array.isArray(data))
|
|
377
|
+
return [];
|
|
378
|
+
return data
|
|
379
|
+
.map((item) => asRecord(item))
|
|
380
|
+
.filter((item) => item !== null);
|
|
381
|
+
}
|
|
382
|
+
function isSupportedFlag(value) {
|
|
383
|
+
return value === true || value === "emulated";
|
|
384
|
+
}
|
|
385
|
+
function deriveDerivativeSupport(hasMap) {
|
|
386
|
+
const supportsPerpsOrFutures = isSupportedFlag(hasMap.fetchPositions) ||
|
|
387
|
+
isSupportedFlag(hasMap.fetchFundingRate) ||
|
|
388
|
+
isSupportedFlag(hasMap.fetchOpenInterest) ||
|
|
389
|
+
isSupportedFlag(hasMap.setLeverage) ||
|
|
390
|
+
hasMap.swap === true ||
|
|
391
|
+
hasMap.future === true;
|
|
392
|
+
return {
|
|
393
|
+
perpsOrFutures: supportsPerpsOrFutures,
|
|
394
|
+
positions: isSupportedFlag(hasMap.fetchPositions),
|
|
395
|
+
funding: isSupportedFlag(hasMap.fetchFundingRate),
|
|
396
|
+
openInterest: isSupportedFlag(hasMap.fetchOpenInterest),
|
|
397
|
+
leverageControl: isSupportedFlag(hasMap.setLeverage),
|
|
398
|
+
marginModeControl: isSupportedFlag(hasMap.setMarginMode),
|
|
399
|
+
positionModeControl: isSupportedFlag(hasMap.setPositionMode),
|
|
400
|
+
transfers: isSupportedFlag(hasMap.fetchTransfers),
|
|
401
|
+
swapMarkets: hasMap.swap === true,
|
|
402
|
+
futureMarkets: hasMap.future === true,
|
|
403
|
+
optionsMarkets: hasMap.option === true,
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
function inferVenueType(exchangeId) {
|
|
407
|
+
const id = exchangeId.toLowerCase();
|
|
408
|
+
if (LIKELY_ONCHAIN_EXCHANGE_IDS.has(id)) {
|
|
409
|
+
return { venue: "onchain_or_hybrid", reason: "known on-chain or hybrid venue id" };
|
|
410
|
+
}
|
|
411
|
+
if (id.includes("defi") || id.includes("swap")) {
|
|
412
|
+
return { venue: "onchain_or_hybrid", reason: "exchange id suggests DEX/DeFi routing" };
|
|
413
|
+
}
|
|
414
|
+
return { venue: "offchain_or_hybrid", reason: "default classification (most CCXT venues are off-chain orderbooks)" };
|
|
415
|
+
}
|
|
416
|
+
function inferAuthModel(requiredCredentials) {
|
|
417
|
+
const apiKey = requiredCredentials.apiKey === true || requiredCredentials.secret === true;
|
|
418
|
+
const wallet = requiredCredentials.privateKey === true || requiredCredentials.walletAddress === true;
|
|
419
|
+
if (apiKey && wallet)
|
|
420
|
+
return "hybrid";
|
|
421
|
+
if (wallet)
|
|
422
|
+
return "wallet";
|
|
423
|
+
if (apiKey)
|
|
424
|
+
return "api_key";
|
|
425
|
+
return "optional_or_unknown";
|
|
426
|
+
}
|
|
427
|
+
function buildMarketStats(instance) {
|
|
428
|
+
const markets = asRecord(instance.markets);
|
|
429
|
+
if (!markets) {
|
|
430
|
+
return {
|
|
431
|
+
loaded: false,
|
|
432
|
+
total: 0,
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
let total = 0;
|
|
436
|
+
let active = 0;
|
|
437
|
+
let inactive = 0;
|
|
438
|
+
let spot = 0;
|
|
439
|
+
let contract = 0;
|
|
440
|
+
let swap = 0;
|
|
441
|
+
let future = 0;
|
|
442
|
+
let option = 0;
|
|
443
|
+
let linear = 0;
|
|
444
|
+
let inverse = 0;
|
|
445
|
+
const settleAssets = new Set();
|
|
446
|
+
const quoteAssets = new Set();
|
|
447
|
+
const baseAssets = new Set();
|
|
448
|
+
const sample = new Set();
|
|
449
|
+
for (const [fallbackSymbol, value] of Object.entries(markets)) {
|
|
450
|
+
const market = asRecord(value);
|
|
451
|
+
if (!market)
|
|
452
|
+
continue;
|
|
453
|
+
total += 1;
|
|
454
|
+
if (market.active === true)
|
|
455
|
+
active += 1;
|
|
456
|
+
if (market.active === false)
|
|
457
|
+
inactive += 1;
|
|
458
|
+
if (market.spot === true)
|
|
459
|
+
spot += 1;
|
|
460
|
+
if (market.contract === true)
|
|
461
|
+
contract += 1;
|
|
462
|
+
if (market.swap === true)
|
|
463
|
+
swap += 1;
|
|
464
|
+
if (market.future === true)
|
|
465
|
+
future += 1;
|
|
466
|
+
if (market.option === true)
|
|
467
|
+
option += 1;
|
|
468
|
+
if (market.linear === true)
|
|
469
|
+
linear += 1;
|
|
470
|
+
if (market.inverse === true)
|
|
471
|
+
inverse += 1;
|
|
472
|
+
if (typeof market.settle === "string")
|
|
473
|
+
settleAssets.add(market.settle);
|
|
474
|
+
if (typeof market.quote === "string")
|
|
475
|
+
quoteAssets.add(market.quote);
|
|
476
|
+
if (typeof market.base === "string")
|
|
477
|
+
baseAssets.add(market.base);
|
|
478
|
+
const symbol = typeof market.symbol === "string" ? market.symbol : fallbackSymbol;
|
|
479
|
+
if (symbol.length > 0 && sample.size < 20) {
|
|
480
|
+
sample.add(symbol);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
return {
|
|
484
|
+
loaded: true,
|
|
485
|
+
total,
|
|
486
|
+
active,
|
|
487
|
+
inactive,
|
|
488
|
+
spot,
|
|
489
|
+
contract,
|
|
490
|
+
swap,
|
|
491
|
+
future,
|
|
492
|
+
option,
|
|
493
|
+
linear,
|
|
494
|
+
inverse,
|
|
495
|
+
settleAssets: [...settleAssets].sort(),
|
|
496
|
+
quoteAssets: [...quoteAssets].sort(),
|
|
497
|
+
baseAssets: [...baseAssets].sort(),
|
|
498
|
+
sampleSymbols: [...sample],
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
function buildCurrencyStats(instance) {
|
|
502
|
+
const currencies = asRecord(instance.currencies);
|
|
503
|
+
if (!currencies) {
|
|
504
|
+
return {
|
|
505
|
+
loaded: false,
|
|
506
|
+
total: 0,
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
let total = 0;
|
|
510
|
+
let active = 0;
|
|
511
|
+
let inactive = 0;
|
|
512
|
+
const sample = new Set();
|
|
513
|
+
for (const [code, value] of Object.entries(currencies)) {
|
|
514
|
+
const currency = asRecord(value);
|
|
515
|
+
if (!currency)
|
|
516
|
+
continue;
|
|
517
|
+
total += 1;
|
|
518
|
+
if (currency.active === true)
|
|
519
|
+
active += 1;
|
|
520
|
+
if (currency.active === false)
|
|
521
|
+
inactive += 1;
|
|
522
|
+
if (sample.size < 30)
|
|
523
|
+
sample.add(code);
|
|
524
|
+
}
|
|
525
|
+
return {
|
|
526
|
+
loaded: true,
|
|
527
|
+
total,
|
|
528
|
+
active,
|
|
529
|
+
inactive,
|
|
530
|
+
sampleCodes: [...sample],
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
function buildFuturesOperationSupport(instance) {
|
|
534
|
+
const methods = new Set(listCallableMethods(instance));
|
|
535
|
+
const support = {};
|
|
536
|
+
for (const operation of SUPPORTED_FUTURES_OPERATIONS) {
|
|
537
|
+
if (operation === "raw" || operation === "futures-methods") {
|
|
538
|
+
support[operation] = {
|
|
539
|
+
supported: true,
|
|
540
|
+
via: operation === "raw" ? ["any callable method"] : ["method filtering"],
|
|
541
|
+
};
|
|
542
|
+
continue;
|
|
543
|
+
}
|
|
544
|
+
const hints = FUTURES_OPERATION_METHOD_HINTS[operation];
|
|
545
|
+
const available = hints.filter((method) => methods.has(method));
|
|
546
|
+
support[operation] = {
|
|
547
|
+
supported: available.length > 0,
|
|
548
|
+
via: available,
|
|
549
|
+
hintMethods: hints,
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
return support;
|
|
553
|
+
}
|
|
554
|
+
function toErrorMessage(err) {
|
|
555
|
+
if (err instanceof Error)
|
|
556
|
+
return err.message;
|
|
557
|
+
return String(err);
|
|
558
|
+
}
|
|
559
|
+
async function executeBestEffortSnapshot(instance, input) {
|
|
560
|
+
const params = input.params ?? {};
|
|
561
|
+
const tasks = [
|
|
562
|
+
{
|
|
563
|
+
key: "markets",
|
|
564
|
+
run: async () => {
|
|
565
|
+
const markets = await callWithFallback(instance, [{ method: "fetchMarkets", args: [params] }], "snapshot.markets");
|
|
566
|
+
const normalized = normalizeToObjectArray(markets);
|
|
567
|
+
const contracts = normalized.filter((market) => market.contract === true || market.swap === true || market.future === true);
|
|
568
|
+
return contracts.length > 0 ? contracts : markets;
|
|
569
|
+
},
|
|
570
|
+
},
|
|
571
|
+
{
|
|
572
|
+
key: "balance",
|
|
573
|
+
run: async () => callWithFallback(instance, [{ method: "fetchBalance", args: [params] }], "snapshot.balance"),
|
|
574
|
+
},
|
|
575
|
+
{
|
|
576
|
+
key: "positions",
|
|
577
|
+
run: async () => callWithFallback(instance, [
|
|
578
|
+
{ method: "fetchPositions", args: [input.symbols, params] },
|
|
579
|
+
{ method: "fetchAccountPositions", args: [input.symbols, params] },
|
|
580
|
+
], "snapshot.positions"),
|
|
581
|
+
},
|
|
582
|
+
{
|
|
583
|
+
key: "openOrders",
|
|
584
|
+
run: async () => callWithFallback(instance, [{ method: "fetchOpenOrders", args: [input.symbol, input.since, input.limit, params] }], "snapshot.openOrders"),
|
|
585
|
+
},
|
|
586
|
+
{
|
|
587
|
+
key: "ticker",
|
|
588
|
+
run: async () => {
|
|
589
|
+
if (input.symbol) {
|
|
590
|
+
return callWithFallback(instance, [{ method: "fetchTicker", args: [input.symbol, params] }], "snapshot.ticker");
|
|
591
|
+
}
|
|
592
|
+
return callWithFallback(instance, [{ method: "fetchTickers", args: [input.symbols, params] }], "snapshot.tickers");
|
|
593
|
+
},
|
|
594
|
+
},
|
|
595
|
+
{
|
|
596
|
+
key: "funding",
|
|
597
|
+
run: async () => {
|
|
598
|
+
if (input.symbol) {
|
|
599
|
+
return callWithFallback(instance, [{ method: "fetchFundingRate", args: [input.symbol, params] }], "snapshot.fundingRate");
|
|
600
|
+
}
|
|
601
|
+
return callWithFallback(instance, [{ method: "fetchFundingRates", args: [input.symbols, params] }], "snapshot.fundingRates");
|
|
602
|
+
},
|
|
603
|
+
},
|
|
604
|
+
{
|
|
605
|
+
key: "openInterest",
|
|
606
|
+
run: async () => {
|
|
607
|
+
if (input.symbol) {
|
|
608
|
+
return callWithFallback(instance, [{ method: "fetchOpenInterest", args: [input.symbol, params] }], "snapshot.openInterest");
|
|
609
|
+
}
|
|
610
|
+
return callWithFallback(instance, [{ method: "fetchOpenInterests", args: [input.symbols, params] }], "snapshot.openInterests");
|
|
611
|
+
},
|
|
612
|
+
},
|
|
613
|
+
];
|
|
614
|
+
const data = {};
|
|
615
|
+
const errors = {};
|
|
616
|
+
for (const task of tasks) {
|
|
617
|
+
try {
|
|
618
|
+
data[task.key] = await task.run();
|
|
619
|
+
}
|
|
620
|
+
catch (err) {
|
|
621
|
+
errors[task.key] = toErrorMessage(err);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
return {
|
|
625
|
+
timestamp: Date.now(),
|
|
626
|
+
symbol: input.symbol ?? null,
|
|
627
|
+
symbols: input.symbols ?? null,
|
|
628
|
+
data,
|
|
629
|
+
errors,
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
export async function executeCcxtFuturesOperation(instance, operationRaw, input) {
|
|
633
|
+
const operation = resolveOperation(operationRaw);
|
|
634
|
+
if (!SUPPORTED_FUTURES_OPERATIONS.includes(operation)) {
|
|
635
|
+
throw new Error(`Unsupported futures operation '${operationRaw}'. Supported operations: ${SUPPORTED_FUTURES_OPERATIONS.join(", ")}`);
|
|
636
|
+
}
|
|
637
|
+
const params = input.params ?? {};
|
|
638
|
+
switch (operation) {
|
|
639
|
+
case "markets": {
|
|
640
|
+
const result = await callWithFallback(instance, [{ method: "fetchMarkets", args: [params] }], "markets");
|
|
641
|
+
const normalized = normalizeToObjectArray(result);
|
|
642
|
+
if (normalized.length === 0)
|
|
643
|
+
return result;
|
|
644
|
+
const futures = normalized.filter((market) => market.contract === true || market.swap === true || market.future === true);
|
|
645
|
+
return futures.length > 0 ? futures : result;
|
|
646
|
+
}
|
|
647
|
+
case "ticker": {
|
|
648
|
+
const symbol = requireString(input.symbol, "--symbol");
|
|
649
|
+
return callWithFallback(instance, [{ method: "fetchTicker", args: [symbol, params] }], "ticker");
|
|
650
|
+
}
|
|
651
|
+
case "tickers": {
|
|
652
|
+
return callWithFallback(instance, [{ method: "fetchTickers", args: [input.symbols, params] }], "tickers");
|
|
653
|
+
}
|
|
654
|
+
case "orderbook": {
|
|
655
|
+
const symbol = requireString(input.symbol, "--symbol");
|
|
656
|
+
return callWithFallback(instance, [{ method: "fetchOrderBook", args: [symbol, input.limit, params] }], "orderbook");
|
|
657
|
+
}
|
|
658
|
+
case "funding-rate": {
|
|
659
|
+
const symbol = requireString(input.symbol, "--symbol");
|
|
660
|
+
return callWithFallback(instance, [{ method: "fetchFundingRate", args: [symbol, params] }], "funding-rate");
|
|
661
|
+
}
|
|
662
|
+
case "funding-rates": {
|
|
663
|
+
if (input.symbol && !input.symbols) {
|
|
664
|
+
return callWithFallback(instance, [{ method: "fetchFundingRate", args: [input.symbol, params] }], "funding-rates");
|
|
665
|
+
}
|
|
666
|
+
return callWithFallback(instance, [{ method: "fetchFundingRates", args: [input.symbols, params] }], "funding-rates");
|
|
667
|
+
}
|
|
668
|
+
case "funding-rate-history": {
|
|
669
|
+
const symbol = requireString(input.symbol, "--symbol");
|
|
670
|
+
return callWithFallback(instance, [{ method: "fetchFundingRateHistory", args: [symbol, input.since, input.limit, params] }], "funding-rate-history");
|
|
671
|
+
}
|
|
672
|
+
case "funding-history": {
|
|
673
|
+
return callWithFallback(instance, [{ method: "fetchFundingHistory", args: [input.symbol, input.since, input.limit, params] }], "funding-history");
|
|
674
|
+
}
|
|
675
|
+
case "open-interest": {
|
|
676
|
+
const symbol = requireString(input.symbol, "--symbol");
|
|
677
|
+
return callWithFallback(instance, [{ method: "fetchOpenInterest", args: [symbol, params] }], "open-interest");
|
|
678
|
+
}
|
|
679
|
+
case "open-interests": {
|
|
680
|
+
if (input.symbol && !input.symbols) {
|
|
681
|
+
return callWithFallback(instance, [{ method: "fetchOpenInterest", args: [input.symbol, params] }], "open-interests");
|
|
682
|
+
}
|
|
683
|
+
return callWithFallback(instance, [{ method: "fetchOpenInterests", args: [input.symbols, params] }], "open-interests");
|
|
684
|
+
}
|
|
685
|
+
case "open-interest-history": {
|
|
686
|
+
const symbol = requireString(input.symbol, "--symbol");
|
|
687
|
+
return callWithFallback(instance, [{ method: "fetchOpenInterestHistory", args: [symbol, input.since, input.limit, params] }], "open-interest-history");
|
|
688
|
+
}
|
|
689
|
+
case "balance": {
|
|
690
|
+
return callWithFallback(instance, [{ method: "fetchBalance", args: [params] }], "balance");
|
|
691
|
+
}
|
|
692
|
+
case "positions": {
|
|
693
|
+
if (input.symbol) {
|
|
694
|
+
return callWithFallback(instance, [
|
|
695
|
+
{ method: "fetchPosition", args: [input.symbol, params] },
|
|
696
|
+
{ method: "fetchPositionsForSymbol", args: [input.symbol, params] },
|
|
697
|
+
{ method: "fetchPositions", args: [[input.symbol], params] },
|
|
698
|
+
{ method: "fetchAccountPositions", args: [[input.symbol], params] },
|
|
699
|
+
], "positions");
|
|
700
|
+
}
|
|
701
|
+
return callWithFallback(instance, [
|
|
702
|
+
{ method: "fetchPositions", args: [input.symbols, params] },
|
|
703
|
+
{ method: "fetchAccountPositions", args: [input.symbols, params] },
|
|
704
|
+
{ method: "fetchPositionsRisk", args: [input.symbols, params] },
|
|
705
|
+
], "positions");
|
|
706
|
+
}
|
|
707
|
+
case "position": {
|
|
708
|
+
const symbol = requireString(input.symbol, "--symbol");
|
|
709
|
+
const result = await callWithFallback(instance, [
|
|
710
|
+
{ method: "fetchPosition", args: [symbol, params] },
|
|
711
|
+
{ method: "fetchPositionsForSymbol", args: [symbol, params] },
|
|
712
|
+
{ method: "fetchPositions", args: [[symbol], params] },
|
|
713
|
+
], "position");
|
|
714
|
+
if (Array.isArray(result)) {
|
|
715
|
+
return result[0] ?? null;
|
|
716
|
+
}
|
|
717
|
+
return result;
|
|
718
|
+
}
|
|
719
|
+
case "positions-history": {
|
|
720
|
+
if (input.symbol) {
|
|
721
|
+
return callWithFallback(instance, [
|
|
722
|
+
{ method: "fetchPositionHistory", args: [input.symbol, input.since, input.limit, params] },
|
|
723
|
+
{ method: "fetchPositionsHistory", args: [[input.symbol], input.since, input.limit, params] },
|
|
724
|
+
], "positions-history");
|
|
725
|
+
}
|
|
726
|
+
return callWithFallback(instance, [{ method: "fetchPositionsHistory", args: [input.symbols, input.since, input.limit, params] }], "positions-history");
|
|
727
|
+
}
|
|
728
|
+
case "position-history": {
|
|
729
|
+
const symbol = requireString(input.symbol, "--symbol");
|
|
730
|
+
return callWithFallback(instance, [{ method: "fetchPositionHistory", args: [symbol, input.since, input.limit, params] }], "position-history");
|
|
731
|
+
}
|
|
732
|
+
case "positions-risk": {
|
|
733
|
+
return callWithFallback(instance, [
|
|
734
|
+
{ method: "fetchPositionsRisk", args: [input.symbols, params] },
|
|
735
|
+
{ method: "fetchPositions", args: [input.symbols, params] },
|
|
736
|
+
], "positions-risk");
|
|
737
|
+
}
|
|
738
|
+
case "account-positions": {
|
|
739
|
+
return callWithFallback(instance, [
|
|
740
|
+
{ method: "fetchAccountPositions", args: [input.symbols, params] },
|
|
741
|
+
{ method: "fetchPositions", args: [input.symbols, params] },
|
|
742
|
+
], "account-positions");
|
|
743
|
+
}
|
|
744
|
+
case "option-positions": {
|
|
745
|
+
return callWithFallback(instance, [{ method: "fetchOptionPositions", args: [input.symbols, params] }], "option-positions");
|
|
746
|
+
}
|
|
747
|
+
case "orders-open": {
|
|
748
|
+
return callWithFallback(instance, [{ method: "fetchOpenOrders", args: [input.symbol, input.since, input.limit, params] }], "orders-open");
|
|
749
|
+
}
|
|
750
|
+
case "orders": {
|
|
751
|
+
return callWithFallback(instance, [{ method: "fetchOrders", args: [input.symbol, input.since, input.limit, params] }], "orders");
|
|
752
|
+
}
|
|
753
|
+
case "orders-closed": {
|
|
754
|
+
return callWithFallback(instance, [{ method: "fetchClosedOrders", args: [input.symbol, input.since, input.limit, params] }], "orders-closed");
|
|
755
|
+
}
|
|
756
|
+
case "orders-canceled": {
|
|
757
|
+
return callWithFallback(instance, [{ method: "fetchCanceledOrders", args: [input.symbol, input.since, input.limit, params] }], "orders-canceled");
|
|
758
|
+
}
|
|
759
|
+
case "order": {
|
|
760
|
+
const id = requireString(input.id, "--id");
|
|
761
|
+
return callWithFallback(instance, [{ method: "fetchOrder", args: [id, input.symbol, params] }], "order");
|
|
762
|
+
}
|
|
763
|
+
case "order-trades": {
|
|
764
|
+
const id = requireString(input.id, "--id");
|
|
765
|
+
return callWithFallback(instance, [{ method: "fetchOrderTrades", args: [id, input.symbol, input.since, input.limit, params] }], "order-trades");
|
|
766
|
+
}
|
|
767
|
+
case "my-trades": {
|
|
768
|
+
return callWithFallback(instance, [{ method: "fetchMyTrades", args: [input.symbol, input.since, input.limit, params] }], "my-trades");
|
|
769
|
+
}
|
|
770
|
+
case "trades-public": {
|
|
771
|
+
const symbol = requireString(input.symbol, "--symbol");
|
|
772
|
+
return callWithFallback(instance, [{ method: "fetchTrades", args: [symbol, input.since, input.limit, params] }], "trades-public");
|
|
773
|
+
}
|
|
774
|
+
case "create-order": {
|
|
775
|
+
const symbol = requireString(input.symbol, "--symbol");
|
|
776
|
+
const side = requireString(input.side, "--side").toLowerCase();
|
|
777
|
+
const orderType = requireString(input.orderType, "--order-type").toLowerCase();
|
|
778
|
+
const amount = requireNumber(input.amount, "--amount");
|
|
779
|
+
if (!["buy", "sell"].includes(side)) {
|
|
780
|
+
throw new Error("--side must be buy or sell");
|
|
781
|
+
}
|
|
782
|
+
if (orderType === "limit" && input.price === undefined) {
|
|
783
|
+
throw new Error("--price is required when --order-type is limit");
|
|
784
|
+
}
|
|
785
|
+
return callWithFallback(instance, [{ method: "createOrder", args: [symbol, orderType, side, amount, input.price, params] }], "create-order");
|
|
786
|
+
}
|
|
787
|
+
case "cancel-order": {
|
|
788
|
+
const id = requireString(input.id, "--id");
|
|
789
|
+
return callWithFallback(instance, [{ method: "cancelOrder", args: [id, input.symbol, params] }], "cancel-order");
|
|
790
|
+
}
|
|
791
|
+
case "cancel-all": {
|
|
792
|
+
return callWithFallback(instance, [{ method: "cancelAllOrders", args: [input.symbol, params] }], "cancel-all");
|
|
793
|
+
}
|
|
794
|
+
case "set-leverage": {
|
|
795
|
+
const symbol = requireString(input.symbol, "--symbol");
|
|
796
|
+
const leverage = requireNumber(input.leverage, "--leverage");
|
|
797
|
+
if (leverage <= 0) {
|
|
798
|
+
throw new Error("--leverage must be a positive number");
|
|
799
|
+
}
|
|
800
|
+
return callWithFallback(instance, [{ method: "setLeverage", args: [leverage, symbol, params] }], "set-leverage");
|
|
801
|
+
}
|
|
802
|
+
case "set-margin-mode": {
|
|
803
|
+
const symbol = requireString(input.symbol, "--symbol");
|
|
804
|
+
const marginMode = requireString(input.marginMode, "--margin-mode");
|
|
805
|
+
return callWithFallback(instance, [{ method: "setMarginMode", args: [marginMode, symbol, params] }], "set-margin-mode");
|
|
806
|
+
}
|
|
807
|
+
case "set-position-mode": {
|
|
808
|
+
const hedged = parsePositionMode(input.positionMode);
|
|
809
|
+
return callWithFallback(instance, [
|
|
810
|
+
{ method: "setPositionMode", args: [hedged, input.symbol, params] },
|
|
811
|
+
{ method: "setPositionMode", args: [hedged, params] },
|
|
812
|
+
], "set-position-mode");
|
|
813
|
+
}
|
|
814
|
+
case "leverage": {
|
|
815
|
+
if (input.symbol) {
|
|
816
|
+
const result = await callWithFallback(instance, [
|
|
817
|
+
{ method: "fetchLeverage", args: [input.symbol, params] },
|
|
818
|
+
{ method: "fetchLeverages", args: [[input.symbol], params] },
|
|
819
|
+
], "leverage");
|
|
820
|
+
if (Array.isArray(result)) {
|
|
821
|
+
return result[0] ?? null;
|
|
822
|
+
}
|
|
823
|
+
return result;
|
|
824
|
+
}
|
|
825
|
+
return callWithFallback(instance, [{ method: "fetchLeverages", args: [input.symbols, params] }], "leverage");
|
|
826
|
+
}
|
|
827
|
+
case "leverage-tiers": {
|
|
828
|
+
if (input.symbol) {
|
|
829
|
+
return callWithFallback(instance, [
|
|
830
|
+
{ method: "fetchMarketLeverageTiers", args: [input.symbol, params] },
|
|
831
|
+
{ method: "fetchLeverageTiers", args: [[input.symbol], params] },
|
|
832
|
+
], "leverage-tiers");
|
|
833
|
+
}
|
|
834
|
+
return callWithFallback(instance, [{ method: "fetchLeverageTiers", args: [input.symbols, params] }], "leverage-tiers");
|
|
835
|
+
}
|
|
836
|
+
case "market-leverage-tiers": {
|
|
837
|
+
const symbol = requireString(input.symbol, "--symbol");
|
|
838
|
+
return callWithFallback(instance, [{ method: "fetchMarketLeverageTiers", args: [symbol, params] }], "market-leverage-tiers");
|
|
839
|
+
}
|
|
840
|
+
case "margin-mode": {
|
|
841
|
+
if (input.symbol) {
|
|
842
|
+
const result = await callWithFallback(instance, [
|
|
843
|
+
{ method: "fetchMarginMode", args: [input.symbol, params] },
|
|
844
|
+
{ method: "fetchMarginModes", args: [[input.symbol], params] },
|
|
845
|
+
], "margin-mode");
|
|
846
|
+
if (Array.isArray(result)) {
|
|
847
|
+
return result[0] ?? null;
|
|
848
|
+
}
|
|
849
|
+
return result;
|
|
850
|
+
}
|
|
851
|
+
return callWithFallback(instance, [{ method: "fetchMarginModes", args: [input.symbols, params] }], "margin-mode");
|
|
852
|
+
}
|
|
853
|
+
case "position-mode": {
|
|
854
|
+
return callWithFallback(instance, [{ method: "fetchPositionMode", args: [input.symbol, params] }], "position-mode");
|
|
855
|
+
}
|
|
856
|
+
case "margin-adjustment-history": {
|
|
857
|
+
const symbol = requireString(input.symbol, "--symbol");
|
|
858
|
+
return callWithFallback(instance, [{ method: "fetchMarginAdjustmentHistory", args: [symbol, input.since, input.limit, params] }], "margin-adjustment-history");
|
|
859
|
+
}
|
|
860
|
+
case "transfers": {
|
|
861
|
+
return callWithFallback(instance, [{ method: "fetchTransfers", args: [input.code, input.since, input.limit, params] }], "transfers");
|
|
862
|
+
}
|
|
863
|
+
case "transfer": {
|
|
864
|
+
const code = requireString(input.code, "--code");
|
|
865
|
+
const amount = requireNumber(input.amount, "--amount");
|
|
866
|
+
const fromAccount = requireString(input.from, "--from");
|
|
867
|
+
const toAccount = requireString(input.to, "--to");
|
|
868
|
+
if (amount <= 0) {
|
|
869
|
+
throw new Error("--amount must be a positive number");
|
|
870
|
+
}
|
|
871
|
+
return callWithFallback(instance, [{ method: "transfer", args: [code, amount, fromAccount, toAccount, params] }], "transfer");
|
|
872
|
+
}
|
|
873
|
+
case "transfer-in": {
|
|
874
|
+
const code = requireString(input.code, "--code");
|
|
875
|
+
const amount = requireNumber(input.amount, "--amount");
|
|
876
|
+
const fromAccount = input.from ?? "spot";
|
|
877
|
+
const toAccount = input.to ?? "swap";
|
|
878
|
+
if (amount <= 0) {
|
|
879
|
+
throw new Error("--amount must be a positive number");
|
|
880
|
+
}
|
|
881
|
+
return callWithFallback(instance, [
|
|
882
|
+
{ method: "transferIn", args: [code, amount, params] },
|
|
883
|
+
{ method: "transfer", args: [code, amount, fromAccount, toAccount, params] },
|
|
884
|
+
], "transfer-in");
|
|
885
|
+
}
|
|
886
|
+
case "transfer-out": {
|
|
887
|
+
const code = requireString(input.code, "--code");
|
|
888
|
+
const amount = requireNumber(input.amount, "--amount");
|
|
889
|
+
const fromAccount = input.from ?? "swap";
|
|
890
|
+
const toAccount = input.to ?? "spot";
|
|
891
|
+
if (amount <= 0) {
|
|
892
|
+
throw new Error("--amount must be a positive number");
|
|
893
|
+
}
|
|
894
|
+
return callWithFallback(instance, [
|
|
895
|
+
{ method: "transferOut", args: [code, amount, params] },
|
|
896
|
+
{ method: "transfer", args: [code, amount, fromAccount, toAccount, params] },
|
|
897
|
+
], "transfer-out");
|
|
898
|
+
}
|
|
899
|
+
case "add-margin": {
|
|
900
|
+
const symbol = requireString(input.symbol, "--symbol");
|
|
901
|
+
const amount = requireNumber(input.amount, "--amount");
|
|
902
|
+
if (amount <= 0) {
|
|
903
|
+
throw new Error("--amount must be a positive number");
|
|
904
|
+
}
|
|
905
|
+
return callWithFallback(instance, [{ method: "addMargin", args: [symbol, amount, params] }], "add-margin");
|
|
906
|
+
}
|
|
907
|
+
case "reduce-margin": {
|
|
908
|
+
const symbol = requireString(input.symbol, "--symbol");
|
|
909
|
+
const amount = requireNumber(input.amount, "--amount");
|
|
910
|
+
if (amount <= 0) {
|
|
911
|
+
throw new Error("--amount must be a positive number");
|
|
912
|
+
}
|
|
913
|
+
return callWithFallback(instance, [{ method: "reduceMargin", args: [symbol, amount, params] }], "reduce-margin");
|
|
914
|
+
}
|
|
915
|
+
case "borrow-margin": {
|
|
916
|
+
const code = requireString(input.code, "--code");
|
|
917
|
+
const amount = requireNumber(input.amount, "--amount");
|
|
918
|
+
if (amount <= 0) {
|
|
919
|
+
throw new Error("--amount must be a positive number");
|
|
920
|
+
}
|
|
921
|
+
return callWithFallback(instance, [{ method: "borrowMargin", args: [code, amount, input.symbol, params] }], "borrow-margin");
|
|
922
|
+
}
|
|
923
|
+
case "repay-margin": {
|
|
924
|
+
const code = requireString(input.code, "--code");
|
|
925
|
+
const amount = requireNumber(input.amount, "--amount");
|
|
926
|
+
if (amount <= 0) {
|
|
927
|
+
throw new Error("--amount must be a positive number");
|
|
928
|
+
}
|
|
929
|
+
return callWithFallback(instance, [{ method: "repayMargin", args: [code, amount, input.symbol, params] }], "repay-margin");
|
|
930
|
+
}
|
|
931
|
+
case "close-position": {
|
|
932
|
+
const symbol = requireString(input.symbol, "--symbol");
|
|
933
|
+
return callWithFallback(instance, [
|
|
934
|
+
{ method: "closePosition", args: [symbol, input.side, params] },
|
|
935
|
+
{ method: "closePosition", args: [symbol, params] },
|
|
936
|
+
], "close-position");
|
|
937
|
+
}
|
|
938
|
+
case "close-all-positions": {
|
|
939
|
+
return callWithFallback(instance, [{ method: "closeAllPositions", args: [params] }], "close-all-positions");
|
|
940
|
+
}
|
|
941
|
+
case "snapshot": {
|
|
942
|
+
return executeBestEffortSnapshot(instance, input);
|
|
943
|
+
}
|
|
944
|
+
case "futures-methods": {
|
|
945
|
+
return listFuturesMethods(instance);
|
|
946
|
+
}
|
|
947
|
+
case "raw": {
|
|
948
|
+
const method = requireString(input.rawMethod, "--raw-method");
|
|
949
|
+
return callMethod(instance, method, input.rawArgs);
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
function buildCcxtClient(exchangeId, buildOptions = {}) {
|
|
954
|
+
const constructors = ccxt;
|
|
955
|
+
const normalized = exchangeId.toLowerCase();
|
|
956
|
+
const ExchangeCtor = constructors[normalized];
|
|
957
|
+
if (!ExchangeCtor) {
|
|
958
|
+
const supported = listCcxtExchangeIds().slice(0, 40).join(", ");
|
|
959
|
+
throw new Error(`Unknown ccxt exchange '${exchangeId}'. Try one of: ${supported} ...`);
|
|
960
|
+
}
|
|
961
|
+
const envOptions = parseEnvJsonObject("CCXT_OPTIONS");
|
|
962
|
+
const envHeaders = parseEnvJsonObject("CCXT_HEADERS");
|
|
963
|
+
const envHedged = parseBooleanLike(process.env.CCXT_HEDGED, "CCXT_HEDGED");
|
|
964
|
+
const envVerbose = parseBooleanLike(process.env.CCXT_VERBOSE, "CCXT_VERBOSE");
|
|
965
|
+
const envEnableRateLimit = parseBooleanLike(process.env.CCXT_ENABLE_RATE_LIMIT, "CCXT_ENABLE_RATE_LIMIT");
|
|
966
|
+
const envTimeout = parseEnvInt("CCXT_TIMEOUT_MS");
|
|
967
|
+
const defaultType = normalizeOptionalString(buildOptions.defaultType) ?? normalizeOptionalString(process.env.CCXT_DEFAULT_TYPE);
|
|
968
|
+
const defaultSubType = normalizeOptionalString(buildOptions.defaultSubType) ?? normalizeOptionalString(process.env.CCXT_DEFAULT_SUB_TYPE);
|
|
969
|
+
const settle = normalizeOptionalString(buildOptions.settle) ?? normalizeOptionalString(process.env.CCXT_DEFAULT_SETTLE);
|
|
970
|
+
const defaultMarginMode = normalizeOptionalString(buildOptions.defaultMarginMode) ??
|
|
971
|
+
normalizeOptionalString(process.env.CCXT_DEFAULT_MARGIN_MODE);
|
|
972
|
+
const hedged = buildOptions.hedged ?? envHedged;
|
|
973
|
+
const mergedOptions = mergeObjects(envOptions, buildOptions.options);
|
|
974
|
+
if (defaultType) {
|
|
975
|
+
mergedOptions.defaultType = defaultType;
|
|
976
|
+
}
|
|
977
|
+
if (defaultSubType) {
|
|
978
|
+
mergedOptions.defaultSubType = defaultSubType;
|
|
979
|
+
}
|
|
980
|
+
if (settle) {
|
|
981
|
+
mergedOptions.defaultSettle = settle;
|
|
982
|
+
mergedOptions.settle = settle;
|
|
983
|
+
}
|
|
984
|
+
if (defaultMarginMode) {
|
|
985
|
+
mergedOptions.defaultMarginMode = defaultMarginMode;
|
|
986
|
+
}
|
|
987
|
+
if (hedged !== undefined) {
|
|
988
|
+
mergedOptions.hedged = hedged;
|
|
989
|
+
}
|
|
990
|
+
const mergedHeaders = mergeObjects(envHeaders, buildOptions.headers);
|
|
991
|
+
const client = new ExchangeCtor({
|
|
992
|
+
enableRateLimit: buildOptions.enableRateLimit ?? envEnableRateLimit ?? true,
|
|
993
|
+
timeout: buildOptions.timeoutMs ?? envTimeout ?? 15_000,
|
|
994
|
+
verbose: buildOptions.verbose ?? envVerbose ?? false,
|
|
995
|
+
apiKey: process.env.CCXT_API_KEY,
|
|
996
|
+
secret: process.env.CCXT_API_SECRET,
|
|
997
|
+
password: process.env.CCXT_PASSWORD,
|
|
998
|
+
uid: process.env.CCXT_UID,
|
|
999
|
+
token: process.env.CCXT_TOKEN,
|
|
1000
|
+
privateKey: process.env.CCXT_PRIVATE_KEY,
|
|
1001
|
+
walletAddress: process.env.CCXT_WALLET_ADDRESS,
|
|
1002
|
+
headers: isEmptyObject(mergedHeaders) ? undefined : mergedHeaders,
|
|
1003
|
+
options: mergedOptions,
|
|
1004
|
+
});
|
|
1005
|
+
if (buildOptions.sandbox && typeof client.setSandboxMode === "function") {
|
|
1006
|
+
client.setSandboxMode(true);
|
|
1007
|
+
}
|
|
1008
|
+
return client;
|
|
1009
|
+
}
|
|
1010
|
+
async function createCcxtClient(exchangeId, buildOptions = {}) {
|
|
1011
|
+
const client = buildCcxtClient(exchangeId, buildOptions);
|
|
1012
|
+
if (buildOptions.loadMarkets) {
|
|
1013
|
+
await callMethod(client, "loadMarkets", []);
|
|
1014
|
+
}
|
|
1015
|
+
return client;
|
|
1016
|
+
}
|
|
1017
|
+
function buildPmxtClient(exchange, options) {
|
|
1018
|
+
const constructors = pmxt;
|
|
1019
|
+
const normalized = exchange.toLowerCase();
|
|
1020
|
+
const ctorName = PMXT_EXCHANGES[normalized];
|
|
1021
|
+
if (!ctorName) {
|
|
1022
|
+
throw new Error(`Unknown pmxt exchange '${exchange}'. Supported: ${Object.keys(PMXT_EXCHANGES).join(", ")}`);
|
|
1023
|
+
}
|
|
1024
|
+
const ExchangeCtor = constructors[ctorName];
|
|
1025
|
+
if (!ExchangeCtor) {
|
|
1026
|
+
throw new Error(`pmxt constructor '${ctorName}' is unavailable in this pmxtjs version`);
|
|
1027
|
+
}
|
|
1028
|
+
const signatureType = process.env.PMXT_SIGNATURE_TYPE
|
|
1029
|
+
? Number.parseInt(process.env.PMXT_SIGNATURE_TYPE, 10)
|
|
1030
|
+
: undefined;
|
|
1031
|
+
return new ExchangeCtor({
|
|
1032
|
+
apiKey: process.env.PMXT_API_KEY,
|
|
1033
|
+
privateKey: process.env.PMXT_PRIVATE_KEY,
|
|
1034
|
+
proxyAddress: process.env.PMXT_PROXY_ADDRESS,
|
|
1035
|
+
signatureType: Number.isFinite(signatureType) ? signatureType : undefined,
|
|
1036
|
+
baseUrl: options.baseUrl,
|
|
1037
|
+
autoStartServer: options.autoStartServer,
|
|
1038
|
+
});
|
|
1039
|
+
}
|
|
1040
|
+
function listCallableMethods(instance) {
|
|
1041
|
+
const methods = new Set();
|
|
1042
|
+
let proto = instance;
|
|
1043
|
+
while (proto && proto !== Object.prototype) {
|
|
1044
|
+
for (const name of Object.getOwnPropertyNames(proto)) {
|
|
1045
|
+
if (name === "constructor" || name.startsWith("_"))
|
|
1046
|
+
continue;
|
|
1047
|
+
const descriptor = Object.getOwnPropertyDescriptor(proto, name);
|
|
1048
|
+
if (descriptor && typeof descriptor.value === "function") {
|
|
1049
|
+
methods.add(name);
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
proto = Object.getPrototypeOf(proto);
|
|
1053
|
+
}
|
|
1054
|
+
return [...methods].sort((a, b) => a.localeCompare(b));
|
|
1055
|
+
}
|
|
1056
|
+
async function callMethod(instance, method, args) {
|
|
1057
|
+
const fn = instance[method];
|
|
1058
|
+
if (typeof fn !== "function") {
|
|
1059
|
+
const sample = listCallableMethods(instance).slice(0, 40).join(", ");
|
|
1060
|
+
throw new Error(`Method '${method}' is not available. Example methods: ${sample}`);
|
|
1061
|
+
}
|
|
1062
|
+
return await fn.apply(instance, args);
|
|
1063
|
+
}
|
|
1064
|
+
async function closeIfNeeded(instance) {
|
|
1065
|
+
if (!instance?.close)
|
|
1066
|
+
return;
|
|
1067
|
+
await Promise.resolve(instance.close()).catch(() => undefined);
|
|
1068
|
+
}
|
|
1069
|
+
function addCcxtSharedOptions(command, defaults) {
|
|
1070
|
+
const configured = command
|
|
1071
|
+
.option("--sandbox", "Enable ccxt sandbox mode (if exchange supports it)", false)
|
|
1072
|
+
.option("--default-type <type>", "CCXT defaultType (swap|future|margin|spot|option)")
|
|
1073
|
+
.option("--default-sub-type <type>", "CCXT defaultSubType (linear|inverse)")
|
|
1074
|
+
.option("--settle <code>", "CCXT default settlement asset (e.g. USDT)")
|
|
1075
|
+
.option("--default-margin-mode <mode>", "CCXT default margin mode (cross|isolated)")
|
|
1076
|
+
.option("--hedged", "Set CCXT hedged option true")
|
|
1077
|
+
.option("--headers <json>", "Extra CCXT headers JSON object")
|
|
1078
|
+
.option("--options <json>", "Extra CCXT options JSON object")
|
|
1079
|
+
.option("--timeout-ms <ms>", "Override CCXT timeout in milliseconds")
|
|
1080
|
+
.option("--verbose", "Enable CCXT verbose mode")
|
|
1081
|
+
.option("--disable-rate-limit", "Disable CCXT rate limiter");
|
|
1082
|
+
if (defaults.loadMarkets) {
|
|
1083
|
+
configured.option("--no-load-markets", "Skip loadMarkets before executing the operation");
|
|
1084
|
+
}
|
|
1085
|
+
else {
|
|
1086
|
+
configured.option("--load-markets", "Call loadMarkets before executing the method", false);
|
|
1087
|
+
}
|
|
1088
|
+
return configured;
|
|
1089
|
+
}
|
|
1090
|
+
function resolveCcxtBuildOptions(opts, defaults) {
|
|
1091
|
+
const timeoutMs = parseOptionalInteger(opts.timeoutMs, "--timeout-ms");
|
|
1092
|
+
const headers = opts.headers ? parseJsonObject(opts.headers, "--headers") : undefined;
|
|
1093
|
+
const options = opts.options ? parseJsonObject(opts.options, "--options") : undefined;
|
|
1094
|
+
return {
|
|
1095
|
+
sandbox: opts.sandbox ?? false,
|
|
1096
|
+
loadMarkets: opts.loadMarkets ?? defaults.loadMarkets,
|
|
1097
|
+
defaultType: normalizeOptionalString(opts.defaultType),
|
|
1098
|
+
defaultSubType: normalizeOptionalString(opts.defaultSubType),
|
|
1099
|
+
settle: normalizeOptionalString(opts.settle),
|
|
1100
|
+
defaultMarginMode: normalizeOptionalString(opts.defaultMarginMode),
|
|
1101
|
+
hedged: opts.hedged ? true : undefined,
|
|
1102
|
+
headers,
|
|
1103
|
+
options,
|
|
1104
|
+
timeoutMs,
|
|
1105
|
+
verbose: opts.verbose ? true : undefined,
|
|
1106
|
+
enableRateLimit: opts.disableRateLimit ? false : undefined,
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1109
|
+
function resolveCcxtFuturesOperationOptions(opts) {
|
|
1110
|
+
const symbols = opts.symbols ? parseJsonStringArray(opts.symbols, "--symbols") : undefined;
|
|
1111
|
+
return {
|
|
1112
|
+
symbol: normalizeOptionalString(opts.symbol),
|
|
1113
|
+
symbols,
|
|
1114
|
+
id: normalizeOptionalString(opts.id),
|
|
1115
|
+
side: normalizeOptionalString(opts.side),
|
|
1116
|
+
orderType: normalizeOptionalString(opts.orderType),
|
|
1117
|
+
amount: parseOptionalPositiveNumber(opts.amount, "--amount"),
|
|
1118
|
+
price: parseOptionalPositiveNumber(opts.price, "--price"),
|
|
1119
|
+
since: parseOptionalInteger(opts.since, "--since"),
|
|
1120
|
+
limit: parseOptionalInteger(opts.limit, "--limit"),
|
|
1121
|
+
leverage: parseOptionalPositiveNumber(opts.leverage, "--leverage"),
|
|
1122
|
+
marginMode: normalizeOptionalString(opts.marginMode),
|
|
1123
|
+
positionMode: normalizeOptionalString(opts.positionMode),
|
|
1124
|
+
code: normalizeOptionalString(opts.code),
|
|
1125
|
+
from: normalizeOptionalString(opts.from),
|
|
1126
|
+
to: normalizeOptionalString(opts.to),
|
|
1127
|
+
params: parseJsonObject(opts.params, "--params"),
|
|
1128
|
+
rawMethod: normalizeOptionalString(opts.rawMethod),
|
|
1129
|
+
rawArgs: parseJsonArray(opts.args),
|
|
1130
|
+
};
|
|
1131
|
+
}
|
|
1132
|
+
function buildCcxtCapabilitiesSnapshot(instance, exchangeId) {
|
|
1133
|
+
const methods = listCallableMethods(instance);
|
|
1134
|
+
const futuresMethods = listFuturesMethods(instance);
|
|
1135
|
+
const has = asRecord(instance.has) ?? {};
|
|
1136
|
+
const requiredCredentials = asRecord(instance.requiredCredentials) ?? {};
|
|
1137
|
+
const urls = asRecord(instance.urls) ?? {};
|
|
1138
|
+
const venue = inferVenueType(exchangeId);
|
|
1139
|
+
const operationSupport = buildFuturesOperationSupport(instance);
|
|
1140
|
+
const derivativeSupport = deriveDerivativeSupport(has);
|
|
1141
|
+
const basic = {
|
|
1142
|
+
provider: "ccxt",
|
|
1143
|
+
exchangeId,
|
|
1144
|
+
exchangeName: typeof instance.name === "string" ? instance.name : exchangeId,
|
|
1145
|
+
venue,
|
|
1146
|
+
authModel: inferAuthModel(requiredCredentials),
|
|
1147
|
+
rateLimit: typeof instance.rateLimit === "number" ? instance.rateLimit : null,
|
|
1148
|
+
timeoutMs: typeof instance.timeout === "number" ? instance.timeout : null,
|
|
1149
|
+
version: typeof instance.version === "string" ? instance.version : null,
|
|
1150
|
+
countries: Array.isArray(instance.countries) ? instance.countries : [],
|
|
1151
|
+
urls,
|
|
1152
|
+
derivatives: {
|
|
1153
|
+
support: derivativeSupport,
|
|
1154
|
+
futuresOperationSupport: operationSupport,
|
|
1155
|
+
},
|
|
1156
|
+
stats: {
|
|
1157
|
+
methodCount: methods.length,
|
|
1158
|
+
futuresMethodCount: futuresMethods.length,
|
|
1159
|
+
marketStats: buildMarketStats(instance),
|
|
1160
|
+
currencyStats: buildCurrencyStats(instance),
|
|
1161
|
+
},
|
|
1162
|
+
};
|
|
1163
|
+
return {
|
|
1164
|
+
...basic,
|
|
1165
|
+
has,
|
|
1166
|
+
features: instance.features ?? null,
|
|
1167
|
+
requiredCredentials,
|
|
1168
|
+
timeframes: asRecord(instance.timeframes) ?? {},
|
|
1169
|
+
options: asRecord(instance.options) ?? {},
|
|
1170
|
+
methods,
|
|
1171
|
+
futuresMethods,
|
|
1172
|
+
};
|
|
1173
|
+
}
|
|
1174
|
+
async function discoverCcxtExchanges(opts) {
|
|
1175
|
+
const includeAll = opts.all ?? false;
|
|
1176
|
+
const includeMethodCounts = opts.withMethodCounts ?? false;
|
|
1177
|
+
const limit = parseOptionalInteger(opts.limit, "--limit");
|
|
1178
|
+
const ids = listCcxtExchangeIds();
|
|
1179
|
+
const exchanges = [];
|
|
1180
|
+
const errors = [];
|
|
1181
|
+
for (const id of ids) {
|
|
1182
|
+
let client = null;
|
|
1183
|
+
try {
|
|
1184
|
+
client = buildCcxtClient(id, {
|
|
1185
|
+
enableRateLimit: false,
|
|
1186
|
+
timeoutMs: 5_000,
|
|
1187
|
+
});
|
|
1188
|
+
const methods = listCallableMethods(client);
|
|
1189
|
+
const futuresMethods = listFuturesMethods(client);
|
|
1190
|
+
const has = asRecord(client.has) ?? {};
|
|
1191
|
+
const derivativeSupport = deriveDerivativeSupport(has);
|
|
1192
|
+
const hasDerivatives = derivativeSupport.perpsOrFutures === true;
|
|
1193
|
+
if (!includeAll && !hasDerivatives) {
|
|
1194
|
+
continue;
|
|
1195
|
+
}
|
|
1196
|
+
const requiredCredentials = asRecord(client.requiredCredentials) ?? {};
|
|
1197
|
+
const row = {
|
|
1198
|
+
id,
|
|
1199
|
+
name: typeof client.name === "string" ? client.name : id,
|
|
1200
|
+
venue: inferVenueType(id),
|
|
1201
|
+
authModel: inferAuthModel(requiredCredentials),
|
|
1202
|
+
derivatives: derivativeSupport,
|
|
1203
|
+
};
|
|
1204
|
+
if (includeMethodCounts) {
|
|
1205
|
+
row.methodCounts = {
|
|
1206
|
+
all: methods.length,
|
|
1207
|
+
futures: futuresMethods.length,
|
|
1208
|
+
};
|
|
1209
|
+
}
|
|
1210
|
+
exchanges.push(row);
|
|
1211
|
+
if (limit !== undefined && exchanges.length >= limit) {
|
|
1212
|
+
break;
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
catch (err) {
|
|
1216
|
+
errors.push({
|
|
1217
|
+
id,
|
|
1218
|
+
error: toErrorMessage(err),
|
|
1219
|
+
});
|
|
1220
|
+
}
|
|
1221
|
+
finally {
|
|
1222
|
+
await closeIfNeeded(client);
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
return {
|
|
1226
|
+
provider: "ccxt",
|
|
1227
|
+
scanned: ids.length,
|
|
1228
|
+
returned: exchanges.length,
|
|
1229
|
+
filters: {
|
|
1230
|
+
includeAll,
|
|
1231
|
+
includeMethodCounts,
|
|
1232
|
+
limit: limit ?? null,
|
|
1233
|
+
},
|
|
1234
|
+
exchanges,
|
|
1235
|
+
errors: errors.slice(0, 50),
|
|
1236
|
+
errorCount: errors.length,
|
|
1237
|
+
};
|
|
1238
|
+
}
|
|
1239
|
+
export function registerDataCommands(program) {
|
|
1240
|
+
const data = program
|
|
1241
|
+
.command("data")
|
|
1242
|
+
.description("Arbitrary connector-backed data pulls (ccxt + pmxt)");
|
|
1243
|
+
addCcxtSharedOptions(data
|
|
1244
|
+
.command("ccxt <exchangeId> <method>")
|
|
1245
|
+
.description("Call a raw ccxt method on an exchange")
|
|
1246
|
+
.option("--args <json>", "JSON array of positional args", "[]"), { loadMarkets: false }).action(async function (exchangeId, method) {
|
|
1247
|
+
const outputOpts = getOutputOptions(this);
|
|
1248
|
+
const opts = this.opts();
|
|
1249
|
+
let client = null;
|
|
1250
|
+
try {
|
|
1251
|
+
const args = parseJsonArray(opts.args);
|
|
1252
|
+
const buildOptions = resolveCcxtBuildOptions(opts, { loadMarkets: false });
|
|
1253
|
+
client = await createCcxtClient(exchangeId, buildOptions);
|
|
1254
|
+
const result = await callMethod(client, method, args);
|
|
1255
|
+
output(result, outputOpts);
|
|
1256
|
+
}
|
|
1257
|
+
catch (err) {
|
|
1258
|
+
outputError(toErrorMessage(err));
|
|
1259
|
+
process.exitCode = 1;
|
|
1260
|
+
}
|
|
1261
|
+
finally {
|
|
1262
|
+
await closeIfNeeded(client);
|
|
1263
|
+
}
|
|
1264
|
+
});
|
|
1265
|
+
addCcxtSharedOptions(data
|
|
1266
|
+
.command("ccxt-methods <exchangeId>")
|
|
1267
|
+
.description("List callable methods exposed by a ccxt exchange client")
|
|
1268
|
+
.option("--futures", "Filter for futures/perps-relevant methods", false), { loadMarkets: false }).action(async function (exchangeId) {
|
|
1269
|
+
const outputOpts = getOutputOptions(this);
|
|
1270
|
+
const opts = this.opts();
|
|
1271
|
+
let client = null;
|
|
1272
|
+
try {
|
|
1273
|
+
const buildOptions = resolveCcxtBuildOptions(opts, { loadMarkets: false });
|
|
1274
|
+
client = await createCcxtClient(exchangeId, buildOptions);
|
|
1275
|
+
const methods = opts.futures ? listFuturesMethods(client) : listCallableMethods(client);
|
|
1276
|
+
output({
|
|
1277
|
+
provider: "ccxt",
|
|
1278
|
+
exchangeId: exchangeId.toLowerCase(),
|
|
1279
|
+
futuresOnly: opts.futures ?? false,
|
|
1280
|
+
methods,
|
|
1281
|
+
}, outputOpts);
|
|
1282
|
+
}
|
|
1283
|
+
catch (err) {
|
|
1284
|
+
outputError(toErrorMessage(err));
|
|
1285
|
+
process.exitCode = 1;
|
|
1286
|
+
}
|
|
1287
|
+
finally {
|
|
1288
|
+
await closeIfNeeded(client);
|
|
1289
|
+
}
|
|
1290
|
+
});
|
|
1291
|
+
data
|
|
1292
|
+
.command("ccxt-exchanges")
|
|
1293
|
+
.description("Discover CCXT exchange coverage for futures/perps and likely venue model")
|
|
1294
|
+
.option("--all", "Include exchanges without derivative support signals", false)
|
|
1295
|
+
.option("--with-method-counts", "Include total/futures method counts", false)
|
|
1296
|
+
.option("--limit <n>", "Limit output rows")
|
|
1297
|
+
.action(async function () {
|
|
1298
|
+
const outputOpts = getOutputOptions(this);
|
|
1299
|
+
const opts = this.opts();
|
|
1300
|
+
try {
|
|
1301
|
+
const result = await discoverCcxtExchanges(opts);
|
|
1302
|
+
output(result, outputOpts);
|
|
1303
|
+
}
|
|
1304
|
+
catch (err) {
|
|
1305
|
+
outputError(toErrorMessage(err));
|
|
1306
|
+
process.exitCode = 1;
|
|
1307
|
+
}
|
|
1308
|
+
});
|
|
1309
|
+
addCcxtSharedOptions(data
|
|
1310
|
+
.command("ccxt-capabilities <exchangeId>")
|
|
1311
|
+
.description("Show deep capability map for one CCXT exchange (methods, features, derivatives support)")
|
|
1312
|
+
.option("--lite", "Return reduced summary only", false)
|
|
1313
|
+
.option("--futures", "Default CCXT market type to swap for this probe", false), { loadMarkets: true }).action(async function (exchangeId) {
|
|
1314
|
+
const outputOpts = getOutputOptions(this);
|
|
1315
|
+
const opts = this.opts();
|
|
1316
|
+
let client = null;
|
|
1317
|
+
const warnings = [];
|
|
1318
|
+
try {
|
|
1319
|
+
const buildOptions = resolveCcxtBuildOptions({
|
|
1320
|
+
...opts,
|
|
1321
|
+
defaultType: opts.defaultType ?? (opts.futures ? "swap" : undefined),
|
|
1322
|
+
}, { loadMarkets: true });
|
|
1323
|
+
try {
|
|
1324
|
+
client = await createCcxtClient(exchangeId, buildOptions);
|
|
1325
|
+
}
|
|
1326
|
+
catch (err) {
|
|
1327
|
+
if (!buildOptions.loadMarkets) {
|
|
1328
|
+
throw err;
|
|
1329
|
+
}
|
|
1330
|
+
warnings.push(`loadMarkets failed; continuing without market metadata: ${toErrorMessage(err)}`);
|
|
1331
|
+
client = await createCcxtClient(exchangeId, {
|
|
1332
|
+
...buildOptions,
|
|
1333
|
+
loadMarkets: false,
|
|
1334
|
+
});
|
|
1335
|
+
}
|
|
1336
|
+
const snapshot = buildCcxtCapabilitiesSnapshot(client, exchangeId.toLowerCase());
|
|
1337
|
+
if (opts.lite) {
|
|
1338
|
+
output({
|
|
1339
|
+
provider: "ccxt",
|
|
1340
|
+
exchangeId: snapshot.exchangeId,
|
|
1341
|
+
exchangeName: snapshot.exchangeName,
|
|
1342
|
+
venue: snapshot.venue,
|
|
1343
|
+
authModel: snapshot.authModel,
|
|
1344
|
+
derivatives: snapshot.derivatives.support,
|
|
1345
|
+
stats: snapshot.stats,
|
|
1346
|
+
warnings,
|
|
1347
|
+
}, outputOpts);
|
|
1348
|
+
return;
|
|
1349
|
+
}
|
|
1350
|
+
output({
|
|
1351
|
+
...snapshot,
|
|
1352
|
+
warnings,
|
|
1353
|
+
}, outputOpts);
|
|
1354
|
+
}
|
|
1355
|
+
catch (err) {
|
|
1356
|
+
outputError(toErrorMessage(err));
|
|
1357
|
+
process.exitCode = 1;
|
|
1358
|
+
}
|
|
1359
|
+
finally {
|
|
1360
|
+
await closeIfNeeded(client);
|
|
1361
|
+
}
|
|
1362
|
+
});
|
|
1363
|
+
addCcxtSharedOptions(data
|
|
1364
|
+
.command("ccxt-futures <exchangeId> <operation>")
|
|
1365
|
+
.description("High-level futures/perps workflow operations via ccxt")
|
|
1366
|
+
.option("--symbol <symbol>", "Market symbol (for example BTC/USDT:USDT)")
|
|
1367
|
+
.option("--symbols <json>", "JSON array of symbols")
|
|
1368
|
+
.option("--id <id>", "Order or transfer ID")
|
|
1369
|
+
.option("--side <side>", "Order side (buy|sell)")
|
|
1370
|
+
.option("--order-type <type>", "Order type (market|limit|stop|take_profit)")
|
|
1371
|
+
.option("--amount <amount>", "Order, transfer, or margin amount")
|
|
1372
|
+
.option("--price <price>", "Order price")
|
|
1373
|
+
.option("--since <ms>", "Start timestamp in ms for pagination")
|
|
1374
|
+
.option("--limit <count>", "Pagination limit")
|
|
1375
|
+
.option("--leverage <x>", "Leverage value")
|
|
1376
|
+
.option("--margin-mode <mode>", "Margin mode (cross|isolated)")
|
|
1377
|
+
.option("--position-mode <mode>", "Position mode (hedged|oneway)")
|
|
1378
|
+
.option("--code <asset>", "Transfer/borrow asset code (for example USDT)")
|
|
1379
|
+
.option("--from <account>", "Transfer source account")
|
|
1380
|
+
.option("--to <account>", "Transfer destination account")
|
|
1381
|
+
.option("--params <json>", "JSON object appended as ccxt params", "{}")
|
|
1382
|
+
.option("--raw-method <method>", "Raw method for operation=raw")
|
|
1383
|
+
.option("--args <json>", "Raw args JSON array for operation=raw", "[]"), { loadMarkets: true }).action(async function (exchangeId, operation) {
|
|
1384
|
+
const outputOpts = getOutputOptions(this);
|
|
1385
|
+
const opts = this.opts();
|
|
1386
|
+
let client = null;
|
|
1387
|
+
try {
|
|
1388
|
+
const buildOptions = resolveCcxtBuildOptions({
|
|
1389
|
+
...opts,
|
|
1390
|
+
defaultType: opts.defaultType ?? "swap",
|
|
1391
|
+
}, { loadMarkets: true });
|
|
1392
|
+
client = await createCcxtClient(exchangeId, buildOptions);
|
|
1393
|
+
const operationOptions = resolveCcxtFuturesOperationOptions(opts);
|
|
1394
|
+
const normalizedOperation = resolveOperation(operation);
|
|
1395
|
+
const result = await executeCcxtFuturesOperation(client, normalizedOperation, operationOptions);
|
|
1396
|
+
output({
|
|
1397
|
+
provider: "ccxt",
|
|
1398
|
+
scope: "futures",
|
|
1399
|
+
exchangeId: exchangeId.toLowerCase(),
|
|
1400
|
+
operation: normalizedOperation,
|
|
1401
|
+
result,
|
|
1402
|
+
}, outputOpts);
|
|
1403
|
+
}
|
|
1404
|
+
catch (err) {
|
|
1405
|
+
outputError(toErrorMessage(err));
|
|
1406
|
+
process.exitCode = 1;
|
|
1407
|
+
}
|
|
1408
|
+
finally {
|
|
1409
|
+
await closeIfNeeded(client);
|
|
1410
|
+
}
|
|
1411
|
+
});
|
|
1412
|
+
data
|
|
1413
|
+
.command("pmxt <exchange> <method>")
|
|
1414
|
+
.description("Call a raw pmxt method on an exchange (polymarket|kalshi|limitless)")
|
|
1415
|
+
.option("--args <json>", "JSON array of positional args", "[]")
|
|
1416
|
+
.option("--base-url <url>", "Override PMXT server URL (default: PMXT_BASE_URL or localhost)")
|
|
1417
|
+
.option("--no-auto-start", "Disable PMXT sidecar auto-start")
|
|
1418
|
+
.action(async function (exchange, method) {
|
|
1419
|
+
const outputOpts = getOutputOptions(this);
|
|
1420
|
+
const opts = this.opts();
|
|
1421
|
+
let client = null;
|
|
1422
|
+
try {
|
|
1423
|
+
const args = parseJsonArray(opts.args);
|
|
1424
|
+
client = buildPmxtClient(exchange, {
|
|
1425
|
+
baseUrl: opts.baseUrl ?? process.env.PMXT_BASE_URL,
|
|
1426
|
+
autoStartServer: opts.autoStart,
|
|
1427
|
+
});
|
|
1428
|
+
const result = await callMethod(client, method, args);
|
|
1429
|
+
output(result, outputOpts);
|
|
1430
|
+
}
|
|
1431
|
+
catch (err) {
|
|
1432
|
+
outputError(toErrorMessage(err));
|
|
1433
|
+
process.exitCode = 1;
|
|
1434
|
+
}
|
|
1435
|
+
finally {
|
|
1436
|
+
await closeIfNeeded(client);
|
|
1437
|
+
}
|
|
1438
|
+
});
|
|
1439
|
+
data
|
|
1440
|
+
.command("pmxt-methods <exchange>")
|
|
1441
|
+
.description("List callable methods exposed by a pmxt exchange client")
|
|
1442
|
+
.option("--base-url <url>", "Override PMXT server URL (default: PMXT_BASE_URL or localhost)")
|
|
1443
|
+
.action(async function (exchange) {
|
|
1444
|
+
const outputOpts = getOutputOptions(this);
|
|
1445
|
+
const opts = this.opts();
|
|
1446
|
+
let client = null;
|
|
1447
|
+
try {
|
|
1448
|
+
client = buildPmxtClient(exchange, {
|
|
1449
|
+
baseUrl: opts.baseUrl ?? process.env.PMXT_BASE_URL,
|
|
1450
|
+
autoStartServer: false,
|
|
1451
|
+
});
|
|
1452
|
+
output({
|
|
1453
|
+
provider: "pmxt",
|
|
1454
|
+
exchange: exchange.toLowerCase(),
|
|
1455
|
+
methods: listCallableMethods(client),
|
|
1456
|
+
}, outputOpts);
|
|
1457
|
+
}
|
|
1458
|
+
catch (err) {
|
|
1459
|
+
outputError(toErrorMessage(err));
|
|
1460
|
+
process.exitCode = 1;
|
|
1461
|
+
}
|
|
1462
|
+
finally {
|
|
1463
|
+
await closeIfNeeded(client);
|
|
1464
|
+
}
|
|
1465
|
+
});
|
|
1466
|
+
}
|