변동성 돌파전략 2
Contents
변동성 돌파전략 2#
외부 데이터를 이용하여 윌리암스의 변동성 돌파전략을 개선해보겠습니다.
주가지수 데이터로 전략 개선#
변동성 돌파전략은 시장이 좋을 때 활용하면 효과가 더 좋을 것 같습니다. 아무래도 상승장에서는 전일의 변동성을 돌파할 올라갈 확률이 높지 않을까요? 코스피 주가지수 데이터를 불러와서, 전일 코스피 주가지수의 수익율(종가 기준) 2%이상 발생한 경우만 매수를 하면 어떤 결과가 나오는 지 테스트 해 보겠습니다. 매수일을 기준으로 2% 수익률이상으로 하면 더 좋을 것 같으나, 매수일의 종가 기준 수익율은 알 수 가 없기 때문에 전일을 기준으로 합니다. 먼저 지수데이터를 가져와서 종가 수익율을 계산합니다.
import FinanceDataReader as fdr
import pandas as pd
kospi_index = fdr.DataReader('KS11', start='2021-01-03', end='2021-12-31')
kospi_index['kospi_return'] = kospi_index['Close']/kospi_index['Close'].shift(1)
kospi_index.to_pickle('kospi_index.pkl')
지수 데이터를 이용하면, 조건이 추가되므로 매수할 기회가 적어집니다. 지수데이터를 이용함으로써 예상수익율(일)이 0.3% 에서 1.6% 으로 올라갔습니다. 예상 최저수익율도 올라가서 리스크를 상당히 줄일 수 가 있습니다. 단, 매수 횟 수가 낮아 누적 수익율도 낮아졌습니다.
kospi_index = pd.read_pickle('kospi_index.pkl')
kospi_list = pd.read_pickle('kospi_list.pkl')
def avg_return(code, K, deci):
stock = fdr.DataReader(code, start='2021-01-03', end='2021-12-31')
stock_data = stock.merge(kospi_index['kospi_return'], left_index=True, right_index=True, how='inner')
stock_data['v'] = (stock_data['High'].shift(1) - stock_data['Low'].shift(1))*K
stock_data['buy_price'] = stock_data['Open'] + stock_data['v']
stock_data.dropna(inplace=True) # shift함수 이용으로 생긴 빈 셀 제거
if deci == 1: # 지수 데이터를 이용한 경우
stock_data['buy'] = (stock_data['High'] > stock_data['buy_price'])*(stock_data['Low'] < stock_data['buy_price'])*(stock_data['kospi_return'].shift(1) > 1.02).astype(int)
else: # 지수 데이터를 이용하지 않은 경우
stock_data['buy'] = (stock_data['High'] > stock_data['buy_price'])*(stock_data['Low'] < stock_data['buy_price']).astype(int)
stock_data['return'] = stock_data['Open'].shift(-1)/stock_data['buy_price']
n = len(stock_data[stock_data['buy']==1])
r = stock_data[stock_data['buy']==1]['return'].mean()
w = stock_data[stock_data['buy']==1]['return'].min()
c = stock_data[stock_data['buy']==1]['return'].prod()
return n, r, w, c
print('------------- 지수 데이터를 이용하지 않은 경우 ---------------')
symbol_list = []
name_list = []
obs_list = []
return_list = []
worst_list = []
cumul_list = []
for code, name in zip(kospi_list['code'], kospi_list['name']):
n, r, w, c = avg_return(code, 0.5, 0)
if (r > 0) and (n > 0): # 수익율 값이 존재하고, 최소한 한번 이상 거래일 존재해야 진행
symbol_list.append(code)
name_list.append(name)
obs_list.append(n) # 매수 횟 수
return_list.append(r)
worst_list.append(w)
cumul_list.append(c)
else:
continue
outcome_0 = pd.DataFrame({'symbol': symbol_list, 'name': name_list, 'num_obs': obs_list, 'return': return_list, 'worst': worst_list, 'cumul': cumul_list})
print(outcome_0[['num_obs','return','worst','cumul']].describe())
print('\n')
print('------------- 지수 데이터를 이용한 경우 ---------------')
symbol_list = []
name_list = []
obs_list = []
return_list = []
worst_list = []
cumul_list = []
for code, name in zip(kospi_list['code'][:50], kospi_list['name'][:50]):
n, r, w, c = avg_return(code, 0.5, 1)
if (r > 0) and (n > 0) : # 수익율 값이 존재하고, 최소한 한번 이상 거래일 존재해야 진행
symbol_list.append(code)
name_list.append(name)
obs_list.append(n) # 매수 횟 수
return_list.append(r)
worst_list.append(w)
cumul_list.append(c)
else:
continue
outcome_1 = pd.DataFrame({'symbol': symbol_list, 'name': name_list, 'num_obs': obs_list, 'return': return_list, 'worst': worst_list, 'cumul': cumul_list})
print(outcome_1[['num_obs','return','worst','cumul']].describe())
------------- 지수 데이터를 이용하지 않은 경우 ---------------
num_obs return worst cumul
count 813.000000 813.000000 813.000000 813.000000
mean 92.398524 1.003090 0.901086 1.327235
std 15.477971 0.004127 0.143681 0.538553
min 2.000000 0.972844 0.000000 0.000000
25% 88.000000 1.000790 0.898420 1.043979
50% 94.000000 1.002838 0.931694 1.255082
75% 101.000000 1.005134 0.953390 1.514587
max 127.000000 1.017648 1.000000 5.318219
------------- 지수 데이터를 이용한 경우 ---------------
num_obs return worst cumul
count 49.000000 49.000000 49.000000 49.000000
mean 2.632653 1.016589 0.999325 1.040317
std 0.950743 0.019532 0.023266 0.044871
min 1.000000 0.975929 0.930901 0.927857
25% 2.000000 1.005605 0.984810 1.015540
50% 3.000000 1.011357 1.000000 1.029940
75% 3.000000 1.025377 1.010989 1.060224
max 4.000000 1.095283 1.066127 1.184608