New to Claude Skills? Learn how to install them →

Nccxt on GitHub

New Exchange Integration

Free

Easily scaffold new CCXT exchange integrations in TypeScript.

by ccxt43.6k stars on ccxt/ccxt
Updated Aug 10, 2026
Get this skill

Free · Opens the source repo

What New Exchange Integration does

The New Exchange Integration skill is designed for developers looking to add support for new cryptocurrency exchanges within the CCXT framework. By following a structured approach, this skill guides users through the process of creating a new exchange integration in TypeScript, ensuring adherence to the established conventions and requirements of the CCXT library. This skill is particularly useful for developers who want to streamline their integration process, avoiding the complexities of starting from scratch.

When using this skill, developers will begin by selecting a reference exchange that closely resembles the new exchange they wish to integrate. The skill provides a variety of certified exchanges to choose from, allowing users to copy and adapt existing code rather than reinventing the wheel. This approach not only saves time but also ensures that the new integration aligns with the standards set by the CCXT community.

Once a reference exchange is selected, the skill walks users through the necessary steps to create a new TypeScript file for the exchange. It covers essential components such as defining API methods, specifying required credentials, and setting up the exchange's capabilities. Additionally, the skill emphasizes the importance of thorough documentation, encouraging users to include docstrings for every public method to facilitate future maintenance and collaboration.

This skill is ideal for developers who are familiar with TypeScript and the CCXT framework, and who need to integrate new exchanges efficiently. By leveraging this skill, users can ensure that their new integrations are robust, well-documented, and compliant with CCXT standards.

When to use it

Use this skill when you need to integrate a new cryptocurrency exchange into the CCXT framework, especially if it does not already exist in the library.

When not to use it

This skill may not be suitable for exchanges that require highly customized implementations or for developers unfamiliar with TypeScript and the CCXT framework.

What you can build with it

Integrating a New Exchange

When a developer needs to add a new exchange to the CCXT library, they can use this skill to scaffold the integration efficiently.

Adapting an Existing Exchange

If a developer wants to create a variation of an existing exchange, they can select a similar certified exchange as a reference and adapt the code.

Documenting Exchange Methods

While implementing the integration, this skill encourages thorough documentation, ensuring that all public methods are well-defined for future reference.

How to install New Exchange Integration

View source

1. Install with the skills CLI

npx skills add ccxt/ccxt/new-exchange --agent claude-code

2. Or install it manually

Download the skill folder and drop it into ~/.claude/skills/ for all projects, or .claude/skills/ to scope it to one repo. Restart Claude Code so it picks up the new skill.

Anthropic's agentic coding CLI, and the reference implementation of Agent Skills. Drop a skill folder into ~/.claude/skills and Claude Code loads it automatically whenever a task matches the skill's description. Claude Code docs

Inside SKILL.md

Written by ccxt

New Exchange Integration

Scaffold a new exchange in ts/src/<id>.ts (REST) and optionally ts/src/pro/<id>.ts (WebSocket).

Read first: wiki/Requirements.md (mandatory unified methods) and CONTRIBUTING.md (transpiler rules). The CCXT root CLAUDE.md is the contributor guide.

Inputs

  • <id>: lowercase exchange id, no separators (e.g. mynewex)
  • <Name>: human-readable name (e.g. My New Exchange)
  • API docs URL(s)
  • Whether the exchange has a testnet/sandbox

Step 1 — Pick a reference exchange

Don't write from scratch. Copy a similar exchange that's already certified and adapt it.

StyleReference
Spot + futures, signed RESTts/src/binance.ts, ts/src/okx.ts
Spot onlyts/src/kraken.ts, ts/src/coinbase.ts
Derivatives focusts/src/bybit.ts, ts/src/bitmex.ts
Decentralised / on-chain signingts/src/hyperliquid.ts, ts/src/dydx.ts
WebSocket referencets/src/pro/binance.ts, ts/src/pro/okx.ts

Open the reference next to your new file and pattern-match — never invent new conventions.

Step 2 — Create ts/src/<id>.ts

Skeleton:

import Exchange from './abstract/<id>.js';
import { /* errors needed */ } from './base/errors.js';
import { Precise } from './base/Precise.js';
import type { /* types needed */ } from './base/types.js';

export default class <id> extends Exchange {
    describe (): any {
        return this.deepExtend (super.describe (), {
            'id': '<id>',
            'name': '<Name>',
            'countries': [ 'XX' ],
            'rateLimit': 1000,        // ms between requests
            'version': 'v1',
            'certified': false,
            'pro': false,             // flip to true when pro/<id>.ts exists
            'has': {
                // start everything false; flip to true as you implement
                'CORS': undefined,
                'spot': true,
                'margin': false,
                'swap': false,
                'future': false,
                'option': false,
                'fetchMarkets': true,
                'fetchCurrencies': true,
                'fetchTicker': true,
                'fetchTickers': false,
                'fetchOrderBook': true,
                'fetchTrades': true,
                'fetchOHLCV': false,
                'fetchBalance': true,
                'createOrder': true,
                'cancelOrder': true,
                'fetchOrder': true,
                'fetchOpenOrders': true,
                'fetchOrders': false,
                'fetchClosedOrders': false,
                'fetchMyTrades': true,
                'fetchDeposits': false,
                'fetchWithdrawals': false,
                'withdraw': false,
            },
            'urls': {
                'logo': 'https://...',
                'api': {
                    'public': 'https://api.<id>.com',
                    'private': 'https://api.<id>.com',
                },
                'test': {                              // OPTIONAL — only if testnet exists
                    'public': 'https://testnet.<id>.com',
                    'private': 'https://testnet.<id>.com',
                },
                'www': 'https://<id>.com',
                'doc': [ 'https://docs.<id>.com' ],
                'fees': 'https://<id>.com/fees',
            },
            'api': {
                'public': {
                    'get': [
                        'symbols',
                        'ticker/{pair}',
                        'orderbook/{pair}',
                    ],
                },
                'private': {
                    'get': [ 'account', 'orders' ],
                    'post': [ 'order' ],
                    'delete': [ 'order/{id}' ],
                },
            },
            'requiredCredentials': {
                'apiKey': true,
                'secret': true,
                // 'password': true,        // for passphrase-based exchanges
                // 'walletAddress': true,   // for on-chain
                // 'privateKey': true,
            },
            'fees': {
                'trading': {
                    'tierBased': false,
                    'percentage': true,
                    'maker': 0.001,
                    'taker': 0.001,
                },
            },
            'precisionMode': /* TICK_SIZE | DECIMAL_PLACES | SIGNIFICANT_DIGITS */,
            'options': {
                // exchange-specific defaults
            },
            'exceptions': {
                'exact': {
                    // 'ERROR_CODE': BadRequest,
                },
                'broad': {
                    // 'invalid signature': AuthenticationError,
                },
            },
        });
    }

    // implement the unified methods you flipped on in `has`
    async fetchMarkets (params = {}): Promise<Market[]> { /* ... */ }
    parseMarket (market: Dict): Market { /* ... */ }
    async fetchTicker (symbol: string, params = {}): Promise<Ticker> { /* ... */ }
    parseTicker (ticker: Dict, market: Market = undefined): Ticker { /* ... */ }
    // ...

    sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        // build URL, sign request — use this.hmac, this.jwt, this.ecdsa, never external libs
    }

    handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
        // throw the right exception based on response
    }
}

Step 3 — Define implicit API methods

URLs in the api block become methods automatically:

  • 'symbols'this.publicGetSymbols(params)
  • 'ticker/{pair}'this.publicGetTickerPair({ pair: market['id'] })
  • 'orders' under private.getthis.privateGetOrders(params)

Don't write explicit HTTP wrappers. After listing the URL in api, run npm run emitAPITs to regenerate ts/src/abstract/<id>.ts (the auto-typed declarations).

Step 4 — Docstrings on every public method

Every public method needs a JSDoc block. The transpilers convert it to native docstrings in Python/PHP/C#/Go, and npm run build-docs produces wiki entries from them. Pattern:

/**
 * @method
 * @name <id>#fetchMyTrades
 * @description fetches all completed trades made by the user
 * @see https://docs.<id>.com/api/trades                 // spot
 * @see https://docs.<id>.com/api/derivatives/trades     // swap
 * @param {string} symbol unified market symbol
 * @param {int} [since] earliest timestamp in ms
 * @param {int} [limit] maximum number of trades to return
 * @param {object} [params] extra parameters specific to the exchange API endpoint
 * @param {int} [params.until] latest timestamp in ms
 * @returns {object[]} a list of [trade structures](https://docs.ccxt.com/#/?id=trade-structure)
 */
async fetchMyTrades (symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}): Promise<Trade[]> {
    // ...
}

Rules: lowercase @description, @param {object} [params] always present, document every params.<key> you read in the body, link @returns to the manual structure. See CLAUDE.md §7 for the full ruleset.

Step 5 — Required parsers

For every fetch method, write a matching parser. The parser is what makes output uniform across all exchanges:

Fetch methodParserValidator (test)
fetchMarketsparseMarketts/src/test/Exchange/base/test.market.ts
fetchCurrenciesparseCurrencytest.currency.ts
fetchTickerparseTickertest.ticker.ts
fetchOrderBookbase parseOrderBooktest.orderBook.ts
fetchTrades, fetchMyTradesparseTradetest.trade.ts
fetchOHLCVparseOHLCVtest.ohlcv.ts
fetchBalanceparseBalancetest.balance.ts
createOrder, fetchOrder, fetchOpenOrdersparseOrdertest.order.ts
fetchPositionsparsePositiontest.position.ts

Parsing rules (also in CLAUDE.md §7):

  • Always safeString first, parse with Precise for math, finalise with parseNumber only at the return.
  • Symbol resolution: this.safeSymbol(marketId, market) — never put exchange-specific ids into unified output.
  • Time: convert seconds → ms using safeTimestamp; everything in unified output is ms.

Step 6 — Static fixtures (TDD)

Capture a request/response fixture as soon as a method works once. Re-run on every change.

# request fixture (URL/body assertion) — NO HTTP
node cli.js <id> fetchTicker BTC/USDT --report
# response fixture (parser assertion) — NO HTTP
node cli.js <id> fetchTicker BTC/USDT --response

Paste each methods.<methodName> entry into ts/src/test/static/request/<id>.json or ts/src/test/static/response/<id>.json. Then run:

npm run request-tests
npm run response-tests

These tests run in all five languages and are your primary regression net.

Step 7 — Verify in all languages

A new exchange means thousands of new lines in Python, PHP, C#, Go and Java. The transpilers must like all of it.

npm run lint
npm run tsBuild
npm run transpile          # → Python, PHP
npm run transpileCS        # → C#
npm run buildCS
npm run transpileGO        # → Go
npm run buildGO
npm run check-python-syntax
npm run check-php-syntax
npm run id-tests
npm run request-tests
npm run response-tests

Then a live smoke test on at least one public method per language:

npm run cli.ts -- <id> fetchTicker BTC/USDT --verbose
npm run cli.py -- <id> fetchTicker BTC/USDT --verbose
npm run cli.php -- <id> fetchTicker BTC/USDT --verbose
npm run cli.cs -- <id> fetchTicker BTC/USDT --verbose
npm run cli.go -- <id> fetchTicker BTC/USDT --verbose

Step 8 — WebSocket support (optional)

If the exchange has WS, create ts/src/pro/<id>.ts. It must extends <id>Rest and add watch* methods. Reference: ts/src/pro/binance.ts. Flip 'pro': true in REST describe().

Step 9 — Update user-facing docs

A new exchange means new public surface area. Update the touchpoints listed in CLAUDE.md §8:

  • wiki/Manual.md doesn't usually list per-exchange specifics, but add a section if your exchange introduces a new pattern (e.g. a new auth scheme, new params).
  • Verify examples/ts/<id>-example.ts has at least one runnable snippet (transpiled to other languages by npm run tsBuildExamples).
  • The end-user skills under .claude/skills/ccxt-{typescript,python,php,csharp,go}/ mention "all 100+ exchanges" — usually no edit needed unless your exchange has unique credential requirements (e.g. wallet/private key) worth calling out.
  • npm run build-docs regenerates wiki entries from your JSDoc — run it once and inspect the output.

Step 10 — PR

Title: feat(<id>): add <Name> integration. Description follows the template in CLAUDE.md §11 — list every test you ran with results, and reference any related issue/PR.

Output checklist

  • ts/src/<id>.ts written (uses Precise, safeString*, safeSymbol)
  • Every public method has a JSDoc block (CLAUDE.md §7)
  • 'has' flags accurately reflect implemented methods
  • 'urls.test' set if exchange has a testnet
  • 'requiredCredentials' matches what sign() actually uses
  • All required parsers (parseMarket, parseTicker, parseTrade, parseOrder, …)
  • handleErrors maps exchange error codes to CCXT exception classes
  • ts/src/abstract/<id>.ts regenerated via npm run emitAPITs
  • Static request + response fixtures for every implemented method
  • npm run lint && npm run tsBuild && npm run transpile && npm run transpileCS && npm run transpileGO all pass
  • npm run id-tests && npm run request-tests && npm run response-tests all pass
  • Live smoke tested in TS + at least one transpiled language (cli.py, cli.cs, cli.go, …) with --verbose
  • npm run build-docs ran, generated wiki entries look correct
  • User-facing docs reviewed (CLAUDE.md §8) — Manual.md / examples / language skills if anything is non-standard
  • PR title follows feat(<id>): ...; description fills CLAUDE.md §11 template

Prediction-market exchange variant

A prediction-market venue (Polymarket-style: events → markets → binary/categorical outcomes) does not extend Exchange — it lives in its own namespace. The differences from the checklist above:

  1. Filets/src/prediction/<id>.ts, class <id> extends PredictionExchange (import Exchange from ./abstract/prediction/<id>.js). Read .claude/rules/prediction-outcomes.md for the outcome-cache contract and ts/src/base/PredictionExchange.ts for the base helpers you inherit (loadOutcome/loadOutcomes/fetchOutcome/populateOutcomes/indexMarketOutcomes/safeOutcome/outcome, setEvents/getEvent/eventsList/applyEventFetchParams, parsePredictionTrades/parsePredictionOrders/parsePredictionPositions, safePrediction*).
  2. describe()has.prediction: true; address methods by an outcome handle, not a symbol. Implement fetchEvents(params) (scope-required via requireEventQuery) and, if the venue has a single-event endpoint, fetchEvent(id). Return Prediction* types from ts/src/base/types.ts (never base Ticker/Order/…). loadAllOutcomes defaults to false (a cache miss resolves one outcome via the base search-backed fetchOutcome); override fetchOutcome with a by-id fetch when the venue has one (see kalshi), and set loadAllOutcomes: true only when the whole universe is a single cheap request (see hyperliquid). No-arg fetchTickers() must throw ArgumentsRequired unless the venue has a true all-tickers endpoint.
  3. Never call the base parseTrades/parseOrders/parsePositions — they filter by symbol and drop prediction rows. Use parsePredictionTrades/Orders/Positions. Never call buildOHLCVC (transpiles to a mangled name) — bucket candles inline.
  4. Registrationnpm run export-exchanges adds the id to exchanges.json prediction[] and wires ts/ccxt.ts / the per-language namespaces / README table. npm run emitAPI emits ts/src/abstract/prediction/<id>.ts. Add a skip-tests.json entry with preferredEventQuery (the harness's fetchEvents scope) and preferredPredictionOutcome (a tradeable handle — validated against the live listing).
  5. Transpile — the scoped single-exchange transpilers auto-route a bare prediction-only id (tsx build/transpile.ts <id>, csharpTranspiler.ts <id>, goTranspiler.ts <id>). After editing PredictionExchange.ts you must also regen the base per language: tsx build/{transpile,csharpTranspiler,goTranspiler,javaTranspiler}.ts --baseClass. Any base→override call (like fetchOutcome) must be registered in VIRTUAL_BASE_METHODS in build/goTranspiler.ts or Go won't dispatch it.
  6. Testnode run-tests <id> --js --prediction --private (add --sandbox for demo hosts like kalshi). Static fixtures live in the normal flat ts/src/test/static/{request,response}/<id>.json; the python/php sync harness skips prediction (they carry "asyncOnly": true).

Frequently asked questions about New Exchange Integration

Similar skills