# TopOne OpenAPI 代理商跟单交易接口(v1)
## 更新日誌
### 2024-11-21
- 增加代理商跟單接口
- 開倉 `POST /gateway/v1/openapi/agent/copy-trading/order`
- 平倉 `POST /gateway/v1/openapi/agent/copy-trading/order/close`
- 倉位清單 `GET /gateway/v1/openapi/future/copy-trading/position`
- 账户余额接口 `GET /gateway/v1/openapi/wallet/copy-trading/balance`
## 基本信息
### 服务器BASE URL
#### 联调环境
- https://pre.top.one
#### 生产环境
- https://top.one
### 接口访问规则
- 需要提前准备APIKEY和APISECRET(申请通过后,TOPONE通过邮件形式发送给代理商)
- 接口请求频率限制为每秒钟10次(单用户下所有APIKEY)
- 每个接口均需使用APIKEY和APISECRET计算签名signature
### 接口签名实现说明
- signature根据每个请求的timestamp, method, path, body计算sha256而来
- 时间戳为当前时间,超过1分钟的请求签名会被拒绝,不建议使用未来时间签名
- 如果是get请求需要忽略body
- path需要包含query字段
#### example-golang
```go
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
)
func GenerateSignature(method, path, body string, timestamp int64, secret string) (string, error) {
// 组合签名原文
var message string
if method == "GET" {
message = fmt.Sprintf("%d%s%s", timestamp, method, path)
} else {
message = fmt.Sprintf("%d%s%s%s", timestamp, method, path, body)
}
// 使用 HMAC-SHA256 算法进行签名
h := hmac.New(sha256.New, []byte(secret))
if _, err := h.Write([]byte(message)); err != nil {
return "", err
}
// 返回签名结果
signature := hex.EncodeToString(h.Sum(nil))
return signature, nil
}
```
#### example-python
```python
import hmac
import hashlib
import time
def generate_signature(method, path, body, timestamp, secret):
"""
生成 HMAC-SHA256 签名
Args:
method: HTTP 方法
path: 请求路径
body: 请求体
timestamp: 时间戳
Returns:
str: 签名结果
"""
# 组合签名原文
message = f"{timestamp}{method}{path}"
if method != "GET":
message += body
# 使用 HMAC-SHA256 算法进行签名
signature = hmac.new(secret.encode('utf-8'), message.encode('utf-8'), hashlib.sha256).hexdigest()
return signature
```
#### example-java
```java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
public class HmacSha256 {
public static String generateSignature(String method, String path, String body, long timestamp, String secret) throws Exception {
// 组合签名原文
StringBuilder messageBuilder = new StringBuilder();
messageBuilder.append(timestamp).append(method).append(path);
if (!method.equals("GET")) {
messageBuilder.append(body);
}
String message = messageBuilder.toString();
// 使用 HMAC-SHA256 算法进行签名
SecretKeySpec signingKey = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8),"HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(signingKey);
byte[] rawHmac = mac.doFinal(message.getBytes(StandardCharsets.UTF_8));
return bytesToHex(rawHmac);
}
private static String bytesToHex(byte[] bytes) {
StringBuilder hexString = new StringBuilder();
for (byte b : bytes) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
}
}
```
### 通用返回接口示例
```json
{
"status": {
"code": 102000,
"error": {},
"messages": "success"
},
"data": {
}
}
```
- code = 102000表示请求成功,否则为请求失败
- 接口返回的数据在data字段中
## 代理商跟單-下委託單
### HTTP请求
**Path:** /gateway/v1/openapi/agent/copy-trading/order
**Method:** POST
### 请求参数
#### Headers
| 参数名称 | 参数值 | 是否必须 | 备注 |
| ------------ | ------------ | ------------ | ------------ |
| Content-Type | application/json | 是 | |
|signature|8bde81ceaff50e7fe2a...|是| 簽名|
| X-MBX-APIKEY | ee9aedd6a1b2a3a610fa2b1dab333d46 | 是 | ApiKey |
| timestamp | 1732003370 | 是 | 請求時間戳 |
#### Query
无
#### Body
```json!
{
"pair": "BTCUSDT", // 填入支持带单的币对
"side": "sell", // 目前只支持单向买多卖空,即buy+long,或者sell+short
"position_side": "long", // 参考side字段配置
"margin": 5.0, // 1.0 <= margin <= 1000
"leverage": 1, // 1 <= 杠杆倍数 <= 1000
"take_profit_price": 0.0, // long必须大于市价,short必须小于市价,填0则不触发
"stop_loss_price": 0.0, // long必须小于市价,short必须大于市价,填0则不触发
"price": 0.0, // price=0则为市价单,否则为限价单(需谨慎检查对应价格)
"is_simulate": false // 是否为模拟盘交易
}
```
### 响应示例
```json!
{
"status": {
"code": 102000,
"error": {},
"messages": "success"
},
"data": {
"order_id": "e0bf978a-b383-4e85-ba71-7684f81abcc7",
"position_order_id": "",
"pair": "BTCUSDT",
"contract_type": 1,
"uid": "00000034",
"side": "sell",
"position_side": "long",
"quantity": "0.01682",
"order_quantity": "0.01682",
"leverage": 10,
"price_type": "market",
"price": "59307",
"open_fee": "0",
"pre_close_fee": "0",
"take_profit_price": "0",
"stop_loss_price": "0",
"pay_margin": "100",
"status": 1,
"is_simulate": 0,
"close_time": "",
"create_time": "2024-01-01T12:23:34Z",
"update_time": "2024-01-01T12:23:45Z",
"copy_trade": {
"success": [
{
"order_id": "e0bf978a-b383-4e85-ba71-7684f81abcc7",
"position_order_id": "",
"pair": "BTCUSDT",
"contract_type": 1,
"uid": "00000034",
"side": "sell",
"position_side": "long",
"quantity": "0.01682",
"order_quantity": "0.01682",
"leverage": 10,
"price_type": "market",
"price": "59307",
"open_fee": "0",
"pre_close_fee": "0",
"take_profit_price": "0",
"stop_loss_price": "0",
"pay_margin": "100",
"status": 1,
"is_simulate": 0,
"close_time": "",
"create_time": "2024-01-01T12:23:34Z",
"update_time": "2024-01-01T12:23:45Z"
}
],
"fail": [
"00001",
"00002"
]
}
}
}
```
#### 接口描述
- ~~quantity(數量下單)與margin(保證金下單) 只能擇一選擇~~
- 普通合約才有止盈止損價,得勁沒有
- position_side 多單 止盈>成交價>止損 空單 止盈<成交價<止損
- 會根據leverage自動判斷是普通/得勁合約
<h5>Error</h5>
<table>
<thead>
<tr>
<th>Error Code</th>
<th>Message</th>
</tr>
</thead>
<tbody>
<tr>
<td>836004</td>
<td>保證金不足(餘額不足)</td>
</tr>
<tr>
<td>837000</td>
<td>目前合約無法開倉</td>
</tr>
<tr>
<td>837004</td>
<td>用戶持倉數已滿</td>
</tr>
<tr>
<td>837005</td>
<td>平台持倉數量已達上限</td>
</tr>
<tr>
<td>837006</td>
<td>標記價格於最新價格差價過大</td>
</tr>
<tr>
<td>837007</td>
<td>價格有問題(精度,限價止盈止損價格有問題)</td>
</tr>
<tr>
<td>837010</td>
<td>系統造市正在運作,不可下單</td>
</tr>
<tr>
<td>837011</td>
<td>用戶觸發風控,暫時停止交易</td>
</tr>
<tr>
<td>837002</td>
<td>止盈倍數有問題(超過上限)</td>
</tr>
<tr>
<td>904059</td>
<td>開倉功能被關閉</td>
</tr>
</tbody>
</table>
<h5>contract_type</h5>
<table>
<thead>
<tr>
<th>type</th>
<th>comment</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>普通合約</td>
</tr>
<tr>
<td>2</td>
<td>閃電合約</td>
</tr>
</tbody>
</table>
<h5>position_side</h5>
<table>
<thead>
<tr>
<th>code</th>
<th>comment</th>
</tr>
</thead>
<tbody>
<tr>
<td>long</td>
<td>多</td>
</tr>
<tr>
<td>short</td>
<td>空</td>
</tr>
</tbody>
</table>
<h5>side</h5>
<table>
<thead>
<tr>
<th>code</th>
<th>comment</th>
</tr>
</thead>
<tbody>
<tr>
<td>buy</td>
<td>買</td>
</tr>
<tr>
<td>sell</td>
<td>賣</td>
</tr>
</tbody>
</table>
<h5>price_type</h5>
<table>
<thead>
<tr>
<th>type</th>
<th>comment</th>
</tr>
</thead>
<tbody>
<tr>
<td>market</td>
<td>市價</td>
</tr>
<tr>
<td>limit</td>
<td>限價</td>
</tr>
</tbody>
</table>
<h5>status</h5>
<table>
<thead>
<tr>
<th>status</th>
<th>comment</th>
</tr>
</thead>
<tbody>
<tr>
<td>0</td>
<td>未成交</td>
</tr>
<tr>
<td>1</td>
<td>成交</td>
</tr>
<tr>
<td>2</td>
<td>取消</td>
</tr>
<tr>
<td>3</td>
<td>異常</td>
</tr>
</tbody>
</table>
<h5>組合關係</h5>
<table>
<thead>
<tr>
<th>side</th>
<th>position_side</th>
<th>price</th>
<th>comment</th>
</tr>
</thead>
<tbody>
<tr>
<td>buy</td>
<td>long</td>
<td>100</td>
<td>買限價多單</td>
</tr>
<tr>
<td>buy</td>
<td>long</td>
<td>0</td>
<td>買市價多單</td>
</tr>
<tr>
<td>sell</td>
<td>long</td>
<td>100</td>
<td>平倉限價多單</td>
</tr>
<tr>
<td>sell</td>
<td>long</td>
<td>0</td>
<td>平倉市價多單</td>
</tr>
<tr>
<td>buy</td>
<td>short</td>
<td>100</td>
<td>平倉限價空單</td>
</tr>
<tr>
<td>buy</td>
<td>short</td>
<td>0</td>
<td>平倉市價空單</td>
</tr>
<tr>
<td>sell</td>
<td>short</td>
<td>100</td>
<td>買限價空單</td>
</tr>
<tr>
<td>sell</td>
<td>short</td>
<td>0</td>
<td>買市價空單</td>
</tr>
</tbody>
</table>
## 代理商跟單-平倉
### HTTP请求
**Path:** /gateway/v1/openapi/agent/copy-trading/order/close
**Method:** POST
### 请求参数
#### Headers
| 参数名称 | 参数值 | 是否必须 | 备注 |
| ------------ | ------------ | ------------ | ------------ |
| Content-Type | application/json | 是 | |
|signature|8bde81ceaff50e7fe2ad69e...|是| 簽名|
| X-MBX-APIKEY | ee9aedd6a1b2a3a610fa2b1dab333d46 | 是 | ApiKey |
| timestamp | 1732003370 | 是 | 請求時間戳 |
#### Query
无
#### Body
```json!
{
"order_id": "TX0000001" //required
}
```
### 响应示例
```json!
{
"status": {
"code": 102000,
"error": {},
"messages": "success"
},
"data": {
}
}
```
## 代理商跟單-倉位清單
### HTTP请求
**Path:** /gateway/v1/openapi/future/copy-trading/position
**Method:** GET
### 请求参数
#### Headers
| 参数名称 | 参数值 | 是否必须 | 备注 |
| ------------ | ------------ | ------------ | ------------ |
| Content-Type | application/json | 是 | |
|signature|8bde81ceaff50e7fe2ad69e...|是| 簽名|
| X-MBX-APIKEY | ee9aedd6a1b2a3a610fa2b1dab333d46 | 是 | ApiKey |
| timestamp | 1732003370 | 是 | 請求時間戳 |
#### Query
| 参数名称 | 是否必须 | 类型 | 备注 |
| ------------ | ------------ | ------------ | ------------ |
| page_index | 是 | int | 第幾頁(默認1) |
| page_size | 是 | int | 每頁多少筆 |
| status | 否 | int | 倉位狀態 |
| start_time | 否 | int | 建倉開始時間 |
| end_time | 否 | int | 建倉結束時間 |
| pair | 否 | string | 交易對 |
| side | 否 | string | 多/空 |
| is_simulate | 否 | int | 是否為模擬單 默認為(不是) 1:是 2:不是 |
| create_platform | 否 | string | "agent"=帶單, "copy-trade"=跟單 |
| position_id | 否 | string | 倉位ID |
#### Body
無
### 响应示例
```json!
{
"status": {
"code": 102000,
"error": {},
"messages": "success"
},
"data": {
"list": [
{
"order_id": "TX000000001",
"uid": "00001",
"pair": "BTCUSDT",
"crypto": "BTC",
"crypto_price_unit": "USDT",
"side": "long",
"contract_type": 1,
"leverage": 10,
"quantity": "100.1",
"number": 123466,
"price": "529.01",
"price_type": "market",
"take_profit_price": "600.01",
"stop_loss_price": "450.01",
"total_funding_fee": "100",
"init_margin": "100",
"margin": "20.01",
"pay_margin": "120",
"status": 1,
"create_platform": "copy-trade",
"create_time": "2024-05-06T19:23:36Z",
"close_time": "2024-05-06T19:23:36Z"
}
],
"page": {
"total": 1,
"index": 1,
"size": 20
}
}
}
```
### 响应說明
| 名称 | 類型 | 備註 | 示例 |
| ------------ | ------------ | ------------ | ------------ |
| order_id | string | 訂單ID | |
| uid | string | 用戶ID | |
| pair | string | 幣對 | BTCUSDT |
| crypto | string | 交易幣 | BTC |
| crypto_price_unit | string | 計價幣 | USDT |
| side | string | 方向 | |
| contract_type | number | 合約類型 | |
| leverage | number | 槓桿倍數 | |
| quantity | string | 數量(幣量) | |
| number | number |總張數=數量/每張多少單位 | |
| price | string | 開倉價 | |
| price_type | string | 下單價格類型(市價/限價) | |
| close_price | string | 平倉價 | |
| take_profit_price | string | 止盈價 | |
| stop_loss_price | string | 止損價 | |
| total_funding_fee | string | 資金費 | |
| margin | string | 倉位保證金 | |
| init_margin | string | 倉位佔用保證金 | |
| pay_margin | string | 開倉成本(開倉保證金) | |
| status | number | 倉位狀態 | 1=開倉中, 2=已平倉 |
| create_platform | string | 開單平台 | "agent"=帶單, "copy-trade"=跟單 |
| create_time | string | 撮合/建立時間 | |
| close_time | string | 平倉時間 | |
## 代理商跟單-账户余额
### HTTP请求
**Path:** /gateway/v1/openapi/wallet/copy-trading/balance
**Method:** GET
### 请求示例
#### Headers
| 参数名称 | 参数值 | 是否必须 | 备注 |
| ------------ | ------------ | ------------ | ------------ |
| Content-Type | application/json | 是 | |
|signature|8bde81ceaff50e7fe2ad69e...|是| 簽名|
| X-MBX-APIKEY | ee9aedd6a1b2a3a610fa2b1dab333d46 | 是 | ApiKey |
| timestamp | 1732003370 | 是 | 請求時間戳 |
#### Query
無
#### Body
無
### 响应示例
```json!
{
"status": {
"code": 102000,
"error": {},
"messages": "success"
},
"data": {
"list": [
{
"uid": "OOOOOTRU",
"trading_available": "999016.0075683", // 合約帳戶可用金額
"trading_freeze": "0", // 合約帳戶凍結保證金
"realized_profit_and_loss": "0" // 已實現盈虧金額
},
{
"uid": "OOOOJOKT",
"trading_available": "0",
"trading_freeze": "0",
"realized_profit_and_loss": "0"
},
{
"uid": "OOOOOEDV",
"trading_available": "99000000",
"trading_freeze": "0",
"realized_profit_and_loss": "0"
},
{
"uid": "OOOOOEJV",
"trading_available": "0",
"trading_freeze": "0",
"realized_profit_and_loss": "0"
}
]
}
}
```