예스트레이더, 메타트레이더가 아닌 시중에 자동매매 프로그램이라고 판매 중인 증권사 API 기반의 프로그램들은 사용자가 직접 코딩을 할 수 없는 대신 HTS에서 사전에 설정한 조건검색을 기반으로 매수/매도를 하도록 되어 있습니다.
그만큼 API를 이용한 자동매매에는 조건검색 기능이 가장 핵심입니다.
이번 포스팅에서는 이베스트증권의 xingAPI를 활용하여 조건검색을 하는 방법을 알아보겠습니다.
1. xingAPI의 조건검색 TR T1857 사용전 알아야 할 점
키움증권 API는 실시간 종목검색을 5개까지 등록가능하고, OnMsg()에 조건명을 파라미터로 넘겨주기 때문에
어떤 조건에 의한 종목인지 처리하기가 쉽습니다.
하지만 이베스트투자증권 xingAPI는 실시간 종목검색을 2개까지 등록가능하고(작성일 기준)
키움증권 API보다 사용하기 어렵습니다.
아래의 TR 속성만 봐서는 일반 TR과의 차이점을 찾아볼 수 없습니다만,
T1857은 TR이긴 하지만 다른 TR들과 다르게 부가서비스로 별도 분류됩니다.
그래서 일단 TR 호출시 사용하는 Request()가 아닌 RequestService()로 호출해야 하는데 이베스트에서 제공하는 설명서만 보고 개발하다 보면 헤매게 되는 부분이 2020.11.29. 기준으로 몇 개 있어서 이 부분 먼저 설명드립니다.
1.1 RequestService() 내의 WM_USER 값 하드코딩
xingAPI에서는 아래와 같이 9개의 MSG를 사용하는데 원래는 WM_USER 보다 큰 값이면 아무 값이나 BASE 값으로 설정할 수 있습니다. BASE값은 초기 서버 연결 단계에서 Connect()함수 호출 시 파라미터로 넘겨주게 되는데, RequestService() 내부에서는 그 값을 무시하고 윈도 기본 WM_USER값을 사용합니다. 그래서 다른 값으로 MSG BASE를 설정하셨으면 WM_USER로 바꾸셔야 응답을 받으실 수 있는데 이 내용은 2년 전부터 있던 내용인데 언급이 없어서 기본 코드값이 아닌 임의의 값으로 변경하면 응답 메시지를 못 받습니다.
1.2 Worker thread에서 RequestService() 호출시 응답 MSG 받지 못함
MFC에서 DLL을 이용하여 멀티스레드 프로그램을 개발하면 스레드를 UI thread 또는 Worker thread 중 적절한 thread 타입을 선택하게 됩니다. RequestService()를 Worker thread에서 호출하면 응답 MSG가 어딘가에 STUCK 상태가 되어 처리할 수 없으므로 UI thread에서 호출되도록 해야 합니다. 그래서 worker thread로 생성된 SendLoop로 패킷을 보내기 직전에 RequestService() 호출이 필요한 부가서비스의 경우에는 별도 처리를 하였습니다.
1.3 t1857OutBlock과 t1857OutBlock1 memory chunk 임의 해제
이베스트 TR 스펙에 따르면, 실시간응답이 아닌 OutBlock의 경우에는 사용자가 ReleaseRequestData()를 호출해야만 메모리 해제가 되고, 호출하지 않을 경우 Request ID가 고갈되어 더 이상 Request가 불가능해진다고 명시되어 있습니다. t1857OutBlock과 t1857OutBlock1은 응답 포맷은 TR 포맷을 따르고 있지만 사실상 실시간 응답이기 때문에 라이브러리에서 ReleaseData Msg를 응답으로 던짐과 동시에 메모리를 해제해 버립니다. 그래서 t1857의 경우에는 OnMsg() 함수 내에서 Memory Copy를 수행하여 OutBlock을 복제하여 사용해야 합니다. 그래서 아래와 같이 TR 응답에 사용하는 OnMsgReceiveData와 부가서비스에서 사용할 OnMsgReceiveDataMemcpy를 별도 분리하였습니다.
2. AlertNum 값에 대한 설명
T1857을 실시간모드로 요청시 Outblock1으로 들어오는 AlertNum 값을 별도 저장해두어야 합니다.
이후 RealDataSearch로 종목명이 들어올 때 AlertNum과 비교해야 어떤 조건에 의한 종목인지(급등/급락 여부)를 파악할 수 있습니다.
T1857을 실시간 모드로 등록할 경우에는 OnMsgReceiveRealDataSearch()로 데이터가 들어오며 실시간패킷은 OnMsg() 반환과 동시에 메모리가 해제됩니다. 프로그램구조상 인터럽트핸들러(OnMsg())에서 여러 로직을 실행하는 것은 바람직하지 않은 구조라서 메모리만 그대로 복제하여 Queue에 담고 별도 처리 thread에서 해당 데이터를 처리하도록 하였습니다. LPARAM이 RECEV_REAL_PACKET이고 RECEV_REAL_PACKET::pszData에 t1857OutBlock1 포인터를 연결해 주면 됩니다.
3. RealDataSearch로 들어온 t1857Outblock1의 조건식명 알아내기
키움증권 API에는 OnMsg 파라미터로 조건식명을 종목명과 같이 주기 때문에 처리가 편리한데
xingAPI는 RECEV_REAL_PACKET의 szRegKey와 등록당시 회신받은 AlertNum값을 비교해야 합니다.
사양서에는 szRegKey인지 szKeyData인지 명시가 안되어 있고 수신된 종목을 저장만 할 뿐 어떤 조건의 종목인지 알아내는 방법이 없습니다.
그래서 실제 확인결과 아래와 같이 szRegKey 또는 szKeyData 둘 중 아무거나 사용해도 되는 것을 확인하였습니다.
xingAPI 예제에는 Request(), Receive()의 매우 기본적인 내용만 나와있습니다.
실제 프로그램에서 사용하기 위해서는 별도 자료구조를 정의하여 단순 STRING을 의미있는 VALUE로 변환 저장해 두어야 합니다.
4. RemoveService() 호출
T1857을 실시간으로 요청해 사용하다가 프로그램 종료나 기타 이유로 실시간을 멈춰야 하면
RemoveService()를 호출해줘야 합니다. RemoveService() 호출 하지 않아도 LogOut()호출시 자동으로 해지가 된다고 하는데 명시적으로 호출하지 않으면 프로그램 종료시점에 메모리 오류 경고도 뜨고 50번 정도 프로그램 비정상 종료되면(개발단계에서) 당일에는 더 이상 실시간등록요청이 안됩니다.
5. 기타 사항
*2020.12.02. DLL 메모리 버그 발견
T1857 실시간등록모드 사용시 좀 지나면 DLL 쪽에서 아래와 같은 예외와 함께 프로그램이 터집니다.
이상으로 xingAPI에서 조건검색이 가능한 T1857 사용방법에 대해 알아보았습니다.
'트레이딩 > 시스템트레이딩' 카테고리의 다른 글
[xingAPI][차트 데이터 수집기 만들기](4) 데이터 수집 설정 기능 (0) | 2021.10.12 |
---|---|
[xingAPI][차트 데이터 수집기 만들기](3) 로그인/로그아웃 (0) | 2021.10.04 |
[xingAPI][차트 데이터 수집기 만들기](2) 프로젝트 셋업 (2) | 2021.10.04 |
[xingAPI][차트 데이터 수집기 만들기](1) 프로젝트 생성 및 화면 만들기 (0) | 2021.10.01 |
이베스트투자증권 XINGAPI DLL버전 개발환경 구축 (0) | 2020.08.19 |