Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Ccxt Laravel Package

kornrunner/ccxt

PHP port of CCXT, giving Laravel and PHP applications a unified API to connect to dozens of cryptocurrency exchanges for market data, tickers, order books, balances, and trading. Fetch prices and account info across exchanges with one consistent interface, without writing separate integrations for e...

View on GitHub
Deep Wiki
Context7

Getting Started

Install with Composer and pin the version, since this library is a snapshot of an older CCXT (Feb 2021):

composer require kornrunner/ccxt

First place to look is src/ccxt/Exchange.php and one exchange class you care about (src/ccxt/binance.php, src/ccxt/kraken.php, etc.). The Exchange base class exposes the uniform API — if a method works on one exchange, the calling convention is the same for all ~110 of them. Also skim the upstream CCXT manual at ccxt.github.io: the method semantics, parameter shapes, and options keys are all inherited from there, even though the PHP port uses snake_case (fetch_ticker, create_order) instead of camelCase.

Minimal first use case — read a public ticker with no credentials:

$exchange = new \ccxt\binance();
$ticker   = $exchange->fetch_ticker('BTC/USDT');
echo $ticker['last'];

Once you trust the read path, add credentials and hit an authenticated endpoint:

$exchange = new \ccxt\kraken([
    'apiKey'        => config('services.kraken.key'),
    'secret'        => config('services.kraken.secret'),
    'enableRateLimit' => true,
]);
$balances = $exchange->fetch_balance();

Store keys in .env, never in code; use read-only keys during development.

Implementation Patterns

Wrap the exchange in a domain service. Don't sprinkle new \ccxt\binance() across controllers — inject a configured client and keep the CCXT array shape out of your domain:

final class BinanceClient
{
    public function __construct(private \ccxt\Exchange $exchange) {}
    public function lastPrice(string $symbol): string
    {
        return $this->exchange->fetch_ticker($symbol)['last'];
    }
}

Bind it once in a service provider so swapping exchanges (Binance → Kraken, spot → futures) is a one-line change.

Normalise the return shapes early. CCXT returns loosely-typed associative arrays with numeric strings. Cast into your own DTOs (value objects for Price, Amount) before they reach business logic. This is what makes the library usable in a Laravel app rather than a script.

Use the options array for exchange behaviour, not for every call. Set defaultType => 'future', adjustForTimeDifference => true, and rate limits once at construction. Method-level overrides belong in the call site only when they genuinely vary per request.

Rate limiting and caching go together. Even with enableRateLimit => true, a dashboard hitting fetch_ticker per request will hammer the exchange. Cache tickers in Redis for a few seconds and cache fetch_balance / fetch_open_orders for longer. Treat fetch_markets() as a boot-time cache — it's the heaviest call and rarely changes.

Order lifecycle. Typical pattern: create_order → store the exchange order id → poll fetch_order on a queue job with backoff → reconcile against fetch_open_orders on a schedule. Don't poll in a web request; put it on a scheduled job.

Sandbox first. Where supported, $exchange->set_sandbox_mode(true) before testing create_order. Not every exchange implements it, and some implementations are stale — validate by placing a minimum-size order on a funded testnet account.

Error handling at the boundary. Catch \ccxt\BaseError subclasses (AuthenticationError, InsufficientFunds, RateLimitExceeded, NetworkError) and translate them into your own exceptions. Retry only idempotent reads; never blind-retry create_order — use a client order id (clientOrderId in params) to make it safely retryable.

Gotchas and Tips

  • The package is stale. Last release was early 2021. Exchange APIs have moved on: some endpoints, signing schemes, and params keys are outdated. Expect certain exchanges in this fork to be broken against live APIs. Pin the version in composer.lock, smoke-test each exchange you rely on, and be prepared to fork/patch individual exchange classes (they're plain PHP, one file each — this is the intended extension point).
  • snake_case, not camelCase. Every CCXT tutorial you find online will say fetchTicker / createOrder. In this library it's fetch_ticker / create_order. This one detail burns most newcomers.
  • Amounts and prices must be strings. PHP floats lose precision; passing 0.1 + 0.2 as a quantity gets your order rejected or silently rounded. Always pass '0.10000000' and format with the exchange's precision/limits from fetch_markets().
  • Time skew kills authenticated calls. Several exchanges reject requests where the local clock is >30s off with an opaque signature error. Set adjustForTimeDifference => true and run NTP on the host.
  • fetch_markets() is expensive and cached server-side. Call once, persist the result, and refresh on a schedule — not in every request.
  • Rate limits are per-exchange and per-endpoint. enableRateLimit uses the exchange's own rateLimit hint, which may be stale. Add your own leaky bucket in front for production traffic.
  • Not all exchanges in the namespace actually work. The 110+ count includes placeholders and abandoned implementations. Read the specific exchange file before committing to it; if you only need two or three exchanges, verify those individually.
  • null and missing keys are normal. CCXT normalises loosely — $ticker['bid'] may be null, fetch_ohlcv rows are [timestamp, open, high, low, close, volume] arrays. Guard every access or use a normaliser.
  • Debugging tip: override the HTTP client or log the raw request/response inside the exchange class ($this->client) rather than trying to infer errors from CCXT's messages — the underlying error is often the exchange's raw JSON in $e->getMessage().
  • Don't run it in a shared hosting sandbox without curl/TLS outbound access, and never in a context where the process can be killed mid-create_order without a client-order-id reconciliation step.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings