본문 바로가기
파이썬 (투자분석용)/Plotly 및 Dash

[python, plotly] 이동평균 그리기

by amAToRoi 2022. 2. 9.
반응형

Pandas의 DataFrame(데이터프레임) 구조를 기본으로 하며, 기초 데이터는 내가 만든 사용자함수 중 GetPriceList()를 통해 획득한 주가정보이다.

0. 준비하기

마음의 준비가 제일 중요한데...

사용자함수 구조와 사용법을 전혀 모르는 python beginner의 경우에는 이 압축파일을 다운받아서 projbullmrkt.py 파일을 작업하고 있는 폴더에 복사해두고 import 해서 사용하자. 그 다음, 바로 "2. plotly로 이동평균 그리기"로 넘어가도 무방하다. 

다음의 3줄로 삼성전자의 일(day)단위 봉차트정보(시가, 고가, 저가, 종가, 거래량 등)와 이동평균 정보를 DataFrame 형태로 구할 수 있다.

import projbullmrkt as bmk

df = bmk.GetPriceList('005930') # 종목코드가 인 삼성전자 주가정보 가져오기
df = bmk.AddMA(df, 'EMA')       # 지수이동평균을 추가하기

'''
>>> df
             Open   High    Low  Close  ...        EMA130        MACD  MACD-signal   MACD-Hist
005930                                  ...
1990-01-03  44000  45000  43200  44800  ...  44800.000000    0.000000     0.000000    0.000000
1990-01-04  45000  45800  44800  45300  ...  45051.923077    2.243590     1.146724    1.096866
1990-01-05  45000  45300  44300  44300  ...  44797.416225   -3.063850    -0.319631   -2.744218
1990-01-06  44800  45000  44500  44500  ...  44721.337574   -4.292888    -1.380125   -2.912763
1990-01-08  44500  44900  44000  44000  ...  44572.597179   -8.678635    -2.972395   -5.706240
...           ...    ...    ...    ...  ...           ...         ...          ...         ...
2022-02-09  74300  74700  74000  74700  ...  75722.009121 -173.000289  -310.116380  137.116091
2022-02-10  75600  75800  74700  75400  ...  75717.092951 -172.969655  -304.153479  131.183824
2022-02-11  75000  75500  74600  74900  ...  75704.618249 -181.613750  -298.825665  117.211914
2022-02-14  74400  74500  73100  73700  ...  75674.013391 -210.779531  -294.997572   84.218041
2022-02-15  74100  74200  73500  73800  ...  75645.402499 -236.700897  -292.462934   55.762037

[8349 rows x 14 columns]

# MACD 도 추가해둔 코드라서, MACD 관련 컬럼을 확인할 수 있다
# 지수이동평균(EMA) 관련 컬럼은 아래와 같다.

                    EMA5         EMA20         EMA45         EMA60        EMA120        EMA130
005930
1990-01-03  44800.000000  44800.000000  44800.000000  44800.000000  44800.000000  44800.000000
1990-01-04  45100.000000  45062.500000  45055.555556  45054.166667  45052.083333  45051.923077
1990-01-05  44721.052632  44782.514571  44792.429230  44794.352375  44797.199139  44797.416225
1990-01-06  44629.230769  44700.956983  44714.377536  44717.044687  44721.031627  44721.337574
1990-01-08  44387.677725  44531.401453  44558.526278  44563.918544  44571.978705  44572.597179
...                  ...           ...           ...           ...           ...           ...
2022-02-09  73857.116894  74976.693359  75568.698060  75549.008831  75697.791570  75722.009121
2022-02-10  74371.411263  75017.008278  75561.363362  75544.123296  75692.869395  75717.092951
2022-02-11  74547.607508  75005.864632  75532.608433  75523.004499  75679.764116  75704.618249
2022-02-14  74265.071672  74881.496572  75452.929805  75463.233860  75647.040742  75674.013391
2022-02-15  74143.381115  74788.020708  75385.411118  75411.980291  75618.164035  75646.929217

[8349 rows x 6 columns]

반대로, 최소한 사용자함수 구조와 사용법을 겨~우 아는 "나" 이상의 수준이라면, 이 포스트에서 rolling과 ewm 메소드를 확인해보고 오자. 물론, 엄청 단순하기 때문에 몰라도 관계없다.

 

1. rolling과 ewm으로 이동평균 데이터 추가하기

데이터 처리전체 소스를 먼저 살짝 보고 다음으로 넘어갈까? (개간단)

import pandas as pd

df = pd.read_csv('https://tistory1.daumcdn.net/tistory/2670941/skin/images/sec_stockprice_amatoroi.c
sv')
df.set_index('005930', inplace=True)

df['SMA005'] = df['Close'].rolling(5, min_periods=5).mean()
df['SMA020'] = df['Close'].rolling(20, min_periods=20).mean()
df['SMA060'] = df['Close'].rolling(60, min_periods=60).mean()
df['SMA120'] = df['Close'].rolling(120, min_periods=120).mean()

df['EMA005'] = df['Close'].ewm(span=5, min_periods=5).mean()
df['EMA020'] = df['Close'].ewm(span=20, min_periods=20).mean()
df['EMA060'] = df['Close'].ewm(span=60, min_periods=60).mean()
df['EMA120'] = df['Close'].ewm(span=120, min_periods=120).mean()

101. 기초 주가데이터

이동평균을 그리기 위해서는 최소한 종가(close) 정보가 필요하다. 주가정보는 네이버에서 스크래핑했으며, 주가정보를 스크래핑하는 방법이 궁금하면 아래의 포스트에서 확인하기 바란다.

 

[python, plotly] 캔들(candlestick) 차트 그리기

★ 프로젝트: Bull Market으로 만들고 있는 사용자 함수 중, GetPriceList( ) 를 활용하여 Plotly 의 Candlestick 차트를 그리는 법을 설명하는 포스트로 GetPriceList()에 대해 정리하고 설명하는 것을 목적함 ☆.

amatoroi.tistory.com

기준 주가 데이터는 Pandas DataFrame 구조로 일자별 해당일의 종가에 해당하며, 다음의 코드를 통해 기초 데이터를 준비할 수 있다. 위 스크래핑 방법으로 네이버금융 홈페이지에서 줏어온 주가정보를 가공한 것이다.

 import pandas as pd
 df = pd.read_csv('https://tistory1.daumcdn.net/tistory/2670941/skin/images/sec_stockprice_amatoroi.csv')
 df.set_index('005930', inplace=True)

>>> df
            Close
005930
2020-02-10  59700
2020-02-11  59900
2020-02-12  60500
2020-02-13  60700
2020-02-14  61800
...           ...
2022-02-09  74700
2022-02-10  75400
2022-02-11  74900
2022-02-14  73700
2022-02-15  73800

[500 rows x 1 columns]

 

이제, rolling 메소드와 ewm 메소드로 이동평균정보를 추가할 차례인데, pandas의 이들 메소드에 대해서는 아래 포스트를 확인하기 바란다.

 

[Pandas] rolling과 ewm으로 이동평균 구하기

Pandas의 rolling 및 ewm 메소드로 차트 분석에서도 사용되는 이동평균을 구해보자. 이동평균에 대해 잘 모르겠다면, 비록, 차트 분석에 맞추어 설명하였지만 이 포스트를 참조하기 바란다. 0. Data 준

amatoroi.tistory.com

 

102. rolling으로 단순이동평균 추가하기

단순이동평균을 구하기 위해서는 종가정보에 rolling 메소드만 적용하면 된다. 아주 간단하다.

df.rolling(5, min_periods=5).mean()

>>>
              Close
005930
2020-02-10      NaN
2020-02-11      NaN
2020-02-12      NaN
2020-02-13      NaN
2020-02-14  60520.0
...             ...
2022-02-09  73700.0
2022-02-10  74120.0
2022-02-11  74300.0
2022-02-14  74440.0
2022-02-15  74500.0

[500 rows x 1 columns]

5일 평균일 경우에는 5라고... 20일 평균이면? 20이라고 바꿔주면 끝이다.

 

103. ewm으로 지수이동평균 추가하기

지수이동평균도 단순이동평균과 마찬가지이다. ewm 메소드만 적용하면 된다.

df.ewm(span=5, min_periods=5).mean()

>>>
                   Close
005930
2020-02-10           NaN
2020-02-11           NaN
2020-02-12           NaN
2020-02-13           NaN
2020-02-14  60921.327014
...                  ...
2022-02-09  73857.116894
2022-02-10  74371.411263
2022-02-11  74547.607508
2022-02-14  74265.071672
2022-02-15  74110.047782

[500 rows x 1 columns]

 

참고: min_periods를 삽입하지 않아도 둘 모두 평균값을 계산해서 제공한다. NaN 데이터가 갖는 데이터 분석의 위험요소를 고려하면, min_periods 조건을 삽입하지 않거나, 사전/사후, 데이터 정제 과정이 필요할 것이다.

 

2. plotly로 이동평균 그리기

plotly에서 가장 손쉽게 사용할 수 있으며, 흔히 시각화 수요가 큰 그래프 오브젝트는 scatter이다. 여기서도 그래프를 그리기 위해 scatter를 사용한다. 또한, plotly 관련 포스트에서 매번 언급하지만,

★ Hint : plotly의 graph_objects는 python의 dict 타입으로, data와 layout를 선언해주면 대부분이 해결된다.

 

데이터셋을 위 2번에서 만들었다고 가정하고, plotly로 시각화하기 위한 코드만 기술하였다. 각 라인에 대한 설명은 코드블럭의 주석을 참고하면 충분하리라 판단한다. 코드 내 ⑦번에 대한 설명만 추가하자면, 이동평균은 주가 차트에 겹쳐 그리는 것이 가장 보기가 좋으므로 겹쳐그리기 위해 주가차트가 포함된 data에 주가차트와 동일한 x축으로 y값만 달리하여 20일, 60일, 120일 이동평균을 추가하였다.

import plotly.graph_objects as go               # ① plotly의 graph_objects를 불러오자

dict_of_stock = dict({                          # ② dict 타입으로 data를 정의한다(layout은 plotly 기본값으로 넣자)
    "data": [
            # 종가기준 기본 주가차트
            {
              "type":"scatter",                 # ③ 그래프 타입은 scatter 이다.
              "x":df.index.to_list(),           # ④ x 축은 날짜
              "y":df.loc[:,'Close'].to_list(),  # ⑤ y 축은 종가
              "name":"삼성전자"                 # ⑥ 그래프 이름은 "삼성전자"로 지정했다.
            }
            # 지수이동평균 (20일)
            ,{                                  # ⑦
              "type":"scatter",
              "x":df.index.to_list(),
              "y":df.loc[:,'EMA020'].to_list(),
              "name":"20일평균"
            }
            # 지수이동평균 (60일)
            ,{
              "type":"scatter",
              "x":df.index.to_list(),
              "y":df.loc[:,'EMA060'].to_list(),
              "name":"60일평균"
            }
            # 지수이동평균 (120일)
            ,{
              "type":"scatter",
              "x":df.index.to_list(),
              "y":df.loc[:,'EMA120'].to_list(),
              "name":"120일평균"
            }
            ]
    })

fig = go.Figure(dict_of_stock)
fig.show()

 

3. 전체코드 및 결과물

더보기
더보기
import pandas as pd

df = pd.read_csv('https://tistory1.daumcdn.net/tistory/2670941/skin/images/sec_stockprice_amatoroi.csv')
df.set_index('005930', inplace=True)

df['SMA005'] = df['Close'].rolling(5, min_periods=5).mean()
df['SMA020'] = df['Close'].rolling(20, min_periods=20).mean()
df['SMA060'] = df['Close'].rolling(60, min_periods=60).mean()
df['SMA120'] = df['Close'].rolling(120, min_periods=120).mean()
df['EMA005'] = df['Close'].ewm(span=5, min_periods=5).mean()
df['EMA020'] = df['Close'].ewm(span=20, min_periods=20).mean()
df['EMA060'] = df['Close'].ewm(span=60, min_periods=60).mean()
df['EMA120'] = df['Close'].ewm(span=120, min_periods=120).mean()

import plotly.graph_objects as go

dict_of_stock = dict({
    "data": [
            # 종가기준 기본 주가차트
            {
              "type":"scatter",
              "x":df.index.to_list(),
              "y":df.loc[:,'Close'].to_list(),
              "name":"삼성전자"
            },
            # 지수이동평균 (20일)
            {
              "type":"scatter",
              "x":df.index.to_list(),
              "y":df.loc[:,'EMA020'].to_list(),
              "name":"20일평균"
            },
            # 지수이동평균 (60일)
            {
              "type":"scatter",
              "x":df.index.to_list(),
              "y":df.loc[:,'EMA060'].to_list(),
              "name":"60일평균"
            },
            # 지수이동평균 (120일)
            {
              "type":"scatter",
              "x":df.index.to_list(),
              "y":df.loc[:,'EMA120'].to_list(),
              "name":"120일평균"
            }
            ]
    })

fig = go.Figure(dict_of_stock)
fig.show()
반응형

댓글