perp-cli 0.15.0 → 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.
Files changed (154) hide show
  1. package/README.ja.md +243 -0
  2. package/README.ko.md +243 -0
  3. package/README.md +129 -535
  4. package/README.zh.md +243 -0
  5. package/dist/api/public/lighter.d.ts +5 -0
  6. package/dist/api/public/lighter.js +5 -0
  7. package/dist/api/public/pacifica.js +2 -2
  8. package/dist/arb/sizing.js +4 -2
  9. package/dist/arb/state.d.ts +6 -0
  10. package/dist/balance-by-address.d.ts +39 -0
  11. package/dist/balance-by-address.js +44 -0
  12. package/dist/bot/quote-rules.js +1 -1
  13. package/dist/bot/strategies/funding-arb-strategy.js +10 -3
  14. package/dist/bot/strategies/funding-arb-utils.d.ts +14 -2
  15. package/dist/bot/strategies/funding-arb-utils.js +48 -15
  16. package/dist/bot/strategies/spot-perp-arb-strategy.d.ts +1 -1
  17. package/dist/bot/strategies/spot-perp-arb-strategy.js +4 -2
  18. package/dist/bot/strategies/spot-perp-executor.js +2 -2
  19. package/dist/cli-program.js +1 -1
  20. package/dist/commands/account.js +168 -24
  21. package/dist/commands/arb/index.js +19 -77
  22. package/dist/commands/arb-auto.d.ts +24 -0
  23. package/dist/commands/arb-auto.js +155 -81
  24. package/dist/commands/arb.d.ts +8 -0
  25. package/dist/commands/arb.js +49 -23
  26. package/dist/commands/backtest.js +23 -21
  27. package/dist/commands/market.d.ts +48 -0
  28. package/dist/commands/market.js +241 -78
  29. package/dist/commands/options.d.ts +5 -0
  30. package/dist/commands/options.js +20 -3
  31. package/dist/commands/pacifica-earn.js +8 -21
  32. package/dist/commands/portfolio.d.ts +16 -0
  33. package/dist/commands/portfolio.js +51 -8
  34. package/dist/commands/trade.js +4 -4
  35. package/dist/cross-chain-margin.d.ts +3 -1
  36. package/dist/cross-chain-margin.js +4 -2
  37. package/dist/dashboard/server.js +2 -2
  38. package/dist/dashboard/ui.js +9 -6
  39. package/dist/errors.d.ts +5 -0
  40. package/dist/errors.js +10 -0
  41. package/dist/exchanges/address.d.ts +8 -0
  42. package/dist/exchanges/address.js +47 -0
  43. package/dist/exchanges/arcus/adapter.d.ts +10 -6
  44. package/dist/exchanges/arcus/adapter.js +33 -6
  45. package/dist/exchanges/arcus/public.js +3 -2
  46. package/dist/exchanges/aster.d.ts +27 -7
  47. package/dist/exchanges/aster.js +124 -42
  48. package/dist/exchanges/canonical-symbols.d.ts +7 -0
  49. package/dist/exchanges/canonical-symbols.js +20 -0
  50. package/dist/exchanges/capabilities.d.ts +2 -0
  51. package/dist/exchanges/capabilities.js +2 -1
  52. package/dist/exchanges/derive/options.d.ts +5 -0
  53. package/dist/exchanges/derive/options.js +20 -1
  54. package/dist/exchanges/extended/adapter.d.ts +16 -2
  55. package/dist/exchanges/extended/adapter.js +96 -34
  56. package/dist/exchanges/extended/public.d.ts +3 -0
  57. package/dist/exchanges/extended/public.js +9 -2
  58. package/dist/exchanges/grvt/adapter.d.ts +16 -2
  59. package/dist/exchanges/grvt/adapter.js +98 -21
  60. package/dist/exchanges/hyperliquid-outcome.d.ts +2 -0
  61. package/dist/exchanges/hyperliquid-outcome.js +29 -1
  62. package/dist/exchanges/hyperliquid-spot.d.ts +8 -0
  63. package/dist/exchanges/hyperliquid-spot.js +20 -12
  64. package/dist/exchanges/hyperliquid.d.ts +180 -13
  65. package/dist/exchanges/hyperliquid.js +487 -185
  66. package/dist/exchanges/interface.d.ts +64 -8
  67. package/dist/exchanges/interface.js +31 -0
  68. package/dist/exchanges/lighter-public.d.ts +66 -11
  69. package/dist/exchanges/lighter-public.js +249 -81
  70. package/dist/exchanges/lighter-spot.d.ts +7 -1
  71. package/dist/exchanges/lighter-spot.js +99 -90
  72. package/dist/exchanges/lighter.d.ts +70 -11
  73. package/dist/exchanges/lighter.js +285 -92
  74. package/dist/exchanges/ondo/adapter.d.ts +34 -8
  75. package/dist/exchanges/ondo/adapter.js +73 -16
  76. package/dist/exchanges/ondo/public.d.ts +27 -2
  77. package/dist/exchanges/ondo/public.js +63 -31
  78. package/dist/exchanges/outcome-interface.d.ts +4 -0
  79. package/dist/exchanges/pacifica-spot.d.ts +6 -0
  80. package/dist/exchanges/pacifica-spot.js +23 -15
  81. package/dist/exchanges/pacifica-vaults.d.ts +9 -0
  82. package/dist/exchanges/pacifica-vaults.js +14 -1
  83. package/dist/exchanges/pacifica.d.ts +77 -6
  84. package/dist/exchanges/pacifica.js +321 -130
  85. package/dist/exchanges/public-balances.d.ts +25 -0
  86. package/dist/exchanges/public-balances.js +158 -0
  87. package/dist/exchanges/public-positions.d.ts +43 -0
  88. package/dist/exchanges/public-positions.js +154 -0
  89. package/dist/exchanges/qfex/adapter.d.ts +52 -9
  90. package/dist/exchanges/qfex/adapter.js +74 -9
  91. package/dist/exchanges/qfex/public.d.ts +62 -9
  92. package/dist/exchanges/qfex/public.js +128 -22
  93. package/dist/exchanges/qfex/ws-transport.d.ts +1 -1
  94. package/dist/exchanges/risex/adapter.d.ts +19 -7
  95. package/dist/exchanges/risex/adapter.js +58 -12
  96. package/dist/exchanges/spot-factory.js +1 -1
  97. package/dist/exchanges/txflow/adapter.d.ts +14 -7
  98. package/dist/exchanges/txflow/adapter.js +51 -19
  99. package/dist/exchanges/txflow/client.js +3 -1
  100. package/dist/exchanges/txflow/public.d.ts +12 -1
  101. package/dist/exchanges/txflow/public.js +82 -11
  102. package/dist/exchanges/unknown-symbol.d.ts +6 -1
  103. package/dist/exchanges/unknown-symbol.js +7 -2
  104. package/dist/exchanges/variational/adapter.d.ts +2 -6
  105. package/dist/exchanges/venue-types.d.ts +46 -3
  106. package/dist/exchanges/venue-types.js +80 -9
  107. package/dist/exchanges/venue.d.ts +99 -3
  108. package/dist/exchanges/venue.js +72 -0
  109. package/dist/exchanges/venues/hyperliquid.js +9 -0
  110. package/dist/exchanges/venues/lighter-rh.js +13 -3
  111. package/dist/exchanges/venues/lighter.js +13 -3
  112. package/dist/exchanges/venues/pacifica.js +9 -0
  113. package/dist/exchanges/venues/risex.js +15 -0
  114. package/dist/funding/legacy-public.d.ts +5 -3
  115. package/dist/funding/legacy-public.js +33 -37
  116. package/dist/funding/rates.d.ts +54 -5
  117. package/dist/funding/rates.js +49 -13
  118. package/dist/liquidity.d.ts +3 -1
  119. package/dist/liquidity.js +8 -4
  120. package/dist/mcp-pacifica-earn.js +11 -5
  121. package/dist/mcp-server.js +104 -15
  122. package/dist/pacifica/client.d.ts +2 -1
  123. package/dist/pacifica/client.js +11 -0
  124. package/dist/positions-by-address.d.ts +34 -0
  125. package/dist/positions-by-address.js +46 -0
  126. package/dist/strategies/funding-arb.js +35 -62
  127. package/dist/utils.d.ts +11 -1
  128. package/dist/venue-health.js +1 -1
  129. package/dist/ws/arcus-market.d.ts +9 -0
  130. package/dist/ws/arcus-market.js +9 -0
  131. package/dist/ws/aster-market.d.ts +33 -0
  132. package/dist/ws/aster-market.js +30 -0
  133. package/dist/ws/index.d.ts +30 -9
  134. package/dist/ws/index.js +180 -15
  135. package/dist/ws/lighter-market.d.ts +14 -0
  136. package/dist/ws/lighter-market.js +13 -0
  137. package/dist/ws/node.d.ts +30 -9
  138. package/dist/ws/node.js +204 -16
  139. package/dist/ws/unclassified.d.ts +16 -0
  140. package/dist/ws/unclassified.js +43 -0
  141. package/package.json +15 -2
  142. package/skills/perp-cli/SKILL.md +97 -33
  143. package/skills/perp-cli/package.json +15 -2
  144. package/skills/perp-cli/references/agent-operations.md +15 -12
  145. package/skills/perp-cli/references/commands.md +67 -12
  146. package/skills/perp-cli/references/strategies.md +38 -3
  147. package/skills/perp-cli/references/ws-library.md +55 -24
  148. package/skills/perp-cli/scripts/arb-monitor.sh +13 -10
  149. package/skills/perp-cli/scripts/funding-analysis.sh +57 -29
  150. package/skills/perp-cli/scripts/preflight.sh +27 -19
  151. package/skills/perp-cli/scripts/spot-perp-scan.sh +58 -38
  152. package/skills/perp-cli/scripts/validate-arb.sh +56 -39
  153. package/dist/cli-spec.d.ts +0 -46
  154. package/dist/cli-spec.js +0 -81
@@ -14,7 +14,9 @@ export interface ExchangeMarketInfo {
14
14
  /**
15
15
  * Open interest in BASE-asset units (contracts of the underlying, e.g. BTC) — every venue
16
16
  * publishes it that way, so it is never a USD figure. null = venue does not publish it
17
- * (never "0" as a stand-in).
17
+ * (never "0" as a stand-in). One side where known (Lighter / Lighter RH: one side — inferred,
18
+ * not documented by the venue). The perp-ws `openInterest` is a different field with its own `unit` (Lighter:
19
+ * USD) — never compare the two without converting.
18
20
  */
19
21
  openInterest: string | null;
20
22
  /** null = the venue does not publish it (Aster: the public exchangeInfo carries no leverage) */
@@ -36,7 +38,31 @@ export interface ExchangeMarketInfo {
36
38
  lowerBound: number;
37
39
  maxLeverage: number;
38
40
  }> | null;
41
+ /**
42
+ * Listed but not tradable right now (VenueMarket.tradable: off-hours, reduce-only, halted, paused)
43
+ * → false. Delisted / disabled / inactive markets are not listed at all (each venue's eligibility
44
+ * rule). Absent = the venue publishes no tradability flag (its adapter lists live markets only).
45
+ */
46
+ tradable?: boolean;
47
+ /**
48
+ * Why a listed market is not tradable (with `tradable: false`), e.g. "nonUsdQuote", "offHours",
49
+ * "reduceOnly", "halted"; or the venue's own status. Absent / null = no reason published.
50
+ */
51
+ status?: string | null;
52
+ /**
53
+ * What `fundingRate` is, in the WS `rateKind` vocabulary: "accruing" (the current period so far),
54
+ * "predicted" (the rate expected at the next payment), "lastSettled" (the last payment). null =
55
+ * not verified for this venue's REST field. Absent on rows built before 0.15.1 conventions.
56
+ */
57
+ fundingRateKind?: FundingRateKind | null;
58
+ /**
59
+ * The venue's predicted rate for the running / next period, same unit as `fundingRate`
60
+ * (Pacifica next_funding_rate; Lighter market_stats current_funding_rate) — the perp-ws
61
+ * `predictedRate`. Absent = the venue publishes none on this path.
62
+ */
63
+ predictedFundingRate?: string | null;
39
64
  }
65
+ export type FundingRateKind = "accruing" | "predicted" | "lastSettled";
40
66
  /**
41
67
  * Effective max leverage for an order of `notional` USD.
42
68
  *
@@ -103,12 +129,35 @@ export interface TapeSkipped {
103
129
  reason: string;
104
130
  }
105
131
  export declare function withTapeSkipped<T>(rows: T[], skipped: TapeSkipped | null): T[];
132
+ /**
133
+ * Rows sorted by time (a copy), keeping every non-index property the adapter attached to the
134
+ * array (TAPE_SKIPPED and any other symbol / metadata key, with its descriptor) — a plain
135
+ * `[...rows].sort()` drops them.
136
+ */
137
+ export declare function sortByTime<T extends {
138
+ time: number;
139
+ }>(rows: readonly T[], order: "asc" | "desc"): T[];
106
140
  export declare function tapeSkippedOf(rows: readonly unknown[]): TapeSkipped | null;
107
141
  export interface ExchangeFundingPayment {
108
142
  time: number;
109
143
  symbol: string;
110
144
  payment: string;
111
145
  }
146
+ /**
147
+ * One row of `market funding` (getFundingHistory). `rate` is a fraction per `intervalHours`
148
+ * (the hours one printed rate covers; null = unknown for that market), positive = longs pay.
149
+ * `rateKind` "lastSettled" = a rate the venue applied at `time`; null = the venue does not say.
150
+ */
151
+ export interface FundingHistoryRow {
152
+ time: number;
153
+ /** null = the venue published no rate for that print (e.g. the market was closed). Never "0" as a stand-in. */
154
+ rate: string | null;
155
+ price: string | null;
156
+ intervalHours: number | null;
157
+ rateKind: "lastSettled" | null;
158
+ /** true = the underlying market was closed for this print (no funding accrued); absent = not reported. */
159
+ marketClosed?: boolean;
160
+ }
112
161
  export interface ExchangeKline {
113
162
  time: number;
114
163
  open: string;
@@ -122,6 +171,13 @@ export interface ExchangeKline {
122
171
  /** null = venue does not publish a trade count for the candle */
123
172
  trades: number | null;
124
173
  }
174
+ /**
175
+ * Guard for a candle row that states its own interval (HL / TxFlow / Pacifica `i`, RISEx
176
+ * `interval`): a row of another interval than requested is never returned as the requested one
177
+ * (RISEx answers unsupported intervals with 1m bars). `rowInterval` undefined = the row carries
178
+ * no interval field (nothing to check).
179
+ */
180
+ export declare function assertCandleInterval(venue: string, requested: string, rowInterval: unknown, remediation?: string): void;
125
181
  /** One indicative quote of an RFQ venue's maker at a fixed size. */
126
182
  export interface RfqQuoteTier {
127
183
  /** Venue tier id ("base" = the market's minimum order size). */
@@ -185,17 +241,17 @@ export interface ExchangeAdapter {
185
241
  /** True if perp and spot share the same balance (e.g., Hyperliquid). False if separate accounts (e.g., Lighter). */
186
242
  readonly isUnifiedAccount?: boolean;
187
243
  init?(): Promise<void>;
188
- getMarkets(): Promise<ExchangeMarketInfo[]>;
189
- getOrderbook(symbol: string): Promise<{
244
+ /** `opts.funding: false` = marks / precision only (Lighter skips its funding snapshot read). */
245
+ getMarkets(opts?: {
246
+ funding?: boolean;
247
+ }): Promise<ExchangeMarketInfo[]>;
248
+ /** `depth` (levels per side) sizes the request on venues that take it; callers cut the answer to it. */
249
+ getOrderbook(symbol: string, depth?: number): Promise<{
190
250
  bids: [string, string][];
191
251
  asks: [string, string][];
192
252
  }>;
193
253
  getRecentTrades(symbol: string, limit?: number): Promise<ExchangePublicTrade[]>;
194
- getFundingHistory(symbol: string, limit?: number): Promise<{
195
- time: number;
196
- rate: string;
197
- price: string | null;
198
- }[]>;
254
+ getFundingHistory(symbol: string, limit?: number): Promise<FundingHistoryRow[]>;
199
255
  getKlines(symbol: string, interval: string, startTime: number, endTime: number): Promise<ExchangeKline[]>;
200
256
  /** RFQ venue (no order book): the maker's indicative quotes. Absent = the venue has an order book. */
201
257
  getRfqQuotes?(symbol: string): Promise<RfqQuotes>;
@@ -1,3 +1,4 @@
1
+ import { PerpError } from "../errors.js";
1
2
  /**
2
3
  * Effective max leverage for an order of `notional` USD.
3
4
  *
@@ -31,7 +32,37 @@ export function withTapeSkipped(rows, skipped) {
31
32
  Object.defineProperty(rows, TAPE_SKIPPED, { value: skipped, enumerable: false });
32
33
  return rows;
33
34
  }
35
+ /**
36
+ * Rows sorted by time (a copy), keeping every non-index property the adapter attached to the
37
+ * array (TAPE_SKIPPED and any other symbol / metadata key, with its descriptor) — a plain
38
+ * `[...rows].sort()` drops them.
39
+ */
40
+ export function sortByTime(rows, order) {
41
+ const out = [...rows].sort((a, b) => (order === "asc" ? a.time - b.time : b.time - a.time));
42
+ for (const key of Reflect.ownKeys(rows)) {
43
+ if (key === "length" || (typeof key === "string" && /^\d+$/.test(key)))
44
+ continue;
45
+ const d = Object.getOwnPropertyDescriptor(rows, key);
46
+ if (d !== undefined)
47
+ Object.defineProperty(out, key, d);
48
+ }
49
+ return out;
50
+ }
34
51
  export function tapeSkippedOf(rows) {
35
52
  const v = rows[TAPE_SKIPPED];
36
53
  return v === undefined ? null : v;
37
54
  }
55
+ /**
56
+ * Guard for a candle row that states its own interval (HL / TxFlow / Pacifica `i`, RISEx
57
+ * `interval`): a row of another interval than requested is never returned as the requested one
58
+ * (RISEx answers unsupported intervals with 1m bars). `rowInterval` undefined = the row carries
59
+ * no interval field (nothing to check).
60
+ */
61
+ export function assertCandleInterval(venue, requested, rowInterval, remediation) {
62
+ if (rowInterval === undefined || rowInterval === requested)
63
+ return;
64
+ throw new PerpError("EXCHANGE_ERROR", `${venue} candles: requested ${requested} candles, got a row labelled ${JSON.stringify(rowInterval)}`, {
65
+ exchange: venue,
66
+ remediation: remediation ?? `Use an interval ${venue} serves (see perp -e ${venue} market kline --help)`,
67
+ });
68
+ }
@@ -6,29 +6,29 @@
6
6
  * amounts, status, mark/index price, IMF, OI, volume). It carries every
7
7
  * field /orderBooks has, so /orderBooks is not fetched (one fewer call
8
8
  * under the 60 req/min standard limit).
9
- * GET /api/v1/funding-rates → MULTI-EXCHANGE aggregate (binance/bybit/
10
- * hyperliquid/lighter). Only rows with exchange === "lighter" are the
11
- * venue's own; the RH host labels its own rows "lighter" too (live
12
- * 2026-09-30: 57 "lighter" rows = RH's 57 perps, matched by market_id).
9
+ * WS market_stats/all (first frame) → per market `funding_rate` (LAST SETTLED, percent per
10
+ * 1 h; = the newest GET /fundings print) and `current_funding_rate` (predicted). REST
11
+ * /funding-rates is the predicted rate × 8 and is not read here (fetchLighterFundingStats).
13
12
  *
14
- * FUNDING: basis 8h per quoted rate, hourly settlement (Lighter
15
- * and Lighter RH identical).
13
+ * FUNDING: market / funding rows carry the settled rate per 1 h (hourly settlement; Lighter and
14
+ * Lighter RH identical).
16
15
  *
17
16
  * ASSET CLASS: the API has no asset-class field (the undocumented
18
17
  * `strategy_index` groups markets on Lighter main but is 0 for every RH market),
19
18
  * so classification is an explicit per-venue table built from live listings on
20
19
  * 2026-09-30:
21
- * - lighter-rh: every listed perp is in RH_CLASS. An unlisted symbol is
22
- * excluded with a warning until it is classified (RH lists mostly equities,
23
- * so no class can be assumed).
20
+ * - lighter-rh: every listed perp is in LIGHTER_RH_CLASS (src/ws/unclassified.ts). An unlisted symbol is
21
+ * "unclassified" (listed, canonical null) until it is classified (RH lists
22
+ * mostly equities, so no class can be assumed).
24
23
  * - lighter: crypto-centric venue. LIGHTER_NON_CRYPTO lists every non-crypto
25
24
  * perp; any other symbol is crypto by this venue's definition.
26
- * LIGHTER_AMBIGUOUS tickers are excluded with a warning so they cannot
27
- * produce a false cross-venue match.
25
+ * UNCLASSIFIED_TICKERS.lighter (src/ws/unclassified.ts) are "unclassified" (listed, canonical null) so
26
+ * they cannot produce a false cross-venue match.
28
27
  *
29
28
  * OPEN INTEREST: `open_interest` in base units (same value legacy getMarkets reports).
30
29
  */
31
30
  import { PerpError } from "../errors.js";
31
+ import type { Network } from "./venue-types.js";
32
32
  import type { VenuePublicData } from "./venue.js";
33
33
  import type { LighterVenueId } from "./venues/lighter-family.js";
34
34
  /**
@@ -40,4 +40,59 @@ import type { LighterVenueId } from "./venues/lighter-family.js";
40
40
  * The API's own answers are JSON, so a JSON 405 / 403 is not a challenge.
41
41
  */
42
42
  export declare function lighterWafChallenge(venue: string, status: number, body: string): PerpError | null;
43
+ /** `limit` of GET /api/v1/orderBookOrders: the documented maximum (apidocs.lighter.xyz/reference/orderbookorders, 1..250). */
44
+ export declare const LIGHTER_BOOK_ORDERS_LIMIT = 250;
45
+ /**
46
+ * One side of GET /api/v1/orderBookOrders (individual resting ORDERS, best price first) → price
47
+ * levels: `remaining_base_amount` summed per price, in the venue's order — the shape of the WS
48
+ * `order_book/{id}` channel (levels). A side of exactly `limit` orders may have more orders at its
49
+ * last price beyond the page, so that (possibly partial) level is dropped. A row without a price /
50
+ * remaining amount is a payload error (never skipped, never "0").
51
+ */
52
+ export declare function lighterBookLevels(venue: string, rows: unknown, what: string, limit?: number): [string, string][];
53
+ /**
54
+ * A GET /orderBookOrders answer → price levels per side, cut to `depth`. A side whose page is full
55
+ * (LIGHTER_BOOK_ORDERS_LIMIT orders, the endpoint max) but aggregates to fewer than `depth` levels
56
+ * cannot be paged: INVALID_PARAMS naming the 250-order cap, never a silently shallower book.
57
+ */
58
+ export declare function lighterBook(venue: string, res: {
59
+ asks?: unknown;
60
+ bids?: unknown;
61
+ }, what: string, depth?: number): {
62
+ bids: [string, string][];
63
+ asks: [string, string][];
64
+ };
65
+ /**
66
+ * Every account of an L1 (EVM) address — `GET /account?by=l1_address&value=` (public). One
67
+ * address can own several accounts (sub-accounts). An address without a Lighter account answers
68
+ * HTTP 400 `{"code":21100,"message":"account not found"}` (live 2026-10-19) → null, not an error.
69
+ */
70
+ export declare function fetchLighterAccountsByL1(venue: LighterVenueId, net: Network, address: string): Promise<Array<Record<string, unknown>> | null>;
71
+ /** Perp price decimals by symbol (upper case) — `GET /orderBooks` `supported_price_decimals`, as the adapter's market map. */
72
+ export declare function fetchLighterPriceDecimals(venue: LighterVenueId, net: Network): Promise<Map<string, number>>;
73
+ /** One market's funding from the WS `market_stats/all` snapshot, fractions per 1 h. */
74
+ export interface LighterFundingStat {
75
+ /** Last settled hourly rate (market_stats funding_rate; = the newest GET /fundings print). */
76
+ rate: string | null;
77
+ /** Predicted rate of the running hour (market_stats current_funding_rate). */
78
+ predictedRate: string | null;
79
+ }
80
+ /** Drop the shared market_stats snapshots and remembered failures (tests; a network switch). */
81
+ export declare function clearLighterFundingStatsCache(): void;
82
+ /**
83
+ * Why the settled rate of `venue` / `net` is unavailable right now (the remembered failure of the
84
+ * last snapshot read), null when it was read or not tried. Callers put it in `meta.warnings`
85
+ * (CLI --json, MCP) next to the rows whose fundingRate is null.
86
+ */
87
+ export declare function lighterFundingStatsWarning(venue: LighterVenueId, net: Network): string | null;
88
+ /**
89
+ * Settled + predicted hourly funding of every market, keyed by market_id: the SNAPSHOT frame
90
+ * (`subscribed/market_stats`, channel `market_stats:all` — later `update/…` frames carry only the
91
+ * markets that changed) of the WS `market_stats/all` channel, the source of the perp-ws `rate` /
92
+ * `predictedRate`. REST has no bulk settled source: /funding-rates is the PREDICTED rate × 8 (live
93
+ * 2026-10-19: ETH 0.0009 % /h predicted → 0.000072; settled 0.0012 % /h), and /fundings is one
94
+ * market per request. One snapshot per venue / network is shared STATS_TTL_MS; a failure is
95
+ * remembered STATS_FAILURE_TTL_MS (lighterFundingStatsWarning).
96
+ */
97
+ export declare function fetchLighterFundingStats(venue: LighterVenueId, net: Network): Promise<Map<number, LighterFundingStat>>;
43
98
  export declare function lighterPublicData(venue: LighterVenueId): VenuePublicData;