본문 바로가기
미래걱정/주식

슬기로운 퀀트투자 - 2장 일단 해보자 편

by JHistory_ 2023. 2. 8.
반응형
 
미국 주식으로 시작하는 슬기로운 퀀트투자
이 책은 서학개미를 위한 미국 주식 퀀트투자 입문+실습서이다. 퀀트투자는 수학적, 통계적 기법을 활용해 투자 종목을 발굴하는 투자 방법이다. 퀀트투자 전략을 만들기 위해서는 유명한 전략들이 어떻게 만들어졌는지 개념을 이해하고, 어떻게 구현됐는지 기본기를 따라 하며 배워야 한다. 다만 투자 대가들의 전략을 소개한 책은 쉽게 찾아볼 수 있지만, 그 전략을 구현한 기술적인 방법을 담은 책은 매우 찾아보기 어렵다. 또한 퀀트투자 전략을 공부하기 위해서는 코딩이나 수학 등 부가적인 배경지식이 필요하다. 이 책은 이미 잘 알려진 투자 대가들의 전략을 소개하고 자신의 컴퓨터에서 이 전략을 구현해보며 응용하는 방법을 알려준다. 책을 따라 미국 주식 퀀트투자 과정을 배우고 나면 자신만의 투자 전략을 스스로 개발할 수 있을 것이다.
저자
김용환, Yubin Kim
출판
한빛미디어
출판일
2021.09.30

● 아아 나는 왜이리도 끈기가 없단 말인가.

 파이썬으로 함께하는 포트폴리오에서 초반에 너무 이론적인 얘기만 나오다보니 실용적인 얘기가 없어서 다른 책을 찾다가 약간 실전적이어 보이는 재미있는 책을 발견했다. 그래서 갑자기 이 책에서 하라는 대로 한 번 해보고 싶어서 포스팅을 진행해본다. 밑은 책에서 해보라고 하는 코딩 내용이며, 추후 내가 검색을 용이하게 해보고자 기록하는데 목적이 있다.

https://colab.research.google.com/

 

Google Colaboratory

 

colab.research.google.com

마찬가지로 여기서도 구글 콜랩을 사용해서 실습을 진행한다.

● 라이브러리는 핀터스텔라

pip install finterstellar

 

 - 주가 가져오기

 

finterstellar라는 모듈로 실습을 시작한다. 주가를 불러올 때는 get price()라는 함수를 사용한다. 일단 finterstellar가 복잡하니까 fs라고 정의하고 AAPL의 주가를 가져와보겠다. 

import finterstellar as fs
df=fs.get_price('AAPL',start_date='2020-01-01', end_date ='2020-12-31')
print(df)

이제 이정도는 쉽다. Chat Gpt형님께 파이썬을 배운 보람이 있다. 이렇게 구글 콜랩에 입력을 하고 shift+enter를 눌러주면 아래와 같이 결과가 발생한다.

만약에 startdate와 enddate를 명시하지 않으면, 현재일을 기준으로 1년치 주가를 가져온다고 한다.

 

- 차트 그리기

 여기서 만약에 차트를 확인하고 싶다면, draw_chart()라는 함수를 이용하면 된다. draw_chart(df, left, right, log)가 기본기능이라서 첫번째는 해당되는 dataframe, left는 왼쪽 ylabel에 표시, right은 오른쪽 ylabel에 표시, log는 축을 로그로 표시할지 여부이다. True/false로 입력하는데 기본은 False이다.

fs.draw_chart(df,left='AAPL')

우왕 이렇게 한 번에 그래프를 얻을 수 있다. 아니, 그럼 밑에서 내가 한 개고생은 뭐람 !

 

https://jhhistory.tistory.com/16

 

코딩 왕초보의 S&P500 그래프와 PER Band 그리기 -1 (with chat GPT)

* 맨 아래 S&P500그래프를 FREDAPI를 통해 그리는 코드를 적어 두었으니 참고하시기 바랍니다. * 맨 처음 의도는 PER Band를 그리려는 것이었으나 FREDAPI로는 PER band그리는 것이 불가능하여 발행의 제목

jhhistory.tistory.com

역시 Chat GPT가 만능은 아닌가 보다. FredAPI로 열심히 열심히 뭔가를 했는데, 뭔가 이렇게 함수 하나로 되니까 허망하다. 

 - 주가 분석 (RSI 확인)

 RSI는 상대강도지수라고 Relative strength Index다 증권사 HTS에 들어가면 이를 산출하는 식이 나오는데, 그 식은 알 것 없고, 통상적으로 30밑으로 RSI가 산출되면 '과매도'구간, 70위로 RSI가 산출되면 '과매수'구간으로 보아 각각 매수하거나 매도하는 기술적 전략을 펼칠 수 있다. 가장 대표적인 기술적 지표 중 하나이다.

 

 rsi(df,w) 이런식으로 사용할 수 있는데, w는 day를 의미한다. 나는 통상 RSI를 14로 놓고 본다. 산출하는 일 수에 따라 RSI의 값이 달라지니 본인이 맞다고 판단되는 적정한 일수를 산정하여 보는 것이 중요하겠다.

 

fs.rsi(df, w=14)
fs.draw_chart(df,left='rsi',right='AAPL')

 

 와우 내가 chat GPT에 물어봐서 하고 싶었던 것을 이 모듈이 한 방에 해결해주었다. 역시 능동적으로 찾아나서야하는 지식에 빠른 진리가 아직은 숨어있는가보다.

이런식으로 산출이 되었는데, 아 2020년 9월에 엄청난 조정이 왔던 때가 떠오른다. RSI가 80을 뚫고 넘어가려고할 때 엄청난 조정이 왔었다. 저 때, 애플 시총이 1000조를 넘어가는 시점이었던 것 같은데 3년 전이나 되었네. 시간 ..

- 백테스팅

 이동평균선으로 chat gpt에게 배웠던 헛짓거리도 finterstellar의 모듈에서는 적당히 편하게 할 수 있다.

https://jhhistory.tistory.com/21

 

Python의 Quandl을 사용하여 간단한 백 테스팅 프로그램 의뢰하기, 50일 이동평균선 200일 이동평균선

* 뭔가 원하는대로 나온 것 같지는 않지만, 일단 진행하면서 글을 써서 아까워서 발행해봅니다. 마지막에 모르는 것이 있어서 발행을 머뭇거렸습니다. 다른 함수 기능에 대해 공부할 수 있어서

jhhistory.tistory.com

 

여기서는 RSI지표를 이용해서 트레이딩 했을 때, 성과가 어땠을지 알아보는 백테스팅을 해볼 것이다. RSI가 40이하일 경우 매수하고, 60이상일 경우 매도하는 전략을 만들어본다고 한다.

 

 이 모듈에서는 indicator_to_signal() 이라는 함수를 이용하면 된다. indicator_to_signal (df, factor, buy, sell), df는 dataframe이고 factor는 기술적 지표(RSI, Stochastic 등의 문자열), buy는 매수 기준 값, sell은 매도 기준 값이다. 따라서 책에서 하라는 대로 아래와 같이 입력해보자.

fs.indicator_to_signal(df,factor='rsi',buy=40,sell=60)

이걸 쳐보니 저번에 배웠던게 마냥 헛짓거리는 아니었다고 느끼게 되었다. 왜냐면 chat gpt가 시그널 list를 만들어서 리스트를 작성하는 모습을 코딩으로 지켜보았었기 때문이다.

 이 모듈에서는 buy, zero, sell 이렇게 3가지로 분류되는데, buy는 매수 상태, sell은 공매도 상태, zero는 무 포지션 상태를 의미한다고 한다. 

 

 이때, 매일 매일의 포지션 (주식 보유 현황)을 산출해볼 수 도 있다. 포지션 산출에는 position()을 이용하면 된다.

fs.position(df)
fs.draw_chart(df,left='rsi',right='position_chart')

그럼 아래와 같이 그래프가 발생하는데, 이 것의 의미는 다음과 같다. 파란선은 왼쪽의 RSI이다. 그래서 2020년 2월 말즈음에 RSI가 40밑으로 내려가는 순간 position이 buy (1)으로 돌아선 것이고, RSI가 60위로 올라온 순간 zero(0)으로 돌아선 것이다. 

  이때, draw_chart맨 끝에 position_chart라고 왜 넣었나 라고 의문을 품고 df를 입력했다.

df

그랬더니 이렇게 position_chart라는 열을 형성하여 있었던 것이다. 저자니까 이걸 알고 미리 적어놨겠지? 오른쪽 위에 저 반짝이는 걸 누르면

이렇게 데이터를 보다 한 눈에 확인할 수 있다. 굳이 csv파일로 빼내지 않아도 데이터의 열을 확인할 수 있어서 매우 편한 것 같다.

 - 수익률 계산

  이제 해당 전략에 대한 수익률을 계산해보자. 여기서는 evaluate()함수를 사용하면 된다고 한다. 와 이 얼마나 쉬운가 !  evaluate(df, cost)의 함수로 이루어져 있는데, 이때, cost는 매매비용이다. 기본 값은 0.001인데, 통상 키움증권에서 개미의 수수료는 0.25%이니까 0.0025를 입력해보자.

fs.evaluate(df, cost=0.0025)
fs.draw_chart(df,left='acc_rtn_dp',right='AAPL')

 그럼 결과가 아래와 같이 나온다. 

  빨간선은 오른쪽 y축에 대한 애플의 주가이고, 파란선은 왼쪽 y축에 대한 수익률 변동이다. 주식을 보유하고 있던 2번의 기간 (40에서 매수, 60에서 매도)만 수익률이 변동되었다. 첫 번째 buy구간에서 매도해서 손해를 봤지만, 뒷 구간 (10월)에서 매수를 해서 매도했을 때, 총 연간 14%정도의 수익률을 얻은 것으로 보인다. 다시 한번 df를 입력해서 리스트의 상태를 보자.

보니까 rtn, daily_rtn, acc_rtn, acc_rtn_dp, mdd, bm_mdd라는 리스트가 새로 생겼다. 각 리스트의 의미를 알기 전에 일단 저자가 시키는대로 더 따라가보자. 내 느낌엔 rtn은 return인데, rtn과 daily_return이 왜 다른지는 모르겠다. acc_rtn은 accumulate_return (누적수익률)로 추정되고, dp..는 모르겠다.  mdd는 maximum draw down이고, bm_mdd는 benchmark의 mdd같은데.. 전자는 전략에서의 mdd같고 뒤에는 종목 전체의 mdd같다.

 

 - 성과 분석

 다른 포스팅에서도 언급했던 바와 같이 그 전략 (포트폴리오)가 효과적이었는지 아니었는지 판단해보는 기준들이 필요하다. 여기서는 performance(df, rf_rate)라는 함수로 평가가 가능하다. rf_rate는 무위험이자율인데, 예를 들어 정기예금 이자나 국채이자율 등이 되겠다. (그냥 돈 맡겨놨을 때, 저절로 버는 이율)

fs.performance(df,rf_rate=0.01)

저 시기에 거의 예금이자가 1%에 가까웠으므로 0.01로 입력해본다. 그러면 아래와 같은 결과가 나타난다.

오 뭔가 이런저런 분석을 많이 써놨다. 대충 하나씩 뜯어보자. 

1. CAGR : Compound Annual Growth Rate (연평균 수익률)

 누적 수익률을 연평균 수익률로 환산한다. 1년보다 짧으면 단리고, 1년보다 길면 복리로 계산해서 축소한다. 1달의 기간 동안 1%의 수익을 얻었으면, 12%가 되는 것이고, 2년으로 했을 때, 누적수익률이 21%라면

 

(1+연간수익률)^2년 = (1+누적수익률)

(1+연간수익률)^2년 = (1+0.21)

1+연간수익률 = (1+0.21)^(1/2)

연간수익률 = (1.21)^(1/2) -1 

연간수익률 = 10%

 

이렇게 된다.

2. Accumulated return : 누적수익률

 말 그대로 누적수익률

3. Average return : 평균수익률

 트레이딩을 한 사이클에서 건별 수익의 평균이다. 2회 트레이딩 했고, 수익률이 10%, 30%라면 Average return은 15%.

4. Benchmark return : 벤치마크수익률

 개별종목에 대한 백테스팅을 했으니 이거 사고 가만히 있었을 때 수익률이다. 통상은 포트폴리오 vs S&P500 이런식으로 많이 비교한다. 베타 수익률이라고도 한다.

 

5. Number of trades :

 거래횟수

6. Number of wins :

전략이 성공한 횟수, 플러스가 되었을 때의 횟수

7. Hit ratio :

성공횟수/ 거래횟수

8. Investment period :

 투자기간으로 테스트를 진행한 기간이다. 주의할 점은 RSI같은 경우에는 14일에 대한 평균 값이 필요하므로 앞쪽 데이터 일부가 투자기간에서 제외된다. 그래서 0.9yrs로 나오는 것 같다. ( 왜.. 0.9yrs지?)

9. Sharp Ratio , MDD

 위에서 말한 다른포스팅은 이거고, Sharp ratio와 MDD는 여기에 개략 적어놨다. 이때, benchmark mdd는 아무것도 안하고 종목을 가지고 있었을 때의 mdd이다. 그러니까 내가 뭔가 전략을 수행한 것이 benchmark mdd보다는 작아야 한다. 그래야 방어를 한 것이라고 판단할 수 있기 때문이다. 

 

 https://jhhistory.tistory.com/22

 

파이썬으로 배우는 포트폴리오 2장 (투자와 자산배분)

https://jhhistory.tistory.com/19 파이썬으로 배우는 포트폴리오 (책 리뷰 및 실습 기록) ● 현자는 자문자답한다고 했던가 나는 아직 현자가 아니었다. 이게 맨땅에 chatgpt형님에게 질문을 너무 크게 갖

jhhistory.tistory.com

 

 즉, 여기서는 최종수익률은 14.5%지만, 벤치마크 수익률이 67.05%이다. 이 시기에 사고 팔고 했던 20대 남자들보다 쭉 가지고 있었던 여자들이 더 수익률이 좋다는 기사가 많이 나왔는데, 대세 상승장에서 벌어질 수 있는 일인데 남녀간 뚜렷한 성향차이가 보여서 한때 사회적으로 이슈가 되었던 적이 있다. 

 

 지금와서 생각해보니, 모멘텀 전략을 알고 있었던 사람이라면 원래 리벨런싱이나 거래를 하고 있었어도 매도를 쉽게 행하지 않았을 것 같다. 

 

https://www.elle.co.kr/article/67424

 

20대 남성이 주식 수익률 가장 낮은 이유_돈쓸신잡 #51

공격적인 투자자 vs. 안정적인 투자자.

www.elle.co.kr

 

- 성과 분석 후 피드백

 대충 성과를 분석해봤다. 근데, 다른 전략이랑 비교하고 싶은 마음이 바로 생긴다. 바로 아까는 RSI가 40일때 매수 60일 때 매도를 했는데, 만약에 거꾸로하면 어떻게 될까? (라고 저자가 말했다.) 그대로 거꾸로해보자.

fs.indicator_to_signal(df,factor='rsi',buy=60,sell=40)
fs.position(df)
fs.evaluate(df,cost=0.0025)
fs.performance(df,rf_rate=0.01)
fs.draw_chart(df,left='rsi',right='position_chart')
fs.draw_chart(df,left='acc_rtn_dp',right='AAPL')

그러면 이런 그래프가 나온다. 시그널이 완전 반대로 뒤집혔다. 그리고 아래쪽을 보면 수익률이 45%정도까지 올라간걸 볼 수 있다.

 누적 총수익률은 46.88%이고 누적 수익률은 44.18%, 전략 한번 쓸 때는 45.1%의 수익률이었고, 벤치마크의 리턴은 역시나 그대로 67.05%이다. 2번의 거래를 했고 1번의 수익을 얻었다. 집계기간은동일하고, sharpe ratio가 0.33대비 4배나 높다는 것을 알 수 있다. MDD는 -30.55%로 benchmark mdd -31.43%와 크게 차이가 나지 않는다. 

 

다음 장에서 ...

 

반응형

댓글