[파이썬] 백테스팅(Back-testing)

2023. 1. 4. 18:55자격증(다다익선)/파이썬

728x90

https://chanytv.tistory.com/137

 

[파이썬] 변수&기본연산 / 리스트,딕셔너리 / 함수 / 조건문 / 반복문

[파이썬] 변수&기본연산 / 리스트,딕셔너리 / 함수 / 조건문 / 반복문 파이썬 기초를 시작하면서.... 크롤링 한 번 해보자고 시작한 파이썬 공부다. 모든 공부는 기초가 중요한 법!! 이 번 공부로 파

chanytv.tistory.com

https://chanytv.tistory.com/138

 

[파이썬] 스크래핑(크롤링)

https://chanytv.tistory.com/137 [파이썬] 변수&기본연산 / 리스트,딕셔너리 / 함수 / 조건문 / 반복문 [파이썬] 변수&기본연산 / 리스트,딕셔너리 / 함수 / 조건문 / 반복문 파이썬 기초를 시작하면서.... 크

chanytv.tistory.com

https://chanytv.tistory.com/139

 

[파이썬] openpyxl / 파일 업로드, 다운로드

https://chanytv.tistory.com/137 [파이썬] 변수&기본연산 / 리스트,딕셔너리 / 함수 / 조건문 / 반복문 [파이썬] 변수&기본연산 / 리스트,딕셔너리 / 함수 / 조건문 / 반복문 파이썬 기초를 시작하면서.... 크

chanytv.tistory.com

https://chanytv.tistory.com/142

 

[파이썬] Pandas와 DataFrame

https://chanytv.tistory.com/137 [파이썬] 변수&기본연산 / 리스트,딕셔너리 / 함수 / 조건문 / 반복문 [파이썬] 변수&기본연산 / 리스트,딕셔너리 / 함수 / 조건문 / 반복문 파이썬 기초를 시작하면서.... 크

chanytv.tistory.com

https://chanytv.tistory.com/143

 

[파이썬] yfinance을 이용한 해외 주식 정보 분석

https://chanytv.tistory.com/137 [파이썬] 변수&기본연산 / 리스트,딕셔너리 / 함수 / 조건문 / 반복문 [파이썬] 변수&기본연산 / 리스트,딕셔너리 / 함수 / 조건문 / 반복문 파이썬 기초를 시작하면서.... 크

chanytv.tistory.com

https://chanytv.tistory.com/148

 

[파이썬] Open API

https://chanytv.tistory.com/137 [파이썬] 변수&기본연산 / 리스트,딕셔너리 / 함수 / 조건문 / 반복문 [파이썬] 변수&기본연산 / 리스트,딕셔너리 / 함수 / 조건문 / 반복문 파이썬 기초를 시작하면서.... 크

chanytv.tistory.com

 

[파이썬] 백테스팅(Back-testing)


주식 기본용어 파악하기

 

백테스팅이란 단어는 주식에 ㅈ자도 모르는 나로선 아주 생소한 단어다. 그 뜻은 '이전 주가의 추이에 전략을 대입해보는 것'이란 거다. 즉 주식의 흐름을 파악하는 것 같다. 이 번 주차를 공부하기 위해선 약간의 주식지식이 필요한 듯하다. 수학공식을 알아야 수학문제를 풀 수 있듯이 어찌 보면 당연한 게 아니겠는가.

 

이동평균선 : 며칠 간의 가격을 평균하여 움직이는 선

골든크로스 : 주가가 높아질 가능성이 있다는 신호

데스크로스 : 주가가 낮아질 가능성이 있다는 신호

 


파이썬으로 주가정보 불러오기

 

환경구성은 아래와 같이 하면 된다.

!pip install yfinance pandas-datareader finance-datareader
	#yfinance : 주가정보를 불러올 수 있는 API

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 = fdr.DataReader('005930','2018')

df.head()

조회를 해보면 'Open: 시초가 / High: 고가 / Low: 저가 / Close: 종가 / Volume: 거래량 / Change: 변동' 을 기준으로 결과물이 프린팅 된다. 결과물이 잘 나오는 게 확인 됐으니 이제 골든크로스와 데스크로스 볼 수 있는 코딩을 하면 되는 거다.


데이터를 그래프롤 만들기

 

그래프를 그리는 방법은 아래와 같다.

df.plot(y=['Close'],figsize=(15,8),grid=True)

plot : df를 그래프화 하는 명령어

 

y=['Close'] : y축은 Close(종가)로 한다.

figsize(15,8) : 그래프의 사이즈다(가로,세로)

grid : 격자추가

 

종목 두 개를 비교하는 방법은 아래와 같다.

df_1 = fdr.DataReader('005930','2018')
df_2 = fdr.DataReader('066570','2018')

df_tot = pd.DataFrame()
df_tot['Samsung'] = df_1[['Change']]
df_tot['LG'] = df_2[['Change']]

df_tot.tail(100).plot(figsize=(15,8))

각 회사 코드별로 명령어를 지정해주고 회사별로 '변동'값을 불러온다.

불러온 값의 마지막 100개의 값을 가로 15 / 세로 8 사이즈 그래프로 프린팅 한다.


이동평균값 구해서 그래프 만들기

 

이동평균은 예를 들면 3일의 평균값의 이동변화를 나타내는 선이다.

즉 내가 불러온 데이터의 1,2,3일의 평균 / 2,3,4일의 평균 / 3,4,5일의 평균..... 의 값을 구하면 이동평균선을 그릴 수 있다는 것이다.

 

매일 3일마다의 평균값을 구하는 명령어는 아래와 같다.

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

df = df[['Close']]

df['ma'] = df.rolling(3).mean()

df

비교를 하기 위해서 'ma'행을 추가해서 표를 출력한다.

 

날짜별로 종가를 알고 3일 별 평균의 값을 알기 때문에 예를 들어 1,2,3일의 평균의 값에서 4일 날 값을 비교하여 올랐다면 3일 날 샀어야 하고 내려갔다면 3일날 팔았어야 할 것이다. 그 변화추이는 아래 코딩을 통해 확인이 가능하다.

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

df = df[['Close']]

df['ma'] = df.rolling(3).mean().shift(1)

df['action'] = np.where(df['Close'] > df['ma'], 'buy', 'sell')

df

'ma'행에 값을 'shift(1)'로 한 칸씩 밀려서 값을 출력한다.

'action'행을 하나 만드는데 'Close'의 값이 'ma'값보다 크면 'buy'를 적으면 'sell'을 출력한다.


수익률 구하기

 

기본적으로 값을 불러와 비교하여 사고파는 값까지 불러낼 수 있다면 이제 코딩 전략을 짜야할 것이다.

'buy'란 값이 3일 연속으로 출력됐다면 당연히 사는 타이밍이고 그다음 값이 'sell'이면 팔아야할 시점이다.

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

df = df[['Close']]

df['ma'] = df.rolling(3).mean().shift(1)

df['action'] = np.where(df['Close'] > df['ma'], 'buy', 'sell')

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

# df_buy = df[cond1]
#df_sell = df[cond2]

df_sell #파는시점(df_buy는 사는 시점)

'action'의 값이 'buy'이고 그 다음 값이 'sell'이면  'real_buy'에 'buy' 아니면 공란

반대로 'sell'이 반복되다 'buy'이면 팔아야 한 시점이니 마찬가지로 코딩을 해주면 된다.

 

수익률을 구할 수 있으니, 사고파는 시점을 표에 표시할 수 있게 됐다.

 

수익률은 판 값 / 산 값이다. 수익률 행을 하나 더 추가해서 수식을 적용해주면 된다.

한 회사만 조회할 것이 아니기 때문에 함수를 사용하여 코드와 이동평균값을 바꿔주면 되겠다. 완성 코드는 아래와 같다.

def get_return(code,n):
  df = fdr.DataReader(code,'2018')

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

  df['ma'] = df.rolling(n).mean().shift(1)

  df['action'] = np.where(df['Close'] > df['ma'], '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_buy.columns = ['날짜','종가(buy)','이평값','액션']

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

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

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

  return df_result[['수익률']].cumprod().iloc[-1,-1] - 1
  
	get_return('005930',3)

	get_return('066570',6)

골든/데스 크로스

 

골든/데스 크로스를 구하려면 단기이평선과 장기이평선을 먼저 구해야 한다.

위에 완성된 코드에서 def 함수의 'n'값만 변경해주면 되기 때문에 값을 구하기는 쉽다.

 

최종 결과물은 아래와 같다.

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

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

  df['ma1'] = df['Close'].rolling(short).mean().shift(1)
  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_buy.columns = ['날짜','종가(buy)','이평값1','이평값2','액션']

  df_sell = df[cond2].reset_index()
  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('005930',3,30)

'005930'코드의 회사 주식정보를 불러오는데 3일 평균과 30일 평균의 이동평균선을 구해내는 코드다.

728x90