2019年8月17日 星期六

[投資組合] 美股ETF投資組合優化

原文: https://github.com/tthustla/efficient_frontier/blob/master/Efficient%20_Frontier_implementation.ipynb

優化函數: https://blog.csdn.net/qcyfred/article/details/77115739

Modern Portfolio Theory

根據1952年由Harry Markowitz發表的投資組合理論Modern Portfolio Theory (MPT)建立投資組合.天下沒有白吃的午餐,"There Ain't No Such Thing As A Free Lunch".追求報酬率越高的商品必須付出越大的風險.但若兩個商品的投資報酬率相同,但風險有差異,投資人會選擇風險較低的商品.以美股ETF為例,VTI(美股)和VB(美國小型股)的年化投資報酬率相同,大約都是9%,但VB的年化波動率為23%,而VTI的年化波動率為20%,因此投資人傾向選擇VTI.
配置投資組合的目的是在組合出一組雞尾酒ETF,他的波動率比相同年化率的單一商品還要低.因為個別投資商品之間的相關係數有所差異,若投資組合中搭配相關係數掉低的商品,則可以讓投資組合的波動率降低,但是長期的年化報酬率卻保持一樣.
我們將利用pandas_datareader讀取美股ETF歷史資料:

股票型

世界指數 Vanguard Total World Stock Inde (VT) 年配息 平均年化報酬率: 10.47% 年化配息率: 2.41%
美股 Vanguard Total Stock Market ETF (VTI) 年配息 平均年化報酬率: 9.44% 年化配息率: 2%
美國以外的已開發市場 Vanguard FTSE Developed Markets(VEA) 年配息 平均年化報酬率: 2.52% 年化配息率: 2.92%
美國小型股 Small Cap ETF (VB) 年配息 平均年化報酬率: 9.66% 年化配息率: 1.54
新興市場 Emerging Markets ETF (VWO) 平均年化報酬率: 10.12% 年化配息率: 2.45

原物料

黃金 SPDR Gold Trust(GLD) 平均年化報酬率: 9.86% 

債卷型

全球債卷 Vanguard Total Bond Market ETF (BND) 月配息 平均年化報酬率: 3.77% 年化配息率: 3.1%
REITs Vanguard Real Estate ETF (VNQ) 年配息 平均年化報酬率: 9.2% 年化配息率: 3.1%
長期債券 Vanguard Long-Term Bond ETF(BLV) 月配息 平均年化報酬率: 6.5% 年化配息率: 4.6%
可轉債 Bloomberg Barclays Convertible Securities ETF(CWB) 年配息 平均年化報酬率: 3.75% 年化配息率: 4.6%
高收益債 High Yield Corporate Bond ETF (HYG) 年配息 平均年化報酬率:7.8% 年化配息率: 5.9%
新興市場債 Vanguard Emerging Markets Government Bond ETF (VWOB) 月配息 平均年化報酬率: 3.22% 年化配息率: 4.29%
美國政府中期債 iShares 3-7 Year Treasury Bond ETF (IEI) 年配息 平均年化報酬率: 2.91%, 年化配息率: 1.61%

以下我們將用兩種不同的方法(隨機亂數法, 函數優化法)找出3種投資組合分別是適用於積極型, 穩健型, 和保守型投資人

積極型:投資報酬率最高的投資組合
穩健型:夏普值最大的投資組合
保守型:風險最低的投資組合
In [1]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import pandas_datareader as web
import scipy.optimize as sco
import seaborn as sns

In [2]:
symbols = ['VT','VTI','VEA','VB','VWO','GLD','BND','VNQ','BLV','HYG','VWOB','IEI']
num_symbols = len(symbols)

In [3]:
price_data = web.get_data_yahoo(symbols,start = '2008-08-16',end = '2019-08-15')
table = price_data.Close
plt.figure(figsize=(14, 7))
for c in table.columns.values:
    plt.plot(table.index, table[c], lw=3, alpha=0.8,label=c)
plt.legend(loc='upper left', fontsize=12)
plt.ylabel('price in $')

/Users/laihunglai/anaconda3/envs/py35/lib/python3.5/site-packages/pandas/plotting/_converter.py:129: FutureWarning: Using an implicitly registered datetime converter for a matplotlib plotting method. The converter was registered by pandas on import. Future versions of pandas will require you to explicitly register matplotlib converters.

To register the converters:
>>> from pandas.plotting import register_matplotlib_converters
>>> register_matplotlib_converters()
  warnings.warn(msg, FutureWarning)

Out[3]:
Text(0,0.5,'price in $')
In [4]:
# 計算變化百分比 看波動率
returns = table.pct_change()

plt.figure(figsize=(14, 7))
for c in returns.columns.values:
    plt.plot(returns.index, returns[c], lw=3, alpha=0.8,label=c)
plt.legend(loc='upper right', fontsize=12)
plt.ylabel('daily returns')

Out[4]:
Text(0,0.5,'daily returns')

隨機亂數法找投資組合

In [5]:
#計算一年的回報率(return)和波動率(volatility),取252天為一年
def portfolio_annualised_performance(weights, mean_returns, cov_matrix):
    returns = np.sum(mean_returns*weights ) *252
    std = np.sqrt(np.dot(weights.T, np.dot(cov_matrix, weights))) * np.sqrt(252)
    return std, returns

In [6]:
# 對每個投資商品產生隨機的權重
def random_portfolios(num_portfolios, mean_returns, cov_matrix, risk_free_rate):
    results = np.zeros((3,num_portfolios))
    weights_record = []
    for i in range(num_portfolios):
        weights = np.random.random(num_symbols)
        weights /= np.sum(weights)
        weights_record.append(weights)
        portfolio_std_dev, portfolio_return = portfolio_annualised_performance(weights, mean_returns, cov_matrix)
        results[0,i] = portfolio_std_dev
        results[1,i] = portfolio_return
        #計算sharp值:(投資組合報酬率-無風險報酬率)/投資組合std
        results[2,i] = (portfolio_return - risk_free_rate) / portfolio_std_dev
    return results, weights_record

In [7]:
returns = table.pct_change()
mean_returns = returns.mean()
cov_matrix = returns.cov()
num_portfolios = 50000  #產生多少了亂數的投資組合
risk_free_rate = 0.0178

In [8]:
def display_simulated_ef_with_random(mean_returns, cov_matrix, num_portfolios, risk_free_rate):
    results, weights = random_portfolios(num_portfolios,mean_returns, cov_matrix, risk_free_rate)
    #找出sharp值最大的投資組合
    max_sharpe_idx = np.argmax(results[2])
    sdp, rp = results[0,max_sharpe_idx], results[1,max_sharpe_idx]
    max_sharpe_allocation = pd.DataFrame(weights[max_sharpe_idx],index=table.columns,columns=['allocation'])
    max_sharpe_allocation.allocation = [round(i*100,2)for i in max_sharpe_allocation.allocation]
    max_sharpe_allocation = max_sharpe_allocation.T
    
    #找出報酬率最高的投資組合
    max_ret_idx = np.argmax(results[1])
    sdp_max, rp_max = results[0,max_ret_idx], results[1,max_ret_idx]
    max_ret_allocation = pd.DataFrame(weights[max_ret_idx],index=table.columns,columns=['allocation'])
    max_ret_allocation.allocation = [round(i*100,2)for i in max_ret_allocation.allocation]
    max_ret_allocation = max_ret_allocation.T
    
    #找出波動率最低的投資組合
    min_vol_idx = np.argmin(results[0])
    sdp_min, rp_min = results[0,min_vol_idx], results[1,min_vol_idx]
    min_vol_allocation = pd.DataFrame(weights[min_vol_idx],index=table.columns,columns=['allocation'])
    min_vol_allocation.allocation = [round(i*100,2)for i in min_vol_allocation.allocation]
    min_vol_allocation = min_vol_allocation.T
    
    print ("."*80)
    print ("Maximum Sharpe Ratio Portfolio Allocation\n")
    print ("Annualised Return:", round(rp,2))
    print ("Annualised Volatility:", round(sdp,2))
    print ("\n")
    print (max_ret_allocation)
    #畫出pie圖
    max_sharpe_record=max_sharpe_allocation[max_sharpe_allocation>0]
    max_sharpe_record.T.plot.pie(y='allocation', figsize=(5, 5), autopct='%1.0f%%')
    title='夏普值最高 年報酬:'+str(np.round(rp,2))+'  風險:'+str(np.round(sdp,2))
    plt.title(title, fontproperties="PMingLiU", fontsize=20)
    plt.show()
    print ("."*80)
    print ("Maximum Return Portfolio Allocation\n")
    print ("Annualised Return:", round(rp_max,2))
    print ("Annualised Volatility:", round(sdp_max,2))
    print ("\n")
    print (max_sharpe_allocation)
    #畫出pie圖
    max_return_record=max_ret_allocation[max_ret_allocation>0]
    max_return_record.T.plot.pie(y='allocation', figsize=(5, 5), autopct='%1.0f%%')
    title='報酬最高 年報酬:'+str(np.round(rp_max,2))+'  風險:'+str(np.round(sdp_max,2))
    plt.title(title, fontproperties="PMingLiU", fontsize=20)
    plt.show() 
    print ("."*80)
    print ("Minimum Volatility Portfolio Allocation\n")
    print ("Annualised Return:", round(rp_min,2))
    print ("Annualised Volatility:", round(sdp_min,2))
    print ("\n")
    print (min_vol_allocation)
    #畫出pie圖
    min_vol_record=min_vol_allocation[min_vol_allocation>0]
    min_vol_record.T.plot.pie(y='allocation', figsize=(5, 5), autopct='%1.0f%%')
    title='風險最低 年報酬:'+str(np.round(rp_min,2))+'  風險:'+str(np.round(sdp_min,2))
    plt.title(title, fontproperties="PMingLiU", fontsize=20)
    plt.show()
    plt.figure(figsize=(10, 7))
    plt.scatter(results[0,:],results[1,:],c=results[2,:],cmap='YlGnBu', marker='o', s=10, alpha=0.3)
    plt.colorbar()
    plt.scatter(sdp,rp,marker='*',color='r',s=500, label='Maximum Sharpe ratio')
    plt.scatter(sdp_max,rp_max,marker='*',color='b',s=500, label='Maximum Return')
    plt.scatter(sdp_min,rp_min,marker='*',color='g',s=500, label='Minimum volatility')
    plt.title('Simulated Portfolio Optimization based on Efficient Frontier')
    plt.xlabel('annualised volatility')
    plt.ylabel('annualised returns')
    plt.legend(labelspacing=0.8)

In [9]:
display_simulated_ef_with_random(mean_returns, cov_matrix, num_portfolios, risk_free_rate)

................................................................................
Maximum Sharpe Ratio Portfolio Allocation

Annualised Return: 0.05
Annualised Volatility: 0.08


Symbols      BLV BND GLD   HYG IEI VB VEA  VNQ VT VTI VWO \
allocation  1.56 5.85 24.66  2.35 0.27 19.76 8.09  3.3 3.3 23.93 6.33   

Symbols     VWOB  
allocation  0.61  

................................................................................
Maximum Return Portfolio Allocation

Annualised Return: 0.07
Annualised Volatility: 0.15


Symbols       BLV BND GLD   HYG IEI VB VEA   VNQ VT VTI \
allocation  28.99 10.35  9.13 0.34 2.01  11.88 2.14 2.22 0.12  18.52   

Symbols     VWO VWOB  
allocation  2.1 12.21  

................................................................................
Minimum Volatility Portfolio Allocation

Annualised Return: 0.03
Annualised Volatility: 0.05


Symbols       BLV BND GLD   HYG IEI VB VEA   VNQ VT VTI \
allocation  18.77 15.47  6.75 6.72 18.1  3.21 0.13 0.51 1.35  10.98   

Symbols      VWO VWOB  
allocation  0.26 17.76  

函數優化法找投資組合

用scipy.optimize找出優化的投資組合, 找出給定目標報酬率下風險最低的投資組合

需要符合以下幾個條件:
  1. 權重加總=1, 使用constraints
  2. 權重介於[0,1]之間, 使用bound
scipy.optimize.sco.minimize()只能找出優化的最小值不能找出最大值,所以如果要找出sharp ratio最大值的權重就必須先把sharp ratio取負號,換成找(-sharp ratio)的最小值所對應的權重
sco.minimize(想要優化的函數, 初始化權重參數, 已知的參數(報酬, 風險, 無風險報酬), 方法, bound參數束縛條件, constraints函數限制嫖件)
這裡使用Sequential quadratic programming(SLSQP)來方法來做optimize.https://en.wikipedia.org/wiki/Sequential_quadratic_programming
sco.minimize()回傳優化的權重儲存在result['x'],在用portfolio_annualised_performance(result['x'], mean_returns, cov_matrix),算出這個以sharp ratio優化後的投資組合報酬率和風險.

計算效率前緣 Efficient Frontiner:

效率前緣指的是在相同風險下,最有效率的投資組合,可以想像是給定風險下找出投資報酬最高的投資組合,因此不同的風險會對應出一個效率前緣報酬率和投資組合.
In [10]:
def neg_sharpe_ratio(weights, mean_returns, cov_matrix, risk_free_rate):
    p_var, p_ret = portfolio_annualised_performance(weights, mean_returns, cov_matrix) #要optimized的參數是權重
    return -(p_ret - risk_free_rate) / p_var

def max_sharpe_ratio(mean_returns, cov_matrix, risk_free_rate):
    num_assets = len(mean_returns)
    args = (mean_returns, cov_matrix, risk_free_rate) #已知的參數
    constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})
    bound = (0.0,1.0)
    bounds = tuple(bound for asset in range(num_assets))
    result = sco.minimize(neg_sharpe_ratio, num_assets*[1./num_assets,], args=args,
                        method='SLSQP', bounds=bounds, constraints=constraints)
    return result

In [11]:
def portfolio_return(weights, mean_returns, cov_matrix):
    return -portfolio_annualised_performance(weights, mean_returns, cov_matrix)[1]

def max_return(mean_returns, cov_matrix):
    num_assets = len(mean_returns)
    args = (mean_returns, cov_matrix)
    constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})
    bound = (0.0,1.0)
    bounds = tuple(bound for asset in range(num_assets))

    result = sco.minimize(portfolio_return, num_assets*[1./num_assets,], args=args,
                        method='SLSQP', bounds=bounds, constraints=constraints)

    return result

In [12]:
def portfolio_volatility(weights, mean_returns, cov_matrix):
    return portfolio_annualised_performance(weights, mean_returns, cov_matrix)[0]

def min_variance(mean_returns, cov_matrix):
    num_assets = len(mean_returns)
    args = (mean_returns, cov_matrix)
    constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})
    bound = (0.0,1.0)
    bounds = tuple(bound for asset in range(num_assets))

    result = sco.minimize(portfolio_volatility, num_assets*[1./num_assets,], args=args,
                        method='SLSQP', bounds=bounds, constraints=constraints)

    return result

In [13]:
# 給定報酬率target下算出風險最低的優化投資組合
def efficient_return(mean_returns, cov_matrix, target):
    num_assets = len(mean_returns)
    args = (mean_returns, cov_matrix)

    def portfolio_return(weights):
        return portfolio_annualised_performance(weights, mean_returns, cov_matrix)[1] #報酬率
    #多了portfolio_return(x) - target的限制條件(報酬率要等於目標報酬率)
    constraints = ({'type': 'eq', 'fun': lambda x: portfolio_return(x) - target},
                   {'type': 'eq', 'fun': lambda x: np.sum(x) - 1})
    bounds = tuple((0,1) for asset in range(num_assets))
    #優化portfolio_volatility風險最低低投資組合權重,並回傳到result['x']
    result = sco.minimize(portfolio_volatility, num_assets*[1./num_assets,], args=args, method='SLSQP', bounds=bounds, constraints=constraints)
    return result

# 找出報酬率array所對應的優化投資組合array
def efficient_frontier(mean_returns, cov_matrix, returns_range):
    efficients = []
    for ret in returns_range:
        efficients.append(efficient_return(mean_returns, cov_matrix, ret))
    return efficients

In [14]:
def display_calculated_ef_with_random(mean_returns, cov_matrix, num_portfolios, risk_free_rate):
    results, _ = random_portfolios(num_portfolios,mean_returns, cov_matrix, risk_free_rate)
    
    #找出最大sharp ratio的投資組合權重
    max_sharpe = max_sharpe_ratio(mean_returns, cov_matrix, risk_free_rate)
    sdp, rp = portfolio_annualised_performance(max_sharpe['x'], mean_returns, cov_matrix)
    max_sharpe_allocation = pd.DataFrame(max_sharpe.x,index=table.columns,columns=['allocation'])
    max_sharpe_allocation.allocation = [round(i*100,2)for i in max_sharpe_allocation.allocation]
    max_sharpe_allocation = max_sharpe_allocation.T

    #找出最大報酬的權重
    max_ret = max_return(mean_returns, cov_matrix)
    sdp_max, rp_max = portfolio_annualised_performance(max_ret['x'], mean_returns, cov_matrix)
    max_ret_allocation = pd.DataFrame(max_ret.x,index=table.columns,columns=['allocation'])
    max_ret_allocation.allocation = [round(i*100,2)for i in max_ret_allocation.allocation]
    max_ret_allocation = max_ret_allocation.T
    
    #找出最小風險的權重
    min_vol = min_variance(mean_returns, cov_matrix)
    sdp_min, rp_min = portfolio_annualised_performance(min_vol['x'], mean_returns, cov_matrix)
    min_vol_allocation = pd.DataFrame(min_vol.x,index=table.columns,columns=['allocation'])
    min_vol_allocation.allocation = [round(i*100,2)for i in min_vol_allocation.allocation]
    min_vol_allocation = min_vol_allocation.T
    
    print ("."*80)
    print ("Maximum Sharpe Ratio Portfolio Allocation\n")
    print ("Annualised Return:", round(rp,2))
    print ("Annualised Volatility:", round(sdp,2))
    print ("\n")
    print (max_sharpe_allocation)
    print ("."*80)
    print ("Maximum Return Portfolio Allocation\n")
    print ("Annualised Return:", round(rp_max,2))
    print ("Annualised Volatility:", round(sdp_max,2))
    print ("\n")
    print (max_ret_allocation)
    print ("."*80)
    print ("Minimum Volatility Portfolio Allocation\n")
    print ("Annualised Return:", round(rp_min,2))
    print ("Annualised Volatility:", round(sdp_min,2))
    print ("\n")
    print (min_vol_allocation)
    
    plt.figure(figsize=(10, 7))
    plt.scatter(results[0,:],results[1,:],c=results[2,:],cmap='YlGnBu', marker='o', s=10, alpha=0.3)
    plt.colorbar()
    plt.scatter(sdp,rp,marker='*',color='r',s=500, label='Maximum Sharpe ratio')
    plt.scatter(sdp_max,rp_max,marker='*',color='b',s=500, label='Maxinum Return')
    plt.scatter(sdp_min,rp_min,marker='*',color='g',s=500, label='Minimum volatility')

    target = np.linspace(rp_min, 0.15, 50)
    efficient_portfolios = efficient_frontier(mean_returns, cov_matrix, target)
    plt.plot([p['fun'] for p in efficient_portfolios], target, linestyle='-.', color='black', label='efficient frontier')
    plt.title('Calculated Portfolio Optimization based on Efficient Frontier')
    plt.xlabel('annualised volatility')
    plt.ylabel('annualised returns')
    plt.legend(labelspacing=0.8)

In [15]:
display_calculated_ef_with_random(mean_returns, cov_matrix, num_portfolios, risk_free_rate)

................................................................................
Maximum Sharpe Ratio Portfolio Allocation

Annualised Return: 0.06
Annualised Volatility: 0.09


Symbols       BLV BND GLD  HYG IEI VB VEA  VNQ VT VTI VWO VWOB
allocation  41.36 0.0 22.43  0.0 0.0 2.71 0.0  0.0 0.0 33.5 0.0 0.0
................................................................................
Maximum Return Portfolio Allocation

Annualised Return: 0.1
Annualised Volatility: 0.23


Symbols     BLV BND GLD  HYG IEI VB  VEA VNQ VT VTI  VWO VWOB
allocation  0.0 0.0 0.0  0.0 0.0 100.0  0.0 0.0 0.0 0.0  0.0 0.0
................................................................................
Minimum Volatility Portfolio Allocation

Annualised Return: 0.02
Annualised Volatility: 0.03


Symbols     BLV BND GLD   HYG IEI VB VEA  VNQ VT VTI VWO VWOB
allocation  0.0 0.0 0.0  3.82 76.93 0.0  0.0 0.0 0.0 6.07  0.0 13.17

In [16]:
def display_ef_with_selected(mean_returns, cov_matrix, risk_free_rate):
    max_sharpe = max_sharpe_ratio(mean_returns, cov_matrix, risk_free_rate)
    sdp, rp = portfolio_annualised_performance(max_sharpe['x'], mean_returns, cov_matrix)
    max_sharpe_allocation = pd.DataFrame(max_sharpe.x,index=table.columns,columns=['allocation'])
    max_sharpe_allocation.allocation = [round(i*100,2)for i in max_sharpe_allocation.allocation]
    max_sharpe_allocation = max_sharpe_allocation.T
    max_sharpe_allocation

    max_ret = max_return(mean_returns, cov_matrix)
    sdp_max, rp_max = portfolio_annualised_performance(max_ret['x'], mean_returns, cov_matrix)
    max_ret_allocation = pd.DataFrame(max_ret.x,index=table.columns,columns=['allocation'])
    max_ret_allocation.allocation = [round(i*100,2)for i in max_ret_allocation.allocation]
    max_ret_allocation = max_ret_allocation.T    
    
    min_vol = min_variance(mean_returns, cov_matrix)
    sdp_min, rp_min = portfolio_annualised_performance(min_vol['x'], mean_returns, cov_matrix)
    min_vol_allocation = pd.DataFrame(min_vol.x,index=table.columns,columns=['allocation'])
    min_vol_allocation.allocation = [round(i*100,2)for i in min_vol_allocation.allocation]
    min_vol_allocation = min_vol_allocation.T
    
    an_vol = np.std(returns) * np.sqrt(252)
    an_rt = mean_returns * 252
    
    portfolio_list=[]
    
    print ("."*80)
    print ("Maximum Sharpe Ratio Portfolio Allocation\n")
    print ("Annualised Return:", round(rp,2))
    print ("Annualised Volatility:", round(sdp,2))
    print ("\n")
    print (max_sharpe_allocation)
    portfolio_list.append(max_sharpe_allocation)
    
    print ("."*80)
    print ("Maximum Return Portfolio Allocation\n")
    print ("Annualised Return:", round(rp_max,2))
    print ("Annualised Volatility:", round(sdp_max,2))
    print ("\n")
    print (max_ret_allocation)
    portfolio_list.append(max_ret_allocation)
    
    print ("."*80)
    print ("Minimum Volatility Portfolio Allocation\n")
    print ("Annualised Return:", round(rp_min,2))
    print ("Annualised Volatility:", round(sdp_min,2))
    print ("\n")
    print (min_vol_allocation)
    portfolio_list.append(min_vol_allocation)
    record = [rp,sdp,rp_max,sdp_max,rp_min,sdp_min]
    print ("."*80)
    print ("Individual Stock Returns and Volatility\n")
    for i, txt in enumerate(table.columns):
        print (txt,":","annuaised return",round(an_rt[i],2),", annualised volatility:",round(an_vol[i],2))
    print ("."*80)
    
    fig, ax = plt.subplots(figsize=(10, 7))
    ax.scatter(an_vol,an_rt,marker='o',s=200)

    for i, txt in enumerate(table.columns):
        ax.annotate(txt, (an_vol[i],an_rt[i]), xytext=(10,0), textcoords='offset points')
    ax.scatter(sdp,rp,marker='*',color='r',s=500, label='Maximum Sharpe ratio')
    ax.scatter(sdp_max,rp_max,marker='*',color='b',s=500, label='Maximum return')
    ax.scatter(sdp_min,rp_min,marker='*',color='g',s=500, label='Minimum volatility')

    target = np.linspace(rp_min, 0.15, 50)
    efficient_portfolios = efficient_frontier(mean_returns, cov_matrix, target)
    ax.plot([p['fun'] for p in efficient_portfolios], target, linestyle='-.', color='black', label='efficient frontier')
    ax.set_title('Portfolio Optimization with Individual Stocks')
    ax.set_xlabel('annualised volatility')
    ax.set_ylabel('annualised returns')
    ax.legend(labelspacing=0.8)
    return portfolio_list,record

In [17]:
portfolio_list = display_ef_with_selected(mean_returns, cov_matrix, risk_free_rate)

................................................................................
Maximum Sharpe Ratio Portfolio Allocation

Annualised Return: 0.06
Annualised Volatility: 0.09


Symbols       BLV BND GLD  HYG IEI VB VEA  VNQ VT VTI VWO VWOB
allocation  41.36 0.0 22.43  0.0 0.0 2.71 0.0  0.0 0.0 33.5 0.0 0.0
................................................................................
Maximum Return Portfolio Allocation

Annualised Return: 0.1
Annualised Volatility: 0.23


Symbols     BLV BND GLD  HYG IEI VB  VEA VNQ VT VTI  VWO VWOB
allocation  0.0 0.0 0.0  0.0 0.0 100.0  0.0 0.0 0.0 0.0  0.0 0.0
................................................................................
Minimum Volatility Portfolio Allocation

Annualised Return: 0.02
Annualised Volatility: 0.03


Symbols     BLV BND GLD   HYG IEI VB VEA  VNQ VT VTI VWO VWOB
allocation  0.0 0.0 0.0  3.82 76.93 0.0  0.0 0.0 0.0 6.07  0.0 13.17
................................................................................
Individual Stock Returns and Volatility

BLV : annuaised return 0.04 , annualised volatility: 0.1
BND : annuaised return 0.01 , annualised volatility: 0.04
GLD : annuaised return 0.07 , annualised volatility: 0.18
HYG : annuaised return 0.0 , annualised volatility: 0.12
IEI : annuaised return 0.02 , annualised volatility: 0.04
VB : annuaised return 0.1 , annualised volatility: 0.23
VEA : annuaised return 0.03 , annualised volatility: 0.23
VNQ : annuaised return 0.09 , annualised volatility: 0.33
VT : annuaised return 0.06 , annualised volatility: 0.21
VTI : annuaised return 0.09 , annualised volatility: 0.2
VWO : annuaised return 0.04 , annualised volatility: 0.29
VWOB : annuaised return 0.0 , annualised volatility: 0.05
................................................................................

函數優化法設計出三種優化後的投資組合:

  1. 夏普值最高
  2. 回報率最高
  3. 風險最低
In [19]:
rec=np.round(portfolio_list[1],2)*100
title='夏普值最高 年報酬:'+str(rec[0])+'%  風險:'+str(rec[1])+'%'
filter=portfolio_list[0][0]>0
portfolio_short=portfolio_list[0][0][filter]
portfolio_short_=portfolio_short.dropna(axis=1)
portfolio_short_.T.plot.pie(y='allocation', figsize=(5, 5), autopct='%1.0f%%')
plt.title(title, fontproperties="PMingLiU", fontsize=20)
plt.show()
title='報酬率最高 年報酬:'+str(rec[2])+'%  風險:'+str(rec[3])+'%'
filter=portfolio_list[0][1]>0
portfolio_short=portfolio_list[0][1][filter]
portfolio_short_=portfolio_short.dropna(axis=1)
portfolio_short_.T.plot.pie(y='allocation', figsize=(5, 5), autopct='%1.0f%%')
plt.title(title, fontproperties="PMingLiU", fontsize=20)
plt.show()
title='風險最低 年報酬:'+str(rec[4])+'%  風險:'+str(rec[5])+'%'
filter=portfolio_list[0][2]>0
portfolio_short=portfolio_list[0][2][filter]
portfolio_short_=portfolio_short.dropna(axis=1)
portfolio_short_.T.plot.pie(y='allocation', figsize=(5, 5), autopct='%1.0f%%')
plt.title(title, fontproperties="PMingLiU", fontsize=20)
plt.show()

三倍槓桿和一倍槓桿的長期定期定額報酬率分析

  以下是中國,美國股票債卷的三倍槓桿和一倍槓桿ETF分析.可以發現,三倍槓桿在下跌時期的跌幅遠比一倍槓桿的多 .且從時間軸來看,三倍槓桿由於下跌力道較強,因此會把之前的漲幅都吃掉,所以對於長期上身的市場,例如美國科技股,由於上升時間遠比下跌時間長,所以持有TQQQ的長期回報率會...