Route the Product Before the Symbol
A price cache keyed only by BTCUSDT can combine a Binance Spot observation with a Bybit linear-contract observation. The strings match, but the products have different account state and execution rules. A later sizing operation can then consume a price from the wrong market.
A connector needs the API family and product alongside the native symbol. For Coinbase Advanced Trade, even the familiar Bitcoin pair may use a different quote asset:
| Example route | Client and method boundary | Native instrument | Meaning of quantity |
|---|---|---|---|
| Binance Spot | MainClient Spot methods | BTCUSDT | BTC for an ordinary base-quantity order. |
| Bybit linear | RestClientV5, category: 'linear' | BTCUSDT | The selected linear instrument's quantity unit and increments. |
| Coinbase Advanced Trade | CBAdvancedTradeClient | BTC-USD | base_size or quote_size, where supported by the order configuration. |
USD and USDT are distinct quote assets. Matching the base asset does not make these routes interchangeable. Instrument metadata must establish any supported conversion before the application compares amounts.
The route also includes environment and account identity. Two accounts on the same exchange must not share private order rows merely because their native symbols match.
Select the Actual Client
The packages linked from the SDK directory expose native API families rather than one common exchange object:
| Package | Selection that remains explicit |
|---|---|
| binance | MainClient, USDMClient, CoinMClient, and other product clients. |
| bybit-api | RestClientV5 category and account configuration. |
| coinbase-api | Advanced Trade, Exchange, Prime, or another supported API family. |
For Binance, MainClient and USDMClient can both address a symbol named BTCUSDT. Constructor selection establishes the product boundary. The Binance tutorial documents those clients and the separate stream families.
For Bybit, V5 methods commonly select the product with category. A successful HTTP response can still contain a nonzero retCode. The connector must inspect that result before exposing account data or acknowledging a command. The Bybit tutorial supplies the method and response shapes.
For Coinbase, CBAdvancedTradeClient and CBExchangeClient address different APIs. Changing a base URL does not translate their authentication or order bodies. The Coinbase migration article follows that boundary; the Coinbase tutorial documents the client setup.
Preserve Native Command Identity
Suppose the application records intent intent-42 before dispatch. Its connector maps that identity to the client-ID field accepted by the selected endpoint:
| Endpoint family | Client-ID field |
|---|---|
| Binance Spot placement | newClientOrderId |
| Bybit V5 placement | orderLinkId where supported. |
| Coinbase Advanced Trade creation | client_order_id |
These fields have endpoint-specific format, uniqueness, and reuse rules. Calling all of them idempotency keys would hide those differences. Retain the application ID, native client ID, and returned order ID together so a private event or status read can locate the original command.
If a placement response is lost, the connector looks up the original order within its recorded route. It must not change API family or invent a second intent to make a generic retry succeed. The order-state workflow covers unresolved outcomes.
Normalize Only the Consumed Fields
A recorder might need exchange time, local receipt time, native execution ID, price, quantity, and fee currency. Keep those units and currencies explicit. A fee paid in BTC cannot be added directly to a USDT fee total.
A narrow application record can retain the native payload or selected native identifiers for diagnosis. It should not flatten every balance, position, and order response into a universal object with zeros for missing fields. A missing wallet value may need initialization; it is not automatically a zero balance.
Order preparation needs the same discipline. A decimal string does not establish a permitted increment or a contract unit. The Binance filter example demonstrates arithmetic for USD-M Futures. Its filters must not be copied unchanged to Bybit or Coinbase.
Expose Unsupported Operations
A consumer may need one public ticker and no private access. Another may need fills for accounting, while an executor needs an order type supported by a particular account. Represent those requirements at the connector boundary and refuse operations the configured route cannot perform.
For example, a Spot-only connector cannot satisfy a request to reduce a derivative position by translating it into an ordinary sell. Position reduction depends on the actual product, account mode, and request fields. A plausible field mapping can change the action's meaning.
A generic isTestnet Boolean is also insufficient when the selected venue distinguishes demo, testnet, and limited sandbox services. The environment comparison describes what each test can establish. Unsupported environments should fail configuration rather than fall back to production.
Check the Native Boundary
A test that mocks only the common application interface never exercises the connector's native request. Keep fixtures at the SDK boundary for the required category, account route, client-ID mapping, quantity units, and business errors. Include an operation that the configured connector must refuse.
Then check one public read and stream through the normal application entrypoint. An account consumer adds the required private reads and topics, followed by an interruption that exercises recovery. A public message alone cannot establish private account access.
Credential loading and log redaction belong to the same configured boundary. Exceptions can contain signed URLs or private payloads; record method, environment, correlation ID, and exchange error instead. The shared security guidance covers credential storage and permissions.
Once that single route works, add another product with its own fixtures. Shared recording, scheduling, and decision code can consume the checked results. The system architecture article follows those consumers without requiring them to understand every exchange's request syntax.
Related articles
Continue from here