STOCK/변동성돌파전략

[파이썬 주식] 변동성돌파전략 - 9. 조건추가 PB

BOTTLE6 2021. 2. 13. 10:13

#20210212_2.

 

## 1. 라이브러리

from Investar import Analyzer
mk = Analyzer.MarketDB()
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import time
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
# matplotlib 한글 폰트 출력코드

import matplotlib
from matplotlib import font_manager, rc
import platform

try : 
    if platform.system() == 'Windows':
    # 윈도우인 경우
        font_name = font_manager.FontProperties(fname="c:/Windows/Fonts/malgun.ttf").get_name()
        rc('font', family=font_name)
    else:    
    # Mac 인 경우
        rc('font', family='AppleGothic')
except : 
    pass
matplotlib.rcParams['axes.unicode_minus'] = False   

 

## 2. 종목 불러오기

## 종목 불러오기
import pandas as pd
"""KRX로부터 상장기업 목록 파일을 읽어와서 데이터프레임으로 반환"""
url = 'http://kind.krx.co.kr/corpgeneral/corpList.do?method='\
    'download&searchType=13'
krx = pd.read_html(url, header=0)[0]
krx = krx[['종목코드', '회사명']]
krx = krx.rename(columns={'종목코드': 'code', '회사명': 'company'})
krx.code = krx.code.map('{:06d}'.format)
krx = krx.set_index('code')
krx

codes = list(krx.index)
companys = [krx.loc[code,'company'] for code in codes]

 

## 3. 백테스트함수 - 조건 추가

pb : Percent Bollinger로 현재 상태가 과매수/ 과매도 상태인지 알려주는 지표, 

조건은 어제 종가기준으로 pb < 특정값보다 작을때 , 오늘 매매 여부를 결정

PB = (close - lower) / (upper - lower)

보통 PB가 0.2이하일 경우, 과매도, PB가 0.8이상일 경우 과매수라고 보는 보조지표임.

def backtest(종목명, k, start='2020-01-01', pb=0.2):
    
    df=mk.get_daily_price(종목명, start)
    df.set_index(df['date'].apply(lambda x:pd.to_datetime(x)),inplace=True)
	
    df['변동폭'] = df['high']-df['low']
    df['목표가'] = df['open'] + df['변동폭'].shift(1)*k
    df['MA3_yes'] = df.close.rolling(window=3).mean().shift(1)
    df['내일시가'] = df.open.shift(-1)
    df['MA20'] = df['close'].rolling(window=20).mean() 
    df['stddev'] = df['close'].rolling(window=20).std() 
    df['upper'] = df['MA20'] + (df['stddev'] * 2)
    df['lower'] = df['MA20'] - (df['stddev'] * 2)
    df['PB'] = (df['close'] - df['lower']) / (df['upper'] - df['lower'])
    df['PB_yes'] = df['PB'].shift(1)
   
    cond = ( df['high'] > df['목표가'] ) & ( df['목표가'] > df['MA3_yes'] ) & ( df['PB_yes'] < pb )

    df.loc[cond,'수익률'] = df.loc[cond,'내일시가']/df.loc[cond,'목표가']*0.9975 - 0.006 #0.9975 수수료, 0.002 슬리피지
    df=df[19:]
    return [df.dropna().shape[0] , df.dropna().수익률.cumprod().iloc[-1] , df.dropna().수익률.cumprod().iloc[-1]**(1/df.dropna().shape[0])]

df = backtest("현대건설",0.5,'2020-01-01', 0.2)
df

 

## 4. 몇가지 종목 확인

def pb구하기(종목명):
    a=[]
    b=[]
    for pb in np.arange(0.1, 1.3, 0.1):
        a.append(backtest(종목명,0.5,'2020-01-01',pb))
        b.append(pb)
    s = pd.Series(a, index=b)
    return s
pb구하기("신풍제약")

▶ pb / [ 만족 횟수 , 누적수익률, 기하평균수익률 ]

▶ pb <1 조건일 때 누적수익률이 가장 좋음, 

 

pb구하기("LG이노텍")

▶ pb < 0.6 일때 누적수익률이 가장 좋음. 

▶ pb < 0.2 일때, 기하평균 수익률이 가장 좋음(9회 만족)

pb구하기("현대글로비스")

▶ PB < 1.2일때, 누적수익률이 가장 좋음

▶ PB < 0.1일때 기하평균 수익률이 가장 좋음(3회 만족)

pb구하기("LG전자")

▶ pb<0.8 일때 누적수익률이 가장 좋음

▶ pb<0.2 일때 기하평균수익률이 가장 좋음 ...

pb구하기("현대바이오")

 

▶ pb < 0.4 일때 누적수익률이 가장 좋음

▶ pb <0.2 일때 기하평균 수익률이 가장 좋음(9회)