首頁 > 上網技巧 > 電腦小技巧 > Python與股市數據分析

Python與股市數據分析

時間:2019-12-09 10:04 作者:QQ地帶 我要評論

寫在前面
上期文章中,小編和大家聊了一下機器學習之中的樸素貝葉斯算法,大致了解了這一算法在文檔分類之中的作用與步驟。闊別上期,本期文章,小編準備和大家談談怎么使用python去處理股市數據,這可以作為投資分析系列主題的第一篇文章,在這期文章中,小編準備和大家大致聊聊怎么使用python獲取股市數據、怎么將這些數據進行可視化以及在最后談論一個經典的投資策略——移動平均策略。另外這里有一點需要特別強調:小編往后的投資分析中將主要使用國外的股票數據,當然這里的國外主要指美國。這樣選擇處于兩方面的考慮:其一,國外股市數據相對時間較長,市場較為成熟,股市數據更具代表性;其二,基于國外股票數據得出的策略必須要在國內股市數據的測試成功之下才能使用,因此就促使了大家自己的動手實踐,當然還有一點就是,小編不要為各位的任何投資行為負擔責任。下面正式開始。
 
使用python獲取股市數據
python中獲取股市數據存在多種方法,你可以使用python去爬取各大財經網站上的股票數據,你也可以通過一些現成的數據包去獲得相應的股市數據,如果你對股市數據的興趣點不是高頻數據,那么使用這些現成的數據包將是非常方便的(當然這些第三方庫目前也可以提供獲取高頻數據的途徑)。小編后面的分析基于美國的股票數據,因此小編在這里選擇使用python中的pandas_datareader庫去獲取股市的數據,關于國內股市數據的獲取,小編在前期的文章中已經做過介紹,這里就不再說明。
 
因為小編在的分析中將主要使用蘋果公司(股票代碼AAPL)、谷歌公司(代碼GOOG)以及微軟公司(代碼為MSFT)的股票數據,因此小編首先需要獲得這些公司的股市數據,小編的代碼用來獲取這些公司的數據。
 
# 導入必要的庫
import numpy as np
import pandas as pd
from pandas_datareader import data as web
import datetime
 
# 設置起始時間
start = datetime.datetime(2016,1,1)
end = datetime.date.today()
 
# 分別獲取蘋果、谷歌以及微軟起始時間內的股價數據
apple = web.DataReader('AAPL','yahoo',start,end)
google = web.DataReader('GOOG','yahoo',start,end)
microsoft = web.DataReader('MSFT','yahoo',start,end)
 
# 查看一下谷歌股價數據的特征
google.head()
谷歌股價數據
代碼的第一部分用來導入必要的python庫,使用pandas_datareader獲取的數據均為pandas數據框形式,因此在這之前最好導入pandas庫,而在導入pandas庫之前小編習慣先導入numpy庫,所以你們可以不必導入這個庫,而至于導入datetime庫則主要是用于處理時間的。代碼的第二部分則主要用于設置股價獲取的起始時間,第一句代碼將股價獲取的初始時間設置為2006年1月1日,而第二行代碼則將介紹時間設置為今天。第三部分的代碼則主要用來獲取三個公司的股價數據,這主要是通過web.DataReader函數實現,這個函數的基本參數為四個:第一個為股票代碼,第二個為獲取來源,一般為yahoo或google,第三個和第四個參數則分別為起止時間。最后一部分的一行代碼則用來顯示谷歌股價的前幾行,如圖所示。
 
可見,使用web.DataReader函數獲取的股價數據主要包括六個指標。其中,Open是當天開盤價;high是股票當天最高價;low是股票當天最低價;close是當天收盤價;Volume為成家量交;Adjust close調整后的收盤價(之所以對股價進行調整是要剔除拆股以及分紅的影響)。
 
在獲取了股價數據之后,下一部分這主要是用來可視化,畢竟人類最喜歡的閱讀方法永遠是圖,所以下面的主題部分將包含各種圖表。
 
股市數據可視化
既然有了股市數據,那么可以根據自己的想法進行可視化,這自然離不開我們的老朋友matplotlib庫。小編在這一部分將介紹兩種可視化思路,第一種是對單只股票股價數據的展示,第二種是對多只股票的對比展示,下面先開始單只股票的展示,這里小編以谷歌的股價為例進行展示。
 
# 導入必要的庫
import matplotlib as mpl
import matplotlib.pyplot as plt
 
# 設置相關的繪圖環境 
%matplotlib inline
plt.rcParam['font.sans-serif'] = ['SimHei']
plt.rcParams['figure.figsize'] = (16, 9)
 
# 繪圖
google["Adj Close"].plot(grid = True)
plt.xlabel('時間')
plt.ylabel('調整后收盤價')
plt.title('谷歌股價走勢圖')
 
這里主要解釋一下代碼的二三部分。第二部分主要用來設置作圖的環境,因為小編是在jupyter notebook中進行程序撰寫與調試的,因此第二部分的第一句代碼主要是用來讓繪制的圖形直接在此頁面進行顯示,而第二行代碼則用來設置中文字體,第三行代碼用來設置圖形的大小。而第三部分的代碼主要用來作圖,第一行是作圖必須,后面三行主要用來設置圖形格式。從作出的圖形中可以看出,谷歌的股價基本呈現上升趨勢,現在的股價水平已經接近1200美元,小編是真的一手都買不起呀。
 
然而股價的數據一般表現為四個值:開盤、收盤、最高以及最低。所以使用線形圖無法完整展示出股價的特征,這種情況下K線圖就主要派上用場了。小編前面已經介紹了怎么使用python繪制K線圖了,這里小編以原來的代碼為基礎重新構造一個更加便利的繪制K線圖的函數,見下面代碼。
 
from matplotlib.dates import DateFormatter, WeekdayLocator,DayLocator, MONDAY
from matplotlib.finance import candlestick_ohlc
from matplotlib.pylab import date2num
def df_candlestick_ohlc(dat, stick = "day", otherseries = None):
    mondays = WeekdayLocator(MONDAY)        
    alldays = DayLocator()              
    dayFormatter = DateFormatter('%d')      
 
    transdat = dat.loc[:,["Open", "High", "Low", "Close"]]
    if (type(stick) == str):
        if stick == "day":
            plotdat = transdat
            stick = 1 
        elif stick in ["week", "month", "year"]:
            if stick == "week":
                transdat["week"] = pd.to_datetime(transdat.index).map(lambda x: x.isocalendar()[1]) # Identify weeks
            elif stick == "month":
                transdat["month"] = pd.to_datetime(transdat.index).map(lambda x: x.month) # Identify months
            transdat["year"] = pd.to_datetime(transdat.index).map(lambda x: x.isocalendar()[0]) # Identify years
            grouped = transdat.groupby(list(set(["year",stick]))) # Group by year and other appropriate variable
            plotdat = pd.DataFrame({"Open": [], "High": [], "Low": [], "Close": []}) # Create empty data frame containing what will be plotted
            for name, group in grouped:
                plotdat = plotdat.append(pd.DataFrame({"Open": group.iloc[0,0],
                                            "High": max(group.High),
                                            "Low": min(group.Low),
                                            "Close": group.iloc[-1,3]},
                                           index = [group.index[0]]))
            if stick == "week": stick = 5
            elif stick == "month": stick = 30
            elif stick == "year": stick = 365
 
    elif (type(stick) == int and stick >= 1):
        transdat["stick"] = [np.floor(i / stick) for i in range(len(transdat.index))]
        grouped = transdat.groupby("stick")
        plotdat = pd.DataFrame({"Open": [], "High": [], "Low": [], "Close": []}) # Create empty data frame containing what will be plotted
        for name, group in grouped:
            plotdat = plotdat.append(pd.DataFrame({"Open": group.iloc[0,0],
                                        "High": max(group.High),
                                        "Low": min(group.Low),
                                        "Close": group.iloc[-1,3]},
                                       index = [group.index[0]]))
 
    else:
        raise ValueError('Valid inputs to argument "stick" include the strings "day", "week", "month", "year", or a positive integer')
 
 
    # Set plot parameters, including the axis object ax used for plotting
    fig, ax = plt.subplots()
    fig.subplots_adjust(bottom=0.2)
    if plotdat.index[-1] - plotdat.index[0] < pd.Timedelta('915 days'):
        weekFormatter = DateFormatter('%b %d')  # e.g., Jan 12
        ax.xaxis.set_major_locator(mondays)
        ax.xaxis.set_minor_locator(alldays)
    else:
        weekFormatter = DateFormatter('%b %d, %Y')
    ax.xaxis.set_major_formatter(weekFormatter)
 
    ax.grid(True)
 
    # Create the candelstick chart
    candlestick_ohlc(ax, list(zip(list(date2num(plotdat.index.tolist())), plotdat["Open"].tolist(), plotdat["High"].tolist(),
                      plotdat["Low"].tolist(), plotdat["Close"].tolist())),
                      colorup = "red", colordown = "green", width = stick * .4)
    plt.xlabel('日期')
    plt.ylabel('股價')
    plt.title('谷歌股價K線圖')
 
    # Plot other series (such as moving averages) as lines
    if otherseries != None:
        if type(otherseries) != list:
            otherseries = [otherseries]
        dat.loc[:,otherseries].plot(ax = ax, lw = 1.3, grid = True)
 
    ax.xaxis_date()
    ax.autoscale_view()
    plt.setp(plt.gca().get_xticklabels(), rotation=45, horizontalalignment='right')
 
    plt.show()
上面小編創建了一個繪制K線圖的快捷程序,之所以重新編寫K線圖的繪制程序是因為原庫中的K線圖繪制方法存在諸多不便而且每次繪制時都需要進行數據的整理,因此為了便利繪制,這里重新設計了K線圖的繪制方法,其中包括天、周、月以及年度的K線圖繪制,在繪制時只需要指定好相應的繪制參數即可。鑒于程序相對較長,小編這里就不再一一講解其中的命令了,有疑問的朋友可以給我留言。下面就使用這個程序來繪制一下谷歌公司自2016年至今的日K線圖。
 
df_candlestick_ohlc(google)
谷歌股價K線圖
小編在繪制K線圖的時候重新設置了圖片的格式,隱去了圖片的行標題和列標題以及圖片標題,所以和函數稍稍有點不同,不過這個不是什麼大問題,所以不需要過多注意。
 
上面小編分別繪制了單只股票的走勢圖以及K線圖,但是很多時候需要對不同的股票數據進行比較,因此需要將這些股價數據整合在一張圖中,這個時候K線圖是很不方便的,還是需要采用線性圖去進行比較,這里小編就以三家公司的調整收盤價為例來繪制相關的圖表,具體如下。
 
closePrice = pd.DataFrame({"AAPL": apple["Adj Close"],
                      "MSFT": microsoft["Adj Close"],
                      "GOOG": google["Adj Close"]})
closePrice.plot(grid=True)
plt.xlabel('時間')
plt.ylabel('調整收盤價')
plt.title('股價走勢比較圖')
三家公司股價走勢比價圖
上面程序繪制了三家公司的股價走勢圖,程序中的第一句主要用來創建三家公司調整收盤價的數據框,而后的四條語句分別用來繪制圖形以及設置相應的圖片格式。不過通過這幅圖形可以看出;谷歌的股價要遠遠地高于其它兩家公司的股價,因此如果將它們放在一張圖的同一個坐標系下會顯得另外兩家公司的股價相對沒有趨勢,為了解決這個問題,可以采取兩種思路:其一,設置雙坐標軸;其二,使用收益率數據。下面首先考慮使用雙坐標軸來解決這個問題。
 
closePrice = pd.DataFrame({"AAPL": apple["Adj Close"],
                      "MSFT": microsoft["Adj Close"],
                      "GOOG": google["Adj Close"]})
closePrice.plot(secondary_y = ["AAPL", "MSFT"], grid = True)
plt.xlabel('時間')
plt.ylabel('調整收盤價')
plt.title('股價走勢比較圖')
雙坐標股價走勢圖
這種方式雖然使得蘋果公司與微軟公司的股價走勢相對明顯,但是一定程度上雙坐標的存在又給閱圖造成了一定的困擾,所以下面小編將采用收益率數據去進行圖形的繪制,請注意,這種方式也是在比較不同的時間序列數據時最為常用的一種方式。小編下面會采用兩種收益率數據進行繪圖,一種是基準收益率(即所有的數據相對于初始價格的收益率),第二種就是常用的日度收益率,即環比收益率。
 
基準收益率(小編這里采用毛收益率)依賴于初始股價水平,這種收益率可以很明顯地看出股價的走勢,因此在考察時間序列的走勢時,這種方式不啻是一種比較好的選擇,這種收益率的計算方法為:
 
returnt=pricetprice0
下面小編就依據這種收益率繪制相應的圖形。
 
stock_return = closePrice.apply(lambda x: x / x[0])
stock_return.plot(grid = True).axhline(y = 1, color = "black", lw = 2)
plt.xlabel('時間')
plt.ylabel('基準收益率')
plt.title('股價收益率')
股價基準收益率
可以看出,這種方式和直接繪制股價比較圖時存在一樣的問題,即數據的范圍差異較大引起的小范圍數據顯示不明顯,因此,下面進一步使用日度收益率來解決這個問題,第t期的收益率可以通過下面公司進行計算:
 
returnt=pricet+1pricet−1
當然也可以通過下面的公司進行計算:
 
returnt=pricetpricet−1−1
這兩種計算方式還是存在一定的差距的,因此為了避免這種影響,小編采用對數收益率方式進行計算,公式為:
 
returnt=log(ptpt−1)
下面給出基于這種收益率的程序的圖形展示。
 
import numpy as np
stock_return = closePrice.apply(lambda x: np.log(x) - np.log(x.shift(1)))
stock_return.plot(grid = True).axhline(y = 0, color = "black", lw = 2)
plt.xlabel('時間')
plt.ylabel('收益率')
plt.title('股價收益率')
股價對數收益率對比
可以看出三只股票的收益率存在趨同的趨勢,遠比單純使用絕對價格更加有用。上面,小編已經相繼介紹了繪制比較圖的各種方式,這里稍微總結一下吧,如果想比較趨勢的話,最后使用基準收益率,如果想對各公司的股價進行同等對比的話最后使用對數收益率。截止到這里,小編介紹了對于單只股票以及多只股票的繪圖方式,下面小編將進行本文的最后一部分,介紹一下移動平均線,這與移動平均策略密切相關,需引起注意。
 
移動平均線圖
對于時期t,一個n天的移動平均值計算公式為:
 
MAnt=1n∑i=0n−1xt−i
移動平均值可以讓一個系列的數據變得更平滑,有助于找到趨勢。n值越大,移動平均對短期的波動越不敏感。移動平均的基本目的就是從噪音中識別趨勢?焖俚囊苿悠骄衅〉膎,它們更接近股票價格;而慢速的移動平均有較大的n值,這使得它們對波動不敏感從而更加穩定。對于移動平均值的計算,python的pandas庫中存在現場的方法,下面小編進行這種方法介紹與繪圖。首先,小編計算蘋果股價的20天移動平均,并將這一移動平均值繪制在K線圖之上。
 
google["20d"] = np.round(google["Close"].rolling(window = 20, center = False).mean(), 2)
df_candlestick_ohlc(google.loc['2017-10-01':'2018-06-30',:], otherseries = "20d")
 
可以看出移動平均比真實的股票價格數據平滑很多。而且這個指數是非常難改變的:一支股票的價格需要變到平局值之上或之下才能改變移動平均線的方向。因此平均線的交叉點代表了潛在的趨勢變化,需要加以注意。交易者往往對不同的移動平均感興趣,例如7天,20天和200天。要同時生成多條移動平均線也不難:
 
google["7d"] = np.round(google["Close"].rolling(window = 7, center = False).mean(), 2)
google["20d"] = np.round(google["Close"].rolling(window = 20, center = False).mean(), 2)
google["200d"] = np.round(google["Close"].rolling(window = 200, center = False).mean(), 2) 
df_candlestick_ohlc(google.loc['2017-10-01':'2018-06-30',:], otherseries = ["7d", "20d", "200d"])
 
7天和20天的移動平均線對小的變化非常敏感,而200天的移動平均線波動最小。200天平均線顯示出來總體的牛市趨勢:股值總體來說一直在上升。20天移動平均線所代表的信息是熊市牛市交替,接下來有可能是牛市。這些平均線的交叉點就是交易信息點,它們代表股票價格的趨勢會有所改變因而你需要作出能盈利的相應決策。這些投資決策會在后續文章中進行講述。
 
后記
本文講到這里就暫時告一段落了,本期文章和大家聊了一下怎么使用python去處理股市數據,了解了怎么使用python去獲取股市數據以及對單只股票和多只股票的可視化,本期文章可以作為投資分析類文章第一篇,后續會持續進行更新。再次感謝你們的支持與鼓勵,你們的陪伴是小編前進的動力!

標簽: Python 股票
頂一下
(0)
0%
踩一下
(0)
0%

Google提供的廣告

辽宁11选5任选四遗漏