import matplotlib.pyplot as plt
from pandas import read_excel
import numpy as np
import tushare as ts
import pandas as pd
import datetime
token=''
pro=ts.pro_api(token)
獲取財務數據
#獲取財務數據
ticker_list = ['601318.SH','601336.SH','601398.SH','601888.SH','603993.SH']
for ticker in ticker_list:df = pro.daily_basic(ts_code = ticker,fields = 'ts_code,trade_date,total_mv,circ_mv,pe,pb')df1 = pro.daily(ts_code = ticker)df1.to_excel('stock_data/'+ticker + '.xlsx')df.to_excel('stock_data/'+ticker + '_basic.xlsx')
獲取股票價格數據
#獲取股票價格數據
ticker_list = ['601318.SH','601336.SH','601398.SH','601888.SH','603993.SH']
for ticker in ticker_list:df = pro.daily(ts_code = ticker)df.to_excel('stock_data/'+ticker + '.xlsx')
?設定股票池
#設定股票池
ticker_list = ['601318.SH','601336.SH','601398.SH','601888.SH','603993.SH']
#循環獲取股票價格和財務數據
for ticker in ticker_list:df1 = pd.read_excel('stock_data/'+ticker + '.xlsx',engine='openpyxl')df2 = pd.read_excel('stock_data/'+ticker + '_basic.xlsx',engine='openpyxl')df2 = df2[['trade_date','pe','pb','total_mv','circ_mv']]df3 = pd.merge(df1,df2,on='trade_date')df3.to_excel('stock_data/'+ticker + '.xlsx')
#設定空的DataFrame變量,存儲數據
StockPrices = pd.DataFrame()
#存儲每只股票的平均市值
market_value_list = []
ticker_list = ['601318.SH','601336.SH','601398.SH','601888.SH','603993.SH']
for ticker in ticker_list:df = read_excel('stock_data/'+ticker+'.xlsx',engine='openpyxl')#更改日期格式df['trade_date'] = df.trade_date.apply(lambda x:datetime.datetime.strptime(str(x),"%Y%m%d").strftime("%Y-%m-%d"))#按照日期升序排列。上小下大df =df.sort_values('trade_date',ascending=True)stock_data = df.set_index('trade_date')#print(stock_data.head())
# stock_data = stock_data.loc['2016-03-01':'2017-12-29']#print(stock_data.head())#獲取股票收盤價StockPrices[ticker] = stock_data['close']#print(StockPrices.head())#將市值存入列表market_value_list.append(stock_data['total_mv'].mean())#print(market_value_list[:5])
StockPrices.index.name= 'trade_date'
print(StockPrices.head())#計算每日收益率,并丟棄缺失值
StockReturns = StockPrices.pct_change().dropna()
#打印前5行數據
print(StockReturns.head())
計算加權收益
#將收益率數據拷貝到新的變量stock_return,這是為了后續調用的方便
stock_return = StockReturns.copy()
#print(stock_return.head())
#設置組合權重,存儲為numpy數據類型
portfolio_weights = np.array([0.32,0.15,0.10,0.18,0.25])
#計算加權的股票收益
WeightedReturns = stock_return.mul(portfolio_weights,axis=1)
#計算投資組合的收益
StockReturns['Portfolio'] = WeightedReturns.sum(axis=1)#print(StockReturns.head())
#繪制組合收益隨時間變化的圖
StockReturns.Portfolio.plot()
plt.show()
組合收益累計曲線
#定義累積收益曲線繪制函數
def cumulative_returns_plot(name_list):for name in name_list:CumlativeReturns = ((1+StockReturns[name]).cumprod()-1)CumlativeReturns.plot(label=name)plt.legend()plt.show()
#計算累積的組合收益,并繪圖
cumulative_returns_plot(['Portfolio'])
等權重收益曲線
#等權重的投資組合
#設置投資組合中的股票的數據
numstocks = 5
#平均分配每一項的權重
portfolio_weights_ew = np.repeat(1/numstocks,numstocks)
#計算等權重組合的收益
StockReturns['Portfolio_EW'] = stock_return.mul(portfolio_weights_ew,axis=1).sum(axis=1)
#打印前5行數據
print(StockReturns.head())
#繪制累計收益曲線
cumulative_returns_plot(['Portfolio','Portfolio_EW'])
市值加權
#市值加權的投資組合
#將上述獲得的每支股票的平均是指轉換為數組
market_values = np.array(market_value_list)
#計算市值權重
market_weights = market_values / np.sum(market_values)
#計算市值加權的組合收益
StockReturns['Portfolio_MVal'] = stock_return.mul(market_weights,axis=1).sum(axis=1)
#打印前5行數據
print(StockReturns.head())
#繪制累積收益曲線
cumulative_returns_plot(['Portfolio','Portfolio_EW','Portfolio_MVal'])
投資組合的相關性分析
#投資組合的相關矩陣
#相關矩陣用于估算多支股票收益之間的線性關系
#計算相關矩陣
correlation_matrix = stock_return.corr()
#輸出相關矩陣
print(correlation_matrix)
import seaborn as sns
#創建熱力圖
sns.heatmap(correlation_matrix,annot=True,cmap='rainbow',linewidths=1.0,annot_kws={'size':8})
plt.xticks(rotation=0)
plt.yticks(rotation=75)
plt.show()
#投資組合的協方差矩陣 #相關系數只反應了股票之間的線性關系,但并不能告訴我們股票的波動情況,而協方差矩陣則包含這一信息
#計算協方差矩陣
cov_mat = stock_return.cov()
#年化協方差矩陣
cov_mat_annual = cov_mat * 252
#輸出協方差矩陣
print(cov_mat_annual)
sns.heatmap(cov_mat_annual,annot=True,cmap='rainbow',linewidths=1.0,annot_kws={'size':8})
#投資組合的標準差
#計算投資組合的標準差
portfolio_volatility = np.sqrt(np.dot(portfolio_weights.T,np.dot(cov_mat_annual,portfolio_weights)))
print(portfolio_volatility)
#計算股票的最優投資組合
#使用蒙特卡洛模擬Markowitz模型
#設置模擬的次數
number = 10000
#設置空的numpy數組,用于存儲每次模擬得到的權重,收益率和標準差
random_p = np.empty((number,7))
#設置隨機數種子,這里是為了結果可重復
np.random.seed(7)#循環模擬10000次隨機的投資組合
for i in range(number):#生成5個隨機數,并歸一化,得到一組隨機的權重數據random5 = np.random.random(5)random_weight = random5/np.sum(random5)#計算年平均收益率mean_return = stock_return.mul(random_weight,axis=1).sum(axis=1).mean()annual_return = (1+mean_return)**252 -1#計算年化標準差,也成為波動率random_volatility = np.sqrt(np.dot(random_weight.T,np.dot(cov_mat_annual,random_weight)))#將上面生成的權重,和計算得到的收益率、標準差存入數據random_p中random_p[i][:5] =random_weightrandom_p[i][:5] = annual_returnrandom_p[i][6] = random_volatility#將Numpy數組轉化為DataF數據框
RandomPortfolios = pd.DataFrame(random_p)
#設置數據框RandomPortfolios每一列的名稱
RandomPortfolios.columns=[ticker + '_weight' for ticker in ticker_list]+['Returns','Volatility']#繪制散點圖
RandomPortfolios.plot('Volatility','Returns',kind='scatter',alpha=0.3)
plt.show()
#投資風險最小組合
#找到標準差最小數據的索引列
min_index = RandomPortfolios.Volatility.idxmin()#在收益-風險散點圖中突出風險最小的點
RandomPortfolios.plot('Volatility','Returns',kind= 'scatter',alpha = 0.3)
x = RandomPortfolios.loc[min_index,'Volatility']
y = RandomPortfolios.loc[min_index,'Returns']
plt.scatter(x,y,color='red')
#將該點坐標顯示在途中并保留四位小數
plt.text(np.round(x,4),np.round(y,4),(np.round(x,4),np.round(y,4)),ha= 'left',va='bottom',fontsize=10)
plt.show()
#提取足校波動組合對應的權重,并轉換成numpy數組
GMV_weights = np.array(RandomPortfolios.iloc[min_index,0:numstocks])
#計算GMV投資組合收益
StockReturns['Portfolio_GMV'] = stock_return.mul(GMV_weights,axis=1).sum(axis=1)
#輸出風險最小投資組合的權重
print(GMV_weights)
#投資風險最大組合
#找到標準差最大數據的索引列
max_index = RandomPortfolios.Volatility.idxmax()#在收益-風險散點圖中突出風險最小的點
RandomPortfolios.plot('Volatility','Returns',kind= 'scatter',alpha = 0.3)
x = RandomPortfolios.loc[max_index,'Volatility']
y = RandomPortfolios.loc[max_index,'Returns']
plt.scatter(x,y,color='red')
#將該點坐標顯示在途中并保留四位小數
plt.text(np.round(x,4),np.round(y,4),(np.round(x,4),np.round(y,4)),ha= 'left',va='bottom',fontsize=10)
plt.show()
#提取足校波動組合對應的權重,并轉換成numpy數組
GMV_weights = np.array(RandomPortfolios.iloc[max_index,0:numstocks])
#計算GMV投資組合收益
StockReturns['Portfolio_GMV'] = stock_return.mul(GMV_weights,axis=1).sum(axis=1)
#輸出風險最小投資組合的權重
print(GMV_weights)
#投資收益最小組合
#找到收益最小數據的索引列
min_index = RandomPortfolios.Returns.idxmin()#在收益-風險散點圖中突出風險最小的點
RandomPortfolios.plot('Volatility','Returns',kind= 'scatter',alpha = 0.3)
x = RandomPortfolios.loc[min_index,'Volatility']
y = RandomPortfolios.loc[min_index,'Returns']
plt.scatter(x,y,color='red')
#將該點坐標顯示在途中并保留四位小數
plt.text(np.round(x,4),np.round(y,4),(np.round(x,4),np.round(y,4)),ha= 'left',va='bottom',fontsize=10)
plt.show()
#提取足校波動組合對應的權重,并轉換成numpy數組
GMV_weights = np.array(RandomPortfolios.iloc[min_index,0:numstocks])
#計算GMV投資組合收益
StockReturns['Portfolio_GMV'] = stock_return.mul(GMV_weights,axis=1).sum(axis=1)
#輸出風險最小投資組合的權重
print(GMV_weights)
#投資收益最大組合
#找到收益最大數據的索引列
max_index = RandomPortfolios.Returns.idxmax()#在收益-風險散點圖中突出風險最小的點
RandomPortfolios.plot('Volatility','Returns',kind= 'scatter',alpha = 0.3)
x = RandomPortfolios.loc[max_index,'Volatility']
y = RandomPortfolios.loc[max_index,'Returns']
plt.scatter(x,y,color='red')
#將該點坐標顯示在途中并保留四位小數
plt.text(np.round(x,4),np.round(y,4),(np.round(x,4),np.round(y,4)),ha= 'left',va='bottom',fontsize=10)
plt.show()
#提取足校波動組合對應的權重,并轉換成numpy數組
GMV_weights = np.array(RandomPortfolios.iloc[max_index,0:numstocks])
#計算GMV投資組合收益
StockReturns['Portfolio_GMV'] = stock_return.mul(GMV_weights,axis=1).sum(axis=1)
#輸出風險最小投資組合的權重
print(GMV_weights)
#投資最優組合
#夏普最優組合的選擇
#設置無風險回報率為0.03
risk_free = 0.03
#計算每項資產的夏普比率
RandomPortfolios['Sharpe'] = (RandomPortfolios.Returns - risk_free) / RandomPortfolios.Volatility
#繪制收益-標準差的散點圖,并用顏色描繪夏普比率
plt.scatter(RandomPortfolios.Volatility,RandomPortfolios.Returns,c=RandomPortfolios.Sharpe)
plt.colorbar(label='Sharpe Ratio')
plt.show()
# 找到夏普比率最大數據對應的索引值
max_index = RandomPortfolios.Sharpe.idxmax()
# 在收益-風險散點圖中突出夏普比率最大的點
RandomPortfolios.plot('Volatility', 'Returns', kind='scatter', alpha=0.3)
x = RandomPortfolios.loc[max_index,'Volatility']
y = RandomPortfolios.loc[max_index,'Returns']
plt.scatter(x, y, color='red')
#將該點坐標顯示在圖中并保留四位小數
plt.text(np.round(x,4),np.round(y,4),(np.round(x,4),np.round(y,4)),ha='left',va='bottom',fontsize=10)
plt.show()# 提取最大夏普比率組合對應的權重,并轉化為numpy數組
MSR_weights = np.array(RandomPortfolios.iloc[max_index, 0:numstocks])
# 計算MSR組合的收益
StockReturns['Portfolio_MSR'] = stock_return.mul(MSR_weights, axis=1).sum(axis=1)
#輸出夏普比率最大的投資組合的權重
print(MSR_weights)
# 找到夏普比率最大數據對應的索引值
max_index = RandomPortfolios.Sharpe.idxmax()
# 在收益-夏普散點圖中突出夏普比率最大的點
RandomPortfolios.plot('Sharpe', 'Returns', kind='scatter', alpha=0.3)
x = RandomPortfolios.loc[max_index,'Sharpe']
y = RandomPortfolios.loc[max_index,'Returns']
plt.scatter(x, y, color='red')
#將該點坐標顯示在圖中并保留四位小數
plt.text(np.round(x,4),np.round(y,4),(np.round(x,4),np.round(y,4)),ha='left',va='bottom',fontsize=10)
plt.show()# 提取最大夏普比率組合對應的權重,并轉化為numpy數組
MSR_weights = np.array(RandomPortfolios.iloc[max_index, 0:numstocks])
# 計算MSR組合的收益
StockReturns['Portfolio_MSR'] = stock_return.mul(MSR_weights, axis=1).sum(axis=1)
#輸出夏普比率最大的投資組合的權重
print(MSR_weights)