時(shí)間序列(或稱動(dòng)態(tài)數(shù)列)是指將同一統(tǒng)計(jì)指標(biāo)的數(shù)值按其發(fā)生的時(shí)間先后順序排列而成的數(shù)列。時(shí)間序列分析的主要目的是根據(jù)已有的歷史數(shù)據(jù)對(duì)未來(lái)進(jìn)行預(yù)測(cè)。本文我們會(huì)分享如何用歷史股票數(shù)據(jù)進(jìn)行基本的時(shí)間序列分析(以下簡(jiǎn)稱時(shí)序分析)。首先我們會(huì)創(chuàng)建一個(gè)靜態(tài)預(yù)測(cè)模型,檢測(cè)模型的效度,然后分享一些用于時(shí)序分析的重要工具。
在創(chuàng)建模型之前,我們先簡(jiǎn)要了解時(shí)間序列的一些基本參數(shù),比如移動(dòng)平均線、趨勢(shì)、季節(jié)性等。
獲取數(shù)據(jù)
我們本文會(huì)用到 MRF 過去五年的“調(diào)整價(jià)格”,用 pandas_datareader 可以從 Yahoo財(cái)經(jīng)上獲取所需的數(shù)據(jù)。我們首先導(dǎo)入需要的庫(kù):
import pandas as pd
import pandas_datareader as web
import matplotlib.pyplot as plt
import numpy as np
現(xiàn)在我們用 datareader 獲取數(shù)據(jù),主要是自 2012 年 1 月 1 日至 2017 年 12 月 21 日的股票數(shù)據(jù)。當(dāng)然也可以只用調(diào)整收盤價(jià),因?yàn)檫@是最相關(guān)的價(jià)格,應(yīng)用在所有的金融分析中。
stock = web.DataReader('MRF.BO','yahoo', start = "01-01-2012", end="31-12-2017")
stock = stock.dropna(how=’any’)
我們可以用 head() 函數(shù)檢查數(shù)據(jù)。
stock.head()
我們可以用導(dǎo)入的 matplotlib 庫(kù)再次繪制出時(shí)間段內(nèi)的調(diào)整價(jià)格。
stock[‘Adj Close’].plot(grid = True)
計(jì)算和繪制每日收益
利用時(shí)間序列,我們可以計(jì)算出隨著時(shí)間變化的每日收益,并繪制出收益變化圖。我們將從股票的調(diào)整收盤價(jià)中計(jì)算出每日收益,以列名“ret”儲(chǔ)存在同一數(shù)據(jù)幀“stock”中。
stock['ret'] = stock['Adj Close'].pct_change()
stock['ret'].plot(grid=True)
移動(dòng)平均數(shù)
和收益相同,我們可以計(jì)算和繪制出調(diào)整收盤價(jià)格的移動(dòng)平均線。移動(dòng)平均線是廣泛應(yīng)用于技術(shù)分析中的一個(gè)非常重要的指標(biāo)。出于簡(jiǎn)要說(shuō)明的目的,這里我們只計(jì)算 20 天移動(dòng)平均線作為示例。
stock['20d'] = stock['Adj Close'].rolling(window=20, center=False).mean()
stock['20d'].plot(grid=True)
在搭建模型預(yù)測(cè)前,我們先快速看看時(shí)間序列中的趨勢(shì)和季節(jié)性。
趨勢(shì)和季節(jié)性
簡(jiǎn)單來(lái)說(shuō),趨勢(shì)表示時(shí)間序列在一段時(shí)間內(nèi)的整體發(fā)展方向。趨勢(shì)和趨勢(shì)分析同樣廣泛應(yīng)用于技術(shù)分析中。如果在時(shí)間序列中定期出現(xiàn)一些模式,我們就說(shuō)數(shù)據(jù)具有季節(jié)性。時(shí)間序列中的季節(jié)性會(huì)影響預(yù)測(cè)模型的結(jié)果,因此對(duì)它不能掉以輕心。
如果你依然在編程的世界里迷茫,可以加入我們的Python學(xué)習(xí)扣qun:784758214,看看前輩們是如何學(xué)習(xí)的。交流經(jīng)驗(yàn)。從基礎(chǔ)的python腳本到web開發(fā)、爬蟲、django、數(shù)據(jù)挖掘等,零基礎(chǔ)到項(xiàng)目實(shí)戰(zhàn)的資料都有整理。送給每一位python的小伙伴!分享一些學(xué)習(xí)的方法和需要注意的小細(xì)節(jié),點(diǎn)擊加入我們的 python學(xué)習(xí)者聚集地
預(yù)測(cè)
我們會(huì)討論一個(gè)簡(jiǎn)單的線性分析模型,假設(shè)時(shí)間序列呈靜態(tài),且沒有季節(jié)性。也就是這里我們假設(shè)時(shí)間序列呈線性趨勢(shì)。模型可以表示為:
Forecast (t) = a + b X t
這里的“a”為時(shí)間序列在Y軸上的截距,“b”為斜率。我們現(xiàn)在看看 a 和 b 的計(jì)算。我們考慮時(shí)間序列在時(shí)間段“t”內(nèi)的值D(t)。
在這個(gè)方程式中,“n”是樣本大小。我們可以通過用上面的模型計(jì)算 D(t)的預(yù)測(cè)值,并將值和實(shí)際觀測(cè)值比較,進(jìn)而驗(yàn)證我們的模型。我們可以計(jì)算出平均誤差,即預(yù)測(cè) D(t)值和實(shí)際 D(t)值之間的差距的平均值。
在我們的股票數(shù)據(jù)中,D(t)是 MRF 的調(diào)整收盤價(jià)。我們現(xiàn)在用 Python 計(jì)算 a,b,預(yù)測(cè)值和它們的誤差值。
#Populates the time period number in stock under head t
stock['t'] = range (1,len(stock)+1)
#Computes t squared, tXD(t) and n
stock['sqr t']=stock['t']**2
stock['tXD']=stock['t']*stock['Adj Close']
n=len(stock)
#Computes slope and intercept
slope = (n*stock['tXD'].sum() - stock['t'].sum()*stock['Adj Close'].sum())/(n*stock['sqr t'].sum() - (stock['t'].sum())**2)
intercept = (stock['Adj Close'].sum()*stock['sqr t'].sum() - stock['t'].sum()*stock['tXD'].sum())/(n*stock['sqr t'].sum() - (stock['t'].sum())**2)
print ('The slope of the linear trend (b) is: ', slope)
print ('The intercept (a) is: ', intercept)
上面的代碼會(huì)給出如下輸出:
The slope of the linear trend (b) is: 41.2816591061
The intercept (a) is: 1272.6557803
我們現(xiàn)在可以通過計(jì)算預(yù)測(cè)值和平均誤差來(lái)驗(yàn)證模型的效度。
#Computes the forecasted values
stock['forecast'] = intercept + slope*stock['t']
#Computes the error
stock['error'] = stock['Adj Close'] - stock['forecast']
mean_error=stock['error'].mean()
print ('The mean error is: ', mean_error)
輸出的平均誤差如下所示:
The mean error is: 1.0813935108094419e-10
從平均誤差值可以看出,我們的模型給出的值非常接近實(shí)際值。因此數(shù)據(jù)沒有受到任何季節(jié)性方面的影響。
下面我們討論一些用于分析時(shí)序數(shù)據(jù)的很實(shí)用的工具,它們對(duì)于金融交易員在設(shè)計(jì)和預(yù)先測(cè)試交易策略時(shí)非常有幫助。
交易員們常常要處理大量的歷史數(shù)據(jù),并且根據(jù)這些時(shí)間序列進(jìn)行數(shù)據(jù)分析。我們這里重點(diǎn)分享一下如何應(yīng)對(duì)時(shí)間序列中的日期和頻率,以及索引、切片等操作。主要會(huì)用到 datetime庫(kù)。
我們首先將 datetime 庫(kù)導(dǎo)入到程序中。
#Importing the required modules
from datetime import datetime
from datetime import timedelta
處理日期和時(shí)間的基本工具
先將當(dāng)前日期和時(shí)間保存在變量“current_time”中,執(zhí)行代碼如下:
#Printing the current date and time
current_time = datetime.now()
current_time
Output: datetime.datetime(2018, 2, 14, 9, 52, 20, 625404)
我們可以用 datetime 計(jì)算兩個(gè)日期的不同之處。
#Calculating the difference between two dates (14/02/2018 and 01/01/2018 09:15AM)
delta = datetime(2018,2,14)-datetime(2018,1,1,9,15)
delta
Output: datetime.timedelta(43, 53100)
使用如下代碼將輸出轉(zhuǎn)換為用“天”或“秒”表達(dá):
#Converting the output to days
delta.days
Output: 43
#Converting the output to seconds
delta.seconds
Output: 53100
如果我們想變換日期,可以用前面導(dǎo)入的 timedelta 模塊。
#Shift a date using timedelta
my_date = datetime(2018,2,10)
#Shift the date by 10 days
my_date + timedelta(10)
Output: datetime.datetime(2018, 2, 20, 0, 0)
我們也可以用 timedelta 函數(shù)的乘法。
#Using multiples of timedelta function
my_date - 2*timedelta(10)
Output: datetime.datetime(2018, 1, 21, 0, 0)
我們前面看過了 datetime 模塊的“datetime”和“timedelta”數(shù)據(jù)類型。我們簡(jiǎn)要說(shuō)明一下在分析時(shí)間序列時(shí)用到的主要數(shù)據(jù)類型:
數(shù)據(jù)類型
描述
Date
用公歷保存日歷上的日期(年,月,日)
Time
將時(shí)間保存為小時(shí)、分鐘、秒和微秒
Datetime
保存date和time兩種數(shù)據(jù)類型
Timedelta
保存兩個(gè)datetime值的不同之處
字符串和 datetime 之間的轉(zhuǎn)換
我們可以將 datetime 格式轉(zhuǎn)換為字符串,并以字符串變量進(jìn)行保存。也可以反過來(lái),將表示日期的字符串轉(zhuǎn)換為 datetime 數(shù)據(jù)類型。
#Converting datetime to string
my_date1 = datetime(2018,2,14)
str(my_date1)
Output: '2018-02-14 00:00:00'
我們可以用 strptime 函數(shù)將字符串轉(zhuǎn)換為 datetime。
#Converting a string to datetime
datestr = '2018-02-14'
datetime.strptime(datestr, '%Y-%m-%d')
Output: datetime.datetime(2018, 2, 14, 0, 0)
也可以用 Pandas 處理日期。我們先導(dǎo)入 Pandas。
#Importing pandas
import pandas as pd
在 Pandas 中用“to_datetime”將日期字符串轉(zhuǎn)換為 date 數(shù)據(jù)類型。
#Using pandas to parse dates
datestrs = ['1/14/2018', '2/14/2018']
pd.to_datetime(datestrs)
Output: DatetimeIndex(['2018-01-14', '2018-02-14'], dtype='datetime64[ns]', freq=None)
在 Pandas 中,將缺失的時(shí)間或時(shí)間中的 NA 值表示為 NaT。
時(shí)間序列的索引和切片
為了更好的理解時(shí)間序列中的多種操作,我們用隨機(jī)數(shù)字創(chuàng)建一個(gè)時(shí)間序列。
#Creating a time series with random numbers
import numpy as np
from random import random
dates = [datetime(2011, 1, 2), datetime(2011, 1, 5), datetime(2011, 1, 7), datetime(2011, 1, 8), datetime(2011, 1, 10), datetime(2011, 1, 12)]
ts = pd.Series(np.random.randn(6), index=dates)
ts
Output:
2011-01-02 0.888329
2011-01-05 -0.152267
2011-01-07 0.854689
2011-01-08 0.680432
2011-01-10 0.123229
2011-01-12 -1.503613
dtype: float64
用我們展示的索引,可以將該時(shí)間序列的元素調(diào)用為任何其它 Pandas 序列。
ts[’01/02/2011′] 或 ts[‘20110102’]會(huì)給出同樣的輸出0.888329
切片操作和我們對(duì)其它 Pandas 序列的切片操作相同。
時(shí)間序列中的重復(fù)索引
有時(shí)你的時(shí)間序列會(huì)包含重復(fù)索引??匆幌氯缦聲r(shí)間序列:
#Slicing the time series
ts[datetime(2011,1,7):]
Output:
2011-01-07 0.854689
2011-01-08 0.680432
2011-01-10 0.123229
2011-01-12 -1.503613
dtype: float64
在上面的時(shí)間序列中,我們可以看到“2018-01-02”重復(fù)出現(xiàn)了 3 次。我們可以用 index 函數(shù)的“is_unique”屬性檢查這一點(diǎn)。
dup_ts.index.is_unique
Output: False
可以用 groupby 功能集合有相同索引的記錄。
grouped=dup_ts.groupby(level=0)
我們現(xiàn)在可以根據(jù)自己的需求,使用這些記錄的平均值、計(jì)數(shù)、總和等等。
grouped.mean()
Output:
2018-01-01 -0.471411
2018-01-02 -0.013973
2018-01-03 -0.611886
dtype: float64
grouped.count()
Output:
2018-01-01 1
2018-01-02 3
2018-01-03 1
dtype: int64
grouped.sum()
Output:
2018-01-01 -0.471411
2018-01-02 -0.041920
2018-01-03 -0.611886
dtype: float64
數(shù)據(jù)位移
我們可以用 shift 函數(shù)轉(zhuǎn)移時(shí)間序列的索引。
#Shifting the time series
ts.shift(2)
Output:
2011-01-02 NaN
2011-01-05 NaN
2011-01-07 0.888329
2011-01-08 -0.152267
2011-01-10 0.854689
2011-01-12 0.680432
dtype: float64
在學(xué)習(xí)過程中有什么不懂得可以加我的
python學(xué)習(xí)交流扣扣qun,784758214
群里有不錯(cuò)的學(xué)習(xí)視頻教程、開發(fā)工具與電子書籍。
與你分享python企業(yè)當(dāng)下人才需求及怎么從零基礎(chǔ)學(xué)習(xí)好python,和學(xué)習(xí)什么內(nèi)容
總結(jié)
本文我們簡(jiǎn)要討論了時(shí)間序列的一些屬性,以及如何用 Python 計(jì)算它們。同時(shí)也用一個(gè)簡(jiǎn)單的線性模型預(yù)測(cè)時(shí)間序列。最后分享了分析時(shí)間序列時(shí)用到的一些基本功能,比如將日期從一種格式轉(zhuǎn)換為另一種格式。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
