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
|
@@ -7,10 +7,11 @@
|
|
|
7
7
|
* Composes with LighterAdapter for signing and API access.
|
|
8
8
|
*/
|
|
9
9
|
import { TX_EVENT_FILL_SOURCE } from "./spot-interface.js";
|
|
10
|
-
import { lighterWafChallenge } from "./lighter-public.js";
|
|
10
|
+
import { LIGHTER_BOOK_ORDERS_LIMIT, lighterBook, lighterWafChallenge } from "./lighter-public.js";
|
|
11
11
|
import { LIGHTER_TIF, lighterEventFilledBase, lighterEventOrderId, lighterGeneratedClientOrderIndex, lighterOrderIdOf, lighterOrderSignIndex, lighterPostSendTx, lighterRowOutcomeOf, lighterSelectAccount, lighterTakerFilledBase, lighterTxState, } from "./lighter.js";
|
|
12
12
|
import { alignProtectionPrice, floorSize, formatComputedPrice, requireOnTick, slippagePrice, subDecimal, toUnitsExact } from "./precision.js";
|
|
13
13
|
import { unsupported } from "./trading-v2.js";
|
|
14
|
+
import { rateLimitedError } from "./rate-limiter.js";
|
|
14
15
|
import { PerpError, orderNotSent, parsePositiveDecimal } from "../errors.js";
|
|
15
16
|
/** The row match (market + send time) _placeOrder attached to its result; absent → null (no extra match). */
|
|
16
17
|
function lighterRowMatchOf(result) {
|
|
@@ -28,6 +29,82 @@ function spotStatusOf(o) {
|
|
|
28
29
|
return "partial";
|
|
29
30
|
return o.status;
|
|
30
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Spot balances of one Lighter-family account object (GET /account `assets`) — the one mapper
|
|
34
|
+
* behind the keyed spot adapter and the keyless `account balance --address`. `quote` is the
|
|
35
|
+
* venue collateral ("USDC" on Lighter, "USDG" on Lighter RH).
|
|
36
|
+
*/
|
|
37
|
+
export function lighterSpotBalanceRows(acct, venue, quote) {
|
|
38
|
+
const balances = [];
|
|
39
|
+
if (acct.assets !== undefined && !Array.isArray(acct.assets)) {
|
|
40
|
+
throw new PerpError("EXCHANGE_ERROR", `${venue} spot balances: account.assets is not an array`, { exchange: venue, raw: acct.assets });
|
|
41
|
+
}
|
|
42
|
+
const assets = (acct.assets ?? []);
|
|
43
|
+
// Docs (docs.lighter.xyz/trading/unified-trading-accounts): "Unified Trading Accounts (UTA)
|
|
44
|
+
// enables unified margin on Spot and Perpetuals USDC balances." vs Simple: "perpetual and spot
|
|
45
|
+
// balances are maintained separately." Mode = this same response's account_trading_mode
|
|
46
|
+
// ("Classic=0 and Unified=1", apidocs reference/account-1); an unknown mode fails the quote row.
|
|
47
|
+
const quoteShared = () => {
|
|
48
|
+
const mode = acct.account_trading_mode;
|
|
49
|
+
if (mode !== 0 && mode !== 1) {
|
|
50
|
+
throw new PerpError("EXCHANGE_ERROR", `${venue} spot balances: account_trading_mode is ${JSON.stringify(mode ?? null)} (expected 0 classic | 1 unified)`, {
|
|
51
|
+
exchange: venue,
|
|
52
|
+
remediation: `Retry; check the account with: perp -e ${venue} account info`,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return mode === 1;
|
|
56
|
+
};
|
|
57
|
+
const plainDecimal = (v, field) => {
|
|
58
|
+
if (typeof v !== "string" || !/^-?\d+(\.\d+)?$/.test(v)) {
|
|
59
|
+
throw new PerpError("EXCHANGE_ERROR", `${venue} spot balances: ${field} is ${JSON.stringify(v ?? null)} (expected a decimal string)`, {
|
|
60
|
+
exchange: venue,
|
|
61
|
+
remediation: `Retry; check the account with: perp -e ${venue} account info`,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
return v;
|
|
65
|
+
};
|
|
66
|
+
for (const asset of assets) {
|
|
67
|
+
const bal = Number(asset.balance);
|
|
68
|
+
const locked = Number(asset.locked_balance);
|
|
69
|
+
if (!Number.isFinite(bal) || !Number.isFinite(locked)) {
|
|
70
|
+
throw new PerpError("EXCHANGE_ERROR", `${venue} spot balance for ${asset.symbol} is not a number (balance=${asset.balance}, locked=${asset.locked_balance})`, { exchange: venue, raw: asset });
|
|
71
|
+
}
|
|
72
|
+
if (asset.symbol === quote && quoteShared()) {
|
|
73
|
+
// Unified account: the quote is ONE balance for spot and perp, and the venue books it
|
|
74
|
+
// under the asset row's `margin_balance` with `balance` "0.000000" (GET /account,
|
|
75
|
+
// mainnet account 723334, 2026-10-05: assets[USDC] balance "0.000000", margin_balance
|
|
76
|
+
// "15.952247503314"; account available_balance "15.952247"). apidocs reference/account-1
|
|
77
|
+
// lists the asset fields `balance`, `locked_balance`, `margin_mode` ("enabled" |
|
|
78
|
+
// "disabled"), `margin_balance` and the account field `available_balance` without
|
|
79
|
+
// defining them further, so:
|
|
80
|
+
// total = balance + margin_balance (the quote the account holds, exact sum);
|
|
81
|
+
// available = account `available_balance` — the only "free" figure the venue reports
|
|
82
|
+
// for the unified margin, i.e. what is not committed as perp margin and
|
|
83
|
+
// therefore usable by a spot order. It is the venue's number, not
|
|
84
|
+
// total − held (it moves with perp margin use and unrealized PnL);
|
|
85
|
+
// held = locked_balance (quote locked by resting spot orders).
|
|
86
|
+
// Named by the bare quote symbol: it is not a separate spot balance (`_SPOT`).
|
|
87
|
+
const total = subDecimal(plainDecimal(asset.balance, `${quote} balance`), subDecimal("0", plainDecimal(asset.margin_balance, `${quote} margin_balance`)));
|
|
88
|
+
if (Number(total) > 0) {
|
|
89
|
+
balances.push({ token: quote, total, available: plainDecimal(acct.available_balance, "available_balance"), held: asset.locked_balance, shared: true });
|
|
90
|
+
}
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (bal > 0) {
|
|
94
|
+
balances.push({
|
|
95
|
+
// The quote row carries the bare quote symbol ("USDC" / "USDG") on classic accounts too:
|
|
96
|
+
// `shared: false` is what says it is a separate spot balance, not a `_SPOT` suffix.
|
|
97
|
+
token: asset.symbol,
|
|
98
|
+
total: asset.balance,
|
|
99
|
+
available: String(bal - locked),
|
|
100
|
+
held: asset.locked_balance,
|
|
101
|
+
// Classic quote: a separate spot balance. Base assets are never perp margin here.
|
|
102
|
+
shared: false,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return balances;
|
|
107
|
+
}
|
|
31
108
|
export class LighterSpotAdapter {
|
|
32
109
|
/** Venue id of the wrapped LighterAdapter ("lighter" | "lighter-rh"). */
|
|
33
110
|
name;
|
|
@@ -159,26 +236,22 @@ export class LighterSpotAdapter {
|
|
|
159
236
|
};
|
|
160
237
|
});
|
|
161
238
|
}
|
|
162
|
-
async getSpotOrderbook(symbol) {
|
|
239
|
+
async getSpotOrderbook(symbol, depth) {
|
|
163
240
|
await this.init();
|
|
164
241
|
const resolved = this.resolveSymbol(symbol);
|
|
165
242
|
const marketId = this._spotMarketMap.get(resolved);
|
|
166
243
|
if (marketId === undefined) {
|
|
167
|
-
throw new
|
|
168
|
-
|
|
169
|
-
try {
|
|
170
|
-
const res = await this._restGet("/orderBookOrders", {
|
|
171
|
-
market_id: String(marketId),
|
|
172
|
-
limit: "50",
|
|
244
|
+
throw new PerpError("SYMBOL_NOT_FOUND", `Unknown Lighter spot market: ${symbol}`, {
|
|
245
|
+
exchange: this.name, remediation: `Check the symbol: perp -e ${this.name} market spot-list`,
|
|
173
246
|
});
|
|
174
|
-
return {
|
|
175
|
-
bids: (res.bids ?? []).map((l) => [l.price, l.remaining_base_amount ?? l.size ?? "0"]),
|
|
176
|
-
asks: (res.asks ?? []).map((l) => [l.price, l.remaining_base_amount ?? l.size ?? "0"]),
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
catch {
|
|
180
|
-
return { bids: [], asks: [] };
|
|
181
247
|
}
|
|
248
|
+
// A failed read throws its typed error (429 / WAF / transport) — never an empty book, which
|
|
249
|
+
// callers (arb-auto, liquidity) would read as "no liquidity". Orders → price levels as on perps.
|
|
250
|
+
const res = await this._restGet("/orderBookOrders", {
|
|
251
|
+
market_id: String(marketId),
|
|
252
|
+
limit: String(LIGHTER_BOOK_ORDERS_LIMIT),
|
|
253
|
+
});
|
|
254
|
+
return lighterBook(this.name, res, resolved, depth);
|
|
182
255
|
}
|
|
183
256
|
/**
|
|
184
257
|
* Spot token balances. Reads the account through the shared 15s `acct:` cache
|
|
@@ -218,80 +291,11 @@ export class LighterSpotAdapter {
|
|
|
218
291
|
remediation: `Check the ${this.name} account index / address (perp -e ${this.name} account info)`,
|
|
219
292
|
});
|
|
220
293
|
}
|
|
221
|
-
|
|
222
|
-
const quote = this._quote;
|
|
223
|
-
if (acct.assets !== undefined && !Array.isArray(acct.assets)) {
|
|
224
|
-
throw new PerpError("EXCHANGE_ERROR", `${this.name} spot balances: account.assets is not an array`, { exchange: this.name, raw: acct.assets });
|
|
225
|
-
}
|
|
226
|
-
const assets = (acct.assets ?? []);
|
|
227
|
-
// Docs (docs.lighter.xyz/trading/unified-trading-accounts): "Unified Trading Accounts (UTA)
|
|
228
|
-
// enables unified margin on Spot and Perpetuals USDC balances." vs Simple: "perpetual and spot
|
|
229
|
-
// balances are maintained separately." Mode = this same response's account_trading_mode
|
|
230
|
-
// ("Classic=0 and Unified=1", apidocs reference/account-1); an unknown mode fails the quote row.
|
|
231
|
-
const quoteShared = () => {
|
|
232
|
-
const mode = acct.account_trading_mode;
|
|
233
|
-
if (mode !== 0 && mode !== 1) {
|
|
234
|
-
throw new PerpError("EXCHANGE_ERROR", `${this.name} spot balances: account_trading_mode is ${JSON.stringify(mode ?? null)} (expected 0 classic | 1 unified)`, {
|
|
235
|
-
exchange: this.name,
|
|
236
|
-
remediation: `Retry; check the account with: perp -e ${this.name} account info`,
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
return mode === 1;
|
|
240
|
-
};
|
|
241
|
-
const plainDecimal = (v, field) => {
|
|
242
|
-
if (typeof v !== "string" || !/^-?\d+(\.\d+)?$/.test(v)) {
|
|
243
|
-
throw new PerpError("EXCHANGE_ERROR", `${this.name} spot balances: ${field} is ${JSON.stringify(v ?? null)} (expected a decimal string)`, {
|
|
244
|
-
exchange: this.name,
|
|
245
|
-
remediation: `Retry; check the account with: perp -e ${this.name} account info`,
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
return v;
|
|
249
|
-
};
|
|
250
|
-
for (const asset of assets) {
|
|
251
|
-
const bal = Number(asset.balance);
|
|
252
|
-
const locked = Number(asset.locked_balance);
|
|
253
|
-
if (!Number.isFinite(bal) || !Number.isFinite(locked)) {
|
|
254
|
-
throw new PerpError("EXCHANGE_ERROR", `${this.name} spot balance for ${asset.symbol} is not a number (balance=${asset.balance}, locked=${asset.locked_balance})`, { exchange: this.name, raw: asset });
|
|
255
|
-
}
|
|
256
|
-
if (asset.symbol === quote && quoteShared()) {
|
|
257
|
-
// Unified account: the quote is ONE balance for spot and perp, and the venue books it
|
|
258
|
-
// under the asset row's `margin_balance` with `balance` "0.000000" (GET /account,
|
|
259
|
-
// mainnet account 723334, 2026-10-05: assets[USDC] balance "0.000000", margin_balance
|
|
260
|
-
// "15.952247503314"; account available_balance "15.952247"). apidocs reference/account-1
|
|
261
|
-
// lists the asset fields `balance`, `locked_balance`, `margin_mode` ("enabled" |
|
|
262
|
-
// "disabled"), `margin_balance` and the account field `available_balance` without
|
|
263
|
-
// defining them further, so:
|
|
264
|
-
// total = balance + margin_balance (the quote the account holds, exact sum);
|
|
265
|
-
// available = account `available_balance` — the only "free" figure the venue reports
|
|
266
|
-
// for the unified margin, i.e. what is not committed as perp margin and
|
|
267
|
-
// therefore usable by a spot order. It is the venue's number, not
|
|
268
|
-
// total − held (it moves with perp margin use and unrealized PnL);
|
|
269
|
-
// held = locked_balance (quote locked by resting spot orders).
|
|
270
|
-
// Named by the bare quote symbol: it is not a separate spot balance (`_SPOT`).
|
|
271
|
-
const total = subDecimal(plainDecimal(asset.balance, `${quote} balance`), subDecimal("0", plainDecimal(asset.margin_balance, `${quote} margin_balance`)));
|
|
272
|
-
if (Number(total) > 0) {
|
|
273
|
-
balances.push({ token: quote, total, available: plainDecimal(acct.available_balance, "available_balance"), held: asset.locked_balance, shared: true });
|
|
274
|
-
}
|
|
275
|
-
continue;
|
|
276
|
-
}
|
|
277
|
-
if (bal > 0) {
|
|
278
|
-
balances.push({
|
|
279
|
-
// The quote row carries the bare quote symbol ("USDC" / "USDG") on classic accounts too:
|
|
280
|
-
// `shared: false` is what says it is a separate spot balance, not a `_SPOT` suffix.
|
|
281
|
-
token: asset.symbol,
|
|
282
|
-
total: asset.balance,
|
|
283
|
-
available: String(bal - locked),
|
|
284
|
-
held: asset.locked_balance,
|
|
285
|
-
// Classic quote: a separate spot balance. Base assets are never perp margin here.
|
|
286
|
-
shared: false,
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
return balances;
|
|
294
|
+
return lighterSpotBalanceRows(acct, this.name, this._quote);
|
|
291
295
|
}
|
|
292
296
|
async spotMarketOrder(symbol, side, size, opts) {
|
|
293
297
|
// Everything up to sendTx is pre-send: a failure there is a definite "not placed"
|
|
294
|
-
// (ORDER_REJECTED); sendTx transport failures are ORDER_PENDING
|
|
298
|
+
// (ORDER_REJECTED); sendTx transport failures are ORDER_PENDING.
|
|
295
299
|
let prep;
|
|
296
300
|
try {
|
|
297
301
|
prep = await this._prepareMarketOrder(symbol, side, size, opts.slippage.bps);
|
|
@@ -392,30 +396,32 @@ export class LighterSpotAdapter {
|
|
|
392
396
|
const resolved = this.resolveSymbol(symbol);
|
|
393
397
|
const marketId = this._spotMarketMap.get(resolved);
|
|
394
398
|
if (marketId === undefined) {
|
|
395
|
-
throw new
|
|
399
|
+
throw new PerpError("SYMBOL_NOT_FOUND", `Unknown Lighter spot market: ${symbol}`, {
|
|
400
|
+
exchange: this.name, remediation: `Check the symbol: perp -e ${this.name} market spot-list`,
|
|
401
|
+
});
|
|
396
402
|
}
|
|
397
403
|
// Validate min order size
|
|
398
404
|
const minSize = this._spotMinSize.get(resolved);
|
|
399
405
|
const sizeNum = parseFloat(size);
|
|
400
406
|
if (minSize && sizeNum < minSize.base) {
|
|
401
|
-
throw new
|
|
407
|
+
throw new PerpError("SIZE_TOO_SMALL", `Size ${size} below min_base_amount ${minSize.base} for ${resolved}`, { exchange: this.name });
|
|
402
408
|
}
|
|
403
|
-
// Protection price = best opposite quote ± the resolved slippage bound
|
|
409
|
+
// Protection price = best opposite quote ± the resolved slippage bound
|
|
404
410
|
const ob = await this.getSpotOrderbook(resolved);
|
|
405
411
|
let refPrice;
|
|
406
412
|
if (side === "buy") {
|
|
407
413
|
if (ob.asks.length === 0)
|
|
408
|
-
throw new
|
|
414
|
+
throw new PerpError("PRICE_STALE", `No asks in ${resolved} spot orderbook — no reference price`, { exchange: this.name });
|
|
409
415
|
refPrice = Number(ob.asks[0][0]);
|
|
410
416
|
}
|
|
411
417
|
else {
|
|
412
418
|
if (ob.bids.length === 0)
|
|
413
|
-
throw new
|
|
419
|
+
throw new PerpError("PRICE_STALE", `No bids in ${resolved} spot orderbook — no reference price`, { exchange: this.name });
|
|
414
420
|
refPrice = Number(ob.bids[0][0]);
|
|
415
421
|
}
|
|
416
422
|
// Validate min quote amount (size × price ≥ min_quote)
|
|
417
423
|
if (minSize && sizeNum * refPrice < minSize.quote) {
|
|
418
|
-
throw new
|
|
424
|
+
throw new PerpError("SIZE_TOO_SMALL", `Order value $${(sizeNum * refPrice).toFixed(2)} below min_quote_amount $${minSize.quote} for ${resolved}`, { exchange: this.name });
|
|
419
425
|
}
|
|
420
426
|
const dec = this._getDecimals(resolved);
|
|
421
427
|
// Tick conversion rounds toward crossing (buy → up, sell → down), never to nearest.
|
|
@@ -453,7 +459,7 @@ export class LighterSpotAdapter {
|
|
|
453
459
|
const sizeStep = dec.size <= 0 ? "1" : `0.${"0".repeat(dec.size - 1)}1`;
|
|
454
460
|
const tick = dec.price <= 0 ? "1" : `0.${"0".repeat(dec.price - 1)}1`;
|
|
455
461
|
// Size floored to the size step (never rounded up); price must already be on tick
|
|
456
|
-
// (INVALID_TICK, never rounded
|
|
462
|
+
// (INVALID_TICK, never rounded).
|
|
457
463
|
const sentSize = floorSize(size, sizeStep);
|
|
458
464
|
const sentPrice = requireOnTick(price, tick);
|
|
459
465
|
// Venue minimums: refused, never bumped up to the minimum (the order would exceed the request).
|
|
@@ -505,7 +511,7 @@ export class LighterSpotAdapter {
|
|
|
505
511
|
};
|
|
506
512
|
}
|
|
507
513
|
/**
|
|
508
|
-
* TIF mapping, as perps
|
|
514
|
+
* TIF mapping, as perps: GTC/GTT → GTT, IOC → IOC, ALO / POST_ONLY → post-only (2).
|
|
509
515
|
* FOK and anything else → CAPABILITY_UNSUPPORTED (never silently GTT).
|
|
510
516
|
*/
|
|
511
517
|
_limitTif(tif) {
|
|
@@ -656,7 +662,7 @@ export class LighterSpotAdapter {
|
|
|
656
662
|
async transferUsdcToPerp(amount) {
|
|
657
663
|
return this._selfTransfer(String(amount), 1, 0); // route: Spot(1) → Perp(0)
|
|
658
664
|
}
|
|
659
|
-
/** SpotTransferCapable
|
|
665
|
+
/** SpotTransferCapable: only the venue collateral (USDC on Lighter, USDG on Lighter RH). */
|
|
660
666
|
async transferToSpot(amount, asset) {
|
|
661
667
|
return this._selfTransfer(this._transferAmount(amount, asset), 0, 1);
|
|
662
668
|
}
|
|
@@ -864,8 +870,7 @@ export class LighterSpotAdapter {
|
|
|
864
870
|
return nonce;
|
|
865
871
|
}
|
|
866
872
|
/**
|
|
867
|
-
* POST /sendTx. `kind` "place" (order placement): failures are typed
|
|
868
|
-
* §12.3): before the request → ORDER_REJECTED; transport error, HTTP 5xx or an
|
|
873
|
+
* POST /sendTx. `kind` "place" (order placement): failures are typed: before the request → ORDER_REJECTED; transport error, HTTP 5xx or an
|
|
869
874
|
* unreadable body after it → ORDER_PENDING (the tx may have been accepted — never
|
|
870
875
|
* resubmit); an explicit non-200 code → ORDER_REJECTED. "order" (cancels) / "action"
|
|
871
876
|
* (transfers): an explicit non-200 code → ORDER_REJECTED / ACTION_REJECTED
|
|
@@ -900,6 +905,9 @@ export class LighterSpotAdapter {
|
|
|
900
905
|
const res = await fetch(url.toString());
|
|
901
906
|
if (!res.ok) {
|
|
902
907
|
const text = await res.text();
|
|
908
|
+
// apidocs.lighter.xyz/docs/rate-limits: a breached limit answers "HTTP 429" (as LighterAdapter.restGet).
|
|
909
|
+
if (res.status === 429)
|
|
910
|
+
throw rateLimitedError(this._lt.name, res.headers.get("retry-after"), text);
|
|
903
911
|
const waf = lighterWafChallenge(this._lt.name, res.status, text);
|
|
904
912
|
if (waf !== null)
|
|
905
913
|
throw waf;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import type { ExchangeAdapter, ExchangeMarketInfo, ExchangePosition, ExchangeOrder, ExchangeBalance, ExchangeTrade, ExchangeFundingPayment, ExchangeKline } from "./interface.js";
|
|
1
|
+
import type { ExchangeAdapter, ExchangeMarketInfo, ExchangePosition, ExchangeOrder, ExchangeBalance, ExchangeTrade, ExchangePublicTrade, ExchangeFundingPayment, ExchangeKline, FundingHistoryRow } from "./interface.js";
|
|
2
2
|
import type { ResolvedSlippage } from "./slippage.js";
|
|
3
3
|
import type { EvmSigner } from "../signer/index.js";
|
|
4
4
|
import type { AgentMeta } from "../settings.js";
|
|
5
5
|
import { PerpError } from "../errors.js";
|
|
6
6
|
import type { Network, VenueNetworkConfig } from "./venue.js";
|
|
7
7
|
import { LIGHTER_REFERENCE_PRICE_SOURCE } from "./venues/lighter-family.js";
|
|
8
|
+
import { type LighterFundingStat } from "./lighter-public.js";
|
|
8
9
|
import type { LighterVenueId } from "./venues/lighter-family.js";
|
|
9
10
|
import { LighterWasmSigner } from "./lighter-signer.js";
|
|
10
11
|
/** Lighter trigger orderType enum (matches WASM signer). */
|
|
@@ -34,7 +35,12 @@ export declare const LIGHTER_TIF: {
|
|
|
34
35
|
readonly POST_ONLY: 2;
|
|
35
36
|
};
|
|
36
37
|
/**
|
|
37
|
-
*
|
|
38
|
+
* One GET /api/v1/fundings row → a funding history row (fraction per 1 h, signed).
|
|
39
|
+
* `rate` is percent per hour, unsigned; `direction` "long" = longs pay (positive), "short" = shorts pay.
|
|
40
|
+
*/
|
|
41
|
+
export declare function lighterFundingRow(venue: string, f: unknown): FundingHistoryRow;
|
|
42
|
+
/**
|
|
43
|
+
* CLI format rule for a Lighter client order id: the venue's
|
|
38
44
|
* `clientOrderIndex` is numeric, so the id must be a plain decimal integer string
|
|
39
45
|
* (digits only, no sign / leading zero / exponent) in 1 ≤ n ≤ 2^48 − 1.
|
|
40
46
|
* Anything else → INVALID_PARAMS before anything is sent.
|
|
@@ -249,6 +255,19 @@ export declare function lighterRowCreatedMs(row: Record<string, unknown>): numbe
|
|
|
249
255
|
* leverage = floor(10000 / bps), which returns the integer leverage that was set. margin_mode:
|
|
250
256
|
* 0 cross, 1 isolated (the values updateLeverage signs). Anything else throws — never a guess.
|
|
251
257
|
*/
|
|
258
|
+
/**
|
|
259
|
+
* Balance of one Lighter-family account object (GET /account) — the one implementation behind
|
|
260
|
+
* LighterAdapter.getBalance() and the keyless `account balance --address`. Equity includes the
|
|
261
|
+
* spot collateral asset (USDC on Lighter, USDG on Lighter RH; separate from perp collateral).
|
|
262
|
+
*/
|
|
263
|
+
export declare function lighterBalanceOf(acct: Record<string, unknown>, venue: string, collateralSymbol: string): ExchangeBalance;
|
|
264
|
+
/**
|
|
265
|
+
* Open positions of one Lighter account (`GET /account` `accounts[].positions[]`): the venue lists
|
|
266
|
+
* every market the account ever traded or configured, so rows with `position` 0 are dropped. The
|
|
267
|
+
* ONE mapper of the keyed `getPositions` and the public-address read; `priceDecimalsOf` formats
|
|
268
|
+
* the computed mark (position_value / size) to the market's price decimals when known.
|
|
269
|
+
*/
|
|
270
|
+
export declare function lighterPositionRows(positions: unknown, venue: string, priceDecimalsOf: (symbol: string) => number | undefined): ExchangePosition[];
|
|
252
271
|
export declare function lighterPositionSettings(p: Record<string, unknown>, venue: string): {
|
|
253
272
|
leverage: number;
|
|
254
273
|
marginMode: "cross" | "isolated";
|
|
@@ -270,13 +289,21 @@ export declare function lighterSelectAccount(accounts: Array<Record<string, unkn
|
|
|
270
289
|
* window is unknown (SYMBOL_NOT_FOUND) until the entry expires.
|
|
271
290
|
*/
|
|
272
291
|
export declare const LIGHTER_MARKET_LIST_TTL_MS: number;
|
|
292
|
+
/** GET /api/v1/candles resolutions, live-verified 2026-10-19 on lighter + lighter-rh mainnet and lighter testnet (3m / 2h / 6h / 8h / 1w / 1M / 2m: code 20001 "invalid param"). */
|
|
293
|
+
export declare const LIGHTER_CANDLE_INTERVALS: Readonly<Record<string, number>>;
|
|
294
|
+
/** "Returns at most 500 candles per call" (apidocs.lighter.xyz/reference/candles). */
|
|
295
|
+
export declare const LIGHTER_CANDLES_PER_CALL = 500;
|
|
296
|
+
/** Max `limit` of GET /api/v1/recentTrades. */
|
|
297
|
+
export declare const LIGHTER_RECENT_TRADES_MAX = 100;
|
|
298
|
+
/** Requests one `market kline` may send (the venue allows 60 / minute on standard accounts). */
|
|
299
|
+
export declare const LIGHTER_KLINE_MAX_PAGES = 10;
|
|
273
300
|
export interface LighterAdapterOpts {
|
|
274
301
|
apiKey?: string;
|
|
275
302
|
accountIndex?: number;
|
|
276
303
|
apiKeyIndex?: number;
|
|
277
304
|
}
|
|
278
305
|
export declare class LighterAdapter implements ExchangeAdapter {
|
|
279
|
-
/** GTC→GTT resting-order lifetime (28 days) for the execution record
|
|
306
|
+
/** GTC→GTT resting-order lifetime (28 days) for the execution record. */
|
|
280
307
|
static readonly gttExpiryMs: number;
|
|
281
308
|
/** Venue id ("lighter" | "lighter-rh"). */
|
|
282
309
|
readonly name: LighterVenueId;
|
|
@@ -300,6 +327,8 @@ export declare class LighterAdapter implements ExchangeAdapter {
|
|
|
300
327
|
private _address;
|
|
301
328
|
private _marketMap;
|
|
302
329
|
private _marketDecimals;
|
|
330
|
+
/** symbol → live (isLighterMarketLive). Inactive markets stay in _marketMap for reads and closes. */
|
|
331
|
+
private _marketLive;
|
|
303
332
|
private _evmKey;
|
|
304
333
|
private _apiKey;
|
|
305
334
|
private _accountIndexInit;
|
|
@@ -434,6 +463,12 @@ export declare class LighterAdapter implements ExchangeAdapter {
|
|
|
434
463
|
* the 60 / minute budget.
|
|
435
464
|
*/
|
|
436
465
|
private _refreshMarketMap;
|
|
466
|
+
/**
|
|
467
|
+
* An order that can open or add exposure (not reduce-only) on a market that is not live
|
|
468
|
+
* (`status` inactive / `is_frozen`) is refused before signing. Reduce-only orders and closes are
|
|
469
|
+
* still sent, so a position on a market that went inactive can be closed.
|
|
470
|
+
*/
|
|
471
|
+
private assertOpenable;
|
|
437
472
|
getMarketIndex(symbol: string): number;
|
|
438
473
|
/**
|
|
439
474
|
* Lot step of a perp market from the loaded market list (size decimals of /orderBooks) —
|
|
@@ -468,7 +503,7 @@ export declare class LighterAdapter implements ExchangeAdapter {
|
|
|
468
503
|
*/
|
|
469
504
|
private pollTx;
|
|
470
505
|
/**
|
|
471
|
-
* Definite IOC outcome
|
|
506
|
+
* Definite IOC outcome from the executed tx: poll /tx by hash. A taker order the
|
|
472
507
|
* venue reports "filled" (event_info `to.st` 3, `is` = sent) filled the whole order. Any other
|
|
473
508
|
* status (the remainder was cancelled — the venue zeroes `rs`, so is − rs is NOT a fill) →
|
|
474
509
|
* the venue's own `filled_base_amount` from accountOrders by client order index. Zero fill →
|
|
@@ -501,7 +536,7 @@ export declare class LighterAdapter implements ExchangeAdapter {
|
|
|
501
536
|
*/
|
|
502
537
|
orderRowOutcome(clientOrderIndex: number, orderId: string | null, what: string, settled?: (out: LighterOrderOutcome, row: Record<string, unknown>) => boolean, match?: LighterRowMatch | null): Promise<LighterOrderOutcome | null>;
|
|
503
538
|
/**
|
|
504
|
-
* Final outcome of a placed resting / post-only order (
|
|
539
|
+
* Final outcome of a placed resting / post-only order (analogue for non-IOC): poll
|
|
505
540
|
* /tx (rejected → ORDER_REJECTED). Our order (`to`, matched by client order index) reported
|
|
506
541
|
* "filled" in event_info → filled = is (the whole order). Any other status — open, or a
|
|
507
542
|
* canceled-* whose remainder the venue zeroed (`rs` 0, so is − rs is NOT a fill) — or an
|
|
@@ -524,7 +559,13 @@ export declare class LighterAdapter implements ExchangeAdapter {
|
|
|
524
559
|
* a size that floors to 0 → SIZE_TOO_SMALL.
|
|
525
560
|
*/
|
|
526
561
|
private toTicks;
|
|
527
|
-
|
|
562
|
+
/** Settled / predicted hourly funding per market_id (WS market_stats snapshot, shared with the public directory). */
|
|
563
|
+
protected fundingStats(): Promise<Map<number, LighterFundingStat>>;
|
|
564
|
+
/** Why the last listing's fundingRate is null (the settled-rate snapshot failed), else null. */
|
|
565
|
+
fundingWarning(): string | null;
|
|
566
|
+
getMarkets(opts?: {
|
|
567
|
+
funding?: boolean;
|
|
568
|
+
}): Promise<ExchangeMarketInfo[]>;
|
|
528
569
|
private get accountCacheKey();
|
|
529
570
|
/** The in-flight cached account read: parallel callers (getBalance + getPositions) share one request. */
|
|
530
571
|
private _accountInFlight;
|
|
@@ -534,9 +575,11 @@ export declare class LighterAdapter implements ExchangeAdapter {
|
|
|
534
575
|
* Book from GET /orderBookOrders?market_id=<id> on this venue's host (Lighter RH: its own host
|
|
535
576
|
* and market ids, e.g. RH testnet TSLA = 112). Rule #2: an unknown symbol (SYMBOL_NOT_FOUND) or
|
|
536
577
|
* a failed read throws — it is never reported as an empty book. An empty `bids`/`asks` is the
|
|
537
|
-
* venue's real answer (no liquidity).
|
|
578
|
+
* venue's real answer (no liquidity). The endpoint lists individual ORDERS (up to 250 per side,
|
|
579
|
+
* the documented max); they are aggregated into price levels (lighterBookLevels), as the WS
|
|
580
|
+
* `order_book` channel publishes them.
|
|
538
581
|
*/
|
|
539
|
-
getOrderbook(symbol: string): Promise<{
|
|
582
|
+
getOrderbook(symbol: string, depth?: number): Promise<{
|
|
540
583
|
bids: [string, string][];
|
|
541
584
|
asks: [string, string][];
|
|
542
585
|
}>;
|
|
@@ -558,7 +601,7 @@ export declare class LighterAdapter implements ExchangeAdapter {
|
|
|
558
601
|
/** Order / trade side from Lighter's `is_ask`; a missing / non-boolean value throws (never defaults to "buy"). */
|
|
559
602
|
private sideOfIsAsk;
|
|
560
603
|
/**
|
|
561
|
-
* Slippage-bounded IOC
|
|
604
|
+
* Slippage-bounded IOC: protection price = orderbook mid ± opts.slippage.bps,
|
|
562
605
|
* tick-aligned toward crossing. The returned raw sendTx result carries `protection`
|
|
563
606
|
* and, when the venue reported the fill, `iocOutcome` (see iocOutcomeOf).
|
|
564
607
|
* `opts.clientOrderIndex` (optional) = caller's numeric client order id (lighterClientOrderIndex rule).
|
|
@@ -569,9 +612,9 @@ export declare class LighterAdapter implements ExchangeAdapter {
|
|
|
569
612
|
clientOrderIndex?: number;
|
|
570
613
|
}): Promise<unknown>;
|
|
571
614
|
/**
|
|
572
|
-
* TIF mapping
|
|
615
|
+
* TIF mapping: GTC/GTT → GTT (28-day expiry, gttExpiryMs), IOC → IOC,
|
|
573
616
|
* ALO / POST_ONLY → time-in-force 2 (POST_ONLY per apidocs trading.md and the official
|
|
574
|
-
* lighter-go signer; 28-day expiry like GTT — testnet confirmation pending
|
|
617
|
+
* lighter-go signer; 28-day expiry like GTT — testnet confirmation pending).
|
|
575
618
|
* FOK and any other value → CAPABILITY_UNSUPPORTED (never silently GTT).
|
|
576
619
|
* `opts.clientOrderIndex` as in marketOrder.
|
|
577
620
|
* IOC: the same definite outcome as marketOrder (awaitIocOutcome — zero fill →
|
|
@@ -640,7 +683,7 @@ export declare class LighterAdapter implements ExchangeAdapter {
|
|
|
640
683
|
/**
|
|
641
684
|
* Trigger order. Market trigger (no limitPrice): execution price bound = trigger price ±
|
|
642
685
|
* `opts.slippage` bps (the caller's resolveSlippage() output — required; the adapter never
|
|
643
|
-
* reads settings
|
|
686
|
+
* reads settings), tick-aligned toward crossing, recorded in the
|
|
644
687
|
* result as `protection`. Accepted risk: a fast move through the bound leaves the
|
|
645
688
|
* triggered order unfilled.
|
|
646
689
|
* TP vs SL: `opts.kind` given (TP/SL legs) → that type as given (a trigger already crossed
|
|
@@ -665,12 +708,27 @@ export declare class LighterAdapter implements ExchangeAdapter {
|
|
|
665
708
|
private _withdrawRaw;
|
|
666
709
|
editOrder(symbol: string, orderId: string, price: string, size: string): Promise<unknown>;
|
|
667
710
|
setLeverage(symbol: string, leverage: number, marginMode?: "cross" | "isolated"): Promise<unknown>;
|
|
668
|
-
getRecentTrades(symbol: string, limit?: number): Promise<
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
711
|
+
getRecentTrades(symbol: string, limit?: number): Promise<ExchangePublicTrade[]>;
|
|
712
|
+
/**
|
|
713
|
+
* Settled funding prints: GET /api/v1/fundings (apidocs.lighter.xyz/reference/fundings;
|
|
714
|
+
* `count_back` rows from `start_timestamp`, max 750). Each row is one hourly settlement:
|
|
715
|
+
* `rate` is PERCENT per 1 h, unsigned, with `direction` "long" (longs pay → positive) or
|
|
716
|
+
* "short" (shorts pay → negative). Live 2026-10-19 BTC: rate "0.0012", value "0.99315" =
|
|
717
|
+
* mark 82,763 × 0.000012, i.e. value / mark = rate / 100. NOT the /funding-rates unit (8 h).
|
|
718
|
+
*/
|
|
719
|
+
getFundingHistory(symbol: string, limit?: number): Promise<FundingHistoryRow[]>;
|
|
720
|
+
/**
|
|
721
|
+
* Candles opening in [startTime, endTime] (ms). GET /api/v1/candles answers the
|
|
722
|
+
* max(count_back, bars in the window) newest bars ending at `end_timestamp`, at most 500
|
|
723
|
+
* (live 2026-10-19, BTC 1h: a 96-bar window with count_back 1 / 96 → those 96 bars; with
|
|
724
|
+
* count_back 500 → 500 bars, 404 of them before start_timestamp; a future window → past bars).
|
|
725
|
+
* So count_back is the window's bar count (≤ 500), rows outside the window are dropped, and a
|
|
726
|
+
* longer window is paged backwards in 500-bar chunks by moving end_timestamp. `end_timestamp` is
|
|
727
|
+
* exclusive at second resolution (live: end = a bar's open excludes it, open + 1 s includes it),
|
|
728
|
+
* so end + 1 s is sent for an inclusive --end. Each answer's `r`
|
|
729
|
+
* must be the requested resolution. Intervals outside LIGHTER_CANDLE_INTERVALS and windows over
|
|
730
|
+
* LIGHTER_KLINE_MAX_PAGES pages are refused with INVALID_PARAMS before any request.
|
|
731
|
+
*/
|
|
674
732
|
getKlines(symbol: string, interval: string, startTime: number, endTime: number): Promise<ExchangeKline[]>;
|
|
675
733
|
/**
|
|
676
734
|
* Account-wide history: ONE request per 100 rows, whatever the number of markets (the former
|
|
@@ -713,8 +771,9 @@ export declare class LighterAdapter implements ExchangeAdapter {
|
|
|
713
771
|
*/
|
|
714
772
|
getFundingPayments(limit?: number): Promise<ExchangeFundingPayment[]>;
|
|
715
773
|
/**
|
|
716
|
-
*
|
|
717
|
-
*
|
|
774
|
+
* GET /api/v1/funding-rates: the venue's PREDICTED rate × 8, a fraction per 8 h — not the venue
|
|
775
|
+
* basis (1 h; market rows carry the settled hourly rate, fundingStats). Not used for funding
|
|
776
|
+
* comparisons; normalize with 8 h if read.
|
|
718
777
|
*/
|
|
719
778
|
getFundingRates(): Promise<Map<string, {
|
|
720
779
|
rate: string;
|
|
@@ -779,7 +838,7 @@ export declare class LighterAdapter implements ExchangeAdapter {
|
|
|
779
838
|
private nextClientOrderIndex;
|
|
780
839
|
private ensureSigner;
|
|
781
840
|
/**
|
|
782
|
-
* One WASM signer (one Go runtime) per `${venueId}:${network}
|
|
841
|
+
* One WASM signer (one Go runtime) per `${venueId}:${network}`.
|
|
783
842
|
* lighter-go keys its clients by (accountIndex, apiKeyIndex) only and keeps a
|
|
784
843
|
* package-global chainId for L1 messages, so two venues must never share a
|
|
785
844
|
* runtime. Keyed by venue+network rather than chainId because Lighter testnet
|