커뮤니티
내가 만든 전략들과 지식을 공유하고 토론합니다.

2. 주식초보자를 위한 마법공식 구현하기

주식초보 2017.07.11 11:11 조회수  7316 추천 0

안녕하세요. 주식초보입니다.

장기적인 가치투자에 관심이 많아서 알게된 조엘 그린블라트의 "마법공식"을 짧은 지식이지만 저와같은 주식 초보분들에게 조금이나마 도움이 되길 바라면서 도전기를 공유합니다.


     2. 주식초보자를 위한 마법공식 구현하기

이제부터는 마법공식을 주식초보자들이 쉽게 접근할 수 있도록 좀더 간단한 방법으로 구현해보겠습니다. 이전 시간에 살펴본대로 마법공식은 "자본수익률 순위 + 이익수익률" 대신 "ROA + PER"를 활용할 수 있습니다. 일반적으로는 자본수익률 + 이익수익률을 이용하는 것이 좀더 효과적이고 왜곡을 최소화하는 방법으로 알려져 있지만, '주식시장을 이기는 작은책'에서도 언급하고 있는 "일반적인 선별 방법"으로 자본수익률 대신 총자산이익률(ROA), 이익수익률 대신 주가수익비율(PER)을 사용하는 것도 개념상으로 크게 차이나지 않으면서, 주식 초보분들이 좀더 쉽게 접근할 수 있는 방법이라 생각합니다.

또한, 마법공식에서 매월 수행하는 점진적인 매수/매도 운용방식도 마법공식의 특징인 '최소 1년'은 유지할 수 있도록 간단하게 매년 36종목씩 전량 매수/매도하는 방식을 사용합니다.


마법공식 순위 = PER (낮은 순위) + ROA (높은 순위)
PER(주가수익비율) = 시가총액 / 당기순이익,   ROA(총자산이익률) = 당기순이익 / 자산총액


우선, 주가수익비율(PER)는 시가총액 대비 당기순이익 비율로 PER가 낮다는 의미는 당기순이익에 비해 주가(시가총액)가 낮다는 의미입니다. 쉽게말해 가성비 좋은 주식을 살 수 있다는 의미입니다. 그리고 총자산이익률(ROA)은 당기순이익 대비 총자산 비율로 ROA가 높다는 의미는 회사규모(총자산)에 비해 순이익이 높다는 의미입니다. 다시말해 이익이 잘나는 주식을 산다는 의미입니다. 그래서 마법공식에서는 PER는 낮은 순위로, ROA는 높은 순위로 합산한 종합순위를 사용합니다.


이제부터는 ROA + PER를 이용하여 실제 마법공식을 구현하는 방법에 대해 말씀드리겠습니다. 예를들어, 초기투자금액 3천만원을 마법공식 순위가 높은 36종목으로 매년 4월에 전량 매수 또는 매도합니다. 그리고 시가총액 5000억 이상, 일거래대금 5억 이상으로 설정하고 코스닥, ETF, 관리종목, 거래정지, 우선주 종목들은 제외합니다. 이렇게 설정한대로 구현한 결과는 아래 그래프와 같습니다.


시뮬레이션 설정 

  • PER (낮은 순위) + ROA (높은 순위)
  • 1년 단위 리밸런싱 적용 (매년 4월에 종목교체)
  • 초기투자금액 3000만원, 포트폴리오 36종목 구성
  • 시가총액 5000억 이상, 일거래 대금 5억 이상
  • 코스닥, ETF, 관리종목, 거래정지, 우선주 종목 제외 


최종 수익률은 839.67%로 코스피 357.26%에 비해 2배 넘게 나왔고, 월평균 수익률도 1.14% 정도로 연평균 수익률로 계산하면 14.57% 정도입니다. 이렇게 간단한 운용방식의 마법공식으로도 이정도의 수익률이 나오는걸 확인하니 마법공식의 매력에 빠져들게 되었고, 마법공식에 좀 더 가까운 종목선정 전략 및 운용방식을 적용해보고 싶은 생각이 듭니다.


그래서 다음 시간에는 "ROA + PER" 대신 "자본수익률 순위 + 이익수익률"을 사용한 결과를 공유하도록 하겠습니다.
감사합니다.

댓글 7
안녕하세요. 자바스크립트 초보인데 질문 드려도 될까요?
다른 건 다 이해가 가는데 stockPortfolioBuilder 함수 안의 내용은 이해가 전혀 안되네요.
아래 부분만 설명 부탁드립니다.

    var sortedByROA = universe.slice().sort(function(a, b) { return getROA(b) - getROA(a); });
    
    universe.forEach(function(stock) {
        stock.setScore('rank_sum', sortedByPER.indexOf(stock) + sortedByROA.indexOf(stock));         
    });
    
    var factorRank = universe.slice().sort(function(a, b) { return a.getScore('rank_sum') - b.getScore('rank_sum'); });     
    return factorRank.slice(0, targetSize);

감사합니다.
오동규 2017.08.25 11:12
우선 sortedByROA는 1차로 필터링된 종목들(universe)을 다시 ROA 값이 높은 순(내림차순)으로 정렬한 종목들이구요. sortedByPER는 테스트 코드 상에서 PER의 역순으로 설정했기 때문에 ROA와 마찬가지로 내림차순으로 정렬합니다.

그런다음, universe.forEach(function(stock)는 모든 universe 종목들에 대해 종목 하나하나를 stock 변수로 넘겨주게 되구요. sortedByPER.indexOf(stock)의 의미는 해당 종목(stock)이 내림차순으로 정렬된 PER의 순위(indexOf)이며, PER와 ROA의 합산순위를 해당 종목의 'rank_sum' 항목으로 저장해둡니다.

그리고 마지막으로 factorRank에서 위에서 저장한 'rank_sum' 값을 오름차순으로 정렬하게 되면 factorRank에는 1등부터 마지막 등수까지의 종목들이 들어있고, factorRank.slice(0, targetSize)에서 해당 종목수 만큼 반환하는 내용입니다.

혹시 이해가 안되시는 부분 있으시면 또 말씀해주세요. 감사합니다.
주식초보 2017.08.25 11:44
네 감사합니다. 딱 한가지가 이해가 안됩니다.
내림차순 sort를 하려면 함수명이  sortDescending,  오름차순 sort 를 하려면 sortDescending 이렇게 되면 이해하기 좋은데요. 여기서는 그냥 함수명이 sort네요. 어떻게 내림차순 혹은 오름차순으로 정렬할수 있는지 가르쳐주세요. 혹시 return 부분에 getROA(b) - getROA (a) 이 부분과 상관이 있나요?
오동규 2017.08.25 14:14
a와 b가 무슨뜻인지 그리고 a와 b가 자리가 바뀌면 sort가 내림차순으로 바뀌는건지 궁금합니다
오동규 2017.08.25 14:17
깜빡하고 sort 내용을 빠트렸네요. sort(function(a, b) { return getROA(b) - getROA(a); })에서 getROA(b) - getROA(a)이 내림차순이고, getROA(a) - getROA(b)가 오름차순입니다. 다시말해, 변수 a, b의 순서에 따라 차순이 변경됩니다.
주식초보 2017.08.25 14:26
완벽히 이해했어요. 친절한 설명 감사드립니다.
오동규 2017.08.25 16:01
안녕하세요?
좋은 글 잘 읽었습니다.

마법공식 백테스팅 관련해서 질문드리고 싶어서요.
책에서는 금융업종(은행, 증권, 보험, 뮤추얼펀드 등)을 투자시 제외할 것을
이야기 했는데 본 조건은 인텔리퀀트 플랫폼에서 어떤식으로 적용해야 할 지 잘 모르겠더라고요.

위 조건을 어떻게 적용하셨는지 궁금합니다.

확인 후 답변 부탁드리겠습니다.
감사합니다.
밸류퀀트 2018.02.04 17:57
댓글 등록을 위해서 로그인해주세요.
 
최신 게시글