AUTO TRADE/[대신증권] CYBOS PLUS

대신증권 CYBOS PLUS 시작하기 (3) - 대신증권 모듈 이해하기

학습 목표

  • 대신증권의 모듈과 메서드(=함수) 살펴보기

지난 게시글에서는 `IsConnect()` 함수를 통해 대신증권 서버와 연결되어 있는지에 대해 살펴보고, 그 결과값이 몇인지에 따라 각기 다른 내용을 출력하도록 하는 기능까지 구현했다. 여기서 우리가 더 추가적인 기능을 구현하기 위해서는 대신증권 CYBOS PLUS에서 제공하는 모듈로는 어떠한 것들이 있는지 이해해야 한다.

 

 

(1) 상태 확인용 모듈: CpUtil.CpCybos

우리가 서버와의 연결 여부를 확인할 때 `self.cybos`로 정의해두었던 모듈인 `CpUtil.CpCybos`는 기본적으로 CYBOS PLUS의 상태를 확인할 수 있는 모듈이다. 즉, 우리가 서버와의 연결 여부를 확인할 때 사용했던 `IsConnect` 함수는 기본적으로 접속 상태를 확인하기 위한 함수였고, 이 함수는 `CpUtil.CpCybos`라는 모듈 안에 위치해 있다.

`CpUtil.CpCybos`는 여러 가지 함수들을 갖고 있는데, 가장 먼저 지난 게시글에서 살펴봤던 `IsConnect`가 있고 그 다음으로는 서버와 연결된 서버의 종류를 반환하는 `ServerType`, 그리고 데이터를 요청한 개수를 다시 계산하기까지 남은 시간을 반환하는 `LimitRequestRemainTime`이 있다. (추가적으로 살펴보진 않겠지만, 기능 구현에 도움을 줄 수 있는 함수들도 있다. 바로 `GetLimitRemainCount(limitType)`이나 `GetLimitRemainTime(limitType)`, 또는 `PlusDisconnect()` 등이 이에 해당한다.) 이러한 함수들은 우리가 `IsConnect`를 지난 게시글에서 사용했던 것처럼 동일한 구조로 사용할 수 있다. 예를 들어 대신증권 서버와 연결되어 있는 서버의 종류를 반환하는 함수인 `ServerType`을 사용해보자. 

`ServerType` 함수 역시 `IsConnect` 함수와 동일하게 반환되는 값이 있다. 아래의 세 줄을 살펴보도록 하자. 대충 봐도 알겠지만, 이전에 살펴봤던 `IsConnect` 함수가 0이 연결 끊김이고 1이 정상 연결을 의미했듯이 `ServerType` 함수 내에서는 아래의 세 가지 값을 반환해준다. 

  • 0: 연결 끊김
  • 1: CybosPlus 서버
  • 2:HTS 보통 서버(1번 제외)
import win32com.client

class cybos:
    def __init__(self):
        self.cybos = win32com.client.Dispatch("CpUtil.CpCybos")  ## COM 연결
        self._IsConnect()
        print(self.cybos.ServerType)


    def _IsConnect(self):
        value = self.cybos.IsConnect
        if value == 1:
            print(f"[통신결과:{value}] 서버와의 연결에 성공했습니다.")
        elif value == 0:
            print(f"[통신결과:{value}] 서버와의 연결에 실패했습니다.")

if __name__ == "__main__":
    cybos()

▶ 실행 결과 확인하기

더보기

[통신결과:1] 서버와의 연결에 성공했습니다.
1
종료 코드 0(으)로 완료된 프로세스

연결된 서버의 종류를 알려주는 `ServerType` 함수의 경우에도 앞서 사용했던 `IsConnect`와 마찬가지로 하나의 함수로 캡슐화 작업을 거쳐서 코드를 짤 수 있다. 이 역시도 초기화 함수(`def __init__(self)`) 내에 `self._ServerType()`를 추가하여 해당 함수를 곧바로 실행하도록 함으로써 연결된 서버의 종류를 확인할 수 있다.

import win32com.client

class cybos:
    def __init__(self):
        self.cybos = win32com.client.Dispatch("CpUtil.CpCybos")  ## COM 연결
        self._IsConnect()
        self._ServerType()

    def _IsConnect(self):
        value = self.cybos.IsConnect
        if value == 1:
            print(f"[통신결과:{value}] 서버와의 연결에 성공했습니다.")
        elif value == 0:
            print(f"[통신결과:{value}] 서버와의 연결에 실패했습니다.")

    def _ServerType(self):
        """
        0: 연결 끊김
        1: CybosPlus 서버
        2:HTS 보통 서버(1번 제외)
        """
        value = self.cybos.ServerType
        if value == 0:
            print(f"[서버종류:{value}] 서버와의 연결이 끊겼습니다.")
        elif value == 1:
            print(f"[서버종류:{value}] CybosPlus 서버와의 연결에 성공했습니다.")
        elif value == 2:
            print(f"[서버종류:{value}] HTS 보통 서버와의 연결에 성공했습니다.")

if __name__ == "__main__":
    cybos()

▶ 실행 결과 확인하기

더보기

[통신결과:1] 서버와의 연결에 성공했습니다.
[서버종류:1] CybosPlus 서버와의 연결에 성공했습니다.
종료 코드 0(으)로 완료된 프로세스

 

이외에도 `CpUtil.CybosPlus` 모듈은 `Object.OnDisConnect`라는 이벤트를 발생시키는데, 이 이벤트는 CybosPlus와의 통신 연결 상태가 끊긴 경우에 발생하는 이벤트이다. 다시 말해, 이 이벤트가 발생했다는 것은 곧 해당 프로그램을 종료시킨 후 다시 실행시켜야 한다는 것을 의미한다. 여기서 우리가 처음 접하는 이벤트란, 단순히 어떠한 사건이 일어났음을 알리는 알림 정도로 생각하면 된다. 예를 들어, 우리가 아침 6시에 알림을 맞춰놓았다고 했을 때 실제로 6시에 알람이 울리는 것이 하나의 이벤트이고 그 이벤트가 발생했을 때 우리의 컨디션이 어떤가에 따라 우리가 '일어난다.' 또는 '한 시간 더 잔다.'와 같은 행동을 수행하게 된다. 즉, 통신이 끊겼다는 이벤트가 발생했을 때 우리가 그 이벤트를 어떻게 처리할지는 우리의 선택이라는 것이다.

그렇다면 이벤트의 처리 방법은 무엇일까 ? COM 방식의 이벤트 처리는 키움증권의 영웅문에 있는 이벤트 처리 방식과 비교했을 때 완전히 다른 방식을 사용해야 하므로 이 내용은 추후에 다시 살펴보도록 하자.

 

 

(2) 주식 코드 조회용 모듈: CpUtil.CpStockCode

위에서 살펴봤던 상태 확인용 모듈인 `CpUtil.CpCybos`를 `win32com.client`의 `Dispatch` 메서드를 활용하여 `self.cybos`라는 하나의 인스턴스를 생성해주었던 것과 동일하게, 주식 코드 조회용 모듈을 사용하기 위해서는 `CpUtil.CpStockCode` 역시 동일한 메서드를 활용하여 하나의 인스턴스를 생성해주어야 한다. 아래의 코드 중 초기화 함수 부분을 참고해보도록 하자. 

import win32com.client

class cybos:
    def __init__(self):
        self.cybos = win32com.client.Dispatch("CpUtil.CpCybos")  ## COM 연결
        self._IsConnect()
        self._ServerType()

        self.stockcode = win32com.client.Dispatch("CpUtil.CpStockCode")  ## COM 연결
        
    def _IsConnect(self):
        value = self.cybos.IsConnect
        if value == 1:
            print(f"[통신결과:{value}] 서버와의 연결에 성공했습니다.")
        elif value == 0:
            print(f"[통신결과:{value}] 서버와의 연결에 실패했습니다.")

    def _ServerType(self):
        """
        0: 연결 끊김
        1: CybosPlus 서버
        2:HTS 보통 서버(1번 제외)
        """
        value = self.cybos.ServerType
        if value == 0:
            print(f"[서버종류:{value}] 서버와의 연결이 끊겼습니다.")
        elif value == 1:
            print(f"[서버종류:{value}] CybosPlus 서버와의 연결에 성공했습니다.")
        elif value == 2:
            print(f"[서버종류:{value}] HTS 보통 서버와의 연결에 성공했습니다.")

if __name__ == "__main__":
    cybos()

이제 주식코드 조회용 모듈을 `self.stockcode`라는 이름으로 인스턴스를 생성해주었으니, 해당 모듈 안에서 제공하는 여러 기능들은 앞서 통신 상태를 알려주는 `CpUtil.CpCybos`의 인스턴스인 `self.cybos`를 활용하여 제작한 여러 함수를 제작했던 방식과 동일하게 제작하면 된다. 그럼 이데 `CpUtil.CpStockCode` 모듈은 어떠한 기능을 제공하는지에 대해 살펴보도록 하자.

① CpUtil.CpStockCode : CodeToName(Code)

이 모듈에서 가장 먼저 확인할 수 있는 함수는 바로 `CodeToName(Code)`이다. 이는 `CodeToName`이라는 함수의 인자로 전달된 변수인 `Code`의 종목명을 반환하는 함수인데, 앞에서 사용했던 모듈과는 다른 부분이 있다면 함수에 대해 설명하는 내용에 있는 Object 란에 `self.cybos`가 아닌 `self.stockcode`가 들어가야 한다는 것이다. 

import win32com.client

class cybos:
    def __init__(self):
        self.cybos = win32com.client.Dispatch("CpUtil.CpCybos")  ## COM 연결
        self._IsConnect()
        self._ServerType()

        self.stockcode = win32com.client.Dispatch("CpUtil.CpStockCode")  ## COM 연결

    def _IsConnect(self):
        value = self.cybos.IsConnect
        if value == 1:
            print(f"[통신결과:{value}] 서버와의 연결에 성공했습니다.")
        elif value == 0:
            print(f"[통신결과:{value}] 서버와의 연결에 실패했습니다.")

    def _ServerType(self):
        """
        0: 연결 끊김
        1: CybosPlus 서버
        2:HTS 보통 서버(1번 제외)
        """
        value = self.cybos.ServerType
        if value == 0:
            print(f"[서버종류:{value}] 서버와의 연결이 끊겼습니다.")
        elif value == 1:
            print(f"[서버종류:{value}] CybosPlus 서버와의 연결에 성공했습니다.")
        elif value == 2:
            print(f"[서버종류:{value}] HTS 보통 서버와의 연결에 성공했습니다.")

    def _CodeToName(self, code):
        value = self.stockcode.CodeToName(code)
        print(f"[인자값:{code}] 결과값:{value}")

if __name__ == "__main__":
    cybos()

이제 이 코드가 정상적으로 동작하는지 살펴보기 위해서는 초기화함수 내부에서 `self._CodeToName()`와 같이 작성함으로써 해당 함수의 인자로 전달된 종목코드의 종목명을 반환받을 수 있다. 아래의 코드와 같이 초기화 함수 부분을 수정해보자.

class cybos:
    def __init__(self):
        self.cybos = win32com.client.Dispatch("CpUtil.CpCybos")  ## COM 연결
        self._IsConnect()
        self._ServerType()

        self.stockcode = win32com.client.Dispatch("CpUtil.CpStockCode")  ## COM 연결
        self._CodeToName("005930")

▶ 실행 결과 확인하기

더보기

[통신결과:1] 서버와의 연결에 성공했습니다.
[서버종류:1] CybosPlus 서버와의 연결에 성공했습니다.
[인자값:005930] 결과값:삼성전자

 

② CpUtil.CpStockCode : CodeToFullCode(Code)

두 번째로 살펴볼 함수는 전달된 Code에 해당하는 전체 코드를 반환하는 함수인데, 이는 일반적으로 우리가 알고 있는 종목코드와 실질적으로 한국증권거래소에 등록되어 있는 종목코드가 다소 상이하기 때문에 존재하는 기능이다. 우리는 잘 모르지만, 원래 표준체계 하에서 종목코드는 12개의 자리수를 가지고 있다.

이 중 우리가 알고있는 삼성전자의 종목코드인 "005930"은 어디까지나 단축코드 체계 하에서의 발행체고유코드일 뿐, 삼성전자의 실질적인 종목코드는 아니다. 단축코드 체계 하에서 단축속성코드는 주식의 경우에는 A가 배정되어 있기 때문에 삼성전자의 실질적인 단축코드 상 종목코드는 "A"으로 시작하는 게 정상이고, 표준코드 체계 하에서는 일단 기본적으로 한국에 상장된 주식이므로 "KR"로 시작하는 게 정상이다. 여기서 "005930"을 전달해주었을 때 그 종목코드에 대응하는 실질적인 종목코드를 반환해주는 함수가 바로 `CodeToFullCode(Code)`인데, 대신증권의 경우에는 단축코드 체계가 아닌 표준코드 체계의 종목코드를 반환해준다. 아래와 같이 해당 함수를 사용하는 함수인 `def _CodeToFullCode()`를 생성한 후에, 초기화 함수 내부에서 `self.stockcode._CodeToFullCode()`과 같은 코드를 입력해서 "005930" 종목의 실질적인 종목코드를 확인해보도록 하자.

import win32com.client

class cybos:
    def __init__(self):
        self.cybos = win32com.client.Dispatch("CpUtil.CpCybos")  ## COM 연결
        self._IsConnect()
        self._ServerType()

        self.stockcode = win32com.client.Dispatch("CpUtil.CpStockCode")  ## COM 연결
        self._CodeToName("005930")
        self._CodeToFullCode("005930")

    def _IsConnect(self):
        value = self.cybos.IsConnect
        if value == 1:
            print(f"[통신결과:{value}] 서버와의 연결에 성공했습니다.")
        elif value == 0:
            print(f"[통신결과:{value}] 서버와의 연결에 실패했습니다.")

    def _ServerType(self):
        """
        0: 연결 끊김
        1: CybosPlus 서버
        2:HTS 보통 서버(1번 제외)
        """
        value = self.cybos.ServerType
        if value == 0:
            print(f"[서버종류:{value}] 서버와의 연결이 끊겼습니다.")
        elif value == 1:
            print(f"[서버종류:{value}] CybosPlus 서버와의 연결에 성공했습니다.")
        elif value == 2:
            print(f"[서버종류:{value}] HTS 보통 서버와의 연결에 성공했습니다.")

    def _CodeToName(self, code):
        value = self.stockcode.CodeToName(code)
        print(f"[인자값:{code}] 결과값:{value}")

    def _CodeToFullCode(self, code):
        value = self.stockcode.CodeToFullCode(code)
        print(f"[인자값:{code}] 결과값:{value}")

if __name__ == "__main__":
    cybos()

▶ 실행 결과 확인하기

더보기

[통신결과:1] 서버와의 연결에 성공했습니다.
[서버종류:1] CybosPlus 서버와의 연결에 성공했습니다.
[인자값:005930] 결과값:삼성전자
[인자값:005930] 결과값:KR7005930003

앞서 살펴봤던 기능 외에도 표준코드 체계 하에서의 종목코드를 기준으로 하여 해당 코드의 종목코드나 종목명을 얻어오는 함수들이 있는데, 가장 먼저 표준코드 체계 하에서의 코드를 전달한 후에 종목코드를 반환받는 ③ CpUtil.CpStockCode : FullCodeToCode(FullCode)와 표준코드 체계 하에서의 코드를 전달한 후에 해당 코드의 종목명을 반환받는 ④ CpUtil.CpStockCode : FullCodeToName(FullCode)가 있다. 이 두 함수의 활용도에 대해 개인적으로는 크게 사용하지 않는다고 생각하기 때문에 아래에 해당 함수의 코드만 기재한 후에 넘어가도록 하겠다.

아래의 실행 결과에서 확인할 수 있겠지만, `FullCodeToCode(FullCode)` 함수는 표준코드 체계 하에서의 코드를 전달하면 서버로부터 단축코드 체계 하에서의 코드(삼성전자의 경우 "A005930")를 반환받는다. 

import win32com.client

class cybos:
    def __init__(self):
        self.cybos = win32com.client.Dispatch("CpUtil.CpCybos")  ## COM 연결
        self._IsConnect()
        self._ServerType()

        self.stockcode = win32com.client.Dispatch("CpUtil.CpStockCode")  ## COM 연결
        self._CodeToName("005930")
        self._CodeToFullCode("005930")
        self._FullCodeToCode("KR7005930003")
        self._FullCodeToName("KR7005930003")

    def _IsConnect(self):
        value = self.cybos.IsConnect
        if value == 1:
            print(f"[통신결과:{value}] 서버와의 연결에 성공했습니다.")
        elif value == 0:
            print(f"[통신결과:{value}] 서버와의 연결에 실패했습니다.")

    def _ServerType(self):
        """
        0: 연결 끊김
        1: CybosPlus 서버
        2:HTS 보통 서버(1번 제외)
        """
        value = self.cybos.ServerType
        if value == 0:
            print(f"[서버종류:{value}] 서버와의 연결이 끊겼습니다.")
        elif value == 1:
            print(f"[서버종류:{value}] CybosPlus 서버와의 연결에 성공했습니다.")
        elif value == 2:
            print(f"[서버종류:{value}] HTS 보통 서버와의 연결에 성공했습니다.")

    def _CodeToName(self, code):
        value = self.stockcode.CodeToName(code)
        print(f"[인자값:{code}] 결과값:{value}")

    def _CodeToFullCode(self, code):
        value = self.stockcode.CodeToFullCode(code)
        print(f"[인자값:{code}] 결과값:{value}")

    def _FullCodeToCode(self, fullcode):
        value = self.stockcode.FullCodeToCode(fullcode)
        print(f"[인자값:{fullcode}] 결과값:{value}")

    def _FullCodeToName(self, fullcode):
        value = self.stockcode.FullCodeToName(fullcode)
        print(f"[인자값:{fullcode}] 결과값:{value}")

if __name__ == "__main__":
    cybos()

▶ 실행 결과 확인하기

더보기

[통신결과:1] 서버와의 연결에 성공했습니다.
[서버종류:1] CybosPlus 서버와의 연결에 성공했습니다.
[인자값:005930] 결과값:삼성전자
[인자값:005930] 결과값:KR7005930003
[인자값:KR7005930003] 결과값:A005930
[인자값:KR7005930003] 결과값:삼성전자

궁금하지 않은 사람도 있겠지만, `CodeToName`이나 `CodeToFullCode` 함수에서 인자로 전달하는 종목코드에다가 우리가 알고 있는 삼성전자의 일반적인 종목코드인 "005930"을 전달해도 올바른 결과값을 받을 수 있지만, 단축코드 체계 하에서의 코드인 "A005930"을 전달해주어도 결과값은 동일하게 출력된다.

class cybos:
    def __init__(self):
        self.cybos = win32com.client.Dispatch("CpUtil.CpCybos")  ## COM 연결
        self._IsConnect()
        self._ServerType()

        self.stockcode = win32com.client.Dispatch("CpUtil.CpStockCode")  ## COM 연결
        self._CodeToName("A005930")
        self._CodeToFullCode("A005930")
        self._FullCodeToCode("KR7005930003")
        self._FullCodeToName("KR7005930003")

▶ 실행 결과 확인하기

더보기

[통신결과:1] 서버와의 연결에 성공했습니다.
[서버종류:1] CybosPlus 서버와의 연결에 성공했습니다.
[인자값:A005930] 결과값:삼성전자
[인자값:A005930] 결과값:KR7005930003
[인자값:KR7005930003] 결과값:A005930
[인자값:KR7005930003] 결과값:삼성전자

 

이외에 종목코드에 대응하는 인덱스 번호를 반환하는 함수인 ⑤ CpUtil.CpStockCode : CodeToIndex(Code), 상장되어 있는 종목코드의 개수를 반환하는 함수인 ⑥ CpUtil.CpStockCode : GetCount(), 5번 함수인 `CodeToIndex`에서 얻은 인덱스 번호와 함께 요청할 데이터 타입(`Type`)을 인자로 전달하면 그 타입의 종류에 따른 데이터(종목코드, 종목명, 표준코드 체계 하에서의 코드)를 반환하는 함수인 ⑦ CpUtil.CpStockCode : GetData(Type, Index) 함수가 있다. 함수별 사용 방법은 아래의 코드를 참고하도록 하자.

import win32com.client

class cybos:
    def __init__(self):
        self.cybos = win32com.client.Dispatch("CpUtil.CpCybos")  ## COM 연결
        self._IsConnect()
        self._ServerType()

        self.stockcode = win32com.client.Dispatch("CpUtil.CpStockCode")  ## COM 연결
        self._CodeToName("005930")
        self._CodeToFullCode("005930")
        self._FullCodeToCode("KR7005930003")
        self._FullCodeToName("KR7005930003")
        self._CodeToIndex("005930")
        self._GetCount()
        self._GetData(0, 325)
        self._GetData(1, 325)
        self._GetData(2, 325)

    def _IsConnect(self):
        value = self.cybos.IsConnect
        if value == 1:
            print(f"[통신결과:{value}] 서버와의 연결에 성공했습니다.")
        elif value == 0:
            print(f"[통신결과:{value}] 서버와의 연결에 실패했습니다.")

    def _ServerType(self):
        """
        0: 연결 끊김
        1: CybosPlus 서버
        2:HTS 보통 서버(1번 제외)
        """
        value = self.cybos.ServerType
        if value == 0:
            print(f"[서버종류:{value}] 서버와의 연결이 끊겼습니다.")
        elif value == 1:
            print(f"[서버종류:{value}] CybosPlus 서버와의 연결에 성공했습니다.")
        elif value == 2:
            print(f"[서버종류:{value}] HTS 보통 서버와의 연결에 성공했습니다.")

    def _CodeToName(self, code):
        value = self.stockcode.CodeToName(code)
        print(f"[인자값:{code}] 결과값:{value}")

    def _CodeToFullCode(self, code):
        value = self.stockcode.CodeToFullCode(code)
        print(f"[인자값:{code}] 결과값:{value}")

    def _FullCodeToCode(self, fullcode):
        value = self.stockcode.FullCodeToCode(fullcode)
        print(f"[인자값:{fullcode}] 결과값:{value}")

    def _FullCodeToName(self, fullcode):
        value = self.stockcode.FullCodeToName(fullcode)
        print(f"[인자값:{fullcode}] 결과값:{value}")

    def _CodeToIndex(self, code):
        value = self.stockcode.CodeToIndex(code)
        print(f"[인자값:{code}] 결과값:{value}")

    def _GetCount(self):
        value = self.stockcode.GetCount()
        print(f"전체 종목코드 개수:{value}")

    def _GetData(self, type, index):
        """
        종목코드의 Index와 함께 Type을 전달해주면 Type에 해당하는 데이터를 반환함
        :param type: 0은 종목코드, 1은 종목명, 2은 표준코드 체계 하에서의 코드
        :param index:종목코드 인덱스
        :return: 해당 데이터
        """
        value = self.stockcode.GetData(type, index)
        print(f"[Type:{type}, Index:{index}] 결과값:{value}")

if __name__ == "__main__":
    cybos()

▶ 실행 결과 확인하기

더보기

[통신결과:1] 서버와의 연결에 성공했습니다.
[서버종류:1] CybosPlus 서버와의 연결에 성공했습니다.
[인자값:005930] 결과값:삼성전자
[인자값:005930] 결과값:KR7005930003
[인자값:KR7005930003] 결과값:A005930
[인자값:KR7005930003] 결과값:삼성전자
[인자값:005930] 결과값:325
전체 종목코드 개수:4225
[Type:0, Index:325] 결과값:A005930
[Type:1, Index:325] 결과값:삼성전자
[Type:2, Index:325] 결과값:KR7005930003

이제 세 번째 모듈을 살펴볼 차례인데, 대신증권 홈페이지의 도움말 상에서 세 번째 모듈은 `CpUtil.CpFutureCode`이고 네 번째 모듈은 `CpUtil.CpOptionCode`이다. 다섯 번째 모듈도 `CpUtil.CpSOptionCode`이고 여섯 번째 모듈도 `CpUtil.KFutureCode`, 일곱 번째 모듈도 `CpUtil.CpElwCode`이다. 이 모듈들은 모두 선물 옵션과 관련된 모듈이며 그 세부적인 함수도 주식 거래에는 크게 필요하지 않으므로 이 게시글에서는 제외하고 넘어가도록 하겠다.

 

 


반응형
728x90

 

 

(3) 주문 오브젝트 실행 모듈 : CpTrade.CpTdUtil

이 모듈은 주문과 관련된 오브젝트를 실행하기 위해 필요한 '초기화' 과정을 수행하는 모듈이다.  여기서 이야기하는 '초기화'란 이전에 우리의 코드 안에도 있는 `def __init__(self)` 함수를 초기화 함수라고 설명했듯이 주문과 관련된 모든 기능을 실행하기 전에 앞서 가장 먼저 실행되는 모듈이라고 볼 수 있다. 이 모듈을 대표하는 함수는 `TradeInit`인데, 이름만 봐도 우리가 제작하는 코드의 초기화 함수의 함수 이름에 있는 init이 들어가 있다. 

일단 이 모듈을 사용하기 위해서는 앞전 두 개의 모듈을 각각 `self.cybos`와 `self.stockcode`라는 인스턴스를 생성한 후에 그 인스턴스를 활용하여 함수를 제작하였던 것과 마찬가지로, 이번에는 `CpTrade.CpTdUtil` 모듈을 `self.trade`라는 인스턴스를 생성하여 이 인스턴스를 활용하여 함수를 제작해주면 된다. (인스턴스 이름은 무엇을 사용하든지 간에 상관 없다.)

그 후에, `def _TradeInit(self)`라는 함수를 새롭게 생성하고 그 함수 내부에서 `self.trade`라는 인스턴스를 활용하여 우리가 사용하고자 하는 함수인 `TradeInit`를 뒤에 붙여서 `self.trade.TradeInit()`과 같이 사용하면 된다. `TradeInit` 함수의 실행 결과로 반환되는 결과값은 아래와 같다.

  • -1 : 오류(계좌 비밀번호 오류도 여기에 포함됨)
  •  0 : 정상
  •  1 : OTP/보안카드 키 입력 잘못됨
  •  3 : 초기화 취소됨

[추신] 이 함수에 대한 대신증권 공식 도움말에 따르면, 이 함수는 기본적으로 `object.TradeInit(Reserved)`와 같은 형태로서, `TradeInit` 함수의 인자로 `Reserved`를 전달해야 하는 것처럼 기재되어 있고 이 `Reserved`를 내부적으로 사용되는 값이라고 설명하고 있긴 하나, Visual Basic과 Visual Basic Script는 따로 설정하지 않아도 되며, Visual Studio Code는 기본값으로 0을 전달하면 된다고 한다. 우리가 사용하는 파이썬 언어는 VC(Visual Studio Code)에서도 사용이 가능하고 동작 방식이 비슷하기 때문에 0을 입력하였으나, 0을 제외하고 공백 상태로 ()만 사용해도 문제는 발생하지 않았다.

import win32com.client

class cybos:
    def __init__(self):
        self.cybos = win32com.client.Dispatch("CpUtil.CpCybos")  ## COM 연결
        self._IsConnect()
        self._ServerType()

        self.stockcode = win32com.client.Dispatch("CpUtil.CpStockCode")  ## COM 연결
        self._CodeToName("005930")
        self._CodeToFullCode("005930")
        self._FullCodeToCode("KR7005930003")
        self._FullCodeToName("KR7005930003")
        self._CodeToIndex("005930")
        self._GetCount()
        self._GetData(0, 325)
        self._GetData(1, 325)
        self._GetData(2, 325)

        self.trade = win32com.client.Dispatch("CpTrade.CpTdUtil")
        self._TradeInit()

    def _IsConnect(self):
        value = self.cybos.IsConnect
        if value == 1:
            print(f"[통신결과:{value}] 서버와의 연결에 성공했습니다.")
        elif value == 0:
            print(f"[통신결과:{value}] 서버와의 연결에 실패했습니다.")

    def _ServerType(self):
        """
        0: 연결 끊김
        1: CybosPlus 서버
        2:HTS 보통 서버(1번 제외)
        """
        value = self.cybos.ServerType
        if value == 0:
            print(f"[서버종류:{value}] 서버와의 연결이 끊겼습니다.")
        elif value == 1:
            print(f"[서버종류:{value}] CybosPlus 서버와의 연결에 성공했습니다.")
        elif value == 2:
            print(f"[서버종류:{value}] HTS 보통 서버와의 연결에 성공했습니다.")

    def _CodeToName(self, code):
        value = self.stockcode.CodeToName(code)
        print(f"[인자값:{code}] 결과값:{value}")

    def _CodeToFullCode(self, code):
        value = self.stockcode.CodeToFullCode(code)
        print(f"[인자값:{code}] 결과값:{value}")

    def _FullCodeToCode(self, fullcode):
        value = self.stockcode.FullCodeToCode(fullcode)
        print(f"[인자값:{fullcode}] 결과값:{value}")

    def _FullCodeToName(self, fullcode):
        value = self.stockcode.FullCodeToName(fullcode)
        print(f"[인자값:{fullcode}] 결과값:{value}")

    def _CodeToIndex(self, code):
        value = self.stockcode.CodeToIndex(code)
        print(f"[인자값:{code}] 결과값:{value}")

    def _GetCount(self):
        value = self.stockcode.GetCount()
        print(f"전체 종목코드 개수:{value}")

    def _GetData(self, type, index):
        """
        종목코드의 Index와 함께 Type을 전달해주면 Type에 해당하는 데이터를 반환함
        :param type: 0은 종목코드, 1은 종목명, 2은 표준코드 체계 하에서의 코드
        :param index:종목코드 인덱스
        :return: 해당 데이터
        """
        value = self.stockcode.GetData(type, index)
        print(f"[Type:{type}, Index:{index}] 결과값:{value}")

    def _TradeInit(self):
        """
        :return: 주문과 관련된 결과값 반환
            -1: 오류 (계좌 비밀번호 오류도 포함함)
             0: 정상
             1: OTP/보안카드 키 입력 잘못됨
             3: 취소
        """
        value = self.trade.TradeInit(0)
        result = ""   ## 지역변수 설정
        if value == -1:
            result = "오류(계좌 비밀번호 오류도 포함함)"
        elif value == 0:
            result = "정상"
        elif value == 1:
            result = "OTP/보안카드 키 입력 잘못됨"
        elif value == 3:
            result = "취소"
        print(f"[주문 오브젝트 초기화 결과] {value}({result})")

if __name__ == "__main__":
    cybos()

▶ 실행 결과 확인하기

더보기

[통신결과:1] 서버와의 연결에 성공했습니다.
[서버종류:1] CybosPlus 서버와의 연결에 성공했습니다.
[인자값:005930] 결과값:삼성전자
[인자값:005930] 결과값:KR7005930003
[인자값:KR7005930003] 결과값:A005930
[인자값:KR7005930003] 결과값:삼성전자
[인자값:005930] 결과값:325
전체 종목코드 개수:4225
[Type:0, Index:325] 결과값:A005930
[Type:1, Index:325] 결과값:삼성전자
[Type:2, Index:325] 결과값:KR7005930003
[주문 오브젝트 초기화 결과] 0(정상)

추가적으로, 대신증권 공식 도움말에 따르면 `TradeInit` 함수를 실행하면 'CybosPlus 주문확인 설정'이라는 창이 뜬다고 설명되어 있었지만 업데이트가 된 탓인지 지금은 이 창이 뜨지 않았다. 그래서 그 창은 어떻게 들어가나 확인해봤는데, 우측 하단 '실행 중인 프로그램'에서 Cybos Plus에 마우스 오른 클릭을 누른 후, [주문내역 확인 설정] 화면을 클릭하면 하단의 우측 사진과 같은 창이 출력되긴 했으나 비밀번호를 입력하거나 하는 란은 없었다.

다만 여기서 주문내역 확인에 체크가 되어 있지 않으면 추후에 주문이 접수될 때 특별한 주문 확인 팝업이 발생하지 않지만, 체크되어 있을 경우에는 주문을 접수하는 함수(예를 들면 추후에 살펴볼 `CpTd0311` 함수 등)가 실행됐을 때 주문 확인 창이 발생하게 된다. 우리는 일단 자동 매매 시스템을 구현하고자 하는 것이니까 체크박스는 해제가 되어 있는 게 맞지만, 혹시 프로그램이 돌아가는 걸 '장 중에 직접 확인이 가능한 사람'의 경우에는 체크를 하고 정상적으로 동작하는지 확인해보는 것도 좋은 방법일 것 같다.

 

이제 다음으로 살펴볼 함수는 계좌번호 목록을 반환하는 함수인 `AccountNumber`인데, 대신증권 도움말에서도 볼 수 있듯이 이 함수는 앞서 살펴봤던 모든 함수를 통틀어서 보더라도 특이한 점이 하나 있는데, 바로 '읽기 전용 함수'라는 것이다. 실제로 코드를 구현해보면 알겠지만, 이 함수는 뒤에 소괄호를 붙이면 코드가 실행되지 않는다. 대신증권의 도움말에 '읽기 전용'으로 표기된 함수만의 특징인지는 모르겠지만, `self.trade.AccountNumber()`가 아니라 `self.trade.AccountNumber`와 같은 형태로 구현해야 정상적으로 작동한다.

import win32com.client

class cybos:
    def __init__(self):
        self.cybos = win32com.client.Dispatch("CpUtil.CpCybos")  ## COM 연결
        self._IsConnect()
        self._ServerType()

        self.stockcode = win32com.client.Dispatch("CpUtil.CpStockCode")  ## COM 연결
        self._CodeToName("005930")
        self._CodeToFullCode("005930")
        self._FullCodeToCode("KR7005930003")
        self._FullCodeToName("KR7005930003")
        self._CodeToIndex("005930")
        self._GetCount()
        self._GetData(0, 325)
        self._GetData(1, 325)
        self._GetData(2, 325)

        self.trade = win32com.client.Dispatch("CpTrade.CpTdUtil")
        self._TradeInit()
        self._AccountNumber()

    def _IsConnect(self):
        value = self.cybos.IsConnect
        if value == 1:
            print(f"[통신결과:{value}] 서버와의 연결에 성공했습니다.")
        elif value == 0:
            print(f"[통신결과:{value}] 서버와의 연결에 실패했습니다.")

    def _ServerType(self):
        """
        0: 연결 끊김
        1: CybosPlus 서버
        2:HTS 보통 서버(1번 제외)
        """
        value = self.cybos.ServerType
        if value == 0:
            print(f"[서버종류:{value}] 서버와의 연결이 끊겼습니다.")
        elif value == 1:
            print(f"[서버종류:{value}] CybosPlus 서버와의 연결에 성공했습니다.")
        elif value == 2:
            print(f"[서버종류:{value}] HTS 보통 서버와의 연결에 성공했습니다.")

    def _CodeToName(self, code):
        value = self.stockcode.CodeToName(code)
        print(f"[인자값:{code}] 결과값:{value}")

    def _CodeToFullCode(self, code):
        value = self.stockcode.CodeToFullCode(code)
        print(f"[인자값:{code}] 결과값:{value}")

    def _FullCodeToCode(self, fullcode):
        value = self.stockcode.FullCodeToCode(fullcode)
        print(f"[인자값:{fullcode}] 결과값:{value}")

    def _FullCodeToName(self, fullcode):
        value = self.stockcode.FullCodeToName(fullcode)
        print(f"[인자값:{fullcode}] 결과값:{value}")

    def _CodeToIndex(self, code):
        value = self.stockcode.CodeToIndex(code)
        print(f"[인자값:{code}] 결과값:{value}")

    def _GetCount(self):
        value = self.stockcode.GetCount()
        print(f"전체 종목코드 개수:{value}")

    def _GetData(self, type, index):
        """
        종목코드의 Index와 함께 Type을 전달해주면 Type에 해당하는 데이터를 반환함
        :param type: 0은 종목코드, 1은 종목명, 2은 표준코드 체계 하에서의 코드
        :param index:종목코드 인덱스
        :return: 해당 데이터
        """
        value = self.stockcode.GetData(type, index)
        print(f"[Type:{type}, Index:{index}] 결과값:{value}")

    def _TradeInit(self):
        """
        :return: 주문과 관련된 결과값 반환
            -1: 오류 (계좌 비밀번호 오류도 포함함)
             0: 정상
             1: OTP/보안카드 키 입력 잘못됨
             3: 취소
        """
        value = self.trade.TradeInit(0)
        result = ""   ## 지역변수 설정
        if value == -1:
            result = "오류(계좌 비밀번호 오류도 포함함)"
        elif value == 0:
            result = "정상"
        elif value == 1:
            result = "OTP/보안카드 키 입력 잘못됨"
        elif value == 3:
            result = "취소"
        print(f"[주문 오브젝트 초기화 결과] {value}({result})")

    def _AccountNumber(self):
        """
        [Only Read, 읽기 전용 함수]
        :return: 계좌 목록 표기
        """
        value = self.trade.AccountNumber
        print(f"[마스터 계좌 표기] {value}")

if __name__ == "__main__":
    cybos()

▶ 실행 결과 확인하기

더보기

[통신결과:1] 서버와의 연결에 성공했습니다.
[서버종류:1] CybosPlus 서버와의 연결에 성공했습니다.
[인자값:005930] 결과값:삼성전자
[인자값:005930] 결과값:KR7005930003
[인자값:KR7005930003] 결과값:A005930
[인자값:KR7005930003] 결과값:삼성전자
[인자값:005930] 결과값:325
전체 종목코드 개수:4225
[Type:0, Index:325] 결과값:A005930
[Type:1, Index:325] 결과값:삼성전자
[Type:2, Index:325] 결과값:KR7005930003
[주문 오브젝트 초기화 결과] 0(정상)
[마스터 계좌 표기] ('3330*****',)

 

 

(4) 각종 코드 정보 및 코드 리스트 획득 모듈 : CpUtil.CpCodeMgr

마지막으로 살펴볼 이 모듈은 종목 코드를 기반으로 하여 종목에 대한 여러 가지 정보와 코드 목록을 얻을 수 있는 모듈이다. 예를 들면 거래에 필요한 매수 증거금 비율이나 상장일자, 종목이 속한 섹터를 판단하기 위한 업종코드, 또는 종목이 거래소(KOSPI) 종목인지 아니면 코스닥(KOSDAQ) 종목인지 등을 구분하거나 실질적인 가격(상하한가 및 전일 시고저종 등) 데이터를 반환받을 수 있다. 여태까지 살펴봤던 모듈에 비해 가장 다양한 메서드를 제공하는 모듈인 만큼, 모든 함수를 설명하고 살펴보기에는 어려움이 있으니 대표적인 함수만 설명하도록 하고, 그 외에 설명하지 않은 함수라 하더라도 직접 사용할 수 있게끔 코드는 함께 기재할 예정이다.

가장 먼저 살펴볼 함수는 종목의 매수 증거금율을 반환하는 `GetStockMarginRate`이다. 증거금율의 경우에는 증권사별로 각기 다르게 설정하고 있는 만큼 증권사에서 반드시 제공해주어야 하는 목록 중 하나이다. 이는 신용이나 미수 등을 사용하지 않는다면 굳이 필요 없겠지만, 알고리즘의 유효성이 검증된 상황이라면 신용과 미수는 좋은 선택지가 된다. (검증되지 않은 상태에서는 절대 사용하지 않도록 하자.) 이 함수는 종목코드를 인자로 받아서 그 종목코드의 매수 증거금율을 반환하며 반환되는 값은 30%인 경우에도 0.3이 아닌 30(숫자형, 'int')으로 반환된다. 만약 추후에 이 데이터를 활용할 목적이라면 이 값을 100으로 나눈 값을 반환하도록 함으로써 정확한 증거금율을 계산하거나, 반환되는 값인 30을 먼저 곱한 후 그 값을 다시 100으로 나눈다거나 하는 등의 계산 로직을 통해 정확한 매수 가능 금액을 계산해야 한다.  

import win32com.client

class cybos:
    def __init__(self):
        self.cybos = win32com.client.Dispatch("CpUtil.CpCybos")  ## COM 연결
        self._IsConnect()
        self._ServerType()

        self.stockcode = win32com.client.Dispatch("CpUtil.CpStockCode")  ## COM 연결
        self._CodeToName("005930")
        self._CodeToFullCode("005930")
        self._FullCodeToCode("KR7005930003")
        self._FullCodeToName("KR7005930003")
        self._CodeToIndex("005930")
        self._GetCount()
        self._GetData(0, 325)
        self._GetData(1, 325)
        self._GetData(2, 325)

        self.trade = win32com.client.Dispatch("CpTrade.CpTdUtil")
        self._TradeInit()
        self._AccountNumber()

        self.codemgr = win32com.client.Dispatch("CpUtil.CpCodeMgr")  ## COM 연결
        self._GetStockMarginRate("005930")

    def _IsConnect(self):
        value = self.cybos.IsConnect
        if value == 1:
            print(f"[통신결과:{value}] 서버와의 연결에 성공했습니다.")
        elif value == 0:
            print(f"[통신결과:{value}] 서버와의 연결에 실패했습니다.")

    def _ServerType(self):
        """
        0: 연결 끊김
        1: CybosPlus 서버
        2:HTS 보통 서버(1번 제외)
        """
        value = self.cybos.ServerType
        if value == 0:
            print(f"[서버종류:{value}] 서버와의 연결이 끊겼습니다.")
        elif value == 1:
            print(f"[서버종류:{value}] CybosPlus 서버와의 연결에 성공했습니다.")
        elif value == 2:
            print(f"[서버종류:{value}] HTS 보통 서버와의 연결에 성공했습니다.")

    def _CodeToName(self, code):
        value = self.stockcode.CodeToName(code)
        print(f"[인자값:{code}] 결과값:{value}")

    def _CodeToFullCode(self, code):
        value = self.stockcode.CodeToFullCode(code)
        print(f"[인자값:{code}] 결과값:{value}")

    def _FullCodeToCode(self, fullcode):
        value = self.stockcode.FullCodeToCode(fullcode)
        print(f"[인자값:{fullcode}] 결과값:{value}")

    def _FullCodeToName(self, fullcode):
        value = self.stockcode.FullCodeToName(fullcode)
        print(f"[인자값:{fullcode}] 결과값:{value}")

    def _CodeToIndex(self, code):
        value = self.stockcode.CodeToIndex(code)
        print(f"[인자값:{code}] 결과값:{value}")

    def _GetCount(self):
        value = self.stockcode.GetCount()
        print(f"전체 종목코드 개수:{value}")

    def _GetData(self, type, index):
        """
        종목코드의 Index와 함께 Type을 전달해주면 Type에 해당하는 데이터를 반환함
        :param type: 0은 종목코드, 1은 종목명, 2은 표준코드 체계 하에서의 코드
        :param index:종목코드 인덱스
        :return: 해당 데이터
        """
        value = self.stockcode.GetData(type, index)
        print(f"[Type:{type}, Index:{index}] 결과값:{value}")

    def _TradeInit(self):
        """
        :return: 주문과 관련된 결과값 반환
            -1: 오류 (계좌 비밀번호 오류도 포함함)
             0: 정상
             1: OTP/보안카드 키 입력 잘못됨
             3: 취소
        """
        value = self.trade.TradeInit(0)
        result = ""   ## 지역변수 설정
        if value == -1:
            result = "오류(계좌 비밀번호 오류도 포함함)"
        elif value == 0:
            result = "정상"
        elif value == 1:
            result = "OTP/보안카드 키 입력 잘못됨"
        elif value == 3:
            result = "취소"
        print(f"[주문 오브젝트 초기화 결과] {value}({result})")

    def _AccountNumber(self):
        """
        [Only Read, 읽기 전용 함수]
        :return: 계좌 목록 표기
        """
        value = self.trade.AccountNumber
        print(f"[마스터 계좌 표기] {value}")

    def _GetStockMarginRate(self, code):
        """
        :param code: 종목코드
        :return:     주식 매수 증거금율
        """
        value = self.codemgr.GetStockMarginRate(code)
        print(f"[인자값:{code}] 매수 증거금율:{value}%({type(value)})")

if __name__ == "__main__":
    cybos()

▶ 실행 결과 확인하기

더보기

[통신결과:1] 서버와의 연결에 성공했습니다.
[서버종류:1] CybosPlus 서버와의 연결에 성공했습니다.
[인자값:005930] 결과값:삼성전자
[인자값:005930] 결과값:KR7005930003
[인자값:KR7005930003] 결과값:A005930
[인자값:KR7005930003] 결과값:삼성전자
[인자값:005930] 결과값:325
전체 종목코드 개수:4225
[Type:0, Index:325] 결과값:A005930
[Type:1, Index:325] 결과값:삼성전자
[Type:2, Index:325] 결과값:KR7005930003
[주문 오브젝트 초기화 결과] 0(정상)
[마스터 계좌 표기] ('333025522',)
[인자값:005930] 매수 증거금율:30%(<class 'int'>)

이외에도 단순하게 전일 시고저종 데이터를 조회하는 `GetStockYdOpenPrice`나 `GetStockYdHighPrice` 또는 `GetStockYdClosePrice` 등의 함수가 있으며 신용을 사용할 수 있는지를 Bool(True 또는 False와 같은 방식) 형태로 반환하는 `IsStockCreditEnable` 함수도 존재한다. 이외에도 스팩주인지 아닌지 여부를 판단할 수 있는 함수(`IsSPAC`)나 정리매매 여부를 확인할 수 있는 함수(`IsStockArrgSby`), 단기과열 여부를 확인할 수 있는 함수(`GetOverHeating`)가 있다.

여기서 그 사용 방법에 대해 대신증권 도움말에 자세히 설명되어 있지 않았던 함수에 대해 살펴보자면 바로 특정 시장에 상장되어 있는 종목 목록을 반환하는 `GetStockListByMarket` 함수이다. 이 함수는 인자로 조회하고자 하는 시장('거래소' 또는 '코스닥', 'K-OTC' 등)을 전달받아야 하는데, 단순히 '거래소'를 전달하면 에러가 발생하고 '거래소'를 의미하는 코드를 전달해주어야 한다. 여기서 '거래소'를 의미하는 코드와 '코스닥'을 의미하는 코드는 `GetStockMarketKind` 함수를 통해 얻을 수 있다. 이 함수는 종목코드를 인자로 전달받은 후 그 종목코드가 소속되어 있는 시장 구분을 반환해주는 함수인데, 그 시장 구분을 정리하자면 아래와 같다.

  • 0: 구분없음
  • 1: 거래소 (=코스피)
  • 2: 코스닥
  • 3: K-OTC
  • 4: KRX
  • 5: KONEX

즉, 특정 시장에 상장되어 있는 종목 목록을 반환하는 `GetStockListByMarket` 함수는 시장 구분을 인자로 받는데, 이 때 인자로 전달해야 하는 변수는 '거래소'나 '코스닥'이 아니라 각각에 대응하는 숫자인 0이나 1을 전달해줘야 그 결과값을 확인할 수 있다는 것이다. 

import win32com.client

class cybos:
    def __init__(self):
        self.cybos = win32com.client.Dispatch("CpUtil.CpCybos")  ## COM 연결
        self._IsConnect()
        self._ServerType()

        self.stockcode = win32com.client.Dispatch("CpUtil.CpStockCode")  ## COM 연결
        self._CodeToName("005930")
        self._CodeToFullCode("005930")
        self._FullCodeToCode("KR7005930003")
        self._FullCodeToName("KR7005930003")
        self._CodeToIndex("005930")
        self._GetCount()
        self._GetData(0, 325)
        self._GetData(1, 325)
        self._GetData(2, 325)

        self.trade = win32com.client.Dispatch("CpTrade.CpTdUtil")
        self._TradeInit()
        self._AccountNumber()

        self.codemgr = win32com.client.Dispatch("CpUtil.CpCodeMgr")  ## COM 연결
        self._GetStockMarginRate("005930")
        self._GetStockMarketKind("005930")
        self._GetStockListByMarket(1)

    def _IsConnect(self):
        value = self.cybos.IsConnect
        if value == 1:
            print(f"[통신결과:{value}] 서버와의 연결에 성공했습니다.")
        elif value == 0:
            print(f"[통신결과:{value}] 서버와의 연결에 실패했습니다.")

    def _ServerType(self):
        """
        0: 연결 끊김
        1: CybosPlus 서버
        2:HTS 보통 서버(1번 제외)
        """
        value = self.cybos.ServerType
        if value == 0:
            print(f"[서버종류:{value}] 서버와의 연결이 끊겼습니다.")
        elif value == 1:
            print(f"[서버종류:{value}] CybosPlus 서버와의 연결에 성공했습니다.")
        elif value == 2:
            print(f"[서버종류:{value}] HTS 보통 서버와의 연결에 성공했습니다.")

    def _CodeToName(self, code):
        value = self.stockcode.CodeToName(code)
        print(f"[인자값:{code}] 결과값:{value}")

    def _CodeToFullCode(self, code):
        value = self.stockcode.CodeToFullCode(code)
        print(f"[인자값:{code}] 결과값:{value}")

    def _FullCodeToCode(self, fullcode):
        value = self.stockcode.FullCodeToCode(fullcode)
        print(f"[인자값:{fullcode}] 결과값:{value}")

    def _FullCodeToName(self, fullcode):
        value = self.stockcode.FullCodeToName(fullcode)
        print(f"[인자값:{fullcode}] 결과값:{value}")

    def _CodeToIndex(self, code):
        value = self.stockcode.CodeToIndex(code)
        print(f"[인자값:{code}] 결과값:{value}")

    def _GetCount(self):
        value = self.stockcode.GetCount()
        print(f"전체 종목코드 개수:{value}")

    def _GetData(self, type, index):
        """
        종목코드의 Index와 함께 Type을 전달해주면 Type에 해당하는 데이터를 반환함
        :param type: 0은 종목코드, 1은 종목명, 2은 표준코드 체계 하에서의 코드
        :param index:종목코드 인덱스
        :return: 해당 데이터
        """
        value = self.stockcode.GetData(type, index)
        print(f"[Type:{type}, Index:{index}] 결과값:{value}")

    def _TradeInit(self):
        """
        :return: 주문과 관련된 결과값 반환
            -1: 오류 (계좌 비밀번호 오류도 포함함)
             0: 정상
             1: OTP/보안카드 키 입력 잘못됨
             3: 취소
        """
        value = self.trade.TradeInit(0)
        result = ""   ## 지역변수 설정
        if value == -1:
            result = "오류(계좌 비밀번호 오류도 포함함)"
        elif value == 0:
            result = "정상"
        elif value == 1:
            result = "OTP/보안카드 키 입력 잘못됨"
        elif value == 3:
            result = "취소"
        print(f"[주문 오브젝트 초기화 결과] {value}({result})")

    def _AccountNumber(self):
        """
        [Only Read, 읽기 전용 함수]
        :return: 계좌 목록 표기
        """
        value = self.trade.AccountNumber
        print(f"[마스터 계좌 표기] {value}")

    def _GetStockMarginRate(self, code):
        """
        :param code: 종목코드
        :return:     주식 매수 증거금율
        """
        value = self.codemgr.GetStockMarginRate(code)
        print(f"[인자값:{code}] 매수 증거금율:{value}%({type(value)})")

    def _GetStockMarketKind(self, code):
        """
        :param code: 종목코드
        :return:     해당 종목코드의 소속 시장 반환
            0: 구분없음
            1: 거래소
            2: 코스닥
            3: K-OTC
            4: KRX
            5: KONEX
        """
        value = self.codemgr.GetStockMarketKind(code)
        name = ""   ## 지역변수 설정
        if value == 0:
            name = "구분없음"
        elif value == 1:
            name = "거래소"
        elif value == 2:
            name = "코스닥"
        elif value == 3:
            name = "K-OTC"
        elif value == 4:
            name = "KRX"
        elif value == 5:
            name = "KONEX"
        print(f"[인자값:{code}] 소속부:{value}({name})")

    def _GetStockListByMarket(self, market_kind_code):
        """
        :param market_kind_code: GetStockMarketKind 함수의 인자값 참조
            1: 거래소, 2: 코스닥, 3: K-OTC, 4: KRX, 5: KONEX
        :return                : 시장 구분에 따른 주식 종목 배열
        """
        value = self.codemgr.GetStockListByMarket(market_kind_code)
        print(f"[인자값:{market_kind_code}] 종목코드 목록:{value}")

if __name__ == "__main__":
    cybos()

▶ 실행 결과 확인하기

더보기

[통신결과:1] 서버와의 연결에 성공했습니다.
[서버종류:1] CybosPlus 서버와의 연결에 성공했습니다.
[인자값:005930] 결과값:삼성전자
[인자값:005930] 결과값:KR7005930003
[인자값:KR7005930003] 결과값:A005930
[인자값:KR7005930003] 결과값:삼성전자
[인자값:005930] 결과값:325
전체 종목코드 개수:4225
[Type:0, Index:325] 결과값:A005930
[Type:1, Index:325] 결과값:삼성전자
[Type:2, Index:325] 결과값:KR7005930003
[주문 오브젝트 초기화 결과] 0(정상)
[마스터 계좌 표기] ('333025522',)
[인자값:005930] 매수 증거금율:30%(<class 'int'>)
[인자값:005930] 소속시장:1(거래소)
[인자값:1] 종목코드 목록:('A000020', 'A000040', 'A000050', 'A000070', · · · ·(중략) · · · 'Q760008', 'Q760009')

이와 비슷하게 설명이 불친절한 함수는 바로 전산 업종코드에 해당하는 종목코드를 반환하는 `GetGroupCodeList` 함수이다. 앞전에 살펴봤던 함수는 '특정 시장에 상장되어 있는 종목코드를 반환'하는 기능이었다면, 이 함수는 '특정 업종코드로 구분되어 있는 종목코드를 반환'하는 기능이다. 이 때 인자로 전달해야 하는 업종코드 역시 정확히 설명되어 있지 않았는데, 그 업종코드 정보는 `GetIndustryList` 함수를 통해 얻으라고 되어 있긴 했지만 이 함수는 정작 `GetIndustryName` 함수에만 적용되는 전산 업종코드를 반환해주었다. 도움말을 잘 살펴보다 보니 `GetIndustryList` 함수를 통해 전달받는 업종코드는 `GetGroupCodeList` 함수가 아닌 `GetIndustryGroupCodeList`에 전달해주었을 때 그 종목 목록을 올바르게 반환해주었다.

그렇다면  `GetGroupCodeList` 함수가 요청하는 인자로 전달할 업종 코드는 어떤 함수를 통해 획득할 수 있는 것일까? 이 질문에 대한 답을 찾기 위해 많은 내용을 살펴보았지만, 정확한 내용은 아직 확인하지 못했다. 다만 대신증권 도움말 내에 작성되어 있는 예제를 통해 유추해보자면, 증권업은 '24'라는 번호가 부여되어 있고 `GetGroupCodeList` 함수에 `24`라는 인자를 전달하여 결과값을 확인해보면 증권업에 속하는 종목들의 종목 코드가 모두 반환됨을 확인했다. 이 점으로 미루어보아, 아마 업종별로 001, 002, 003 등과 같은 형태의 코드가 부여되어 있고 그 코드를 전달하면 그 안에 있는 종목코드를 반환하여 주는 것까지는 유추할 수 있으나, 001, 002 등의 업종 코드를 어떤 함수를 통해 반환받을 수 있는지는 확인하지 못했다. (추후에 확인되면 보완 작성할 예정이다.)

import win32com.client

class cybos:
    def __init__(self):
        self.cybos = win32com.client.Dispatch("CpUtil.CpCybos")  ## COM 연결
        self._IsConnect()
        self._ServerType()

        self.stockcode = win32com.client.Dispatch("CpUtil.CpStockCode")  ## COM 연결
        self._CodeToName("005930")
        self._CodeToFullCode("005930")
        self._FullCodeToCode("KR7005930003")
        self._FullCodeToName("KR7005930003")
        self._CodeToIndex("005930")
        self._GetCount()
        self._GetData(0, 325)
        self._GetData(1, 325)
        self._GetData(2, 325)

        self.trade = win32com.client.Dispatch("CpTrade.CpTdUtil")
        self._TradeInit()
        self._AccountNumber()

        self.codemgr = win32com.client.Dispatch("CpUtil.CpCodeMgr")  ## COM 연결
        self._GetStockMarginRate("005930")
        self._GetStockMarketKind("005930")
        self._GetStockListByMarket(1)
        self._GetIndustryList()
        self._GetIndustryName("KGS02P")
        self._GetIndustryGroupCodeList("KGS02P")

    def _IsConnect(self):
        value = self.cybos.IsConnect
        if value == 1:
            print(f"[통신결과:{value}] 서버와의 연결에 성공했습니다.")
        elif value == 0:
            print(f"[통신결과:{value}] 서버와의 연결에 실패했습니다.")

    def _ServerType(self):
        """
        0: 연결 끊김
        1: CybosPlus 서버
        2:HTS 보통 서버(1번 제외)
        """
        value = self.cybos.ServerType
        if value == 0:
            print(f"[서버종류:{value}] 서버와의 연결이 끊겼습니다.")
        elif value == 1:
            print(f"[서버종류:{value}] CybosPlus 서버와의 연결에 성공했습니다.")
        elif value == 2:
            print(f"[서버종류:{value}] HTS 보통 서버와의 연결에 성공했습니다.")

    def _CodeToName(self, code):
        value = self.stockcode.CodeToName(code)
        print(f"[인자값:{code}] 결과값:{value}")

    def _CodeToFullCode(self, code):
        value = self.stockcode.CodeToFullCode(code)
        print(f"[인자값:{code}] 결과값:{value}")

    def _FullCodeToCode(self, fullcode):
        value = self.stockcode.FullCodeToCode(fullcode)
        print(f"[인자값:{fullcode}] 결과값:{value}")

    def _FullCodeToName(self, fullcode):
        value = self.stockcode.FullCodeToName(fullcode)
        print(f"[인자값:{fullcode}] 결과값:{value}")

    def _CodeToIndex(self, code):
        value = self.stockcode.CodeToIndex(code)
        print(f"[인자값:{code}] 결과값:{value}")

    def _GetCount(self):
        value = self.stockcode.GetCount()
        print(f"전체 종목코드 개수:{value}")

    def _GetData(self, type, index):
        """
        종목코드의 Index와 함께 Type을 전달해주면 Type에 해당하는 데이터를 반환함
        :param type: 0은 종목코드, 1은 종목명, 2은 표준코드 체계 하에서의 코드
        :param index:종목코드 인덱스
        :return: 해당 데이터
        """
        value = self.stockcode.GetData(type, index)
        print(f"[Type:{type}, Index:{index}] 결과값:{value}")

    def _TradeInit(self):
        """
        :return: 주문과 관련된 결과값 반환
            -1: 오류 (계좌 비밀번호 오류도 포함함)
             0: 정상
             1: OTP/보안카드 키 입력 잘못됨
             3: 취소
        """
        value = self.trade.TradeInit(0)
        result = ""   ## 지역변수 설정
        if value == -1:
            result = "오류(계좌 비밀번호 오류도 포함함)"
        elif value == 0:
            result = "정상"
        elif value == 1:
            result = "OTP/보안카드 키 입력 잘못됨"
        elif value == 3:
            result = "취소"
        print(f"[주문 오브젝트 초기화 결과] {value}({result})")

    def _AccountNumber(self):
        """
        [Only Read, 읽기 전용 함수]
        :return: 계좌 목록 표기
        """
        value = self.trade.AccountNumber
        print(f"[마스터 계좌 표기] {value}")

    def _GetStockMarginRate(self, code):
        """
        :param code: 종목코드
        :return:     주식 매수 증거금율
        """
        value = self.codemgr.GetStockMarginRate(code)
        print(f"[인자값:{code}] 매수 증거금율:{value}%({type(value)})")

    def _GetStockMarketKind(self, code):
        """
        :param code: 종목코드
        :return:     해당 종목코드의 소속 시장 반환
            0: 구분없음
            1: 거래소
            2: 코스닥
            3: K-OTC
            4: KRX
            5: KONEX
        """
        value = self.codemgr.GetStockMarketKind(code)
        name = ""   ## 지역변수 설정
        if value == 0:
            name = "구분없음"
        elif value == 1:
            name = "거래소"
        elif value == 2:
            name = "코스닥"
        elif value == 3:
            name = "K-OTC"
        elif value == 4:
            name = "KRX"
        elif value == 5:
            name = "KONEX"
        print(f"[인자값:{code}] 소속시장:{value}({name})")

    def _GetStockListByMarket(self, market_kind_code):
        """
        :param market_kind_code: GetStockMarketKind 함수의 인자값 참조
            1: 거래소, 2: 코스닥, 3: K-OTC, 4: KRX, 5: KONEX
        :return                : 시장 구분에 따른 주식 종목 배열
        """
        value = self.codemgr.GetStockListByMarket(market_kind_code)
        print(f"[인자값:{market_kind_code}] 종목코드 목록:{value}")

    def _GetIndustryList(self):
        """
        :return: 증권 전산 업종코드 리스트를 모두 반환
        """
        value = self.codemgr.GetIndustryList()
        print(f"[증권 전산 업종코드 목록] {value}")

    def _GetIndustryName(self, code):
        """
        :param code: 증권 전산 업종코드
        :return    : 증권 전산 업종명
        """
        value = self.codemgr.GetIndustryName(code)
        print(f"[증권 전산 업종코드:{code}] 업종명:{value}")

    def _GetIndustryGroupCodeList(self, code):
        value = self.codemgr.GetIndustryGroupCodeList(code)
        print(f"[증권 전산 업종코드:{code}] 종목목록:{value}")

if __name__ == "__main__":
    cybos()

▶ 실행 결과 확인하기

더보기

[통신결과:1] 서버와의 연결에 성공했습니다.
[서버종류:1] CybosPlus 서버와의 연결에 성공했습니다.
[인자값:005930] 결과값:삼성전자
[인자값:005930] 결과값:KR7005930003
[인자값:KR7005930003] 결과값:A005930
[인자값:KR7005930003] 결과값:삼성전자
[인자값:005930] 결과값:325
전체 종목코드 개수:4225
[Type:0, Index:325] 결과값:A005930
[Type:1, Index:325] 결과값:삼성전자
[Type:2, Index:325] 결과값:KR7005930003
[주문 오브젝트 초기화 결과] 0(정상)
[마스터 계좌 표기] ('333025522',)
[인자값:005930] 매수 증거금율:30%(<class 'int'>)
[인자값:005930] 소속시장:1(거래소)
[인자값:1] 종목코드 목록:('A000020', 'A000040', 'A000050', 'A000070', · · · ·(중략) · · · 'Q760008', 'Q760009')

[증권 전산 업종코드 목록] ('KGG01P', 'KGG01T', 'KGZ01P', · · · (중략) · · ·  'K2V03P', 'K2V04P')
[증권 전산 업종코드:KGS02P] 업종명:섬유,의복
[증권 전산 업종코드:KGS02P] 종목목록:('A001460', 'A001465', 'A383220', · · · (중략) · · · 'A093240', 'A111110')

 

이상으로, 대신증권 CYBOS PLUS에서 국내 주식 거래를 위해 사용되는 네 가지 모듈에 대해 살펴보았다. 대신증권 도움말을 보면 각 모듈 별로 제공되는 여러 가지 함수들에 대해 설명해주고 있으니, 그 내용을 참고하면 자동 매매 프로그램을 구현하는 데에 있어서 필요한 추가적인 기능을 제작하고 직접 사용할 수 있을 것이다. 

 

 


728x90
반응형
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.