제가 직접 해보려고 했는데...도저히 안되겠네요.
# Universe
1. PBR: 하위 20프로 - 구현 가능하다면, 안 되면 빼주세요.
2. 거래정지 제외.
3. 상장폐지 종목 포함.
4. 관리종목 제외 - 구현 가능하다면, 안 되면 빼주셔도 됩니다.
5. 감리구분: 정상(경고, 주의 제외) - 구현 가능하다면, 안 되면 빼주셔도 됩니다.
# 거래 조건
1. FQ 매출액 전년 동기 대비 증가율 >0
2. FQ 영업이익 전년동기 대비 증가율 >0
3. FQ 영업이익 전년동기 대비 증가율 > FQ 매출액 전년 동기 대비 증가율
4. FQ-1 영업이익 전년동기 대비 증가율 < FQ-1 매출액 전년 동기 대비 증가율
# 리밸런싱: 3달에 1번 - 안 된다면 1달에 1번으로.
부탁드립니다.ㅠㅠ
var basket; // 주식 종목들을 담을 Basket var STOCK_WEIGHT = 0.95; // 주식 비율 현금 보유를 0% var MAX_SIZE = 20; // 각 바스켓에 최대 20주 편입 // 이 전략이 초기화되면 Initialize 함수가 호출됩니다. function initialize() { var account = IQAccount.getDefaultAccount(); basket = new Basket(account, MAX_SIZE, IQEnvironment.aum * STOCK_WEIGHT); basket.setPortfolioBuilder(portfolioBuilder); } //portfolioBuilder 함수에서 사용할 필터링 함수를 정의합니다. function stockFilter(stock) { if (stock.getMarketCapital() === 0) { return false; } if (stock.getClose() === 0) { return false; } // filter out delisted stocks if (stock.getTradingValue() === 0) { return false; } // 거래정지 중인 종목 제외 if (stock.isETF) { return false; } // ETF 제외 if (stock.manage == 1) {return false;} //관리종목 제외 if (stock.manage == 2) {return false;} //투자유의 제외 if (stock.manage == 4) {return false;} //거래정지 제외 return true; } // PBR 값 역순 구하기 function bp(stock) { return stock.getFundamentalTotalEquity() / stock.getMarketCapital(); } //특정 조건에 부합하는 종목만으로 필터링한 종목들만으로 유니버스를 구성합니다. function portfolioBuilder(targetSize) { var universe = IQStock.filter(stockFilter); //PBR 정렬 남기기 var sortedByPbr = universe.slice().sort( function(a, b) { return bp(b) - bp(a); }); // pbr 역순 정렬 sortedByPbr.forEach( function(stock) { stock.setScore('bp_rank', sortedByPbr.indexOf(stock)); }); // pbr점수매기기 // PBR 필터링(역순 정렬했으니 상위 20%만 남기기) var pbr_filter = sortedByPbr.filter(function(stock) { if ( stock.getScore('bp_rank') > (0.2 * universe.length) ) { return false; } return true; } ); var filtered = pbr_filter.filter(function(stock) { //거래조건으로 필터링 stock.loadPrevData(2,0,0); //이전 재무데이터 로드 if (stock.getFundamentalRevenue(0) <= stock.getFundamentalRevenue(4)) { return false; } // 매출 전년동기대비 성장 if (stock.getFundamentalOperatingIncome(0) <= stock.getFundamentalOperatingIncome(4)) { return false; } // 영업이익 전년동기대비 성장 // 영업성장률 > 매출성장률 if ((stock.getFundamentalRevenue(0) / stock.getFundamentalRevenue(4)) >= (stock.getFundamentalOperatingIncome(0) / stock.getFundamentalOperatingIncome(4))) { return false; } // 영업성장률(-1Q) < 매출성장률(-1Q) if ((stock.getFundamentalRevenue(1) / stock.getFundamentalRevenue(5)) <= (stock.getFundamentalOperatingIncome(1) / stock.getFundamentalOperatingIncome(5))) { return false; } return true; }); MAX_SIZE = (filtered.length === null) ? 0 : filtered.length; //필터링된 종목수만큼 바스켓 수량조정 return filtered; } var lastRebalMonth = 1; var startDate = 1; //시뮬레이션 기간동안 매일 매일 호출됩니다. function onDayClose(now) { // 2월 / 5월 / 8월 / 11월에 리밸런싱을 수행합니다. if (( (now.getMonth() == 10 || now.getMonth() == 7 || now.getMonth() == 4 || now.getMonth() == 1) && now.getMonth() != lastRebalMonth && now.getDate() >= startDate)) { var totalEquity = IQAccount.totalEquity(); // 계좌의 총평가금액(주식평가액+예수금 모두) basket.buildPortfolio(); basket.reset(); logger.debug('size : ' + MAX_SIZE); basket.targetSize = MAX_SIZE; // 바스켓 사이즈 수정 basket.setPortfolioBuilder(portfolioBuilder); basket.setBudget(totalEquity * STOCK_WEIGHT); basket.buildPortfolio(); lastRebalMonth = now.getMonth(); } }