快速入门
快速入门
接入准备
如需使用API ,请先登录网页端,完成API key的申请和权限配置,再据此文档详情进行开发和交易。
您可以点击 API Key管理 创建 API Key。
每个UID可创建50组Api Key,每个Api Key可对应设置读取、交易两种权限:读和写
子账户 API Key
子账户(虚拟子账户及普通子账户)支持自行创建和管理 API Key,无需母账户代为操作。
前提条件:母账户需为该子账户开启 API Key 管理 权限开关,该开关默认关闭,母账户可在子账户权限设置中进行配置。
开启后,子账户可对自己的 API Key 执行以下操作:
- 创建 API Key
- 查看 API Key
- 编辑 API Key 权限
- 删除 API Key
母账户保留全局管控能力,可随时查看、编辑或删除任意子账户的 API Key。
权限说明如下:
- 统一账户交易只读:允许调用读取统一账户订单相关接口
- 统一账户交易读写:相比于交易只读权限,它允许执行下单、撤单等操作
- 统一账户管理读取:允许调用统一账户账户和仓位读取接口
- 统一账户管理读写:相比于管理只读权限,它允许执行调整杠杆、切换持仓模式等接口
创建成功后请务必记住以下信息:
APIKeyAPI交易的身份标识,随机算法生成。Secretkey私钥,由系统随机生成,用于签名的生成。Passphrase口令,由用户自己设定,需要注意的是,Passphrase忘记之后是无法找回的,需要重新创建APIKey。不要使用特殊字符
模拟盘
模拟盘通过虚拟资金让您在实时市场环境练习交易、测试策略,从而提高熟练度并降低亏损风险
API Key
若要进行模拟盘API交易,请先创建模拟盘API Key。操作步骤如下:
登录Bitget账户 → 切换至模拟盘 → 进入个人中心 → 访问API Key管理 → 创建模拟盘API Key → 使用模拟盘API Key开始交易Rest
请使用创建的模拟盘API Key进行接口调用,并在请求头中添加
paptrading参数,值设置为1Websocket
请使用创建的模拟盘API Key进行接口调用,并请求模拟盘的服务地址:
公共频道 wss://wspap.bitget.com/v3/ws/public
私有频道 wss://wspap.bitget.com/v3/ws/private
域名
| 域名 | API | 建议使用 |
|---|---|---|
| REST | https://api.bitget.com | 主域名 |
| websocket 公共频道 | wss://ws.bitget.com/v3/ws/public | 主域名, 公共频道 |
| websocket 私有频道 | wss://ws.bitget.com/v3/ws/private | 主域名, 私有频道 |
Header
所有REST请求的header都必须包含以下key:
ACCESS-KEY:API KEY作为一个字符串。ACCESS-SIGN:使用base64编码签名(请参阅签名消息)。ACCESS-TIMESTAMP:您请求的时间戳。ACCESS-PASSPHRASE:您在创建API KEY时设置的口令。Content-Type:统一设置为application/json。locale:支持多语言,如:中文(zh-CN),英语(en-US)
Response
X-BG-REQUEST-ACCEPT-TIME:BG服务端接受到请求的时间X-BG-RESPONSE-COMPLETE-TIME:BG服务端请求处理完成时间x-mbx-used-remain-limit:当前接口剩余限频额度
SDK
Bitget V3 将提供以下语言的官方 SDK:
| 语言 | 链接 |
|---|---|
| Java | Java |
| Python | Python |
| Node.js | Node.js |
| Golang | Golang |
| PHP | PHP |
参数签名
生成签名
ACCESS-SIGN 请求头是对 timestamp + method.toUpperCase() + requestPath + "?" + queryString + body 字符串(+ 表示字符串连接)使用 HMAC SHA256 算法以 secretKey 加密,再通过 BASE64 编码输出得到的。
签名各字段说明
- timestamp:与
ACCESS-TIMESTAMP请求头相同,值等于毫秒级时间戳。 - method:请求方法(POST/GET),字母全部大写。
- requestPath:请求接口路径。
- queryString:请求 URL 中
?后的查询字符串。 - body:请求主体对应的字符串,如果请求没有主体(通常为 GET 请求)则 body 可省略。
queryString 为空时,签名格式:
timestamp + method.toUpperCase() + requestPath + body
queryString 不为空时,签名格式:
timestamp + method.toUpperCase() + requestPath + "?" + queryString + body
举例说明
GET 示例 — 获取账户手续费率(BTCUSDT 现货):
- Timestamp = 16273667805456
- Method = "GET"
- requestPath = "/api/v3/account/fee-rate"
- queryString = "category=SPOT&symbol=BTCUSDT"
待签名的字符串:
16273667805456GET/api/v3/account/fee-rate?category=SPOT&symbol=BTCUSDT
POST 示例 — 现货限价下单(BTCUSDT):
- Timestamp = 16273667805456
- Method = "POST"
- requestPath = "/api/v3/trade/place-order"
- body = {"category":"SPOT","symbol":"BTCUSDT","side":"buy","orderType":"limit","qty":"0.1","price":"30000","timeInForce":"gtc"}
待签名的字符串:
16273667805456POST/api/v3/trade/place-order{"category":"SPOT","symbol":"BTCUSDT","side":"buy","orderType":"limit","qty":"0.1","price":"30000","timeInForce":"gtc"}
生成最终签名的步骤
HMAC
String payload = hmac_sha256(secretkey, Message);
String signature = base64.encode(payload);
RSA
第1步,使用 RSA 私钥 privateKey 对待签名字符串进行 SHA-256 签名。
第2步,对生成的签名字符串进行 Base64 编码。
HMAC 签名示例代码
- Java
- Python
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.management.RuntimeErrorException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import org.springframework.util.Base64Utils;
@Slf4j
public class CheckSign {
private static final String secretKey = "";
public static void main(String[] args) throws Exception {
//POST 签名示例
// String timestamp = "1684813405151";
// String body = "{\"symbol\":\"BTCUSDT\",\"productType\":\"usdt-futures\",\"marginMode\":\"crossed\",\"marginCoin\":\"USDT\",\"size\":\"8\",\"side\":\"buy\",\"orderType\":\"limit\",\"price\":\"30000\"}";
//
// String sign = generate(timestamp,"POST","/api/v3/trade/place-order" ,null,body,secretKey);
// log.info("sign:{}",sign);
//GET 签名示例
String timestamp = "1684814440729";
String queryString = "category=SPOT&symbol=BTCUSDT"; // 需按 key 的字典序升序排列
String sign = generate(timestamp,"GET","/api/v3/account/fee-rate" ,queryString,null,secretKey);
log.info("sign:{}",sign);
}
private static Mac MAC;
static {
try {
CheckSign.MAC = Mac.getInstance("HmacSHA256");
} catch (NoSuchAlgorithmException var1) {
throw new RuntimeErrorException(new Error("Can't get Mac's instance."));
}
}
public static String generate(String timestamp, String method, String requestPath,
String queryString, String body, String secretKey)
throws CloneNotSupportedException, InvalidKeyException, UnsupportedEncodingException {
method = method.toUpperCase();
body = StringUtils.defaultIfBlank(body, StringUtils.EMPTY);
queryString = StringUtils.isBlank(queryString) ? StringUtils.EMPTY : "?" + queryString;
String preHash = timestamp + method + requestPath + queryString + body;
log.info("preHash:{}",preHash);
byte[] secretKeyBytes = secretKey.getBytes("UTF-8");
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKeyBytes, "HmacSHA256");
Mac mac = (Mac) CheckSign.MAC.clone();
mac.init(secretKeySpec);
return Base64.getEncoder().encodeToString(mac.doFinal(preHash.getBytes("UTF-8")));
}
}
import hmac
import base64
import json
import time
def get_timestamp():
return int(time.time() * 1000)
def sign(message, secret_key):
mac = hmac.new(bytes(secret_key, encoding='utf8'), bytes(message, encoding='utf-8'), digestmod='sha256')
d = mac.digest()
return base64.b64encode(d)
def pre_hash(timestamp, method, request_path, body):
return str(timestamp) + str.upper(method) + request_path + body
def parse_params_to_str(params):
params = [(key, val) for key, val in params.items()]
params.sort(key=lambda x: x[0])
url = '?' +toQueryWithNoEncode(params);
if url == '?':
return ''
return url
def toQueryWithNoEncode(params):
url = ''
for key, value in params:
url = url + str(key) + '=' + str(value) + '&'
return url[0:-1]
if __name__ == '__main__':
API_SECRET_KEY = ""
timestamp = "1685013478665" # get_timestamp()
request_path = "/api/v3/trade/place-order"
# POST
params = {"category": "SPOT", "symbol": "BTCUSDT", "side": "buy", "orderType": "limit", "qty": "0.1", "price": "30000", "timeInForce": "gtc"}
body = json.dumps(params)
sign = sign(pre_hash(timestamp, "POST", request_path, str(body)), API_SECRET_KEY)
print(sign)
# GET
body = ""
request_path = "/api/v3/account/fee-rate"
params = {"category": "SPOT", "symbol": "BTCUSDT"}
request_path = request_path + parse_params_to_str(params) # 需按 key 的字典序升序排列
sign = sign(pre_hash(timestamp, "GET", request_path, body), API_SECRET_KEY)
print(sign)
RSA 签名示例代码
- Python
import base64
import json
import time
from Crypto.Hash import SHA256
from Crypto.Signature import PKCS1_v1_5
from Crypto.PublicKey import RSA
def get_timestamp():
return int(time.time() * 1000)
def rsa_sign(message, private_key):
pri_key = RSA.importKey(private_key)
encoded_param = SHA256.new(bytes(message, encoding='utf-8'))
sign_str = PKCS1_v1_5.new(pri_key).sign(encoded_param)
return base64.b64encode(sign_str).decode()
def pre_hash(timestamp, method, request_path, body):
return str(timestamp) + str.upper(method) + request_path + body
def parse_params_to_str(params):
params = [(key, val) for key, val in params.items()]
params.sort(key=lambda x: x[0])
from urllib.parse import urlencode
url = '?' +urlencode(params);
if url == '?':
return ''
return url
if __name__ == '__main__':
private_key = '''-----BEGIN PRIVATE KEY-----
YOUR_PRIVATE_KEY_HERE
-----END PRIVATE KEY-----'''
timestamp = get_timestamp()
request_path = "/api/v3/trade/place-order"
# POST
params = {"category": "SPOT", "symbol": "BTCUSDT", "side": "buy", "orderType": "limit", "qty": "0.1", "price": "30000", "timeInForce": "gtc"}
body = json.dumps(params)
sign = rsa_sign(pre_hash(timestamp, "POST", request_path, str(body)), private_key)
print(sign)
# GET
body = ""
request_path = "/api/v3/account/fee-rate"
params = {"category": "SPOT", "symbol": "BTCUSDT"}
request_path = request_path + parse_params_to_str(params) # 需按 key 的字典序升序排列
sign = rsa_sign(pre_hash(timestamp, "GET", request_path, body), private_key)
print(sign)
限频规则
如果请求过于频繁,系统会自动限制请求并返回 429 Too Many Requests 状态码。
限频规则:
- 各 API 接口的限频规则在各自文档页面中有标注;
- 各 API 接口的限频互相独立计算;
- REST 与 WebSocket 共享限频额度;
- 总体有 6000 次/IP/分钟的限频规则
WebSocket
概述
WebSocket 是 HTML5 一种新的协议(Protocol)。它实现了客户端与服务器全双工通信,使得数据可以快速地双向传播。通过一次简单的握手就可以建立客户端和服务器连接,服务器根据业务规则可以主动推送信息给客户端。其优点如下:
- 客户端和服务器进行数据传输时,请求头信息比较小,大概 2 个字节。
- 客户端和服务器皆可以主动地发送数据给对方。
- 不需要多次创建 TCP 请求和销毁,节约宽带和服务器的资源。
强烈建议开发者使用 WebSocket API 获取市场行情和深度等信息。
连接
连接限制:300 次连接请求/IP/5 分钟,单个 IP 最多可以创建 100 个连接
订阅限制:240 次/小时/连接,单个连接最多可以订阅 1000 个频道
为了保持连接有效且稳定,建议您进行以下操作:
- 用户设置一个定时器,每 30 秒发送字符串
"ping",并期待一个字符串"pong"作为回应。如果未收到字符串"pong"响应,请重新连接。 - 如果 2 分钟内服务端没收到
"ping",会自动断开连接。 - WebSocket 服务器每秒每连接最多接受 10 个消息,消息包括:
- 字符串
"ping" - JSON 格式的消息,包含登录、订阅、取消订阅
- 字符串
- 如果用户发送的消息超过限制,连接会被断开。反复被断开连接的 IP 有可能被服务器屏蔽。
- 为了保持连接的稳定性,强烈建议单个连接不要订阅超过 50 个频道。订阅频道数越少的连接,稳定性会更高。
登录
apiKey:用于调用 API 的用户身份唯一标识,需要用户申请。
passphrase:API Key 的密码。
timestamp:Unix 毫秒时间戳,时间戳 30 秒后会过期。
sign:签名字符串,签名规则如下:
待签名字符串(Message)为:timestamp + "GET" + "/user/verify"
const timestamp = '' + Date.now()
sign = CryptoJS.enc.Base64.Stringify(CryptoJS.HmacSHA256(timestamp + 'GET' + '/user/verify', secretKey))
method:一律默认为 'GET'。
requestPath:一律默认为 '/user/verify'。
请求在时间戳之后 30 秒会失效。如果您的服务器时间和 API 服务器时间有偏差,推荐使用 REST API 查询 API 服务器时间,然后同步时间戳。
生成最终签名的步骤
HMAC
第 1 步,拼接待签名字符串:
Long timestamp = System.currentTimeMillis() / 1000;
String content = timestamp + "GET" + "/user/verify";
第 2 步,使用私钥 secretkey 对字符串进行 HMAC SHA256 加密:
String hash = hmac_sha256(content, secretkey);
第 3 步,对 hash 进行 Base64 编码:
String sign = base64.encode(hash);
RSA
第 1 步,使用 RSA 私钥 privateKey 对待签名字符串进行 SHA-256 签名。
第 2 步,对生成的签名字符串进行 Base64 编码。
如果登录失败会自动断开连接。
{
"op":"login",
"args":[
{
"apiKey":"<api_key>",
"passphrase":"<passphrase>",
"timestamp":"<timestamp>",
"sign":"<sign>"
}
]
}
{
"op":"login",
"args":[
{
"apiKey":"xx_xxx",
"passphrase":"12345678",
"timestamp":"1538054050",
"sign":"8RCOqCJAhhEh4PWcZB/96QojLDqMAg4qNynIixFzS3E="
}
]
}
{
"event":"login",
"code":"0",
"msg":""
}
{
"event":"error",
"code":"30005",
"msg":"login fail"
}