统一API结果分页
大多数统一API的方法会返回单一对象或对象数组(交易、委托单等)。 然而,极少数交易所会返回一次返回全部委托单、全部交易或全部ohlcv烛线图数据。 更常见的是交易所API会限制返回一定数量的最新对象,你不能一次调用就 获取从开始时间到当前时刻的全部对象。实际上,极少有交易所能容忍或允许 这样的调用。
要获取历史委托单或交易,用户需要分页遍历数据。分页通常表示要循环 提取部分数据。
在大多数情况下,用户需要使用某种类型的分页来获取期望的结果。如果 用户没有使用分页,大多数方法将返回交易所的默认结果,这可能是从历史 的开始时刻或者也可能是返回最近的一部分数据。默认行为是交易所相关的! 分页通常会在以下方法中用到:
- fetchTrades
- fetchOHLCV
- fetchOrders
- fetchOpenOrders
- fetchClosedOrders
- fetchMyTrades
- fetchTransactions
- fetchDeposits
- fetchWithdrawals
对于返回对象列表的方法,交易所可能提供一种或多种分页类型。CCXT默认 统一了基于日期、基于毫秒时间戳的分页。
用于UTC日期和时间戳的方法集:
exchange.parse8601 ('2018-01-01T00:00:00Z') == 1514764800000 // integer, Z = UTC
exchange.iso8601 (1514764800000) == '2018-01-01T00:00:00Z' // iso8601 string
exchange.seconds () // integer UTC timestamp in seconds
exchange.milliseconds () // integer UTC timestamp in milliseconds
基于日期的分页
这是目前CCXT统一API使用的分页类型。调用者提供一个毫秒时间戳作为since
参数的值,同时传入一个数值来限定返回结果的数量。要逐页遍历感兴趣的对象,
调用者运行如下的伪代码。
JavaScript:
if (exchange.has['fetchTrades']) {
let since = exchange.milliseconds () - 86400000 // -1 day from now
// alternatively, fetch from a certain starting datetime
// let since = exchange.parse8601 ('2018-01-01T00:00:00Z')
let allTrades = []
while (since < exchange.milliseconds ()) {
const symbol = undefined // change for your symbol
const limit = 20 // change for your limit
const trades = await exchange.fetchTrades (symbol, since, limit)
if (trades.length) {
since = trades[trades.length - 1]['timestamp']
allTrades = allTrades.concat (trades)
} else {
break
}
}
}
Python:
if exchange.has['fetchOrders']:
since = exchange.milliseconds () - 86400000 # -1 day from now
# alternatively, fetch from a certain starting datetime
# since = exchange.parse8601('2018-01-01T00:00:00Z')
all_orders = []
while since < exchange.milliseconds ():
symbol = None # change for your symbol
limit = 20 # change for your limit
orders = await exchange.fetch_orders(symbol, since, limit)
if len(orders):
since = orders[len(orders) - 1]['timestamp']
all_orders += orders
else:
break
PHP:
if ($exchange->has['fetchMyTrades']) {
$since = exchange->milliseconds () - 86400000; // -1 day from now
// alternatively, fetch from a certain starting datetime
// $since = $exchange->parse8601 ('2018-01-01T00:00:00Z');
$all_trades = array ();
while (since < exchange->milliseconds ()) {
$symbol = null; // change for your symbol
$limit = 20; // change for your limit
$trades = $exchange->fetchMyTrades ($symbol, $since, $limit);
if (count($trades)) {
$since = $trades[count($trades) - 1]['timestamp'];
$all_trades = array_merge ($all_trades, $trades);
} else {
break;
}
}
}
基于ID的分页
调用者提供对象的from_id
,以及一个用于限定返回结果数量的值。这是一些交易所
的默认行为,然而,这一分页类型目前还不是统一的。要基于ID进行分页,调用者可以
运行如下伪代码:
JavaScript:
if (exchange.has['fetchTrades']) {
let from_id = 'abc123' // all ids are strings
let allTrades = []
while (true) {
const symbol = undefined // change for your symbol
const since = undefined
const limit = 20 // change for your limit
const params = {
'from_id': from_id, // exchange-specific non-unified parameter name
}
const trades = await exchange.fetchTrades (symbol, since, limit, params)
if (trades.length) {
from_id = trades[trades.length - 1]['id']
allTrades.push (trades)
} else {
break
}
}
}
Python:
if exchange.has['fetchOrders']:
from_id = 'abc123' # all ids are strings
all_orders = []
while True:
symbol = None # change for your symbol
since = None
limit = 20 # change for your limit
params = {
'from_id': from_id, # exchange-specific non-unified parameter name
}
orders = await exchange.fetch_orders(symbol, since, limit, params)
if len(orders):
from_id = orders[len(orders) - 1]['id']
all_orders += orders
else:
break
PHP:
if ($exchange->has['fetchMyTrades']) {
$from_id = 'abc123' // all ids are strings
$all_trades = array ();
while (true) {
$symbol = null; // change for your symbol
$since = null;
$limit = 20; // change for your limit
$params = array (
'from_id' => $from_id, // exchange-specific non-unified parameter name
);
$trades = $exchange->fetchMyTrades ($symbol, $since, $limit, $params);
if (count($trades)) {
$from_id = $trades[count($trades) - 1]['id'];
$all_trades = array_merge ($all_trades, $trades);
} else {
break;
}
}
}
基于页号的分页
调用者提供一个页号或者初始的游标值。交易所范围一页结果以及后续的游标值以便继续。 大多数实现这种类型分页的交易所,在响应内容或响应头中返回下一个游标。
可以访问这里 查看示例代码实现。
在每个迭代周期,调用者必须拿到下一个游标并将其传入下一次迭代的查询。
JavaScript:
if (exchange.has['fetchTrades']) {
let page = 0 // exchange-specific type and value
let allTrades = []
while (true) {
const symbol = undefined // change for your symbol
const since = undefined
const limit = 20 // change for your limit
const params = {
'page': page, // exchange-specific non-unified parameter name
}
const trades = await exchange.fetchTrades (symbol, since, limit, params)
if (trades.length) {
// not thread-safu and exchange-specific !
page = exchange.last_json_response['cursor']
allTrades.push (trades)
} else {
break
}
}
}
Python:
if exchange.has['fetchOrders']:
cursor = 0 # exchange-specific type and value
all_orders = []
while True:
symbol = None # change for your symbol
since = None
limit = 20 # change for your limit
params = {
'cursor': cursor, # exchange-specific non-unified parameter name
}
orders = await exchange.fetch_orders(symbol, since, limit, params)
if len(orders):
# not thread-safu and exchange-specific !
cursor = exchange.last_http_headers['CB-AFTER']
all_orders += orders
else:
break
PHP:
if ($exchange->has['fetchMyTrades']) {
$start = '0' // exchange-specific type and value
$all_trades = array ();
while (true) {
$symbol = null; // change for your symbol
$since = null;
$limit = 20; // change for your limit
$params = array (
'start' => $start, // exchange-specific non-unified parameter name
);
$trades = $exchange->fetchMyTrades ($symbol, $since, $limit, $params);
if (count($trades)) {
// not thread-safu and exchange-specific !
$start = $exchange->last_json_response['next'];
$all_trades = array_merge ($all_trades, $trades);
} else {
break;
}
}
}