FCoin API支持

96
华子1889
2018.10.13 21:27* 字数 701

以下文档内容引用自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/resolution/symbol
这个api也有问题,其中的limit默认值不是20,而是根据resolution的不同而不同。比如resolution为D1,则为24;如果是M1,则为150;其它的没试

交易手续费:
https://support.fcoin.com/hc/zh-cn/articles/360003715514-%E4%BA%A4%E6%98%93%E6%89%8B%E7%BB%AD%E8%B4%B9%E5%8F%8A%E8%AE%A2%E5%8D%95%E8%A7%84%E5%88%99%E8%AF%B4%E6%98%8E

以下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)

日记本
Web note ad 1