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,6 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* QFEX adapter — native TradingV2 + legacy ExchangeAdapter shim
|
|
3
|
-
* (design §14.3–§14.6 as amended by §14.12; §10.7, §10.10, §13).
|
|
4
3
|
*
|
|
5
4
|
* Signer: imported HMAC API key only (QfexAgentMeta → ~/.perp/qfex-agents/<publicKey>.json).
|
|
6
5
|
* Orders go over the Trade WebSocket (ws-transport.ts); account reads, leverage and transfers
|
|
@@ -51,7 +50,7 @@ import { QFEX_BANKER_NETWORK, QFEX_ENDPOINTS, QFEX_WITHDRAW_DISABLED, QFEX_WITHD
|
|
|
51
50
|
import { loadQfexCredentials, QFEX_IMPORT_REMEDIATION } from "./agent.js";
|
|
52
51
|
import { QfexClient } from "./client.js";
|
|
53
52
|
import { qfexStatusClass } from "./errors.js";
|
|
54
|
-
import { fetchQfexInstruments, qfexPlainSymbol, qfexPublicData, qfexTradable, qfexVenueSymbol, } from "./public.js";
|
|
53
|
+
import { buildQfexFundingRates, buildQfexMarkets, fetchQfexInstruments, fetchQfexMarketsWithInstruments, qfexFundingWindowClosed, qfexIndexPrices, qfexListedStatus, qfexPlainSymbol, qfexPublicData, qfexTradable, qfexVenueSymbol, } from "./public.js";
|
|
55
54
|
import { QFEX_AUTOMATION_VERIFIED, QFEX_MODIFY_KEEPS_CLIENT_ID, QFEX_REDUCE_ONLY_WIRE, QFEX_STOP_CLIENT_ID_ECHO, decimalsEqual, fromWireNumber, isZeroDecimal, qfexAutomationGate, qfexReduceOnlyGate, reduceOnlyWireValue, subDecimals, sumDecimals, toWireNumber, weightedAveragePrice, } from "./signing.js";
|
|
56
55
|
import { QFEX_IDLE_CLOSE_MS, QFEX_MDS_TIMEOUT_MS, QFEX_TIMEOUTS, fetchQfexMarketStats, qfexPendingRemediation, qfexTradeSession, } from "./ws-transport.js";
|
|
57
56
|
/** A mark price entry older than this (its own venue `time`) is not used as an order reference. */
|
|
@@ -78,6 +77,24 @@ const STOP_TYPES = new Set(["TAKE_PROFIT", "STOP_LOSS"]);
|
|
|
78
77
|
const KLINE_RESOLUTION = {
|
|
79
78
|
"1m": "1MIN", "5m": "5MINS", "15m": "15MINS", "30m": "30MINS", "1h": "1HOUR", "4h": "4HOURS", "1d": "1DAY",
|
|
80
79
|
};
|
|
80
|
+
/**
|
|
81
|
+
* Candle volumes. GET /candles returns `usdVolume` (populated) and `baseTokenVolume`, which the
|
|
82
|
+
* venue leaves "0" on traded candles (live 2026-10-14, CL-USD 1HOUR: baseTokenVolume "0" with
|
|
83
|
+
* usdVolume "52534.48506" on every row; startingOpenInterest / orderbookMidPrice* are "0" too).
|
|
84
|
+
* A base "0" next to a non-zero USD volume is a placeholder → null (unknown), never 0; when
|
|
85
|
+
* both are zero the candle really had no volume.
|
|
86
|
+
*/
|
|
87
|
+
export function qfexCandleVolumes(c) {
|
|
88
|
+
const decimal = (v, what) => {
|
|
89
|
+
if (typeof v !== "string" || v.trim() === "" || !Number.isFinite(Number(v))) {
|
|
90
|
+
throw new PerpError("EXCHANGE_ERROR", `QFEX candles: ${what} is not a decimal string (${JSON.stringify(v)})`, { exchange: "qfex" });
|
|
91
|
+
}
|
|
92
|
+
return v;
|
|
93
|
+
};
|
|
94
|
+
const quoteVolume = decimal(c.usdVolume, "usdVolume");
|
|
95
|
+
const base = decimal(c.baseTokenVolume, "baseTokenVolume");
|
|
96
|
+
return { volume: Number(base) === 0 && Number(quoteVolume) !== 0 ? null : base, quoteVolume };
|
|
97
|
+
}
|
|
81
98
|
/** Client order id sent to the venue: a fresh UUID (the format the venue itself generates). */
|
|
82
99
|
export function qfexClientOrderId() {
|
|
83
100
|
return randomUUID();
|
|
@@ -262,7 +279,21 @@ export class QfexAdapter {
|
|
|
262
279
|
const venueSymbol = qfexVenueSymbol(symbol);
|
|
263
280
|
const i = (await this.instrumentMap()).get(venueSymbol);
|
|
264
281
|
if (i === undefined) {
|
|
265
|
-
throw new PerpError("SYMBOL_NOT_FOUND", `QFEX has no market ${venueSymbol}`, { exchange: "qfex", remediation: "List markets
|
|
282
|
+
throw new PerpError("SYMBOL_NOT_FOUND", `QFEX has no market ${venueSymbol}`, { exchange: "qfex", remediation: "List markets: perp -e qfex market list" });
|
|
283
|
+
}
|
|
284
|
+
return i;
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Instrument of a per-symbol read (book / funding / kline / info). Unknown → SYMBOL_NOT_FOUND; a
|
|
288
|
+
* listed market whose /refdata status is not ACTIVE (DELISTED, INACTIVE) → SYMBOL_NOT_FOUND with
|
|
289
|
+
* that status: it is not a live market. A non-USD ACTIVE market is readable (only orders refuse it).
|
|
290
|
+
*/
|
|
291
|
+
async readableInstrument(symbol) {
|
|
292
|
+
const i = await this.instrumentOf(symbol);
|
|
293
|
+
if (i.status !== "ACTIVE") {
|
|
294
|
+
throw new PerpError("SYMBOL_NOT_FOUND", `QFEX ${i.venueSymbol} is ${i.status.toLowerCase()} (status ${i.status}) — not a live market`, {
|
|
295
|
+
exchange: "qfex", status: i.status, remediation: "List tradable markets with: perp market list -e qfex",
|
|
296
|
+
});
|
|
266
297
|
}
|
|
267
298
|
return i;
|
|
268
299
|
}
|
|
@@ -339,7 +370,7 @@ export class QfexAdapter {
|
|
|
339
370
|
stopOrderGate() {
|
|
340
371
|
if (QFEX_STOP_CLIENT_ID_ECHO === true)
|
|
341
372
|
return null;
|
|
342
|
-
return unsupported("qfex", "stopOrder", "the stop order acknowledgement is not documented to echo a client order id, so a stop cannot be correlated safely (Q21)", "Set stops / TP / SL on the QFEX web app until
|
|
373
|
+
return unsupported("qfex", "stopOrder", "the stop order acknowledgement is not documented to echo a client order id, so a stop cannot be correlated safely (Q21)", "Set stops / TP / SL on the QFEX web app until QFEX item Q21 passes");
|
|
343
374
|
}
|
|
344
375
|
/**
|
|
345
376
|
* One reduce-only stop-market order (add_order with order_type TAKE_PROFIT / STOP_LOSS).
|
|
@@ -571,7 +602,7 @@ export class QfexAdapter {
|
|
|
571
602
|
/**
|
|
572
603
|
* A reduce-only order the venue did not confirm as reduce-only (`reduce_only` false or absent
|
|
573
604
|
* on an order frame — reduceOnlyUnconfirmedFrame — or on a read-back row of THIS order). The order may be live as a normal order, so the outcome is
|
|
574
|
-
* unknown (ORDER_PENDING,
|
|
605
|
+
* unknown (ORDER_PENDING, never re-sent). It is NOT cancelled here: a cancel
|
|
575
606
|
* is a second mutating command with its own unknown outcome and cannot undo a fill.
|
|
576
607
|
*/
|
|
577
608
|
reduceOnlyEchoError(i, orderId, clientOrderId, echo, venueRaw) {
|
|
@@ -746,7 +777,7 @@ export class QfexAdapter {
|
|
|
746
777
|
}
|
|
747
778
|
if (isZeroDecimal(filled)) {
|
|
748
779
|
if (ctx.immediate) {
|
|
749
|
-
// A terminal frame with nothing filled — IOC_CANCELLED or CANCELLED alike
|
|
780
|
+
// A terminal frame with nothing filled — IOC_CANCELLED or CANCELLED alike.
|
|
750
781
|
throw new PerpError("ORDER_REJECTED", `QFEX ${i.venueSymbol}: the ${t.time_in_force} order filled nothing and was cancelled (${t.status})`, {
|
|
751
782
|
exchange: "qfex", reason: "iocNoFill", venueStatus: t.status, orderId: add.orderId, clientOrderId: add.clientOrderId, venueRaw,
|
|
752
783
|
remediation: "Nothing was filled. Widen --slippage-bps (within the price band), reduce the size, or place a resting limit order",
|
|
@@ -781,7 +812,7 @@ export class QfexAdapter {
|
|
|
781
812
|
}
|
|
782
813
|
/**
|
|
783
814
|
* Final filled size of an order placed through the legacy shim — non-null ONLY when a venue
|
|
784
|
-
* terminal frame was received
|
|
815
|
+
* terminal frame was received. A pending result is never an outcome.
|
|
785
816
|
*/
|
|
786
817
|
iocOutcomeOf(raw) {
|
|
787
818
|
const r = raw;
|
|
@@ -1094,24 +1125,70 @@ export class QfexAdapter {
|
|
|
1094
1125
|
return { venue: "qfex", symbol: i.symbol, leverage: raw.leverage, marginMode: "cross", venueRaw: raw };
|
|
1095
1126
|
}
|
|
1096
1127
|
// ── Legacy ExchangeAdapter: market data ──
|
|
1128
|
+
/**
|
|
1129
|
+
* Legacy rows plus `tradable` (ACTIVE and USD-quoted, qfexTradable), the /refdata `status`
|
|
1130
|
+
* (ACTIVE / INACTIVE / DELISTED) and `quoteAsset` (prices of KRW / JPY / CNY / SEK / HKD markets
|
|
1131
|
+
* are in that currency, not USD).
|
|
1132
|
+
*/
|
|
1097
1133
|
async getMarkets() {
|
|
1098
|
-
|
|
1134
|
+
const { markets, instruments, volumeNotional } = await fetchQfexMarketsWithInstruments(this.network);
|
|
1135
|
+
const bySymbol = new Map(instruments.map(i => [i.venueSymbol, i]));
|
|
1136
|
+
return markets.map(m => this.marketRow(m, bySymbol.get(m.venueSymbol), volumeNotional));
|
|
1137
|
+
}
|
|
1138
|
+
marketRow(m, i, volumeNotional) {
|
|
1139
|
+
if (i === undefined)
|
|
1140
|
+
throw new PerpError("EXCHANGE_ERROR", `QFEX ${m.venueSymbol} is missing from /refdata`, { exchange: "qfex" });
|
|
1141
|
+
return {
|
|
1142
|
+
...toLegacyMarketInfo(m), tradable: m.tradable, status: qfexListedStatus(i), quoteAsset: i.quoteAsset,
|
|
1143
|
+
volume24hQuote: volumeNotional.get(i.venueSymbol) ?? null,
|
|
1144
|
+
};
|
|
1099
1145
|
}
|
|
1146
|
+
/**
|
|
1147
|
+
* `market info` of one ACTIVE market. fundingRate is the CURRENT /md/contracts `funding_rate`
|
|
1148
|
+
* (the rate `market funding` / `arb scan --rates --include-unverified` show), labelled fundingVerified false: QFEX funding
|
|
1149
|
+
* is unverified (Q4, display only). Market lists keep fundingRate null so no scan / bot reads it.
|
|
1150
|
+
*/
|
|
1151
|
+
async getMarketInfo(symbol) {
|
|
1152
|
+
const i = await this.readableInstrument(symbol);
|
|
1153
|
+
const snap = await fetchQfexMarketStats(QFEX_ENDPOINTS[this.network].mdsWs, i.venueSymbol, QFEX_MDS_TIMEOUT_MS);
|
|
1154
|
+
const contracts = await this.client.publicGet("/md/contracts", null);
|
|
1155
|
+
const { markets } = buildQfexMarkets([i], snap, Date.now(), qfexIndexPrices(listOf(contracts.data, "/md/contracts data")));
|
|
1156
|
+
if (markets.length === 0)
|
|
1157
|
+
throw new PerpError("PRICE_STALE", `QFEX ${i.venueSymbol}: no mark price in the market_stats snapshot`, { exchange: "qfex" });
|
|
1158
|
+
const { rates } = buildQfexFundingRates([i], listOf(contracts.data, "/md/contracts data").filter(c => c.ticker_id === i.venueSymbol), snap.marks, Date.now());
|
|
1159
|
+
return {
|
|
1160
|
+
...this.marketRow(markets[0], i, snap.volumeNotional),
|
|
1161
|
+
fundingRate: rates.length === 0 ? null : rates[0].rate,
|
|
1162
|
+
// true = the window in progress is outside the market's funding hours (fundingRate null).
|
|
1163
|
+
marketClosed: rates.length === 0 ? null : rates[0].marketClosed === true,
|
|
1164
|
+
fundingVerified: false,
|
|
1165
|
+
fundingNote: "QFEX funding rate UNVERIFIED (not confirmed against settled payments) — display only, never a basis for trading",
|
|
1166
|
+
};
|
|
1167
|
+
}
|
|
1168
|
+
/** `quoteAsset`: level prices are in the market's quote currency (KRW for SAMSUNG-KRW). */
|
|
1100
1169
|
async getOrderbook(symbol) {
|
|
1101
|
-
|
|
1170
|
+
// Resolved against refdata first: an unknown symbol is SYMBOL_NOT_FOUND, not the venue's
|
|
1171
|
+
// HTTP 404 surfacing as a retryable EXCHANGE_ERROR.
|
|
1172
|
+
const instrument = await this.readableInstrument(symbol);
|
|
1173
|
+
const venueSymbol = instrument.venueSymbol;
|
|
1102
1174
|
const book = await this.client.publicGet(`/md/orderbook/${encodeURIComponent(venueSymbol)}`, null);
|
|
1103
1175
|
// The venue lists empty price levels (quantity "0"); they are not part of the book.
|
|
1104
1176
|
const side = (v, what) => listOf(v, what)
|
|
1105
1177
|
.filter(l => Array.isArray(l) && typeof l[0] === "string" && typeof l[1] === "string" && Number(l[1]) > 0)
|
|
1106
1178
|
.map(l => [l[0], l[1]]);
|
|
1107
|
-
return { bids: side(book.bids, "orderbook bids"), asks: side(book.asks, "orderbook asks") };
|
|
1179
|
+
return { bids: side(book.bids, "orderbook bids"), asks: side(book.asks, "orderbook asks"), quoteAsset: instrument.quoteAsset };
|
|
1108
1180
|
}
|
|
1109
1181
|
async getRecentTrades() {
|
|
1110
1182
|
throw unsupported("qfex", "recentTrades", "the documented public trade endpoint (GET /public/trades) answers 404", "Use the order book: perp market book <symbol> -e qfex");
|
|
1111
1183
|
}
|
|
1112
|
-
/**
|
|
1184
|
+
/**
|
|
1185
|
+
* Hourly funding windows (GET /funding/{symbol}, intervalMinutes 60). `limit` = hours back (default 24).
|
|
1186
|
+
* A window outside the market's funding hours (qfexFundingWindowClosed) is `rate: null,
|
|
1187
|
+
* marketClosed: true` — the venue prints 0 there, which is "no funding", not a 0 rate.
|
|
1188
|
+
*/
|
|
1113
1189
|
async getFundingHistory(symbol, limit) {
|
|
1114
|
-
const
|
|
1190
|
+
const instrument = await this.readableInstrument(symbol);
|
|
1191
|
+
const venueSymbol = instrument.venueSymbol;
|
|
1115
1192
|
const hours = limit === undefined ? 24 : limit;
|
|
1116
1193
|
if (!Number.isInteger(hours) || hours < 1)
|
|
1117
1194
|
throw new PerpError("INVALID_PARAMS", `funding history limit must be a positive integer of hours (got ${hours})`);
|
|
@@ -1126,23 +1203,31 @@ export class QfexAdapter {
|
|
|
1126
1203
|
const time = typeof r.windowStart === "string" ? Date.parse(r.windowStart) : NaN;
|
|
1127
1204
|
if (!Number.isFinite(time))
|
|
1128
1205
|
throw new PerpError("EXCHANGE_ERROR", `QFEX funding history: invalid windowStart ${JSON.stringify(r.windowStart)}`);
|
|
1129
|
-
|
|
1206
|
+
const rate = plainNumber(r.rate, "funding rate");
|
|
1207
|
+
const marketClosed = qfexFundingWindowClosed(instrument.marketHours, time, Number(rate));
|
|
1208
|
+
out.push({ time, rate: marketClosed ? null : rate, price: null, intervalHours: 1, rateKind: marketClosed ? null : "lastSettled", marketClosed });
|
|
1130
1209
|
}
|
|
1131
1210
|
return out.sort((a, b) => a.time - b.time);
|
|
1132
1211
|
}
|
|
1212
|
+
/** Rows carry `quoteAsset`: OHLC prices are in the market's quote currency (KRW for SAMSUNG-KRW). */
|
|
1133
1213
|
async getKlines(symbol, interval, startTime, endTime) {
|
|
1134
1214
|
const resolution = KLINE_RESOLUTION[interval.trim()];
|
|
1135
1215
|
if (resolution === undefined) {
|
|
1136
1216
|
throw new PerpError("INVALID_PARAMS", `Unsupported kline interval "${interval}" on QFEX`, { remediation: `Use one of: ${Object.keys(KLINE_RESOLUTION).join(", ")}` });
|
|
1137
1217
|
}
|
|
1138
|
-
const
|
|
1218
|
+
const instrument = await this.readableInstrument(symbol);
|
|
1219
|
+
const venueSymbol = instrument.venueSymbol;
|
|
1220
|
+
const body = await this.client.publicGet(`/candles/${encodeURIComponent(venueSymbol)}`, {
|
|
1139
1221
|
resolution, fromISO: new Date(startTime).toISOString(), toISO: new Date(endTime).toISOString(),
|
|
1140
1222
|
});
|
|
1141
1223
|
return listOf(body.candles, "candles").map(c => {
|
|
1142
1224
|
const time = Date.parse(c.startedAt);
|
|
1143
1225
|
if (!Number.isFinite(time))
|
|
1144
1226
|
throw new PerpError("EXCHANGE_ERROR", `QFEX candles: invalid startedAt "${c.startedAt}"`);
|
|
1145
|
-
|
|
1227
|
+
const v = qfexCandleVolumes(c);
|
|
1228
|
+
// `usdVolume` is Σ price × qty in the QUOTE currency (live 2026-10-19: SAMSUNG-KRW 1m candles
|
|
1229
|
+
// equal the KRW trade tape exactly); quoteVolume is USD → null for a non-USD quote.
|
|
1230
|
+
return { time, open: c.open, high: c.high, low: c.low, close: c.close, ...v, quoteVolume: instrument.quoteAsset === "USD" ? v.quoteVolume : null, trades: null, quoteAsset: instrument.quoteAsset };
|
|
1146
1231
|
}).sort((a, b) => a.time - b.time);
|
|
1147
1232
|
}
|
|
1148
1233
|
// ── Legacy ExchangeAdapter: account ──
|
|
@@ -1258,7 +1343,7 @@ export class QfexAdapter {
|
|
|
1258
1343
|
async getFundingPayments() {
|
|
1259
1344
|
throw unsupported("qfex", "fundingPayments", "funding payments are GET /executions rows, but the execution_type that marks them is not documented (Q10)", "See funding in the QFEX web app; net funding per position is in: perp account positions -e qfex --json");
|
|
1260
1345
|
}
|
|
1261
|
-
// ── Legacy ExchangeAdapter: trading (shim → TradingV2
|
|
1346
|
+
// ── Legacy ExchangeAdapter: trading (shim → TradingV2). Client ids are generated here. ──
|
|
1262
1347
|
async marketOrder(symbol, side, size, opts) {
|
|
1263
1348
|
return this.placeOrder({
|
|
1264
1349
|
symbol, side, type: "market", size, price: null, triggerPrice: null, triggerSource: null, tif: null,
|
|
@@ -1294,7 +1379,7 @@ export class QfexAdapter {
|
|
|
1294
1379
|
reduceOnly: opts?.reduceOnly === true, clientOrderId: qfexClientOrderId(), slippage: null, tpsl: null,
|
|
1295
1380
|
});
|
|
1296
1381
|
}
|
|
1297
|
-
// ── Funds
|
|
1382
|
+
// ── Funds ──
|
|
1298
1383
|
/**
|
|
1299
1384
|
* Deposit address for USDC on Arbitrum One (banker GET /address). The address is returned
|
|
1300
1385
|
* only when the venue confirms exactly that network and asset — anything else is refused,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* QFEX API key import
|
|
2
|
+
* QFEX API key import.
|
|
3
3
|
*
|
|
4
4
|
* Keys are created on the QFEX website (Developer Settings, 2FA) — there is no programmatic
|
|
5
5
|
* approval. The public key + secret are entered via hidden prompt / stdin only (never flags,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* QFEX API key import
|
|
2
|
+
* QFEX API key import.
|
|
3
3
|
*
|
|
4
4
|
* Keys are created on the QFEX website (Developer Settings, 2FA) — there is no programmatic
|
|
5
5
|
* approval. The public key + secret are entered via hidden prompt / stdin only (never flags,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* QFEX raw REST client
|
|
2
|
+
* QFEX raw REST client: raw fetch + node:crypto HMAC, no SDK.
|
|
3
3
|
*
|
|
4
4
|
* Two hosts: the API (`api.qfex.*` — market data, account reads, leverage, subaccount
|
|
5
5
|
* transfer) and the banker (`banker.qfex.*` — deposit address, withdraw). Both take the same
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* QFEX raw REST client
|
|
2
|
+
* QFEX raw REST client: raw fetch + node:crypto HMAC, no SDK.
|
|
3
3
|
*
|
|
4
4
|
* Two hosts: the API (`api.qfex.*` — market data, account reads, leverage, subaccount
|
|
5
5
|
* transfer) and the banker (`banker.qfex.*` — deposit address, withdraw). Both take the same
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* QFEX venue status / error → PerpError
|
|
2
|
+
* QFEX venue status / error → PerpError.
|
|
3
3
|
*
|
|
4
4
|
* Three sources:
|
|
5
5
|
* - order_response.status engine verdict on one order (definite once correlated);
|
|
@@ -90,7 +90,7 @@ const STATUS_REMEDIATION = {
|
|
|
90
90
|
CANNOT_MODIFY_PARTIAL_FILL: "A partially filled order cannot be modified — cancel it and place a new order",
|
|
91
91
|
CANNOT_MODIFY_ALO_WOULD_CROSS: "The new price would cross the book — choose a passive price, or cancel and place a LIMIT order",
|
|
92
92
|
REJECTED_MARKET_CLOSED: "The market is closed for this order right now — check the session: perp market info <symbol> -e qfex",
|
|
93
|
-
INVALID_CLIENT_ORDER_ID: "The venue refused the generated client order id — report it (
|
|
93
|
+
INVALID_CLIENT_ORDER_ID: "The venue refused the generated client order id — report it (QFEX item Q18)",
|
|
94
94
|
};
|
|
95
95
|
/** "… retry after 200ms" / "… retry after 2 seconds" → ms; null when the message carries no hint. */
|
|
96
96
|
export function parseRetryAfterMs(message) {
|
|
@@ -1,21 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* QFEX public market data
|
|
2
|
+
* QFEX public market data.
|
|
3
3
|
*
|
|
4
4
|
* Sources (all public):
|
|
5
5
|
* GET /refdata instruments: tick, lot, min/max quantity, price band, status,
|
|
6
6
|
* quote / margin asset, allowed order types + TIFs, market hours
|
|
7
7
|
* MDS market_stats snapshot mark price (each entry with its own `time`), open interest,
|
|
8
8
|
* 24h notional volume
|
|
9
|
-
* GET /md/contracts funding_rate / next_funding_rate_timestamp (funding reads
|
|
9
|
+
* GET /md/contracts funding_rate / next_funding_rate_timestamp (funding reads);
|
|
10
|
+
* index_price (market rows, best effort)
|
|
10
11
|
*
|
|
11
|
-
* Coupling
|
|
12
|
-
* Markets need /refdata + the MDS snapshot
|
|
13
|
-
*
|
|
12
|
+
* Coupling: order-entry precision comes from /refdata ALONE (fetchQfexInstruments).
|
|
13
|
+
* Markets need /refdata + the MDS snapshot; /md/contracts only adds indexPrice — its failure
|
|
14
|
+
* leaves indexPrice null (unknown) with a warning, never fails market listing or order entry.
|
|
15
|
+
* Funding reads need /md/contracts.
|
|
16
|
+
*
|
|
17
|
+
* indexPrice = /md/contracts `index_price` (docs contract-specifications: the Index Price is "the
|
|
18
|
+
* reference spot price for the asset"; the OpenAPI field has no description). Live 2026-10-19 it
|
|
19
|
+
* tracked the MDS `underlier` channel (AAPL 342.47 = 342.47, GOLD 4170.22 vs 4170.05, SAMSUNG-KRW
|
|
20
|
+
* 220092 vs 220082 KRW), moved on 122 of 222 markets within 45 s, and sat a median 0.015 % from
|
|
21
|
+
* the mark (max 5 %, CVNA pre-market). It is in the quote currency (`index_currency`), like the mark.
|
|
22
|
+
* /md/contracts lists ACTIVE markets only; a non-positive / missing value is null.
|
|
14
23
|
*
|
|
15
24
|
* Funding is UNVERIFIED (venue flag fundingVerified: false, Q4): the rate's unit is not
|
|
16
25
|
* confirmed against settled payments and `funding_rate` vs `next_funding_rate` is undecided.
|
|
17
26
|
* Markets therefore carry fundingRate null; fetchFundingRates returns the raw `funding_rate`
|
|
18
|
-
* for the explicit, flagged reads only (`
|
|
27
|
+
* for the explicit, flagged reads only (`arb scan --rates|--compare --include-unverified`).
|
|
19
28
|
*
|
|
20
29
|
* Symbols: "AAPL-USD" → CLI symbol "AAPL". Non-USD quotes keep the suffix ("SKHYNIX-KRW"),
|
|
21
30
|
* have no canonical symbol and are NOT tradable through perp-cli (USD-assuming sizing / risk).
|
|
@@ -60,6 +69,14 @@ export interface QfexContractRow {
|
|
|
60
69
|
funding_rate: string;
|
|
61
70
|
next_funding_rate: string;
|
|
62
71
|
next_funding_rate_timestamp: number;
|
|
72
|
+
/** Index (reference spot) price in the quote currency — see the module header. */
|
|
73
|
+
index_price?: string;
|
|
74
|
+
/**
|
|
75
|
+
* NOT USD on a non-USD market despite the name: live 2026-10-19 SAMSUNG-KRW 1,234,418 =
|
|
76
|
+
* open_interest 5.58 × index 221,118 → KRW (as is target_volume). Nothing reads it; never wire it
|
|
77
|
+
* up as a USD figure. OI is reported in base units (VenueMarket.openInterest, MDS open_interests).
|
|
78
|
+
*/
|
|
79
|
+
open_interest_usd?: string;
|
|
63
80
|
}
|
|
64
81
|
/** One instrument, as order entry needs it — from /refdata only. */
|
|
65
82
|
export interface QfexInstrument {
|
|
@@ -89,18 +106,43 @@ export declare function qfexPlainSymbol(venueSymbol: string): string;
|
|
|
89
106
|
export declare function qfexVenueSymbol(symbol: string): string;
|
|
90
107
|
export declare function qfexAssetClass(row: Pick<QfexRefdataRow, "symbol" | "product_category" | "base_asset">): AssetClass;
|
|
91
108
|
export declare function toQfexInstrument(raw: unknown): QfexInstrument;
|
|
92
|
-
/** Is the market one perp-cli may send orders to? USD-quoted and ACTIVE
|
|
109
|
+
/** Is the market one perp-cli may send orders to? USD-quoted and ACTIVE. */
|
|
93
110
|
export declare function qfexTradable(i: Pick<QfexInstrument, "status" | "quoteAsset">): boolean;
|
|
94
111
|
/**
|
|
95
|
-
* Whether `nowMs` falls inside a `session: "open"` window of the instrument's market_hours
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
* accrues (the schedule and the documented funding hours do not map 1:1, Q9).
|
|
112
|
+
* Whether `nowMs` falls inside a `session: "open"` window of the instrument's market_hours.
|
|
113
|
+
* null = the venue published no usable schedule. This is the underlying's regular session only;
|
|
114
|
+
* funding hours are qfexFundingWindowClosed's question.
|
|
99
115
|
*/
|
|
100
116
|
export declare function qfexUnderlyingOpen(marketHours: Record<string, unknown> | null, nowMs: number): boolean | null;
|
|
117
|
+
/**
|
|
118
|
+
* Was the funding window labelled `windowStartMs` outside the market's funding hours? Docs
|
|
119
|
+
* (docs.qfex.com/qfex/funding): "Funding is only active during a symbol's configured
|
|
120
|
+
* market_hours"; outside them "funding rate is 0 and no funding payment is exchanged".
|
|
121
|
+
*
|
|
122
|
+
* The window labelled T covers the hour BEFORE T (live 2026-10-19, GET /funding, 9 symbols over
|
|
123
|
+
* 10 days: AAPL-USD prints its last non-zero rate at Sat 00:00Z = Fri 20:00 ET and its first at
|
|
124
|
+
* Mon 01:00Z = Sun 21:00 ET, i.e. funding Sun 20:00–Fri 20:00 ET as documented, only when each
|
|
125
|
+
* label is read as the end of its hour).
|
|
126
|
+
*
|
|
127
|
+
* market_hours alone does not say whether an unlisted gap funds (US equities fund overnight
|
|
128
|
+
* between post_market and pre_market; Korean equities do not fund outside "open"), so a window is
|
|
129
|
+
* closed when the venue printed exactly 0 AND no part of the hour was in a funding session
|
|
130
|
+
* (anything but "weekend" / "close"). A non-zero rate is never marked closed, and a 0 inside a
|
|
131
|
+
* session stays a real 0. No usable schedule → never closed.
|
|
132
|
+
*
|
|
133
|
+
* Known limits (review B2-4 / B2-5):
|
|
134
|
+
* - market holidays are not in market_hours: a holiday inside a configured weekday session
|
|
135
|
+
* (SAMSUNG-KRW on Hangul Day) prints the venue's 0 as a real-looking "0", marketClosed false;
|
|
136
|
+
* - US equities fund in the weekday overnight gap (post_market → pre_market, docs "Sunday 20:00 –
|
|
137
|
+
* Friday 20:00 ET"), so a gap is never closed by schedule alone — only an exact 0 there is, and
|
|
138
|
+
* a genuine 0 rate in such a gap is (rarely) reported as closed.
|
|
139
|
+
*/
|
|
140
|
+
export declare function qfexFundingWindowClosed(marketHours: Record<string, unknown> | null, windowStartMs: number, rate: number): boolean;
|
|
101
141
|
export declare function qfexPublicClient(net: Network): QfexClient;
|
|
102
142
|
/** Every instrument of /refdata (all statuses). The only input of order-entry validation. */
|
|
103
143
|
export declare function fetchQfexInstruments(client: QfexClient): Promise<QfexInstrument[]>;
|
|
144
|
+
/** venue symbol → /md/contracts `index_price` (positive finite only). */
|
|
145
|
+
export declare function qfexIndexPrices(contracts: readonly Partial<QfexContractRow>[]): Map<string, string>;
|
|
104
146
|
export declare function buildQfexMarkets(instruments: readonly QfexInstrument[], snap: {
|
|
105
147
|
marks: ReadonlyMap<string, {
|
|
106
148
|
price: string;
|
|
@@ -108,10 +150,21 @@ export declare function buildQfexMarkets(instruments: readonly QfexInstrument[],
|
|
|
108
150
|
}>;
|
|
109
151
|
openInterest: ReadonlyMap<string, string>;
|
|
110
152
|
volumeNotional: ReadonlyMap<string, string>;
|
|
111
|
-
}, nowMs: number): {
|
|
153
|
+
}, nowMs: number, indexPrices?: ReadonlyMap<string, string>): {
|
|
112
154
|
markets: VenueMarket[];
|
|
113
155
|
activeWithoutMark: string[];
|
|
114
156
|
};
|
|
157
|
+
/**
|
|
158
|
+
* Priced markets, the /refdata instruments they were built from (status / quote asset per row) and
|
|
159
|
+
* the 24h notional per venue symbol in its QUOTE currency (KRW for SAMSUNG-KRW).
|
|
160
|
+
*/
|
|
161
|
+
export declare function fetchQfexMarketsWithInstruments(net: Network): Promise<{
|
|
162
|
+
markets: VenueMarket[];
|
|
163
|
+
instruments: QfexInstrument[];
|
|
164
|
+
volumeNotional: ReadonlyMap<string, string>;
|
|
165
|
+
}>;
|
|
166
|
+
/** "active" = ACTIVE and USD-quoted; "nonUsdQuote" = ACTIVE, quoted in KRW / JPY / … (readable, never ordered). */
|
|
167
|
+
export declare function qfexListedStatus(i: Pick<QfexInstrument, "status" | "quoteAsset" | "venueSymbol">): "active" | "nonUsdQuote";
|
|
115
168
|
export declare function buildQfexFundingRates(instruments: readonly QfexInstrument[], contracts: readonly QfexContractRow[], marks: ReadonlyMap<string, {
|
|
116
169
|
price: string;
|
|
117
170
|
time: number;
|