Python股市數據分析教程——可以實現半“智能”炒股 (Part 1)

本篇文章是"Python股市數據分析"兩部曲中的第一部分,內容基於我在猶他州立大學MATH 3900 (Data Mining)課程上的一次講座。在這些文章中,我將介紹一些關於金融數據分析的基礎知識,例如,使用pandas獲取雅虎財經上的數據,股票數據可視化,移動均線,開發一種均線交叉策略,回溯檢驗以及基準測試。第二篇文章會介紹一些實踐中可能出現的問題,而本篇文章著重討論移動平均線。

注意:本篇文章所涉及的看法、意見等一般性信息僅為作者個人觀點。本文的任何內容都不應被視為金融投資方面的建議。此外,在此提供的所有代碼均無法提供任何保證。選擇使用這些代碼的個人需自行承擔風險。

引言

高等數學與統計學已在金融領域應用了一段時間。 在20世紀80年代以前,銀行業和金融界以"枯燥乏味"而聞名;投資銀行與商業銀行不同,銀行的主要職責在於處理"簡單的"(至少與今天相比)金融商品,如貸款。里根政府的放松管制,再加上一大批數學天才,將整個行業從"枯燥的"銀行業務轉變成了今天這個樣子,而且,從那時起,金融便融入了其他自然學科,激勵著數學領域的研究與發展。比如,近期數學領域最大的成就之一,便是Black-Scholes公式的推導,這一成果可用於股票期權(一種賦予持有人以特定價格向期權發行商購買或出售股票權利的合約)的定價。可以說,在一定程度上,包括 Black-Scholes公式在內的糟糕的統計學模型導致了2008年金融危機的爆發。

近幾年來,為了在買賣金融資產的過程中賺取利潤,計算機科學也同高等數學一起,參與到了金融與貿易領域的變革當中。最近幾年,計算機主導著貿易的進行;算法相比人類能夠更快速地做出交易決策(如此之迅速,以至於在設計系統時,光的傳導速度成為了約束)。此外,機器學習與數據挖掘技術在金融領域越來越受歡迎,而且以後也可能會繼續這樣下去。實際上,大部分的算法交易都屬於高頻交易(HFT)。儘管算法的表現可能超過人類,但是這項技術並不成熟,應用的領域又充滿著高風險與動盪。高頻交易導致了2010年與2013年市場的閃電崩盤,其中,2013年的崩盤是由一條美聯社被黑客偽造的關於白宮受到攻擊的推文所引發的。

然而,本篇文章並不會討論如何使用糟糕的數學模型和交易算法使股市崩盤。相反,我打算向大家介紹一些用於處理和分析股市數據的Python工具。我還將討論移動均線、如何使用移動均線來構建交易策略、如何在進入倉位時制定退出策略以及如何使用回溯檢驗評估交易策略等方面的內容。

聲明:這不是關於金融投資的建議!!!而且,我從未從事過交易員等工作(許多這方面的知識我都是在鹽湖城社區學院中一門為期一學期的股市交易課程中接觸到的)!這些只是單純的入門級知識,並不足以讀者在股市中進行實際的交易操作。股市有風險,入市需謹慎!

獲取並可視化股票數據

使用pandas從雅虎財經中獲取數據

在我們處理股票數據之前,我們首先需要通過一些可行的途徑獲取它們。股票數據可以從雅虎財經、谷歌財經或者其他數據源中獲得,而pandas可以輕鬆訪問雅虎財經、谷歌財經以及其他來源中的數據。在本篇文章中,我們從雅虎財經獲取股票數據。

以下代碼演示了直接創建一個包含股票信息的DataFrame對象的過程。(你可以在這裡瞭解更多關於遠程數據訪問的信息。)

<code>import pandas as pd
import pandas.io.data as web
import datetime

start = datetime.datetime(2016,1,1)
end = datetime.date.today()

apple = web.DataReader("AAPL", "yahoo", start, end)

type(apple)/<code>
<code>C:\\Anaconda3\\lib\\site-packages\\pandas\\io\\data.py:35: FutureWarning: 
The pandas.io.data module is moved to a separate package (pandas-datareader) and will be removed from pandas in a future version.
After installing the pandas-datareader package (https://github.com/pydata/pandas-datareader), you can change the import ``from pandas.io import data, wb`` to ``from pandas_datareader import data, wb``.
FutureWarning)

pandas.core.frame.DataFrame/<code>
<code>apple.head()/<code>


Python股市數據分析教程——可以實現半“智能”炒股 (Part 1)

讓我們簡單介紹一下。開盤價是指股票在交易日開市時的股價(並不一定是前一交易日的收盤價格),最高價是指在交易日當天股價的最高價格,最低價是指在交易日當天股價的最低價格,收盤價是指股票在交易日收盤時的股價。交易量表示被交易股票的數量。調整收盤價是根據公司行為調整後的股票收盤價格。儘管我們認為大多數股票的價格是由交易員設定的,但是股票分割(公司將當前的一張股票拆分成價值一半的兩張股票)和派付股息(為每份股份支付公司紅利)仍然會影響到股票的價格,這些情況我們都應該考慮進來。

股票數據可視化

既然我們現在有了股票數據,我們可以通過可視化的形式展示它。我首先演示如何使用matplotlib來可視化股票數據。注意,名為apple的DataFrame對象有一個很方便的方法plot(),這個函數使創建圖表更加容易。

<code>import matplotlib.pyplot as plt

%matplotlib inline

%pylab inline
pylab.rcParams['figure.figsize'] = (15, 9)

apple["Adj Close"].plot(grid = True) /<code>
<code>Populating the interactive namespace from numpy and matplotlib/<code> 


Python股市數據分析教程——可以實現半“智能”炒股 (Part 1)

折線圖是很不錯,但是每個日期都至少包含四個變量(開盤價、最高價、最低價、收盤價),我們希望有一些可視化的方法能夠同時展示這四個變量,而不是簡單地畫四條折線。金融數據通常以日本蠟燭圖(即K線圖)的形式繪製,這種圖表最早在18世紀由日本米市商人命名。matplotlib可以繪製這樣的圖表,但操作起來比較複雜。

我實現了一個函數,你可以更容易地在pandas數據框架中創建蠟燭圖,並使用它繪製我們的股票數據。(代碼基於這個例子,你可以在這裡找到相關函數的文檔)

<code>from matplotlib.dates import DateFormatter, WeekdayLocator,\\
DayLocator, MONDAY
from matplotlib.finance import candlestick_ohlc

def pandas_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])
elif stick == "month":
transdat["month"] = pd.to_datetime(transdat.index).map(lambda x: x.month)
transdat["year"] = pd.to_datetime(transdat.index).map(lambda x: x.isocalendar()[0])
grouped = transdat.groupby(list(set(["year",stick])))
plotdat = pd.DataFrame({"Open": [], "High": [], "Low": [], "Close": []})

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": []})
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')

fig, ax = plt.subplots()
fig.subplots_adjust(bottom=0.2)
if plotdat.index[-1] - plotdat.index[0] < pd.Timedelta('730 days'):
weekFormatter = DateFormatter('%b %d')
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)

candlestick_ohlc(ax, list(zip(list(date2num(plotdat.index.tolist())), plotdat["Open"].tolist(), plotdat["High"].tolist(),
plotdat["Low"].tolist(), plotdat["Close"].tolist())),
colorup = "black", colordown = "red", width = stick * .4)

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()

pandas_candlestick_ohlc(apple)/<code>


Python股市數據分析教程——可以實現半“智能”炒股 (Part 1)

在蠟燭圖中,黑色蠟燭表示交易日當天收盤價高於開盤價(盈利),而紅色蠟燭表示交易日當天開盤價高於收盤價(虧損)。燭芯表示最高價與最低價,蠟燭體則表示開盤價與收盤價(顏色用來區分哪一側為開盤價,哪一側為收盤價)。蠟燭圖在金融領域很受歡迎,根據圖表中蠟燭的形狀、顏色以及位置,技術分析中的一些策略可以使用它來制定交易策略。但在這裡我不會介紹有關這類策略的內容。

我們可能希望在同一張圖表中繪製多個金融商品的數據;我們可能想要對比股票,將它們與市場進行比較,或者看看其他證券,比如交易所交易基金(ETFs)。之後,我們可能還想看看如何根據一些指標,如移動均線,來繪製金融商品。對於這種情況,你最好使用折線圖而不是蠟燭圖。(如何將多個蠟燭圖相互疊加在一起而不使圖表混亂?)

在下面的代碼中,我獲取了一些其他科技公司的股票數據,並把它們的調整收盤價格繪製在了一起。

<code>microsoft = web.DataReader("MSFT", "yahoo", start, end)
google = web.DataReader("GOOG", "yahoo", start, end)

stocks = pd.DataFrame({"AAPL": apple["Adj Close"],
"MSFT": microsoft["Adj Close"],
"GOOG": google["Adj Close"]})

stocks.head()/<code>


Python股市數據分析教程——可以實現半“智能”炒股 (Part 1)

<code>stocks.plot(grid = True)/<code>


Python股市數據分析教程——可以實現半“智能”炒股 (Part 1)

這張圖有什麼問題?儘管絕對價格很重要(昂貴的股票很難購買,這不僅影響著這類股票的價格波動,也影響著你交易這類股票的能力),但是在交易過程中,相比絕對價格,我們更加關心資產的相對變化。谷歌的股票比蘋果和微軟的股票貴得多,這種差異使得蘋果和微軟股票的波動看起來比實際情況小得多。

一種解決方案是在繪製圖表時使用兩種不同的尺度;一種尺度用於蘋果和微軟的股票,另一種尺度用於谷歌股票。

<code>stocks.plot(secondary_y = ["AAPL", "MSFT"], grid = True)/<code>


Python股市數據分析教程——可以實現半“智能”炒股 (Part 1)

然而,一個"更好的"解決方案是,僅在圖表中繪製我們真正想要的信息:股票的回報。這就需要我們根據需求將數據轉換成更有用的形式。這裡有幾種我們可以應用的轉換。

一種方式是考慮股票自利息週期開始以來的回報。換句話說,我們繪製:


Python股市數據分析教程——可以實現半“智能”炒股 (Part 1)

正如我下面演示的這樣,這意味著轉換stocks對象中的數據。

<code>stock_return = stocks.apply(lambda x: x / x[0])
stock_return.head()/<code>


Python股市數據分析教程——可以實現半“智能”炒股 (Part 1)

<code>stock_return.plot(grid = True).axhline(y = 1, color = "black", lw = 2)/<code>


Python股市數據分析教程——可以實現半“智能”炒股 (Part 1)

這樣的圖表就更有用了。現在,我們可以看到每隻股票在週期開始以來的盈利。而且,我們還能發現這些股票密切相關;它們通常朝同一個方向發展,在其他的圖表中很難發現這樣的事實。

除此之外,我們還可以繪製每隻股票在每一個交易日的變化。比如,我們可以通過比較第t天與第t+1天的價格來繪製股票增長的百分比,公式如下:


Python股市數據分析教程——可以實現半“智能”炒股 (Part 1)

但是這種變化也可以通過如下公式定義:


Python股市數據分析教程——可以實現半“智能”炒股 (Part 1)

這些公式多少有些不同,可能會分析出不同的結論,但是還有另外一種對股票增長建模的方法:對數差值。


Python股市數據分析教程——可以實現半“智能”炒股 (Part 1)

(這裡的log為自然對數,我們的定義並不關心使用的是第t天與第t-1天的對數差值還是第t+1天與第t天的對數差值。)使用對數差值的好處在於,這種差值可以理解為股價的百分比變化,且不依賴於計算過程中分數的分母。

我們可以通過如下方式獲取並繪製stocks對象中數據的對數差值:

<code>import numpy as np

stock_change = stocks.apply(lambda x: np.log(x) - np.log(x.shift(1)))
stock_change.head()/<code>


Python股市數據分析教程——可以實現半“智能”炒股 (Part 1)

<code>stock_change.plot(grid = True).axhline(y = 0, color = "black", lw = 2)/<code>


Python股市數據分析教程——可以實現半“智能”炒股 (Part 1)

你傾向於哪一種轉換?關注股票以往的盈利情況會使得證券的整體趨勢更加明顯。但是,在對股票的行為模式建模時,更先進的方法實際考慮的是交易日間股價的變化。因此,我們不應該忽略這部分的信息。

移動均線

圖表是很非常有用的。實際上,一些交易員做出的策略幾乎完全基於圖表(他們屬於"技術人員",因為基於在圖表中查找模式的交易策略是被稱為技術分析的貿易規則的一部分)。現在,讓我們考慮如何才能找到股票的趨勢。

對於序列xt以及時刻t,q天均線表示過去q天股價的均值:也就是說,如果MAtq表示t時刻的q天均線,那麼:


Python股市數據分析教程——可以實現半“智能”炒股 (Part 1)

移動均線平滑了數據序列,並有助於識別股市的發展趨勢。q值越大,移動均線就越難反映序列xt中的短期波動。這裡的想法是,移動均線過程能夠從"噪聲"中識別股市的發展趨勢。短期均線具有較小的q值,比較緊密地跟隨股票的趨勢發展,而長期均線的q值較大,進而使得均線對股票波動的響應較小,而且更加平穩。

pandas提供了輕鬆計算移動均線的功能。下面的代碼展示了這部分功能,我首先為蘋果股票創建了一條20天(1個月)均線,隨後,將其與股票數據一同繪製在圖表中。

<code>apple["20d"] = np.round(apple["Close"].rolling(window = 20, center = False).mean(), 2)
pandas_candlestick_ohlc(apple.loc['2016-01-04':'2016-08-07',:], otherseries = "20d")/<code>


Python股市數據分析教程——可以實現半“智能”炒股 (Part 1)

注意滾動均值是從什麼時候開始的。只有在積累了20天的交易日數據之後,我們才能計算股票的20天均線。這個限制對於長期均線而言更加嚴重。如果我們想要計算股票的200天均線,我們需要多少蘋果公司的股票數據才行?在這裡,我們將主要關注2016年的股票走勢。

<code>start = datetime.datetime(2010,1,1)
apple = web.DataReader("AAPL", "yahoo", start, end)
apple["20d"] = np.round(apple["Close"].rolling(window = 20, center = False).mean(), 2)

pandas_candlestick_ohlc(apple.loc['2016-01-04':'2016-08-07',:], otherseries = "20d")/<code>


Python股市數據分析教程——可以實現半“智能”炒股 (Part 1)

你會注意到,移動均線要比實際的股票數據平滑得多。此外,這是一個難以處理的標誌;股票需要在移動均線的上方或下方,以便改變股票走勢的方向。因此,股票走勢越過移動均線的情況表明了股票一種可能的走向,應該引起我們的注意。

交易員通常對多條移動均線感興趣,比如20天均線、50天均線以及200天均線。同時檢查多條移動均線也很容易。

<code>apple["50d"] = np.round(apple["Close"].rolling(window = 50, center = False).mean(), 2)
apple["200d"] = np.round(apple["Close"].rolling(window = 200, center = False).mean(), 2)

pandas_candlestick_ohlc(apple.loc['2016-01-04':'2016-08-07',:], otherseries = ["20d", "50d", "200d"])/<code>


Python股市數據分析教程——可以實現半“智能”炒股 (Part 1)

其中,20天均線對局部變化最為敏感,而200天均線對局部變化最不敏感。在這裡,200天均線表明股票整體呈熊市行情:股票隨著時間的推移趨勢向下。20天均線有時呈熊市行情,而在其他時候呈牛市行情,預期股票會出現積極的波動。你還可以看到,移動均線的交叉表示著股票趨勢的變化。我們將這些交叉看作交易信號或指示器,表示金融證券正在改變趨勢,我們可能從中獲取利潤。


分享到:


相關文章: