# Quantum Execute Python SDK
[](https://pypi.org/project/qe-connector/)
[](https://pypi.org/project/qe-connector/)
[](https://opensource.org/licenses/MIT)
这是 Quantum Execute 公共 API 的官方 Python SDK,为开发者提供了一个轻量级、易于使用的接口来访问 Quantum Execute 的交易服务。
## 功能特性
- ✅ 完整的 Quantum Execute API 支持
- ✅ 交易所 API 密钥管理
- ✅ 主订单创建与管理(TWAP、VWAP 等算法)
- ✅ 订单查询和成交明细
- ✅ 多种认证方式支持(HMAC、RSA、Ed25519)
- ✅ 支持生产环境和测试环境
- ✅ 异步和同步调用支持
- ✅ 完善的错误处理和日志记录
## 安装
```bash
pip install qe-connector
```
或者从源码安装:
```bash
git clone https://github.com/Quantum-Execute/qe-connector-python.git
cd qe-connector-python
pip install -e .
```
## 快速开始
### 初始化客户端
```python
from qe.user import User as Client
import logging
# 配置日志(可选)
logging.basicConfig(level=logging.INFO)
# 创建生产环境客户端
client = Client(
api_key="your-api-key",
api_secret="your-api-secret"
)
# 创建测试环境客户端
client = Client(
api_key="your-api-key",
api_secret="your-api-secret",
base_url="https://testapi.quantumexecute.com"
)
```
## API 参考
### 交易所 API 管理
#### 查询交易所 API 列表
查询当前用户绑定的所有交易所 API 账户。
**请求参数:**
- `page` (int) - 页码,可选
- `pageSize` (int) - 每页数量,可选
- `exchange` (str) - 交易所名称筛选,可选
**响应字段:**
- `items` - API 列表,每个 API 包含以下字段:
- `id` - API 记录的唯一标识
- `createdAt` - API 添加时间
- `accountName` - 账户名称(如:账户1、账户2)
- `exchange` - 交易所名称(如:Binance、OKX、Bybit)
- `apiKey` - 交易所 API Key(部分隐藏)
- `verificationMethod` - API 验证方式(如:OAuth、API)
- `balance` - 账户余额(美元)
- `status` - API 状态:正常、异常(不可用)
- `isValid` - API 是否有效
- `isTradingEnabled` - 是否开启交易权限
- `isDefault` - 是否为该交易所的默认账户
- `isPm` - 是否为 Pm 账户
- `total` - API 总数
- `page` - 当前页码
- `pageSize` - 每页显示数量
**示例代码:**
```python
# 获取所有交易所 API 密钥
apis = client.list_exchange_apis()
print(f"共有 {apis['total']} 个 API 密钥")
# 打印每个 API 的详细信息
for api in apis['items']:
print(f"""
API 信息:
账户: {api['accountName']}
交易所: {api['exchange']}
状态: {api['status']}
余额: ${api['balance']:.2f}
交易权限: {'开启' if api['isTradingEnabled'] else '关闭'}
是否默认: {'是' if api['isDefault'] else '否'}
是否PM账户: {'是' if api['isPm'] else '否'}
添加时间: {api['createdAt']}
""")
# 带分页和过滤
apis = client.list_exchange_apis(
page=1,
pageSize=10,
exchange="binance"
)
```
#### 添加交易所 API
添加新的交易所 API 账户。
**请求参数:**
- `accountName` (str) - 账户名称,必填
- `exchange` (str) - 交易所名称(如:Binance、OKX、Bybit),必填
- `apiKey` (str) - 交易所 API Key,必填
- `apiSecret` (str) - 交易所 API Secret,必填
- `passphrase` (str) - API 密码短语(部分交易所需要),可选
- `verificationMethod` (str) - API 验证方式(如:OAuth、API),可选
- `enableTrading` (bool) - 是否开启交易权限,可选
**响应字段:**
- `id` - 新创建的 API ID
- `success` - 添加是否成功
- `message` - 操作结果消息
**示例代码:**
```python
# 添加币安 API
result = client.add_exchange_api(
accountName="我的币安账户",
exchange="binance",
apiKey="your-exchange-api-key",
apiSecret="your-exchange-api-secret",
enableTrading=True # 启用交易权限
)
if result['success']:
print(f"API Key 添加成功,ID: {result['id']}")
else:
print(f"API Key 添加失败:{result['message']}")
# 添加 OKX API(需要 passphrase)
result = client.add_exchange_api(
accountName="我的 OKX 账户",
exchange="okx",
apiKey="your-okx-api-key",
apiSecret="your-okx-api-secret",
passphrase="your-okx-passphrase",
verificationMethod="API",
enableTrading=True
)
```
### 交易订单管理
#### 创建主订单
创建新的主订单并提交到算法侧执行。
**请求参数:**
- `algorithm` (str) - 交易算法(如:VWAP、TWAP),必填
- `algorithmType` (str) - 算法分类,暂时固定传 "TIME_WEIGHTED",必填
- `exchange` (str) - 交易所名称(如:Binance、OKX),必填
- `symbol` (str) - 交易对符号(如:BTCUSDT),必填
- `marketType` (str) - 市场类型(SPOT:现货, FUTURES:合约),必填
- `side` (str) - 买卖方向(BUY:买入, SELL:卖出),必填
- `apiKeyId` (str) - 指定使用的 API 密钥 ID,必填
- `totalQuantity` (float) - 要交易的总数量(按币值时使用),与 orderNotional 二选一
- `orderNotional` (float) - 按价值下单时的金额(USDT),与 totalQuantity 二选一
- `strategyType` (str) - 策略类型(如:AGGRESSIVE、PASSIVE),可选
- `startTime` (str) - 开始执行时间(ISO 8601格式),可选
- `endTime` (str) - 结束时间(ISO 8601格式),TWAP-2 时必填
- `executionDuration` (int) - 执行时长(秒),TWAP-1 时必填
- `worstPrice` (float) - 最差成交价,必须完成为 true 时可选
- `limitPriceString` (str) - 限价字符串,超出范围停止交易,填 "-1" 不限制
- `upTolerance` (str) - 允许超出 schedule 的容忍度(如 "0.1" 表示 10%)
- `lowTolerance` (str) - 允许落后 schedule 的容忍度
- `strictUpBound` (bool) - 是否严格小于 upTolerance,不建议开启
- `mustComplete` (bool) - 是否必须在 duration 内执行完,默认 true
- `makerRateLimit` (float) - 要求 maker 占比超过该值(0-1)
- `povLimit` (float) - 占市场成交量比例限制(0-1)
- `marginType` (str) - 合约交易保证金类型(CROSS:全仓, ISOLATED:逐仓)
- `reduceOnly` (bool) - 合约交易时是否仅减仓,默认 false
- `notes` (str) - 订单备注,可选
- `clientId` (str) - 客户端唯一标识符,可选
**响应字段:**
- `masterOrderId` - 创建成功的主订单 ID
- `success` - 创建是否成功
- `message` - 创建结果消息
**示例代码:**
```python
# TWAP 订单示例 - 在 30 分钟内分批买入价值 $10,000 的 BTC
response = client.create_master_order(
algorithm="TWAP",
algorithmType="TIME_WEIGHTED",
exchange="binance",
symbol="BTCUSDT",
marketType="SPOT",
side="BUY",
apiKeyId="your-api-key-id", # 从 list_exchange_apis 获取
orderNotional=10000, # $10,000 名义价值
startTime="2024-01-01T10:00:00Z",
endTime="2024-01-01T10:30:00Z",
executionDuration="1800", # 30 分钟 = 1800 秒
mustComplete=True, # 必须完成全部订单
worstPrice=60000, # 最差价格 $60,000
upTolerance="0.1", # 允许超出 10%
lowTolerance="0.1", # 允许落后 10%
strictUpBound=False, # 不严格限制上界
clientId="my-order-001", # 自定义订单 ID
notes="测试 TWAP 订单" # 订单备注
)
if response.get('success'):
print(f"主订单创建成功,ID: {response['masterOrderId']}")
else:
print(f"创建失败:{response.get('message')}")
# 使用限价字符串的示例
response = client.create_master_order(
algorithm="TWAP",
algorithmType="TIME_WEIGHTED",
exchange="binance",
symbol="BTCUSDT",
marketType="SPOT",
side="BUY",
apiKeyId="your-api-key-id",
orderNotional=5000,
executionDuration="1800",
limitPriceString="50000", # 限价 $50,000(字符串格式)
upTolerance="0.05", # 允许超出 5%
lowTolerance="0.1", # 允许落后 10%
strictUpBound=False, # 关闭严格上界限制
mustComplete=True
)
```
#### 查询主订单列表
获取用户的主订单列表。
**请求参数:**
- `page` (int) - 页码,可选
- `pageSize` (int) - 每页数量,可选
- `status` (str) - 订单状态筛选,可选
- `exchange` (str) - 交易所名称筛选,可选
- `symbol` (str) - 交易对筛选,可选
- `startTime` (str) - 开始时间筛选,可选
- `endTime` (str) - 结束时间筛选,可选
**响应字段:**
- `items` - 主订单列表,每个订单包含:
- `masterOrderId` - 主订单 ID
- `algorithm` - 算法
- `algorithmType` - 算法类型
- `exchange` - 交易所
- `symbol` - 交易对
- `marketType` - 市场类型
- `side` - 买卖方向
- `totalQuantity` - 总数量
- `filledQuantity` - 已成交数量
- `averagePrice` - 平均成交价
- `status` - 状态
- `executionDuration` - 执行时长(秒)
- `priceLimit` - 价格限制
- `startTime` - 开始时间
- `endTime` - 结束时间
- `createdAt` - 创建时间
- `updatedAt` - 更新时间
- `notes` - 备注
- `marginType` - 保证金类型(U:U本位, C:币本位)
- `reduceOnly` - 是否仅减仓
- `strategyType` - 策略类型
- `orderNotional` - 订单金额(USDT)
- `mustComplete` - 是否必须完成
- `makerRateLimit` - 最低 Maker 率
- `povLimit` - 最大市场成交量占比
- `clientId` - 客户端 ID
- `date` - 发单日期(格式:YYYYMMDD)
- `ticktimeInt` - 发单时间(格式:093000000 表示 9:30:00.000)
- `limitPriceString` - 限价(字符串)
- `upTolerance` - 上容忍度
- `lowTolerance` - 下容忍度
- `strictUpBound` - 严格上界
- `ticktimeMs` - 发单时间戳(epoch 毫秒)
- `category` - 交易品种(spot 或 perp)
- `filledAmount` - 成交金额
- `totalValue` - 成交总值
- `base` - 基础币种
- `quote` - 计价币种
- `completionProgress` - 完成进度(0-1)
- `reason` - 原因(如取消原因)
- `total` - 总数
- `page` - 当前页码
- `pageSize` - 每页数量
**示例代码:**
```python
# 查询所有主订单
orders = client.get_master_orders()
# 带过滤条件查询
orders = client.get_master_orders(
page=1,
pageSize=20,
status="NEW", # 活跃订单
symbol="BTCUSDT",
startTime="2024-01-01T00:00:00Z",
endTime="2024-01-31T23:59:59Z"
)
# 打印订单详细信息
for order in orders['items']:
print(f"""
订单详情:
ID: {order['masterOrderId']}
算法: {order['algorithm']} ({order.get('strategyType', 'N/A')})
交易对: {order['symbol']} ({order['marketType']})
方向: {order['side']}
状态: {order['status']}
完成度: {order['completionProgress'] * 100:.2f}%
平均价格: ${order.get('averagePrice', 0):.2f}
已成交: {order['filledQuantity']:.4f} / {order['totalQuantity']:.4f}
成交金额: ${order.get('filledAmount', 0):.2f}
创建时间: {order['createdAt']}
发单日期: {order.get('date', 'N/A')}
限价: {order.get('limitPriceString', '-1')}
上容忍度: {order.get('upTolerance', 'N/A')}
下容忍度: {order.get('lowTolerance', 'N/A')}
严格上界: {order.get('strictUpBound', False)}
客户端ID: {order.get('clientId', 'N/A')}
备注: {order.get('notes', '')}
""")
# 统计信息
total_orders = len(orders['items'])
active_orders = sum(1 for o in orders['items'] if o['status'] == 'ACTIVE')
completed_orders = sum(1 for o in orders['items'] if o['status'] == 'COMPLETED')
print(f"\n统计:总订单 {total_orders},活跃 {active_orders},已完成 {completed_orders}")
```
#### 查询成交记录
获取用户的成交记录。
**请求参数:**
- `page` (int) - 页码,可选
- `pageSize` (int) - 每页数量,可选
- `masterOrderId` (str) - 主订单 ID 筛选,可选
- `subOrderId` (str) - 子订单 ID 筛选,可选
- `symbol` (str) - 交易对筛选,可选
- `startTime` (str) - 开始时间筛选,可选
- `endTime` (str) - 结束时间筛选,可选
**响应字段:**
- `items` - 成交记录列表,每条记录包含:
- `id` - 记录 ID
- `orderCreatedTime` - 订单创建时间
- `masterOrderId` - 主订单 ID
- `exchange` - 交易所
- `category` - 市场类型
- `symbol` - 交易对
- `side` - 方向
- `filledValue` - 成交价值
- `filledQuantity` - 成交数量
- `avgPrice` - 平均价格
- `price` - 成交价格
- `fee` - 手续费
- `tradingAccount` - 交易账户
- `status` - 状态
- `rejectReason` - 拒绝原因
- `base` - 基础币种
- `quote` - 计价币种
- `type` - 订单类型
- `total` - 总数
- `page` - 当前页码
- `pageSize` - 每页数量
**示例代码:**
```python
# 查询特定主订单的成交明细
fills = client.get_order_fills(
masterOrderId="your-master-order-id",
page=1,
pageSize=50
)
# 查询所有成交
fills = client.get_order_fills(
symbol="BTCUSDT",
startTime="2024-01-01T00:00:00Z",
endTime="2024-01-01T23:59:59Z"
)
# 分析成交数据
total_value = 0
total_fee = 0
fill_types = {}
for fill in fills['items']:
print(f"""
成交记录:
时间: {fill['orderCreatedTime']}
交易对: {fill['symbol']} ({fill['category']})
方向: {fill['side']}
成交价格: ${fill['price']:.2f}
成交数量: {fill['filledQuantity']:.6f}
成交金额: ${fill['filledValue']:.2f}
手续费: ${fill['fee']:.4f}
账户: {fill['tradingAccount']}
类型: {fill.get('type', 'N/A')}
状态: {fill['status']}
""")
total_value += fill['filledValue']
total_fee += fill['fee']
# 统计订单类型
order_type = fill.get('type', 'Unknown')
fill_types[order_type] = fill_types.get(order_type, 0) + 1
print(f"\n成交统计:")
print(f"总成交额: ${total_value:.2f}")
print(f"总手续费: ${total_fee:.2f}")
print(f"手续费率: {(total_fee/total_value*100):.3f}%")
print(f"订单类型分布: {fill_types}")
```
#### 取消主订单
取消指定的主订单。
**请求参数:**
- `masterOrderId` (str) - 要取消的主订单 ID,必填
- `reason` (str) - 取消原因,可选
**响应字段:**
- `success` - 取消是否成功
- `message` - 取消结果消息
**示例代码:**
```python
# 取消订单
response = client.cancel_master_order(
masterOrderId="your-master-order-id",
reason="用户手动取消" # 可选的取消原因
)
if response.get('success'):
print("订单取消成功")
else:
print(f"订单取消失败: {response.get('message')}")
# 批量取消示例
def cancel_all_active_orders(client):
"""取消所有活跃订单"""
orders = client.get_master_orders(status="ACTIVE")
cancelled_count = 0
for order in orders['items']:
try:
response = client.cancel_master_order(
masterOrderId=order['masterOrderId'],
reason="批量取消活跃订单"
)
if response.get('success'):
cancelled_count += 1
print(f"已取消订单: {order['masterOrderId']}")
else:
print(f"取消失败: {order['masterOrderId']} - {response.get('message')}")
except Exception as e:
print(f"取消异常: {order['masterOrderId']} - {str(e)}")
print(f"\n总计取消 {cancelled_count} 个订单")
return cancelled_count
```
## 错误处理
SDK 提供了详细的错误类型,方便进行精确的错误处理:
```python
from qe.error import ClientError, APIError
try:
response = client.create_master_order(
# ... 订单参数
)
except APIError as error:
# API 返回的业务错误
print(f"API 错误 - 代码: {error.code}, 原因: {error.reason}, 消息: {error.message}")
print(f"追踪 ID: {error.trace_id}") # 用于技术支持
# 根据错误代码处理
if error.code == 400:
print("请求参数错误,请检查输入")
elif error.code == 401:
print("认证失败,请检查 API 密钥")
elif error.code == 403:
print("权限不足")
elif error.code == 429:
print("请求过于频繁,请稍后重试")
except ClientError as error:
# 客户端错误(如参数错误、网络错误等)
print(f"客户端错误 - 状态码: {error.status_code}, 错误消息: {error.error_message}")
except Exception as error:
# 其他未预期的错误
print(f"未知错误: {error}")
```
## 高级配置
### 配置超时和代理
```python
client = Client(
api_key="your-api-key",
api_secret="your-api-secret",
timeout=30, # 30 秒超时
proxies={
'https': 'http://proxy.example.com:8080'
}
)
```
### 使用 RSA 或 Ed25519 签名
```python
# 使用 RSA 私钥
with open('private_key.pem', 'r') as f:
private_key = f.read()
client = Client(
api_key="your-api-key",
private_key=private_key,
private_key_pass="your-password" # 如果私钥有密码
)
# 使用 Ed25519 私钥
with open('ed25519_key.pem', 'r') as f:
ed25519_key = f.read()
client = Client(
api_key="your-api-key",
private_key=ed25519_key
)
```
### 显示请求限制使用情况
```python
client = Client(
api_key="your-api-key",
api_secret="your-api-secret",
show_limit_usage=True,
show_header=True
)
# API 响应将包含限制信息
response = client.get_master_orders()
if isinstance(response, dict) and 'limit_usage' in response:
print(f"限制使用情况: {response['limit_usage']}")
print(f"实际数据: {response['data']}")
```
### 配置日志
```python
import logging
from qe.lib.utils import config_logging
# 配置详细日志
config_logging(logging, logging.DEBUG)
# 只记录警告和错误
config_logging(logging, logging.WARNING)
```
## 完整示例
### 完整的交易流程示例
```python
import logging
from qe.user import User as Client
from qe.error import ClientError, APIError
from qe.lib.utils import config_logging
import time
from datetime import datetime, timedelta
# 配置日志
config_logging(logging, logging.INFO)
logger = logging.getLogger(__name__)
# 初始化客户端
client = Client("your-api-key", "your-api-secret")
try:
# 1. 获取可用的 API 密钥
apis = client.list_exchange_apis(exchange="binance")
if not apis['items']:
logger.error("没有找到可用的币安 API 密钥")
exit(1)
# 选择余额最高的账户
api_info = max(apis['items'], key=lambda x: x.get('balance', 0))
api_key_id = api_info['id']
logger.info(f"使用 API 密钥: {api_key_id}, 账户: {api_info['accountName']}, 余额: ${api_info['balance']:.2f}")
# 2. 创建 TWAP 订单
start_time = datetime.utcnow().isoformat() + 'Z'
end_time = (datetime.utcnow() + timedelta(minutes=10)).isoformat() + 'Z'
order_response = client.create_master_order(
algorithm="TWAP",
algorithmType="TIME_WEIGHTED",
exchange="binance",
symbol="BTCUSDT",
marketType="SPOT",
side="BUY",
apiKeyId=api_key_id,
orderNotional=1000, # $1000
startTime=start_time,
endTime=end_time,
executionDuration="30", # 每 30 秒执行一次
mustComplete=True,
worstPrice=70000, # 最差价格 $70,000
upTolerance="0.05", # 允许超出 5%
lowTolerance="0.05", # 允许落后 5%
strictUpBound=False,
clientId=f"test_order_{int(time.time())}",
notes="Python SDK 测试订单"
)
if not order_response.get('success'):
logger.error(f"创建订单失败: {order_response.get('message')}")
exit(1)
master_order_id = order_response['masterOrderId']
logger.info(f"订单创建成功,ID: {master_order_id}")
# 3. 监控订单状态
previous_progress = 0
while True:
orders = client.get_master_orders(
page=1,
pageSize=1,
status="ACTIVE"
)
if not orders['items']:
logger.info("订单已完成或取消")
break
order = orders['items'][0]
current_progress = order['completionProgress'] * 100
# 只在进度变化时打印
if current_progress != previous_progress:
logger.info(f"订单进度: {current_progress:.2f}%, "
f"已成交: {order['filledQuantity']:.6f}/{order['totalQuantity']:.6f}, "
f"平均价格: ${order.get('averagePrice', 0):.2f}")
previous_progress = current_progress
# 检查是否需要取消(演示用)
if current_progress > 50: # 完成超过 50%
logger.info("演示:取消订单")
cancel_response = client.cancel_master_order(
masterOrderId=master_order_id,
reason="演示取消"
)
if cancel_response.get('success'):
logger.info("订单已取消")
break
time.sleep(10) # 每 10 秒检查一次
# 4. 获取最终成交明细
fills = client.get_order_fills(masterOrderId=master_order_id)
logger.info(f"总成交笔数: {fills['total']}")
total_value = 0
total_fee = 0
for fill in fills['items']:
logger.info(f"成交: {fill['side']} {fill['filledQuantity']:.6f} {fill['symbol']} "
f"@ ${fill['price']:.2f}, 手续费: ${fill['fee']:.4f}")
total_value += fill['filledValue']
total_fee += fill['fee']
if total_value > 0:
logger.info(f"\n成交总结:")
logger.info(f"总成交额: ${total_value:.2f}")
logger.info(f"总手续费: ${total_fee:.2f}")
logger.info(f"手续费率: {(total_fee/total_value*100):.3f}%")
except APIError as error:
logger.error(f"API 错误: {error}")
except ClientError as error:
logger.error(f"客户端错误: {error}")
except Exception as error:
logger.error(f"未知错误: {error}")
```
### 策略执行示例
```python
def execute_vwap_strategy(client, symbol, amount_usd, duration_hours=8):
"""执行 VWAP 策略"""
logger = logging.getLogger(__name__)
try:
# 获取默认 API
apis = client.list_exchange_apis(exchange="binance")
default_api = next((api for api in apis['items'] if api.get('isDefault')), None)
if not default_api:
raise ValueError("没有找到默认的币安 API")
# 创建 VWAP 订单
start_time = datetime.utcnow().isoformat() + 'Z'
end_time = (datetime.utcnow() + timedelta(hours=duration_hours)).isoformat() + 'Z'
response = client.create_master_order(
algorithm="VWAP",
algorithmType="VOLUME_WEIGHTED",
exchange="binance",
symbol=symbol,
marketType="SPOT",
side="BUY",
apiKeyId=default_api['id'],
orderNotional=amount_usd,
startTime=start_time,
endTime=end_time,
strategyType="PASSIVE", # 被动策略,减少市场影响
makerRateLimit=0.5, # 50% Maker 订单
povLimit=0.05, # 最多占市场成交量 5%
mustComplete=False, # 不强制完成,避免滑点
upTolerance="0.02", # 2% 容忍度
lowTolerance="0.05", # 5% 容忍度
notes=f"VWAP 策略 - {symbol}"
)
if response.get('success'):
logger.info(f"VWAP 订单创建成功: {response['masterOrderId']}")
return response['masterOrderId']
else:
raise ValueError(f"订单创建失败: {response.get('message')}")
except Exception as e:
logger.error(f"执行 VWAP 策略失败: {str(e)}")
raise
# 使用示例
master_order_id = execute_vwap_strategy(
client,
symbol="ETHUSDT",
amount_usd=5000,
duration_hours=6
)
```
## API 文档
完整的 API 文档请参考 [Quantum Execute API 文档](https://docs.quantumexecute.com)
## 支持的算法类型
- **TWAP (Time Weighted Average Price)**: 时间加权平均价格算法,在指定时间段内平均分配订单
- **VWAP (Volume Weighted Average Price)**: 成交量加权平均价格算法,根据市场成交量分布执行订单
- **POV (Percentage of Volume)**: 成交量百分比算法,保持占市场成交量的固定比例
- **IMPLEMENTATION_SHORTFALL**: 执行缺口算法,最小化执行成本
## 最佳实践
### 1. API 密钥管理
```python
def check_api_health(client):
"""检查 API 密钥健康状态"""
apis = client.list_exchange_apis()
for api in apis['items']:
if not api['isValid']:
print(f"⚠️ 警告: API '{api['accountName']}' 状态异常")
if api['balance'] < 100:
print(f"⚠️ 警告: 账户 '{api['accountName']}' 余额不足 (${api['balance']:.2f})")
if not api['isTradingEnabled']:
print(f"ℹ️ 提示: API '{api['accountName']}' 未开启交易权限")
```
### 2. 订单参数验证
```python
def validate_order_params(params):
"""验证订单参数"""
errors = []
# 必填参数检查
required = ['algorithm', 'exchange', 'symbol', 'marketType', 'side', 'apiKeyId']
for field in required:
if not params.get(field):
errors.append(f"缺少必填参数: {field}")
# 数量验证
if not params.get('totalQuantity') and not params.get('orderNotional'):
errors.append("必须指定 totalQuantity 或 orderNotional")
# 时间验证
if params.get('startTime') and params.get('endTime'):
start = datetime.fromisoformat(params['startTime'].rstrip('Z'))
end = datetime.fromisoformat(params['endTime'].rstrip('Z'))
if start >= end:
errors.append("开始时间必须早于结束时间")
# 容忍度验证
for field in ['upTolerance', 'lowTolerance']:
if field in params:
try:
val = float(params[field])
if val < 0 or val > 1:
errors.append(f"{field} 必须在 0-1 之间")
except ValueError:
errors.append(f"{field} 必须是有效的数字")
return errors
```
### 3. 重试机制
```python
import time
from functools import wraps
def retry_on_error(max_retries=3, delay=1):
"""装饰器:自动重试失败的请求"""
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
last_error = None
for attempt in range(max_retries):
try:
return func(*args, **kwargs)
except APIError as e:
last_error = e
# 不重试客户端错误
if 400 <= e.code < 500:
raise
# 服务器错误,等待后重试
if attempt < max_retries - 1:
wait_time = delay * (2 ** attempt) # 指数退避
logger.warning(f"请求失败,{wait_time}秒后重试...")
time.sleep(wait_time)
except Exception as e:
last_error = e
if attempt < max_retries - 1:
time.sleep(delay)
raise last_error
return wrapper
return decorator
# 使用示例
@retry_on_error(max_retries=3, delay=2)
def create_order_with_retry(client, **params):
return client.create_master_order(**params)
```
## 常见问题
### 1. 如何获取 API 密钥?
请登录 Quantum Execute 平台,在用户设置中创建 API 密钥。确保保管好您的密钥,不要将其提交到版本控制系统中。
### 2. 时间戳错误怎么处理?
如果遇到时间戳相关的错误,可能是您的系统时间与服务器时间不同步。请确保系统时间准确。
### 3. 如何处理大量数据的分页?
```python
def get_all_data(fetch_func, **params):
"""通用的分页数据获取函数"""
all_items = []
page = 1
page_size = 100
while True:
result = fetch_func(page=page, pageSize=page_size, **params)
all_items.extend(result['items'])
if len(result['items']) < page_size:
break
page += 1
return all_items
# 使用示例
all_orders = get_all_data(client.get_master_orders, status="COMPLETED")
all_fills = get_all_data(client.get_order_fills, symbol="BTCUSDT")
```
### 4. 如何设置订单的时间?
时间格式使用 ISO 8601 标准,例如:
- UTC 时间:`2024-01-01T10:00:00Z`
- 带时区:`2024-01-01T18:00:00+08:00`
```python
from datetime import datetime, timezone
# 获取当前 UTC 时间
now_utc = datetime.now(timezone.utc).isoformat()
# 转换本地时间到 UTC
local_time = datetime.now()
utc_time = local_time.astimezone(timezone.utc).isoformat()
```
### 5. 容忍度参数说明
- `upTolerance`:允许超出计划进度的容忍度,如 "0.1" 表示允许超出 10%
- `lowTolerance`:允许落后计划进度的容忍度
- `strictUpBound`:是否严格限制在 upTolerance 以内,开启后可能导致小订单被过度拆分
## 示例代码
更多示例代码请参考 [examples](./examples) 目录:
- [添加交易所 API](examples/user/add_exchange_api.py)
- [创建主订单](examples/user/create_master_order.py)
- [取消主订单](examples/user/cancel_master_order.py)
- [查询订单列表](examples/user/get_master_orders.py)
- [查询成交明细](examples/user/get_order_fills.py)
## 开发和测试
### 安装开发依赖
```bash
pip install -r requirements/requirements-dev.txt
```
### 运行测试
```bash
python -m pytest tests/
```
### 代码格式化
```bash
black qe/
flake8 qe/
```
## 贡献指南
欢迎提交 Issue 和 Pull Request!请确保:
1. 代码符合 PEP 8 规范
2. 添加适当的测试
3. 更新相关文档
## 更新日志
### v1.0.0 (2024-01-01)
- 初始版本发布
- 支持完整的 Quantum Execute API
- 支持多种认证方式
- 完善的错误处理
## 许可证
本项目采用 MIT 许可证 - 详见 [LICENSE](LICENSE) 文件。
## 联系我们
- 官网:[https://test.quantumexecute.com](https://test.quantumexecute.com)
- 邮箱:support@quantumexecute.com
- GitHub:[https://github.com/Quantum-Execute/qe-connector-python](https://github.com/Quantum-Execute/qe-connector-python)
Raw data
{
"_id": null,
"home_page": "https://github.com/Quantum-Execute/qe-connector-python",
"name": "qe-connector",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "Quantum-Execute, Public API",
"author": "Quantum-Execute",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/88/da/debe587b57bd0815994dc86e4f5c0a05159bb2b8658b353d33b0fb030caf/qe-connector-1.0.1.tar.gz",
"platform": null,
"description": "# Quantum Execute Python SDK\r\n\r\n[](https://pypi.org/project/qe-connector/)\r\n[](https://pypi.org/project/qe-connector/)\r\n[](https://opensource.org/licenses/MIT)\r\n\r\n\u8fd9\u662f Quantum Execute \u516c\u5171 API \u7684\u5b98\u65b9 Python SDK\uff0c\u4e3a\u5f00\u53d1\u8005\u63d0\u4f9b\u4e86\u4e00\u4e2a\u8f7b\u91cf\u7ea7\u3001\u6613\u4e8e\u4f7f\u7528\u7684\u63a5\u53e3\u6765\u8bbf\u95ee Quantum Execute \u7684\u4ea4\u6613\u670d\u52a1\u3002\r\n\r\n## \u529f\u80fd\u7279\u6027\r\n\r\n- \u2705 \u5b8c\u6574\u7684 Quantum Execute API \u652f\u6301\r\n- \u2705 \u4ea4\u6613\u6240 API \u5bc6\u94a5\u7ba1\u7406\r\n- \u2705 \u4e3b\u8ba2\u5355\u521b\u5efa\u4e0e\u7ba1\u7406\uff08TWAP\u3001VWAP \u7b49\u7b97\u6cd5\uff09\r\n- \u2705 \u8ba2\u5355\u67e5\u8be2\u548c\u6210\u4ea4\u660e\u7ec6\r\n- \u2705 \u591a\u79cd\u8ba4\u8bc1\u65b9\u5f0f\u652f\u6301\uff08HMAC\u3001RSA\u3001Ed25519\uff09\r\n- \u2705 \u652f\u6301\u751f\u4ea7\u73af\u5883\u548c\u6d4b\u8bd5\u73af\u5883\r\n- \u2705 \u5f02\u6b65\u548c\u540c\u6b65\u8c03\u7528\u652f\u6301\r\n- \u2705 \u5b8c\u5584\u7684\u9519\u8bef\u5904\u7406\u548c\u65e5\u5fd7\u8bb0\u5f55\r\n\r\n## \u5b89\u88c5\r\n\r\n```bash\r\npip install qe-connector\r\n```\r\n\r\n\u6216\u8005\u4ece\u6e90\u7801\u5b89\u88c5\uff1a\r\n\r\n```bash\r\ngit clone https://github.com/Quantum-Execute/qe-connector-python.git\r\ncd qe-connector-python\r\npip install -e .\r\n```\r\n\r\n## \u5feb\u901f\u5f00\u59cb\r\n\r\n### \u521d\u59cb\u5316\u5ba2\u6237\u7aef\r\n\r\n```python\r\nfrom qe.user import User as Client\r\nimport logging\r\n\r\n# \u914d\u7f6e\u65e5\u5fd7\uff08\u53ef\u9009\uff09\r\nlogging.basicConfig(level=logging.INFO)\r\n\r\n# \u521b\u5efa\u751f\u4ea7\u73af\u5883\u5ba2\u6237\u7aef\r\nclient = Client(\r\n api_key=\"your-api-key\",\r\n api_secret=\"your-api-secret\"\r\n)\r\n\r\n# \u521b\u5efa\u6d4b\u8bd5\u73af\u5883\u5ba2\u6237\u7aef\r\nclient = Client(\r\n api_key=\"your-api-key\",\r\n api_secret=\"your-api-secret\",\r\n base_url=\"https://testapi.quantumexecute.com\"\r\n)\r\n```\r\n\r\n## API \u53c2\u8003\r\n\r\n### \u4ea4\u6613\u6240 API \u7ba1\u7406\r\n\r\n#### \u67e5\u8be2\u4ea4\u6613\u6240 API \u5217\u8868\r\n\r\n\u67e5\u8be2\u5f53\u524d\u7528\u6237\u7ed1\u5b9a\u7684\u6240\u6709\u4ea4\u6613\u6240 API \u8d26\u6237\u3002\r\n\r\n**\u8bf7\u6c42\u53c2\u6570\uff1a**\r\n- `page` (int) - \u9875\u7801\uff0c\u53ef\u9009\r\n- `pageSize` (int) - \u6bcf\u9875\u6570\u91cf\uff0c\u53ef\u9009\r\n- `exchange` (str) - \u4ea4\u6613\u6240\u540d\u79f0\u7b5b\u9009\uff0c\u53ef\u9009\r\n\r\n**\u54cd\u5e94\u5b57\u6bb5\uff1a**\r\n- `items` - API \u5217\u8868\uff0c\u6bcf\u4e2a API \u5305\u542b\u4ee5\u4e0b\u5b57\u6bb5\uff1a\r\n - `id` - API \u8bb0\u5f55\u7684\u552f\u4e00\u6807\u8bc6\r\n - `createdAt` - API \u6dfb\u52a0\u65f6\u95f4\r\n - `accountName` - \u8d26\u6237\u540d\u79f0\uff08\u5982\uff1a\u8d26\u62371\u3001\u8d26\u62372\uff09\r\n - `exchange` - \u4ea4\u6613\u6240\u540d\u79f0\uff08\u5982\uff1aBinance\u3001OKX\u3001Bybit\uff09\r\n - `apiKey` - \u4ea4\u6613\u6240 API Key\uff08\u90e8\u5206\u9690\u85cf\uff09\r\n - `verificationMethod` - API \u9a8c\u8bc1\u65b9\u5f0f\uff08\u5982\uff1aOAuth\u3001API\uff09\r\n - `balance` - \u8d26\u6237\u4f59\u989d\uff08\u7f8e\u5143\uff09\r\n - `status` - API \u72b6\u6001\uff1a\u6b63\u5e38\u3001\u5f02\u5e38\uff08\u4e0d\u53ef\u7528\uff09\r\n - `isValid` - API \u662f\u5426\u6709\u6548\r\n - `isTradingEnabled` - \u662f\u5426\u5f00\u542f\u4ea4\u6613\u6743\u9650\r\n - `isDefault` - \u662f\u5426\u4e3a\u8be5\u4ea4\u6613\u6240\u7684\u9ed8\u8ba4\u8d26\u6237\r\n - `isPm` - \u662f\u5426\u4e3a Pm \u8d26\u6237\r\n- `total` - API \u603b\u6570\r\n- `page` - \u5f53\u524d\u9875\u7801\r\n- `pageSize` - \u6bcf\u9875\u663e\u793a\u6570\u91cf\r\n\r\n**\u793a\u4f8b\u4ee3\u7801\uff1a**\r\n\r\n```python\r\n# \u83b7\u53d6\u6240\u6709\u4ea4\u6613\u6240 API \u5bc6\u94a5\r\napis = client.list_exchange_apis()\r\nprint(f\"\u5171\u6709 {apis['total']} \u4e2a API \u5bc6\u94a5\")\r\n\r\n# \u6253\u5370\u6bcf\u4e2a API \u7684\u8be6\u7ec6\u4fe1\u606f\r\nfor api in apis['items']:\r\n print(f\"\"\"\r\nAPI \u4fe1\u606f\uff1a\r\n \u8d26\u6237: {api['accountName']}\r\n \u4ea4\u6613\u6240: {api['exchange']}\r\n \u72b6\u6001: {api['status']}\r\n \u4f59\u989d: ${api['balance']:.2f}\r\n \u4ea4\u6613\u6743\u9650: {'\u5f00\u542f' if api['isTradingEnabled'] else '\u5173\u95ed'}\r\n \u662f\u5426\u9ed8\u8ba4: {'\u662f' if api['isDefault'] else '\u5426'}\r\n \u662f\u5426PM\u8d26\u6237: {'\u662f' if api['isPm'] else '\u5426'}\r\n \u6dfb\u52a0\u65f6\u95f4: {api['createdAt']}\r\n \"\"\")\r\n\r\n# \u5e26\u5206\u9875\u548c\u8fc7\u6ee4\r\napis = client.list_exchange_apis(\r\n page=1,\r\n pageSize=10,\r\n exchange=\"binance\"\r\n)\r\n```\r\n\r\n#### \u6dfb\u52a0\u4ea4\u6613\u6240 API\r\n\r\n\u6dfb\u52a0\u65b0\u7684\u4ea4\u6613\u6240 API \u8d26\u6237\u3002\r\n\r\n**\u8bf7\u6c42\u53c2\u6570\uff1a**\r\n- `accountName` (str) - \u8d26\u6237\u540d\u79f0\uff0c\u5fc5\u586b\r\n- `exchange` (str) - \u4ea4\u6613\u6240\u540d\u79f0\uff08\u5982\uff1aBinance\u3001OKX\u3001Bybit\uff09\uff0c\u5fc5\u586b\r\n- `apiKey` (str) - \u4ea4\u6613\u6240 API Key\uff0c\u5fc5\u586b\r\n- `apiSecret` (str) - \u4ea4\u6613\u6240 API Secret\uff0c\u5fc5\u586b\r\n- `passphrase` (str) - API \u5bc6\u7801\u77ed\u8bed\uff08\u90e8\u5206\u4ea4\u6613\u6240\u9700\u8981\uff09\uff0c\u53ef\u9009\r\n- `verificationMethod` (str) - API \u9a8c\u8bc1\u65b9\u5f0f\uff08\u5982\uff1aOAuth\u3001API\uff09\uff0c\u53ef\u9009\r\n- `enableTrading` (bool) - \u662f\u5426\u5f00\u542f\u4ea4\u6613\u6743\u9650\uff0c\u53ef\u9009\r\n\r\n**\u54cd\u5e94\u5b57\u6bb5\uff1a**\r\n- `id` - \u65b0\u521b\u5efa\u7684 API ID\r\n- `success` - \u6dfb\u52a0\u662f\u5426\u6210\u529f\r\n- `message` - \u64cd\u4f5c\u7ed3\u679c\u6d88\u606f\r\n\r\n**\u793a\u4f8b\u4ee3\u7801\uff1a**\r\n\r\n```python\r\n# \u6dfb\u52a0\u5e01\u5b89 API\r\nresult = client.add_exchange_api(\r\n accountName=\"\u6211\u7684\u5e01\u5b89\u8d26\u6237\",\r\n exchange=\"binance\",\r\n apiKey=\"your-exchange-api-key\",\r\n apiSecret=\"your-exchange-api-secret\",\r\n enableTrading=True # \u542f\u7528\u4ea4\u6613\u6743\u9650\r\n)\r\n\r\nif result['success']:\r\n print(f\"API Key \u6dfb\u52a0\u6210\u529f\uff0cID: {result['id']}\")\r\nelse:\r\n print(f\"API Key \u6dfb\u52a0\u5931\u8d25\uff1a{result['message']}\")\r\n\r\n# \u6dfb\u52a0 OKX API\uff08\u9700\u8981 passphrase\uff09\r\nresult = client.add_exchange_api(\r\n accountName=\"\u6211\u7684 OKX \u8d26\u6237\",\r\n exchange=\"okx\",\r\n apiKey=\"your-okx-api-key\",\r\n apiSecret=\"your-okx-api-secret\",\r\n passphrase=\"your-okx-passphrase\",\r\n verificationMethod=\"API\",\r\n enableTrading=True\r\n)\r\n```\r\n\r\n### \u4ea4\u6613\u8ba2\u5355\u7ba1\u7406\r\n\r\n#### \u521b\u5efa\u4e3b\u8ba2\u5355\r\n\r\n\u521b\u5efa\u65b0\u7684\u4e3b\u8ba2\u5355\u5e76\u63d0\u4ea4\u5230\u7b97\u6cd5\u4fa7\u6267\u884c\u3002\r\n\r\n**\u8bf7\u6c42\u53c2\u6570\uff1a**\r\n- `algorithm` (str) - \u4ea4\u6613\u7b97\u6cd5\uff08\u5982\uff1aVWAP\u3001TWAP\uff09\uff0c\u5fc5\u586b\r\n- `algorithmType` (str) - \u7b97\u6cd5\u5206\u7c7b\uff0c\u6682\u65f6\u56fa\u5b9a\u4f20 \"TIME_WEIGHTED\"\uff0c\u5fc5\u586b\r\n- `exchange` (str) - \u4ea4\u6613\u6240\u540d\u79f0\uff08\u5982\uff1aBinance\u3001OKX\uff09\uff0c\u5fc5\u586b\r\n- `symbol` (str) - \u4ea4\u6613\u5bf9\u7b26\u53f7\uff08\u5982\uff1aBTCUSDT\uff09\uff0c\u5fc5\u586b\r\n- `marketType` (str) - \u5e02\u573a\u7c7b\u578b\uff08SPOT:\u73b0\u8d27, FUTURES:\u5408\u7ea6\uff09\uff0c\u5fc5\u586b\r\n- `side` (str) - \u4e70\u5356\u65b9\u5411\uff08BUY:\u4e70\u5165, SELL:\u5356\u51fa\uff09\uff0c\u5fc5\u586b\r\n- `apiKeyId` (str) - \u6307\u5b9a\u4f7f\u7528\u7684 API \u5bc6\u94a5 ID\uff0c\u5fc5\u586b\r\n- `totalQuantity` (float) - \u8981\u4ea4\u6613\u7684\u603b\u6570\u91cf\uff08\u6309\u5e01\u503c\u65f6\u4f7f\u7528\uff09\uff0c\u4e0e orderNotional \u4e8c\u9009\u4e00\r\n- `orderNotional` (float) - \u6309\u4ef7\u503c\u4e0b\u5355\u65f6\u7684\u91d1\u989d\uff08USDT\uff09\uff0c\u4e0e totalQuantity \u4e8c\u9009\u4e00\r\n- `strategyType` (str) - \u7b56\u7565\u7c7b\u578b\uff08\u5982\uff1aAGGRESSIVE\u3001PASSIVE\uff09\uff0c\u53ef\u9009\r\n- `startTime` (str) - \u5f00\u59cb\u6267\u884c\u65f6\u95f4\uff08ISO 8601\u683c\u5f0f\uff09\uff0c\u53ef\u9009\r\n- `endTime` (str) - \u7ed3\u675f\u65f6\u95f4\uff08ISO 8601\u683c\u5f0f\uff09\uff0cTWAP-2 \u65f6\u5fc5\u586b\r\n- `executionDuration` (int) - \u6267\u884c\u65f6\u957f\uff08\u79d2\uff09\uff0cTWAP-1 \u65f6\u5fc5\u586b\r\n- `worstPrice` (float) - \u6700\u5dee\u6210\u4ea4\u4ef7\uff0c\u5fc5\u987b\u5b8c\u6210\u4e3a true \u65f6\u53ef\u9009\r\n- `limitPriceString` (str) - \u9650\u4ef7\u5b57\u7b26\u4e32\uff0c\u8d85\u51fa\u8303\u56f4\u505c\u6b62\u4ea4\u6613\uff0c\u586b \"-1\" \u4e0d\u9650\u5236\r\n- `upTolerance` (str) - \u5141\u8bb8\u8d85\u51fa schedule \u7684\u5bb9\u5fcd\u5ea6\uff08\u5982 \"0.1\" \u8868\u793a 10%\uff09\r\n- `lowTolerance` (str) - \u5141\u8bb8\u843d\u540e schedule \u7684\u5bb9\u5fcd\u5ea6\r\n- `strictUpBound` (bool) - \u662f\u5426\u4e25\u683c\u5c0f\u4e8e upTolerance\uff0c\u4e0d\u5efa\u8bae\u5f00\u542f\r\n- `mustComplete` (bool) - \u662f\u5426\u5fc5\u987b\u5728 duration \u5185\u6267\u884c\u5b8c\uff0c\u9ed8\u8ba4 true\r\n- `makerRateLimit` (float) - \u8981\u6c42 maker \u5360\u6bd4\u8d85\u8fc7\u8be5\u503c\uff080-1\uff09\r\n- `povLimit` (float) - \u5360\u5e02\u573a\u6210\u4ea4\u91cf\u6bd4\u4f8b\u9650\u5236\uff080-1\uff09\r\n- `marginType` (str) - \u5408\u7ea6\u4ea4\u6613\u4fdd\u8bc1\u91d1\u7c7b\u578b\uff08CROSS:\u5168\u4ed3, ISOLATED:\u9010\u4ed3\uff09\r\n- `reduceOnly` (bool) - \u5408\u7ea6\u4ea4\u6613\u65f6\u662f\u5426\u4ec5\u51cf\u4ed3\uff0c\u9ed8\u8ba4 false\r\n- `notes` (str) - \u8ba2\u5355\u5907\u6ce8\uff0c\u53ef\u9009\r\n- `clientId` (str) - \u5ba2\u6237\u7aef\u552f\u4e00\u6807\u8bc6\u7b26\uff0c\u53ef\u9009\r\n\r\n**\u54cd\u5e94\u5b57\u6bb5\uff1a**\r\n- `masterOrderId` - \u521b\u5efa\u6210\u529f\u7684\u4e3b\u8ba2\u5355 ID\r\n- `success` - \u521b\u5efa\u662f\u5426\u6210\u529f\r\n- `message` - \u521b\u5efa\u7ed3\u679c\u6d88\u606f\r\n\r\n**\u793a\u4f8b\u4ee3\u7801\uff1a**\r\n\r\n```python\r\n# TWAP \u8ba2\u5355\u793a\u4f8b - \u5728 30 \u5206\u949f\u5185\u5206\u6279\u4e70\u5165\u4ef7\u503c $10,000 \u7684 BTC\r\nresponse = client.create_master_order(\r\n algorithm=\"TWAP\",\r\n algorithmType=\"TIME_WEIGHTED\",\r\n exchange=\"binance\",\r\n symbol=\"BTCUSDT\",\r\n marketType=\"SPOT\",\r\n side=\"BUY\",\r\n apiKeyId=\"your-api-key-id\", # \u4ece list_exchange_apis \u83b7\u53d6\r\n orderNotional=10000, # $10,000 \u540d\u4e49\u4ef7\u503c\r\n startTime=\"2024-01-01T10:00:00Z\",\r\n endTime=\"2024-01-01T10:30:00Z\",\r\n executionDuration=\"1800\", # 30 \u5206\u949f = 1800 \u79d2\r\n mustComplete=True, # \u5fc5\u987b\u5b8c\u6210\u5168\u90e8\u8ba2\u5355\r\n worstPrice=60000, # \u6700\u5dee\u4ef7\u683c $60,000\r\n upTolerance=\"0.1\", # \u5141\u8bb8\u8d85\u51fa 10%\r\n lowTolerance=\"0.1\", # \u5141\u8bb8\u843d\u540e 10%\r\n strictUpBound=False, # \u4e0d\u4e25\u683c\u9650\u5236\u4e0a\u754c\r\n clientId=\"my-order-001\", # \u81ea\u5b9a\u4e49\u8ba2\u5355 ID\r\n notes=\"\u6d4b\u8bd5 TWAP \u8ba2\u5355\" # \u8ba2\u5355\u5907\u6ce8\r\n)\r\n\r\nif response.get('success'):\r\n print(f\"\u4e3b\u8ba2\u5355\u521b\u5efa\u6210\u529f\uff0cID: {response['masterOrderId']}\")\r\nelse:\r\n print(f\"\u521b\u5efa\u5931\u8d25\uff1a{response.get('message')}\")\r\n\r\n\r\n# \u4f7f\u7528\u9650\u4ef7\u5b57\u7b26\u4e32\u7684\u793a\u4f8b\r\nresponse = client.create_master_order(\r\n algorithm=\"TWAP\",\r\n algorithmType=\"TIME_WEIGHTED\",\r\n exchange=\"binance\",\r\n symbol=\"BTCUSDT\",\r\n marketType=\"SPOT\",\r\n side=\"BUY\",\r\n apiKeyId=\"your-api-key-id\",\r\n orderNotional=5000,\r\n executionDuration=\"1800\",\r\n limitPriceString=\"50000\", # \u9650\u4ef7 $50,000\uff08\u5b57\u7b26\u4e32\u683c\u5f0f\uff09\r\n upTolerance=\"0.05\", # \u5141\u8bb8\u8d85\u51fa 5%\r\n lowTolerance=\"0.1\", # \u5141\u8bb8\u843d\u540e 10%\r\n strictUpBound=False, # \u5173\u95ed\u4e25\u683c\u4e0a\u754c\u9650\u5236\r\n mustComplete=True\r\n)\r\n```\r\n\r\n#### \u67e5\u8be2\u4e3b\u8ba2\u5355\u5217\u8868\r\n\r\n\u83b7\u53d6\u7528\u6237\u7684\u4e3b\u8ba2\u5355\u5217\u8868\u3002\r\n\r\n**\u8bf7\u6c42\u53c2\u6570\uff1a**\r\n- `page` (int) - \u9875\u7801\uff0c\u53ef\u9009\r\n- `pageSize` (int) - \u6bcf\u9875\u6570\u91cf\uff0c\u53ef\u9009\r\n- `status` (str) - \u8ba2\u5355\u72b6\u6001\u7b5b\u9009\uff0c\u53ef\u9009\r\n- `exchange` (str) - \u4ea4\u6613\u6240\u540d\u79f0\u7b5b\u9009\uff0c\u53ef\u9009\r\n- `symbol` (str) - \u4ea4\u6613\u5bf9\u7b5b\u9009\uff0c\u53ef\u9009\r\n- `startTime` (str) - \u5f00\u59cb\u65f6\u95f4\u7b5b\u9009\uff0c\u53ef\u9009\r\n- `endTime` (str) - \u7ed3\u675f\u65f6\u95f4\u7b5b\u9009\uff0c\u53ef\u9009\r\n\r\n**\u54cd\u5e94\u5b57\u6bb5\uff1a**\r\n- `items` - \u4e3b\u8ba2\u5355\u5217\u8868\uff0c\u6bcf\u4e2a\u8ba2\u5355\u5305\u542b\uff1a\r\n - `masterOrderId` - \u4e3b\u8ba2\u5355 ID\r\n - `algorithm` - \u7b97\u6cd5\r\n - `algorithmType` - \u7b97\u6cd5\u7c7b\u578b\r\n - `exchange` - \u4ea4\u6613\u6240\r\n - `symbol` - \u4ea4\u6613\u5bf9\r\n - `marketType` - \u5e02\u573a\u7c7b\u578b\r\n - `side` - \u4e70\u5356\u65b9\u5411\r\n - `totalQuantity` - \u603b\u6570\u91cf\r\n - `filledQuantity` - \u5df2\u6210\u4ea4\u6570\u91cf\r\n - `averagePrice` - \u5e73\u5747\u6210\u4ea4\u4ef7\r\n - `status` - \u72b6\u6001\r\n - `executionDuration` - \u6267\u884c\u65f6\u957f\uff08\u79d2\uff09\r\n - `priceLimit` - \u4ef7\u683c\u9650\u5236\r\n - `startTime` - \u5f00\u59cb\u65f6\u95f4\r\n - `endTime` - \u7ed3\u675f\u65f6\u95f4\r\n - `createdAt` - \u521b\u5efa\u65f6\u95f4\r\n - `updatedAt` - \u66f4\u65b0\u65f6\u95f4\r\n - `notes` - \u5907\u6ce8\r\n - `marginType` - \u4fdd\u8bc1\u91d1\u7c7b\u578b\uff08U:U\u672c\u4f4d, C:\u5e01\u672c\u4f4d\uff09\r\n - `reduceOnly` - \u662f\u5426\u4ec5\u51cf\u4ed3\r\n - `strategyType` - \u7b56\u7565\u7c7b\u578b\r\n - `orderNotional` - \u8ba2\u5355\u91d1\u989d\uff08USDT\uff09\r\n - `mustComplete` - \u662f\u5426\u5fc5\u987b\u5b8c\u6210\r\n - `makerRateLimit` - \u6700\u4f4e Maker \u7387\r\n - `povLimit` - \u6700\u5927\u5e02\u573a\u6210\u4ea4\u91cf\u5360\u6bd4\r\n - `clientId` - \u5ba2\u6237\u7aef ID\r\n - `date` - \u53d1\u5355\u65e5\u671f\uff08\u683c\u5f0f\uff1aYYYYMMDD\uff09\r\n - `ticktimeInt` - \u53d1\u5355\u65f6\u95f4\uff08\u683c\u5f0f\uff1a093000000 \u8868\u793a 9:30:00.000\uff09\r\n - `limitPriceString` - \u9650\u4ef7\uff08\u5b57\u7b26\u4e32\uff09\r\n - `upTolerance` - \u4e0a\u5bb9\u5fcd\u5ea6\r\n - `lowTolerance` - \u4e0b\u5bb9\u5fcd\u5ea6\r\n - `strictUpBound` - \u4e25\u683c\u4e0a\u754c\r\n - `ticktimeMs` - \u53d1\u5355\u65f6\u95f4\u6233\uff08epoch \u6beb\u79d2\uff09\r\n - `category` - \u4ea4\u6613\u54c1\u79cd\uff08spot \u6216 perp\uff09\r\n - `filledAmount` - \u6210\u4ea4\u91d1\u989d\r\n - `totalValue` - \u6210\u4ea4\u603b\u503c\r\n - `base` - \u57fa\u7840\u5e01\u79cd\r\n - `quote` - \u8ba1\u4ef7\u5e01\u79cd\r\n - `completionProgress` - \u5b8c\u6210\u8fdb\u5ea6\uff080-1\uff09\r\n - `reason` - \u539f\u56e0\uff08\u5982\u53d6\u6d88\u539f\u56e0\uff09\r\n- `total` - \u603b\u6570\r\n- `page` - \u5f53\u524d\u9875\u7801\r\n- `pageSize` - \u6bcf\u9875\u6570\u91cf\r\n\r\n**\u793a\u4f8b\u4ee3\u7801\uff1a**\r\n\r\n```python\r\n# \u67e5\u8be2\u6240\u6709\u4e3b\u8ba2\u5355\r\norders = client.get_master_orders()\r\n\r\n# \u5e26\u8fc7\u6ee4\u6761\u4ef6\u67e5\u8be2\r\norders = client.get_master_orders(\r\n page=1,\r\n pageSize=20,\r\n status=\"NEW\", # \u6d3b\u8dc3\u8ba2\u5355\r\n symbol=\"BTCUSDT\",\r\n startTime=\"2024-01-01T00:00:00Z\",\r\n endTime=\"2024-01-31T23:59:59Z\"\r\n)\r\n\r\n# \u6253\u5370\u8ba2\u5355\u8be6\u7ec6\u4fe1\u606f\r\nfor order in orders['items']:\r\n print(f\"\"\"\r\n\u8ba2\u5355\u8be6\u60c5\uff1a\r\n ID: {order['masterOrderId']}\r\n \u7b97\u6cd5: {order['algorithm']} ({order.get('strategyType', 'N/A')})\r\n \u4ea4\u6613\u5bf9: {order['symbol']} ({order['marketType']})\r\n \u65b9\u5411: {order['side']}\r\n \u72b6\u6001: {order['status']}\r\n \u5b8c\u6210\u5ea6: {order['completionProgress'] * 100:.2f}%\r\n \u5e73\u5747\u4ef7\u683c: ${order.get('averagePrice', 0):.2f}\r\n \u5df2\u6210\u4ea4: {order['filledQuantity']:.4f} / {order['totalQuantity']:.4f}\r\n \u6210\u4ea4\u91d1\u989d: ${order.get('filledAmount', 0):.2f}\r\n \u521b\u5efa\u65f6\u95f4: {order['createdAt']}\r\n \u53d1\u5355\u65e5\u671f: {order.get('date', 'N/A')}\r\n \u9650\u4ef7: {order.get('limitPriceString', '-1')}\r\n \u4e0a\u5bb9\u5fcd\u5ea6: {order.get('upTolerance', 'N/A')}\r\n \u4e0b\u5bb9\u5fcd\u5ea6: {order.get('lowTolerance', 'N/A')}\r\n \u4e25\u683c\u4e0a\u754c: {order.get('strictUpBound', False)}\r\n \u5ba2\u6237\u7aefID: {order.get('clientId', 'N/A')}\r\n \u5907\u6ce8: {order.get('notes', '')}\r\n \"\"\")\r\n\r\n# \u7edf\u8ba1\u4fe1\u606f\r\ntotal_orders = len(orders['items'])\r\nactive_orders = sum(1 for o in orders['items'] if o['status'] == 'ACTIVE')\r\ncompleted_orders = sum(1 for o in orders['items'] if o['status'] == 'COMPLETED')\r\nprint(f\"\\n\u7edf\u8ba1\uff1a\u603b\u8ba2\u5355 {total_orders}\uff0c\u6d3b\u8dc3 {active_orders}\uff0c\u5df2\u5b8c\u6210 {completed_orders}\")\r\n```\r\n\r\n#### \u67e5\u8be2\u6210\u4ea4\u8bb0\u5f55\r\n\r\n\u83b7\u53d6\u7528\u6237\u7684\u6210\u4ea4\u8bb0\u5f55\u3002\r\n\r\n**\u8bf7\u6c42\u53c2\u6570\uff1a**\r\n- `page` (int) - \u9875\u7801\uff0c\u53ef\u9009\r\n- `pageSize` (int) - \u6bcf\u9875\u6570\u91cf\uff0c\u53ef\u9009\r\n- `masterOrderId` (str) - \u4e3b\u8ba2\u5355 ID \u7b5b\u9009\uff0c\u53ef\u9009\r\n- `subOrderId` (str) - \u5b50\u8ba2\u5355 ID \u7b5b\u9009\uff0c\u53ef\u9009\r\n- `symbol` (str) - \u4ea4\u6613\u5bf9\u7b5b\u9009\uff0c\u53ef\u9009\r\n- `startTime` (str) - \u5f00\u59cb\u65f6\u95f4\u7b5b\u9009\uff0c\u53ef\u9009\r\n- `endTime` (str) - \u7ed3\u675f\u65f6\u95f4\u7b5b\u9009\uff0c\u53ef\u9009\r\n\r\n**\u54cd\u5e94\u5b57\u6bb5\uff1a**\r\n- `items` - \u6210\u4ea4\u8bb0\u5f55\u5217\u8868\uff0c\u6bcf\u6761\u8bb0\u5f55\u5305\u542b\uff1a\r\n - `id` - \u8bb0\u5f55 ID\r\n - `orderCreatedTime` - \u8ba2\u5355\u521b\u5efa\u65f6\u95f4\r\n - `masterOrderId` - \u4e3b\u8ba2\u5355 ID\r\n - `exchange` - \u4ea4\u6613\u6240\r\n - `category` - \u5e02\u573a\u7c7b\u578b\r\n - `symbol` - \u4ea4\u6613\u5bf9\r\n - `side` - \u65b9\u5411\r\n - `filledValue` - \u6210\u4ea4\u4ef7\u503c\r\n - `filledQuantity` - \u6210\u4ea4\u6570\u91cf\r\n - `avgPrice` - \u5e73\u5747\u4ef7\u683c\r\n - `price` - \u6210\u4ea4\u4ef7\u683c\r\n - `fee` - \u624b\u7eed\u8d39\r\n - `tradingAccount` - \u4ea4\u6613\u8d26\u6237\r\n - `status` - \u72b6\u6001\r\n - `rejectReason` - \u62d2\u7edd\u539f\u56e0\r\n - `base` - \u57fa\u7840\u5e01\u79cd\r\n - `quote` - \u8ba1\u4ef7\u5e01\u79cd\r\n - `type` - \u8ba2\u5355\u7c7b\u578b\r\n- `total` - \u603b\u6570\r\n- `page` - \u5f53\u524d\u9875\u7801\r\n- `pageSize` - \u6bcf\u9875\u6570\u91cf\r\n\r\n**\u793a\u4f8b\u4ee3\u7801\uff1a**\r\n\r\n```python\r\n# \u67e5\u8be2\u7279\u5b9a\u4e3b\u8ba2\u5355\u7684\u6210\u4ea4\u660e\u7ec6\r\nfills = client.get_order_fills(\r\n masterOrderId=\"your-master-order-id\",\r\n page=1,\r\n pageSize=50\r\n)\r\n\r\n# \u67e5\u8be2\u6240\u6709\u6210\u4ea4\r\nfills = client.get_order_fills(\r\n symbol=\"BTCUSDT\",\r\n startTime=\"2024-01-01T00:00:00Z\",\r\n endTime=\"2024-01-01T23:59:59Z\"\r\n)\r\n\r\n# \u5206\u6790\u6210\u4ea4\u6570\u636e\r\ntotal_value = 0\r\ntotal_fee = 0\r\nfill_types = {}\r\n\r\nfor fill in fills['items']:\r\n print(f\"\"\"\r\n\u6210\u4ea4\u8bb0\u5f55\uff1a\r\n \u65f6\u95f4: {fill['orderCreatedTime']}\r\n \u4ea4\u6613\u5bf9: {fill['symbol']} ({fill['category']})\r\n \u65b9\u5411: {fill['side']}\r\n \u6210\u4ea4\u4ef7\u683c: ${fill['price']:.2f}\r\n \u6210\u4ea4\u6570\u91cf: {fill['filledQuantity']:.6f}\r\n \u6210\u4ea4\u91d1\u989d: ${fill['filledValue']:.2f}\r\n \u624b\u7eed\u8d39: ${fill['fee']:.4f}\r\n \u8d26\u6237: {fill['tradingAccount']}\r\n \u7c7b\u578b: {fill.get('type', 'N/A')}\r\n \u72b6\u6001: {fill['status']}\r\n \"\"\")\r\n \r\n total_value += fill['filledValue']\r\n total_fee += fill['fee']\r\n \r\n # \u7edf\u8ba1\u8ba2\u5355\u7c7b\u578b\r\n order_type = fill.get('type', 'Unknown')\r\n fill_types[order_type] = fill_types.get(order_type, 0) + 1\r\n\r\nprint(f\"\\n\u6210\u4ea4\u7edf\u8ba1\uff1a\")\r\nprint(f\"\u603b\u6210\u4ea4\u989d: ${total_value:.2f}\")\r\nprint(f\"\u603b\u624b\u7eed\u8d39: ${total_fee:.2f}\")\r\nprint(f\"\u624b\u7eed\u8d39\u7387: {(total_fee/total_value*100):.3f}%\")\r\nprint(f\"\u8ba2\u5355\u7c7b\u578b\u5206\u5e03: {fill_types}\")\r\n```\r\n\r\n#### \u53d6\u6d88\u4e3b\u8ba2\u5355\r\n\r\n\u53d6\u6d88\u6307\u5b9a\u7684\u4e3b\u8ba2\u5355\u3002\r\n\r\n**\u8bf7\u6c42\u53c2\u6570\uff1a**\r\n- `masterOrderId` (str) - \u8981\u53d6\u6d88\u7684\u4e3b\u8ba2\u5355 ID\uff0c\u5fc5\u586b\r\n- `reason` (str) - \u53d6\u6d88\u539f\u56e0\uff0c\u53ef\u9009\r\n\r\n**\u54cd\u5e94\u5b57\u6bb5\uff1a**\r\n- `success` - \u53d6\u6d88\u662f\u5426\u6210\u529f\r\n- `message` - \u53d6\u6d88\u7ed3\u679c\u6d88\u606f\r\n\r\n**\u793a\u4f8b\u4ee3\u7801\uff1a**\r\n\r\n```python\r\n# \u53d6\u6d88\u8ba2\u5355\r\nresponse = client.cancel_master_order(\r\n masterOrderId=\"your-master-order-id\",\r\n reason=\"\u7528\u6237\u624b\u52a8\u53d6\u6d88\" # \u53ef\u9009\u7684\u53d6\u6d88\u539f\u56e0\r\n)\r\n\r\nif response.get('success'):\r\n print(\"\u8ba2\u5355\u53d6\u6d88\u6210\u529f\")\r\nelse:\r\n print(f\"\u8ba2\u5355\u53d6\u6d88\u5931\u8d25: {response.get('message')}\")\r\n\r\n# \u6279\u91cf\u53d6\u6d88\u793a\u4f8b\r\ndef cancel_all_active_orders(client):\r\n \"\"\"\u53d6\u6d88\u6240\u6709\u6d3b\u8dc3\u8ba2\u5355\"\"\"\r\n orders = client.get_master_orders(status=\"ACTIVE\")\r\n cancelled_count = 0\r\n \r\n for order in orders['items']:\r\n try:\r\n response = client.cancel_master_order(\r\n masterOrderId=order['masterOrderId'],\r\n reason=\"\u6279\u91cf\u53d6\u6d88\u6d3b\u8dc3\u8ba2\u5355\"\r\n )\r\n if response.get('success'):\r\n cancelled_count += 1\r\n print(f\"\u5df2\u53d6\u6d88\u8ba2\u5355: {order['masterOrderId']}\")\r\n else:\r\n print(f\"\u53d6\u6d88\u5931\u8d25: {order['masterOrderId']} - {response.get('message')}\")\r\n except Exception as e:\r\n print(f\"\u53d6\u6d88\u5f02\u5e38: {order['masterOrderId']} - {str(e)}\")\r\n \r\n print(f\"\\n\u603b\u8ba1\u53d6\u6d88 {cancelled_count} \u4e2a\u8ba2\u5355\")\r\n return cancelled_count\r\n```\r\n\r\n## \u9519\u8bef\u5904\u7406\r\n\r\nSDK \u63d0\u4f9b\u4e86\u8be6\u7ec6\u7684\u9519\u8bef\u7c7b\u578b\uff0c\u65b9\u4fbf\u8fdb\u884c\u7cbe\u786e\u7684\u9519\u8bef\u5904\u7406\uff1a\r\n\r\n```python\r\nfrom qe.error import ClientError, APIError\r\n\r\ntry:\r\n response = client.create_master_order(\r\n # ... \u8ba2\u5355\u53c2\u6570\r\n )\r\nexcept APIError as error:\r\n # API \u8fd4\u56de\u7684\u4e1a\u52a1\u9519\u8bef\r\n print(f\"API \u9519\u8bef - \u4ee3\u7801: {error.code}, \u539f\u56e0: {error.reason}, \u6d88\u606f: {error.message}\")\r\n print(f\"\u8ffd\u8e2a ID: {error.trace_id}\") # \u7528\u4e8e\u6280\u672f\u652f\u6301\r\n \r\n # \u6839\u636e\u9519\u8bef\u4ee3\u7801\u5904\u7406\r\n if error.code == 400:\r\n print(\"\u8bf7\u6c42\u53c2\u6570\u9519\u8bef\uff0c\u8bf7\u68c0\u67e5\u8f93\u5165\")\r\n elif error.code == 401:\r\n print(\"\u8ba4\u8bc1\u5931\u8d25\uff0c\u8bf7\u68c0\u67e5 API \u5bc6\u94a5\")\r\n elif error.code == 403:\r\n print(\"\u6743\u9650\u4e0d\u8db3\")\r\n elif error.code == 429:\r\n print(\"\u8bf7\u6c42\u8fc7\u4e8e\u9891\u7e41\uff0c\u8bf7\u7a0d\u540e\u91cd\u8bd5\")\r\n \r\nexcept ClientError as error:\r\n # \u5ba2\u6237\u7aef\u9519\u8bef\uff08\u5982\u53c2\u6570\u9519\u8bef\u3001\u7f51\u7edc\u9519\u8bef\u7b49\uff09\r\n print(f\"\u5ba2\u6237\u7aef\u9519\u8bef - \u72b6\u6001\u7801: {error.status_code}, \u9519\u8bef\u6d88\u606f: {error.error_message}\")\r\n \r\nexcept Exception as error:\r\n # \u5176\u4ed6\u672a\u9884\u671f\u7684\u9519\u8bef\r\n print(f\"\u672a\u77e5\u9519\u8bef: {error}\")\r\n```\r\n\r\n## \u9ad8\u7ea7\u914d\u7f6e\r\n\r\n### \u914d\u7f6e\u8d85\u65f6\u548c\u4ee3\u7406\r\n\r\n```python\r\nclient = Client(\r\n api_key=\"your-api-key\",\r\n api_secret=\"your-api-secret\",\r\n timeout=30, # 30 \u79d2\u8d85\u65f6\r\n proxies={\r\n 'https': 'http://proxy.example.com:8080'\r\n }\r\n)\r\n```\r\n\r\n### \u4f7f\u7528 RSA \u6216 Ed25519 \u7b7e\u540d\r\n\r\n```python\r\n# \u4f7f\u7528 RSA \u79c1\u94a5\r\nwith open('private_key.pem', 'r') as f:\r\n private_key = f.read()\r\n\r\nclient = Client(\r\n api_key=\"your-api-key\",\r\n private_key=private_key,\r\n private_key_pass=\"your-password\" # \u5982\u679c\u79c1\u94a5\u6709\u5bc6\u7801\r\n)\r\n\r\n# \u4f7f\u7528 Ed25519 \u79c1\u94a5\r\nwith open('ed25519_key.pem', 'r') as f:\r\n ed25519_key = f.read()\r\n\r\nclient = Client(\r\n api_key=\"your-api-key\",\r\n private_key=ed25519_key\r\n)\r\n```\r\n\r\n### \u663e\u793a\u8bf7\u6c42\u9650\u5236\u4f7f\u7528\u60c5\u51b5\r\n\r\n```python\r\nclient = Client(\r\n api_key=\"your-api-key\",\r\n api_secret=\"your-api-secret\",\r\n show_limit_usage=True,\r\n show_header=True\r\n)\r\n\r\n# API \u54cd\u5e94\u5c06\u5305\u542b\u9650\u5236\u4fe1\u606f\r\nresponse = client.get_master_orders()\r\nif isinstance(response, dict) and 'limit_usage' in response:\r\n print(f\"\u9650\u5236\u4f7f\u7528\u60c5\u51b5: {response['limit_usage']}\")\r\n print(f\"\u5b9e\u9645\u6570\u636e: {response['data']}\")\r\n```\r\n\r\n### \u914d\u7f6e\u65e5\u5fd7\r\n\r\n```python\r\nimport logging\r\nfrom qe.lib.utils import config_logging\r\n\r\n# \u914d\u7f6e\u8be6\u7ec6\u65e5\u5fd7\r\nconfig_logging(logging, logging.DEBUG)\r\n\r\n# \u53ea\u8bb0\u5f55\u8b66\u544a\u548c\u9519\u8bef\r\nconfig_logging(logging, logging.WARNING)\r\n```\r\n\r\n## \u5b8c\u6574\u793a\u4f8b\r\n\r\n### \u5b8c\u6574\u7684\u4ea4\u6613\u6d41\u7a0b\u793a\u4f8b\r\n\r\n```python\r\nimport logging\r\nfrom qe.user import User as Client\r\nfrom qe.error import ClientError, APIError\r\nfrom qe.lib.utils import config_logging\r\nimport time\r\nfrom datetime import datetime, timedelta\r\n\r\n# \u914d\u7f6e\u65e5\u5fd7\r\nconfig_logging(logging, logging.INFO)\r\nlogger = logging.getLogger(__name__)\r\n\r\n# \u521d\u59cb\u5316\u5ba2\u6237\u7aef\r\nclient = Client(\"your-api-key\", \"your-api-secret\")\r\n\r\ntry:\r\n # 1. \u83b7\u53d6\u53ef\u7528\u7684 API \u5bc6\u94a5\r\n apis = client.list_exchange_apis(exchange=\"binance\")\r\n if not apis['items']:\r\n logger.error(\"\u6ca1\u6709\u627e\u5230\u53ef\u7528\u7684\u5e01\u5b89 API \u5bc6\u94a5\")\r\n exit(1)\r\n \r\n # \u9009\u62e9\u4f59\u989d\u6700\u9ad8\u7684\u8d26\u6237\r\n api_info = max(apis['items'], key=lambda x: x.get('balance', 0))\r\n api_key_id = api_info['id']\r\n logger.info(f\"\u4f7f\u7528 API \u5bc6\u94a5: {api_key_id}, \u8d26\u6237: {api_info['accountName']}, \u4f59\u989d: ${api_info['balance']:.2f}\")\r\n \r\n # 2. \u521b\u5efa TWAP \u8ba2\u5355\r\n start_time = datetime.utcnow().isoformat() + 'Z'\r\n end_time = (datetime.utcnow() + timedelta(minutes=10)).isoformat() + 'Z'\r\n \r\n order_response = client.create_master_order(\r\n algorithm=\"TWAP\",\r\n algorithmType=\"TIME_WEIGHTED\",\r\n exchange=\"binance\",\r\n symbol=\"BTCUSDT\",\r\n marketType=\"SPOT\",\r\n side=\"BUY\",\r\n apiKeyId=api_key_id,\r\n orderNotional=1000, # $1000\r\n startTime=start_time,\r\n endTime=end_time,\r\n executionDuration=\"30\", # \u6bcf 30 \u79d2\u6267\u884c\u4e00\u6b21\r\n mustComplete=True,\r\n worstPrice=70000, # \u6700\u5dee\u4ef7\u683c $70,000\r\n upTolerance=\"0.05\", # \u5141\u8bb8\u8d85\u51fa 5%\r\n lowTolerance=\"0.05\", # \u5141\u8bb8\u843d\u540e 5%\r\n strictUpBound=False,\r\n clientId=f\"test_order_{int(time.time())}\",\r\n notes=\"Python SDK \u6d4b\u8bd5\u8ba2\u5355\"\r\n )\r\n \r\n if not order_response.get('success'):\r\n logger.error(f\"\u521b\u5efa\u8ba2\u5355\u5931\u8d25: {order_response.get('message')}\")\r\n exit(1)\r\n \r\n master_order_id = order_response['masterOrderId']\r\n logger.info(f\"\u8ba2\u5355\u521b\u5efa\u6210\u529f\uff0cID: {master_order_id}\")\r\n \r\n # 3. \u76d1\u63a7\u8ba2\u5355\u72b6\u6001\r\n previous_progress = 0\r\n while True:\r\n orders = client.get_master_orders(\r\n page=1,\r\n pageSize=1,\r\n status=\"ACTIVE\"\r\n )\r\n \r\n if not orders['items']:\r\n logger.info(\"\u8ba2\u5355\u5df2\u5b8c\u6210\u6216\u53d6\u6d88\")\r\n break\r\n \r\n order = orders['items'][0]\r\n current_progress = order['completionProgress'] * 100\r\n \r\n # \u53ea\u5728\u8fdb\u5ea6\u53d8\u5316\u65f6\u6253\u5370\r\n if current_progress != previous_progress:\r\n logger.info(f\"\u8ba2\u5355\u8fdb\u5ea6: {current_progress:.2f}%, \"\r\n f\"\u5df2\u6210\u4ea4: {order['filledQuantity']:.6f}/{order['totalQuantity']:.6f}, \"\r\n f\"\u5e73\u5747\u4ef7\u683c: ${order.get('averagePrice', 0):.2f}\")\r\n previous_progress = current_progress\r\n \r\n # \u68c0\u67e5\u662f\u5426\u9700\u8981\u53d6\u6d88\uff08\u6f14\u793a\u7528\uff09\r\n if current_progress > 50: # \u5b8c\u6210\u8d85\u8fc7 50%\r\n logger.info(\"\u6f14\u793a\uff1a\u53d6\u6d88\u8ba2\u5355\")\r\n cancel_response = client.cancel_master_order(\r\n masterOrderId=master_order_id,\r\n reason=\"\u6f14\u793a\u53d6\u6d88\"\r\n )\r\n if cancel_response.get('success'):\r\n logger.info(\"\u8ba2\u5355\u5df2\u53d6\u6d88\")\r\n break\r\n \r\n time.sleep(10) # \u6bcf 10 \u79d2\u68c0\u67e5\u4e00\u6b21\r\n \r\n # 4. \u83b7\u53d6\u6700\u7ec8\u6210\u4ea4\u660e\u7ec6\r\n fills = client.get_order_fills(masterOrderId=master_order_id)\r\n logger.info(f\"\u603b\u6210\u4ea4\u7b14\u6570: {fills['total']}\")\r\n \r\n total_value = 0\r\n total_fee = 0\r\n for fill in fills['items']:\r\n logger.info(f\"\u6210\u4ea4: {fill['side']} {fill['filledQuantity']:.6f} {fill['symbol']} \"\r\n f\"@ ${fill['price']:.2f}, \u624b\u7eed\u8d39: ${fill['fee']:.4f}\")\r\n total_value += fill['filledValue']\r\n total_fee += fill['fee']\r\n \r\n if total_value > 0:\r\n logger.info(f\"\\n\u6210\u4ea4\u603b\u7ed3\uff1a\")\r\n logger.info(f\"\u603b\u6210\u4ea4\u989d: ${total_value:.2f}\")\r\n logger.info(f\"\u603b\u624b\u7eed\u8d39: ${total_fee:.2f}\")\r\n logger.info(f\"\u624b\u7eed\u8d39\u7387: {(total_fee/total_value*100):.3f}%\")\r\n\r\nexcept APIError as error:\r\n logger.error(f\"API \u9519\u8bef: {error}\")\r\nexcept ClientError as error:\r\n logger.error(f\"\u5ba2\u6237\u7aef\u9519\u8bef: {error}\")\r\nexcept Exception as error:\r\n logger.error(f\"\u672a\u77e5\u9519\u8bef: {error}\")\r\n```\r\n\r\n### \u7b56\u7565\u6267\u884c\u793a\u4f8b\r\n\r\n```python\r\ndef execute_vwap_strategy(client, symbol, amount_usd, duration_hours=8):\r\n \"\"\"\u6267\u884c VWAP \u7b56\u7565\"\"\"\r\n logger = logging.getLogger(__name__)\r\n \r\n try:\r\n # \u83b7\u53d6\u9ed8\u8ba4 API\r\n apis = client.list_exchange_apis(exchange=\"binance\")\r\n default_api = next((api for api in apis['items'] if api.get('isDefault')), None)\r\n \r\n if not default_api:\r\n raise ValueError(\"\u6ca1\u6709\u627e\u5230\u9ed8\u8ba4\u7684\u5e01\u5b89 API\")\r\n \r\n # \u521b\u5efa VWAP \u8ba2\u5355\r\n start_time = datetime.utcnow().isoformat() + 'Z'\r\n end_time = (datetime.utcnow() + timedelta(hours=duration_hours)).isoformat() + 'Z'\r\n \r\n response = client.create_master_order(\r\n algorithm=\"VWAP\",\r\n algorithmType=\"VOLUME_WEIGHTED\",\r\n exchange=\"binance\",\r\n symbol=symbol,\r\n marketType=\"SPOT\",\r\n side=\"BUY\",\r\n apiKeyId=default_api['id'],\r\n orderNotional=amount_usd,\r\n startTime=start_time,\r\n endTime=end_time,\r\n strategyType=\"PASSIVE\", # \u88ab\u52a8\u7b56\u7565\uff0c\u51cf\u5c11\u5e02\u573a\u5f71\u54cd\r\n makerRateLimit=0.5, # 50% Maker \u8ba2\u5355\r\n povLimit=0.05, # \u6700\u591a\u5360\u5e02\u573a\u6210\u4ea4\u91cf 5%\r\n mustComplete=False, # \u4e0d\u5f3a\u5236\u5b8c\u6210\uff0c\u907f\u514d\u6ed1\u70b9\r\n upTolerance=\"0.02\", # 2% \u5bb9\u5fcd\u5ea6\r\n lowTolerance=\"0.05\", # 5% \u5bb9\u5fcd\u5ea6\r\n notes=f\"VWAP \u7b56\u7565 - {symbol}\"\r\n )\r\n \r\n if response.get('success'):\r\n logger.info(f\"VWAP \u8ba2\u5355\u521b\u5efa\u6210\u529f: {response['masterOrderId']}\")\r\n return response['masterOrderId']\r\n else:\r\n raise ValueError(f\"\u8ba2\u5355\u521b\u5efa\u5931\u8d25: {response.get('message')}\")\r\n \r\n except Exception as e:\r\n logger.error(f\"\u6267\u884c VWAP \u7b56\u7565\u5931\u8d25: {str(e)}\")\r\n raise\r\n\r\n# \u4f7f\u7528\u793a\u4f8b\r\nmaster_order_id = execute_vwap_strategy(\r\n client,\r\n symbol=\"ETHUSDT\",\r\n amount_usd=5000,\r\n duration_hours=6\r\n)\r\n```\r\n\r\n## API \u6587\u6863\r\n\r\n\u5b8c\u6574\u7684 API \u6587\u6863\u8bf7\u53c2\u8003 [Quantum Execute API \u6587\u6863](https://docs.quantumexecute.com)\r\n\r\n## \u652f\u6301\u7684\u7b97\u6cd5\u7c7b\u578b\r\n\r\n- **TWAP (Time Weighted Average Price)**: \u65f6\u95f4\u52a0\u6743\u5e73\u5747\u4ef7\u683c\u7b97\u6cd5\uff0c\u5728\u6307\u5b9a\u65f6\u95f4\u6bb5\u5185\u5e73\u5747\u5206\u914d\u8ba2\u5355\r\n- **VWAP (Volume Weighted Average Price)**: \u6210\u4ea4\u91cf\u52a0\u6743\u5e73\u5747\u4ef7\u683c\u7b97\u6cd5\uff0c\u6839\u636e\u5e02\u573a\u6210\u4ea4\u91cf\u5206\u5e03\u6267\u884c\u8ba2\u5355\r\n- **POV (Percentage of Volume)**: \u6210\u4ea4\u91cf\u767e\u5206\u6bd4\u7b97\u6cd5\uff0c\u4fdd\u6301\u5360\u5e02\u573a\u6210\u4ea4\u91cf\u7684\u56fa\u5b9a\u6bd4\u4f8b\r\n- **IMPLEMENTATION_SHORTFALL**: \u6267\u884c\u7f3a\u53e3\u7b97\u6cd5\uff0c\u6700\u5c0f\u5316\u6267\u884c\u6210\u672c\r\n\r\n## \u6700\u4f73\u5b9e\u8df5\r\n\r\n### 1. API \u5bc6\u94a5\u7ba1\u7406\r\n\r\n```python\r\ndef check_api_health(client):\r\n \"\"\"\u68c0\u67e5 API \u5bc6\u94a5\u5065\u5eb7\u72b6\u6001\"\"\"\r\n apis = client.list_exchange_apis()\r\n \r\n for api in apis['items']:\r\n if not api['isValid']:\r\n print(f\"\u26a0\ufe0f \u8b66\u544a: API '{api['accountName']}' \u72b6\u6001\u5f02\u5e38\")\r\n \r\n if api['balance'] < 100:\r\n print(f\"\u26a0\ufe0f \u8b66\u544a: \u8d26\u6237 '{api['accountName']}' \u4f59\u989d\u4e0d\u8db3 (${api['balance']:.2f})\")\r\n \r\n if not api['isTradingEnabled']:\r\n print(f\"\u2139\ufe0f \u63d0\u793a: API '{api['accountName']}' \u672a\u5f00\u542f\u4ea4\u6613\u6743\u9650\")\r\n```\r\n\r\n### 2. \u8ba2\u5355\u53c2\u6570\u9a8c\u8bc1\r\n\r\n```python\r\ndef validate_order_params(params):\r\n \"\"\"\u9a8c\u8bc1\u8ba2\u5355\u53c2\u6570\"\"\"\r\n errors = []\r\n \r\n # \u5fc5\u586b\u53c2\u6570\u68c0\u67e5\r\n required = ['algorithm', 'exchange', 'symbol', 'marketType', 'side', 'apiKeyId']\r\n for field in required:\r\n if not params.get(field):\r\n errors.append(f\"\u7f3a\u5c11\u5fc5\u586b\u53c2\u6570: {field}\")\r\n \r\n # \u6570\u91cf\u9a8c\u8bc1\r\n if not params.get('totalQuantity') and not params.get('orderNotional'):\r\n errors.append(\"\u5fc5\u987b\u6307\u5b9a totalQuantity \u6216 orderNotional\")\r\n \r\n # \u65f6\u95f4\u9a8c\u8bc1\r\n if params.get('startTime') and params.get('endTime'):\r\n start = datetime.fromisoformat(params['startTime'].rstrip('Z'))\r\n end = datetime.fromisoformat(params['endTime'].rstrip('Z'))\r\n if start >= end:\r\n errors.append(\"\u5f00\u59cb\u65f6\u95f4\u5fc5\u987b\u65e9\u4e8e\u7ed3\u675f\u65f6\u95f4\")\r\n \r\n # \u5bb9\u5fcd\u5ea6\u9a8c\u8bc1\r\n for field in ['upTolerance', 'lowTolerance']:\r\n if field in params:\r\n try:\r\n val = float(params[field])\r\n if val < 0 or val > 1:\r\n errors.append(f\"{field} \u5fc5\u987b\u5728 0-1 \u4e4b\u95f4\")\r\n except ValueError:\r\n errors.append(f\"{field} \u5fc5\u987b\u662f\u6709\u6548\u7684\u6570\u5b57\")\r\n \r\n return errors\r\n```\r\n\r\n### 3. \u91cd\u8bd5\u673a\u5236\r\n\r\n```python\r\nimport time\r\nfrom functools import wraps\r\n\r\ndef retry_on_error(max_retries=3, delay=1):\r\n \"\"\"\u88c5\u9970\u5668\uff1a\u81ea\u52a8\u91cd\u8bd5\u5931\u8d25\u7684\u8bf7\u6c42\"\"\"\r\n def decorator(func):\r\n @wraps(func)\r\n def wrapper(*args, **kwargs):\r\n last_error = None\r\n for attempt in range(max_retries):\r\n try:\r\n return func(*args, **kwargs)\r\n except APIError as e:\r\n last_error = e\r\n # \u4e0d\u91cd\u8bd5\u5ba2\u6237\u7aef\u9519\u8bef\r\n if 400 <= e.code < 500:\r\n raise\r\n # \u670d\u52a1\u5668\u9519\u8bef\uff0c\u7b49\u5f85\u540e\u91cd\u8bd5\r\n if attempt < max_retries - 1:\r\n wait_time = delay * (2 ** attempt) # \u6307\u6570\u9000\u907f\r\n logger.warning(f\"\u8bf7\u6c42\u5931\u8d25\uff0c{wait_time}\u79d2\u540e\u91cd\u8bd5...\")\r\n time.sleep(wait_time)\r\n except Exception as e:\r\n last_error = e\r\n if attempt < max_retries - 1:\r\n time.sleep(delay)\r\n \r\n raise last_error\r\n return wrapper\r\n return decorator\r\n\r\n# \u4f7f\u7528\u793a\u4f8b\r\n@retry_on_error(max_retries=3, delay=2)\r\ndef create_order_with_retry(client, **params):\r\n return client.create_master_order(**params)\r\n```\r\n\r\n## \u5e38\u89c1\u95ee\u9898\r\n\r\n### 1. \u5982\u4f55\u83b7\u53d6 API \u5bc6\u94a5\uff1f\r\n\r\n\u8bf7\u767b\u5f55 Quantum Execute \u5e73\u53f0\uff0c\u5728\u7528\u6237\u8bbe\u7f6e\u4e2d\u521b\u5efa API \u5bc6\u94a5\u3002\u786e\u4fdd\u4fdd\u7ba1\u597d\u60a8\u7684\u5bc6\u94a5\uff0c\u4e0d\u8981\u5c06\u5176\u63d0\u4ea4\u5230\u7248\u672c\u63a7\u5236\u7cfb\u7edf\u4e2d\u3002\r\n\r\n### 2. \u65f6\u95f4\u6233\u9519\u8bef\u600e\u4e48\u5904\u7406\uff1f\r\n\r\n\u5982\u679c\u9047\u5230\u65f6\u95f4\u6233\u76f8\u5173\u7684\u9519\u8bef\uff0c\u53ef\u80fd\u662f\u60a8\u7684\u7cfb\u7edf\u65f6\u95f4\u4e0e\u670d\u52a1\u5668\u65f6\u95f4\u4e0d\u540c\u6b65\u3002\u8bf7\u786e\u4fdd\u7cfb\u7edf\u65f6\u95f4\u51c6\u786e\u3002\r\n\r\n### 3. \u5982\u4f55\u5904\u7406\u5927\u91cf\u6570\u636e\u7684\u5206\u9875\uff1f\r\n\r\n```python\r\ndef get_all_data(fetch_func, **params):\r\n \"\"\"\u901a\u7528\u7684\u5206\u9875\u6570\u636e\u83b7\u53d6\u51fd\u6570\"\"\"\r\n all_items = []\r\n page = 1\r\n page_size = 100\r\n \r\n while True:\r\n result = fetch_func(page=page, pageSize=page_size, **params)\r\n all_items.extend(result['items'])\r\n \r\n if len(result['items']) < page_size:\r\n break\r\n page += 1\r\n \r\n return all_items\r\n\r\n# \u4f7f\u7528\u793a\u4f8b\r\nall_orders = get_all_data(client.get_master_orders, status=\"COMPLETED\")\r\nall_fills = get_all_data(client.get_order_fills, symbol=\"BTCUSDT\")\r\n```\r\n\r\n### 4. \u5982\u4f55\u8bbe\u7f6e\u8ba2\u5355\u7684\u65f6\u95f4\uff1f\r\n\r\n\u65f6\u95f4\u683c\u5f0f\u4f7f\u7528 ISO 8601 \u6807\u51c6\uff0c\u4f8b\u5982\uff1a\r\n- UTC \u65f6\u95f4\uff1a`2024-01-01T10:00:00Z`\r\n- \u5e26\u65f6\u533a\uff1a`2024-01-01T18:00:00+08:00`\r\n\r\n```python\r\nfrom datetime import datetime, timezone\r\n\r\n# \u83b7\u53d6\u5f53\u524d UTC \u65f6\u95f4\r\nnow_utc = datetime.now(timezone.utc).isoformat()\r\n\r\n# \u8f6c\u6362\u672c\u5730\u65f6\u95f4\u5230 UTC\r\nlocal_time = datetime.now()\r\nutc_time = local_time.astimezone(timezone.utc).isoformat()\r\n```\r\n\r\n### 5. \u5bb9\u5fcd\u5ea6\u53c2\u6570\u8bf4\u660e\r\n\r\n- `upTolerance`\uff1a\u5141\u8bb8\u8d85\u51fa\u8ba1\u5212\u8fdb\u5ea6\u7684\u5bb9\u5fcd\u5ea6\uff0c\u5982 \"0.1\" \u8868\u793a\u5141\u8bb8\u8d85\u51fa 10%\r\n- `lowTolerance`\uff1a\u5141\u8bb8\u843d\u540e\u8ba1\u5212\u8fdb\u5ea6\u7684\u5bb9\u5fcd\u5ea6\r\n- `strictUpBound`\uff1a\u662f\u5426\u4e25\u683c\u9650\u5236\u5728 upTolerance \u4ee5\u5185\uff0c\u5f00\u542f\u540e\u53ef\u80fd\u5bfc\u81f4\u5c0f\u8ba2\u5355\u88ab\u8fc7\u5ea6\u62c6\u5206\r\n\r\n## \u793a\u4f8b\u4ee3\u7801\r\n\r\n\u66f4\u591a\u793a\u4f8b\u4ee3\u7801\u8bf7\u53c2\u8003 [examples](./examples) \u76ee\u5f55\uff1a\r\n\r\n- [\u6dfb\u52a0\u4ea4\u6613\u6240 API](examples/user/add_exchange_api.py)\r\n- [\u521b\u5efa\u4e3b\u8ba2\u5355](examples/user/create_master_order.py)\r\n- [\u53d6\u6d88\u4e3b\u8ba2\u5355](examples/user/cancel_master_order.py)\r\n- [\u67e5\u8be2\u8ba2\u5355\u5217\u8868](examples/user/get_master_orders.py)\r\n- [\u67e5\u8be2\u6210\u4ea4\u660e\u7ec6](examples/user/get_order_fills.py)\r\n\r\n## \u5f00\u53d1\u548c\u6d4b\u8bd5\r\n\r\n### \u5b89\u88c5\u5f00\u53d1\u4f9d\u8d56\r\n\r\n```bash\r\npip install -r requirements/requirements-dev.txt\r\n```\r\n\r\n### \u8fd0\u884c\u6d4b\u8bd5\r\n\r\n```bash\r\npython -m pytest tests/\r\n```\r\n\r\n### \u4ee3\u7801\u683c\u5f0f\u5316\r\n\r\n```bash\r\nblack qe/\r\nflake8 qe/\r\n```\r\n\r\n## \u8d21\u732e\u6307\u5357\r\n\r\n\u6b22\u8fce\u63d0\u4ea4 Issue \u548c Pull Request\uff01\u8bf7\u786e\u4fdd\uff1a\r\n\r\n1. \u4ee3\u7801\u7b26\u5408 PEP 8 \u89c4\u8303\r\n2. \u6dfb\u52a0\u9002\u5f53\u7684\u6d4b\u8bd5\r\n3. \u66f4\u65b0\u76f8\u5173\u6587\u6863\r\n\r\n## \u66f4\u65b0\u65e5\u5fd7\r\n\r\n### v1.0.0 (2024-01-01)\r\n- \u521d\u59cb\u7248\u672c\u53d1\u5e03\r\n- \u652f\u6301\u5b8c\u6574\u7684 Quantum Execute API\r\n- \u652f\u6301\u591a\u79cd\u8ba4\u8bc1\u65b9\u5f0f\r\n- \u5b8c\u5584\u7684\u9519\u8bef\u5904\u7406\r\n\r\n## \u8bb8\u53ef\u8bc1\r\n\r\n\u672c\u9879\u76ee\u91c7\u7528 MIT \u8bb8\u53ef\u8bc1 - \u8be6\u89c1 [LICENSE](LICENSE) \u6587\u4ef6\u3002\r\n\r\n## \u8054\u7cfb\u6211\u4eec\r\n\r\n- \u5b98\u7f51\uff1a[https://test.quantumexecute.com](https://test.quantumexecute.com)\r\n- \u90ae\u7bb1\uff1asupport@quantumexecute.com\r\n- GitHub\uff1a[https://github.com/Quantum-Execute/qe-connector-python](https://github.com/Quantum-Execute/qe-connector-python)\r\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "This is a lightweight library that works as a connector to Quantum Execute public API.",
"version": "1.0.1",
"project_urls": {
"Homepage": "https://github.com/Quantum-Execute/qe-connector-python"
},
"split_keywords": [
"quantum-execute",
" public api"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "bf46d5f0a99a28003254cc1ae8d02b67a75e2dc89609be8294fcab3e85a9d5a7",
"md5": "c3331affc1b870b0d43b82d94ae2bc1c",
"sha256": "b3f77737eab7432660e620fcd840751df8d2930a4d11e3bde46e951c51c493ca"
},
"downloads": -1,
"filename": "qe_connector-1.0.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "c3331affc1b870b0d43b82d94ae2bc1c",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 20500,
"upload_time": "2025-08-17T13:01:30",
"upload_time_iso_8601": "2025-08-17T13:01:30.585145Z",
"url": "https://files.pythonhosted.org/packages/bf/46/d5f0a99a28003254cc1ae8d02b67a75e2dc89609be8294fcab3e85a9d5a7/qe_connector-1.0.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "88dadebe587b57bd0815994dc86e4f5c0a05159bb2b8658b353d33b0fb030caf",
"md5": "146a3c59bfcbb7a62198f6d148f186bf",
"sha256": "ded6e9c89c0298964460f0ef2b7c5c5f3e578e49e0eeff023954d5c32d5aa123"
},
"downloads": -1,
"filename": "qe-connector-1.0.1.tar.gz",
"has_sig": false,
"md5_digest": "146a3c59bfcbb7a62198f6d148f186bf",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 36586,
"upload_time": "2025-08-17T13:01:33",
"upload_time_iso_8601": "2025-08-17T13:01:33.176468Z",
"url": "https://files.pythonhosted.org/packages/88/da/debe587b57bd0815994dc86e4f5c0a05159bb2b8658b353d33b0fb030caf/qe-connector-1.0.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-17 13:01:33",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "Quantum-Execute",
"github_project": "qe-connector-python",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"tox": true,
"lcname": "qe-connector"
}