FCoin API支持
以下文档内容引用自FCoin官方API支持群,如有侵权请联系我删除,谢谢。
严正声明:任何买卖软件的行为均与官方无关,请提高安全意识。避免资产损失。
目前只有rust版本的sdk,其他版本还在开发中。。。
目前不需要注册开发者,只需要申请apikey
apikey申请流程:
1.先注册账户
2.在设置页面,绑定GA
3.在设置页面,申请api,必须填写标签
limit:限价
market:市价
市价下单不需要传price
api文档:
https://developer.fcoin.com/zh.html#32c808cbe5
获取最新的成交明细接口中,before暂时无用
https://api.fcoin.com/v2/market/trades/ftusdt?limit=1
https://api.fcoin.com/v2/market/candles/symbol
这个api也有问题,其中的limit默认值不是20,而是根据resolution的不同而不同。比如resolution为D1,则为24;如果是M1,则为150;其它的没试
以下3个参数,需要放在headers中
FC-ACCESS-KEY
FC-ACCESS-SIGNATURE
FC-ACCESS-TIMESTAMP
post时:headers中一定要加'content-type': 'application/json;charset=UTF-8'
websocket:
def get_market_price(symbol):
ws = create_connection("wss://ws.fcoin.com/api/v2/ws")
ws.recv()
s = "ticker.{}".format(symbol['name'])
req = {
'cmd':'req',
'args':[s],
'id':'1'
}
ws.send(json.dumps(req))
r = json.loads(ws.recv())
ws.close()
return r['data']['ticker'][0]
深度订阅,实际发送的内容是:{"cmd":"sub","args":["depth.L100.btcusdt"],"id":"1"}
获取订单列表中:
至少传symbol和state
git地址:https://github.com/FCoinCommunity
Post请求时一定要加json头:
'content-type': 'application/json;charset=UTF-8'
请求的body要传json格式
可以查询以提交和部分成交的数据:
submitted, partial_filled, partial_canceled, filled, canceled
这些状态,可以同时传,中间用逗号隔开
Post签名前的字符串:
POST
https://api.fcoin.com/v2/orders1528532934527amount=1000&price=0.192011&side=buy&symbol=ftusdt&type=limit
Get签名前的字符串:
GET https://api.fcoin.com/v2/orders?limit=20&states=submitted,partial_filled&symbol=ethusdt1528532959168
获取订单接口中before和after表示时间戳,只能有1个时间戳,limit最大支持100
public是要传给服务器的,secret是用来签名的
1002 system busy 是因为下单太快了
获取行情深度接口中,只有L20,L150,full
python版本的签名代码:
def sort_payload(self, payload):
keys = sorted(payload.keys())
result = ''
for i in range(len(keys)):
if i != 0:
result += '&' + keys[i] + "=" + str(payload[keys[i]])
else:
result += keys[i] + "=" + str(payload[keys[i]])
return result
# 对请求数据进行加密编码
def encrypt_data(self, HTTP_METHOD, HTTP_REQUEST_URI, TIMESTAMP, POST_BODY, secret):
payload_result = ''
if POST_BODY != '':
payload_result = self.sort_payload(POST_BODY)
data = HTTP_METHOD + HTTP_REQUEST_URI + TIMESTAMP + payload_result
print(data)
data_base64 = base64.b64encode(bytes(data, encoding='utf8'))
# print(data_base64)
data_base64_sha1 = hmac.new(bytes(secret, encoding='utf8'), data_base64, hashlib.sha1).digest()
data_base64_sha1_base64 = base64.b64encode(data_base64_sha1)
# print(data_base64_sha1_base64)
return str(data_base64_sha1_base64, encoding='utf-8')
def create_headers(self, HTTP_METHOD, HTTP_REQUEST_URI, TIMESTAMP, POST_BODY, public_key, secret_key):
signature = self.encrypt_data(HTTP_METHOD, HTTP_REQUEST_URI, str(TIMESTAMP), POST_BODY, secret_key)
self.headers['FC-ACCESS-KEY'] = public_key
self.headers['FC-ACCESS-TIMESTAMP'] = str(TIMESTAMP)
self.headers['FC-ACCESS-SIGNATURE'] = signature
Php版本的签名代码:
// 获取毫秒时间戳
function get_millisecond() {
list($t1, $t2) = explode(' ', microtime());
return (float)sprintf('%.0f', (floatval($t1) + floatval($t2)) * 1000);
}
//hmac_sha1算法
function getSignature($str, $key) {
$signature = "";
if (function_exists('hash_hmac')) {
$signature = base64_encode(hash_hmac("sha1", $str, $key, true));
} else {
$blocksize = 64;
$hashfunc = 'sha1';
if (strlen($key) > $blocksize) {
$key = pack('H*', $hashfunc($key));
}
$key = str_pad($key, $blocksize, chr(0x00));
$ipad = str_repeat(chr(0x36), $blocksize);
$opad = str_repeat(chr(0x5c), $blocksize);
$hmac = pack(
'H*', $hashfunc(
($key ^ $opad) . pack(
'H*', $hashfunc(
($key ^ $ipad) . $str
)
)
)
);
$signature = base64_encode($hmac);
}
return $signature;
}
// 组合参数
function bind_param($param) {
if($param){
$u = [];
$sort_rank = [];
foreach($param as $k=>$v) {
$u[] = $k."=".urlencode($v);
$sort_rank[] = ord($k);
}
asort($u);
return implode('&', $u);
}else{
return '';
}
}
// 生成签名
function create_sig($param) {
$this->access_timestamp = $this->get_millisecond();
$sign_param_1 = $this->req_method.$this->sign_url.$this->api_method.$this->access_timestamp.$this->bind_param($param);
$sign_param_1 = base64_encode($sign_param_1);
$signature = $this->getSignature($sign_param_1,SECRET_KEY);
return $signature;
}
Java版签名程序:
public String sign(String method, String url, String timestamp, Map params, String accessKey) {
StringBuilder sb = new StringBuilder(500);
method = Objects.requireNonNull(method).toUpperCase();
sb.append(method).append(url).append(timestamp).append(extractPostBody(method, params));
String concat = sb.toString();
log.info(concat);
byte[] encodeData = Base64.getEncoder().encode(concat.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder()
.encodeToString(hmacSha1(encodeData, accessKey.getBytes(StandardCharsets.UTF_8)));
}
public static String extractPostBody(String method, Map params) {
if (!"POST".equals(method)) {
return "";
}
if (params.isEmpty()) {
return "";
}
List paramKeys = new LinkedList();
for(Map.Entry entry : params.entrySet()){
if (entry.getValue() == null) {
return;
}
if ((entry.getValue() instanceof String) && ((String) entry.getValue()).isEmpty()) {
return;
}
paramKeys.add(entry.getKey());
}
Collections.sort(paramKeys);
StringBuilder sb = new StringBuilder(100);
for (String paramKey : paramKeys) {
sb.append(paramKey).append("=").append(params.get(paramKey)).append("&");
}
sb.deleteCharAt(sb.length() - 1);// 删除结尾多余的&
return sb.toString();
}
public static byte[] hmacSha1(byte[] data, byte[] key) {
try {
String digestMethod = "HmacSHA1";
SecretKeySpec signingKey = new SecretKeySpec(key, digestMethod);
Mac mac = Mac.getInstance(digestMethod);
mac.init(signingKey);
return mac.doFinal(data);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("不支持的加密方式", e);
} catch (InvalidKeyException e) {
throw new RuntimeException("无效的私钥", e);
}
}
各种语言常见问题:
所有语言的header中都要加:'content-type': 'application/json;charset=UTF-8'
易语言中默认是ansi编码的,我转为utf8再base64跟直接base64结果不一样。
Python在post请求时,参数一定要json.dumps(payload)