Skip to content

keel-broker-binance Phase A: adapter package + port conformance suite green #565

Description

@eaitbrahim

Blocked on #564 — the entity decides the endpoints, the auth scheme and the fee table.

Mirrors #369 (keel-broker-alpaca Phase A). The path is well-trodden now: keel-broker-api is the
port, four adapters implement it, and the conformance suite in
keel_broker_api/conformance/suite.py holds every one of them to the same contract.

Scope

A packages/keel-broker-binance/ distribution implementing Broker, registered through the
keel.brokers entry point, with tests/conformance/test_binance_conformance.py green.

The port's full surface, as it stands after #563:

method note
capabilities() venue, asset_classes={"crypto"}, quote_currencies — see #564 on whether that includes USDT
market_clock() / market_schedule() 24×7, so both are the trivial declarations test_market_clock_is_open_without_a_call_for_24x7_venues expects
get_candles() /api/v3/klines
get_balances() /api/v3/account, mapped to Balance(currency, available, total)available is spendable, total includes locked, and the distinction is load-bearing (rail 13; see #562)
get_instrument() /api/v3/exchangeInfo → the LOT_SIZE filter's stepSize is base_increment
preview_order() Binance has no preview endpoint; declare can_preview=False and refuse, as the fake does — never synthesise a quote
place_order() / get_order() / cancel_order() /api/v3/order; cancel_order must return CancelOutcome honestly — CONFIRMED only when the venue states this order is terminal-cancelled
get_fee_summary() /sapi/v1/asset/tradeFee

The order kinds, and the one that needs a decision

OrderSpec is MarketIOCByQuote | MarketIOCByBase | LimitGTC | StopLimitGTC | BracketGTC. The
first four map cleanly. BracketGTC is the question: Binance spot has OCO (/api/v3/orderList/oco),
which is genuinely the same shape keel means — one order carrying both protective prices, with the
venue owning the race.

If it maps, declare it and let test_the_bracket_declaration_cannot_lie_in_either_direction prove
it. If it does not, refuse it explicitly in to_order_configuration#521 records that widening
the union broke Alpaca and Robinhood under mypy and each needed an explicit refusal case, "the
better outcome", and every new adapter meets the same wall by construction.

Not in scope

Margin, futures, Earn, lending, staking. Rails 18/19 are the charter — "Spot-only is this agent's
CHARTER, not an operator preference" — and an adapter that could express them would be a shape no
keel path produces.

Acceptance

  • tests/conformance/test_binance_conformance.py green, no test skipped or specialised for this venue.
  • capabilities() declares only what the adapter actually does; the conformance suite proves each claim.
  • No venue-native type crosses the port (test_get_balances_returns_only_domain_types and its siblings).
  • get_instrument returns None for an unlisted symbol and never a non-positive increment.
  • The bracket is either implemented and declared, or refused explicitly with the reason recorded.
  • Dev-only dependency, like keel-broker-robinhood, until something constructs it at runtime (Finish the broker-port migration: _build_broker still constructs CoinbaseClient directly #524).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions