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

거래대금 함수 관련 질문

So-Young Sung 2018.01.04 16:51 조회수  870 추천 0

기본 전략에 아래와 같이 거래대금 필터를 한 번 만들어 걸어 보았습니다. 


아래와 같이 42 거래일(달력기준 2달)의 평균 거래대금을 구하는 함수를 만들어서 , 


function TVal(stock) {

    var TValsum=0;

    

    for (var i=0; i <42;i++) {

        var TValsum=TValsum+stock.getTradingValue(i);

    }

    

    return TValsum/42 ;

    logger.debug(TValsum/42);

}


아래와 같이 stockFilter 함수에 구문을 추가하였습니다.(42 거래일 평균 거래량 천만원 미만인 주식들만 유니버스 포함)


function stockFilter(stock) {

 

  if (stock.market != 1 || stock.isETF) {   // 코스닥 종목, 인버스 ETF 종목 제외

      return false;

  }

//=========================================================================================================

    

    if (TVal(stock) > 10) {  ///42 거래일 평균 거래량 10백만원 이상인 경우 제외함

        return false;

    logger.debug(stock.name + '=== 거래량 초과로 제외함');

        logger.debug(TVal(stock));  // 제외된 주식 거래량 표시

    }


//=========================================================================================================    


그랬더니, 선택된 종목들이 아래와 같이 뜨는데..

날짜 보유종목
2017-07-04
없음
2017-07-05
세아홀딩스: 6주
대우조선해양: 42주
영원무역홀딩스: 16주
동아타이어: 21주
동원산업: 3주
고려제강: 27주
세방전지: 24주
한국쉘석유: 2주
오리온: 24주
제일약품: 19주
2017-08-17
대우조선해양: 40주
2017-09-18
대우조선해양: 39주
2017-11-16
없음


대우조선 해양은 거래정지 상태였으니, 그렇다 치고 나머지 종목들은 전부 일 평균 거래대금이 천만원을 훌쩍 넘는 종목들이 선정되는데... 무엇이 문제일까요?

함수를 잘못 적용한 것인지... 아니면 데이터가 잘못된것인지... 아직 자바스크립트 초보라 잘 모르겠습니다... 

고수님들 좀 알려주십시오. 꾸벅

아래는 알고리듬 전문입니다.

===================================================================================================================
/**
이 코드는 인텔리퀀트 스튜디오 사용법을 설명하기 위한 예제입니다.
인텔리퀀트는 이 알고리즘의 수익률을 보장하지 않습니다. 그러나 정량적인 가설 -> 검증(시뮬레이션) -> 실증 과정을 통해
여러분이 보다 안정적인 높은 수익률을 낼 수 있을거라 확신합니다.

[뼈대 전략 및 예제 코드]
예제 코드에서는 가치(Value) 팩터들 중에서 대표적인 주가수익비율(PER)을 사용하여
저평가된 투자 종목을 선정하는 방법을 다룹니다.

1. 일정 기준 이상 거래량과 유동성을 가지고 있는 종목들 중 PER 순위가 가장 낮은(저평가된) 10종목 매수
2. 한 달에 한 번(매달 15일, 영업일 기준) 포트폴리오 종목 교체
*/

var stock_basket;               // 주식 종목들을 관리하는 Basket 객체
var stock_weight = 0.95;        // 주식 비율
var stock_num = 10;             // 주식 종목 수

// 1) 포트폴리오 초기화 함수 - 전략이 실행될 때 최초 한번 자동으로 실행
function initialize() {
    // 필요한 바스켓을 선언합니다. 이 바스켓을 통해 종목을 선정하고 주문을 수행합니다.
    // 바스켓을 사용하지 않고 직접 Account 객체에 매수/매도 주문을 낼 수도 있습니다.

    // 주식 종목을 담을 Basket 객체입니다. 10개의 종목을 담을 예정이며,
    // 투자 예정 금액은 전체(aum: Asset Under Management) 금액 중 95% 입니다.
    stock_basket = new Basket(IQAccount.getDefaultAccount(), stock_num, IQEnvironment.aum * stock_weight);

    // 주식 포트폴리오 빌더 함수를 설정합니다.
    stock_basket.setPortfolioBuilder(stockPortfolioBuilder);
}

// 2) 팩터(factor) 정의 - 필터링 함수 및 포트폴리오 빌더 함수에서 사용
// 주가수익비율(PER) 팩터 정의
function getPER(stock) {
  // 해당 종목의 종가 또는 당기순이익이 0인 경우에는 제외합니다.
  if (stock.getClose() === 0 || stock.getFundamentalNetProfit() === 0) {
    return -1;
  }

  //stock.loadPrevData(0, 14, 0);   // 이전 분기 데이터가 필요할때만 사용합니다.

  // 주가수익비율을 계산한 결과를 getPER(stock) 함수를 호출한 곳으로 넘겨줍니다.
  return stock.getMarketCapital() / (stock.getFundamentalNetProfit() * 4);
}


function TVal(stock) {
    var TValsum=0;
    
    for (var i=0; i <42;i++) {
        var TValsum=TValsum+stock.getTradingValue(i);
    }
    
    return TValsum/42 ;
    logger.debug(TValsum/42);
}


// 3) 필터링 함수 정의 - 필터링 조건에 따라 종목들의 포함 여부 판단
function stockFilter(stock) {
  // 코스닥 종목과 ETF 종목들을 제외합니다. 그리고 필요 시 관리코드(manage),
  // 대형/중형/소형 등의 구분코드(capLevel)도 필터링 조건으로 추가할 수 있습니다.
  // 자세한 내용은 Stock 객체 도움말(https://www.intelliquant.co.kr/help/ref/1)을 참고하세요.

  if (stock.market != 1 || stock.isETF) {   // 코스닥 종목, 인버스 ETF 종목 제외
      return false;
  }
//=========================================================================================================
    
    if (TVal(stock) > 10) {  ///42 거래일 평균 거래량 10백만원 이상인 경우 제외함
        return false;
    logger.debug(stock.name + '=== 거래량 초과로 제외함');
        logger.debug(TVal(stock));  // 제외된 주식 거래량 표시
    }

//=========================================================================================================    

    
  var filterMarketCapital = (stock.getMarketCapital() > 500000); // 시가총액 5000억 이상 기준
  var filterPER = (getPER(stock) > 0);                            // PER 값이 마이너스인 경우 제외


  // 2개 필터링 조건을 모두 만족(true)할 경우에만 해당 종목(stock)이 포함됩니다.
  return (filterMarketCapital && filterPER);
    
    //logger.debug(TValsum/42);
}

// 4) 포트폴리오 빌더 함수 정의 - 필터링 및 팩터 기반 종목 선정
function stockPortfolioBuilder(targetSize) {
  // 필터링 함수(stockFilter)의 필터링 조건에 맞는 종목들이 유니버스(universe) 변수에 저장됩니다.
  var universe = IQStock.filter(stockFilter);

  // 유니버스(universe) 변수의 모든 종목들을 원하는 팩터 값으로 다시 정렬(sort)합니다.
  // 여기서 sort() 함수는 자바스크립트에서 기본적으로 제공하는 함수이며 사용 방법은 이미 정의한 팩터 함수들을 이용하여
  // 오름차순(return getPER(a)-getPER(b);) 또는 내림차순(return getPER(b)-getPER(a);)으로
  // 유니버스 변수의 모든 종목들을 순서에 맞게 재배열합니다.

  var sortedByPer = universe.slice().sort(function(a,b){return getPER(a)-getPER(b);});  // 종목들을 PER 값의 오름차순으로 정렬

  // 저평가된 종목부터 targetSize 만큼 종목을 최종적으로 선정합니다.
  return sortedByPer.slice(0, targetSize);
}

var enterForInit = false;  // 시뮬레이션이 처음 시작할 때 최초 한번 리밸런싱(buildPortfolio())이 수행되도록 설정
var lastRebalMonth = 0;    // 이전 리밸런싱을 수행한 달(Month) 저장

// 5) 리밸런싱 수행 - 시뮬레이션 기간 동안 장 마감 후 매일 자동으로 호출되는 함수
// 시뮬레이션 기간 동안 장 마감 후(영업일 기준) 매일 자동으로 호출됩니다.
// 매개 변수로 전달되는 now 객체는 onDayClose() 함수가 실행되는 날짜 정보를 담고 있는 자바스크립트의 Date 객체입니다.
// 그래서 Date 객체가 지원하는 여러 기능들을 활용할 수 있습니다.

function onDayClose(now) {
  // onDayClose() 함수가 처음 실행됐거나 실행된 날짜가 15일인 경우 리밸런싱을 수행합니다.
  // 여기서 15일이 영업일이 아닐 수도 있기 때문에 15일보다 큰 경우로 설정하고 같은 달에는 한번만 실행되도록 설정합니다.

  if (enterForInit == false || (now.getDate() >= 15 && now.getMonth() != lastRebalMonth)) {
      // 디폴트 계좌에서 현재 계좌 평가액을 가져옵니다.
      var currentTotalEquity = IQAccount.getDefaultAccount().getTotalEquity();

      // 현재 계좌 평가액에 주식 투자 비중을 반영하여 주식 포트폴리오 예산을 다시 설정합니다.
      stock_basket.setBudget(currentTotalEquity * stock_weight);

      // 주식 리밸런싱을 수행합니다. 등록된 주식 포트폴리오 빌더 함수가 자동으로 호출됩니다.
      stock_basket.buildPortfolio();

      lastRebalMonth = now.getMonth();      // 리밸런싱을 수행한 달(Month) 저장
      enterForInit = true;                  // 최초 진입 플래그를 true로 변경
  }
}

// 6) 시뮬레이션 종료 함수 - 시뮬레이션이 종료될 때 한번 자동으로 호출
function onComplete() {
    logger.debug("계좌 총 평가금액은 " + parseInt(IQAccount.getDefaultAccount().getTotalEquity()) + "원 입니다.");
}







댓글 6
안녕하세요. So-Young Sung님

메모리에 시작 일자부터의 데이터를 로드합니다.
따라서, 시작 일자 이전의 데이터를 가지고 작업하기 위해서
stock.loadPrevData(0, 3, 0); 란 함수로 과거 데이터를 로드 시킵니다.
인자는 stock.loadPrevData(년, 월, 일); 입니다.

올리신 알고리즘에서 stockFilter 함수 시작시 
stock.loadPrevData(0, 3, 0);로  
3개월정도 데이터 로드 시키면 될 것 같습니다.

감사합니다.
푸른주전자 2018.01.04 17:49
그리고, 부탁의 말씀 드리자면 게시판 제목에 오류란 제목을 자제해 주시기 바랍니다.
작성하신 알고리즘의 문제이지, 스튜디오 자체의 문제가 아님으로
다른 사용자분들이 오해 할 여지가 있습니다. (^o^)y
다시한번 저희 스튜디오를 사용해주셔서 감사합니다. 새해 복 많이 받으세요.
푸른주전자 2018.01.04 17:53
앗 이전 데이터 로드를 빠뜨렸군요... ! 감사합니다. 제목은 쓰고보니 좀 그랬네요.. 죄송합니다. 다시 수정했습니다.
So-Young Sung 2018.01.04 18:58
한가지 더 질문을 드리면, filter 에 걸렸을 때, 그 제외된 주식 이름을 로그창에 표시하고 싶어서 stockFilter함수에 logger.debug(stock.name); 을 넣었는데, 이게 전혀 표시가 안되네요... 어디를 어떻게 고쳐야 할까요? 
So-Young Sung 2018.01.04 19:03
아~ 살짝 말씀 드릴께요.
로그가 리턴값 뒤에 있어요. 
푸른주전자 2018.01.04 19:14
앗 감사합니다!. 아직 초보티를 벗으려면 멀었나봅니다 ㅠㅠ
So-Young Sung 2018.01.04 21:29
댓글 등록을 위해서 로그인해주세요.
 
최신 게시글