玩轉Python量化金融工具之NumPy
一切事物的開頭總是困難這句話,在任何一種科學上都是適用的。 —— 馬克思
前言
“手把手教你”系列將為Python初學者一一介紹Python在量化金融中運用最廣泛的幾個庫(Library): NumPy(數組、線性代數)、SciPy(統計)、pandas(時間序列、數據分析)、matplotlib(可視化分析)。建議安裝Anaconda軟件(自帶上述常見庫),并使用Jupyter Notebook交互學習。
1、使用“import”命令導入numpy庫
import?numpy?as?np
2、生成數組,使用命令np.array(),括號里的數據類型為系列(list)
?
a=[1,2,3,4,5,6,7,8]?????????????#a是系列(list)
b=np.array(a)???????????#b是數組
print(a,b)??????????????#打印a和b
print(type(a),type(b))??#查看a和b的類型
?
[1,?2,?3,?4,?5,?6,?7,?8]?[1?2?3?4?5?6?7?8]
對數組進行操作:
?
b=b.reshape(2,4)??????#改變數組的維度
print(b)??????????????#從原來的1x8變成2x4?(兩行四列)
#元素訪問
print("取第1行第2列元素:",b[1][2])??#注意是從0行0列開始數!!!
?
[[1?2?3?4]
?[5?6?7?8]]
取第1行第2列元素:?7
變成三維數組:
?
c=b.reshape(2,2,2)
print(c)
?
[[[1?2]
??[3?4]]
?[[5?6]
??[7?8]]]
特殊的數組有特別定制的命令生成,如零和1矩陣:
?
d=(3,4)
print(np.zeros(d))??????????#零矩陣
print(np.ones(d))
#默認生成的類型是浮點型,可以通過指定類型改為整型
print(np.ones(d,dtype=int))
?
[[?0.??0.??0.??0.]
?[?0.??0.??0.??0.]
?[?0.??0.??0.??0.]]
[[?1.??1.??1.??1.]
?[?1.??1.??1.??1.]
?[?1.??1.??1.??1.]]
[[1?1?1?1]
?[1?1?1?1]
?[1?1?1?1]]
3、常用函數
arange指定范圍和數值間的間隔生成 array,注意范圍包左不包右
注意:系統自帶的range生成的是tupe,要產生list需要使用循環取出元素
?
#使用range產生list
L=[i?for?i?in?a]
print(L)
?
[1,?2,?3,?4,?5,?6,?7,?8]
?
b=np.arange(10)?????#注意包含0,不包含10
c=np.arange(0,10,2)?#2表示間隔
d=np.arange(1,10,3)?#3表示間隔
print(b,c,d)
?
[0?1?2?3?4?5?6?7?8?9]?[0?2?4?6?8]?[1?4?7]
金融分析常常需要產生隨機數,Numpy的random函數派上用場。
均勻分布:
?
a=np.random.rand(3,4)??????#創建指定為3行4列)的數組(范圍在0至1之間)
b=np.random.uniform(0,100)?#創建指定范圍內的一個數
c=np.random.randint(0,100)?#創建指定范圍內的一個整數
print("創建指定為3行4列)的數組:\n",a)???#\n?表示換行
print("創建指定范圍內的一個數:%.2f"?%b)?#%.2f?表示結果保留2位小數
print("創建指定范圍內的一個整數:",c)
?
創建指定為3行4列)的數組:
?[[?0.41381256??0.92295862??0.93350059??0.78374808]
?[?0.71077228??0.27084757??0.50303507??0.46643957]
?[?0.39789158??0.93730999??0.24616428??0.43307303]]
創建指定范圍內的一個數:66.05
創建指定范圍內的一個整數:?77
正態分布
給定均值/標準差/維度的正態分布np.random.normal(u, r, (x, y)) 數組的索引
?
#正態生成3行4列的二維數組
a=?np.random.normal(1.5,?3,?(3,?4))??#均值為1.5,標準差為3
print(a)
#?截取第1至2行的第2至3列(從第0行、0列算起算起)
b?=?a[1:3,?2:4]
print("截取第1至2行的第2至3列:?\n",b)
?
[[-0.77790783??7.09340234??3.46848684??3.13337912]
?[-1.98384413??4.14324286??3.98562892??3.58336292]
?[-0.80908369?-0.23560019?-0.67037947??2.25007073]]
截取第1至2行的第2至3列:?
?[[?3.98562892??3.58336292]
?[-0.67037947??2.25007073]]
4、數組ndarray 運算
元素之間依次相加、減、乘、除;統計運算
?
a?=?np.array([1,2,3,4])?#1行4列
b?=?np.array(2)?????????#只有一個元素
a?-?b,a+b
?
(array([-1,??0,??1,??2]),?array([3,?4,?5,?6]))
?
python的次方使用**實現:
?
??File?"
????python的次方使用**實現:
???????????????????^
SyntaxError:?invalid?character?in?identifier
?
a**2??#二次方,a里元素的平方
?
array([?1,??4,??9,?16],?dtype=int32)
?
np.sqrt(a)??#開根號
?
array([?1.????????,??1.41421356,??1.73205081,??2.????????])
?
np.exp(a)??#e?求方
?
array([??2.71828183,???7.3890561?,??20.08553692,??54.59815003])
?
np.floor(10*np.random.random((2,2)))?#向下取整
?
array([[?1.,??8.],
???????[?6.,??5.]])
?
a.resize(2,2)?#變換結構
a
?
array([[1,?2],
???????[3,?4]])
統計運算:
需要知道二維數組的最大最小值怎么辦?想計算全部元素的和、按行求和、按列求和怎么辦?NumPy的ndarray類已經做好函數了
?
a=np.arange(20).reshape(4,5)
print("原數組a:\n",a)
print("a全部元素和:?",?a.sum())
print("a的最大值:?",?a.max())
print("a的最小值:?",?a.min())
print("a每行的最大值:?",?a.max(axis=1))??#axis=1代表行
print("a每列的最大值:?",?a.min(axis=0))??#axis=0代表列
print("a每行元素的求和:?",?a.sum(axis=1))?
print("a每行元素的均值:",np.mean(a,axis=1))
print("a每行元素的標準差:",np.std(a,axis=1))
?
原數組a:
?[[?0??1??2??3??4]
?[?5??6??7??8??9]
?[10?11?12?13?14]
?[15?16?17?18?19]]
a全部元素和:??190
a的最大值:??19
a的最小值:??0
a每行的最大值:??[?4??9?14?19]
a每列的最大值:??[0?1?2?3?4]
a每行元素的求和:??[10?35?60?85]
a每行元素的均值:?[??2.???7.??12.??17.]
a每行元素的標準差:?[?1.41421356??1.41421356??1.41421356??1.41421356]
5、矩陣及其運算
?
A?=?np.array([[0,1],?[1,2]])??#數組
B?=?np.array([[2,5],[3,4]])???#數組
print("對應元素相乘:\n",A*B)
print("矩陣點乘:\n",A.dot(B))
print("矩陣點乘:\n",np.dot(A,B))??#(M行,?N列)?*?(N行,?Z列)?=?(M行,?Z列)
print("橫向相加:\n",np.hstack((A,B)))
print("縱向相加:\n",np.vstack((A,B)))
?
對應元素相乘:
?[[0?5]
?[3?8]]
矩陣點乘:
?[[?3??4]
?[?8?13]]
矩陣點乘:
?[[?3??4]
?[?8?13]]
橫向相加:
?[[0?1?2?5]
?[1?2?3?4]]
縱向相加:
?[[0?1]
?[1?2]
?[2?5]
?[3?4]]
數組可以通過asmatrix或者mat轉換為矩陣,或者直接生成也可以
?
A=np.arange(6).reshape(2,3)
A=np.asmatrix(A)????????????????????????#將數組轉化成矩陣
print?(A)
B=np.matrix('1.0?2.0?3.0;4.0?5.0?6.0')??#直接生成矩陣
print(B)
?
[[0?1?2]
?[3?4?5]]
[[?1.??2.??3.]
?[?4.??5.??6.]]
?
A*B.T????#A和B已經是矩陣了,但A的列要與B的行相等才能相乘,對B進行轉置(B.T)
?
matrix([[??8.,??17.],
????????[?26.,??62.]])
線性代數運算
矩陣求逆:
?
import?numpy.linalg?as?nlg??#線性代數函數
import?numpy?as?np
a=np.random.rand(2,2)
a=np.mat(a)
print(a)
ia=nlg.inv(a)
print("a的逆:\n",ia)
?
[[?0.05263888??0.6813566?]
?[?0.81685383??0.02770063]]
a的逆:
?[[-0.04990111??1.22742491]
?[?1.47151541?-0.09482594]]
求特征值和特征向量
?
a=np.array([2,4,3,9,1,4,3,4,2]).reshape(3,3)??
eig_value,eig_vector=nlg.eig(a)
print("特征值:",eig_value)
print("特征向量:",eig_vector)
?
特征值:?[?10.48331477??-4.48331477??-1.????????]
特征向量:?[[-0.50772731?-0.36224208?-0.28571429]
?[-0.69600716??0.85881392?-0.42857143]
?[-0.50772731?-0.36224208??0.85714286]]
實例分析:假設股票收益率服從正態分布,使用numpy產生正態分布隨機數,模擬股票收益率,并采用正態分布策略進行交易。
假設有2000只股票,一年股市共250個交易日。一年365天-全民法定節假日=365-每周雙休日*52-節日放假日 ?(國慶3天+春節3天+勞動節、元旦、清明、端午、中秋共11天)=365-104-11=250日,產生2000x500的數組。
?
stocks?=?2000???#?2000支股票
days?=??500??#?兩年大約500個交易日
#?生成服從正態分布:均值期望=0,標準差=1的序列
stock_day?=?np.random.standard_normal((stocks,?days))???
print(stock_day.shape)???#打印數據組結構
#?打印出前五只股票,頭五個交易日的漲跌幅情況
print(stock_day[0:5,?:5])
?
(2000,?500)
[[-0.07551455??0.29357958?-0.30444034??1.92766721?-0.23077118]
?[-0.10149728?-0.66709552??1.53380182?-0.27389357?-0.96988518]
?[?0.53005545??1.12241132??0.49236533?-0.67694298??0.67307296]
?[-0.199584????0.47197832?-0.25854041??0.16278091??0.68747893]
?[-0.74029997??0.25514721?-0.69150807?-1.9827364??-0.49419039]]
正態分布買入策略:
?
#?保留后250天的隨機數據作為策略驗證數據
keep_days?=?250
#?統計前450,?切片切出0-250day,days?=?500
stock_day_train?=?stock_day[:,0:days?-?keep_days]
#?打印出前250天跌幅最大的三支,總跌幅通過np.sum計算,np.sort對結果排序
print(np.sort(np.sum(stock_day_train,?axis=1))[:3])
#?使用np.argsort針對股票跌幅進行排序,返回序號,即符合買入條件的股票序號
stock_lower?=?np.argsort(np.sum(stock_day_train,?axis=1))[:3]
#?輸出符合買入條件的股票序號
stock_lower
?
[-48.47837792?-47.2409051??-46.15811624]
array([1348,?1376,?1325],?dtype=int64)
封裝函數plot_buy_lower()可視化選中的前3只跌幅最大的股票前450走勢以及從第454日買入后的走勢
?
import?matplotlib.pyplot?as?plt??#引入畫圖庫
%matplotlib?inline???????????????
#python定義函數使用def?函數名:然后enter
def?buy_lower(stock):
????#設置一個一行兩列的可視化圖表
????_,?axs=plt.subplots(nrows=1,ncols=2,figsize=(16,5))
????#繪制前450天的股票走勢圖,np.cumsum():序列連續求和
????axs[0].plot(np.arange(0,days-keep_days),
???????????????stock_day_train[stock].cumsum())
????#從第250天開始到500天的股票走勢
????buy=stock_day[stock][days-keep_days:days].cumsum()
????#繪制從第450天到500天中股票的走勢圖
????axs[1].plot(np.arange(days-keep_days,days),buy)
????#返回從第450天開始到第500天計算盈虧的盈虧序列的最后一個值
????return?buy[-1]
?
#假設等權重地買入3只股票
profit=0??#盈虧比例
#遍歷跌幅最大的3只股票序列序號序列
for?stock?in?stock_lower:
????#profit即三只股票從第250天買入開始計算,直到最后一天的盈虧比例
????profit+=buy_lower(stock)
????print("買入第{}只股票,從第250個交易日開始持有盈虧:{:.2f}%".format(stock,profit))
?
買入第1348只股票,從第250個交易日開始持有盈虧:32.69%
買入第1376只股票,從第250個交易日開始持有盈虧:15.69%
買入第1325只股票,從第250個交易日開始持有盈虧:16.40%
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

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