Skip to content

Add Betfair Exchange and Smarkets (market data and streams) - #33

Merged
YukiC0804 merged 2 commits into
mainfrom
sp/betfair-delayed
Oct 21, 2026
Merged

YukiC0804 merged 2 commits into
mainfrom
sp/betfair-delayed

Conversation

@YukiC0804

Copy link
Copy Markdown
Collaborator

Adds two betting exchanges as venues, read side only. Neither trades yet.

Mapping

  • Each runner (Betfair) or contract (Smarkets) is a binary YES/NO market: betfair:<marketId>-<selectionId> (a non-zero handicap adds -<handicap>) and smarkets:<marketId>-<contractId>. The exchange market is its event, the way multi-outcome events already work.
  • Betfair: back offers become YES asks at 1/odds and lay offers YES bids. Sizes are contracts = stake × odds. A test checks no book is crossed.
  • Smarkets: prices are basis points of 100%. Quantities are in 1/10,000 of a £1 contract. Smarkets bids are YES bids. Volume is whole GBP per Smarkets market.
  • Commission on net winnings per market is a new net_market_winnings fee type: Betfair at the market base rate, Smarkets at 2%.

Betfair (betfair), for the free delayed app key

  • Interactive and certificate login, a session kept alive in memory, jurisdiction hosts.
  • Event types, events, the market catalogue and books, batched to stay under the 200-point request weight. Prices stay on the CLASSIC odds ladder.
  • Books are marked delayed.
  • An Exchange Stream API client over TLS (not WebSocket): images, deltas, resubscribe with clk. It warns once that a delayed key is conflated to 3 minutes.
  • No trade tape or candles, because Betfair publishes neither.

Smarkets (smarkets), with no login needed for market data

  • Events, markets, contracts, quotes, volumes, last prices, states, recent trades and search, with an optional session login.
  • A polled market stream, because push streaming is for approved API users only.
  • Cloudflare refuses the default python and curl User-Agents, so the adapter identifies itself as synpath/<version>.

Also

  • Client.trading("betfair" | "smarkets") raises NotSupported.
  • init and doctor say what each credential is for.
  • The README, capabilities, API, streaming and trading docs cover the delayed data, the API region blocks, and the licence terms on showing prices to others.
  • The contract and server tests now use notavenue as their unknown-venue example.

Tests

  • 182 new offline tests: 69 for Betfair, 22 for the Betfair stream, 68 for Smarkets, 23 for the Smarkets stream.
  • Smarkets uses real recorded responses. Betfair samples are hand-built from its documentation, because Betfair needs a login for every call.
  • Full suite: 2443 passed, 3 skipped, 140 deselected (live/demo). The Smarkets live tests (3) pass.

Not verified live

  • Betfair has had no live call yet: no account exists.
  • Betfair's .it/.es/.ro/.com.au hosts, error-body shapes and the response from blocked countries.
  • Smarkets' login flow, the delay on anonymous quotes and its restricted countries.

Merge order

Overlaps with #32 in credentials, init, feeds and docs. Merge #32 first, then rebase this.

🤖 Generated with Claude Code

Two betting exchanges as venues, read side only. Each runner or contract is a
binary YES/NO market (betfair:<marketId>-<selectionId>,
smarkets:<marketId>-<contractId>) and the exchange market is its event, the
way multi-outcome events already work.

Betfair (betfair): interactive and certificate login with session keep-alive,
catalogue, events and books batched under the request-weight limit, the
CLASSIC odds ladder, a net-market-winnings commission fee type, and an
Exchange Stream API client over TLS. Built for the free delayed app key:
books are marked delayed and the stream warns that it is conflated to three
minutes. Back offers are YES asks at 1/odds and lay offers YES bids.

Smarkets (smarkets): public market data with no login (events, markets,
contracts, quotes, volumes, last prices, states, recent trades, search),
prices in basis points and quantities in 1/10,000 of a pound contract, 2%
commission on net winnings, an optional session login, and a polled market
stream, since push streaming is for approved API users only.

Neither venue trades yet; Client.trading() says so. init and doctor say what
each credential is for. Docs cover the delayed data, API region blocks and
the licence terms on showing prices to others.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@YukiC0804
YukiC0804 merged commit 0ababe8 into main Oct 21, 2026
3 of 4 checks passed
YukiC0804 added a commit that referenced this pull request Oct 21, 2026
YukiC0804 pushed a commit that referenced this pull request Oct 21, 2026
Keeps #30's venue_streams / market_stream / MarketStreams structure and fits
main into it:

- venue_streams accepts a MarketDataKey (Opinion, predict.fun, SX Bet) and
  builds the market stream alone from it, with a keyed catalog where no
  adapter supplies one; market_stream and default_streams(market_data) go
  through it.
- Betfair and Smarkets market streams (Smarkets without credentials).
- SX Bet's account stream only with an account address, warning otherwise.
- serve always loads market_data, passes it to default_streams and to the
  /ws/market factory, and gives the read app's default VenueRegistry its
  dotenv keys; #30's auth dependency, hosted routes and buckets stay.
- The dotenv read-app test sends serve's access token.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
YukiC0804 pushed a commit that referenced this pull request Oct 21, 2026
Merges cleanly. Main's trading changes (SX Bet's key-only trading, Betfair
and Smarkets instruments, init/doctor) build no OrderRequest, Order or Fill
and bring back no reduce_only or fair values, so nothing needed porting to
outcome + action.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant