참고사항 시스템 트레이딩 관련 블로그들은 개인 경험을 바탕으로 작성되었습니다. 각자 자신만의 투자방식과 매매전략을 만들어 가시기 바랍니다.

개요

시스템 트레이딩을 하면 백테스트 과정을 필수로 거쳐서 매매로직에 대한 검증을 수행해야합니다. 매매로직의 검증은 수익률로 매매결과를 확인할수 있습니다.

수익률를 계산하기 위해서는 매매수행이 되어야하는데, 여기서 거래소의 역활을 대신할 구성요소가 필요합니다. 저는 자금관리자라는 이름의 객체로 거래소역할을 대신하였습니다.

자금관리자 객체에 대해서 알아보겠습니다.

자금관리자 객체의 스펙정보

자금관리자가 하는 역할을 거래소의 역활을 대신합니다. 우리는 거래를 위하여 원화를 거래소에 입금을 합니다. 그리고 거래소에서는 입금된 원화안에서 거래가 수행됩니다. 거래소가 하는 역할은 자금관리, 거래요청에 대한 승인을 담당합니다(수수료도 계산해야합니다). (최근에 업비트의 화면을 보니 월별, 년기준으로 수익률을 볼수 있도록 UI가 개선이 되었더군요. )

자금관리자에는 내가 거래할수 있는 금액을 관리하고, 각 종목별로 발생한 매수/매도목록에 대해서 승인여부를 결정하는 역할을 합니다.

  • 자금관리자 객체가 가지고 있는 정보와 메소드
    • 정보 (variable)
      • 총투자금액을 관리합니다.(number 형식입니다). 총투자금액안에서 거래가 수행되어야합니다.
      • 건별투자금액을 관리합니다. (number형식입니다). 매수할때 거래되는 금액을 의미합니다.
      • 현재 남은 현금을 계산합니다. (number 형식입니다). 처음에는 총투자금액과 남은현금금액이 동일하지만, 매수를 하게 되면 남은현금이 감소하게 됩니다. 매도를 하면 다시 현금이 증가됩니다.
      • 추가매수비율을 관리합니다. 매매처리방안에서 고려되는 내용입니다. 매매의 시작인 첫매수는 건별투자금액이지만. 이후 추가매수가 있을경우 건별투자금액에서 비율을 계산하여 매수금액을 높입니다.
      • 매매수수료를 관리합니다. 수수료는 0.05%(업비트기준)로 설정합니다.
    • 메소드 (method)
      • 가상매매(매매계획) - 종목별로 매매결과를 가져와서 현재 남은 금액에서 거래가능여부를 결정합니다. 거래가 되면 매매목록에 완료 FLAG를 설정후에 남은현금을 변경해줍니다.
      • 중간매매결과출력(종목그룹, 조회날짜,조회시간) - 가상거래이후 결과를 출력합니다. 조회날짜와 조회시간을 인자로 받는 이유는 각 종목별로 매매거래자객체로 부터 매매결과를 검색하기 위해서 입니다. 모든 거래는 거래여부와 상관없이 매매이력으로 관리되며 조회날짜와 조회시간을 조건으로 매매결과를 계산합니다.
      • 전체매매결과출력() - 전체 매매에 대한 결과를 리포팅하는 역할을 합니다. MDD 및 손익비등을 계산합니다.
      • 매수수량계산(투자금액,현재가) - 매수수량을 계산합니다. 투자금액/현재가를 수식으로 사용하여 소수점 밑 8자리까지 수량을 계산합니다.
      • 수수료계산(매매그룹) - 매매수수료에 대해서 계산합니다.
      • 매수종목정렬(매매목록, 매매종류) - 매수 순서를 위하여 우선순위기준으로 정렬합니다.
  • 고려사항
    • 매매계획이 있을경우 매매순서와 매수시 종목우선순위를 결정해야합니다.
      • 매매계획에는 각 종목별로 매수/추가매수/매도의 신호가 있습니다.
      • 매도를 먼저해서 현금을 확보한후에 매수/추가매수하는것이 좋습니다.
      • 남은현금에서 매수/추가매수 작업이 수행되는데 이때 어느 종목을 우선처리할것인지 우선순위를 설정해야합니다.

다음은 자금관리자 객체를 작성한 Pseudo 코드입니다.

자금관리자 ={
  총투자금액 = 100만원 
  건별투자금액 = 1만원
  남은현금= 총투자금액
  추가매수비율 = 4
  매매수수료 = 0.05
  가상매매(매매계획) = {
    var 매도목록 = 매매계획으로 부터 매도목록을 가져옴.
    매도처리 ={
        for(매도 in 매도목록) loop
            // 매도계획은 완료됨
            매도.완료여부(true)
            // 수수료계산
            var 수수료 = 수수료계산(매도.매매그룹)
            // 매도금액을 남은 현금에 추가함
            남은현금 = 남은현금 + (매도수량 * 매도.종목().현재가() - 수수료)
        end loop
    }

    var 추가매수목록 = 매매계획으로 부터 추가매수목록을 가져옴.
    추가매수처리 ={
        for(추가매수 in 매수종목정렬(추가매수목록,"추가매수")) loop
            // 남은현금에 매매가 가능한지 확인
            boolean 매수가능여부 = 남은현금 > 건별투자금액*추가매수비율;
            if 매수가능여부 == true then  
                // 매수수량을 계산
                var 매수수량 = 매수수량계산(건별투자금액*추가매수비율,추가매수.종목().현재가())
                // 매수수량을 저장
                추가매수.체결수량(매수수량)
                // 매수계획은 완료됨
                추가매수.완료여부(true)
                // 매수금액을 남은 현금에 빼기
                남은현금 = 남은현금 - (매도수량 * 추가매수.종목().현재가())     
            end if
        end loop
    }

    var 매수목록 = 매매계획으로 부터 매수목록을 가져옴.
    매수처리 = {
       for(매수 in 매수종목정렬(매수목록,"매수")) loop
            // 남은현금에 매매가 가능한지 확인
            boolean 매수가능여부 = 남은현금 > 건별투자금액;
            if 매수가능여부 == true then  
                // 매수수량을 계산
                var 매수수량 = 매수수량계산(건별투자금액,매수.종목().현재가())
                // 매수수량을 저장
                매수.체결수량(매수수량)
                // 매수계획은 완료됨
                매수.완료여부(true)
                // 매수금액을 남은 현금에 빼기
                남은현금 = 남은현금 - (매도수량 * 매수.종목().현재가())     
            end if
        end loop
    }
  }

  수수료계산(매매그룹) = {
    // 매매그룹에는 한사이클에 대한 매수와 매도정보가 있습니다. 그중에 완료가 된 매매정보를 가져와서 매매수수료를 계산합니다.
    var 총매수금액 =  매매그룹중 "완료" "매수"목록을 가져와서, 수량*매수가의 총합을 구함
    var 총매도금액 =  매매그룹중 "완료" "매도"목록을 가져와서, 수량*매도가의 총합을 구함 
    return 총매수금액 * 매매수수료 / 100 + 총매도금액 * 매매수수료 / 100 ;
  }

  매수종목정렬(매매목록, 매매종류) = {
    // 매매목록을 정렬합니다. 
    if 매매종류 == "매수" then
      // 매수일때 정렬합니다.    
    else if 매매종류 == "추가매수" then
      // 추가매수일때 정렬합니다.
    end if
    return 매매목록
  }

  매수수량계산(투자금액,현재가) = {
    // 소수점 8자리까지 계산합니다.
    return 투자금액/현재가
  }

  // 중간 출력결과를 저장하고 계산하는 객체로 분리하는것이 좋음
  중간매매결과출력(종목그룹, 조회날짜,조회시간) = { 
    for 종목 in 종목그룹.종목리스트 loop
      매매그룹 = 종목.매매이력목록.검색(조회날짜,조회시간);
      // 매매그룹에서 매수가격, 매도가격, 손익금액 계산가능
      // 평가금액은 아직 매도가 되지 않는 종목에서 현재 체결수량 * 현재가로 계산함 
    end loop
    //수익률 = (평가금액+남은현금)/총투자금액

    출력방식 : 조회날짜 ,조회시간, 총투자금액,남은현금,"평가금액","손익금액","수익률"
  }

  전체매매결과출력() = {
    // 중간매매결과출력결과들을 저장해놓고, 마지막에 MDD와 손익비계산을 수행
  }
}

마무리

자금관리자에서는 매매수행과 함께 매매결과에 대해서도 같이 관리합니다. 자금관리자는 거래소를 대신하기 때문에 슬리피지는 계산할수 없으므로 일부러 슬리피지를 계산하도록 추가할수도 있습니다. 현실 거래소와 자금관리자간에 Gap을 줄이는것이 가장 중요합니다. 1차적으로 매매우선순위지정, 매매간격을 늘려서 슬리피지를 줄이는 방법들이 있을것같습니다. 어느정도 기능구현이 되면 소량의 금액으로 실전거래를 수행하여 거래소의 손익금액과 내가 백테스트를 하면서 얻은 결과값을 비교하여 검증하는 작업을 꼭 수행해보셔야합니다. 그래야 간과했거나 미처 생각해보지 못한 코드 오류나 로직적인 개선사항이 발견이 됩니다.

댓글남기기