PYTHON/AUTO TRADE SYSTEM

[자동 매매 시스템 구축하기] 실시간 해제하기 (2) - tableWidget 업데이트

  • -

지난 게시글에서는 실시간 해제와 함께   self.setrealreg  변수를 업데이트하는 기능을 구현했으니, 이번 게시글에서는 tableWidget 내에서 데이터를 삭제하는 방법에 대해 살펴볼 예정이다.

 

 

tableWidget은 어떻게 삭제하나? Method : removeRow()  

사실 self.setrealreg 변수 내에서 데이터를 삭제하는 건 간단했지만, tableWidget을 수정하는 것은 별도의 게시글로 분리한 이유가 있다. 바로 데이터프레임 내에서 데이터를 삭제하는 것처럼 간단하지가 않기 때문이다. 아니, 간단하지 않다기 보다는 코드는 간단하지만, 그 개념을 이해하는 것이 조금 어려울 수도 있다. (쉽게 느껴진다면 다행이다.)

일단 tableWidget 객체에서 특정 데이터를 삭제하는 메서드는   .removeRow()  이다. 이 때 괄호 안에는 데이터 열의 번호를 함꼐 전달해줘야 하는데, 이 번호는 예전에 실시간 등록 기능을 구현하는 게시글에서 self.setrealreg의 인덱스 값과 동일하다는 설명을 했었다. 즉, tableWidget과 self.setrealreg 변수는 데이터와 인덱스 정보가 함께 움직이는 것이다. tableiWdget은 곧 self.setrealreg의 정보를 시각화해주는 수단일 뿐이라고 볼 수도 있지만 어떻게 보면 self.setrealreg가 tableWidget의 기능을 뒤에서 보조하고 있는 것이기도 하다. 말이 길어졌는데, 코드부터 작성해보도록 하자. 아주 간단하다.
※ Line : 5

    """실시간 해제 함수"""
    def __setrealremove(self, scrno, item_code):
        idx = self.setrealreg.index[self.setrealreg['item_code'] == item_code].item()
        self.setrealreg = self.setrealreg.drop(index=idx).reset_index(drop=True)
        self.tableWidget.removeRow(idx)
        return self.kiwoom.dynamicCall("SetRealRemove(QString, QString)", [scrno, item_code])

 

우리가 이전에   self.setrealreg   변수 내에서 특정 종목의 데이터 열을 삭제하기 위해 해당 데이터가 변수 내에서 위치한 열의 번호인 인덱스 값(idx)을 얻어다가 삭제했는데, 그 값이 tableWIdget 내에서도 동일한 종목의 데이터 번호를 지칭하는 인덱스 번호이기에 별 다른 작업 없이 단순하게   .removeRow()   안에 인덱스 번호를 전달해줌으로써 데이터를 삭제할 수 있는 것이다.

첨언하자면, tableWidget의 경우에는 removeRow() 메서드를 사용하게 되면 데이터프레임과는 달리 열의 번호가 자동적으로 새롭게 정렬되기 때문에 데이터프레임에서 사용했던   .reset_index(drop=True)  와 같은 기능을 수행하는 메서드를 사용할 필요가 없다. 

 

 


728x90

 

 

잠시만요, 아직 안 끝났어요.

우리는 실시간 해제 시에 반드시 눈 여겨봐야 하는 것이 있다. 바로 코드의 순서인데, 이 코드의 순서를 왜 살펴봐야 하는지에 대해 생각해봐야 한다. 예전에 실시간 데이터가 발생하는 동시에 tableWIdget에 데이터를 입력하도록 하는 기능을 구현하는 게시글 내에서   ValueError  와   UnboundLocalError  라는 두 가지 오류를 처리해줬던 것이 기억나는가?

그 오류를 처리하면서 오류를 처리해야 하는 이유를 설명했는데, 가장 주된 이유는 차트 데이터 조회 등을 이유로 실시간 등록이 이루어졌으나,   self.setrealreg  변수와 tableWidget 내에는 종목코드가 추가되지 않아 데이터를 입력할 공간이 없음에도 실시간 데이터가 발생하는 경우가 있다고 설명했다. 예전에는 이러한 오류가 어떻게 발생하는지 이해를 못했을 수도 있지만, 실시간 해제를 하는 과정에서 데이터가 발생하게 되면 어떤 일들이 벌어지는지 어렵지 않게 확인할 수 있다.

아래의 사진은 실시간 해제 함수의 전체 코드이고, 한 줄 한 줄 사이에 위치한 원숫자는 코드가 진행되는 과정에서 실시간 데이터가 발생하는 시점이다. ①번 시점과 ②번 시점, ③번 시점에서 실시간 데이터가 발생할 때 각각 어떤 문제가 발생할 수 있는지 살펴보도록 하자.  

 

현재 self.setrealreg 변수와 tableWIdget의 상태는 아래의 이미지와 같은 상태라고 가정하고, 실시간으로 등록되어 있는 세 개의 종목 중 "000020" 종목에 대한 실시간을 해제한다고 가정하고 한 단계씩 그 변화를 살펴보도록 하자.

 

 

①번 시점 : idx 조회 이후

①번 시점에서는 딱히 문제가 될 만한 부분은 없다. 왜냐하면 오류가 발생하기 위해서는 반드시 self.setrealreg와 tableWidget 간에 불일치가 일어나야 하기 때문이다.

 

②번 시점 : drop(index=idx) 이후

해당 시점에서는 idx 데이터를 얻어다가 self.setrealreg 내에서는 해당 종목 코드에 대한 데이터를 삭제했지만 tableWidget 내에는 아직 종목코드 데이터를 입력할 공간이 남아 있는 상태로, 충분히 오류가 발생할 수 있다. 아래의 사진을 참고해보자.

"000020" 종목에 대한 실시간 등록은 ON 상태이기 때문에 실시간 데이터는 계속해서 발생하고 있는 상황이지만, self.setrealreg 변수 내에는 이미 종목코드가 삭제된 상태이기 때문에 "000020" 종목코드의 인덱스 번호를 얻어올 수 없다. self.setrealreg 내 종목코드의 인덱스 번호는 우리가 실시간 데이터를 tableWidget 내에 입력할 때 불러왔던 데이터이기 때문에, 실시간 데이터가 발생하는 상황에서 self.setrealreg 변수로부터 해당 종목코드의 인덱스 번호를 불러올 수 없는 경우 ValueError가 발생한다.

 

③번 시점 : removeRow(idx) 이후

3번 시점에서는 self.setrealreg 변수외 tableWidget 간의 데이터가 모두 일치하는 상황이 되었다. 하지만 어떤 오류가 발생할까? 바로 우리는 모든 지점에서 "000020" 종목에 대한 데이터는 모든 흔적을 지웠지만 여전히 서버에는 실시간으로 등록되어 있는 상태이기 때문에 실시간 주식 시세 데이터를 우리에게 전달하게 되면서 우리에게 있어서는 "000020" 종목에 대한 데이터를 처리할 수 있는 방법이 없어지는 오류가 발생하는 것이다. 이 때에는 UnboundLocalError가 발생하게 된다.

 

마지막으로, ③번 시점 아래의   return  뒤의 실시간 해제 코드가 수행되면 "000020" 종목에 대한 실시간 등록이 해제됨에 따라 아래와 같이 self.setrealreg 변수와 tableWidget이 일치하고 실시간 데이터가 발생하지 않는 상태가 되면서 프로그램은 안정적으로 작동할 것이다.

 

 

이처럼 하나의 기능에 엮여 있는 모든 데이터와 변수들을 함께 관리해줘야만 오류 없는 데이터 처리가 가능하다. 앞서 살펴봤던 내용들은 항상 오류가 발생하는 것은 아니다. 반드시 ②번과 ③번 지점의 코드를 수행하고 있을 때, 서버로부터 실시간 데이터를 전달받게 되어야만 오류가 발생하기 때문이다. 따라서 운좋게 단 한 번도 오류가 없었을 수도 있지만, 앞으로도 오류가 없을 거라는 보장은 할 수 없다. 

이번 게시글에서 살펴본 실시간 해제 중 발생하는 오류는 실시간으로 등록되어 있는 종목의 수가 많을수록 서버로부터 발생하는 실시간 데이터도 많아지기 때문에 오류가 발생할 가능성은 기하급수적으로 상승한다. 따라서 오류를 만드시 처리해줘야만 내가 직접 프로그램을 살피고 있지 않을때, 부재중일 때, 문제 없이 동작할 수 있다. 명색이 자동 매매 시스템인데 내가 모니터링을 해줘야 하는 친구다? 이건 앞뒤가 안 맞는다.

 

 


728x90
반응형
Contents

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

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