Bitmex历史订单查询:数据迷宫探险与API指南

频道: 平台 日期: 浏览:50

Bitmex 比特币历史订单详情查询:一场数据迷宫的探险

作为一名加密货币交易者,尤其是使用 Bitmex 这样的衍生品交易所,精准地追踪历史订单详情至关重要。它不仅仅是复盘交易策略、评估盈亏情况的必要步骤,更是税务申报、风险管理、以及潜在的争议解决的重要依据。然而,Bitmex 提供的历史订单数据,对于不熟悉 API 和相关工具的用户来说,可能像迷宫一样复杂。

数据的入口:Bitmex API

Bitmex 的历史订单数据主要通过其 API (Application Programming Interface,应用程序编程接口) 提供。API 是一种预定义的接口,允许不同的软件系统通过标准化的方式进行通信和数据交换。在加密货币领域,API 被广泛用于访问交易所的实时行情、历史数据、账户信息等。通过 Bitmex API,开发者可以编写自动化程序,高效地获取所需的交易数据,无需手动操作,从而实现量化交易策略、数据分析和风险管理等功能。

Bitmex 提供了 REST API 和 WebSocket API 两种方式获取订单数据,满足不同场景的需求。REST API (Representational State Transfer) 是一种基于 HTTP 协议的 API 设计风格,适用于一次性的大批量数据请求,例如获取特定时间段内的历史订单数据。WebSocket API 则提供了一种持久化的连接,适用于实时数据流的订阅,例如实时行情推送,交易事件通知。对于历史订单查询,REST API 因其易用性和高效性而更为常用。开发者可以根据自身需求和应用场景选择合适的 API 类型。

要使用 Bitmex API,首先需要在 Bitmex 平台创建一个 API 密钥。API 密钥是一对字符串,包含公钥 (API Key) 和私钥 (API Secret)。公钥用于标识你的身份,类似于用户名,告诉 Bitmex 你是谁。私钥用于对请求进行签名,确保数据的完整性和安全性,防止数据在传输过程中被篡改。在使用 API 发送请求时,需要使用私钥对请求进行签名。务必妥善保管你的私钥,切勿泄露给他人,因为拥有私钥的人可以模拟你的身份进行操作,造成资产损失。建议启用 IP 地址白名单、权限限制等安全措施,进一步保护 API 密钥的安全。

构建查询请求:参数详解

要查询历史订单详情,我们需要向 Bitmex 的 /api/v1/order 端点发送一个 HTTP GET 请求。此端点提供了一种强大的方式来检索和分析您的交易历史。请求中包含的参数允许您精确地定义所需的数据范围和类型,从而优化查询效率并减少不必要的数据传输。

  • symbol : 交易对。此参数指定您希望查询的交易品种。例如, XBTUSD 代表比特币/美元永续合约。其他可能的取值包括 ETHUSD (以太坊/美元) 或 ADAZ24 (Cardano 的合约)。准确的交易对符号取决于 Bitmex 提供的合约类型和期限。
  • filter : 订单状态的过滤器。此参数允许您根据订单的状态筛选结果。例如, {"ordStatus": "Filled"} 表示仅检索已完全成交的订单。 可以根据需求设置不同的状态: New (新订单,已提交但尚未成交), PartiallyFilled (部分成交,订单已经部分执行), Canceled (已取消,用户主动取消或因系统原因取消), Rejected (已拒绝,订单因某种原因被交易所拒绝,例如保证金不足或价格超出限制), PendingCancel (等待取消,用户已提交取消请求,但尚未生效) 等。您可以组合多种状态进行过滤,例如 {"ordStatus": ["Filled", "Canceled"]}
  • startTime : 查询的起始时间。此参数定义了您希望检索数据的起始时间点。 必须是 ISO8601 格式的字符串,例如 2023-01-01T00:00:00.000Z 。时区必须为 UTC。如果不提供此参数,则默认从最早的订单开始查询。
  • endTime : 查询的结束时间。此参数定义了查询的截止时间点。 同样必须是 ISO8601 格式的字符串,例如 2024-01-01T00:00:00.000Z 。时区必须为 UTC。如果不提供此参数,则默认查询到当前时间。 startTime endTime 的合理设置对于控制查询范围至关重要。
  • count : 返回订单的数量上限。此参数限制了 API 返回的订单数量。默认为 100,最大值为 500。如果您的查询结果超过 500 个订单,您需要使用 start 参数进行分页查询。 谨慎设置此参数,过大的值可能导致服务器响应时间过长。
  • start : 结果的起始位置。用于分页查询。此参数允许您从结果集的指定位置开始检索数据。 例如,如果已经查询了 500 个订单,想要查询接下来的 500 个订单,可以将 start 设置为 500。这对于处理大量订单数据非常有用,可以避免一次性加载所有数据导致的性能问题。 start 值必须是整数,且大于等于 0。
  • reverse : 是否反向排序。如果设置为 true ,则按照时间倒序排列,即最新的订单将首先返回。如果设置为 false 或省略此参数,则按照时间正序排列,即最早的订单将首先返回。在分析近期交易活动时,通常会将此参数设置为 true

例如,以下是一个查询过去 7 天内,XBTUSD 交易对所有已成交订单的 API 请求示例 (假设当前日期为 2024-10-27):

GET /api/v1/order?symbol=XBTUSD&filter={"ordStatus": "Filled"}&startTime=2024-10-20T00:00:00.000Z&endTime=2024-10-27T00:00:00.000Z&count=500&reverse=true

代码实现:Python 示例

使用 Python 编写脚本可以方便地自动化与加密货币交易所 API 的交互,例如检索历史交易数据。以下是一个使用 requests 库发送 API 请求的示例,该示例着重展示了如何构建身份验证所需的签名,这在与大多数交易所 API 交互时至关重要。

requests 库允许你发送 HTTP 请求, hashlib hmac 模块用于创建消息认证码,而 urllib.parse 则用于处理 URL。

import requests
import hashlib
import hmac
import time
import urllib.parse

请将以下占位符替换为你的实际 API 密钥和密钥。 这些密钥通常可以在你的交易所账户设置中找到。 请务必妥善保管你的 API 密钥,因为它们允许访问你的账户。

api_key = "YOUR_API_KEY"
api_secret = "YOUR_API_SECRET"

generate_signature 函数负责创建请求的数字签名。签名用于验证请求是否来自授权用户,并且数据在传输过程中未被篡改。此函数接收 API 密钥、HTTP 方法、API 端点路径、请求过期时间和请求数据作为输入。它将所有这些信息组合成一个消息,然后使用 HMAC-SHA256 算法和 API 密钥对其进行哈希处理。哈希值用作签名。

def generate_signature(api_secret, method, path, expires, data):
    """Generates an API signature."""
    if isinstance(data, bytes):
        data = data.decode('utf-8')

    parsed_url = urllib.parse.urlparse(path)
    query = parsed_url.query

    message = method + path + str(expires) + (data if method in ['POST', 'PUT'] else '')
    signature = hmac.new(api_secret.encode('utf-8'), message.encode('utf-8'), hashlib.sha256).hexdigest()
    return signature

get_orders 函数封装了对特定加密货币交易所 (例如 Bitmex) 历史订单的 API 调用。它接受各种参数,包括交易对的代码(symbol)、开始时间(start_time)、结束时间(end_time)、要返回的最大订单数量(count)、起始索引(start)和排序方向(reverse)。

该函数构造带有适当查询参数的 API 请求,例如交易对代码、已完成订单的状态筛选器、时间范围和分页参数。它使用 generate_signature 函数生成必要的 API 签名,然后将 API 密钥、签名和过期时间作为标头添加到请求中。

def get_orders(symbol, start_time, end_time, count=500, start=0, reverse=True):
    """Fetches historical orders from Bitmex API."""
    method = 'GET'
    path = '/api/v1/order'
    expires = int(time.time()) + 60  # Signature expires in 60 seconds
    data = ''   # No data for GET requests
    query_params = {
        'symbol': symbol,
        'filter': '{"ordStatus": "Filled"}',   # Only filled orders
        'startTime': start_time,
        'endTime': end_time,
        'count': count,
        'start': start,
        'reverse': reverse
    }

构建包含查询参数的完整 URL,然后使用 API 密钥、生成的签名和过期时间创建请求头。 requests.get 函数发送带有这些头信息的 GET 请求。

API 返回的响应会检查状态码。如果状态码为 200,则表示请求成功,函数会将响应数据(通常是 JSON 格式)返回。否则,将打印错误消息并返回 None

    # Construct the query string
    query_string = urllib.parse.urlencode(query_params)
    url = 'https://www.bitmex.com' + path + '?' + query_string

    signature = generate_signature(api_secret, method, path + '?' + query_string, expires, data)

    headers = {
        'api-key': api_key,
        'api-signature': signature,
        'api-expires': str(expires)
    }

    response = requests.get(url, headers=headers)

    if response.status_code == 200:
        return response.()
    else:
        print(f"Error: {response.status_code} - {response.text}")
        return None

Example usage:

为了从BitMEX交易所获取历史订单数据,您需要定义以下参数:

symbol = 'XBTUSD' :指定交易对,例如XBTUSD代表比特币/美元永续合约。您可以根据需要更改此参数以获取其他交易对的数据。

start_time = '2024-10-20T00:00:00.000Z' :指定数据起始时间,时间格式必须符合ISO 8601标准,并使用UTC时间。

end_time = '2024-10-27T00:00:00.000Z' :指定数据结束时间,同样需要符合ISO 8601标准和UTC时间。确保结束时间晚于起始时间。

然后,你可以调用 get_orders 函数,传入上述参数来获取订单数据:

orders = get_orders(symbol, start_time, end_time)

get_orders 函数将返回一个订单列表。您可以遍历该列表并处理每个订单的数据:

if orders: for order in orders: print(order) # Process each order data

请注意, print(order) 仅仅是一个示例。您需要根据您的实际需求来处理每个订单的数据,例如保存到数据库、进行统计分析等。订单数据通常包含订单ID、价格、数量、订单状态、下单时间等信息。

务必将 YOUR_API_KEY YOUR_API_SECRET 替换为你从BitMEX获得的真实API密钥。API密钥用于验证您的身份并授权您访问API。请妥善保管您的API密钥,避免泄露。建议开启两步验证以增强账户安全性。

代码段落概述:定义了 generate_signature 函数,它利用您的API密钥和API密钥的密钥,以及请求的HTTP方法和API端点,根据HMAC-SHA256算法生成加密签名。这个签名确保了请求在传输过程中没有被篡改,并验证了请求的来源。BitMEX要求在每个API请求头中都包含这个签名。接着, get_orders 函数负责构建API请求,包含必要的请求头(例如API密钥,API密钥的密钥和签名),以及查询参数(如交易对、起始时间和结束时间)。该函数会向BitMEX API发送请求并解析返回的JSON数据,提取订单信息。

数据解析与存储:选择合适的工具

获取到BitMEX API返回的原始订单数据后,首要任务便是对这些数据进行解析和高效存储。BitMEX API以JSON(JavaScript Object Notation)格式返回订单数据,这是一种轻量级的数据交换格式,易于阅读和解析。在Python环境中,标准库中的 模块是处理JSON数据的强大工具。通过该模块,可以将JSON格式的字符串数据转化为Python中的字典(dict)或列表(list)等数据结构,便于后续的数据处理和分析。

例如,可以使用以下Python代码片段进行JSON数据的解析:

import 

# 假设从BitMEX API获取的JSON数据存储在名为 _data 的字符串变量中
# _data = '{"orderID": "...", "symbol": "XBTUSD", "side": "Buy", ...}'

try:
    data = .loads(_data) # 将JSON字符串解析为Python字典或列表
    # 现在,可以通过键访问解析后的数据
    # order_id = data["orderID"]
    # symbol = data["symbol"]
    # side = data["side"]
    # ... 进行后续数据处理
except .JSONDecodeError as e:
    print(f"JSON解析错误: {e}")
    # 在实际应用中,需要妥善处理JSON解析错误,例如记录错误日志或采取重试策略

# 如果需要将Python对象转换为JSON字符串,可以使用 .dumps() 函数:
# _string = .dumps(data)

在存储方面,根据数据量和使用场景,可以选择不同的存储方案。对于小规模数据,可以直接存储在内存中,或者写入简单的文本文件或CSV文件中。对于中等规模的数据,可以选择关系型数据库(如MySQL、PostgreSQL)或NoSQL数据库(如MongoDB、Redis)。对于大规模数据,可以考虑使用分布式存储系统(如Hadoop HDFS、Amazon S3)或专门的时序数据库(如InfluxDB)以实现高效的数据读写和分析。

数据库的选择需要综合考虑以下因素:数据结构、数据量、查询需求、并发访问量、数据持久化要求以及成本等。例如,关系型数据库适合存储结构化数据,并支持复杂的SQL查询;NoSQL数据库适合存储非结构化或半结构化数据,具有较高的读写性能;时序数据库则专门为存储时间序列数据而设计,能够高效地处理带有时间戳的数据,非常适合存储交易数据。

假设 'response.text' 包含 JSON 数据

data = .loads(response.text)

这段代码首先使用 Python 的 .loads() 函数将 response.text 中包含的 JSON 字符串解析成 Python 字典或列表对象。 .loads() 是 Python 标准库 模块中的一个函数,专门用于将 JSON 格式的字符串转换为 Python 对象,从而方便后续的数据处理和访问。 确保 response.text 确实包含有效的 JSON 格式数据,否则 .loads() 函数会抛出异常。

接下来,代码遍历解析后的数据,假设 data 是一个包含订单信息的列表。每个订单都是一个字典,包含订单的详细信息。

for order in data:

对于每个订单,代码提取以下关键字段:

  • orderID = order['orderID'] : 订单的唯一标识符。
  • symbol = order['symbol'] : 交易对的符号,例如 "BTCUSDT"。
  • side = order['side'] : 订单方向,是买入 (buy) 还是卖出 (sell)。
  • orderQty = order['orderQty'] : 订单的数量,即交易的加密货币数量。
  • price = order['price'] : 订单的价格,即交易的单价。
  • ordStatus = order['ordStatus'] : 订单的状态,例如 "NEW", "FILLED", "CANCELED"。
  • transactTime = order['transactTime'] : 订单的交易时间,通常是 Unix 时间戳或 ISO 8601 格式的字符串。

这些字段通过字典的键来访问,例如 order['orderID'] 。确保 JSON 数据中包含这些键,否则会引发 KeyError 异常。在实际应用中,建议使用 try-except 块来处理可能出现的键不存在的情况。

print(f"OrderID: {orderID}, Symbol: {symbol}, Side: {side}, Quantity: {orderQty}, Price: {price}, Status: {ordStatus}, Time: {transactTime}")

代码使用 f-string 格式化字符串,将提取的订单信息打印到控制台。这是一个用于调试和验证数据的好方法。 在生产环境中,通常会将这些数据存储到数据库或文件中。

解析后的订单数据可以存储到不同的介质中,例如 CSV 文件、数据库 (如 SQLite, MySQL, PostgreSQL) 或数据仓库 (如 Amazon Redshift, Google BigQuery)。选择哪种存储方式取决于数据的量级、查询的复杂性和分析的需求。

  • CSV 文件 : 适用于小规模数据,易于导出和导入,可以使用 Python 的 csv 模块进行读写操作。例如,可以使用 csv.writer 将订单数据写入 CSV 文件。
  • 数据库 : 适用于中等规模数据,支持复杂查询和数据关系。可以使用 Python 的数据库连接库 (如 sqlite3 , pymysql , psycopg2 ) 连接到相应的数据库,并使用 SQL 语句进行数据插入、查询和更新操作。
  • 数据仓库 : 适用于大规模数据,支持高性能的分析和报表。通常需要使用专门的数据仓库客户端库 (如 boto3 for Redshift, google-cloud-bigquery for BigQuery) 连接到数据仓库,并使用 SQL 或其他查询语言进行数据分析。 数据仓库通常还提供分布式计算和存储能力,以处理海量数据。

应对分页:循环查询与高效数据抓取

BitMEX API 对单次请求返回的订单数量存在限制,通常最多为 500 条。因此,在需要检索大量历史订单数据时,必须采用分页查询的策略。一种常见的实现方式是使用循环迭代地调用 get_orders 函数,并动态调整 start 参数的值,从而实现对不同页面的数据抓取。

为了确保代码的健壮性和可维护性,分页查询的实现需要考虑以下几个关键因素:

  • 起始位置( start ): 每次循环迭代时, start 参数都需要递增,以指向下一页数据的起始位置。
  • 每次查询的数量( count ): 应保持每次查询的数量不变,通常设置为 API 允许的最大值(例如 500),以最大化数据抓取效率。
  • 循环终止条件: 需要明确定义循环终止的条件,以避免无限循环。通常有两种情况可以作为循环终止的标志:一是 get_orders 函数返回空列表,表示已经没有更多数据;二是返回的订单数量小于 count ,表明当前页面是最后一页,数据量不足 count

以下代码示例展示了如何通过循环调用 get_orders 函数来实现分页查询,并将查询结果存储到一个列表中:


all_orders = []
start = 0
count = 500  # BitMEX API 允许的最大单次返回订单数量

while True:
    orders = get_orders(symbol, start_time, end_time, count, start, reverse)

    if not orders:
        break  # API 返回空列表,表示没有更多数据

    all_orders.extend(orders)
    start += count

    if len(orders) < count:
        break  # 返回的订单数量小于 count,表明已到达最后一页

上述代码片段首先初始化一个空列表 all_orders ,用于存储所有查询到的订单数据。然后,进入一个无限循环,每次循环调用 get_orders 函数,并将返回的订单列表添加到 all_orders 中。 start 参数在每次循环后递增 count ,指向下一页数据的起始位置。循环在遇到空列表或返回订单数量小于 count 时终止,确保能够抓取所有数据,避免无限循环。

需要根据实际情况调整 get_orders 函数的参数,例如 symbol (交易对)、 start_time (起始时间)、 end_time (结束时间)和 reverse (排序方式)等,以满足特定的查询需求。

错误处理与重试机制

在实际的加密货币交易或数据获取应用中,与交易所API的交互并非总是顺利的。API请求不可避免地会遇到各种各样的错误,这些错误可能源于多种因素,例如临时性的网络连接中断、交易所服务器自身的错误(如内部错误或维护)、客户端请求超过了交易所设定的频率限制(Rate Limiting)等。为了显著提高程序的稳定性和健壮性,防止因偶发性错误导致程序崩溃或数据丢失,至关重要的是要实现完善的错误处理和重试机制。

import time

def get_orders_with_retry(symbol, start_time, end_time, count=500, start=0, reverse=True, max_retries=3):
"""Fetches historical orders with retry mechanism."""
for attempt in range(max_retries):
try:
orders = get_orders(symbol, start_time, end_time, count, start, reverse)
if orders:
return orders
else:
print("No orders returned.")
return None
except Exception as e:
print(f"Attempt {attempt + 1} failed: {e}")
time.sleep(2 ** attempt) # Exponential backoff
print("Max retries reached. Aborting.")
return None

上述代码片段展示了在 get_orders 函数的基础上,如何添加一个有效的重试机制。该机制的核心思想是:当与交易所API的请求交互过程中出现任何类型的异常(例如 requests.exceptions.ConnectionError requests.exceptions.Timeout 或交易所返回的特定错误码),程序并不会立即终止,而是会捕获这些异常,并根据预设的最大重试次数 max_retries 尝试重新发送请求。每次重试之间,程序会暂停一段时间,这个等待时间会随着重试次数的增加而呈指数增长(Exponential Backoff)。指数退避策略的优势在于,它可以在最初的几次重试时快速尝试恢复,而在后续的重试中,逐渐延长等待时间,从而避免在服务器繁忙或网络拥堵时对服务器造成过大的压力,同时也有助于提高重试成功的可能性。如果在达到最大重试次数后,请求仍然失败,则函数会放弃并返回 None ,同时打印错误信息,方便开发者进行问题排查。