摘要:先彙總相關股票價格,然後有選擇地對其分類,再計算移動均線、布林線等。
一、彙總資料
彙總整個交易週中從週一到週五的所有資料(包括日期、開盤價、最高價、最低價、收盤價,成交量等),由於我們的資料是從2020年8月24日開始匯出,資料多達420條,先擷取部分時間段的資料,不妨先讀取開始20個交易日的價格。程式碼如下:
import numpy as np from datetime import datetime def datestr2num(s): #定義一個函式 return datetime.strptime(s.decode('ascii'),"%Y-%m-%d").date().weekday() #decode('ascii') 將字串s轉化為ascii碼 #讀取csv檔案 ,將日期、開盤價、最低價、最高價、收盤價、成交量等全部讀取 dates, opens, high, low, close,vol=np.loadtxt('data.csv',delimiter=',', usecols=(1,2,3,4,5,6),converters={1:datestr2num},unpack=True) #按順序對應好data.csv與usecols=(1,2,3,4,5,6)中的列
#獲取20個交易日的資料
closes = close[0:20] #實際存取下標是0-19
dateslist = dates[0:20]
print(closes) #列印出closes數列
print(dateslist)
這樣就把data.csv中對應的日期、開盤價、最高價、最低價、收盤價,成交量等分別存入到dates, opens, high, low, close,vol中。由於後面示例只統計20個交易日資料,所以closes = close[0:20] ,即擷取close中前20個資料。
執行結果:
[37.5 37.58 37.23 36.9 38.45 37.69 37.42 37.2 36.98 36.8 36.79 37.59 37.6 37.7 37.24 37.35 37.9 38.06 37.87 38.99]
[0. 1. 2. 3. 4. 0. 1. 2. 3. 4. 0. 1. 2. 3. 4. 0. 1. 2. 3. 4.]
即20個交易日的收盤價和所屬的星期(0表示週一、4表示週五)。
分別看一下最開始週一的下標和最後一個週五的下標
first_monday = np.ravel(np.where(dateslist == 0))[0] print ("The first Monday index is", first_monday) #返回最後一個週五的位置 last_friday = np.ravel(np.where(dateslist == 4))[-1] print ("The last Friday index is", last_friday) print('\n')
執行結果:
The first Monday index is 0 The last Friday index is 19
定義一個陣列,用於儲存20個交易日的索引值
weeks_indices = np.arange(first_monday, last_friday+1) print ("Weeks indices initial", weeks_indices)
按5個交易日,分成4周,對20個交易日分成4周:
weeks_indices = np.split(weeks_indices,4) print("Weeks indices after split", weeks_indices)
Weeks indices initial [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19]
Weeks indices after split [array([0, 1, 2, 3, 4], dtype=int64), array([5, 6, 7, 8, 9], dtype=int64), array([10, 11, 12, 13, 14], dtype=int64), array([15, 16, 17, 18, 19], dtype=int64)]
NumPy中,陣列的維度也被稱作軸。apply_along_axis 函式會呼叫另外一個由我們給出的函式,作用於每一個陣列元素上,陣列中有4個元素,分別對應於示例資料中的4個星期,元素中的索引值對應於示例資料中的1天。在呼叫apply_along_axis 時提供我們自定義的函式名summarize,並指定要作用的軸或維度的編號(如取1)、目標陣列以及可變數量的summarize函式的引數,同時進行儲存。
# 定義一個函式,該函式將為每一週的資料返回一個元組,包含這一週的開盤價、最高價、最低價和收盤價,類似於每天的盤後資料
def summarize(a, o, h, l, c):
monday_open = o[a[0]] #週一開盤價
week_high = np.max( np.take(h, a) ) # 某周最高價 week_low = np.min( np.take(l, a) ) # 某周最低價 friday_close = c[a[-1]] #某周的收盤價 return("招商銀行", monday_open, week_high, week_low, friday_close) #返回某周開盤、最高、低價、收盤價 weeksummary = np.apply_along_axis(summarize, 1, weeks_indices,opens, high, low, close) print ("Week summary", weeksummary) np.savetxt("weeksummary.csv", weeksummary, delimiter=",", fmt="%s")
實際執行如下:
二、均線
1、波動幅度均值(ATR)
ATR(Average True Range,真實波動幅度均值)是一個用來衡量股價波動性的技術指標。ATR是基於N個交易日的最高價和最低價進行計算的,通常取最近20個交易日。
(1) 前一個交易日的收盤價。 previousclose = c[-N -1: -1]
對於每一個交易日,計算以下各項。
h – l 當日最高價和最低價之差。 h – previousclose 當日最高價和前一個交易日收盤價之差。 previousclose – l 前一個交易日收盤價和當日最低價之差。
(2) 用NumPy中的 maximum 函式返回上述三個中的最大值。 truerange = np.maximum(h - l, h - previousclose, previousclose - l)
(3) 建立一個長度為 N 的陣列 atr ,並初始化陣列元素為0。atr = np.zeros(N)
(4) 這個陣列的首個元素就是 truerange 陣列元素的平均值。atr[0] = np.mean(truerange)
5)計算出每個交易日的波動幅度:
for i in range(1, N):
atr[i] = (N - 1) * atr[i - 1] + truerange[i]
atr[i] /= N
示例程式碼如下:
import numpy as np from datetime import datetime def datestr2num(s): #定義一個函式 return datetime.strptime(s.decode('ascii'),"%Y-%m-%d").date().weekday() dates, opens, high, low, close,vol=np.loadtxt('data.csv',delimiter=',', usecols=(1,2,3,4,5,6), converters={1:datestr2num},unpack=True) closes = close[0:20] #實際存取下標是0-19 dateslist = dates[0:20] first_monday = np.ravel(np.where(dateslist == 0))[0] last_friday = np.ravel(np.where(dateslist == 4))[-1]#從最後一個位置開始 weeks_indices = np.split(np.arange(first_monday, last_friday+1),4) #波動幅度均值(ATR) N = 20 h = high[-N:] l = low[-N:] print ("len(high)", len(h), "len(low)", len(l)) #print ("Close", close) #前一日的收盤價數列 previousclose = close[-N-1: -1] print ("len(previousclose)", len(previousclose)) print ("Previous close", previousclose) #用NumPy中的maximum函式,在 最高-最低,最高-昨日收盤,昨日收盤 三個資料選擇最大 truerange = np.maximum(h-l,h-previousclose,previousclose) print ("True range", truerange) atr = np.zeros(N) # 建立一個長度為 N 的陣列 atr ,並初始化陣列元素為0 atr[0] = np.mean(truerange) # 陣列的首個元素設定為truerange陣列元素的平均值 for i in range(1, N): #迴圈,計算每個交易日的波幅,並儲存 atr[i] = (N - 1) * atr[i - 1] + truerange[i] atr[i] /= N print ("ATR", atr)
執行結果:
len(high) 20 len(low) 20 len(previousclose) 20 Previous close [42.1 41.1 41.28 42.5 38.83 38.41 38.04 39.62 39.93 39.26 37.91 36.47 36.98 37.21 36.61 37.15 36.89 38.6 38.5 38.03] True range [1.08 1.5 2.32 2.23 1.56 1.02 2.13 1.49 1.16 0.85 1.67 1.9 0.96 0.63 0.99 0.69 1.74 1.18 0.73 2.15] ATR [1.399 1.40405 1.4498475 1.48885513 1.49241237 1.46879175 1.50185216 1.50125955 1.48419658 1.45248675 1.46336241
1.48519429 1.45893458 1.41748785 1.39611345 1.36080778 1.37976739 1.36977902 1.33779007 1.37840057]
2、移動均線:股市中最常見的是指標,移動平均線只需要少量的迴圈和均值函式即可計算得出。簡單移動平均線是計算與等權重的指示函式的卷積。
簡單移動平均線(simple moving average)通常用於分析時間序列上的資料。我們按照時間序列,並N個週期資料的均值。
(1) 使用 ones 函式建立一個長度為 N 的元素均初始化為1的陣列,然後對整個陣列除以 N ,即可得到權重,比如 5日均線,即N=5,則平均每天的權重都為0.2.
N = 5 weights = np.ones(N) / N print ("Weights", weights)
(2)使用 convolve 函式呼叫上述的權重值
sma = np.convolve(weights, c)[N-1:-N+1]
從 convolve 函式返回的陣列中,取出中間的長度為N的部分,下面的程式碼將建立 一個儲存時間值的陣列
N = 5 weights = np.ones(N) / N print ("Weights", weights) sma = np.convolve(weights, close)[N-1:-N+1] print(sma) print(len(sma))
執行結果如下,可以看到,匯出的420個資料,通過計算,得到的均線陣列有416個。
很明顯sma是一個數列,用前期matplotlib中的函式,可以繪製畫面,增加如下程式碼:
import matplotlib.pyplot as plt #省略上述程式碼 plt.plot(sma, linewidth=5)
執行結果如下:
3、指數移動平均線
指數移動平均線(exponential moving average)是另一種技術指標。指數移動平均線使用的權重是指數衰減的。對歷史資料點賦予的權重以指數速度減小,但不會到達0。在計算權重的過程中使用 exp 和 linspace 函式。
1)先了解numpy中的exp 和 linspace 函式
x = np.arange(5) y = np.arange(10) print ("Exp", np.exp(x)) # exp 函式可以計算出每個陣列元素的指數 print ("Exp", np.exp(y))
執行結果:
ExpX [ 1. 2.71828183 7.3890561 20.08553692 54.59815003]
ExpY [1.00000000e+00 2.71828183e+00 7.38905610e+00 2.00855369e+01 5.45981500e+01 1.48413159e+02 4.03428793e+02 1.09663316e+03 2.98095799e+03 8.10308393e+03]
可以看出,exp()函式接受一個數列,計算出每個陣列元素的指數。
print( "Linspace", np.linspace(-1, 0, 5))
執行結果:
Linspace [-1. -0.75 -0.5 -0.25 0. ]
linspace中有三個引數,其中前2個是一個範圍:一個起始值和一個終止值引數,後一個是生成的陣列元素的個數。
2)計算指數移動平均線
利用上述兩個函式對權重進行計算:weights = np.exp(np.linspace(-1. , 0. , N))
全部程式碼如下:
import numpy as np from datetime import datetime import matplotlib.pyplot as plt from matplotlib.pyplot import show def datestr2num(s): #定義一個函式 return datetime.strptime(s.decode('ascii'),"%Y-%m-%d").date().weekday() dates, opens, high, low, close,vol=np.loadtxt('data.csv',delimiter=',', usecols=(1,2,3,4,5,6), converters={1:datestr2num},unpack=True) N = 5 """ weights = np.ones(N) / N print ("Weights", weights) sma = np.convolve(weights, close)[N-1:-N+1] print(sma) print(len(sma)) plt.plot(sma, linewidth=5) """ weights = np.exp(np.linspace(-1., 0., N)) # weights /= weights.sum() #對權重值做歸一化處理 print( "Weights", weights) ema = np.convolve(weights, close)[N-1:-N+1] #print(ema) t = np.arange(N - 1, len(close)) plt.plot (t, close[N-1:], lw=1.0) #收盤價繪製曲線圖 plt.plot (t, ema, lw=2.0) #按權重計算均線曲線圖 show()
執行結果: