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

1개월 수익률 역전 현상을 기반으로한 역추세 전략

푸른주전자 2020.06.11 11:54 조회수  1588 추천 8

안녕하세요

인텔리퀀트 푸른주전자입니다.


이번 테스트는 앞선 "5일 이평선에서 많이 떨어진...."에서 언급했던 1개월 수익률 역전 현상을 기반으로한 역투자(역추세) 전략입니다. 과연 손실이 많이 난 종목들을 매수해서 수익이 날 수 있을까? 상당히 의문스러웠지만, 재무제표를 이용한 value 팩터 PER, PBR, PSR 등의 지표를 사용한 전략 자체도 대표적인 역투자 전략이기에 테스트를 진행해 보았습니다.


상당히 간단한 개념으로 매주 월요일 한달 동안 수익률이 가장 낮은 종목 10개를 선택해서 매수/매도 하는 전략입니다.

테스트 조건은 
유니버스 : 코스피, 코스닥, 합계(시장전체) 세가지
종목 : ETF, 우선주 제외한 일반 종목
시총 : 100억 이상
거래대금 : 20일 평균 1억 이상
종목수 : 10
관리 종목 제외하고 매주 월요일 리밸런싱하며 
2010년 1월 1일부터 2020년 6월 9일까지 테스트 해보았습니다.


모멘텀 전략은 소형주 보다 대형주에 더 잘 맞다고 알려져있고 12년도부터는 중형주가 수익률이 월등했습니다(https://www.intelliquant.co.kr/article/100).  그런데 역추세 전략에서는 예상밖으로 코스피 보다는 코스닥에서 더 높은 수익률이 나왔습니다. 다만  표준편차가 크고 베타가 1이상으로 다소 롤러코스터 타는 느낌이 들지 않을까 생각되며 멀미약을 준비해야 겠습니다. ^^



그럼 이번에는 수익률이 높은 코스닥 전략에서 10개 종목을 동일 비중이 아니라 하락률이 높은 순으로 많은 비중을 주도록 "개별 종목 하락률 / (전체 하락률 합계)" 로 비중을 조절해서 테스트 해보겠습니다. 그래야 많이 떨어진 종목을 매수한 효과가 확대되겠죠.

여기서 주의할 점~

setPortfolioBuilder()와 buildPortfolio() 는 바스켓에 동일 비중으로만 포트폴리오를 만들어줍니다. 따라서 이번 테스트에서는 reset() 함수와 enter() 함수를 사용해 보겠습니다.

reset() : Basket 에 직접 추가한 종목 전체를 삭제합니다.

enter(stock, quantity) : Basket 에 직접 종목을 추가합니다.


먼저 initialize() 에서 setPortfolioBuilder()가 필요 없으니 삭제하고

function initialize() {
    logger.debug('init..');
    
    IQEnvironment.stockCommission = 0.0010;   // commission for stocks 0.0015
    IQEnvironment.stockTax = 0.003;            // trade tax for stocks     
    
    IQAccount.addAccount("1111-1111-11", "코스닥", IQEnvironment.aum);
    
    // 바스켓 생성    
    stock_port = new Basket(IQAccount.getAccount("1111-1111-11"), stock_num, IQEnvironment.aum * stock_weight);
    
    // 리밸런싱 주기를 설정 : 매주 월일
    IQDate.addRebalSchedule(IQDate.setWeekly(1));    
}


stockPortfolioBuilder() 를 대신하여 종목을 선택하고 비중을 조절할 함수를 만듭니다.

function stock_control() {
    var universe0 = IQStock.filter(marketFilter);                 // 코스피/ETF, 상폐종목 필터링
var universe = universe0.filter(stockFilter);
    var modelPortfolio = universe.slice().sort(function(a,b){return getRate(a)-getRate(b);});
    var real = modelPortfolio.slice(0, stock_num);
    var totRate = 0;
    var stockRate = 0;
    var stockQty= 0;
    
    var acc = IQAccount.getAccount("1111-1111-11");
    var totalEquity = acc.getTotalEquity();
    
    stock_port.reset();
    for (var i = 0; i < real.length; i++) {             
totRate += getRate(real[i]);     
    }
    
    for (var i = 0; i < real.length; i++) {
        stockRate = getRate(real[i]);
        stockQty= Math.floor(totalEquity * (stockRate/totRate*0.95) / real[i].getAdjClose());
        stock_port.enter(real[i], stockQty); 
    }
}

코드를 보면 잘 아시겠지만 종목을 선택하는 과정까지는 같습니다. 단, stock_port.reset()으로 바스켓을 비운 다음 첫번째 for문에서 전체 하락률 합계를 계산하고, 두번째 for문에서 개별 종목 하락률을 전체 하락률 합계로 나누어 개별 종목 비중을 계산하였습니다. 그리고, stock_port.enter(real[i], stockQty) 으로 바스켓에 개별 종목들을 추가하면 끝.


마지막으로 onDayClose()에서 buildPortfolio()가 필요 없으니 삭제하고 만든 함수만 추가하면 됩니다.

function onDayClose(now) {        
    // 주 단위
  // initialize에서 설정한 리밸런싱 주기 체크
    if (IQDate.isRebalancingDay(now)) {           
        // 종목을 선택하고 비중을 조절할 함수 추가
        stock_control();      
  }
}

결과를 보면 동일 배분보다 수익률이 개선되는 것이 많이 빠진 종목을 더 매수하는 것이 효과적인 것을 알 수 있습니다.


"떨어지는 칼날은 붙잡지말고, 달리는 말에 올라 타라" 라는 주식 격언을 약간 수정할 필요도 있을 것 같습니다. ^^

댓글 3
흥미롭네요. 전략만들 때 좋은 아이디어가 될 것 같습니다.
koa55 2020.06.12 06:42
이제 처음해보려는데 신기하네요! 열심히 하겠습니다.
채 미 2020.06.14 20:39
좋은 내용 감사합니다.
James 2020.07.04 18:26
댓글 등록을 위해서 로그인해주세요.
 
최신 게시글