Python 金融编程第二版(四)(1)

简介: Python 金融编程第二版(四)

第八章:金融时间序列

时间的唯一目的是让一切不是同时发生。

阿尔伯特·爱因斯坦

金融时间序列数据是金融领域最重要的数据类型之一。这是按日期和/或时间索引的数据。例如,随着时间的推移,股票价格代表金融时间序列数据。类似地,随时间变化的欧元/美元汇率代表金融时间序列;汇率在较短的时间间隔内报价,一系列这样的报价则是汇率的时间序列。

没有任何金融学科能够不考虑时间因素而存在。这与物理学和其他科学基本相同。在 Python 中处理时间序列数据的主要工具是pandaspandas的原始和主要作者 Wes McKinney 在 AQR Capital Management,一家大型对冲基金的分析员时开始开发这个库。可以肯定地说pandas是从头开始设计用于处理金融时间序列数据的。

本章主要基于两个以逗号分隔值(CSV)文件形式的金融时间序列数据集。它沿以下线路进行:

“金融数据”

这一部分介绍了使用pandas处理金融时间序列数据的基础知识:数据导入,导出摘要统计信息,计算随时间变化的数据和重采样。

“滚动统计”

在金融分析中,滚动统计起着重要作用。这些统计数据通常在一个固定的时间间隔内进行计算,并在整个数据集上“滚动前进”。简单移动平均线(SMAs)是一个流行的例子。这一部分说明了pandas如何支持计算这种统计数据。

“相关性分析”

这一部分提供了一个基于标普 500 股票指数和 VIX 波动率指数的金融时间序列数据的案例研究。它为两个指数都呈现负相关的模式提供了一些支持。

“高频数据”

高频数据或者说 tick 数据在金融领域已经变得司空见惯。这一部分处理 tick 数据。pandas再次在处理这样的数据集时表现强大。

金融数据

这一部分处理的是一个以 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 等)以及将数据导出为不同的格式(详见第九章)。下面的代码使用pd.read_csv()函数从 CSV 文件中导入时间序列数据集。¹

In [2]: filename = '../../source/tr_eikon_eod_data.csv'  # ①
In [3]: !head -5 $filename  # ②
        Date,AAPL.O,MSFT.O,INTC.O,AMZN.O,GS.N,SPY,.SPX,.VIX,EUR=,XAU=,GDX,GLD
        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
        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
        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
        2010-01-07,30.082827060000003,30.452,20.6,130.0,177.67,114.19,1141.69,19.06,1.4318,1131.9,49.1,110.82
In [4]: data = pd.read_csv(filename,  # ③
                           index_col=0, # ④
                           parse_dates=True)  # ⑤
In [5]: data.info()  # ⑥
        <class 'pandas.core.frame.DataFrame'>
        DatetimeIndex: 1972 entries, 2010-01-04 to 2017-10-31
        Data columns (total 12 columns):
        AAPL.O    1972 non-null float64
        MSFT.O    1972 non-null float64
        INTC.O    1972 non-null float64
        AMZN.O    1972 non-null float64
        GS.N      1972 non-null float64
        SPY       1972 non-null float64
        .SPX      1972 non-null float64
        .VIX      1972 non-null float64
        EUR=      1972 non-null float64
        XAU=      1972 non-null float64
        GDX       1972 non-null float64
        GLD       1972 non-null float64
        dtypes: float64(12)
        memory usage: 200.3 KB

指定路径和文件名。

显示原始数据的前五行(Linux/Mac)。

传递给pd.read_csv()函数的文件名。

这指定第一列将被处理为索引。

这另外指定索引值的类型为日期时间。

结果的DataFrame对象。

在这个阶段,金融分析师可能会通过检查数据或将其可视化(参见图 8-1)来首次查看数据。

In [6]: data.head()  # ①
Out[6]:                AAPL.O  MSFT.O  INTC.O  AMZN.O    GS.N     SPY     .SPX   .VIX  \
        Date
        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
        2010-01-08  30.282827  30.660   20.83  133.52  174.31  114.57  1144.98  18.13
                      EUR=     XAU=    GDX     GLD
        Date
        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
        2010-01-08  1.4412  1136.10  49.84  111.37
In [7]: data.tail()  # ②
Out[7]:             AAPL.O  MSFT.O  INTC.O   AMZN.O    GS.N     SPY     .SPX   .VIX  \
        Date
        2017-10-25  156.41   78.63   40.78   972.91  241.71  255.29  2557.15  11.23
        2017-10-26  157.41   78.76   41.35   972.43  241.72  255.62  2560.40  11.30
        2017-10-27  163.05   83.81   44.40  1100.95  241.71  257.71  2581.07   9.80
        2017-10-30  166.72   83.89   44.37  1110.85  240.89  256.75  2572.83  10.50
        2017-10-31  169.04   83.18   45.49  1105.28  242.48  257.15  2575.26  10.18
                      EUR=     XAU=    GDX     GLD
        Date
        2017-10-25  1.1812  1277.01  22.83  121.35
        2017-10-26  1.1650  1266.73  22.43  120.33
        2017-10-27  1.1608  1272.60  22.57  120.90
        2017-10-30  1.1649  1275.86  22.76  121.13
        2017-10-31  1.1644  1271.20  22.48  120.67
In [8]: data.plot(figsize=(10, 12), subplots=True)  # ③
        # plt.savefig('../../images/ch08/fts_01.png');

前五行 …

… 最后五行显示。

这通过多个子图可视化完整数据集。


图 8-1. 金融时间序列数据的线图

使用的数据来自汤森路透(TR)Eikon 数据 API。在 TR 世界中,金融工具的符号称为“路透社仪器代码”或RICs。单个RICs代表的金融工具是:

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 pari in zip(data.columns, instruments):
             print('{:8s} | {}'.format(pari[0], pari[1]))
         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: 1972 entries, 2010-01-04 to 2017-10-31
         Data columns (total 12 columns):
         AAPL.O    1972 non-null float64
         MSFT.O    1972 non-null float64
         INTC.O    1972 non-null float64
         AMZN.O    1972 non-null float64
         GS.N      1972 non-null float64
         SPY       1972 non-null float64
         .SPX      1972 non-null float64
         .VIX      1972 non-null float64
         EUR=      1972 non-null float64
         XAU=      1972 non-null float64
         GDX       1972 non-null float64
         GLD       1972 non-null float64
         dtypes: float64(12)
         memory usage: 200.3 KB
In [12]: data.describe().round(2)  # ②
Out[12]:         AAPL.O   MSFT.O   INTC.O   AMZN.O     GS.N      SPY     .SPX     .VIX  \
         count  1972.00  1972.00  1972.00  1972.00  1972.00  1972.00  1972.00  1972.00
         mean     86.53    40.59    27.70   401.15   163.61   172.84  1727.54    17.21
         std      34.04    14.39     5.95   257.12    37.17    42.33   424.35     5.92
         min      27.44    23.01    17.66   108.61    87.70   102.20  1022.58     9.19
         25%      57.57    28.12    22.23   202.66   144.23   132.64  1325.53    13.25
         50%      84.63    36.54    26.41   306.42   162.09   178.80  1783.81    15.65
         75%     111.87    50.08    33.74   559.45   184.11   208.01  2080.15    19.20
         max     169.04    83.89    45.49  1110.85   252.89   257.71  2581.07    48.00
                   EUR=     XAU=      GDX      GLD
         count  1972.00  1972.00  1972.00  1972.00
         mean      1.25  1352.47    34.50   130.60
         std       0.12   195.38    15.44    19.46
         min       1.04  1051.36    12.47   100.50
         25%       1.13  1214.56    22.22   116.77
         50%       1.29  1288.82    26.59   123.90
         75%       1.35  1491.98    49.77   145.43
         max       1.48  1897.10    66.63   184.59

.info()提供有关DataFrame对象的一些元信息。

.describe() 提供每列有用的标准统计数据。

提示

pandas提供了许多方法来快速查看新导入的金融时间序列数据集的概述,例如.info().describe()。它们还允许快速检查导入过程是否按预期工作(例如,DataFrame对象是否确实具有DatetimeIndex作为索引)。

当然,也有选项来自定义要推导和显示的统计信息类型。

In [13]: data.mean()  # ①
Out[13]: AAPL.O      86.530152
         MSFT.O      40.586752
         INTC.O      27.701411
         AMZN.O     401.154006
         GS.N       163.614625
         SPY        172.835399
         .SPX      1727.538342
         .VIX        17.209498
         EUR=         1.252613
         XAU=      1352.471593
         GDX         34.499391
         GLD        130.601856
         dtype: float64
In [14]: data.aggregate(min,  ![2                         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.19  1.04
         mean     86.53   40.59   27.70   401.15  163.61  172.84  1727.54  17.21  1.25
         std      34.04   14.39    5.95   257.12   37.17   42.33   424.35   5.92  0.12
         median   84.63   36.54   26.41   306.42  162.09  178.80  1783.81  15.65  1.29
         max     169.04   83.89   45.49  1110.85  252.89  257.71  2581.07  48.00  1.48
                    XAU=    GDX     GLD
         min     1051.36  12.47  100.50
         mean    1352.47  34.50  130.60
         std      195.38  15.44   19.46
         median  1288.82  26.59  123.90
         max     1897.10  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-04       NaN     NaN     NaN     NaN   NaN   NaN   NaN   NaN     NaN
         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
         2010-01-08  0.200000   0.208    0.23    3.52 -3.36  0.38  3.29 -0.93  0.0094
                      XAU=   GDX   GLD
         Date
         2010-01-04    NaN   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
         2010-01-08   4.20  0.74  0.55
In [16]: data.diff().mean()  # ②
Out[16]: AAPL.O    0.070252
         MSFT.O    0.026499
         INTC.O    0.012486
         AMZN.O    0.492836
         GS.N      0.035211
         SPY       0.072968
         .SPX      0.731745
         .VIX     -0.005003
         EUR=     -0.000140
         XAU=      0.076712
         GDX      -0.012801
         GLD       0.005515
         dtype: float64

.diff()提供了两个索引值之间的绝对变化。

当然,还可以应用聚合操作。

从统计学的角度来看,绝对变化不是最佳选择,因为它们依赖于时间序列数据本身的比例。因此,通常更喜欢百分比变化。以下代码推导了金融背景下的百分比变化或百分比收益(也称为:简单收益),并可视化其每列的均值(参见 图 8-2)。

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-04     NaN     NaN     NaN     NaN    NaN    NaN    NaN    NaN    NaN
         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
         2010-01-08   0.007   0.007   0.011   0.027 -0.019  0.003  0.003 -0.049  0.007
                      XAU=    GDX    GLD
         Date
         2010-01-04    NaN    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
         2010-01-08  0.004  0.015  0.005
In [18]: data.pct_change().mean().plot(kind='bar', figsize=(10, 6));  # ②
         # plt.savefig('../../images/ch08/fts_02.png');

.pct_change()计算两个索引值之间的百分比变化。

结果的均值作为条形图可视化。


图 8-2. 百分比变化的均值作为条形图

作为百分比收益的替代,可以使用对数收益。在某些情况下,它们更容易处理,因此在金融背景下通常更受欢迎。² 图 8-3 展示了单个金融时间序列的累积对数收益。这种类型的绘图导致某种形式的归一化

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-04     NaN     NaN     NaN     NaN    NaN    NaN    NaN    NaN    NaN
         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
         2010-01-08   0.007   0.007   0.011   0.027 -0.019  0.003  0.003 -0.050  0.007
                      XAU=    GDX    GLD
         Date
         2010-01-04    NaN    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
         2010-01-08  0.004  0.015  0.005
In [21]: rets.cumsum().apply(np.exp).plot(figsize=(10, 6));  # ③
         # plt.savefig('../../images/ch08/fts_03.png');

这以向量化方式计算对数收益。

结果的子集。

这绘制了随时间累积的对数收益;首先调用.cumsum()方法,然后将np.exp()应用于结果。


图 8-3. 随时间累积的对数收益

重采样

对于金融时间序列数据,重采样是一项重要的操作。通常,这采取上采样的形式,意味着例如,具有每日观测的时间序列被重采样为具有每周或每月观测的时间序列。这也可能意味着将金融 Tick 数据系列重采样为一分钟间隔(也称为:柱)。

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-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
         2010-02-07  27.922829   28.02   19.47  117.39  154.16  106.66  1066.19  26.11
                       EUR=     XAU=    GDX     GLD
         Date
         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
         2010-02-07  1.3662  1064.95  42.41  104.68
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.2267  1213.81  49.86  118.881
In [24]: rets.cumsum().resample('1m', label='right').last(
                                   ).plot(figsize=(10, 6));  # ③
         # plt.savefig('../../images/ch08/fts_04.png');

EOD 数据被重采样为

结果的子集。

这绘制了随时间累积的对数收益;首先调用.cumsum()方法,然后将np.exp()应用于结果。


图 8-4. 随时间重采样的累积对数收益(每月)
注意

在重新取样时,默认情况下,pandas采用区间的左标签(或索引值)。为了保持金融一致性,请确保使用右标签(索引值)和通常是区间中最后一个可用数据点。否则,可能会在金融分析中引入预见偏差。^(3)


Python 金融编程第二版(四)(2)https://developer.aliyun.com/article/1559418

相关文章
|
2天前
|
存储 分布式计算 数据可视化
Python 金融编程第二版(四)(2)
Python 金融编程第二版(四)
10 0
|
2天前
|
数据可视化 Python
Python 金融编程第二版(三)(4)
Python 金融编程第二版(三)
12 2
|
2天前
|
存储 数据可视化 API
Python 金融编程第二版(三)(5)
Python 金融编程第二版(三)
8 1
|
2天前
|
存储 机器学习/深度学习 关系型数据库
Python 金融编程第二版(四)(5)
Python 金融编程第二版(四)
8 0
|
2天前
|
存储 SQL 数据库
Python 金融编程第二版(四)(4)
Python 金融编程第二版(四)
8 0
|
2天前
|
SQL 存储 数据库
Python 金融编程第二版(四)(3)
Python 金融编程第二版(四)
8 0
|
2天前
|
存储 SQL 数据可视化
Python 金融编程第二版(二)(4)
Python 金融编程第二版(二)
10 1
|
2天前
|
数据挖掘 索引 Python
Python 金融编程第二版(二)(5)
Python 金融编程第二版(二)
7 0
|
2天前
|
存储 索引 Python
Python 金融编程第二版(二)(1)
Python 金融编程第二版(二)
9 2
|
2天前
|
存储 算法 数据建模
Python 金融编程第二版(一)(5)
Python 金融编程第二版(一)
13 2