CCXT adapter
One venue class covering 100+ crypto exchanges: Binance, Coinbase, Kraken, OKX, Bybit, KuCoin.
horizon.venues.ccxt_venue.CcxtVenue wraps any CCXT-supported exchange behind Horizon’s Venue Protocol. CCXT unifies 100+ exchanges under one API shape; CcxtVenue normalizes it further into VenueOrder, VenueFill, VenueCapital.
Each exchange is a separate CcxtVenue instance. venue_name is ccxt:<exchange_id>.
What you get
- Any CCXT exchange.
CcxtVenue(exchange_id="binance")or"coinbase","kraken","okx","bybit","kucoin", etc. - Unified auth. API key + secret for all; plus passphrase for Coinbase, OKX, KuCoin, Bitget, Crypto.com. Resolution via Secrets under
<exchange_id>.key/.secret/.passphrase. - Sandbox toggle.
sandbox=Truecallsexchange.set_sandbox_mode(True)when the exchange supports it (Binance Futures testnet, OKX demo, Kraken futures demo). - Unified order status.
open,closed,canceled,expired,rejected.PartiallyFilledderived fromfilledvs.amount. - Multi-stablecoin balance. Sums
USDT,USDC,USD,BUSD,FDUSD,DAI. - Fill dedup by trade id.
fetch_my_tradesemits each fill once.
Quickstart: Binance testnet
from horizon.venues.ccxt_venue import CcxtVenue
v = CcxtVenue(
exchange_id="binance",
api_key="...", api_secret="...",
sandbox=True,
)
v.connect()
print(v.balance())
from horizon.types import OrderAction
order = v.submit(OrderAction.place(
market_id="BTC/USDT", side="buy",
quantity=0.001, price=65000.0,
client_order_id="coid_1",
))
Coinbase, OKX, KuCoin, and Bitget additionally require a passphrase:
v = CcxtVenue(
exchange_id="okx",
api_key="...", api_secret="...", api_passphrase="...",
sandbox=True,
)
Symbology
CCXT uses BASE/QUOTE: "BTC/USDT", "ETH/USDC", "SOL/USDT". Derivatives on some exchanges use BASE/QUOTE:SETTLE, e.g. "BTC/USDT:USDT" for USDT-margined perps.
Pass asset_class=AssetClass.Perp at construction when the venue trades futures to mark positions correctly.
Order types
| Type | OrderAction.order_type | Notes |
|---|---|---|
| Limit | "limit" | Requires price. |
| Market | "market" | Price ignored. |
| Stop | "stop" | stopPrice passed in params. |
| Stop-limit | "stop_limit" | stopPrice + price. |
TIF maps to GTC, IOC, FOK, PO (post-only). client_order_id passes as clientOrderId; post_only and reduce_only as boolean params. Exchange support varies; unsupported params are often silently dropped by CCXT.
Amend
CCXT’s edit_order is supported by a subset of exchanges (Binance, OKX, Kraken). When exposed, CcxtVenue.amend(order_id, new_quantity=..., new_price=...) calls it. Otherwise raises NotImplementedError.
WebSocket feed (ccxt.pro)
ccxt.pro became MIT-licensed in late 2023 and ships alongside ccxt. CcxtLiveFeed wraps its watch_* coroutines in a dedicated asyncio loop running on a daemon thread.
from horizon.data.live import CcxtLiveFeed, SubscriptionKind
feed = CcxtLiveFeed(
exchange_id="binance",
api_key="...", api_secret="...",
fill_hook=v.push_fill,
)
feed.subscribe(["BTC/USDT"], SubscriptionKind.Trades)
feed.subscribe(["BTC/USDT"], SubscriptionKind.OrderBook)
Channels: watch_trades, watch_ticker, watch_order_book, watch_my_trades. Public channels work without credentials; watch_my_trades requires auth.
Rate limiting
CCXT throttles client-side via enableRateLimit=True (the adapter sets this). Each exchange class carries a published rateLimit (ms between calls). Raise alerts via the Alerting module on reject streaks.
Pinning
CCXT ships frequent releases and sometimes breaks API details on minor versions. Pin tightly in production:
ccxt==4.4.86 # or whatever you tested
Status by phase
| Capability | Status |
|---|---|
| One class covers 100+ exchanges | Shipped |
| Submit, cancel, cancel_all, amend (where supported) | Shipped |
| Positions, balance, open_orders | Shipped |
| WebSocket via ccxt.pro | Shipped |
| Sandbox toggle | Shipped |
| Per-exchange fee and liquidity parsing | Unified; custom subclass to tune per exchange |
Related
- Live feeds.
- Order lifecycle.
- Secrets for per-exchange credential keys.