This release is a pre-release and may not be stable for production use.
spectre-terminal
Python client for the Local API of Spectre Terminal: connections, the
instrument catalogue, trades, order books, clusters, candles and the
account from a running terminal on the same machine, plus orders placed
with the same commands the window uses — over HTTP and WebSocket on
127.0.0.1.
- Python 3.10+, one dependency (
websockets), HTTP through the standard library. - Money is
decimal.Decimal, neverfloat; timestamps areintUTC milliseconds. - The token is taken only from
SPECTRE_LOCAL_API_TOKENor the constructor argument and never appears in errors or logs.
Install
pip install spectre-terminal
Switch the API on in the terminal: Settings App → General → Local API,
then Copy token and keep it in SPECTRE_LOCAL_API_TOKEN.
Quick start
from spectre_terminal import Terminal
terminal = Terminal.discover() # port from instance.json, token from SPECTRE_LOCAL_API_TOKEN
for connection in terminal.connections():
print(connection.id, connection.exchange, connection.market, connection.status.state)
snapshot = terminal.snapshot("binance:futures:BTCUSDT")
print(snapshot.best_bid, snapshot.best_ask, snapshot.last_trade)
book = terminal.orderbook("binance:futures:BTCUSDT", depth=10)
print(book.bids[0], book.asks[0])
Live data over the stream:
import asyncio
from spectre_terminal import Terminal
async def main():
terminal = Terminal.discover()
async with terminal.stream() as stream:
await stream.subscribe("trades", "binance:futures:BTCUSDT")
await stream.subscribe("book.top", "binance:futures:BTCUSDT", depth=5, interval_ms=200)
async for frame in stream:
print(frame)
asyncio.run(main())
Every operation of the contract is a method of Terminal: meta, health,
connections, connection, instruments / iter_instruments,
intervals, candles, trades, snapshot, orderbook, clusters,
account_orders, account_positions, account_balances, account_fills,
place_order, cancel_order, cancel_all, close_position, place_trigger,
cancel_trigger, cancel_all_triggers, amend_trigger, leverage,
set_leverage, set_margin_mode, workspace, workspace_window,
open_stack, open_tab, add_stacks, open_multiview,
set_stack_instrument, close_stack,
close_tab, activate_tab, close_window, activate_window, settings,
orderbook_settings, update_settings, stream.
Errors derive from SpectreTerminalError; the terminal's own refusals are
ApiError with the contract's code and the HTTP status.
Runnable scripts live in examples/; examples/smoke.py calls
every read operation once against a running terminal.
Account
Orders, positions, balances and fills of one connection: connection_id
is required, there is no default connection here. Balances and fills are
accumulated from the moment the API was switched on.
orders = terminal.account_orders(12)
for order in orders.data:
print(order.key, order.side, order.order_type, order.remaining, "@", order.price)
for trigger in orders.triggers:
print(trigger.trigger_type, trigger.rule, trigger.trigger_price)
for position in terminal.account_positions(12).data:
print(position.instrument, position.side, position.size, position.unrealized_pnl)
for balance in terminal.account_balances(12).data:
print(balance.currency, balance.total, balance.available)
for fill in terminal.account_fills(12, limit=50).data:
print(fill.ts, fill.instrument, fill.side, fill.qty, "@", fill.price, fill.fee)
The JSON key type is order_type on Order and trigger_type on
TriggerOrder. Live changes come over the stream: the account.* topics
subscribe by connection_id and take no instrument, and Event.data is an
OrdersUpdate (orders and triggers of one instrument), a PositionUpdate
(position is None on a close), a Balance or a Fill. There is no
snapshot frame on subscribe: read the current state over HTTP first.
async with terminal.stream() as stream:
await stream.subscribe("account.orders", connection_id=12)
await stream.subscribe("account.fills", connection_id=12)
async for frame in stream:
print(frame.topic, frame.data)
Trading
place_order, cancel_order, cancel_all and close_position go through
the same handlers as the window. Each returns Accepted — accepted by the
terminal, not by the exchange: the confirmation, fill or rejection arrives
on account.orders, under Accepted.key. Money is Decimal, str or
int and travels as a string; a float is refused.
from decimal import Decimal
accepted = terminal.place_order(
12,
"binance:futures:BTCUSDT",
side="buy",
order_type="limit",
price=Decimal("60000"),
size="0.001",
client_key="bot-42", # idempotency: a repeat with the same key places nothing
)
print(accepted.key, accepted.operation_id)
terminal.cancel_order(12, "binance:futures:BTCUSDT", accepted.key)
terminal.cancel_all(12, "binance:futures:BTCUSDT") # the space bar in the order book
terminal.close_position(12, "binance:futures:BTCUSDT") # as the window closes it
A connection that does not trade (disabled, read-only, without credentials)
is ApiError with code not_tradable; a venue minimum or step refusal is
invalid_request; more than meta().limits.commands_per_second commands
per second is rate_limited. examples/place_and_cancel.py places one
limit far below the market, watches it appear on account.orders and
cancels it — on a real account, so pick a test one.
Trigger orders and leverage go the same way. A stop loss or take profit is
placed on the open position (its side and size come from the position); a
stop carries its own side and quote amount. Triggers are cancelled and
moved by the numeric id from account_orders().triggers.
sl = terminal.place_trigger(12, "binance:futures:BTCUSDT", kind="stop_loss", trigger_price="59000")
trigger = next(t for t in terminal.account_orders(12).triggers if t.client_id == sl.key)
terminal.amend_trigger(
12, "binance:futures:BTCUSDT", trigger.id, kind="stop_loss", trigger_price="58500"
)
terminal.cancel_trigger(12, "binance:futures:BTCUSDT", trigger.id)
print(
terminal.leverage(12, "binance:futures:BTCUSDT")
) # not_active until the terminal touched the instrument
terminal.set_leverage(12, "binance:futures:BTCUSDT", leverage=20)
terminal.set_margin_mode(12, "binance:futures:BTCUSDT", "isolated")
The layout — windows, tabs, stacks and charts — is read with workspace()
and changed with commands the window applies itself: a stack opens in a new
tab or window, tabs and windows are selected and closed, a stack is
re-pointed or closed. Ids are numbers of the current run of the terminal;
the workspace stream topic sends the whole layout on every change.
opened = terminal.open_stack("binance:futures:BTCUSDT", chart=True, activate=False)
terminal.set_stack_instrument(opened.stacks[0], "binance:futures:ETHUSDT")
terminal.close_tab(opened.window_id, opened.tab_id)
majors = terminal.open_tab(
[TabItem("binance:futures:BTCUSDT", chart=True), "binance:futures:ETHUSDT"], name="Majors"
)
terminal.add_stacks(majors.window_id, majors.tab_id, ["binance:futures:SOLUSDT"])
Settings are read as stored (settings()), resolved the way a stack sees
them (orderbook_settings()), and written through the same path as the
Settings App after the terminal's catalogue checked every change
(update_settings()); the settings stream topic reports every written
row.
from spectre_terminal import SettingChange
terminal.update_settings([SettingChange("multiview", "stack_width_px", 300)])
Documentation
The guides are in ../docs; the authoritative description of
the API is ../contract/contract-v1.md.
Development
python3 -m venv .venv && .venv/bin/pip install -e '.[dev]'
.venv/bin/pytest -q
.venv/bin/ruff check . && .venv/bin/ruff format --check .
The tests run against the fixtures in ../contract/fixtures; no terminal is
needed.
Metadata
Release files for spectre-terminal 0.1.0rc1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| spectre_terminal-0.1.0rc1.tar.gz | 50.7 kB | With provenance | Details for spectre_terminal-0.1.0rc1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| spectre_terminal-0.1.0rc1-py3-none-any.whl | Python 3 | none | any | Details for spectre_terminal-0.1.0rc1-py3-none-any.whl |
Total release size: 85.1 kB
Release files / spectre_terminal-0.1.0rc1.tar.gz
| Download URL | spectre_terminal-0.1.0rc1.tar.gz |
|---|---|
| Size | 50.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0d6cdbeb58cfec899b9a710d1b97b40ffdde4c50e5e11ecc811b5bfa7f3d9f73
|
|
BLAKE2b-256 checksum How to use checksums |
3d1b9c2732364d4a7a844ca3082603fadbab5b6335a4d7352624a8d74312c89c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logRelease files / spectre_terminal-0.1.0rc1-py3-none-any.whl
| Download URL | spectre_terminal-0.1.0rc1-py3-none-any.whl |
|---|---|
| Size | 34.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
fa13629270adb033daefe16a18839c12639f8f9f3288ee54d183a3bc4fb85363
|
|
BLAKE2b-256 checksum How to use checksums |
229f7596cff77faea5bbac0d5b26a3c1c818bbc1584697b91f0c416dd4dc03b9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logSecurity for spectre-terminal 0.1.0rc1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for spectre_terminal-0.1.0rc1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.