本文使用的是以CSV文件形式在本地存储的金融数据集形式为本地存储的CSV文件。从技术上讲,CSV文件是包含数据行结构的文本文件,其特征是以逗号分隔单个值。在导入数据之前,导入一些软件包并进行定制:
In [1]: import numpy as np
import pandas as pd
from pylab import mpl, plt
plt.style.use('seaborn')
mpl.rcParams['font.family'] = 'serif'
%matplotlib inline
数据导入
pandas提供不同的函数和DataFrame方法,以导入不同存储格式(CSV、SQL、Excel等)的数据,并将数据导出为不同格式(详见第9章)。下面的代码通过pd.read_csv()函数导入CSV[1]文件中的时间序列数据:
In [2]: filename = '../../source/tr_eikon_eod_data.csv' ❶
In [3]: f = open(filename, 'r') ❷
f.readlines()[:5] ❷
Out[3]: ['Date,AAPL.O,MSFT.O,INTC.O,AMZN.O,GS.N,SPY,.SPX,.VIX,EUR=,XAU=,GDX,
,GLD\n',
'2010-01-01,,,,,,,,,1.4323,1096.35,,\n',
'2010-01-04,30.57282657,30.95,20.88,133.9,173.08,113.33,1132.99,20.04,
,1.4411,1120.0,47.71,109.8\n',
'2010-01-05,30.625683660000004,30.96,20.87,134.69,176.14,113.63,1136.52,
,19.35,1.4368,1118.65,48.17,109.7\n',
'2010-01-06,30.138541290000003,30.77,20.8,132.25,174.26,113.71,1137.14,
,19.16,1.4412,1138.5,49.34,111.51\n']
In [4]: data = pd.read_csv(filename, ❸
index_col=0, ❹
parse_dates=True) ❺
In [5]: data.info() ❻
<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 2216 entries, 2010-01-01 to 2018-06-29
Data columns (total 12 columns):
AAPL.O 2138 non-null float64
MSFT.O 2138 non-null float64
INTC.O 2138 non-null float64
AMZN.O 2138 non-null float64
GS.N 2138 non-null float64
SPY 2138 non-null float64
.SPX 2138 non-null float64
.VIX 2138 non-null float64
EUR= 2216 non-null float64
XAU= 2211 non-null float64
GDX 2138 non-null float64
GLD 2138 non-null float64
dtypes: float64(12)
memory usage: 225.1 KB
❶ 指定路径和文件名。
❷ 显示原始数据(Linux/Mac)的前5行。
❸ 传递给pd.read_scv()函数的文件名。
❹ 指定第一列作为索引处理。
❺ 指定索引值为datetime类型。
❻ 结果为DataFrame对象。
在这一阶段,金融分析师可能首先观察数据,对其进行检查或者可视化:
In [6]: data.head() ❶
Out[6]:
AAPL.O MSFT.O INTC.O AMZN.O GS.N SPY .SPX .VIX \
Date
2010-01-01 NaN NaN NaN NaN NaN NaN NaN NaN
2010-01-04 30.572827 30.950 20.88 133.90 173.08 113.33 1132.99 20.04
2010-01-05 30.625684 30.960 20.87 134.69 176.14 113.63 1136.52 19.35
2010-01-06 30.138541 30.770 20.80 132.25 174.26 113.71 1137.14 19.16
2010-01-07 30.082827 30.452 20.60 130.00 177.67 114.19 1141.69 19.06
EUR= XAU= GDX GLD
Date
2010-01-01 1.4323 1096.35 NaN NaN
2010-01-04 1.4411 1120.00 47.71 109.80
2010-01-05 1.4368 1118.65 48.17 109.70
2010-01-06 1.4412 1138.50 49.34 111.51
2010-01-07 1.4318 1131.90 49.10 110.82
In [7]: data.tail() ❷
Out[7]:
AAPL.O MSFT.O INTC.O AMZN.O GS.N SPY .SPX.VIX \
Date
2018-06-25 182.17 98.39 50.71 1663.15 221.54 271.00 2717.07 17.33
2018-06-26 184.43 99.08 49.67 1691.09 221.58 271.60 2723.06 15.92
2018-06-27 184.16 97.54 48.76 1660.51 220.18 269.35 2699.63 17.91
2018-06-28 185.50 98.63 49.25 1701.45 223.42 270.89 2716.31 16.85
2018-06-29 185.11 98.61 49.71 1699.80 220.57 271.28 2718.37 16.09
EUR= XAU= GDX GLD
Date
2018-06-25 1.1702 1265.00 22.01 119.89
2018-06-26 1.1645 1258.64 21.95 119.26
2018-06-27 1.1552 1251.62 21.81 118.58
2018-06-28 1.1567 1247.88 21.93 118.22
2018-06-29 1.1683 1252.25 22.31 118.65
In [8]: data.plot(figsize=(10, 12), subplots=True); ❸
❶ 前5行。
❷最后5行显示。
❸ 这个语句通过多个子图来可视化整个数据集。
这里使用的数据来自Thomson Reuters (TR) Eikon Data API。TR金融工具代码称作路透金融工具代码(RIC)。RIC表示的金融工具为:
In [9]: instruments = ['Apple Stock', 'Microsoft Stock',
'Intel Stock', 'Amazon Stock', 'Goldman Sachs Stock',
'SPDR S&P 500 ETF Trust', 'S&P 500 Index',
'VIX Volatility Index', 'EUR/USD Exchange Rate',
'Gold Price', 'VanEck Vectors Gold Miners ETF',
'SPDR Gold Trust']
In [10]: for ric, name in zip(data.columns, instruments):
print('{:8s} | {}'.format(ric, name))
AAPL.O | Apple Stock
MSFT.O | Microsoft Stock
INTC.O | Intel Stock
AMZN.O | Amazon Stock
GS.N | Goldman Sachs Stock
SPY | SPDR S&P 500 ETF Trust
.SPX | S&P 500 Index
.VIX | VIX Volatility Index
EUR= | EUR/USD Exchange Rate
XAU= | Gold Price
GDX | VanEck Vectors Gold Miners ETF
GLD | SPDR Gold Trust
汇总统计
金融分析师采取的下一个步骤是观察不同的数据集汇总统计,从而对其有个总体的“感觉”:
In [11]: data.info() ❶
<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 2216 entries, 2010-01-01 to 2018-06-29
Data columns (total 12 columns):
AAPL.O 2138 non-null float64
MSFT.O 2138 non-null float64
INTC.O 2138 non-null float64
AMZN.O 2138 non-null float64
GS.N 2138 non-null float64
SPY 2138 non-null float64
.SPX 2138 non-null float64
.VIX 2138 non-null float64
EUR= 2216 non-null float64
XAU= 2211 non-null float64
GDX 2138 non-null float64
GLD 2138 non-null float64
dtypes: float64(12)
memory usage: 225.1 KB
In [12]: data.describe().round(2) ❷
Out[12]:
AAPL.O MSFT.O INTC.O AMZN.O GS.N SPY .SPX .VIX \
Count 2138.00 2138.00 2138.00 2138.00 2138.00 2138.00 2138.00 2138.00
mean 93.46 44.56 29.36 480.46 170.22 180.32 1802.71 17.03
std 40.55 19.53 8.17 372.31 42.48 48.19 483.34 5.88
min 27.44 23.01 17.66 108.61 87.70 102.20 1022.58 9.14
25% 60.29 28.57 22.51 213.60 146.61 133.99 1338.57 13.07
50% 90.55 39.66 27.33 322.06 164.43 186.32 1863.08 15.58
75% 117.24 54.37 34.71 698.85 192.13 210.99 2108.94 19.07
max 193.98 102.49 57.08 1750.08 273.38 286.58 2872.87 48.00
EUR= XAU= GDX GLD
count 2216.00 2211.00 2138.00 2138.00
mean 1.25 1349.01 33.57 130.09
std 0.11 188.75 15.17 18.78
min 1.04 1051.36 12.47 100.50
25% 1.13 1221.53 22.14 117.40
50% 1.27 1292.61 25.62 124.00
75% 1.35 1428.24 48.34 139.00
max 1.48 1898.99 66.63 184.59
❶ info()给出DataFrame对象的相关元信息。
❷ describe()提供每列的实用标准统计量。
敏锐的洞察力
pandas提供了许多方法如info和describe(),可以获得新导入的金融时间序列数据集的简单概况。它们还能快捷地检查导入程序是否按照要求进行(例如,DataFrame对象是否真正包含DatetimeIndex类型的索引)。
当然,pandas也提供自定义统计类型及显示方式的选项:
In [13]: data.mean() ❶
Out[13]: AAPL.O 93.455973
MSFT.O 44.561115
INTC.O 29.364192
AMZN.O 480.461251
GS.N 170.216221
SPY 180.323029
.SPX 1802.713106
.VIX 17.027133
EUR= 1.248587
XAU= 1349.014130
GDX 33.566525
GLD 130.086590
dtype: float64
In [14]: data.aggregate([min, ❷
np.mean, ❸
np.std, ❹
np.median, ❺
max] ❻
).round(2)
Out[14]:
AAPL.O MSFT.O INTC.O AMZN.O GS.N SPY .SPX.VIX EUR= \
min 27.44 23.01 17.66 108.61 87.70 102.20 1022.58 9.14 1.04
mean 93.46 44.56 29.36 480.46 170.22 180.32 1802.71 17.03 1.25
std 40.55 19.53 8.17 372.31 42.48 48.19 483.34 5.88 0.11
median 90.55 39.66 27.33 322.06 164.43 186.32 1863.08 15.58 1.27
max 193.98 102.49 57.08 1750.08 273.38 286.58 2872.87 48.00 1.48
XAU= GDX GLD
min 1051.36 12.47 100.50
mean 1349.01 33.57 130.09
std 188.75 15.17 18.78
median 1292.61 25.62 124.00
max 1898.99 66.63 184.59
❶ 每列均值。
❷ 每列最小值。
❸ 每列均值。
❹ 每列标准差。
❺ 每列中位数。
❻ 每列最大值。
使用aggregate方法还可以传递自定义函数。
随时间推移的变化
统计分析方法往往基于随时间推移的变化,而不是绝对值。计算时间序列中的随时变化有多种选择,包括绝对偏差、变化率和对数回报率。
首先介绍绝对偏差,pandas为此提供了一个特殊的方法:
In [15]: data.diff().head() ❶
Out[15]:
AAPL.O MSFT.O INTC.O AMZN.O GS.N SPY .SPX .VIX EUR= \
Date
2010-01-01 NaN NaN NaN NaN NaN NaN NaN NaN NaN
2010-01-04 NaN NaN NaN NaN NaN NaN NaN NaN 0.0088
2010-01-05 0.052857 0.010 -0.01 0.79 3.06 0.30 3.53 -0.69 -0.0043
2010-01-06 -0.487142 -0.190 -0.07 -2.44 -1.88 0.08 0.62 -0.19 0.0044
2010-01-07 -0.055714 -0.318 -0.20 -2.25 3.41 0.48 4.55 -0.10 -0.0094
XAU= GDX GLD
Date
2010-01-01 NaN NaN NaN
2010-01-04 23.65 NaN NaN
2010-01-05 -1.35 0.46 -0.10
2010-01-06 19.85 1.17 1.81
2010-01-07 -6.60 -0.24 -0.69
In [16]: data.diff().mean() ❷
Out[16]: AAPL.O 0.064737
MSFT.O 0.031246
INTC.O 0.013540
AMZN.O 0.706608
GS.N 0.028224
SPY 0.072103
.SPX 0.732659
.VIX -0.019583
EUR= -0.000119
XAU= 0.041887
GDX -0.015071
GLD -0.003455
dtype: float64
❶ diff提供两个索引值之间的绝对变化。
❷ 当然,还可以应用聚合运算。
从统计学角度讲,绝对变化不是最优的,因为它们与时间序列数据本身的比例相关。因此,我们通常更偏重变化率。下面的代码可以计算金融环境里的变动率或者回报率(也称为简单回报率),并对其每列的平均值进行可视化:
In [17]: data.pct_change().round(3).head() ❶
Out[17]:
AAPL.O MSFT.O INTC.O AMZN.O GS.N SPY .SPX .VIX EUR= \
Date
2010-01-01 NaN NaN NaN NaN NaN NaN NaN NaN NaN
2010-01-04 NaN NaN NaN NaN NaN NaN NaN NaN 0.006
2010-01-05 0.002 0.000 -0.000 0.006 0.018 0.003 0.003 -0.034 -0.003
2010-01-06 -0.016 -0.006 -0.003 -0.018 -0.011 0.001 0.001 -0.010 0.003
2010-01-07 -0.002 -0.010 -0.010 -0.017 0.020 0.004 0.004 -0.005 -0.007
XAU= GDX GLD
Date
2010-01-01 NaN NaN NaN
2010-01-04 0.022 NaN NaN
2010-01-05 -0.001 0.010 -0.001
2010-01-06 0.018 0.024 0.016
2010-01-07 -0.006 -0.005 -0.006
In [18]: data.pct_change().mean().plot(kind='bar', figsize=(10, 6)); ❷
❶ pct_change()计算两个索引值之间的变化率。
❷ 将结果的均值可视化为一个柱状图。
对数回报率可作为回报率的替代品。在某些情况下,它们更容易处理,因此在金融环境中往往优先使用对数回报率。[2]
下图展示了单个金融时间序列的累计对数回报率。这种类型的图表导致了某种形式的规范化:
In [19]: rets = np.log(data / data.shift(1))❶
In [20]: rets.head().round(3) ❷
Out[20]:
AAPL.O MSFT.O INTC.O AMZN.O GS.N SPY .SPX .VIX EUR= \
Date
2010-01-01 NaN NaN NaN NaN NaN NaN NaN NaN NaN
2010-01-04 NaN NaN NaN NaN NaN NaN NaN NaN 0.006
2010-01-05 0.002 0.000 -0.000 0.006 0.018 0.003 0.003 -0.035 -0.003
2010-01-06 -0.016 -0.006 -0.003 -0.018 -0.011 0.001 0.001 -0.010 0.003
2010-01-07 -0.002 -0.010 -0.010 -0.017 0.019 0.004 0.004 -0.005 -0.007
XAU= GDX GLD
Date
2010-01-01 NaN NaN NaN
2010-01-04 0.021 NaN NaN
2010-01-05 -0.001 0.010 -0.001
2010-01-06 0.018 0.024 0.016
2010-01-07 -0.006 -0.005 -0.006
In [21]: rets.cumsum().apply(np.exp).plot(figsize=(10, 6)); ❸
❶ 以向量的方式计算对数回报率。
❷ 结果的一个子集。
❸ 绘制一段时间的累计对数回报率图表;首先调用cumsum()方法,然后对结果应用np.exp()。
重新采样
重新采样是金融时间序列数据的重要操作之一,通常采用向下采样的形式,例如,分笔交易数据序列重新采样的时间间隔为一分钟,也可以将每日观察数据的时间序列重新采样为每周或者每月观察数据:
In [22]: data.resample('1w', label='right').last().head() ❶
Out[22]:
AAPL.O MSFT.O INTC.O AMZN.O GS.N SPY .SPX .VIX \
Date
2010-01-03 NaN NaN NaN NaN NaN NaN NaN NaN
2010-01-10 30.282827 30.66 20.83 133.52 174.31 114.57 1144.98 18.13
2010-01-17 29.418542 30.86 20.80 127.14 165.21 113.64 1136.03 17.91
2010-01-24 28.249972 28.96 19.91 121.43 154.12 109.21 1091.76 27.31
2010-01-31 27.437544 28.18 19.40 125.41 148.72 107.39 1073.87 24.62
EUR= XAU= GDX GLD
Date
2010-01-03 1.4323 1096.35 NaN NaN
2010-01-10 1.4412 1136.10 49.84 111.37
2010-01-17 1.4382 1129.90 47.42 110.86
2010-01-24 1.4137 1092.60 43.79 107.17
2010-01-31 1.3862 1081.05 40.72 105.96
In [23]: data.resample('1m', label='right').last().head() ❷
Out[23]:
AAPL.O MSFT.O INTC.O AMZN.O GS.N SPY .SPX \
Date
2010-01-31 27.437544 28.1800 19.40 125.41 148.72 107.3900 1073.87
2010-02-28 29.231399 28.6700 20.53 118.40 156.35 110.7400 1104.49
2010-03-31 33.571395 29.2875 22.29 135.77 170.63 117.0000 1169.43
2010-04-30 37.298534 30.5350 22.84 137.10 145.20 118.8125 1186.69
2010-05-31 36.697106 25.8000 21.42 125.46 144.26 109.3690 1089.41
.VIX EUR= XAU= GDX GLD
Date
2010-01-31 24.62 1.3862 1081.05 40.72 105.960
2010-02-28 19.50 1.3625 1116.10 43.89 109.430
2010-03-31 17.59 1.3510 1112.80 44.41 108.950
2010-04-30 22.05 1.3295 1178.25 50.51 115.360
2010-05-31 32.07 1.2305 1215.71 49.86 118.881
In [24]: rets.cumsum().apply(np.exp). resample('1m', label='right').last(
).plot(figsize=(10, 6)); ❸
❶ 日终数据以一周为时间间隔重新采样。
❷ 以一月为时间间隔重新采样。
❸ 这就绘制了随时间变化的累计对数回报率图表:首先调用cumsun(),然后对结果应用np.exp,最后进行重新采样。
避免预见偏差
在很多情况下,pandas在重新采样时默认使用区间的左侧标签(或者索引值)。为了在金融业务中保持一致,请确保使用右标签(索引值)——一般是区间内最后一个可用数据点。否则,金融分析中可能潜藏着预见偏差。
本文摘自《Python金融大数据分析 第2版》
文源网络,仅供学习之用,如有侵权请联系删除。
在学习Python的道路上肯定会遇见困难,别慌,我这里有一套学习资料,包含40+本电子书,800+个教学视频,涉及Python基础、爬虫、框架、数据分析、机器学习等,不怕你学不会! shimo.im/docs/JWCghr… 《Python学习资料》
关注公众号【Python圈子】,优质文章每日送达。