Skip to main content

ITMatrixHQ Python SDK

pip install itmatrix
# For WebSocket streams:
pip install "itmatrix[stream]"
import os
import itmatrix as itm

client = itm.ITMClient(api_key=os.environ["ITM_API_KEY"])
result = client.get_gex("SPY", top=10)
print(result.data.spot, result.data.net_gex)
for row in result.data.strikes:
    print(row.strike, row.gex, row.expiry)

No with block is needed. The same client works as a context manager, which closes it when the block ends:

with itm.ITMClient(api_key=os.environ["ITM_API_KEY"]) as client:
    print(client.get_gex("SPY").data.net_gex)

itmatrix is the distribution and import name. Python 3.10+ is supported. To build from source instead, run pip install ./python from the repository root.

A small vocabulary

Method result.data
get_gex(symbol, at=..., top=..., by_expiry=...) GexGrid and GexStrike values
get_gex_reference(symbol, date=..., basis="open") Exact persisted reference book, or explicit unavailable values
get_option_chain(symbol, expiry=..., strike_gte=...) OptionChain with contract/quote models
list_expirations(symbol) ISO expiry date strings
list_symbols(symbol_class="equity") Symbol values from the registry
lookup_symbol("spy") SymbolIdentity with broad class and conservative instrument classification
get_bars(symbol, from_=..., to=..., timeframe="1m") Bars with bars, cursor, and completeness
get_replay(symbol, date="2026-09-04") Replay with Tick or Bar events
get_gex_analysis(symbol) Server net GEX and zero gamma plus ranked visible positive/negative strike levels
get_bars_for_period(symbol, "today") New York calendar-day intraday bars; longer named periods default to daily bars

The convenience methods are local compositions; they add no API route. get_bars_for_period(symbol, "calendar_month", month="2024-02") requests the whole named month with daily bars; inspect the returned cursor for another page. resolve_bar_window can be used without a client. See convenience semantics before treating visible GEX levels as full-chain levels or a month as a completed session set.

Result retains meta, HTTP status, request_id, and etag. Unknown metadata is preserved. Nullable measurements stay None; zero is a real value. Timestamps are epoch milliseconds, dates are ISO strings, bar/quote prices are dollars, and strike filters use integer thousandths of dollars. row.strike is a convenient dollar value; row.strike_thousandths preserves the exact integer. GEX values (gex, net_gex, max_abs_gex, delta_adj, gex_0dte) are dollars of dealer hedging per $1 move. Each has a served *_shares sibling (gex_shares, net_gex_shares, max_abs_gex_shares, delta_adj_shares, gex_0dte_shares) in shares of the underlying per $1 move, on the grid, history and reference book; None means the server does not know it.

The public protobuf representation omits an option contract's OSI root. Its underlying is therefore None on that transport, rather than a guessed value. The normalized model otherwise uses the same field names and units for JSON and public protobuf. Set transport="protobuf" to negotiate public protobuf on the bulk market-data and off-exchange endpoints. Streaming always uses the public protobuf protocol.

Account, journal, watchlists, economy, offexchange, market, reference, screener, flow, fundamentals, vol, protocol and service-info operations are grouped on both clients. Together with the client's own methods they model every non-internal /v2 operation the contract declares; the pre-/v2 aliases are deliberately not modelled.

client.offexchange is the typed synthetic surface: activity, concentration, profile, and composition. client.darkpool is a compatibility alias to the same safe resource. There is no generic dataset method or raw-evidence route.

with itm.ITMClient(api_key=os.environ["ITM_API_KEY"]) as client:
    rates = client.economy.treasury_yields()
    trades = client.journal.list_trades()
    news = client.fundamentals.digest(kind="brief", scope="market")

    # A whole session's GEX captures. `to` is exclusive, so 16:00 drops the close.
    day = client.get_gex_history("SPY", date="2026-09-04", from_="09:25", to="16:05", top=120)

    # Exact immutable book; captured_at=None means unavailable, not zero.
    reference = client.get_gex_reference("SPY", date="2026-09-25", basis="prev_close")

    # First-party app session only: Pro + CBOE attestation, explicitly partial.
    premium = client.flow.premium("SPY", sessions=2, dte="zero", min_premium_usd=100_000)

    # Our own implied vol, out of the greeks engine.
    term = client.vol.term("SPY")

    # Is the API up, and what does this deployment serve? No credential needed.
    ready = client.info.ready()
    spec = client.info.openapi()

info.health() and info.ready() are the only calls that leave /v2/: the client keeps a two-entry allowlist for them and rejects every other path, so request() cannot wander off the documented surface. ready() is the deploy contract rather than a synonym for health() — it is non-2xx while the process is still warming up.

Grouped resources and request("/v2/...") expose raw JSON data for less common operations. Endpoint availability still depends on server entitlements; installing an SDK does not grant app-only products such as bars or chain data.

Async and streaming

import asyncio

async def main():
    async with itm.AsyncITMClient(api_key=os.environ["ITM_API_KEY"]) as client:
        spy, qqq = await asyncio.gather(
            client.get_gex("SPY"), client.get_gex("QQQ"))
        print(spy.data.net_gex, qqq.data.net_gex)

asyncio.run(main())

Subscriptions live on AsyncITMClient.stream; they are bounded async iterators of public protobuf frames. See the repository streaming documentation and the stream.gex(symbol) / stream.spot(symbol) helpers. Close subscriptions with async with or aclose(), and close the client with async with or aclose(). Falling behind the configured queue limit raises an error rather than silently discarding market updates.

Client lifecycle

The blocking ITMClient owns one persistent background event loop and HTTP pool; it never reuses async connections across short-lived loops. Create it once and reuse it. close() is optional:

  • Call close() (or use with) when you want the loop thread and connections released at a known point, such as a long-running process that makes a client per task. It is safe to call more than once; a request after it raises RuntimeError, and client.closed reports it.
  • A client you never close is closed when it is garbage-collected or when the interpreter exits. Its loop runs on a daemon thread, so it never keeps a script from exiting.

Blocking requests are serialized. Use AsyncITMClient for concurrent work; an async client belongs to the loop where it is used. Without async with, call await client.aclose() when you are done: async cleanup cannot run from a finalizer, so an async client that owns its pool and is collected unclosed only emits ResourceWarning. Injected async HTTP clients remain owned by the caller.

Errors, retries, and configuration

client = itm.ITMClient(api_key=os.environ["ITM_API_KEY"], timeout=15, retries=2)
try:
    grid = client.get_gex("SPY")
except itm.ITMError as error:
    print(error.code, error.status, error.request_id)

Only GET responses with status 429, 502, 503, or 504 are retried; mutations and transport exceptions are not replayed. Retry waits are bounded at 30 seconds, with exponential fallback. timeout is HTTPX's per-operation timeout, not an end-to-end deadline including retries. HTTPX transport exceptions propagate. Redirects are disabled even for injected clients. The request escape hatch accepts only /v2/ paths; query parameters go in query={...}. Credentials are resolved for each attempt and never attached to arbitrary absolute URLs.

base_url must be an HTTP(S) origin and defaults to itm.DEFAULT_BASE_URL, the one place the package defines it. api_key and token are mutually exclusive; each accepts a string or refresh callback (sync or async). No credentials are inferred from environment variables. Tests can inject http_transport.

Studies and indicators

There is no native evaluator in Python. The ITMScript runtime is TypeScript, unpublished, and has no Python port planned; this package hands you normalized bars and stops there. A study over get_bars(...).data is either computed in your own code or run through the TypeScript runtime out of process. The rules a host has to resolve either way — a 304 is revalidation and not an empty history, pagination is the caller's loop, entitlement belongs to the credential — are in docs/itmscript.md.

Contributing

From python/, install with pip install -e ., run python -m unittest discover -s tests, and build with python -m build. The repository contract-coverage test also requires the sibling spec/ directory. Only the protobuf serializers in itmatrix/_core/_wire are generated. Public clients, models, options, resources, and tests are hand maintained. Wheels and source archives contain the single itmatrix import package and its py.typed marker.

Release files for itmatrix 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for itmatrix 1.0.0
File Size Uploaded
itmatrix-1.0.0.tar.gz 44.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for itmatrix 1.0.0
File Interpreter ABI Platform
itmatrix-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 85.5 kB

Release files / itmatrix-1.0.0.tar.gz

Download URL itmatrix-1.0.0.tar.gz
Size 44.4 kB
Tags Source
SHA-256 checksum
How to use checksums
669929336b6fb637d76d45e2723aa3b561d303639bb9b6a6f2cf43e74bccc34f
BLAKE2b-256 checksum
How to use checksums
fc7a28dba5d57bdb4af796e9155762ff595022cfd2cc3ae50e2bc0b09a18aaeb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release files / itmatrix-1.0.0-py3-none-any.whl

Download URL itmatrix-1.0.0-py3-none-any.whl
Size 41.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
170b17a50c155022b8bc78c90049f267bf21e83101dc3e9c3f4ac764ef839a9d
BLAKE2b-256 checksum
How to use checksums
11c34a34c9eb5a500c6c40f658858dc7031c7d1e5356708a5886b5f1c285319f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page