CCXT Pro手册#
CCXT Pro堆栈是构建在CCXT之上的,并通过以下方式扩展了核心CCXT类:
JavaScript原型级Mixin
Python多继承
PHP Traits
CCXT Pro极大地依赖于CCXT的转译器,用于多语言支持。
用户
+-------------------------------------------------------------+
| CCXT Pro |
+------------------------------+------------------------------+
| 公共 . 私人 |
+=============================================================+
│ . |
│ 统一的CCXT Pro API |
| . |
| loadMarkets . watchBalance |
| watchTicker . watchOrders |
| watchTickers . watchMyTrades |
| watchOrderBook . watchPositions |
| watchOHLCV . createOrderWs |
| watchStatus . editOrderWs |
| watchTrades . cancelOrderWs |
│ . cancelOrdersWs |
│ . cancelAllOrdersWs |
│ . |
│ . |
+=============================================================+
│ . |
| 底层特定交易所API |
| (派生类及其实现) |
│ . |
+=============================================================+
│ . |
| CCXT Pro基础交易所类 |
│ . |
+=============================================================+
+-------------------------------------------------------------+
| |
| CCXT |
| |
+=============================================================+
交易所#
CCXT Pro库当前支持以下52个加密货币交易所市场和WebSocket交易API:
logo |
id |
name |
ver |
certified |
pro |
---|---|---|---|---|---|
alpaca |
|||||
ascendex |
|||||
bequant |
|||||
binance |
|||||
binancecoinm |
|||||
binanceus |
|||||
binanceusdm |
|||||
bitfinex |
|||||
bitget |
|||||
bitmart |
|||||
bitmex |
|||||
bitopro |
|||||
bitpanda |
|||||
bitrue |
|||||
bitstamp |
|||||
bittrex |
|||||
bitvavo |
|||||
blockchaincom |
|||||
bybit |
|||||
cex |
|||||
coinbaseprime |
|||||
coinbasepro |
|||||
coinex |
|||||
cryptocom |
|||||
currencycom |
|||||
deribit |
|||||
fmfwio |
|||||
gate |
|||||
gemini |
|||||
hitbtc |
|||||
hollaex |
|||||
huobi |
|||||
huobijp |
|||||
idex |
|||||
independentreserve |
|||||
kraken |
|||||
krakenfutures |
|||||
kucoin |
|||||
kucoinfutures |
|||||
luno |
|||||
mexc |
|||||
ndax |
|||||
okcoin |
|||||
okx |
|||||
phemex |
|||||
poloniex |
|||||
poloniexfutures |
|||||
probit |
|||||
upbit |
|||||
wazirx |
|||||
whitebit |
|||||
woo |
以下是CCXT Pro中支持WebSocket API的交易所列表。此列表将定期更新以包含新的交易所。# CCXT 支持的加密货币交易所市场全列表
使用方法#
- 这部分文档目前正在重度开发中
- 随处可能有一些拼写错误、错误和缺少的信息
- 欢迎贡献、拉取请求和反馈
先决条件#
了解 CCXT Pro 的最佳方法是确保您完全理解整个 CCXT 手册并且先练习标准的 CCXT。CCXT Pro 借用了 CCXT 的一些概念。这两个库有很多共同之处,包括:
公共 API 和私有身份验证 API 的概念
市场、符号、货币代码和 ID
统一的数据结构和格式,订单簿、成交、订单、蜡烛、时间段等
异常和错误映射
身份验证和 API 密钥(用于私有源和调用)
配置选项
CCXT Pro 的受众主要是专业的算法交易员和开发人员。为了能够高效地使用该库,用户需要对流式传输的概念有很好的了解。用户必须了解连接式流媒体 API(WebSocket,CCXT Pro)和请求-响应式 API(REST,CCXT)之间的基本差异。
CCXT 应用程序的一般异步流程如下所示:
// 一个 RESTful 订单簿轮询请求-响应循环
while (condition) {
try {
// fetch some of the public data
orderbook = await exchange.fetchOrderBook (symbol, limit)
// do something or react somehow based on that data
// ...
} catch (e) {
// handle errors
}
}
在 CCXT Pro
中,每个具有 “fetch*” 前缀的公共和私有统一RESTful方法也有一个相应的基于流的对应方法,前缀为 “watch*”,如下所示:
公共API
fetchStatus
→watchStatus
fetchOrderBook
→watchOrderBook
fetchTicker
→watchTicker
fetchTickers
→watchTickers
fetchOHLCV
→watchOHLCV
fetchTrades
→watchTrades
私有API
fetchBalance
→watchBalance
fetchOrders
→watchOrders
(注意以watch
为前缀)fetchMyTrades
→watchMyTrades
fetchPositions
→watchPositions
即将推出createOrder
→createOrderWs
editOrder
→editOrderWs
cancelOrder
→cancelOrderWs
cancelOrders
→cancelOrdersWs
cancelAllOrders
→cancelAllOrdersWs
统一的CCXT Pro
流API继承了CCXT
的使用模式,使迁移更容易。
下面展示了CCXT Pro
应用程序的一般异步风格流程(与上面的CCXT
应用程序相对比):
// 一个基于流(WebSocket)的订单簿数据订阅循环
while (condition) {
try {
// 订阅一些公共数据
orderbook = await exchange.watchOrderBook (symbol, limit)
// 基于该数据做一些操作或者做出相应的反应
// ...
} catch (e) {
// 处理错误
}
}
这种使用模式通常被封装成一个核心业务逻辑方法,称为“tick()
函数”,因为它会重复对传入事件(也称为“ticks”)做出反应。从上面的两个示例中可以看出,CCXT Pro 和 CCXT 的通用使用模式是相同的。
CCXT 的许多规则和概念也适用于 CCXT Pro:
CCXT Pro将在第一次调用统一API方法时加载市场,并在缓存中保存市场信息
如果需要的话,CCXT Pro将在幕后调用CCXT的RESTful方法
如有必要,CCXT Pro将抛出标准的CCXT异常
…
流媒体特定信息#
尽管有许多共同之处,基于流媒体的API具有其自身的特定之处,这是因为它们的连接性质。
具有连接性界面意味着需要处理连接。连接由CCXT Pro透明地管理给用户。每个交易所实例都管理着自己的一组连接。
当您首次调用任何watch*()
方法时,库将建立与交易所特定流/资源的连接并保持连接。如果连接已经存在,则会重复使用该连接。库将处理订阅的请求/响应消息序列,以及如果请求的流是私有的,则处理身份验证和签名。
库还将监听上行链路的状态,并保持连接通畅。在发生关键异常、断开连接或连接超时/失败时,tick函数的下一次迭代将调用watch
方法,触发重新连接。这样,库可以透明地处理用户的断开连接和重新连接。CCXT Pro应用了必要的速率限制和指数回退重新连接延迟。所有这些功能都是默认启用的,并且可以通过交易所属性进行配置,与往常一样。
大多数交易所的流媒体API只有一个基本URL(通常是WebSocket,以ws://
或wss://
开头)。其中一些交易所可能为每个流提供多个URL,具体取决于所涉及的信息源。
交易所的流媒体API可以分为两个不同的类别:
sub或者subscribe允许接收消息
pub或者publish允许发送和接收消息
订阅#
订阅接口通常允许订阅数据流并监听它。大多数支持WebSockets的交易所只提供sub类型的API。sub类型包括流式传输的公共市场数据。有时,交易所还允许订阅私有用户数据。用户订阅数据源后,频道将以单向方式工作,不间断地向用户发送来自交易所的更新。
常见的公共数据流类型有:
委托簿(最常见)- 添加、编辑和删除订单的更新(也称为改变增量)
行情更新(在24小时统计数据发生变化时)
成交记录(也很常见)- 公共交易的实时流
OHLCV蜡烛图更新
心跳
交易所聊天/喷子盒
较不常见的私有用户数据流类型有:
用户的私有交易流
实时订单更新
余额更新
自定义流
特定于交易所和其他流
Pub#
发布接口通常允许用户向服务器发送数据请求。通常包括以下常见用户操作:
下单
取消订单
提交提款请求
发布聊天/喷子盒消息
等等
某些交易所不提供 pub WS API,它们只提供 sub WS API。 不过,也有交易所提供完整的流式API。在大多数情况下,用户仅通过流式API无法有效操作。交易所将流式传输公共市场数据( sub ),而仍需使用REST API来完成缺失的 pub 部分。
增量数据结构#
在许多情况下,由于底层数据源的单向性质,客户端上监听的应用程序必须在内存中保留数据的本地快照,并将从交易所服务器接收到的更新合并到本地快照中。来自交易所的更新通常也被称为 增量,因为在大多数情况下,这些更新将仅包含数据两个状态之间的更改,并不包含未更改的数据,因此需要存储本地缓存的所有相关数据对象的当前状态 S。
所有这些功能都由 CCXT Pro 为用户处理。要使用 CCXT Pro,用户无需跟踪或管理订阅和相关数据。CCXT Pro 将在内存中保存一组结构来处理底层的麻烦。
每个传入的更新都会说明哪些数据部分发生了变化,接收方通过将更新与当前状态 S 合并并移至下一个本地状态 S’ 来“增加”本地状态 S。在 CCXT Pro 中,这被称为 “增量状态”,负责存储和更新缓存状态的结构被称为 “增量结构”。 CCXT Pro 引入了几个新的基类来处理所需的增量状态。
从 CCXT Pro 的统一方法返回的增量结构通常是以下两种类型之一:
JSON 解码后的对象(JavaScript 中的
object
,Python 中的dict
,PHP 中的array()
)。这种类型可以从公共和私有方法(如watchOrderBook
、watchTicker
、watchBalance
、watchOrder
等)返回。对象的数组/列表(通常按时间顺序排序)。这种类型可以从诸如
watchOHLCV
、watchTrades
、watchMyTrades
、watchOrders
等方法返回。
像 watchOHLCV
、watchTrades
、watchMyTrades
、watchOrders
这样返回数组的统一方法都基于缓存层。用户必须了解缓存层的内部工作原理才能有效地使用它。
缓存是一个具有两个端点的固定大小的 deque(双端队列)或数组/列表。CCXT Pro 库对存储在内存中的对象数量有一个合理的限制。默认情况下,缓存数组结构将存储每种类型的最多 1000 个条目(1000 条最近的交易记录,1000 个最近的蜡烛图,1000 个最近的订单)。用户可以在实例化时或以后配置允许的最大数量:
ccxtpro.binance({
'options': {
'tradesLimit': 1000,
'OHLCVLimit': 1000,
'ordersLimit': 1000,
},
})
# 或者
exchange.options['tradesLimit'] = 1000
exchange.options['OHLCVLimit'] = 1000
exchange.options['ordersLimit'] = 1000
缓存限制必须在调用任何watch方法之前设置,而且在程序运行期间不能更改。
当缓存中有剩余空间时,新元素会被简单地追加到缓存的末尾。如果没有足够的空间来容纳新元素,最旧的元素将从缓存的开头删除以释放一些空间。因此,例如,缓存从0到1000的最近交易增长,然后保持在1000的最近交易上限,每次从交易所收到新的更新时,都会重新存储数据。它类似于一个滑动框架窗口或滑动门,如下所示:
过去 > ------------------ > 时间 > - - - - - - - - > 未来
滑动框架
最近1000
笔交易
+-----------------+
| |
|===========+=====|
+----------------+------| | | - - - - - + - - - - - - - - + - - -
| | | | | | |
0 1000 | 2000 | 3000 4000 ...
| | | | | | |
+----------------+------| | | - - - - - + - - - - - - - - + - - -
|===========+=====|
| |
+---+---------+---+
| |
开始 ^ ^ 上限
基于日期的分页参数
总是应用于
缓存的框架内部
用户可以使用exchange.options
配置缓存限制,如上所示。不要将缓存限制与分页限制混淆。
请注意,since
和limit
date-based pagination 参数具有不同的含义,并且始终在缓存窗口内应用! 如果用户在watchTrades()
调用中指定了since
参数,CCXT Pro将返回所有缓存的交易,其timestamp >= since
。如果用户没有指定since
参数,CCXT Pro将从滑动窗口的开头返回缓存的交易。如果用户指定了limit
参数,库将返回从since
或从缓存的开头开始的最多limit
个交易。由于WebSocket实时特性的原因,用户不能在缓存框架之外进行分页。
exchange.options['tradesLimit'] = 5 # 将缓存大小设置为5
# 此调用将返回最多5个缓存的交易
await exchange.watchTrades (symbol)
# 以下调用将返回最多5个缓存交易中的前2个
await exchange.watchTrades (symbol, since=None, limit=2)# 这个调用首先会通过 trade['timestamp'] >= since 条件过滤缓存的交易
# 并返回最多 5 条通过过滤条件的交易中的前 2 条
since = exchange.iso8601('2020-01-01T00:00:00Z')
limit = 2
await exchange.watchTrades(symbol, since, limit)
newUpdates 模式#
如果你想始终获取最新的交易,你应该实例化交易所时将 newUpdates 标志设置为 true。
exchange = ccxtpro.binance({'newUpdates': True})
while True:
trades = await exchange.watchTrades(symbol)
print(trades)
newUpdates 模式会在后台继续使用滑动缓存,但用户只会得到新的更新。这是因为一些交易所使用增量结构,所以我们需要保持一个缓存的对象,因为交易所可能只提供部分信息,例如状态更新。
newUpdates 模式的结果将是自上次 exchange.watchMethod
解析后发生的一个或多个更新。CCXT Pro 可以返回自上次调用后更新的一个或多个订单。调用 exchange.watchOrders
的结果将如下所示:
[
order, // 详见 https://docs.ccxt.com/#/?id=order-structure
order,
order,
...
]
弃用警告:未来 newUpdates: true
将成为默认模式,你需要将 newUpdates 设置为 false 才能获取滑动缓存。
// JavaScript
const ccxtpro = require ('ccxt').pro
console.log('CCXT 版本', ccxtpro.version)
console.log('支持的交易所:', ccxtpro.exchanges)
# Python
import ccxt.pro as ccxtpro
print('CCXT version', ccxtpro.__version__)
print('Supported exchanges:', ccxtpro.exchanges)
// PHP
use \ccxt\pro; // 可选,因为你可以使用完全限定的名称
echo 'CCXT 版本 ', \ccxt\pro\Exchange::VERSION, "\n";
echo '支持的交易所: ', json_encode(\ccxt\pro\Exchange::$exchanges), "\n";
导入的 CCXT Pro 模块在自身内部包装了 CCXT - 通过 CCXT Pro 实例化的每个交易所都具有所有的 CCXT 方法以及其他额外的功能。
实例化#
CCXT Pro 采用了异步/等待样式的语法,并且在很大程度上依赖于异步原语,比如promises和futures。
创建 CCXT Pro 交易所实例与创建 CCXT 交易所实例基本相同。
// JavaScript
const ccxt = require ('ccxt').pro
const exchange = new ccxtpro.binance ({ newUpdates: false })
CCXT Pro 的 Python 实现基于内置的 asyncio 和 Event Loop。在 Python 中,可以在构造函数参数中提供 asyncio 的 event loop 实例,如下所示(与 ccxt.async support
相同):
# Python
import ccxt.pro as ccxtpro
from asyncio import run
async def main():
exchange = ccxtpro.kraken({'newUpdates': False})
while True:
orderbook = await exchange.watch_order_book('BTC/USD')
print(orderbook['asks'][0], orderbook['bids'][0])
await exchange.close()
run(main())
在PHP中,异步原语是从ReactPHP借用的。CCXT Pro的PHP实现特别依赖于Promise和EventLoop。在PHP中,必须在构造函数的参数中提供一个ReactPHP的事件循环实例,如下所示:
// PHP
error_reporting(E_ALL | E_STRICT);
date_default_timezone_set('UTC');
require_once 'vendor/autoload.php';
$exchange = new \ccxt\pro\kucoin(array( 'newUpdates' => false ));
交易所属性#
每个CCXT Pro实例都包含底层CCXT实例的所有属性。除了标准的CCXT属性之外,CCXT Pro实例还包括以下内容:
{
'has': { // 扩展交易所功能的关联数组
'ws': true, // 仅在CCXT Pro中可用
'watchOrderBook': true,
'watchTicker': true,
'watchTrades': true,
'watchOHLCV': true,
'watchBalance': true,
'watchCreateOrder': true,
'watchCancelOrder': true,
...
},
'urls': {
'api': { // 根据底层协议将包含流API的基本URL
'ws': 'wss://ws.exchange.com', // https://en.wikipedia.org/wiki/WebSocket
'signalr': 'https://signalr.exchange.com' // https://en.wikipedia.org/wiki/SignalR
'socketio': 'wss://socket.exchange.io' // https://socket.io
},
},
'version': '1.21',
'streaming': {
'keepAlive': 30000, // 以毫秒为单位的整数keep-alive频率
'maxPingPongMisses': 2.0, // 多少次ping pong丢失后进行重连
... // 其他流选项
},
// 增量数据结构
'orderbooks': {}, // 按交易对索引的增量订单簿
'ohlcvs': {}, // 按交易对和时间周期索引的标准CCXT OHLCV
'balance': {}, // 按币种代码索引的标准CCXT余额结构,按账户
'orders': {}, // 按订单ID索引的标准CCXT订单结构
'trades': {}, // 按交易对索引的CCXT交易数组
'tickers': {}, // 按交易对索引的标准CCXT行情
'transactions': {}, // 按id或txid索引的标准CCXT存款和提款
...
}
统一的API#
统一的CCXT Pro API鼓励直接控制流程,以获得更好的代码风格、更可读和架构更优的代码,相比使用EventEmitters和回调函数的方式,后者被认为是一种过时的方法,因为它需要控制的倒置(人们不习惯倒置思维)。
CCXT Pro遵循现代方法,并且专为异步语法设计。在底层,CCXT Pro有时仍然必须使用倒置的控制流,因为依赖项和无法以其他方式处理的WebSocket库。
对于JS/ES6以及Python 3的异步代码也是如此。在PHP中,异步原语是从ReactPHP借用的。现代异步语法允许您将执行组合和拆分为并行路径,然后合并、分组、优先处理等等。使用 Promises,您可以轻松地从直接的异步风格控制流转换为反转的回调风格控制流,来回切换。
实时 vs 限流#
CCXT Pro 支持两种 tick 函数循环模式 - 实时模式和限流模式。以下是它们的伪代码:
// 实时模式
const limit = 5 // 可选
while (true) {
try {
const orderbook = await exchange.watchOrderBook (symbol, limit)
// 您的对更新的反应发生在这里
// 在实时从交易所接收更新后,您会立即到达这里
console.log (orderbook) // 每次更新
} catch (e) {
console.log (e)
// throw e // 取消注释以在出现异常时停止循环
}
}
// 限流模式
const limit = 5 // 可选
// await 是可选的,或者您可以在后台启动它,而不等待
await exchange.watchOrderBook (symbol, limit)
while (true) {
// 您的反应发生在这里
// 每 100 毫秒无论是否有更新,您都会到达这里
// 在限流模式中,使用 .limit () 卸载 orderbook 是必需的
console.log (exchange.orderbooks[symbol].limit (limit))
await exchange.sleep (100) // 每 100 毫秒
}
在实时模式下,CCXT Pro 会在每个来自交易所的新 delta 到达时立即返回结果。在实时循环中,统一调用的通用逻辑是等待下一个 delta 并立即多次将统一结果结构返回给用户。这在响应时间至关重要或必须尽可能快的情况下非常有用。
然而,实时模式在需要同步多个并行 tick 循环时需要有异步流程的程序开发经验。此外,交易所在高活动或高波动性期间可以流式传输大量更新数据。因此,开发实时算法的用户必须确保用户代码能够快速消耗数据。在某些情况下,实时模式可能对资源要求更高。
在限流模式下,CCXT Pro 会在后台接收和管理数据。用户负责在需要时定期调用结果。限流循环的通用逻辑是大部分时间睡眠,并在必要时唤醒以检查结果。这通常在固定频率或“帧速率”下完成。限流循环中的代码通常更容易在多个交易所之间进行同步。在限流循环中花费的时间配额还有助于将资源使用减少到最低。当您的算法较重且要精确控制执行以避免过频繁运行时,这非常方便。
限流模式的明显缺点是对更新反应不够敏锐或响应迟缓。当一个交易算法必须等待几毫秒才能执行时,可能有一两个更新可能会在该时间超过之前到达。在限流模式下,用户只会在下次唤醒(循环迭代)时检查这些更新,因此反应延迟可能随时间在几毫秒内变化。
公共方法#
市场数据#
watchOrderBook#
watchOrderBook
接口与fetchOrderBook接口完全相同。它接受三个参数:
symbol
– 字符串,统一的CCXT符号,必填limit
– 整数,返回的竞价/要价数量上限,可选params
– 字典,覆盖参数的可选字段,如覆盖统一API参数中所述
一般来说,交易所可以分为两类:
支持有限订单簿的交易所(仅流式传输订单堆栈的顶部部分)
仅流式传输完整订单簿的交易所
如果交易所接受限制参数,limit
参数将在订阅WebSocket连接上的订单簿流时发送到交易所。交易所随后只会发送指定数量的订单,从而减少流量。某些交易所可能仅接受特定的limit
值,如10、25、50、100等。
如果底层交易所不接受限制参数,则限制操作在客户端执行。
limit
参数不能保证竞价或要价的数量总是等于limit
。它表示一个上限或最大值,因此在某一时刻,竞价或要价的数量可能少于limit
,但绝不会超过limit
。当交易所在订单簿上没有足够的订单时,或者订单簿中的一个顶部订单被匹配并从订单簿中删除时,两边(竞价或要价)都可能少于limit
条目。订单簿中的空闲空间通常会迅速填充新数据。
// JavaScript
if (exchange.has['watchOrderBook']) {
while (true) {
try {
const orderbook = await exchange.watchOrderBook (symbol, limit, params)
console.log (new Date (), symbol, orderbook['asks'][0], orderbook['bids'][0])
} catch (e) {
console.log (e)
// 在出现异常时停止循环或将其注释以重试
// throw e
}
}
}
# Python
if exchange.has['watchOrderBook']:
while True:
try:
orderbook = await exchange.watch_order_book(symbol, limit, params)
print(exchange.iso8601(exchange.milliseconds()), symbol, orderbook['asks'][0], orderbook['bids'][0])
except Exception as e:
print(e)
# stop the loop on exception or leave it commented to retry
# raise e
// PHP
if ($exchange->has['watchOrderBook']) {
$exchange::execute_and_run(function() use ($exchange, $symbol, $limit, $params) {
while (true) {
try {
$orderbook = yield $exchange->watch_order_book($symbol, $limit, $params);
echo date('c'), ' ', $symbol, ' ', json_encode(array($orderbook['asks'][0], $orderbook['bids'][0])), "\n";
} catch (Exception $e) {
echo get_class($e), ' ', $e->getMessage(), "\n";
}
}
});
}
watchTicker#
Some exchanges allow different topics to listen to tickers (ie: bookTicker). You can set this in exchange.options['watchTicker']['name']
// JavaScript
if (exchange.has['watchTicker']) {
while (true) {
try {
const ticker = await exchange.watchTicker (symbol, params)
console.log (new Date (), ticker)
} catch (e) {
console.log (e)
// stop the loop on exception or leave it commented to retry
// throw e
}
}
}
# Python
if exchange.has['watchTicker']:
while True:
try:
ticker = await exchange.watch_ticker(symbol, params)
print(exchange.iso8601(exchange.milliseconds()), ticker)
except Exception as e:
print(e)
# stop the loop on exception or leave it commented to retry
# raise e
// PHP
if ($exchange->has['watchTicker']) {
$exchange::execute_and_run(function() use ($exchange, $symbol, $params) {
while (true) {
try {
$ticker = yield $exchange->watch_ticker($symbol, $params);
echo date('c'), ' ', json_encode($ticker), "\n";
} catch (Exception $e) {
echo get_class($e), ' ', $e->getMessage(), "\n";
}
}
});
}
watchTickers#
// JavaScript
if (exchange.has['watchTickers']) {
while (true) {
try {
const tickers = await exchange.watchTickers (symbols, params)
console.log (new Date (), tickers)
} catch (e) {
console.log (e)
// stop the loop on exception or leave it commented to retry
// throw e
}
}
}
# Python
if exchange.has['watchTickers']:
while True:
try:
tickers = await exchange.watch_tickers(symbols, params)
print(exchange.iso8601(exchange.milliseconds()), tickers)
except Exception as e:
print(e)
# stop the loop on exception or leave it commented to retry
# raise e
// PHP
if ($exchange->has['watchTickers']) {
$exchange::execute_and_run(function() use ($exchange, $symbols, $params) {
while (true) {
try {
$tickers = yield $exchange->watch_tickers($symbols, $params);
echo date('c'), ' ', json_encode($tickers), "\n";
} catch (Exception $e) {
echo get_class($e), ' ', $e->getMessage(), "\n";
}
}
});
}
watchOHLCV#
有一个非常普遍的误解是,WebSocket的WS OHLCV数据流可以在某种程度上加快交易策略的速度。 如果你的应用程序的目的是实现OHLCV交易或者投机性算法策略,请仔细考虑以下情况。
一般来说,算法使用两种类型的交易数据:
第一类型的实时数据,如订单簿和交易
第二类型的非实时数据,如市场行情、OHLCV等
当开发者说”实时”时,通常指的是伪实时,或者简单说是”尽可能快、尽可能接近实时”。
第二类型的数据是从第一类型数据中计算出来的。OHLCV是从聚合的交易中计算出来的。市场行情是从交易和订单簿中计算出来的。
一些交易所会在交易所端为您计算OHLCV(第二类型数据),然后通过WebSocket向您发送更新(币安)。其他一些交易所认为这并不是必需的,有其原因。
显然,从交易中计算出第二类型的OHLCV蜡烛需要时间。除此之外,将计算出的蜡烛发送回所有连接的用户也需要时间。在高波动的时期,如果一个交易所在高负载下交易非常活跃,可能会出现额外的延迟。
无法严格保证交易所从计算2nd order数据到通过WS向您传输数据需要多长时间。不同交易所的OHLCV蜡烛的延迟和滞后可能会有很大的差异。例如,有的交易所可能在对应时期的实际收盘后约30秒发送OHLCV更新。其他交易所可能以固定间隔发送当前OHLCV更新(比如每100毫秒一次),而实际上交易可能发生得更频繁。
大多数人使用WebSocket来避免任何延迟并获取实时数据。因此,在大多数情况下,最好不要等待交易所。使用CCXT的内置方法如build_ohlcvc()
,自行重新计算第二类型数据可能更快,这样可以降低不必要的延迟。因此,仅仅使用WebSocket观察交易所的OHLCV蜡烛并没有太多意义。开发者更倾向于使用watch_trades()
,然后使用CCXT的内置方法build_ohlcvc()
重新计算OHLCV蜡烛。
# Python
exchange = ccxtpro.binance()
if not exchange.has['watchOHLCV']:
while True:
try:
trades = await exchange.watch_trades(symbol)
ohlcvc = exchange.build_ohlcvc(trades, '1m')
print(ohlcvc)
except Exception as e:
print(e)
# 发生异常时停止循环或者将注释保留以重试
# raise e
这就解释了为什么一些交易所认为在WS上下文中不需要使用OHLCV数据,因为用户可以通过在用户界面上只订阅实时一级交易的WS流来更快地计算这些信息。
如果你的应用程序不是非常时间敏感,你仍然可以订阅OHLCV数据流,用于绘制图表。如果底层 exchange.has['watchOHLCV']
,你可以像下面这样使用 watchOHLCV()
或者 watch_ohlcv()
:
// JavaScript
if (exchange.has['watchOHLCV']) {
while (true) {
try {
const candles = await exchange.watchOHLCV (symbol, timeframe, since, limit, params)
console.log (new Date (), candles)
} catch (e) {
console.log (e)
// 发生异常时停止循环或者将其注释以重试
// throw e
}
}
}
# Python
if exchange.has['watchOHLCV']:
while True:
try:
candles = await exchange.watch_ohlcv(symbol, timeframe, since, limit, params)
print(exchange.iso8601(exchange.milliseconds()), candles)
except Exception as e:
print(e)
# 发生异常时停止循环或者将其注释以重试
# raise e
// PHP
if ($exchange->has['watchOHLCV']) {
$exchange::execute_and_run(function() use ($exchange, $symbol, $timeframe, $since, $limit, $params) {
while (true) {
try {
$candles = yield $exchange->watch_ohlcv($symbol, $timeframe, $since, $limit, $params);
echo date('c'), ' ', $symbol, ' ', $timeframe, ' ', json_encode($candles), "\n";
} catch (Exception $e) {
echo get_class($e), ' ', $e->getMessage(), "\n";
}
}
});
}
watchTrades#
// JavaScript
if (exchange.has['watchTrades']) {
while (true) {
try {
const trades = await exchange.watchTrades (symbol, since, limit, params)
console.log (new Date (), trades)
} catch (e) {
console.log (e)
// 发生异常时停止循环或者将其注释以重试
// throw e
}
}
}
# Python
if exchange.has['watchTrades']:
while True:
try:
trades = await exchange.watch_trades(symbol, since, limit, params)
print(exchange.iso8601(exchange.milliseconds()), trades)
except Exception as e:
print(e)
# 发生异常时停止循环或者将其注释以重试
# raise e
// PHP
if ($exchange->has['watchTrades']) {
$exchange::execute_and_run(function() use ($exchange, $symbol, $since, $limit, $params) {
while (true) {
try {
$trades = yield $exchange->watch_trades($symbol, $since, $limit, $params);
echo date('c'), ' ', json_encode($trades), "\n";
} catch (Exception $e) {
echo get_class($e), ' ', $e->getMessage(), "\n";
}
}
});
}
私有方法#
鉴权#
在大多数情况下,鉴权逻辑是从CCXT借用的,因为交易所在REST API和WebSocket API中使用相同的密钥对和签名算法。有关更多详细信息,请参阅API密钥设置。
交易#
watchBalance#
// JavaScript
if (exchange.has['watchBalance']) {
while (true) {
try {
const balance = await exchange.watchBalance (params)
console.log (new Date (), balance)
} catch (e) {
console.log (e)
// 在出现异常时停止循环,或者将其注释以重试
// throw e
}
}
}
# Python
if exchange.has['watchBalance']:
while True:
try:
balance = await exchange.watch_balance(params)
print(exchange.iso8601(exchange.milliseconds()), balance)
except Exception as e:
print(e)
# 在出现异常时停止循环,或者将其注释以重试
# raise e
// PHP
if ($exchange->has['watchBalance']) {
$exchange::execute_and_run(function() use ($exchange, $params) {
while (true) {
try {
$balance = yield $exchange->watch_balance($params);
echo date('c'), ' ', json_encode($balance), "\n";
} catch (Exception $e) {
echo get_class($e), ' ', $e->getMessage(), "\n";
}
}
});
}
watchOrders#
// JavaScript
watchOrders (symbol = undefined, since = undefined, limit = undefined, params = {})
# Python
watch_orders(symbol=None, since=None, limit=None, params={})
// PHP
watch_orders($symbol = null, $since = null, $lmit = null, $params = array());
watchMyTrades#
// JavaScript
watchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {})
# Python
watch_my_trades(symbol=None, since=None, limit=None, params={})
// PHP
watch_my_trades($symbol = null, $since = null, $lmit = null, $params = array());
Trading#
createOrderWs#
// JavaScript
createOrderWs (symbol: string, type: OrderType, side: OrderSide, amount: number, price: number = undefined, params = {})
# Python
create_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Optional[float] = None, params={})
// PHP
create_order_ws(string $symbol, string $type, string $side, float $amount, ?float $price = null, $params = array ())
editOrderWs#
// JavaScript
editOrderWs (id, symbol: string, type: OrderType, side: OrderSide, amount: number, price: number = undefined, params = {})
# Python
edit_order_ws(self, id, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Optional[float] = None, params={})
// PHP
edit_order_ws(string id, string $symbol, string $type, string $side, float $amount, ?float $price = null, $params = array ())
cancelOrderWs#
// JavaScript
cancelOrderWs(id: string, symbol: string = undefined, params = {})
# Python
cancel_order_ws(self, id, symbol: str, params={})
// PHP
cancel_order_ws(string $id, string $symbol, $params = array ())
cancelOrdersWs#
// JavaScript
cancelOrdersWs(ids: string[], symbol: string = undefined, params = {})
# Python
cancel_orders_ws(self, ids, symbol: str, params={})
// PHP
cancel_orders_ws(string[] $ids, string $symbol, $params = array ())
cancelAllOrdersWs#
// JavaScript
cancelAllOrdersWs(symbol: string = undefined, params = {})
# Python
cancel_all_orders_ws(self, symbol: str, params={})
// PHP
cancel__all_orders_ws(string $symbol, $params = array ())
资金#
watchTransactions#
- 此方法正在开发中(可能无法使用)
错误处理#
在发生错误时,CCXT Pro将抛出一个标准的CCXT异常,请参阅错误处理获取更多详细信息。