Rolling
Rolling#
주식을 하신 분들은 이동평균선에 대하여 많이 들어보셨을 것이라고 생각합니다. rolling 은 이동평균선을 간단하게 만들어줄 수 있는 메소드입니다. 예제를 보시면 금방 이해가 되 실 것이라고 생각합니다. 일단 삼성전자 일봉을 가져오겠습니다.
import FinanceDataReader as fdr
code = '005930' # 삼성전자
stock_data = fdr.DataReader(code, start='2021-01-03', end='2021-12-31')
stock_data.head().style.set_table_attributes('style="font-size: 12px"')
Open | High | Low | Close | Volume | Change | |
---|---|---|---|---|---|---|
Date | ||||||
2021-01-04 00:00:00 | 81000 | 84400 | 80200 | 83000 | 38655276 | 0.024691 |
2021-01-05 00:00:00 | 81600 | 83900 | 81600 | 83900 | 35335669 | 0.010843 |
2021-01-06 00:00:00 | 83300 | 84500 | 82100 | 82200 | 42089013 | -0.020262 |
2021-01-07 00:00:00 | 82800 | 84200 | 82700 | 82900 | 32644642 | 0.008516 |
2021-01-08 00:00:00 | 83300 | 90000 | 83000 | 88800 | 59013307 | 0.071170 |
일봉의 종가에 대하여 5 일 이동평균선을 만들어 '5 day moving average' 라는 이름의 컬럼에 담았습니다. rolling(5) 은 5 개 row 로 만들어진 창(window) 을 한 단계씩 진행하라는 뜻이고, mean() 을 한 이유는 각 창의 평균값을 구하라는 뜻입니다. 처음 4개의 row 에는 5 일의 창이 만들어지지 않으므로 'NaN'(값 없음) 이 되고 처음으로 시작하는 '5 day moving average' 값은 2021년 1월 8일부터 시작하게 됩니다. 2021년 1월 8일의 5일 이동평균선 값 84,160 은 1월 4일 ~ 1월 8일까지 5일 종가들의 평균값입니다.
stock_data['5 day moving average'] = stock_data['Close'].rolling(5).mean()
stock_data.head(6).style.set_table_attributes('style="font-size: 12px"')
Open | High | Low | Close | Volume | Change | 5 day moving average | |
---|---|---|---|---|---|---|---|
Date | |||||||
2021-01-04 00:00:00 | 81000 | 84400 | 80200 | 83000 | 38655276 | 0.024691 | nan |
2021-01-05 00:00:00 | 81600 | 83900 | 81600 | 83900 | 35335669 | 0.010843 | nan |
2021-01-06 00:00:00 | 83300 | 84500 | 82100 | 82200 | 42089013 | -0.020262 | nan |
2021-01-07 00:00:00 | 82800 | 84200 | 82700 | 82900 | 32644642 | 0.008516 | nan |
2021-01-08 00:00:00 | 83300 | 90000 | 83000 | 88800 | 59013307 | 0.071170 | 84160.000000 |
2021-01-11 00:00:00 | 90000 | 96800 | 89500 | 91000 | 90306177 | 0.024775 | 85760.000000 |
같은 방식으로 20일 이동평균선도 만들어 보겠습니다. 그리고 골든크로스(5일 이동평균선이 20일 이동평균선을 뚫고 올라가는) 지점이 어디 인지도 알아보겠습니다. 5일 이동평균선과 동일하게 20일 이동평균선은 20번째 열부터 존재합니다.
stock_data['20 day moving average'] = stock_data['Close'].rolling(20).mean()
stock_data.head(21).style.set_table_attributes('style="font-size: 12px"')
Open | High | Low | Close | Volume | Change | 5 day moving average | 20 day moving average | |
---|---|---|---|---|---|---|---|---|
Date | ||||||||
2021-01-04 00:00:00 | 81000 | 84400 | 80200 | 83000 | 38655276 | 0.024691 | nan | nan |
2021-01-05 00:00:00 | 81600 | 83900 | 81600 | 83900 | 35335669 | 0.010843 | nan | nan |
2021-01-06 00:00:00 | 83300 | 84500 | 82100 | 82200 | 42089013 | -0.020262 | nan | nan |
2021-01-07 00:00:00 | 82800 | 84200 | 82700 | 82900 | 32644642 | 0.008516 | nan | nan |
2021-01-08 00:00:00 | 83300 | 90000 | 83000 | 88800 | 59013307 | 0.071170 | 84160.000000 | nan |
2021-01-11 00:00:00 | 90000 | 96800 | 89500 | 91000 | 90306177 | 0.024775 | 85760.000000 | nan |
2021-01-12 00:00:00 | 90300 | 91400 | 87800 | 90600 | 48682416 | -0.004396 | 87100.000000 | nan |
2021-01-13 00:00:00 | 89800 | 91200 | 89100 | 89700 | 36068848 | -0.009934 | 88600.000000 | nan |
2021-01-14 00:00:00 | 88700 | 90000 | 88700 | 89700 | 26393970 | 0.000000 | 89960.000000 | nan |
2021-01-15 00:00:00 | 89800 | 91800 | 88000 | 88000 | 33431809 | -0.018952 | 89800.000000 | nan |
2021-01-18 00:00:00 | 86600 | 87300 | 84100 | 85000 | 43227951 | -0.034091 | 88600.000000 | nan |
2021-01-19 00:00:00 | 84500 | 88000 | 83600 | 87000 | 39895044 | 0.023529 | 87880.000000 | nan |
2021-01-20 00:00:00 | 89000 | 89000 | 86500 | 87200 | 25211127 | 0.002299 | 87380.000000 | nan |
2021-01-21 00:00:00 | 87500 | 88600 | 86500 | 88100 | 25318011 | 0.010321 | 87060.000000 | nan |
2021-01-22 00:00:00 | 89000 | 89700 | 86800 | 86800 | 30861661 | -0.014756 | 86820.000000 | nan |
2021-01-25 00:00:00 | 87000 | 89900 | 86300 | 89400 | 27258534 | 0.029954 | 87700.000000 | nan |
2021-01-26 00:00:00 | 88800 | 89200 | 86500 | 86700 | 33178936 | -0.030201 | 87640.000000 | nan |
2021-01-27 00:00:00 | 86600 | 87700 | 85600 | 85600 | 26423070 | -0.012687 | 87320.000000 | nan |
2021-01-28 00:00:00 | 83200 | 85600 | 83200 | 83700 | 31859808 | -0.022196 | 86440.000000 | nan |
2021-01-29 00:00:00 | 84500 | 85000 | 82000 | 82000 | 39615978 | -0.020311 | 85480.000000 | 86565.000000 |
2021-02-01 00:00:00 | 81700 | 83400 | 81000 | 83000 | 28046832 | 0.012195 | 84200.000000 | 86565.000000 |
우선 NaN 으로 표시가 된 값이 없는 모든 열을 제거하고 싶습니다. dropna 라는 메소드도 활용할 것인데요. dropna 를 하면 NaN 가 있는 모든 열을 제거합니다. 제거한 후 자기 자신을 덮어쓰라고 명령하는 것은 inplace=True 라는 인수인데요. 새로운 DataFrame 을 만들지 않고 dropna(inplace=True) 하여 값이 없는 모든 열을 제거한 후, 자기 자신을 덮어쓰도록 하겠습니다.
stock_data.dropna(inplace=True) # NaN 이 있는 모든 row 제거
stock_data.head().style.set_table_attributes('style="font-size: 12px"')
Open | High | Low | Close | Volume | Change | 5 day moving average | 20 day moving average | |
---|---|---|---|---|---|---|---|---|
Date | ||||||||
2021-01-29 00:00:00 | 84500 | 85000 | 82000 | 82000 | 39615978 | -0.020311 | 85480.000000 | 86565.000000 |
2021-02-01 00:00:00 | 81700 | 83400 | 81000 | 83000 | 28046832 | 0.012195 | 84200.000000 | 86565.000000 |
2021-02-02 00:00:00 | 84100 | 86400 | 83700 | 84400 | 26302077 | 0.016867 | 83740.000000 | 86590.000000 |
2021-02-03 00:00:00 | 84800 | 85400 | 83400 | 84600 | 22112205 | 0.002370 | 83540.000000 | 86710.000000 |
2021-02-04 00:00:00 | 83500 | 83800 | 82100 | 82500 | 24171688 | -0.024823 | 83300.000000 | 86690.000000 |
이제 5일 이동평균선이 20일 이동평균선보다 작았다가 커지는 지점을 찾으면 됩니다. DataFrame 의 필터링에 대하여는 아직 다루지 않았습니다. 설명을 드리면, df(DataFrame) 에서 원하는 row 를 가져오고 싶을 때는 df[조건] 처럼 대괄호 안에 조건을 넣어 주면 됩니다. 아래에서 stock_data['cross_flag'==1] 은 stock_data 에서 True 인 열과 False 인 열을 구분하는 역할을 합니다. stock_data['cross_flag'].shift(1)==0 은 전 날의 cross_flag 값이 0 인 경우를 찾는 것인데요. 결국 전날은 cross_flag 값이 0, 당일은 cross_flag 값이 1 날을 찾는 조건이 됩니다. 최종 결과를 보시면 2021년은 3월 3일에 최초 골든크로스가 일어났습니다.
stock_data['cross_flag'] = (stock_data['5 day moving average'] > stock_data['20 day moving average']).astype(int) # True/False 결과 값을 1/0 으로 바꿔줌
s = stock_data[(stock_data['cross_flag'].shift(1)==0) & (stock_data['cross_flag']==1)] # 조건 - 전날에는 5일 이평선이 20일 이평선보다 작거나 같아는데, 당일은 5일 이평선이 20일 이평선 보다 커짐
s.style.set_table_attributes('style="font-size: 12px"')
Open | High | Low | Close | Volume | Change | 5 day moving average | 20 day moving average | cross_flag | |
---|---|---|---|---|---|---|---|---|---|
Date | |||||||||
2021-03-03 00:00:00 | 83500 | 84000 | 82800 | 84000 | 19882132 | 0.004785 | 83480.000000 | 83195.000000 | 1 |
2021-03-18 00:00:00 | 82800 | 83800 | 82600 | 82900 | 18585244 | 0.007290 | 82520.000000 | 82485.000000 | 1 |
2021-04-02 00:00:00 | 84000 | 85200 | 83900 | 84800 | 22997538 | 0.022919 | 82580.000000 | 82060.000000 | 1 |
2021-06-03 00:00:00 | 81300 | 83000 | 81100 | 82800 | 29546007 | 0.024752 | 80960.000000 | 80490.000000 | 1 |
2021-06-29 00:00:00 | 81900 | 82100 | 80800 | 81000 | 15744317 | -0.010989 | 81160.000000 | 81150.000000 | 1 |
2021-08-04 00:00:00 | 82200 | 83100 | 81800 | 82900 | 25642368 | 0.018428 | 80220.000000 | 79590.000000 | 1 |
2021-09-03 00:00:00 | 76400 | 76700 | 76000 | 76600 | 12096419 | 0.007895 | 76140.000000 | 76060.000000 | 1 |
2021-11-03 00:00:00 | 71700 | 71700 | 70100 | 70400 | 12770428 | -0.015385 | 70460.000000 | 70355.000000 | 1 |
2021-11-15 00:00:00 | 71700 | 71900 | 70900 | 71400 | 12420710 | 0.011331 | 70520.000000 | 70460.000000 | 1 |