Open-source project
ccxt/ccxt avatar
ccxt/ccxt

CCXT 4.5.84: patches counted as releases, generated C# and Java, and optional normalization

A unified trading API with more than 100 crypto exchanges and prediction markets in JavaScript / TypeScript / Python / C# / PHP / Go / Java

44,224 stars8,880 forksPythonMIT

At a glance

What is it?
CCXT is an MIT licensed trading API covering more than 100 exchanges and prediction markets across eight language targets, published to seven package registries. The design decisions worth understanding are all in the build files rather than the pitch: the last version component is a release counter, the C# and Java ports are transpiled from one source tree, the coverage report excludes the shared base classes, and data normalization is opt-in rather than the default.
Who is it for?
CCXT fits a reader who wants one calling convention across several venues, who can name the specific exchange implementations they actually depend on, and who reads a changelog before every version bump. It does not fit a reader who needs the same method to return the same shape with and without options, who needs a language surface the build container does not cover, or who needs a portable abstraction and expects not to read vendor documentation.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The last version component is a release counter, so 4.5.84 is the 84th ship

Three releases in three days: v4.5.82 on 2026-09-21, v4.5.83 on 2026-09-23, and v4.5.84 on 2026-09-24, with the default branch pushed on 2026-09-29. The same number appears in two manifests, package.json and pyproject.toml, both at 4.5.84. Consequence: the trailing component is a counter, not a patch in the sense of no behaviour change. This library sits directly on other people's REST and WebSocket endpoints, and those endpoints change without a major version announcement on anyone's part, so a patch bump here can alter what a method returns or which URL it calls. Treat every patch as a release, pin exactly, and read CHANGELOG.md on each bump rather than letting a floating range pull a new one. The single project-wide counter is also a symptom of the packaging model, because the same version string has to stay in step across an npm manifest, a Python manifest, a composer.json, and eight language trees.

One exchange appears three times, and every table link is a referral URL

The certified exchange table has rows for binance, binanceusdm for Binance USD-margined futures, and binancecoinm for Binance COIN-M, then bybit and okx. Three ids for one venue is the abstraction showing its seam: spot, dollar-margined derivatives and coin-margined derivatives are three different APIs with three different endpoint sets, so they are three implementations rather than one with options. The table also has a column that links each exchange's own API documentation, which is the honest admission that the unified surface does not replace reading the vendor's docs. Consequence: a method that behaves correctly on binance tells you nothing about binanceusdm until you have read that exchange's documentation, so the count of 100 or more implementations is a count of independent adapters with uneven coverage. One more detail about the table: its links carry referral parameters such as ref=CCXTCOM, ref=XDK12WP and a join path, so clicking an exchange name in the README takes you to a signup page rather than to the exchange.

Normalization is optional, so the same method has two return shapes

One line in the feature list says the library optionally normalizes data for cross-exchange analytics and arbitrage. Optional is the operative word. Consequence: with the option off you get the exchange's own payload, and with it on you get the unified shape, which means the parsing code in your project has two branches and the branch you built against during development is not the branch that runs in production if the flag differs. The line also draws the project's own boundary. Normalization is positioned for cross-exchange analytics and arbitrage, not presented as a general-purpose canonicalizer, which tells you that without that option there is no cross-exchange layer at all and you are reading vendor formats. Related to the same theme, the list claims public and private APIs over both REST and WebSocket, so a single method name can be a request you make and an event you subscribe to, and the two are not the same object.

The coverage report excludes the base classes, the abstract layer and the WebSocket code

The coverage script is worth reading as a statement about what is and is not tested. It runs against an instrumented copy of js/ and passes excludes for js/src/pro/, js/src/base/, js/src/test/, js/src/abstract/ and js/src/static_dependencies. Those four source areas are the shared exchange base, the abstract layer, the WebSocket path, and the static dependency shims. Consequence: the coverage figure describes the per-exchange endpoint code, which is where the bulk of the lines are, and says nothing about the classes every exchange inherits from. A healthy percentage is therefore not evidence that the shared abstraction is exercised, and a change to the base class is exactly the kind of change that breaks 100 adapters at once without moving the number. The transpiler scripts draw the same line in a different place, since the C# and Java generators run with rest-and-ws flags and there are separate force variants plus a baseTests variant, so REST and WebSocket surfaces and the base class are generated as distinct pieces.

One source tree and two transpilers produce the C# and Java ports

The repository holds one directory per language target, cs/, go/, java/, js/, php/, python/, rust/ and ts/, and the build scripts name two generators by path: build/csharpTranspiler.ts and build/javaTranspiler.ts, the latter paired with generateJavaWrappers.ts. Consequence: a fix made in the canonical tree reaches the C# and Java ports on the next transpile run, and a change made only inside cs/ or java/ is overwritten by that run. So if you need different behaviour in a generated port, the change belongs upstream and is then regenerated, not patched in place. The scripts also carry force variants, which exist to overwrite a generated tree on request rather than merge into it, and that is the clearest signal that those directories are outputs. Go, PHP, Python and Rust are not covered by the two generators named in the scripts, so those ports are maintained some other way, and the script list does not say what way.

The ESM entry resolves into the source tree while the CommonJS entry resolves into dist

The exports map is asymmetric. The import condition points at types ./js/ccxt.d.ts and default ./js/ccxt.js, which is the source directory. The require condition points at types ./index.d.cts and default ./dist/ccxt.cjs, which is the build output. Consequence: an ESM consumer and a CommonJS consumer of the same version can execute different code, and the type declarations they see are two different files. For the browser the entry is a single file, dist/ccxt.browser.min.js, declared as the unpkg target, so a browser consumer gets one minified bundle rather than a tree of modules, which is the heaviest way to use the library and does not get the dead-code elimination that the sideEffects false flag exists to enable. One thing the manifest does set is publishConfig provenance true, so the published npm tarball carries a build attestation tied to its source, even though the README never mentions it.

The Docker setup is an interactive build shell with masked node_modules, not a service

docker-compose.yml defines one service named ccxt with entrypoint /bin/bash, stdin_open and tty, no published ports, and a comment showing how it is meant to be run:

bash
docker-compose run --rm ccxt

The volumes are the interesting part. The repository is bind-mounted at /ccxt, and two anonymous volumes are layered over /ccxt/node_modules/ and /ccxt/vendor/, each with a comment saying it prevents exposing the container's node_modules to the host filesystem. Consequence: there is nothing to start with up, this is a shell with the source tree mounted, and those two masked paths are there so a developer with their own node_modules or a PHP vendor directory on the host does not have it replaced by the container's. The image itself is a polyglot build environment on ubuntu:22.04 with PHP 8.4 from the ondrej repository, Node 20 from NodeSource, Python 3 with pip, and the .NET 10 SDK, while the README's support list names PHP 8.1+, Node 18+, Go 1.20+ and Java 21+ as well. The container and the support matrix are not the same set, and setuptools is pinned to 83.0.0 in both the Python build requirement and the pip install line.

Prediction markets joined the exchange list, and the agent surface is a second thing to keep in step

The feature list says the library supports 100 or more cryptocurrency exchanges and prediction markets, and the five named are Polymarket, Kalshi, Hyperliquid, Limitless and Myriad. A prediction market and a spot exchange do not share a domain model: an order book, a fill and a ticker mean different things in each, so the unified method set is a union of two vocabularies and the newest categories are where the abstraction is thinnest. The language lists disagree too. The README names eight targets including Rust, the repository description names seven without Rust, and the descriptions inside package.json and pyproject.toml name six without Java or Rust. The claim about being ideal for AI agents has files behind it rather than adjectives, in the form of an mcp/ directory, a context7.json, llms.txt and llms-full.txt for LLM context, a .claude-plugin/ directory, an install-skills.sh script and a skills-lock.json. So there is a second integration surface, an MCP server and a set of agent skills, to keep in step with the language packages, and the context files are their own maintenance task.

Editorial conclusion

CCXT fits a reader who wants one calling convention across several venues, who can name the specific exchange implementations they actually depend on, and who reads a changelog before every version bump. It does not fit a reader who needs the same method to return the same shape with and without options, who needs a language surface the build container does not cover, or who needs a portable abstraction and expects not to read vendor documentation. Before you build on it, check five things: which exchange ids you actually need, because spot, USD-margined and coin-margined variants of one venue are separate ids; whether you want normalized output, since normalization is described as optional and the two shapes are not interchangeable; whether your language is covered by the two transpilers, since the C# and Java ports are generated and a local edit there is overwritten; which exchange implementations are excluded from continuous testing, since a skip-tests.json sits in the tree; and whether a patch bump is safe, because in this numbering a patch is a release.

Frequently asked questions

What does CCXT stand for?

The repository title expands it as CryptoCurrency eXchange Trading Library. The README then describes it as a crypto trading API with more than 100 exchanges and prediction markets in JavaScript, TypeScript, Python, C#, PHP, Go, Java and Rust, intended for coders, developers, technically-skilled traders, data-scientists and financial analysts who are building trading algorithms.

Is CCXT free or is there a paid Pro tier?

The library itself is MIT licensed and the repository declares no paid tier. A separate hosted product called CCXT Terminal is described as a non-custodial trading platform built on the same open-source library, offering a scalper DOM, real-time liquidity visualization and low-latency order routing. The certified exchange table has a column linking a pro manual, and the coverage configuration excludes a js/src/pro/ path, so the paid material is adjacent to the library rather than part of it.

Which languages does CCXT ship for?

The README names JavaScript, TypeScript, Python, C#, PHP, Go, Java and Rust, with runtime requirements of Node 18+, Python 3, PHP 8.1+, netstandard2.0/2.1, Go 1.20+ and Java 21+, plus web browsers. The repository description lists seven of those and drops Rust, and the descriptions inside package.json and pyproject.toml list six, dropping Java and Rust, so the README carries the fullest list.

How do I install CCXT?

There is one published package per ecosystem, with badges for npm, PyPI, NuGet, Go modules, Maven Central, Packagist and crates.io. The npm manifest requires Node 18 or newer, the Python manifest requires Python 3.10 or newer even though the README says only Python 3, and the browser build is a single minified file served as the unpkg target.

Official sources

  1. Official documentation
  2. Official README
  3. Project repository
  4. Release notes
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/ccxt-ccxt.svg)](https://hysenlabs.com/projects/ccxt-ccxt)