AUTO TRADE/[대신증권] CYBOS PLUS

대신증권 CYBOS PLUS 프로그램 구현 (22) - 실시간 데이터 수신받기 ②

프로그램 구현 목표

  • 실시간 등록 개수 확인하기
  • 실시간 해제 기능 구현하기
  • 실시간 등록 목록 변수: 중복 처리 방지하기
  • 전체 종목 실시간 해제하기

 

실시간 등록 개수 확인하기

대신증권 CYBOS PLUS Open API는 기본적으로 400개 종목에 대한 실시간 등록을 지원하고 있다. 또한 이 400개라는 데이터를 따로 확인할 수 있는 기능도 지원하고 있는데, 바로 CpUtil의 CpCybos에서 사용할 수 있는 `GetLimitRemainCount`함수이다. 이 함수는 기본적으로 3개의 데이터를 반환해주는데 그 목록은 아래와 같다.
※ 아래 이미지의 잔여 요청 횟수 부분 아래에 있는 주문 RQ, 시세 RQ, 시세 구독이라는 세 가지 부분에 대응하는 내용이다.

  • Index 0(LT_TRADE_REQUEST): 주문 및 계좌와 관련된 요청 개수
  • Index 1(LT_NONTRADE_REQUEST): 시세와 관련된 요청 개수
  • Index 2(LT_SUBSCRIBE): 시세 관련 구독 건수

이 기능을 구현한 후에는 크게 ① 실시간 등록이나 해제가 이루어졌을 때마다 함수를 호출해서 실시간으로 수신받을 수 있는 종목의 개수를 업데이트하거나 ② 별도의 쓰레드(Thread)를 생성하여 1초(또는 지정 시간마다)마다 계속해서 함수를 호출해서 그 개수를 업데이트하는 방식으로 구현할 수 있다. 두 번째 방법도 나쁜 방법은 아니지만, 실제로 서버로 실시간 데이터를 요청할 수 있는지 없는지의 여부는 시세 구독 관련 건수가 0건이 아닐 때만 구현할 수 있기 때문에 본인의 경우에는 첫 번째 방법(실시간 데이터를 구독하거나 해제할 때마다)으로 잔여 구독 개수 데이터를 획득해볼 것이다. 일단 CpUtil.py 파일을 열어서 `GetLimitRemainCount` 함수를 구현해보자.
※ Line: 7 ~ 15

class CpCybos:
    def __init__(self):
        self.cybos = win32com.client.Dispatch("CpUtil.CpCybos")           ## COM 연결
        self.handlers = win32com.client.WithEvents(self.cybos, event_handler_CpUtil)
        self.handlers.set_instance(self.cybos, "CpCybos")

    def _GetLimitRemainCount(self, Type):
        """
        Type에 대한 조회 제한이 이루어지기까지 남은 요청 개수를 반환
        LT_TRADE_REQUEST = 0, 주문 및 계좌 관련 RQ요청
        LT_NONTRADE_REQUEST = 1, 시세 관련 RQ요청
        LT_SUBSCRIBE = 2, 시세 관련 구독 건수
        """
        value = self.cybos.GetLimitRemainCount(Type)
        return value

그 후에 다시 Boss.py 파일로 돌아와서, 실시간 데이터를 요청하는 함수에서 `_GetLimitRemainCount()` 함수에 "2"라는 데이터를 전달하여 결과값을 확인해보도록 하자.
※ Line: 3, 4

## Boss.py ##
    def _RealReceive(self):
        value = CpUtil.CpCybos()._GetLimitRemainCount(2)
        print(value)
        item_code = self.lineEdit_13.text()
        DsCbo1.StockCur()._StockCur(item_code)

▶ 실행 결과 확인하기(400개 종목에 대해 요청할 수 있음을 반환해주고 있다.)

이제 DsCbo1.py 파일로 돌아가서, 실시간 데이터를 요청하는 실질적인 함수에서 이 400이라는 데이터를 받아올 수 있도록 파라미터를 하나 더 생성해주도록 하자. 그리고 이 인자를 전달받은 후에는 조건문을 사용하여 이 인자의 값이 0보다 클 때(1 이상일 때)에만 실시간 데이터를 수신받을 종목으로 등록하도록 하는 기능을 추가해주도록 하자.
※ Line: 10, 11

## DsCbo1.py ##
import win32com.client

class StockCur:
    def __init__(self):
        self.stockcur = win32com.client.Dispatch("DsCbo1.StockCur")         ## COM 연결
        self.handler = win32com.client.WithEvents(self.stockcur, event_handler)

    def _StockCur(self, item_code, remain_count):
        print(f"실시간으로 구독할 수 있는 잔여 종목 개수:{remain_count}")
        if remain_count > 0:
            self.stockcur.SetInputValue(0, item_code)
            self.handler.set_instance(self.stockcur, "StockCur")
            self.stockcur.Subscribe()
            print(f"실시간 데이터를 수신합니다. ({item_code})")

다시 Boss.py 파일로 돌아와서, 실시간 데이터를 요청하는 함수를 호출할 때 잔여 종목 개수(`value`)를 이 함수의 인자로 전달해주도록 하자. 그 후에 프로그램을 실행시켜서 A005930 종목과 A000660 종목을 실시간 데이터를 수신받을 종목으로 등록해보자.
※Line: 5

## Boss.py ##
    def _RealReceive(self):
        value = CpUtil.CpCybos()._GetLimitRemainCount(2)
        item_code = self.lineEdit_13.text()
        DsCbo1.StockCur()._StockCur(item_code, value)

▶ 실행 결과 확인하기(조회할 때마다 등록할 수 있는 잔여 종목 개수의 값이 1씩 감소하는 것을 확인할 수 있다.)

더보기

실시간으로 구독할 수 있는 잔여 종목 개수:400
self.client:<win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x118807504>
self.object:StockCur
실시간 데이터를 수신합니다. (A005930)
실시간으로 구독할 수 있는 잔여 종목 개수:399
self.client:<win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x16908880>
self.object:StockCur
실시간 데이터를 수신합니다. (A000660)

 

 

실시간 해제 기능 구현하기

특정 종목을 실시간으로 등록하는 기능을 구현했다면 그 종목의 실시간 데이터 수신을 중지하는 기능도 구현해주어야 한다. 어떻게 보면 이는 당연히 존재해야 하는 기능이다. 다시 GUI 파일을 열어서 실시간 해제 등록 버튼을 만들어주도록 하자. GUI 파일에서 만든 이 실시간 해제 버튼의 객체명은 `pushButton_6`이다.

버튼을 생성했다면 이제 생성할 기능은 실시간으로 등록되어 있는 종목에 대한 데이터 수신을 중단하는 것인데, 이 기능을 담당하는 함수는 Subscribe와 반대의 의미를 가진 영단어인 `Unsubscribe()`함수이다. 하지만 실시간 해제 기능을 구현할 때 주의해야 하는 부분이 하나 있다. 바로 실시간 데이터를 수신하도록 `Subscribe()` 함수를 사용했을 때 사용했던 `self.stockcur`의 인스턴스 주소가 있을 것인데, 이 주소를 가지고 데이터를 처리해야 한다는 것이다. 무슨 내용인지 이해가 가지 않는다면 아래와 같이 `print()` 구문을 활용하여 인스턴스의 주소를 확인해보자. 

## DsCbo1.py ##
import win32com.client

class StockCur:
    def __init__(self):
        self.stockcur = win32com.client.Dispatch("DsCbo1.StockCur")         ## COM 연결
        self.handler = win32com.client.WithEvents(self.stockcur, event_handler)
        print(f"self.stockcur 인스턴스 주소:{self.stockcur}")

▶ 실행 결과 확인하기(인스턴스 주소는 종목 코드를 조회할 때마다 다른 주소가 생성됨)

더보기

self.stockcur 인스턴스 주소:<win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x113629424>

위의 실행 결과 확인하기 부분을 열어서 보면 현재 실시간 데이터를 요청한 종목의 실시간 데이터를 반환해주는 인스턴스의 주소는 0x113629424라는 것을 확인할 수 있다. 즉, 이 주소에서 우리가 요청한 종목코드의 실시간 데이터를 반환해준다는 것을 의미한다. 따라서 우리는 실시간 해제 기능을 구현할 때에도 이 주소를 활용하여 `Unsubscribe()` 기능을 구현해주어야 한다. 즉, 이 함수는 종목코드만 전달받아서는 제 기능을 다 할 수 없다는 것이다. 다시 말해, 종목의 실시간 해제 처리를 하기 위해서는 `0x113629424.Unsubscribe()`와 같은 방식으로 작성해야 한다. 그렇다면 특정 종목 별로 실시간 데이터를 처리하는 기능이 담긴 인스턴스의 주소는 무엇인지에 대한 정보를 종목별로 하나씩 관리해주어야 한다. 일단 실시간 데이터를 요청하는 함수(`_StockCur`)에서 이 인스턴스 주소(`0x113629424`)를 `return`하도록 하여 Boss.py 파일에서 얻어와보도록 하자.
※ Line: 16

## DsCbo1.py ##
import win32com.client

class StockCur:
    def __init__(self):
        self.stockcur = win32com.client.Dispatch("DsCbo1.StockCur")         ## COM 연결
        self.handler = win32com.client.WithEvents(self.stockcur, event_handler)
        print(f"self.stockcur 인스턴스 주소:{self.stockcur}")

    def _StockCur(self, item_code, remain_count):
        if remain_count > 0:
            self.stockcur.SetInputValue(0, item_code)
            self.handler.set_instance(self.stockcur, "StockCur")
            self.stockcur.Subscribe()
            print(f"실시간 데이터를 수신합니다. ({item_code})")
            return self.stockcur

이제 다시 Boss.py 파일로 돌아와서, `초기화 함수` 내부에서는 실시간으로 등록되어 있는 종목들의 인스턴스 주소를 저장할 변수(`self.instance_subscribe`)를 튜플 형태로 새롭게 생성(line: 8)해준 후에, 앞서 `return` 함수를 통해 반환해주었던 인스턴스 값을 얻어온 후 print() 구문을 통해 주소를 확인해보도록 하자.
※ Line: 8, 22, 23

## Boss.py ##
( 생 략 )
class cybos(QMainWindow, main_ui):
    def __init__(self):
        ( 생 략 )
        
        ## 실시간 데이터 관리 목적
        self.instance_subscribe = {}

        ## GUI 관련 이벤트 처리 ##
        self.pushButton.clicked.connect(self._GetStockListByMarket)
        self.pushButton_2.clicked.connect(self._day_range)
        self.pushButton_3.clicked.connect(self._len_chart)
        self.comboBox_2.currentIndexChanged.connect(lambda: qt_gui.etc(self).comboBox_2_CIC())
        self.pushButton_4.clicked.connect(self._save_all_chart)
        self.pushButton_5.clicked.connect(self._RealReceive)
        self.pushButton_6.clicked.connect(self._Unsubscribe)

    def _RealReceive(self):
        value = CpUtil.CpCybos()._GetLimitRemainCount(2)
        item_code = self.lineEdit_13.text()
        instance_link = DsCbo1.StockCur()._StockCur(item_code, value)
        print(instance_link)

▶ 실행 결과 확인하기(인스턴스 주소가 정상적으로 반환되고 있음 / ※ 인스턴스 주소는 조회 시마다 달라짐)

더보기

self.stockcur 인스턴스 주소:<win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x119456528>(DsCbo1.py)
실시간 데이터를 수신합니다. (A005930)
<win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x119456528> (Boss.py)

그렇다면 이제 아래와 같은 구문을 추가하여 앞서 생성했던 `self.instance_subscribe` 변수에 우리가 실시간으로 등록했던 종목코드와 함께 이 인스턴스 주소를 저장해주자. 마지막으로 프린트 구문을 통해 그 데이터를 확인해보도록 하자.
※ Line: 6, 7

## Boss.py ##
    def _RealReceive(self):
        value = CpUtil.CpCybos()._GetLimitRemainCount(2)
        item_code = self.lineEdit_13.text()
        instance_link = DsCbo1.StockCur()._StockCur(item_code, value)
        self.instance_subscribe[item_code] = instance_link
        print(self.instance_subscribe)

▶ 실행 결과 확인하기

더보기

self.stockcur 인스턴스 주소:<win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x122276528>
self.client:<win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x122276528>
self.object:StockCur
실시간 데이터를 수신합니다. (A005930)
{'A005930': <win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x122276528>}

여기까지 잘 따라왔다면 이제 실시간 해제 함수를 생성하여 이 인스턴스 주소를 전달해준 후 `Unsubscribe()` 함수를 사용해주기만 하면, 실시간 해제 기능은 모두 구현되는 것이다. 다시 DsCbo1.py 파일로 돌아가서 실시간 해제 함수를 생성해보자.

실시간 해제 기능을 담당할 함수의 이름은 `_Unsubscribe()`로 하도록 하고, 다만 이 함수의 인자로 `obejct`라는 파라미터를 추가하여 우리가 앞서 계속해서 확인했던 인스턴스 주소(`0x122276528`과 같은 형태)를 전달받은 후 그 인스턴스 주소의 뒤에 `Unsubscribe()` 함수를 사용하여 실시간 등록을 해제해주면 된다.
※ Line: 18 ~ 20

## DsCbo1.py ##
import win32com.client

class StockCur:
    def __init__(self):
        self.stockcur = win32com.client.Dispatch("DsCbo1.StockCur")         ## COM 연결
        self.handler = win32com.client.WithEvents(self.stockcur, event_handler)
        print(f"self.stockcur 인스턴스 주소:{self.stockcur}")

    def _StockCur(self, item_code, remain_count):
        if remain_count > 0:
            self.stockcur.SetInputValue(0, item_code)
            self.handler.set_instance(self.stockcur, "StockCur")
            self.stockcur.Subscribe()
            print(f"실시간 데이터를 수신합니다. ({item_code})")
            return self.stockcur

    def _Unsubscribe(self, object):
        object.Unsubscribe()
        print(f"실시간 데이터 수신을 중지했습니다.")

다시 Boss.py 파일로 돌아와서, 이 파일에서도 실시간 해제를 담당할 함수(`def _Unsubscribe()`)를 생성해준 후에 이 함수가 호출되는 즉시 우리가 이전에 실시간으로 등록되어 있는 종목들과 그 종목별로 할당되어 있는 인스턴스 주소를 저장했던 변수(`self.instance_subscribe`)를 출력하도록 해보자. 그 후에 프로그램을 실행시켜서 확인해보아야 하니, 앞서 생성해주었던 버튼과 이 함수를 연결해주도록 하자. 마지막으로, 삼성전자('A005930') 종목에 대한 실시간 등록 버튼을 누른 후에 곧바로 실시간 해제 버튼을 클릭하여 우리가 확인하고자 하는 변수를 출력해보자.
※ Line: 5, 14~16

## Boss.py ##
class cybos(QMainWindow, main_ui):
    def __init__(self):
        self.pushButton_5.clicked.connect(self._RealReceive)
        self.pushButton_6.clicked.connect(self._Unsubscribe)

    def _RealReceive(self):
        value = CpUtil.CpCybos()._GetLimitRemainCount(2)
        item_code = self.lineEdit_13.text()
        instance_link = DsCbo1.StockCur()._StockCur(item_code, value)
        self.instance_subscribe[item_code] = instance_link
        print(self.instance_subscribe)

    def _Unsubscribe(self):
        print("_Unsubscribe 아래 변수 확인")
        print(self.instance_subscribe)

▶ 실행 결과 확인하기(실시간 등록 후 해제 버튼 클릭해보기)

더보기

self.stockcur 인스턴스 주소:<win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x121074160>
self.client:<win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x121074160>
self.object:StockCur
실시간 데이터를 수신합니다. (A005930)
{'A005930': <win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x121074160>}
_Unsubscribe 아래 변수 확인
{'A005930': <win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x121074160>}

이제 우리는 이 주소를 DsCbo1.py 파일의 실시간 해제 함수로 전달한 후, 그 경로에 대하여 `Unsubscribe()` 함수를 적용해주기만 하면 실시간 해제가 이루어지게 된다. 여기서 실시간 해제를 처리하는 함수를 수행한 이후에는 실시간 등록 목록이 담겨 있는 변수(`self.instance_subscribe`)에서 기존에 추가해두었던 종목코드와 관련된 정보를 삭제(`del` 메서드 활용)해주어야 한다. 왜냐하면 실시간 해제만 처리해놓고 변수 내에서 종목과 관련된 정보는 삭제하지 않는다면 실시간 등록은 해제되어 있지만 변수 상에서는 아직 실시간 데이터를 수신받고 있는 것처럼 오인하는 오류가 발생하기 때문이다.
※ Line: 3~6

## Boss.py ##
    def _Unsubscribe(self):
        item_code = self.lineEdit_13.text()
        print(self.instance_subscribe[item_code])
        DsCbo1.StockCur()._Unsubscribe(self.instance_subscribe[item_code])
        del self.instance_subscribe[item_code]

▶ 실행 결과 확인하기

더보기

self.stockcur 인스턴스 주소:<win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x122864048>
self.client:<win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x122864048>
self.object:StockCur
실시간 데이터를 수신합니다. (A005930)
{'A005930': <win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x122864048>}
<win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x122864048>
self.stockcur 인스턴스 주소: <win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x122864048>
실시간 데이터 수신을 중지했습니다.

 


반응형
728x90

 

실시간 등록 목록 변수: 중복 처리 방지하기

실시간 등록 목록이라 하여 뭔가 어렵게 생각할 건 없다. 우리는 이미 실시간 등록 목록을 `self.instance_subscribe`라는 변수 안에 모두 저장하도록 기능을 만들어두었기 떄문이다. 그렇다면 시스템 안정성을 확보하는 것은 무엇을 의미하는 것일까 ? 일단 프로그램을 실행시켜서 종목코드 란에 삼성전자의 종목코드를 넣고 실시간 등록 버튼을 두 번 클릭해보자. 어떠한 현상이 발생할까 ?

## 똑같은 종목에 대하여 두 번 실시간 등록을 해보았다.
{'A005930': <win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x118142128>}
{'A005930': <win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x118144976>}

바로 두 개의 인스턴스 주소가 생성되지만, 기존에 획득했던 인스턴스 주소인 0x118142128은 0x118144976에 덮어쓰기되어 그 데이터를 어디서도 찾을 수 없게끔 사라져버린다. 다시 말해, 이미 실시간으로 등록되어 있는 종목에 대해서는 다시 실시간 등록 요청을 하더라도 등록으로 처리하지 않고 이미 등록되어 있으므로 등록하는 절차를 넘겨야 한다는 것이다. 이 기능을 구현하려면 어떻게 해야 할까 ? 아래의 코드를 확인해보자.

단순하게 4번째 줄과 같은 조건문을 추가하여 `item_code` 데이터가 이미 `self.instance_subscribe` 변수 안에 저장되어 있지 않은 경우에만 실시간 데이터를 수신할 종목으로 추가하고, 그 외의 경우에는 이미 실시간 데이터를 수신 중이기 때문에 아무런 작업을 처리하지 않으면 된다. 아래와 같이 코드를 구현한 후, 똑같이 프로그램을 실행시켜서 동일한 종목 코드를 넣고 실시간 등록 버튼을 두 번 눌러보자.
※ Line: 4, 8~10

## Boss.py ##
    def _RealReceive(self):
        item_code = self.lineEdit_13.text()
        if not item_code in self.instance_subscribe:
            value = CpUtil.CpCybos()._GetLimitRemainCount(2)
            instance_link = DsCbo1.StockCur()._StockCur(item_code, value)
            self.instance_subscribe[item_code] = instance_link
        else:
            print(f"이미 실시간 데이터를 수신 중인 종목입니다. {item_code}")
            print(self.instance_subscribe)

▶ 실행 결과 확인하기(실시간 등록 버튼을 두 번 눌러보자)

더보기

self.stockcur 인스턴스 주소:<win32cohttp://m.gen_py.CpDib 1.0 Type Library.IDib instance at 0x114078800>
실시간 데이터를 수신합니다. (A005930)
이미 실시간 데이터를 수신 중인 종목입니다. A005930
{'A005930': <win32cohttp://m.gen_py.CpDib 1.0 Type Library.IDib instance at 0x114078800>}

다음으로 실시간 해제 함수의 경우에도 마찬가지로 이미 실시간 데이터를 수신 중인 종목인지 아닌지에 대한 검증이 필요하다. 실제로 프로그램을 실행시켜서 실시간 등록을 하지 않고 바로 실시간 해제 버튼을 누르면 아래와 같은 오류를 확인할 수 있다.

## 실시간 등록을 하지 않고 해제만 누를 경우
Traceback (most recent call last):
  File "Boss.py", line 65, in _Unsubscribe
    print(self.instance_subscribe[item_code])
KeyError: 'A005930'

이 오류는 간단하게 해석하면 `self.instance_subscribe` 변수 안에 'A005930'이라는 데이터가 없다는 것으로 해석할 수 있다. 즉, 실시간 등록이 되지 않아 실시간 등록 목록 변수(`self.instance_subscribe`)에 종목코드가 입력되지 않았다는 것이다. 따라서 이러한 오류가 발생할 수 있으니 조건문을 통해 실시간으로 등록되어 있는 경우에만 실시간 해제 기능을 처리하도록 코드를 수정해보자.

## Boss.py ##
    def _Unsubscribe(self):
        item_code = self.lineEdit_13.text()
        if item_code in self.instance_subscribe:
            print(self.instance_subscribe[item_code])
            DsCbo1.StockCur()._Unsubscribe(self.instance_subscribe[item_code])
        else:
            print(f"실시간 데이터를 수신하지 않고 있는 종목입니다. {item_code}")
            print(self.instance_subscribe)

▶ 실행 결과 확인하기(실시간 등록을 하지 않고 해제만 클릭했을 때)

더보기

실시간 데이터를 수신하지 않고 있는 종목입니다. A005930
{}

 

 

전체 종목 실시간 해제하기

대신증권 Open API에 실시간 데이터를 수신받도록 등록되어 있는 모든 종목에 대해 실시간 데이터 수신을 중지하는 기능을 구현해보자. 물론 장 마감과 함께 프로그램이 종료된다면 실시간으로 등록되었던 종목들의 이력은 모두 삭제되고 초기화된 상태로 시작하게 되므로 사실상 문제는 없지만, 이 기능이 필요한 이유는 장 중에 다른 데이터를 요청해서 전달받아야 할 때 발생할 오류를 사전에 방지해주어야 하기 때문이다. 즉, 장중에 차트 데이터를 요청한다거나 할 경우에는 실시간 데이터를 수신받는 걸 잠깐 중지해두었다가 차트 데이터를 모두 수신받은 후에 다시 요청하는 작업을 진행시켜야 한다는 것이다. 이 기능을 수행할 수 있는 버튼을 GUI 파일을 열어서 생성해준 후, 다시 Boss.py 파일에서 함수를 만들어보자. 

나의 경우 이 [실시간 초기화] 버튼이 GUI 내에서 갖는 객체 이름은 `pushButton_7`이니 이 점을 참고하여 코드를 읽으면 도움이 될 것이다.(버튼을 만들었다가 삭제했거나 했을 때 객체 이름이 자동적으로 생성되기 때문에 뒤에 따라오는 번호가 다를 수 있다. 따라서 본인의 GUI 파일에 있는 객체 이름을 참조하도록 하자.) 

일단 Boss.py 파일에서 전체 종목에 대한 실시간 등록을 해제하는 기능을 담당할 함수(`def _Unsubscribe_ALL()`)를 생성해주자. 그 후에는 이 함수를 활용하여 현재 실시간으로 등록되어 있는 종목에 대해 실시간 해제를 하는 작업을 거쳐야 하는데, 현재 실시간으로 등록되어 있는 종목의 경우에는 `self.instance_subscribe` 변수 안에 모두 저장되어 있으므로 우리는 앞서 만들어주었던 실시간 해제 함수와 동일한 로직에 따라 동작하도록 코드를 만들어주면 된다. 다만 두 가지 유의할 점이 있는데, 첫 번째로 유의할 점은 현재 실시간으로 등록되어 있는 종목이 없을 때(`self.instance_subscribe` 변수의 데이터 개수가 0개일 때)는 조건문을 통해 별도의 작업을 처리하지 않도록 해야 한다는 것이고, 두 번째로 유의해야 할 점은 실시간 등록 목록 변수의 데이터 타입을 보면 딕셔너리(dictionary) 형태의 데이터인데, 이 데이터에 대해 반복문을 사용하기 위해서는 `copy()` 함수를 사용하여 복사본을 대상으로 반복문을 돌도록 해야 한다는 것이다(자세한 내용은 이 게시글을 참조). 이후에는 반복문(`for` 문)을 통해 실시간 등록 목록 변수에 있는 종목코드를 하나씩 가져다가 실시간 해제 처리를 해주면 된다. 여기까지의 내용을 코드로 만들면 아래의 같다.

## Boss.py ##
    def _Unsubscribe_ALL(self):
        if len(self.instance_subscribe) > 0:
            for i in self.instance_subscribe.copy():
                print(i)
        else:
            print(f"실시간으로 등록되어 있는 종목이 없습니다.")

▶ 실행 결과 확인하기(A005930, A000660, A000020 종목을 순서대로 실시간 등록한 후, 실시간 초기화 버튼을 클릭)

더보기

self.stockcur 인스턴스 주소:<win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x884797552>
self.client: <win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x884797552>
self.object:StockCur
실시간 데이터를 수신합니다. (A005930)
A005930
self.stockcur 인스턴스 주소:<win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x910406864>
self.client:<win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x910406864>
self.object:StockCur
실시간 데이터를 수신합니다. (A000660)
self.stockcur 인스턴스 주소: <win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x910475792>
self.client: <win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x910475792>
self.object:StockCur
실시간 데이터를 수신합니다. (A000020)
A005930
A000660
A000020

이제 반복문 안에 있는 `i` 변수에는 종목코드가 들어있다는 걸 확인했으니, 이 종목코드에 할당되어 있는 인스턴스 주소를 획득하여 실시간 해제 함수에 전달해주도록 하자. 그 후에는 `del` 메서드를 활용하여 실시간 등록이 해제된 종목 코드를 가지고 실시간 등록 목록 변수에 있는 종목코드 데이터를 삭제해준 후 실시간 등록 목록 변수를 출력하도록 해보자.

    def _Unsubscribe_ALL(self):
        if len(self.instance_subscribe) > 0:
            for i in self.instance_subscribe.copy():
                DsCbo1.StockCur()._Unsubscribe(self.instance_subscribe[i])
                del self.instance_subscribe[i]
                print("self.instance_subscribe")
                print(self.instance_subscribe)
        else:
            print(f"실시간으로 등록되어 있는 종목이 없습니다.")

▶ 실행 결과 확인하기(A005930, A000660, A000020 종목을 순서대로 실시간 등록한 후, 실시간 초기화 버튼을 클릭)

더보기

self.client:<win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x164535088>
self.object:StockCur
실시간 데이터를 수신합니다. (A005930)
self.client: <win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x164091248>
self.object:StockCur
실시간 데이터를 수신합니다. (A000660)
self.client: <win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x164168368>
self.object:StockCur
실시간 데이터를 수신합니다. (A000020)
{'A005930': <win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x164535088>, 'A000660': <win32com.gen_py.CpDib  1.0 Type Library.IDib instance at 0x164091248>, 'A000020': <win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x164168368>}
[A005930] 실시간 등록을 해제합니다.
<win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x164535088 >    ## A005930 종목의 인스턴스 주소
실시간 데이터 수신을 중지했습니다.
self.instance_subscribe
{'A000660': <win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x164091248>, 'A000020': <win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x164168368>}
[A000660] 실시간 등록을 해제합니다.
<win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x164091248>     ## A000660 종목의 인스턴스 주소
실시간 데이터 수신을 중지했습니다.
self.instance_subscribe
{'A000020': <win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x164168368>} 
[A000020] 실시간 등록을 해제합니다.
<win32com.gen_py.CpDib 1.0 Type Library.IDib instance at 0x164168368 >   ## A000020 종목의 인스턴스 주소
실시간 데이터 수신을 중지했습니다.
self.instance_subscribe
{}

 

 


728x90
반응형
Contents

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

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