本文將使用Python來視覺化股票資料,比如繪製K線圖,並且探究各項指標的含義和關係,最後使用移動平均線方法初探投資策略。
資料匯入
這裡將股票資料儲存在stockData.txt文字檔案中,我們使用pandas.read_table()函式將檔案資料讀入成DataFrame格式。
其中引數usecols=range(15)限制只讀取前15列資料,parse_dates=[0]表示將第一列資料解析成時間格式,index_col=0則將第一列資料指定為索引。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
%config InlineBackend.figure_format = ‘retina’
%pylab inline
pylab.rcParams[‘figure.figsize’] = (10, 6) #設定繪圖尺寸
#讀取資料
stock = pd.read_table(‘stockData.txt’, usecols=range(15), parse_dates=[0], index_col=0)
stock = stock[::-1] #逆序排列
stock.head()
以上顯示了前5行資料,要得到資料的更多資訊,可以使用.info()方法。它告訴我們該資料一共有20行,索引是時間格式,日期從2015年1月5日到2015年1月30日。總共有14列,併列出了每一列的名稱和資料格式,並且沒有缺失值。
stock.info()
<class ‘pandas.core.frame.DataFrame’>
DatetimeIndex: 20 entries, 2015–01–05 to 2015–01–30
Data columns (total 14 columns):
open 20 non–null float64
high 20 non–null float64
close 20 non–null float64
low 20 non–null float64
volume 20 non–null float64
price_change 20 non–null float64
p_change 20 non–null float64
ma5 20 non–null float64
ma10 20 non–null float64
ma20 20 non–null float64
v_ma5 20 non–null float64
v_ma10 20 non–null float64
v_ma20 20 non–null float64
turnover 20 non–null float64
dtypes: float64(14)
memory usage: 2.3 KB
在觀察每一列的名稱時,我們發現’open’的列名前面似乎與其它列名不太一樣,為了更清楚地檢視,使用.columns得到該資料所有的列名如下:
stock.columns
Index([‘ open’, ‘high’, ‘close’, ‘low’, ‘volume’, ‘price_change’,
‘p_change’, ‘ma5’, ‘ma10’, ‘ma20’, ‘v_ma5’, ‘v_ma10’, ‘v_ma20’,
‘turnover’],
dtype=‘object’)
於是發現’open’列名前存在多餘的空格,我們使用如下方法修正列名。
stock.rename(columns={‘ open’:’open’}, inplace=True)
至此,我們完成了股票資料的匯入和清洗工作,接下來將使用視覺化的方法來觀察這些資料。
資料觀察
首先,我們觀察資料的列名,其含義對應如下:
這些指標總體可分為兩類:
價格相關指標
當日價格:開盤、收盤價,最高、最低價
價格變化:價格變動和漲跌幅
均價:5、10、20日均價
成交量相關指標
成交量
換手率:成交量/發行總股數×100%
成交量均量:5、10、20日均量
由於這些指標都是隨時間變化的,所以讓我們先來觀察它們的時間序列圖。
時間序列圖
以時間為橫坐標,每日的收盤價為縱坐標,做折線圖,可以觀察股價隨時間的波動情況。這裡直接使用DataFrame資料格式自帶的做圖工具,其優點是能夠快速做圖,並自動最佳化圖形輸出形式。
stock[‘close’].plot(grid=True)
如果我們將每日的開盤、收盤價和最高、最低價以折線的形式繪製在一起,難免顯得凌亂,也不便於分析。那麼有什麼好的方法能夠在一張圖中顯示出這四個指標?答案下麵揭曉。
K線圖
相傳K線圖起源於日本德川幕府時代,當時的商人用此圖來記錄米市的行情和價格波動,後來K線圖被引入到股票市場。每天的四項指標資料用如下蠟燭形狀的圖形來記錄,不同的顏色代表漲跌情況。
圖片來源:http://wiki.mbalib.com/wiki/K線理論
Matplotlib.finance模組提供了繪製K線圖的函式candlestick_ohlc(),但如果要繪製比較美觀的K線圖還是要下點功夫的。下麵定義了pandas_candlestick_ohlc()函式來繪製適用於本文資料的K線圖,其中大部分程式碼都是在設定坐標軸的格式。
from matplotlib.finance import candlestick_ohlc
from matplotlib.dates import DateFormatter, WeekdayLocator, DayLocator, MONDAY
def pandas_candlestick_ohlc(stock_data, otherseries=None):
# 設定繪圖引數,主要是坐標軸
mondays = WeekdayLocator(MONDAY)
alldays = DayLocator()
dayFormatter = DateFormatter(‘%d’)
fig, ax = plt.subplots()
fig.subplots_adjust(bottom=0.2)
if stock_data.index[–1] – stock_data.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)
# 建立K線圖
stock_array = np.array(stock_data.reset_index()[[‘date’,‘open’,‘high’,‘low’,‘close’]])
stock_array[:,0] = date2num(stock_array[:,0])
candlestick_ohlc(ax, stock_array, colorup = “red”, colordown=“green”, width=0.4)
# 可同時繪製其他折線圖
if otherseries is not None:
for each in otherseries:
plt.plot(stock_data[each], label=each)
plt.legend()
ax.xaxis_date()
ax.autoscale_view()
plt.setp(plt.gca().get_xticklabels(), rotation=45, horizontalalignment=‘right’)
plt.show()
pandas_candlestick_ohlc(stock)
這裡紅色代表上漲,綠色代表下跌。
相對變化量
股票中關註的不是價格的絕對值,而是相對變化量。有多種方式可以衡量股價的相對值,最簡單的方法就是將股價除以初始時的價格。
stock[‘return’] = stock[‘close’] / stock.close.iloc[0]
stock[‘return’].plot(grid=True)
第二種方法是計算每天的漲跌幅,但計算方式有兩種:
這兩者可能導致不同的分析結果,樣例資料中的漲跌幅使用的是第一個公式,並乘上了100%。
stock[‘p_change’].plot(grid=True).axhline(y=0, color=’black’, lw=2)
為瞭解決第二種方法中的兩難選擇,我們引入第三種方法,就是計算價格的對數之差,公式如下:
close_price = stock[‘close’]
log_change = np.log(close_price) – np.log(close_price.shift(1))
log_change.plot(grid=True).axhline(y=0, color=‘black’, lw=2)
相關關係
在觀察了價格的走勢之後,我們來看看各指標之間的關係。下麵挑選了部分代表性的指標,並使用pandas.scatter_matrix()函式,將各項指標資料兩兩關聯做散點圖,對角線是每個指標資料的直方圖。
small = stock[[‘close’, ‘price_change’, ‘ma20’,‘volume’, ‘v_ma20’, ‘turnover’]]
_ = pd.scatter_matrix(small)
圖中可以明顯發現成交量(volume)和換手率(turnover)有非常明顯的線性關係,其實換手率的定義就是:成交量除以發行總股數,再乘以100%。所以下麵的分析中我們將換手率指標去除,這裡使用了相關性關係來實現資料降維。
上面的散點圖看著有些眼花繚亂,我們可以使用numpy.corrcof()來直接計算各指標資料間的相關係數。
small = stock[[‘close’, ‘price_change’, ‘ma20’,‘volume’, ‘v_ma20’]]
cov = np.corrcoef(small.T)
cov
array([[ 1. , 0.30308764, 0.10785519, 0.91078009, –0.37602193],
[ 0.30308764, 1. , –0.45849273, 0.3721832 , –0.25950305],
[ 0.10785519, –0.45849273, 1. , –0.06002202, 0.51793654],
[ 0.91078009, 0.3721832 , –0.06002202, 1. , –0.37617624],
[–0.37602193, –0.25950305, 0.51793654, –0.37617624, 1. ]])
如果覺得看數字還是不夠方便,我們繼續將上述相關性矩陣轉換成圖形,如下圖所示,其中用顏色來代表相關係數。我們發現位於(0,3)位置的相關係數非常大,檢視數值達到0.91。這兩個強烈正相關的指標是收盤價和成交量。
img = plt.matshow(cov,cmap=plt.cm.winter)
plt.colorbar(img, ticks=[–1,0,1])
plt.show()
以上我們用矩陣圖表的方式在多個指標中迅速找到了強相關的指標。接著做出收盤價和成交量的折線圖,因為它們的數值差異很大,所以我們採用兩套縱坐標體系來做圖。
stock[[‘close’,’volume’]].plot(secondary_y=’volume’, grid=True)
觀察這兩個指標的走勢,在大部分時候股價上漲,成交量也上漲,反之亦然。但個別情況下則不成立,可能是成交量受到前期的慣性影響,或者還有其他因素。
移動平均線
吳軍老師曾講述他的投資經驗,大意是說好的投資方式不是做預測,而是能在合適的時機做出合適的應對和決策。同樣股市也沒法預測,我們能做的是選擇恰當的策略應對不同的情況。
好的指標是能驅動決策的。在上面的分析中我們一直沒有使用的一類指標是5、10、20日均價,它們又稱為移動平均值,下麵我們就使用這項指標來演示一個簡單的股票交易策略。(警告:這裡僅僅是演示說明,並非投資建議。)
為了得到更多的資料來演示,我們使用pandas_datareader直接從雅虎中下載最近一段時間的谷歌股票資料。
import datetime
import pandas_datareader.data as web
# 設定股票資料的時間跨度
start = datetime.datetime(2016,10,1)
end = datetime.date.today()
# 從yahoo中獲取google的股價資料。
goog = web.DataReader(“GOOG”, “yahoo”, start, end)
#修改索引和列的名稱,以適應本文的分析
goog.index.rename(‘date’, inplace=True)
goog.rename(columns={‘Open’:‘open’, ‘High’:‘high’, ‘Low’:‘low’, ‘Close’:‘close’}, inplace=True)
goog.head()
資料中只有每天的價格和成交量,所以我們需要自己算出5日均價和10日均價,並將均價的折線圖(也稱移動平均線)與K線圖畫在一起。
goog[“ma5”] = np.round(goog[“close”].rolling(window = 5, center = False).mean(), 2)
goog[“ma20”] = np.round(goog[“close”].rolling(window = 20, center = False).mean(), 2)
goog = goog[‘2017-01-01’:]
pandas_candlestick_ohlc(goog, [‘ma5’,‘ma20’])
觀察上圖,我們發現5日均線與K線圖較為接近,而20日均線則更平坦,可見移動平均線具有抹平短期波動的作用,更能反映長期的走勢。比較5日均線和20日均線,特別是關註它們的交叉點,這些是交易的時機。移動平均線策略,最簡單的方式就是:當5日均線從下方超越20日均線時,買入股票,當5日均線從上方越到20日均線之下時,賣出股票。
為了找出交易的時機,我們計算5日均價和20日均價的差值,並取其正負號,作於下圖。當圖中水平線出現跳躍的時候就是交易時機。
goog[‘ma5-20’] = goog[‘ma5’] – goog[‘ma20’]
goog[‘diff’] = np.sign(goog[‘ma5-20’])
goog[‘diff’].plot(ylim=(–2,2)).axhline(y=0, color=‘black’, lw=2)
為了更方便觀察,上述計算得到的均價差值,再取其相鄰日期的差值,得到訊號指標。當訊號為1時,表示買入股票;當訊號為-1時,表示賣出股票;當訊號為0時,不進行任何操作。
goog[‘signal’] = np.sign(goog[‘diff’] – goog[‘diff’].shift(1))
goog[‘signal’].plot(ylim=(–2,2))
從上圖中看出,從今年初到現在,一共有兩輪買進和賣出的時機。到目前為止,似乎一切順利,那麼讓我們看下這兩輪交易的收益怎麼樣吧。
trade = pd.concat([
pd.DataFrame({“price”: goog.loc[goog[“signal”] == 1, “close”],
“operation”: “Buy”}),
pd.DataFrame({“price”: goog.loc[goog[“signal”] == –1, “close”],
“operation”: “Sell”})
])
trade.sort_index(inplace=True)
trade
上述表格列出了交易日期、操作和當天的價格。但很遺憾地發現,這兩輪交易的賣出價都小於買入價,實際上按上述方法交易我們虧本了!!!
你是否很憤怒呢?原來分析到現在,都是假的呀!我之前就警告過,這裡的分析只是演示移動平均線策略的思想,而並非真正的投資建議。股票市場是何其的複雜多變,又如何是一個小小的策略所能戰勝的呢?
那麼這個策略就一無是處嗎?非也!如果考慮更長的時間跨度,比如5年、10年,並考慮更長的均線,比如將20日均線和50日均線比較;雖然過程中也有虧損的時候,但贏的機率更大。也就是說,在更長的時間尺度上該策略也是可行的。但即使你賺了,又能跑贏大盤嗎?這時候還需用到其他方法,比如合理配置投資比例等。
還是那句話,股市有風險,投資需謹慎。本文不是分析股票的文章,而是借用股票資料來說明資料分析的基本方法,以及演示什麼樣的指標是好的指標。
參考資料:
-
An Introduction to Stock Market Data Analysis with Python (Part 1)
-
An Introduction to Stock Market Data Analysis with Python (Part 2)
-
K線理論
-
K線圖做圖示例
來源:魚心DrFish
www.jianshu.com/p/ce0e0773c6ec#
————廣告時間————
馬哥教育2018年Python自動化運維開發實戰面授班2018年3月5號開班,馬哥聯合BAT、豆瓣等一線網際網路Python開發達人,根據目前企業需求的Python開發人才進行了深度定製,加入了大量一線網際網路公司:大眾點評、餓了麼、騰訊等生產環境真是專案,課程由淺入深,從Python基礎到Python高階,讓你融匯貫通Python基礎理論,手把手教學讓你具備Python自動化開發需要的前端介面開發、Web框架、大監控系統、CMDB系統、認證堡壘機、自動化流程平臺六大實戰能力,讓你從0開始蛻變成Hold住年薪20萬的Python自動化開發人才。
掃描二維碼領取學習資料
更多Python好文請點選【閱讀原文】哦
↓↓↓