Skip to main content

Binance4s

A typeclass-driven, functional Scala 3 library for the Binance API.

Built on Cats Effect, http4s, Circe, and fs2.

Why Binance4s?

The Binance API exposes hundreds of REST endpoints and WebSocket streams. Building a Scala client means dealing with:

  • URI construction for each endpoint with different paths, query parameters, and authentication requirements
  • Response deserialization for dozens of different JSON shapes (objects, arrays, arrays of arrays)
  • HMAC-SHA256 signing for authenticated endpoints with precise query string ordering
  • HTTP client lifecycle management across many concurrent requests
  • Error handling for API-specific error codes, rate limits, and network failures

Binance4s solves all of this with a single abstraction.

The Core Idea

Every Binance endpoint follows the same pattern: a request produces a response through a specific HTTP method, path, security model, and set of query parameters. This is a textbook use case for typeclasses.

trait BinanceEndpoint[Req, Resp]:
def method: HttpMethod
def path: Vector[String]
def security: SecurityType
def queryParams(req: Req): QueryString
def decoder: Decoder[Resp]

Each endpoint is a given instance. The compiler statically resolves which endpoint to call and what type the response will be — zero runtime reflection, full type safety.

// The compiler knows this returns F[OrderBook]
client.execute(DepthReq("BTCUSDT", Some(10)))

// Equivalent via syntax extension
client.depth("BTCUSDT", limit = Some(10))

Quick Example

import cats.effect.{IO, IOApp}
import io.github.rafafrdz.binance4s.config.BinanceConfig
import io.github.rafafrdz.binance4s.domain.BinanceMode
import io.github.rafafrdz.binance4s.http.client.BinanceClient
import io.github.rafafrdz.binance4s.api.*

object Main extends IOApp.Simple:
val config = BinanceConfig(mode = BinanceMode.Live)

def run: IO[Unit] =
BinanceClient.resource[IO](config).use { client =>
for
time <- client.serverTime
_ <- IO.println(s"Server time: ${time.serverTime}")
price <- client.tickerPrice("BTCUSDT")
_ <- IO.println(s"BTC price: ${price.price}")
yield ()
}

Features

56+ REST endpointsGeneral, Market Data, Spot Trading, Account, Wallet, and User Data Stream
12 WebSocket streamsReal-time market data via fs2.Stream — aggTrade, trade, kline, ticker, depth, and more
Typeclass architecturegiven/using for compile-time endpoint resolution — no runtime reflection
Resource-safe clientResource[F, BinanceClient[F]] with shared connection pool
Effect-polymorphicF[_]: Async — works with IO, ZIO interop, etc.
Typed errorsBinanceError enum with exhaustive pattern matching
Zero-boilerplate codecsCirce derives Codec.AsObject for all response models
HMAC-SHA256 signingAutomatic for authenticated endpoints, zero external dependencies

Module Structure

binance4s-api        ← what you depend on
├── binance4s-http ← http4s ember client with Resource lifecycle
├── binance4s-ws ← WebSocket client with fs2 streams
└── binance4s-core ← domain types, typeclasses, config, auth (zero HTTP deps)

Tech Stack

LibraryVersionPurpose
Scala3.3.6 LTSLanguage
Cats Effect3.6.1Effect system
http4s0.23.30HTTP client
Circe0.14.13JSON codecs
fs23.12.0Streaming
munit1.1.1Testing

License

Apache License 2.0