CCXT中文开发手册

CCXT开发概述
CCXT概述 支持的交易所 实例化交易所类 设置交易所的属性
CCXT交易所模型
交易所的数据结构 交易所API访问的限流 DDoS保护异常及处理办法
CCXT市场模型
市场数据结构 数据精度和极限值 委托单数值要求和格式化方法 载入市场清单 交易符号和市场ID 符号命名的一致性 符号命名冲突的解决流程 符号命名常见问题及解答 市场缓存强制重载
CCXT API
方法与访问端结点 隐式API方法 公开/私有API 同步调用与异步调用 API方法参数与返回值 API方法命名规范 统一API 改写统一API的参数 统一API结果的分页
CCXT委托账本模型
交易委托账本 委托账本模型的结构 查询市场深度 查询市场价格
CCXT市场行情
实时行情 实时行情数据结构 查询指定交易对实时行情 查询所有交易对实时行情
CCXT烛线图数据
OHLCV烛线图 OHLCV数据结构 OHLCV数据模拟
CCXT数字货币交易
查询交易 - fetchTrade 交易身份验证 API密钥设置 查询账户余额 - fetchBalance 查询委托单 - fetchOrders 查询交易 - fetchTrades 委托单缓存 清理缓存的委托单 - purgeCachedOrders 查询指定ID的委托单 - fetchOrder 查询全部委托单 - fetchOrders 查询全部敞口委托单 - fetchOpenOrders 查询全部已完结委托单 - fetchClosedOrders 委托单数据结构 委托下单 市价委托 - createMarketSellOrder/createMarketBuyOrder 市价买入委托的特殊情况 - createMarketBuyOrderRequiresPrice 用限价单模拟市价单 限价委托 - createLimitBuyOrder/createLimitSellOrder 委托单的自定义参数 其他类型的委托单 取消委托单 - cancelOrder 委托单与交易的关系 查询个人的历史交易 - fetchMyTrade 交易的数据结构 查询指定委托单的交易 获取充值地址 - fetchDepositAddress/createDepositAddress 地址的数据结构 提现 - withdraw 链上交易数据结构 查询充值记录 - fetchDoposits 查询提现记录 - fetchWithdrawals 查询链上交易 - fetchTransactions 查询手续费 - fetchFees 查询交易所状态 - fetchStatus 预算交易费 - calculateFee 资金操作费 - currencies 查询账本 - fetchLedger 账本记录结构 修改Nonce值 - seconds/milliseconds/microseconds
CCXT错误处理
错误处理概述 - try/catch 异常类的体系 交易所异常 网络异常

统一API结果分页

大多数统一API的方法会返回单一对象或对象数组(交易、委托单等)。 然而,极少数交易所会返回一次返回全部委托单、全部交易或全部ohlcv烛线图数据。 更常见的是交易所API会限制返回一定数量的最新对象,你不能一次调用就 获取从开始时间到当前时刻的全部对象。实际上,极少有交易所能容忍或允许 这样的调用。

要获取历史委托单或交易,用户需要分页遍历数据。分页通常表示要循环 提取部分数据。

在大多数情况下,用户需要使用某种类型的分页来获取期望的结果。如果 用户没有使用分页,大多数方法将返回交易所的默认结果,这可能是从历史 的开始时刻或者也可能是返回最近的一部分数据。默认行为是交易所相关的! 分页通常会在以下方法中用到:

  • fetchTrades
  • fetchOHLCV
  • fetchOrders
  • fetchOpenOrders
  • fetchClosedOrders
  • fetchMyTrades
  • fetchTransactions
  • fetchDeposits
  • fetchWithdrawals

对于返回对象列表的方法,交易所可能提供一种或多种分页类型。CCXT默认 统一了基于日期、基于毫秒时间戳的分页。

用于UTC日期和时间戳的方法集:

exchange.parse8601 ('2018-01-01T00:00:00Z') == 1514764800000 // integer, Z = UTC
exchange.iso8601 (1514764800000) == '2018-01-01T00:00:00Z'   // iso8601 string
exchange.seconds ()      // integer UTC timestamp in seconds
exchange.milliseconds () // integer UTC timestamp in milliseconds

基于日期的分页

这是目前CCXT统一API使用的分页类型。调用者提供一个毫秒时间戳作为since 参数的值,同时传入一个数值来限定返回结果的数量。要逐页遍历感兴趣的对象, 调用者运行如下的伪代码。

JavaScript:

if (exchange.has['fetchTrades']) {
    let since = exchange.milliseconds () - 86400000 // -1 day from now
    // alternatively, fetch from a certain starting datetime
    // let since = exchange.parse8601 ('2018-01-01T00:00:00Z')
    let allTrades = []
    while (since < exchange.milliseconds ()) {
        const symbol = undefined // change for your symbol
        const limit = 20 // change for your limit
        const trades = await exchange.fetchTrades (symbol, since, limit)
        if (trades.length) {
            since = trades[trades.length - 1]['timestamp']
            allTrades = allTrades.concat (trades)
        } else {
            break
        }
    }
}

Python:

if exchange.has['fetchOrders']:
    since = exchange.milliseconds () - 86400000  # -1 day from now
    # alternatively, fetch from a certain starting datetime
    # since = exchange.parse8601('2018-01-01T00:00:00Z')
    all_orders = []
    while since < exchange.milliseconds ():
        symbol = None  # change for your symbol
        limit = 20  # change for your limit
        orders = await exchange.fetch_orders(symbol, since, limit)
        if len(orders):
            since = orders[len(orders) - 1]['timestamp']
            all_orders += orders
        else:
            break

PHP:

if ($exchange->has['fetchMyTrades']) {
    $since = exchange->milliseconds () - 86400000; // -1 day from now
    // alternatively, fetch from a certain starting datetime
    // $since = $exchange->parse8601 ('2018-01-01T00:00:00Z');
    $all_trades = array ();
    while (since < exchange->milliseconds ()) {
        $symbol = null; // change for your symbol
        $limit = 20; // change for your limit
        $trades = $exchange->fetchMyTrades ($symbol, $since, $limit);
        if (count($trades)) {
            $since = $trades[count($trades) - 1]['timestamp'];
            $all_trades = array_merge ($all_trades, $trades);
        } else {
            break;
        }
    }
}

基于ID的分页

调用者提供对象的from_id,以及一个用于限定返回结果数量的值。这是一些交易所 的默认行为,然而,这一分页类型目前还不是统一的。要基于ID进行分页,调用者可以 运行如下伪代码:

JavaScript:

if (exchange.has['fetchTrades']) {
    let from_id = 'abc123' // all ids are strings
    let allTrades = []
    while (true) {
        const symbol = undefined // change for your symbol
        const since = undefined
        const limit = 20 // change for your limit
        const params = {
            'from_id': from_id, // exchange-specific non-unified parameter name
        }
        const trades = await exchange.fetchTrades (symbol, since, limit, params)
        if (trades.length) {
            from_id = trades[trades.length - 1]['id']
            allTrades.push (trades)
        } else {
            break
        }
    }
}

Python:

if exchange.has['fetchOrders']:
    from_id = 'abc123'  # all ids are strings
    all_orders = []
    while True:
        symbol = None  # change for your symbol
        since = None
        limit = 20  # change for your limit
        params = {
            'from_id': from_id,  # exchange-specific non-unified parameter name
        }
        orders = await exchange.fetch_orders(symbol, since, limit, params)
        if len(orders):
            from_id = orders[len(orders) - 1]['id']
            all_orders += orders
        else:
            break

PHP:

if ($exchange->has['fetchMyTrades']) {
    $from_id = 'abc123' // all ids are strings
    $all_trades = array ();
    while (true) {
        $symbol = null; // change for your symbol
        $since = null;
        $limit = 20; // change for your limit
        $params = array (
            'from_id' => $from_id, // exchange-specific non-unified parameter name
        );
        $trades = $exchange->fetchMyTrades ($symbol, $since, $limit, $params);
        if (count($trades)) {
            $from_id = $trades[count($trades) - 1]['id'];
            $all_trades = array_merge ($all_trades, $trades);
        } else {
            break;
        }
    }
}

基于页号的分页

调用者提供一个页号或者初始的游标值。交易所范围一页结果以及后续的游标值以便继续。 大多数实现这种类型分页的交易所,在响应内容或响应头中返回下一个游标。

可以访问这里 查看示例代码实现。

在每个迭代周期,调用者必须拿到下一个游标并将其传入下一次迭代的查询。

JavaScript:

if (exchange.has['fetchTrades']) {
    let page = 0  // exchange-specific type and value
    let allTrades = []
    while (true) {
        const symbol = undefined // change for your symbol
        const since = undefined
        const limit = 20 // change for your limit
        const params = {
            'page': page, // exchange-specific non-unified parameter name
        }
        const trades = await exchange.fetchTrades (symbol, since, limit, params)
        if (trades.length) {
            // not thread-safu and exchange-specific !
            page = exchange.last_json_response['cursor']
            allTrades.push (trades)
        } else {
            break
        }
    }
}

Python:

if exchange.has['fetchOrders']:
    cursor = 0  # exchange-specific type and value
    all_orders = []
    while True:
        symbol = None  # change for your symbol
        since = None
        limit = 20  # change for your limit
        params = {
            'cursor': cursor,  # exchange-specific non-unified parameter name
        }
        orders = await exchange.fetch_orders(symbol, since, limit, params)
        if len(orders):
            # not thread-safu and exchange-specific !
            cursor = exchange.last_http_headers['CB-AFTER']
            all_orders += orders
        else:
            break

PHP:

if ($exchange->has['fetchMyTrades']) {
    $start = '0' // exchange-specific type and value
    $all_trades = array ();
    while (true) {
        $symbol = null; // change for your symbol
        $since = null;
        $limit = 20; // change for your limit
        $params = array (
            'start' => $start, // exchange-specific non-unified parameter name
        );
        $trades = $exchange->fetchMyTrades ($symbol, $since, $limit, $params);
        if (count($trades)) {
            // not thread-safu and exchange-specific !
            $start = $exchange->last_json_response['next'];
            $all_trades = array_merge ($all_trades, $trades);
        } else {
            break;
        }
    }
}