Está en la página 1de 14

Final Project

: 20164548
:

1 / 14

1. ................................................................................................... 3

2. ........................................................... 3

3. Constraints ................................................... 5

4. ............................................................................. 5

5. Data Analysis ............................................................................... 5

6. ..................................................................................................... 7

7. Code ................................................................................................. 8

2 / 14
1.

25 FamaFrench
Factor 25 Mean Variance
Optimization, Black Litterman Optimization, Robust Optimization
. 3 Optimization
.

Return 1966.01 2015.12


Window 120 . 1976.01-2015.12 Out of
Sample .

3 Weight
Sharpe Ratio
.

6 Equally weighted Benchmark


Market Portfolio .

2.

Portfolio Markowitz Modern Portfolio Theory


.

3 / 14
- Mean Variance Optimization : Markowitz
Efficient frontier 1) Mean Variance ,
2) Variance Mean 3) Sharpe Ratio
Optimization .

- Black Litterman Optimization : Mean Variance Optimization


Investor View Prior Posterior ,
Mean Variance
Optimization .

- Robust Optimization : Mean Variance Optimization


weight ,
/ objective ,
/ objective weight . ,
Optimization .

- Equally Weighted Portfolio : weight


.

4 / 14
3. Constraints

Optimization Python Minimize function


Method SLSQP . SLSQP Sequential Least SQuares Programming ,
bounds, equality and inequality constraints .

Weight 0~0.06 ,
Equality Weight 1 . Inequality constraints
Robust Optimization .

4.

3 Optimization Portfolio ,
Weight .

5. Black Litterman Investors View

Window Variance mean


. Window Variance
mean Variance
Prior , Posterior Mean
Variance Optimization .

6. Robust Optimization

Variance Risk Minimization ,


delta k 1/sqrt(120) ,
5 / 14
market Window

5. Data Analysis

Market EW MV BL RO
- 0.06386 0.07084 0.07085 0.12309
Cum Bal 80.3800 181.7197 216.5948 216.5136 235.1236
Sharpe Ratio 0.045 0.876 0.717 0.717 0.704
CAGR 0.1159 0.1389 0.1439 0.1439 0.1463
Vol 0.154 0.17 0.24 0.24 0.247
MDD -0.3553 -0.4331 -1.4047 -1.4047 -1.4637

Market Portfolio 40 80% ,


Volatility . Sharpe Ratio
.

Equally weighted portfolio 3


Volatility . EW Portfolio 5
Sharpe Ratio . Risk free asset Leverage
.
.

Mean Variance Portfolio Black Litterman Portfolio . Black Litterman


Optimization Window 120
Investors View Mean Variance Portfolio
. Black Litterman View
.

Robust Optimization .
. Mean Variance, Black Litterman
Sharpe Ratio .

MDD MDD
., Market Portfolio MDD
Volatility .
6 / 14
Balance Plot .

MV BL MV BL .

Weight Constraints Equally Weight


,
.

6.

Project Efficient Portfolio, CAPM


, Sharpe Ratio
. Constraints
.
EW Sharpe
Ratio . Leverage

. 40

7 / 14
, Robust
.

Short Sale Constraints


Risk Free asset optimal portfolio
Risk Taking Return .

7. Code

1. # -*- coding: utf-8 -*-


2. """
3. Created on Fri Oct 6 17:28:23 2017
4.
5. @author: 20164548
6. """
7.
8. import os
9. # !
10. os.chdir('C:/Users/CSJSK/Desktop/2017 2 / /Assignmen
t/Data')
11.
12. import pandas as pd
13. from pandas import DataFrame
14. from datetime import datetime, timedelta
15. import matplotlib.pyplot as plt
16. import numpy as np
17. import matplotlib
18. import math
19. from scipy.optimize import minimize
20.
21. Table_FF_Factors = pd.read_csv('FF_Factors.CSV', header=0, index_col=0)
22. Table_25_FF = pd.read_csv('25_FF.CSV', header=0, index_col=0)
23. MKT_Return = 0.01 * ( Table_FF_Factors.ix[197601:201512]['Mkt-
RF'] + Table_FF_Factors.ix[197601:201512]['RF'] )
24. Df25_Return = Table_25_FF.ix[196601:201512]*0.01
25. Df25_ExcessReturn = Table_25_FF.ix[196601:201512].sub(Table_FF_Factors['RF'].ix[196
601:201512], axis=0)*0.01
26. 0.01 * ( Table_FF_Factors.ix[196601:201512]['Mkt-
RF'] + Table_FF_Factors.ix[196601:201512]['RF'] )
27. # Df25.iloc[0,:]
28. # np.array(Df25)[0,:]
29. Matrix25_Return = np.array(Df25_Return)
30. Matrix25_ExcessReturn = np.array(Df25_ExcessReturn)
31. NumofInSample = len(Matrix25_ExcessReturn)-120
32. NumofAsset = len(Matrix25_ExcessReturn[0])
33.
34. # InSample Covariance Matrix List
35. def All_Cov(matrix):
36. List = []
37. for i in range(len(matrix)-120):
38. List.append(np.cov(matrix[i:i+120,:].T))
39. return List
40.
41. def All_Mean(matrix):

8 / 14
42. List = []
43. for i in range(len(matrix)-120):
44. List.append(np.mean(matrix[i:i+120,:],axis=0))
45. return List
46.
47. def All_Std(matrix):
48. List = []
49. for i in range(len(matrix)-120):
50. List.append(np.std(matrix[i:i+120,:],axis=0))
51. return List
52.
53. All_Mean = All_Mean(Matrix25_ExcessReturn)
54. All_Std = All_Std(Matrix25_ExcessReturn)
55. All_Cov = All_Cov(Matrix25_ExcessReturn)
56.
57. # EquallyWeighted Portfolio Weight
58. def EW_Portfolio(NumofInSample,NumofAsset):
59. return np.ones([NumofInSample, NumofAsset])/NumofAsset
60.
61. #
62. n = 25
63. lb = [0] * n # lower bound
64. ub = [0.06] * n # upper bound
65.
66. # MeanVariance Portfolio Optimization
67. def MeanVariance_Portfolio(All_Cov, lb, ub) :
68. WeightMatrix_MV = []
69. x0 = np.matrix( np.ones(25)/25 )
70. bnds = tuple(zip(lb, ub))
71. constraints = {'type': 'eq', 'fun': lambda W: sum(W)-1. }
72. options = {'ftol': 1e-20, 'maxiter': 800}
73. for i in range(len(All_Cov)):
74. CovMatrix = All_Cov[i]
75. result = minimize(fun = lambda Weight: (Weight @ CovMatrix @ Weight.T).it
em(0),
76. x0 = x0,
77. method = 'SLSQP',
78. constraints = constraints,
79. options = options,
80. bounds = bnds)
81. WeightMatrix_MV.append(result.x)
82. return(np.array(WeightMatrix_MV))
83.
84. # BlackRitterman Portfolio Optimization
85. def BlackRitterman_Portfolio(All_Cov, lb, ub) :
86. WeightMatrix_BR = []
87. x0 = np.matrix( np.ones(25)/25 )
88. bnds = tuple(zip(lb, ub))
89. constraints = {'type': 'eq', 'fun': lambda W: sum(W)-1. }
90. options = {'ftol': 1e-20, 'maxiter': 800}
91. for i in range(len(All_Cov)):
92. CovMatrixBeforeBL = All_Cov[i]
93. ### Black Litterman Investor's View
94. # Black-Litterman Investor's View
95. # Variance
96. P0 = np.zeros([1,25])
97. P0[:,np.argmin(np.std(Matrix25_ExcessReturn[i:i+120,:],axis=0))] = 1
98. Q0 = np.mean(Matrix25_ExcessReturn[i:i+120,:][:,np.argmin(np.std(Matrix25
_ExcessReturn[i:i+120,:],axis=0))],axis=0)
99.
100. # Black-Litterman Investor's View
9 / 14
101. # Variance
102. DicForSub = {}
103. for m in range(25):
104. for n in range(m+1,25):
105. DicForSub[m,n] = Matrix25_ExcessReturn[i:i+120,m] - Matrix25_Ex
cessReturn[i:i+120,n]
106. DFforSub = pd.DataFrame(DicForSub)
107. np.std(DFforSub)
108. P1 = np.zeros([1,25])
109. P1[0, np.argmin(np.std(DFforSub))[0]] = 1
110. P1[0, np.argmin(np.std(DFforSub))[1]] = -1
111. Q1 = np.mean(DFforSub[np.argmin(np.std(DFforSub))])
112.
113. # Black-Litterman Investor's View
114. P = np.array([P0[0],P1[0]])
115. Q = np.array([[Q0],[Q1]])
116. Tau = 1/120
117. Omega = Tau * P @ CovMatrixBeforeBL @ P.T
118.
119. # Posterior Sigma
120. Sigma_Bar = Tau * CovMatrixBeforeBL
121. Sigma_mean = Sigma_Bar - Sigma_Bar @ P.T @ np.linalg.inv( P @ Sigma_Bar @
P.T + Omega ) @ P @ Sigma_Bar
122.
123. # Sigma Hat
124. Sigma_Hat = CovMatrixBeforeBL + Sigma_mean
125.
126. CovMatrix = Sigma_Hat
127. result = minimize(fun = lambda Weight: (Weight @ CovMatrix @ Weight.T).it
em(0),
128. x0 = x0,
129. method = 'SLSQP',
130. constraints = constraints,
131. options = options,
132. bounds = bnds)
133. WeightMatrix_BR.append(result.x)
134. return(np.array(WeightMatrix_BR))
135.
136. def Robust_Portfolio(All_Cov, All_Mean, All_Std, lb, ub) :
137. WeightMatrix_MV = []
138. bnds = tuple(zip(lb, ub))
139. k = 1/np.sqrt(120)
140. options = {'ftol': 1e-20, 'maxiter': 800}
141. for i in range(len(All_Cov)):
142. x0 = np.matrix( np.ones(25)/25 )
143.
144. CovMatrix = All_Cov[i].reshape(25,25)
145. Mean_Hat = All_Mean[i].reshape(25,1)
146. Std_Hat = All_Std[i].reshape(25,1)
147. MKTreturn = (0.01 * ( Table_FF_Factors.ix[196601:201512]['Mkt-
RF'] + Table_FF_Factors.ix[196601:201512]['RF'] ))[i:i+120].mean()
148. constraints = ({'type': 'eq', 'fun': lambda W: sum(W)-1 },
149. {'type': 'ineq', 'fun': lambda W: (W @ Mean_Hat - np.abs(
W) @ (k/120 * Std_Hat) - MKTreturn ).item(0) })
150. result = minimize(fun = lambda Weight: (Weight @ CovMatrix @ Weight.T).it
em(0),
151. x0 = x0,
152. method = 'SLSQP',
153. constraints = constraints,
154. options = options,
155. bounds = bnds)

10 / 14
156. WeightMatrix_MV.append(result.x)
157. return(np.array(WeightMatrix_MV))
158.
159. # Portfolio Return Weight Matrix return
160. def ReturnofPortfolio(WeightMatrix):
161. return np.sum( Matrix25_Return[120:,:] * WeightMatrix, axis=1)
162.
163. # Portfolio balance array , cumprod array
164. def CumProd(Array_Return):
165. return ( Array_Return + 1 ).cumprod()
166.
167. # np.zeros([480, 1])
168. def TransactionCostatReturn(WeightMatrix,ReturnMatrix):
169. TransactionCost = np.zeros([len(WeightMatrix), 1])
170. TransactionCost[0] = 0.003
171. TransactionCost[1:] = 0.003 * np.sum(np.abs(WeightMatrix[1:]-
(WeightMatrix * (ReturnMatrix+1))[:-1]),axis=1).reshape(len(WeightMatrix)-1,1)
172. return TransactionCost
173.
174.
175. WeightFromMV = MeanVariance_Portfolio(All_Cov, lb, ub)
176. WeightFromEW = EW_Portfolio(NumofInSample,NumofAsset)
177. WeightFromBL = BlackRitterman_Portfolio(All_Cov, lb, ub)
178. WeightFromRO = Robust_Portfolio(All_Cov, All_Mean, All_Std, lb, ub)
179.
180. ReturnOnMV = ReturnofPortfolio(WeightFromMV)
181. ReturnOnEW = ReturnofPortfolio(WeightFromEW)
182. ReturnOnBL = ReturnofPortfolio(WeightFromBL)
183. ReturnOnRO = ReturnofPortfolio(WeightFromRO)
184.
185. CumProd_MKT = CumProd( np.array(MKT_Return) )
186. CumProd_EW = CumProd(ReturnOnEW)
187. CumProd_EW_WithTransFee = CumProd(ReturnOnEW.reshape(1,480)-
TransactionCostatReturn(WeightFromEW,Matrix25_Return[120:,:]).T)
188. CumProd_MV = CumProd(ReturnOnMV)
189. CumProd_MV_WithTransFee = CumProd(ReturnOnMV.reshape(1,480)-
TransactionCostatReturn(WeightFromMV,Matrix25_Return[120:,:]).T)
190. CumProd_BL = CumProd(ReturnOnBL)
191. CumProd_BL_WithTransFee = CumProd(ReturnOnBL.reshape(1,480)-
TransactionCostatReturn(WeightFromBL,Matrix25_Return[120:,:]).T)
192. CumProd_RO = CumProd(ReturnOnRO)
193. CumProd_RO_WithTransFee = CumProd(ReturnOnRO.reshape(1,480)-
TransactionCostatReturn(WeightFromRO,Matrix25_Return[120:,:]).T)
194.
195.
196. #TransactionFee Plotting
197. plt.figure(figsize=(12,8))
198. plt.plot(list(range(NumofInSample)), CumProd_MKT, 'g', label='MKT')
199. plt.plot(list(range(NumofInSample)), CumProd_EW_WithTransFee, 'r', label='EW_Fee')

200. plt.plot(list(range(NumofInSample)), CumProd_MV_WithTransFee, 'c', label='MV_Fee')

201. plt.plot(list(range(NumofInSample)), CumProd_BL_WithTransFee, 'y', label='BL_Fee')

202. plt.plot(list(range(NumofInSample)), CumProd_RO_WithTransFee, 'b', label='RO_Fee')

203. plt.legend()
204. plt.show()
205.
206. TransFeeEW = np.sum(TransactionCostatReturn(WeightFromEW,Matrix25_Return[120:,:]))

11 / 14
207. TransFeeMV = np.sum(TransactionCostatReturn(WeightFromMV,Matrix25_Return[120:,:]))

208. TransFeeBL = np.sum(TransactionCostatReturn(WeightFromBL,Matrix25_Return[120:,:]))

209. TransFeeRO = np.sum(TransactionCostatReturn(WeightFromRO,Matrix25_Return[120:,:]))

210. print(TransFeeEW)
211. print(TransFeeMV)
212. print(TransFeeBL)
213. print(TransFeeRO)
214. print(CumProd_MKT[-1])
215. print(CumProd_EW_WithTransFee[-1])
216. print(CumProd_MV_WithTransFee[-1])
217. print(CumProd_BL_WithTransFee[-1])
218. print(CumProd_RO_WithTransFee[-1])
219.
220. CAGR_MKT = np.power(CumProd_MKT[-1], 1/40)-1
221. CAGR_EW_Fee = np.power(CumProd_EW_WithTransFee[-1], 1/40)-1
222. CAGR_MV_Fee = np.power(CumProd_MV_WithTransFee[-1], 1/40)-1
223. CAGR_BL_Fee = np.power(CumProd_BL_WithTransFee[-1], 1/40)-1
224. CAGR_RO_Fee = np.power(CumProd_RO_WithTransFee[-1], 1/40)-1
225.
226. pd.DataFrame([CumProd_EW_WithTransFee[0]])
227. return_EW_Fee = pd.DataFrame(CumProd_EW_WithTransFee).pct_change()
228. return_EW_Fee.iloc[0] = CumProd_EW_WithTransFee[0]-1
229. return_MV_Fee = pd.DataFrame(CumProd_MV_WithTransFee).pct_change()
230. return_MV_Fee.iloc[0] = CumProd_MV_WithTransFee[0]
231. return_BL_Fee = pd.DataFrame(CumProd_BL_WithTransFee).pct_change()
232. return_BL_Fee.iloc[0] = CumProd_BL_WithTransFee[0]
233. return_RO_Fee = pd.DataFrame(CumProd_RO_WithTransFee).pct_change()
234. return_RO_Fee.iloc[0] = CumProd_RO_WithTransFee[0]
235.
236. def calCumulRet(pf_return):
237. #
238. cumul_return = (1 + pf_return).cumprod()
239. if type(pf_return) == type(pd.DataFrame()):
240. cumul_return.ix[0] = 1
241. else : cumul_return[0] = 1
242. return cumul_return
243.
244. def calCAGR(returns):
245. cumul_return = calCumulRet(returns)
246. cagr = np.round((cumul_return.iloc[-
1] / cumul_return.iloc[0]) ** (12. / len(returns)) -1, decimals=3)
247. # cagr = np.round((cumul_return[-
1] / cumul_return[0]) ** (24. / len(returns)) - 1, decimals=3)
248. return cagr
249.
250. # excess return portfolio returns need = False
251. # risk free rate sharpe need = True
252. def sharpe_ratio(returns, risk_free_rate, need):
253. if need == True:
254. return np.round( (calCAGR(returns) - calCAGR(risk_free_rate) ) / vol(return
s), decimals=3)
255. if need == False:
256. return np.round( (calCAGR(returns) ) / vol(returns), decimals=3)
257.
258. print(sharpe_ratio(MKT_Return,Table_FF_Factors.ix[197601:201512]['RF'],True))
259. print(sharpe_ratio(return_EW_Fee,Table_FF_Factors.ix[197601:201512]['RF'],True)[0])

12 / 14
260. print(sharpe_ratio(return_MV_Fee,Table_FF_Factors.ix[197601:201512]['RF'],True)[0])

261. print(sharpe_ratio(return_BL_Fee,Table_FF_Factors.ix[197601:201512]['RF'],True)[0])

262. print(sharpe_ratio(return_RO_Fee,Table_FF_Factors.ix[197601:201512]['RF'],True)[0])

263.
264. def vol(returns):
265. # Return the annualized standard deviation of returns
266. return np.round(np.std(returns) * np.sqrt(12), decimals=3)
267. # return np.round(np.std(returns) * np.sqrt(24), decimals=3)
268. print(vol(MKT_Return))
269. print(vol(return_EW_Fee[0]))
270. print(vol(return_MV_Fee[0]))
271. print(vol(return_BL_Fee[0]))
272. print(vol(return_RO_Fee[0]))
273.
274. def MaxDrawdown(data):
275. # MDD
276. #input data : percentage performace(monthly return)
277. Drawdown=[]
278. for i in range(1,len(data)):
279. Drawdown.append((data.iloc[i]-max(data.iloc[:i+1])))
280.
281. return min(Drawdown)
282.
283. print(MaxDrawdown(MKT_Return))
284. print(MaxDrawdown(return_EW_Fee[0]))
285. print(MaxDrawdown(return_MV_Fee[0]))
286. print(MaxDrawdown(return_BL_Fee[0]))
287. print(MaxDrawdown(return_RO_Fee[0]))
288.
289. """
290. DataFrame :
291. 1.
292. 2.
293. 3. Sharpe Ratio
294. 4. CAGR
295. 5. Volatility
296. 6. MDD
297. 7. (Legend )
298. """

13 / 14
14 / 14

También podría gustarte