Intraday Gamma Exposure (GEX) imbalance tracking in a terminal UI.
An asynchronous, high-performance command-line dashboard for tracking real-time dealer options hedging pressure in index futures such as ES and NQ. The terminal uses cumulative intraday session volume as a proxy for changing open interest, then translates live option-chain activity into strike-level gamma exposure, imbalance, and structural market zones.
The goal is to isolate hidden institutional support, resistance, and volatility acceleration boundaries at terminal speed, without the overhead of a browser UI.
Design target:
This project is intended for market research and engineering experimentation. It is not financial advice.
gex-terminal is an open-source GEX research terminal for traders and developers
who want a local, explainable workflow instead of a closed market-structure
dashboard. The project is designed around:
- Open-source model development: contributors can inspect the assumptions, improve the math, and compare results against replayable sessions.
- Local-first credential handling: API keys and market-data credentials stay in local environment files, not in source code or hosted dashboards.
- Transparent calculations: the current model documents its practical assumptions, including intraday volume as an open-interest proxy.
- Provider-agnostic ingestion: market data flows through adapters so the app can grow beyond any single broker or feed.
- Replayable research datasets: normalized fixtures make it possible to learn, test, and reproduce behavior without paid data access.
- Fast ES/NQ intraday workflow: the terminal is built for traders who already have data access and want quick structural reads without browser overhead.
That openness is the invitation: contributors can improve the model, add providers, submit normalized payload fixtures, and build export or visualization tools without needing to join a closed commercial platform.
Helpful contributions include provider adapters, normalized market-data fixtures, math/model improvements, terminal UI experiments, replay datasets, data-quality checks, and docs that make GEX research easier to understand.
Good starting points:
- Pick an issue labeled
good first issueorhelp wanted. - Submit sanitized replay or provider payload fixtures.
- Improve the assumptions documentation around GEX calculations.
- Prototype one of the signature capabilities in the roadmap.
- Help validate provider-specific option-chain payload shapes.
.
|-- .env.example # Template for local provider credentials
|-- .gitignore # Keeps secrets, virtualenvs, and caches out of Git
|-- .github/workflows/ # GitHub Actions smoke-test workflow
|-- CHANGELOG.md # Notable project changes and public-prep milestones
|-- CODE_OF_CONDUCT.md # Community participation expectations
|-- LICENSE # MIT License
|-- CONTRIBUTING.md # Contribution guidelines and verification notes
|-- README.md # Project overview and setup notes
|-- ROADMAP.md # Planned project phases and future work
|-- SECURITY.md # Credential handling and vulnerability reporting
|-- requirements.txt # Runtime Python dependencies
|-- pyproject.toml # Package metadata and console entry point
|-- main.py # Backward-compatible CLI wrapper
|-- assets/ # Screenshots, mockups, and social preview assets
|-- docs/ # Adapter and contributor-facing technical notes
|-- gex_terminal/ # Application package
| |-- cli.py # Console command and orchestration
| |-- config.py # Environment-driven runtime configuration
| |-- engine.py # Vectorized Black-Scholes and GEX calculation matrix
| |-- consumer.py # Stateful asynchronous market-data aggregator
| |-- tui.py # Textual reactive terminal user interface
| |-- gex_terminal.tcss # Terminal dashboard theme and layout styles
| |-- market_data_adapter.py # Shared provider adapter contract
| `-- adapters/ # Replay, Tradovate, Databento, IBKR, and yfinance adapters
|-- sample_data/ # Normalized replay data for local demos
|-- tests/ # Math regression tests
- Vectorized mathematical engine: calculates Black-Scholes Greeks across the option chain with NumPy, avoiding slow per-contract Python loops.
- Thread-safe state architecture: uses asynchronous queues and guarded state updates to ingest high-frequency WebSocket ticks without race conditions.
- Low-overhead terminal interface: renders a live matrix in a Textual UI, keeping the workflow fast and local.
- Intraday open-interest proxy: treats cumulative session volume as the active positioning input when official open interest is stale or delayed.
- Strike-level structural mapping: identifies the gamma wall, zero-gamma node, net exposure bands, and call/put imbalance zones.
- Credential isolation: keeps API keys and production market-data credentials outside the execution logic through environment variables.
The engine estimates dealer hedging pressure by calculating option gamma and scaling it into net intraday dollar gamma exposure per 1% underlying move.
For each option contract, the Black-Scholes gamma is:
where:
and:
| Symbol | Meaning |
|---|---|
| Option gamma | |
| Standard normal probability density function | |
| Current underlying spot or futures price | |
| Option strike price | |
| Implied volatility | |
| Time to expiration, expressed as a fraction of a 365-day year | |
| Risk-free rate |
Raw gamma is converted into dollar gamma exposure by scaling it with cumulative transaction volume and contract multiplier.
Call exposure is treated as positive:
Put exposure is treated as negative:
Strike-level net gamma exposure is:
Total session net gamma exposure is:
The call/put imbalance ratio can be represented as:
Values above 1.0 indicate call-side gamma dominance; values below 1.0
indicate put-side gamma dominance.
The terminal derives key market zones from the strike-level GEX matrix:
- Gamma Wall: the strike with the largest absolute concentration of net dealer exposure. This level often behaves like a price magnet or overhead resistance/support zone.
- Zero-Gamma Node: the strike or interpolated price where net positioning flips sign from positive to negative. This marks the transition between a lower-volatility, mean-reverting regime and a higher-volatility, trend-prone regime.
- Positive Gamma Zone: a region where dealer hedging may dampen volatility as hedging flows lean against price movement.
- Negative Gamma Zone: a region where dealer hedging may amplify volatility as hedging flows move with price direction.
- Imbalance Boundary: the area where call-side and put-side dollar gamma exposure materially diverge, highlighting asymmetric hedging pressure.
Market Data WebSocket
|
v
gex_terminal/consumer.py
- Receives ticks
- Normalizes option-chain payloads
- Updates cumulative intraday volume
- Publishes state snapshots
|
v
gex_terminal/engine.py
- Vectorizes Black-Scholes inputs
- Calculates gamma
- Converts gamma to dollar GEX
- Computes wall, node, and imbalance metrics
|
v
gex_terminal/tui.py
- Renders live strike matrix
- Displays aggregate exposure
- Highlights structural zones
|
v
gex_terminal/cli.py
- Starts async tasks
- Coordinates shutdown
- Handles application lifecycle
Create a virtual environment:
python3 -m venv .venv
source .venv/bin/activateInstall dependencies:
pip install -e .Run the terminal with seeded demo data:
gex-terminal --demoRun live mode for ES:
gex-terminal --mode live --provider tradovate --symbol ESRun NQ with its futures multiplier:
gex-terminal --demo --symbol NQ --multiplier 20Export the actual Textual terminal screenshot used by GitHub:
gex-terminal --demo --screenshot assets/gex-terminal-actual.svgCopy the example environment file and fill in your local Tradovate credentials:
cp .env.example .envGEX_SYMBOL=ES
GEX_SYMBOLS=ES,NQ,SPX,QQQ
GEX_DATA_MODE=demo
GEX_DATA_PROVIDER=tradovate
GEX_CONTRACT_MULTIPLIER=50
GEX_RISK_FREE_RATE=0.045
GEX_DAYS_TO_EXPIRY=0.25
GEX_REFRESH_INTERVAL_SECONDS=1.0
GEX_STALE_AFTER_SECONDS=10.0
GEX_REPLAY_PATH=sample_data/demo_replay.jsonl
GEX_REPLAY_DELAY_SECONDS=0.05
TRADOVATE_ENV=demo
TRADOVATE_NAME=your_username
TRADOVATE_PASSWORD=your_password
TRADOVATE_APP_ID=your_app_id
TRADOVATE_APP_VERSION=1.0
TRADOVATE_CID=your_client_id
TRADOVATE_SEC=your_client_secret
DATABENTO_API_KEY=your_databento_api_key
DATABENTO_DATASET=GLBX.MDP3
IBKR_HOST=127.0.0.1
IBKR_PORT=7497
IBKR_CLIENT_ID=17Suggested futures multipliers:
| Product | Symbol | Multiplier |
|---|---|---|
| E-mini S&P 500 | ES | 50 |
| Micro E-mini S&P 500 | MES | 5 |
| E-mini Nasdaq-100 | NQ | 20 |
| Micro E-mini Nasdaq-100 | MNQ | 2 |
Launch the terminal:
gex-terminalRun with seeded demo data:
gex-terminal --demoRun with normalized replay data:
gex-terminal --replay sample_data/demo_replay.jsonlOverride .env settings from the command line:
gex-terminal --providers
gex-terminal --mode live --provider tradovate --symbol ES
gex-terminal --mode live --provider databento --symbol ES
gex-terminal --mode live --provider ibkr --symbol ES
gex-terminal --mode live --provider yfinance --symbol SPY
gex-terminal --demo --symbol NQ --multiplier 20
gex-terminal --demo --refresh 0.5Export an actual Textual screenshot for GitHub:
gex-terminal --demo --screenshot assets/gex-terminal-actual.svgExport a JSON snapshot of the current GEX state (metrics, call/put walls, concentration, expiry breakdown, and the full strike matrix):
gex-terminal --demo --export gex_snapshot.jsonWhile the terminal is running, these keys are available:
| Key | Action |
|---|---|
r |
Refresh the snapshot now |
s |
Cycle strike sort (strike / |net| / volume) |
f |
Cycle strike filter (all / near-money / active) |
e |
Export the current snapshot to a timestamped JSON file |
q |
Quit |
The dashboard is designed to update continuously as new option-chain and trade events arrive. During a live session, the matrix should surface:
- strike-level call GEX
- strike-level put GEX
- net GEX by strike
- aggregate session GEX
- gamma wall
- zero-gamma node
- call/put imbalance
- positive and negative gamma zones
The terminal surfaces runtime lifecycle state as LIVE, SIM, STALE,
CONNECTED, or DISCONNECTED so the UI distinguishes real-time data from demo
and stale sessions.
If live mode is missing credentials or market-data dependencies, the app exits with an install/configuration hint instead of a Python traceback:
pip install -e .- Keep
.envout of version control. - Keep market-data adapters isolated from calculation logic.
- Prefer vectorized NumPy operations inside
gex_terminal/engine.py. - Treat consumer state as shared mutable data and update it through explicit locks or queue ownership.
- Use deterministic fixtures for engine tests so the math can be regression tested independently from live data.
- See CONTRIBUTING.md for contribution guidelines.
- See CODE_OF_CONDUCT.md for community expectations.
- See CHANGELOG.md for notable project changes.
- See docs/adapters.md for the provider adapter contract.
- See docs/product-vision.md for signature capability concepts and mockups.
- See ROADMAP.md for planned phases and future work.
- See SECURITY.md for credential-handling guidance.
Recommended early test coverage:
- Black-Scholes gamma values against known reference cases.
- Dollar GEX conversion for calls and puts.
- Net GEX aggregation by strike.
- Zero-gamma interpolation across sign changes.
- Runtime lifecycle states for demo, live, stale, and disconnected sessions.
- Async consumer state updates under bursty tick delivery.
- Terminal rendering with empty, partial, and live-like snapshots.
This project is licensed under the MIT License. See LICENSE for details.
