TypeScript SDK
Клиент, стрим, поиск терминала и ошибки пакета @spectre-trade/terminal.
Установка
npm install @spectre-trade/terminalTerminal
Клиент одного запущенного терминала.
Создайте его с токеном или дайте Terminal.discover найти порт
и токен и проверить версию API. Все методы async и
бросают ApiError на ответ не 2xx и
TerminalUnreachableError, когда ответа нет.
| Поле | Тип | Описание |
|---|---|---|
host | string | |
port | number | |
timeoutMs | number | |
baseUrl | string | http://127.0.0.1:48180/v1/ — токен в него не входит. |
Terminal()
new Terminal(options: TerminalOptions)discover()
static discover(options: DiscoverOptions = {}): Promise<Terminal>Найти терминал и проверить его: токен из options.token или
SPECTRE_LOCAL_API_TOKEN (иначе TokenMissingError), порт из
options.port или instance.json (иначе 48180; LocalApiDisabledError,
если файл говорит, что API выключен), затем один GET /v1/meta.
api_version, отличный от "1", — это IncompatibleTerminalError;
ответ unauthorized — это ApiError, чьё сообщение говорит, что токен
мог устареть или API выключен.
| Опции | Тип | Описание |
|---|---|---|
tokenнеобязательный | string | Имеет приоритет над SPECTRE_LOCAL_API_TOKEN. |
portнеобязательный | number | Имеет приоритет над instance.json. |
hostнеобязательный | string | |
timeoutMsнеобязательный | number | |
instancePathнеобязательный | string | Читать этот файл вместо пути к instance.json, зависящего от ОС (для тестов). |
meta()
meta(): Promise<Meta>GET /v1/meta: версия API, сборка, права токена, лимиты, топики стрима.
Операция HTTP: GET /v1/meta
health()
health(): Promise<Health>GET /v1/health.
Операция HTTP: GET /v1/health
connections()
connections(): Promise<List<Connection>>GET /v1/connections (connections:read).
Операция HTTP: GET /v1/connections
connection()
connection(id: number): Promise<Connection>GET /v1/connections/{id} (connections:read); not_found для неизвестного id.
Операция HTTP: GET /v1/connections/{id}
instruments()
instruments(options: InstrumentsOptions): Promise<InstrumentsPage>GET /v1/instruments (market:read): одна страница справочника
биржи и рынка, по connectionId или exchange + market. Листайте
по next_cursor сами или используйте iterInstruments.
Операция HTTP: GET /v1/instruments
| Опции | Тип | Описание |
|---|---|---|
connectionIdнеобязательный | number | |
exchangeнеобязательный | string | |
marketнеобязательный | string | |
qнеобязательный | string | Подстрока символа или базовой монеты, без учёта регистра. |
limitнеобязательный | number | 1–2000, по умолчанию 500. |
cursorнеобязательный | string | next_cursor предыдущей страницы. |
iterInstruments()
iterInstruments(options: InstrumentsOptions): AsyncGenerator<Instrument, void, undefined>Все инструменты, подходящие под параметры, страница за страницей.
| Опции | Тип | Описание |
|---|---|---|
connectionIdнеобязательный | number | |
exchangeнеобязательный | string | |
marketнеобязательный | string | |
qнеобязательный | string | Подстрока символа или базовой монеты, без учёта регистра. |
limitнеобязательный | number | 1–2000, по умолчанию 500. |
cursorнеобязательный | string | next_cursor предыдущей страницы. |
intervals()
intervals(): Promise<Intervals>GET /v1/market/intervals (market:read): интервалы свечей и кластеров.
Операция HTTP: GET /v1/market/intervals
candles()
candles(instrument: InstrumentAddress, options: CandlesOptions): Promise<Candles>GET /v1/market/candles (market:read): история свечей, от старых к новым.
Операция HTTP: GET /v1/market/candles
| Опции | Тип | Описание |
|---|---|---|
interval | string | Код из /v1/market/intervals: 1m, 5m, … |
limitнеобязательный | number | До 2000, по умолчанию 500. |
endнеобязательный | number | Правая граница, миллисекунды UTC; по умолчанию — сейчас. |
connectionIdнеобязательный | number |
trades()
trades(instrument: InstrumentAddress, options: TradesOptions = {}): Promise<Trades>GET /v1/market/trades (market:read): последние сделки пары,
от старых к новым. Пара без подписки открывается по запросу, и
вызов может занять до 3 с.
Операция HTTP: GET /v1/market/trades
| Опции | Тип | Описание |
|---|---|---|
limitнеобязательный | number | 1–1000 последних, по умолчанию 100. |
sinceTsнеобязательный | number | Не раньше этого времени получения, миллисекунды UTC. |
connectionIdнеобязательный | number |
snapshot()
snapshot(instrument: InstrumentAddress, options: ConnectionOptions = {}): Promise<Snapshot>GET /v1/market/snapshot (market:read): лучшие bid/ask, последняя сделка, mark, тикер.
Операция HTTP: GET /v1/market/snapshot
| Опции | Тип | Описание |
|---|---|---|
connectionIdнеобязательный | number |
orderbook()
orderbook(instrument: InstrumentAddress, options: OrderbookOptions = {}): Promise<Orderbook>GET /v1/market/orderbook (market:read); unavailable, если полный стакан не пришёл за 3 с.
Операция HTTP: GET /v1/market/orderbook
| Опции | Тип | Описание |
|---|---|---|
depthнеобязательный | number | 1–200, по умолчанию 50. |
connectionIdнеобязательный | number |
clusters()
clusters(instrument: InstrumentAddress, options: ConnectionOptions = {}): Promise<Clusters>GET /v1/market/clusters (market:read): до десяти бакетов с
интервалом, выбранным в терминале. Первый вызов для инструмента, не
открытого в окне, может ответить not_active (409); повтор через
несколько секунд кластеры находит.
Операция HTTP: GET /v1/market/clusters
| Опции | Тип | Описание |
|---|---|---|
connectionIdнеобязательный | number |
accountOrders()
accountOrders(connectionId: number): Promise<AccountOrders>GET /v1/account/orders (account:read): открытые заявки и триггерные
заявки одного подключения, тот же срез, что видит окно терминала.
not_found для неизвестного подключения.
Операция HTTP: GET /v1/account/orders
accountPositions()
accountPositions(connectionId: number): Promise<AccountPositions>GET /v1/account/positions (account:read): открытые позиции одного подключения.
Операция HTTP: GET /v1/account/positions
accountBalances()
accountBalances(connectionId: number): Promise<AccountBalances>GET /v1/account/balances (account:read): по каждой валюте последнее
значение, которое биржа прислала с момента включения API. Валюты, с
которой с тех пор ничего не происходило, в ответе нет.
Операция HTTP: GET /v1/account/balances
accountFills()
accountFills(connectionId: number, options: AccountFillsOptions = {}): Promise<AccountFills>GET /v1/account/fills (account:read): исполнения подключения с
момента включения API (последняя тысяча), от старых к новым.
Операция HTTP: GET /v1/account/fills
| Опции | Тип | Описание |
|---|---|---|
limitнеобязательный | number | 1–1000 последних, по умолчанию 100. |
sinceTsнеобязательный | number | Не раньше этого времени биржи, миллисекунды UTC. |
placeOrder()
placeOrder(options: PlaceOrderOptions): Promise<Accepted>POST /v1/orders (trading:write): поставить лимитную или рыночную
заявку той же командой, что использует окно. Ответ значит «принято
терминалом», а не биржей: следите за account.orders в стриме или за
accountOrders — заявка там под ключом key. not_tradable (409)
для выключенного подключения, подключения только для чтения или без
учётных данных, invalid_request (400) для чужого инструмента или
отклонённых размера или цены, rate_limited (429) выше
limits.commands_per_second.
Операция HTTP: POST /v1/orders
| Опции | Тип | Описание |
|---|---|---|
connectionId | number | Торговое подключение; умолчания нет. |
instrument | InstrumentAddress | |
side | Side | |
type | OrderType | limit требует price, market его не принимает. |
priceнеобязательный | Decimal | |
sizeнеобязательный | Decimal | Количество в базовой монете; ровно одно из size и notional. |
notionalнеобязательный | Decimal | Сумма в валюте котировки; ровно одно из size и notional. |
reduceOnlyнеобязательный | boolean | По умолчанию false. |
postOnlyнеобязательный | boolean | По умолчанию false. |
timeInForceнеобязательный | TimeInForce | Отсутствует — умолчание площадки. |
clientKeyнеобязательный | string | Ключ идемпотентности: повтор с тем же ключом возвращает прежний ответ и не дублирует заявку (терминал помнит последнюю тысячу). |
cancelOrder()
cancelOrder(options: CancelOrderOptions): Promise<Accepted>DELETE /v1/orders/{id} (trading:write): снять одну заявку по ключу
терминала (t-…) или биржевому id. Снятие уходит на биржу напрямую;
подтверждение приходит через стрим.
Операция HTTP: DELETE /v1/orders/{id}
| Опции | Тип | Описание |
|---|---|---|
connectionId | number | |
instrument | InstrumentAddress | |
orderId | string | Ключ терминала (t-…) или биржевой id заявки. |
cancelAll()
cancelAll(options: InstrumentCommandOptions): Promise<Accepted>POST /v1/orders/cancel-all (trading:write): снять все заявки инструмента, как это делает пробел.
Операция HTTP: POST /v1/orders/cancel-all
| Опции | Тип | Описание |
|---|---|---|
connectionId | number | |
instrument | InstrumentAddress |
closePosition()
closePosition(options: InstrumentCommandOptions): Promise<Accepted>POST /v1/positions/close (trading:write): закрыть позицию по
инструменту так, как это делает окно, — рыночной заявкой на размер
позиции на фьючерсах, одной атомарной командой «снять всё и закрыть»
на споте. invalid_request без открытой позиции.
Операция HTTP: POST /v1/positions/close
| Опции | Тип | Описание |
|---|---|---|
connectionId | number | |
instrument | InstrumentAddress |
placeTrigger()
placeTrigger(options: PlaceTriggerOptions): Promise<Accepted>POST /v1/orders/trigger (trading:write): стоп-лосс, тейк-профит или
стоп, поставленные теми же сервисами, что использует окно. stop_loss и
take_profit ставятся на открытую позицию (сторона, размер и правило
берутся из неё; invalid_request без позиции); для stop нужны side и
notional. key в ответе — ключ триггера (sl_…, tp_…,
stop_…), который виден как client_id триггера в
accountOrders; снятие и правка используют числовой id
оттуда. unsupported (501) на площадке без триггерных заявок в терминале.
Операция HTTP: POST /v1/orders/trigger
| Опции | Тип | Описание |
|---|---|---|
connectionId | number | |
instrument | InstrumentAddress | |
kind | TriggerType | stop_loss и take_profit ставятся на открытую позицию; stop — самостоятельная заявка. |
triggerPrice | Decimal | |
sideнеобязательный | Side | Только для stop. |
notionalнеобязательный | Decimal | Только для stop: сумма в валюте котировки. |
ruleнеобязательный | TriggerRule | Только для stop; без него — выше рынка для покупки, ниже для продажи. |
clientKeyнеобязательный | string | Ключ идемпотентности, как у Terminal.placeOrder. |
cancelTrigger()
cancelTrigger(options: CancelTriggerOptions): Promise<Accepted>DELETE /v1/orders/trigger/{id} (trading:write): снять один триггер по его числовому id.
Операция HTTP: DELETE /v1/orders/trigger/{id}
| Опции | Тип | Описание |
|---|---|---|
connectionId | number | |
instrument | InstrumentAddress | |
triggerId | string | number | Числовой id триггера из accountOrders().triggers. |
cancelAllTriggers()
cancelAllTriggers(options: InstrumentCommandOptions): Promise<Accepted>POST /v1/orders/trigger/cancel-all (trading:write): снять все триггеры инструмента; обычные заявки остаются.
Операция HTTP: POST /v1/orders/trigger/cancel-all
| Опции | Тип | Описание |
|---|---|---|
connectionId | number | |
instrument | InstrumentAddress |
amendTrigger()
amendTrigger(options: AmendTriggerOptions): Promise<Accepted>PATCH /v1/orders/trigger/{id} (trading:write): перенести триггер на
новую цену — последовательная замена, как в окне: снять, затем поставить.
kind обязателен; для stop нужен ещё и его side. key равен null.
Операция HTTP: PATCH /v1/orders/trigger/{id}
| Опции | Тип | Описание |
|---|---|---|
connectionId | number | |
instrument | InstrumentAddress | |
triggerId | string | number | Числовой id триггера из accountOrders().triggers. |
kind | TriggerType | |
triggerPrice | Decimal | |
sideнеобязательный | Side | Только для stop. |
ruleнеобязательный | TriggerRule | Только для stop. |
leverage()
leverage(options: InstrumentCommandOptions): Promise<Leverage>GET /v1/account/leverage (account:read): плечо и режим маржи
фьючерсного инструмента из кэша терминала. Инструмент, которого
терминал ещё не касался, — not_active (409): откройте его в окне
или вызовите setLeverage — так он попадает в кэш.
Операция HTTP: GET /v1/account/leverage
| Опции | Тип | Описание |
|---|---|---|
connectionId | number | |
instrument | InstrumentAddress |
setLeverage()
setLeverage(options: SetLeverageOptions): Promise<Accepted>POST /v1/account/leverage (trading:write): задать плечо так, как
это делает окно, — ровно одно из leverage (целое ≥ 1) и mode
(max, smart). Применённое значение видно в leverage после
ответа биржи.
Операция HTTP: POST /v1/account/leverage
| Опции | Тип | Описание |
|---|---|---|
connectionId | number | |
instrument | InstrumentAddress | |
leverageнеобязательный | number | Целое число не меньше 1. |
modeнеобязательный | "max" | "smart" |
setMarginMode()
setMarginMode(options: SetMarginModeOptions): Promise<Accepted>POST /v1/account/margin-mode (trading:write): cross или isolated.
Смену при открытой позиции биржа отклоняет, как и в окне; ответ
accepted этого ещё не знает.
Операция HTTP: POST /v1/account/margin-mode
| Опции | Тип | Описание |
|---|---|---|
connectionId | number | |
instrument | InstrumentAddress | |
marginMode | MarginMode |
workspace()
workspace(): Promise<Workspace>GET /v1/workspace (workspace:read): все окна с их вкладками,
стеками и графиками из снимка, который окно публикует при каждом
изменении структуры. Идентификаторы внутренние для этого запуска терминала.
Операция HTTP: GET /v1/workspace
workspaceWindow()
workspaceWindow(options: WindowOptions): Promise<WorkspaceWindow>GET /v1/workspace/windows/{id} (workspace:read): одно окно; неизвестный id — not_found.
Операция HTTP: GET /v1/workspace/windows/{id}
| Опции | Тип | Описание |
|---|---|---|
windowId | number |
openStack()
openStack(options: OpenStackOptions): Promise<WorkspaceOutcome>POST /v1/workspace/stacks (workspace:write): стек инструмента в
новой вкладке или новом окне, с графиком над ним, если задан chart.
Ответ называет окно, вкладку и новые виджеты. Инструмент, которого
справочник терминала не знает, — invalid_request.
Операция HTTP: POST /v1/workspace/stacks
| Опции | Тип | Описание |
|---|---|---|
instrument | InstrumentAddress | |
connectionIdнеобязательный | number | Без него выбирается по общему правилу. |
chartнеобязательный | boolean | График того же инструмента над стеком. |
targetнеобязательный | OpenTarget | new_tab (по умолчанию) или new_window. |
windowIdнеобязательный | number | Окно для новой вкладки; без него — окно в фокусе. |
activateнеобязательный | boolean | false открывает вкладку в фоне; новое окно всегда получает фокус. |
openTab()
openTab(options: OpenTabOptions): Promise<WorkspaceOutcome>POST /v1/workspace/tabs (workspace:write): вкладка с колонкой на
элемент — стек и, с chart, график над ним — в новой вкладке или новом
окне. Без name имя — единственный инструмент или первый плюс число
остальных. Отказ называет элемент (items[1]: …), и до окна не доходит
ничего.
Операция HTTP: POST /v1/workspace/tabs
| Опции | Тип | Описание |
|---|---|---|
items | Array<TabItemOptions | InstrumentAddress> | Колонки по порядку, от одной до пятидесяти; голый адрес — стек без графика. |
nameнеобязательный | string | До 64 символов; без него терминал называет вкладку по инструментам. |
targetнеобязательный | OpenTarget | new_tab (по умолчанию) или new_window. |
windowIdнеобязательный | number | Окно для новой вкладки; без него — окно в фокусе. |
activateнеобязательный | boolean | false открывает вкладку в фоне; новое окно всегда получает фокус. |
addStacks()
addStacks(options: AddStacksOptions): Promise<WorkspaceOutcome>POST /v1/workspace/windows/{id}/tabs/{tab}/stacks (workspace:write):
те же колонки после последней колонки вкладки; вкладка сохраняет имя и
ширины колонок. Ответ перечисляет только добавленные виджеты.
Операция HTTP: POST /v1/workspace/windows/{id}/tabs/{tab}/stacks
| Опции | Тип | Описание |
|---|---|---|
windowId | number | |
tabId | number | |
items | Array<TabItemOptions | InstrumentAddress> | Колонки по порядку, от одной до пятидесяти; голый адрес — стек без графика. |
openMultiview()
openMultiview(options: OpenMultiviewOptions): Promise<WorkspaceOutcome>POST /v1/workspace/multiview (workspace:write): монета на каждой
площадке из «Раскладки бирж», тот же план, что у кнопки «Мультивью» в
окне. Нет ни одной ячейки для монеты — not_found.
Операция HTTP: POST /v1/workspace/multiview
| Опции | Тип | Описание |
|---|---|---|
base | string | Монета (BTC) или пара (BTC/USDT). |
targetнеобязательный | OpenTarget | Без него решает настройка мультивью «Открывать». |
windowIdнеобязательный | number | |
activateнеобязательный | boolean |
setStackInstrument()
setStackInstrument(options: StackInstrumentOptions): Promise<WorkspaceOutcome>PATCH /v1/workspace/stacks/{widget_id} (workspace:write): другой инструмент в стеке и его графиках.
Операция HTTP: PATCH /v1/workspace/stacks/{widget_id}
| Опции | Тип | Описание |
|---|---|---|
widgetId | number | |
instrument | InstrumentAddress | |
connectionIdнеобязательный | number |
closeStack()
closeStack(options: StackOptions): Promise<WorkspaceOutcome>DELETE /v1/workspace/stacks/{widget_id} (workspace:write): закрыть один стек, как это делает его кнопка закрытия.
Операция HTTP: DELETE /v1/workspace/stacks/{widget_id}
| Опции | Тип | Описание |
|---|---|---|
widgetId | number |
closeTab()
closeTab(options: TabOptions): Promise<WorkspaceOutcome>DELETE /v1/workspace/windows/{id}/tabs/{tab} (workspace:write): единственная вкладка окна — invalid_request.
Операция HTTP: DELETE /v1/workspace/windows/{id}/tabs/{tab}
| Опции | Тип | Описание |
|---|---|---|
windowId | number | |
tabId | number |
activateTab()
activateTab(options: TabOptions): Promise<WorkspaceOutcome>POST /v1/workspace/windows/{id}/tabs/{tab}/activate (workspace:write): выбрать вкладку; фокус окна не трогается.
Операция HTTP: POST /v1/workspace/windows/{id}/tabs/{tab}/activate
| Опции | Тип | Описание |
|---|---|---|
windowId | number | |
tabId | number |
closeWindow()
closeWindow(options: WindowOptions): Promise<WorkspaceOutcome>DELETE /v1/workspace/windows/{id} (workspace:write): главное окно — invalid_request.
Операция HTTP: DELETE /v1/workspace/windows/{id}
| Опции | Тип | Описание |
|---|---|---|
windowId | number |
activateWindow()
activateWindow(options: WindowOptions): Promise<WorkspaceOutcome>POST /v1/workspace/windows/{id}/activate (workspace:write): развернуть, если свёрнуто, и вывести на передний план.
Операция HTTP: POST /v1/workspace/windows/{id}/activate
| Опции | Тип | Описание |
|---|---|---|
windowId | number |
settings()
settings(options: SettingsOptions = {}): Promise<Settings>GET /v1/settings (settings:read): строки, как они хранятся, без
лестницы умолчаний. Без параметров: глобальные строки без подключения.
Каждая строка говорит, пишется ли она (writable) через updateSettings.
Операция HTTP: GET /v1/settings
| Опции | Тип | Описание |
|---|---|---|
scopeнеобязательный | "global" | "order_book" | global (по умолчанию) или order_book. |
categoryнеобязательный | string | |
keyнеобязательный | string | |
connectionIdнеобязательный | number | Строки подключения; без него — строки без подключения. |
instrumentнеобязательный | InstrumentAddress | Строки пары (область order_book). |
orderbookSettings()
orderbookSettings(options: InstrumentCommandOptions): Promise<OrderbookSettings>GET /v1/settings/orderbook (settings:read): настройки стека
инструмента, как их видит его стек на подключении, — строка пары,
умолчание подключения, строка пары без подключения, глобальное
умолчание — с resolved_from у каждого ключа.
Операция HTTP: GET /v1/settings/orderbook
| Опции | Тип | Описание |
|---|---|---|
connectionId | number | |
instrument | InstrumentAddress |
updateSettings()
updateSettings(changes: SettingChange[]): Promise<SettingsApplied>PATCH /v1/settings (settings:write): записать настройки так, как это
делает Settings App. Каждое изменение сначала проверяется по словарю
терминала (invalid_request с указанием changes[i], ничего не
записано; плечо здесь unsupported — используйте setLeverage), затем
они применяются по порядку: та же строка, событие окну и кэши сервисов,
что у Settings App. Первое неудавшееся изменение отклоняет вызов;
предыдущие остаются применёнными.
Операция HTTP: PATCH /v1/settings
stream()
stream(options: StreamOptions = {}): Promise<Stream>Открыть /v1/stream. Только в Node: токен передаётся в заголовке рукопожатия.
| Опции | Тип | Описание |
|---|---|---|
timeoutMsнеобязательный | number | Таймаут рукопожатия; по умолчанию — timeoutMs клиента. |
StreamProtocol
Половина протокола стрима без сокета: выдаёт идентификаторы запросов,
держит запросы, ждущие ответа, разрешает их по кадрам subscribed /
unsubscribed / error и превращает всё остальное в кадры, по
которым итерируется потребитель. Чистая, поэтому тестируется без сервера.
nextRequestId()
nextRequestId(): stringНовый request_id, уникальный в пределах этого стрима.
expect()
expect(requestId: string): Promise<ReplyFrame>Зарегистрировать запрос и получить промис, который разрешит его ответ.
pendingCount
pendingCount: numberЗапросы, всё ещё ждущие ответа.
route()
route(raw: unknown): StreamFrame | undefinedКлассифицировать декодированный кадр. Ответы на наши запросы разрешают
соответствующий промис и возвращают undefined; event, gap и ошибки
подписок возвращаются потребителю; всё неизвестное или искажённое отбрасывается.
abortAll()
abortAll(error: Error): voidОтклонить все ждущие запросы, например при закрытии сокета.
Stream
class Stream extends AsyncIterable<StreamFrame>Живое соединение /v1/stream.
Получите его через terminal.stream(). Подпишитесь через subscribe, затем
итерируйтесь: for await (const frame of stream) отдаёт события, пропуски и
ошибки подписок в порядке прихода, буферизуя их без ограничения, пока
потребитель занят (сервер защищает себя сам: клиент, отстающий дольше
5 с, закрывается с 4008). Итерируется один потребитель за раз; второй
одновременный next() просто ждёт своей очереди.
Когда соединение закрывает сервер, итерация заканчивается; для 1001, 4008,
4029 и потерянного соединения (1006) она заканчивается исключением
StreamClosedError. closeCode и closeReason заполняются
в любом случае. Закрытие со стороны клиента (close или break из
цикла) завершает итерацию штатно.
connect()
static connect(options: StreamConnectOptions): Promise<Stream>Открыть WebSocket и пройти рукопожатие. Отклоняется с
TerminalUnreachableError, когда терминал его не принимает:
WebSocket в Node сообщает об отклонённом рукопожатии (терминал не запущен,
API выключен, токен отклонён) одной общей ошибкой, поэтому три случая не различаются.
| Опции | Тип | Описание |
|---|---|---|
url | string | ws://127.0.0.1:48180/v1/stream. |
token | string | |
timeoutMsнеобязательный | number | Таймаут рукопожатия; по умолчанию 10 000. |
url
url: stringURL стрима (токена в нём нет никогда).
closed
closed: booleantrue, как только сокет закрыт, кем бы он ни был закрыт.
closeCode
closeCode: number | undefinedКод закрытия WebSocket, после закрытия.
closeReason
closeReason: string | undefinedПричина закрытия WebSocket, после закрытия.
subscribe()
subscribe(options: SubscribeOptions): Promise<Subscribed>Подписаться на топик инструмента или на топик счёта подключения.
Разрешается кадром subscribed сервера (плюс запрошенный topic и, для
рыночных топиков, instrument) и отклоняется с StreamRequestError на
ответ error сервера; события других подписок тем временем идут дальше.
Помните о лимите терминала на новые подписки на биржах в секунду
(/v1/meta); топики счёта биржу не трогают и кадра-снимка не шлют —
сначала прочитайте текущее состояние операциями /v1/account/*.
| Опции | Тип | Описание |
|---|---|---|
topic | Topic | |
instrumentнеобязательный | InstrumentAddress | Обязателен для рыночных топиков; игнорируется для account.*. |
connectionIdнеобязательный | number | Обязателен для account.*; для рыночных топиков без него выбирается по общему правилу. |
paramsнеобязательный | BookTopParams | Читает их только book.top; имена как на проводе (depth, interval_ms). |
unsubscribe()
unsubscribe(subscription: Subscribed | SubscribedFrame | string): Promise<void>Снять подписку сразу. Принимает значение, которым разрешился subscribe,
или голый id sub. Разрешается на unsubscribed сервера.
close()
close(code: number = CLOSE_NORMAL, reason?: string): Promise<void>Закрыть стрим. Сервер завершает рукопожатие закрытия кодом клиента; промис разрешается, когда это произошло, или после короткой паузы, если этого так и не случилось. Повторный вызов безопасен.
Поиск терминала
| Константы | Значение | Описание |
|---|---|---|
DEFAULT_PORT | 48180 | Порт, который слушает терминал, если его не переопределяет SPECTRE_LOCAL_API_PORT. |
TOKEN_ENV | "SPECTRE_LOCAL_API_TOKEN" | Переменная окружения, из которой читается токен. |
instancePath()
function instancePath(options: DiscoveryEnvironment = {}): stringПуть к instance.json терминала по ОС:
- Linux:
$XDG_DATA_HOME/spectre-terminal/instance.json, иначе~/.local/share/spectre-terminal/instance.json; - macOS:
~/Library/Application Support/spectre-terminal/instance.json; - Windows:
%LOCALAPPDATA%\spectre-terminal\instance.json, иначе%USERPROFILE%\AppData\Local\....
Это повторяет собственный каталог данных терминала (dirs::data_local_dir).
readPort()
function readPort(options: ReadPortOptions = {}): Promise<number | undefined>Порт Local API, опубликованный в instance.json.
Разрешается в undefined, когда файла нет или он нечитаем (терминал не
запущен, или терминал не публикует это поле): вызывающий откатывается
на DEFAULT_PORT. Бросает LocalApiDisabledError, когда файл есть,
но local_api_port равен null или отсутствует — терминал запущен,
а API выключен. Читает только это одно поле.
tokenFromEnv()
function tokenFromEnv(env: Record<string, string | undefined> = process.env): string | undefinedТокен из SPECTRE_LOCAL_API_TOKEN или undefined, если переменная не задана или пуста.
Ошибки
SpectreTerminalError
class SpectreTerminalError extends ErrorБазовый класс всех ошибок, которые бросает этот пакет.
ApiError
class ApiError extends SpectreTerminalErrorТерминал ответил статусом не 2xx.
code — стабильный код из конверта ошибки контракта
(unauthorized, not_found, rate_limited, …); status — HTTP-статус.
Тело не 2xx, которое не является конвертом, даёт код "unknown".
| Поле | Тип | Описание |
|---|---|---|
code | string | Стабильный код ошибки из контракта или "unknown". |
status | number | HTTP-статус ответа. |
detail | string | Сообщение сервера для человека, без префикса. |
TerminalUnreachableError
class TerminalUnreachableError extends SpectreTerminalErrorHTTP-ответа нет вовсе: соединение отклонено, запрос истёк по таймауту,
неожиданный редирект или рукопожатие WebSocket не завершилось.
Исходная ошибка — в cause.
LocalApiDisabledError
class LocalApiDisabledError extends SpectreTerminalErrorinstance.json есть, но порта Local API в нём нет: терминал запущен
с выключенным API, или файл остался от терминала, который завершился
нештатно. В любом случае подключаться некуда, пока API не включён в
Settings App (Общие → Local API).
TokenMissingError
class TokenMissingError extends SpectreTerminalErrorНи параметр token, ни SPECTRE_LOCAL_API_TOKEN токена не дали.
IncompatibleTerminalError
class IncompatibleTerminalError extends SpectreTerminalError/v1/meta сообщил версию API, на которой этот клиент не говорит.
| Поле | Тип | Описание |
|---|---|---|
apiVersion | string | api_version, который сообщил терминал. |
appVersion | string | app_version, который сообщил терминал. |
StreamRequestError
class StreamRequestError extends SpectreTerminalErrorСтрим ответил на запрос subscribe или unsubscribe кадром error.
code — код ошибки контракта (not_found, rate_limited,
invalid_request, …). Остальные подписки идут дальше.
| Поле | Тип | Описание |
|---|---|---|
code | string | Стабильный код ошибки из контракта. |
detail | string | Сообщение сервера для человека, без префикса. |
StreamClosedError
class StreamClosedError extends SpectreTerminalErrorСервер закрыл стрим по причине, на которую потребитель должен отреагировать:
1001 — API выключен или токен перевыпущен; 4008 — этот клиент
читал слишком медленно; 4029 — лимит соединений на токен. Также
бросается для 1006, когда соединение оборвалось без кадра закрытия, и из
subscribe / unsubscribe на уже закрытом стриме.
| Поле | Тип | Описание |
|---|---|---|
code | number | Код закрытия WebSocket. |
reason | string | Причина закрытия, присланная сервером; может быть пустой. |
Собрано из кода @spectre-trade/terminal, коммит 2d1c324.