Spread Scope is a local dashboard for discovering spot/perpetual spread opportunities across crypto exchanges.
It focuses on market discovery and monitoring only. It does not place orders, manage positions, or provide financial advice.
- Matches markets by token contract address instead of symbol name.
- Supports intra-exchange spot/perp comparisons.
- Supports cross-exchange spot/spot, spot/perp, and perp/perp comparisons.
- Maintains local price and order book caches from exchange WebSocket streams.
- Calculates executable depth near the mid price with configurable bps range.
- Shows confidence based on address mapping status.
- Displays funding rates for perpetual markets.
- Uses per-tab dashboard WebSocket streams: only the selected tab is connected and computed.
- Periodically refreshes exchange metadata and symbol mappings.
The dashboard currently supports:
- Binance
- MEXC
Client implementations for Gate and CoinEx are present in the codebase, but the current dashboard allow-list is intentionally limited in src/dashboard.py.
- Python 3.11+
uvorpip- Optional exchange API keys for address metadata lookup
Using uv:
uv syncUsing pip:
pip install -e .Copy the example environment file:
cp .env.example .envCommon settings:
BINANCE_API_KEY=your_key_here
BINANCE_API_SECRET=your_secret_here
MEXC_API_KEY=your_key_here
MEXC_API_SECRET=your_secret_here
DEBUG=true
PROXY_URL=http://127.0.0.1:7890
DASHBOARD_HOST=127.0.0.1
DASHBOARD_PORT=8000
DASHBOARD_VENUES=binance,mexc
DASHBOARD_SYMBOLS=
DASHBOARD_SPREAD_BPS_THRESHOLD=50
DASHBOARD_MIN_DEPTH_USD=2000
DASHBOARD_MAX_DEPTH_BPS_FROM_MID=30
DASHBOARD_DEPTH_REST_SUPPLEMENT_AFTER_SECONDS=600
DASHBOARD_SNAPSHOT_REFRESH_INTERVAL_SECONDS=0.5
DASHBOARD_SYMBOL_MAPPING_REFRESH_SECONDS=1800Authentication settings are used when DEBUG=false:
AUTH_TOTP_SECRET=change_me_base32_totp_secret
AUTH_SESSION_SECRET=change_me_to_a_long_random_string
AUTH_SESSION_TTL_SECONDS=43200
AUTH_SESSION_COOKIE_NAME=spread_scope_session
AUTH_COOKIE_SECURE=false.env is ignored by Git. Do not commit API keys or secrets.
Generate a session secret:
python -c "import secrets; print(secrets.token_urlsafe(32))"Run the dashboard locally:
PYTHONPATH=src .venv/bin/python src/dashboard.pyOr use the installed script:
spread-scope-dashboardOpen:
http://127.0.0.1:8000
Start with Docker Compose:
docker compose up --buildRun in the background:
docker compose up -d --buildStop:
docker compose downIf Docker needs to use a proxy running on the host, use host.docker.internal instead of 127.0.0.1:
DEBUG=true
PROXY_URL=http://host.docker.internal:7890- Exchange clients load market metadata and token address mappings through REST APIs.
- Exchange clients maintain local price, funding, and order book state through WebSocket streams.
- The dashboard builds
MatchedPairrows from local client state. - The frontend connects only the selected tab's WebSocket stream:
intra_spot_perpcross_spot_spotcross_spot_perpcross_perp_perp
- The backend computes only categories with active WebSocket clients.
/api/markets/{category}is retained as a debugging endpoint that returns the latest cached payload.
depth-missing: one or both local order book caches are missing.depth-thin: executable depth is below the expected threshold.spread-extreme: spread is unusually large and needs manual review.wss-disconnected: an exchange WebSocket stream is reconnecting or unavailable.cross-exchange: the pair compares markets across exchanges.address-mapping-untrusted: one or both legs were not matched through a trusted token address mapping.
For a pair to be marked trusted, both legs must have address_mapping_flag=true.
Run syntax checks:
PYTHONPATH=src .venv/bin/python -m py_compile $(rg --files src -g '*.py')
node --check src/web/app.jsRun tests:
PYTHONPATH=src .venv/bin/python -m unittest discover -s tests -vPlease do not open public issues containing API keys, secrets, private logs, or account data. See SECURITY.md.
Contributions are welcome. See CONTRIBUTING.md.
Spread Scope is released under the MIT License.