CCXT

CCXT Pro 手册

CCXT Pro 是 CCXT 的免费组成部分,增加了对 WebSocket 流式传输的支持:https://github.com/ccxt/ccxt/issues/15171

手册

CCXT Pro 是 CCXT 的免费组成部分,增加了对 WebSocket 流式传输的支持:https://github.com/ccxt/ccxt/issues/15171

CCXT Pro 技术栈构建于 CCXT 之上,并扩展了 CCXT 核心类,使用了:

  • JavaScript 原型级混入(prototype-level mixins)
  • Python 多重继承
  • PHP Traits
  • Java 类继承(pro 交易所类继承自基础交易所类)

CCXT Pro 大量依赖 CCXT 的转译器来实现多语言支持

                                 User

    +-------------------------------------------------------------+
    |                          CCXT Pro                           |
    +------------------------------+------------------------------+
    |            Public            .           Private            |
    +=============================================================+
    │                              .                              |
    │                  The Unified CCXT Pro API                   |
    |                              .                              |
    |     loadMarkets              .         watchBalance         |
    |     watchTicker              .         watchOrders          |
    |     watchTickers             .         watchMyTrades        |
    |     watchOrderBook           .         watchPositions       |
    |     watchOHLCV               .         createOrderWs        |
    |     watchStatus              .         editOrderWs          |
    |     watchTrades              .         cancelOrderWs        |
    │     watchOHLCVForSymbols     .         cancelOrdersWs       |
    │     watchTradesForSymbols    .         cancelAllOrdersWs    |
    │     watchOrderBookForSymbols .                              |
    │                              .                              |
    +=============================================================+
    │                          unWatch                            |
    │                   (to stop **watch** method)                |
    +=============================================================+
    │                              .                              |
    |            The Underlying Exchange-Specific APIs            |
    |         (Derived Classes And Their Implementations)         |
    │                              .                              |
    +=============================================================+
    │                              .                              |
    |                 CCXT Pro Base Exchange Class                |
    │                              .                              |
    +=============================================================+

    +-------------------------------------------------------------+
    |                                                             |
    |                            CCXT                             |
    |                                                             |
    +=============================================================+

交易所

CCXT Pro 库目前支持以下 74 个加密货币交易所市场和 WebSocket 交易 API:
logoidnamevertypecertifiedpro
aftermathaftermathAftermathFinanceAPI Version 1DEX - Distributed EXchangeCCXT Pro
alpacaalpacaAlpacaAPI Version *CEX – Centralized EXchangeCCXT Pro
apexapexApexAPI Version 3DEX - Distributed EXchangeCCXT Pro
arkhamarkhamARKHAMAPI Version 1CEX – Centralized EXchangeCCXT Pro
ascendexascendexAscendEXAPI Version 2CEX – Centralized EXchangeCCXT Pro
asterasterAsterAPI Version 1DEX - Distributed EXchangeCCXT Pro
backpackbackpackBackpackAPI Version 1CEX – Centralized EXchangeCCXT Pro
bequantbequantBequantAPI Version 3CEX – Centralized EXchangeCCXT Pro
binancebinanceBinanceAPI Version *CEX – Centralized EXchangeCCXT CertifiedCCXT Pro
binancecoinmbinancecoinmBinance COIN-MAPI Version *CEX – Centralized EXchangeCCXT CertifiedCCXT Pro
binanceusbinanceusBinance USAPI Version *CEX – Centralized EXchangeCCXT Pro
binanceusdmbinanceusdmBinance USDⓈ-MAPI Version *CEX – Centralized EXchangeCCXT CertifiedCCXT Pro
bingxbingxBingXAPI Version 1CEX – Centralized EXchangeCCXT CertifiedCCXT Pro
bitfinexbitfinexBitfinexAPI Version 2CEX – Centralized EXchangeCCXT Pro
bitgetbitgetBitgetAPI Version 2CEX – Centralized EXchangeCCXT CertifiedCCXT Pro
bithumbbithumbBithumbAPI Version *CEX – Centralized EXchangeCCXT Pro
bitmartbitmartBitMartAPI Version 2CEX – Centralized EXchangeCCXT CertifiedCCXT Pro
bitmexbitmexBitMEXAPI Version 1CEX – Centralized EXchangeCCXT CertifiedCCXT Pro
bitoprobitoproBitoProAPI Version 3CEX – Centralized EXchangeCCXT Pro
bitruebitrueBitrueAPI Version 1CEX – Centralized EXchangeCCXT Pro
bitstampbitstampBitstampAPI Version 2CEX – Centralized EXchangeCCXT Pro
bittradebittradeBitTradeAPI Version 1CEX – Centralized EXchangeCCXT Pro
bitvavobitvavoBitvavoAPI Version 2CEX – Centralized EXchangeCCXT Pro
blockchaincomblockchaincomBlockchain.comAPI Version 3CEX – Centralized EXchangeCCXT Pro
blofinblofinBloFinAPI Version 1CEX – Centralized EXchangeCCXT Pro
bullishbullishBullishAPI Version 3CEX – Centralized EXchangeCCXT Pro
bybitbybitBybitAPI Version 5CEX – Centralized EXchangeCCXT CertifiedCCXT Pro
bybiteubybiteuBybit EUAPI Version 5CEX – Centralized EXchangeCCXT Pro
bydfibydfiBYDFiAPI Version 1CEX – Centralized EXchangeCCXT Pro
cexcexCEX.IOAPI Version *CEX – Centralized EXchangeCCXT Pro
coinbasecoinbaseCoinbase AdvancedAPI Version 2CEX – Centralized EXchangeCCXT Pro
coinbaseexchangecoinbaseexchangeCoinbase ExchangeAPI Version *CEX – Centralized EXchangeCCXT Pro
coinbaseinternationalcoinbaseinternationalCoinbase InternationalAPI Version 1CEX – Centralized EXchangeCCXT Pro
coinexcoinexCoinExAPI Version 2CEX – Centralized EXchangeCCXT CertifiedCCXT Pro
cryptocomcryptocomCrypto.comAPI Version 2CEX – Centralized EXchangeCCXT CertifiedCCXT Pro
deepcoindeepcoinDeepCoinAPI Version 1CEX – Centralized EXchangeCCXT Pro
deribitderibitDeribitAPI Version 2CEX – Centralized EXchangeCCXT Pro
derivederivederiveAPI Version 1DEX - Distributed EXchangeCCXT Pro
dydxdydxdYdXAPI Version 4DEX - Distributed EXchangeCCXT Pro
gategateGateAPI Version 4CEX – Centralized EXchangeCCXT CertifiedCCXT Pro
geminigeminiGeminiAPI Version 1CEX – Centralized EXchangeCCXT Pro
grvtgrvtGRVTAPI Version 1DEX - Distributed EXchangeCCXT Pro
hashkeyhashkeyHashKey GlobalAPI Version 1CEX – Centralized EXchangeCCXT CertifiedCCXT Pro
hollaexhollaexHollaExAPI Version 2CEX – Centralized EXchangeCCXT Pro
htxhtxHTXAPI Version 1CEX – Centralized EXchangeCCXT CertifiedCCXT Pro
hyperliquidhyperliquidHyperliquidAPI Version 1DEX - Distributed EXchangeCCXT CertifiedCCXT Pro
independentreserveindependentreserveIndependent ReserveAPI Version *CEX – Centralized EXchangeCCXT Pro
krakenkrakenKrakenAPI Version 0CEX – Centralized EXchangeCCXT Pro
krakenfutureskrakenfuturesKraken FuturesAPI Version 3CEX – Centralized EXchangeCCXT Pro
kucoinkucoinKuCoinAPI Version 2CEX – Centralized EXchangeCCXT CertifiedCCXT Pro
kucoinfutureskucoinfuturesKuCoin FuturesAPI Version 2CEX – Centralized EXchangeCCXT CertifiedCCXT Pro
lbanklbankLBankAPI Version 2CEX – Centralized EXchangeCCXT Pro
lighterlighterLighterAPI Version 1DEX - Distributed EXchangeCCXT Pro
lunolunolunoAPI Version 1CEX – Centralized EXchangeCCXT Pro
mexcmexcMEXC GlobalAPI Version 3CEX – Centralized EXchangeCCXT CertifiedCCXT Pro
modetrademodetradeMode TradeAPI Version 1DEX - Distributed EXchangeCCXT Pro
myokxmyokxMyOKX (EEA)API Version 5CEX – Centralized EXchangeCCXT Pro
ndaxndaxNDAXAPI Version *CEX – Centralized EXchangeCCXT Pro
okxokxOKXAPI Version 5CEX – Centralized EXchangeCCXT CertifiedCCXT Pro
okxusokxusOKX (US)API Version 5CEX – Centralized EXchangeCCXT Pro
onetradingonetradingOne TradingAPI Version 1CEX – Centralized EXchangeCCXT Pro
oxfunoxfunOXFUNAPI Version 3CEX – Centralized EXchangeCCXT Pro
p2bp2bp2bAPI Version 2CEX – Centralized EXchangeCCXT Pro
pacificapacificaPacificaAPI Version 1DEX - Distributed EXchangeCCXT Pro
paradexparadexParadexAPI Version 1DEX - Distributed EXchangeCCXT Pro
phemexphemexPhemexAPI Version 1CEX – Centralized EXchangeCCXT Pro
poloniexpoloniexPoloniexAPI Version *CEX – Centralized EXchangeCCXT Pro
toobittoobitToobitAPI Version 1CEX – Centralized EXchangeCCXT Pro
upbitupbitUpbitAPI Version 1CEX – Centralized EXchangeCCXT Pro
weexweexWeexAPI Version 3CEX – Centralized EXchangeCCXT Pro
whitebitwhitebitWhiteBitAPI Version 4CEX – Centralized EXchangeCCXT Pro
woowooWOO XAPI Version 1CEX – Centralized EXchangeCCXT CertifiedCCXT Pro
woofiprowoofiproWOOFI PROAPI Version 1DEX - Distributed EXchangeCCXT CertifiedCCXT Pro
xtxtXTAPI Version 4CEX – Centralized EXchangeCCXT Pro

这是 CCXT Pro 中支持 WebSockets API 的交易所列表。该列表将定期更新,加入新的交易所。

CCXT 通过 REST 提供的完整交易所列表:支持的加密货币交易市场

使用方法

- this part of the doc is under heavy development right now
- there may be some typos, mistakes and missing info here and there
- contributions, pull requests and feedback appreciated

前提条件

理解 CCXT Pro 的最佳方式是确保您完全掌握 CCXT 手册,并先熟练使用标准 CCXT。CCXT Pro 借鉴自 CCXT,两个库有许多共同之处,包括:

  • 公共 API 和私有认证 API 的概念
  • 市场、交易对、货币代码和 id
  • 统一的数据结构和格式:订单簿、交易、订单、K 线、时间周期等
  • 异常与错误映射
  • 认证和 API 密钥(用于私有订阅和调用)
  • 配置选项

CCXT Pro 的用户群主要由专业量化交易者和开发者构成。为了高效使用本库,用户需要熟悉流式传输的相关概念,理解基于连接的流式 API(WebSocket,CCXT Pro)与基于请求-响应的 API(REST,CCXT)之间的本质区别。

CCXT 应用程序的通用异步流程如下:


// a RESTful orderbook polling request-response loop

while (condition) {

    try {

        // fetch some of the public data
        orderbook = await exchange.fetchOrderBook (symbol, limit)

        // do something or react somehow based on that data
        // ...

    } catch (e) {

        // handle errors
    }
}

在 CCXT Pro 中,每个带有 fetch* 前缀的公共和私有统一 RESTful 方法,都有一个对应的以 watch* 为前缀的基于流的对应方法,如下所示:

  • 公共 API
    • fetchStatuswatchStatus
    • fetchOrderBookwatchOrderBook
    • fetchOrderBookForSymbolswatchOrderBookForSymbols
    • fetchTickerwatchTicker
    • fetchTickerswatchTickers
    • fetchOHLCVwatchOHLCV
    • fetchOHLCVForSymbolswatchOHLCVForSymbols
    • fetchTradeswatchTrades
    • fetchTradesForSymbolswatchTradesForSymbols
    • fetchBidsAskswatchBidsAsks
    • fetchLiquidationswatchLiquidations
    • fetchLiquidationsForSymbolswatchLiquidationsForSymbols
  • 私有 API
    • fetchBalancewatchBalance
    • fetchOrderswatchOrders
    • fetchOrdersForSymbolswatchOrdersForSymbols
    • fetchMyTradeswatchMyTrades
    • fetchPositionwatchPosition
    • fetchPositionswatchPositions
    • fetchLiquidationswatchLiquidations
    • fetchMyLiquidationswatchMyLiquidations
    • fetchMyLiquidationsForSymbolswatchMyLiquidationsForSymbols
    • fetchFundingRateswatchFundingRates
  • REST 替代方法
    • fetchTradesfetchTradesWs
    • createOrdercreateOrderWs
    • editOrdereditOrderWs
    • cancelOrdercancelOrderWs
    • cancelOrderscancelOrdersWs
    • cancelAllOrderscancelAllOrdersWs
    • 等等……
  • unWatch(停止 watch 方法的后台订阅)
    • unWatchOrderBook
    • unWatchOrderBooksForSymbols
    • unWatchTrades
    • unWatchTradesForSymbols
    • unWatchOHLCVForSymbols
    • unWatchOrderBookForSymbols
    • unWatchPositions
    • unWatchTickers
    • unWatchMyTrades
    • unWatchTicker
    • unWatchOHLCV
    • unWatchOrders

统一的 CCXT Pro 流式 API 继承了 CCXT 的使用模式,以便于迁移。

CCXT Pro 应用程序(与上面的 CCXT 应用程序相对)的通用异步流程如下所示:


// a stream-based (WebSocket) orderbook feed loop

while (condition) {

    try {

        // watch some of the public data
        orderbook = await exchange.watchOrderBook (symbol, limit)

        // do something or react somehow based on that data
        // ...

    } catch (e) {

        // handle errors
    }
}

这种使用模式通常被封装成一个核心业务逻辑方法,称为 "tick() 函数",因为它循环响应传入的事件(即 ticks)。从上面两个示例可以明显看出,CCXT Pro 和 CCXT 的通用使用模式是相同的。

CCXT 的许多规则和概念同样适用于 CCXT Pro:

  • CCXT Pro 会在第一次调用统一 API 方法时加载并缓存市场数据
  • CCXT Pro 在必要时会在底层调用 CCXT 的 RESTful 方法
  • CCXT Pro 在必要时会抛出标准的 CCXT 异常
  • ……

流式传输的特殊性

尽管有许多共同之处,基于流的 API 由于其基于连接的本质,具有其自身的特殊性。

基于连接的接口意味着需要连接管理机制。连接由 CCXT Pro 透明地管理,用户无需关心。每个交易所实例管理自己的一组连接。

当您第一次调用任何 watch*() 方法时,库将与交易所的特定流/资源建立连接并保持该连接。如果连接已存在,则会复用。库将处理订阅请求/响应的消息序列,以及在请求的流为私有时进行身份验证/签名。

库还会监视上行链路的状态并保持连接活跃。在发生严重异常、断开连接或连接超时/失败时,tick 函数的下一次迭代将调用 watch 方法,从而触发重新连接。通过这种方式,库透明地为用户处理断线和重连。CCXT Pro 会应用必要的速率限制和指数退避重连延迟。所有这些功能均默认启用,可通过交易所属性进行配置。

大多数交易所的流式 API 只有一个基础 URL(通常是 WebSocket,以 ws://wss:// 开头)。部分交易所可能针对不同的数据流提供多个 URL。

交易所的流式 API 可以分为两类:

  • subsubscribe:仅允许接收
  • pubpublish:允许发送和接收

Sub

sub 接口通常允许订阅数据流并监听。大多数支持 WebSocket 的交易所只提供 sub 类型的 API。sub 类型包括流式公共市场数据。有时交易所也允许订阅私有用户数据。用户订阅数据流后,该频道便开始单向工作,持续向用户推送来自交易所的更新。

常见的公共数据流类型:

  • 订单簿(最常见)——新增、修改和删除订单的更新(即 变化增量
  • 24 小时统计数据变化时的行情更新
  • 成交流(也很常见)——公共交易的实时流
  • OHLCV K 线数据流
  • 心跳
  • 交易所聊天/水区

不太常见的私有用户数据流类型:

  • 用户私有交易流
  • 实时订单更新
  • 余额更新
  • 自定义数据流
  • 交易所特定及其他数据流

Pub

pub 接口通常允许用户向服务器发送数据请求。这通常包括常见的用户操作,例如:

  • 下单
  • 撤单
  • 发起提币请求
  • 发送聊天/水区消息
  • 等等

部分交易所不提供 pub WS API,仅提供 sub WS API。 不过,也有交易所提供完整的流式 API。在大多数情况下,仅依靠流式 API 无法有效操作。交易所通过 sub 推送公共市场数据,而缺失的 pub 部分仍需通过 REST API 来完成。

unWatch

每个 watchX 方法都会建立对某个数据流的订阅,并持续从交易所获取更新。即使您停止获取 watchX 方法的返回值,数据流仍会继续发送数据,由后台处理并存储。要停止这些后台订阅,应使用 unWatch 方法(例如 watchTrades -> unWatchTrades)。

增量数据结构

在许多情况下,由于底层数据流的单向性,客户端监听的应用程序必须在内存中保存本地数据快照,并将从交易所服务器接收到的更新合并到本地快照中。来自交易所的更新通常也被称为 增量,因为在大多数情况下,这些更新只包含两个数据状态之间的变化,不包含未发生变化的数据,因此需要在本地缓存所有相关数据对象的当前状态 S。

所有这些功能都由 CCXT Pro 为用户处理。使用 CCXT Pro 时,用户无需跟踪或管理订阅及相关数据。CCXT Pro 会在内存中保存结构缓存以处理底层的繁琐工作。

每个传入的更新都会说明数据的哪些部分发生了变化,接收方通过将更新合并到当前状态 S 上来"增量"更新本地状态 S,并移动到下一个本地状态 S'。在 CCXT Pro 中,这被称为 "增量状态",参与存储和更新缓存状态过程的结构被称为 "增量结构"。CCXT Pro 引入了几个新的基类,在必要时处理增量状态。

从 CCXT Pro 统一方法返回的增量结构通常是以下两种类型之一:

  1. JSON 解码对象(JavaScript 中的 object,Python 中的 dict,PHP 中的 array())。此类型可由公共和私有方法返回,如 watchOrderBookwatchTickerwatchBalancewatchOrder 等。
  2. 对象数组/列表(通常按时间顺序排序)。此类型可由 watchOHLCVwatchTradeswatchMyTradeswatchOrders 等方法返回。

返回数组的统一方法,如 watchOHLCVwatchTradeswatchMyTradeswatchOrders,均基于缓存层。用户需要了解缓存层的内部工作原理,才能高效使用。

缓存是一个固定大小的双端队列(即数组/列表)。CCXT Pro 库对内存中存储的对象数量有合理的限制。默认情况下,缓存数组结构最多存储每种类型 1000 条记录(最近 1000 笔交易、最近 1000 根 K 线、最近 1000 个订单)。用户可以在实例化时或之后配置允许的最大数量:

ccxtpro.binance({
    'options': {
        'tradesLimit': 1000,
        'OHLCVLimit': 1000,
        'ordersLimit': 1000,
    },
})

# or

exchange.options['tradesLimit'] = 1000
exchange.options['OHLCVLimit'] = 1000
exchange.options['ordersLimit'] = 1000

缓存限制必须在调用任何 watch 方法之前设置,且在程序运行期间不能更改。

当缓存中还有空间时,新元素会直接追加到末尾。如果没有足够空间容纳新元素,则会从缓存开头删除最旧的元素以释放空间。因此,例如,缓存从 0 增长到最近 1000 笔交易,之后始终保持最多 1000 笔最近交易,随着每次来自交易所的新更新不断刷新存储的数据。这就像一个滑动框架窗口或滑动门,如下所示:

      past > ------------------ > time > - - - - - - - - > future


                           sliding frame
                           of 1000 most
                           recent trades
                        +-----------------+
                        |                 |
                        |===========+=====|
+----------------+------|           |     | - - - - - + - - - - - - - - + - - -
|                |      |           |     |           |                 |
0              1000     |         2000    |         3000              4000  ...
|                |      |           |     |           |                 |
+----------------+------|           |     | - - - - - + - - - - - - - - + - - -
                        |===========+=====|
                        |                 |
                        +---+---------+---+
                            |         |
                      since ^         ^ limit

                   date-based pagination arguments
                         are always applied
                       within the cached frame

用户可以如上所示使用 exchange.options 配置缓存限制。请不要将缓存限制与分页限制混淆。

请注意,sincelimit 基于日期的分页 参数具有不同的含义,且始终在缓存窗口内生效! 如果用户为 watchTrades() 调用指定了 since 参数,CCXT Pro 将返回所有时间戳 >= since 的缓存交易。如果用户未指定 since 参数,CCXT Pro 将从滑动窗口的起始位置返回缓存的交易。如果用户指定了 limit 参数,库将从 since 或缓存起始位置开始返回最多 limit 根 K 线。因此,由于 WebSocket 实时特性的限制,用户无法在缓存帧之外进行分页。

exchange.options['tradesLimit'] = 5  # set the size of the cache to 5

# this call will return up to 5 cached trades
await exchange.watchTrades (symbol)

# the following call will return the first 2 of up to 5 cached trades
await exchange.watchTrades (symbol, since=None, limit=2)

# this call will first filter cached trades by trade['timestamp'] >= since
# and will return the first 2 of up to 5 cached trades that pass the filter
since = exchange.iso8601('2020-01-01T00:00:00Z')
limit = 2
await exchange.watchTrades (symbol, since, limit)

newUpdates 模式

如果您希望始终只获取最新的交易记录,应在实例化交易所时将 newUpdates 标志设置为 true

exchange = ccxtpro.binance({'newUpdates': True})
while True:
    trades = await exchange.watchTrades (symbol)
    print(trades)

newUpdates 模式在后台仍然使用滑动缓存,但用户只会收到新的更新内容。这是因为某些交易所使用增量结构,因此我们需要维护对象缓存,因为交易所可能只提供部分信息(例如状态更新)。

newUpdates 模式的结果将是自上次 exchange.watchMethod 解析以来发生的一条或多条更新。CCXT Pro 可以返回自上次调用以来更新的一个或多个订单。调用 exchange.watchOrders 的结果如下所示:

[
    order, // see /docs/manual#order-structure
    order,
    order,
    ...
]

弃用警告:未来 newUpdates: true 将成为默认模式,届时您需要将 newUpdates 设置为 false 才能获取滑动缓存。

const ccxtpro = require ('ccxt').pro
console.log ('CCXT version', ccxtpro.version)
console.log ('Supported exchanges:', ccxtpro.exchanges)

导入的 CCXT Pro 模块将 CCXT 封装在其内部——通过 CCXT Pro 实例化的每个交易所都具备所有 CCXT 方法以及额外的功能。

实例化

CCXT Pro 专为 async/await 语法风格设计,并大量依赖于 promisesfutures 等异步原语。

创建 CCXT Pro 交易所实例与创建 CCXT 交易所实例几乎完全相同。

const ccxt = require ('ccxt').pro
const exchange = new ccxtpro.binance ({ newUpdates: false })

Python

CCXT Pro 的 Python 实现依赖于内置的 asyncio,尤其是 Event Loop。在 Python 中,可以在构造函数参数中提供 asyncio 的事件循环实例,如下所示(与 ccxt.async support 相同):

import ccxt.pro as ccxtpro
from asyncio import run

async def main():
    exchange = ccxtpro.kraken({'newUpdates': False})
    while True:
        orderbook = await exchange.watch_order_book('BTC/USD')
        print(orderbook['asks'][0], orderbook['bids'][0])
    await exchange.close()


run(main())

PHP

在 PHP 中,异步原语借自 ReactPHP。CCXT Pro 的 PHP 实现依赖于 PromiseEventLoop。在 PHP 中,用户需要在构造函数参数中提供 ReactPHP 的事件循环实例,如下所示:

error_reporting(E_ALL);
date_default_timezone_set('UTC');
require_once 'vendor/autoload.php';

$exchange = new \ccxt\pro\kucoin(array( 'newUpdates' => false ));
using ccxt.pro;

    public async static Task Watch()
    {
        var exchange = new binance();
        while (true)
        {
            var trades = await exchange.WatchTrades("BTC/USDT");
            Console.WriteLine("Trades: " + JsonConvert.SerializeObject(trades, Formatting.Indented));
        }
    }

交易所属性

每个 CCXT Pro 实例都包含底层 CCXT 实例的所有属性。除标准 CCXT 属性外,CCXT Pro 实例还包含以下属性:

{
    'has': { // an associative array of extended exchange capabilities
        'ws': true, // only available in CCXT Pro
        'watchOrderBook': true,
        'watchTicker': true,
        'watchTickers': true,
        'watchTrades': true,
        'watchMyTrades': true,
        'watchOHLCV': true,
        'watchBalance': true,
        'watchPositions': true,
        'createOrderWs': true,
        'editOrderWs': true,
        'cancelOrderWs': true,
        'cancelOrdersWs': false,
        'cancelAllOrdersWs': true,
        'fetchOrderWs': true,
        'fetchOrdersWs': true,
        'fetchBalanceWs': true,
        'fetchMyTradesWs': true,
        ...
    },
    'urls': {
        'api': { // will contain a streaming API base URL, depending on the underlying protocol
            'ws': 'wss://ws.exchange.com',            // https://en.wikipedia.org/wiki/WebSocket
            'signalr': 'https://signalr.exchange.com' // https://en.wikipedia.org/wiki/SignalR
            'socketio': 'wss://socket.exchange.io'    // https://socket.io
        },
    },
    'version': '1.21',
    'streaming': {
        'keepAlive': 30000, // integer keep-alive rate in milliseconds
        'maxPingPongMisses': 2.0, // how many ping pong misses to drop and reconnect
        ... // other streaming options
    },
    // incremental data structures
    'orderbooks':   {}, // incremental order books indexed by symbol
    'ohlcvs':       {}, // standard CCXT OHLCVs indexed by symbol by timeframe
    'balance':      {}, // a standard CCXT balance structure, accounts indexed by currency code
    'orders':       {}, // standard CCXT order structures indexed by order id
    'trades':       {}, // arrays of CCXT trades indexed by symbol
    'tickers':      {}, // standard CCXT tickers indexed by symbol
    'transactions': {}, // standard CCXT deposits and withdrawals indexed by id or txid
    ...
}

统一 API

统一 CCXT Pro API 鼓励使用直接控制流,与使用 EventEmitter 和回调相比,代码风格更佳、可读性更强、架构也更优秀。后者如今被视为过时的方式,因为它需要控制反转(人们不习惯这种反转思维)。

CCXT Pro 采用现代方式,专为异步语法而设计。在底层,CCXT Pro 有时仍不得不使用反转控制流,这是由于依赖项和 WebSocket 库本身的限制。

这不仅适用于 JS/ES6,同样适用于 Python 3 的异步代码。在 PHP 中,异步原语借自 ReactPHP

现代异步语法允许您将执行拆分为多个并行路径,再对它们进行合并、分组、排序等操作。使用 promises,可以轻松地在直接异步风格控制流和反转回调风格控制流之间来回切换。

实时模式与节流模式

CCXT Pro 支持两种 tick 函数循环模式——实时模式和节流模式。下面以伪代码形式展示:

// real-time mode
const limit = 5 // optional
while (true) {
    try {
        const orderbook = await exchange.watchOrderBook (symbol, limit)
        // your reaction to the update takes place here
        // you arrive here after receiving the update from the exchange in real time
        console.log (orderbook) // every update
    } catch (e) {
        console.log (e)
        // throw e // uncomment to stop the loop on exceptions
    }
}
// throttling mode
const limit = 5 // optional
// await is optional, alternatively you can launch it in bg without await
await exchange.watchOrderBook (symbol, limit)
while (true) {
    // your reaction takes place here
    // you arrive here every 100 ms regardless of whether there was an update or not
    // in throttling mode offloading the orderbook with .limit () is required
    console.log (exchange.orderbooks[symbol].limit (limit))
    await exchange.sleep (100) // every 100 ms
}

实时模式下,CCXT Pro 将在每次收到来自交易所的新增量时立即返回结果。统一调用在实时循环中的一般逻辑是等待下一个增量,并立即将统一结果结构返回给用户,如此循环往复。当反应时间至关重要或需要尽可能快时,此模式非常有用。

然而,实时模式在同步多个并行 tick 循环时需要具备异步流编程经验。除此之外,在高活跃度或高波动性时期,交易所可能会推送大量更新。因此,开发实时算法的用户必须确保用户端代码能够跟上如此快速的数据消费速度。实时模式有时对资源的要求更高。

节流模式下,CCXT Pro 将在后台接收和管理数据。用户负责在必要时定期提取结果。节流循环的一般逻辑是大部分时间处于休眠状态,偶尔唤醒以检查结果。这通常以固定频率(即"帧率")执行。节流循环中的代码通常更易于跨多个交易所同步。节流循环中对时间的合理分配也有助于将资源使用量降至最低。当算法较为复杂且需要精确控制执行频率以避免过于频繁运行时,此模式非常实用。

节流模式的明显缺点是对更新的响应速度较慢。当交易算法需要等待若干毫秒才能执行时,可能有一两条更新在此时间到期之前就已到达。在节流模式下,用户只会在下次唤醒(循环迭代)时检查这些更新,因此反应延迟可能在若干毫秒的范围内随时间波动。

公共方法

watchOrderBook

watchOrderBook 的接口与 fetchOrderBook 相同,接受三个参数:

  • symbol – 字符串,统一 CCXT 交易对符号,必填
  • limit – 整数,返回的最大买/卖单数量,可选
  • params – 关联字典,可选覆盖项,详见覆盖统一 API 参数

总体而言,交易所可分为两类:

  1. 支持有限订单簿的交易所(仅推送订单栈顶部分)
  2. 仅推送完整订单簿的交易所

如果交易所接受限制参数,则 limit 参数会在通过 WebSocket 连接订阅订单簿流时发送给交易所。交易所随后只发送指定数量的订单,从而有助于减少流量。部分交易所可能只接受特定的 limit 值,例如 10、25、50、100 等。

如果底层交易所不接受限制参数,则限制在客户端进行。

limit 参数并不保证买单或卖单的数量始终等于 limit。它指定的是上限或最大值,因此在某些时刻买单或卖单可能少于 limit,但永远不会超过 limit。这种情况发生在交易所订单簿中没有足够订单时,或者订单簿中某个顶部订单被撮合并从订单簿中移除,导致买方或卖方剩余条目少于 limit 时。订单簿中的空位通常会很快被新数据填补。

if (exchange.has['watchOrderBook']) {
    while (true) {
        try {
            const orderbook = await exchange.watchOrderBook (symbol, limit, params)
            console.log (new Date (), symbol, orderbook['asks'][0], orderbook['bids'][0])
        } catch (e) {
            console.log (e)
            // stop the loop on exception or leave it commented to retry
            // throw e
        }
    }
}

watchOrderBookForSymbols

watchOrderBook 类似,但接受一个交易对符号数组,可通过单条消息订阅多个订单簿。

if (exchange.has['watchOrderBookForSymbols']) {
    while (true) {
        try {
            const orderbook = await exchange.watchOrderBookForSymbols (['BTC/USDT', 'LTC/USDT'], limit, params)
            console.log (new Date (), symbol, orderbook['asks'][0], orderbook['bids'][0])
        } catch (e) {
            console.log (e)
            // stop the loop on exception or leave it commented to retry
            // throw e
        }
    }
}

watchTicker

部分交易所允许使用不同的主题来监听行情(例如:bookTicker)。您可以在 exchange.options['watchTicker']['name'] 中进行设置。

// JavaScript
if (exchange.has['watchTicker']) {
    while (true) {
        try {
            const ticker = await exchange.watchTicker (symbol, params)
            console.log (new Date (), ticker)
        } catch (e) {
            console.log (e)
            // stop the loop on exception or leave it commented to retry
            // throw e
        }
    }
}
# Python
if exchange.has['watchTicker']:
    while True:
        try:
            ticker = await exchange.watch_ticker(symbol, params)
            print(exchange.iso8601(exchange.milliseconds()), ticker)
        except Exception as e:
            print(e)
            # stop the loop on exception or leave it commented to retry
            # raise e
if ($exchange->has['watchTicker']) {
    $exchange::execute_and_run(function() use ($exchange, $symbol, $params) {
        while (true) {
            try {
                $ticker = yield $exchange->watch_ticker($symbol, $params);
                echo date('c'), ' ', json_encode($ticker), "\n";
            } catch (Exception $e) {
                echo get_class($e), ' ', $e->getMessage(), "\n";
            }
        }
    });
}

watchTickers

if (exchange.has['watchTickers']) {
    while (true) {
        try {
            const tickers = await exchange.watchTickers (symbols, params)
            console.log (new Date (), tickers)
        } catch (e) {
            console.log (e)
            // stop the loop on exception or leave it commented to retry
            // throw e
        }
    }
}

watchOHLCV

关于 WebSocket 有一个非常常见的误解,即 WS OHLCV 数据流能够以某种方式加速交易策略。 如果您的应用程序目的是实现 OHLCV 交易或投机性算法策略,请仔细考虑以下内容

总体而言,算法中使用的交易数据分为两种类型:

  • 一阶实时数据,如订单簿和成交记录
  • 二阶非实时数据,如行情、OHLCV 等

当开发者说"实时"时,通常指伪实时,简单来说就是"尽可能快、尽可能接近实时"。

二阶数据始终由一阶数据计算得出。OHLCV 由聚合成交记录计算得出。行情由成交记录和订单簿计算得出。

部分交易所会在交易所端为您计算 OHLCV(二阶数据)并通过 WS 推送更新(如 Binance)。其他交易所则认为这不是必要的,自有其原因。

显然,从成交记录计算二阶 OHLCV K 线需要时间。除此之外,将计算后的 K 线发送给所有已连接用户也需要时间。在高波动期间,若交易所在高负载下被频繁交易,还可能出现额外延迟。

从交易所计算二阶数据并通过 WS 推送给您所需的时间没有严格保证。不同交易所的 OHLCV K 线延迟和滞后可能差异显著。例如,某交易所可能在对应周期实际收盘约 30 秒后才发送 OHLCV 更新。其他交易所可能以固定间隔(例如每 100 毫秒一次)发送当前 OHLCV 更新,而实际上成交记录的发生频率可能远高于此。

大多数人使用 WS 是为了避免各种延迟并获取实时数据。因此,在大多数情况下,不等待交易所计算往往更好。自行从一阶数据重新计算二阶数据可能快得多,从而降低不必要的延迟。因此,仅使用 WS 监听来自交易所的 OHLCV K 线意义不大。开发者更倾向于使用 watch_trades(),并利用 CCXT 内置方法(如 build_ohlcvc())重新计算 OHLCV K 线。

# Python
exchange = ccxtpro.binance()
if not exchange.has['watchOHLCV']:
    while True:
        try:
            trades = await exchange.watch_trades(symbol)
            ohlcvc = exchange.build_ohlcvc(trades, '1m')
            print(ohlcvc)
        except Exception as e:
            print(e)
            # stop the loop on exception or leave it commented to retry
            # raise e

这解释了为何某些交易所合理地认为 WS 场景中不需要 OHLCV,因为用户仅凭一阶实时成交记录的 WS 数据流即可在用户端更快地计算出该信息。

如果您的应用对时间不是非常敏感,仍可出于图表绘制目的订阅 OHLCV 数据流。如果底层 exchange.has['watchOHLCV'] 为真,您可以按以下方式使用 watchOHLCV()/watch_ohlcv()

if (exchange.has['watchOHLCV']) {
    while (true) {
        try {
            const candles = await exchange.watchOHLCV (symbol, timeframe, since, limit, params)
            console.log (new Date (), candles)
        } catch (e) {
            console.log (e)
            // stop the loop on exception or leave it commented to retry
            // throw e
        }
    }
}

watchOHLCVForSymbols

watchOHLCV 类似,但允许同时订阅多个交易对和时间周期。

if (exchange.has['watchOHLCVForSymbols']) {
    while (true) {
        try {
            const subscriptions = [[
                ['BTC/USDT', '1d'],
                ['LTC/USDT', '5m'],
                ['ETH/USDT', '1h']
            ]]
            const candles = await exchange.watchOHLCVForSymbols (subscriptions, since, limit, params)
            console.log (new Date (), candles)
        } catch (e) {
            console.log (e)
            // stop the loop on exception or leave it commented to retry
            // throw e
        }
    }
}

watchTrades

// JavaScript
if (exchange.has['watchTrades']) {
    while (true) {
        try {
            const trades = await exchange.watchTrades (symbol, since, limit, params)
            console.log (new Date (), trades)
        } catch (e) {
            console.log (e)
            // stop the loop on exception or leave it commented to retry
            // throw e
        }
    }
}

watchTradesForSymbols

watchTrades 类似,但允许在单次调用中订阅多个交易对。

if (exchange.has['watchTradesForSymbols']) {
    while (true) {
        try {
            const trades = await exchange.watchTradesForSymbols (['LTC/USDT', 'BTC/USDT'], since, limit, params)
            console.log (new Date (), trades)
        } catch (e) {
            console.log (e)
            // stop the loop on exception or leave it commented to retry
            // throw e
        }
    }
}

私有方法

在大多数情况下,认证逻辑借自 CCXT,因为交易所对 REST API 和 WebSocket API 使用相同的密钥对和签名算法。详见 API Keys Setup

watchBalance

if (exchange.has['watchBalance']) {
    while (true) {
        try {
            const balance = await exchange.watchBalance (params)
            console.log (new Date (), balance)
        } catch (e) {
            console.log (e)
            // stop the loop on exception or leave it commented to retry
            // throw e
        }
    }
}

watchOrders

watchOrders (symbol = undefined, since = undefined, limit = undefined, params = {})

watchMyTrades

watchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {})

watchPositions

监听所有持仓并返回 持仓结构 列表

watchPositions (symbols = undefined, since = undefined, limit = undefined, params = {}) 

createOrderWs

createOrderWs (symbol: string, type: OrderType, side: OrderSide, amount: number, price: number = undefined, params = {})

editOrderWs

// JavaScript
editOrderWs (id, symbol: string, type: OrderType, side: OrderSide, amount: number, price: number = undefined, params = {})

cancelOrderWs

cancelOrderWs(id: string, symbol: string = undefined, params = {})

cancelOrdersWs

cancelOrdersWs(ids: string[], symbol: string = undefined, params = {})

cancelAllOrdersWs

cancelAllOrdersWs(symbol: string = undefined, params = {})

watchTransactions

- this method is a work in progress now (may be unavailable)

自定义处理器

如果您希望访问原始传入消息并使用自定义处理器,可以覆盖交易所的 handleMessage/handle_message 方法,例如:

A) 通过继承:

class myExchange extends ccxt.pro.coinbase {
    handleMessage (wsClient, data) {
        console.log("Raw incoming message:", message) // this is the raw update
        super.handleMessage(wsClient, data);
        // your extra logic here
    }
}
const ex = new myExchange();
ex.watchTicker('BTC/USDT');

B) 通过覆盖方法:

function myHandler(ws, data, orignal_handler){
    orignal_handler(ws, data); // trigger original `handleMessage`
    if (your_condition) {
        // execute your additional code
    }
}

const ex = new ccxt.pro.binance();
const original_handler = ex.handleMessage.bind(ex);
ex.handleMessage = (ws, data) => myHandler(ws, data, original_handler);
ex.watchTicker('BTC/USDT');

错误处理

发生错误时,CCXT Pro 将抛出标准的 CCXT 异常,详情请参阅 错误处理

本页内容