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.
- package/README.md +152 -13
- 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/pacifica.js +83 -13
- package/dist/api/public/urls.d.ts +2 -0
- package/dist/api/public/urls.js +3 -0
- package/dist/arb/utils.d.ts +1 -2
- package/dist/arb/utils.js +1 -2
- 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/strategies/apex-strategy.js +3 -2
- package/dist/bot/strategies/engine-mm.js +6 -5
- package/dist/bot/strategies/funding-arb-strategy.js +9 -9
- package/dist/bot/strategies/funding-arb-utils.d.ts +15 -2
- package/dist/bot/strategies/funding-arb-utils.js +43 -24
- 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.js +23 -12
- package/dist/bot/strategies/spot-perp-executor.d.ts +1 -1
- package/dist/bot/strategies/spot-perp-executor.js +1 -1
- 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 +125 -5
- 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 +4 -4
- package/dist/commands/arb-auto.js +21 -17
- package/dist/commands/arb.d.ts +12 -0
- package/dist/commands/arb.js +61 -143
- 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.js +168 -36
- package/dist/commands/options.d.ts +9 -0
- package/dist/commands/options.js +134 -0
- package/dist/commands/pacifica-earn.d.ts +5 -0
- package/dist/commands/pacifica-earn.js +468 -0
- package/dist/commands/pacifica-orders.d.ts +14 -0
- package/dist/commands/pacifica-orders.js +142 -0
- package/dist/commands/portfolio.js +32 -47
- 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 +63 -58
- 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/dashboard/server.js +1 -1
- package/dist/dashboard/ui.js +1 -1
- package/dist/errors.d.ts +24 -1
- package/dist/errors.js +25 -3
- package/dist/exchanges/arcus/adapter.d.ts +7 -7
- package/dist/exchanges/arcus/adapter.js +12 -12
- 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/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 +9 -4
- package/dist/exchanges/aster.js +125 -55
- package/dist/exchanges/builder-fee.d.ts +1 -1
- package/dist/exchanges/builder-fee.js +13 -2
- package/dist/exchanges/canonical-symbols.d.ts +1 -2
- package/dist/exchanges/canonical-symbols.js +26 -2
- package/dist/exchanges/derive/client.d.ts +37 -0
- package/dist/exchanges/derive/client.js +135 -0
- package/dist/exchanges/derive/options.d.ts +68 -0
- package/dist/exchanges/derive/options.js +360 -0
- package/dist/exchanges/extended/adapter.d.ts +82 -0
- package/dist/exchanges/extended/adapter.js +179 -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 +130 -0
- package/dist/exchanges/extended/public.js +429 -0
- package/dist/exchanges/grvt/adapter.d.ts +86 -0
- package/dist/exchanges/grvt/adapter.js +206 -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-spot.d.ts +1 -1
- package/dist/exchanges/hyperliquid-spot.js +5 -5
- package/dist/exchanges/hyperliquid.d.ts +22 -16
- package/dist/exchanges/hyperliquid.js +80 -55
- package/dist/exchanges/index.d.ts +1 -1
- package/dist/exchanges/index.js +1 -1
- package/dist/exchanges/interface.d.ts +97 -8
- package/dist/exchanges/interface.js +19 -2
- 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 +2 -2
- package/dist/exchanges/lighter-public.js +2 -2
- package/dist/exchanges/lighter-signer.d.ts +1 -1
- package/dist/exchanges/lighter-signer.js +1 -1
- package/dist/exchanges/lighter-spot.d.ts +3 -4
- package/dist/exchanges/lighter-spot.js +6 -7
- package/dist/exchanges/lighter.d.ts +11 -11
- package/dist/exchanges/lighter.js +28 -14
- package/dist/exchanges/ondo/adapter.d.ts +5 -6
- package/dist/exchanges/ondo/adapter.js +16 -14
- 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 +8 -1
- package/dist/exchanges/ondo/public.js +13 -2
- 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/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 +2 -2
- package/dist/exchanges/pacifica-spot.js +3 -3
- 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 +121 -0
- package/dist/exchanges/pacifica-vaults.js +264 -0
- package/dist/exchanges/pacifica.d.ts +32 -5
- package/dist/exchanges/pacifica.js +114 -48
- package/dist/exchanges/precision.d.ts +3 -1
- package/dist/exchanges/precision.js +9 -2
- package/dist/exchanges/qfex/adapter.d.ts +18 -5
- package/dist/exchanges/qfex/adapter.js +32 -12
- 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 +3 -3
- package/dist/exchanges/qfex/public.js +3 -3
- 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 +2 -2
- 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 +148 -0
- package/dist/exchanges/risex/adapter.js +796 -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 +7 -7
- 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 +54 -0
- package/dist/exchanges/txflow/adapter.js +118 -0
- package/dist/exchanges/txflow/client.d.ts +47 -0
- package/dist/exchanges/txflow/client.js +153 -0
- package/dist/exchanges/txflow/public.d.ts +76 -0
- package/dist/exchanges/txflow/public.js +284 -0
- package/dist/exchanges/unknown-symbol.d.ts +29 -0
- package/dist/exchanges/unknown-symbol.js +51 -0
- package/dist/exchanges/variational/adapter.d.ts +71 -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 +6 -7
- package/dist/exchanges/venue-types.js +2 -2
- package/dist/exchanges/venue.d.ts +51 -8
- package/dist/exchanges/venue.js +54 -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 +10 -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 +7 -5
- package/dist/exchanges/venues/lighter.d.ts +1 -1
- package/dist/exchanges/venues/lighter.js +5 -3
- 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 +6 -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 +116 -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 +1 -1
- package/dist/funding/legacy-public.js +9 -4
- package/dist/funding/normalize.d.ts +1 -1
- package/dist/funding/normalize.js +1 -1
- package/dist/funding/rates.d.ts +44 -4
- package/dist/funding/rates.js +56 -12
- 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/mcp-pacifica-earn.d.ts +9 -0
- package/dist/mcp-pacifica-earn.js +58 -0
- package/dist/mcp-server.js +113 -59
- package/dist/pacifica/client.d.ts +67 -4
- package/dist/pacifica/client.js +170 -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/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 +1 -1
- package/dist/trade-validator.d.ts +1 -1
- package/dist/trade-validator.js +9 -4
- package/dist/utils.d.ts +12 -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/index.d.ts +959 -0
- package/dist/ws/index.js +4295 -0
- package/dist/ws/node.d.ts +975 -0
- package/dist/ws/node.js +4366 -0
- package/dist/ws/pacifica-instrument.d.ts +8 -0
- package/dist/ws/pacifica-instrument.js +8 -0
- package/dist/ws-cli/credentials.d.ts +62 -0
- package/dist/ws-cli/credentials.js +126 -0
- package/package.json +58 -10
- package/skills/perp-cli/SKILL.md +62 -9
- package/skills/perp-cli/references/agent-operations.md +7 -0
- package/skills/perp-cli/references/commands.md +76 -5
- package/skills/perp-cli/references/ws-library.md +492 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Derive options — read-only `OptionsVenue` over the v3 public API (official, no auth).
|
|
3
|
+
*
|
|
4
|
+
* Reads (docs.derive.xyz/openapi.json, shapes checked live 2026-10-18):
|
|
5
|
+
* - `get_all_currencies` → currencies with an `option` asset (underlyings).
|
|
6
|
+
* - `get_all_instruments {instrument_type:"option", currency, expired:false, page_size:1000, page}`
|
|
7
|
+
* → instruments; `option_details {expiry (unix s), strike, option_type "C"|"P"}`. Paginated
|
|
8
|
+
* (`pagination.num_pages`, page_size ≤ 1000). `is_active:false` = listed for a future activation
|
|
9
|
+
* (`scheduled_activation`), not tradable and with no ticker — left out of expiries / chains.
|
|
10
|
+
* An unknown currency is RPC 12001.
|
|
11
|
+
* - `get_tickers {instrument_type:"option", currency, expiry_date:"YYYYMMDD"}` → `{tickers: {name: TickerSlim}}`;
|
|
12
|
+
* expiry_date is required for options. ONE call per chain (never one per instrument).
|
|
13
|
+
* - `get_instrument` + `get_ticker` for a single quote (unknown instrument = RPC 12001).
|
|
14
|
+
*
|
|
15
|
+
* Ticker encoding (live): an empty book side is price "0" / size "0" → `null` side; an IV the
|
|
16
|
+
* pricer could not compute (no quote, or a quote below intrinsic) is "0" → `null`; 24 h high / low
|
|
17
|
+
* are "0" when there were no trades → `null`. Greeks are passed through verbatim (a delta of 0 is real).
|
|
18
|
+
*/
|
|
19
|
+
import type { Network } from "../venue-types.js";
|
|
20
|
+
import { type OptionChain, type OptionChainQuery, type OptionExpiries, type OptionExpiry, type OptionKind, type OptionQuote, type OptionsVenue, type OptionUnderlyings } from "../options-interface.js";
|
|
21
|
+
import { DeriveClient } from "./client.js";
|
|
22
|
+
/** One option instrument, as perp-cli uses it. */
|
|
23
|
+
export interface DeriveOptionInstrument {
|
|
24
|
+
name: string;
|
|
25
|
+
underlying: string;
|
|
26
|
+
quoteCurrency: string;
|
|
27
|
+
kind: OptionKind;
|
|
28
|
+
strike: string;
|
|
29
|
+
expiryMs: number;
|
|
30
|
+
/** UTC YYYY-MM-DD of the expiry. */
|
|
31
|
+
expiry: string;
|
|
32
|
+
isActive: boolean;
|
|
33
|
+
/** ms epoch of `scheduled_activation`. */
|
|
34
|
+
activationMs: number;
|
|
35
|
+
}
|
|
36
|
+
/** ms epoch → UTC YYYY-MM-DD. */
|
|
37
|
+
export declare function utcDate(ms: number): string;
|
|
38
|
+
/** User expiry, exactly "2026-12-25" or "20261225" (not mixed) → YYYY-MM-DD; anything else INVALID_PARAMS. */
|
|
39
|
+
export declare function normalizeExpiry(input: string): string;
|
|
40
|
+
/** User underlying → venue currency (upper case); INVALID_PARAMS for anything that is not a ticker. */
|
|
41
|
+
export declare function normalizeUnderlying(input: string): string;
|
|
42
|
+
export declare function parseDeriveInstrument(raw: unknown): DeriveOptionInstrument;
|
|
43
|
+
/** A ticker_slim snapshot (get_ticker / get_tickers value) of `inst` → OptionQuote. */
|
|
44
|
+
export declare function parseDeriveOptionTicker(raw: unknown, inst: DeriveOptionInstrument): OptionQuote;
|
|
45
|
+
/** Distinct active expiries of `instruments`, soonest first. */
|
|
46
|
+
export declare function expiriesOf(instruments: readonly DeriveOptionInstrument[]): OptionExpiry[];
|
|
47
|
+
/** The `n` strikes closest to `price` (ties → lower strike), returned ascending. */
|
|
48
|
+
export declare function strikesAround(strikes: readonly string[], price: string, n: number): string[];
|
|
49
|
+
/**
|
|
50
|
+
* Chain for one expiry from its instruments and the `get_tickers` map. Rows come from the listed
|
|
51
|
+
* instruments; a listed instrument without a ticker leaves its side null and is named in
|
|
52
|
+
* `missingTickers`. Index / forward are those of the newest ticker (largest `t`) — one ticker's values,
|
|
53
|
+
* not an average over the expiry.
|
|
54
|
+
*/
|
|
55
|
+
export declare function buildChain(underlying: string, expiry: OptionExpiry, selection: OptionChain["expirySelection"], instruments: readonly DeriveOptionInstrument[], tickersRaw: unknown, strikesAroundAtm: number | null): OptionChain;
|
|
56
|
+
export declare class DeriveOptionsVenue implements OptionsVenue {
|
|
57
|
+
private readonly client;
|
|
58
|
+
readonly id = "derive";
|
|
59
|
+
readonly displayName = "Derive";
|
|
60
|
+
constructor(client: DeriveClient);
|
|
61
|
+
static forNetwork(network: Network): DeriveOptionsVenue;
|
|
62
|
+
listUnderlyings(): Promise<OptionUnderlyings>;
|
|
63
|
+
/** Every non-expired option instrument of `underlying` (all pages). 12001 → SYMBOL_NOT_FOUND. */
|
|
64
|
+
instruments(underlying: string): Promise<DeriveOptionInstrument[]>;
|
|
65
|
+
listExpiries(underlyingInput: string): Promise<OptionExpiries>;
|
|
66
|
+
getChain(q: OptionChainQuery): Promise<OptionChain>;
|
|
67
|
+
getQuote(instrumentInput: string): Promise<OptionQuote>;
|
|
68
|
+
}
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Derive options — read-only `OptionsVenue` over the v3 public API (official, no auth).
|
|
3
|
+
*
|
|
4
|
+
* Reads (docs.derive.xyz/openapi.json, shapes checked live 2026-10-18):
|
|
5
|
+
* - `get_all_currencies` → currencies with an `option` asset (underlyings).
|
|
6
|
+
* - `get_all_instruments {instrument_type:"option", currency, expired:false, page_size:1000, page}`
|
|
7
|
+
* → instruments; `option_details {expiry (unix s), strike, option_type "C"|"P"}`. Paginated
|
|
8
|
+
* (`pagination.num_pages`, page_size ≤ 1000). `is_active:false` = listed for a future activation
|
|
9
|
+
* (`scheduled_activation`), not tradable and with no ticker — left out of expiries / chains.
|
|
10
|
+
* An unknown currency is RPC 12001.
|
|
11
|
+
* - `get_tickers {instrument_type:"option", currency, expiry_date:"YYYYMMDD"}` → `{tickers: {name: TickerSlim}}`;
|
|
12
|
+
* expiry_date is required for options. ONE call per chain (never one per instrument).
|
|
13
|
+
* - `get_instrument` + `get_ticker` for a single quote (unknown instrument = RPC 12001).
|
|
14
|
+
*
|
|
15
|
+
* Ticker encoding (live): an empty book side is price "0" / size "0" → `null` side; an IV the
|
|
16
|
+
* pricer could not compute (no quote, or a quote below intrinsic) is "0" → `null`; 24 h high / low
|
|
17
|
+
* are "0" when there were no trades → `null`. Greeks are passed through verbatim (a delta of 0 is real).
|
|
18
|
+
*/
|
|
19
|
+
import { PerpError } from "../../errors.js";
|
|
20
|
+
import { OPTIONS_SCHEMA, } from "../options-interface.js";
|
|
21
|
+
import { DERIVE_INSTRUMENT_NOT_FOUND, DERIVE_INVALID_PARAMS, DeriveClient, deriveRpcCode, deriveShapeError } from "./client.js";
|
|
22
|
+
const VENUE = "derive";
|
|
23
|
+
const PAGE_SIZE = 1000;
|
|
24
|
+
function obj(v, what) {
|
|
25
|
+
if (v === null || typeof v !== "object" || Array.isArray(v))
|
|
26
|
+
throw deriveShapeError(`${what} is not an object`);
|
|
27
|
+
return v;
|
|
28
|
+
}
|
|
29
|
+
function str(o, key, what) {
|
|
30
|
+
const v = o[key];
|
|
31
|
+
if (typeof v !== "string")
|
|
32
|
+
throw deriveShapeError(`${what}.${key} is not a string`);
|
|
33
|
+
return v;
|
|
34
|
+
}
|
|
35
|
+
/** A decimal string (checked to parse as a finite number; returned verbatim). */
|
|
36
|
+
function dec(o, key, what) {
|
|
37
|
+
const v = str(o, key, what);
|
|
38
|
+
if (v.trim() === "" || !Number.isFinite(Number(v)))
|
|
39
|
+
throw deriveShapeError(`${what}.${key} is not a decimal ("${v}")`);
|
|
40
|
+
return v;
|
|
41
|
+
}
|
|
42
|
+
function int(o, key, what) {
|
|
43
|
+
const v = o[key];
|
|
44
|
+
if (typeof v !== "number" || !Number.isInteger(v))
|
|
45
|
+
throw deriveShapeError(`${what}.${key} is not an integer`);
|
|
46
|
+
return v;
|
|
47
|
+
}
|
|
48
|
+
/** Derive's "0" placeholder → null; anything else verbatim. */
|
|
49
|
+
function nonZero(v) {
|
|
50
|
+
return Number(v) === 0 ? null : v;
|
|
51
|
+
}
|
|
52
|
+
// ── dates ──
|
|
53
|
+
/** ms epoch → UTC YYYY-MM-DD. */
|
|
54
|
+
export function utcDate(ms) {
|
|
55
|
+
return new Date(ms).toISOString().slice(0, 10);
|
|
56
|
+
}
|
|
57
|
+
/** User expiry, exactly "2026-12-25" or "20261225" (not mixed) → YYYY-MM-DD; anything else INVALID_PARAMS. */
|
|
58
|
+
export function normalizeExpiry(input) {
|
|
59
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(input.trim()) ?? /^(\d{4})(\d{2})(\d{2})$/.exec(input.trim());
|
|
60
|
+
const iso = m !== null ? `${m[1]}-${m[2]}-${m[3]}` : null;
|
|
61
|
+
if (iso === null || Number.isNaN(Date.parse(`${iso}T00:00:00Z`)) || utcDate(Date.parse(`${iso}T00:00:00Z`)) !== iso) {
|
|
62
|
+
throw new PerpError("INVALID_PARAMS", `Invalid expiry "${input}" — expected YYYY-MM-DD (UTC)`, {
|
|
63
|
+
remediation: `List expiries: perp -e ${VENUE} options expiries <UNDERLYING>`,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return iso;
|
|
67
|
+
}
|
|
68
|
+
/** User underlying → venue currency (upper case); INVALID_PARAMS for anything that is not a ticker. */
|
|
69
|
+
export function normalizeUnderlying(input) {
|
|
70
|
+
const u = input.trim().toUpperCase();
|
|
71
|
+
if (!/^[A-Z0-9_]{1,20}$/.test(u)) {
|
|
72
|
+
throw new PerpError("INVALID_PARAMS", `Invalid underlying "${input}"`, {
|
|
73
|
+
remediation: `List underlyings: perp -e ${VENUE} options underlyings`,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return u;
|
|
77
|
+
}
|
|
78
|
+
// ── parsing ──
|
|
79
|
+
export function parseDeriveInstrument(raw) {
|
|
80
|
+
const o = obj(raw, "instrument");
|
|
81
|
+
const name = str(o, "instrument_name", "instrument");
|
|
82
|
+
const what = `instrument ${name}`;
|
|
83
|
+
if (str(o, "instrument_type", what) !== "option")
|
|
84
|
+
throw deriveShapeError(`${what} is not an option`);
|
|
85
|
+
const d = obj(o.option_details, `${what}.option_details`);
|
|
86
|
+
const t = str(d, "option_type", `${what}.option_details`);
|
|
87
|
+
if (t !== "C" && t !== "P")
|
|
88
|
+
throw deriveShapeError(`${what}.option_details.option_type "${t}" is not C / P`);
|
|
89
|
+
const expiryMs = int(d, "expiry", `${what}.option_details`) * 1000;
|
|
90
|
+
const isActive = o.is_active;
|
|
91
|
+
if (typeof isActive !== "boolean")
|
|
92
|
+
throw deriveShapeError(`${what}.is_active is not a boolean`);
|
|
93
|
+
return {
|
|
94
|
+
name,
|
|
95
|
+
underlying: str(o, "base_currency", what),
|
|
96
|
+
quoteCurrency: str(o, "quote_currency", what),
|
|
97
|
+
kind: t === "C" ? "call" : "put",
|
|
98
|
+
strike: dec(d, "strike", `${what}.option_details`),
|
|
99
|
+
expiryMs,
|
|
100
|
+
expiry: utcDate(expiryMs),
|
|
101
|
+
isActive,
|
|
102
|
+
activationMs: int(o, "scheduled_activation", what) * 1000,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/** A ticker_slim snapshot (get_ticker / get_tickers value) of `inst` → OptionQuote. */
|
|
106
|
+
export function parseDeriveOptionTicker(raw, inst) {
|
|
107
|
+
const what = `ticker ${inst.name}`;
|
|
108
|
+
const t = obj(raw, what);
|
|
109
|
+
const bidPx = dec(t, "b", what), bidSz = dec(t, "B", what);
|
|
110
|
+
const askPx = dec(t, "a", what), askSz = dec(t, "A", what);
|
|
111
|
+
const bid = Number(bidPx) === 0 ? null : { price: bidPx, size: bidSz };
|
|
112
|
+
const ask = Number(askPx) === 0 ? null : { price: askPx, size: askSz };
|
|
113
|
+
const s = obj(t.stats, `${what}.stats`);
|
|
114
|
+
const trades = int(s, "n", `${what}.stats`);
|
|
115
|
+
const pr = t.option_pricing;
|
|
116
|
+
let p = null;
|
|
117
|
+
if (pr !== null && pr !== undefined)
|
|
118
|
+
p = obj(pr, `${what}.option_pricing`);
|
|
119
|
+
const pw = `${what}.option_pricing`;
|
|
120
|
+
return {
|
|
121
|
+
schema: OPTIONS_SCHEMA,
|
|
122
|
+
venue: VENUE,
|
|
123
|
+
instrument: inst.name,
|
|
124
|
+
underlying: inst.underlying,
|
|
125
|
+
quoteCurrency: inst.quoteCurrency,
|
|
126
|
+
kind: inst.kind,
|
|
127
|
+
strike: inst.strike,
|
|
128
|
+
expiry: inst.expiry,
|
|
129
|
+
expiryMs: inst.expiryMs,
|
|
130
|
+
bid,
|
|
131
|
+
ask,
|
|
132
|
+
mark: dec(t, "M", what),
|
|
133
|
+
index: dec(t, "I", what),
|
|
134
|
+
forward: p === null ? null : dec(p, "f", pw),
|
|
135
|
+
discountFactor: p === null ? null : dec(p, "df", pw),
|
|
136
|
+
iv: {
|
|
137
|
+
mark: p === null ? null : nonZero(dec(p, "i", pw)),
|
|
138
|
+
bid: p === null || bid === null ? null : nonZero(dec(p, "bi", pw)),
|
|
139
|
+
ask: p === null || ask === null ? null : nonZero(dec(p, "ai", pw)),
|
|
140
|
+
},
|
|
141
|
+
greeks: p === null ? null : {
|
|
142
|
+
delta: dec(p, "d", pw), gamma: dec(p, "g", pw), theta: dec(p, "t", pw), vega: dec(p, "v", pw), rho: dec(p, "r", pw),
|
|
143
|
+
},
|
|
144
|
+
openInterest: dec(s, "oi", `${what}.stats`),
|
|
145
|
+
stats24h: {
|
|
146
|
+
contracts: dec(s, "c", `${what}.stats`),
|
|
147
|
+
notional: dec(s, "v", `${what}.stats`),
|
|
148
|
+
premium: dec(s, "pr", `${what}.stats`),
|
|
149
|
+
trades,
|
|
150
|
+
high: trades === 0 ? null : dec(s, "h", `${what}.stats`),
|
|
151
|
+
low: trades === 0 ? null : dec(s, "l", `${what}.stats`),
|
|
152
|
+
},
|
|
153
|
+
timestampMs: int(t, "t", what),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
/** Distinct active expiries of `instruments`, soonest first. */
|
|
157
|
+
export function expiriesOf(instruments) {
|
|
158
|
+
const by = new Map();
|
|
159
|
+
for (const i of instruments) {
|
|
160
|
+
if (!i.isActive)
|
|
161
|
+
continue;
|
|
162
|
+
const e = by.get(i.expiryMs) ?? { strikes: new Set(), n: 0 };
|
|
163
|
+
e.strikes.add(i.strike);
|
|
164
|
+
e.n++;
|
|
165
|
+
by.set(i.expiryMs, e);
|
|
166
|
+
}
|
|
167
|
+
return [...by.entries()]
|
|
168
|
+
.sort((a, b) => a[0] - b[0])
|
|
169
|
+
.map(([ms, e]) => ({ expiry: utcDate(ms), expiryMs: ms, strikes: e.strikes.size, instruments: e.n }));
|
|
170
|
+
}
|
|
171
|
+
/** The `n` strikes closest to `price` (ties → lower strike), returned ascending. */
|
|
172
|
+
export function strikesAround(strikes, price, n) {
|
|
173
|
+
const p = Number(price);
|
|
174
|
+
const nearest = [...strikes].sort((a, b) => (Math.abs(Number(a) - p) - Math.abs(Number(b) - p)) || (Number(a) - Number(b)));
|
|
175
|
+
return nearest.slice(0, n).sort((a, b) => Number(a) - Number(b));
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Chain for one expiry from its instruments and the `get_tickers` map. Rows come from the listed
|
|
179
|
+
* instruments; a listed instrument without a ticker leaves its side null and is named in
|
|
180
|
+
* `missingTickers`. Index / forward are those of the newest ticker (largest `t`) — one ticker's values,
|
|
181
|
+
* not an average over the expiry.
|
|
182
|
+
*/
|
|
183
|
+
export function buildChain(underlying, expiry, selection, instruments, tickersRaw, strikesAroundAtm) {
|
|
184
|
+
const tickers = obj(tickersRaw, "get_tickers result.tickers");
|
|
185
|
+
const rowsByStrike = new Map();
|
|
186
|
+
const missingTickers = [];
|
|
187
|
+
let latest = null;
|
|
188
|
+
for (const inst of instruments) {
|
|
189
|
+
const row = rowsByStrike.get(inst.strike) ?? { strike: inst.strike, call: null, put: null };
|
|
190
|
+
rowsByStrike.set(inst.strike, row);
|
|
191
|
+
if (!(inst.name in tickers)) {
|
|
192
|
+
missingTickers.push(inst.name);
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
const q = parseDeriveOptionTicker(tickers[inst.name], inst);
|
|
196
|
+
row[inst.kind] = q;
|
|
197
|
+
if (latest === null || q.timestampMs > latest.timestampMs)
|
|
198
|
+
latest = q;
|
|
199
|
+
}
|
|
200
|
+
const strikes = [...rowsByStrike.keys()];
|
|
201
|
+
let atm = null;
|
|
202
|
+
if (latest !== null) {
|
|
203
|
+
const reference = latest.forward !== null ? "forward" : "index";
|
|
204
|
+
const price = latest.forward !== null ? latest.forward : latest.index;
|
|
205
|
+
atm = { strike: strikesAround(strikes, price, 1)[0], reference, price };
|
|
206
|
+
}
|
|
207
|
+
let keep = strikes;
|
|
208
|
+
if (strikesAroundAtm !== null) {
|
|
209
|
+
if (atm === null) {
|
|
210
|
+
throw new PerpError("EXCHANGE_ERROR", `Derive returned no ticker for ${underlying} ${expiry.expiry}; the ATM strike for --strikes is unknown`, {
|
|
211
|
+
exchange: VENUE, remediation: `Run without --strikes to see the listed strikes`,
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
keep = strikesAround(strikes, atm.price, strikesAroundAtm);
|
|
215
|
+
}
|
|
216
|
+
const rows = keep
|
|
217
|
+
.sort((a, b) => Number(a) - Number(b))
|
|
218
|
+
.map(k => rowsByStrike.get(k));
|
|
219
|
+
return {
|
|
220
|
+
schema: OPTIONS_SCHEMA,
|
|
221
|
+
venue: VENUE,
|
|
222
|
+
underlying,
|
|
223
|
+
expiry: expiry.expiry,
|
|
224
|
+
expiryMs: expiry.expiryMs,
|
|
225
|
+
expirySelection: selection,
|
|
226
|
+
index: latest === null ? null : latest.index,
|
|
227
|
+
forward: latest === null ? null : latest.forward,
|
|
228
|
+
atm,
|
|
229
|
+
strikesListed: strikes.length,
|
|
230
|
+
rows,
|
|
231
|
+
missingTickers: missingTickers.sort(),
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
// ── venue ──
|
|
235
|
+
function noOptions(underlying) {
|
|
236
|
+
return new PerpError("SYMBOL_NOT_FOUND", `Derive has no ${underlying} options`, {
|
|
237
|
+
exchange: VENUE, remediation: `List underlyings: perp -e ${VENUE} options underlyings`,
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
export class DeriveOptionsVenue {
|
|
241
|
+
client;
|
|
242
|
+
id = VENUE;
|
|
243
|
+
displayName = "Derive";
|
|
244
|
+
constructor(client) {
|
|
245
|
+
this.client = client;
|
|
246
|
+
}
|
|
247
|
+
static forNetwork(network) {
|
|
248
|
+
return new DeriveOptionsVenue(new DeriveClient(network));
|
|
249
|
+
}
|
|
250
|
+
async listUnderlyings() {
|
|
251
|
+
const raw = await this.client.call("get_all_currencies", {});
|
|
252
|
+
if (!Array.isArray(raw))
|
|
253
|
+
throw deriveShapeError("get_all_currencies result is not a list");
|
|
254
|
+
const underlyings = raw
|
|
255
|
+
.map((c, i) => obj(c, `currency #${i}`))
|
|
256
|
+
.filter(c => c.option !== null && c.option !== undefined)
|
|
257
|
+
.map(c => {
|
|
258
|
+
const what = `currency ${String(c.currency)}`;
|
|
259
|
+
return { underlying: str(c, "currency", what), spotPrice: c.spot_price === null ? null : dec(c, "spot_price", what) };
|
|
260
|
+
})
|
|
261
|
+
.sort((a, b) => a.underlying.localeCompare(b.underlying));
|
|
262
|
+
return { schema: OPTIONS_SCHEMA, venue: VENUE, underlyings };
|
|
263
|
+
}
|
|
264
|
+
/** Every non-expired option instrument of `underlying` (all pages). 12001 → SYMBOL_NOT_FOUND. */
|
|
265
|
+
async instruments(underlying) {
|
|
266
|
+
const out = [];
|
|
267
|
+
for (let page = 1, pages = 1; page <= pages; page++) {
|
|
268
|
+
let res;
|
|
269
|
+
try {
|
|
270
|
+
res = await this.client.call("get_all_instruments", {
|
|
271
|
+
instrument_type: "option", currency: underlying, expired: false, page_size: PAGE_SIZE, page,
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
catch (e) {
|
|
275
|
+
if (deriveRpcCode(e) === DERIVE_INSTRUMENT_NOT_FOUND)
|
|
276
|
+
throw noOptions(underlying);
|
|
277
|
+
throw e;
|
|
278
|
+
}
|
|
279
|
+
const r = obj(res, "get_all_instruments result");
|
|
280
|
+
if (!Array.isArray(r.instruments))
|
|
281
|
+
throw deriveShapeError("get_all_instruments result.instruments is not a list");
|
|
282
|
+
pages = int(obj(r.pagination, "get_all_instruments result.pagination"), "num_pages", "pagination");
|
|
283
|
+
for (const i of r.instruments)
|
|
284
|
+
out.push(parseDeriveInstrument(i));
|
|
285
|
+
}
|
|
286
|
+
return out;
|
|
287
|
+
}
|
|
288
|
+
async listExpiries(underlyingInput) {
|
|
289
|
+
const underlying = normalizeUnderlying(underlyingInput);
|
|
290
|
+
const expiries = expiriesOf(await this.instruments(underlying));
|
|
291
|
+
if (expiries.length === 0)
|
|
292
|
+
throw noOptions(underlying);
|
|
293
|
+
return { schema: OPTIONS_SCHEMA, venue: VENUE, underlying, expiries };
|
|
294
|
+
}
|
|
295
|
+
async getChain(q) {
|
|
296
|
+
const underlying = normalizeUnderlying(q.underlying);
|
|
297
|
+
const wanted = q.expiry === null ? null : normalizeExpiry(q.expiry);
|
|
298
|
+
if (q.strikesAroundAtm !== null && (!Number.isInteger(q.strikesAroundAtm) || q.strikesAroundAtm < 1)) {
|
|
299
|
+
throw new PerpError("INVALID_PARAMS", `--strikes must be a positive integer (got ${q.strikesAroundAtm})`, {
|
|
300
|
+
remediation: "Pass a positive integer, e.g. --strikes 10",
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
const all = await this.instruments(underlying);
|
|
304
|
+
const expiries = expiriesOf(all);
|
|
305
|
+
if (expiries.length === 0)
|
|
306
|
+
throw noOptions(underlying);
|
|
307
|
+
const expiry = wanted === null ? expiries[0] : expiries.find(e => e.expiry === wanted);
|
|
308
|
+
if (expiry === undefined) {
|
|
309
|
+
throw new PerpError("SYMBOL_NOT_FOUND", `Derive has no active ${underlying} option expiry ${wanted}`, {
|
|
310
|
+
exchange: VENUE,
|
|
311
|
+
remediation: `Active expiries: ${expiries.map(e => e.expiry).join(", ")} (perp -e ${VENUE} options expiries ${underlying})`,
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
const listed = all.filter(i => i.isActive && i.expiryMs === expiry.expiryMs);
|
|
315
|
+
const res = obj(await this.client.call("get_tickers", {
|
|
316
|
+
instrument_type: "option", currency: underlying, expiry_date: expiry.expiry.replace(/-/g, ""),
|
|
317
|
+
}), "get_tickers result");
|
|
318
|
+
return buildChain(underlying, expiry, wanted === null ? "nearest" : "requested", listed, res.tickers, q.strikesAroundAtm);
|
|
319
|
+
}
|
|
320
|
+
async getQuote(instrumentInput) {
|
|
321
|
+
const name = instrumentInput.trim().toUpperCase();
|
|
322
|
+
// Both reads are needed (instrument facts + live ticker); issued together, judged instrument first.
|
|
323
|
+
const [instR, tickR] = await Promise.allSettled([
|
|
324
|
+
this.client.call("get_instrument", { instrument_name: name }),
|
|
325
|
+
this.client.call("get_ticker", { instrument_name: name }),
|
|
326
|
+
]);
|
|
327
|
+
if (instR.status === "rejected") {
|
|
328
|
+
if (deriveRpcCode(instR.reason) === DERIVE_INSTRUMENT_NOT_FOUND) {
|
|
329
|
+
throw new PerpError("SYMBOL_NOT_FOUND", `Derive has no instrument ${name}`, {
|
|
330
|
+
exchange: VENUE, remediation: `Find option names: perp -e ${VENUE} options chain <UNDERLYING>`,
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
throw instR.reason;
|
|
334
|
+
}
|
|
335
|
+
const o = obj(instR.value, "get_instrument result");
|
|
336
|
+
if (o.instrument_type !== "option") {
|
|
337
|
+
throw new PerpError("INVALID_PARAMS", `${name} is a Derive ${String(o.instrument_type)}, not an option`, {
|
|
338
|
+
exchange: VENUE, remediation: `Find option names: perp -e ${VENUE} options chain <UNDERLYING>`,
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
const inst = parseDeriveInstrument(o);
|
|
342
|
+
if (!inst.isActive) {
|
|
343
|
+
throw new PerpError("SYMBOL_NOT_FOUND", `Derive option ${name} is listed but not active (activation ${new Date(inst.activationMs).toISOString()})`, {
|
|
344
|
+
exchange: VENUE, remediation: `Active expiries: perp -e ${VENUE} options expiries ${inst.underlying}`,
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
if (tickR.status === "rejected") {
|
|
348
|
+
// An active instrument with no ticker (-32602 "Ticker not found for instrument", live): an
|
|
349
|
+
// activation / expiry race on Derive's side — transient, never the user's INVALID_PARAMS.
|
|
350
|
+
if (deriveRpcCode(tickR.reason) === DERIVE_INVALID_PARAMS) {
|
|
351
|
+
throw new PerpError("EXCHANGE_ERROR", `Derive has no live ticker for active option ${name} (${tickR.reason instanceof Error ? tickR.reason.message : String(tickR.reason)})`, {
|
|
352
|
+
exchange: VENUE, rpcCode: DERIVE_INVALID_PARAMS,
|
|
353
|
+
remediation: `The option may be activating or expiring right now; retry in a moment, or list live instruments: perp -e ${VENUE} options chain ${inst.underlying} --expiry ${inst.expiry}`,
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
throw tickR.reason;
|
|
357
|
+
}
|
|
358
|
+
return parseDeriveOptionTicker(tickR.value, inst);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extended public-only adapter — official API, MARKET DATA ONLY in this version (venues/extended.ts).
|
|
3
|
+
*
|
|
4
|
+
* Market data (markets, orderbook, trades, funding history, candles) is implemented with the
|
|
5
|
+
* documented public endpoints (https://api.docs.extended.exchange/ "Public REST-API"). Every
|
|
6
|
+
* account / trading method refuses with CAPABILITY_UNSUPPORTED before any request — there is no
|
|
7
|
+
* Extended account, order or signing code.
|
|
8
|
+
*
|
|
9
|
+
* A symbol is resolved first (resolveExtendedMarketRemote: `?market=<name>` reads, the full listing
|
|
10
|
+
* only when no wire-name candidate matches), so an unlisted symbol is SYMBOL_NOT_FOUND before any
|
|
11
|
+
* per-market request (the orderbook of an unknown market answers `{"status":"OK"}` without data,
|
|
12
|
+
* its trades `[]` — live 2026-10-19).
|
|
13
|
+
*/
|
|
14
|
+
import type { ExchangeAdapter, ExchangeBalance, ExchangeFundingPayment, ExchangeKline, ExchangeMarketInfo, ExchangeOrder, ExchangePosition, ExchangeTrade, ExchangePublicTrade } from "../interface.js";
|
|
15
|
+
import { type VenueDefinition } from "../venue.js";
|
|
16
|
+
import { type AssetClass, type Network } from "../venue-types.js";
|
|
17
|
+
/** CLI candle interval → Extended ISO-8601 duration (docs "Get candles history" / candles stream). */
|
|
18
|
+
export declare const EXTENDED_KLINE_INTERVALS: Readonly<Record<string, {
|
|
19
|
+
wire: string;
|
|
20
|
+
ms: number;
|
|
21
|
+
}>>;
|
|
22
|
+
/** Documented per-request maximum of the candles and funding-history endpoints. */
|
|
23
|
+
export declare const EXTENDED_MAX_RECORDS = 10000;
|
|
24
|
+
/** Legacy market row plus the Extended fields shown in JSON (asset class, precision, schedule). */
|
|
25
|
+
export type ExtendedMarketInfo = ExchangeMarketInfo & {
|
|
26
|
+
venueSymbol: string;
|
|
27
|
+
canonical: string | null;
|
|
28
|
+
assetClass: AssetClass;
|
|
29
|
+
tickSize: string;
|
|
30
|
+
minSize: string;
|
|
31
|
+
tradable: boolean;
|
|
32
|
+
status: "ACTIVE" | "REDUCE_ONLY";
|
|
33
|
+
isRfq: boolean;
|
|
34
|
+
tradingHours: string;
|
|
35
|
+
isOffHours: boolean;
|
|
36
|
+
/** `fundingRate` is the current hour's accruing rate (fraction per hour), applied at nextFundingTime. */
|
|
37
|
+
fundingRateKind: "accruing";
|
|
38
|
+
nextFundingTime: number | null;
|
|
39
|
+
};
|
|
40
|
+
/** One applied hourly funding print (fraction per hour) with its normalization. */
|
|
41
|
+
export interface ExtendedFundingPrint {
|
|
42
|
+
time: number;
|
|
43
|
+
rate: string;
|
|
44
|
+
price: null;
|
|
45
|
+
rateKind: "lastSettled";
|
|
46
|
+
intervalHours: 1;
|
|
47
|
+
/** rate × 24 × 365 × 100 (APR %, simple). */
|
|
48
|
+
annualizedPct: number;
|
|
49
|
+
}
|
|
50
|
+
export declare class ExtendedPublicAdapter implements ExchangeAdapter {
|
|
51
|
+
readonly venue: VenueDefinition;
|
|
52
|
+
readonly network: Network;
|
|
53
|
+
readonly name: "extended";
|
|
54
|
+
readonly aliases: readonly ["ext", "x10"];
|
|
55
|
+
private readonly client;
|
|
56
|
+
constructor(venue: VenueDefinition, network: Network);
|
|
57
|
+
/** Per-market reads resolve the symbol with the small `?market=` read (public.ts), not the full listing. */
|
|
58
|
+
private market;
|
|
59
|
+
getMarkets(): Promise<ExtendedMarketInfo[]>;
|
|
60
|
+
getOrderbook(symbol: string): Promise<{
|
|
61
|
+
bids: [string, string][];
|
|
62
|
+
asks: [string, string][];
|
|
63
|
+
}>;
|
|
64
|
+
getRecentTrades(symbol: string, limit?: number): Promise<ExchangePublicTrade[]>;
|
|
65
|
+
/** Applied (settled) hourly rates, newest first — fraction per hour; no oracle price published. */
|
|
66
|
+
getFundingHistory(symbol: string, limit?: number): Promise<ExtendedFundingPrint[]>;
|
|
67
|
+
getKlines(symbol: string, interval: string, startTime: number, endTime: number): Promise<ExchangeKline[]>;
|
|
68
|
+
private refuse;
|
|
69
|
+
getBalance(): Promise<ExchangeBalance>;
|
|
70
|
+
getPositions(): Promise<ExchangePosition[]>;
|
|
71
|
+
getOpenOrders(): Promise<ExchangeOrder[]>;
|
|
72
|
+
getOrderHistory(): Promise<ExchangeOrder[]>;
|
|
73
|
+
getTradeHistory(): Promise<ExchangeTrade[]>;
|
|
74
|
+
getFundingPayments(): Promise<ExchangeFundingPayment[]>;
|
|
75
|
+
marketOrder(): Promise<unknown>;
|
|
76
|
+
limitOrder(): Promise<unknown>;
|
|
77
|
+
editOrder(): Promise<unknown>;
|
|
78
|
+
cancelOrder(): Promise<unknown>;
|
|
79
|
+
cancelAllOrders(): Promise<unknown>;
|
|
80
|
+
setLeverage(): Promise<unknown>;
|
|
81
|
+
stopOrder(): Promise<unknown>;
|
|
82
|
+
}
|