2021 미래에셋자산운용 빅데이터 페스티벌

2021 미래에셋자산운용 빅데이터 페스티벌

2022, Mar 24    
2021 빅페_미래에셋자산운용_코드

2021 미래에셋자산운용 빅데이터 페스티벌

- ETF를 활용한 데이터 기반 투자 전략 알고리즘 개발 -

UNIST 산업공학과 박준표

References

Data Processing

In [1]:
import pandas as pd
import numpy as np
from magi_module import get_report
import matplotlib.pyplot as plt
%matplotlib inline
from dateutil.relativedelta import relativedelta
c:\users\wnsvy\miniconda3\lib\site-packages\numpy\_distributor_init.py:30: UserWarning: loaded more than 1 DLL from .libs:
c:\users\wnsvy\miniconda3\lib\site-packages\numpy\.libs\libopenblas.NOIJJG62EMASZI6NYURL6JBKM4EVBGM7.gfortran-win_amd64.dll
c:\users\wnsvy\miniconda3\lib\site-packages\numpy\.libs\libopenblas.WCDJNK7YVMPZQ2ME2ZZHJJRJ3JIKNDB7.gfortran-win_amd64.dll
  warnings.warn("loaded more than 1 DLL from .libs:"

기본 제공된 126개의 TIGER ETF 종가 데이터를 사용하였으며 전략의 비교지수로 활용할 코스피 지수 데이터를 외부 데이터로 사용

  • 코스피 지수 데이터 출처: FinanceDataReader 모듈을 사용하여 다운로드
import FinanceDataReader as fdr
ks11 = fdr.DataReader('ks11')
In [2]:
ks11 = pd.read_pickle('외부데이터/kospi_price.pkl')
In [3]:
kospi_close = ks11['Close']
In [4]:
etf_data = pd.read_csv('./data/etf_data.csv', encoding = 'euc_kr', parse_dates= ['tdate'])
In [5]:
etf_ohlcv = etf_data.set_index(['tdate', 'etf_code', 'data_name'])['value'].unstack()

# 종가 데이터 (126개의 etf에 대한)
etf_close = etf_ohlcv['종가'].unstack()

전략의 장기적 성과 확인을 위해 target_start_date'2012-12-31'로 설정

In [6]:
# target_start_date = '2018-12-31'
target_start_date = '2012-12-31'

target_end_date = '2021-05-31'

Accelerated Momentum Scoring

  • 모멘텀 팩터에 대한 연구는 Jegadeesh(1990), Jegadeesh and Titman(1993)의 연구를 기점으로 폭발적으로 진행되었으며 모멘텀 측정 지표를 개선하기 위한 시도도 꾸준히 이루어짐
  • 가장 널리 쓰이는 모멘텀 지표인 직전 1개월 제외 12개월 수익률(PR1YR)에 근거한 전략은 최근 몇 년간 KOSPI 내에서의 성과가 부진한 모습을 보임
  • Xiong and Ibbotson(2015)의 가속화 모멘텀 전략은 주가가 끝없이 상승할 수는 없기에 상승의 가속 뒤 주가 성과가 부진할 것이라는 가정을 전제로 함
  • 가속화 모멘텀은 KOSPI 대형주 유니버스에서 PR1YR 모멘텀 전략 대비 훨씬 개선된 성과를 기록하였으며 본 전략에서는 가속화 모멘텀(Accelerated Momentum) Scoring 방법론을 사용함

Momentum Weighting Scheme

주가 상승의 가속화를 측정하기 위해 직전 1개월 ~ 12개월 수익률에 1에서 -1 사이의 가중치를 부여하여 합산

  • Xiong and Ibbotson(2015)의 연구에서는 스코어가 클수록 주가 상승의 가속화가 더 크게 일어났다고 판단하지만 본 전략에서는 가속화가 더욱 크게 일어난 종목에 낮은 점수를 부여해야 하기 때문에 직전 1개월 ~ 6개월 까지는 -1, 7개월 ~ 12개월 까지는 1의 가중치를 부여함
  • 본 전략에서는 Step Function 형태의 simple weighting scheme을 사용하였으며 후속 전략연구에서는 매크로 데이터 또는 다른 시계열 데이터와 딥러닝 모델을 통해 해당 가중치를 학습시켜 최적의 weight를 찾으려 함

Accelerated Momentum Scoring

# initialize score
acc_score = pd.DataFrame(columns = etf_close.columns, index=etf_close.index).fillna(0) 

# 분위 선정 방식이 반대(score가 큰 값이 1분위)이기 때문에 weight의 부호가 바뀜
weight_scheme = [-1] * 6 + [1] * 6

for i in range(1,13):
    days = i * 20 # 한달을 20거래일로 가정
    acc_score += (etf_close.pct_change(days)) * weight_scheme[i-1]
In [7]:
# 분위 선정 방식이 반대(score가 큰 값이 1분위)이기 때문에 weight의 부호가 바뀜
weight_scheme = [-1] * 6 + [1] * 6
In [8]:
acc_score = pd.DataFrame(columns = etf_close.columns, index=etf_close.index).fillna(0) # initialize score

for i in range(1,13):
    days = i * 20 # 한달을 20거래일로 가정
    acc_score += (etf_close.pct_change(days)) * weight_scheme[i-1]
  • 반복되는 코드를 최적화 하기 위해 magi_module.py의 get_report wrapper 함수를 만듦
  • 비교지수인 코스피 지수를 ress DataFrame에 추가함 (그래프의 회색 선)
  • 포트폴리오 성과지표로 - CAGR / MDD를 추가함

Portfolio Results and Summaries

In [9]:
def get_report_(score, kospi_close):
    
    summary, ress = get_report(score) #magi_module.py의 get_report 모듈
    
    col_kospi = kospi_close[ress.index]
    col_kospi /= col_kospi.iloc[0]
    
    ress['KOSPI'] = col_kospi

    CAGR_MDD = -summary.loc['CAGR'] / summary.loc['MDD']
    CAGR_MDD.name = 'CAGR / MDD'
    summary = summary.append(CAGR_MDD)

    return summary, ress
In [10]:
def get_ress(score, target_start_date, target_end_date):
    # 매일 리밸런싱
    daily_score = score.loc[target_start_date: target_end_date]

    # 매주(마지막일 기준) 리밸런싱
    weekly_score =score.resample('W').last().loc[target_start_date: target_end_date]

    # 매달(마지막일 기준) 리밸런싱
    monthly_score =score.resample('M').last().loc[target_start_date: target_end_date]
    
    res = {}
    res['daily_summary'], res['daily_ress'] = get_report_(daily_score, kospi_close)
    res['weekly_summary'], res['weekly_ress'] = get_report_(weekly_score, kospi_close)
    res['monthly_summary'], res['monthly_ress'] = get_report_(monthly_score, kospi_close)
    
    return res
In [11]:
# 12-12-31 ~ 21-05-31 까지의 results들 get
res = get_ress(acc_score, target_start_date, target_end_date)
In [12]:
res['daily_summary']
Out[12]:
QUAN_5 QUAN_4 QUAN_3 QUAN_2 QUAN_1 L-S RANK_L-S
RETURN 0.901287 1.197970 1.259051 2.048160 2.002137 1.983727 1.977734
MDD -0.452061 -0.403174 -0.342472 -0.280086 -0.495780 -0.373098 -0.288742
TURNOVER 102.493692 250.158178 270.966726 210.723853 87.804089 190.297781 151.825623
CAGR -0.034050 0.062059 0.079811 0.269954 0.260370 0.256495 0.255228
SHARPE -0.002240 0.051986 0.066860 0.174087 0.131616 0.121735 0.144550
CAGR / MDD -0.075323 0.153926 0.233044 0.963825 0.525172 0.687473 0.883931
In [13]:
res['daily_ress'].plot(figsize=(12,5));
In [14]:
res['weekly_summary']
Out[14]:
QUAN_5 QUAN_4 QUAN_3 QUAN_2 QUAN_1 L-S RANK_L-S
RETURN 0.991068 1.142243 1.214235 1.791059 2.120476 1.903058 1.881192
MDD -0.424330 -0.410664 -0.341269 -0.299227 -0.464067 -0.386322 -0.297275
TURNOVER 41.129776 97.415119 111.900973 90.995988 38.453296 79.583072 62.390783
CAGR -0.002986 0.045329 0.066844 0.214423 0.284728 0.239227 0.234462
SHARPE 0.015009 0.042073 0.059064 0.144352 0.141139 0.115558 0.135719
CAGR / MDD -0.007037 0.110379 0.195869 0.716589 0.613549 0.619241 0.788704
In [15]:
res['weekly_ress'].plot(figsize=(12,5));
In [16]:
res['monthly_summary']
Out[16]:
QUAN_5 QUAN_4 QUAN_3 QUAN_2 QUAN_1 L-S RANK_L-S
RETURN 0.945031 1.138964 1.149270 1.996755 2.219841 2.050014 1.991591
MDD -0.479965 -0.405425 -0.308225 -0.324398 -0.409206 -0.359706 -0.296237
TURNOVER 18.144548 39.372166 41.575748 36.475909 16.732382 34.876930 27.445784
CAGR -0.018669 0.044327 0.047468 0.259239 0.304490 0.270337 0.258153
SHARPE 0.008490 0.042784 0.045031 0.168781 0.151549 0.126487 0.147301
CAGR / MDD -0.038897 0.109336 0.154004 0.799139 0.744099 0.751550 0.871440
In [17]:
res['monthly_ress'].plot(figsize=(12,5));

Disparity - Accelerated Momentum Scoring

Disparity Score Concepts

  • Mebane Faber는 “A Quantitative Approach to Tactical Asset Allocation” (2006)에서 10개월 이동평균선(이하 200일 이평)을 활용한 타이밍 전략을 소개함
  • 해당 전략의 성과(수익률, MDD 등)가 단순 보유 전략보다 우수하였고 이를 scoring에 반영하기 위해 200일 이평과 종가의 괴리를 나타내는 지표인 이격도를 사용함
$$ \text{Disparity Score} = \frac{\text{Close Price}}{\text{200 days Moving Average}} $$

Disparity Score는 위에서 계산한 가속화 모멘텀 스코어에 곱해지게 되며 이는 종가가 200일 이동평균선 위에 위치하고 있다면 score에 가산점을 받게 되고 반대로 종가가 200일 이동평균선 아래에 위치하고 있다면 score에 페널티를 받음을 의미함

Disparity Scoring

# 200일 이평
ma_200 = etf_close.rolling(window=200).mean()
disparity_score = etf_close / ma_200 # 이격도
In [18]:
# 200일 이평
ma_200 = etf_close.rolling(window=200).mean()
disparity_score = etf_close / ma_200 # 이격도

위에서 계산한 가속화 모멘텀 스코어에 이격도 스코어를 반영하여 최종 스코어를 산출하였으며 실험 결과 disparity score의 제곱을 곱해주었을 때 포트폴리오의 성과가 더욱 개선됨을 확인

In [19]:
# acc_disparity_score_score = acc_score * disparity_score # 200일 이평에 대한 이격도 반영

# 두번 반영(제곱을 곱)해주면 성과가 더 좋아짐
acc_disparity_score = acc_score * disparity_score * disparity_score # 200일 이평에 대한 이격도 반영

Portfolio Results and Summaries

In [20]:
res = get_ress(acc_disparity_score, target_start_date, target_end_date)
In [21]:
res['daily_summary']
Out[21]:
QUAN_5 QUAN_4 QUAN_3 QUAN_2 QUAN_1 L-S RANK_L-S
RETURN 0.873359 1.177259 1.343030 1.837923 2.183083 2.243034 2.045957
MDD -0.450202 -0.420804 -0.327783 -0.327272 -0.461366 -0.365949 -0.275576
TURNOVER 115.637477 268.149403 280.850485 214.040888 85.816408 201.453885 161.872001
CAGR -0.044133 0.055903 0.103304 0.224924 0.297249 0.309017 0.269498
SHARPE -0.009886 0.047550 0.078846 0.144333 0.149610 0.141295 0.152402
CAGR / MDD -0.098028 0.132848 0.315160 0.687269 0.644281 0.844426 0.977947
In [22]:
res['daily_ress'].plot(figsize=(12,5));
In [23]:
res['weekly_summary']
Out[23]:
QUAN_5 QUAN_4 QUAN_3 QUAN_2 QUAN_1 L-S RANK_L-S
RETURN 0.907914 1.273203 1.224800 1.670524 2.204752 2.179303 1.896677
MDD -0.432481 -0.399746 -0.345850 -0.331252 -0.453618 -0.379622 -0.288311
TURNOVER 48.101218 106.879541 114.864615 88.741846 35.922284 84.023502 66.999041
CAGR -0.031689 0.083842 0.069929 0.186545 0.301527 0.296500 0.237840
SHARPE -0.002315 0.062826 0.059859 0.124472 0.150883 0.137370 0.138582
CAGR / MDD -0.073272 0.209738 0.202195 0.563152 0.664716 0.781041 0.824943
In [24]:
res['weekly_ress'].plot(figsize=(12,5));
In [25]:
res['monthly_summary']
Out[25]:
QUAN_5 QUAN_4 QUAN_3 QUAN_2 QUAN_1 L-S RANK_L-S
RETURN 0.913240 1.122860 1.181150 1.894848 2.393430 2.337826 2.069487
MDD -0.477065 -0.413165 -0.306704 -0.320499 -0.405787 -0.361154 -0.275035
TURNOVER 21.075927 41.872736 41.560526 35.263655 16.043115 37.119042 29.028868
CAGR -0.029799 0.039382 0.057065 0.237442 0.337643 0.327203 0.274347
SHARPE 0.000292 0.038321 0.050978 0.153973 0.165240 0.149272 0.156639
CAGR / MDD -0.062464 0.095318 0.186059 0.740851 0.832069 0.905993 0.997498
In [26]:
res['monthly_ress'].plot(figsize=(12,5));

성과 분석

월말을 기준으로 리밸런싱을 한 'RANK_L-S' 포트폴리오 결과를 기준으로 전략의 성과 분석을 진행함 이는 대부분의 전략에서 포트폴리오의 성과지표가 가장 우수하였고 turnover도 낮은 수치이기 때문에 거래비용을 줄일 수 있기 때문임

In [27]:
monthly_ress = res['monthly_ress']

위험등급

과거 3년간 (로그)수익률 변동성(연환산 표준편차)을 계산하여 전략의 위험등급을 판단함

In [28]:
monthly_logret = np.log(monthly_ress / monthly_ress.shift(1)).dropna()
In [29]:
std_3y = monthly_logret[-252*3:].std() * np.sqrt(252)
In [30]:
std_3y
Out[30]:
QUAN_5      0.198285
QUAN_4      0.154538
QUAN_3      0.132954
QUAN_2      0.147386
QUAN_1      0.177966
L-S         0.199571
RANK_L-S    0.159263
KOSPI       0.202868
dtype: float64

전략 별 성과 비교

성과 지표 산출 방식은 magi_module.py에서 사용한 방식과 동일하게 적용

In [31]:
def MDD(res):
    return (res / res.cummax() -1).min()

def CAGR(res):
    return res.values[-1] ** (1 / 36 / 30 * 360) - 1

def sharpe(res):
    return np.mean(res.pct_change().dropna()) / np.std(res.pct_change().dropna()) * np.sqrt(12)

def compare_port(port_res, bench_res):
    compare_summary = {}
    compare_summary['Return'] = port_res.iloc[-1], bench_res.iloc[-1]
    compare_summary['CAGR'] = CAGR(port_res), CAGR(bench_res)
    compare_summary['MDD'] = MDD(port_res), MDD(bench_res)
    compare_summary['Sharpe'] = sharpe(port_res), sharpe(bench_res)
    compare_summary['CAGR / MDD'] = -CAGR(port_res) / MDD(port_res), -CAGR(bench_res) / MDD(bench_res)
    compare_summary = pd.DataFrame(compare_summary).T
    compare_summary.columns = [port_res.name, bench_res.name]
    
    return compare_summary

단순 모멘텀 전략과 가속화 모멘텀 전략의 성과 비교

가속화 모멘텀 전략이 단순 모멘텀 전략에 비해 우위가 있는지 확인을 위해 직전 1개월 제외 12개월 수익률(PR1YR)에 근거한 scoring 전략과 성과를 비교함

pr1y_score: 1개월 제외 12개월 수익률을 기준으로 scoring

In [32]:
pr1y_score = pd.DataFrame(columns = etf_close.columns, index=etf_close.index).fillna(0) # initialize score
for i in range(240,len(pr1y_score)):
    pr1y_score.iloc[i] = etf_close.iloc[i] / etf_close.iloc[i-220]
In [33]:
monthly_score =pr1y_score.resample('M').last().loc[target_start_date: target_end_date]
In [34]:
pr1y_summary, pr1y_ress = get_report(monthly_score) # pr1y 포트폴리오 결과물

전체기간(2013-01 ~ 2021-05)의 성과 지표 비교

In [35]:
port_res = monthly_ress['RANK_L-S']
bench_res = pr1y_ress['RANK_L-S']
In [36]:
plt.figure(figsize=(12,5))
port_res.plot(label='Accelerated Momentum');
bench_res.plot(label='PR1YR Momentum');
plt.legend();
In [37]:
compare_results = compare_port(port_res,bench_res)
compare_results.columns = ['Accelerated','PR1YR']
compare_results
Out[37]:
Accelerated PR1YR
Return 2.069487 1.736468
CAGR 0.274347 0.201957
MDD -0.275035 -0.347733
Sharpe 0.156639 0.109055
CAGR / MDD 0.997498 0.580782

전체 기간동안 가속화 모멘텀 전략을 사용한 포트폴리오의 모든 성과지표가 단순 모멘텀 전략보다 우수함을 확인함

설정기간(2019-01 ~ 2021-05)의 성과 지표 비교

In [38]:
port_res = monthly_ress['RANK_L-S']['2018-12-31':'2021-05-31']
port_res = port_res / port_res[0] # 시작일을 1로 설정

bench_res = pr1y_ress['RANK_L-S']['2018-12-31':'2021-05-31']
bench_res = bench_res / bench_res[0] # 시작일을 1로 설정
In [39]:
plt.figure(figsize=(12,5))
port_res.plot(label='Accelerated Momentum');
bench_res.plot(label='PR1YR Momentum');
plt.legend();
In [40]:
compare_results = compare_port(port_res,bench_res)
compare_results.columns = ['Accelerated','PR1YR']
compare_results
Out[40]:
Accelerated PR1YR
Return 1.283353 1.262658
CAGR 0.086714 0.080841
MDD -0.143026 -0.312279
Sharpe 0.157045 0.123775
CAGR / MDD 0.606286 0.258875

설정기간동안 가속화 모멘텀 전략을 사용한 포트폴리오의 모든 성과지표가 단순 모멘텀 전략보다 우수하며 특히 MDD를 절반 이하(31% -> 14%)로 낮춰줌을 확인

Disparity Score의 영향 분석

이격도 스코어가 실제 전략에 어떤 영향을 주었는지 파악하기 위하여 단순히 가속화 모멘텀 스코어만 반영한 포트폴리오와 성과 분석을 진행함

전체기간(2013-01 ~ 2021-05)의 성과 지표 비교

In [41]:
monthly_score =acc_score.resample('M').last().loc[target_start_date: target_end_date]
In [42]:
acc_only_summary, acc_only_ress = get_report(monthly_score)
In [43]:
port_res = monthly_ress['RANK_L-S']
bench_res = acc_only_ress['RANK_L-S']
In [44]:
plt.figure(figsize=(12,5))
port_res.plot(label='Disparity-Accelerated Momentum');
bench_res.plot(label='Accelerated Momentum Only');
plt.legend();
In [45]:
compare_results = compare_port(port_res,bench_res)
compare_results.columns = ['Disparity-Accelerated','Accelerated Only']
compare_results
Out[45]:
Disparity-Accelerated Accelerated Only
Return 2.069487 1.991591
CAGR 0.274347 0.258153
MDD -0.275035 -0.296237
Sharpe 0.156639 0.147301
CAGR / MDD 0.997498 0.871440

설정기간(2019-01 ~ 2021-05)의 성과 지표 비교

In [46]:
port_res = monthly_ress['RANK_L-S']['2018-12-31':'2021-05-31']
port_res = port_res / port_res[0] # 시작일을 1로 설정

bench_res = acc_only_ress['RANK_L-S']['2018-12-31':'2021-05-31']
bench_res = bench_res / bench_res[0] # 시작일을 1로 설정
In [47]:
plt.figure(figsize=(12,5))
port_res.plot(label='Disparity-Accelerated Momentum');
bench_res.plot(label='Accelerated Momentum Only');
plt.legend();
In [48]:
compare_results = compare_port(port_res,bench_res)
compare_results.columns = ['Disparity-Accelerated','Accelerated Only']
compare_results
Out[48]:
Disparity-Accelerated Accelerated Only
Return 1.283353 1.265239
CAGR 0.086714 0.081577
MDD -0.143026 -0.153984
Sharpe 0.157045 0.147166
CAGR / MDD 0.606286 0.529778
  • 이격도 지표를 활용한다는 아이디어도 큰 틀에서는 모멘텀과 같은 추세추종 전략임
  • 이격도 스코어가 전반적인 포트폴리오 성과 개선에 소폭 도움을 줌을 확인

비교지수(코스피)와의 성과 비교

전체기간(2013-01 ~ 2021-05)의 성과 지표 비교

In [49]:
port_res = monthly_ress['RANK_L-S']
bench_res = monthly_ress['KOSPI']
In [50]:
plt.figure(figsize=(12,5))
port_res.plot(label='Acc-Disparity Strategy')
bench_res.plot(label='KOSPI')
plt.legend();
In [51]:
compare_port(port_res,bench_res)
Out[51]:
RANK_L-S KOSPI
Return 2.069487 1.613013
CAGR 0.274347 0.172769
MDD -0.275035 -0.438979
Sharpe 0.156639 0.099154
CAGR / MDD 0.997498 0.393571

전체기간에서 장기적으로 봤을 때 포트폴리오의 모든 성과지표가 비교지수인 코스피 지수보다 우수함을 확인 가능

설정기간(2019-01 ~ 2021-05)의 성과지표 비교

In [52]:
target_start_date = '2018-12-31'
target_end_date = '2021-05-31'
In [53]:
score = acc_disparity_score.loc[target_start_date: target_end_date]
In [54]:
res = get_ress(score, target_start_date, target_end_date)
In [55]:
port_res = res['monthly_ress']['RANK_L-S']
port_res = port_res / port_res[0] # 시작일을 1로 설정

bench_res = res['monthly_ress']['KOSPI']
bench_res = bench_res / bench_res[0] # 시작일을 1로 설정
In [56]:
plt.figure(figsize=(12,5))
port_res.plot(label='Portfolio');
bench_res.plot(label='KOSPI');
plt.legend();
In [57]:
compare_port(port_res,bench_res)
Out[57]:
RANK_L-S KOSPI
Return 1.368328 1.485902
CAGR 0.110188 0.141117
MDD -0.143026 -0.357089
Sharpe 0.194002 0.195096
CAGR / MDD 0.770411 0.395186

본 과제의 설정기간에서 전략 포트폴리오의 MDD와 CAGR/MDD는 우수하지만 수익률이 비교지수보다 낮으며 그에 따라 샤프지수도 낮은 결과를 보임

설정기간에서 비교지수에 비해 성과가 부진한 이유 분석

설정 기간에서 전략의 성과가 부진한 이유를 크게 2가지 이유로 설명할 수 있음

1. 큰 틀에서 모멘텀 전략과 같은 추세추종 전략이 그 알파를 잃어가고 있음 (2010년대의 전반적인 특성, COVID 이전)

* AQR(2019)에서 나온 논문 You Can't Always Trend When You Want에 따르면 모멘텀과 같은 추세추종 전략이 2010년도 이후 힘을 잃어가는 가장 주요한 이유를 시장의 가격 움직임이 작아졌기 때문이라고 설명하고 있음


2. 본 전략이 COVID 이후 계속되는 주가 상승을 스코어에 정확히 반영하지 못함(COVID 이후의 특성)

* 가속화 모멘텀 전략은 주가가 끝없이 상승할 수는 없기에 상승의 가속 뒤 주가 성과가 부진할 것이라는 가정을 전제로 하여 가중치를 부여함

* 본 전략에서는 6개월을 기준으로 주가 상승에 페널티를 주는 단순한 가중치 부여 방식(Simple Weighting Scheme)을 사용하였는데 이는 COVID 이후 12개월 이상 상승하고 있는 현재의 시장상황을 정확히 반영하지 못한다 판단됨

후속 전략 연구 계획

딥러닝 모델을 통한 weighting scheme 재설계

  • 위의 설정기간에서 성과가 부진한 이유를 종합하면 변화하는 시장 상황에 맞추어 스코어링 전략이 변화하지 못하기 때문임 특히, 스코어를 산출할 때 직전 1개월에서 직전 12개월에 부여하는 가중치를 본 전략에서는 단순히 -1과 1로 지정하였는데 이 부분을 아래와 같이 딥러닝 모델을 활용하여 개선한다면 더 좋은 성과를 얻을 수 있을것

    • 트레이닝 기간에 ETF 가격 데이터를 바탕으로 적당한 최적 가중치를 미리 만들어(forward looking) label로 사용 (12차원 벡터)
    • Input 데이터는 ETF 가격 데이터 뿐만 아니라 다른 매크로나 시계열 데이터 또한 사용 가능
    • 딥러닝 모델을 통해 위에서 설정한 시계열 Input 데이터와 forward looking을 통해 만들어 놓은 최적 가중치를 mapping 시키는 함수를 학습
  • 현재 GAN, LSTM, GRU 등의 딥러닝 모델을 활용하여 다변량 시계열의 joint distribution과 conditional distribution을 모델링 하는 연구를 진행하고 있는데 해당 모델들을 활용하여 가속화 모멘텀의 weighting scheme을 재설계 하는데 도움을 받을 수 있음

스코어 기반 섹터 로테이션 전략으로의 활용

본 전략은 섹터 로테이션에도 적용이 가능함 예를 들어 WICS 26개 업종 중 상위 n개를 편입하는 전략 또는 상위 n개를 매수, n개를 매도 하는 롱-숏 전략 등을 만들어 볼 수 있음

포트폴리오 최적화 과정, 위험관리 방법의 적용

포트폴리오 구성 단계에서 최적화 프로세스(robust optimization 등)를 집어넣거나 위험관리 방법(특정 종목, 업종에 대한 비중 제한 등)을 적용하면 더욱 우수한 성과가 나올 것

최종 Score 결과물 저장

In [58]:
submission = score.stack()
submission = submission.reset_index()
submission.columns = ['tdate', 'code', 'score']
In [59]:
submission.to_csv('2021 빅페_미래에셋자산운용_score.csv')
In [60]:
pd.read_csv('2021 빅페_미래에셋자산운용_score.csv')
Out[60]:
Unnamed: 0 tdate code score
0 0 2019-01-02 A091220 -0.512893
1 1 2019-01-02 A091230 -0.414221
2 2 2019-01-02 A098560 0.327446
3 3 2019-01-02 A102110 -0.469448
4 4 2019-01-02 A105010 -0.414497
... ... ... ... ...
60438 60438 2021-05-31 A315270 1.402657
60439 60439 2021-05-31 A319640 -0.381514
60440 60440 2021-05-31 A329200 1.179918
60441 60441 2021-05-31 A329750 -0.325947
60442 60442 2021-05-31 A341850 0.109628

60443 rows × 4 columns