Documentos de Académico
Documentos de Profesional
Documentos de Cultura
: 20164548
:
1 / 14
1. ................................................................................................... 3
2. ........................................................... 3
3. Constraints ................................................... 5
4. ............................................................................. 5
6. ..................................................................................................... 7
7. Code ................................................................................................. 8
2 / 14
1.
25 FamaFrench
Factor 25 Mean Variance
Optimization, Black Litterman Optimization, Robust Optimization
. 3 Optimization
.
3 Weight
Sharpe Ratio
.
2.
3 / 14
- Mean Variance Optimization : Markowitz
Efficient frontier 1) Mean Variance ,
2) Variance Mean 3) Sharpe Ratio
Optimization .
4 / 14
3. Constraints
Weight 0~0.06 ,
Equality Weight 1 . Inequality constraints
Robust Optimization .
4.
3 Optimization Portfolio ,
Weight .
6. Robust Optimization
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
Robust Optimization .
. Mean Variance, Black Litterman
Sharpe Ratio .
MDD MDD
., Market Portfolio MDD
Volatility .
6 / 14
Balance Plot .
MV BL MV BL .
6.
7 / 14
, Robust
.
7. Code
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')
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:,:]))
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