오늘의 예제: 이동 평균 선 추가하기
파이쏜에서 이동평균은 어떻게 계산할 수 있을까요?
일단 이동평균 정의는 이렇습니다.
n개의 항목이 있는 시계열 time series의 경우,
P1, P2, ..., Pn
길이 2m+1인 이동 평균은
MAk= (Pk-m, Pk-m+1, ..., Pk, ..., Pk+m-1, Pk+m)/(2m+1)
포트란이나 C처럼 좀 더 원초적인 프로그래밍에 익숙한 사람이라면 이런 알고리즘이 떠오를 거에요
Loop j in (1, n)
Loop i in (-m, m)
ma(j)=ma(j)+P(j+i)
End Loop
End Loop
그런데 Matlab과 유사한 Numpy의 경우 원소 하나하나를 직접 방문하며 계산하는 게 비효율적 입니다. 최대한 Matrix 형태를 유지한 채로 계산하는 게 좋죠. 그럼 어떻게 해야 할까요. 혹시 Numpy에서 지원하는 이동평균에 특화된 함수가 있는 지 한 번 찾아봤습니다.
있네요. 당연히 누군가 이미 질문 했고, 누군가 이미 답을 달았습니다.
https://stackoverflow.com/questions/14313510/how-to-calculate-moving-average-using-numpy
여기서 가져온 답은 아래와 같습니다.
def moving_average(a, n=3) :
ret = np.cumsum(a, dtype=float)
ret[n:] = ret[n:] - ret[:-n]
return ret[n - 1:] / n
Numpy에 이미 정의된 함수 중에 "cumsum"을 이용했습니다. Cumulative Sum 누적합계를 계산하는 함수입니다. 예를 들면,
>> np.cumsum([1,2,3,4,5])
이렇게 계산하면 출력은
[1,3,6,10,15]
이렇게 나오는 거죠.
참고로, 누적합계를 이용한 방법이 Numpy이기 때문에 가능한, 그런 특별한 건 아니구요, 프로그래밍 언어에 관계없이 알고리즘 상으로 더 효율적인 방법입니다. 위에 루프 2번 돌리는 것 보다 시간을 많이 절약할 수 있죠. (이렇게 더 효율적인 알고리즘을 연구하는 학문이 Computational Science 계산과학입니다.)
그런데 가격을 이용한 이동평균선은 내일의 가격을 모르니까 앞 뒤로 몇 개의 값들을 이용해 평균을 하지 않고, 어떤 시점에서 과거 몇 개의 가격을 이용해서 평균을 계산합니다. 그래서 위 함수를 살짝 고쳤습니다.
def moving_average(a, n=3): ### "n=3" indicates the default value
ret = np.cumsum(a, dtype=float)
ret[n:] = ret[n:] - ret[:-n]
ret/=n
### Masking initial a few values to prevent weird values
ret[:n-1]=ret[n-1]
return ret
이렇게 하면 주어진 시계열 자료와 길이가 똑같은 이동평균 시계열 자료가 나오겠죠. 처음 몇 값들은 Dummy이긴 하지만요.
그리고 중간에 "ret[:-n]" 이라는 표현이 어려울 것 같은데, 파이쏜에서 기본적으로 "-1"이라는 인덱스는 List이든 Numpy Array이든 가장 마지막 값을 가리킵니다. "-2"는 끝에서 2번째 값을 가리키구요. 그래서 "a[:-1]" 이라는 표현이 있다면 이것은 a라고 하는 변수 값들 중 마지막 값을 제외한 나머지라는 뜻이 됩니다.
자, 이제 정리해봅시다.
저번 시간에서 작성했던 "read_txt+plot_candle.py3.py"를 새 이름으로 저장합니다. 새 이름은 "read_txt+plot_candle+ma.py3.py" 입니다.
위쪽의 함수들 모아놓은 곳에 2개의 함수를 추가합니다.
def moving_average(a, n=3): ### "n=3" indicates the default value
ret = np.cumsum(a, dtype=float)
ret[n:] = ret[n:] - ret[:-n]
ret/=n
### Masking initial a few values to prevent weird values
ret[:n-1]=ret[n-1]
return ret
def draw_ma_line(ax1,dates,ma,c='b',label=''):
### Line Plot
line1=ax1.plot(dates, ma, color=c, linewidth=0.7, linestyle='-', alpha=0.7, label=label)
return line1
본문 중간에 "ini_date= dates[0]" 줄 위에 다음 부분을 끼워 넣습니다.
### Add Moving Average
## Here, MA is based on the closing price
ma10= moving_average(prices[3,:],n=10)
ma50= moving_average(prices[3,:],n=50)
### Cut only for targeted period
이후 캔들스틱 그리고 나서 그림 저장하기 전에 다음 부분을 끼워 넣습니다.
line10=draw_ma_line(ax1,dates,ma10,c='b',label='10-day MA')
line50=draw_ma_line(ax1,dates,ma50,c='r',label='50-day MA')
ax1.legend(loc='upper left',bbox_to_anchor=(0.06, 0.9),fontsize=11) # x and y relative location in ax1
이렇게 해서 다음과 같은 결과를 얻었습니다.
다음 시간에는 @roostermine 님이 알려주신,
http://www.cryptodatadownload.com/data/northamerican/
이 사이트에서 받을 수 있는 CSV 파일을 파이쏜에서 다뤄보도록 하겠습니다.
관련 글들
Matplotlib List
[Matplotlib] 00. Intro + 01. Page Setup
[Matplotlib] 02. Axes Setup: Subplots
[Matplotlib] 03. Axes Setup: Text, Label, and Annotation
[Matplotlib] 04. Axes Setup: Ticks and Tick Labels
[Matplotlib] 05. Plot Accessories: Grid and Supporting Lines
[Matplotlib] 06. Plot Accessories: Legend
[Matplotlib] 07. Plot Main: Plot
[Matplotlib] 08. Plot Main: Imshow
[Matplotlib] 09. Plot Accessary: Color Map (part1)
[Matplotlib] 10. Plot Accessary: Color Map (part2) + Color Bar
F2PY List
[F2PY] 01. Basic Example: Simple Gaussian 2D Filter
[F2PY] 02. Basic Example: Moving Average
[F2PY] 03. Advanced Example: Using OpenMP
Scipy+Numpy List
[SciPy] 1. Linear Regression (Application to Scatter Plot)
[SciPy] 2. Density Estimation (Application to Scatter Plot)
[Scipy+Numpy] 3. 2D Histogram + [Matplotlib] 11. Plot Main: Pcolormesh
Road to Finance
#00 Read Text File
#01 Draw CandleSticks
#02 Moving Average
zorba님이 dj-on-steem님을 멘션하셨습니당. 아래 링크를 누르시면 연결되용~ ^^
zorba님의 [2019/7/21] 가장 빠른 해외 소식! 해외 스티미언 소모임 회원들의 글을 소개해드립니다.
Downvoting a post can decrease pending rewards and make it less visible. Common reasons:
Submit
Congratulations @dj-on-steem! You have completed the following achievement on the Steem blockchain and have been rewarded with new badge(s) :
You can view your badges on your Steem Board and compare to others on the Steem Ranking
If you no longer want to receive notifications, reply to this comment with the word
STOP
Vote for @Steemitboard as a witness to get one more award and increased upvotes!
Downvoting a post can decrease pending rewards and make it less visible. Common reasons:
Submit
zorba님이 dj-on-steem님을 멘션하셨습니당. 아래 링크를 누르시면 연결되용~ ^^
zorba님의 [2019/7/20] 가장 빠른 해외 소식! 해외 스티미언 소모임 회원들의 글을 소개해드립니다.
Downvoting a post can decrease pending rewards and make it less visible. Common reasons:
Submit