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

섹터(KRX) ETF + 모멘텀

칸트 2018.03.05 16:31 조회수  1145 추천 0


http://suma_maple.blog.me/221006132300



해당 글의 내용을 구현해보고 싶었습니다.

결과적으로 다른 결과가 나와 좀 당황스럽습니다. ㅎㅎ

어디서 잘못된 것인지 고수님들 검토 부탁드립니다.


구현한 해당전략은 case3와 case4입니다.


유니버스: 스탁필터를 보시면 아시겠지만, 12개의 섹터ETF로 하였습니다. (16년 9월 KRX는 섹터 개편이 이뤄집니다.)

백테스트 기간: 13년 1월~16년 12월, 총 48개월

상대모멘텀 : 3/6/9/12의 수익률 상위 3개ETF(해당 글에서는 5개이나, 5개는 더더욱 성과가 안 좋습니다).

절대모멘텀 : 상대모멘텀 < 1 이하 제외


코스피보다 나은 성과는 헬스케어ETF 때문인 것으로 파악됩니다.

어찌보면 해당기간 박스피였기 때문에 섹터ETF도 크게 성과를 보지 못한 부분일 수도 있고,

주도 섹터는 어느정도는 모멘텀 효과를 본다고 볼 수도 있을 것 같습니다.



향후 과제로는,

각 섹터ETF의 모멘텀(스코어)으로 비중조절을 어떻게 해야 할 것인지?

자산배분전략 (최소변동성전략 등) 을 어떻게 구현할 것인지?




문의)

//IQEnvironment.etfCommission = 0.05; // ETF 수수료

이 코드가 먹히지 않습니다. 어떻게 해야 슬리피지를 더할 수 있을까요?

Created with Highcharts 4.2.7AlgorithmKOSPI2013-04-012013-08-012013-12-012014-04-012014-08-012014-12-012015-04-012015-08-012015-12-012016-04-012016-08-012016-12-01-20%-10%0%10%20%30%40%powered by IntelliQuant
Algorithmpowered by IntelliQuant
초기투자금액
10000000
수익률
16.41%
월평균 수익률
0.32%
표준편차
1.08%
베타
0.96
Sharpe Ratio
0.11
(젠센) 알파
-0.00
최대 손실폭
22.56%
x
50
 
1
2
var basket;                // 주식 종목들을 담을 Basket
3
var STOCK_WEIGHT = 0.98;    // 주식 비율 현금 보유를 0%
4
//var short_basket;
5
//var short_weight = 0.2
6
7
var MAX_SIZE = 20;         // 각 바스켓에 최대 20주 편입
8
var result_array = [];  //월별 수익률 기록용
9
10
11
12
function initialize() {
13
    //IQEnvironment.etfCommission = 0.05;    // 주식 세금 1.3% (슬리피지 1%포함)
14
    var account = IQAccount.getDefaultAccount();
15
    basket = new Basket(account, MAX_SIZE, IQEnvironment.aum * STOCK_WEIGHT);
16
    basket.setPortfolioBuilder(stockPortfolioBuilder);
17
    
18
    //short_basket = new Basket(account, 1, IQEnvironment.aum * short_weight);
19
    //short_basket.setPortfolioBuilder(shortPortfolioBuilder);
20
}
21
    
22
23
24
function stockFilter(stock) {
25
if (stock.code === "A091160") {return true;}   // KODEX 반도체    2006/06/27
26
if (stock.code === "A091170") {return true;}   // KODEX 은행    2006/06/27
27
if (stock.code === "A091180") {return true;}   // KODEX 자동차    2006/06/27
28
if (stock.code === "A098560") {return true;}   // TIGER 방송통신    2007/09/07
29
if (stock.code === "A102960") {return true;}   // KODEX 기계장비    2008/05/29
30
if (stock.code === "A102970") {return true;}   // KODEX 증권    2008/05/29
31
if (stock.code === "A117460") {return true;}   // KODEX 에너지화학    2009/10/12
32
if (stock.code === "A117700") {return true;}   // KODEX 건설    2009/10/30
33
if (stock.code === "A117680") {return true;}   // KODEX 철강    2009/10/30
34
if (stock.code === "A140700") {return true;}   // KODEX 보험    2011/04/26
35
if (stock.code === "A140710") {return true;}   // KODEX 운송    2011/04/26
36
if (stock.code === "A143860") {return true;}   // TIGER 헬스케어    2011/07/18
37
if (stock.code === "A266360") {return true;}   // KODEX IT소프트웨어    2017/03/28
38
if (stock.code === "A266370") {return true;}   // KODEX IT하드웨어    2017/03/28
39
if (stock.code === "A266390") {return true;}   // KODEX 경기소비재    2017/03/28
40
if (stock.code === "A266410") {return true;}   // KODEX 필수소비재    2017/03/28
41
42
   return false;
43
}
44
45
46
// 평균 모멘텀 스코어 구하기 -> 12M 
47
function m_score(stock) {
48
...
49
(코드는 일부만 보여지며 전체 코드는 "내 알고리즘에 복사" 버튼을 클릭하여 복사할  있습니다. 
50
알고리즘 복사  일정한 포인트가 차감되어 게시자에게 보상해 드립니다.)
댓글 8
//IQEnvironment.etfCommission = 0.05; // ETF 수수료

'//' <- 이걸 삭제하셔야 합니다 ( // = 주석처리 기능 = 동작안함)
Prophit 2018.03.06 16:53
function sma_di(stock) { stock.loadPrevData(2,0,0);
    var sumMV = 0;
    for(var i=0; i < 240; i++) { sumMV = sumMV + stock.getAdjClose(i); }
    return sumMV / 240;   <-- 리턴됐기때문에 이 아래 두줄은 작동 안합니다
    var sma_di = (( (sumMV / 10) / sumMV ) -1 );
    return sma_di ;
  }
Prophit 2018.03.06 17:00
   universe.forEach( function(stock) { stock.setScore('rank_sum',
                                       //+ sortedBySMA_di.indexOf(stock) 
                                       //+ sortedByM_score.indexOf(stock)
                                       + sortedByM12_score.indexOf(stock)   <==  맨앞에 '+' 있으면 오류 안나나요?
                                       ); 
});
Prophit 2018.03.06 17:02
var moment = universe.slice().sort( function(a, b) {
        return a.getScore('rank_sum') - b.getScore('rank_sum');  }); 

a (작은) - b(큰) 순 정렬입니다 = 오름차순
b (큰) - a(작은) 순 정렬입니다 = 내림차순
Prophit 2018.03.06 17:03
프로핏님 안녕하세요^^
1. 주석기능을 적용해봤었습니다. 결과는 같아서 그냥 // 해놓고 게시하였어요.
2. 리턴! 자꾸 잊어버리네요;; var로 고쳐야겠네요. 고맙습니다.
3. 네. 두 번 다 해봤는데, 오류/결과가 다르지 않아 저렇게 해놓고 노가다로 돌려보고 있습니다. (제 선에서는 그나마 좀 편하더군요;;; ㅎㅎ ㅠ)
4.일단 sortedByM12를 b-a(모멘텀이 강한 순-높은 순)를 정렬하여 셋스코어 하였고, 겟스코어는 a-b를 해야, 모멘텀 강한 1위가 낮은 순번에 위치하는 것이라 생각했는데요. 혹시 아닌가요?

고맙습니다 ^^
칸트 2018.03.06 17:34
4. 그럼 맞네요. 자세히 본건 아니어서 ㅎㅎ. 
굳이 겟스코어 안해도 되고 바로
sortedByM12_score 를 슬라이스 하면 코드가 더 깔끔합니다
Prophit 2018.03.06 17:49
네. 그렇게 해보겠습니다.

function sma_di(stock) { stock.loadPrevData(2,0,0);
    var sumMV = 0;
    for(var i=0; i < 240; i++) { sumMV = sumMV + stock.getAdjClose(i); }
    var sma = sumMV / 240;
    var sma_di = (( (sma / 10) / sma ) -1 );
    return sma_di ;
  }
이렇게 고치면 되겠죠?

프로핏님 혹시 ETF갖고 백테스트 해보셨나요?
칸트 2018.03.06 18:11
아니요
시계열이 너무 짧아서 안했어요
Prophit 2018.03.07 10:21
댓글 등록을 위해서 로그인해주세요.
 
최신 게시글