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

PER+모멘텀 전략입니다.

등엔트로피 2017.04.21 16:52 조회수  1215 추천 0

안녕하세요. 등엔트로피입니다.

아래 질문에 답변하기에 너무 긴 내용이라 별도의 글을 하나 팠습니다.


바로 아래 보이는 메뉴의 알고리즘을 클릭하시면 자세한 코드를 보실 수 있습니다.

(perMomentumBuilder 함수 참고)


저희가 이 기회에 강조하고 싶은건 모멘텀에서 사용하는 수정주가입니다.

모멘텀을 구하기 위해서는 수정주가를 사용해야 하는것은 누구나 알고 있지요.

그러나 정확한 수정주가를 구하기는 생각보다 어렵습니다.

각종 합병, 분할, 배당등의 이벤트를 모두 트랙킹해야 하거든요.

저희는 정확한 수정주가를 위해 한땀한땀 전수조사를 통해 이 데이터를 만들었습니다.

이태리장인 처럼요. :)


아래 "내 알고리즘에 복사" 버튼을 누르시면 내 알고리즘으로 가져와서 이리저리 변경하면서 테스트 해 볼 수 있습니다.

Created with Highcharts 4.2.7AlgorithmKOSPI2010-06-012010-12-012011-06-012011-12-012012-06-012012-12-012013-06-012013-12-012014-06-012014-12-012015-06-012015-12-012016-06-012016-12-01-250%0%250%500%750%1000%1250%1500%powered by IntelliQuant
Algorithmpowered by IntelliQuant
초기투자금액
10000000
수익률
884.97%
월평균 수익률
2.76%
표준편차
1.32%
베타
0.67
Sharpe Ratio
1.49
(젠센) 알파
0.32
최대 손실폭
29.61%
x
57
 
1
/*
2
초기 예수금 1000만원
3
1. KOSPI 종목 대상. ETF 제외
4
2. 총 계좌평가액 중 90%를 리밸런싱에 사용(10%는 현금보유)
5
3. PER 필터링후 모멘텀으로 종목선정
6
*/
7
8
var basket;                // 주식 종목들을 담을 Basket
9
var STOCK_WEIGHT = 0.9;    // 주식 비율 현금 보유를 10%
10
var MAX_SIZE = 10;         // 각 바스켓에 최대 10주 편입
11
12
13
// 이 전략이 초기화되면 Initialize 함수가 호출됩니다.
14
function initialize() {
15
    
16
    var account = IQAccount.getDefaultAccount();
17
    basket = new Basket(account, MAX_SIZE, IQEnvironment.aum * STOCK_WEIGHT);
18
    
19
    //빌더 함수를 정의합니다.
20
    basket.setPortfolioBuilder(perMomentumBuilder);
21
}
22
23
//portfolioBuilder 함수에서 사용할 필터링 함수를 정의합니다.
24
function stockFilter(stock) {
25
    if (stock.getMarketCapital() === 0) { return false; }
26
    if (stock.getFundamentalTotalAsset() === 0) { return false; } 
27
    if (stock.getClose() === 0) { return false; }                      // filter out delisted stocks
28
    if (stock.getTradingValue() === 0) { return false; }               // 거래정지 중인 종목 제외
29
    if (stock.market != 1 || stock.isETF) { return false; }            // KOSPI만 & ETF 제외
30
    if (stock.getFundamentalNetProfit() <= 0) { return false; }        // 당기 순이익 0 이하 종목 제외
31
    if (stock.getFundamentalTotalEquity <= 0) { return false; }        // 당기 자본총계 0 이하 종목 제외
32
33
    return true;
34
}
35
36
37
// stock_basket 포트폴리오를 어떻게 구성할지를 정의합니다.
38
// Basket.buildPortfolio() 함수를 호출하면 이 함수가 호출됩니다.
39
function perMomentumBuilder(targetSize) {
40
41
    //위 필터링 조건에 부합하는 종목만으로 필터링한 종목들만으로 유니버스를 구성합니다.
42
    var universe = IQStock.filter(stockFilter);
43
    //logger.debug("universe size:" + universe.length);
44
45
    //PER 를 기준으로 작은 순서부터 정렬합니다.
46
    //그리고 상위 30개만 가져옵니다.. (slice)
47
    var sortedByPer30 = universe.slice().sort(function(a,b){return a.getPER()-b.getPER();}).slice(0,30);
48
    for (var i=0, stock; stock=sortedByPer30[i]; i++) {
49
        //최초 실행시에는 모멘텀을 구하는데 필요한 앞데이터가 없으므로 로딩합니다.
50
        stock.loadPrevData(1,0,0);
51
        
52
        if (stock.getAdjClose(250) === 0) {
53
            //logger.debug(stock.code + " adjClose(255) == 0. " + stock.getDate(250));
54
            //상장한지 1
55
...
56
(코드는 일부만 보여지며 전체 코드는 "내 알고리즘에 복사" 버튼을 클릭하여 복사할  있습니다. 
57
알고리즘 복사  일정한 포인트가 차감되어 게시자에게 보상해 드립니다.)
댓글 3
정성어린 답변 감사드립니다 :)

공부가 부족해서 질문 투성이네요.
추가 질문을 드려보자면 원래 질문의 의도는 
모멘텀을 구해서 0 이하인 종목을 제외하고 basket에 담으려 합니다.

근데 모멘텀 0 이상인 종목만 담았더니
MAX_SIZE의 영향이 남아서 종목당 매수액에 문제가 되더라고요
(ex. 투자금 1000만원 //  모멘텀 필터된 종목은 10종목일경우 = 종목당 100만원씩 매수 의도;
그러나 MAX_SIZE = 20 이라 종목당 50만원씩만 매수됨)

그래서 MAX_SIZE를 수정하려고 stockfilter 에 
    모멘텀 0인 종목을 제외시켜 momentumPort 로 지정하고 다음과 같이 추가했습니다.

    var momentumPort = modelPortfolio.filter(function(stock) { ~~~ 위의 내용들~
    } );
    MAX_SIZE = (momentumPort == null) ? 0 : momentumPort.length;
    return momentumPort;

이렇게 했는데 MAX_SIZE는 그대로더라고요.
그래서 onDayClose 쪽으로
var account = IQAccount.getDefaultAccount();
basket = new Basket(account, MAX_SIZE, IQEnvironment.aum * STOCK_WEIGHT);
basket.setPortfolioBuilder(portfolioBuilder);

이 항목들을 옮겨놨는데 또 에러 ㅠㅠ
어떻게 해야할까요?
Prophit 2017.04.21 19:12
중요한건 onInitialize()에서 아래줄입니다.
basket = new Basket(account, MAX_SIZE, IQEnvironment.aum * STOCK_WEIGHT);
이렇게 basket이 생성될때 종목의 수가 결정됩니다.
일단 결정되면 MAX_SIZE 변수를 바꾼다고 종목의 수가 바뀌지는 않습니다.
수정을 원하신다면 위 샘플의 10번째 줄을 직접 수정하시면 됩니다.

그리고 onDayClose에서 new Basket을 하시면 원하는대로 동작하지 않을 가능성이 큽니다.



등엔트로피 2017.04.25 17:07
그렇네요. new Basket을 하니까 cash를 자꾸 버리는 현상이 발생되네요.
Prophit 2017.04.27 00:53
댓글 등록을 위해서 로그인해주세요.
 
최신 게시글