Minimal, dependency-light clients for the Rocky Spot API in Python and TypeScript, plus three runnable examples: a quickstart, a two-sided quoter with the safety rails an external market maker needs, and a settlement reconciliation job. Apache-2.0 licensed.
Rocky settles spot fills on the Canton Network. If you trade from your own Canton party (your validator or a supported wallet), every fill is a two-leg DvP between your party and the counterparty's, your spot balance is a mirror of your wallet, exchange fees are zero, and your validator pays Canton traffic (in CC) for its side of every fill. The examples therefore treat fills as a budgeted resource and reconcile against the settlement ledger, not just the order acknowledgement. Read the External Market Maker Guide first.
python/ rocky_spot package (signing, REST, WebSocket) + examples/ + tests/
typescript/ src/ (same three modules, zero runtime deps, Node ≥ 22) + examples/ + test/
.env.example configuration shared by both
Both clients cover the whole /api/v3 surface: public market data, signed order endpoints (order, openOrders incl. cancel-all, allOrders, myTrades with orderId), account (with the settlement segment block), and the settlement ledger (settlements, settlements/summary). Signing is verified against the published HMAC and Ed25519 test vectors in the unit tests.
cp .env.example .env # fill in ROCKY_API_KEY / ROCKY_API_SECRET (or the Ed25519 seed file)
set -a; . ./.env; set +aPython 3.10+:
cd python
python -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]"
pytest # signing vectors
python -m rocky_spot.signing # same, as a one-liner
python examples/quickstart.py # public data → account → place/cancel one resting bid → fills → settlement summary
python examples/market_maker.py # two-sided quoter (Ctrl-C pulls every quote)
python examples/reconcile.py # settlement ledger reportTypeScript (Node 22+):
cd typescript
npm install
npm test # signing vectors
npm run quickstart
npm run mm
npm run reconcile- Reads
exchangeInfofilters (tickSize,stepSize,minQty,minNotional) andaccount.settlement(refuses to start iffrozen). - Takes the reference price from the
@depth5stream mid (swap in your own feed inreference()). - Every
MM_REQUOTE_Sseconds: counts fills in the last hour frommyTrades, readssettlements/summary, reads inventory, then either pulls all quotes (DELETE /api/v3/openOrders, weight 1, not order-counted) because the fill budget is spent or a settlementfailed, or reposts a skewed ladder ofMM_LEVELSlevels per side. - Stops on
-2010(frozen) /-2012(not enrolled) and on SIGINT/SIGTERM, always cancelling first.
It is deliberately simple. Keep the structure — filters, kill switch, fill budget, settlement check — and replace the pricing.
-
HMAC: Rocky issues
key+secret. -
Ed25519 (recommended for institutions): generate a seed, register the public key. Both clients print the base64 public key from a seed and accept raw / hex / base64 / PKCS#8 PEM seed files:
openssl genpkey -algorithm ed25519 -out spot-ed25519.pem ROCKY_KEY_TYPE=ED25519 ROCKY_ED25519_SEED_FILE=./spot-ed25519.pem
External market makers are on the ext-mm tier (2400 weight/min, 100 orders/10 s, 600 orders/min). Cancels are free on the order buckets. myTrades and settlements cost weight 10; both clients expose x-mbx-used-weight-1m / x-mbx-order-count-1m after every call. There is no user-data WebSocket stream; fills are polled.
Endpoint reference: https://developers.rocky.exchange/spot/intro. Quickstart with the same snippets: https://developers.rocky.exchange/spot/quickstart. Issues and pull requests welcome.