数字货币量化系统之数据分析
通过上一博文数字货币行情数据获取,我们已经学会如何通过交易所提供的开放接口获取交易数据了,这一节我们将通过获取的数据进行更深层次的分析。
分析步骤
1、获取加密货币市场行情
2、可视化数据
- 2.1 收盘价可视化
- 2.2 日成交量可视化
3、金融数据分析
- 3.1 价格相关分析
- 3.2 日收益率分析
- 3.3 累计日收益率分析
加密货币数据分析
运用所学的知识,对3个交易对市场行情进行分析。
- BTC/USDT
- ETH/USDT
- BCH/USDT
Step 0: 引入相关模块/包
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
Step 1: 获取加密货币市场行情
import datetime
import cryptocoin_data_utils as cdu
btc_df = cdu.get_single_kline_data(symbol='btc_usdt', kline_type='1day')
eth_df = cdu.get_single_kline_data(symbol='eth_usdt', kline_type='1day')
bch_df = cdu.get_single_kline_data(symbol='bch_usdt', kline_type='1day')
btc_df.head()
datetime | open | high | low | close | vol | symbol | |
---|---|---|---|---|---|---|---|
0 | 2017-10-10 16:00:00 | 1 | 4901 | 1 | 4901 | 19.26 | BTC/USDT |
1 | 2017-10-11 16:00:00 | 4901 | 4999 | 4790 | 4989 | 0.580096 | BTC/USDT |
2 | 2017-10-12 16:00:00 | 4989 | 5922 | 4989 | 5741.7 | 20.7398427 | BTC/USDT |
3 | 2017-10-13 16:00:00 | 5741.7 | 5849.95 | 5473.77 | 5849.95 | 19.25958 | BTC/USDT |
4 | 2017-10-14 16:00:00 | 5849.95 | 5849.95 | 5686.41 | 5848 | 8.65860682 | BTC/USDT |
eth_df.head()
datetime | open | high | low | close | vol | symbol | |
---|---|---|---|---|---|---|---|
0 | 2017-10-10 16:00:00 | 1 | 310 | 1 | 300 | 260.826 | ETH/USDT |
1 | 2017-10-11 16:00:00 | 300 | 300 | 285 | 285 | 0.33326666 | ETH/USDT |
2 | 2017-10-12 16:00:00 | 285 | 304.8 | 285 | 304.8 | 2.39326666 | ETH/USDT |
3 | 2017-10-13 16:00:00 | 304.8 | 343.99 | 304.8 | 343.8 | 8.284 | ETH/USDT |
4 | 2017-10-14 16:00:00 | 343.8 | 348 | 331 | 331 | 25.58901316 | ETH/USDT |
bch_df.head()
datetime | open | high | low | close | vol | symbol | |
---|---|---|---|---|---|---|---|
0 | 2018-11-18 16:00:00 | 245 | 254.9999 | 203.001 | 234.2346 | 9480.54967848 | BCH/USDT |
1 | 2018-11-19 16:00:00 | 234.2346 | 259.97 | 196.2657 | 255 | 15922.975 | BCH/USDT |
2 | 2018-11-20 16:00:00 | 255 | 257.0754 | 216.71 | 240 | 8035.08557488 | BCH/USDT |
3 | 2018-11-21 16:00:00 | 240 | 241.48 | 219.13 | 220.5 | 4822.2932 | BCH/USDT |
4 | 2018-11-22 16:00:00 | 220.5 | 223.4319 | 197.4958 | 209 | 5841.8491 | BCH/USDT |
btc_df.to_csv('./btc_usdt_data.csv', index=False)
eth_df.to_csv('./eth_usdt_data.csv', index=False)
bch_df.to_csv('./bch_usdt_data.csv', index=False)
Step 2: 可视化数据
2.1 收盘价可视化
btc_df = pd.read_csv('./btc_usdt_data.csv', index_col='datetime', parse_dates=True)
eth_df = pd.read_csv('./eth_usdt_data.csv', index_col='datetime', parse_dates=True)
bch_df = pd.read_csv('./bch_usdt_data.csv', index_col='datetime', parse_dates=True)
# 检查是否有重复的index
btc_df[btc_df.index.duplicated()]
btc_df.loc['2018-02-03']
open | high | low | close | vol | symbol | |
---|---|---|---|---|---|---|
datetime | ||||||
2018-02-03 16:00:00 | 9188.9281 | 9470.6318 | 8450.0 | 8837.6286 | 46148.596221 | BTC/USDT |
if btc_df.index.duplicated().any():
print('BTC索引去重')
btc_df = btc_df[~btc_df.index.duplicated()]
if eth_df.index.duplicated().any():
print('ETH索引去重')
eth_df = eth_df.loc[~eth_df.index.duplicated()]
if bch_df.index.duplicated().any():
print('BCH索引去重')
bch_df = bch_df.loc[~bch_df.index.duplicated()]
btc_df['close'].plot(label='BTH/USDT', figsize=(16,8), title='Close Price')
eth_df['close'].plot(label='ETH/USDT')
bch_df['close'].plot(label='BCH/USDT')
plt.legend()
2.2 日成交量可视化
btc_df['vol'].plot(label='BTC/USDT', figsize=(16, 8), title='Volume Traded')
eth_df['vol'].plot(label='ETH/USDT')
bch_df['vol'].plot(label='BCH/USDT')
plt.legend()
eth_df['vol'].idxmax()
Timestamp('2019-04-03 16:00:00')
Q: 2018年2月5日,2018年9月5日,2018年9月13日, 2019年4月3日 这四天以太坊发生了什么?
A: 2018年2月5日,Truebit将Dogecoin带入以太坊区块链。http://www.o-o-o.link/article/6034.html
bch_df['vol'].idxmax()
Timestamp('2019-07-16 16:00:00')
Step 3: 金融数据分析
3.1 价格相关性分析
from pandas.plotting import scatter_matrix
coins_index = bch_df.index
coins_df = pd.DataFrame(columns=['BTC/USDT', 'ETH/USDT', 'BCH/USDT'], index=bch_df.index)
coins_df.head()
BTC/USDT | ETH/USDT | BCH/USDT | |
---|---|---|---|
datetime | |||
2018-11-18 16:00:00 | NaN | NaN | NaN |
2018-11-19 16:00:00 | NaN | NaN | NaN |
2018-11-20 16:00:00 | NaN | NaN | NaN |
2018-11-21 16:00:00 | NaN | NaN | NaN |
2018-11-22 16:00:00 | NaN | NaN | NaN |
coins_df['BTC/USDT'] = btc_df['close']
coins_df['ETH/USDT'] = eth_df['close']
coins_df['BCH/USDT'] = bch_df['close']
coins_df.head()
BTC/USDT | ETH/USDT | BCH/USDT | |
---|---|---|---|
datetime | |||
2018-11-18 16:00:00 | 5217.2507 | 157.3733 | 234.2346 |
2018-11-19 16:00:00 | 4947.8746 | 149.3194 | 255.0000 |
2018-11-20 16:00:00 | 4631.8422 | 137.7829 | 240.0000 |
2018-11-21 16:00:00 | 4561.4075 | 133.2573 | 220.5000 |
2018-11-22 16:00:00 | 4406.7303 | 124.1879 | 209.0000 |
- 使用scatter_matrix()可视化相关性
scatter_matrix(coins_df, figsize=(10, 10), hist_kwds={'bins': 50});
# 说明该图可以按照对角线看,第一行第一列表示BTC自己对比,第一行第二列表示BTC/ETH 对比,第一行第三列表示BTC/BCH 对比
- 使用pairplot()可视化相关性
import seaborn as sns
sns.pairplot(coins_df)
# 从下图可以看出以太坊和BCH相关性比较强
- 使用corr()量化相关性
coins_df.corr()
BTC/USDT | ETH/USDT | BCH/USDT | |
---|---|---|---|
BTC/USDT | 1.000000 | 0.814809 | 0.800630 |
ETH/USDT | 0.814809 | 1.000000 | 0.937294 |
BCH/USDT | 0.800630 | 0.937294 | 1.000000 |
结论:
根据corr()得出的结果可以看出 ETH和BCH有很强的正相关性,我们可以根据这个相关性来对 ETH、BCH做出买卖,如果ETH一段时间内飞涨,
而BCH没有涨动,我们可以买入BCH,同理如果有一个暴跌,另外一个还没有跌时,我们可以卖出。
3.2 日收益率分析
日收益率计算公式:
$r_t = \frac{pt}{p{t-1}} -1$
-
$p_t$: $t$ 时刻的价格
-
$p_{t-1}$: $t-1$ 时刻的价格
-
方法1:用shift()操作
btc_df['returns'] = (btc_df['close'] / btc_df['close'].shift(1) ) - 1
btc_df.head()
open | high | low | close | vol | symbol | returns | |
---|---|---|---|---|---|---|---|
datetime | |||||||
2017-10-10 16:00:00 | 1.00 | 4901.00 | 1.00 | 4901.00 | 19.260000 | BTC/USDT | NaN |
2017-10-11 16:00:00 | 4901.00 | 4999.00 | 4790.00 | 4989.00 | 0.580096 | BTC/USDT | 0.017956 |
2017-10-12 16:00:00 | 4989.00 | 5922.00 | 4989.00 | 5741.70 | 20.739843 | BTC/USDT | 0.150872 |
2017-10-13 16:00:00 | 5741.70 | 5849.95 | 5473.77 | 5849.95 | 19.259580 | BTC/USDT | 0.018853 |
2017-10-14 16:00:00 | 5849.95 | 5849.95 | 5686.41 | 5848.00 | 8.658607 | BTC/USDT | -0.000333 |
- 方法2:使用pct_change()操作
btc_df['returns'] = btc_df['close'].pct_change(1)
btc_df.head()
open | high | low | close | vol | symbol | returns | |
---|---|---|---|---|---|---|---|
datetime | |||||||
2017-10-10 16:00:00 | 1.00 | 4901.00 | 1.00 | 4901.00 | 19.260000 | BTC/USDT | NaN |
2017-10-11 16:00:00 | 4901.00 | 4999.00 | 4790.00 | 4989.00 | 0.580096 | BTC/USDT | 0.017956 |
2017-10-12 16:00:00 | 4989.00 | 5922.00 | 4989.00 | 5741.70 | 20.739843 | BTC/USDT | 0.150872 |
2017-10-13 16:00:00 | 5741.70 | 5849.95 | 5473.77 | 5849.95 | 19.259580 | BTC/USDT | 0.018853 |
2017-10-14 16:00:00 | 5849.95 | 5849.95 | 5686.41 | 5848.00 | 8.658607 | BTC/USDT | -0.000333 |
eth_df['returns'] = eth_df['close'].pct_change(1)
bch_df['returns'] = bch_df['close'].pct_change(1)
eth_df.head()
open | high | low | close | vol | symbol | returns | |
---|---|---|---|---|---|---|---|
datetime | |||||||
2017-10-10 16:00:00 | 1.0 | 310.00 | 1.0 | 300.0 | 260.826000 | ETH/USDT | NaN |
2017-10-11 16:00:00 | 300.0 | 300.00 | 285.0 | 285.0 | 0.333267 | ETH/USDT | -0.050000 |
2017-10-12 16:00:00 | 285.0 | 304.80 | 285.0 | 304.8 | 2.393267 | ETH/USDT | 0.069474 |
2017-10-13 16:00:00 | 304.8 | 343.99 | 304.8 | 343.8 | 8.284000 | ETH/USDT | 0.127953 |
2017-10-14 16:00:00 | 343.8 | 348.00 | 331.0 | 331.0 | 25.589013 | ETH/USDT | -0.037231 |
bch_df.head()
open | high | low | close | vol | symbol | returns | |
---|---|---|---|---|---|---|---|
datetime | |||||||
2018-11-18 16:00:00 | 245.0000 | 254.9999 | 203.0010 | 234.2346 | 9480.549678 | BCH/USDT | NaN |
2018-11-19 16:00:00 | 234.2346 | 259.9700 | 196.2657 | 255.0000 | 15922.975000 | BCH/USDT | 0.088652 |
2018-11-20 16:00:00 | 255.0000 | 257.0754 | 216.7100 | 240.0000 | 8035.085575 | BCH/USDT | -0.058824 |
2018-11-21 16:00:00 | 240.0000 | 241.4800 | 219.1300 | 220.5000 | 4822.293200 | BCH/USDT | -0.081250 |
2018-11-22 16:00:00 | 220.5000 | 223.4319 | 197.4958 | 209.0000 | 5841.849100 | BCH/USDT | -0.052154 |
- 使用直方图查看日收益率的稳定性
btc_df['returns'].hist(bins=100)
eth_df['returns'].hist(bins=100)
bch_df['returns'].hist(bins=100)
btc_df['returns'].hist(bins=100, label='BTC/USDT', figsize=(10, 8), alpha=0.5)
eth_df['returns'].hist(bins=100, label='ETH/USDT', alpha=0.5)
bch_df['returns'].hist(bins=100, label='BCH/USDT', alpha=0.5)
plt.legend()
- 使用盒子图比较不同加密货币的日收益率
returns_df = pd.concat([btc_df['returns'], eth_df['returns'], bch_df['returns']], axis=1)
returns_df.columns = ['BTC Returns', 'ETH Returns', 'BCH Returns']
returns_df.head()
BTC Returns | ETH Returns | BCH Returns | |
---|---|---|---|
datetime | |||
2017-10-10 16:00:00 | NaN | NaN | NaN |
2017-10-11 16:00:00 | 0.017956 | -0.050000 | NaN |
2017-10-12 16:00:00 | 0.150872 | 0.069474 | NaN |
2017-10-13 16:00:00 | 0.018853 | 0.127953 | NaN |
2017-10-14 16:00:00 | -0.000333 | -0.037231 | NaN |
plt.figure(figsize=(10, 8))
sns.boxplot(data=returns_df)
3.3 累计日收益率
以下是某个加密货币的价格:
日期 价格
01/01/2018 10
01/02/2018 15
01/03/2018 20
01/04/2018 25
日收益 : $\frac{pt}{p{t-1}}$,表示和前一天相比的获利/损失。大于1,表示获利;小于1,表示损失。
日收益率 : $\frac{pt}{p{t-1}} - 1$,表示和前一天相比的获利/损失的百分比。大于0,表示获利;小于0,表示损失。
日期 日收益 日收益率%
01/01/2018 10/10 = 1 -
01/02/2018 15/10 = 3/2 50%
01/03/2018 20/15 = 4/3 33%
01/04/2018 25/20 = 5/4 20%
累计收益:
日期 累计收益 累计收益率%
01/01/2018 10/10 = 1 -
01/02/2018 15/10 = 3/2 50 %
01/03/2018 20/10 = 2 100 %
01/04/2018 25/10 = 5/2 150 %
累计日收益 : $\frac{p_t}{p_1}$,表示和第一天相比的获利/损失。大于1,表示获利;小于1,表示损失。
累计日收益率 : $\frac{p_t}{p_1} - 1$,表示和第一天相比的获利/损失的百分比。大于0,表示获利;小于0,表示损失。
btc_df.head()
open | high | low | close | vol | symbol | returns | |
---|---|---|---|---|---|---|---|
datetime | |||||||
2017-10-10 16:00:00 | 1.00 | 4901.00 | 1.00 | 4901.00 | 19.260000 | BTC/USDT | NaN |
2017-10-11 16:00:00 | 4901.00 | 4999.00 | 4790.00 | 4989.00 | 0.580096 | BTC/USDT | 0.017956 |
2017-10-12 16:00:00 | 4989.00 | 5922.00 | 4989.00 | 5741.70 | 20.739843 | BTC/USDT | 0.150872 |
2017-10-13 16:00:00 | 5741.70 | 5849.95 | 5473.77 | 5849.95 | 19.259580 | BTC/USDT | 0.018853 |
2017-10-14 16:00:00 | 5849.95 | 5849.95 | 5686.41 | 5848.00 | 8.658607 | BTC/USDT | -0.000333 |
btc_df['Cumulative Returns'] = btc_df['close'] / btc_df.iloc[0]['close'] - 1
btc_df.head()
open | high | low | close | vol | symbol | returns | Cumulative Returns | |
---|---|---|---|---|---|---|---|---|
datetime | ||||||||
2017-10-10 16:00:00 | 1.00 | 4901.00 | 1.00 | 4901.00 | 19.260000 | BTC/USDT | NaN | 0.000000 |
2017-10-11 16:00:00 | 4901.00 | 4999.00 | 4790.00 | 4989.00 | 0.580096 | BTC/USDT | 0.017956 | 0.017956 |
2017-10-12 16:00:00 | 4989.00 | 5922.00 | 4989.00 | 5741.70 | 20.739843 | BTC/USDT | 0.150872 | 0.171536 |
2017-10-13 16:00:00 | 5741.70 | 5849.95 | 5473.77 | 5849.95 | 19.259580 | BTC/USDT | 0.018853 | 0.193624 |
2017-10-14 16:00:00 | 5849.95 | 5849.95 | 5686.41 | 5848.00 | 8.658607 | BTC/USDT | -0.000333 | 0.193226 |
eth_df['Cumulative Returns'] = eth_df['close'] / eth_df.iloc[0]['close'] - 1
bch_df['Cumulative Returns'] = bch_df['close'] / bch_df.iloc[0]['close'] - 1
btc_df['Cumulative Returns'].plot(label='BTC', figsize=(22, 10), title='Cumulative Returns')
eth_df['Cumulative Returns'].plot(label='ETH')
bch_df['Cumulative Returns'].plot(label='BCH')
plt.legend()
辅助函数
cryptocoin_data_utils.py
# -*- coding:utf-8 -*-
"""
@author: Corwien
@file: cryptocoin_data_utils.py
@time: 19/12/1 12:47
"""
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
import pandas as pd
from datetime import datetime
# ----------------- 代理相关 Begin -----------------
# 这里的代理IP是从showdocsocks软件「复制终端代理命令」找到的
proxies = {'https': "http://127.0.0.1:1087", 'http': "http://127.0.0.1:1087"}
# ----------------- 代理相关 End -----------------
# HTTPS certificate warning(去掉https警告提示)
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
def get_single_ticker_data(symbol):
'''
单个交易对的ticker数据获取
'''
ticker_url = 'https://www.okex.com/api/v1/ticker.do?symbol={}'.format(symbol)
# 异常处理,api请求超时等问题,设置超时时间,防止程序阻塞
try:
res_obj = requests.get(ticker_url, timeout=5, verify=False, proxies=proxies) # 获取到的是一个对象
except Exception as e:
print('错误:', e)
return None
ticker_df = None
json_obj = res_obj.json()
if res_obj.status_code == 200:
if 'error_code' in res_obj:
print('错误码:{}'.format(json_obj['error_code']))
else:
raw_df = pd.DataFrame(json_obj) # json -> df
ticker_df = pd.DataFrame(index=[0], columns=['datetime', 'symbol'] + raw_df.index.tolist())
ticker_df['datetime'] = pd.to_datetime(datetime.utcnow())
ticker_df['symbol'] = symbol.replace('_', '/').upper()
ticker_df[raw_df.index.tolist()] = raw_df['ticker'].values
else:
print('状态码:{}'.format(res_obj.status_code))
return ticker_df
def get_tickers_data(symbols):
"""
多个交易对的数据获取和处理
:param symbols:
:return:
"""
tickers_df = pd.DataFrame()
for symbol in symbols:
ticker_df = get_single_ticker_data(symbol)
if ticker_df is None:
continue
tickers_df = tickers_df.append(ticker_df)
return tickers_df
def get_single_kline_data(symbol, kline_type='1min', size=2000):
'''
单个交易对的K线数据获取
size 最大2000
'''
kline_url = 'https://www.okex.com/api/v1/kline.do?symbol={}&type={}&size={}'.format(symbol, kline_type, size)
# 异常处理,api请求超时等问题,设置超时时间,防止程序阻塞
try:
res_obj = requests.get(kline_url, timeout=5, verify=False, proxies=proxies) # 获取到的是一个对象
except Exception as e:
print('错误:', e)
return None
kline_df = None
json_obj = res_obj.json()
if res_obj.status_code == 200:
if 'error_code' in res_obj:
print('错误码:{}'.format(json_obj['error_code']))
else:
raw_df = pd.DataFrame(json_obj) # json ->
kline_df = raw_df.copy()
kline_df.columns = ['datetime', 'open', 'high', 'low', 'close', 'vol']
kline_df['datetime'] = pd.to_datetime(kline_df['datetime'], unit='ms')
kline_df['symbol'] = symbol.replace('_', '/').upper()
else:
print('状态码:{}'.format(res_obj.status_code))
return kline_df
def get_klines_data(symbols, kline_type='1min', size=2000):
"""
多个交易对的K线数据获取和处理
:param symbols:
:return:
"""
klines_df = pd.DataFrame()
for symbol in symbols:
kline_df = get_single_kline_data(symbol, kline_type, size)
if kline_df is None:
continue
klines_df = klines_df.append(kline_df)
return klines_df
为者常成,行者常至
自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)