Showing
2 changed files
with
202 additions
and
9 deletions
... | @@ -5,19 +5,37 @@ import FinanceDataReader as fdr | ... | @@ -5,19 +5,37 @@ import FinanceDataReader as fdr |
5 | from scipy.optimize import minimize | 5 | from scipy.optimize import minimize |
6 | import json | 6 | import json |
7 | 7 | ||
8 | +#소숫점 표현 | ||
9 | +pd.options.display.float_format = '{:.3f}'.format | ||
10 | +np.set_printoptions(precision=3, suppress=True) | ||
11 | + | ||
8 | class c_Models: | 12 | class c_Models: |
9 | #Input 값으로, 자산 list, 사용자 포트폴리오 비중, 시작일, 마지막일 | 13 | #Input 값으로, 자산 list, 사용자 포트폴리오 비중, 시작일, 마지막일 |
10 | def __init__(self, assets, assets_w, start, end): | 14 | def __init__(self, assets, assets_w, start, end): |
11 | self.result = None | 15 | self.result = None |
12 | self.graph = None | 16 | self.graph = None |
17 | + | ||
18 | + stocks = pd.read_csv('stockcodename.csv', index_col=0) | ||
19 | + symbol = '' | ||
20 | + self.asset_name = assets[:] | ||
21 | + for k in range(len(assets)): | ||
22 | + for i in enumerate(stocks.Name): | ||
23 | + if i[1] == assets[k]: | ||
24 | + assets[k] = (stocks.iloc[i[0]].Symbol) | ||
25 | + break | ||
13 | 26 | ||
14 | data = pd.DataFrame() | 27 | data = pd.DataFrame() |
15 | # 전체 자산 data들을 가지고 온 후, 정리함 | 28 | # 전체 자산 data들을 가지고 온 후, 정리함 |
29 | + | ||
16 | for asset in assets: #total_list: | 30 | for asset in assets: #total_list: |
17 | tmp = fdr.DataReader(asset,start,end).Close | 31 | tmp = fdr.DataReader(asset,start,end).Close |
18 | - tmp.rename(columns={'Close': asset}, inplace=True) | 32 | + if len(data) == 0 : |
19 | - data = pd.concat([data, tmp], axis=1) | 33 | + data = tmp |
20 | - | 34 | + else: |
35 | + data = pd.concat([data,tmp], axis=1) | ||
36 | + | ||
37 | + data.columns = self.asset_name | ||
38 | + | ||
21 | if data.isnull().values.any() == True: #불러온 data에 오류가 있다면 | 39 | if data.isnull().values.any() == True: #불러온 data에 오류가 있다면 |
22 | return "No Data",'' | 40 | return "No Data",'' |
23 | 41 | ||
... | @@ -39,9 +57,9 @@ class c_Models: | ... | @@ -39,9 +57,9 @@ class c_Models: |
39 | constraints = ({'type':'eq', 'fun':lambda x: np.sum(x)-1}) | 57 | constraints = ({'type':'eq', 'fun':lambda x: np.sum(x)-1}) |
40 | bd = ((0,1),) * n_assets | 58 | bd = ((0,1),) * n_assets |
41 | #cov = data.cov() * 12 | 59 | #cov = data.cov() * 12 |
42 | - | ||
43 | gmv = minimize(fun, w0, method = 'SLSQP', constraints=constraints, bounds=bd) | 60 | gmv = minimize(fun, w0, method = 'SLSQP', constraints=constraints, bounds=bd) |
44 | - return gmv.x | 61 | + result = dict(zip(self.asset_name, np.round(gmv.x,3))) |
62 | + return result | ||
45 | 63 | ||
46 | #Max Sharp ratio : risk free rate은 0.8%로 지정했고, | 64 | #Max Sharp ratio : risk free rate은 0.8%로 지정했고, |
47 | def ms_opt(self): | 65 | def ms_opt(self): |
... | @@ -51,7 +69,8 @@ class c_Models: | ... | @@ -51,7 +69,8 @@ class c_Models: |
51 | bd = ((0,1),) * n_assets | 69 | bd = ((0,1),) * n_assets |
52 | constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1}) | 70 | constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1}) |
53 | maxsharp = minimize(fun, w0, method ='SLSQP', constraints=constraints, bounds=bd) | 71 | maxsharp = minimize(fun, w0, method ='SLSQP', constraints=constraints, bounds=bd) |
54 | - return maxsharp.x | 72 | + result = dict(zip(self.asset_name, np.round(maxsharp.x,3))) |
73 | + return result | ||
55 | 74 | ||
56 | def rp_opt(self): | 75 | def rp_opt(self): |
57 | def RC(cov, w): | 76 | def RC(cov, w): |
... | @@ -80,5 +99,5 @@ class c_Models: | ... | @@ -80,5 +99,5 @@ class c_Models: |
80 | bd = ((0,1),) * n_assets | 99 | bd = ((0,1),) * n_assets |
81 | 100 | ||
82 | rp = minimize(RP_objective, w0, constraints=constraints, bounds = bd, method='SLSQP') | 101 | rp = minimize(RP_objective, w0, constraints=constraints, bounds = bd, method='SLSQP') |
83 | - | 102 | + result = dict(zip(self.asset_name, np.round(rp.x,3))) |
84 | - return rp.x #, RC(self.cov, rp.x) | 103 | + return result #, RC(self.cov, rp.x) |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -2,7 +2,7 @@ | ... | @@ -2,7 +2,7 @@ |
2 | "cells": [ | 2 | "cells": [ |
3 | { | 3 | { |
4 | "cell_type": "code", | 4 | "cell_type": "code", |
5 | - "execution_count": 1, | 5 | + "execution_count": 2, |
6 | "metadata": {}, | 6 | "metadata": {}, |
7 | "outputs": [], | 7 | "outputs": [], |
8 | "source": [ | 8 | "source": [ |
... | @@ -66,6 +66,180 @@ | ... | @@ -66,6 +66,180 @@ |
66 | "stocks = fdr.StockListing('KOSPI') # 코스피\n", | 66 | "stocks = fdr.StockListing('KOSPI') # 코스피\n", |
67 | "stocks.to_csv(\"stockcodename.csv\",mode='w', encoding='utf-8-sig')" | 67 | "stocks.to_csv(\"stockcodename.csv\",mode='w', encoding='utf-8-sig')" |
68 | ] | 68 | ] |
69 | + }, | ||
70 | + { | ||
71 | + "cell_type": "code", | ||
72 | + "execution_count": 123, | ||
73 | + "metadata": {}, | ||
74 | + "outputs": [], | ||
75 | + "source": [ | ||
76 | + "import datetime\n", | ||
77 | + "import pandas as pd\n", | ||
78 | + "import numpy as np\n", | ||
79 | + "import FinanceDataReader as fdr\n", | ||
80 | + "from scipy.optimize import minimize\n", | ||
81 | + "import json\n", | ||
82 | + "\n", | ||
83 | + "#소숫점 표현\n", | ||
84 | + "pd.options.display.float_format = '{:.3f}'.format\n", | ||
85 | + "np.set_printoptions(precision=3, suppress=True)\n", | ||
86 | + "\n", | ||
87 | + "class c_Models:\n", | ||
88 | + " #Input 값으로, 자산 list, 사용자 포트폴리오 비중, 시작일, 마지막일\n", | ||
89 | + " def __init__(self, assets, assets_w, start, end):\n", | ||
90 | + " self.result = None\n", | ||
91 | + " self.graph = None\n", | ||
92 | + " \n", | ||
93 | + " stocks = pd.read_csv('stockcodename.csv', index_col=0)\n", | ||
94 | + " symbol = ''\n", | ||
95 | + " self.asset_name = assets[:]\n", | ||
96 | + " for k in range(len(assets)):\n", | ||
97 | + " for i in enumerate(stocks.Name):\n", | ||
98 | + " if i[1] == assets[k]:\n", | ||
99 | + " assets[k] = (stocks.iloc[i[0]].Symbol)\n", | ||
100 | + " break\n", | ||
101 | + "\n", | ||
102 | + " data = pd.DataFrame()\n", | ||
103 | + " # 전체 자산 data들을 가지고 온 후, 정리함\n", | ||
104 | + " \n", | ||
105 | + " for asset in assets: #total_list:\n", | ||
106 | + " tmp = fdr.DataReader(asset,start,end).Close\n", | ||
107 | + " if len(data) == 0 :\n", | ||
108 | + " data = tmp\n", | ||
109 | + " else:\n", | ||
110 | + " data = pd.concat([data,tmp], axis=1)\n", | ||
111 | + " \n", | ||
112 | + " data.columns = self.asset_name\n", | ||
113 | + " \n", | ||
114 | + " if data.isnull().values.any() == True: #불러온 data에 오류가 있다면\n", | ||
115 | + " return \"No Data\",''\n", | ||
116 | + "\n", | ||
117 | + " else:\n", | ||
118 | + " data = data.resample('M').mean() #일별 데이터를 월별 데이터로 만들어줌\n", | ||
119 | + " data = data.pct_change() #월별 주가 데이터를 이용해 수익률 데이터로 변환\n", | ||
120 | + " data.dropna(inplace=True) #결측치 제외(첫 row)\n", | ||
121 | + "\n", | ||
122 | + " self.data = data\n", | ||
123 | + " self.assets_w = assets_w\n", | ||
124 | + " self.mu = data.mean() * 12\n", | ||
125 | + " self.cov = data.cov() * 12\n", | ||
126 | + "\n", | ||
127 | + " #GMV 최적화 : 제약 조건은 비중합=1, 공매도 불가능\n", | ||
128 | + " def gmv_opt(self):\n", | ||
129 | + " n_assets = len(self.data.columns)\n", | ||
130 | + " w0 = np.ones(n_assets) / n_assets\n", | ||
131 | + " fun = lambda w: np.dot(w.T, np.dot(self.cov, w))\n", | ||
132 | + " constraints = ({'type':'eq', 'fun':lambda x: np.sum(x)-1})\n", | ||
133 | + " bd = ((0,1),) * n_assets\n", | ||
134 | + " #cov = data.cov() * 12\n", | ||
135 | + " gmv = minimize(fun, w0, method = 'SLSQP', constraints=constraints, bounds=bd)\n", | ||
136 | + " result = dict(zip(self.asset_name, np.round(gmv.x,3)))\n", | ||
137 | + " return result\n", | ||
138 | + " \n", | ||
139 | + " #Max Sharp ratio : risk free rate은 0.8%로 지정했고, \n", | ||
140 | + " def ms_opt(self):\n", | ||
141 | + " n_assets = len(self.data.columns)\n", | ||
142 | + " w0 = np.ones(n_assets) / n_assets\n", | ||
143 | + " fun = lambda w: -(np.dot(w.T, self.mu) - 0.008) / np.sqrt(np.dot(w.T, np.dot(self.cov, w)))\n", | ||
144 | + " bd = ((0,1),) * n_assets \n", | ||
145 | + " constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})\n", | ||
146 | + " maxsharp = minimize(fun, w0, method ='SLSQP', constraints=constraints, bounds=bd)\n", | ||
147 | + " result = dict(zip(self.asset_name, np.round(maxsharp.x,3)))\n", | ||
148 | + " return result\n", | ||
149 | + " \n", | ||
150 | + " def rp_opt(self):\n", | ||
151 | + " def RC(cov, w):\n", | ||
152 | + " pfo_std = np.sqrt(np.dot(w.T, np.dot(self.cov, w)))\n", | ||
153 | + " mrc = 1/pfo_std * (np.dot(self.cov, w))\n", | ||
154 | + " rc = mrc * w\n", | ||
155 | + " rc = rc / rc.sum()\n", | ||
156 | + " return rc\n", | ||
157 | + " \n", | ||
158 | + " \n", | ||
159 | + " def RP_objective(x):\n", | ||
160 | + " pfo_std = np.sqrt(np.dot(x.T, np.dot(self.cov, x)))\n", | ||
161 | + " mrc = 1/pfo_std * (np.dot(self.cov, x))\n", | ||
162 | + " rc = mrc * x\n", | ||
163 | + " rc = rc / rc.sum()\n", | ||
164 | + "\n", | ||
165 | + " a = np.reshape(rc, (len(rc),1))\n", | ||
166 | + " differs = a - a.T\n", | ||
167 | + " objective = np.sum(np.square(differs))\n", | ||
168 | + "\n", | ||
169 | + " return objective \n", | ||
170 | + " \n", | ||
171 | + " n_assets = len(self.data.columns)\n", | ||
172 | + " w0 = np.ones(n_assets) / n_assets\n", | ||
173 | + " constraints = [{'type':'eq', 'fun': lambda x: np.sum(x) -1}]\n", | ||
174 | + " bd = ((0,1),) * n_assets\n", | ||
175 | + "\n", | ||
176 | + " rp = minimize(RP_objective, w0, constraints=constraints, bounds = bd, method='SLSQP')\n", | ||
177 | + " result = dict(zip(self.asset_name, np.round(rp.x,3)))\n", | ||
178 | + " return result #, RC(self.cov, rp.x)" | ||
179 | + ] | ||
180 | + }, | ||
181 | + { | ||
182 | + "cell_type": "code", | ||
183 | + "execution_count": 122, | ||
184 | + "metadata": {}, | ||
185 | + "outputs": [ | ||
186 | + { | ||
187 | + "data": { | ||
188 | + "text/plain": [ | ||
189 | + "{'삼성전자': 0.727, 'LG전자': 0.0, '카카오': 0.273}" | ||
190 | + ] | ||
191 | + }, | ||
192 | + "execution_count": 122, | ||
193 | + "metadata": {}, | ||
194 | + "output_type": "execute_result" | ||
195 | + } | ||
196 | + ], | ||
197 | + "source": [ | ||
198 | + "#gmv 포트폴리오 -> 해당 종목을 각각 몇 퍼센트로 투자해야 위험이 제일 적은가\n", | ||
199 | + "c_Models(['삼성전자','LG전자','카카오'],[0,0,0],'2015-01-01','2021-04-01').gmv_opt()" | ||
200 | + ] | ||
201 | + }, | ||
202 | + { | ||
203 | + "cell_type": "code", | ||
204 | + "execution_count": 124, | ||
205 | + "metadata": {}, | ||
206 | + "outputs": [ | ||
207 | + { | ||
208 | + "data": { | ||
209 | + "text/plain": [ | ||
210 | + "{'삼성전자': 0.674, 'LG전자': 0.0, '카카오': 0.326}" | ||
211 | + ] | ||
212 | + }, | ||
213 | + "execution_count": 124, | ||
214 | + "metadata": {}, | ||
215 | + "output_type": "execute_result" | ||
216 | + } | ||
217 | + ], | ||
218 | + "source": [ | ||
219 | + "#maxsharp ratio -> 위험대비 수익률이 제일 좋은 포트폴리오 비중 , 즉 가성비가 좋다\n", | ||
220 | + "c_Models(['삼성전자','LG전자','카카오'],[0,0,0],'2015-01-01','2021-04-01').ms_opt()" | ||
221 | + ] | ||
222 | + }, | ||
223 | + { | ||
224 | + "cell_type": "code", | ||
225 | + "execution_count": 125, | ||
226 | + "metadata": {}, | ||
227 | + "outputs": [ | ||
228 | + { | ||
229 | + "data": { | ||
230 | + "text/plain": [ | ||
231 | + "{'삼성전자': 0.443, 'LG전자': 0.238, '카카오': 0.319}" | ||
232 | + ] | ||
233 | + }, | ||
234 | + "execution_count": 125, | ||
235 | + "metadata": {}, | ||
236 | + "output_type": "execute_result" | ||
237 | + } | ||
238 | + ], | ||
239 | + "source": [ | ||
240 | + "#risk parity -> 포트폴리오에 대한 자산 위험 비중을 동일하게 조정, 즉 삼전,lg,카카오의 포트폴리오 위험 기여도를 0.33으로 하게 만드는 비중\n", | ||
241 | + "c_Models(['삼성전자','LG전자','카카오'],[0,0,0],'2015-01-01','2021-04-01').rp_opt()" | ||
242 | + ] | ||
69 | } | 243 | } |
70 | ], | 244 | ], |
71 | "metadata": { | 245 | "metadata": { | ... | ... |
-
Please register or login to post a comment