ZuseongZIN

feature add: portfoliio optimization , 투자 전략 구현

...@@ -5,18 +5,36 @@ import FinanceDataReader as fdr ...@@ -5,18 +5,36 @@ 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
13 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
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
34 + else:
35 + data = pd.concat([data,tmp], axis=1)
36 +
37 + data.columns = self.asset_name
20 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",''
...@@ -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": {
......