# CCXT Client
Elixir client for 100+ cryptocurrency exchanges. This is a standalone package
generated from [ccxt_ex](https://github.com/ZenHive/ccxt_ex).
## Status
**This is an early release (v0.x).** Here's what works and what needs testing:
- **Public endpoints** (tickers, orderbooks, trades) work across all 110+ exchanges
- **All exchanges** compile and pass unit tests with mocked HTTP responses
- **7 signing patterns** are implemented, covering 95%+ of exchanges
- **Authenticated endpoints** (trading, balances) have been verified with real API
credentials on a small number of exchanges (Deribit, Bybit, and a few others)
The signing implementations are correct to the spec, but most exchanges still need
real-world validation with actual API credentials. This is where you can help.
**We'd love your help testing.** If you use an exchange we haven't validated yet:
1. Try public endpoints first (`fetch_ticker`, `fetch_order_book`)
2. Then try authenticated endpoints with testnet/sandbox credentials
3. [Open an issue](https://github.com/ZenHive/ccxt_client/issues) with what worked and what didn't
Every exchange you test helps the whole community.
## Installation
```elixir
def deps do
[
{:ccxt_client, "~> 0.1"}
]
end
```
## Usage
```elixir
# Get ticker from any exchange
{:ok, ticker} = CCXT.Binance.fetch_ticker("BTC/USDT")
{:ok, ticker} = CCXT.Bybit.fetch_ticker("BTC/USDT")
{:ok, ticker} = CCXT.OKX.fetch_ticker("BTC/USDT")
# Authenticated requests
credentials = CCXT.Credentials.new(api_key: "...", secret: "...")
{:ok, balance} = CCXT.Binance.fetch_balance(credentials)
```
## Configuration
Configure the client via application config (:ccxt_client).
```elixir
config :ccxt_client,
recv_window_ms: 10_000,
request_timeout_ms: 60_000,
rate_limit_cleanup_interval_ms: 120_000,
rate_limit_max_age_ms: 120_000,
retry_policy: :safe_transient,
debug: false,
broker_id: "MY_APP_BROKER"
config :ccxt_client, :circuit_breaker,
enabled: true,
max_failures: 5,
window_ms: 10_000,
reset_ms: 15_000
```
### Top-level keys
| Key | Type | Default | Description |
| --- | --- | --- | --- |
| `recv_window_ms` | `pos_integer` | `5000` | Request timestamp validity window (rejects stale requests). |
| `request_timeout_ms` | `pos_integer` | `30000` | HTTP request timeout in milliseconds. |
| `extraction_timeout_ms` | `pos_integer` | `30000` | Per-exchange extraction timeout used by mix tasks. Notes: Only used by mix tasks, not runtime requests. |
| `rate_limit_cleanup_interval_ms` | `pos_integer` | `60000` | Interval for cleaning up old rate limit timestamps. |
| `rate_limit_max_age_ms` | `pos_integer` | `60000` | Maximum age for rate limit request timestamps. |
| `retry_policy` | `retry_policy` | `:safe_transient (test: false)` | Req retry policy for HTTP requests. Notes: In :test, default is false (no retries). |
| `debug` | `boolean` | `false` | Log exceptions with full stack traces. Notes: May log sensitive data; use only in development. |
| `broker_id` | `string` | `nil` | Optional broker identifier appended to requests. |
### Circuit breaker keys
| Key | Type | Default | Description |
| --- | --- | --- | --- |
| `enabled` | `boolean` | `true` | Enable or disable the circuit breaker. |
| `max_failures` | `pos_integer` | `5` | Failures before circuit opens (0 disables). |
| `window_ms` | `pos_integer` | `10000` | Time window for counting failures. |
| `reset_ms` | `pos_integer` | `15000` | Time before circuit resets (closes). |
### Machine-readable config spec
```json
[
{
"default": 5000,
"type": "pos_integer",
"path": [
"recv_window_ms"
],
"description": "Request timestamp validity window (rejects stale requests).",
"key": "recv_window_ms",
"examples": [
"config :ccxt_client, recv_window_ms: 10_000"
]
},
{
"default": 30000,
"type": "pos_integer",
"path": [
"request_timeout_ms"
],
"description": "HTTP request timeout in milliseconds.",
"key": "request_timeout_ms",
"examples": [
"config :ccxt_client, request_timeout_ms: 60_000"
]
},
{
"default": 30000,
"type": "pos_integer",
"path": [
"extraction_timeout_ms"
],
"description": "Per-exchange extraction timeout used by mix tasks.",
"key": "extraction_timeout_ms",
"examples": [
"config :ccxt_client, extraction_timeout_ms: 60_000"
],
"notes": [
"Only used by mix tasks, not runtime requests."
]
},
{
"default": 60000,
"type": "pos_integer",
"path": [
"rate_limit_cleanup_interval_ms"
],
"description": "Interval for cleaning up old rate limit timestamps.",
"key": "rate_limit_cleanup_interval_ms",
"examples": [
"config :ccxt_client, rate_limit_cleanup_interval_ms: 120_000"
]
},
{
"default": 60000,
"type": "pos_integer",
"path": [
"rate_limit_max_age_ms"
],
"description": "Maximum age for rate limit request timestamps.",
"key": "rate_limit_max_age_ms",
"examples": [
"config :ccxt_client, rate_limit_max_age_ms: 120_000"
]
},
{
"default": "safe_transient",
"type": "retry_policy",
"path": [
"retry_policy"
],
"description": "Req retry policy for HTTP requests.",
"key": "retry_policy",
"examples": [
"config :ccxt_client, retry_policy: :safe_transient"
],
"notes": [
"In :test, default is false (no retries)."
],
"default_test": false
},
{
"default": false,
"type": "boolean",
"path": [
"debug"
],
"description": "Log exceptions with full stack traces.",
"key": "debug",
"examples": [
"config :ccxt_client, debug: true"
],
"notes": [
"May log sensitive data; use only in development."
]
},
{
"default": null,
"type": "string",
"path": [
"broker_id"
],
"description": "Optional broker identifier appended to requests.",
"key": "broker_id",
"examples": [
"config :ccxt_client, broker_id: \"MY_APP_BROKER\""
]
},
{
"default": true,
"type": "boolean",
"path": [
"circuit_breaker",
"enabled"
],
"description": "Enable or disable the circuit breaker.",
"key": "circuit_breaker",
"examples": [
"config :ccxt_client, :circuit_breaker, enabled: true"
]
},
{
"default": 5,
"type": "pos_integer",
"path": [
"circuit_breaker",
"max_failures"
],
"description": "Failures before circuit opens (0 disables).",
"key": "circuit_breaker",
"examples": [
"config :ccxt_client, :circuit_breaker, max_failures: 5"
]
},
{
"default": 10000,
"type": "pos_integer",
"path": [
"circuit_breaker",
"window_ms"
],
"description": "Time window for counting failures.",
"key": "circuit_breaker",
"examples": [
"config :ccxt_client, :circuit_breaker, window_ms: 10_000"
]
},
{
"default": 15000,
"type": "pos_integer",
"path": [
"circuit_breaker",
"reset_ms"
],
"description": "Time before circuit resets (closes).",
"key": "circuit_breaker",
"examples": [
"config :ccxt_client, :circuit_breaker, reset_ms: 15_000"
]
}
]
```
## Selective Compilation
By default, all bundled exchanges are compiled. To compile only a subset:
```elixir
config :ccxt_client, exchanges: [:binance, :bybit, :okx]
```
Pass a list of exchange atoms or strings. Unlisted exchanges become stub modules
(no API functions generated), reducing compile time and binary size.
## Scaffolding Exchange Modules
Generate exchange modules in your application's namespace:
```bash
mix ccxt.gen binance kraken # Generate specific exchanges
mix ccxt.gen --list # Show available specs with tier info
mix ccxt.gen --tier1 # Generate all Tier 1 exchanges
mix ccxt.gen --all # All available exchanges
mix ccxt.gen --force # Overwrite existing files
mix ccxt.gen --namespace Trading # Custom module namespace
```
This creates modules like:
```elixir
defmodule MyApp.Exchanges.Binance do
use CCXT.Generator, spec: "binance"
end
```
## Discovering Available Specs
List bundled exchange specs at runtime:
```elixir
CCXT.Exchange.Discovery.available_specs()
# => ["binance", "bybit", "deribit", ...]
CCXT.Exchange.Discovery.available_spec?("binance")
# => true
```
## Supported Exchanges
This package supports 100+ exchanges. See the `lib/ccxt/exchanges/` directory
for the full list.
## Generated Package
This package was generated using:
```bash
mix ccxt.sync --all --output ../ccxt_client
```
To regenerate with updated exchange specs, run the above command from the
ccxt_ex project directory.