币安API接入-一键划转现货账户和资金账户的某个币种的所有资金

1、币安API接入资料

注意:币安的API需要开代理才能调,就是国内调不通,要用国外的IP才能调,还不是所有国家都可以,所以没有这个条件的可以不用往下看了,有代理就是能翻墙,才可以继续走下去。

币安API文档位置
币安提供了详细的API文档,其中包含了各种可用的API端点和参数。您可以根据自己的需求选择合适的API端点来执行自动划转。右上角有简体中文切换。

java代码
这是binance官方提供的代码,可以用于生成签名,下面需要用到,如果是其它语言,也可以在上面文档中:
Introduction -> API Library

需求:一键划转现货账户和资金账户的某个币种的所有资金

建议1:从头开始阅读该文档,不要漏掉开头,因为很多参数和专业术语的介绍都在前面,如果你直接去找API,里面的参数可能你可能并不理解。公共参数看完后,后面的参数都是类似的,所以多花点时间阅读前面的文档。

建议2:先使用工具进行测试,比如我是使用ApiPost工具,将参数设置好后发送请求,看看调用结果,最后再编写代码自动运行,从简单到复杂。

2、文档部分专业词汇摘录

账户
SPOT:现货账户
MARGIN:杠杆账户
FUTURES:期货账户

接口鉴权
NONE 不需要鉴权的接口
TRADE 需要有效的 API-Key 和签名
MARGIN 需要有效的 API-Key 和签名
USER_DATA 需要有效的 API-Key 和签名
USER_STREAM 需要有效的 API-Key
MARKET_DATA 需要有效的 API-Key

API-Key密钥
登录到您的币安账户,进入“API管理”页面,然后创建一个新的API密钥。确保选择适当的权限和限制,以便只允许进行必要的操作。
(主页自己的头像-》APIManagement,里面可以添加密钥;注意:普通查询不用添加IP地址限制,但是转账这些操作,需要添加IP地址,防止资金被盗)

接口鉴权中需要有效的 API-Key
就是上面在币安账户页面生成的一个API秘钥串,应当在HTTP头中以 X-MBX-APIKEY字段传递。
我用的是ApiPost,本地测试时可以在文件夹里设置公共的header {X-MBX-APIKEY : “xxxxxAPI-Keyxxxxx”}

签名(重点,这里很容易出错)
文档中有对前面单独介绍:基本信息-》SIGNE
下载代码后,搜索HmacSignatureGenerator.java类,里面有一个 getSignature 方法。
注意:签名是对你传入的 所有参数+值+&拼接的字符串进行签名,且顺序最好不要改变,你就按照文档的顺序,传值,拼接,因为本来我是用map来传的,后来总是不通,后来换成List,添加参数的顺序和我前面时参数的顺序一致,就通了。

3、编码实践

1、首先,使用不需要鉴权,也不需要代理的API:如:测试服务连通性,返回服务时间

// 测试服务连通性,返回服务时间
https://data-api.binance.vision/api/v3/time

// 测试服务连通性,返回{}
https://data-api.binance.vision/api/v3/ping

2、使用查询类的API,需要鉴权+代理

在这里插入图片描述

base URL-摘录文档(基本信息-》API基本信息)
https://api.binance.com
https://api-gcp.binance.com
https://api1.binance.com
https://api2.binance.com
https://api3.binance.com
https://api4.binance.com
上述列表的最后4个接口 (api1-api4) 可能会提供更好的性能,但其稳定性略为逊色。因此,请务必使用最适合您现有配置的那款。所有接口的响应都是 JSON 格式。

// 这里以查询接口为例,进行账户参数解释
USER_DATA:表示这个接口需要有效的 API-Key 和签名
API-key:需要放到header中,以 X-MBX-APIKEY 为参数名传递

type:账户类型
startTime,endTime为查询资产快照起始时间,可以不填,默认七天。
limit:天数
recvWindow:这个比较重要,是以你传入的timestamp为起点,计算是否超过有效期,最大设置为60000,就是一分钟内有效
timestamp:签名需要这个参数,且要和 recvWindow 一起判断,有没有超过现在时间点,如果 timestamp+recvWindow<now(),就表示过期了。
signature:注意参数顺序,调用币安的签名函数,对data进行签名。
String data = "type=LIMIT&recvWindow=60000&timestamp=1499827319559";

// ApiPost调用信息
https://api.binance.com/sapi/v1/accountSnapshot?type=SPOT&recvWindow=60000&timestamp=1499827319559&signature=e335b4e7a2d7cede3246ed0f1915766d3fb8175ae183b09cc3a886aeb5ac256b

3、提币API(重点)

这里需要打开 API-Key的权限,且需要添加IP地址,否则提币功能是调不通的。
难点:币安需要开代理才能调通,开了代理还要查询自己的公网IP,最好还是静态外网IP,否则下次再用,又要去币安登记IP地址,不过亲测也快,三分钟就搞定。注意不是局域网IP,192.168.x.x这是局域网IP地址,注意区分。
Windows查看外网IP地址:curl ipinfo.io
MAC 查看外网IP地址:curl ifconfig.me

package com.binance.connector.client.utils.signaturegenerator;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.codec.binary.Hex;

import com.binance.connector.client.utils.ParameterChecker;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.net.URI;
import java.util.*;

public final class HmacSignatureGenerator implements SignatureGenerator {
    private static final String apiKey = "this is my apiKey";
    private static final String HMAC_SHA256 = "HmacSHA256";
    private String apiSecret = "this is my secretKey"; // 和 apiKey一起生成的

    public HmacSignatureGenerator() {
    }

    public HmacSignatureGenerator(String apiSecret) {
        ParameterChecker.checkParameterType(apiSecret, String.class, "apiSecret");
        this.apiSecret = apiSecret;
    }

    public String getSignature(String data) {
        byte[] hmacSha256;
        try {
            SecretKeySpec secretKeySpec = new SecretKeySpec(apiSecret.getBytes(), HMAC_SHA256);
            Mac mac = Mac.getInstance(HMAC_SHA256);
            mac.init(secretKeySpec);
            hmacSha256 = mac.doFinal(data.getBytes());
        } catch (Exception e) {
            throw new RuntimeException("Failed to calculate hmac-sha256", e);
        }
        return Hex.encodeHexString(hmacSha256);
    }

    public static void main(String[] args) {
        transferSpotAndFund();
    }

    /**
     * 正式环境:一键划转现货账户和资金账户的某个币种的所有资金
     */
    public static void transferSpotAndFund() {
        // 1、获取现货账户资金余额
        String spotAccountTokenInfo = spotAccountInfo();

        // 2、获取资金账户的余额
        String fundAccountTokenInfo = fundAccountInfo();

        // 3、解析现货账户需要划转的币种的余额
        String tokenName = "USDT";
        String spotTokenFree = jsonParseSpotAccount(spotAccountTokenInfo, tokenName).split("\\.")[0];
        System.out.println(String.format("现货账户转出的币种为:%s, 转出的金额为:%s", tokenName, spotTokenFree));

        // 4、解析资金账户需要划转的币种的余额
        String fundTokenFree = jsonParseFundAccount(fundAccountTokenInfo, tokenName).split("\\.")[0];
        System.out.println(String.format("资金账户转出的币种为:%s, 转出的金额为:%s", tokenName, fundTokenFree));

        // 5、对此金额进行划转(0现货账户,1资金账户)
//        withdraw(tokenName, spotTokenFree, "0");
//        withdraw(tokenName, fundTokenFree, "1");

    }

    /**
     * 解析现货账户的JSON,获取指定币种的余额,没查到则返回 0
     */
    public static String jsonParseSpotAccount(String jsonStr, String tokenName) {
        String tokenNameKey = "asset"; // 币安返回币种列表的名称key
        String tokenFreeKey = "free"; // 币安返回币种列表的余额key
        JSONObject jsonObject = JSON.parseObject(jsonStr);
        JSONArray balances = jsonObject.getJSONArray("balances");
        for (int i = 0; i < balances.size(); i++) {
            JSONObject balance = balances.getJSONObject(i);
            if (tokenName.equals(balance.getString(tokenNameKey))) {
                return balance.getString(tokenFreeKey);
            }
        }
        return "0";
    }

    /**
     * 解析资金账户的JSON,获取指定币种的余额,没查到则返回 0
     */
    public static String jsonParseFundAccount(String jsonStr, String tokenName) {
        String tokenNameKey = "asset"; // 币安返回币种列表的名称key
        String tokenFreeKey = "free"; // 币安返回币种列表的余额key
        JSONArray balances = JSON.parseArray(jsonStr);
        for (int i = 0; i < balances.size(); i++) {
            JSONObject balance = balances.getJSONObject(i);
            if (tokenName.equals(balance.getString(tokenNameKey))) {
                return balance.getString(tokenFreeKey);
            }
        }
        return "0";
    }

    /**
     * 正式环境:查询每日资产快照 (USER_DATA)
     */
    public static void accountSnapshot() {
        // 1、构造参数和签名
        String type = "SPOT";
        String startTime = String.valueOf(System.currentTimeMillis());
        String limit = "1";
        String recvWindow = "60000";
        String timestamp = String.valueOf(System.currentTimeMillis());
        String signature;
        //TODO 注意:如果修改了上面的参数,需要修改签名,增加此参数,否则签名验证会失效
        String data = String.format("type=%s&limit=%s&recvWindow=%s&timestamp=%s", type, limit, recvWindow, timestamp);
        HmacSignatureGenerator generator = new HmacSignatureGenerator();
        signature = generator.getSignature(data);

        System.out.println("需要签名的数据:" + data);
        System.out.println("时间戳:" + timestamp);
        System.out.println("签名:" + signature);

        // 2、发送请求
        // 构造参数的顺序必须一定,否则会导致签名验证失败
        List<NameValuePair> paramList = new ArrayList<>();
        paramList.add(new BasicNameValuePair("type", type));
        paramList.add(new BasicNameValuePair("limit", limit));
        paramList.add(new BasicNameValuePair("recvWindow", recvWindow));
        paramList.add(new BasicNameValuePair("timestamp", timestamp));
        paramList.add(new BasicNameValuePair("signature", signature));

        String url = "https://api.binance.com/sapi/v1/accountSnapshot";
        doGet(url, paramList);
    }

    /**
     * 正式环境:提币 (USER_DATA)
     */
    public static void withdraw(String coin, String amount, String walletType) {
        // 1、构造参数和签名
        String network = "TRX";
        String address = "this is someone receiveAddress";
        String transactionFeeFlag = "true"; // 当站内转账时免手续费, true: 手续费归资金转入方; false: 手续费归资金转出方; . 默认 false.
        String recvWindow = "60000";
        String timestamp = String.valueOf(System.currentTimeMillis());
        String signature;

        String data = String.format("coin=%s&network=%s&address=%s&amount=%s&transactionFeeFlag=%s&walletType=%s" +
                        "&recvWindow=%s&timestamp=%s",
                coin, network, address, amount, transactionFeeFlag, walletType, recvWindow, timestamp);

        HmacSignatureGenerator generator = new HmacSignatureGenerator();
        signature = generator.getSignature(data);
//        System.out.println("需要签名的数据:" + data);
//        System.out.println("时间戳:" + timestamp);
//        System.out.println("签名:" + signature);

        // 2、发送请求
        // 构造参数的顺序必须一定,否则会导致签名验证失败
        List<NameValuePair> paramList = new ArrayList<>();
        paramList.add(new BasicNameValuePair("coin", coin));
        paramList.add(new BasicNameValuePair("network", network));
        paramList.add(new BasicNameValuePair("address", address));
        paramList.add(new BasicNameValuePair("amount", amount));
        paramList.add(new BasicNameValuePair("transactionFeeFlag", transactionFeeFlag));
        paramList.add(new BasicNameValuePair("walletType", walletType));
        paramList.add(new BasicNameValuePair("recvWindow", recvWindow));
        paramList.add(new BasicNameValuePair("timestamp", timestamp));
        paramList.add(new BasicNameValuePair("signature", signature));

        String url = "https://api.binance.com/sapi/v1/capital/withdraw/apply";
        doPost(url, paramList);
    }

    /**
     * 正式环境:现货账户信息 (USER_DATA)
     */
    public static String spotAccountInfo() {
        // 1、构造参数和签名
        String recvWindow = "60000";
        String timestamp = String.valueOf(System.currentTimeMillis());
        String signature;
        //TODO 注意:如果修改了上面的参数,需要修改签名,增加此参数,否则签名验证会失效
        String data = String.format("recvWindow=%s&timestamp=%s", recvWindow, timestamp);
        HmacSignatureGenerator generator = new HmacSignatureGenerator();
        signature = generator.getSignature(data);

//        System.out.println("需要签名的数据:" + data);
//        System.out.println("时间戳:" + timestamp);
//        System.out.println("签名:" + signature);

        // 2、发送请求
        // 构造参数的顺序必须一定,否则会导致签名验证失败
        List<NameValuePair> paramList = new ArrayList<>();
        paramList.add(new BasicNameValuePair("recvWindow", recvWindow));
        paramList.add(new BasicNameValuePair("timestamp", timestamp));
        paramList.add(new BasicNameValuePair("signature", signature));

        String url = "https://api.binance.com/api/v3/account";
        return doGet(url, paramList);
    }

    /**
     * 正式环境:资金账户信息 (USER_DATA)
     */
    public static String fundAccountInfo() {
        // 1、构造参数和签名
        String recvWindow = "60000";
        String timestamp = String.valueOf(System.currentTimeMillis());
        String signature;
        //TODO 注意:如果修改了上面的参数,需要修改签名,增加此参数,否则签名验证会失效
        String data = String.format("recvWindow=%s&timestamp=%s", recvWindow, timestamp);
        HmacSignatureGenerator generator = new HmacSignatureGenerator();
        signature = generator.getSignature(data);

        // 2、发送请求
        // 构造参数的顺序必须一定,否则会导致签名验证失败
        List<NameValuePair> paramList = new ArrayList<>();
        paramList.add(new BasicNameValuePair("recvWindow", recvWindow));
        paramList.add(new BasicNameValuePair("timestamp", timestamp));
        paramList.add(new BasicNameValuePair("signature", signature));

        String url = "https://api.binance.com/sapi/v1/asset/get-funding-asset";
        return doPost(url, paramList);
    }

    /**
     * POST请求
     * 执行流程:
     */
    public static String doPost(String url, List<NameValuePair> paramList) {
        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";
        try {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);
            httpPost.setHeader("X-MBX-APIKEY", apiKey);
            httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");

            // 模拟表单
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);
            httpPost.setEntity(entity);

            // 执行http请求
            response = httpClient.execute(httpPost);
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
            System.out.println("执行结果:" + resultString);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return resultString;
    }

    /**
     * GET请求
     * 流程:
     * 1、URL
     * 2、转换为 URIBuilder 用来加参数
     * 3、转换为 URI
     * 4、构造 HTTPGET 对象并放入 URI
     * 5、设置 header 并发送
     */
    public static String doGet(String url, List<NameValuePair> paramList) {
        // 创建Httpclient对象
        CloseableHttpClient httpclient = HttpClients.createDefault();
        String resultString = "";
        CloseableHttpResponse response = null;
        try {
            // 2、转换为 URIBuilder 用来加参数
            URIBuilder builder = new URIBuilder(url);
            builder.addParameters(paramList);
            // 3、转换为 URI
            URI uri = builder.build();
            // 4、构造 HTTPGET 对象并放入 URI
            HttpGet httpGet = new HttpGet(uri);
            httpGet.setHeader("X-MBX-APIKEY", apiKey);
            // 5、执行请求
            response = httpclient.execute(httpGet);
            // 解析返回状态
            if (response != null) {
                resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
                System.out.println("查询结果:" + resultString);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                httpclient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return resultString;
    }

}

4、图片

代码下载位置
在这里插入图片描述

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值