ZuseongZIN

feature add: backtest code (백테스트코드 추가)

...@@ -4,6 +4,17 @@ import numpy as np ...@@ -4,6 +4,17 @@ import numpy as np
4 import FinanceDataReader as fdr 4 import FinanceDataReader as fdr
5 from scipy.optimize import minimize 5 from scipy.optimize import minimize
6 import json 6 import json
7 +from datetime import date
8 +import math
9 +import itertools as it
10 +import operator
11 +from datetime import datetime
12 +from scipy import stats
13 +from scipy.stats import norm
14 +from dateutil import rrule
15 +from calendar import monthrange
16 +from dateutil.relativedelta import relativedelta
17 +from ast import literal_eval
7 18
8 #소숫점 표현 19 #소숫점 표현
9 pd.options.display.float_format = '{:.3f}'.format 20 pd.options.display.float_format = '{:.3f}'.format
...@@ -100,4 +111,472 @@ class c_Models: ...@@ -100,4 +111,472 @@ class c_Models:
100 111
101 rp = minimize(RP_objective, w0, constraints=constraints, bounds = bd, method='SLSQP') 112 rp = minimize(RP_objective, w0, constraints=constraints, bounds = bd, method='SLSQP')
102 result = dict(zip(self.asset_name, np.round(rp.x,3))) 113 result = dict(zip(self.asset_name, np.round(rp.x,3)))
103 - return result #, RC(self.cov, rp.x)
...\ No newline at end of file ...\ No newline at end of file
114 + return result #, RC(self.cov, rp.x)
115 +
116 + def plotting(self):
117 + wt_gmv = np.asarray(list(self.gmv_opt().values()))
118 + wt_ms = np.asarray(list(self.ms_opt().values()))
119 + wt_rp = np.asarray(list(self.rp_opt().values()))
120 +
121 + ret_gmv = np.dot(wt_gmv, self.mu)
122 + ret_ms = np.dot(wt_ms, self.mu)
123 + ret_rp = np.dot(wt_rp, self.mu)
124 + vol_gmv = np.sqrt(np.dot(wt_gmv.T, np.dot(self.cov, wt_gmv)))
125 + vol_ms = np.sqrt(np.dot(wt_ms.T, np.dot(self.cov, wt_ms)))
126 + vol_rp = np.sqrt(np.dot(wt_rp.T, np.dot(self.cov, wt_rp)))
127 +
128 + wt_gmv = wt_gmv.tolist()
129 + wt_ms = wt_ms.tolist()
130 + wt_rp = wt_rp.tolist()
131 +
132 + user_ret = np.dot(self.assets_w, self.mu)
133 + user_risk = np.sqrt(np.dot(self.assets_w, np.dot(self.cov, self.assets_w)))
134 +
135 + weights = {'gmv': wt_gmv, "ms" : wt_ms, "rp": wt_rp}
136 +
137 + #rec_rs = recommended_asset()
138 +
139 + trets = np.linspace(ret_gmv, max(self.mu), 30) # 30개 짜르기
140 + tvols = []
141 +
142 + efpoints = dict()
143 + for i, tret in enumerate(trets): #이 개별 return마다 최소 risk 찾기
144 + n_assets = len(self.data.columns)
145 + w0 = np.ones(n_assets) / n_assets
146 + fun = lambda w: np.dot(w.T ,np.dot(self.cov, w))
147 + constraints = [{'type': 'eq', 'fun': lambda x: np.sum(x) - 1},
148 + {'type': 'ineq', 'fun': lambda x: np.dot(x, self.mu) - tret}]
149 + #{'type': 'ineq', 'fun': lambda x: x}]
150 + bd = ((0,1),) * n_assets
151 +
152 + minvol = minimize(fun, w0, method='SLSQP',bounds = bd, constraints=constraints)
153 + tvols.append(np.sqrt(np.dot(minvol.x, np.dot(self.cov, minvol.x))))
154 +
155 + pnumber = '{}point'.format(i+1)
156 + efpoints[pnumber] = minvol.x.tolist()
157 +
158 + if self.data.shape[0] <= 1:
159 + error = '기간에러'
160 + return error,1,1
161 + else:
162 + ret_vol = {"GMV": [vol_gmv, ret_gmv],"MaxSharp": [vol_ms, ret_ms],"RiskParity": [vol_rp, ret_rp], "Trets" : trets.tolist(), "Tvols": tvols, "User" : [user_risk,user_ret]} #, "Recommended" : rec_rs}
163 + return ret_vol, json.dumps(efpoints), json.dumps(weights)
164 +
165 +
166 +class back_test:
167 + # 단순 일별수익률의 평균을 *365하여 연간수익률을 산출
168 + def __init__(self):
169 + self.test = 0
170 +
171 + def Arithmetic_Mean_Annual(self,ret):
172 + month_return = np.mean(ret)
173 + return (month_return*252)
174 +
175 + # 기간중 투자했을때 하락할 수 있는 비율
176 + def dd(self,ret):
177 + cum_ret = (1 + ret).cumprod()
178 + max_drawdown = 0
179 + max_ret = 1
180 + dd_list = []
181 + c = 0
182 + for ix_ret in cum_ret.values:
183 + if max_ret < ix_ret:
184 + max_ret = ix_ret
185 + dd_list.append((ix_ret - max_ret) / max_ret)
186 + c= c+1
187 + return dd_list
188 +
189 + # 기간중 투자했을때 최고로 많이 하락할 수 있는 비율
190 + def mdd(self,ret):
191 +
192 + cum_ret = (1 + ret).cumprod()
193 + max_drawdown = 0
194 + max_ret = 1
195 + for ix_ret in cum_ret.values:
196 + if max_drawdown > (ix_ret - max_ret) / max_ret:
197 + max_drawdown = (ix_ret - max_ret) / max_ret
198 + if max_ret < ix_ret:
199 + max_ret = ix_ret
200 +
201 + return abs(max_drawdown)
202 +
203 + # 포트폴리오 수익률에서 무위험 수익률을 제한 후 이를 포트폴리오의 표준편차로 나눠 산출한 값, 즉 위험대비 얼마나 수익이 좋은지의 척도
204 + def sharpe_ratio(self,ret, rf=0.008, num_of_date=252):
205 +
206 + return ((np.mean(ret - (rf / num_of_date))) / (np.std(ret))) * np.sqrt(num_of_date)
207 +
208 + # 설정한 confidence level에 따른(95%) 확률로 발생할 수 있는 손실액의 최대 액수
209 + def value_at_risk(self,ret, para_or_hist="para", confidence_level=0.95):
210 +
211 + vol = np.std(ret)
212 + if para_or_hist == "para":
213 + VaR = np.mean(ret) - vol * norm.ppf(confidence_level)
214 + else:
215 + print('error')
216 +
217 + return VaR
218 +
219 + # 전체 투자기간에서 상승한 ( ret > 0 ) 기간의 비율
220 + def winning_rate(self,ret):
221 + var_winning_rate = np.sum(ret > 0) / len(ret)
222 + return var_winning_rate
223 +
224 + # 상승한날의 평균상승값을 하락한날의 평균하락값으로 나눈 비율
225 + def profit_loss_ratio(self,ret):
226 +
227 + if np.sum(ret > 0) == 0:
228 + var_profit_loss_ratio = 0
229 + elif np.sum(ret < 0) == 0:
230 + var_profit_loss_ratio = np.inf
231 + else:
232 + win_mean = np.mean(ret[ret > 0])
233 + loss_mean = np.mean(ret[ret < 0])
234 + var_profit_loss_ratio = win_mean / loss_mean
235 + return abs(var_profit_loss_ratio)
236 +
237 + # 데이터 취합하는 코드
238 + #임시로 5가지 데이터 예시를 활용해 코드작성
239 + # 선택한 종목의 이름과 비중, 투자기간을 input 값으로 받음
240 +
241 + def backtest_data(self, assets,weight,start_data_1, end_data_1,start_amount,rebalancing_month, interval, opt_option):
242 + # input으로 받는 assetnames 입력
243 + a = assets
244 + stock_num = len(a)
245 + # input으로 받는 assetweights 입력
246 + rebal_month = int(rebalancing_month)
247 + # input으로 받는 rebalancing_month를 입력
248 + # 나타내는 데이터 간격을 표시
249 +
250 + # weight 간격
251 + b = list(map(float, weight))
252 +
253 +
254 + # input으로 받는 from_period와 to_period 입력
255 + stock_return = pd.date_range(start=start_data_1, end=end_data_1)
256 + stock_return = pd.DataFrame(stock_return)
257 + stock_return.columns = ['Date']
258 +
259 + stocks = pd.read_csv('stockcodename.csv', index_col=0)
260 + symbol = ''
261 + asset_name = assets[:]
262 + for k in range(len(assets)):
263 + for i in enumerate(stocks.Name):
264 + if i[1] == assets[k]:
265 + assets[k] = (stocks.iloc[i[0]].Symbol)
266 + break
267 +
268 + # input으로 받는 from_period와 to_period 입력
269 + stock_return = pd.date_range(start=start_data_1, end=end_data_1)
270 + stock_return = pd.DataFrame(stock_return)
271 + stock_return.columns = ['Date']
272 +
273 +
274 + for asset in assets: #total_list:
275 + tmp = fdr.DataReader(asset,start_data_1,end_data_1)
276 + tmp.insert(1,"Date",tmp.index.copy(),True)
277 + tmp = tmp[['Date','Change']]
278 + tmp.columns = ['Date',asset]
279 + tmp = tmp.reset_index(drop=True)
280 + stock_return = pd.merge(stock_return,tmp,how='inner', on='Date')
281 +
282 + stock_return = stock_return.dropna(axis=0)
283 +
284 + #print(stock_return)
285 + if opt_option == 'basic' :
286 +
287 + # 투자비중으로 이루어진 dataframe 만들기
288 +
289 + start_datetime = stock_return.iloc[0,0]
290 + end_datetime = stock_return.iloc[-1,0]
291 + diff_months_list = list(rrule.rrule(rrule.MONTHLY, dtstart=start_datetime, until=end_datetime))
292 + month_gap = len(diff_months_list)
293 + rebal_roof = month_gap//rebal_month
294 + rebal_weight = pd.DataFrame()
295 +
296 + for i in range(rebal_roof+1):
297 + # 데이터로부터 리밸런싱기간만큼 가져오기
298 + filtered_df =stock_return.loc[stock_return["Date"].between(start_datetime,
299 + start_datetime + relativedelta(months=rebal_month)+relativedelta(days = -1))]
300 + # 리밸런싱 기간의 누적수익률 산출
301 + for j in range(stock_num):
302 + filtered_df.iloc[:,j+1] = (1 + filtered_df.iloc[:,j+1]).cumprod()
303 + # 해당 누적수익률에 initial 투자비중을 곱해준다
304 + for j in range(stock_num):
305 + filtered_df.iloc[:,j+1] = filtered_df.iloc[:,j+1]*float(b[j])
306 + # 이후 각각의 종목의 비중을 계산해서 산출한다
307 + filtered_df['total_value'] = filtered_df.sum(axis=1)
308 + for j in range(stock_num):
309 + filtered_df.iloc[:,j+1] = filtered_df.iloc[:,j+1]/filtered_df['total_value']
310 +
311 + rebal_weight = pd.concat([rebal_weight,filtered_df])
312 + start_datetime = start_datetime + relativedelta(months=rebal_month)
313 +
314 + #final_day = monthrange(start_datetime.year, start_datetime.month)
315 +
316 + stock_weight = rebal_weight.iloc[:,:-1]
317 + #print(stock_weight)
318 + '''
319 + stock_weight = stock_return.Date
320 + stock_weight = pd.DataFrame(stock_weight)
321 + c = 0
322 + for stockweight in b:
323 + stock_weight[a[c]] = float(stockweight)
324 + c = c + 1
325 + #print(stock_weight)
326 + '''
327 + else :
328 + # 포트폴리오 최적화 코드를 통한 리벨런싱 이중 리스트 weight 산출
329 + # 1. 입력 받은 start ~ end 날짜를 리밸런싱 기간으로 쪼개기
330 + opt_start_datetime = stock_return.iloc[0,0]
331 + opt_end_datetime = stock_return.iloc[-1,0]
332 + opt_diff_months_list = list(rrule.rrule(rrule.MONTHLY, dtstart=opt_start_datetime, until=opt_end_datetime))
333 + opt_month_gap = len(opt_diff_months_list)
334 + opt_rebal_roof = opt_month_gap//rebal_month
335 + opt_rebal_weight = pd.DataFrame()
336 + #opt_array = [[0]*stock_num]*(opt_rebal_roof+1)
337 +
338 + for i in range(opt_rebal_roof+1):
339 + opt_df = stock_return.loc[stock_return["Date"].between(opt_start_datetime,opt_start_datetime + relativedelta(months=rebal_month)+relativedelta(days = -1))]
340 + # 최적화 코드에서 기간마다의 가중치를 가져온다
341 + c_m = c_Models(a,b,opt_df.iat[0,0]- relativedelta(months=3),opt_df.iat[-1,0])
342 + ret_vol, efpoints, weights = c_m.plotting()
343 + weights = literal_eval(weights)
344 + weights = weights.get(opt_option)
345 + ##print(weights)
346 + # 리밸런싱 기간의 누적수익률 산출
347 + for j in range(stock_num):
348 + opt_df.iloc[:,j+1] = (1 + opt_df.iloc[:,j+1]).cumprod()
349 + # 해당 누적수익률에 initial 투자비중을 곱해준다
350 + for j in range(stock_num):
351 + opt_df.iloc[:,j+1] = opt_df.iloc[:,j+1]*float(weights[j])
352 + # 이후 각각의 종목의 비중을 계산해서 산출한다
353 + opt_df['total_value'] = opt_df.sum(axis=1)
354 + for j in range(stock_num):
355 + opt_df.iloc[:,j+1] = opt_df.iloc[:,j+1]/opt_df['total_value']
356 +
357 + # 이후 각각의 종목의 비중을 계산해서 산출한다
358 + #print(opt_df)
359 + opt_rebal_weight = pd.concat([opt_rebal_weight,opt_df])
360 + opt_start_datetime = opt_start_datetime + relativedelta(months=rebal_month)
361 + #리밸런싱으로 start 기간이 고객이 원하는 end 기간보다 커지게 되면 종료
362 + if opt_start_datetime > stock_return.iloc[-1,0]: # i가 100일 때
363 + break
364 + stock_weight = opt_rebal_weight.iloc[:,:-1]
365 + ##print(stock_weight)
366 + # 수익률 데이터와 투자비중을 곱한 하나의 데이터 생성
367 + pfo_return = stock_weight.Date
368 + pfo_return = pd.DataFrame(pfo_return)
369 + # weight 와 return의 날짜 맞춰주기
370 + #pfo_return = pfo_return[0:len(stock_weight)]
371 + pfo_return = pd.merge(pfo_return, stock_return, left_on='Date', right_on='Date', how='left')
372 + pfo_return['mean_return'] = 0
373 + ##print(pfo_return)
374 + for i in range(0,len(pfo_return)):
375 + return_result = list(pfo_return.iloc[i,1:1+stock_num])
376 + return_weight = list(stock_weight.iloc[i,1:1+stock_num])
377 + pfo_return.iloc[i,1+stock_num] = np.dot(return_result,return_weight)
378 + #rint(pfo_return)
379 + pfo_return['acc_return'] = [x+1 for x in pfo_return['mean_return']]
380 + pfo_return['acc_return'] = list(it.accumulate(pfo_return['acc_return'], operator.mul))
381 + pfo_return['acc_return'] = [x-1 for x in pfo_return['acc_return']]
382 + pfo_return['final_balance'] = float(start_amount) + float(start_amount)*pfo_return['acc_return']
383 + pfo_return['Drawdown_list'] = back_test.dd(input,pfo_return['mean_return'])
384 + pfo_return = pfo_return.set_index('Date')
385 + #print(pfo_return)
386 +
387 +
388 + ### 벤치마크 데이터 로드 및 전처리
389 +
390 + tiker_list = ['KS11','US500']
391 + bench_list = [fdr.DataReader(ticker, start_data_1, end_data_1)['Change'] for ticker in tiker_list]
392 + bench = pd.concat(bench_list, axis=1)
393 + bench.columns = ['KOSPI', 'S&P500']
394 + bench['KOSPI'] = bench['KOSPI'].fillna(0)
395 + bench['S&P500'] = bench['S&P500'].fillna(0)
396 + #bench = bench.dropna()
397 +
398 + # 벤치마크 누적수익률, DD 값
399 +
400 + bench['KOSPI_acc'] = [x+1 for x in bench['KOSPI']]
401 + bench['KOSPI_acc'] = list(it.accumulate(bench['KOSPI_acc'], operator.mul))
402 + bench['KOSPI_acc'] = [x-1 for x in bench['KOSPI_acc']]
403 + bench['KOSPI_balance'] = float(start_amount) + float(start_amount)*bench['KOSPI_acc']
404 + bench['KOSPI_Drawdown'] = back_test.dd(input,bench['KOSPI'])
405 + bench['S&P500_acc'] = [x+1 for x in bench['S&P500']]
406 + bench['S&P500_acc'] = list(it.accumulate(bench['S&P500_acc'], operator.mul))
407 + bench['S&P500_acc'] = [x-1 for x in bench['S&P500_acc']]
408 + bench['S&P500_balance'] = float(start_amount) + float(start_amount)*bench['S&P500_acc']
409 + bench['S&P500_Drawdown'] = back_test.dd(input,bench['S&P500'])
410 +
411 + if interval == 'monthly' or interval == 'weekly' :
412 + if interval == 'monthly' :
413 + inter = 'M'
414 + if interval == 'weekly' :
415 + inter = 'W'
416 + pfo_return_interval = pfo_return.resample(inter).last()
417 + pfo_return_first = pd.DataFrame(pfo_return.iloc[0]).transpose()
418 + pfo_return_interval = pd.concat([pfo_return_first, pfo_return_interval])
419 + pfo_return_interval['mean_return'] = pfo_return_interval['final_balance'].pct_change()
420 + pfo_return_interval = pfo_return_interval.dropna()
421 +
422 + # 월별 간격으로 만들어주기, 여기서는 return과 value만 monthly로 산출함 나머지값은 daily
423 + bench_interval = bench.resample(inter).last()
424 + #bench_ex['KOSPI'] = bench_ex['final_balance'].pct_change()
425 + bench_first = pd.DataFrame(bench.iloc[0]).transpose()
426 + bench_interval = pd.concat([bench_first, bench_interval])
427 + bench_interval['KOSPI'] = bench_interval['KOSPI_balance'].pct_change()
428 + bench_interval['S&P500'] = bench_interval['S&P500_balance'].pct_change()
429 + bench_interval = bench_interval.dropna()
430 +
431 + # 날짜타입 열로 만들기 및 str 타입으로 전처리
432 + pfo_return = pfo_return.rename_axis('Date').reset_index()
433 + pfo_return['Date'] = pd.to_datetime(pfo_return['Date'], format='%d/%m/%Y').dt.date
434 + pfo_return['Date'] = list(map(str, pfo_return['Date']))
435 +
436 + pfo_return_interval = pfo_return_interval.rename_axis('Date').reset_index()
437 + pfo_return_interval['Date'] = pd.to_datetime(pfo_return_interval['Date'], format='%d/%m/%Y').dt.date
438 + pfo_return_interval['Date'] = list(map(str, pfo_return_interval['Date']))
439 +
440 + bench = bench.rename_axis('Date').reset_index()
441 + bench['Date'] = pd.to_datetime(bench['Date'], format='%d/%m/%Y').dt.date
442 + bench['Date'] = list(map(str, bench['Date']))
443 +
444 + bench_interval = bench_interval.rename_axis('Date').reset_index()
445 + bench_interval['Date'] = pd.to_datetime(bench_interval['Date'], format='%d/%m/%Y').dt.date
446 + bench_interval['Date'] = list(map(str, bench_interval['Date']))
447 +
448 + backtest_return = {
449 + 'pfo_return': [
450 + {
451 + 'Date': list(pfo_return_interval['Date']),
452 + 'mean_return': list(pfo_return_interval['mean_return']),
453 + 'acc_return ratio': list(pfo_return_interval['acc_return']),
454 + 'final_balance': list(pfo_return_interval['final_balance']),
455 + 'Drawdown_list' : list(pfo_return_interval['Drawdown_list'])
456 + }
457 + ],
458 + 'bench': [
459 + {
460 + 'Date': list(bench_interval['Date']),
461 + 'KOSPI_return': list(bench_interval['KOSPI']),
462 + 'S&P500_return': list(bench_interval['S&P500']),
463 + 'KOSPI_acc_return': list(bench_interval['KOSPI_acc']),
464 + 'KOSPI_balance' : list(bench_interval['KOSPI_balance']),
465 + 'KOSPI_Drawdown': list(bench_interval['KOSPI_Drawdown']),
466 + 'S&P500_acc_return': list(bench_interval['S&P500_acc']),
467 + 'S&P500_balance' : list(bench_interval['S&P500_balance']),
468 + 'S&P500_Drawdown': list(bench_interval['S&P500_Drawdown'])
469 + }
470 + ],
471 + 'indicator': [
472 + {
473 + 'Mean': back_test.Arithmetic_Mean_Annual(input,pfo_return['mean_return']),
474 + 'Std': pfo_return['mean_return'].std() * np.sqrt(365),
475 + 'Sharpe ratio': back_test.sharpe_ratio(input,pfo_return['mean_return']),
476 + 'VaR': back_test.value_at_risk(input,pfo_return['mean_return']),
477 + 'MDD': back_test.mdd(input,pfo_return['mean_return']),
478 + 'Winning ratio': back_test.winning_rate(input,pfo_return['mean_return']),
479 + 'Gain/Loss Ratio': back_test.profit_loss_ratio(input,pfo_return['mean_return'])
480 + }
481 + ],
482 + 'KOSPI_indicator': [
483 + {
484 + 'Mean': back_test.Arithmetic_Mean_Annual(input,bench['KOSPI']),
485 + 'Std': bench['KOSPI'].std() * np.sqrt(365),
486 + 'Sharpe ratio': back_test.sharpe_ratio(input,bench['KOSPI']),
487 + 'VaR': back_test.value_at_risk(input,bench['KOSPI']),
488 + 'MDD': back_test.mdd(input,bench['KOSPI']),
489 + 'Winning ratio': back_test.winning_rate(input,bench['KOSPI']),
490 + 'Gain/Loss Ratio': back_test.profit_loss_ratio(input,bench['KOSPI'])
491 + }
492 + ],
493 + 'S&P500_indicator': [
494 + {
495 + 'Mean': back_test.Arithmetic_Mean_Annual(input,bench['S&P500']),
496 + 'Std': bench['S&P500'].std() * np.sqrt(365),
497 + 'Sharpe ratio': back_test.sharpe_ratio(input,bench['S&P500']),
498 + 'VaR': back_test.value_at_risk(input,bench['S&P500']),
499 + 'MDD': back_test.mdd(input,bench['S&P500']),
500 + 'Winning ratio': back_test.winning_rate(input,bench['S&P500']),
501 + 'Gain/Loss Ratio': back_test.profit_loss_ratio(input,bench['S&P500'])
502 + }
503 + ]
504 + }
505 +
506 + else :
507 + # 날짜타입 열로 만들기 및 str 타입으로 전처리
508 + pfo_return = pfo_return.rename_axis('Date').reset_index()
509 + pfo_return['Date'] = pd.to_datetime(pfo_return['Date'], format='%d/%m/%Y').dt.date
510 + pfo_return['Date'] = list(map(str, pfo_return['Date']))
511 +
512 + bench = bench.rename_axis('Date').reset_index()
513 + bench['Date'] = pd.to_datetime(bench['Date'], format='%d/%m/%Y').dt.date
514 + bench['Date'] = list(map(str, bench['Date']))
515 + backtest_return = {
516 + 'pfo_return': [
517 + {
518 + 'Date': list(pfo_return['Date']),
519 + 'mean_return': list(pfo_return['mean_return']),
520 + 'acc_return ratio': list(pfo_return['acc_return']),
521 + 'final_balance': list(pfo_return['final_balance']),
522 + 'Drawdown_list' : list(pfo_return['Drawdown_list'])
523 + }
524 + ],
525 + 'bench': [
526 + {
527 + 'Date': list(bench['Date']),
528 + 'KOSPI_return': list(bench['KOSPI']),
529 + 'S&P500_return': list(bench['S&P500']),
530 + 'KOSPI_acc_return': list(bench['KOSPI_acc']),
531 + 'KOSPI_balance' : list(bench['KOSPI_balance']),
532 + 'KOSPI_Drawdown': list(bench['KOSPI_Drawdown']),
533 + 'S&P500_acc_return': list(bench['S&P500_acc']),
534 + 'S&P500_balance' : list(bench['S&P500_balance']),
535 + 'S&P500_Drawdown': list(bench['S&P500_Drawdown'])
536 + }
537 + ],
538 + 'indicator': [
539 + {
540 + 'Mean': back_test.Arithmetic_Mean_Annual(input,pfo_return['mean_return']),
541 + 'Std': pfo_return['mean_return'].std() * np.sqrt(365),
542 + 'Sharpe ratio': back_test.sharpe_ratio(input,pfo_return['mean_return']),
543 + 'VaR': back_test.value_at_risk(input,pfo_return['mean_return']),
544 + 'MDD': back_test.mdd(input,pfo_return['mean_return']),
545 + 'Winning ratio': back_test.winning_rate(input,pfo_return['mean_return']),
546 + 'Gain/Loss Ratio': back_test.profit_loss_ratio(input,pfo_return['mean_return'])
547 + }
548 + ],
549 + 'KOSPI_indicator': [
550 + {
551 + 'Mean': back_test.Arithmetic_Mean_Annual(input,bench['KOSPI']),
552 + 'Std': bench['KOSPI'].std() * np.sqrt(365),
553 + 'Sharpe ratio': back_test.sharpe_ratio(input,bench['KOSPI']),
554 + 'VaR': back_test.value_at_risk(input,bench['KOSPI']),
555 + 'MDD': back_test.mdd(input,bench['KOSPI']),
556 + 'Winning ratio': back_test.winning_rate(input,bench['KOSPI']),
557 + 'Gain/Loss Ratio': back_test.profit_loss_ratio(input,bench['KOSPI'])
558 + }
559 + ],
560 + 'S&P500_indicator': [
561 + {
562 + 'Mean': back_test.Arithmetic_Mean_Annual(input,bench['S&P500']),
563 + 'Std': bench['S&P500'].std() * np.sqrt(365),
564 + 'Sharpe ratio': back_test.sharpe_ratio(input,bench['S&P500']),
565 + 'VaR': back_test.value_at_risk(input,bench['S&P500']),
566 + 'MDD': back_test.mdd(input,bench['S&P500']),
567 + 'Winning ratio': back_test.winning_rate(input,bench['S&P500']),
568 + 'Gain/Loss Ratio': back_test.profit_loss_ratio(input,bench['S&P500'])
569 + }
570 + ]
571 + }
572 +
573 + return backtest_return
574 +
575 +
576 +
577 +print(back_test().backtest_data(['삼성전자','LG전자'],[0.9,0.1],'2010-01-01', '2021-01-01',10000000,3, 'monthly', 'gmv')['pfo_return'].mean_return)
578 +
579 +
580 +
581 +
582 +
......
This diff could not be displayed because it is too large.
...@@ -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": 2, 5 + "execution_count": 1,
6 "metadata": {}, 6 "metadata": {},
7 "outputs": [], 7 "outputs": [],
8 "source": [ 8 "source": [
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
13 }, 13 },
14 { 14 {
15 "cell_type": "code", 15 "cell_type": "code",
16 - "execution_count": 41, 16 + "execution_count": 2,
17 "metadata": {}, 17 "metadata": {},
18 "outputs": [], 18 "outputs": [],
19 "source": [ 19 "source": [
...@@ -42,14 +42,14 @@ ...@@ -42,14 +42,14 @@
42 }, 42 },
43 { 43 {
44 "cell_type": "code", 44 "cell_type": "code",
45 - "execution_count": 42, 45 + "execution_count": 4,
46 "metadata": {}, 46 "metadata": {},
47 "outputs": [ 47 "outputs": [
48 { 48 {
49 "name": "stdout", 49 "name": "stdout",
50 "output_type": "stream", 50 "output_type": "stream",
51 "text": [ 51 "text": [
52 - "{'현재가': 79700, '거래랑': 13358073, '전일 대비 수익률:': -0.004993757802746579}\n" 52 + "{'현재가': 82800, '거래랑': 29341312, '전일 대비 수익률:': 0.024752475247524774}\n"
53 ] 53 ]
54 } 54 }
55 ], 55 ],
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
59 }, 59 },
60 { 60 {
61 "cell_type": "code", 61 "cell_type": "code",
62 - "execution_count": 6, 62 + "execution_count": 5,
63 "metadata": {}, 63 "metadata": {},
64 "outputs": [], 64 "outputs": [],
65 "source": [ 65 "source": [
...@@ -69,7 +69,7 @@ ...@@ -69,7 +69,7 @@
69 }, 69 },
70 { 70 {
71 "cell_type": "code", 71 "cell_type": "code",
72 - "execution_count": 123, 72 + "execution_count": 3,
73 "metadata": {}, 73 "metadata": {},
74 "outputs": [], 74 "outputs": [],
75 "source": [ 75 "source": [
...@@ -79,6 +79,17 @@ ...@@ -79,6 +79,17 @@
79 "import FinanceDataReader as fdr\n", 79 "import FinanceDataReader as fdr\n",
80 "from scipy.optimize import minimize\n", 80 "from scipy.optimize import minimize\n",
81 "import json\n", 81 "import json\n",
82 + "from datetime import date\n",
83 + "import math\n",
84 + "import itertools as it\n",
85 + "import operator\n",
86 + "from datetime import datetime\n",
87 + "from scipy import stats\n",
88 + "from scipy.stats import norm\n",
89 + "from dateutil import rrule\n",
90 + "from calendar import monthrange\n",
91 + "from dateutil.relativedelta import relativedelta\n",
92 + "from ast import literal_eval\n",
82 "\n", 93 "\n",
83 "#소숫점 표현\n", 94 "#소숫점 표현\n",
84 "pd.options.display.float_format = '{:.3f}'.format\n", 95 "pd.options.display.float_format = '{:.3f}'.format\n",
...@@ -175,33 +186,567 @@ ...@@ -175,33 +186,567 @@
175 "\n", 186 "\n",
176 " rp = minimize(RP_objective, w0, constraints=constraints, bounds = bd, method='SLSQP')\n", 187 " 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", 188 " result = dict(zip(self.asset_name, np.round(rp.x,3)))\n",
178 - " return result #, RC(self.cov, rp.x)" 189 + " return result #, RC(self.cov, rp.x)\n",
190 + "\n",
191 + " def plotting(self):\n",
192 + " wt_gmv = np.asarray(list(self.gmv_opt().values()))\n",
193 + " wt_ms = np.asarray(list(self.ms_opt().values()))\n",
194 + " wt_rp = np.asarray(list(self.rp_opt().values()))\n",
195 + " \n",
196 + " ret_gmv = np.dot(wt_gmv, self.mu)\n",
197 + " ret_ms = np.dot(wt_ms, self.mu)\n",
198 + " ret_rp = np.dot(wt_rp, self.mu)\n",
199 + " vol_gmv = np.sqrt(np.dot(wt_gmv.T, np.dot(self.cov, wt_gmv)))\n",
200 + " vol_ms = np.sqrt(np.dot(wt_ms.T, np.dot(self.cov, wt_ms)))\n",
201 + " vol_rp = np.sqrt(np.dot(wt_rp.T, np.dot(self.cov, wt_rp)))\n",
202 + " \n",
203 + " wt_gmv = wt_gmv.tolist()\n",
204 + " wt_ms = wt_ms.tolist()\n",
205 + " wt_rp = wt_rp.tolist()\n",
206 + " \n",
207 + " user_ret = np.dot(self.assets_w, self.mu)\n",
208 + " user_risk = np.sqrt(np.dot(self.assets_w, np.dot(self.cov, self.assets_w)))\n",
209 + "\n",
210 + " weights = {'gmv': wt_gmv, \"ms\" : wt_ms, \"rp\": wt_rp}\n",
211 + " \n",
212 + " #rec_rs = recommended_asset()\n",
213 + "\n",
214 + " trets = np.linspace(ret_gmv, max(self.mu), 30) # 30개 짜르기 \n",
215 + " tvols = []\n",
216 + " \n",
217 + " efpoints = dict()\n",
218 + " for i, tret in enumerate(trets): #이 개별 return마다 최소 risk 찾기\n",
219 + " n_assets = len(self.data.columns)\n",
220 + " w0 = np.ones(n_assets) / n_assets\n",
221 + " fun = lambda w: np.dot(w.T ,np.dot(self.cov, w))\n",
222 + " constraints = [{'type': 'eq', 'fun': lambda x: np.sum(x) - 1},\n",
223 + " {'type': 'ineq', 'fun': lambda x: np.dot(x, self.mu) - tret}]\n",
224 + " #{'type': 'ineq', 'fun': lambda x: x}]\n",
225 + " bd = ((0,1),) * n_assets\n",
226 + "\n",
227 + " minvol = minimize(fun, w0, method='SLSQP',bounds = bd, constraints=constraints)\n",
228 + " tvols.append(np.sqrt(np.dot(minvol.x, np.dot(self.cov, minvol.x))))\n",
229 + " \n",
230 + " pnumber = '{}point'.format(i+1)\n",
231 + " efpoints[pnumber] = minvol.x.tolist()\n",
232 + " \n",
233 + " if self.data.shape[0] <= 1:\n",
234 + " error = '기간에러'\n",
235 + " return error,1,1\n",
236 + " else:\n",
237 + " ret_vol = {\"GMV\": [vol_gmv, ret_gmv],\"MaxSharp\": [vol_ms, ret_ms],\"RiskParity\": [vol_rp, ret_rp], \"Trets\" : trets.tolist(), \"Tvols\": tvols, \"User\" : [user_risk,user_ret]} #, \"Recommended\" : rec_rs} \n",
238 + " return ret_vol, json.dumps(efpoints), json.dumps(weights)"
179 ] 239 ]
180 }, 240 },
181 { 241 {
182 "cell_type": "code", 242 "cell_type": "code",
183 - "execution_count": 122, 243 + "execution_count": 8,
184 "metadata": {}, 244 "metadata": {},
245 + "outputs": [],
246 + "source": [
247 + "class back_test:\n",
248 + " # 단순 일별수익률의 평균을 *365하여 연간수익률을 산출\n",
249 + " def __init__(self):\n",
250 + " self.test = 0\n",
251 + " \n",
252 + " def Arithmetic_Mean_Annual(self,ret):\n",
253 + " month_return = np.mean(ret)\n",
254 + " return (month_return*252)\n",
255 + "\n",
256 + " # 기간중 투자했을때 하락할 수 있는 비율\n",
257 + " def dd(self,ret):\n",
258 + " cum_ret = (1 + ret).cumprod()\n",
259 + " max_drawdown = 0\n",
260 + " max_ret = 1\n",
261 + " dd_list = []\n",
262 + " c = 0\n",
263 + " for ix_ret in cum_ret.values:\n",
264 + " if max_ret < ix_ret:\n",
265 + " max_ret = ix_ret\n",
266 + " dd_list.append((ix_ret - max_ret) / max_ret) \n",
267 + " c= c+1\n",
268 + " return dd_list\n",
269 + " \n",
270 + " # 기간중 투자했을때 최고로 많이 하락할 수 있는 비율\n",
271 + " def mdd(self,ret):\n",
272 + " \n",
273 + " cum_ret = (1 + ret).cumprod()\n",
274 + " max_drawdown = 0\n",
275 + " max_ret = 1\n",
276 + " for ix_ret in cum_ret.values:\n",
277 + " if max_drawdown > (ix_ret - max_ret) / max_ret:\n",
278 + " max_drawdown = (ix_ret - max_ret) / max_ret\n",
279 + " if max_ret < ix_ret:\n",
280 + " max_ret = ix_ret\n",
281 + "\n",
282 + " return abs(max_drawdown)\n",
283 + "\n",
284 + " # 포트폴리오 수익률에서 무위험 수익률을 제한 후 이를 포트폴리오의 표준편차로 나눠 산출한 값, 즉 위험대비 얼마나 수익이 좋은지의 척도\n",
285 + " def sharpe_ratio(self,ret, rf=0.008, num_of_date=252):\n",
286 + " \n",
287 + " return ((np.mean(ret - (rf / num_of_date))) / (np.std(ret))) * np.sqrt(num_of_date)\n",
288 + " \n",
289 + " # 설정한 confidence level에 따른(95%) 확률로 발생할 수 있는 손실액의 최대 액수\n",
290 + " def value_at_risk(self,ret, para_or_hist=\"para\", confidence_level=0.95):\n",
291 + " \n",
292 + " vol = np.std(ret)\n",
293 + " if para_or_hist == \"para\":\n",
294 + " VaR = np.mean(ret) - vol * norm.ppf(confidence_level)\n",
295 + " else:\n",
296 + " print('error')\n",
297 + "\n",
298 + " return VaR\n",
299 + " \n",
300 + " # 전체 투자기간에서 상승한 ( ret > 0 ) 기간의 비율\n",
301 + " def winning_rate(self,ret):\n",
302 + " var_winning_rate = np.sum(ret > 0) / len(ret)\n",
303 + " return var_winning_rate \n",
304 + " \n",
305 + " # 상승한날의 평균상승값을 하락한날의 평균하락값으로 나눈 비율\n",
306 + " def profit_loss_ratio(self,ret):\n",
307 + "\n",
308 + " if np.sum(ret > 0) == 0:\n",
309 + " var_profit_loss_ratio = 0\n",
310 + " elif np.sum(ret < 0) == 0:\n",
311 + " var_profit_loss_ratio = np.inf\n",
312 + " else:\n",
313 + " win_mean = np.mean(ret[ret > 0])\n",
314 + " loss_mean = np.mean(ret[ret < 0])\n",
315 + " var_profit_loss_ratio = win_mean / loss_mean\n",
316 + " return abs(var_profit_loss_ratio)\n",
317 + "\n",
318 + " # 데이터 취합하는 코드 \n",
319 + " #임시로 5가지 데이터 예시를 활용해 코드작성\n",
320 + " # 선택한 종목의 이름과 비중, 투자기간을 input 값으로 받음 \n",
321 + " \n",
322 + " def backtest_data(self, assets,weight,start_data_1, end_data_1,start_amount,rebalancing_month, interval, opt_option):\n",
323 + " # input으로 받는 assetnames 입력\n",
324 + " a = assets\n",
325 + " stock_num = len(a)\n",
326 + " # input으로 받는 assetweights 입력\n",
327 + " rebal_month = int(rebalancing_month)\n",
328 + " # input으로 받는 rebalancing_month를 입력\n",
329 + " # 나타내는 데이터 간격을 표시\n",
330 + "\n",
331 + " # weight 간격 \n",
332 + " b = list(map(float, weight))\n",
333 + " \n",
334 + "\n",
335 + " # input으로 받는 from_period와 to_period 입력\n",
336 + " stock_return = pd.date_range(start=start_data_1, end=end_data_1)\n",
337 + " stock_return = pd.DataFrame(stock_return)\n",
338 + " stock_return.columns = ['Date']\n",
339 + "\n",
340 + " stocks = pd.read_csv('stockcodename.csv', index_col=0)\n",
341 + " symbol = ''\n",
342 + " asset_name = assets[:]\n",
343 + " for k in range(len(assets)):\n",
344 + " for i in enumerate(stocks.Name):\n",
345 + " if i[1] == assets[k]:\n",
346 + " assets[k] = (stocks.iloc[i[0]].Symbol)\n",
347 + " break\n",
348 + " \n",
349 + " # input으로 받는 from_period와 to_period 입력\n",
350 + " stock_return = pd.date_range(start=start_data_1, end=end_data_1)\n",
351 + " stock_return = pd.DataFrame(stock_return)\n",
352 + " stock_return.columns = ['Date']\n",
353 + " \n",
354 + "\n",
355 + " for asset in assets: #total_list:\n",
356 + " tmp = fdr.DataReader(asset,start_data_1,end_data_1)\n",
357 + " tmp.insert(1,\"Date\",tmp.index.copy(),True)\n",
358 + " tmp = tmp[['Date','Change']]\n",
359 + " tmp.columns = ['Date',asset]\n",
360 + " tmp = tmp.reset_index(drop=True)\n",
361 + " stock_return = pd.merge(stock_return,tmp,how='inner', on='Date')\n",
362 + "\n",
363 + " stock_return = stock_return.dropna(axis=0)\n",
364 + "\n",
365 + " #print(stock_return)\n",
366 + " if opt_option == 'basic' :\n",
367 + "\n",
368 + " # 투자비중으로 이루어진 dataframe 만들기\n",
369 + "\n",
370 + " start_datetime = stock_return.iloc[0,0]\n",
371 + " end_datetime = stock_return.iloc[-1,0]\n",
372 + " diff_months_list = list(rrule.rrule(rrule.MONTHLY, dtstart=start_datetime, until=end_datetime))\n",
373 + " month_gap = len(diff_months_list)\n",
374 + " rebal_roof = month_gap//rebal_month\n",
375 + " rebal_weight = pd.DataFrame()\n",
376 + "\n",
377 + " for i in range(rebal_roof+1):\n",
378 + " # 데이터로부터 리밸런싱기간만큼 가져오기\n",
379 + " filtered_df =stock_return.loc[stock_return[\"Date\"].between(start_datetime, \n",
380 + " start_datetime + relativedelta(months=rebal_month)+relativedelta(days = -1))]\n",
381 + " # 리밸런싱 기간의 누적수익률 산출\n",
382 + " for j in range(stock_num):\n",
383 + " filtered_df.iloc[:,j+1] = (1 + filtered_df.iloc[:,j+1]).cumprod()\n",
384 + " # 해당 누적수익률에 initial 투자비중을 곱해준다 \n",
385 + " for j in range(stock_num):\n",
386 + " filtered_df.iloc[:,j+1] = filtered_df.iloc[:,j+1]*float(b[j])\n",
387 + " # 이후 각각의 종목의 비중을 계산해서 산출한다\n",
388 + " filtered_df['total_value'] = filtered_df.sum(axis=1)\n",
389 + " for j in range(stock_num):\n",
390 + " filtered_df.iloc[:,j+1] = filtered_df.iloc[:,j+1]/filtered_df['total_value']\n",
391 + "\n",
392 + " rebal_weight = pd.concat([rebal_weight,filtered_df])\n",
393 + " start_datetime = start_datetime + relativedelta(months=rebal_month)\n",
394 + "\n",
395 + " #final_day = monthrange(start_datetime.year, start_datetime.month)\n",
396 + "\n",
397 + " stock_weight = rebal_weight.iloc[:,:-1]\n",
398 + " #print(stock_weight)\n",
399 + " '''\n",
400 + " stock_weight = stock_return.Date\n",
401 + " stock_weight = pd.DataFrame(stock_weight)\n",
402 + " c = 0\n",
403 + " for stockweight in b:\n",
404 + " stock_weight[a[c]] = float(stockweight)\n",
405 + " c = c + 1\n",
406 + " #print(stock_weight)\n",
407 + " '''\n",
408 + " else :\n",
409 + " # 포트폴리오 최적화 코드를 통한 리벨런싱 이중 리스트 weight 산출\n",
410 + " # 1. 입력 받은 start ~ end 날짜를 리밸런싱 기간으로 쪼개기 \n",
411 + " opt_start_datetime = stock_return.iloc[0,0]\n",
412 + " opt_end_datetime = stock_return.iloc[-1,0]\n",
413 + " opt_diff_months_list = list(rrule.rrule(rrule.MONTHLY, dtstart=opt_start_datetime, until=opt_end_datetime))\n",
414 + " opt_month_gap = len(opt_diff_months_list)\n",
415 + " opt_rebal_roof = opt_month_gap//rebal_month\n",
416 + " opt_rebal_weight = pd.DataFrame()\n",
417 + " #opt_array = [[0]*stock_num]*(opt_rebal_roof+1)\n",
418 + "\n",
419 + " for i in range(opt_rebal_roof+1):\n",
420 + " opt_df = stock_return.loc[stock_return[\"Date\"].between(opt_start_datetime,opt_start_datetime + relativedelta(months=rebal_month)+relativedelta(days = -1))]\n",
421 + " # 최적화 코드에서 기간마다의 가중치를 가져온다\n",
422 + " c_m = c_Models(a,b,opt_df.iat[0,0]- relativedelta(months=3),opt_df.iat[-1,0])\n",
423 + " ret_vol, efpoints, weights = c_m.plotting()\n",
424 + " weights = literal_eval(weights)\n",
425 + " weights = weights.get(opt_option)\n",
426 + " ##print(weights)\n",
427 + " # 리밸런싱 기간의 누적수익률 산출\n",
428 + " for j in range(stock_num):\n",
429 + " opt_df.iloc[:,j+1] = (1 + opt_df.iloc[:,j+1]).cumprod()\n",
430 + " # 해당 누적수익률에 initial 투자비중을 곱해준다 \n",
431 + " for j in range(stock_num):\n",
432 + " opt_df.iloc[:,j+1] = opt_df.iloc[:,j+1]*float(weights[j])\n",
433 + " # 이후 각각의 종목의 비중을 계산해서 산출한다\n",
434 + " opt_df['total_value'] = opt_df.sum(axis=1)\n",
435 + " for j in range(stock_num):\n",
436 + " opt_df.iloc[:,j+1] = opt_df.iloc[:,j+1]/opt_df['total_value']\n",
437 + "\n",
438 + " # 이후 각각의 종목의 비중을 계산해서 산출한다\n",
439 + " #print(opt_df)\n",
440 + " opt_rebal_weight = pd.concat([opt_rebal_weight,opt_df])\n",
441 + " opt_start_datetime = opt_start_datetime + relativedelta(months=rebal_month)\n",
442 + " #리밸런싱으로 start 기간이 고객이 원하는 end 기간보다 커지게 되면 종료 \n",
443 + " if opt_start_datetime > stock_return.iloc[-1,0]: # i가 100일 때\n",
444 + " break \n",
445 + " stock_weight = opt_rebal_weight.iloc[:,:-1]\n",
446 + " ##print(stock_weight)\n",
447 + " # 수익률 데이터와 투자비중을 곱한 하나의 데이터 생성 \n",
448 + " pfo_return = stock_weight.Date\n",
449 + " pfo_return = pd.DataFrame(pfo_return)\n",
450 + " # weight 와 return의 날짜 맞춰주기 \n",
451 + " #pfo_return = pfo_return[0:len(stock_weight)]\n",
452 + " pfo_return = pd.merge(pfo_return, stock_return, left_on='Date', right_on='Date', how='left')\n",
453 + " pfo_return['mean_return'] = 0\n",
454 + " ##print(pfo_return)\n",
455 + " for i in range(0,len(pfo_return)):\n",
456 + " return_result = list(pfo_return.iloc[i,1:1+stock_num])\n",
457 + " return_weight = list(stock_weight.iloc[i,1:1+stock_num])\n",
458 + " pfo_return.iloc[i,1+stock_num] = np.dot(return_result,return_weight)\n",
459 + " #rint(pfo_return)\n",
460 + " pfo_return['acc_return'] = [x+1 for x in pfo_return['mean_return']]\n",
461 + " pfo_return['acc_return'] = list(it.accumulate(pfo_return['acc_return'], operator.mul))\n",
462 + " pfo_return['acc_return'] = [x-1 for x in pfo_return['acc_return']]\n",
463 + " pfo_return['final_balance'] = float(start_amount) + float(start_amount)*pfo_return['acc_return']\n",
464 + " pfo_return['Drawdown_list'] = back_test.dd(input,pfo_return['mean_return'])\n",
465 + " pfo_return = pfo_return.set_index('Date') \n",
466 + " #print(pfo_return)\n",
467 + " \n",
468 + " \n",
469 + " ### 벤치마크 데이터 로드 및 전처리\n",
470 + " \n",
471 + " tiker_list = ['KS11','US500'] \n",
472 + " bench_list = [fdr.DataReader(ticker, start_data_1, end_data_1)['Change'] for ticker in tiker_list]\n",
473 + " bench = pd.concat(bench_list, axis=1)\n",
474 + " bench.columns = ['KOSPI', 'S&P500']\n",
475 + " bench['KOSPI'] = bench['KOSPI'].fillna(0)\n",
476 + " bench['S&P500'] = bench['S&P500'].fillna(0)\n",
477 + " #bench = bench.dropna()\n",
478 + " \n",
479 + " # 벤치마크 누적수익률, DD 값 \n",
480 + " \n",
481 + " bench['KOSPI_acc'] = [x+1 for x in bench['KOSPI']]\n",
482 + " bench['KOSPI_acc'] = list(it.accumulate(bench['KOSPI_acc'], operator.mul))\n",
483 + " bench['KOSPI_acc'] = [x-1 for x in bench['KOSPI_acc']]\n",
484 + " bench['KOSPI_balance'] = float(start_amount) + float(start_amount)*bench['KOSPI_acc']\n",
485 + " bench['KOSPI_Drawdown'] = back_test.dd(input,bench['KOSPI'])\n",
486 + " bench['S&P500_acc'] = [x+1 for x in bench['S&P500']]\n",
487 + " bench['S&P500_acc'] = list(it.accumulate(bench['S&P500_acc'], operator.mul))\n",
488 + " bench['S&P500_acc'] = [x-1 for x in bench['S&P500_acc']]\n",
489 + " bench['S&P500_balance'] = float(start_amount) + float(start_amount)*bench['S&P500_acc']\n",
490 + " bench['S&P500_Drawdown'] = back_test.dd(input,bench['S&P500'])\n",
491 + " \n",
492 + " if interval == 'monthly' or interval == 'weekly' :\n",
493 + " if interval == 'monthly' :\n",
494 + " inter = 'M'\n",
495 + " if interval == 'weekly' :\n",
496 + " inter = 'W'\n",
497 + " pfo_return_interval = pfo_return.resample(inter).last()\n",
498 + " pfo_return_first = pd.DataFrame(pfo_return.iloc[0]).transpose()\n",
499 + " pfo_return_interval = pd.concat([pfo_return_first, pfo_return_interval])\n",
500 + " pfo_return_interval['mean_return'] = pfo_return_interval['final_balance'].pct_change()\n",
501 + " pfo_return_interval = pfo_return_interval.dropna()\n",
502 + " \n",
503 + " # 월별 간격으로 만들어주기, 여기서는 return과 value만 monthly로 산출함 나머지값은 daily\n",
504 + " bench_interval = bench.resample(inter).last()\n",
505 + " #bench_ex['KOSPI'] = bench_ex['final_balance'].pct_change()\n",
506 + " bench_first = pd.DataFrame(bench.iloc[0]).transpose()\n",
507 + " bench_interval = pd.concat([bench_first, bench_interval])\n",
508 + " bench_interval['KOSPI'] = bench_interval['KOSPI_balance'].pct_change()\n",
509 + " bench_interval['S&P500'] = bench_interval['S&P500_balance'].pct_change()\n",
510 + " bench_interval = bench_interval.dropna()\n",
511 + " \n",
512 + " # 날짜타입 열로 만들기 및 str 타입으로 전처리 \n",
513 + " pfo_return = pfo_return.rename_axis('Date').reset_index()\n",
514 + " pfo_return['Date'] = pd.to_datetime(pfo_return['Date'], format='%d/%m/%Y').dt.date\n",
515 + " pfo_return['Date'] = list(map(str, pfo_return['Date']))\n",
516 + " \n",
517 + " pfo_return_interval = pfo_return_interval.rename_axis('Date').reset_index()\n",
518 + " pfo_return_interval['Date'] = pd.to_datetime(pfo_return_interval['Date'], format='%d/%m/%Y').dt.date\n",
519 + " pfo_return_interval['Date'] = list(map(str, pfo_return_interval['Date']))\n",
520 + " \n",
521 + " bench = bench.rename_axis('Date').reset_index()\n",
522 + " bench['Date'] = pd.to_datetime(bench['Date'], format='%d/%m/%Y').dt.date\n",
523 + " bench['Date'] = list(map(str, bench['Date'])) \n",
524 + " \n",
525 + " bench_interval = bench_interval.rename_axis('Date').reset_index()\n",
526 + " bench_interval['Date'] = pd.to_datetime(bench_interval['Date'], format='%d/%m/%Y').dt.date\n",
527 + " bench_interval['Date'] = list(map(str, bench_interval['Date'])) \n",
528 + " \n",
529 + " backtest_return = {\n",
530 + " 'pfo_return': [\n",
531 + " {\n",
532 + " 'Date': list(pfo_return_interval['Date']),\n",
533 + " 'mean_return': list(pfo_return_interval['mean_return']), \n",
534 + " 'acc_return ratio': list(pfo_return_interval['acc_return']),\n",
535 + " 'final_balance': list(pfo_return_interval['final_balance']),\n",
536 + " 'Drawdown_list' : list(pfo_return_interval['Drawdown_list'])\n",
537 + " }\n",
538 + " ], \n",
539 + " 'bench': [\n",
540 + " {\n",
541 + " 'Date': list(bench_interval['Date']),\n",
542 + " 'KOSPI_return': list(bench_interval['KOSPI']), \n",
543 + " 'S&P500_return': list(bench_interval['S&P500']),\n",
544 + " 'KOSPI_acc_return': list(bench_interval['KOSPI_acc']),\n",
545 + " 'KOSPI_balance' : list(bench_interval['KOSPI_balance']), \n",
546 + " 'KOSPI_Drawdown': list(bench_interval['KOSPI_Drawdown']),\n",
547 + " 'S&P500_acc_return': list(bench_interval['S&P500_acc']),\n",
548 + " 'S&P500_balance' : list(bench_interval['S&P500_balance']), \n",
549 + " 'S&P500_Drawdown': list(bench_interval['S&P500_Drawdown'])\n",
550 + " }\n",
551 + " ], \n",
552 + " 'indicator': [\n",
553 + " {\n",
554 + " 'Mean': back_test.Arithmetic_Mean_Annual(input,pfo_return['mean_return']),\n",
555 + " 'Std': pfo_return['mean_return'].std() * np.sqrt(365), \n",
556 + " 'Sharpe ratio': back_test.sharpe_ratio(input,pfo_return['mean_return']),\n",
557 + " 'VaR': back_test.value_at_risk(input,pfo_return['mean_return']),\n",
558 + " 'MDD': back_test.mdd(input,pfo_return['mean_return']),\n",
559 + " 'Winning ratio': back_test.winning_rate(input,pfo_return['mean_return']),\n",
560 + " 'Gain/Loss Ratio': back_test.profit_loss_ratio(input,pfo_return['mean_return'])\n",
561 + " }\n",
562 + " ], \n",
563 + " 'KOSPI_indicator': [\n",
564 + " {\n",
565 + " 'Mean': back_test.Arithmetic_Mean_Annual(input,bench['KOSPI']),\n",
566 + " 'Std': bench['KOSPI'].std() * np.sqrt(365), \n",
567 + " 'Sharpe ratio': back_test.sharpe_ratio(input,bench['KOSPI']),\n",
568 + " 'VaR': back_test.value_at_risk(input,bench['KOSPI']),\n",
569 + " 'MDD': back_test.mdd(input,bench['KOSPI']),\n",
570 + " 'Winning ratio': back_test.winning_rate(input,bench['KOSPI']),\n",
571 + " 'Gain/Loss Ratio': back_test.profit_loss_ratio(input,bench['KOSPI'])\n",
572 + " }\n",
573 + " ], \n",
574 + " 'S&P500_indicator': [\n",
575 + " {\n",
576 + " 'Mean': back_test.Arithmetic_Mean_Annual(input,bench['S&P500']),\n",
577 + " 'Std': bench['S&P500'].std() * np.sqrt(365), \n",
578 + " 'Sharpe ratio': back_test.sharpe_ratio(input,bench['S&P500']),\n",
579 + " 'VaR': back_test.value_at_risk(input,bench['S&P500']),\n",
580 + " 'MDD': back_test.mdd(input,bench['S&P500']),\n",
581 + " 'Winning ratio': back_test.winning_rate(input,bench['S&P500']),\n",
582 + " 'Gain/Loss Ratio': back_test.profit_loss_ratio(input,bench['S&P500'])\n",
583 + " }\n",
584 + " ]\n",
585 + " } \n",
586 + " \n",
587 + " else :\n",
588 + " # 날짜타입 열로 만들기 및 str 타입으로 전처리 \n",
589 + " pfo_return = pfo_return.rename_axis('Date').reset_index()\n",
590 + " pfo_return['Date'] = pd.to_datetime(pfo_return['Date'], format='%d/%m/%Y').dt.date\n",
591 + " pfo_return['Date'] = list(map(str, pfo_return['Date']))\n",
592 + " \n",
593 + " bench = bench.rename_axis('Date').reset_index()\n",
594 + " bench['Date'] = pd.to_datetime(bench['Date'], format='%d/%m/%Y').dt.date\n",
595 + " bench['Date'] = list(map(str, bench['Date']))\n",
596 + " backtest_return = {\n",
597 + " 'pfo_return': [\n",
598 + " {\n",
599 + " 'Date': list(pfo_return['Date']),\n",
600 + " 'mean_return': list(pfo_return['mean_return']), \n",
601 + " 'acc_return ratio': list(pfo_return['acc_return']),\n",
602 + " 'final_balance': list(pfo_return['final_balance']),\n",
603 + " 'Drawdown_list' : list(pfo_return['Drawdown_list'])\n",
604 + " }\n",
605 + " ], \n",
606 + " 'bench': [\n",
607 + " {\n",
608 + " 'Date': list(bench['Date']),\n",
609 + " 'KOSPI_return': list(bench['KOSPI']), \n",
610 + " 'S&P500_return': list(bench['S&P500']),\n",
611 + " 'KOSPI_acc_return': list(bench['KOSPI_acc']),\n",
612 + " 'KOSPI_balance' : list(bench['KOSPI_balance']), \n",
613 + " 'KOSPI_Drawdown': list(bench['KOSPI_Drawdown']),\n",
614 + " 'S&P500_acc_return': list(bench['S&P500_acc']),\n",
615 + " 'S&P500_balance' : list(bench['S&P500_balance']), \n",
616 + " 'S&P500_Drawdown': list(bench['S&P500_Drawdown'])\n",
617 + " }\n",
618 + " ], \n",
619 + " 'indicator': [\n",
620 + " {\n",
621 + " 'Mean': back_test.Arithmetic_Mean_Annual(input,pfo_return['mean_return']),\n",
622 + " 'Std': pfo_return['mean_return'].std() * np.sqrt(365), \n",
623 + " 'Sharpe ratio': back_test.sharpe_ratio(input,pfo_return['mean_return']),\n",
624 + " 'VaR': back_test.value_at_risk(input,pfo_return['mean_return']),\n",
625 + " 'MDD': back_test.mdd(input,pfo_return['mean_return']),\n",
626 + " 'Winning ratio': back_test.winning_rate(input,pfo_return['mean_return']),\n",
627 + " 'Gain/Loss Ratio': back_test.profit_loss_ratio(input,pfo_return['mean_return'])\n",
628 + " }\n",
629 + " ], \n",
630 + " 'KOSPI_indicator': [\n",
631 + " {\n",
632 + " 'Mean': back_test.Arithmetic_Mean_Annual(input,bench['KOSPI']),\n",
633 + " 'Std': bench['KOSPI'].std() * np.sqrt(365), \n",
634 + " 'Sharpe ratio': back_test.sharpe_ratio(input,bench['KOSPI']),\n",
635 + " 'VaR': back_test.value_at_risk(input,bench['KOSPI']),\n",
636 + " 'MDD': back_test.mdd(input,bench['KOSPI']),\n",
637 + " 'Winning ratio': back_test.winning_rate(input,bench['KOSPI']),\n",
638 + " 'Gain/Loss Ratio': back_test.profit_loss_ratio(input,bench['KOSPI'])\n",
639 + " }\n",
640 + " ], \n",
641 + " 'S&P500_indicator': [\n",
642 + " {\n",
643 + " 'Mean': back_test.Arithmetic_Mean_Annual(input,bench['S&P500']),\n",
644 + " 'Std': bench['S&P500'].std() * np.sqrt(365), \n",
645 + " 'Sharpe ratio': back_test.sharpe_ratio(input,bench['S&P500']),\n",
646 + " 'VaR': back_test.value_at_risk(input,bench['S&P500']),\n",
647 + " 'MDD': back_test.mdd(input,bench['S&P500']),\n",
648 + " 'Winning ratio': back_test.winning_rate(input,bench['S&P500']),\n",
649 + " 'Gain/Loss Ratio': back_test.profit_loss_ratio(input,bench['S&P500'])\n",
650 + " }\n",
651 + " ]\n",
652 + " } \n",
653 + "\n",
654 + " \n",
655 + "\n",
656 + " return backtest_return"
657 + ]
658 + },
659 + {
660 + "cell_type": "code",
661 + "execution_count": 5,
662 + "metadata": {
663 + "scrolled": true
664 + },
185 "outputs": [ 665 "outputs": [
186 { 666 {
187 "data": { 667 "data": {
188 "text/plain": [ 668 "text/plain": [
189 - "{'삼성전자': 0.727, 'LG전자': 0.0, '카카오': 0.273}" 669 + "({'GMV': [0.1858389981988727, 0.21203948231342723],\n",
670 + " 'MaxSharp': [0.18671958740979067, 0.2139596912413942],\n",
671 + " 'RiskParity': [0.20795176890404793, 0.21559809699947152],\n",
672 + " 'Trets': [0.21203948231342723,\n",
673 + " 0.21294773988703294,\n",
674 + " 0.21385599746063863,\n",
675 + " 0.21476425503424434,\n",
676 + " 0.21567251260785003,\n",
677 + " 0.21658077018145575,\n",
678 + " 0.21748902775506146,\n",
679 + " 0.21839728532866715,\n",
680 + " 0.21930554290227286,\n",
681 + " 0.22021380047587857,\n",
682 + " 0.22112205804948426,\n",
683 + " 0.22203031562308997,\n",
684 + " 0.22293857319669566,\n",
685 + " 0.22384683077030137,\n",
686 + " 0.2247550883439071,\n",
687 + " 0.22566334591751278,\n",
688 + " 0.2265716034911185,\n",
689 + " 0.2274798610647242,\n",
690 + " 0.2283881186383299,\n",
691 + " 0.2292963762119356,\n",
692 + " 0.2302046337855413,\n",
693 + " 0.231112891359147,\n",
694 + " 0.23202114893275272,\n",
695 + " 0.2329294065063584,\n",
696 + " 0.23383766407996412,\n",
697 + " 0.23474592165356983,\n",
698 + " 0.23565417922717552,\n",
699 + " 0.23656243680078123,\n",
700 + " 0.23747069437438692,\n",
701 + " 0.23837895194799263],\n",
702 + " 'Tvols': [0.1858389981987725,\n",
703 + " 0.18603980681220794,\n",
704 + " 0.1866279462874506,\n",
705 + " 0.18759977333781017,\n",
706 + " 0.1889493691852574,\n",
707 + " 0.19066871063768298,\n",
708 + " 0.19274790351948154,\n",
709 + " 0.1951754484924986,\n",
710 + " 0.19793852894483158,\n",
711 + " 0.2010233088543836,\n",
712 + " 0.20441522611870286,\n",
713 + " 0.2080992618687252,\n",
714 + " 0.21206019173944504,\n",
715 + " 0.2162828032765981,\n",
716 + " 0.2207520817102024,\n",
717 + " 0.22545335668848557,\n",
718 + " 0.230372426146853,\n",
719 + " 0.2354956425317311,\n",
720 + " 0.24080997621842265,\n",
721 + " 0.24630305688942764,\n",
722 + " 0.25196319408160095,\n",
723 + " 0.25777938370335385,\n",
724 + " 0.2637413018896242,\n",
725 + " 0.2698392894833826,\n",
726 + " 0.2760643295664975,\n",
727 + " 0.2824080201417004,\n",
728 + " 0.288862545420281,\n",
729 + " 0.29542064013059877,\n",
730 + " 0.3020755588277587,\n",
731 + " 0.3088210356801474],\n",
732 + " 'User': [0.25113519989524385, 0.2169925302290805]},\n",
733 + " '{\"1point\": [0.7270000003851871, 0.0, 0.272999999614813], \"2point\": [0.701931034333944, 0.0, 0.29806896566605606], \"3point\": [0.6768620689166184, 0.0, 0.32313793108338174], \"4point\": [0.6517931118624203, 0.0, 0.3482068881375798], \"5point\": [0.6267241338618083, 0.0, 0.37327586613819175], \"6point\": [0.6016551680700105, 0.0, 0.3983448319299896], \"7point\": [0.5765862068839319, 1.0625181290357943e-17, 0.42341379311606814], \"8point\": [0.5515172410659429, 3.469446951953614e-17, 0.4484827589340571], \"9point\": [0.5264482750472359, 0.0, 0.47355172495276426], \"10point\": [0.501379313669539, 0.0, 0.49862068633046097], \"11point\": [0.4763103453392776, 2.0816681711721685e-17, 0.5236896546607225], \"12point\": [0.45124137745684034, 0.0, 0.5487586225431597], \"13point\": [0.426172412012964, 0.0, 0.573827587987036], \"14point\": [0.40110344933541525, 6.938893903907228e-18, 0.5988965506645848], \"15point\": [0.376034481762012, 2.0816681711721685e-17, 0.623965518237988], \"16point\": [0.3509655176307255, 0.0, 0.6490344823692745], \"17point\": [0.3258965525334883, 0.0, 0.6741034474665117], \"18point\": [0.300827586518259, 4.163336342344337e-17, 0.699172413481741], \"19point\": [0.2757586213143949, 4.163336342344337e-17, 0.724241378685605], \"20point\": [0.2506896557025046, 2.7755575615628914e-17, 0.7493103442974953], \"21point\": [0.22562069008962146, 3.122502256758253e-17, 0.7743793099103785], \"22point\": [0.2005517244760024, 0.0, 0.7994482755239977], \"23point\": [0.17548275872525812, 1.3877787807814457e-17, 0.8245172412747419], \"24point\": [0.15041379287609932, 0.0, 0.8495862071239008], \"25point\": [0.12534482753941983, 1.6046192152785466e-17, 0.8746551724605802], \"26point\": [0.10027586412659925, 1.1102230246251565e-16, 0.8997241358734006], \"27point\": [0.07520689805671478, 0.0, 0.9247931019432855], \"28point\": [0.050137931954542976, 0.0, 0.9498620680454571], \"29point\": [0.025068965852762182, 0.0, 0.9749310341472383], \"30point\": [0.0, 3.533653586407226e-08, 0.9999999646634645]}',\n",
734 + " '{\"gmv\": [0.727, 0.0, 0.273], \"ms\": [0.674, 0.0, 0.326], \"rp\": [0.443, 0.238, 0.319]}')"
190 ] 735 ]
191 }, 736 },
192 - "execution_count": 122, 737 + "execution_count": 5,
193 "metadata": {}, 738 "metadata": {},
194 "output_type": "execute_result" 739 "output_type": "execute_result"
195 } 740 }
196 ], 741 ],
197 "source": [ 742 "source": [
198 "#gmv 포트폴리오 -> 해당 종목을 각각 몇 퍼센트로 투자해야 위험이 제일 적은가\n", 743 "#gmv 포트폴리오 -> 해당 종목을 각각 몇 퍼센트로 투자해야 위험이 제일 적은가\n",
199 - "c_Models(['삼성전자','LG전자','카카오'],[0,0,0],'2015-01-01','2021-04-01').gmv_opt()" 744 + "c_Models(['삼성전자','LG전자','카카오'],[0.2,0.5,0.3],'2015-01-01','2021-04-01').plotting()"
200 ] 745 ]
201 }, 746 },
202 { 747 {
203 "cell_type": "code", 748 "cell_type": "code",
204 - "execution_count": 124, 749 + "execution_count": 6,
205 "metadata": {}, 750 "metadata": {},
206 "outputs": [ 751 "outputs": [
207 { 752 {
...@@ -210,7 +755,7 @@ ...@@ -210,7 +755,7 @@
210 "{'삼성전자': 0.674, 'LG전자': 0.0, '카카오': 0.326}" 755 "{'삼성전자': 0.674, 'LG전자': 0.0, '카카오': 0.326}"
211 ] 756 ]
212 }, 757 },
213 - "execution_count": 124, 758 + "execution_count": 6,
214 "metadata": {}, 759 "metadata": {},
215 "output_type": "execute_result" 760 "output_type": "execute_result"
216 } 761 }
...@@ -222,7 +767,7 @@ ...@@ -222,7 +767,7 @@
222 }, 767 },
223 { 768 {
224 "cell_type": "code", 769 "cell_type": "code",
225 - "execution_count": 125, 770 + "execution_count": 39,
226 "metadata": {}, 771 "metadata": {},
227 "outputs": [ 772 "outputs": [
228 { 773 {
...@@ -231,7 +776,7 @@ ...@@ -231,7 +776,7 @@
231 "{'삼성전자': 0.443, 'LG전자': 0.238, '카카오': 0.319}" 776 "{'삼성전자': 0.443, 'LG전자': 0.238, '카카오': 0.319}"
232 ] 777 ]
233 }, 778 },
234 - "execution_count": 125, 779 + "execution_count": 39,
235 "metadata": {}, 780 "metadata": {},
236 "output_type": "execute_result" 781 "output_type": "execute_result"
237 } 782 }
...@@ -240,6 +785,219 @@ ...@@ -240,6 +785,219 @@
240 "#risk parity -> 포트폴리오에 대한 자산 위험 비중을 동일하게 조정, 즉 삼전,lg,카카오의 포트폴리오 위험 기여도를 0.33으로 하게 만드는 비중\n", 785 "#risk parity -> 포트폴리오에 대한 자산 위험 비중을 동일하게 조정, 즉 삼전,lg,카카오의 포트폴리오 위험 기여도를 0.33으로 하게 만드는 비중\n",
241 "c_Models(['삼성전자','LG전자','카카오'],[0,0,0],'2015-01-01','2021-04-01').rp_opt()" 786 "c_Models(['삼성전자','LG전자','카카오'],[0,0,0],'2015-01-01','2021-04-01').rp_opt()"
242 ] 787 ]
788 + },
789 + {
790 + "cell_type": "code",
791 + "execution_count": null,
792 + "metadata": {
793 + "scrolled": true
794 + },
795 + "outputs": [],
796 + "source": [
797 + "#def backtest_data(self,assets,weight,start_data_1, end_data_1,start_amount,rebalancing_month, interval, opt_option):\n",
798 + "back_test().backtest_data(['삼성전자','LG전자'],[0.9,0.1],'2010-01-01', '2021-01-01',10000000,3, 'monthly', 'basic')"
799 + ]
800 + },
801 + {
802 + "cell_type": "code",
803 + "execution_count": 185,
804 + "metadata": {
805 + "scrolled": true
806 + },
807 + "outputs": [
808 + {
809 + "data": {
810 + "text/html": [
811 + "<div>\n",
812 + "<style scoped>\n",
813 + " .dataframe tbody tr th:only-of-type {\n",
814 + " vertical-align: middle;\n",
815 + " }\n",
816 + "\n",
817 + " .dataframe tbody tr th {\n",
818 + " vertical-align: top;\n",
819 + " }\n",
820 + "\n",
821 + " .dataframe thead th {\n",
822 + " text-align: right;\n",
823 + " }\n",
824 + "</style>\n",
825 + "<table border=\"1\" class=\"dataframe\">\n",
826 + " <thead>\n",
827 + " <tr style=\"text-align: right;\">\n",
828 + " <th></th>\n",
829 + " <th>Open</th>\n",
830 + " <th>High</th>\n",
831 + " <th>Low</th>\n",
832 + " <th>Close</th>\n",
833 + " <th>Volume</th>\n",
834 + " <th>Change</th>\n",
835 + " </tr>\n",
836 + " <tr>\n",
837 + " <th>Date</th>\n",
838 + " <th></th>\n",
839 + " <th></th>\n",
840 + " <th></th>\n",
841 + " <th></th>\n",
842 + " <th></th>\n",
843 + " <th></th>\n",
844 + " </tr>\n",
845 + " </thead>\n",
846 + " <tbody>\n",
847 + " <tr>\n",
848 + " <td>1997-06-02</td>\n",
849 + " <td>1215</td>\n",
850 + " <td>1222</td>\n",
851 + " <td>1179</td>\n",
852 + " <td>1190</td>\n",
853 + " <td>74990</td>\n",
854 + " <td>nan</td>\n",
855 + " </tr>\n",
856 + " <tr>\n",
857 + " <td>1997-06-03</td>\n",
858 + " <td>1190</td>\n",
859 + " <td>1195</td>\n",
860 + " <td>1174</td>\n",
861 + " <td>1176</td>\n",
862 + " <td>71360</td>\n",
863 + " <td>-0.012</td>\n",
864 + " </tr>\n",
865 + " <tr>\n",
866 + " <td>1997-06-04</td>\n",
867 + " <td>1161</td>\n",
868 + " <td>1197</td>\n",
869 + " <td>1161</td>\n",
870 + " <td>1197</td>\n",
871 + " <td>85220</td>\n",
872 + " <td>0.018</td>\n",
873 + " </tr>\n",
874 + " <tr>\n",
875 + " <td>1997-06-05</td>\n",
876 + " <td>1193</td>\n",
877 + " <td>1206</td>\n",
878 + " <td>1181</td>\n",
879 + " <td>1188</td>\n",
880 + " <td>81890</td>\n",
881 + " <td>-0.008</td>\n",
882 + " </tr>\n",
883 + " <tr>\n",
884 + " <td>1997-06-07</td>\n",
885 + " <td>1197</td>\n",
886 + " <td>1215</td>\n",
887 + " <td>1190</td>\n",
888 + " <td>1197</td>\n",
889 + " <td>32550</td>\n",
890 + " <td>0.008</td>\n",
891 + " </tr>\n",
892 + " <tr>\n",
893 + " <td>...</td>\n",
894 + " <td>...</td>\n",
895 + " <td>...</td>\n",
896 + " <td>...</td>\n",
897 + " <td>...</td>\n",
898 + " <td>...</td>\n",
899 + " <td>...</td>\n",
900 + " </tr>\n",
901 + " <tr>\n",
902 + " <td>2021-05-28</td>\n",
903 + " <td>79800</td>\n",
904 + " <td>80400</td>\n",
905 + " <td>79400</td>\n",
906 + " <td>80100</td>\n",
907 + " <td>12360199</td>\n",
908 + " <td>0.006</td>\n",
909 + " </tr>\n",
910 + " <tr>\n",
911 + " <td>2021-05-31</td>\n",
912 + " <td>80300</td>\n",
913 + " <td>80600</td>\n",
914 + " <td>79600</td>\n",
915 + " <td>80500</td>\n",
916 + " <td>13321324</td>\n",
917 + " <td>0.005</td>\n",
918 + " </tr>\n",
919 + " <tr>\n",
920 + " <td>2021-06-01</td>\n",
921 + " <td>80500</td>\n",
922 + " <td>81300</td>\n",
923 + " <td>80100</td>\n",
924 + " <td>80600</td>\n",
925 + " <td>14058401</td>\n",
926 + " <td>0.001</td>\n",
927 + " </tr>\n",
928 + " <tr>\n",
929 + " <td>2021-06-02</td>\n",
930 + " <td>80400</td>\n",
931 + " <td>81400</td>\n",
932 + " <td>80300</td>\n",
933 + " <td>80800</td>\n",
934 + " <td>16414644</td>\n",
935 + " <td>0.002</td>\n",
936 + " </tr>\n",
937 + " <tr>\n",
938 + " <td>2021-06-03</td>\n",
939 + " <td>81300</td>\n",
940 + " <td>83000</td>\n",
941 + " <td>81100</td>\n",
942 + " <td>82800</td>\n",
943 + " <td>29341312</td>\n",
944 + " <td>0.025</td>\n",
945 + " </tr>\n",
946 + " </tbody>\n",
947 + "</table>\n",
948 + "<p>6000 rows × 6 columns</p>\n",
949 + "</div>"
950 + ],
951 + "text/plain": [
952 + " Open High Low Close Volume Change\n",
953 + "Date \n",
954 + "1997-06-02 1215 1222 1179 1190 74990 nan\n",
955 + "1997-06-03 1190 1195 1174 1176 71360 -0.012\n",
956 + "1997-06-04 1161 1197 1161 1197 85220 0.018\n",
957 + "1997-06-05 1193 1206 1181 1188 81890 -0.008\n",
958 + "1997-06-07 1197 1215 1190 1197 32550 0.008\n",
959 + "... ... ... ... ... ... ...\n",
960 + "2021-05-28 79800 80400 79400 80100 12360199 0.006\n",
961 + "2021-05-31 80300 80600 79600 80500 13321324 0.005\n",
962 + "2021-06-01 80500 81300 80100 80600 14058401 0.001\n",
963 + "2021-06-02 80400 81400 80300 80800 16414644 0.002\n",
964 + "2021-06-03 81300 83000 81100 82800 29341312 0.025\n",
965 + "\n",
966 + "[6000 rows x 6 columns]"
967 + ]
968 + },
969 + "execution_count": 185,
970 + "metadata": {},
971 + "output_type": "execute_result"
972 + }
973 + ],
974 + "source": [
975 + "df = fdr.DataReader('005930')\n",
976 + "df"
977 + ]
978 + },
979 + {
980 + "cell_type": "code",
981 + "execution_count": 192,
982 + "metadata": {},
983 + "outputs": [
984 + {
985 + "name": "stdout",
986 + "output_type": "stream",
987 + "text": [
988 + "{\"gmv\": [0.727, 0.0, 0.273], \"ms\": [0.674, 0.0, 0.326], \"rp\": [0.443, 0.238, 0.319]}\n",
989 + "[0.674, 0.0, 0.326]\n"
990 + ]
991 + }
992 + ],
993 + "source": [
994 + "c_m = c_Models(['삼성전자','LG전자','카카오'],[0,0,0],'2015-01-01','2021-04-01')\n",
995 + "ret_vol, efpoints, weights = c_m.plotting()\n",
996 + "print(weights)\n",
997 + "weights = literal_eval(weights)\n",
998 + "weights = weights.get('ms')\n",
999 + "print(weights)"
1000 + ]
243 } 1001 }
244 ], 1002 ],
245 "metadata": { 1003 "metadata": {
......