본문 바로가기
개발일지

파이썬 데이터분석 4주차 정리 (주식 그래프 백테스팅)

by 디지털뚜이 2022. 12. 19.

스파르타코딩클럽 파이썬 데이터분석 공부 4주차 개발일지 기록

!pip install yfinance pandas-datareader finance-datareader
from pandas_datareader import data as pdr

import yfinance as yf
yf.pdr_override()

import numpy as np
import pandas as pd

import FinanceDataReader as fdr
df.plot(y=['Open','Close'],figsize=(15,3), grid=True
#X축은 데이터 기본 행인 날짜, Y축은 지정한 Open(시가), Close(종가) 
#figsize는 그래프 표시크기
#grid는 눈금
 
# 한 표에 그래프를 여럿 넣는 방법 => df변수에 여러 종목의 원하는 항목의 값을 담는다.

df_1 = fdr.DataReader('005930','2018'#삼성
df_2 = fdr.DataReader('066570','2018'#LG

df = pd.DataFrame()
df['Samsung'] = df_1[['Close']] #삼성 종목의 종가를 df변수에 Samsung 항목을 만들어 넣음
df['LG'] = df_2[['Close']] #LG 종목의 종가를 df변수에 LG 항목을 만들어 넣음

df.tail(100).plot(figsize=(15,3)) #최근100일만
# 3일 이동평균선

df = fdr.DataReader('005930','2018')
df = df[['Close']]
df['ma'] = df.rolling(3).mean() #3일마다 평균구하기 #3일이평선값을 ma 항목에 넣기
df
 

사고팔고 백테스팅


def get_return(code,n): #code는 종목코드 n은 n일이동평균선

  df = fdr.DataReader(code,'2018')

  df = df[['Close']].copy() # 나중에 수익률을 다루는데 원본이 바뀔수 있어 에러뜸 이땐 복사본으로 처리

  df['ma'] = df.rolling(n).mean().shift(1#n일이평선을 그 다음날로 한칸씩 밀어서 비교해야 맞음 그래서 shift(1)로 밀어줌

  df['action'] = np.where(df['Close'] > df['ma'], 'buy''sell'#np.where는 if문과 비슷함 #일봉보다 이평선이 낮으면 buy값, 높으면 sell값 설정해둠

  df.iloc[-1,-1] = 'sell' #iloc[-1,-1]은 마지막값 마지막 값은 sell값으로 지정 #마지막은 팔아야 수익율 측정 가능??

  cond1 = (df['action'] == 'buy') & (df['action'].shift(1) == 'sell'# 기준일이 이평선이 낮은데 다음날 이평선이 높으면 살 시점 
  cond2 = (df['action'] == 'sell') & (df['action'].shift(1) == 'buy'# 기준일이 이평선이 높은데 다음날 이평선이 낮으면 팔 시점 

  df_buy = df[cond1].reset_index() # 살 시점을 변수로 모아서 지정 
  df_sell = df[cond2].reset_index() # 팔 시점을 변수로 모아서 지정
  #아래 concat으로 묶어줄때 서로 index가 달라 안붙음 그래서 reset_index()으로 인덱스값 없애고 가로로 붙게함

  df_buy.columns = ['날짜','종가(buy)','이평값','액션']
  df_sell.columns = ['날짜','종가(sell)','이평값','액션'#밑에 합치면 항목이름이 중복되기 때문에 미리 항목이름을 바꿔줌

  df_result = pd.concat([df_buy,df_sell],axis=1#사고 파는 시점을 pd.concat으로 붙이기(공통항목으로 묶어줌) #axis=1는 가로로 붙이는 기능

  df_result['수익률'] = df_result['종가(sell)'] / df_result['종가(buy)'# 수익률 항목 추가

  return (df_result[['수익률']].cumprod().iloc[-1,-1] - 1)*100 
  #.cumprod()은 누적곱 기능 (수익률이 0.9 1.1로 적혀있어서 다 곱하면 최종 수익률이 나옴)
  #iloc[-1,-1]은 누적곱의 마지막 값
  #1.xx 값이기 때문에 -1을 하고 *100은 퍼센테이지화함
  #함수화 하면 함수의 최종값은 return 걸어줘야함
 
get_return('066570',3)

 

 

단기이평선과 장기이평선의 크로스로 백테스팅


def get_return_sl(codeshortlong):
  df = fdr.DataReader(code,'2018')

  df = df[['Close']].copy()

  df['ma1'] = df['Close'].rolling(short).mean().shift(1#없는 값때문에 에러가 나서 close항목만 롤링해서 이평선 값 넣음 
  df['ma2'] = df['Close'].rolling(long).mean().shift(1)

  df['action'] = np.where(df['ma1'] > df['ma2'], 'buy''sell')

  df.iloc[-1,-1] = 'sell'

  cond1 = (df['action'] == 'buy') & (df['action'].shift(1) == 'sell')
  cond2 = (df['action'] == 'sell') & (df['action'].shift(1) == 'buy')

  df_buy = df[cond1].reset_index()
  df_sell = df[cond2].reset_index()
  
  df_buy.columns = ['날짜','종가(buy)','이평값1','이평값2','액션']
  df_sell.columns = ['날짜','종가(sell)','이평값1','이평값2','액션']

  df_result = pd.concat([df_buy,df_sell],axis=1)

  df_result['수익률'] = df_result['종가(sell)'] / df_result['종가(buy)']

  df_final = (df_result[['수익률']].cumprod().tail(1) - 1)*100
  df_final['단기'] = short
  df_final['장기'] = long

  return df_final
get_return_sl('066570'330)

 

# 특정 종목의 최적의 단기이평선의 설정일, 장기이평선의 설정일 값을 구하기

def get_high_sl(code):
  dfs = [] # df의 값들을 배열시킬 배열변수 dfs선언
  for short in range(3,11): # range(3,11)은 3부터 10까지의 값
    for long in range(30,61):
      df = get_return_sl(code,short,long)
      dfs.append(df) #수익률 df를 배열변수 dfs에 하나씩 추가

  df_result = pd.concat(dfs) #최종 dfs값을 공통항목으로 보기좋게 정리
  return df_result.sort_values(by='수익률', ascending=False#수익률 순으로 정렬
 
get_high_sl('066570')