perp-cli 0.14.2 → 0.15.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 (313) hide show
  1. package/README.md +152 -13
  2. package/dist/agent-wallet/store.d.ts +3 -2
  3. package/dist/agent-wallet/store.js +2 -2
  4. package/dist/api/public/hyperliquid.js +4 -0
  5. package/dist/api/public/pacifica.js +83 -13
  6. package/dist/api/public/urls.d.ts +2 -0
  7. package/dist/api/public/urls.js +3 -0
  8. package/dist/arb/utils.d.ts +1 -2
  9. package/dist/arb/utils.js +1 -2
  10. package/dist/bot/apex/pulse.js +3 -0
  11. package/dist/bot/apex/radar.js +2 -1
  12. package/dist/bot/engine.d.ts +10 -1
  13. package/dist/bot/engine.js +14 -6
  14. package/dist/bot/indicators.d.ts +7 -0
  15. package/dist/bot/indicators.js +16 -0
  16. package/dist/bot/perp-order.d.ts +4 -4
  17. package/dist/bot/perp-order.js +5 -5
  18. package/dist/bot/quarantine.d.ts +1 -1
  19. package/dist/bot/quarantine.js +1 -1
  20. package/dist/bot/strategies/apex-strategy.js +3 -2
  21. package/dist/bot/strategies/engine-mm.js +6 -5
  22. package/dist/bot/strategies/funding-arb-strategy.js +9 -9
  23. package/dist/bot/strategies/funding-arb-utils.d.ts +15 -2
  24. package/dist/bot/strategies/funding-arb-utils.js +43 -24
  25. package/dist/bot/strategies/funding-auto.js +2 -2
  26. package/dist/bot/strategies/liquidation-mm.d.ts +1 -0
  27. package/dist/bot/strategies/liquidation-mm.js +8 -2
  28. package/dist/bot/strategies/momentum-breakout.d.ts +1 -0
  29. package/dist/bot/strategies/momentum-breakout.js +11 -3
  30. package/dist/bot/strategies/spot-perp-arb-strategy.js +23 -12
  31. package/dist/bot/strategies/spot-perp-executor.d.ts +1 -1
  32. package/dist/bot/strategies/spot-perp-executor.js +1 -1
  33. package/dist/bot/strategy-types.d.ts +2 -1
  34. package/dist/bot/tui/BotDashboard.d.ts +1 -1
  35. package/dist/bot/tui/BotDashboard.js +1 -1
  36. package/dist/cache.js +12 -6
  37. package/dist/cli-program.d.ts +15 -0
  38. package/dist/cli-program.js +125 -5
  39. package/dist/commands/agent-import.d.ts +7 -0
  40. package/dist/commands/agent-import.js +30 -1
  41. package/dist/commands/agent.d.ts +6 -3
  42. package/dist/commands/agent.js +160 -12
  43. package/dist/commands/arb/index.js +4 -4
  44. package/dist/commands/arb-auto.js +21 -17
  45. package/dist/commands/arb.d.ts +12 -0
  46. package/dist/commands/arb.js +61 -143
  47. package/dist/commands/bot.js +1 -1
  48. package/dist/commands/builder.js +1 -1
  49. package/dist/commands/funds.js +113 -3
  50. package/dist/commands/init.d.ts +1 -1
  51. package/dist/commands/init.js +27 -7
  52. package/dist/commands/manage.js +23 -21
  53. package/dist/commands/market.js +168 -36
  54. package/dist/commands/options.d.ts +9 -0
  55. package/dist/commands/options.js +134 -0
  56. package/dist/commands/pacifica-earn.d.ts +5 -0
  57. package/dist/commands/pacifica-earn.js +468 -0
  58. package/dist/commands/pacifica-orders.d.ts +14 -0
  59. package/dist/commands/pacifica-orders.js +142 -0
  60. package/dist/commands/portfolio.js +32 -47
  61. package/dist/commands/rebalance.d.ts +1 -0
  62. package/dist/commands/rebalance.js +15 -0
  63. package/dist/commands/risk.d.ts +11 -2
  64. package/dist/commands/risk.js +39 -44
  65. package/dist/commands/trade.d.ts +1 -0
  66. package/dist/commands/trade.js +63 -58
  67. package/dist/commands/wallet.js +1 -1
  68. package/dist/config.d.ts +2 -2
  69. package/dist/config.js +15 -4
  70. package/dist/constants.js +6 -0
  71. package/dist/dashboard/server.js +1 -1
  72. package/dist/dashboard/ui.js +1 -1
  73. package/dist/errors.d.ts +24 -1
  74. package/dist/errors.js +25 -3
  75. package/dist/exchanges/arcus/adapter.d.ts +7 -7
  76. package/dist/exchanges/arcus/adapter.js +12 -12
  77. package/dist/exchanges/arcus/agent.d.ts +1 -1
  78. package/dist/exchanges/arcus/agent.js +1 -1
  79. package/dist/exchanges/arcus/client.js +1 -1
  80. package/dist/exchanges/arcus/signing.d.ts +2 -3
  81. package/dist/exchanges/arcus/signing.js +1 -1
  82. package/dist/exchanges/arcus/spot-chain.d.ts +1 -1
  83. package/dist/exchanges/arcus/spot-chain.js +1 -1
  84. package/dist/exchanges/arcus/spot-router.d.ts +1 -1
  85. package/dist/exchanges/arcus/spot-router.js +2 -2
  86. package/dist/exchanges/arcus/spot.d.ts +2 -3
  87. package/dist/exchanges/arcus/spot.js +2 -3
  88. package/dist/exchanges/aster-spot.d.ts +3 -3
  89. package/dist/exchanges/aster-spot.js +6 -9
  90. package/dist/exchanges/aster-typed-data.d.ts +1 -1
  91. package/dist/exchanges/aster-typed-data.js +1 -1
  92. package/dist/exchanges/aster.d.ts +9 -4
  93. package/dist/exchanges/aster.js +125 -55
  94. package/dist/exchanges/builder-fee.d.ts +1 -1
  95. package/dist/exchanges/builder-fee.js +13 -2
  96. package/dist/exchanges/canonical-symbols.d.ts +1 -2
  97. package/dist/exchanges/canonical-symbols.js +26 -2
  98. package/dist/exchanges/derive/client.d.ts +37 -0
  99. package/dist/exchanges/derive/client.js +135 -0
  100. package/dist/exchanges/derive/options.d.ts +68 -0
  101. package/dist/exchanges/derive/options.js +360 -0
  102. package/dist/exchanges/extended/adapter.d.ts +82 -0
  103. package/dist/exchanges/extended/adapter.js +179 -0
  104. package/dist/exchanges/extended/client.d.ts +38 -0
  105. package/dist/exchanges/extended/client.js +88 -0
  106. package/dist/exchanges/extended/public.d.ts +130 -0
  107. package/dist/exchanges/extended/public.js +429 -0
  108. package/dist/exchanges/grvt/adapter.d.ts +86 -0
  109. package/dist/exchanges/grvt/adapter.js +206 -0
  110. package/dist/exchanges/grvt/client.d.ts +25 -0
  111. package/dist/exchanges/grvt/client.js +86 -0
  112. package/dist/exchanges/grvt/public.d.ts +151 -0
  113. package/dist/exchanges/grvt/public.js +438 -0
  114. package/dist/exchanges/hyperliquid-spot.d.ts +1 -1
  115. package/dist/exchanges/hyperliquid-spot.js +5 -5
  116. package/dist/exchanges/hyperliquid.d.ts +22 -16
  117. package/dist/exchanges/hyperliquid.js +80 -55
  118. package/dist/exchanges/index.d.ts +1 -1
  119. package/dist/exchanges/index.js +1 -1
  120. package/dist/exchanges/interface.d.ts +97 -8
  121. package/dist/exchanges/interface.js +19 -2
  122. package/dist/exchanges/ioc-outcome.d.ts +1 -1
  123. package/dist/exchanges/ioc-outcome.js +1 -1
  124. package/dist/exchanges/legacy-trading-v2.d.ts +2 -2
  125. package/dist/exchanges/legacy-trading-v2.js +7 -2
  126. package/dist/exchanges/lighter-public.d.ts +2 -2
  127. package/dist/exchanges/lighter-public.js +2 -2
  128. package/dist/exchanges/lighter-signer.d.ts +1 -1
  129. package/dist/exchanges/lighter-signer.js +1 -1
  130. package/dist/exchanges/lighter-spot.d.ts +3 -4
  131. package/dist/exchanges/lighter-spot.js +6 -7
  132. package/dist/exchanges/lighter.d.ts +11 -11
  133. package/dist/exchanges/lighter.js +28 -14
  134. package/dist/exchanges/ondo/adapter.d.ts +5 -6
  135. package/dist/exchanges/ondo/adapter.js +16 -14
  136. package/dist/exchanges/ondo/agent.d.ts +1 -1
  137. package/dist/exchanges/ondo/agent.js +1 -1
  138. package/dist/exchanges/ondo/client.d.ts +1 -1
  139. package/dist/exchanges/ondo/client.js +2 -2
  140. package/dist/exchanges/ondo/public.d.ts +8 -1
  141. package/dist/exchanges/ondo/public.js +13 -2
  142. package/dist/exchanges/ondo/spot.d.ts +2 -2
  143. package/dist/exchanges/ondo/spot.js +3 -3
  144. package/dist/exchanges/options-interface.d.ts +158 -0
  145. package/dist/exchanges/options-interface.js +17 -0
  146. package/dist/exchanges/options-venues.d.ts +12 -0
  147. package/dist/exchanges/options-venues.js +35 -0
  148. package/dist/exchanges/pacifica-atomic.d.ts +211 -0
  149. package/dist/exchanges/pacifica-atomic.js +440 -0
  150. package/dist/exchanges/pacifica-decimal.d.ts +10 -0
  151. package/dist/exchanges/pacifica-decimal.js +51 -0
  152. package/dist/exchanges/pacifica-presigned.d.ts +53 -0
  153. package/dist/exchanges/pacifica-presigned.js +141 -0
  154. package/dist/exchanges/pacifica-print.d.ts +200 -0
  155. package/dist/exchanges/pacifica-print.js +417 -0
  156. package/dist/exchanges/pacifica-spot.d.ts +2 -2
  157. package/dist/exchanges/pacifica-spot.js +3 -3
  158. package/dist/exchanges/pacifica-typed-data.d.ts +1 -1
  159. package/dist/exchanges/pacifica-typed-data.js +1 -1
  160. package/dist/exchanges/pacifica-vaults.d.ts +121 -0
  161. package/dist/exchanges/pacifica-vaults.js +264 -0
  162. package/dist/exchanges/pacifica.d.ts +32 -5
  163. package/dist/exchanges/pacifica.js +114 -48
  164. package/dist/exchanges/precision.d.ts +3 -1
  165. package/dist/exchanges/precision.js +9 -2
  166. package/dist/exchanges/qfex/adapter.d.ts +18 -5
  167. package/dist/exchanges/qfex/adapter.js +32 -12
  168. package/dist/exchanges/qfex/agent.d.ts +1 -1
  169. package/dist/exchanges/qfex/agent.js +1 -1
  170. package/dist/exchanges/qfex/client.d.ts +1 -1
  171. package/dist/exchanges/qfex/client.js +1 -1
  172. package/dist/exchanges/qfex/errors.d.ts +1 -1
  173. package/dist/exchanges/qfex/errors.js +2 -2
  174. package/dist/exchanges/qfex/public.d.ts +3 -3
  175. package/dist/exchanges/qfex/public.js +3 -3
  176. package/dist/exchanges/qfex/signing.d.ts +2 -2
  177. package/dist/exchanges/qfex/signing.js +4 -5
  178. package/dist/exchanges/qfex/ws-transport.d.ts +2 -2
  179. package/dist/exchanges/qfex/ws-transport.js +3 -3
  180. package/dist/exchanges/rate-limiter.d.ts +1 -1
  181. package/dist/exchanges/rate-limiter.js +5 -2
  182. package/dist/exchanges/registry.d.ts +1 -1
  183. package/dist/exchanges/registry.js +1 -1
  184. package/dist/exchanges/risex/adapter.d.ts +148 -0
  185. package/dist/exchanges/risex/adapter.js +796 -0
  186. package/dist/exchanges/risex/agent.d.ts +154 -0
  187. package/dist/exchanges/risex/agent.js +384 -0
  188. package/dist/exchanges/risex/client.d.ts +47 -0
  189. package/dist/exchanges/risex/client.js +174 -0
  190. package/dist/exchanges/risex/nonce.d.ts +43 -0
  191. package/dist/exchanges/risex/nonce.js +212 -0
  192. package/dist/exchanges/risex/public.d.ts +64 -0
  193. package/dist/exchanges/risex/public.js +150 -0
  194. package/dist/exchanges/risex/session.d.ts +71 -0
  195. package/dist/exchanges/risex/session.js +171 -0
  196. package/dist/exchanges/risex/typed-data.d.ts +173 -0
  197. package/dist/exchanges/risex/typed-data.js +240 -0
  198. package/dist/exchanges/risex/units.d.ts +29 -0
  199. package/dist/exchanges/risex/units.js +104 -0
  200. package/dist/exchanges/slippage.d.ts +1 -1
  201. package/dist/exchanges/slippage.js +1 -1
  202. package/dist/exchanges/spot-factory.d.ts +3 -3
  203. package/dist/exchanges/spot-factory.js +7 -7
  204. package/dist/exchanges/spot-interface.d.ts +5 -5
  205. package/dist/exchanges/spot-interface.js +2 -2
  206. package/dist/exchanges/spot-result.d.ts +3 -3
  207. package/dist/exchanges/spot-result.js +3 -3
  208. package/dist/exchanges/trading-v2.d.ts +3 -3
  209. package/dist/exchanges/trading-v2.js +9 -6
  210. package/dist/exchanges/txflow/adapter.d.ts +54 -0
  211. package/dist/exchanges/txflow/adapter.js +118 -0
  212. package/dist/exchanges/txflow/client.d.ts +47 -0
  213. package/dist/exchanges/txflow/client.js +153 -0
  214. package/dist/exchanges/txflow/public.d.ts +76 -0
  215. package/dist/exchanges/txflow/public.js +284 -0
  216. package/dist/exchanges/unknown-symbol.d.ts +29 -0
  217. package/dist/exchanges/unknown-symbol.js +51 -0
  218. package/dist/exchanges/variational/adapter.d.ts +71 -0
  219. package/dist/exchanges/variational/adapter.js +137 -0
  220. package/dist/exchanges/variational/client.d.ts +21 -0
  221. package/dist/exchanges/variational/client.js +66 -0
  222. package/dist/exchanges/variational/public.d.ts +126 -0
  223. package/dist/exchanges/variational/public.js +430 -0
  224. package/dist/exchanges/venue-types.d.ts +6 -7
  225. package/dist/exchanges/venue-types.js +2 -2
  226. package/dist/exchanges/venue.d.ts +51 -8
  227. package/dist/exchanges/venue.js +54 -4
  228. package/dist/exchanges/venues/arcus.d.ts +1 -2
  229. package/dist/exchanges/venues/arcus.js +5 -4
  230. package/dist/exchanges/venues/aster.d.ts +2 -2
  231. package/dist/exchanges/venues/aster.js +6 -4
  232. package/dist/exchanges/venues/create-helpers.d.ts +1 -1
  233. package/dist/exchanges/venues/create-helpers.js +3 -3
  234. package/dist/exchanges/venues/extended.d.ts +21 -0
  235. package/dist/exchanges/venues/extended.js +96 -0
  236. package/dist/exchanges/venues/grvt.d.ts +30 -0
  237. package/dist/exchanges/venues/grvt.js +98 -0
  238. package/dist/exchanges/venues/hyperliquid.d.ts +2 -2
  239. package/dist/exchanges/venues/hyperliquid.js +10 -8
  240. package/dist/exchanges/venues/index.d.ts +7 -2
  241. package/dist/exchanges/venues/index.js +8 -2
  242. package/dist/exchanges/venues/lighter-family.d.ts +7 -9
  243. package/dist/exchanges/venues/lighter-family.js +9 -11
  244. package/dist/exchanges/venues/lighter-rh.d.ts +2 -2
  245. package/dist/exchanges/venues/lighter-rh.js +7 -5
  246. package/dist/exchanges/venues/lighter.d.ts +1 -1
  247. package/dist/exchanges/venues/lighter.js +5 -3
  248. package/dist/exchanges/venues/ondo.d.ts +1 -1
  249. package/dist/exchanges/venues/ondo.js +5 -3
  250. package/dist/exchanges/venues/pacifica.d.ts +2 -2
  251. package/dist/exchanges/venues/pacifica.js +6 -4
  252. package/dist/exchanges/venues/qfex.d.ts +1 -1
  253. package/dist/exchanges/venues/qfex.js +4 -2
  254. package/dist/exchanges/venues/risex-release.d.ts +14 -0
  255. package/dist/exchanges/venues/risex-release.js +14 -0
  256. package/dist/exchanges/venues/risex.d.ts +31 -0
  257. package/dist/exchanges/venues/risex.js +116 -0
  258. package/dist/exchanges/venues/txflow.d.ts +18 -0
  259. package/dist/exchanges/venues/txflow.js +77 -0
  260. package/dist/exchanges/venues/variational.d.ts +21 -0
  261. package/dist/exchanges/venues/variational.js +85 -0
  262. package/dist/execution-log.d.ts +1 -1
  263. package/dist/funding/legacy-public.d.ts +1 -1
  264. package/dist/funding/legacy-public.js +9 -4
  265. package/dist/funding/normalize.d.ts +1 -1
  266. package/dist/funding/normalize.js +1 -1
  267. package/dist/funding/rates.d.ts +44 -4
  268. package/dist/funding/rates.js +56 -12
  269. package/dist/index.js +7 -6
  270. package/dist/jobs.d.ts +1 -0
  271. package/dist/jobs.js +25 -1
  272. package/dist/landing.d.ts +2 -0
  273. package/dist/landing.js +1 -1
  274. package/dist/mcp-pacifica-earn.d.ts +9 -0
  275. package/dist/mcp-pacifica-earn.js +58 -0
  276. package/dist/mcp-server.js +113 -59
  277. package/dist/pacifica/client.d.ts +67 -4
  278. package/dist/pacifica/client.js +170 -8
  279. package/dist/pacifica/rate-limit.d.ts +144 -0
  280. package/dist/pacifica/rate-limit.js +267 -0
  281. package/dist/pacifica/types/order.d.ts +2 -1
  282. package/dist/plan-executor.js +7 -2
  283. package/dist/rebalance.js +1 -1
  284. package/dist/risk.d.ts +2 -1
  285. package/dist/risk.js +2 -4
  286. package/dist/settings.d.ts +32 -3
  287. package/dist/signer/ows-evm.d.ts +1 -1
  288. package/dist/signer/ows-evm.js +1 -1
  289. package/dist/smart-order.d.ts +1 -1
  290. package/dist/smart-order.js +1 -1
  291. package/dist/strategies/funding-arb.d.ts +1 -1
  292. package/dist/strategies/funding-arb.js +1 -1
  293. package/dist/trade-validator.d.ts +1 -1
  294. package/dist/trade-validator.js +9 -4
  295. package/dist/utils.d.ts +12 -3
  296. package/dist/utils.js +11 -3
  297. package/dist/venue-health.d.ts +40 -0
  298. package/dist/venue-health.js +75 -0
  299. package/dist/withdraw-gate.d.ts +1 -1
  300. package/dist/withdraw-gate.js +1 -1
  301. package/dist/ws/index.d.ts +959 -0
  302. package/dist/ws/index.js +4295 -0
  303. package/dist/ws/node.d.ts +975 -0
  304. package/dist/ws/node.js +4366 -0
  305. package/dist/ws/pacifica-instrument.d.ts +8 -0
  306. package/dist/ws/pacifica-instrument.js +8 -0
  307. package/dist/ws-cli/credentials.d.ts +62 -0
  308. package/dist/ws-cli/credentials.js +126 -0
  309. package/package.json +58 -10
  310. package/skills/perp-cli/SKILL.md +62 -9
  311. package/skills/perp-cli/references/agent-operations.md +7 -0
  312. package/skills/perp-cli/references/commands.md +76 -5
  313. package/skills/perp-cli/references/ws-library.md +492 -0
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Variational public-only adapter — OFFICIAL read-only API (venues/variational.ts).
3
+ *
4
+ * Markets, current funding terms and the OLP's indicative RFQ quotes come from the one stats
5
+ * payload (variational/public.ts). Variational is an RFQ venue with a single maker, so there is no
6
+ * order book, trade tape or candle feed in the API: getOrderbook / getRecentTrades / getKlines /
7
+ * getFundingHistory refuse with CAPABILITY_UNSUPPORTED (with the command that does work), and every
8
+ * account / trading method refuses before any request.
9
+ */
10
+ import { unsupported } from "../trading-v2.js";
11
+ import { roleUnsupported } from "../venue.js";
12
+ import { rateToHourly } from "../venue-types.js";
13
+ import { annualizeHourlyRate } from "../../funding/normalize.js";
14
+ import { currentPerpRate, fetchVariationalListings, fundingBasisOf, resolveVariationalListing, } from "./public.js";
15
+ const RFQ_NOTE = "Variational is an RFQ venue: the single market maker (OLP) quotes every trade. These are its INDICATIVE quotes at fixed notionals (may be cached up to 600 s), not order-book levels; the executed price is a firm quote at submit time.";
16
+ export class VariationalPublicAdapter {
17
+ venue;
18
+ network;
19
+ name = "variational";
20
+ aliases = ["var", "omni"];
21
+ constructor(venue, network) {
22
+ this.venue = venue;
23
+ this.network = network;
24
+ }
25
+ warn(msg) {
26
+ process.stderr.write(`${msg}\n`);
27
+ }
28
+ async listing(symbol) {
29
+ return resolveVariationalListing(await fetchVariationalListings(this.network), symbol);
30
+ }
31
+ // ── Market data ──
32
+ async getMarkets() {
33
+ return (await fetchVariationalListings(this.network)).map(l => {
34
+ const rate = currentPerpRate(l, m => this.warn(m));
35
+ const f = l.funding;
36
+ return {
37
+ symbol: l.symbol,
38
+ markPrice: l.markPrice,
39
+ indexPrice: null,
40
+ fundingRate: rate,
41
+ volume24h: l.volume24h,
42
+ // Base-unit OI is not published (USD, single-sided only — see openInterestUsd).
43
+ openInterest: null,
44
+ maxLeverage: null,
45
+ sizeDecimals: null,
46
+ stepSize: null,
47
+ fundingHours: f === null ? null : f.intervalSeconds / 3600,
48
+ marginTiers: null,
49
+ venueApi: "official",
50
+ ticker: l.ticker,
51
+ contractType: l.contractType,
52
+ name: l.name,
53
+ fundingRateKind: rate === null ? null : "predicted",
54
+ nextFundingTime: f === null ? null : f.nextFundingTime,
55
+ openInterestUsd: { long: l.longOpenInterestUsd, short: l.shortOpenInterestUsd },
56
+ swapFunding: f !== null && f.kind === "swap" ? { last: f.last, next: f.next } : null,
57
+ };
58
+ });
59
+ }
60
+ /** Current funding terms of one market (the API publishes no funding history). */
61
+ async getFundingTerms(symbol) {
62
+ const l = await this.listing(symbol);
63
+ const f = l.funding;
64
+ const rate = currentPerpRate(l, m => this.warn(m));
65
+ const base = { kind: "currentFunding", venue: "variational", symbol: l.symbol, ticker: l.ticker, contractType: l.contractType };
66
+ if (f === null) {
67
+ return { ...base, rateKind: null, intervalRate: null, intervalHours: null, hourlyRate: null, annualizedPct: null, venueAnnualizedRate: null, nextFundingTime: null, swap: null, note: "Variational publishes no funding terms for this market right now" };
68
+ }
69
+ const intervalHours = f.intervalSeconds / 3600;
70
+ if (f.kind === "swap") {
71
+ return {
72
+ ...base, rateKind: null, intervalRate: null, intervalHours, hourlyRate: null, annualizedPct: null, venueAnnualizedRate: null,
73
+ nextFundingTime: f.nextFundingTime, swap: { last: f.last, next: f.next },
74
+ note: "Swap: separate long / short rates paid once per trading day (positive long rate = longs pay, positive short rate = shorts receive); no single funding rate",
75
+ };
76
+ }
77
+ const hourlyRate = rate === null ? null : rateToHourly(Number(rate), fundingBasisOf(f));
78
+ return {
79
+ ...base,
80
+ rateKind: rate === null ? null : "predicted",
81
+ intervalRate: rate,
82
+ intervalHours,
83
+ hourlyRate,
84
+ annualizedPct: hourlyRate === null ? null : annualizeHourlyRate(hourlyRate),
85
+ venueAnnualizedRate: f.last.annualized,
86
+ nextFundingTime: f.nextFundingTime,
87
+ swap: null,
88
+ note: rate === null
89
+ ? "The published interval and annualized rates disagree; funding is not shown"
90
+ : `Current (predicted) rate for the ${intervalHours}h window ending at nextFundingTime; positive = longs pay. Variational publishes no funding history`,
91
+ };
92
+ }
93
+ /** The OLP's indicative RFQ quotes (Variational has no order book). */
94
+ async getRfqQuotes(symbol) {
95
+ const l = await this.listing(symbol);
96
+ return {
97
+ kind: "rfqQuotes",
98
+ venue: "variational",
99
+ symbol: l.symbol,
100
+ ticker: l.ticker,
101
+ markPrice: l.markPrice,
102
+ updatedAt: l.quotes === null ? null : l.quotes.updatedAt,
103
+ baseSpreadBps: l.baseSpreadBps,
104
+ quotes: l.quotes === null ? [] : l.quotes.tiers,
105
+ note: RFQ_NOTE,
106
+ };
107
+ }
108
+ async getOrderbook() {
109
+ throw unsupported("variational", "orderbook", "Variational is an RFQ venue with a single market maker (OLP); there is no order book", "See the OLP's indicative RFQ quotes at fixed notionals: perp -e variational market book <symbol>");
110
+ }
111
+ async getRecentTrades() {
112
+ throw unsupported("variational", "recentTrades", "Variational's public API publishes no trade tape", "Market stats (24h volume, open interest): perp -e variational market info <symbol>");
113
+ }
114
+ async getFundingHistory() {
115
+ throw unsupported("variational", "fundingHistory", "Variational's public API publishes no funding history", "Current funding terms: perp -e variational market funding <symbol>, or perp arb scan --rates");
116
+ }
117
+ async getKlines() {
118
+ throw unsupported("variational", "klines", "Variational's public API publishes no candles", "Current mark price: perp -e variational market info <symbol>");
119
+ }
120
+ // ── Account / trading: refused (market-data-only venue, no public trading API) ──
121
+ refuse(feature) {
122
+ throw roleUnsupported(this.venue, feature);
123
+ }
124
+ async getBalance() { return this.refuse("account"); }
125
+ async getPositions() { return this.refuse("account"); }
126
+ async getOpenOrders() { return this.refuse("account"); }
127
+ async getOrderHistory() { return this.refuse("account"); }
128
+ async getTradeHistory() { return this.refuse("account"); }
129
+ async getFundingPayments() { return this.refuse("account"); }
130
+ async marketOrder() { return this.refuse("trading"); }
131
+ async limitOrder() { return this.refuse("trading"); }
132
+ async editOrder() { return this.refuse("trading"); }
133
+ async cancelOrder() { return this.refuse("trading"); }
134
+ async cancelAllOrders() { return this.refuse("trading"); }
135
+ async setLeverage() { return this.refuse("trading"); }
136
+ async stopOrder() { return this.refuse("trading"); }
137
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Variational transport — the OFFICIAL read-only API (docs.variational.io/technical-documentation/api).
3
+ *
4
+ * One endpoint, `GET <rest>/metadata/v2/stats`, serves every market. Limits (documented): 10
5
+ * requests / 10 s per IP, 1000 / min globally, shared with the legacy v1 endpoint; over the limit
6
+ * the venue answers HTTP 429 with a JSON body whose `retry_after_seconds` says when to retry.
7
+ * Every request first takes a token from the per-process limiter (venue rateLimit policy).
8
+ */
9
+ import { PerpError } from "../../errors.js";
10
+ import type { RateLimitPolicy } from "../venue.js";
11
+ export declare const VARIATIONAL_HTTP_TIMEOUT_MS = 15000;
12
+ export declare const VARIATIONAL_STATS_PATH = "/metadata/v2/stats";
13
+ /** Payload drift in the documented API: an explicit EXCHANGE_ERROR, never a guessed value. */
14
+ export declare function variationalShapeError(what: string): PerpError;
15
+ export declare class VariationalClient {
16
+ private readonly restUrl;
17
+ private readonly rateLimit;
18
+ constructor(restUrl: string, rateLimit: RateLimitPolicy);
19
+ /** GET /metadata/v2/stats. Returns the parsed body; every error path is a PerpError. */
20
+ stats(): Promise<unknown>;
21
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Variational transport — the OFFICIAL read-only API (docs.variational.io/technical-documentation/api).
3
+ *
4
+ * One endpoint, `GET <rest>/metadata/v2/stats`, serves every market. Limits (documented): 10
5
+ * requests / 10 s per IP, 1000 / min globally, shared with the legacy v1 endpoint; over the limit
6
+ * the venue answers HTTP 429 with a JSON body whose `retry_after_seconds` says when to retry.
7
+ * Every request first takes a token from the per-process limiter (venue rateLimit policy).
8
+ */
9
+ import { PerpError, extractErrorMessage } from "../../errors.js";
10
+ import { acquireRate, rateLimitedError } from "../rate-limiter.js";
11
+ export const VARIATIONAL_HTTP_TIMEOUT_MS = 15_000;
12
+ export const VARIATIONAL_STATS_PATH = "/metadata/v2/stats";
13
+ /** Payload drift in the documented API: an explicit EXCHANGE_ERROR, never a guessed value. */
14
+ export function variationalShapeError(what) {
15
+ return new PerpError("EXCHANGE_ERROR", `Variational ${VARIATIONAL_STATS_PATH} shape changed: ${what}`, {
16
+ exchange: "variational",
17
+ remediation: "Variational's stats payload no longer matches its documentation (docs.variational.io/technical-documentation/api); perp-cli needs an update to read it",
18
+ });
19
+ }
20
+ /** `retry_after_seconds` from a 429 body (documented), else the Retry-After header. */
21
+ function retryAfterOf(res, parsed) {
22
+ const v = parsed?.retry_after_seconds;
23
+ if (typeof v === "number" && Number.isFinite(v))
24
+ return String(v);
25
+ return res.headers.get("retry-after");
26
+ }
27
+ export class VariationalClient {
28
+ restUrl;
29
+ rateLimit;
30
+ constructor(restUrl, rateLimit) {
31
+ this.restUrl = restUrl;
32
+ this.rateLimit = rateLimit;
33
+ }
34
+ /** GET /metadata/v2/stats. Returns the parsed body; every error path is a PerpError. */
35
+ async stats() {
36
+ await acquireRate("variational", this.rateLimit, VARIATIONAL_STATS_PATH);
37
+ let res;
38
+ try {
39
+ res = await fetch(`${this.restUrl}${VARIATIONAL_STATS_PATH}`, { signal: AbortSignal.timeout(VARIATIONAL_HTTP_TIMEOUT_MS) });
40
+ }
41
+ catch (e) {
42
+ throw new PerpError("EXCHANGE_UNREACHABLE", `Variational stats: ${extractErrorMessage(e)}`, { exchange: "variational" });
43
+ }
44
+ const text = await res.text().catch((e) => {
45
+ throw new PerpError("EXCHANGE_UNREACHABLE", `Variational stats: response body unreadable (${extractErrorMessage(e)})`, { exchange: "variational" });
46
+ });
47
+ let parsed;
48
+ try {
49
+ parsed = JSON.parse(text);
50
+ }
51
+ catch {
52
+ parsed = undefined;
53
+ }
54
+ if (res.status === 429)
55
+ throw rateLimitedError("variational", retryAfterOf(res, parsed), text);
56
+ if (!res.ok) {
57
+ throw new PerpError("EXCHANGE_ERROR", `Variational stats: HTTP ${res.status} ${text.slice(0, 200)}`, {
58
+ exchange: "variational", status: res.status,
59
+ remediation: "Variational's public stats API answered with an error; retry later",
60
+ });
61
+ }
62
+ if (parsed === undefined)
63
+ throw variationalShapeError("response is not JSON");
64
+ return parsed;
65
+ }
66
+ }
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Variational public market data — the OFFICIAL read-only API (venues/variational.ts).
3
+ *
4
+ * Source: `GET /metadata/v2/stats` (docs.variational.io/technical-documentation/api). One call
5
+ * returns every listing; it is shared by every reader for VARIATIONAL_STATS_TTL_MS through the
6
+ * file cache (cache.ts, cross-process, raw JSON body only) plus an in-process in-flight promise,
7
+ * so `market list` + `arb scan` + `perp health` inside the window cost ONE request.
8
+ *
9
+ * Listings (575 on 2026-10-19: 557 perpetuals, 18 swaps):
10
+ * - ticker "BTC-PERP" / "XAU-SWAP", contract_type "perpetual" | "swap". Perp display symbol =
11
+ * the base ("BTC"); a swap keeps its suffix ("XAU-SWAP") so it never collides with "XAU" perp.
12
+ * - mark_price, volume_24h (USDC), open_interest.{long,short}_open_interest (USDC, single-sided:
13
+ * trader positions only — the OLP is the other side). Base-unit OI is NOT published, so the
14
+ * legacy openInterest (base units) is null; the USD figures are carried separately.
15
+ * - quotes.{base,size_1k,size_100k,size_1m}.{bid,ask}: the OLP's INDICATIVE RFQ quotes at fixed
16
+ * notionals (may be cached up to 600 s; quotes.updated_at). Omitted while a market is closed.
17
+ *
18
+ * Funding (docs.variational.io/omni/trading/funding-rates):
19
+ * - perpetual: funding.last.interval_rate is a decimal fraction for ONE interval_seconds window
20
+ * (1h / 4h / 8h, per market), positive = longs pay. annualized_rate is the same rate × 365 d /
21
+ * interval — the identity is checked per row; a row that breaks it gets no rate (warned).
22
+ * - rateKind "predicted": `last` is recomputed during the window (live samples 2026-10-19: 175
23
+ * of 557 perps changed within 2 min under the same next_timestamp) and `next` ("predicted
24
+ * funding rate for the next interval") equals it. It is the rate the OLP will charge at
25
+ * next_timestamp, not a settled print.
26
+ * - swap: separate long / short rates paid once per trading day — there is no single funding
27
+ * rate, so fundingRate is null and swaps are never matched across venues (canonical null);
28
+ * the long / short rates are shown on the Variational rows only.
29
+ */
30
+ import { type VenuePublicData } from "../venue.js";
31
+ import type { AssetClass, FundingRateBasis, Network, VenueFundingRate, VenueMarket } from "../venue-types.js";
32
+ import type { SwapFundingRates } from "../interface.js";
33
+ /** How long one stats payload serves every reader (the venue itself sends max-age=30). */
34
+ export declare const VARIATIONAL_STATS_TTL_MS = 5000;
35
+ /**
36
+ * Hint for a cross-venue lookup by a Variational ticker whose canonical symbol differs (arb scan
37
+ * --compare US500): where it is compared instead, or that it is never matched. null = no override.
38
+ */
39
+ export declare function canonicalHintFor(symbol: string): string | null;
40
+ export declare function looksTradFi(name: string | null): boolean;
41
+ export declare function warnOnce(warn: (msg: string) => void, msg: string): void;
42
+ export type QuoteTier = "base" | "size_1k" | "size_100k" | "size_1m";
43
+ export declare const QUOTE_TIERS: readonly QuoteTier[];
44
+ /** USD notional of each quote tier; "base" = the market's minimum order size (notional not published). */
45
+ export declare const QUOTE_TIER_NOTIONAL_USD: Readonly<Record<QuoteTier, string | null>>;
46
+ export interface VariationalQuote {
47
+ tier: QuoteTier;
48
+ notionalUsd: string | null;
49
+ bid: string;
50
+ ask: string;
51
+ }
52
+ export interface VariationalQuotes {
53
+ updatedAt: string;
54
+ tiers: VariationalQuote[];
55
+ }
56
+ export interface VariationalPerpRate {
57
+ annualized: string;
58
+ interval: string;
59
+ }
60
+ export type VariationalSwapRate = SwapFundingRates;
61
+ export type VariationalFunding = {
62
+ kind: "perpetual";
63
+ intervalSeconds: number;
64
+ nextFundingTime: number | null;
65
+ last: VariationalPerpRate;
66
+ next: VariationalPerpRate | null;
67
+ } | {
68
+ kind: "swap";
69
+ intervalSeconds: number;
70
+ nextFundingTime: number | null;
71
+ last: VariationalSwapRate | null;
72
+ next: VariationalSwapRate | null;
73
+ };
74
+ export interface VariationalListing {
75
+ ticker: string;
76
+ contractType: "perpetual" | "swap";
77
+ /** Display symbol: "BTC" for BTC-PERP, "XAU-SWAP" for a swap. */
78
+ symbol: string;
79
+ base: string;
80
+ name: string | null;
81
+ markPrice: string;
82
+ volume24h: string;
83
+ longOpenInterestUsd: string;
84
+ shortOpenInterestUsd: string;
85
+ funding: VariationalFunding | null;
86
+ baseSpreadBps: string | null;
87
+ quotes: VariationalQuotes | null;
88
+ assetClass: AssetClass;
89
+ canonical: string | null;
90
+ }
91
+ /**
92
+ * Parse the stats payload. A non-object payload / missing listings array is EXCHANGE_ERROR; a
93
+ * single malformed or unclassifiable listing is dropped with a warning naming it (never guessed).
94
+ */
95
+ export declare function parseVariationalStats(body: unknown, warn: (msg: string) => void): VariationalListing[];
96
+ /** interval_rate agrees with annualized_rate × interval / 365 d (both published, both rounded). */
97
+ export declare function perpRateConsistent(rate: VariationalPerpRate, intervalSeconds: number): boolean;
98
+ /** Basis of one perp's interval_rate: perHours(interval_seconds / 3600). */
99
+ export declare function fundingBasisOf(f: VariationalFunding): FundingRateBasis;
100
+ /**
101
+ * The current (predicted) funding rate per interval, or null: swaps (no single rate), no funding
102
+ * terms, or a perp whose two published representations disagree (unit drift — warned).
103
+ */
104
+ export declare function currentPerpRate(l: VariationalListing, warn: (msg: string) => void): string | null;
105
+ export interface VariationalPublicDeps {
106
+ stats: (net: Network) => Promise<unknown>;
107
+ cache: {
108
+ get: (key: string) => unknown;
109
+ set: (key: string, value: unknown, ttlMs: number) => void;
110
+ };
111
+ warn: (msg: string) => void;
112
+ }
113
+ export declare const statsCacheKey: (net: Network) => string;
114
+ /**
115
+ * The raw stats body: from the cache when fresh, else ONE request shared by every concurrent
116
+ * caller in this process. Only the raw JSON body is cached (JSON-safe); parsing runs per read.
117
+ */
118
+ export declare function fetchVariationalStatsRaw(net: Network, deps?: VariationalPublicDeps): Promise<unknown>;
119
+ export declare function fetchVariationalListings(net: Network, deps?: VariationalPublicDeps): Promise<VariationalListing[]>;
120
+ /** null when the listing has no funding terms (its interval — part of VenueMarket — is unknown). */
121
+ export declare function toVariationalVenueMarket(l: VariationalListing, warn: (msg: string) => void): VenueMarket | null;
122
+ export declare function fetchVariationalMarkets(net: Network, deps?: VariationalPublicDeps): Promise<VenueMarket[]>;
123
+ export declare function fetchVariationalFundingRates(net: Network, deps?: VariationalPublicDeps): Promise<VenueFundingRate[]>;
124
+ export declare const variationalPublicData: VenuePublicData;
125
+ /** Resolve a CLI symbol ("btc", "BTC-PERP", "xau-swap") against the parsed listings. */
126
+ export declare function resolveVariationalListing(listings: readonly VariationalListing[], input: string): VariationalListing;