概述#

ccxt库是一个可用的加密交易所或交易类的集合。每个类都实现特定加密交易所的公共和私有API。所有交易所都派生自基本Exchange类,并共享一组常见的方法。要从ccxt库访问特定交易所,您需要创建相应交易所类的实例。支持的交易所会经常更新,并定期添加新的交易所。

库的结构可以概述如下:

                                 用户
    +-----------------------------------------------------------+
    |                          CCXT                               |
    +------------------------------+------------------------------+
    |            公共             |           私有                |
    +===========================================================+
    │                             .                              |
    │                     统一的CCXT API                          |
    │                             .                              |
    |      loadMarkets            .           fetchBalance        |
    |      fetchMarkets           .           createOrder        |
    |      fetchCurrencies        .           cancelOrder        |
    |      fetchTicker            .            fetchOrder        |
    |      fetchTickers           .           fetchOrders        |
    |      fetchOrderBook         .        fetchOpenOrders        |
    |      fetchOHLCV             .       fetchClosedOrders       |
    |      fetchStatus            .           fetchMyTrades       |
    |      fetchTrades            .               deposit         |
    |                             .              withdraw        |
    │                             .                              |
    +===========================================================+
    │                             .                              |
    |                     自定义交易所API                        |
    |                  (派生类及其隐式方法)                      |
    │                             .                              |
    |      publicGet...           .          privateGet...        |
    |      publicPost...          .          privatePost...       |
    |                             .          privatePut...       |
    |                             .       privateDelete...       |
    |                             .                sign          |
    │                             .                              |
    +===========================================================+
    │                             .                              |
    |                    基本交易所类                           |
    │                             .                              |
    +===========================================================+

所有交易所都实现了完整的公共和私有HTTP REST API。JavaScript、PHP、Python的WebSocket实现可在CCXT Pro中使用,它是CCXT的专业附加组件,支持WebSocket流。

交易所#

CCXT库目前支持以下98个加密货币交易所市场和交易API:

logo

id

name

ver

certified

pro

ace

ace

ACE

API Version 2

alpaca

alpaca

Alpaca

API Version *

CCXT Pro

ascendex

ascendex

AscendEX

API Version 2

CCXT Pro

bequant

bequant

Bequant

API Version 2

CCXT Pro

bigone

bigone

BigONE

API Version 3

binance

binance

Binance

API Version *

CCXT Certified

CCXT Pro

binancecoinm

binancecoinm

Binance COIN-M

API Version *

CCXT Certified

CCXT Pro

binanceus

binanceus

Binance US

API Version *

CCXT Pro

binanceusdm

binanceusdm

Binance USDⓈ-M

API Version *

CCXT Certified

CCXT Pro

bit2c

bit2c

Bit2C

API Version *

bitbank

bitbank

bitbank

API Version 1

bitbns

bitbns

Bitbns

API Version 2

bitfinex

bitfinex

Bitfinex

API Version 1

CCXT Pro

bitfinex2

bitfinex2

Bitfinex

API Version 2

bitflyer

bitflyer

bitFlyer

API Version 1

bitforex

bitforex

Bitforex

API Version 1

bitget

bitget

Bitget

API Version 1

CCXT Certified

CCXT Pro

bithumb

bithumb

Bithumb

API Version *

bitmart

bitmart

BitMart

API Version 2

CCXT Certified

CCXT Pro

bitmex

bitmex

BitMEX

API Version 1

CCXT Certified

CCXT Pro

bitopro

bitopro

BitoPro

API Version 3

CCXT Pro

bitpanda

bitpanda

Bitpanda Pro

API Version 1

CCXT Pro

bitrue

bitrue

Bitrue

API Version 1

CCXT Pro

bitso

bitso

Bitso

API Version 3

bitstamp

bitstamp

Bitstamp

API Version 2

CCXT Pro

bitstamp1

bitstamp1

Bitstamp

API Version 1

bittrex

bittrex

Bittrex

API Version 3

CCXT Pro

bitvavo

bitvavo

Bitvavo

API Version 2

CCXT Certified

CCXT Pro

bkex

bkex

BKEX

API Version 2

bl3p

bl3p

BL3P

API Version 1

blockchaincom

blockchaincom

Blockchain.com

API Version 3

CCXT Pro

btcalpha

btcalpha

BTC-Alpha

API Version 1

btcbox

btcbox

BtcBox

API Version 1

btcmarkets

btcmarkets

BTC Markets

API Version 3

btctradeua

btctradeua

BTC Trade UA

API Version *

btcturk

btcturk

BTCTurk

API Version *

bybit

bybit

Bybit

API Version 5

CCXT Certified

CCXT Pro

cex

cex

CEX.IO

API Version *

CCXT Pro

coinbase

coinbase

Coinbase

API Version 2

coinbaseprime

coinbaseprime

Coinbase Prime

API Version *

CCXT Pro

coinbasepro

coinbasepro

Coinbase Pro

API Version *

CCXT Pro

coincheck

coincheck

coincheck

API Version *

coinex

coinex

CoinEx

API Version 1

CCXT Pro

coinfalcon

coinfalcon

CoinFalcon

API Version 1

coinmate

coinmate

CoinMate

API Version *

coinone

coinone

CoinOne

API Version 2

coinsph

coinsph

Coins.ph

API Version 1

coinspot

coinspot

CoinSpot

API Version *

cryptocom

cryptocom

Crypto.com

API Version 2

CCXT Certified

CCXT Pro

currencycom

currencycom

Currency.com

API Version 2

CCXT Pro

delta

delta

Delta Exchange

API Version 2

deribit

deribit

Deribit

API Version 2

CCXT Pro

digifinex

digifinex

DigiFinex

API Version 3

exmo

exmo

EXMO

API Version 1.1

fmfwio

fmfwio

FMFW.io

API Version 2

CCXT Pro

gate

gate

Gate.io

API Version 4

CCXT Certified

CCXT Pro

gemini

gemini

Gemini

API Version 1

CCXT Pro

hitbtc

hitbtc

HitBTC

API Version 2

CCXT Pro

hitbtc3

hitbtc3

HitBTC

API Version 3

hollaex

hollaex

HollaEx

API Version 2

CCXT Pro

huobi

huobi

Huobi

API Version 1

CCXT Certified

CCXT Pro

huobijp

huobijp

Huobi Japan

API Version 1

CCXT Pro

idex

idex

IDEX

API Version 3

CCXT Pro

independentreserve

independentreserve

Independent Reserve

API Version *

CCXT Pro

indodax

indodax

INDODAX

API Version 2.0

kraken

kraken

Kraken

API Version 0

CCXT Pro

krakenfutures

krakenfutures

Kraken Futures

API Version 3

CCXT Pro

kucoin

kucoin

KuCoin

API Version 2

CCXT Certified

CCXT Pro

kucoinfutures

kucoinfutures

KuCoin Futures

API Version 1

CCXT Pro

kuna

kuna

Kuna

API Version 2

latoken

latoken

Latoken

API Version 2

lbank

lbank

LBank

API Version 1

lbank2

lbank2

LBank

API Version 2

luno

luno

luno

API Version 1

CCXT Pro

lykke

lykke

Lykke

API Version 2

mercado

mercado

Mercado Bitcoin

API Version 3

mexc

mexc

MEXC Global

API Version 3

CCXT Certified

CCXT Pro

ndax

ndax

NDAX

API Version *

CCXT Pro

novadax

novadax

NovaDAX

API Version 1

oceanex

oceanex

OceanEx

API Version 1

okcoin

okcoin

OKCoin

API Version 3

CCXT Pro

okx

okx

OKX

API Version 5

CCXT Certified

CCXT Pro

paymium

paymium

Paymium

API Version 1

phemex

phemex

Phemex

API Version 1

CCXT Pro

poloniex

poloniex

Poloniex

API Version *

CCXT Pro

poloniexfutures

poloniexfutures

Poloniex Futures

API Version 1

CCXT Pro

probit

probit

ProBit

API Version 1

CCXT Pro

tidex

tidex

Tidex

API Version 3

timex

timex

TimeX

API Version 1

tokocrypto

tokocrypto

Tokocrypto

API Version 1

upbit

upbit

Upbit

API Version 1

CCXT Pro

wavesexchange

wavesexchange

Waves.Exchange

API Version *

CCXT Certified

wazirx

wazirx

WazirX

API Version 2

CCXT Pro

whitebit

whitebit

WhiteBit

API Version 4

CCXT Pro

woo

woo

WOO X

API Version 1

CCXT Certified

CCXT Pro

yobit

yobit

YoBit

API Version 3

zaif

zaif

Zaif

API Version 1

zonda

zonda

Zonda

API Version *

除了进行基本的市价和限价订单外,一些交易所还提供杠杆交易、各种衍生品(如期货合约和期权),并且还有暗池OTC(场外交易)、商户API等等。

实例化#

要连接到交易所并开始交易,您需要从ccxt库中实例化一个交易所类。

要以编程方式获取支持的交易所的完整id列表:

// JavaScript
const ccxt = require ('ccxt')
console.log (ccxt.exchanges)
# Python
import ccxt
print (ccxt.exchanges)
// PHP
include 'ccxt.php';
var_dump (\ccxt\Exchange::$exchanges);

可以按照以下示例中的方法实例化交易所:

// JavaScript
const ccxt = require ('ccxt')
let exchange = new ccxt.kraken () // 默认id
let kraken1 = new ccxt.kraken ({ id: 'kraken1' })
let kraken2 = new ccxt.kraken ({ id: 'kraken2' })
let id = 'coinbasepro'
let coinbasepro = new ccxt[id] ();

// 根据变量id
const exchangeId = 'binance'
    , exchangeClass = ccxt[exchangeId]
    , exchange = new exchangeClass ({
        'apiKey': 'YOUR_API_KEY',
        'secret': 'YOUR_SECRET',
    })
# Python
import ccxt
exchange = ccxt.okcoinusd () # 默认id
okcoin1 = ccxt.okcoinusd ({ 'id': 'okcoin1' })
okcoin2 = ccxt.okcoinusd ({ 'id': 'okcoin2' })
id = 'btcchina'
btcchina = eval ('ccxt.%s ()' % id)
coinbasepro = getattr (ccxt, 'coinbasepro') ()

## 来自变量 id
exchange_id = 'binance'
exchange_class = getattr(ccxt, exchange_id)
exchange = exchange_class({
    'apiKey': 'YOUR_API_KEY',
    'secret': 'YOUR_SECRET',
})

PHP中的ccxt库使用内置的UTC/GMT时间函数,因此在使用库的PHP版本之前,需要在php.ini中设置date.timezone或调用date_default_timezone_set()函数。推荐的时区设置是"UTC"

// PHP
date_default_timezone_set('UTC');
include 'ccxt.php';
$bitfinex = new \ccxt\bitfinex(); // 默认id
$bitfinex1 = new \ccxt\bitfinex(array('id' => 'bitfinex1'));
$bitfinex2 = new \ccxt\bitfinex(array('id' => 'bitfinex2'));
$id = 'kraken';
$exchange = '\\ccxt\\' . $id;
$kraken = new $exchange();

// 来自变量 id
$exchange_id = 'binance';
$exchange_class = "\\ccxt\\$exchange_id";
$exchange = new $exchange_class(array(
    'apiKey' => 'YOUR_API_KEY',
    'secret' => 'YOUR_SECRET',
));

在实例化时覆盖交易所属性#

大部分交易所属性以及特定选项可以在实例化交易所类时或之后被覆盖,如下所示:

// JavaScript
const exchange = new ccxt.binance ({
    'rateLimit': 10000, // 统一的交易所属性
    'headers': {
        'YOUR_CUSTOM_HTTP_HEADER': 'YOUR_CUSTOM_VALUE',
    },
    'options': {
        'adjustForTimeDifference': true, // 交易所特定选项
    }
})
exchange.options['adjustForTimeDifference'] = false
# Python
exchange = ccxt.binance ({
    'rateLimit': 10000,  # 统一的交易所属性
    'headers': {
        'YOUR_CUSTOM_HTTP_HEADER': 'YOUR_CUSTOM_VALUE',
    },
    'options': {
        'adjustForTimeDifference': True,  # 交易所特定选项
    }
})
exchange.options['adjustForTimeDifference'] = False
// PHP
$exchange_id = 'binance';
$exchange_class = "\\ccxt\\$exchange_id";
$exchange = new $exchange_class(array(
    'rateLimit' => 10000, // 统一的交易所属性
    'headers' => array(
        'YOUR_CUSTOM_HTTP_HEADER' => 'YOUR_CUSTOM_VALUE',
    ),
    'options' => array(
        'adjustForTimeDifference' => true, // 交易所特定选项
    ),
));
$exchange->options['adjustForTimeDifference'] = false;

Testnets和Sandbox环境#

一些交易所还提供用于测试目的的单独API,使开发人员可以免费交易虚拟货币并测试他们的想法。这些API被称为 “testnets”、“sandboxes” 或者 “staging environments”(具有虚拟测试资产的环境),与 “mainnets” 和 “production environments”(具有真实资产的环境)相对应。大多数情况下,沙盒API是生产API的克隆,所以它们基本上是相同的API,除了与交易所服务器的URL不同。

CCXT统一了这一方面,并允许用户切换到交易所的沙盒(如果底层交易所支持)。 要切换到沙盒模式,用户必须在创建交易所后 立即调用 exchange.setSandboxMode (true)exchange.set_sandbox_mode(true) 之前,而且不能在之前有其他调用!

// JavaScript
const exchange = new ccxt.binance (config)
exchange.setSandboxMode (true) // enable sandbox mode
# Python
exchange = ccxt.binance(config)
exchange.set_sandbox_mode(True)  # enable sandbox mode
// PHP
$exchange = new \ccxt\binance($config);
$exchange->set_sandbox_mode(true); // enable sandbox mode
  • 在创建交易所后立即调用 exchange.setSandboxMode (true) / exchange.set_sandbox_mode (True),在其他调用之前

  • 要获取API keys以访问沙盒,用户必须在相关交易所的沙盒网站上注册并创建沙盒 API 密钥对

  • 沙盒密钥与生产密钥不能互换!

交易所结构#

每个交易所都有一组属性和方法,大多数情况下,你可以通过将参数的关联数组传递给交易所构造函数来覆盖这些属性和方法。你也可以创建一个子类并覆盖所有内容。

这是一个带有示例值的通用交易所属性概览:

{
    'id':   'exchange'                   // 小写字符串交易所 id
    'name': 'Exchange'                   // 可读的字符串
    'countries': [ 'US', 'CN', 'EU' ],   // ISO 国家代码数组
    'urls': {
        'api': 'https://api.example.com/data',  // API 基本 URL 的字符串或字典
        'www': 'https://www.example.com'        // 网站 URL 的字符串
        'doc': 'https://docs.example.com/api',  // URL 字符串或URL数组
    },
    'version':         'v1',             // 以数字结尾的字符串
    'api':             { ... },          // API 端点的字典
    'has': {                             // 交易所功能
        'CORS': false,
        'cancelOrder': true,
        'createDepositAddress': false,
        'createOrder': true,
        'fetchBalance': true,
        'fetchCanceledOrders': false,
        'fetchClosedOrder': false,
        'fetchClosedOrders': false,
        'fetchCurrencies': false,
        'fetchDepositAddress': false,
        'fetchMarkets': true,
        'fetchMyTrades': false,
        'fetchOHLCV': false,
        'fetchOpenOrder': false,
        'fetchOpenOrders': false,
        'fetchOrder': false,
        'fetchOrderBook': true,
        'fetchOrders': false,
        'fetchStatus': 'emulated',
        'fetchTicker': true,
        'fetchTickers': false,
        'fetchBidsAsks': false,
        'fetchTrades': true,
        'withdraw': false,
    },
    'timeframes': {                      // 如果exchange.has['fetchOHLCV'] !== true,则为空
        '1m': '1minute',
        '1h': '1hour',
        '1d': '1day',
        '1M': '1month',
        '1y': '1year',
    },
    'timeout':           10000,          // 毫秒数
    'rateLimit':         2000,           // 毫秒数
    'userAgent':        'ccxt/1.1.1 ...' // 字符串,HTTP User-Agent 标头
    'verbose':           false,          // 布尔值,输出错误详情
    'markets':          { ... }          // 交易对的字典
    'symbols':          [ ... ]          // 按字符串排序的交易对列表
    'currencies':       { ... }          // 按币种代码的货币字典
    'markets_by_id':    { ... },         // 根据 id 的 array of dictionaries (markets) 的字典
    'currencies_by_id': { ... },         // 根据 id 的字典的字典 (markets) 的字典
    'apiKey':   '92560ffae9b8a0421...',  // 公共的 apiKey 字符串 (ASCII, hex, Base64, ...)
    'secret':   '9aHjPmW+EtRRKN/Oi...'   // 私有的 secret key 字符串
    'password': '6kszf4aci8r',           // password 字符串
    'uid':      '123456',                // user id 字符串
    'options':          { ... },         // 交易所特定的选项
    // ... 这里还有其他属性 ...
}

交易所属性#

以下是每个基本交易所属性的详细描述:

  • id:每个交易所都有一个默认的 id。这个 id 不用于任何用途,它是一个字符串文字,用于用户级别的交易所实例标识目的。您可以对同一交易所有多个链接,并通过 id 进行区分。默认 id 全部小写,并与交易所名称对应。

  • name:这是一个包含易于理解的交易所名称的字符串文字。

  • countries:一个包含交易所所在地的二字母 ISO 国家代码的字符串文字数组。

  • urls['api']:用于 API 调用的单个字符串文字基本 URL,或者一个关联数组,其中包含私有和公共 API 的单独 URL。

  • urls['www']:主要的 HTTP 网站 URL。

  • urls['doc']:指向交易所 API 原始文档的单个字符串 URL 链接,或者指向文档的链接数组。

  • version:包含当前交易所 API 版本标识符的字符串文字。ccxt 库在每个请求上附加此版本字符串到 API 基本 URL 上。除非您正在实现一个新的交易所 API,否则不需要修改它。版本标识符通常是以字母 “v” 开头的数值字符串,如 v1.1。除非您正在实现自己的新加密交易所类,否则不要覆盖它。

  • api:一个包含密码交换所公开的所有 API 端点定义的关联数组。API 定义用于 ccxt 自动构建每个可用端点的可调用实例方法。- has: 这是一个交易所能力的关联数组(例如 fetchTickersfetchOHLCVCORS)。

  • timeframes: 一个关联数组,包含交易所的 fetchOHLCV 方法支持的时间框架。只有在 has['fetchOHLCV'] 属性为 true 时才会填充该数组。

  • timeout: 请求-响应往返的超时时间,以毫秒为单位(默认超时时间为 10000 ms = 10 秒)。如果在此时间内未收到响应,库将抛出 RequestTimeout 异常。你可以使用默认的超时值,也可以将其设置为一个合理的值。毫无超时的悬挂是不可行的,当然。一般情况下,你不必覆盖此选项。

  • rateLimit: 请求限制速率,以毫秒为单位。指定两个连续的对同一交易所的HTTP请求之间的最小延迟。内置的速率限制器默认是启用的,可以通过将 enableRateLimit 属性设置为 false 来关闭它。

  • enableRateLimit: 一个布尔 (true/false) 值,启用内置的速率限制器,限制连续的请求。默认情况下,此设置为 true(启用)。用户需要实现自己的速率限制或者保持内置的速率限制器启用,以避免被交易所封禁

  • userAgent: 一个对象,用于设置 HTTP User-Agent 头。ccxt 库默认会设置它的 User-Agent。有些交易所可能不喜欢它。如果你无法从交易所收到回复并希望关闭 User-Agent 或使用默认值,请将此值设置为 false、undefined 或空字符串。userAgent 的值可以被下面的 HTTP headers 属性覆盖。

  • headers: 一个关联数组,包含 HTTP 头和它们的值。默认值为空 {}。所有头将被添加到所有请求的前面。如果在 headers 中设置了 User-Agent 头,它将覆盖上面 userAgent 属性设置的任何值。

  • verbose: 一个布尔标志,指示是否将 HTTP 请求记录到 stdout(verbose 标志默认为 false)。Python 用户有一种替代方法,可以使用标准的 Pythonic 记录器进行调试日志记录,只需在代码开头添加以下两行:

    import logging
    logging.basicConfig(level=logging.DEBUG)
    
  • markets: 一个关联数组,通过常见的交易对或符号进行索引的市场。在访问此属性之前,应该先加载市场。在交易所实例上调用 loadMarkets() / load_markets() 方法之前,市场是不可用的。

  • symbols: 一个非关联数组(列表),包含交易所提供的可用符号,并按字母顺序排序。这些是 markets 属性的键。符号是从市场加载和重新加载的。此属性为所有市场键提供了方便的简写形式。- currencies: 一个关联数组(字典),按代码(通常是3或4个字母)列出了可用于交换的货币。货币会从市场中加载和重新加载。

  • markets_by_id: 一个关联数组,按交易所特定的id索引的市场数组列表。通常只包含一个元素,除非有多个具有相同marketId的市场。在访问此属性之前,应该先加载市场。

  • apiKey: 这是您的公共API密钥字符串。大多数交易所都需要设置API密钥

  • secret: 您的私密API密钥字符串字面量。大多数交易所也需要此密钥和apiKey一起使用。

  • password: 一个包含您的密码/短语的字符串字面量。某些交易所在交易时需要此参数,但大多数交易所不需要。

  • uid: 您账户的唯一id。这可以是一个字符串字面量或数字。某些交易所在交易时也需要这个id,但大多数交易所不需要。

  • requiredCredentials: 一个统一的关联字典,显示发出私有API调用到底层交易所所需的API凭证(交易所可能需要特定的一组密钥)。

  • options: 一个特定于交易所的关联字典,包含底层交易所接受并在CCXT中支持的特殊键和选项。

  • precisionMode: 交易所十进制精度计算模式,请阅读更多关于精确度和限制的信息

  • 有关代理 - proxyUrlhttpUrlhttpsUrlsocksProxy:特定代理的URL。请在代理部分详细了解。请参考覆盖交换属性部分。

交换元数据#

  • has:一个包含交换能力标志的关联数组,包括以下内容:

    'has': {
    
        'CORS': false,  // 是否启用了跨域资源共享(来自浏览器) 
    
        // 统一的方法可用性标志(可以为true、false或'emulated'):
    
        'cancelOrder': true,
        'createDepositAddress': false,
        'createOrder': true,
        'fetchBalance': true,
        'fetchCanceledOrders': false,
        'fetchClosedOrder': false,
        'fetchClosedOrders': false,
        'fetchCurrencies': false,
        'fetchDepositAddress': false,
        'fetchMarkets': true,
        'fetchMyTrades': false,
        'fetchOHLCV': false,
        'fetchOpenOrder': false,
        'fetchOpenOrders': false,
        'fetchOrder': false,
        'fetchOrderBook': true,
        'fetchOrders': false,
        'fetchStatus': 'emulated',
        'fetchTicker': true,
        'fetchTickers': false,
        'fetchBidsAsks': false,
        'fetchTrades': true,
        'withdraw': false,
        ...
    }
    

    每个标志表示该方法的可用性,具体含义如下:

    • undefined / None / null的值表示ccxt目前未实现该方法(ccxt尚未统一该方法或交换API原生不支持该方法)

    • boolean值false表示交换API原生不支持该端点

    • boolean值true表示该端点在交换API中原生可用,并在ccxt库中统一

    • 字符串'emulated'表示交换API原生不支持该端点,但在ccxt库中通过其他可用的真实方法进行了重构(尽可能)

    有关所有交换和它们支持的方法的完整列表,请参阅以下示例:https://github.com/ccxt/ccxt/blob/master/examples/js/exchange-capabilities.js## 速率限制

交易所通常会设置所谓的速率限制。交易所会记住并跟踪你的用户凭据和IP地址,如果你对API的查询太频繁,他们将不允许你继续查询。他们通过平衡负载和控制流量拥堵来保护API服务器免受(D)DoS攻击和滥用。

警告:请保持在速率限制范围内,以避免被禁止!

大多数交易所允许每秒最多1~2个请求。如果你对您的请求过于激进,交易所可能会暂时限制您访问其API或封禁你一段时间。

exchange.rateLimit属性默认设置为安全值,但这不是最优的。一些交易所对不同的终端点可能有不同的速率限制。用户根据特定应用目的来调整rateLimit是用户的责任。

CCXT库内置了一个实验性的速率限制器,它会在后台为用户透明地进行必要的节流控制。警告:用户负责至少某种类型的速率限制:可以通过实现自定义算法或使用内置速率限制器来实现。

使用.enableRateLimit属性来开启/关闭内置速率限制器,示例如下:

// JavaScript

// 在交易所实例化时开启内置速率限制器
const exchange = new ccxt.bitfinex ({
    // 'enableRateLimit': true, // 默认开启
})

// 或者在实例化后随时开关内置速率限制器
exchange.enableRateLimit = true // 开启
exchange.enableRateLimit = false // 关闭
# Python

# 启用实例化交换时的内置速率限制
exchange = ccxt.bitfinex({
    # 'enableRateLimit': True,  # 默认启用
})

# 或者在实例化后以后随时打开或关闭内置速率限制
exchange.enableRateLimit = True  # 启用
exchange.enableRateLimit = False  # 禁用
// PHP

// 启用实例化交换时的内置速率限制
$exchange = new \ccxt\bitfinex (array (
    // 'enableRateLimit' => true, // 默认启用
));

// 或者在实例化后以后随时打开或关闭内置速率限制
$exchange->enableRateLimit = true; // 启用
$exchange->enableRateLimit = false; // 禁用

如果您的调用达到速率限制或出现nonce错误,ccxt库将抛出InvalidNonce异常,或者在某些情况下可能抛出以下类型之一:

  • DDoSProtection

  • ExchangeNotAvailable

  • ExchangeError

  • InvalidNonce

通常,稍后的重试足以处理此问题。

关于速率限制器的注意事项#

速率限制器是交换实例的一个属性,换句话说,每个交换实例都有自己的速率限制器,不知道其他实例的存在。在许多情况下,用户应该在整个程序中重复使用同一个交换实例。不要使用同一IP地址上具有相同API密钥对的多个相同交换实例。

// 不要这样做!

const binance1 = new ccxt.binance ({ enableRateLimit: true })
const binance2 = new ccxt.binance ({ enableRateLimit: true })
const binance3 = new ccxt.binance ({ enableRateLimit: true })

while (true) {
    const result = await Promise.all ([
        binance1.fetchOrderBook ('BTC/USDT'),
        binance2.fetchOrderBook ('ETH/USDT'),
        binance3.fetchOrderBook ('ETH/BTC'),
    ])
    console.log (result)
}

尽量重复使用交换实例,如下所示:

// 做这个代替:

const binance = new ccxt.binance ({ enableRateLimit: true })

while (true) {
    const result = await Promise.all ([
        binance.fetchOrderBook ('BTC/USDT'),
        binance.fetchOrderBook ('ETH/USDT'),
        binance.fetchOrderBook ('ETH/BTC'),
    ])
    console.log (result)
}

由于速率限制器属于交换实例,销毁交换实例也会销毁速率限制器。在使用速率限制时,最常见的陷阱之一就是反复创建和销毁交换实例。如果在程序中你反复创建和销毁交换实例(比如,在多次调用的函数内),那么你就会不断地重置速率限制器,最终会破坏速率限制。如果你每次重新创建交换实例而不是重复使用它,CCXT 将会尝试重新加载市场。因此,你将不断地强制加载市场,如 Loading Markets 部分所述。滥用市场接口最终也会破坏速率限制器。

// DO NOT DO THIS!

async function tick () {
    const exchange = new ccxt.binance ({ enableRateLimit: true })
    const response = await exchange.fetchOrderBook ('BTC/USDT')
    // ... some processing here ...
    return response
}

while (true) {
    const result = await tick ()
    console.log (result)
}

如果不理解速率限制器的内部工作方式,并且百分之百确定自己知道自己在做什么,请勿违反此规则。为了确保安全,请始终在函数和方法调用链中重复使用交易所实例,如下所示:

// DO THIS INSTEAD:

async function tick (exchange) {
    const response = await exchange.fetchOrderBook ('BTC/USDT')
    // ... some processing here ...
    return response
}

const exchange = new ccxt.binance ({ enableRateLimit: true })
while (true) {
    const result = await tick (exchange)
    console.log (result)
}

Cloudflare / Incapsula DDoS防护#

一些交易所部署了Cloudflare或者Incapsula来进行DDoS防护。在高负载时,你的IP可能会被临时屏蔽。有时他们甚至会限制整个国家或地区。这种情况下,它们的服务器通常会返回一个显示HTTP 40x错误的页面,或者运行一个浏览器的AJAX测试/验证码测试,并延迟页面的重新加载数秒钟。然后你的浏览器/指纹会被临时授权并被添加到白名单中,或者接收到一个HTTP cookie以供进一步使用。

DDoS防护问题、速率限制问题或基于位置的过滤问题的最常见症状:

  • 所有类型交易方法都出现“RequestTimeout”异常

  • 捕获到带有HTTP错误代码400、403、404、429、500、501、503等的“ExchangeError”或“ExchangeNotAvailable”

  • 存在DNS解析问题、SSL证书问题和低级连接问题

  • 收到交易所的模板HTML页面而不是JSON

如果遇到DDoS保护错误,无法连接到特定交易所,则:- 使用代理(尽管这样会减缓响应速度)

  • 请求交易所支持将您添加到白名单中

  • 尝试使用不同地理区域的替代IP

  • 在分布式服务器网络中运行软件

  • 将软件运行在靠近交易所的地方(同一国家,同一城市,同一数据中心,同一服务器架构,同一服务器)

市场#

每个交易所是交易某种有价值的东西的地方。交易所可能使用不同的术语来称呼它们:”一种货币””一种资产””一枚代币””一只股票””一种商品””一种加密货币””法定货币”等等。通常称交易一种资产换取另一种资产的地方为”一个市场””一个符号””一个交易对”,_”一个合约”_等等。

在ccxt库中,每个交易所都提供多个市场。每个市场由两个或多个货币定义。市场的集合因交易所而异,为跨交易所和跨市场套利提供了可能性。

货币结构#

{
    'id':       'btc',       // 引用交易所内部的字符串字面量
    'code':     'BTC',       // 统一的大写字符串字面量代码
    'name':     '比特币',   // 字符串,可读性强的名称,如果指定了的话
    'active':    true,       // 布尔值,货币状态(可交易和可提取)
    'fee':       0.123,      // 提款费用,平坦的
    'precision': 8,          // 小数位数的数量 "小数点之后"(取决于exchange.precisionMode)
    'deposit':   true        // 布尔值,是否可存款
    'withdraw':  true        // 布尔值,是否可提款
    'limits': {              // 在该市场上下单的价值限制
        'amount': {
            'min': 0.01,     // 订单数量应>最小值
            'max': 1000,     // 订单数量应<最大值
        },
        'withdraw': { ... }, // 提款限制
        'deposit': {...},
    },
    'networks': {...}        // 由统一网络标识符(ERC20,TRC20,BSC等)索引的网络结构
    'info': { ... },         // 交易所中未解析的原始货币信息
}

每个货币都是一个关联数组(也称为字典),包含以下键:

  • id。货币在交易所内部的字符串或数字ID。货币ID在交易所内部用于在请求/响应过程中标识货币。

  • code。特定货币的大写字符串代码表示。货币代码用于在ccxt库中引用货币(下面会解释)。

  • name。货币的可读性强的名称(可以是大写和小写字符的混合)。

  • fee。由交易所指定的提款费值。在大多数情况下,这意味着以相同货币支付的固定金额。如果交易所没有通过公共端点指定它,则fee可能是undefined/None/null或缺失。

  • active。一个布尔值,表示当前是否可以交易或资金(存款或提取)该货币,详细信息请参见:active状态

  • info。关联数组,包含非常用市场属性,包括费用、汇率、限制和其他一般市场信息。每个特定市场的内部info数组都不同,其内容取决于交易所。

  • precision。交易所在引用此货币时接受的结果的精度。此属性的值取决于exchange.precisionMode

  • limits。金额(成交量)、提款和存款的最小和最大值。

网络结构#

{
    'id': 'tron', // 在交易所内部引用的字符串字面量
    'network': 'TRC20', // 统一的网络
    'name': '波场网络', // 字符串,可读性强的名称(如果有)
    'active': true, // 币种状态(可交易和可提现)的布尔值
    'fee': 0.123, // 提现费用,固定数额
    'precision': 8, // 小数点后的位数(取决于exchange.precisionMode)
    'deposit': true, // 是否允许存款的布尔值
    'withdraw': true, // 是否允许提款的布尔值
    'limits': { // 下单时的最小和最大值限制
        'amount': {
            'min': 0.01, // 订单数量必须大于min
            'max': 1000, // 订单数量必须小于max
        },
        'withdraw': { ... }, // 提款限制
        'deposit': { ... }, // 存款限制
    },
    'info': { ... }, // 来自交易所的原始未解析货币信息
}

每个网络都是一个关联数组(也称为字典),具有以下键:

  • id。网络在交易所内的字符串或数字ID。在请求/响应过程中,交易所内部使用网络ID来标识网络。

  • network。特定网络的大写字符串表示。在ccxt库中用于引用网络。

  • name。网络的可读名称(可以是大写和小写字母的混合形式)。

  • fee。交易所指定的提款费用。在大多数情况下,这意味着以同一货币支付的固定金额。如果交易所未通过公共端点指定它,则fee可能为undefined/None/null或缺失。

  • active。一个布尔值,指示此货币当前是否可以交易或充提币。详细信息请参见active状态

  • info。非公共市场属性的关联数组,包括费用、汇率、限制和其他一般市场信息。内部信息数组因特定市场而异,其内容取决于交易所。

  • precision。在引用该货币时交易所接受的精度。该属性的值取决于exchange.precisionMode

  • limits。金额(交易量)、提款和存款的最小和最大值。

市场结构#

{
    'id': 'btcusd', // 在交易所内部引用的字符串字面量
    'symbol': 'BTC/USD', // 交易对的大写字符串字面量
    'base': 'BTC', // 大写字符串,统一的基础货币代码,3个或更多字母
    'quote': 'USD', // 大写字符串,统一的报价货币代码,3个或更多字母
    'baseId': 'btc', // 基础货币的交易所特定ID,不统一。可以是任何字符串。
    'quoteId': 'usd', // 报价货币的交易所特定ID,不统一。
    'active': true, // 市场状态的布尔值
    'type': 'spot', // spot表示现货,future表示到期期货,swap表示永续互换,'option'表示期权
    'spot': true, // 市场是否是现货市场的布尔值
    'margin': true, // 市场是否是保证金市场的布尔值
    'future': false, // 市场是否是到期期货
    'swap': false, // 市场是否是永续互换
    'option': false, // 市场是否是期权合约
    'contract': false, // 市场是否是期货、永续互换或期权
    'settle': 'USDT', // 合约结算的统一货币代码,仅当`contract`为true时设置
    'settleId': 'usdt', // 合约结算的货币ID,仅当`contract`为true时设置
    'contractSize': 1, // 一个合约的大小,仅在`contract`为true时使用
    'linear': true, // 合约是否是线性合约(以报价货币结算)
    'inverse': false, // 合约是否是反向合约(以基础货币结算)
    'expiry': 1641370465121, // 以毫秒为单位的Unix到期时间戳,除了market['type']为`future`之外,都为未定义
    'expiryDatetime': '2022-03-26T00:00:00.000Z', // iso8601格式的合约到期时间
    'strike': 4000, // 可以行使看涨或看跌期权的价格
    'optionType': 'call', // 看涨或看跌的字符串,看涨期权表示具有购买权的期权,看跌期权表示具有出售权的期权
    'taker': 0.002, // 吃单者手续费率,0.002 = 0.2%
    'maker': 0.0016, // 挂单者手续费率,0.0016 = 0.16%
    'percentage': true, // 吃单者和挂单者手续费率是否为乘数或固定金额的布尔值
    'tierBased': false, // 手续费是否取决于交易等级(交易量)
    'feeSide': 'get', // 字符串字面量可以是'get'、'give'、'base'、'quote'、'other'
    'precision': { // 小数点后的位数
        'price': 8, // 四舍五入模式的整数或浮点数,如果交易所未提供,则可能缺失
        'amount': 8, // 整数,如果交易所未提供,则可能缺失
        'cost': 8, // 整数,很少有交易所实际提供
    },
    'limits': { // 在该市场上下单时的最小值和最大值限制
        'amount': {
            'min': 0.01, // 订单数量必须大于min
            'max': 1000, // 订单数量必须小于max
        },
        'price': { ... }, // 订单价格的相同min/max限制
        'cost': { ... }, // 订单成本(cost = price * amount)的相同限制
        'leverage': { ... }, // 杠杆的相同min/max限制
    },
    'info': { ... }, // 来自交易所的原**警告!有关费用的信息是实验性的,不稳定的,可能是部分的或根本不可用。**
    }

精度与限制#

不要将“限制”与“精度”混淆! 精度与最小限制无关。8位数字的精度并不一定意味着最小限制为0.00000001。相反,最小限制为0.0001并不一定意味着精度为4。

示例:

  1. (market['limits']['amount']['min'] == 0.05) && (market['precision']['amount'] == 4)

在此示例中,放置在市场上的任何订单的金额必须满足这两个条件

  • 金额的值应该 >= 0.05:

    + 好: 0.05, 0.051, 0.0501, 0.0502, ..., 0.0599, 0.06, 0.0601, ...
    - 不好:0.04, 0.049, 0.0499
    
  • 金额的精度应为4位小数:

    + 好: 0.05, 0.051, 0.052, ..., 0.0531, ..., 0.06, ...0.0719, ...
    - 不好:0.05001, 0.05000, 0.06001
    
  1. (market['limits']['price']['min'] == 0.019) && (market['precision']['price'] == 5)

在此示例中,放置在市场上的任何订单的价格必须满足这两个条件

  • 价格的值应该 >= 0.019:

    + 好: 0.019, ... 0.0191, ... 0.01911, 0.01912, ...
    - 不好:0.016, ..., 0.01699
    
  • 价格的精度应为5位小数或更低:

    + 好: 0.02, 0.021, 0.0212, 0.02123, 0.02124, 0.02125, ...
    - 不好:0.017000, 0.017001, ...
    
  1. (market['limits']['amount']['min'] == 50) && (market['precision']['amount'] == -1)

在这个例子中,两个条件都必须满足

  • amount值应该大于或等于50:

    + good: 50, 60, 70, 80, 90, 100, ... 2000, ...
    - bad: 1, 2, 3, ..., 9
    
  • 负的amount精度意味着amount应该是指定幂次的10的整数倍:

    + good: 50, ..., 110, ... 1230, ..., 1000000, ..., 1234560, ...
    - bad: 9.5, ... 10.1, ..., 11, ... 200.71, ...
    

precisionlimits参数目前正在研发中,一些字段可能在一致化过程完成之前会有所缺失。这并不会影响大多数订单,但在非常大或非常小的订单的极端情况下可能会有影响。

关于精度和限制的说明#

用户必须遵守所有限制和精度!订单的值应满足以下条件:

  • 订单amount >= limits['amount']['min']

  • 订单amount <= limits['amount']['max']

  • 订单price >= limits['price']['min']

  • 订单price <= limits['price']['max']

  • 订单cost (amount * price) >= limits['cost']['min']

  • 订单cost (amount * price) <= limits['cost']['max']

  • amount的精度必须小于等于precision['amount']

  • price的精度必须小于等于precision['price']

上述的值在一些交易所的API中可能会缺失或尚未实现。

格式化小数的方法#

每个交易所都有自己的四舍五入、计数和填充模式。支持的舍入模式有:

  • ROUND – 将最后几位小数舍入到指定精度

  • TRUNCATE – 截取指定精度后的小数位

可以通过 exchange.precisionMode 属性设置小数精度计数模式。

精度模式#

exchange['precisionMode'] 中支持的精度模式有:

  • DECIMAL_PLACES – 计算所有数字的位数,99% 的交易所使用这种计数模式。在这种精密度模式中,market_or_currency['precision'] 中的数字指定小数点后要进行舍入或截断的位数。

  • SIGNIFICANT_DIGITS – 仅计算非零数字的位数,一些交易所(如 bitfinex 和其他一些)实施这种计算小数位数的模式。在这种精度模式中,market_or_currency['precision'] 中的数字指定小数点后最后一个重要(非零)数字的第 N 位。

  • TICK_SIZE – 一些交易所只允许使用特定值的倍数(例如 bitmexftx 使用此模式)。在这种模式下,market_or_currency['precision'] 中的数字指定用于舍入或截断的最小精度小数部分。

填充模式#

支持的填充模式有:

  • NO_PADDING – 大多数情况下的默认模式

  • PAD_WITH_ZERO – 在精度之后添加零字符大多数情况下,当用户下订单或发送提款请求时,用户不必关心精确的格式化,因为CCXT会在用户按照精度和限制的规则操作时为用户处理这些。然而,在某些情况下,精确格式化细节可能很重要,因此以下方法可能对用户很有用。

交易所基类包含decimalToPrecision方法,可帮助以不同的四舍五入、计数和填充模式格式化值。

// JavaScript
function decimalToPrecision (x, roundingMode, numPrecisionDigits, countingMode = DECIMAL_PLACES, paddingMode = NO_PADDING)
# Python
# 警告!`decimal_to_precision`方法容易受到`getcontext().prec`的影响!
def decimal_to_precision(n, rounding_mode=ROUND, precision=None, counting_mode=DECIMAL_PLACES, padding_mode=NO_PADDING):
// PHP
function decimalToPrecision ($x, $roundingMode = ROUND, $numPrecisionDigits = null, $countingMode = DECIMAL_PLACES, $paddingMode = NO_PADDING)

请参阅以下文件,了解如何使用decimalToPrecision格式化字符串和浮点数的示例:

Python 警告!decimal_to_precision方法容易受到getcontext().prec的影响!

为了方便用户,CCXT基类还实现了以下方法:

// JavaScript
function amountToPrecision (symbol, amount)
function priceToPrecision (symbol, price)
function costToPrecision (symbol, cost)
function currencyToPrecision (code, amount)
# Python
def amount_to_precision (symbol, amount):
def price_to_precision (symbol, price):
def cost_to_precision (symbol, cost):
def currency_to_precision (code, amount):
// PHP
function amount_to_precision($symbol, $amount)
function price_to_precision($symbol, $price)
function cost_to_precision($symbol, $cost)
function currency_to_precision($code, $amount)

每个交易所都有自己的精度设置,上述方法将根据交易所特定的精度规则格式化这些值,以一种可移植且与底层交易所无关的方式。为了实现这一点,在格式化任何值之前,必须先加载市场和货币。

在调用这些方法之前,确保 使用 exchange.loadMarkets() 加载市场

例如:

// JavaScript
await exchange.loadMarkets ()
const symbol = 'BTC/USDT'
const amount = 1.2345678 // BTC 的基本货币数量
const price = 87654.321 // USDT 的报价货币价格
const formattedAmount = exchange.amountToPrecision (symbol, amount)
const formattedPrice = exchange.priceToPrecision (symbol, price)
console.log (formattedAmount, formattedPrice)
# Python
exchange.load_markets()
symbol = 'BTC/USDT'
amount = 1.2345678  # BTC 的基本货币数量
price = 87654.321  # USDT 的报价货币价格
formatted_amount = exchange.amount_to_precision(symbol, amount)
formatted_price = exchange.price_to_precision(symbol, price)
print(formatted_amount, formatted_price)
// PHP
$exchange->load_markets();
$symbol = 'BTC/USDT';
$amount = 1.2345678;  // BTC 的基本货币数量
$price = 87654.321; // USDT 的报价货币价格
$formatted_amount = $exchange->amount_to_precision($symbol, $amount);
$formatted_price = $exchange->price_to_precision($symbol, $price);
echo $formatted_amount, " ", $formatted_price, "\n";

更多描述 exchange.precisionMode 行为的实际示例:

// 情况 A
exchange.precisionMode = ccxt.DECIMAL_PLACES
market = exchange.market (symbol)
market['precision']['amount'] === 8 // 小数点后最多 8 位数
exchange.amountToPrecision (symbol, 0.123456789) === 0.12345678
exchange.amountToPrecision (symbol, 0.0000000000123456789) === 0.0000000 === 0.0
// B 情况
exchange.precisionMode = ccxt.TICK_SIZE
market = exchange.market (symbol)
market['precision']['amount'] === 0.00000001 // 高达 0.00000001 精度
exchange.amountToPrecision (symbol, 0.123456789) === 0.12345678
exchange.amountToPrecision (symbol, 0.0000000000123456789) === 0.00000000 === 0.0
// C 情况
exchange.precisionMode = ccxt.SIGNIFICANT_DIGITS
market = exchange.market (symbol)
market['precision']['amount'] === 8 // 高达 8 个有效数字
exchange.amountToPrecision (symbol, 0.0000000000123456789) === 0.000000000012345678
exchange.amountToPrecision (symbol, 123.4567890123456789) === 123.45678

加载市场#

在大多数情况下,在访问其他 API 方法之前,您需要先加载特定交易所的市场列表和交易符号。如果您忘记加载市场,ccxt 库会在首次调用统一 API 时自动完成加载市场的工作。它会依次发送两个 HTTP 请求,第一个请求用于获取市场信息,第二个请求用于获取其他数据。因此,首次调用统一 CCXT API 方法(比如 fetchTicker、fetchBalance 等)会比后续的调用时间更长,因为它需要在交易所 API 中加载更多的市场信息。有关详细信息,请参见速率限制器注意事项

为了手动预先加载市场,请在交易所实例上调用 loadMarkets() / load_markets() 方法。它返回一个按交易符号索引的市场关联数组。如果您想要更多地控制逻辑的执行,建议手动预加载市场。

// JavaScript
(async () => {
    let kraken = new ccxt.kraken ()
    let markets = await kraken.loadMarkets ()
    console.log (kraken.id, markets)
}) ()
# Python
okcoin = ccxt.okcoinusd()
markets = okcoin.load_markets()
print(okcoin.id, markets)
// PHP
$id = 'huobipro';
$exchange = '\\ccxt\\' . $id;
$huobipro = new $exchange();
$markets = $huobipro->load_markets();
var_dump($huobipro->id, $markets);

除了市场信息外,loadMarkets() 调用还会加载交易所的货币信息,并将信息分别缓存在 .markets.currencies 属性中。

用户也可以绕过缓存,直接调用统一方法从交易所端点获取这些信息,即 fetchMarkets()fetchCurrencies(),尽管不建议终端用户使用这些方法。推荐的预加载市场的方式是调用 loadMarkets() 统一方法。然而,对于新的交易所集成,如果底层交易所具有相应的 API 端点,需要实现这些方法。## 符号和市场标识

货币代码是一个包含三到五个字母的代码,例如 BTC, ETH, USD, GBP, CNY, JPY, DOGE, RUB, ZEC, XRP, XMR等等。一些交易所拥有更长的代码来表示奇特的货币。

符号通常是一个以斜线分隔的交易货币对的大写字符串。斜线前的货币通常被称为基准货币,斜线后的货币被称为报价货币。一些代表符号的例子是: BTC/USD, DOGE/LTC, ETH/EUR, DASH/XRP, BTC/CNY, ZEC/XMR, ETH/JPY

市场标识在REST请求-响应过程中用于引用交易所内的交易对。市场标识集在每个交易所中是唯一的,不可以跨交易所使用。例如,BTC/USD货币对/市场在不同的流行交易所上可能有不同的标识,例如btcusdBTCUSDXBTUSDbtc/usd42 (数字标识),BTC/USDBtc/UsdtBTCUSDXXBTZUSD。你不需要记住或使用市场标识,它们只是交易所内部实现中用于HTTP请求-响应目的的存在。

ccxt库将不常见的市场标识抽象成符号,统一为一种常见格式。符号并不等同于市场标识。每个市场都通过对应的符号进行引用。符号在交易所之间是通用的,这使得它们适用于套利和其他许多应用。

有时候用户可能会注意到像 'XBTM18''.XRPUSDM20180101' 这样的 “奇特/罕见的符号”。符号不必须包含斜线或表示一对货币。符号中的字符串实际上取决于市场的类型(是现货市场还是期货市场,是暗池市场还是过期市场等等)。强烈不推荐尝试解析符号字符串,不应依赖符号格式,建议使用市场属性代替。

市场结构以符号和标识为索引。基础交易所类也有内置方法,可以通过符号访问市场。大多数API方法在第一个参数中需要传入一个符号。在查询当前价格、下订单等方面,通常要求指定一个符号。

在大多数情况下,用户将与市场符号一起使用。在这些词典中访问不存在的键时,将得到一个标准的用户异常。

市场和货币的方法#

// JavaScript(async () => {

    console.log(await exchange.loadMarkets())

    let btcusd1 = exchange.markets['BTC/USD']     // 根据交易对获取市场结构
    let btcusd2 = exchange.market('BTC/USD')     // 以略微不同的方式得到相同结果

    let btcusdId = exchange.marketId('BTC/USD')  // 根据交易对获取市场ID

    let symbols = exchange.symbols                // 获取交易对数组
    let symbols2 = Object.keys(exchange.markets) // 与上一行相同

    console.log(exchange.id, symbols)            // 打印所有交易对

    let currencies = exchange.currencies          // 一种货币字典

    let bitfinex = new ccxt.bitfinex()
    await bitfinex.loadMarkets()

    bitfinex.markets['BTC/USD']                   // 交易对 → 市场(通过交易对获取市场)
    bitfinex.markets_by_id['XRPBTC'][0]           // id → 市场(通过ID获取市场)

    bitfinex.markets['BTC/USD']['id']             // 交易对 → ID(通过交易对获取ID)
    bitfinex.markets_by_id['XRPBTC'][0]['symbol'] // id → 交易对(通过ID获取交易对)

}) ()
# Python

print(exchange.load_markets())

etheur1 = exchange.markets['ETH/EUR']          # 通过交易对获取交易所结构
etheur2 = exchange.market('ETH/EUR')           # 通过交易对以略微不同的方式获取相同的结果

etheurId = exchange.market_id('ETH/EUR')       # 通过交易对获取交易对的ID

symbols = exchange.symbols                     # 获取交易所支持的所有交易对列表
symbols2 = list(exchange.markets.keys())       # 与上一行代码相同

print(exchange.id, symbols)                    # 打印所有交易对

currencies = exchange.currencies               # 货币词典

kraken = ccxt.kraken ()
kraken.load_markets()

kraken.markets['BTC/USD']                      # 交易对 --> 交易所 (通过交易对获取交易所)
kraken.markets_by_id['XXRPZUSD'][0]            # ID --> 交易所 (通过ID获取交易所)
# Python

kraken.markets['BTC/USD']['id']  # 符号 → ID(通过符号获取ID)
kraken.markets_by_id['XXRPZUSD'][0]['symbol']  # ID → 符号(通过ID获取符号)
// PHP

$var_dump($exchange->load_markets());

$dashcny1 = $exchange->markets['DASH/CNY'];  // 通过符号获取市场结构
$dashcny2 = $exchange->market('DASH/CNY');  // 以稍微不同的方式获得相同的结果

$dashcnyId = $exchange->market_id('DASH/CNY');  // 通过符号获取市场ID

$symbols = $exchange->symbols;  // 获取符号数组
$symbols2 = array_keys($exchange->markets);  // 与前一行相同

var_dump($exchange->id, $symbols);  // 打印所有符号

$currencies = $exchange->currencies;  // 货币的关联数组

$okcoinusd = '\\ccxt\\okcoinusd';
$okcoinusd = new $okcoinusd();

$okcoinusd->load_markets();```php
$okcoinusd->markets['BTC/USD'];                    // symbol → 市场(根据符号获取市场)
$okcoinusd->markets_by_id['btc_usd'][0];              // id → 市场(根据ID获取市场)

$okcoinusd->markets['BTC/USD']['id'];              // symbol → ID (根据符号获取ID)
$okcoinusd->markets_by_id['btc_usd'][0]['symbol']; // id → 符号(根据ID获取符号)

命名一致性#

在各种交易所之间存在术语模糊性,这可能会导致新入行的交易者产生困惑。一些交易所将市场称为“交易对”,而其他交易所将符号称为“产品”。根据ccxt库的术语,每个交易所包含一个或多个交易市场。每个市场都具有ID和符号。大多数符号是基础货币和报价货币的组合。

交易所 市场 符号 货币

从历史上看,不同的交易对称用于指代相同的交易对。一些加密货币(如Dash)甚至在其运行的整个生命周期中多次更改其名称。为了在交易所之间保持一致性,ccxt库将针对符号和货币执行以下已知替换操作:

  • XBT BTCXBT是较新的符号,但是BTC在各交易所中更常见,并且更像比特币(了解更多)。

  • BCC BCH:比特币现金的分叉通常有两个不同的符号名称:BCCBCHBCC是比特现金的一个误导性符号,它与比特币连接(BitConnect)混淆。ccxt库将BCC转换为BCH(一些交易所和聚合器将其搞混)。

  • DRK DASHDASH曾被称为Darkcoin,然后变成了Dash(了解更多)。

  • BCHABC BCH:2018年11月15日,比特币现金第二次分叉,因此现在有BCH(用于BCH ABC)和BSV(用于BCH SV)。

  • BCHSV BSV:这是比特币现金SV分叉的常见替换映射(有些交易所称其为BSV,其他交易所称其为BCHSV,我们使用前者)。

  • DSH DASH:尽量不要混淆符号和货币。DSH(Dashcoin)与DASH(Dash)不同。一些交易所将DASH不一致地标记为DSH,ccxt库对此进行了更正(DSH DASH),但只会在一些混淆了这两种货币的交易所上进行。大多数交易所都将它们标记正确。只要记住DASH/BTCDSH/BTC不同即可。

  • XRBNANONANO是RaiBlocks的较新代码,因此,CCXT统一的API在需要的地方将旧的XRB替换为NANO。https://hackernoon.com/nano-rebrand-announcement-9101528a7b76

  • USDUSDT:一些交易所,如Bitfinex,HitBTC和其他一些交易所,在其列表中将货币命名为USD,但实际上这些市场实际上是交易USDT。混淆可能来自符号名称的三个字母限制,或者可能是由其他原因引起的。在实际上交易的货币是USDT而不是USD的情况下,ccxt库将执行USDUSDT转换。然而,请注意,一些交易所同时具有USDUSDT符号,例如, Kraken拥有“USDT/USD”交易对。

关于命名一致性的注释#

每个交易所都有自己的国际货币符号的关联数组,并存储在exchange.commonCurrencies属性中。有时,用户可能会在代码中注意到带有大小写词和空格的奇异符号名称。在命名和货币编码冲突的解决规则中,这些名称背后的逻辑解释如下:

  • 首先,我们收集有关所涉及货币代码的交易所自身提供的所有信息。它们通常在其API或其文档、知识库或其他地方的网站上有他们的币种清单的描述。

  • 当我们确定与货币代码相关的每个特定加密货币时,我们在CoinMarketCap上查找它们。

  • 所有竞争加密货币中市场资本化最大的那个获胜,并保留其货币代码。例如,HOT通常代表HoloHydro Protocol。在这种情况下,Holo保留代码HOT,而Hydro Protocol将其名称作为其代码,即Hydro Protocol。因此,可能会出现HOT/USD(对应于Holo)和Hydro Protocol/USD的交易对 - 这些是两个不同的市场。

  • 如果特定加密货币的市值未知或不足以确定获胜者,我们还会考虑交易量和其他因素。

  • 确定获胜者之后,将通过.commonCurrencies在冲突的交易所内正确重新映射和替换所有其他竞争货币的代码名称。

  • 不幸的是,这是一个正在进行中的工作,因为每天都有新的货币上市,并且会不时添加新的交易所,因此,总的来说,这是一个永无止境的在快速变化的环境中进行自我修复的过程,实际上是以“实时模式”。我们对您发现的所有冲突和不匹配表示感谢。#### 对命名一致性的问题的疑问

符号是否可能发生变化?

简而言之,是的,有时候会发生变化,但很少见。如果绝对需要并且无法避免,符号映射可以更改。然而,以前的符号更改都是为了解决冲突或分叉的问题。到目前为止,还没有出现过在CCXT中一个币的市值超过了另一个币的情况下,两个币具有相同的符号代码。

我们能否依赖于总是用相同的符号列出相同的加密货币?

多多少少地)首先,这个库还在不断发展中,它试图适应不断变化的实际情况,所以可能会出现我们将来会通过更改一些映射来修复的冲突。最终,许可证上说“不提供保证,请自行承担风险”。然而,我们不会随意更改所有的符号映射,因为我们明白其中的后果,并且我们也希望依赖于这个库,并且我们不喜欢破坏向后兼容性。

如果一个重要代币的符号被分叉或必须更改,那么控制权仍然掌握在用户手中。exchange.commonCurrencies属性可以在初始化或后期进行覆盖,就像任何其他交易所属性一样。如果涉及到重要的代币,我们通常会发布关于如何通过向构造函数参数添加几行代码保留旧行为的说明。

基础货币和报价货币的一致性#

这取决于你使用的交易所,但其中一些交易所的基础货币和报价货币的配对是颠倒的(不一致的)。它们实际上是把基础货币和报价货币搞错了(交换/互换了位置)。在这种情况下,你会看到解析的basequote货币值与市场子结构中的未解析的info不同。

对于这些交易所,ccxt会进行更正,当解析交易所的回复时,会交换和规范化基础货币和报价货币的位置。这种逻辑在财务和术语上是正确的。如果你想避免混淆,记住以下规则:基础货币总是在斜线前,报价货币总是在斜线后,无论是任何符号和任何市场

基础货币 ↓
             BTC / USDT
             ETH / BTC
            DASH / ETH
                    ↑ 报价货币
```#### 合约命名规范

我们目前将统一的`BASE/QUOTE`符号模式加载到`.markets`映射中,以符号为索引。这将导致期货和其他衍生品与其现货市场相同的符号之间存在命名冲突。为了在`.markets`中同时容纳这两种类型的市场,我们要求“期货”和“现货”市场之间的符号不同,以及“线性”和“反向”合约之间的符号不同。

**请查看此公告:[统一合约命名规范](https://github.com/ccxt/ccxt/issues/10931)**

CCXT支持以下类型的衍生合约:

- `future` – 到期的期货合约,具有交割/结算日期 [](https://en.wikipedia.org/wiki/Futures_contract)
- `swap` – 没有交割日期的永续互换合约 [](https://en.wikipedia.org/wiki/Perpetual_futures)
- `option` – 期权合约 (https://en.wikipedia.org/wiki/Option_contract)

##### 期货合约

期货市场的符号由基础货币、报价货币、结算货币和任意标识符组成。通常,标识符是期货合约的结算日期,格式为`YYMMDD`:

```javascript
// 基础资产或货币
// ↓
// ↓  报价资产或货币
// ↓  ↓
// ↓  ↓    结算资产或货币
// ↓  ↓    ↓
// ↓  ↓    ↓     标识符(结算日期)
// ↓  ↓    ↓     ↓
// ↓  ↓    ↓     ↓
'BTC/USDT:BTC-211225'  // BTC/USDT期货合约在2021年12月25日以BTC(反向)结算
'BTC/USDT:USDT-211225' // BTC/USDT期货合约在2021年12月25日以USDT(线性,香草)结算
'ETH/USDT:ETH-210625'  // ETH/USDT期货合约在2021年6月25日以ETH(反向)结算
'ETH/USDT:USDT-210625' // ETH/USDT期货合约在2021年6月25日以USDT(线性,香草)结算
永续互换(永续期货)#
// 基础资产或货币
// ↓
// ↓  报价资产或货币
// ↓  ↓
// ↓  ↓    结算资产或货币
// ↓  ↓    ↓
// ↓  ↓    ↓
'BTC/USDT:BTC'  // BTC/USDT反向永续互换合约以BTC资助
'BTC/USDT:USDT' // BTC/USDT线性永续互换合约以USDT资助
'ETH/USDT:ETH'  // ETH/USDT反向永续互换合约以ETH资助
'ETH/USDT:USDT' // ETH/USDT线性永续互换合约以USDT资助
选项#
//
// 基础资产或货币
// ↓
// ↓  目标资产或货币
// ↓  ↓
// ↓  ↓    结算资产或货币
// ↓  ↓    ↓
// ↓  ↓    ↓       标识符(结算日期)
// ↓  ↓    ↓       ↓
// ↓  ↓    ↓       ↓   行权价
// ↓  ↓    ↓       ↓   ↓
// ↓  ↓    ↓       ↓   ↓   类型,看跌(P)或看涨(C)
// ↓  ↓    ↓       ↓   ↓   ↓
'BTC/USDT:BTC-211225-60000-P'  // BTC/USDT看跌期权行权价为60000 USDT在2021-12-25以BTC反向结算
'ETH/USDT:USDT-211225-40000-C' // BTC/USDT看涨期权行权价为40000 USDT在2021-12-25以USDT线性香草结算
'ETH/USDT:ETH-210625-5000-P'   // ETH/USDT看跌期权行权价为5000 USDT在2021-06-25以ETH反向结算
'ETH/USDT:USDT-210625-5000-C'  // ETH/USDT看涨期权行权价为5000 USDT在2021-06-25以USDT线性香草结算

市场缓存强制重新加载#

loadMarkets()/ load_markets()也是一种“脏”方法,带有在交易所实例上保存市场数组的副作用。您只需调用一次此方法,在交换机上的所有后续对该方法的调用都将返回本地保存(缓存)的市场数组。

当加载交易所市场后,您可以随时通过 markets 属性访问市场信息。此属性包含按符号索引的市场的关联数组。如果您需要在已加载市场之后强制重新加载市场列表,再次向相同的方法传递 reload = true 标志即可。

// JavaScript
(async () => {
    let kraken = new ccxt.kraken{ verbose: true }//记录HTTP请求
    await kraken.loadMarkets()//请求市场
    console.logkraken.id, kraken.markets//输出所有已加载市场的完整列表
    console.logObject.keyskraken.markets))//输出市场符号的简短列表
    console.logkraken.markets [ 'BTC/USD' ]//输出单个市场详细信息
    await kraken.loadMarkets()//返回本地缓存的版本,无需重新加载
    let reloadedMarkets = await kraken.loadMarketstrue//强制HTTP重新加载= true
    console.logreloadedMarkets [ 'ETH/BTC' ]
}) ()
# Python
poloniex = ccxt.poloniex{ verbose: True }//记录HTTP请求
poloniex.load_markets()//请求市场
printpoloniex.idpoloniex.markets//输出所有已加载市场的完整列表
printlistpoloniex.markets.keys()))//输出市场符号的简短列表
printpoloniex.markets [ 'BTC/ETH' ]//输出单个市场详细信息
poloniex.load_markets()//返回本地缓存的版本无需重新加载
reloadedMarkets = poloniex.load_marketsTrue//强制HTTP重新加载= True
printreloadedMarkets [ 'ETH/ZEC' ]
// PHP
$bitfinex = new \ccxt\bitfinex(array('verbose' => true))//记录HTTP请求
$bitfinex.load_markets()//请求市场
var_dump($bitfinex->id,$bitfinex->markets)//输出所有已加载市场的完整列表
var_dump(array_keys($bitfinex->markets))//输出市场符号的简短列表
var_dump($bitfinex->markets [ 'XRP/USD' ])//输出单个市场详细信息
$bitfinex->load_markets()//返回本地缓存的版本,无需重新加载
$reloadedMarkets = $bitfinex->load_markets(true)//强制HTTP重新加载= true
var_dump($bitfinex->markets [ 'XRP/BTC' ])。

隐式API#

API方法/终端点#

每个交易所都提供了一组API方法。 API的每个方法被称为 终端点。 终端点是用于查询各种类型信息的HTTP URL。 所有终端点都返回JSON以响应客户端请求。

通常,交易所有一个用于获取市场列表的终端点,一个用于检索特定市场的订单簿的终端点,一个用于检索交易历史的终端点,以及用于下订单、取消订单、存款和提款的终端点等等… 基本上,你在一个特定交易所内执行的每种操作都有一个API提供的单独的终端点URL。

由于每个交易所的方法集不同,ccxt库实现了以下功能:

  • 为所有可能的URL和方法提供的公共和私有API

  • 一个支持一部分常见方法的统一API

终端点的URL在每个交易所的api属性中预定义。除非你正在实现新的交易所API(至少你应该知道你在做什么),否则你不必覆盖它。

大多数特定交易所的API方法是隐式的,这意味着它们在代码的任何地方都没有明确定义。该库实现了一种声明式的方法来定义隐式(非统一化)交易所API方法。

隐式API方法#

API的每个方法通常有自己的终端点。库在.api属性中定义了每个特定交易所的所有终端点。在交易所实例的defineRestApi()/define_rest_api()中,针对.api终端点列表中的每个终端点,将会创建一个隐式的神奇方法(也称为部分函数闭包)。这个操作对于所有交易所来说都是通用的。每个生成的方法都可以以camelCaseunder_score表示法访问。

终端点定义是一个暴露给交易所的全部API URL列表。在交易所实例化时,该列表会被转换为可调用的方法。API终端点列表中的每个URL都会得到一个相应的可调用方法。这对于所有交易所都是自动完成的,因此ccxt库支持加密交易所提供的所有可能的URL

每个隐式方法都有一个唯一的名称,该名称是根据.api定义构建的。例如,私有HTTPS PUT https://api.exchange.com/order/{id}/cancel终端点将具有相应的交易所方法名称.privatePutOrderIdCancel()/ .private_put_order_id_cancel()。公共HTTPS GET https://api.exchange.com/market/ticker/{pair}终端点将导致相应的方法名称.publicGetTickerPair()/ .public_get_ticker_pair(),依此类推。隐式方法接受一个参数字典,将请求发送到交易所,并返回 API 的特定于交易所的 JSON 结果原样,未解析。要传递参数,请将其明确地添加到字典中,键的名称等于参数的名称。对于上面的例子,这将类似于 .privatePutOrderIdCancel ({ id: '41987a2b-...' }).publicGetTickerPair ({ pair: 'BTC/USD' })

与交易所一起工作的推荐方式不是使用特定于交易所的隐式方法,而是使用统一的 ccxt 方法。特定于交易所的方法应在没有对应的统一方法可用(尚未提供)的情况下使用。

要获取交易所实例的所有可用方法列表,包括隐式方法和统一方法,只需执行以下操作:

console.log (new ccxt.kraken ())   // JavaScript
print(dir(ccxt.kraken()))           # Python
var_dump (new \ccxt\kraken ()); // PHP

公共/私有 API#

API URL 经常被分为两组方法集,称为用于市场数据的“公共 API”和用于交易和账户访问的“私有 API”。这些 API 方法组通常以“public”或“private”为前缀。

公共 API 用于访问市场数据,不需要任何身份验证。大多数交易所向所有人(在其限制速率下)公开提供市场数据。使用 ccxt 库,任何人都可以直接获取市场数据,无需在交易所注册,并且无需设置账户密钥和密码。

公共 API 包括以下内容:

  • 交易对/货币对

  • 价格源(汇率)

  • 订单簿(L1、L2、L3…)

  • 交易历史记录(已关闭订单、交易、执行)

  • Ticker(实时价格 / 24 小时价格)

  • 用于图表的 OHLCV 数据

  • 其他公共终点

私有 API 主要用于交易和访问特定于账户的私有数据,因此需要进行身份验证。您必须从交易所获取私有 API 密钥。通常这意味着在交易所网站注册并为您的账户创建 API 密钥。大多数交易所需要个人信息或身份验证。完成 KYC 验证后,才允许进行交易。 私有 API 允许以下操作:- 管理个人帐户信息

  • 查询账户余额

  • 通过市价和限价单进行交易

  • 创建存款地址和资金账户

  • 请求提取法定货币和加密货币资金

  • 查询个人的开放/关闭订单

  • 查询保证金/杠杆交易的头寸

  • 获取总账历史

  • 在账户之间转移资金

  • 使用商家服务

一些交易所以不同的名称提供相同的逻辑。例如,公共API通常也被称为市场数据基础数据市场mapiapi价格等等… 所有这些都表示一组方法,用于访问公共可用数据。私有API通常也被称为交易交易所tapi账户等等…

一些交易所还提供一个商家API,允许您创建发票并接受来自客户的加密货币和法定货币支付。这种类型的API通常被称为商家钱包支付ecapi(用于电子商务)。

要获取交换实例的所有可用方法列表,只需执行以下操作:

console.log(new ccxt.kraken())   // JavaScript
print(dir(ccxt.kraken()))           # Python
var_dump(new \ccxt\kraken()); // PHP

仅合约和仅保证金

  • 在这份文档中标记为仅合约仅保证金的方法仅用于合约交易和保证金交易。尽管在其他类型的交易市场中也可能工作,但很可能返回无关的信息。

同步调用与异步调用#

JavaScript#

在CCXT的JavaScript版本中,所有方法都是异步的,并返回解码的JSON对象的Promises。在CCXT中,我们使用现代化的async/await语法来处理Promises。如果您对这种语法不熟悉,可以在此处了解更多信息。```javascript // JavaScript

(async () => { let pairs = await kraken.publicGetSymbolsDetails () let marketIds = Object.keys (pairs[‘result’]) let marketId = marketIds[0] let ticker = await kraken.publicGetTicker ({ pair: marketId }) console.log (kraken.id, marketId, ticker) }) ()


### Python

ccxt库在Python 3.5+中支持异步并发模式,使用async/await语法。异步Python版本使用纯[asyncio](https://docs.python.org/3/library/asyncio.html)和[aiohttp](http://aiohttp.readthedocs.io)。在异步模式下,您拥有所有相同的属性和方法,但大多数方法都带有async关键字。如果想使用异步模式,应该链接到`ccxt.async_support`子包,就像下面的例子一样:

```python
# Python

import asyncio
import ccxt.async_support as ccxt

async def print_poloniex_ethbtc_ticker():
    poloniex = ccxt.poloniex()
    print(await poloniex.fetch_ticker('ETH/BTC'))

asyncio.run(print_poloniex_ethbtc_ticker())

PHP#

在兼容PHP 5的版本中,所有API方法都是同步的,但是在PHP 7.1+中,CCXT库可以选择支持使用’yield’语法的异步并发模式(与Python中的async/await非常类似)。异步PHP版本使用RecoilPHPReactPHPclue/reactphp-buzz库。在异步模式下,您拥有所有相同的属性和方法,但是任何网络API方法都应该用yield关键字进行修饰,脚本应该位于ReactPHP/RecoilPHP的包装器中,所有的交易所构造函数都需要从包装器中传递循环和内核实例。要使用该库的异步版本,请使用ccxt_async命名空间,如下所示示例:

// PHP
<?php
include 'vendor/autoload.php';

use function React\Async\await;

$okx = new \ccxt\async\okx();
while (true) {
    $result = await($okx->fetch_ticker('ETH/BTC'));
    var_dump($result);
}

请在examples/php目录中查看更多示例;搜索包含async一词的文件名。另外,请确保您安装了所需的依赖关系,使用composer require recoil/recoil clue/buzz-react react/event-loop recoil/react react/http。最后,这篇文章对这里使用的方法进行了很好的介绍。虽然从语法上讲,更改很简单(即在相关的方法之前使用yield关键字),但并发对于代码的整体设计有重要影响。

返回的 JSON 对象#

所有公共和私有 API 方法都以在交易所中响应的原始解码 JSON 对象的形式返回,原样返回。统一的 API 以统一格式和结构化方式返回以 JSON 解码的对象。

传递参数给 API 方法#

从交易所到交易所,可能的 API 终点集合是不同的。大多数方法接受一个关联数组(或 Python 的字典)作为键值参数。参数的传递方式如下所示:

bitso.publicGetTicker ({ book: 'eth_mxn' })                 // JavaScript
ccxt.zaif().public_get_ticker_pair ({ 'pair': 'btc_jpy' })  # Python
$luno->public_get_ticker (array ('pair' => 'XBTIDR'));      // PHP
```交易所的统一方法可能会期望并接受影响其功能的各种参数,例如:

```python
params = {'type':'margin', 'isIsolated': 'TRUE'}  # --------------┑
# params将作为统一方法的最后一个参数                   |
#                                                     v
binance.create_order('BTC/USDT', 'limit', 'buy', amount, price, params)

一个交易所不会接受来自其他交易所的参数,它们是不可互换的。接受的参数列表由每个具体交易所定义。

要找出可以传递给统一方法的参数:

  • 要么打开 exchange-specific implementation 文件并搜索所需的函数(例如 createOrder)以查看和了解 params 的使用细节

  • 要么进入交易所的API文档,并阅读特定函数或端点(例如 order)的参数列表

有关每个交易所接受的方法参数的完整列表,请参阅 API文档

API方法命名约定#

交易所方法名称是一个连接的字符串,由类型(公共或私有)、HTTP方法(GET、POST、PUT、DELETE)和端点URL路径组成,如以下示例所示:

方法名称

基本API URL

端点URL路径

publicGetIdOrderbook

https://bitbay.net/API/Public

{id}/orderbook

publicGetPairs

https://bitlish.com/api

pairs

publicGetJsonMarketTicker

https://www.bitmarket.net

json/{market}/ticker

privateGetUserMargin

https://bitmex.com

user/margin

privatePostTrade

https://btc-x.is/api

trade

tapiCancelOrder

https://yobit.net

tapi/CancelOrder

ccxt库支持驼峰命名法(在JavaScript中首选)和下划线命名法(在Python和PHP中首选),因此所有方法都可以在任何语言的命名风格中以任一命名法或编码风格进行调用。在JavaScript、Python和PHP中,这两种命名法都可以使用:

exchange.methodName()  // 驼峰形式的伪代码
exchange.method_name()  // 下划线形式的伪代码

要获取交易所实例的所有可用方法列表,只需执行以下操作:

console.log(new ccxt.kraken())   // JavaScript
print(dir(ccxt.hitbtc()))           # Python
var_dump(new \ccxt\okcoinusd()); // PHP

统一 API#

统一的 ccxt API 是交易所之间常见方法的子集。它当前包含以下方法:

  • fetchMarkets(): 从交易所获取所有可用市场的列表,并返回一个市场数组(包含 symbolbasequote 等属性的对象)。某些交易所没有通过其在线 API 获取市场列表的方式。对于这些交易所,市场列表是硬编码的。

  • fetchCurrencies(): 从交易所获取所有可用的货币,并返回一个关联的货币字典(包含 codename 等属性的对象)。某些交易所没有通过其在线 API 获取货币的方式。对于这些交易所,货币将从市场对中提取或者硬编码。

  • loadMarkets([reload]): 将市场列表作为按符号索引的对象返回,并将其缓存到交易所实例中。如果已经加载了缓存的市场,则返回缓存的市场,除非强制使用 reload = true 标志。

  • fetchOrderBook(symbol[, limit = undefined[, params = {}]]): 获取特定市场交易对的 L2/L3 深度订单簿。

  • fetchStatus([, params = {}]): 根据交易所实例中的固定信息或可用的 API 返回有关交易所状态的数据。

  • fetchL2OrderBook(symbol[, limit = undefined[, params]]): 获取特定交易对的 2 级(按价格聚合)深度订单簿。

  • fetchTrades(symbol[, since[, [limit, [params]]]]): 获取特定交易对的最近成交记录。

  • fetchTicker(symbol): 获取特定交易对的最新行情数据。

  • fetchBalance(): 获取余额。

  • createOrder(symbol, type, side, amount[, price[, params]])

  • createLimitBuyOrder(symbol, amount, price[, params])

  • createLimitSellOrder(symbol, amount, price[, params])

  • createMarketBuyOrder(symbol, amount[, params])

  • createMarketSellOrder(symbol, amount[, params])

  • cancelOrder(id[, symbol[, params]])

  • fetchOrder(id[, symbol[, params]])

  • fetchOrders([symbol[, since[, limit[, params]]]])

  • fetchOpenOrders([symbol[, since, limit, params]]]])

  • fetchCanceledOrders([symbol[, since[, limit[, params]]]])

  • fetchClosedOrders([symbol[, since[, limit[, params]]]])

  • fetchMyTrades([symbol[, since[, limit[, params]]]])

  • fetchOpenInterest([symbol[, params]])

待办事项:改进格式

覆盖统一 API 参数#

注意,统一 API 的大多数方法都接受一个可选的 params 参数。这是一个关联数组(字典),默认为空,其中包含要覆盖的参数。params 的内容是特定于交易所的,请查阅交易所的 API 文档以了解支持的字段和值。如果需要传递自定义设置或可选参数到统一查询中,请使用 params 字典。

// JavaScript
(async () => {

    const params = {
        'foo': 'bar',      // exchange-specific overrides in unified queries
        'Hello': 'World!', // see their docs for more details on parameter names
    }

    // the overrides go into the last argument to the unified call ↓ HERE
    const result = await exchange.fetchOrderBook (symbol, length, params)
}) ()
# Python
params = {
    'foo': 'bar',       # exchange-specific overrides in unified queries
    'Hello': 'World!',  # see their docs for more details on parameter names
}

# overrides go in the last argument to the unified call ↓ HERE
result = exchange.fetch_order_book(symbol, length, params)
// PHP
$params = array (
    'foo' => 'bar',       // exchange-specific overrides in unified queries
    'Hello' => 'World!',  // see their docs for more details on parameter names
}

// overrides go into the last argument to the unified call ↓ HERE
$result = $exchange->fetch_order_book ($symbol, $length, $params);

分页#

大多数的统一方法都会返回一个单一的对象或者一个普通数组(列表)的对象(交易、订单、交易记录等等)。然而,很少有交易所会一次性返回所有订单、所有交易、所有的K线数据、所有交易记录。大多数时候,它们的API都会限制输出的数量,只返回某个特定数量的最新对象。你不能通过一次调用获取从开始到现在的所有数据。实际上,很少有交易所会容忍或允许这样做。

要获取历史订单或交易记录,用户需要分段或按页获取数据。分页通常意味着在循环中“逐个获取数据的部分”。

在大多数情况下,用户需要至少使用某种分页方式,以便在一致性上能得到预期的结果。如果用户没有应用任何分页,大多数方法将返回交易所的默认值,该默认值可能从历史开始,也可能是最近对象的子集。默认行为(无分页)是特定于交易所的!分页的方式通常在特定的方法中使用,如下所示:

  • fetchTrades()

  • fetchOHLCV()

  • fetchOrders()

  • fetchCanceledOrders()

  • fetchClosedOrder()

  • fetchClosedOrders()

  • fetchOpenOrder()

  • fetchOpenOrders()

  • fetchMyTrades()

  • fetchTransactions()

  • fetchDeposit()

  • fetchDeposits()

  • fetchWithdrawals()

对于返回对象列表的方法,交易所可以提供一种或多种类型的分页方法。CCXT默认使用基于日期的分页,在整个库中使用的是以毫秒为单位的时间戳。

使用日期和时间戳#

以下是用于处理UTC日期和时间戳以及在它们之间进行转换的一组方法:

exchange.parse8601('2018-01-01T00:00:00Z') == 1514764800000 // 整数,Z = UTC
exchange.iso8601(1514764800000) == '2018-01-01T00:00:00Z'   // iso8601字符串
exchange.seconds()      // 整数,以秒为单位的UTC时间戳
exchange.milliseconds() // 整数,以毫秒为单位的UTC时间戳

基于日期的分页#

这是目前在CCXT统一API中使用的分页类型。用户提供一个以毫秒为单位的since时间戳,并提供一个limit参数来限制结果。为了逐页遍历感兴趣的对象,用户运行以下代码(下面是伪代码,可能需要根据具体的交易所覆盖一些交易所特定的参数):

// JavaScript
if (exchange.has['fetchTrades']) {
    let since = exchange.milliseconds() - 86400000 // 从当前时间倒推一天
    // 或者,从特定的起始日期获取
    // let since = exchange.parse8601('2018-01-01T00:00:00Z')
    let allTrades = []
    while (since < exchange.milliseconds()) {
        const symbol = undefined // 更改为您的交易对
        const limit = 20 // 更改为您的限制
        const trades = await exchange.fetchTrades(symbol, since, limit)
        if (trades.length) {
            since = trades[trades.length - 1]['timestamp'] + 1
            allTrades = allTrades.concat(trades)
        } else {
            break
        }
    }
}
# Python
if exchange.has['fetchOrders']:
    since = exchange.milliseconds() - 86400000  # 从当前时间倒推一天
    # 或者,从特定的起始日期获取
    # since = exchange.parse8601('2018-01-01T00:00:00Z')
    all_orders = []
    while since < exchange.milliseconds():
        symbol = None  # 更改为您的交易对
        limit = 20  # 更改为您的限制
        orders = await exchange.fetch_orders(symbol, since, limit)
        if len(orders):
            since = orders[len(orders) - 1]['timestamp'] + 1
            all_orders += orders
        else:
            break
// PHP
if ($exchange->has['fetchMyTrades']) {
    $pageNumber = 1;
    $all_trades = array ();
    while (true) {
        $symbol = null; // change for your symbol
        $since = null;
        $limit = 20; // change for your limit
        $params = array (
            'page' => $pageNumber, // exchange-specific non-unified parameter name
        );
        $trades = $exchange->fetchMyTrades ($symbol, $since, $limit, $params);
        if (count($trades)) {
            $all_trades = array_merge ($all_trades, $trades);
            $pageNumber++;
        } else {
            break;
        }
    }
}

基於 ID 的分頁#

用戶提供對象的 from_id,從該處開始查詢並返回結果,以及一個限制結果數量的數字。這是某些交易所的默認值,但這種類型尚未統一。為了根據 ID 分頁,用戶應運行以下操作:

// JavaScript
if (exchange.has['fetchTrades']) {
    let from_id = 'abc123' // 所有 id 都是字符串
    let allTrades = []
    while (true) {
        const symbol = undefined // 更改你的交易對
        const since = undefined
        const limit = 20 // 更改你的限制
        const params = {
            'from_id': from_id, // 特定交易所的非統一參數名稱
        }
        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'  # 所有 id 都是字符串
    all_orders = []
    while True:
        symbol = None  # 更改你的交易對
        since = None
        limit = 20  # 更改你的限制
        params = {
            'from_id': from_id,  # 特定交易所的非統一參數名稱
        }
        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' // 所有 id 都是字符串
    $all_trades = array ();
    while (true) {
        $symbol = null; // 更改你的交易對
        $since = null;
        $limit = 20; // 更改你的限制
        $params = array (
            'from_id' => $from_id, // 特定交易所的非統一參數名稱
        );
        $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;
        }
    }
}

基於頁碼的 (游標) 分頁#

用戶提供頁碼或**初始的「游標」**值。交易所返回一頁結果和接下來的「游標」值,以便繼續查詢。大多數實現此類分頁的交易所要麼在響應本身中返回下一個游標,要麼在 HTTP 響應標頭中返回下一個游標值。

在每次循環迭代中,用戶必須取出下一個游標,並將其放入下一個查詢的覆蓋參數中(在後續迭代中使用):

// JavaScript
if (exchange.has['fetchTrades']) {
    let page = 0  // 交易所特定的类型和值
    let allTrades = []
    while (true) {
        const symbol = undefined // 更改为您的交易对
        const since = undefined
        const limit = 20 // 更改为您的限制
        const params = {
            'page': page, // 交易所特定的非统一参数名
        }
        const trades = await exchange.fetchTrades (symbol, since, limit, params)
        if (trades.length) {
            // 非线程安全相关和交易所特定的部分!
            page = exchange.last_json_response['cursor']
            allTrades.push (trades)
        } else {
            break
        }
    }
}
# Python
if exchange.has['fetchOrders']:
    cursor = 0  # 交易所特定的类型和值
    all_orders = []
    while True:
        symbol = None  # // 更改为您的交易对
        since = None
        limit = 20  # 更改为您的限制
        params = {
            'cursor': cursor,  # 交易所特定的非统一参数名
        }
        orders = await exchange.fetch_orders(symbol, since, limit, params)
        if len(orders):
            # 非线程安全相关和交易所特定的部分!
            cursor = exchange.last_response_headers['CB-AFTER']
            all_orders += orders
        else:
            break
// PHP
if ($exchange->has['fetchMyTrades']) {
    $start = '0' // 交易所特定的类型和值
    $all_trades = array ();
    while (true) {
        $symbol = null; // 更改为您的交易对
        $since = null;
        $limit = 20; // 更改为您的限制
        $params = array (
            'start' => $start, // 交易所特定的非统一参数名
        );
        $trades = $exchange->fetchMyTrades ($symbol, $since, $limit, $params);
        if (count($trades)) {
            // 非线程安全相关和交易所特定的部分!
            $start = $exchange->last_json_response['next'];
            $all_trades = array_merge ($all_trades, $trades);
        } else {
            break;
        }
    }
}

公共 API#

订单簿#

交易所提供了有关买盘(bid)和卖盘(ask)价格、数量和其他数据的未平仓报表信息。通常为特定市场查询当前 订单簿 的状态(堆栈框架)有一个单独的终端。订单簿也经常被称为市场深度。订单簿信息在交易决策过程中发挥作用。

要获取订单簿数据,您可以使用以下方法:

  • fetchOrderBook () // 获取单个市场订单簿

  • fetchOrderBooks ( symbols ) // 获取多个市场订单簿

  • fetchOrderBooks () // 获取所有市场的订单簿

async fetchOrderBook (symbol, limit = undefined, params = {})

参数

  • symbol (字符串) 必填 统一的CCXT符号 (例如,"BTC/USDT")

  • limit (整数) 订单簿中返回的订单数量 (例如,10)

  • params (字典) 特定于交易所API端点的额外参数 (例如,{"endTime": 1645807945000})

返回

async fetchOrderBooks (symbols = undefined, limit = undefined, params = {})

参数

  • symbols ([字符串]) 统一的CCXT符号 (例如,["BTC/USDT", "ETH/USDT"])

  • limit (整数) 订单簿中返回的订单数量 (例如,10)

  • params (字典) 特定于交易所API端点的额外参数 (例如,{"endTime": 1645807945000})

返回

fetchOrderBook Examples#

// JavaScript
delay = 2000 // 毫秒 = 秒 * 1000
(async () => {
    for (symbol in exchange.markets) {
        console.log (await exchange.fetchOrderBook (symbol))
        await new Promise (resolve => setTimeout (resolve, delay)) // 速率限制
    }
}) ()
# Python
import time
delay = 2 # 秒
for symbol in exchange.markets:
    print (exchange.fetch_order_book (symbol))
    time.sleep (delay) # 速率限制
// PHP
$delay = 2000000; // 微秒 = 秒 * 1000000
foreach ($exchange->markets as $symbol => $market) {
    var_dump ($exchange->fetch_order_book ($symbol));
    usleep ($delay); // 速率限制
}

订单薄结构#

{
    'bids': [
        [ price, amount ], // [ 浮点数, 浮点数 ]
        [ price, amount ],
        ...
    ],
    'asks': [
        [ price, amount ],
        [ price, amount ],
        ...
    ],
    'symbol': 'ETH/BTC', // 统一的市场符号
    'timestamp': 1499280391811, // UNIX时间戳,毫秒(秒 * 1000)
    'datetime': '2017-07-05T18:47:14.692Z', // ISO8601 格式的带有毫秒的时间字符串
    'nonce': 1499280391811, // 订单薄快照的递增唯一标识符
}

如果所查询的交易所在API响应中没有提供相应的值,timestampdatetime可能会缺失(undefined/None/null)。

价格和数量是浮点数。bids数组按价格降序排列。最佳(最高)买价是第一个元素,最差(最低)买价是最后一个元素。asks数组按价格升序排列。最佳(最低)卖价是第一个元素,最差(最高)卖价是最后一个元素。如果交易所的订单薄中没有相应的订单,买/卖数组可以为空。

交易所可能以不同的细节级别返回订单堆栈以进行分析。它可以是包含每个订单的完整细节,也可以是聚合的,其中订单按价格和数量进行分组和合并的细节稍微较少。更详细的信息需要更多的流量和带宽,通常会更慢,但可以提供更高的精度。较少的细节通常更快,但在某些非常特定的情况下可能不足够。

订单薄结构注释#

  • orderbook['timestamp']是交易所生成此订单薄响应的时间(在回复给您之前)。这可能会缺失(undefined/None/null),正如文档中所述,不是所有交易所都在此处提供时间戳。如果定义了时间戳,则它是从1970年1月1日00:00:00到UTC时间的毫秒数

  • 有些交易所可能通过订单ID将订单薄中的订单进行索引,在这种情况下,订单ID可能会作为买单和卖单的第三个元素返回:[ price, amount, id ]。这通常在不聚合的L3订单薄中发生。订单ID(如果在订单薄中显示)指的是订单薄,并不一定对应于交易所数据库中由所有者或其他人看到的实际订单ID。订单ID是订单薄内行的ID,但不一定是订单的真实ID(尽管它们也可能相等,这取决于具体的交易所)。

  • 在某些情况下,交易所可能以第三个元素的形式返回订单薄的订单时间戳:[ price, amount, timestamp ]。时间戳指明了订单何时放置在订单薄中。### 市场深度

一些交易所接受额外参数的字典用于 fetchOrderBook () / fetch_order_book () 函数。所有额外的 params 都是特定于交易所的(非统一的)。如果想覆盖特定的参数,例如订单簿的深度,您需要查阅交易所的文档。您可以通过指定限制参数和交易所特定的额外 params 来获取返回订单的数量或所需的聚合级别(即 市场深度), 如下所示:

// JavaScript

(async function test () {
    const ccxt = require ('ccxt')
    const exchange = new ccxt.bitfinex ()
    const limit = 5
    const orders = await exchange.fetchOrderBook ('BTC/USD', limit, {
        // 这个参数是特定于交易所的,所有额外参数都具有独特的名称
        'group': 1, // 1 = 按价格分组订单,0 = 订单分开
    })
}) ()
# Python

import ccxt
# 在订单簿堆栈的每一侧返回最多十个出价和请求
limit = 10
ccxt.cex().fetch_order_book('BTC/USD', limit)
// PHP

// 根据id实例化交易所
$exchange = '\\ccxt\\kraken';
$exchange = new $exchange ();
// 在每一侧最多返回十个订单
$limit = 20;
var_dump ($exchange->fetch_order_book ('BTC/USD', $limit));

详细级别或订单簿聚合级别通常以L1、L2、L3等数字标注…

  • L1: 提供较少的细节,仅用于快速获取基本信息,即市价。它看起来像是订单簿中的一个订单。

  • L2: 最常见的聚合级别,其中按价格分组的订单数量。如果两个订单具有相同的价格,则它们作为一个订单出现,并具有相等于它们总和的交易量。这很可能是您大部分需求的聚合级别。

  • L3: 最详细的级别,没有聚合,每个订单与其他订单分开。该级别的输出中自然包含重复项。因此,如果两个订单具有相同的价格,它们不会合并在一起,而是由交易所的撮合引擎决定它们在堆栈中的优先级。您实际上并不需要L3的详细信息来进行成功的交易。事实上,您很可能根本不需要它。因此,一些交易所不支持它,并且始终返回聚合的订单簿。如果您想获取L2订单簿,无论交易所返回什么,请使用fetchL2OrderBook(symbol, limit, params)fetch_l2_order_book(symbol, limit, params)这个统一的方法。

limit参数不能保证买单或卖单的数量总是等于limit。它指定了上限或最大值,因此在某个时间点上可能会有少于limit个买单或卖单。这种情况发生在交易所订单簿上没有足够的订单时。然而,如果底层交易所API根本不支持订单簿端点的limit参数,则limit参数将被忽略。如果交易所返回的数据超过您要求的数量,CCXT不会截断bidsasks

市场价格#

为了获取当前的最佳价格(查询市场价格)并计算买卖价差,请从买单和卖单的第一个元素开始,例如:

// JavaScript
let orderbook = await exchange.fetchOrderBook(exchange.symbols[0]);
let bid = orderbook.bids.length ? orderbook.bids[0][0] : undefined;
let ask = orderbook.asks.length ? orderbook.asks[0][0] : undefined;
let spread = (bid && ask) ? ask - bid : undefined;
console.log(exchange.id, '市场价格', { bid, ask, spread });
# Python
orderbook = exchange.fetch_order_book(exchange.symbols[0])
bid = orderbook['bids'][0][0] if len(orderbook['bids']) > 0 else None
ask = orderbook['asks'][0][0] if len(orderbook['asks']) > 0 else None
spread = (ask - bid) if (bid and ask) else None
print(exchange.id, '市场价格', { 'bid': bid, 'ask': ask, 'spread': spread })
// PHP
$orderbook = $exchange->fetch_order_book($exchange->symbols[0]);
$bid = count($orderbook['bids']) ? $orderbook['bids'][0][0] : null;
$ask = count($orderbook['asks']) ? $orderbook['asks'][0][0] : null;
$spread = ($bid && $ask) ? $ask - $bid : null;
$result = array('bid' => $bid, 'ask' => $ask, 'spread' => $spread);
var_dump($exchange->id, '市场价格', $result);

价格行情#

价格行情包含某个市场/交易对在最近的一段时间内(通常为24小时)的统计数据。下面介绍了获取价格行情的方法。

单个交易对的行情信息#

{
  "symbol": "ETH/BTC",         // the trading symbol
  "info": {                    // raw ticker data from the exchange
    "bid": 0.069,
    "ask": 0.071,
    "high": 0.072,
    "low": 0.068,
    "volume": 1000,
    "open": 0.07,
    "close": 0.069,
    "timestamp": 1534868640
  },
  "timestamp": 1534868640000,  // the timestamp when the ticker was fetched
  "datetime": "2018-08-21T12:24:00Z",  // ISO8601 representation of timestamp
  "high": 0.072,               // highest price in the past 24 hours
  "low": 0.068,                // lowest price in the past 24 hours
  "bid": 0.069,                // current highest bid price
  "bidVolume": undefined,      // highest bid volume
  "ask": 0.071,                // current lowest ask price
  "askVolume": undefined,      // lowest ask volume
  "vwap": undefined,           // volume weighted average price
  "open": 0.07,                // opening price
  "close": 0.069,              // closing price
  "last": 0.069,               // last trade (closing) price
  "previousClose": undefined,  // previous day's closing price
  "change": undefined,         // absolute change, positive if the price has risen, or negative if it has fallen
  "percentage": undefined,     // relative change, positive if the price has risen, or negative if it has fallen
  "average": undefined        // average price
}

Description#

The ticker represents the current state of a specific market. It includes data such as the trading symbol, the prices of the last trade, the highest and lowest prices in the past 24 hours, and the trading volume.

按币对逐个获取#

要从交易所获取特定交易对或特定标记的个别 ticker 数据,请调用 fetchTicker (symbol)

// JavaScript
if (exchange.has['fetchTicker']) {
    console.log (await (exchange.fetchTicker ('BTC/USD'))) // BTC/USD 的 ticker
    let symbols = Object.keys (exchange.markets)
    let random = Math.floor (Math.random () * (symbols.length - 1))
    console.log (exchange.fetchTicker (symbols[random])) // 随机标记的 ticker
}
# Python
import random
if (exchange.has['fetchTicker']):
    print(exchange.fetch_ticker('LTC/ZEC')) # LTC/ZEC 的 ticker
    symbols = list(exchange.markets.keys())
    print(exchange.fetch_ticker(random.choice(symbols))) # 随机标记的 ticker
// PHP (不要忘记正确设置时区!)
if ($exchange->has['fetchTicker']) {
    var_dump ($exchange->fetch_ticker ('ETH/CNY')); // ETH/CNY 的 ticker
    $symbols = array_keys ($exchange->markets);
    $random = rand () % count ($symbols);
    var_dump ($exchange->fetch_ticker ($symbols[$random])); // 随机标记的 ticker
}

同时获取所有#

一些交易所(不是所有的)还支持一次性获取所有的 tickers。详情请参见 它们的文档。您可以通过一次调用来获取所有的 tickers,如下所示:

// JavaScript
if (exchange.has['fetchTickers']) {
    console.log (await (exchange.fetchTickers ())) // 以它们的标记为索引的所有 tickers
}
# Python
if (exchange.has['fetchTickers']):
    print(exchange.fetch_tickers()) # 以它们的标记为索引的所有 tickers
// PHP
if ($exchange->has['fetchTickers']) {
    var_dump ($exchange->fetch_tickers ()); // 所有按其符号索引的交易对的行情数据
}

获取所有交易对的行情数据比获取单个交易对的行情数据需要更多的流量。此外,注意有些交易所对获取所有交易对的行情数据的频率限制更高(请参阅其文档中相应的终端点的详细信息)。从请求fetchTickers()的频率限制来看,它往往比平均值更高。如果你只需要一个交易对的行情数据,通过特定的符号获取的速度更快。只有在真正需要获取全部行情数据时,才需要获取所有交易对的行情数据,并且最好不要频繁地调用fetchTickers()方法,最好每隔一分钟或者更久调用一次。

此外,某些交易所对fetchTickers()方法可能有其他要求,在某些情况下,由于交易所的 API 限制,你可能无法获取所有交易对的行情数据。有些交易所可以通过 HTTP URL 查询参数接受一个交易对符号列表,然而,由于 URL 长度有限,而在极端情况下交易所可能拥有数千个市场 - 它们所有交易对的列表是不可能放入 URL 中的,因此只能是它们的交易对的有限子集。有时,还有其他原因需要交易对符号列表,并且可能对一次可获取的交易对数量有限制,但无论限制是什么,请责备交易所。要将感兴趣的交易对符号传递给交易所,可以将字符串列表作为fetchTickers的第一个参数:

//JavaScript
if (exchange.has['fetchTickers']) {
    console.log (await (exchange.fetchTickers ([ 'ETH/BTC', 'LTC/BTC' ]))) // 按其符号索引的交易对的行情数据
}
# Python
if (exchange.has['fetchTickers']):
    print(exchange.fetch_tickers(['ETH/BTC', 'LTC/BTC'])) # 按其符号索引的交易对的行情数据
// PHP
if ($exchange->has['fetchTickers']) {
    var_dump ($exchange->fetch_tickers (array ('ETH/BTC', 'LTC/BTC'))); // 按其符号索引的交易对的行情数据
}

请注意,在大多数情况下,交易对符号列表是不需要的,但是如果你想处理可能会在交易所端强加的所有可能限制,则必须添加附加逻辑。

与统一的 CCXT API 的大多数方法一样,fetchTickers的最后一个参数是用于覆盖发送给交易所的请求参数的params参数。

返回值的结构如下所示:

{
    'info':    { ... }, // 交易所原始的 JSON 响应
    'BTC/USD': { ... }, // BTC/USD 的单个行情数据
    'ETH/BTC': { ... }, // ETH/BTC 的行情数据
    ...
}
```一个从所有交易所(甚至那些没有对应API端点的交易所)获取所有股票代码的通用解决方案正在开发中,本部分将很快更新。

```text
正在建设中

OHLCV蜡烛图表#

- 目前正在进行大规模开发,欢迎贡献

大多数交易所都有用于获取OHLCV数据的端点,但其中一些没有。名为has['fetchOHLCV']的布尔属性指示交易所是否支持蜡烛图数据系列。

fetchOHLCV方法声明如下:

fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {})

您可以调用统一的fetchOHLCV / fetch_ohlcv方法来获取特定交易对的OHLCV蜡烛图列表,如下所示:

// JavaScript
let sleep = (ms) => new Promise (resolve => setTimeout (resolve, ms));
if (exchange.has.fetchOHLCV) {
    for (symbol in exchange.markets) {
        await sleep (exchange.rateLimit) // 毫秒
        console.log (await exchange.fetchOHLCV (symbol, '1m')) // 一分钟
    }
}
# Python
import time
if exchange.has['fetchOHLCV']:
    for symbol in exchange.markets:
        time.sleep (exchange.rateLimit / 1000) # time.sleep希望秒钟为单位
        print (symbol, exchange.fetch_ohlcv (symbol, '1d')) # 一天
// PHP
if ($exchange->has['fetchOHLCV']) {
    foreach ($exchange->markets as $symbol => $market) {
        usleep ($exchange->rateLimit * 1000); // usleep wants microseconds
        var_dump ($exchange->fetch_ohlcv ($symbol, '1M')); // 一个月
    }
}

要获得您的交易所可用的时间帧列表,请参考 timeframes 属性。注意,只有当 has['fetchOHLCV'] 为真时,它才会被填充。

返回的蜡烛列表可能会有一个或多个缺失的时间段,如果交易所在指定的时间范围和交易对上没有任何交易。对于用户来说,这将出现在连续的蜡烛列表中的间隙。这被认为是正常的。如果交易所在该时间内没有蜡烛,CCXT 库将显示从交易所本身返回的结果。

您的请求可以向过去查询的时间有一个限制。 大多数交易所不允许查询过去太久的详细蜡烛历史(如 1 分钟和 5 分钟时间帧)。它们通常保留一定量的最近的蜡烛,对于任何时间帧,最近的 1000 根蜡烛足够满足大多数需求。您可以通过持续调用(也称为REST 轮询)最新的 OHLCV 并将其存储在 CSV 文件或数据库中来绕过此限制。

请注意,直到蜡烛关闭(下一根蜡烛开始)为止,来自最后一根蜡烛的信息可能是不完整的。

与大多数其他统一和隐式方法一样,fetchOHLCV 方法的最后一个参数接受一个关联数组(字典),用于覆盖默认值,这些默认值会在发送请求到交易所时使用。params 的内容是特定于交易所的,请查阅交易所的 API 文档以获取受支持的字段和值。

since 参数是一个整数的 UTC 时间戳,以毫秒为单位(在库中的所有统一方法中都是如此)。

如果未指定 sincefetchOHLCV 方法将返回交易所自身默认的时间范围。 这不是个 bug。一些交易所将返回自时间开始以来的蜡烛,而其他交易所则只返回最新的蜡烛,交易所的默认行为是可以预期的。因此,为了确保获得所需的历史范围,请传递 since 参数。

关于延迟的说明#

交易策略需要来自交易所的最新信息进行技术分析、指标和信号。基于从交易所接收到的 OHLCV 蜡烛构建一个投机性的交易策略可能具有重大的缺陷。开发者应该考虑本节中解释的细节来构建成功的机器人。首先,当使用CCXT时,您正在直接与交易所交流。CCXT既不是服务器也不是服务,而是一个软件库。您通过CCXT获取的所有数据都是第一手从交易所获取的。

交易所通常提供两类公共市场数据:

  1. 快速主要的一级数据,包括实时订单簿和成交或交易

  2. 慢速的二级数据,包括衍生的行情和K线图(OHLCV蜡烛),这些数据是从一级数据计算得出的

交易所通过API以准实时的方式更新一级数据,尽可能的快速更新。而需花费时间的是计算二级数据。例如,行情只是订单簿和交易的滚动24小时统计截断。OHLCV蜡烛和交易量也是由一级交易计算得出,并表示特定时间段的固定统计数据。在一个小时内交易的成交量只是在该小时内发生的交易的成交量之和。

很明显,交易所需要一些时间来收集一级数据并计算出二级统计数据。这意味着行情和OHLCV蜡烛簿总是比订单簿和交易慢。换句话说,在交易发生时,直到交易所API更新或发布相应的OHLCV蜡烛,总是会有一些延迟。

延迟(或者交易所API计算二级数据所需的时间)取决于交易引擎的速度,因此是特定于交易所的。顶级交易引擎通常以非常快的速度返回和更新最近一分钟的OHLCV蜡烛和行情。一些交易所可能以固定间隔返回更新,比如每秒钟或几秒钟返回一次。慢速的交易引擎可能需要几分钟才能更新二级统计信息,它们的API可能会返回当前最新的OHLCV蜡烛,但滞后几分钟。

如果您的策略依赖于最新的一分钟数据,您不想基于交易所接收到的行情或OHLCV蜡烛来构建它。行情和交易所的OHLCV蜡烛仅适用于显示目的,或者对于小时级别或日级别的简单交易策略,这些策略对延迟不太敏感。

幸运的是,对于时间关键的交易策略开发人员来说,他们不必依赖交易所的二级数据,可以在用户端计算OHLCV蜡烛和行情。这样可能比等待交易所端更新信息更快、更高效。可以通过频繁地轮询公共交易历史并通过遍历交易列表来计算蜡烛。CCXT提供了一个buildOHLCVC/build_ohlcvc的基本方法来实现这一点:

  • JavaScript: https://github.com/ccxt/ccxt/blob/master/js/base/functions/misc.js#L43

  • Python: https://github.com/ccxt/ccxt/blob/master/python/ccxt/base/exchange.py#L1933

  • PHP: https://github.com/ccxt/ccxt/blob/master/php/Exchange.php#L631

由于交易所内部实现的差异,使用WebSocket更新主要和次要市场数据可能更快(请参阅https://ccxt.pro)。延迟仍然是特定于交易所的,因为交易引擎仍然需要时间来计算二级数据,无论是通过CCXT的RESTful API轮询还是通过CCXT Pro的WebSocket获取更新。WebSocket可以改善网络延迟,因此快速的交易所将工作得更好,但添加对WebSocket订阅的支持不会使慢速交易引擎的速度有太大改善。如果您想保持二级数据延迟的最新状态,那么您将需要在您的端计算它,并在速度上击败交易所引擎。根据您的应用需求,这可能会比较棘手,因为您需要处理冗余、历史数据中的“数据空洞”、交易所停机和数据聚合的其他方面,这是一个庞大的领域,本手册无法完全覆盖。

OHLCV 结构#

上面显示的 fetchOHLCV 方法返回一个由以下结构表示的 OHLCV 蜡烛列表(一个扁平数组):

[
    [
        1504541580000, // UTC 时间戳(以毫秒为单位),整数
        4235.4,        // 开盘价,浮点数
        4240.6,        // 最高价,浮点数
        4230.0,        // 最低价,浮点数
        4230.7,        // 收盘价,浮点数
        37.72941911    // 交易量,浮点数(通常用基础货币来表示,交易所的文档字符串可能会说明使用了报价单位还是基础单位)
    ],
    ...
]

蜡烛列表按升序(历史/时间顺序)排序,最旧的蜡烛排在前面,最新的蜡烛排在最后面。

Mark、指数和溢价指数 K 线图表#

要获取历史的 Mark、指数价格和溢价指数蜡烛图,请将 'price' params-override 作为参数传递给 fetchOHLCV'price' 参数接受以下值之一:

  • 'mark'

  • 'index'

  • 'premiumIndex'

// JavaScript
async function main () {
    const exchange = new ccxt.binanceusdm ()
    const markKlines = await exchange.fetchOHLCV ('ADA/USDT', '1h', undefined, undefined, { 'price': 'mark' })
    console.log (markKlines)
    const indexKlines = await exchange.fetchOHLCV ('ADA/USDT', '1h', undefined, undefined, { 'price': 'index' })
    console.log (indexKlines)
}

main ()
```还有方便的方法 `fetchMarkOHLCV`、`fetchIndexOHLCV` 和 `fetchPremiumIndexOHLCV`

```javascript
// JavaScript
async function main () {
    const exchange = new ccxt.binanceusdm ()
    const markKlines = await exchange.fetchMarkOHLCV ('ADA/USDT', '1h')
    console.log (markKlines)
    const indexKlines = await exchange.fetchIndexOHLCV ('ADA/USDT', '1h')
    console.log (indexKlines)
}

main ()
# Python
exchange = ccxt.binance()
response = exchange.fetch_ohlcv('ADA/USDT', '1h', params={'price':'index'})
pprint(response)
# Convenience methods
mark_klines = exchange.fetch_mark_ohlcv('ADA/USDT', '1h')
index_klines = exchange.fetch_index_ohlcv('ADA/USDT', '1h')
pprint(mark_klines)
pprint(index_klines)

OHLCV 模拟#

一些交易所没有提供任何 OHLCV 方法,对于这些交易所,ccxt 库将从公共交易中模拟生成 OHLCV 蜡烛图。在这种情况下,您将看到 exchange.has['fetchOHLCV'] = 'emulated'。然而,由于交易历史通常非常有限,模拟的 fetchOHLCV 方法仅涵盖最近的信息,应仅用作备选方案,当没有其他选项可用时使用。

警告:fetchOHLCV 模拟功能处于实验阶段!

UNDER CONSTRUCTION

公共交易#

- 这目前在大力开发中,欢迎贡献
```你可以调用统一的`fetchTrades` / `fetch_trades`方法来获取特定交易对最近交易的列表。`fetchTrades`方法的声明如下:

```javascript
async fetchTrades (symbol, since = undefined, limit = undefined, params = {})

例如,如果你想按顺序逐个打印所有交易对的最新交易 (要注意速率限制!),你可以这样做:

// JavaScript
if (exchange.has['fetchTrades']) {
    let sleep = (ms) => new Promise (resolve => setTimeout (resolve, ms));
    for (symbol in exchange.markets) {
        console.log (await exchange.fetchTrades (symbol))
    }
}
# Python
import time
if exchange.has['fetchTrades']:
    for symbol in exchange.markets:  # 确保你已经调用了loadMarkets()或load_markets()方法。
        print (symbol, exchange.fetch_trades (symbol))
// PHP
if ($exchange->has['fetchTrades']) {
    foreach ($exchange->markets as $symbol => $market) {
        var_dump ($exchange->fetch_trades ($symbol));
    }
}

上面展示的fetchTrades方法返回一个有序的交易列表(一个扁平数组,按时间戳升序排序,最早的交易在前,最新的交易在后)。交易列表由交易结构表示。

[
    {
        'info':          { ... },                  // 原始解码后的JSON
        'id':           '12345-67890:09876/54321', // 字符串类型的交易ID
        'timestamp':     1502962946216,            // 毫秒级别的Unix时间戳
        'datetime':     '2017-08-17 12:42:48.000', // ISO8601格式的时间戳,带有毫秒
        'symbol':       'ETH/BTC',                 // 交易对
        'order':        '12345-67890:09876/54321', // 字符串类型的订单ID或undefined/None/null
        'type':         'limit',                   // 订单类型,'market'、'limit'或undefined/None/null
        'side':         'buy',                     // 交易方向,'buy'或'sell'
        'takerOrMaker': 'taker',                   // 字符串,'taker'或'maker'
        'price':         0.06917684,               // 基础货币的浮点价格
        'amount':        1.5,                      // 基础货币的数量
        'cost':          0.10376526,               // 总成本,`price * amount`
        'fee':           {                         // exchange提供或由ccxt计算的费用
            'cost':  0.0015,                       // 浮点数
            'currency': 'ETH',                     // 通常是买入的基础货币,卖出的报价货币
            'rate': 0.002,                         // 费率(如果提供)
        },
        'fees': [                                  // 如果以多种货币支付,会有一个费用的数组
            {                                      // exchange提供或由ccxt计算的费用
                'cost':  0.0015,                   // 浮点数
                'currency': 'ETH',                 // 通常是买入的基础货币,卖出的报价货币
                'rate': 0.002,                     // 费率(如果提供)
            },
        ]
    },
    ...
]

大多数交易所返回每笔交易的大部分字段,不过也有些交易所不返回交易的类型、方向、交易ID或订单ID。大多数情况下,你可以确保每笔交易都会有时间戳、日期时间、交易对、价格和数量。

第二个可选参数since可以按时间戳缩小数组,第三个limit参数可以按数量(个数)缩小返回的项目。如果用户没有指定since参数,fetchTrades方法将返回交易所的默认公共交易范围。 默认设置是特定于交易所的,某些交易所将返回从在交易所上列出一对货币开始的交易,其他交易所将返回减少量的交易(例如,最近24小时的交易、最近100个交易等)。 如果用户想要精确控制时间范围,用户需要负责指定since参数。

大多数统一的方法将返回单个对象或普通数组(列表)对象(交易)。但是,很少有交易所(如果有的话)会一次性返回所有交易。通常,他们的API会将输出限制在一定数量的最近对象上。您无法一次性获取从起始时间到现在的所有对象。实际上,很少有交易所能够容忍或允许这样做。

要获取历史交易,用户需要分批(“页”)地遍历数据。通常,分页意味着在循环中逐个“获取数据片段”。

在大多数情况下,为了能够稳定地获取预期结果,用户必须至少使用某种类型的分页

另一方面,有些交易所根本不支持对公共交易的分页。一般来说,交易所只会提供最近的交易。

fetchTrades() / fetch_trades()方法还接受一个可选的params(关联键数组/字典,默认为空)作为其第四个参数。您可以使用它来将额外的参数传递给方法调用,或者覆盖特定的默认值(如果交易所支持)。请查阅您所使用交易所的API文档以了解更多详情。

交易所时间#

fetchTime()方法(如果可用)将从交易所服务器返回当前的整数时间戳(以毫秒为单位)。

fetchTime(params = {})

交易所状态#

交易所状态描述了交易所API的可用性的最新已知信息。这些信息要么被硬编码到交易所类中,要么直接从交易所API中实时获取。可以使用fetchStatus(params = {})方法来获取这些信息。fetchStatus返回的状态是以下之一:

  • 硬编码到交易所类中,例如如果API已中断或关闭。

  • 使用交易所ping或fetchTime端点进行更新,以查看其是否活动。

  • 使用专用的交易所API状态端点进行更新。

fetchStatus(params = {})

交易所状态结构#

fetchStatus()方法将返回以下的状态结构:

{
    'status': 'ok', // 'ok', 'shutdown', 'error', 'maintenance'
    'updated': undefined, // integer, last updated timestamp in milliseconds if updated via the API
    'eta': undefined, // when the maintenance or outage is expected to end
    'url': undefined, // a link to a GitHub issue or to an exchange post on the subject
}

status字段中可能的值有:

  • 'ok'表示交易所API完全可操作

  • 'shutdown’表示交易所已关闭,updated字段应该包含关闭的日期时间

  • 'error'表示交易所API或CCXT中的交易所实现存在故障

  • 'maintenance'表示定期维护,eta字段应该包含交易所预计恢复运行的日期时间

借款利率#

仅限于保证金交易当在现货市场做空交易或杠杆交易时,需要借入货币。被借入货币会产生利息。

可以使用以下方法来获取货币的借入利率:

  • fetchBorrowRate() 用于获取单个货币的借入利率

  • fetchBorrowRates() 用于获取所有货币的借入利率

  • fetchBorrowRatesPerSymbol() 用于获取各个市场中货币的借入利率

fetchBorrowRate(code, params = {})

参数

  • code (String) 统一的 CCXT 货币代码,必填项(例如 "USDT")

  • params (Dictionary) 特定交易所 API 端点的参数(例如 {"marginMode": "cross"}

返回值

fetchBorrowRates(params = {})

参数- 参数(字典):与交易所API端点特定的参数(例如{"marginMode": "cross"}

返回结果

fetchBorrowRatesPerSymbol (params = {})

参数

  • 参数(字典):与交易所API端点特定的参数(例如{"marginMode": "cross"}

返回结果

借贷利率结构#

{
  currency: 'USDT',  // 统一货币代码
  rate: 0.0006,  // 利率的比例,计算利息的速度
  period: 86400000,  // 利息倍增所需的时间(以毫秒为单位)
  timestamp: 1646956800000,  // 货币具有该利率时的时间戳
  datetime: '2022-03-11T00:00:00.000Z',  // 货币具有该利率时的日期和时间
  info: [ ... ]
}

借贷利率历史#

仅限保证金

fetchBorrowRateHistory 方法会获取特定时间槽内货币借贷利率的历史记录

fetchBorrowRateHistory (code, since = undefined, limit = undefined, params = {})

参数

  • code (String) 必填 统一的 CCXT 货币代码(例如 "USDT"

  • since (Integer) 最早借贷利率的时间戳(例如 1645807945000

  • limit (Integer) 要获取的最大借贷利率结构的数量(例如 10

  • params (Dictionary) 与交易所 API 端点相关的额外参数(例如 {"endTime": 1645807945000}

返回值

杠杆层级#

仅限合约- 在币安上,杠杆方法是私有的

fetchLeverageTiers() 方法可用于获取不同仓位大小下市场的最大杠杆。当市场对象中没有该信息时,它还可用于获取维持保证金率和市场的最大可交易数量。

虽然您可以通过访问 market['limits']['leverage']['max'] 来获取市场的绝对最大杠杆,但对于许多合约市场来说,最大杠杆将取决于您的仓位大小。

您可以通过以下方式访问这些限制:

  • fetchMarketLeverageTiers()(单个交易对)

  • fetchLeverageTiers([symbol1, symbol2, ...])(多个交易对)

  • fetchLeverageTiers()(所有市场交易对)

fetchMarketLeverageTiers(symbol, params = {})

参数

  • symbol (字符串) 必填 统一的 CCXT 交易对符号(例如 "BTC/USDT:USDT"

  • params (字典) 特定于交易所 API 端点的参数(例如 {"settle": "usdt"}

返回值

fetchLeverageTiers(symbols = undefined, params = {})

参数

  • symbols ([String]) 统一的 CCXT 交易对符号(例如 "BTC/USDT:USDT"

  • params (字典) 特定于交易所 API 终点的参数(例如 {"settle": "usdt"}

返回结果

杠杆分层结构#

[
    {
        "tier": 1,                      // 分层索引
        "notionalCurrency": "USDT",     // 最小和最大名义货币所在的货币单位
        "minNotional": 0,               // 该分层中的最低金额 // 投注 = 0.0
        "maxNotional": 10000,           // 该分层中的最高金额 // 在75倍杠杆下最大投注金额 = 133.33333333333334
        "maintenanceMarginRate": 0.0065, // 维持保证金率
        "maxLeverage": 75,              // 当交易价值 > minNotional 且 < maxNotional 时,此市场的最大可用杠杆
        "info": { ... }                 // 交易所响应
    },
    {
        "tier": 2,
        "notionalCurrency": "USDT",
        "minNotional": 10000,           // 在50倍杠杆下的最小投注金额 = 200.0
        "maxNotional": 50000,           // 在50倍杠杆下的最大投注金额 = 1000.0
        "maintenanceMarginRate": 0.01,
        "maxLeverage": 50,
        "info": { ... },
    },
    ...
    {
        "tier": 9,
        "notionalCurrency": "USDT",
        "minNotional": 20000000,
        "maxNotional": 50000000,
        "maintenanceMarginRate": 0.5,
        "maxLeverage": 1,
        "info": { ... },
    },
]

在上面的示例中:

  • 小于 133.33 的投注金额 = 最大杠杆 75

  • 介于 200 和 1000 之间的投注金额 = 最大杠杆 50

  • 投注金额为 150 = 最大杠杆 (10000 / 150) = 66.66

  • 介于 133.33 和 200 之间的投注金额 = 最大杠杆 (10000 / 投注金额) = 50.01 -> 74.99

对于火币用户的注意事项: 火币使用杠杆和金额来确定维持保证金率:https://www.huobi.com/support/en-us/detail/900000089903## 资金费率

仅适用于合约

可以使用以下方法获取当前、最近和下一个资金费率的数据:

  • fetchFundingRates() 获取所有市场交易对的资金费率

  • fetchFundingRates([symbol1, symbol2, ...]) 获取多个市场交易对的资金费率

  • fetchFundingRate(symbol) 获取单个市场交易对的资金费率

fetchFundingRate(symbol, params = {})

参数

  • symbol (String) 必填 统一的 CCXT 交易对符号 (例如 "BTC/USDT:USDT")

  • params (Dictionary) 特定于交易所 API 终点的参数 (例如 {"endTime": 1645807945000})

返回值

fetchFundingRates(symbols = undefined, params = {})

参数

  • symbols ([String]) 可选的统一CCXT交易对数组(例如 ["BTC/USDT:USDT", "ETH/USDT:USDT"]

  • params (字典) 特定交易所API端点相关的参数 (例如 {"endTime": 1645807945000})

返回值

  • 按市场交易对索引的资金费率结构字典

资金费率结构#

{
    info: { ... },
    symbol: 'BTC/USDT:USDT',
    markPrice: 39294.43,
    indexPrice: 39291.78,
    interestRate: 0.0003,
    estimatedSettlePrice: undefined,
    timestamp: undefined,
    datetime: undefined,
    fundingRate: 0.000072,
    fundingTimestamp: 1645833600000,
    fundingDatetime: '2022-02-26T00:00:00.000Z',
    nextFundingRate: -0.000018,
    nextFundingTimestamp: undefined,
    nextFundingDatetime: undefined,
    previousFundingRate: undefined,
    previousFundingTimestamp: undefined,
    previousFundingDatetime: undefined
}

资金费率历史#

仅限合约

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

参数- symbol (String) 统一的 CCXT 交易对标志符(例如 "BTC/USDT:USDT"

  • since (Integer) 最早的资金费率的时间戳(例如 1645807945000

  • limit (Integer) 要获取的资金费率的最大数量(例如 10

  • params (字典) 特定于交易所 API 端点的额外参数(例如 {"endTime": 1645807945000}

返回值

资金费率历史结构#

{
    info: { ... },
    symbol: "BTC/USDT:USDT",
    fundingRate: -0.000068,
    timestamp: 1642953600000,
    datetime: "2022-01-23T16:00:00.000Z"
}

持仓量#

只适用于合约

使用fetchOpenInterest方法从交易所获取给定交易对的当前持仓量。

fetchOpenInterest (symbol, params = {})

参数- symbol(字符串):统一的CCXT市场符号(例如,"BTC/USDT:USDT"

  • params(字典):特定于交易所API端点的额外参数(例如,{"endTime": 1645807945000}

返回结果

持仓量历史#

仅适用于合约

使用fetchOpenInterestHistory方法从交易所获取某个符号的持仓量历史。

fetchOpenInterestHistory (symbol, timeframe = '5m', since = undefined, limit = undefined, params = {})

参数

  • symbol(字符串):统一的CCXT市场符号(例如,"BTC/USDT:USDT"

  • timeframe(字符串):查看可用的交易所.timeframes值

  • since(整数):最早持仓量记录的时间戳(例如,1645807945000

  • limit(整数):要检索的最大持仓量结构数量(例如,10

  • params(字典):特定于交易所API端点的额外参数(例如,{"endTime": 1645807945000}

OKX用户注意事项:与统一的符号不同,okx.fetchOpenInterestHistory方法在symbol参数中需要统一的货币代码(例如,'BTC')。返回

持仓结构#

{
    symbol: 'BTC/USDT',
    baseVolume: 80872.801, // 已废弃
    quoteVolume: 3508262107.38, // 已废弃
    openInterestAmount: 80872.801,
    openInterestValue: 3508262107.38,
    timestamp: 1649379000000,
    datetime: '2022-04-08T00:50:00.000Z',
    info: {
        symbol: 'BTCUSDT',
        sumOpenInterest: '80872.80100000',
        sumOpenInterestValue: '3508262107.38000000',
        timestamp: '1649379000000'
    }
}

私有 API#

为了能够访问您的用户账户,通过下单市价和限价交易进行算法交易,查询余额信息、存款和提款等操作,您需要从您要交易的每个交易所获取 API 密钥进行身份验证。它们通常会在用户账户设置的单独选项卡或页面上提供。API 密钥是与交易所特定的,不能在任何情况下互换使用。

交易所的私有 API 通常允许以下类型的交互:

  • 使用 fetchBalance() 方法可以获取用户账户余额的当前状态,详情请参阅账户余额部分

  • 用户可以使用 createOrder()cancelOrder() 来下单和取消订单,以及使用类似 fetchOrderfetchOrders()fetchOpenOrder()fetchOpenOrders()fetchCanceledOrdersfetchClosedOrderfetchClosedOrders 等方法获取当前的未成交订单和历史订单记录,详情请参阅订单部分

  • 用户可以使用 fetchMyTrades 查询他们账户中执行过的交易历史,详情请参阅我的成交部分,还可参阅订单如何与交易相关

  • 用户可以使用 fetchPositions()fetchPosition() 查询他们的持仓,详情请参阅持仓部分

  • 用户可以使用 fetchTransactions() 或者 fetchDeposit()fetchDeposits()fetchWithdrawal()fetchWithdrawals() 单独查询交易历史记录,包括 充值提款 等发生在交易所账户的链上 交易,具体取决于交易所 API 提供的内容

  • 如果交易所的 API 提供了一个记账账簿端点,则用户可以使用 fetchLedger 获取所有对余额有影响的资金流动历史记录,包括交易、存款、提款、账户之间的内部转账、折扣、奖金、费用、质押收益等等,详情请参阅分账部分。

身份验证#

使用正确的API密钥,所有交易所的身份验证都会自动处理。身份验证的流程通常经过以下步骤:

  1. 生成新的随机数(nonce)。随机数是一个整数,通常是Unix时间戳,以秒或毫秒为单位(自1970年1月1日开始计时)。随机数应该对于特定的请求是唯一的,并且不断递增,以确保没有两个请求共享相同的随机数。每个后续的请求的随机数应该比前一个请求的随机数更大。默认的随机数是32位的Unix时间戳,单位是秒。

  2. 如果有其他端点参数,将公共API密钥和随机数附加到这些参数中,然后对整个内容进行序列化以进行签名。

  3. 使用HMAC-SHA256/384/512或MD5算法使用您的私钥对序列化的参数进行签名。

  4. 将签名的结果(十六进制或Base64编码)和随机数附加到HTTP头部或请求体中。

这个流程在不同的交易所可能有所不同。一些交易所可能希望以不同的编码形式提供签名,一些交易所在头部和请求体参数的名称和格式上也可能有所变化,但总体的模式对于所有交易所都是相同的。

不要同时在多个实例、不同的脚本或多个线程中使用相同的API密钥对。同时使用相同的密钥对可能会导致各种意外行为。

不要重复使用不同软件的API密钥!其他软件会让您的随机数过高。如果您收到InvalidNonce(无效的随机数)错误,请确保首先生成一个新的密钥对。

身份验证已经为您处理好了,所以除非您正在实现一个新的交易所类,否则不需要手动执行这些步骤。在交易时,您只需要真正的API密钥对即可。

设置API密钥#

必需的凭证#

API凭证通常包括以下内容:

  • apiKey。这是您的公共API密钥和/或令牌。此部分是非机密的,它包含在您的请求头部或请求体中,并以明文的形式通过HTTPS发送,用于标识您的请求。它通常是十六进制或Base64编码的字符串或UUID标识符。

  • secret。这是您的私钥。请保密,不要告诉任何人。在将请求发送到交易所之前,它用于在本地对请求进行签名。私钥不会在请求-响应过程中通过互联网发送,并且不应该公开或通过电子邮件发送。它与随机数一起用于生成具有密码学强度的签名。该签名随公共密钥一起发送,以鉴别您的身份。每个请求都有一个唯一的随机数,因此也有一个唯一的密码学签名。

  • uid。一些交易所(不是所有交易所)还会为用户生成一个用户ID或简称为uid。它可以是字符串或数字文字。如果您的交易所明确要求设置此值,则应该设置。有关详细信息,请参阅它们的文档

  • password。一些交易所(不是所有交易所)还要求您在交易时输入密码/短语。如果您的交易所明确要求设置这个字符串,请设置。有关详细信息,请参阅它们的文档。要创建API密钥,请在交易所网站上的用户设置中找到API选项卡或按钮。然后创建您的密钥并将它们复制粘贴到配置文件中。配置文件的权限应正确设置,只有所有者才能读取。

请记住保护好您的apiKey和secret key,不要向任何人发送或告诉他们。秘密密钥泄露或安全漏洞可能导致您丧失资金。

凭据验证#

为了检查用户是否提供了所有必需的凭据,Exchange基类有一个名为exchange.checkRequiredCredentials()exchange.check_required_credentials()的方法。调用该方法会抛出AuthenticationError,如果某些凭据缺失或为空。Exchange基类还有一个名为exchange.requiredCredentials的属性,允许用户查看该交易所需要哪些凭据,如下所示:

// JavaScript
const ccxt = require ('ccxt')
const exchange = new ccxt.binance()
console.log (exchange.requiredCredentials) // 打印所需的凭据
exchange.checkRequiredCredentials() // 抛出AuthenticationError
# Python
import ccxt
exchange = ccxt.coinbasepro()
print(exchange.requiredCredentials)  # 打印所需的凭据
exchange.check_required_credentials()  # 抛出AuthenticationError
// PHP
include 'ccxt.php';
$exchange = new \ccxt\bittrex ();
var_dump($exchange->requiredCredentials); // 打印所需的凭据
$exchange->check_required_credentials(); // 抛出AuthenticationError

配置API密钥#

要为交易设置交易所,只需将API凭据分配给现有的交易所实例或在实例化期间将它们传递给交易所构造函数,如下所示:

// JavaScript```php
// PHP

require_once 'path/to/ccxt.php';

// any time
$coinbasepro = new \ccxt\coinbasepro ();
$coinbasepro->apiKey = 'YOUR_COINBASEPRO_API_KEY';
$coinbasepro->secret = 'YOUR_COINBASEPRO_SECRET_KEY';

// upon instantiation
$bitstamp = new \ccxt\bitstamp (array (
    'apiKey' => 'YOUR_BITSTAMP_API_KEY',
    'secret' => 'YOUR_BITSTAMP_SECRET_KEY',
));

// from variable id
$exchangeId = 'binance';
$exchangeClass = "\\ccxt\\" . $exchangeId;
$exchange = new $exchangeClass (array (
    'apiKey' => 'YOUR_API_KEY',
    'secret' => 'YOUR_SECRET',
));
# Python

import ccxt

# any time
bittrex = ccxt.bittrex ()
bittrex.apiKey = 'YOUR_BITTREX_API_KEY'
bittrex.secret = 'YOUR_BITTREX_SECRET_KEY'

# upon instantiation
poloniex = ccxt.poloniex ({
    'apiKey': 'YOUR_POLONIEX_API_KEY',
    'secret': 'YOUR_POLONIEX_SECRET_KEY',
})

# from variable id
exchange_id = 'binance'
exchange_class = getattr(ccxt, exchange_id)
exchange = exchange_class({
    'apiKey': 'YOUR_API_KEY',
    'secret': 'YOUR_SECRET',
})
// JavaScript

const ccxt = require ('ccxt')

// any time
let kraken = new ccxt.kraken ()
kraken.apiKey = 'YOUR_KRAKEN_API_KEY'
kraken.secret = 'YOUR_KRAKEN_SECRET_KEY'

// upon instantiation
let okcoinusd = new ccxt.okcoinusd ({
    apiKey: 'YOUR_OKCOIN_API_KEY',
    secret: 'YOUR_OKCOIN_SECRET_KEY',
})

// from variable id
const exchangeId = 'binance'
    , exchangeClass = ccxt[exchangeId]
    , exchange = new exchangeClass ({
        'apiKey': 'YOUR_API_KEY',
        'secret': 'YOUR_SECRET',
    })
include 'ccxt.php'

// 任何时候
$quoinex = new \ccxt\quoinex ();
$quoinex->apiKey = 'YOUR_QUOINE_API_KEY';
$quoinex->secret = 'YOUR_QUOINE_SECRET_KEY';

// 实例化时
$zaif = new \ccxt\zaif (array (
    'apiKey' => 'YOUR_ZAIF_API_KEY',
    'secret' => 'YOUR_ZAIF_SECRET_KEY'
));

// 通过变量 id
$exchange_id = 'binance';
$exchange_class = "\\ccxt\\$exchange_id";
$exchange = new $exchange_class (array (
    'apiKey' => 'YOUR_API_KEY',
    'secret' => 'YOUR_SECRET',
));

注意,如果在开始交易之前没有设置 API 凭证,您的私有请求将失败并引发异常或错误。为了避免字符转义问题,请始终使用单引号而不是双引号来编写凭证 ('VERY_GOOD', "VERY_BAD")。

登录#

有些交易所在调用私有方法之前要求您先登录,可以使用 signIn 方法进行登录

signIn (params = {})

参数

  • params (字典) 与交易所 API 端点相关的参数(例如 {"2fa": "329293"}

覆盖 Nonce 值#

默认的 Nonce 值由底层交易所定义。如果您想要更频繁地进行私有请求,可以使用毫秒级的 Nonce 值来覆盖它!大多数交易所会在您达到速率限制时限制您的请求,请仔细阅读您交易所的API文档

如果您需要重置 Nonce 值,通常最简单的方法是创建另一对用于私有API的密钥。在您的配置中创建新密钥并设置一个全新且未使用的密钥对通常就足够了。

在某些情况下,由于权限不足或其他原因,您无法创建新的密钥。如果发生这种情况,您仍然可以覆盖 Nonce 值。基础市场类有以下方便的方法:

  • seconds(): 返回秒级的 Unix 时间戳。

  • milliseconds(): 返回毫秒级的 Unix 时间戳(ms = 1000 * s,千分之一秒)。

  • microseconds(): 返回微秒级的 Unix 时间戳(μs = 1000 * ms,百万分之一秒)。

有些交易所在其API文档中将毫秒与微秒混淆了,请原谅他们。您可以使用上述方法来覆盖 Nonce 值。如果您需要同时使用多个实例使用相同的密钥对,请使用闭包或公共函数来避免 Nonce 冲突。在 JavaScript 中,您可以通过在交易所构造函数中提供一个 nonce 参数或在交易所对象上显式设定来覆盖 Nonce 值。

// JavaScript

// 1: 在构造函数参数中重新定义自定义Nonce值
let nonce = 1
let kraken1 = new ccxt.kraken ({ nonce: () => nonce++ })// 2: nonce被重新定义
let kraken2 = new ccxt.kraken ()
kraken2.nonce = function () { return nonce++ } // 使用与kraken1相同的nonce

// 3: 毫秒级nonce
let kraken3 = new ccxt.kraken ({
    nonce: function () { return this.milliseconds () },
})

// 4: 较新的ES语法
let kraken4 = new ccxt.kraken ({
    nonce () { return this.milliseconds () },
})

在Python和PHP中,您可以通过子类化并覆盖特定交易所类的nonce函数来实现相同的效果:

# Python

# 1: 最短的方式
coinbasepro = ccxt.coinbasepro({'nonce': ccxt.Exchange.milliseconds})

# 2: 自定义nonce
class MyKraken(ccxt.kraken):
    n = 1
    def nonce(self):
        self.n += 1
        return self.n

# 3: 毫秒级nonce
class MyBitfinex(ccxt.bitfinex):
    def nonce(self):
        return self.milliseconds()

# 4: 内联方式的毫秒级nonce
hitbtc = ccxt.hitbtc({
    'nonce': lambda: int(time.time() * 1000)
})

# 5: 毫秒级nonce
acx = ccxt.acx({'nonce': lambda: ccxt.Exchange.milliseconds()})
// PHP

// 1: 自定义 nonce 值
class MyOKCoinUSD extends \ccxt\okcoinusd {
    public function __construct ($options = array ()) {
        parent::__construct (array_merge (array ('i' => 1), $options));
    }
    public function nonce () {
        return $this->i++;
    }
}

// 2: 毫秒级 nonce
class MyZaif extends \ccxt\zaif {
    public function __construct ($options = array ()) {
        parent::__construct (array_merge (array ('i' => 1), $options));
    }
    public function nonce () {
        return $this->milliseconds ();
    }
}

账户#

您可以使用 fetchAccounts() 方法获取与配置文件关联的所有账户

fetchAccounts (params = {})

账户结构#

fetchAccounts() 方法将返回如下结构:

[
    {
        id: "s32kj302lasli3930",
        type: "main",
        name: "main",
        code: "USDT",
        info: { ... }
    },
    {
        id: "20f0sdlri34lf90",
        name: "customAccount",
        type: "margin",
        code: "USDT",
        info: { ... }
    },
    {
        id: "4oidfk40dadeg4328",
        type: "spot",
        name: "spotAccount32",
        code: "BTC",
        info: { ... }
    },
    ...
]

账户类型是 统一的账户类型或者 subaccount## 账户余额

要查询余额并获取可用于交易或锁定在订单中的资金金额,可以使用 fetchBalance 方法:

fetchBalance (params = {})

参数

  • params(Dictionary):特定于交易所 API 端点的额外参数(例如 {"currency": "usdt"}

返回值

余额结构#

{
    'info':  { ... },    // 未经解析的原始回复及其详细信息
    'timestamp': 1499280391811, // 毫秒级时间戳(秒数 * 1000)
    'datetime': '2017-07-05T18:47:14.692Z', // ISO8601 带毫秒的日期时间字符串

    //-------------------------------------------------------------------------
    // 先按可用资金索引,然后按货币索引```javascript
'free': { // 货币的可交易余额,按货币计
    'BTC': 321.00, // 浮点数...
    'USD': 123.00,
    ...
},

'used': { ... }, // 按货币计的持有、锁定、冻结或未决金额

'total': { ... }, // 按货币计的总余额(可用 + 使用)

//-------------------------------------------------------------------------
// 先按货币索引,再按资金可用性索引

'BTC': { // 字符串,三位大写货币代码
    'free': 321.00 // 浮点数,可交易金额
    'used': 234.00, // 浮点数,持有、锁定、冻结或未决金额
    'total': 555.00, // 浮点数,总余额(可用 + 使用)
},

'USD': { // ...
    'free': 123.00 // ...
    'used': 456.00,
    'total': 579.00,
},

...
}

如果底层交易所不提供timestampdatetime值,则可能为未定义或缺失。

某些交易所可能不返回完整的余额信息。许多交易所不会返回空或未使用帐户的余额。在这种情况下,返回的余额结构中可能缺少某些货币。

// JavaScript
(async () => {
    console.log (await exchange.fetchBalance())
})()
# Python
print (exchange.fetch_balance ())
// PHP
var_dump($exchange->fetch_balance());

订单#

-统一API的这部分目前仍在进行中
-可能会有一些问题和缺失的实现
-欢迎贡献、拉取请求和反馈

查询订单#

大多数情况下,您可以根据ID或符号查询订单,但并非所有交易所都提供完整且灵活的查询订单终点集。有些交易所可能没有获取最近关闭订单的方法,其他交易所可能没有通过ID获取订单的方法,等等。ccxt库将通过尽可能地进行绕过来解决这些情况。

查询订单的方法列表如下:

-fetchCanceledOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) -fetchClosedOrder(id,symbol = undefined,params = {}) -fetchClosedOrders(symbol = undefined,since = undefined,limit = undefined,params = {}) -fetchOpenOrder(id,symbol = undefined,params = {}) -fetchOpenOrders(symbol = undefined,since = undefined,limit = undefined,params = {}) -fetchOrder(id,symbol = undefined,params = {}) -fetchOrders(symbol = undefined,since = undefined,limit = undefined,params = {})

请注意,这些方法的命名方式表示该方法返回单个订单还是多个订单(订单数组/列表)。fetchOrder()方法需要一个强制性的订单ID参数(字符串)。某些交易所还需要一个符号来通过ID获取订单,其中订单ID可以与各种交易对相交。此外,注意上述所有其他方法都返回一个数组(列表)的订单。其中大多数还需要一个符号参数,但是某些交易所允许在未指定符号的情况下进行查询(表示“所有符号”)。

如果用户调用了交易所不提供的方法或在ccxt中未实现的方法,该库将抛出NotSupported异常。查询某个交易所是否支持特定功能,可以查看交易所的.has属性:

// JavaScript
'use strict';

const ccxt = require ('ccxt')
const id = 'poloniex'
exchange = new ccxt[id] ()
console.log (exchange.has)
# Python
import ccxt
id = 'binance'
exchange = getattr(ccxt, id)()
print(exchange.has)
// PHP
$exchange = new \ccxt\bitfinex();
print_r ($exchange->has); // or var_dump

.has 属性一般具有以下标志,对应于用于查询订单的订单API方法:

exchange.has = {

    // ... other flags ...

    'fetchOrder': true, // 通过交易所直接可用,已在ccxt中实现
    'fetchOrders': false, // 无法通过交易所访问或未在ccxt中实现
    'fetchOpenOrders': true,
    'fetchClosedOrders': 'emulated', // 无法通过交易所访问,但在ccxt中已模拟实现

    // ... other flags ...}`

布尔值truefalse的含义是显而易见的。字符串值emulated意味着该交易所API中缺少特定的方法,ccxt将在可能的情况下在客户端上解决这个问题。

理解订单API设计#

各交易所的订单管理API设计不同。用户必须了解每个特定方法的目的以及它们如何组合成完整的订单API:

  • fetchCanceledOrders()- 获取已取消订单的列表

  • fetchClosedOrder()- 根据订单ID获取单个已关闭订单

  • fetchClosedOrders() – 获取已关闭(或已取消)订单的列表。

  • fetchMyTrades() – 虽然不是订单API的一部分,但它与之密切相关,因为它提供了已结算交易的历史记录。

  • fetchOpenOrder()- 根据订单ID获取单个未完成订单

  • fetchOpenOrders() – 获取未完成订单的列表。

  • fetchOrder() – 根据订单ID获取单个订单(未完成或已关闭)。

  • fetchOrders() – 获取所有订单的列表(未完成或已关闭/取消)。

  • createOrder() – 用于下订单

  • cancelOrder() – 用于取消订单

大多数交易所都有一种获取当前未完成订单的方法。因此,存在exchange.has['fetchOpenOrders']。如果该方法不可用,则很可能存在exchange.has['fetchOrders'],该方法将提供所有订单的列表。交易所将从fetchOpenOrders()fetchOrders()返回一个未完成订单列表。任何交易所通常会提供这两个方法中的一个。

某些交易所将提供订单历史记录,而其他交易所则不会。如果底层交易所提供订单历史记录,则存在exchange.has['fetchClosedOrders']exchange.has['fetchOrders']。如果底层交易所不提供订单历史记录,则fetchClosedOrders()fetchOrders()将不可用。在后一种情况下,用户需要构建一个本地订单缓存,并使用fetchOpenOrders()fetchOrder()来跟踪未完成订单的状态,并在用户环境中标记为已关闭(当它们不再处于未完成状态时)。

如果底层交易所没有用于订单历史记录的方法(fetchClosedOrders()fetchOrders()),那么它将提供fetchOpenOrders + 使用fetchMyTrades的交易历史记录(参见订单如何与交易相关)。对于实时交易机器人来说,这组信息在许多情况下足够进行跟踪。如果没有订单历史记录,您需要跟踪您的实时订单,并从未完成订单和历史交易中恢复历史信息。

一般来说,底层交易所通常提供以下一种或多种类型的历史数据:

  • fetchClosedOrders()

  • fetchOrders()

  • fetchMyTrades()以上三种方法可能有缺失,但是交易所API通常会提供其中至少一种方法。

如果底层交易所不提供历史订单,CCXT库将不会模拟缺失的功能 - 这需要用户在必要时自行添加。

请注意,某个方法可能丢失的原因是交易所没有相应的API端点,或者CCXT尚未实现(该库还在不断完善中)。在后一种情况下,缺失的方法将尽快添加上。

查询多个订单和交易#

所有返回交易列表和订单列表的方法,都接受第二个 since 参数和第三个 limit 参数:

  • fetchTrades()(公共方法)

  • fetchMyTrades()(私有方法)

  • fetchOrders()

  • fetchOpenOrders()

  • fetchClosedOrders()

  • fetchCanceledOrders()

第二个 since 参数用于按时间戳筛选数组,第三个 limit 参数用于按返回项目数(数量)筛选。

如果用户没有指定 sincefetchTrades()/fetchOrders() 方法将返回交易所的默认结果集。默认结果集是特定于交易所的,某些交易所将返回从货币对在交易所上市之日起的交易或最近订单,其他交易所将返回一组减少了交易或订单的结果(例如,最近24小时、最近100笔交易、前100个订单等)。如果用户要精确控制时间范围,用户需要负责指定 since 参数。

注意:并非所有交易所都提供通过起始时间过滤交易和订单的方法,因此 sincelimit 的支持因交易所而异。但是,大多数交易所至少提供了一些用于 “分页” 和 “滚动加载” 的替代方法,可以使用额外的 params 参数进行覆盖。

某些交易所没有获取已关闭订单或所有订单的方法。它们只提供 fetchOpenOrders() 端点,有时也会提供 fetchOrder 端点。这些交易所没有任何获取订单历史的方法。对于这些交易所,用户必须在用户端存储订单的字典或数据库,并在调用 createOrder()fetchOpenOrders()cancelOrder()cancelAllOrders() 等方法后更新数据库中的订单。

按订单 ID#

要通过订单 ID 获取特定订单的详细信息,请使用 fetchOrder() / fetch_order() 方法。一些交易所在按 ID 获取特定订单时也需要一个交易对。

fetchOrder/fetch_order 方法的签名如下:

if (exchange.has['fetchOrder']) {
    // 你可以使用 params 参数进行自定义覆盖
    let order = await exchange.fetchOrder(id, symbol = undefined, params = {})
}

有些交易所没有按 ID 获取订单的终端,ccxt 将在可能的情况下模拟它。 目前可能还有一些地方缺失,因为这还在进行中。

您可以通过额外的 params 参数传递自定义的键值对来提供特定的订单类型,或者根据需要设置其他设置。

以下是使用 fetchOrder 方法从已经认证的交易所实例获取订单信息的示例:

// JavaScript
(async function () {
    const order = await exchange.fetchOrder(id)
    console.log(order)
})()
# Python 3(同步)
if exchange.has['fetchOrder']:
    order = exchange.fetch_order(id)
    print(order)

# Python 3.5+ asyncio(异步)
import asyncio
import ccxt.async_support as ccxt
if exchange.has['fetchOrder']:
    order = asyncio.run(exchange.fetch_order(id))
    print(order)
// PHP
if ($exchange->has['fetchOrder']) {
    $order = $exchange->fetch_order($id);
    var_dump($order);
}

所有订单#

if (exchange.has['fetchOrders'])
    exchange.fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {})

有些交易所没有用于获取所有订单的端点,在可能的情况下,ccxt 将对此进行模拟。 目前可能仍然会偶尔缺失一些订单,因为这是一个正在进行的工作。

未完成订单#

if (exchange.has['fetchOpenOrders'])
    exchange.fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {})

已完成订单#

不要将 已完成订单交易(俗称 fills)混淆!一个订单可以通过多个相反的交易来完成!因此,一个 已完成订单 并不等同于一个 交易。通常来说,订单本身并没有 fee,但每个用户交易都会有 feecost 和其他属性。然而,许多交易所也会将这些属性传递给订单。

有些交易所没有用于获取已完成订单的端点,在可能的情况下,ccxt 将对此进行模拟。 目前可能仍然会偶尔缺失一些订单,因为这是一个正在进行的工作。

if (exchange.has['fetchClosedOrders'])
    exchange.fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {})
```### 订单结构

ccxt统一API中大多数返回订单的方法将生成以下订单结构:

```javascript
{
    'id':                '12345-67890:09876/54321', // string
    'clientOrderId':     'abcdef-ghijklmnop-qrstuvwxyz', // 自定义的clientOrderId(如果有的话)
    'datetime':          '2017-08-17 12:42:48.000', // ISO8601格式的'timestamp',带有毫秒
    'timestamp':          1502962946216, // 下单/开仓的Unix时间戳(毫秒)
    'lastTradeTimestamp': 1502962956216, // 该订单上最近一笔交易的Unix时间戳
    'status':      'open',        // 'open'(未成交或部分成交)、'closed'(已成交)、'canceled'(未成交并已取消或部分成交后取消)、'expired'(未成交并已过期)、'rejected'(拒绝)
    'symbol':      'ETH/BTC',     // 交易对
    'type':        'limit',       // 'market'(市价)、'limit'(限价)
    'timeInForce': 'GTC',         // 'GTC'(一直有效)、'IOC'(立即成交或取消)、'FOK'(全部成交或取消)、'PO'(只限制挂单)
    'side':        'buy',         // 'buy'(买入)、'sell'(卖出)
    'price':        0.06917684,   // 以计价货币表示的浮点类型价格(市价单可能为空)
    'average':      0.06917684,   // 浮点类型的平均成交价格
    'amount':       1.5,          // 基础货币的下单数额
    'filled':       1.1,          // 基础货币的已成交数额
    'remaining':    0.4,          // 剩余待成交数额
    'cost':         0.076094524,  // 'filled' * 'price'(基于可用填充价格)
    'trades':     [ ... ],        // 一系列订单成交或执行情况
    'fee': {                      // 如果可用,费用信息
        'currency': 'BTC',        // 费用所使用的货币(通常为计价货币)
        'cost': 0.0009,           // 费用数额
        'rate': 0.002,            // 费用率(如果可用)
    },
    'info': { ... },              // 原始未经解析的订单结构
}
  • 订单的status通常为'open'(未成交或部分成交)、'closed'(全部成交)或'canceled'(未成交并已取消或部分成交后取消)。

  • 一些交易所允许用户在下单时指定有效期限。如果订单在有效期限内未成交,其status将变为'expired'

  • 使用filled的值来确定订单是否已成交、部分成交或全部成交,以及成交量。

  • 对于fee信息的工作尚在进行中,根据交易所功能,费用信息可能部分或完全缺失。

  • fee货币可以与交易货币不同(例如,以USD计价的ETH/BTC订单的费用)。

  • lastTradeTimestamp时间戳可能为空值、undefined/None/null,若交易所不支持该字段或订单为未成交或部分成交的开放订单。

  • lastTradeTimestamp(如果有)表示最后一笔交易的时间戳,如果订单全部或部分成交,否则lastTradeTimestampundefined/None/null

  • 订单的status优先于lastTradeTimestamp

  • 订单的cost为:{ filled * price }

  • 订单的cost表示订单的总量(计价货币),而amount表示订单的数量(基础货币)。cost的值应尽可能接近实际的最近已知订单总量。cost字段本身主要是为了方便,可以从其他字段推导出来。

  • clientOrderId字段可以由用户在下单时设置,使用自定义订单参数。用户可以使用clientOrderId在以后区分自己的订单。这仅适用于当前支持clientOrderId的交易所。

timeInForce#

如果未经交易所指定,timeInForce字段可能为undefined/None/nulltimeInForce的统一化工作正在进行中。

timeInForce字段可能的取值:

  • 'GTC' = 至撤销为止,订单一直保留在订单簿中,直到被匹配或取消。

  • 'IOC' = 立即成交或取消,订单必须立即得到匹配并部分或全部成交,未成交部分将被取消(或整个订单将被取消)。

  • 'FOK' = 全部成交或取消,订单必须得到全部成交并立即关闭,否则整个订单将被取消。

  • 'PO' = 仅限挂单,订单仅能作为挂单下达,否则将被取消。这意味着订单必须至少在一段时间内保持为未成交状态。将PO作为timeInForce选项的统一化工作正在进行中,统一的交易所应具备exchange.has['postOnly'] == True

下单#

用户可以向交易所发出不同类型的订单,定期订单最终会进入相应交易对的订单簿,其他订单可能更加高级。以下是各种类型订单的概述列表:- 限价订单 – 有一个以基准货币计量的数量(想要购买或卖出的数量)和一个以报价货币计量的价格(想要购买或卖出的价格)的常规订单。

  • 市价订单 – 有一个以基准货币计量的数量(想要购买或卖出的数量)的常规订单

    • 市价买单 – 有一个以报价货币计量的数量(想要用于购买的金额)的市价买单(某些交易所要求以市价买单来购买)

  • 触发订单 – 一种高级订单类型,用于等待市场上的特定条件,然后自动触发:当达到触发价格时,触发订单被激活,然后下达一个常规限价价格或市价订单,最终导致进入或退出一个仓位

  • 止损订单 – 与触发订单几乎相同,但用于在一个仓位上停止进一步亏损:当价格达到触发价格时,触发止损订单,导致下达另一个常规限价或市价订单,以特定限价价格或市价来平仓(一个与止损订单相关联的仓位)。

  • 止盈订单 – 停损订单的对应品种,这种订单类型用于在一个仓位上平仓以获得利润:当价格达到触发价格时,触发止盈订单,导致下达另一个常规限价或市价订单,以特定限价价格或市价来平仓(一个与止盈订单相关联的仓位)。

  • 止损和止盈订单关联到一个仓位 – 高级订单,由上述三种类型的订单组成:下达一个常规限价或市价订单来进入一个仓位,并在打开仓位时下达一个止损和/或止盈订单,以后用于关闭该仓位(当触发止损时,将关闭该仓位并取消相应的止盈订单,反之亦然,当触发止盈时,将关闭该仓位并取消相应的止损订单,这两个相对方也被称为“OCO订单 - 一个取消另一个),除了开仓的数量(和限价订单的价格)外,还需要一个止损订单的触发价格(如果是止损限价订单,则需要一个限价的价格)和/或一个止盈订单的触发价格(如果是止盈限价订单,则需要一个限价的价格)。

下订单总是需要指定一个用户指定的symbol(要交易的市场)。

要下订单,请使用createOrder方法。您可以使用返回的统一classid查询订单的状态和状态。

createOrder (symbol, type, side, amount, price = undefined, params = {})

参数

  • symbol (String) 必需 统一CCXT市场符号

    • 确保所讨论的符号在目标交换中存在,并可用于交易。

  • side 必需 指定您订单方向的字符串字面量。 统一的方向:

    • buy 给予报价货币,并收到基准货币;例如,购买BTC/USD表示您将以美元购买比特币。

    • sell 给予基准货币,并收到报价货币;例如,出售BTC/USD表示您将以比特币出售美元。

  • type 指定订单类型的字符串字面量 统一的类型:

    • 市价 某些交易所不允许,详情请参阅他们的文档

    • 限价

    • 请参阅#自定义订单参数和#其他订单类型获取非统一类型的信息。

  • amount,要交易的货币的数量,通常是基准货币的单位(某些交易所的单位取决于订单的方向:详细信息请参阅其API文档。)

  • price 订单要以的报价货币计量的价格(市价订单中忽略)

  • params (字典) 特定于交换API端点的额外参数(例如,{"settle": "usdt"}

返回

createOrder备注

  • 有些交易所只允许使用限价订单进行交易。返回的订单结构中的一些字段可能为 undefined / None / null,如果这些信息没有在交易所API的响应中返回。用户能够确保 createOrder 方法会返回一个统一的订单结构,该结构至少包含订单的 idinfo(交易所原始响应的解码后的JSON数据):

{
    'id': '字符串',  // 订单id
    'info': { ... }, // 从交易所解码的原始JSON响应
}

限价订单#

限价订单是以交易者指定的价格在交易所的订单簿上下单的。当在同一市场上没有更好价格的订单时,它们将被成交(关闭),并且另一位交易者会创建一个市价订单或一个价格等于或超过限价订单价格的对手订单。

限价订单可能无法完全成交。这是当成交订单的数量小于限价订单指定的数量时发生的情况。

// 使用驼峰命名法
exchange.createLimitSellOrder (symbol, amount, price, params)
exchange.createLimitBuyOrder (symbol, amount, price, params)

// 使用下划线命名法
exchange.create_limit_sell_order (symbol, amount, price, params)
exchange.create_limit_buy_order (symbol, amount, price, params)

// 使用通用的 createLimitOrder 和 side = 'buy' 或 'sell'
exchange.createLimitOrder (symbol, side, amount, price, params)
exchange.create_limit_order (symbol, side, amount, price, params)

// 使用通用的 createOrder,type = 'limit' 和 side = 'buy' 或 'sell'
exchange.createOrder (symbol, 'limit', side, amount, price, params)
exchange.create_order (symbol, 'limit', side, amount, price, params)

市价订单也被称为#

  • 市价订单

  • 现货订单

  • 瞬间订单

市价订单通过履行交易所委托订单簿卖方的一份或多份已存在的订单,立即执行。您的市价订单所履行的订单是从订单簿堆栈的顶部选择的,这意味着您的市价订单以最优价格履行。下市价订单时,您无需指定订单价格,如果指定了价格,该价格将被忽略。

在下单之前,不能保证订单将以您观察到的价格执行。原因包括但不限于:

  • 价格滑动:在执行订单过程中,市场价格出现轻微变动。价格滑动的原因包括但不限于:

    • 网络往返延迟

    • 交易所负载过高

    • 价格波动

  • 不确定的订单大小:如果市价订单金额大于订单簿顶部订单的数量,则在顶部订单被完全成交后,市价订单将继续成交下一个订单,这意味着市价订单以多个价格成交。

// 小驼峰命名法
exchange.createMarketSellOrder (symbol, amount, params)
exchange.createMarketBuyOrder (symbol, amount, params)

// 下划线命名法
exchange.create_market_sell_order (symbol, amount, params)
exchange.create_market_buy_order (symbol, amount, params)

// 使用通用的createMarketOrder和side = 'buy'或'sell'
exchange.createMarketOrder (symbol, side, amount, params)
exchange.create_market_order (symbol, side, amount, params)// 使用 createOrder 函数创建市价订单,订单类型为 'market',买入或卖出方向为 'buy' 或 'sell'
exchange.createOrder (symbol, 'market', side, amount, ...)
exchange.create_order (symbol, 'market', side, amount, ...)

**注意,有些交易所不接受市价订单(仅允许限价订单)。**为了在程序中检测交易所是否支持市价订单,可以使用 .has ['createMarketOrder'] 交易所属性:

// JavaScript
if (exchange.has['createMarketOrder']) {
    ...
}
# Python
if exchange.has['createMarketOrder']:
    ...
// PHP
if ($exchange->has['createMarketOrder']) {
    ...
}

市价买入#

一般来说,当下达市价买入或市价卖出订单时,用户只需要指定要买入或卖出的基础货币数量。然而,有些交易所在市价买入订单中采用了不同的计算方法。

假设你在交易 BTC/USD,BTC 的当前市价超过 9000 美元。对于市价买入或市价卖出,你可以指定购买 2 个 BTC,这将导致你的账户上增加或减少大约 18000 美元(加减号取决于订单方向)。

在某些交易所中,市价买入订单要求用计价货币表示订单的总成本! 这种做法背后的逻辑很简单,交易所不是通过买入或卖出基础币种的数量来操作,而是通过 “你要花费多少计价货币来购买”

要在这些交易所上下达市价买入订单,你不能指定购买 2 个 BTC,而应该指定订单的总成本,例如此例中的 18000 美元。对于采用这种方式处理 market buy 订单的交易所,有一个交易所特定选项 createMarketBuyOrderRequiresPrice,可以用两种方式指定 market buy 订单的总成本。第一种方式是默认的,如果你在amount参数后面指定了price参数,那么订单的总成本将会在库中通过这两个值的简单乘法运算(cost = amount * price)计算出来。计算结果cost将作为美元报价货币在该特定市场购买订单上的花费金额。

// 这个示例过于简化,没有展示处理错误和交换元数据所需的全部代码
// 它只展示了一个下达市价买单的概念

const exchange = new ccxt.cex({
    'apiKey': YOUR_API_KEY,
    'secret': 'YOUR_SECRET',
    // 'options': {
    //     'createMarketBuyOrderRequiresPrice': true, // 默认值
    // },
})

;(async () => {

    // 当 `createMarketBuyOrderRequiresPrice` 为 true 时,我们可以传递价格
    // 这样订单的总成本将在库中通过乘法计算(amount * price)得到

    const symbol = 'BTC/USD'
    const amount = 2 // BTC
    const price = 9000 // USD
    // 总成本 = 金额 * 价格 = 2 * 9000 = 18000(USD)

    // 注意这里我们不使用 createMarketBuyOrder 函数,而是使用 createOrder 函数
    // createMarketBuyOrder 函数将省略价格,并且在 exchange.options['createMarketBuyOrderRequiresPrice'] = true 时无法工作
    const order = await exchange.createOrder(symbol, 'market', 'buy', amount, price)

    console.log(order)
})()

第二种方式适用于用户想要自己计算和指定订单的总成本的情况。通过将 createMarketBuyOrderRequiresPrice 选项设置为 false 来关闭这个选项:

const exchange = new ccxt.cex({
    'apiKey': YOUR_API_KEY,
    'secret': 'YOUR_SECRET',
    'options': {
        'createMarketBuyOrderRequiresPrice': false, // 关闭
    },
})// 或者,可以在交易实例化后关闭它,可以执行以下操作
exchange.options['createMarketBuyOrderRequiresPrice'] = false

;(async () => {

    // 当 `createMarketBuyOrderRequiresPrice` 为 true 时,我们可以传递价格
    // 这样订单的总成本将在库内进行计算
    // 通过将数量乘以价格 (amount * price)

    const symbol = 'BTC/USD'
    const amount = 2 // BTC
    const price = 9000 // USD
    cost = amount * price // ← 而不是成本 ↓ 在此处
    const order = await exchange.createMarketBuyOrder (symbol, cost)
    console.log (order)
}) ()

更多相关信息:

使用限价单模拟市价单#

还可以使用限价单来模拟市价单。

警告:由于高波动性,这种方法可能存在风险,请自行承担风险,并且在确切了解自己在做什么的情况下使用!

大多数情况下,可以通过以非常低的价格进行限价卖单来模拟市价卖单- 交易所将自动将其设置为市价单(价格当前最适合你的订单簿中可用的价格)。当交易所检测到你以非常低的价格出售时,它将自动为你提供订单簿中可用的最佳买家价格。这实际上与下达市价卖单是相同的。因此,可以使用限价单(其中适用)来模拟市价单。相反的情况同样成立 - 可以通过以非常高的价格进行“限价买入”来模拟“市价买入”。大多数交易所将会根据最佳可用价格关闭您的订单,即市场价格。

然而,您绝不能完全依赖此功能,**始终先用小额资金进行测试!**您可以首先在他们的网络界面中进行尝试以验证该逻辑。您可以以指定的限价出售最小金额(适度的亏损水平,以防万一),然后在交易历史中检查实际成交价格。

限价订单#

限价订单也称为限价单。一些交易所只接受限价订单。限价订单需要提交一个价格(每单位价格)与订单一起。只有当市场价格达到所期望的水平时,交易所才会关闭限价订单。

// 驼峰命名风格
exchange.createLimitBuyOrder (symbol, amount, price[, params])
exchange.createLimitSellOrder (symbol, amount, price[, params])

// 下划线风格
exchange.create_limit_buy_order (symbol, amount, price[, params])
exchange.create_limit_sell_order (symbol, amount, price[, params])

止损订单#

当基础资产价格达到触发价格时,止损订单将在订单簿中放置。

触发订单#

传统的”止损”订单(您可能会在交易所的网站上看到)现在在CCXT库中称为”触发”订单。通过添加一个triggerPrice参数来实现。它们是独立的基本触发订单,可以开仓和平仓。

  • 当基础资产/合约的价格从任何方向穿越triggerPrice时激活

// JavaScript
const symbol = 'ETH/BTC'
const type = 'limit' // 或者 'market'
const side = 'sell'
const amount = 123.45 // 您的数量
const price = 54.321 // 您的价格
const params = {
    'triggerPrice': 123.45, // 您的止损价格
}
const order = await exchange.createOrder (symbol, type, side, amount, price, params)
# Python
symbol = 'ETH/BTC'
type = 'limit'  # 或者 'market'
side = 'sell'
amount = 123.45  # 您的数量
price = 54.321  # 您的价格
params = {
    'triggerPrice': 123.45,  # 您的止损价格
}
order = exchange.create_order(symbol, type, side, amount, price, params)
// PHP
$symbol = 'ETH/BTC';
$type = 'limit'; // 或者 'market'
$side = 'sell';
$amount = 123.45; // 您的数量
$price = 54.321; // 您的价格
$params = {
    'triggerPrice': 123.45, // 您的止损价格
}
$order = $exchange->create_order ($symbol, $type, $side, $amount, $price, $params);
止损订单#

与触发订单相同,但方向是重要的。通过指定stopLossPrice参数(用于标记止损触发价格)来实现。

假设您以1000的价格进入了多头头寸(购买),并希望在可能的价格下跌到700以下时保护自己免受损失。您将在700处设置一个止损订单,触发价格为700。对于该止损订单,您可以指定限价,或者它将以市价执行。

    | price  | amount
----|----------------
    |  1500 | 200
    |  1400 | 300
  a |  1300 | 100
  s |  1200 | 200
  k |  1100 | 300
    |  1000 | 100 <--- 您以1000的价格购买,进入多头头寸
    |   900 | 100
----|---------------- 最后成交价为900
    |   800 | 100
    |   700 | 200 <------- 您在700处设置了一个止损订单 <----------------------+
  b |   600 | 100       当触发价格从上方达到您的止损价格时                     |
  i |   500 | 300   它将以市价在700以下平仓 -----------------------------------+
  d |   400 | 200 <- 或者它将以低于止损价格的限价执行 --------------------------+
    |   300 | 100
    |   200 | 100

假设您以700的价格进入了空头头寸(卖出),并希望在可能的价格上涨到1300以上时保护自己免受损失。您将在1300处设置一个止损订单,触发价格为1300。对于该止损订单,您可以指定限价,或者它将以市价执行。``` // PHP

// for a stop loss order $params = array( ‘stopLossPrice’ => 55.45, // your stop loss price );

$order = $exchange->createOrder($symbol, $type, $side, $amount, $price, $params);


Stop Loss订单在以下情况下被激活,即基础资产/合约价格:

* 从上方下降到低于`stopLossPrice`时,用于卖出订单(例如:平仓多头头寸,避免进一步亏损)
* 从下方上升到高于`stopLossPrice`时,用于买入订单(例如:平仓空头头寸,避免进一步亏损)// 停损指令
$params = {
    'stopLossPrice': 55.45, // 设置你的停损价
}

$order = $exchange->create_order ($symbol, $type, $side, $amount, $price, $params);
止盈指令#

与停损指令相似,但方向不同。通过指定takeProfitPrice参数来实施(用于触发止盈的价格)。

假设你以1000的价格进入多头持仓(买入),希望从可能的价格上涨中获利,价格上涨到1300以上。你可以在触发价格为1300的止盈指令中设置一个限价价格,或者按市价执行。

    | 价格   | 数量
----|----------------
    |  1500 | 200
    |  1400 | 300 <------------------------------------------------------------------------------+
  a |  1300 | 100 <--- 当价格达到或超过1300时,止盈指令将按市价平仓                                       |
  s |  1200 | 200        当从下方触发触发价格时                                                       |
  k |  1100 | 300   或者按你指定的高于触发价格的限价价格执行                                     -+
    |  1000 | 100 <-  这里以1000的价格买入进入多头持仓
    |   900 | 100
----|---------------- 最新价格为900
    |   800 | 100
    |   700 | 200
  b |   600 | 100
  i |   500 | 300
  d |   400 | 200
    |   300 | 100
    |   200 | 100

假设你以700的价格做空(卖出),希望从可能的价格下跌中获利,价格下跌到600以下。你可以在触发价格为600的止盈指令中设置一个限价价格,或者按市价执行。

    | 价格   | 数量
----|----------------
    |  1500 | 200
    |  1400 | 300
  a |  1300 | 100
  s |  1200 | 200
  k |  1100 | 300
    |  1000 | 100
    |   900 | 100
----|---------------- 最新价格为900(你以700的价格卖出)
    |   800 | 100
    |   700 | 200 <--- 你以700的价格卖出进入空头持仓
  b |   600 | 100 <------- 你在600的价格放置一个止盈指令
  i |   500 | 300  当价格从上方达到或降至触发价格时
  d |   400 | 200  它将按市价平仓,价格低于600
    |   300 | 100 <- 或者按你指定的低于触发价格的限价价格执行
    |   200 | 100

当基础资产价格:

  • 从低于takeProfitPrice上涨时,对于卖出指令激活止盈(例如:以利润为目的关闭多头持仓)

  • 从高于takeProfitPrice下跌时,对于买入指令激活止盈(例如:以利润为目的关闭空头持仓)```javascript // JavaScript

// 附加止损和止盈订单到仓位

const stopLossPrice = 110.50; // your stop loss price const takeProfitPrice = 120.45; // your take profit price

const position = await exchange.getPosition(symbol); if (position) { const params = { ‘stopLossPrice’: stopLossPrice, ‘takeProfitPrice’: takeProfitPrice, }

const order = await exchange.createOrder(symbol, type, side, amount, price, params)

}


```python
# Python

# 附加止损和止盈订单到仓位

stop_loss_price = 110.50  # your stop loss price
take_profit_price = 120.45  # your take profit price

position = exchange.get_position(symbol)
if position:
    params = {
        'stopLossPrice': stop_loss_price,
        'takeProfitPrice': take_profit_price,
    }

    order = exchange.create_order(symbol, type, side, amount, price, params)
// PHP

// 附加止损和止盈订单到仓位

$stopLossPrice = 110.50; // your stop loss price
$takeProfitPrice = 120.45; // your take profit price

$position = $exchange->get_position($symbol);
if ($position) {
    $params = [
        'stopLossPrice' => $stopLossPrice,
        'takeProfitPrice' => $takeProfitPrice,
    ];

    $order = $exchange->create_order($symbol, $type, $side, $amount, $price, $params);
}

请注意,Transposit的命令和代码示例中的symboltypesideamountprice参数应该由实际的值替换。止盈 / 止损订单与开仓主要订单相关。通过提供 stopLosstakeProfit 的字典参数来实现。分别描述这两个参数。

  • 默认情况下,止损和止盈订单的幅度与主要订单相同,但方向相反。

  • 附加止损订单是条件性的,需要主要订单执行。

  • 并非所有交易所都支持。

  • 可以提供 stopLosstakeProfit 中的一个或两个参数,这取决于交易所。

注意:这部分还在统一的过程中,正在进行中

// JavaScript

const params = {
    'stopLoss': {
        'type': 'limit', // 或者 'market',如果指定了限价,则不需要这个字段
        'price': 100.33, // 限价止损订单的限价
        'triggerPrice': 101.25,
    },
    'takeProfit': {
        'type': 'market', // 或者 'limit',如果指定了限价,则不需要这个字段
        // 市价止盈订单没有限价
        // 'price': 160.33, // 市价止盈订单不需要这个字段
        'triggerPrice': 150.75,
    }
}
const order = await exchange.createOrder (symbol, type, side, amount, price, params)
# Python
symbol = 'ETH/BTC'
type = 'limit'  # 或者 'market'
side = 'buy'
amount = 123.45  # 购买数量
price = 115.321  # 价格
params = {
    'stopLoss': {
        'type': 'limit',  # 或者 'market',如果指定了限价,则不需要这个字段
        'price': 100.33,  # 限价止损订单的限价
        'triggerPrice': 101.25,
    },
    'takeProfit': {
        'type': 'market',  # 或者 'limit',如果指定了限价,则不需要这个字段
        # 市价止盈订单没有限价
        # 'price': 160.33,  # 市价止盈订单不需要这个字段
        'triggerPrice': 150.75,
    }
}
order = exchange.create_order (symbol, type, side, amount, price, params)
// PHP
$symbol = 'ETH/BTC';
$type = 'limit'; // 或者 'market'
$side = 'buy';
$amount = 123.45; // 购买数量
$price = 115.321; // 价格
$params = {
    'stopLoss': {
        'type': 'limit', // 或者 'market',如果指定了限价,则不需要这个字段
        'price': 100.33, // 限价止损订单的限价
        'triggerPrice': 101.25,
    },
    'takeProfit': {
        'type': 'market', // 或者 'limit',如果指定了限价,则不需要这个字段
        // 市价止盈订单没有限价
        // 'price': 160.33, // 市价止盈订单不需要这个字段
        'triggerPrice': 150.75,
    }
}
$order = $exchange->create_order ($symbol, $type, $side, $amount, $price, $params);

自定义订单参数#

一些交易所允许您为订单指定可选参数。您可以通过使用 params 参数将可选参数和关联数组一起传递给您的统一API调用,并覆盖您的查询。所有自定义参数都是特定于交易所的,换句话说,不要期望一个交易所的自定义参数适用于另一个交易所。

// JavaScript
// 使用自定义订单类型
bitfinex.createLimitSellOrder ('BTC/USD', 1, 10, { 'type': 'trailing-stop' })
# Python
# Python
# 添加自定义订单标志
kraken.create_market_buy_order('BTC/USD', 1, {'trading_agreement': '同意'})
// PHP
// 添加自定义用户ID到您的订单
$hitbtc->create_order ('BTC/USD', '限价', '买入', 1, 3000, array ('clientOrderId' => '123'));
用户定义的 clientOrderId#
- 统一API的这一部分仍在进行中
- 这个地方可能会有一些问题和缺失的实现
- 欢迎贡献、拉取请求和反馈

用户可以在下单时使用 params 来指定自定义的 clientOrderId 字段。使用 clientOrderId 可以后续区分自己的订单。这仅适用于目前支持 clientOrderId 的交易所。对于不支持的交易所,可能会在提供了 clientOrderId 后,抛出错误或将 clientOrderId 设置为 undefined/None/null

exchange.createOrder (symbol, type, side, amount, price, {
    'clientOrderId': '你好',
})
exchange.create_order(symbol, type, side, amount, price, {
    'clientOrderId': '世界',
})
$exchange->create_order($symbol, $type, $side, $amount, $price, array(
    'clientOrderId' => 'Foobar',
))

编辑订单#

要编辑订单,可以使用 editOrder 方法。```javascript editOrder (id, symbol, type, side, amount, price = undefined, params = {})


参数

- **id**(字符串)*必填* 订单ID(例如 `1645807945000`)
- **symbol**(字符串)*必填* 统一的CCXT市场代号
- **side**(字符串)*必填* 订单的方向。
  **统一的方向:**
  - `buy` 给出报价货币并接收基础货币;例如,购买 `BTC/USD` 表示你将用美元购买比特币。
  - `sell` 给出基础货币并接收报价货币;例如,购买 `BTC/USD` 表示你将用比特币换取美元。
- **type**(字符串)*必填* 订单类型
  **统一的类型:**
  - [`market`](市价订单) 一些交易所不允许使用,请参考[它们的文档](#exchanges)了解详情
  - [`limit`](限价订单)
  - 参见#自定义订单参数 和 #其他订单类型来了解非统一的类型
- **amount**(数字)*必填* 你想要交易的货币数量,通常是以交易对的基础货币为单位(某些交易所的单位取决于订单的方向:请参阅其API文档以了解详情)
- **price**(浮点数)订单成交的价格,以报价货币为单位(在市价订单中被忽略)
- **params**(字典)特定交易所API端点的额外参数(例如 `{"settle": "usdt"}`)

返回

- 一个[订单结构](#order-structure)

### 取消订单

要取消现有订单,请使用:

- `cancelOrder()` 取消单个订单
- `cancelOrders()` 取消多个订单
- `cancelAllOrders()` 取消所有未完成的订单

```javascript
cancelOrder(id, symbol = undefined, params = {})

参数- id(字符串)必填 订单ID(例如 1645807945000

  • symbol(字符串)在某些交易所上统一的CCXT市场符号 必填(例如 "BTC/USDT"

  • params(字典)特定于交易所API端点的额外参数(例如 {"settle": "usdt"}

返回值

cancelOrders(ids, symbol = undefined, params = {})

参数

  • ids([字符串])必填 订单ID(例如 1645807945000

  • symbol(字符串)在某些交易所上统一的CCXT市场符号 必填(例如 "BTC/USDT"

  • params(字典)特定于交易所API端点的额外参数(例如 {"settle": "usdt"}

返回值

async cancelAllOrders(symbol = undefined, params = {})

参数- symbol(字符串):在一些交易所上,统一的CCXT市场符号是必需的(例如"BTC/USDT")。

  • params(字典):特定于交易所API端点的额外参数(例如{"settle": "usdt"}

返回值

取消订单时的异常#

cancelOrder()通常仅用于未成交的订单。然而,可能会出现您的订单在取消请求之前已执行(已成交并关闭)的情况,因此取消请求可能会命中已关闭的订单。

取消请求还可能引发NetworkError异常,指示订单可能已经成功取消,也可能未成功取消,以及是否需要重试。对cancelOrder()的连续调用也可能命中已经取消的订单。

因此,在以下情况下,cancelOrder()可能会引发OrderNotFound异常:

  • 取消已关闭的订单

  • 取消已取消的订单

我的交易#

- 统一的API的这部分目前正在开发中
- 可能会有一些问题和一些缺失的实现
- 欢迎贡献、拉请求和反馈

订单如何对应到交易#

订单与交易的关系一个交易通常被称为“成交”。每个交易都是订单执行的结果。请注意,订单和交易之间是一对多的关系:一个订单的执行可能会导致多个交易。然而,当一个订单与另一个相反的订单匹配时,两个匹配订单组成一笔交易。因此,当一个订单匹配多个相反的订单时,会产生多笔交易,每对匹配订单一笔交易。

简而言之,一个订单可以包含一笔或多笔交易。换句话说,一个订单可以被成交一次或多次。

例如,一个订单簿可以包含以下订单(无论是什么交易标志或交易对):

    | 价格   | 数量
----|----------------
  a |  1.200 | 200
  s |  1.100 | 300
  k |  0.900 | 100
----|----------------
  b |  0.800 | 100
  i |  0.700 | 200
  d |  0.500 | 100

上面的所有具体数字都是虚构的,只是为了说明订单和交易的一般关系。

卖家决定在卖方出价0.700、数量为150的盘口上放置一个卖出限价单。

    | 价格   | 数量
----|----------------  ↓
  a |  1.200 | 200     ↓
  s |  1.100 | 300     ↓
  k |  0.900 | 100     ↓
----|----------------  ↓
  b |  0.800 | 100     ↓ 卖出150个,价格为0.700
  i |  0.700 | 200     --------------------
  d |  0.500 | 100

由于卖出(卖方)订单的价格和数量涵盖了多个买入订单(订单bi),以下事件通常会在交易所引擎中很快地但不立即发生:

  1. 订单b与卖出订单匹配,因为它们的价格交叉。它们的数量相互相消,所以投标者以0.800的价格获得100。卖方(询价者)将其卖出订单部分填满,以0.800的价格成交100。请注意,对于订单的已成交部分,卖方获得的价格比他最初要求的价格要好。他至少要求0.7,但实际得到的是0.8,对卖方来说更好。大多数传统交易所按照最优价格成交订单。

  2. 为订单b和卖出订单生成一笔交易。该交易“成交”整个订单b并填满了卖出订单的大部分。每对匹配订单生成一笔交易,无论数量是否完全填满。在这个例子中,卖家的数量(100)完全填满了订单b(关闭了订单b)并部分填满了卖出订单(在订单簿中保留了未成交的部分)。3. 订单 b 现在的状态为 closed,已成交量为100。它包含了一笔与卖单匹配的交易。卖单的状态是 open,已成交量为100。卖单也包含了一笔与订单 b 匹配的交易。因此,每个订单到目前为止只有一笔成交交易。

  3. 进来的卖单已成交数量为100,并且还需要将剩余的50从初始总量150中交易完。

订单簿的中间状态如下(订单 b 已经 closed 并且不再订单簿中):

    | 价格  | 数量
----|----------------  ↓
  a |  1.200 | 200     ↓
  s |  1.100 | 300     ↓
  k |  0.900 | 100     ↓
----|----------------  ↓ 以 0.700 的价格卖出剩余50
  i |  0.700 | 200     -----------------------------
  d |  0.500 | 100
  1. 订单 i 与剩余的卖单部分匹配,因为它们的价格相交。购买订单 i 的数量为200,完全抵消了50的剩余卖单量。订单 i 被部分成交了50,但剩余的150仍然留在订单簿中。然而,这次匹配完全满足了卖单。

  2. 一笔交易产生了,是订单 i 与进来的卖单之间的交易。这笔交易部分成交了订单 i,并完成了卖单的成交。同样,这只是一对匹配订单之间的一笔交易。

  3. 订单 i 现在的状态是 open,已成交数量为50,剩余数量为150。它包含了一笔与卖单匹配的成交交易。卖单现在的状态是 closed,已经完全成交了初始总量150。然而,卖单包含了两笔交易,第一笔是与订单 b 的匹配,第二笔是与订单 i 的匹配。因此,每个订单可能有一个或多个成交交易,取决于它们的交易量如何被交易引擎匹配。

经过上述步骤后,更新的订单簿将会如下所示。

    | 价格  | 数量
----|----------------
  a |  1.200 | 200
  s |  1.100 | 300
  k |  0.900 | 100
----|----------------
  i |  0.700 | 150
  d |  0.500 | 100

请注意,订单 b 已经消失,卖单也不在其中。所有已关闭并完全成交的订单都会从订单簿中消失。订单 i 部分成交但仍然有剩余量和 open 状态,仍然存在于订单簿中。### 个人交易

大多数统一的方法将返回单个对象或对象的纯数组(交易列表)。但是,很少有交易所会一次性返回所有的交易。它们大多数情况下将API的输出限制为最新的一定数量的对象。你不能只用一个API调用从时间的开始获得到现在的所有对象。实际上,很少有交易所会容忍或允许这样做。

与其他用于获取历史数据的统一方法一样,fetchMyTrades方法接受一个since参数来进行日期分页。就像CCXT库中的所有其他统一方法一样,fetchMyTrades方法的since参数必须是一个整数的毫秒级时间戳

为了获取历史交易记录,用户需要以部分或“页面”的方式遍历数据。在循环中通常意味着“逐个获取数据的一部分”。

在许多情况下,交易所的API需要一个symbol参数,因此您必须循环遍历所有符号以获取所有的交易。如果缺少symbol并且交易所要求其存在,那么CCXT将抛出一个ArgumentsRequired异常来向用户表示该要求。然后必须指定symbol。其中一种方法是通过查看非零余额以及交易(提款和存款)从所有符号列表中筛选出相关符号。此外,交易所还会限制您可以查看多远的历史记录。

大多数情况下,用户**需要使用至少一种类型的分页**方法,以确保始终获得预期的结果。

// JavaScript
// fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {})

if (exchange.has['fetchMyTrades']) {
    const trades = await exchange.fetchMyTrades(symbol, since, limit, params)
}
# Python
# fetch_my_trades(symbol=None, since=None, limit=None, params={})

if exchange.has['fetchMyTrades']:
    exchange.fetch_my_trades(symbol=None, since=None, limit=None, params={})
// PHP
// fetch_my_trades($symbol = null, $since = null, $limit = null, $params = array())

if ($exchange->has['fetchMyTrades']) {
    $trades = $exchange->fetch_my_trades($symbol, $since, $limit, $params);
}

返回按时间顺序排序的交易数组 [](最近交易排在最后)。

交易结构#

{
    'info':         { ... },                    // 原始的解码后的 JSON 数据
    'id':           '12345-67890:09876/54321',  // 字符串型交易 ID
    'timestamp':    1502962946216,              // 以毫秒为单位的 Unix 时间戳
    'datetime':     '2017-08-17 12:42:48.000',  // 带有毫秒的 ISO8601 日期时间
    'symbol':       'ETH/BTC',                  // 交易对
    'order':        '12345-67890:09876/54321',  // 字符串型订单 ID 或未定义/空值
    'type':         'limit',                    // 订单类型,'market'(市价), 'limit'(限价)或未定义/空值
    'side':         'buy',                      // 交易的方向,'buy'(买入)或 'sell'(卖出)
    'takerOrMaker': 'taker',                    // 字符串型,'taker'(吃单)或 'maker'(挂单)
    'price':        0.06917684,                 // 以计价货币表示的浮点数价格
    'amount':       1.5,                        // 基础货币的数量
    'cost':         0.10376526,                 // 总成本,`price * amount`
    'fee':          {                           // 由交易所提供或由 ccxt 计算得到的手续费信息
        'cost':  0.0015,                        // 浮点数
        'currency': 'ETH',                      // 对于买入,通常是基础货币;对于卖出,通常是计价货币
        'rate': 0.002,                          // 手续费率(如果有)
    },
    'fees': [                                   // 如果使用多个货币支付费用,则使用一个费用数组
        {                                       // 由交易所提供或由 ccxt 计算得到
            'cost':  0.0015,                    // 浮点数
            'currency': 'ETH',                  // 对于买入,通常是基础货币;对于卖出,通常是计价货币
            'rate': 0.002,                      // 手续费率(如果有)
        },
    ],
}
  • 'fee''fees' 信息的处理仍在进行中,手续费信息可能部分或全部缺失,这取决于交易所的能力。

  • fee 的货币可能与交易的两种货币(例如使用美元支付的 ETH/BTC 订单)不同。

  • 交易的 cost 表示 amount * price。它是交易的 计价 总量(而 amount基础 总量)。cost 字段本身主要是为了方便,可以从其他字段中推导出来。

  • 交易的 cost 是一个“毛利”值。即在手续费前的价值,手续费必须在之后应用。

根据订单 ID 获取交易#

// JavaScript
// fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {})

if (exchange.has['fetchOrderTrades']) {
    const trades = await exchange.fetchOrderTrades (orderId, symbol, since, limit, params)
}
# Python
# fetch_order_trades(id, symbol=None, since=None, limit=None, params={})

if exchange.has['fetchOrderTrades']:
    exchange.fetch_order_trades(order_id, symbol=None, since=None, limit=None, params={})
// PHP
// fetch_order_trades ($id, $symbol = null, $since = null, $limit = null, $params = array())

if ($exchange->has['fetchOrderTrades']) {
    $trades = $exchange->fetch_order_trades($order_id, $symbol, $since, $limit, $params);
}

账本#

账本是用户进行的更改、用户执行的操作或以任何方式改变用户余额的操作的历史记录,即用户所有账户之间的所有资金流动(包括 but 不限于以下内容)

  • 存款和提款(资金)

  • 作为交易或订单结果的金额进出

  • 交易费用

  • 账户之间的转账

  • 折扣、返现和其他需要记账的活动

可以使用以下方法来获取账本条目的数据:

  • fetchLedgerEntry() 获取单个账本条目

  • fetchLedger(code) 获取同一种货币的多个账本条目

  • fetchLedger() 获取所有账本条目

fetchLedgerEntry(id, code = undefined, params = {})

参数- id(字符串)必需 账本条目ID

  • code(字符串) 统一的CCXT货币代码,必需(例如 "USDT"

  • params(字典)特定于交易所API端点的参数(例如 {"type": "deposit"}

返回值

async fetchLedger (code = undefined, since = undefined, limit = undefined, params = {})

参数

  • code(字符串) 统一的CCXT货币代码;如果不支持一次获取所有资产的所有账本条目,则必需(例如 "USDT"

  • since(整数) 用于检索提款的最早时间的时间戳(毫秒)(例如 1646940314000

  • limit(整数) 要检索的账本条目结构的数量(例如 5

  • params(字典)特定于交易所API端点的参数(例如 {"endTime": 1645807945000}

返回值

账本条目结构#

{
    'id': 'hqfl-f125f9l2c9',                // 账本条目的字符串ID,例如订单ID
    'direction': 'out',                     // 或'in'
    'account': '06d4ab58-dfcd-468a',        // 如果有的话,账户的字符串ID
    'referenceId': 'bf7a-d4441fb3fd31',     // 交易、事务等的字符串ID
    'referenceAccount': '3146-4286-bb71',   // 对方账户的字符串ID(如果有)
    'type': 'trade',                        // 字符串,参考类型,见下文
    'currency': 'BTC',                      // 字符串,统一货币代码,'ETH','USDT'等等。。。
    'amount': 123.45,                       // 绝对值,浮点数(不包括手续费)
    'timestamp': 1544582941735,             // 以UTC的千分之一秒为单位的毫秒时间戳
    'datetime': "2018-12-12T02:49:01.735Z", // 时间戳的字符串,ISO8601
    'before': 0,                            // 余额变动之前的货币数量
    'after': 0,                             // 余额变动之后的货币数量
    'status': 'ok',                         // 'ok, 'pending', 'canceled'
    'fee': {                                // 对象或未定义
        'cost': 54.321,                     // 绝对值,额外的费用
        'currency': 'ETH',                  // 字符串,统一货币代码,'ETH','USDT'等等。。。
    },
    'info': { ... },                        // 原始的账本条目,和来自交易所的一样
}
```#### 关于账本条目结构的注意事项

账本条目的类型与其关联的操作类型相同。如果金额来自于卖单,则与相应的交易类型的账本条目相关联,并且`referenceId`字段将包含相关的交易ID(如果所涉及的交易所提供)。如果金额来自于提现,则与相应的交易相关联。

- `trade`(交易)
- `transaction`(交易)
- `fee`(手续费)
- `rebate`(返利)
- `cashback`(返现)
- `referral`(推荐)
- `transfer`(转账)
- `airdrop`(空投)
- `whatever`(其他)
- ...

`referenceId`字段保存了通过向账本添加新项进行注册的相应事件的ID。

`status`字段用于支持将待处理和已取消的更改包括在账本中的交易所。账本自然表示已经发生的实际更改,因此在大多数情况下,状态为`'ok'`。

账本条目类型可以与常规交易或资金交易(存款或提款)或同一用户的两个帐户之间的内部`转账`相关联。如果账本条目与内部转账相关联,则`account`字段将包含被该账本条目更改的帐户的ID。`referenceAccount`字段将包含资金转入或转出的相反帐户的ID,具体取决于`方向`(`'in'`或`'out'`)。

## 存款

为了将资金存入交易所,您必须从交易所获取要存入的货币的地址。大多数交易所都会为用户创建和管理这些地址。

可以使用以下方法检索有关存入账户的数据:

- `fetchDeposit()` 用于单个存款
- `fetchDeposits(code)` 用于相同货币的多个存款
- `fetchDeposits()` 用于账户的所有存款```javascript
fetchDeposit (id, code = undefined, params = {})

参数

  • id (String) 必需 存款id

  • code (String) 统一CCXT货币代码,必需 (例如 "USDT")

  • params (字典) 特定于交易所API端点的参数 (例如 {"network": "TRX"})

返回值

fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {})

参数

  • code (String) 统一CCXT货币代码 (例如 "USDT")

  • since (Integer) 最早的存款时间戳(以毫秒为单位) (例如 1646940314000)

  • limit (Integer) 要检索的交易结构体的数量 (例如 5)

  • params (字典) 特定于交易所API端点的参数 (例如 {"endTime": 1645807945000})

返回值

withdraw 方法可用于从账户中提取资金。

一些交易所要求通过两步验证(2FA)手动批准每笔提现。为了批准您的提现,通常您需要在电子邮件收件箱中点击他们的秘密链接,或者在他们的网站上输入 Google Authenticator 代码或 Authy 代码,以验证提取交易是否是有意请求的。

在某些情况下,您还可以使用提现 ID 以后检查提现状态(是否成功),并提交两步验证确认代码(如果交易所支持)。有关详细信息,请参阅他们的文档

// JavaScript
withdraw (code, amount, address, tag = undefined, params = {})
# Python
withdraw(code, amount, address, tag=None, params={})
// PHP
withdraw ($code, $amount, $address, $tag = null, $params = array ())

参数

  • code (String) 必填 统一的CCXT货币代码(例如,"USDT"

  • amount (Float) 必填 要提取的货币数量(例如,20

  • address (String) 必填 提现的接收地址(例如,"TEY6qjnKDyyq5jDc3DJizWLCdUySrpQ4yp"

  • tag (String) 某些网络需要(例如,"52055"

  • params (Dictionary) 特定于交易所API端点的参数(例如,{"network": "TRX"}

返回值- 交易结构


可以使用以下方式获取有关账户提款的数据:

  • 对于单个提款,可以使用 fetchWithdrawal ()

  • 对于相同货币的多个提款,可以使用 fetchWithdrawals ( code )

  • 对于账户的所有提款,可以使用 fetchWithdrawals ()

fetchWithdrawal (id, code = undefined, params = {})

参数

  • id (字符串) 必填 提款 id

  • code (字符串) 统一的 CCXT 货币代码(例如 "USDT"

  • params (字典) 特定于交易所 API 端点的参数(例如 {"network": "TRX"}

fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {})

参数

  • code (字符串) 统一的 CCXT 货币代码(例如 "USDT"

  • since (整数) 检索提款的最早时间戳(毫秒)(例如 1646940314000

  • limit (整数) 要检索的交易结构的数量(例如 5

  • params (字典) 特定于交易所 API 端点的参数(例如 {"endTime": 1645807945000})返回

  • 一个交易结构的数组

存款和提款网络#

您还可以将参数作为第四个参数传递,可以带有指定的标签,也可以没有指定标签

// JavaScript
withdraw (code, amount, address, { tag, network: 'ETH' })
# Python
withdraw(code, amount, address, { 'tag': tag, 'network': 'ETH' })
// PHP
withdraw ($code, $amount, $address, array( 'tag' => tag, 'network' -> 'ETH' ));

以下network的别名可用于在多个链上提取加密货币

货币

网络

ETH

ERC20

TRX

TRC20

BSC

BEP20

BNB

BEP2

HT

HECO

OMNI

OMNI

您可以设置exchange.withdraw ('USDT', 100, 'TVJ1fwyJ1a8JbtUxZ8Km95sDFN9jhLxJ2D', { 'network': 'TRX' })以在TRON链上提取USDT,或者设置’BSC’以在币安智能链上提取USDT。在上面的表格中,BSC和BEP20是等效的别名,因此无论您使用哪个,都可以达到相同的效果。### 交易结构

  • 存款结构

  • 提款结构

{
    'info':      { ... },    // 来自交易所的JSON响应
    'id':       '123456',    // 交易所特定的交易ID,字符串
    'txid':     '0x68bfb29821c50ca35ef3762f887fd3211e4405aba1a94e448a4f218b850358f0',
    'timestamp': 1534081184515,             // 时间戳(以毫秒为单位)
    'datetime': '2018-08-12T13:39:44.515Z', // 时间戳的ISO8601字符串
    'addressFrom': '0x38b1F8644ED1Dbd5DcAedb3610301Bf5fa640D6f', // 发送方
    'address':  '0x02b0a9b7b4cDe774af0f8e47cb4f1c2ccdEa0806', // “来自”或者“到”
    'addressTo': '0x304C68D441EF7EB0E2c056E836E8293BD28F8129', // 接收方
    'tagFrom', '0xabcdef', // 与发送方相关的“标签”、“备注”或“付款ID”
    'tag':      '0xabcdef' // 与地址相关的“标签”、“备注”或“付款ID”
    'tagTo': '0xhijgklmn', // 与接收方相关的“标签”、“备注”或“付款ID”
    'type':     'deposit',   // 或者 'withdrawal',字符串
    'amount':    1.2345,     // 数量(不包括手续费),浮点数
    'currency': 'ETH',       // 通用的货币代码,字符串
    'status':   'pending',   // 'ok'、'failed'、'canceled',字符串
    'updated':   undefined,  // 最近更改状态的UTC时间戳(以毫秒为单位)
    'comment':  '如果有,由用户定义的评论或消息',
    'fee': {                 // 整个手续费结构可能不存在
        'currency': 'ETH',   // 通用的手续费货币代码
        'cost': 0.1234,      // 浮点数
        'rate': undefined,   // 按比例,手续费['cost'] / 数量,浮点数
    },
}

交易结构注意事项#

  • 如果对应的交易所不指定交易的双方,则addressFromaddressTo可能为undefinedNonenull

  • address字段的语义是与交易所相关的。在某些情况下,它可能包含发送方的地址,而在其他情况下可能包含接收方的地址。实际的值取决于交易所。

  • updated字段是指与该资金操作的状态最近更改相关的UTC时间戳,不论是“提款”还是“存款”。如果您想要跟踪时间上的更改,超过静态快照的话,这是必需的。例如,如果对应的交易所为交易报告了created_atconfirmed_at,那么updated字段将取值为Math.max(created_at, confirmed_at),即状态最近更改的时间戳。

  • 在某些交易所特定的情况下,updated字段可以为undefinedNonenull

  • 如果来自交易所的回复中没有提供fee子结构,则可能会缺少fee子结构。

  • comment字段可以为undefinedNonenull,否则它将包含由用户在创建交易时定义的消息或注释。

  • 在处理tagaddress时要小心。tag不是任意用户自定义的字符串!不能在tag中发送用户消息和注释。tag字段的目的是正确地标识您的钱包,因此它必须是正确的。您应该仅使用来自您正在使用的交易所的tag,否则您的交易可能永远无法到达目的地。

获取存款示例#

// JavaScript
// fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {})

if (exchange.has['fetchDeposits']) {
    const deposits = await exchange.fetchDeposits (code, since, limit, params)
} else {
    throw new Error (exchange.id + '不具有fetchDeposits方法')
}
# Python
# fetch_deposits(code = None, since = None, limit = None, params = {})

if exchange.has['fetchDeposits']:
    deposits = exchange.fetch_deposits(code, since, limit, params)
else:
    raise Exception (exchange.id + '不具有fetch_deposits方法')
// PHP
// fetchTransactions ($code = null, $since = null, $limit = null, $params = {})

if ($exchange->has['fetchTransactions']) {
    $transactions = $exchange->fetchTransactions ($code, $since, $limit, $params);
} else {
    throw new Exception ($exchange->id . ' does not have the fetchTransactions method');
}

fetchWithdrawals Examples#

// JavaScript
// fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {})

if (exchange.has['fetchTransactions']) {
    const transactions = await exchange.fetchTransactions (code, since, limit, params)
} else {
    throw new Error (exchange.id + ' does not have the fetchTransactions method')
}
# Python
# fetch_transactions(code = None, since = None, limit = None, params = {})

if exchange.has['fetchTransactions']:
    transactions = exchange.fetch_transactions(code, since, limit, params)
else:
    raise Exception (exchange.id + ' does not have the fetch_transactions method')
// PHP
// fetch_transactions ($code = null, $since = null, $limit = null, $params = {})

if ($exchange->has['fetchTransactions']) {
    $transactions = $exchange->fetch_transactions ($code, $since, $limit, $params);
} else {
    throw new Exception ($exchange->id . ' does not have the fetch_transactions method');
}

fetchTransactions Examples#

// JavaScript
// fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {})

if (exchange.has['fetchTransactions']) {
    const transactions = await exchange.fetchTransactions (code, since, limit, params)
} else {
    throw new Error (exchange.id + ' does not have the fetchTransactions method')
}
# Python
# fetch_transactions(code = None, since = None, limit = None, params = {})

if exchange.has['fetchTransactions']:
    transactions = exchange.fetch_transactions(code, since, limit, params)
else:
    raise Exception (exchange.id + ' does not have the fetch_transactions method')
// PHP
// fetch_transactions ($code = null, $since = null, $limit = null, $params = {})

if ($exchange->has['fetchTransactions']) {
    $transactions = $exchange->fetch_transactions ($code, $since, $limit, $params);
} else {
    throw new Exception ($exchange->id . ' does not have the fetch_transactions method');
}

存款地址#

存款地址可以是之前与交易所创建的已存在地址,也可以根据需求创建。若要查看支持哪种方法,请检查 exchange.has['fetchDepositAddress']exchange.has['createDepositAddress'] 属性。

fetchDepositAddress (code, params = {})
createDepositAddress (code, params = {})

参数- code(字符串)必填 统一的CCXT货币代码(例如 "USDT"

  • params(字典)与交易所API端点相关的参数(例如 {"endTime": 1645807945000}

返回


一些交易所也可能有一种一次性获取多个存款地址或所有存款地址的方法。

fetchDepositAddresses (codes = undefined, params = {})

参数

  • code([字符串])统一的CCXT货币代码数组。根据交易所的要求可能需要或不需要(例如 ["USDT", "BTC"]

  • params(字典)与交易所API端点相关的参数(例如 {"endTime": 1645807945000}

返回

  • 地址结构数组```javascript fetchDepositAddressesByNetwork (code, params = {})


参数

- **code** (字符串) *必填* 统一的 CCXT 货币代码(例如 `"USDT"`)
- **params** (字典) 交易所 API 端点特定的参数(例如 `{"endTime": 1645807945000}`)

返回值

- 一个[地址结构的数组](#地址结构)

### 地址结构

从 `fetchDepositAddress`、`fetchDepositAddresses`、`fetchDepositAddressesByNetwork` 和 `createDepositAddress` 返回的地址结构如下所示:

```javascript
{
    'currency': currency, // 货币代码
    'network': network,   // 存取款网络列表,ERC20、TRC20、BSC20 (参见下文)
    'address': address,   // 以所请求货币表示的地址
    'tag': tag,           // 特定货币的标签、备注或付款ID(XRP、XMR 等)
    'info': response,     // 作为从交易所返回的未解析的原始数据
}

对于某些货币,如 AEON、BTS、GXS、NXT、SBD、STEEM、STR、XEM、XLM、XMR、XRP,交易所通常需要附加参数 tag。其他货币的 tag 会设置为 undefined / None / nulltag 是附加到提款交易的便函、消息或付款 ID。对于这些货币,tag 是必需的,并且它能够标识收款人用户账户。

请注意,在指定 tagaddress 时要小心。tag 不是你随意选择的任意用户定义字符串!你不能在 tag 中发送用户消息和评论。tag 字段的目的是正确地定位你的钱包,所以它必须是正确的。你应该仅使用你所使用的交易所接收到的 tag,否则你的交易可能永远不会到达目的地。network字段相对较新,在某些情况下(某些交易所)可能为undefined / None / null或完全缺失,但它最终将被添加到所有地方。它仍在统一的过程中。

转账#

transfer方法在同一交易所的账户之间进行资金的内部转账。这可以包括子账户或不同类型的账户(spotmarginfuture等)。如果交易所在CCXT中被区分为现货和期货类别(例如binanceusdmkucoinfutures,…),则可能会提供transferIn方法来将资金转入期货账户,可能会提供transferOut方法来将资金从期货账户转出。

transfer (code, amount, fromAccount, toAccount, params = {})

参数

  • code(字符串)统一的CCXT货币代码(例如"USDT"

  • amount(浮点数)要转账的货币数量(例如10.5

  • fromAccount(字符串)要从中转账的账户。

  • toAccount(字符串)要转账至的账户。

  • params(字典)特定于交易所API端点的参数(例如{"endTime": 1645807945000}

  • params.symbol(字符串)在转入或转出保证金账户时的市场代码(例如'BTC/USDT'

账户类型#

fromAccounttoAccount可以接受交易所账户ID或以下统一值之一:

  • funding 对某些交易所而言,fundingspot是同一个账户

  • main 对某些允许子账户的交易所

  • spot

  • margin

  • future

  • swap

  • lending

您可以通过从exchange.options['accountsByType']中选择键来检索所有账户类型。一些交易所允许通过电子邮件地址、电话号码或通过用户ID向其他用户进行转账。

返回值

transferIn (code, amount, params = {})
transferOut (code, amount, params = {})

参数

  • code (字符串) 统一的 CCXT 货币代码(例如:”USDT”)

  • amount (浮点数) 要转账的货币数量(例如:10.5)

  • params (字典) 与交易所 API 端点相关的参数(例如:{“endTime”: 1645807945000})

返回值

fetchTransfers (code = undefined, since = undefined, limit = undefined, params = {})

参数- code(String):统一的CCXT货币代码(例如"USDT"

  • since(Integer):要检索转账操作的最早时间戳(以毫秒为单位)(例如1646940314000

  • limit(Integer):要检索的转账结构的数量(例如5

  • params(Dictionary):特定于交易所API端点的参数(例如{"endTime": 1645807945000}

返回结果

fetchTransfer (idsince = undefinedlimit = undefinedparams = {})

参数

  • id(String):转账ID(例如"12345"

  • since(Integer):要检索转账操作的最早时间戳(以毫秒为单位)(例如1646940314000

  • limit(Integer):要检索的转账结构的数量(例如5

  • params(Dictionary):特定于交易所API端点的参数(例如{"endTime": 1645807945000}

返回结果

转账结构#

{
    info: { ... },
    id: "93920432048",
    timestamp: 1646764072000,
    datetime: "2022-03-08T18:27:52.000Z",
    currency: "USDT",
    amount: 11.31,
    fromAccount: "spot",
    toAccount: "future",
    status: "ok"
}

费用#

Unified CCXT API 正在开发的这个部分。

费用通常分为两类:

  • 交易费用。交易费是要支付给交易所的金额,通常是交易量(成交量)的百分比。

  • 交易费用。在存款和提款以及底层加密货币交易中支付给交易所的金额(tx费用)。

由于费用结构可以根据用户交易的实际货币量而变化,所以费用可能是针对特定账户的。处理账户特定费用的方法有:

fetchFees (params = {})
fetchTradingFee (symbol, params = {})
fetchTradingFees (params = {})
fetchTransactionFee (code, params = {})
fetchTransactionFees (codes  = undefined, params = {})

费用方法将返回统一的费用结构,在订单和交易中也经常出现。费用结构是表示库中的费用信息的常用格式。费用结构通常按市场或货币进行索引。

由于这仍然是一个正在进行中的工作,本节中描述的方法和信息可能会在这个或那个交易所中缺失。

请勿使用交易所实例的 .fees 属性,因为它通常包含预定义/硬编码的信息。实际费用应该只从市场和货币中访问。

fetchFees 方法将自动调用 fetchTradingFeesfetchTransactionFees 来获取所有的费用信息。你可以调用 fetchTradingFeesfetchTransactionFees 来更精确地控制对交易所上的哪个端点发出请求。

费用结构#

订单、私人交易、交易和账本条目可能在其fee字段中定义以下信息:

{
    'currency': 'BTC', // 统一的手续费货币代码
    'rate': percentage, // 手续费率,0.05% = 0.0005,1% = 0.01,...
    'cost': feePaid, // 手续费成本(数量 * 手续费率)
}

费率表#

fetchFees (params = {})
{
    'funding': {
        'withdraw': {
            'BTC': 0.00001,
            'ETH': 0.001,
            'LTC': 0.0003,
        },
        'deposit': {
            'BTC': 0,
        },
        'info': { ... },
    },
    'trading': {
        'ETH/BTC': {
            'maker': 0.001,
            'taker': 0.002,
            'info': { ... },
            'symbol': 'ETH/BTC',
        },
        'LTC/BTC': {
            'maker': 0.001,
            'taker': 0.002,
            'info': { ... },
            'symbol': 'LTC/BTC',
        },
    },
}

交易费用#

交易费用是市场的属性。大部分情况下,交易费用通过fetchMarkets调用从市场中加载。然而,有时交易所会从不同的终端提供费用。

calculateFee方法可用于预计将支付的交易费用。**警告!此方法属于实验性质,不稳定,并且在某些情况下可能产生错误的结果。**您应该小心使用它。实际费用可能与calculateFee返回的值不同,这仅用于预计。请不要依赖预计值,因为市场条件经常变化。很难预先知道您的订单是市场的接单方还是挂单方。

    calculateFee (symbol, type, side, amount, price, takerOrMaker = 'taker', params = {})

calculateFee方法将返回一个统一的费率结构,其中包含指定参数的预计费用。访问交易费率应通过.markets属性进行,如下所示:

exchange.markets['ETH/BTC']['taker'] // ETH/BTC的taker手续费率
exchange.markets['BTC/USD']['maker'] // BTC/USD的maker手续费率

存储在.markets属性下的交易市场可能包含其他与费用相关的信息:

{
    'taker': 0.002,   // taker手续费率,0.002 = 0.2%
    'maker': 0.0016,  // maker手续费率,0.0016 = 0.16%
    'percentage': true, // taker和maker手续费率是否是乘法器还是固定的金额
    'tierBased': false, // 费用是否根据您的交易等级(交易量)而定

    'tiers': {
        'taker': [
            [0, 0.0026], // 元组(以美元计量的交易量,taker手续费)按增加的交易量顺序排列
            [50000, 0.0024],
            ...
        ],
        'maker': [
            [0, 0.0016], // 元组(以美元计量的交易量,maker手续费)按增加的交易量顺序排列
            [50000, 0.0014],
            ...
        ],
    },
}

警告!与费用相关的信息为实验性的、不稳定的,可能只能部分使用或根本不可用。

当您向交易所提供流动性(即您设置市价单,并有其他人填充它)时,会支付maker手续费。maker手续费通常较低。同样,当您从交易所获取流动性并填充他人的订单时,会支付taker手续费。

费用可以是负值,在衍生品交易所中非常常见。负费用意味着交易所将向用户支付退款(奖励)。

此外,一些交易所可能不会将费用指定为交易量的百分比,请务必检查市场的percentage字段以确保。

Trading Fee Schedule#

一些交易所提供了用于获取交易费率的端点,这被映射为统一方法 fetchTradingFeesfetchTradingFee

fetchTradingFee (symbol, params = {})

参数

  • symbol (字符串) 必需 统一的市场符号(例如 "BTC/USDT"

  • params (字典) 交易所 API 端点特定的参数 (例如 {"currency": "quote"})

返回值

fetchTradingFees (params = {})

参数

  • params (字典) 交易所 API 端点特定的参数 (例如 {"currency": "quote"})

返回值- 一个包含交易手续费结构的数组

交易手续费结构#

{
    'ETH/BTC': {
        'maker': 0.001,
        'taker': 0.002,
        'info': { ... },
        'symbol': 'ETH/BTC',
    },
    'LTC/BTC': {
        'maker': 0.001,
        'taker': 0.002,
        'info': { ... },
        'symbol': 'LTC/BTC',
	},
}

交易手续费#

交易手续费是货币(账户余额)的属性。

通过.currencies属性来获取交易手续费率。这个方面尚未统一,可能会发生变化。

exchange.currencies['ETH']['fee'] // ETH的交易/提现手续费率
exchange.currencies['BTC']['fee'] // BTC的交易/提现手续费率

交易手续费计划#

一些交易所有一个用于获取交易手续费计划的端点,这会映射到统一的方法中:

  • fetchTransactionFee () 用于获取单个交易手续费计划

  • fetchTransactionFees () 用于获取所有交易手续费计划```javascript fetchTransactionFee (code, params = {})


参数

- **code** (String) *required* 统一的CCXT货币代码,必填 (例如 `"USDT"`)
- **params** (Dictionary) 该交易所API端点特定的参数 (例如 `{"type": "deposit"}`)
- **params.network** (String) 指定统一的CCXT网络 (例如 `{"network": "TRC20"}`)

返回值

- 一个 [交易费用结构体](#transaction-fee-structure) 

```javascript
fetchTransactionFees (codes = undefined, params = {})

参数

  • params (Dictionary) 该交易所API端点特定的参数 (例如 {"type": "deposit"})

返回值

{
    'withdraw': {
        'BTC': 0.00001,
        'ETH': 0.001,
        'LTC': 0.0003,
    },
    'deposit': {
        'BTC': 0,
    },
    'info': { ... },
}

借款利息#

  • 仅限杠杆交易

在现货或保证金交易市场进行杠杆交易时,必须以贷款方式借入货币。这笔借入的货币必须带有利息归还。您可以使用fetchBorrowInterest方法获取已产生的利息量。

fetchBorrowInterest (code = undefined, symbol = undefined, since = undefined, limit = undefined, params = {})

参数

  • code(字符串)利息的货币统一代码(例如 "USDT"

  • symbol(字符串)孤立保证金市场的市场符号,如果未定义,则返回跨保证金市场的利息(例如 "BTC/USDT:USDT"

  • since(整数)收到利息记录的最早时间戳(毫秒)(例如 1646940314000

  • limit(整数)要检索的借款利息结构的数量(例如 5

  • params(字典)特定于交易所API端点的参数(例如 {"endTime": 1645807945000}

返回结果

{
    account: 'BTC/USDT',                    // 借贷利息所对应的交易对
    currency: 'USDT',                       // 借贷利息的货币类型
    interest: 0.00004842,                   // 所收取的利息金额
    interestRate: 0.0002,                   // 借贷利息率
    amountBorrowed: 5.81,                   // 借入的货币数量
    timestamp: 1648699200000,               // 收取利息的时间戳
    datetime: '2022-03-31T04:00:00.000Z',   // 收取利息的日期时间
    info: { ... }                           // 未解析的交易所返回信息
}

借贷和还款保证金#

仅适用于保证金交易

可以使用borrowMarginrepayMargin来借入和还款货币作为保证金贷款。

borrowMargin (code, amount, symbol = undefined, params = {})
repayMargin (code, amount, symbol = undefined, params = {})

参数

  • code (String) 必需 要借入或还清的货币的统一货币代码 (例如:“USDT”)

  • amount (Float) 必需 要借入或还清的保证金数量 (例如:20.92)

  • symbol (String) 一个隔离保证金市场的统一CCXT市场符号 (例如:“BTC/USDT”)

  • params (Dictionary) 特定于交易所API端点的参数 (例如:{“rate”: 0.002})

返回值

保证金贷款结构#

{
    id: '1234323',                          // 整数,交易 ID
    currency: 'USDT',                       // 字符串,被借出或偿还的货币
    amount: 5.81,                           // 浮点数,借出或偿还的货币数量
    symbol: 'BTC/USDT:USDT',                // 字符串,统一的市场交易对
    timestamp: 1648699200000,               // 整数,交易的时间戳
    datetime: '2022-03-31T04:00:00.000Z',   // 字符串,交易的日期时间
    info: { ... }                           // 未解析的交易所响应
}

杠杆#

仅适用于杠杆交易和合约交易

要在已开设的杠杆交易仓位中增加、减少或设置您的保证金余额,可以使用 addMarginreduceMarginsetMargin 方法。这有点像调整您在已打开仓位上使用的杠杆量。

一些使用这些方法的场景包括:

  • 如果交易不利于您,您可以增加保证金,减少清算风险

  • 如果您的交易表现良好,您可以减少仓位的保证金余额并获利

addMargin (symbol, amount, params = {})
reduceMargin (symbol, amount, params = {})
setMargin (symbol, amount, params = {})

参数

  • symbol(字符串)必填 统一的 CCXT 市场交易对(例如 "BTC/USDT:USDT"

  • amount(字符串)必填 要增加或减少的保证金数量(例如 20

  • params(字典)特定于交易所 API 端点的参数(例如 {"leverage": 5}

返回值

{
    info: { ... },
    type: 'add', // 'add', 'reduce', 'set'
    amount: 1, // 被添加、减少或设置的数量
    total: 2,  // 交易所未指定时的总保证金或未指定
    code: 'USDT',
    symbol: 'XRP/USDT:USDT',
    status: 'ok'
}

保证金模式#

仅适用于保证金和合约

更新所使用的保证金类型为以下之一:

  • 交叉 在多个市场间共享抵押品的一个账户。在需要时,从总账户余额中拿取保证金以避免强制平仓。

  • 分离 每个市场将抵押品保留在特定的账户内

setMarginMode (marginMode, symbol = undefined, params = {})

参数

  • marginMode (String) 必填 所使用的保证金类型 统一的保证金类型:

    • "交叉"

    • "分离"

  • symbol (String) CCXT 统一市场交易对符号(例如 "BTC/USDT:USDT"必填 大多数交易所都要求填写。当保证金模式不特定于某个市场时,此参数不是必填项。

  • params (Dictionary) 特定于交易所 API 端点的参数(例如 {"leverage": 5}

返回值- 交易所的回应

没有setMarginMode的交易所#

交易所可能没有setMarginMode的常见原因包括:

exchange.has['setMarginMode'] == false
  • 该交易所不提供杠杆交易

  • 该交易所只提供 crossisolated 两种保证金模式中的一种,而不同时提供两种

  • 使用 createOrder 时,必须使用交易所特定的 params 参数来设置保证金模式

关于setMarginMode的错误抑制#

某些交易所 API 在收到将保证金模式设置为已有的模式(例如,在已将 BTC/USDT:USDT 设置为使用交叉保证金后,发送请求将保证金模式设置为 cross)时返回错误响应。CCXT 不将此视为错误,因为最终结果是用户想要的,所以错误被抑制,将错误结果作为对象返回。

例如:

{ code: -4046, msg: 'No need to change margin type.' }

杠杆#

仅限保证金和合约

setLeverage (leverage, symbol = undefined, params = {})

参数

  • leverage(整数)必填 所需杠杆

  • symbol(字符串)统一的CCXT市场符号(例如 "BTC/USDT:USDT"大多数交易所必填。当杠杆没有特定的市场时不需要填写(例如在FTX上不需要填写,因为杠杆是针对账户而不是每个市场设置的)

  • params(字典)与交易所API端点特定的参数(例如 {"marginMode": "cross"}

返回值

  • 交易所的响应

合约交易#

这可以包括具有设定到期日的期货、具有资金支付功能的永续互换,以及反向期货或互换。关于头寸的信息可以从不同的端点提供,具体取决于交易所。在存在多个端点提供不同类型的衍生品的情况下,CCXT会默认加载”线性”(相对于”反向”)合约或”互换”(相对于”期货”)合约。

仓位#

仅合约

要获取有关当前在合约市场上持有的头寸的信息,请使用以下函数:

  • fetchPosition() // 获取单个市场的头寸

  • fetchPositions() // 获取所有头寸

  • fetchAccountPositions() // TODO

fetchPosition(symbol, params = {})                         // 获取单个市场的头寸

参数

  • symbol (字符串) 必填 统一的CCXT市场代号 (例如 "BTC/USDT:USDT")

  • params (字典) 特定于交易所API端点的参数 (例如 {"endTime": 1645807945000})

返回值

fetchPositions(symbols = undefined, params = {})
fetchAccountPositions(symbols = undefined, params = {})

参数- symbols([字符串])统一的CCXT市场符号,不设置以检索所有仓位(例如,["BTC/USDT:USDT"]

  • params(字典)特定于交易所API端点的参数(例如,{"endTime": 1645807945000}

返回

仓位结构#

{
   'info': { ... },             // 从交易所返回的原样的JSON响应
   'id': '1234323',             // 字符串,参考仓位的仓位ID,类似于订单ID
   'symbol': 'BTC/USD',         // 大写字符串,一对货币的文字
   'timestamp': 1607723554607,  // 整数,从1970年1月1日开始的Unix时间(毫秒)
   'datetime': '2020-12-11T21:52:34.607Z',  // Unix时间的ISO8601表示
   'isolated': true,            // 布尔值,仓位是否为孤立的,相对于自动添加保证金的交叉仓位而言
   'hedged': false,             // 布尔值,仓位是否已对冲,即如果按相反方向交易将关闭该仓位还是开设新仓位
   'side': 'long',              // 字符串,多头或空头
   'contracts': 5,              // 浮点数,购买的合约数量,即仓位的金额或大小
   'contractSize': 100,         // 浮点数,报价单位中的一个合约的大小
   'entryPrice': 20000,         // 浮点数,仓位的平均入场价格
   'markPrice': 20050,          // 浮点数,用于资金计算的价格
   'notional': 100000,          // 浮点数,以结算货币计量的仓位价值
   'leverage': 100,             // 浮点数,仓位的杠杆,与给定的担保品数量可以购买多少合约有关
   'collateral': 5300,          // 浮点数,可以损失的最大担保品金额,受盈亏影响
   'initialMargin': 5000,       // 浮点数,锁定在该仓位中的担保品数量
   'maintenanceMargin': 1000,   // 浮点数,避免被强制平仓所需的最小担保品金额
   'initialMarginPercentage': 0.05,      // 浮点数,initialMargin占notional的百分比
   'maintenanceMarginPercentage': 0.01,  // 浮点数,maintenanceMargin占notional的百分比
   'unrealizedPnl': 300,        // 浮点数,市价与入场价格的差乘以合约数量的差异,可能为负数
   'liquidationPrice': 19850,   // 浮点数,担保品低于maintenanceMargin时的价格
   'marginMode': 'cross',       // 字符串,可以是cross或isolated
   'percentage': 3.32,          // 浮点数,表示unrealizedPnl / initialMargin * 100
}

仓位允许您从交易所借钱来进行多头或空头交易。有些交易所要求您支付资金费用以保持仓位开放。

当您开多头仓位时,您打赌价格在未来会上涨,并且价格永远不会低于“强制平仓价格”。

随着基础指数价格的变动,未实现盈亏也会随之变化,同样影响到仓位中剩余的担保品(因为您只能以市价或更差的价格平仓)。在某个价格点上,您将没有剩余的担保品,这被称为“破产”或“零”价格。超过这个点,如果价格朝相反方向变动足够远,仓位的担保品将低于“维持保证金”。维持保证金在您的仓位和负担保品之间起到安全缓冲的作用,情况下交易所将代表您承担损失,迅速清算您的仓位。即使价格回升到还清价格以上,您也不会收回您的资金,因为交易所以市价卖出您以市价购买的contracts。换句话说,维持保证金是借款的隐藏费用。

建议使用maintenanceMargininitialMargin而不是maintenanceMarginPercentageinitialMarginPercentage,因为前者更准确。维持保证金可能是根据维持保证金百分比之外的其他因素计算的,包括资金费率和Taker费用,例如在kucoin上。

反向合约将允许您通过以BTC作为担保品进行多头或空头交易BTC/USD。我们的反向合约API与线性合约的API相同。反向合约中的金额以USD/BTC交易的形式进行报价,但价格仍以BTC/USD的形式进行报价。反向合约的盈亏和担保品将以BTC进行报价,合约数量以USD进行报价。

强制平仓价格#

这是 initialMargin + unrealized = collateral = maintenanceMargin 的价格。价格已经朝着与您的头寸相对的方向走了,只剩下 maintenanceMargin 的抵押品,如果价格再下跌,头寸将会有负面抵押品。

// 如果多头
(强平价格 - 价格) * 合约数 = 维持保证金

// 如果空头
(价格 - 强平价格) * 合约数 = 维持保证金
// 如果反向多头
(1/强平价格 - 1/价格) * 合约数 = 维持保证金

// 如果反向空头
(1/价格 - 1/强平价格) * 合约数 = 维持保证金

资金费用历史记录#

仅适用于合约

永续互换(也称为永续期货)合约维持与其基于的资产价格相一致的市场价格,因为永续互换市场中的交易者之间交换资金费用。

如果合约的交易价格高于其所代表的资产价格,则多头持仓的交易者在特定时间向空头持仓的交易者支付资金费用,在此之前鼓励更多的交易者进入空头持仓。

如果合约的交易价格低于其所代表的资产价格,则空头持仓的交易者在特定时间向多头持仓的交易者支付资金费用,在此之前鼓励更多的交易者进入多头持仓。

这些费用通常在交易者之间交换,没有任何佣金归交易所所有。fetchFundingHistory方法可用于检索帐户支付或接收的资金费用的历史记录。

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

参数

  • symbol (String) 统一的CCXT市场交易对符号(例如 "BTC/USDT:USDT"

  • since (Integer) 检索资金历史记录的最早时间戳(毫秒)(例如 1646940314000

  • limit (Integer) 要检索的funding history structures数量(例如 5

  • params (Dictionary) 特定于交易所API端点的参数(例如 {"endTime": 1645807945000}

返回

资金历史记录结构#

{
    info: { ... },
    symbol: "XRP/USDT:USDT",
    code: "USDT",
    timestamp: 1646954920000,
    datetime: "2022-03-08T16:00:00.000Z",
    id: "1520286109858180",
    amount: -0.027722
}

代理#

在某些特定情况下,您可能需要使用代理,例如:

  • 交易所在您所在的地区不可用

  • 您的IP被交易所禁止

  • 您经历了随机限制,例如 Cloudflare的DDoS保护然而,请注意每个中间人可能会增加请求的延迟。

支持的代理类型#

CCXT支持以下代理类型:

proxyUrl#

该属性会在API请求之前添加一个url。这也可以用来设置一个CORS代理。

ex = ccxt.binance({'proxyUrl': 'YOUR_PROXY_URL'})

// 或者在实例化之后任何时候设置

ex.proxyUrl = 'YOUR_PROXY_URL';

‘YOUR_PROXY_URL’的格式可以是:

  • http://127.0.0.1:8080/

  • https://cors-anywhere.herokuapp.com/

  • http://your-website.com/sample-script.php?url=

  • 等等

因此,请求将发送到 http://127.0.0.1:8080/https://exchange.xyz/api/endpoint。您可以通过以下方式测试是否有效:

// Python
print(await ex.fetch('https://api.ipify.org/')) // 对于同步版本,请移除 'await'

// JS
console.log(await ex.fetch('https://api.ipify.org/'));

// PHP
print(\React\Async\await($my_ex->fetch('https://api.ipify.org/'))); // 对于同步版本,请移除 '\React\Async\await'

您还可以在您的设备/网站上运行一个小型代理脚本,并在.proxyUrl中使用它。在 examples文件夹中有一个名为”sample-local-proxy-server”的示例脚本。#### httpProxy和httpsProxy 如果你可以访问远程的http或https代理,你可以设置:

ex.httpProxy = 'http://1.2.3.4:8080/';
// 或者
ex.httpsProxy = 'http://1.2.3.4:8080/';

socksProxy#

你也可以使用以下格式的socks代理

ex.socksProxy = 'socks5://1.2.3.4:8080/';

使用代理回调函数#

**注意,在上述属性之外,你还可以将回调函数设置为proxyUrlCallback, http(s)ProxyCallback, socksProxyCallback中的任何一个。回调函数的签名应该像这样:

function my_callback(url, method, headers, body) {
    if (my_condition) {
        return 'http://222.222.222.222';
    } else {
        return 'http://333.333.333.333';
    }
}

额外的代理相关细节#

userAgent#

如果你需要特殊情况下改写userAgent属性,可以这样:

ex.userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)...'

自定义代理代理商#

根据你使用的编程语言,你可以设置自定义代理代理商。

CORS(访问控制允许来源)#

CORS(跨域资源共享)主要影响浏览器,并且是引发“没有’Access-Control-Allow-Origin’标头的请求的资源”警告的原因。这是因为脚本(在浏览器中运行)可能尝试从另一个域请求数据,但该域不允许此连接(默认情况下,除非域专门启用此功能)。 因此,在这种情况下,你将需要一个“CORS”代理,它会将请求(与直接在浏览器端请求相对)重定向到目标交换所。要设置CORS代理,请参考proxyUrl部分,了解如何通过cors/proxy服务器路由请求。

错误处理#

CCXT的错误处理是通过各种语言的异常机制来完成的。处理错误时,应将try块添加到调用统一方法的周围,并像处理语言的其他情况一样捕获异常:

// JavaScript

// 尝试调用统一方法
try {
    const response = await exchange.fetchTicker ('ETH/BTC')
    console.log (response)
} catch (e) {
    // 如果抛出了异常,则会被"捕获"并可以在此处处理
    // 处理反应取决于异常的类型
    // 以及应用程序的目的或业务逻辑
    if (e instanceof ccxt.NetworkError) {
        console.log (exchange.id, '由于网络错误导致fetchTicker失败:', e.message)
        // 重试或其他操作
    } else if (e instanceof ccxt.ExchangeError) {
        console.log (exchange.id, '由于交易所错误导致fetchTicker失败:', e.message)
        // 重试或其他操作
    } else {
        console.log (exchange.id, 'fetchTicker失败:', e.message)
        // 重试或其他操作
    }
}
# Python

# 尝试调用统一方法
try:
    response = await exchange.fetch_order_book('ETH/BTC')
    print(response)
except ccxt.NetworkError as e:
    print(exchange.id, '由于网络错误导致fetch_order_book失败:', str(e))
    # 重试或其他操作
except ccxt.ExchangeError as e:
    print(exchange.id, '由于交易所错误导致fetch_order_book失败:', str(e))
    # 重试或其他操作
except Exception as e:
    print(exchange.id, 'fetch_order_book失败:', str(e))
    # 重试或其他操作
// PHP

// 尝试调用统一方法
try {
    $response = $exchange->fetch_trades('ETH/BTC');
    print_r($response);
} catch (\ccxt\NetworkError $e) {
    echo $exchange->id . ' 由于网络错误导致fetch_trades失败: ' . $e->getMessage () . "\n";
    // 重试或其他操作
} catch (\ccxt\ExchangeError $e) {
    echo $exchange->id . ' 由于交易所错误导致fetch_trades失败: ' . $e->getMessage () . "\n";
    // 重试或其他操作
} catch (Exception $e) {
    echo $exchange->id . ' fetch_trades失败: ' . $e->getMessage () . "\n";
    // 重试或其他操作
}

异常层次结构#

所有异常都派生自基本的BaseError异常,它在ccxt库中定义如下:

// JavaScript
class BaseError extends Error {
    constructor () {
        super ()
        // 使`instanceof BaseError`在ES5中工作的解决方法
        this.constructor = BaseError
        this.__proto__   = BaseError.prototype
    }
}
# Python
class BaseError (Exception):
    pass
// PHP
class BaseError extends \Exception {}

下面是异常继承层次结构的概述:

+ BaseError
|
+---+ ExchangeError
|   |
|   +---+ AuthenticationError
|   |   |
|   |   +---+ PermissionDenied(权限被拒绝)
|   |   |
|   |   +---+ AccountSuspended(帐户已停用)
|   |
|   +---+ ArgumentsRequired(需要参数)
|   |
|   +---+ BadRequest(请求错误)
|   |   |
|   |   +---+ BadSymbol(错误的符号)
|   |
|   +---+ BadResponse(错误的响应)
|   |   |
|   |   +---+ NullResponse(空响应)
|   |
|   +---+ InsufficientFunds(资金不足)
|   |
|   +---+ InvalidAddress(无效地址)
|   |   |
|   |   +---+ AddressPending(地址待定)
|   |
|   +---+ InvalidOrder(无效订单)
|   |   |
|   |   +---+ OrderNotFound(订单不存在)
|   |   |
|   |   +---+ OrderNotCached(订单未缓存)
|   |   |
|   |   +---+ CancelPending(取消待定)
|   |   |
|   |   +---+ OrderImmediatelyFillable(订单可立即成交)
|   |   |
|   |   +---+ OrderNotFillable(订单不可成交)
|   |   |
|   |   +---+ DuplicateOrderId(重复的订单ID)
|   |
|   +---+ NotSupported(不支持)
|
+---+ NetworkError(可恢复错误)
    |
    +---+ InvalidNonce(无效的Nonce)
    |
    +---+ RequestTimeout(请求超时)
    |
    +---+ ExchangeNotAvailable(交易所不可用)
    |   |
    |   +---+ OnMaintenance(正在维护)
    |
    +---+ DDoSProtection(DDoS保护)
        |
        +---+ RateLimitExceeded(超过速率限制)

BaseError 类是一个通用的错误类,用于各种错误,包括可访问性和请求/响应不匹配。用户至少应该捕获这个异常,如果不需要区分错误的话。

在错误层次结构中,有两个通用的特殊情况或子树,都是从 BaseError 派生的:

  • NetworkError(网络错误)

  • ExchangeError(交易所错误)

NetworkError 是一个非关键的非致命错误,不是完全意义上的错误,而更像是一个临时的不可用情况,可能由任何条件或因素引起,包括维护、DDoS保护和临时封禁。之所以有一个大的 NetworkError 类别是为了将所有在后续重试时能够重新出现或消失的异常分组在一起,其他所有条件都相同(例如,相同的用户输入,简单来说,即相同的订单价格和数量、相同的符号等)。

相比之下,ExchangeError 确实是一个关键错误,并且与 NetworkError 有一个非常具体的区别 - 如果通过相同的输入获得了 ExchangeError,那么在相同的输入下,每次都应该获得相同的 ExchangeError

这两个异常类别之间的区别在于一个是可恢复的,另一个是不可恢复的。NetworkError 意味着您可以稍后重试,它可能会自动消失,因此后续的重试可能会成功,并且用户可以通过等待来从 NetworkError 中恢复。ExchangeError 是致命错误,这意味着出现了问题,并且每次都会出现问题,除非更改输入。### ExchangeError

当交易所服务器以 JSON 错误回复时,会抛出此异常。可能的原因包括:

  • 交易所关闭了端点

  • 在交易所上找不到符号

  • 缺少必需参数

  • 参数格式不正确

  • 交易所回复不清楚

派生自ExchangeError的其他异常有:

  • NotSupported:如果交易所API不提供/不支持端点,则会引发此异常。

  • AuthenticationError:当交易所要求你指定的API凭据之一缺失时,或者密钥对或过时的nonce存在错误时,会引发此异常。大多数情况下,你需要apiKeysecret,有时还需要uid和/或password

  • PermissionDenied:当没有对指定操作访问权限或指定的apiKey权限不足时引发此异常。

  • InsufficientFunds:当你的账户余额不足以下订单时,会引发此异常。

  • InvalidAddress:在调用fetchDepositAddresscreateDepositAddresswithdraw时遇到错误的资金地址或资金地址长度小于.minFundingAddressLength(默认为10个字符)时,会引发此异常。

  • InvalidOrder:此异常是与统一订单 API 相关的所有异常的基类。

  • OrderNotFound:当尝试获取或取消不存在的订单时引发此异常。

NetworkError#

通常,与网络相关的所有错误都是可恢复的,也就是说,网络问题、流量拥堵、不可用通常是时间相关的。稍后重试通常足以从 NetworkError 中恢复,但如果问题仍然存在,那么可能表示交易所或你的连接存在持久性问题。

DDoSProtection#

在以下两种情况下会抛出此异常:

  • 当启用 Cloudflare 或 Incapsula 限制每个用户或每个区域/位置的速率限制器时

  • 当交易所限制用户请求相应端点的频率过高时#### 请求超时

当与交换所的连接失败或在指定的时间内未完全接收到数据时,会引发此异常。这由timeout选项控制。当引发RequestTimeout时,用户不知道请求的结果(是否被交换服务器接受)。

因此,建议按以下方式处理此类异常:

  • 对于获取请求,可以安全地重试调用

  • 对于取消订单(cancelOrder())的请求,用户需要重新尝试同一次调用。对cancelOrder()的后续重试将返回以下可能的结果之一:

    • 请求成功完成,表示订单已经被正确取消

    • 引发OrderNotFound异常,这意味着订单在第一次尝试时已被取消,或在两次尝试之间的期间已被执行(成交并关闭)。

  • 如果createOrder()的请求因RequestTimeout而失败,用户应该:

    • 调用fetchOrders()fetchOpenOrders()fetchClosedOrders()检查下单请求是否成功,并且订单现在是开放状态

    • 如果订单不是’open’状态,则用户应该调用fetchBalance()检查自第一次运行时创建的订单填充并关闭后的余额是否发生了变化,然后再进行第二次检查。

交易所不可用#

当底层交易所无法访问时,会抛出这种类型的异常。

如果ccxt库在响应中检测到以下关键字之一,也会抛出此错误:

  • offline

  • unavailable

  • busy

  • retry

  • wait

  • maintain

  • maintenance

  • maintenancing

非法的Nonce值#

当您的Nonce小于您的密钥对使用的先前Nonce时,会引发此异常,详细描述见身份验证部分。此类异常在以下情况下被抛出(按照检查优先顺序):# 故障排除

如果您在连接到特定交易所时遇到任何困难,请按以下优先顺序进行操作:

  • 确保您使用的是最新版本的ccxt。 不要相信软件包安装程序(无论是npmpip还是composer),而应该始终通过在环境中运行以下代码来检查您的实际(真实)运行时版本号

    console.log (ccxt.version) // JavaScript
    
    print('CCXT version:', ccxt.__version__)  # Python
    
    echo "CCXT v." . \ccxt\Exchange::VERSION . "\n"; // PHP
    
  • Issues中查看最新更新情况。

  • 确保已启用速率限制器enableRateLimit: true(可以是内置速率限制器或自定义速率限制器)。

  • 打开verbose = true以获取更多详细信息!

    import ccxt
    exchange = ccxt.binance()
    exchange.load_markets()
    exchange.verbose = True  # 在加载市场后启用详细模式
    

    为了获得帮助,您需要提供产生问题的代码以及详细输出。查找帮助所需的信息

  • Python用户可以使用标准的Python日志记录器打开DEBUG日志级别,只需将以下两行添加到其代码开头:

    import logging
    logging.basicConfig(level=logging.DEBUG)
    
  • 使用详细模式确保所使用的API凭据与您打算使用的密钥相对应。确保没有密钥对的混淆。

  • 尽可能使用全新的密钥对。

  • 阅读常见问题的答案:https://github.com/ccxt/ccxt/wiki/FAQ

  • 检查密钥对在交易所网站上的权限!

  • 检查您的nonce。如果您的API密钥曾与其他软件一起使用过,您很可能应该覆盖您的nonce函数以与以前的nonce值相匹配。通常可以通过生成一个未使用的新密钥对来轻松重置nonce。如果您在使用现有密钥时遇到nonce错误,请尝试使用尚未使用过的新API密钥。

  • 如果出现nonce错误,请检查您的请求速率。您的私有请求不应该快速连续发送。您不应该在短时间内或几乎同时发送它们。如果您不在发送频繁的无限制私有请求之前进行延迟,交易所很可能会禁止您。为了避免发送过于频繁的请求并超过交易所的速率限制,可以在后续请求中添加延迟或启用内置速率限制器,如长轮询 exampleshere 演示的那样。

  • 阅读您的交易所的文档并将详细输出与文档进行比较。

  • 通过浏览器访问交易所以检查与交易所的连接。

  • 通过代理检查与交易所的连接。

  • 尝试从另一台计算机或远程服务器访问交易所,以查看这是否是与交易所相关的本地或全球问题。

  • 检查交易所最近是否有关于维护停机的通知。有些交易所定期进行更新(例如每周一次)。

  • 确保系统时间与世界上其他时钟同步,否则可能会收到无效的nonce错误。

注意事项#

  • 使用verbose = true选项或者用 new ccxt.exchange ({ 'verbose': true })实例化您的有问题的交易所来查看HTTP请求和响应的详细内容。如果您在GitHub上提交问题,详细输出也将对我们进行调试有所帮助。

  • 在Python中使用DEBUG日志级别!

  • 某些交易所在某些国家或地区不可用,使用代理可能是解决方案。

  • 如果您收到认证错误或“无效密钥”错误,则很可能是由于nonce问题引起的。

  • 有些交易所在认证请求失败时没有明确说明。在这种情况下,它们可能会响应异常错误代码,例如HTTP 502 Bad Gateway Error或与实际错误原因更不相关的其他错误代码。