perp-cli 0.14.3 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +243 -0
- package/README.ko.md +243 -0
- package/README.md +138 -405
- package/README.zh.md +243 -0
- package/dist/agent-wallet/store.d.ts +3 -2
- package/dist/agent-wallet/store.js +2 -2
- package/dist/api/public/hyperliquid.js +4 -0
- package/dist/api/public/lighter.d.ts +5 -0
- package/dist/api/public/lighter.js +5 -0
- package/dist/api/public/pacifica.js +85 -15
- package/dist/api/public/urls.d.ts +2 -0
- package/dist/api/public/urls.js +3 -0
- package/dist/arb/sizing.js +4 -2
- package/dist/arb/state.d.ts +6 -0
- package/dist/arb/utils.d.ts +1 -2
- package/dist/arb/utils.js +1 -2
- package/dist/balance-by-address.d.ts +39 -0
- package/dist/balance-by-address.js +44 -0
- package/dist/bot/apex/pulse.js +3 -0
- package/dist/bot/apex/radar.js +2 -1
- package/dist/bot/engine.d.ts +10 -1
- package/dist/bot/engine.js +14 -6
- package/dist/bot/indicators.d.ts +7 -0
- package/dist/bot/indicators.js +16 -0
- package/dist/bot/perp-order.d.ts +4 -4
- package/dist/bot/perp-order.js +5 -5
- package/dist/bot/quarantine.d.ts +1 -1
- package/dist/bot/quarantine.js +1 -1
- package/dist/bot/quote-rules.js +1 -1
- package/dist/bot/strategies/apex-strategy.js +3 -2
- package/dist/bot/strategies/engine-mm.js +6 -5
- package/dist/bot/strategies/funding-arb-strategy.js +12 -5
- package/dist/bot/strategies/funding-arb-utils.d.ts +15 -3
- package/dist/bot/strategies/funding-arb-utils.js +53 -20
- package/dist/bot/strategies/funding-auto.js +2 -2
- package/dist/bot/strategies/liquidation-mm.d.ts +1 -0
- package/dist/bot/strategies/liquidation-mm.js +8 -2
- package/dist/bot/strategies/momentum-breakout.d.ts +1 -0
- package/dist/bot/strategies/momentum-breakout.js +11 -3
- package/dist/bot/strategies/spot-perp-arb-strategy.d.ts +1 -1
- package/dist/bot/strategies/spot-perp-arb-strategy.js +6 -4
- package/dist/bot/strategies/spot-perp-executor.d.ts +1 -1
- package/dist/bot/strategies/spot-perp-executor.js +3 -3
- package/dist/bot/strategy-types.d.ts +2 -1
- package/dist/bot/tui/BotDashboard.d.ts +1 -1
- package/dist/bot/tui/BotDashboard.js +1 -1
- package/dist/cache.js +12 -6
- package/dist/cli-program.d.ts +15 -0
- package/dist/cli-program.js +126 -6
- package/dist/commands/account.js +168 -24
- package/dist/commands/agent-import.d.ts +7 -0
- package/dist/commands/agent-import.js +30 -1
- package/dist/commands/agent.d.ts +6 -3
- package/dist/commands/agent.js +160 -12
- package/dist/commands/arb/index.js +23 -81
- package/dist/commands/arb-auto.d.ts +24 -0
- package/dist/commands/arb-auto.js +175 -97
- package/dist/commands/arb.d.ts +20 -0
- package/dist/commands/arb.js +107 -163
- package/dist/commands/backtest.js +23 -21
- package/dist/commands/bot.js +1 -1
- package/dist/commands/builder.js +1 -1
- package/dist/commands/funds.js +113 -3
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.js +27 -7
- package/dist/commands/manage.js +23 -21
- package/dist/commands/market.d.ts +48 -0
- package/dist/commands/market.js +395 -100
- package/dist/commands/options.d.ts +14 -0
- package/dist/commands/options.js +151 -0
- package/dist/commands/pacifica-earn.d.ts +5 -0
- package/dist/commands/pacifica-earn.js +455 -0
- package/dist/commands/pacifica-orders.d.ts +14 -0
- package/dist/commands/pacifica-orders.js +142 -0
- package/dist/commands/portfolio.d.ts +16 -0
- package/dist/commands/portfolio.js +83 -55
- package/dist/commands/rebalance.d.ts +1 -0
- package/dist/commands/rebalance.js +15 -0
- package/dist/commands/risk.d.ts +11 -2
- package/dist/commands/risk.js +39 -44
- package/dist/commands/trade.d.ts +1 -0
- package/dist/commands/trade.js +67 -62
- package/dist/commands/wallet.js +1 -1
- package/dist/config.d.ts +2 -2
- package/dist/config.js +15 -4
- package/dist/constants.js +6 -0
- package/dist/cross-chain-margin.d.ts +3 -1
- package/dist/cross-chain-margin.js +4 -2
- package/dist/dashboard/server.js +3 -3
- package/dist/dashboard/ui.js +9 -6
- package/dist/errors.d.ts +29 -1
- package/dist/errors.js +35 -3
- package/dist/exchanges/address.d.ts +8 -0
- package/dist/exchanges/address.js +47 -0
- package/dist/exchanges/arcus/adapter.d.ts +16 -12
- package/dist/exchanges/arcus/adapter.js +45 -18
- package/dist/exchanges/arcus/agent.d.ts +1 -1
- package/dist/exchanges/arcus/agent.js +1 -1
- package/dist/exchanges/arcus/client.js +1 -1
- package/dist/exchanges/arcus/public.js +3 -2
- package/dist/exchanges/arcus/signing.d.ts +2 -3
- package/dist/exchanges/arcus/signing.js +1 -1
- package/dist/exchanges/arcus/spot-chain.d.ts +1 -1
- package/dist/exchanges/arcus/spot-chain.js +1 -1
- package/dist/exchanges/arcus/spot-router.d.ts +1 -1
- package/dist/exchanges/arcus/spot-router.js +2 -2
- package/dist/exchanges/arcus/spot.d.ts +2 -3
- package/dist/exchanges/arcus/spot.js +2 -3
- package/dist/exchanges/aster-spot.d.ts +3 -3
- package/dist/exchanges/aster-spot.js +6 -9
- package/dist/exchanges/aster-typed-data.d.ts +1 -1
- package/dist/exchanges/aster-typed-data.js +1 -1
- package/dist/exchanges/aster.d.ts +30 -10
- package/dist/exchanges/aster.js +153 -53
- package/dist/exchanges/builder-fee.d.ts +1 -1
- package/dist/exchanges/builder-fee.js +13 -2
- package/dist/exchanges/canonical-symbols.d.ts +8 -2
- package/dist/exchanges/canonical-symbols.js +46 -2
- package/dist/exchanges/capabilities.d.ts +2 -0
- package/dist/exchanges/capabilities.js +2 -1
- package/dist/exchanges/derive/client.d.ts +37 -0
- package/dist/exchanges/derive/client.js +135 -0
- package/dist/exchanges/derive/options.d.ts +73 -0
- package/dist/exchanges/derive/options.js +379 -0
- package/dist/exchanges/extended/adapter.d.ts +96 -0
- package/dist/exchanges/extended/adapter.js +241 -0
- package/dist/exchanges/extended/client.d.ts +38 -0
- package/dist/exchanges/extended/client.js +88 -0
- package/dist/exchanges/extended/public.d.ts +133 -0
- package/dist/exchanges/extended/public.js +436 -0
- package/dist/exchanges/grvt/adapter.d.ts +100 -0
- package/dist/exchanges/grvt/adapter.js +283 -0
- package/dist/exchanges/grvt/client.d.ts +25 -0
- package/dist/exchanges/grvt/client.js +86 -0
- package/dist/exchanges/grvt/public.d.ts +151 -0
- package/dist/exchanges/grvt/public.js +438 -0
- package/dist/exchanges/hyperliquid-outcome.d.ts +2 -0
- package/dist/exchanges/hyperliquid-outcome.js +29 -1
- package/dist/exchanges/hyperliquid-spot.d.ts +9 -1
- package/dist/exchanges/hyperliquid-spot.js +24 -16
- package/dist/exchanges/hyperliquid.d.ts +199 -22
- package/dist/exchanges/hyperliquid.js +550 -202
- package/dist/exchanges/index.d.ts +1 -1
- package/dist/exchanges/index.js +1 -1
- package/dist/exchanges/interface.d.ts +157 -13
- package/dist/exchanges/interface.js +47 -0
- package/dist/exchanges/ioc-outcome.d.ts +1 -1
- package/dist/exchanges/ioc-outcome.js +1 -1
- package/dist/exchanges/legacy-trading-v2.d.ts +2 -2
- package/dist/exchanges/legacy-trading-v2.js +7 -2
- package/dist/exchanges/lighter-public.d.ts +67 -12
- package/dist/exchanges/lighter-public.js +250 -82
- package/dist/exchanges/lighter-signer.d.ts +1 -1
- package/dist/exchanges/lighter-signer.js +1 -1
- package/dist/exchanges/lighter-spot.d.ts +10 -5
- package/dist/exchanges/lighter-spot.js +105 -97
- package/dist/exchanges/lighter.d.ts +80 -21
- package/dist/exchanges/lighter.js +312 -105
- package/dist/exchanges/ondo/adapter.d.ts +38 -13
- package/dist/exchanges/ondo/adapter.js +86 -27
- package/dist/exchanges/ondo/agent.d.ts +1 -1
- package/dist/exchanges/ondo/agent.js +1 -1
- package/dist/exchanges/ondo/client.d.ts +1 -1
- package/dist/exchanges/ondo/client.js +2 -2
- package/dist/exchanges/ondo/public.d.ts +35 -3
- package/dist/exchanges/ondo/public.js +75 -32
- package/dist/exchanges/ondo/spot.d.ts +2 -2
- package/dist/exchanges/ondo/spot.js +3 -3
- package/dist/exchanges/options-interface.d.ts +158 -0
- package/dist/exchanges/options-interface.js +17 -0
- package/dist/exchanges/options-venues.d.ts +12 -0
- package/dist/exchanges/options-venues.js +35 -0
- package/dist/exchanges/outcome-interface.d.ts +4 -0
- package/dist/exchanges/pacifica-atomic.d.ts +211 -0
- package/dist/exchanges/pacifica-atomic.js +440 -0
- package/dist/exchanges/pacifica-decimal.d.ts +10 -0
- package/dist/exchanges/pacifica-decimal.js +51 -0
- package/dist/exchanges/pacifica-presigned.d.ts +53 -0
- package/dist/exchanges/pacifica-presigned.js +141 -0
- package/dist/exchanges/pacifica-print.d.ts +200 -0
- package/dist/exchanges/pacifica-print.js +417 -0
- package/dist/exchanges/pacifica-spot.d.ts +8 -2
- package/dist/exchanges/pacifica-spot.js +26 -18
- package/dist/exchanges/pacifica-typed-data.d.ts +1 -1
- package/dist/exchanges/pacifica-typed-data.js +1 -1
- package/dist/exchanges/pacifica-vaults.d.ts +130 -0
- package/dist/exchanges/pacifica-vaults.js +277 -0
- package/dist/exchanges/pacifica.d.ts +108 -10
- package/dist/exchanges/pacifica.js +428 -171
- package/dist/exchanges/precision.d.ts +3 -1
- package/dist/exchanges/precision.js +9 -2
- package/dist/exchanges/public-balances.d.ts +25 -0
- package/dist/exchanges/public-balances.js +158 -0
- package/dist/exchanges/public-positions.d.ts +43 -0
- package/dist/exchanges/public-positions.js +154 -0
- package/dist/exchanges/qfex/adapter.d.ts +69 -13
- package/dist/exchanges/qfex/adapter.js +102 -17
- package/dist/exchanges/qfex/agent.d.ts +1 -1
- package/dist/exchanges/qfex/agent.js +1 -1
- package/dist/exchanges/qfex/client.d.ts +1 -1
- package/dist/exchanges/qfex/client.js +1 -1
- package/dist/exchanges/qfex/errors.d.ts +1 -1
- package/dist/exchanges/qfex/errors.js +2 -2
- package/dist/exchanges/qfex/public.d.ts +65 -12
- package/dist/exchanges/qfex/public.js +131 -25
- package/dist/exchanges/qfex/signing.d.ts +2 -2
- package/dist/exchanges/qfex/signing.js +4 -5
- package/dist/exchanges/qfex/ws-transport.d.ts +3 -3
- package/dist/exchanges/qfex/ws-transport.js +3 -3
- package/dist/exchanges/rate-limiter.d.ts +1 -1
- package/dist/exchanges/rate-limiter.js +5 -2
- package/dist/exchanges/registry.d.ts +1 -1
- package/dist/exchanges/registry.js +1 -1
- package/dist/exchanges/risex/adapter.d.ts +160 -0
- package/dist/exchanges/risex/adapter.js +842 -0
- package/dist/exchanges/risex/agent.d.ts +154 -0
- package/dist/exchanges/risex/agent.js +384 -0
- package/dist/exchanges/risex/client.d.ts +47 -0
- package/dist/exchanges/risex/client.js +174 -0
- package/dist/exchanges/risex/nonce.d.ts +43 -0
- package/dist/exchanges/risex/nonce.js +212 -0
- package/dist/exchanges/risex/public.d.ts +64 -0
- package/dist/exchanges/risex/public.js +150 -0
- package/dist/exchanges/risex/session.d.ts +71 -0
- package/dist/exchanges/risex/session.js +171 -0
- package/dist/exchanges/risex/typed-data.d.ts +173 -0
- package/dist/exchanges/risex/typed-data.js +240 -0
- package/dist/exchanges/risex/units.d.ts +29 -0
- package/dist/exchanges/risex/units.js +104 -0
- package/dist/exchanges/slippage.d.ts +1 -1
- package/dist/exchanges/slippage.js +1 -1
- package/dist/exchanges/spot-factory.d.ts +3 -3
- package/dist/exchanges/spot-factory.js +8 -8
- package/dist/exchanges/spot-interface.d.ts +5 -5
- package/dist/exchanges/spot-interface.js +2 -2
- package/dist/exchanges/spot-result.d.ts +3 -3
- package/dist/exchanges/spot-result.js +3 -3
- package/dist/exchanges/trading-v2.d.ts +3 -3
- package/dist/exchanges/trading-v2.js +9 -6
- package/dist/exchanges/txflow/adapter.d.ts +61 -0
- package/dist/exchanges/txflow/adapter.js +150 -0
- package/dist/exchanges/txflow/client.d.ts +47 -0
- package/dist/exchanges/txflow/client.js +155 -0
- package/dist/exchanges/txflow/public.d.ts +87 -0
- package/dist/exchanges/txflow/public.js +355 -0
- package/dist/exchanges/unknown-symbol.d.ts +34 -0
- package/dist/exchanges/unknown-symbol.js +56 -0
- package/dist/exchanges/variational/adapter.d.ts +67 -0
- package/dist/exchanges/variational/adapter.js +137 -0
- package/dist/exchanges/variational/client.d.ts +21 -0
- package/dist/exchanges/variational/client.js +66 -0
- package/dist/exchanges/variational/public.d.ts +126 -0
- package/dist/exchanges/variational/public.js +430 -0
- package/dist/exchanges/venue-types.d.ts +52 -10
- package/dist/exchanges/venue-types.js +82 -11
- package/dist/exchanges/venue.d.ts +150 -11
- package/dist/exchanges/venue.js +126 -4
- package/dist/exchanges/venues/arcus.d.ts +1 -2
- package/dist/exchanges/venues/arcus.js +5 -4
- package/dist/exchanges/venues/aster.d.ts +2 -2
- package/dist/exchanges/venues/aster.js +6 -4
- package/dist/exchanges/venues/create-helpers.d.ts +1 -1
- package/dist/exchanges/venues/create-helpers.js +3 -3
- package/dist/exchanges/venues/extended.d.ts +21 -0
- package/dist/exchanges/venues/extended.js +96 -0
- package/dist/exchanges/venues/grvt.d.ts +30 -0
- package/dist/exchanges/venues/grvt.js +98 -0
- package/dist/exchanges/venues/hyperliquid.d.ts +2 -2
- package/dist/exchanges/venues/hyperliquid.js +19 -8
- package/dist/exchanges/venues/index.d.ts +7 -2
- package/dist/exchanges/venues/index.js +8 -2
- package/dist/exchanges/venues/lighter-family.d.ts +7 -9
- package/dist/exchanges/venues/lighter-family.js +9 -11
- package/dist/exchanges/venues/lighter-rh.d.ts +2 -2
- package/dist/exchanges/venues/lighter-rh.js +20 -8
- package/dist/exchanges/venues/lighter.d.ts +1 -1
- package/dist/exchanges/venues/lighter.js +18 -6
- package/dist/exchanges/venues/ondo.d.ts +1 -1
- package/dist/exchanges/venues/ondo.js +5 -3
- package/dist/exchanges/venues/pacifica.d.ts +2 -2
- package/dist/exchanges/venues/pacifica.js +15 -4
- package/dist/exchanges/venues/qfex.d.ts +1 -1
- package/dist/exchanges/venues/qfex.js +4 -2
- package/dist/exchanges/venues/risex-release.d.ts +14 -0
- package/dist/exchanges/venues/risex-release.js +14 -0
- package/dist/exchanges/venues/risex.d.ts +31 -0
- package/dist/exchanges/venues/risex.js +131 -0
- package/dist/exchanges/venues/txflow.d.ts +18 -0
- package/dist/exchanges/venues/txflow.js +77 -0
- package/dist/exchanges/venues/variational.d.ts +21 -0
- package/dist/exchanges/venues/variational.js +85 -0
- package/dist/execution-log.d.ts +1 -1
- package/dist/funding/legacy-public.d.ts +6 -4
- package/dist/funding/legacy-public.js +42 -41
- package/dist/funding/normalize.d.ts +1 -1
- package/dist/funding/normalize.js +1 -1
- package/dist/funding/rates.d.ts +95 -6
- package/dist/funding/rates.js +99 -19
- package/dist/index.js +7 -6
- package/dist/jobs.d.ts +1 -0
- package/dist/jobs.js +25 -1
- package/dist/landing.d.ts +2 -0
- package/dist/landing.js +1 -1
- package/dist/liquidity.d.ts +3 -1
- package/dist/liquidity.js +8 -4
- package/dist/mcp-pacifica-earn.d.ts +9 -0
- package/dist/mcp-pacifica-earn.js +64 -0
- package/dist/mcp-server.js +211 -68
- package/dist/pacifica/client.d.ts +69 -5
- package/dist/pacifica/client.js +181 -8
- package/dist/pacifica/rate-limit.d.ts +144 -0
- package/dist/pacifica/rate-limit.js +267 -0
- package/dist/pacifica/types/order.d.ts +2 -1
- package/dist/plan-executor.js +7 -2
- package/dist/positions-by-address.d.ts +34 -0
- package/dist/positions-by-address.js +46 -0
- package/dist/rebalance.js +1 -1
- package/dist/risk.d.ts +2 -1
- package/dist/risk.js +2 -4
- package/dist/settings.d.ts +32 -3
- package/dist/signer/ows-evm.d.ts +1 -1
- package/dist/signer/ows-evm.js +1 -1
- package/dist/smart-order.d.ts +1 -1
- package/dist/smart-order.js +1 -1
- package/dist/strategies/funding-arb.d.ts +1 -1
- package/dist/strategies/funding-arb.js +36 -63
- package/dist/trade-validator.js +2 -2
- package/dist/utils.d.ts +22 -3
- package/dist/utils.js +11 -3
- package/dist/venue-health.d.ts +40 -0
- package/dist/venue-health.js +75 -0
- package/dist/withdraw-gate.d.ts +1 -1
- package/dist/withdraw-gate.js +1 -1
- package/dist/ws/arcus-market.d.ts +9 -0
- package/dist/ws/arcus-market.js +9 -0
- package/dist/ws/aster-market.d.ts +33 -0
- package/dist/ws/aster-market.js +30 -0
- package/dist/ws/index.d.ts +980 -0
- package/dist/ws/index.js +4460 -0
- package/dist/ws/lighter-market.d.ts +14 -0
- package/dist/ws/lighter-market.js +13 -0
- package/dist/ws/node.d.ts +996 -0
- package/dist/ws/node.js +4554 -0
- package/dist/ws/pacifica-instrument.d.ts +8 -0
- package/dist/ws/pacifica-instrument.js +8 -0
- package/dist/ws/unclassified.d.ts +16 -0
- package/dist/ws/unclassified.js +43 -0
- package/dist/ws-cli/credentials.d.ts +62 -0
- package/dist/ws-cli/credentials.js +126 -0
- package/package.json +71 -10
- package/skills/perp-cli/SKILL.md +153 -36
- package/skills/perp-cli/package.json +15 -2
- package/skills/perp-cli/references/agent-operations.md +22 -12
- package/skills/perp-cli/references/commands.md +143 -17
- package/skills/perp-cli/references/strategies.md +38 -3
- package/skills/perp-cli/references/ws-library.md +523 -0
- package/skills/perp-cli/scripts/arb-monitor.sh +13 -10
- package/skills/perp-cli/scripts/funding-analysis.sh +57 -29
- package/skills/perp-cli/scripts/preflight.sh +27 -19
- package/skills/perp-cli/scripts/spot-perp-scan.sh +58 -38
- package/skills/perp-cli/scripts/validate-arb.sh +56 -39
- package/dist/cli-spec.d.ts +0 -46
- package/dist/cli-spec.js +0 -81
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { assertCanClosePositions } from "../exchanges/trading-v2.js";
|
|
2
2
|
import { MAX_PRICE_DEVIATION_PCT } from "../exchanges/index.js";
|
|
3
|
-
import { symbolMatch
|
|
3
|
+
import { symbolMatch } from "../utils.js";
|
|
4
4
|
import { logExecution } from "../execution-log.js";
|
|
5
5
|
import { updateJobState } from "../jobs.js";
|
|
6
6
|
import { invalidateCache } from "../cache.js";
|
|
7
7
|
import { fetchBalancesWithFailures, computeRebalancePlan, hasEnoughBalance, marketLeverageOf, requiredArbMargin } from "../rebalance.js";
|
|
8
8
|
import { checkArbLiquidity } from "../liquidity.js";
|
|
9
|
-
import { computeAnnualSpread } from "../funding.js";
|
|
10
|
-
import {
|
|
9
|
+
import { computeAnnualSpread, getFundingHours } from "../funding.js";
|
|
10
|
+
import { fetchVenuesRates } from "../funding/rates.js";
|
|
11
|
+
import { getVenue } from "../exchanges/venue.js";
|
|
12
|
+
import { sharedApiNetwork } from "../api/public/urls.js";
|
|
11
13
|
import { computeMatchedSize } from "../arb-sizing.js";
|
|
12
14
|
import { closePerpPairVerified, openPerpPairVerified } from "../commands/arb-auto.js";
|
|
13
15
|
import { closePerpVerified, isOutcomeUnknown } from "../bot/perp-order.js";
|
|
@@ -21,58 +23,21 @@ async function sizeDecimalsOf(adapter, symbol) {
|
|
|
21
23
|
return m === undefined ? null : m.sizeDecimals;
|
|
22
24
|
}
|
|
23
25
|
async function fetchAllRates() {
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
// stderr (explicit
|
|
27
|
-
const [
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const [details, funding] = await Promise.all([
|
|
36
|
-
fetchLighterOrderBookDetails(),
|
|
37
|
-
fetchLighterFundingRates(),
|
|
38
|
-
]);
|
|
39
|
-
const priceMap = new Map(details.map(d => [d.marketId, d.lastTradePrice]));
|
|
40
|
-
const symMap = new Map(details.map(d => [d.marketId, d.symbol]));
|
|
41
|
-
const out = [];
|
|
42
|
-
for (const fr of funding) {
|
|
43
|
-
const symbol = fr.symbol || symMap.get(fr.marketId) || "";
|
|
44
|
-
if (!symbol)
|
|
45
|
-
continue;
|
|
46
|
-
// Prefer fr.markPrice; fall back to orderBook last-trade as documented
|
|
47
|
-
// price source preference (NOT an error fallback).
|
|
48
|
-
const directMark = fr.markPrice;
|
|
49
|
-
const fallbackMark = priceMap.get(fr.marketId);
|
|
50
|
-
let markPrice;
|
|
51
|
-
if (directMark !== null && Number.isFinite(directMark) && directMark > 0) {
|
|
52
|
-
markPrice = directMark;
|
|
53
|
-
}
|
|
54
|
-
else if (fallbackMark !== undefined && Number.isFinite(fallbackMark) && fallbackMark > 0) {
|
|
55
|
-
markPrice = fallbackMark;
|
|
56
|
-
}
|
|
57
|
-
// SSOT rule #2: skip rows whose mark price cannot be resolved at all
|
|
58
|
-
// — never publish a 0 mark price downstream.
|
|
59
|
-
if (markPrice === undefined)
|
|
60
|
-
continue;
|
|
61
|
-
out.push({ exchange: "lighter", symbol, fundingRate: fr.rate, markPrice });
|
|
62
|
-
}
|
|
63
|
-
return out;
|
|
64
|
-
})(),
|
|
65
|
-
]);
|
|
66
|
-
logSettledRejections([pacRates, hlRates, ltRates], ["pacifica", "hyperliquid", "lighter"], "funding-arb");
|
|
67
|
-
return [
|
|
68
|
-
...(pacRates.status === "fulfilled" ? pacRates.value : []),
|
|
69
|
-
...(hlRates.status === "fulfilled" ? hlRates.value : []),
|
|
70
|
-
...(ltRates.status === "fulfilled" ? ltRates.value : []),
|
|
71
|
-
];
|
|
26
|
+
// The SAME rate rows as `arb scan --rates` (fetchVenuesRates): one per venue and canonical
|
|
27
|
+
// symbol (unclassified / ambiguous tickers have no canonical and never pair). Each venue is
|
|
28
|
+
// independent; a failed one is reported on stderr (explicit, never silent).
|
|
29
|
+
const venues = ["pacifica", "hyperliquid", "lighter"].map(id => getVenue(id));
|
|
30
|
+
const { rates: fetched, exchangeErrors } = await fetchVenuesRates(venues, sharedApiNetwork(), false);
|
|
31
|
+
// Never a leg on an unverified rate (row label; the venue filter already drops them).
|
|
32
|
+
const rates = fetched.filter(r => r.fundingVerified);
|
|
33
|
+
for (const [ex, msg] of Object.entries(exchangeErrors))
|
|
34
|
+
process.stderr.write(`[funding-arb] ${ex}: funding rates unavailable — ${msg}\n`);
|
|
35
|
+
// computeAnnualSpread / toHourlyRate normalize with the venue's basis: keep each rate in it.
|
|
36
|
+
return rates.map(r => ({ exchange: r.exchange, symbol: r.canonical, venueSymbol: r.symbol, fundingRate: r.hourlyRate * getFundingHours(r.exchange), markPrice: r.markPrice }));
|
|
72
37
|
}
|
|
73
38
|
// annualize: use computeAnnualSpread from funding.ts for cross-exchange comparison
|
|
74
39
|
/**
|
|
75
|
-
* `perp strategy funding-arb` loop. With autoExecute
|
|
40
|
+
* `perp strategy funding-arb` loop. With autoExecute:
|
|
76
41
|
* - entry = openPerpPairVerified (long, then the short sized to the long's VERIFIED fill;
|
|
77
42
|
* definite short failure → reduce-only rollback; unknown outcome → quarantine). A lot-size
|
|
78
43
|
* rejection is never resubmitted blindly: the long is re-sized only when it was definitely
|
|
@@ -111,8 +76,12 @@ export async function runFundingArb(adapters, params, jobId, log = console.log)
|
|
|
111
76
|
const rates = await fetchAllRates();
|
|
112
77
|
// Group by symbol
|
|
113
78
|
const rateMap = new Map();
|
|
79
|
+
// --symbols selects an asset by its canonical key or any venue's own symbol (kPEPE selects
|
|
80
|
+
// the whole 1000PEPE group, Lighter's leg included).
|
|
81
|
+
const want = new Set((params.symbols ?? []).map(s => s.toUpperCase()));
|
|
82
|
+
const wanted = new Set(rates.filter(r => want.has(r.symbol.toUpperCase()) || want.has(r.venueSymbol.toUpperCase())).map(r => r.symbol));
|
|
114
83
|
for (const r of rates) {
|
|
115
|
-
if (
|
|
84
|
+
if (want.size > 0 && !wanted.has(r.symbol))
|
|
116
85
|
continue;
|
|
117
86
|
if (!rateMap.has(r.symbol))
|
|
118
87
|
rateMap.set(r.symbol, []);
|
|
@@ -233,6 +202,8 @@ export async function runFundingArb(adapters, params, jobId, log = console.log)
|
|
|
233
202
|
if (annualSpread >= params.minSpread) {
|
|
234
203
|
const longEx = lowest.exchange;
|
|
235
204
|
const shortEx = highest.exchange;
|
|
205
|
+
const longSym = lowest.venueSymbol;
|
|
206
|
+
const shortSym = highest.venueSymbol;
|
|
236
207
|
log(`[ARB] ENTRY signal: ${symbol} spread ${annualSpread.toFixed(1)}% — long ${longEx} (${(lowest.fundingRate * 100).toFixed(4)}%) / short ${shortEx} (${(highest.fundingRate * 100).toFixed(4)}%)`);
|
|
237
208
|
if (params.autoExecute) {
|
|
238
209
|
const longAdapter = adapters.get(longEx);
|
|
@@ -243,7 +214,7 @@ export async function runFundingArb(adapters, params, jobId, log = console.log)
|
|
|
243
214
|
}
|
|
244
215
|
// Check orderbook liquidity & adjust size
|
|
245
216
|
const requestedUsd = params.sizeUsd ?? Number(params.size) * highest.markPrice;
|
|
246
|
-
const liq = await checkArbLiquidity(longAdapter, shortAdapter,
|
|
217
|
+
const liq = await checkArbLiquidity(longAdapter, shortAdapter, longSym, requestedUsd, 0.5, log, shortSym);
|
|
247
218
|
if (!liq.viable)
|
|
248
219
|
continue;
|
|
249
220
|
// Compute matched size (same for both legs) at each venue's published size precision —
|
|
@@ -251,7 +222,7 @@ export async function runFundingArb(adapters, params, jobId, log = console.log)
|
|
|
251
222
|
let longDec;
|
|
252
223
|
let shortDec;
|
|
253
224
|
try {
|
|
254
|
-
[longDec, shortDec] = await Promise.all([sizeDecimalsOf(longAdapter,
|
|
225
|
+
[longDec, shortDec] = await Promise.all([sizeDecimalsOf(longAdapter, longSym), sizeDecimalsOf(shortAdapter, shortSym)]);
|
|
255
226
|
}
|
|
256
227
|
catch (e) {
|
|
257
228
|
log(`[ARB] Skip ${symbol}: could not read the market size precision (${e instanceof Error ? e.message : String(e)})`);
|
|
@@ -272,7 +243,7 @@ export async function runFundingArb(adapters, params, jobId, log = console.log)
|
|
|
272
243
|
let longLev;
|
|
273
244
|
let shortLev;
|
|
274
245
|
try {
|
|
275
|
-
[longLev, shortLev] = await Promise.all([marketLeverageOf(longAdapter,
|
|
246
|
+
[longLev, shortLev] = await Promise.all([marketLeverageOf(longAdapter, longSym), marketLeverageOf(shortAdapter, shortSym)]);
|
|
276
247
|
}
|
|
277
248
|
catch (e) {
|
|
278
249
|
log(`[ARB] Skip ${symbol}: could not read the market leverage (${e instanceof Error ? e.message : String(e)})`);
|
|
@@ -288,8 +259,8 @@ export async function runFundingArb(adapters, params, jobId, log = console.log)
|
|
|
288
259
|
log(`[ARB] Opening: ${matched.size} ${symbol} — long ${longEx} then short ${shortEx}, each verified ($${matched.notional.toFixed(0)}/leg, slippage ~${liq.longSlippage.toFixed(2)}%/${liq.shortSlippage.toFixed(2)}%)...`);
|
|
289
260
|
const openPair = (size) => openPerpPairVerified({
|
|
290
261
|
source: SOURCE, sym: symbol,
|
|
291
|
-
longAdapter, longExch: longEx, longSym
|
|
292
|
-
shortAdapter, shortExch: shortEx, shortSym
|
|
262
|
+
longAdapter, longExch: longEx, longSym,
|
|
263
|
+
shortAdapter, shortExch: shortEx, shortSym,
|
|
293
264
|
size, smart: false, log, shortLotRetry: true,
|
|
294
265
|
});
|
|
295
266
|
let res = await openPair(matched.size);
|
|
@@ -323,6 +294,8 @@ export async function runFundingArb(adapters, params, jobId, log = console.log)
|
|
|
323
294
|
entrySpread: annualSpread,
|
|
324
295
|
openedAt: Date.now(),
|
|
325
296
|
entryPrices: { long: lowest.markPrice, short: highest.markPrice },
|
|
297
|
+
longSymbol: longSym,
|
|
298
|
+
shortSymbol: shortSym,
|
|
326
299
|
});
|
|
327
300
|
// Entry record: `arb status` / `arb close` confirm this pair from it (arbPairProvenance).
|
|
328
301
|
logExecution({
|
|
@@ -403,8 +376,8 @@ async function closeArbPosition(pos, adapters, log) {
|
|
|
403
376
|
let shortSize;
|
|
404
377
|
try {
|
|
405
378
|
[longSize, shortSize] = await Promise.all([
|
|
406
|
-
venueLegSize(longAdapter, pos.
|
|
407
|
-
venueLegSize(shortAdapter, pos.
|
|
379
|
+
venueLegSize(longAdapter, pos.longSymbol, "long").then(cap),
|
|
380
|
+
venueLegSize(shortAdapter, pos.shortSymbol, "short").then(cap),
|
|
408
381
|
]);
|
|
409
382
|
}
|
|
410
383
|
catch (err) {
|
|
@@ -418,8 +391,8 @@ async function closeArbPosition(pos, adapters, log) {
|
|
|
418
391
|
if (longSize !== null && shortSize !== null) {
|
|
419
392
|
const res = await closePerpPairVerified({
|
|
420
393
|
source: SOURCE, sym: pos.symbol,
|
|
421
|
-
longAdapter, longExch: pos.longExchange, longSym: pos.
|
|
422
|
-
shortAdapter, shortExch: pos.shortExchange, shortSym: pos.
|
|
394
|
+
longAdapter, longExch: pos.longExchange, longSym: pos.longSymbol, longSize,
|
|
395
|
+
shortAdapter, shortExch: pos.shortExchange, shortSym: pos.shortSymbol, shortSize,
|
|
423
396
|
smart: false, log,
|
|
424
397
|
});
|
|
425
398
|
if (res.status === "closed") {
|
|
@@ -448,7 +421,7 @@ async function closeArbPosition(pos, adapters, log) {
|
|
|
448
421
|
return false;
|
|
449
422
|
};
|
|
450
423
|
try {
|
|
451
|
-
const c = await closePerpVerified(adapter, venue, pos.
|
|
424
|
+
const c = await closePerpVerified(adapter, venue, leg === "long" ? pos.longSymbol : pos.shortSymbol, side, size);
|
|
452
425
|
if (c.residual > 0)
|
|
453
426
|
return q(`orphaned ${leg} close on ${venue} closed ${c.closed} of ${size}, ${c.residual} still open${c.note !== null ? ` (${c.note})` : ""}`);
|
|
454
427
|
}
|
package/dist/trade-validator.js
CHANGED
|
@@ -12,7 +12,7 @@ export async function validateTrade(adapter, params) {
|
|
|
12
12
|
const checks = [];
|
|
13
13
|
const warnings = [];
|
|
14
14
|
const sym = params.symbol.toUpperCase();
|
|
15
|
-
// Liquidity threshold = the bound a market order on this venue would carry
|
|
15
|
+
// Liquidity threshold = the bound a market order on this venue would carry.
|
|
16
16
|
const maxSlippage = resolveAdapterSlippage(adapter, null).bps / 10_000;
|
|
17
17
|
// Fetch market list, balance, and positions in parallel.
|
|
18
18
|
// Defer the orderbook call until symbol membership is confirmed so invalid
|
|
@@ -264,7 +264,7 @@ export async function enforceOrderRisk(adapter, p) {
|
|
|
264
264
|
const markets = await adapter.getMarkets();
|
|
265
265
|
const m = markets.find((mk) => symbolMatch(mk.symbol, p.symbol));
|
|
266
266
|
if (!m) {
|
|
267
|
-
throw new PerpError("SYMBOL_NOT_FOUND", `${p.symbol} not found on ${adapter.name}`, { exchange: adapter.name });
|
|
267
|
+
throw new PerpError("SYMBOL_NOT_FOUND", `${p.symbol} not found on ${adapter.name}`, { exchange: adapter.name, remediation: `List markets: perp -e ${adapter.name} market list` });
|
|
268
268
|
}
|
|
269
269
|
price = Number(m.markPrice);
|
|
270
270
|
}
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { OrderResult } from "./exchanges/venue-types.js";
|
|
2
2
|
export declare function symbolMatch(candidate: string, target: string): boolean;
|
|
3
3
|
export declare function formatUsd(value: string | number): string;
|
|
4
|
+
/**
|
|
5
|
+
* Symbol argument as typed, normalized for display and lookup: upper case, except a HIP-3 dex
|
|
6
|
+
* prefix, which is lower case on the venue ("xyz:xyz100" / "XYZ:XYZ100" → "xyz:XYZ100").
|
|
7
|
+
*/
|
|
8
|
+
export declare function normalizeSymbolArg(symbol: string): string;
|
|
4
9
|
export declare function formatPnl(value: string | number): string;
|
|
5
10
|
export declare function formatPercent(value: string | number): string;
|
|
6
11
|
export declare function makeTable(head: string[], rows: string[][]): string;
|
|
@@ -26,6 +31,20 @@ export interface ApiResponse<T = unknown> {
|
|
|
26
31
|
exchange?: string;
|
|
27
32
|
timestamp: string;
|
|
28
33
|
duration_ms?: number;
|
|
34
|
+
skippedRows?: {
|
|
35
|
+
count: number;
|
|
36
|
+
reason: string;
|
|
37
|
+
}; /** Why a value is null / degraded (e.g. a venue's funding rate unavailable). */
|
|
38
|
+
warnings?: string[]; /** `arb scan --rates`: the --min threshold (annualized %) and how many pairs it hid. */
|
|
39
|
+
minSpread?: number;
|
|
40
|
+
belowMinSpread?: number; /** Public-address reads (`account positions --address`): the address read, "public", the sub-reads that failed and notes on an empty answer. */
|
|
41
|
+
address?: string;
|
|
42
|
+
source?: "public";
|
|
43
|
+
errors?: Record<string, {
|
|
44
|
+
code: string;
|
|
45
|
+
message: string;
|
|
46
|
+
}>;
|
|
47
|
+
notes?: string[];
|
|
29
48
|
};
|
|
30
49
|
}
|
|
31
50
|
/** Wrap successful result in standard envelope */
|
|
@@ -50,18 +69,18 @@ export declare function withJsonErrors<T>(isJson: boolean, fn: () => Promise<T>,
|
|
|
50
69
|
/**
|
|
51
70
|
* Central CLI error printer. JSON: the structured envelope incl. details and
|
|
52
71
|
* remediation. Human: the uniform "not supported" line for CAPABILITY_UNSUPPORTED
|
|
53
|
-
*
|
|
72
|
+
* — `✗ <Venue>: <feature> not supported — <reason>. Alternative: <remediation>` —
|
|
54
73
|
* otherwise `Error: <message>` plus the remediation.
|
|
55
74
|
*/
|
|
56
75
|
export declare function printCliError(err: unknown, isJson: boolean, exchange?: string): void;
|
|
57
76
|
/**
|
|
58
|
-
* JSON payload of an order result
|
|
77
|
+
* JSON payload of an order result: the uniform OrderResult (+ execution)
|
|
59
78
|
* with the venue's raw response duplicated under `legacy` for one release.
|
|
60
79
|
*/
|
|
61
80
|
export declare function orderResultJson(r: OrderResult & {
|
|
62
81
|
remediation?: string | null;
|
|
63
82
|
}, extra?: Record<string, unknown>): Record<string, unknown>;
|
|
64
|
-
/** Human lines for an order result — one format for every venue
|
|
83
|
+
/** Human lines for an order result — one format for every venue. */
|
|
65
84
|
export declare function formatOrderResult(r: OrderResult & {
|
|
66
85
|
remediation?: string | null;
|
|
67
86
|
}): string[];
|
package/dist/utils.js
CHANGED
|
@@ -30,6 +30,14 @@ export function formatUsd(value) {
|
|
|
30
30
|
maximumFractionDigits: maxDecimals,
|
|
31
31
|
});
|
|
32
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Symbol argument as typed, normalized for display and lookup: upper case, except a HIP-3 dex
|
|
35
|
+
* prefix, which is lower case on the venue ("xyz:xyz100" / "XYZ:XYZ100" → "xyz:XYZ100").
|
|
36
|
+
*/
|
|
37
|
+
export function normalizeSymbolArg(symbol) {
|
|
38
|
+
const i = symbol.indexOf(":");
|
|
39
|
+
return i === -1 ? symbol.toUpperCase() : `${symbol.slice(0, i).toLowerCase()}:${symbol.slice(i + 1).toUpperCase()}`;
|
|
40
|
+
}
|
|
33
41
|
export function formatPnl(value) {
|
|
34
42
|
const num = Number(value);
|
|
35
43
|
if (isNaN(num))
|
|
@@ -235,7 +243,7 @@ export async function withJsonErrors(isJson, fn, exchange) {
|
|
|
235
243
|
/**
|
|
236
244
|
* Central CLI error printer. JSON: the structured envelope incl. details and
|
|
237
245
|
* remediation. Human: the uniform "not supported" line for CAPABILITY_UNSUPPORTED
|
|
238
|
-
*
|
|
246
|
+
* — `✗ <Venue>: <feature> not supported — <reason>. Alternative: <remediation>` —
|
|
239
247
|
* otherwise `Error: <message>` plus the remediation.
|
|
240
248
|
*/
|
|
241
249
|
export function printCliError(err, isJson, exchange) {
|
|
@@ -262,13 +270,13 @@ export function printCliError(err, isJson, exchange) {
|
|
|
262
270
|
}
|
|
263
271
|
}
|
|
264
272
|
/**
|
|
265
|
-
* JSON payload of an order result
|
|
273
|
+
* JSON payload of an order result: the uniform OrderResult (+ execution)
|
|
266
274
|
* with the venue's raw response duplicated under `legacy` for one release.
|
|
267
275
|
*/
|
|
268
276
|
export function orderResultJson(r, extra) {
|
|
269
277
|
return { ...r, ...extra, legacy: r.venueRaw };
|
|
270
278
|
}
|
|
271
|
-
/** Human lines for an order result — one format for every venue
|
|
279
|
+
/** Human lines for an order result — one format for every venue. */
|
|
272
280
|
export function formatOrderResult(r) {
|
|
273
281
|
const lines = [];
|
|
274
282
|
const statusColor = r.status === "filled" ? chalk.green
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Venue connectivity probe — the one implementation behind `perp health`,
|
|
3
|
+
* `perp portfolio --health` and the MCP `health_check` tool.
|
|
4
|
+
*
|
|
5
|
+
* Pacifica / Hyperliquid / Lighter / Aster / QFEX / GRVT: a REST ping (status = HTTP status, 0 = no
|
|
6
|
+
* response). Every other venue — including read-only (market-data-only) venues such as TxFlow —
|
|
7
|
+
* is probed with its public market-data read (status null). A venue with no environment on the
|
|
8
|
+
* selected network (TxFlow has no testnet) is not probed and is listed in `skipped`.
|
|
9
|
+
*
|
|
10
|
+
* The ping helpers (shared-api) read the shared API URLs, which follow the network the caller
|
|
11
|
+
* selected (setSharedApiNetwork); Aster / QFEX / market-data probes take `network` directly.
|
|
12
|
+
*/
|
|
13
|
+
import type { Network, VenueId } from "./exchanges/venue-types.js";
|
|
14
|
+
import "./exchanges/venues/index.js";
|
|
15
|
+
export interface VenueProbe {
|
|
16
|
+
venue: VenueId;
|
|
17
|
+
ok: boolean;
|
|
18
|
+
latencyMs: number;
|
|
19
|
+
/** HTTP status of a REST ping (0 = no response); null for a market-data probe. */
|
|
20
|
+
status: number | null;
|
|
21
|
+
/** null when ok. */
|
|
22
|
+
error: string | null;
|
|
23
|
+
probe: "ping" | "markets";
|
|
24
|
+
/** "unofficial" = the venue is read through an undocumented API (VenueDefinition.apiStatus). */
|
|
25
|
+
apiStatus: "official" | "unofficial";
|
|
26
|
+
}
|
|
27
|
+
export interface VenueHealth {
|
|
28
|
+
probes: VenueProbe[];
|
|
29
|
+
/** Venues requested but not probed: no environment on `network`. */
|
|
30
|
+
skipped: Array<{
|
|
31
|
+
venue: VenueId;
|
|
32
|
+
reason: string;
|
|
33
|
+
}>;
|
|
34
|
+
allHealthy: boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Probe `venueIds` (default: every registered venue) on `network`, in parallel. Never throws for a
|
|
38
|
+
* venue failure — each failure is a probe with ok:false and its message.
|
|
39
|
+
*/
|
|
40
|
+
export declare function probeVenueHealth(network: Network, venueIds?: readonly string[]): Promise<VenueHealth>;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Venue connectivity probe — the one implementation behind `perp health`,
|
|
3
|
+
* `perp portfolio --health` and the MCP `health_check` tool.
|
|
4
|
+
*
|
|
5
|
+
* Pacifica / Hyperliquid / Lighter / Aster / QFEX / GRVT: a REST ping (status = HTTP status, 0 = no
|
|
6
|
+
* response). Every other venue — including read-only (market-data-only) venues such as TxFlow —
|
|
7
|
+
* is probed with its public market-data read (status null). A venue with no environment on the
|
|
8
|
+
* selected network (TxFlow has no testnet) is not probed and is listed in `skipped`.
|
|
9
|
+
*
|
|
10
|
+
* The ping helpers (shared-api) read the shared API URLs, which follow the network the caller
|
|
11
|
+
* selected (setSharedApiNetwork); Aster / QFEX / market-data probes take `network` directly.
|
|
12
|
+
*/
|
|
13
|
+
import { extractErrorMessage } from "./errors.js";
|
|
14
|
+
import { getVenue, listVenues, networkConfig } from "./exchanges/venue.js";
|
|
15
|
+
import { pingHyperliquid, pingLighter, pingPacifica } from "./shared-api.js";
|
|
16
|
+
import "./exchanges/venues/index.js";
|
|
17
|
+
async function timed(probe, fn) {
|
|
18
|
+
const start = Date.now();
|
|
19
|
+
try {
|
|
20
|
+
const r = await fn();
|
|
21
|
+
return { ok: r.ok, latencyMs: Date.now() - start, status: r.status, error: r.ok ? null : `HTTP ${r.status}`, probe };
|
|
22
|
+
}
|
|
23
|
+
catch (e) {
|
|
24
|
+
return { ok: false, latencyMs: Date.now() - start, status: probe === "ping" ? 0 : null, error: extractErrorMessage(e), probe };
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const restPing = (url) => timed("ping", async () => {
|
|
28
|
+
const res = await fetch(url);
|
|
29
|
+
return { ok: res.ok, status: res.status };
|
|
30
|
+
});
|
|
31
|
+
/** shared-api helpers report a transport failure as status 0 with no message. */
|
|
32
|
+
const helperPing = (fn) => async () => {
|
|
33
|
+
const r = await fn();
|
|
34
|
+
return { ...r, error: r.ok ? null : r.status === 0 ? "no response" : `HTTP ${r.status}`, probe: "ping" };
|
|
35
|
+
};
|
|
36
|
+
function pingFor(id, network) {
|
|
37
|
+
switch (id) {
|
|
38
|
+
case "pacifica": return helperPing(pingPacifica);
|
|
39
|
+
case "hyperliquid": return helperPing(pingHyperliquid);
|
|
40
|
+
case "lighter": return helperPing(pingLighter);
|
|
41
|
+
case "aster": return () => restPing(`${networkConfig(getVenue("aster"), network).restUrl}/fapi/v1/time`);
|
|
42
|
+
// QFEX: public GET /refdata for one instrument.
|
|
43
|
+
case "qfex": return () => restPing(`${networkConfig(getVenue("qfex"), network).restUrl}/refdata?ticker=AAPL-USD`);
|
|
44
|
+
// GRVT: one public instrument read (the market-data probe would fan out over every ticker).
|
|
45
|
+
case "grvt": return () => timed("ping", async () => {
|
|
46
|
+
const res = await fetch(`${networkConfig(getVenue("grvt"), network).restUrl}/full/v1/instrument`, {
|
|
47
|
+
method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ instrument: "BTC_USDT_Perp" }),
|
|
48
|
+
});
|
|
49
|
+
return { ok: res.ok, status: res.status };
|
|
50
|
+
});
|
|
51
|
+
default: return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Probe `venueIds` (default: every registered venue) on `network`, in parallel. Never throws for a
|
|
56
|
+
* venue failure — each failure is a probe with ok:false and its message.
|
|
57
|
+
*/
|
|
58
|
+
export async function probeVenueHealth(network, venueIds) {
|
|
59
|
+
const defs = venueIds === undefined ? listVenues() : venueIds.map(id => getVenue(id));
|
|
60
|
+
const skipped = [];
|
|
61
|
+
const probed = defs.filter(v => {
|
|
62
|
+
if (v.networks[network] !== null)
|
|
63
|
+
return true;
|
|
64
|
+
skipped.push({ venue: v.id, reason: `${v.displayName} has no ${network} environment` });
|
|
65
|
+
return false;
|
|
66
|
+
});
|
|
67
|
+
const results = await Promise.all(probed.map(v => {
|
|
68
|
+
const ping = pingFor(v.id, network);
|
|
69
|
+
return ping !== null
|
|
70
|
+
? ping()
|
|
71
|
+
: timed("markets", async () => { await v.publicData.fetchMarkets(network, { funding: false }); return { ok: true, status: null }; });
|
|
72
|
+
}));
|
|
73
|
+
const probes = probed.map((v, i) => ({ venue: v.id, ...results[i], apiStatus: v.apiStatus.kind }));
|
|
74
|
+
return { probes, skipped, allHealthy: probes.every(p => p.ok) };
|
|
75
|
+
}
|
package/dist/withdraw-gate.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Withdraw gate for venues whose withdrawals are authorized by an API key alone — no owner
|
|
3
|
-
* signature (settings.withdraw.<venue>; today: qfex)
|
|
3
|
+
* signature (settings.withdraw.<venue>; today: qfex)..
|
|
4
4
|
*
|
|
5
5
|
* Before such a withdrawal is sent it must pass, locally:
|
|
6
6
|
* 1. a gate is configured at all (absent → refused);
|
package/dist/withdraw-gate.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Withdraw gate for venues whose withdrawals are authorized by an API key alone — no owner
|
|
3
|
-
* signature (settings.withdraw.<venue>; today: qfex)
|
|
3
|
+
* signature (settings.withdraw.<venue>; today: qfex)..
|
|
4
4
|
*
|
|
5
5
|
* Before such a withdrawal is sent it must pass, locally:
|
|
6
6
|
* 1. a gate is configured at all (absent → refused);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Arcus GET /v1/markets eligibility — the one rule for every Arcus surface (WS directory, CLI
|
|
3
|
+
* adapter market-data reads, public market data / funding / arb, MCP): a market is listed only
|
|
4
|
+
* while `status` is "ONLINE". OFFLINE markets (live 2026-10-19: F, BAC, CCL, VT, SGOV, RVI-USD —
|
|
5
|
+
* 6 of 70) publish placeholder zeros for mark / index / rate / OI / volume, never real values.
|
|
6
|
+
*/
|
|
7
|
+
export declare function isArcusOnlineMarket(row: {
|
|
8
|
+
status?: unknown;
|
|
9
|
+
}): boolean;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Arcus GET /v1/markets eligibility — the one rule for every Arcus surface (WS directory, CLI
|
|
3
|
+
* adapter market-data reads, public market data / funding / arb, MCP): a market is listed only
|
|
4
|
+
* while `status` is "ONLINE". OFFLINE markets (live 2026-10-19: F, BAC, CCL, VT, SGOV, RVI-USD —
|
|
5
|
+
* 6 of 70) publish placeholder zeros for mark / index / rate / OI / volume, never real values.
|
|
6
|
+
*/
|
|
7
|
+
export function isArcusOnlineMarket(row) {
|
|
8
|
+
return row.status === "ONLINE";
|
|
9
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aster GET /fapi/v3/exchangeInfo market eligibility — the one rule for every Aster surface (WS
|
|
3
|
+
* directory, CLI adapter, public market data / funding / arb, MCP): a market is listed only while
|
|
4
|
+
* `contractType` is "PERPETUAL" and `status` is "TRADING". Live 2026-10-19: TRADING/PERPETUAL 605,
|
|
5
|
+
* SETTLING/PERPETUAL 23 (being delisted: TONUSDT, IRUSDT, …), PENDING_TRADING with contractType ""
|
|
6
|
+
* 6 (MBLUSDT, AFEEUSDT, …) — neither of the latter two streams or trades.
|
|
7
|
+
*
|
|
8
|
+
* The quote asset is NOT part of eligibility: USD1 / U quoted perps are live markets, listed by
|
|
9
|
+
* every surface (asterCliSymbol gives the CLI symbol, asterMatchable whether it gets a canonical).
|
|
10
|
+
*/
|
|
11
|
+
export declare function isAsterListedPerpetual(row: {
|
|
12
|
+
contractType?: unknown;
|
|
13
|
+
status?: unknown;
|
|
14
|
+
}): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* CLI symbol of a listed Aster perpetual: the base for the USDT-quoted market (ETHUSDT → ETH, the
|
|
17
|
+
* venue's main listing), the venue symbol for any other quote (BTCUSD1, BTCU) — unique per market
|
|
18
|
+
* and passed to the venue as is.
|
|
19
|
+
*/
|
|
20
|
+
export declare function asterCliSymbol(row: {
|
|
21
|
+
symbol: string;
|
|
22
|
+
baseAsset: string;
|
|
23
|
+
quoteAsset?: unknown;
|
|
24
|
+
}): string;
|
|
25
|
+
/**
|
|
26
|
+
* Whether a listed Aster market may carry a cross-venue canonical (then `base`): only its USDT
|
|
27
|
+
* market. USD1 / U quoted ones (BTCUSD1, GPROUSD1, BTCU) are listed but never matched across
|
|
28
|
+
* venues — so `arb` (scan / auto / exec) never takes one as a leg: Aster arb sizing, margin checks
|
|
29
|
+
* and transfers are USDT-collateral, and a USD1 / U margined leg is not handled.
|
|
30
|
+
*/
|
|
31
|
+
export declare function asterMatchable(row: {
|
|
32
|
+
quoteAsset?: unknown;
|
|
33
|
+
}): boolean;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aster GET /fapi/v3/exchangeInfo market eligibility — the one rule for every Aster surface (WS
|
|
3
|
+
* directory, CLI adapter, public market data / funding / arb, MCP): a market is listed only while
|
|
4
|
+
* `contractType` is "PERPETUAL" and `status` is "TRADING". Live 2026-10-19: TRADING/PERPETUAL 605,
|
|
5
|
+
* SETTLING/PERPETUAL 23 (being delisted: TONUSDT, IRUSDT, …), PENDING_TRADING with contractType ""
|
|
6
|
+
* 6 (MBLUSDT, AFEEUSDT, …) — neither of the latter two streams or trades.
|
|
7
|
+
*
|
|
8
|
+
* The quote asset is NOT part of eligibility: USD1 / U quoted perps are live markets, listed by
|
|
9
|
+
* every surface (asterCliSymbol gives the CLI symbol, asterMatchable whether it gets a canonical).
|
|
10
|
+
*/
|
|
11
|
+
export function isAsterListedPerpetual(row) {
|
|
12
|
+
return row.contractType === "PERPETUAL" && row.status === "TRADING";
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* CLI symbol of a listed Aster perpetual: the base for the USDT-quoted market (ETHUSDT → ETH, the
|
|
16
|
+
* venue's main listing), the venue symbol for any other quote (BTCUSD1, BTCU) — unique per market
|
|
17
|
+
* and passed to the venue as is.
|
|
18
|
+
*/
|
|
19
|
+
export function asterCliSymbol(row) {
|
|
20
|
+
return row.quoteAsset === "USDT" ? row.baseAsset : row.symbol;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Whether a listed Aster market may carry a cross-venue canonical (then `base`): only its USDT
|
|
24
|
+
* market. USD1 / U quoted ones (BTCUSD1, GPROUSD1, BTCU) are listed but never matched across
|
|
25
|
+
* venues — so `arb` (scan / auto / exec) never takes one as a leg: Aster arb sizing, margin checks
|
|
26
|
+
* and transfers are USDT-collateral, and a USD1 / U margined leg is not handled.
|
|
27
|
+
*/
|
|
28
|
+
export function asterMatchable(row) {
|
|
29
|
+
return row.quoteAsset === "USDT";
|
|
30
|
+
}
|