Orderbook Watcher
The orderbook watcher aggregates maker offers from directory servers and exposes a web UI/API.
Install
With the recommended installer:
curl -sSL https://raw.githubusercontent.com/joinmarket-ng/joinmarket-ng/main/install.sh | bash
source ~/.joinmarket-ng/activate.sh
The orderbook watcher is part of the default complete profile. To install only
the watcher and its core dependencies, pass --orderbook-watcher. Rerunning
the installer repairs existing 0.35.0 installations that are missing the
watcher entry point.
From a source checkout:
python -m pip install -e ./jmcore
python -m pip install -e ./jmwallet
python -m pip install -e ./orderbook_watcher
Run:
jm-orderbook-watcher
The former orderbook-watcher command still works but is deprecated and
will be removed in a future release.
The reference JoinMarket implementation's ob-watcher.py is a separate
program. Its presence does not install the JoinMarket NG console script.
Configuration
Use ~/.joinmarket-ng/config.toml and/or env vars.
Important settings:
NETWORK_CONFIG__NETWORKNETWORK_CONFIG__DIRECTORY_SERVERSDIRECTORY_NODES(optional comma-separated override)TOR__SOCKS_HOST,TOR__SOCKS_PORTORDERBOOK_WATCHER__HTTP_HOST,ORDERBOOK_WATCHER__HTTP_PORTORDERBOOK_WATCHER__UPDATE_INTERVALORDERBOOK_WATCHER__MEMPOOL_API_URLORDERBOOK_WATCHER__MEMPOOL_API_USE_TOR(defaults totrue)
Mempool API lookups are disabled by default. When enabled, the watcher routes
them through Tor by default. Set mempool_api_use_tor = false only when a
direct endpoint is intentional, such as a local service. Direct access exposes
the watcher's source IP and the bond transactions it queries; it also ignores
HTTP_PROXY and HTTPS_PROXY inherited by the process.
Docker
orderbook_watcher/docker-compose.yml provides watcher + Tor.
From orderbook_watcher/:
mkdir -p tor/conf tor/data tor/run
cat > tor/conf/torrc << 'EOF'
SocksPort 0.0.0.0:9050
ControlPort 0.0.0.0:9051
CookieAuthentication 1
DataDirectory /var/lib/tor
Log notice stdout
EOF
docker compose up -d
UI is exposed on http://localhost:8000 by default.
Set orderbook_watcher.http_host = "0.0.0.0" only when remote access is intentional and
protected by an appropriate firewall or reverse proxy.
Web UI
The orderbook table's Pick Chance column estimates how often each offer is
included in a CoinJoin and displays the result as 1/N. For example, 1/100
means an offer is expected to be selected in one of every 100 rounds.
The estimate uses nine makers (the average of the default randomized range of
8 to 10), the default 5% bondless allowance, active bonded SW0 offers, and
zero-fee bondless SW0 offers. It calculates selection without replacement and
uses bond-value weighting for the default bonded slots; allowance slots select
uniformly from zero-fee offers. Fee and amount filtering are intentionally
omitted, so the estimate assumes every counted offer passes the taker's limits.
Offers sharing one active fidelity bond UTXO count as one candidate, matching
the taker's bond deduplication. Each sibling row shows the bond-level chance
with an asterisk because the omitted fee and amount filters determine which
offer the taker keeps.
Bonded inclusion chances come from a deterministic simulation of this
without-replacement chooser when weights or fee categories differ. The UI shows
N/A when fewer than nine qualifying offers are available. Hover over a Pick
Chance value, or select it by touch or keyboard, to see how that value was determined.
API Endpoints
GET /UIGET /orderbook.jsonaggregated offersGET /healthhealthcheck
Testing
Backend unit tests:
pytest orderbook_watcher
Frontend (web UI) tests run the real static files in a headless browser with fixture payloads; they need Node.js but no Docker stack:
cd tests/playwright
npm install && npx playwright install chromium
npm run test:obwatcher
They also run in CI (test-playwright job) and as part of
scripts/run_parallel_tests.sh.