# 加密货币量化系列之一：下载加密货币数据并交易

By [Trader Li](https://paragraph.com/@trader-li) · 2022-08-04

---

本文以Python为例，展示如何从全球最大的加密货币交易所「币安（Binance）」交易所下载加密货币的历史数据，并交易加密货币期货的方法，为此后加密货币的量化交易提供数据基础。

### 步骤一：搭建Python开发环境

Anaconda是包管理器和环境管理器，它附带了 conda、Python 和 150 多个科学包及其依赖项，因此对Python开发者非常友好。建议大家前往下面的官方网站进行下载：

[https://www.anaconda.com/](https://www.anaconda.com/)

### 步骤二：安装开发量化策略所需的Python包

除了常用的一些Python包（pandas，numpy等），ccxt（[https://github.com/ccxt/ccxt）是一个非常常用的加密货币量化包，它是一个开源的数字货币交易框架，连接了全球几乎所有的交易所，为用户提供了市场数据访问、算法交易等功能。初次使用前需要啊下载该工具包，方法如下：](https://github.com/ccxt/ccxt%EF%BC%89%E6%98%AF%E4%B8%80%E4%B8%AA%E9%9D%9E%E5%B8%B8%E5%B8%B8%E7%94%A8%E7%9A%84%E5%8A%A0%E5%AF%86%E8%B4%A7%E5%B8%81%E9%87%8F%E5%8C%96%E5%8C%85%EF%BC%8C%E5%AE%83%E6%98%AF%E4%B8%80%E4%B8%AA%E5%BC%80%E6%BA%90%E7%9A%84%E6%95%B0%E5%AD%97%E8%B4%A7%E5%B8%81%E4%BA%A4%E6%98%93%E6%A1%86%E6%9E%B6%EF%BC%8C%E8%BF%9E%E6%8E%A5%E4%BA%86%E5%85%A8%E7%90%83%E5%87%A0%E4%B9%8E%E6%89%80%E6%9C%89%E7%9A%84%E4%BA%A4%E6%98%93%E6%89%80%EF%BC%8C%E4%B8%BA%E7%94%A8%E6%88%B7%E6%8F%90%E4%BE%9B%E4%BA%86%E5%B8%82%E5%9C%BA%E6%95%B0%E6%8D%AE%E8%AE%BF%E9%97%AE%E3%80%81%E7%AE%97%E6%B3%95%E4%BA%A4%E6%98%93%E7%AD%89%E5%8A%9F%E8%83%BD%E3%80%82%E5%88%9D%E6%AC%A1%E4%BD%BF%E7%94%A8%E5%89%8D%E9%9C%80%E8%A6%81%E5%95%8A%E4%B8%8B%E8%BD%BD%E8%AF%A5%E5%B7%A5%E5%85%B7%E5%8C%85%EF%BC%8C%E6%96%B9%E6%B3%95%E5%A6%82%E4%B8%8B%EF%BC%9A)

### 步骤三：下载交易所历史数据

#### 步骤三a：连接交易所，下载并处理数据

ccxt下载成功后，可以使用如下方法连接交易所：

    import ccxt
    exchange = ccxt.binance()  #连接币安
    

使用fetch\_ohlcv方程即可下载历史数据，其中ohlcv分别代表了o（open，开盘价），h（high，最高价），l（low，最低价），c（close，收盘价），v（volume，交易量）。以比特币为例：

    symbol = 'BTCUSDT' #设置要查询的加密货币对
    time_interval = '1d' #设置数据频率
    start = exchange.parse8601('2020-01-01T00:00:00') #设置起始时间
    data = exchange.fetch_ohlcv(symbol=symbol, timeframe=time_interval,
                                since=start)
    

此时返回的数据是list of list的格式（下图所示）：

![下载的历史数据](https://storage.googleapis.com/papyrus_images/0fd406c021f519142137026cf7c0622a7d559346e608b07a84efb67ffbeb34cf.png)

下载的历史数据

该格式不方便浏览，因此需要将其设置成dataframe格式：

    df = pd.DataFrame(data, dtype=float)  # 将数据转换为dataframe
    df.columns = ['Time','Open','High','Low','Close','Volume'] #重新命名
    df['Time'] = pd.to_datetime(df['Time'], unit='ms')  # 处理时间
    

数据处理结果如下图：

![简单处理后的量价数据](https://storage.googleapis.com/papyrus_images/0e9e2bd61a81e6c774a29ccf35619f6349122451875533bdca01ea4670ab414a.png)

简单处理后的量价数据

#### 步骤三b：获得完整的历史K线数据

ccxt存在下载限制，并不能下载完整的K线数据。etch\_ohlcv默认只能换一性下载500个数据点。循环下载历史数据的方法如下：

    # 下载最新数据
    data = exchange.fetch_ohlcv(symbol=symbol, timeframe=time_interval)
    formated = formatData(data) #将原数据生成dataframe
    while formated.shape[0] > 1:
        list_data.append(formated.copy())
        # 计算返回数据中最早的日期数据
        early_time = formated['Time'].iloc[0]
        # 计算回看多少小时
        hoursToRevert = toHours(time_interval)
        start_time = early_time - timedelta(hours=hoursToRevert)
        start_time = str(start_time).replace(" ","T")
        print(start_time)
        # 转换时间
        new_start_time = exchange.parse8601(start_time)
        data = exchange.fetch_ohlcv(symbol=symbol, timeframe=time_interval,
                                since=new_start_time)
        formated = formatData(data)
    # 将所有数据合并
    combined_df = pd.concat(list_data,axis=0)
    # 调成北京时间
    combined_df['Time_GMT8'] = combined_df['Time'] + timedelta(hours=8)
    del combined_df['Time']
    # 删除重复值
    combined_df = combined_df.set_index('Time_GMT8')
    combined_df = combined_df.sort_index()
    combined_df = combined_df[~combined_df.index.duplicated(keep='last')]
    # 保存数据到本地
    combined_df.to_csv('{}_{}.csv'.format(symbol,time_interval))
    

其中，该循环方程运用到了时间转换方程toHours():

    """将time interval转换成以小时为单位"""
    def toHours(interval):
        if interval[-1] == 'm':
            return int(interval[:-1])/60
        if interval[-1] == 'h':
            return int(interval[:-1])
        if interval[-1] == 'd':
            return int(interval[:-1])*24
    

至此，我们获得了来自交易所的最完整烛线数据。

### 步骤四：交易

币安提供了官方API：

[https://binance-docs.github.io/apidocs](https://binance-docs.github.io/apidocs)

几乎以上所有的官方API可以通过ccxt的API实现，参考ccxt开发手册（[http://cw.hubwiz.com/card/c/ccxt-dev-manual/1/4/2/）。为了找出输入可以获得所有API的对应公式名称，可以输入如下命令：](http://cw.hubwiz.com/card/c/ccxt-dev-manual/1/4/2/%EF%BC%89%E3%80%82%E4%B8%BA%E4%BA%86%E6%89%BE%E5%87%BA%E8%BE%93%E5%85%A5%E5%8F%AF%E4%BB%A5%E8%8E%B7%E5%BE%97%E6%89%80%E6%9C%89API%E7%9A%84%E5%AF%B9%E5%BA%94%E5%85%AC%E5%BC%8F%E5%90%8D%E7%A7%B0%EF%BC%8C%E5%8F%AF%E4%BB%A5%E8%BE%93%E5%85%A5%E5%A6%82%E4%B8%8B%E5%91%BD%E4%BB%A4%EF%BC%9A)

    dir(ccxt.binance())
    

部分API接口可能需要签名（如下图），标志是括号含有HMAC SHA256。

![](https://storage.googleapis.com/papyrus_images/a08b8e9a136973007bbf691cdc76eb26fb92096c4194860835477c095145bd99.png)

根据币安API的官网介绍，对于此类API用户需要提供**API-KEY**和**API-Secret**。为了得到API Key和Secret，用户需要注册币安账户并创建API。方法是：

1\. 在币安（[binance.com](http://binance.com)）完成账户的注册\*\*（可以使用我10%的返佣码：485323223）\*\*后，点击右上角的人物头像，在下拉菜单中选择“API管理”。

![](https://storage.googleapis.com/papyrus_images/ad49d91ae42fcf053cc5a968814a44c5950d41ea5598e6fe684330ad22e857fc.png)

2\. 给API密钥设置一个标签后点击创建API，输入验证码之后，就会有API Key和Secret Key。

![](https://storage.googleapis.com/papyrus_images/f8b27cfe51227c453598cbaa3e746ec91eb39626f330f0a25879ce704c604620.png)

这样，我们便能对账户进行自动化操作。以交易**币本位期货**为例，由于保证金制度，币安需要用于将现货账户里的部分加密货币转移到币本位账户作为保证金。通过币安API查询，需要使用asset/transfer接口，ccxt提供了对应的接口sapi\_post\_asset\_transfer，红色方框是必须需要提供的参数。

![](https://storage.googleapis.com/papyrus_images/2408883a795d67e56607e53084b0d0c6269ec22513a1217b7f6963a7392de35c.png)

对应代码如下，将0.1个以太币从现货钱包转移至币本位合约钱包。

    import time
    import ccxt
    BINANCE_CONFIG = {
        'apiKey': '<填写APIkey>', #填写APIkey
        'secret': '<填写secret>', #填写secret
        'timeout': 3000,
        'rateLimit': 10,
        'enableRateLimit': False}
    exchange = ccxt.binance(BINANCE_CONFIG)
    res = exchange.sapi_post_asset_transfer({'type':'MAIN_CMFUTURE',
                                                  'asset':'ETH',
                                                  'amount':0.1,
                                             'timestamp':int(time.time() * 1000)})
    

其中type选择MAIN\_CMFUTURE是因为该类型符合转账需求。

![](https://storage.googleapis.com/papyrus_images/9cc625b5c9a62bd609823df2c9e51fdbd5cf213bc9e251d3331ceea27ba98c44.png)

而查看币安账户，可以发现0.1个以太币已经转移到了币本位钱包。

![](https://storage.googleapis.com/papyrus_images/d83ccd027bcaba099e247a24e292cfb15a6b8388390e7a5cdd8cf34d628544cf.png)

钱包中有了少许以太币便可以买卖以太币期货，通过查询币安官方API介绍，可以了解所需要的参数。

![](https://storage.googleapis.com/papyrus_images/2081d877d828d3b2ddb5d78dd12f5d5e3288f5f0773e4757366be688ebebca83.png)

确保币安开启双向持仓，即允许同时持有同一币种多空两个仓位。

![](https://storage.googleapis.com/papyrus_images/7799556f48cdb63cba592ceb93b5fea22a0826e4ac8a2059a56fce393b6227b4.png)

以市价开一单ETHUSD\_210924的期货代码如下：

    res  = exchange.dapiPrivate_post_order({'symbol':'ETHUSD_210924',
                                            'side': 'BUY',
                                            'positionSide':'LONG',
                                            'type':'MARKET',
                                            'timestamp':int(time.time() * 1000),
                                            'quantity':1})
    

从下图可以看到，已经成功买到了以太币期货。

![交易成功](https://storage.googleapis.com/papyrus_images/c938911c49d4a85edcc1cd261ea399479eaea8f7166bea0acc917dd99452bffa.png)

交易成功

---

*Originally published on [Trader Li](https://paragraph.com/@trader-li/DEIxofrVxMm8LxIReh71)*
