Bullshitting Blog

개소리하는 블로그

[ trading ]

한국투자증권 API 되살리기

회사 동료랑 밥을 먹던 도중, 내가 라이브러리로 배포해 두고 잊고 있었던 Rust 한국투자증권 API에 대한 이야기가 나왔다. 회사 동료의 지인이 그 라이브러리에 대해 유지보수 안하냐는 질문을 했다는 것이다. 갑자기 개발자의 피가 끓기 시작했다. 아, 해야죠. 넵.
1차적으로, 유지보수를 예고하는 듯한 README 문구를 추가했다. "문제 있으면 알려달라, 처리하겠다."는 내용이다. 물론, 당연히 아무 인기척이 없었다. 지금은 1주일째 rebirth 브렌치를 생성해서 모의투자 시장을 이용해서 테스트를 하면서 동작 안하는 부분들을 고치고 있다. 거의 2년을 방치했더니, TR Code가 바뀌고, 넥스트레이드 시장이 오픈하고, 난리도 아니다. 게다가 원래도 모든 API를 지원하지 않는 상태였다. 딱 나 쓸 것만 만들고 있었기 때문. 사실 그래서 지금 상태로 사용해도 그만이긴 하다.
그리고, 한국투자증권 측에서는 예측하지 못한 유저플로우에 골치를 앓으며 개발자센터 사이트에 경고 문구를 열심히 올리고 있었다. 그 부분도 조금 해결해줘야겠다. 제일 쉬운건 주문 rate를 제한하는 부분이다. 실시간 시세 수신을 끝낼 때 unsubscribe를 보내야 하는 부분도 있는데, 그것도 api가 drop될 때 박아넣어야겠다.

한투 API 작업 진도를 확 나가버림.

슬슬 해야지 한 것들을 다 해버렸다. 집안일 하는 와중에, 웨이트 갔다 오고 장도 보고 차에 기름도 넣고 온 와중에. 중간에 웹소켓 스레드 abort하는 부분 막혔는데, 테스트 삼아 codex랑 비교하기 위해 설치한 claude를 써서 돌파함.
claude 소감은 아직 잘 모르겠다. 가볍게 써서 그런 듯 하다. 다만, 뭔가 코드베이스를 파악하는데 공을 많이 들이는 것 같은 느낌이 있다. 좀더 이해하고 코드를 짜는 느낌? 그래서 컴파일 에러는 안뜸. 그래서 회사에서 claude로 갈아탈까? 하면 아직은 아니다. 결재 올리기 귀찮은데, 그걸 올릴 만한 가치를 아직 보여주지 못했다.
무엇보다 한투 쪽에서 API 설계를 잘 한게 일등공신이다. 인터페이스에 큰 변경 없이 넥스트레이드를 지원할 수 있게 해 뒀다. 문서 상 페이지가 나뉘어 있긴 하지만 잘 보면 리퀘스트 리스폰스가 거의 같다. 리스폰스의 float가 str로 바뀐 것 정도인데, 이것 또한 어차피 전문 구조에선 의미가 없다. 오히려 KRX쪽을 float로 표기해둔 것이 더 이상한 것일 수 있다. 그래서 실제 작업 시간은 직장인이 농땡이 부리면서 일한 정도의 1영업일 정도로 보인다.
이제 남은건 영업일에 테스트가 돌고 나서 귀가해서 보면서 고치는 것 뿐이다. 남은 휴일 동안 할 수 있는 일은 없다.

그럼, 집안일은 다 했을까? 아니다. 분리수거를 안했다. 내일 할 것이다. 주유 후 세차도 기계가 점검중이라 못했다. 탈개발기계 코스프레를 위해 내일 차를 직접 닦아볼 것이다. 물론 에너지 딸려서 그냥 새똥만 닦고 끝낼 것으로 예상한다.

기술적 분석

허리도 괜찮아지는 중이고, 뭔가 최근들어 머리가 팽팽 도는 상태이다. 이유는 모른다. 허리 아프다고 안쓴게 보관되나. 아 그러고보니, 불면증이 해결되는 중이구나.

여튼 그래서 오늘은 훈련 가기 전에 서적의 기술적 분석 부분을 다시 복습했다. 이미 수치 계산은 trading-toolkit에 만들어 놓은 상태였는데, 이때는 계산식 자체를 구현하는데 초점이 맞춰져 있었다면, 이번엔 기술적 분석을 통한 거래 방법에 초점을 맞추고 읽었다.

참고로 서적은 아래와 같다.

나의 트레이딩 룸으로 오라! - 알렉산더 엘더

조금 공격적인 느낌의 이름이긴 하다. 근데 뭐 영어로 "Come to my trading room"이면 그렇게 들리진 않을듯? 각설하고, 읽은 내용을 요약해 보겠다.

종목 선택 - 무엇을 살 것인가

일단 기본적으로, 채널이 넓어야 한다. 채널이 넓지 않으면 많이 못먹기 때문. 이게 그냥 단순히 많이 못먹는게 문제가 아니다. 트레이딩의 성적을 계산할 때에는 이 채널에서 얼마나 많이 먹었는지를 기준으로 한다. 따라서, 채널이 좁은 경우, 아무리 좋은 성적을 내도 이득을 크게 보지 못한다. 그리고 거래비용을 지불해야 함. 남좋은 일만 하는 꼴이다.

또 한 가지, 많은 종목을 전체적으로 보기보다, 주종목으로 할 몇몇 종목을 골라서 그것만 파는게 유리하다고 함.

이동평균선을 통한 추세 파악 - 지금 어떤가

이동평균선, 그 중 지수이동평균을 권장함. 여튼 이 선을 이용해서 상승장인지 하락장인지 추세를 파악하면 된다.

예상되는 추세 반전 지점이 있는지 확인 - 특별한 기회가 있나

MACD 히스토그램. 이 중 다이버전스를 포착한다면 좋은 기회가 될 수 있음. 다이버전스는 여러번 읽고 나서야 이해할 수 있었다. 상승 다이버전스는 가격이 두 번 이상 저점을 찍을 때, MACD 히스토그램의 두 바닥을 비교하면 상승하는 경우이다. 하락 다이버전스는 가격이 두 번 이상 고점을 찍을 때, MACD 히스토그램의 두 천정을 비교하면 하락하는 경우. 이 다이버전스의 경우, 자주 있는 일은 아니지만, 일어나는 경우 꽤 좋은 신호가 된다고 함. 약간 이벤트같다고 해야 하나.

매수/매도 시점 파악 - 언제 사고 팔 것인가

책의 저자가 개발한 강도지수라는게 있다. 이걸 이용해서 이동평균을 구하면 매수/매도 시점을 파악하기 좋다고 함. 2일 강도지수 이동평균을 이용했을 때, 만약 상승장의 경우 이 값이 음수인 경우 매수 타이밍, 반대로 하락장에서 이 값이 양수인 경우 매도 타이밍이라 함. 일시적으로 반전이 일어나는 케이스를 포착할 수 있음.

추세 재개여부 파악 - 지금 이 상태는 일시적인 것인가

이 역시 책의 저자가 개발한 엘더-레이라는게 있다. 반전이 포착되었을 때, 이전의 추세를 여전히 가져갈것인가를 알 수 있다고 함. 상승추세에서 매도 강도가 음수에서 양수로 올라가는 경우 상승이 재개되고, 하락 추세인데 매수강도가 양수에서 음수로 전환되는 경우 하락이 재개된다. 그냥 보면 당연해 보이기도 하다.

아 참고로, 매도강도는 작을 수록 강한 것이다.

위험요소 회피 - 이 포지션을 취해도 괜찮을 것인가

스토캐스틱이라는 지표가 있다. 이 지표는 과매수/과매도 상태를 나타낼 수 있음. 저자는 주로 극단적인 상황을 막기 위해 이 지표를 본다고 한다. 마지막 단계에서 이용하면 될 것 같다. 예를 들어, 매수하고 싶은데 스토캐스틱의 상단기준선 위로 올라가 있다면 매수하지 않는다. 반대로 공매도하고 싶은데 스토캐스틱의 하단기준선 아래라면 하지 않는다.

펀더멘털에 의한 변수

아무리 다이버전스를 포착하고, 매수/매도 시점 찾고 스토캐스틱으로 검증한다고 해도, 결국 기본적인 펀더멘털의 변화가 심하면 이 신호들이 의미없게 되는 경우가 있다고 한다. 저자는 이럴 때 반대 포지션을 즉시 취한다던가 하는 트레이딩적 노하우를 맛보기로 소개해 줬는데, 나같은 쩌리는 그냥 펀더멘털에 큰 변화가 찾아올 만한 주식은, 트레이딩이 아니라 투자적 관점에서 바라봐야 할 듯 하다.

시스템 트레이딩 도전

핀테크 분야에 있다보니, 개발을 진행할 수록 금융에 대해 알아야 할 것들이 많아져서 내친김에 기본 지식도 갖출 겸 트레이딩 서적을 구매했다. 하지만 책만 읽으면 재미없을까봐 내친 김에 시스템 트레이딩에 도전하기로 했다. 그리고, Python 쓰면 재미없을까봐 내친 김에 Rust로 개발하기로 했다. 그리고, 트레이딩 서적을 그냥 읽기만 하면 기억이 안날 수 있으니, 계산식들을 직접 구현하고 있다. 그리고, Rust 개발자로서... 왠만하면 라이브러리가 없다는 고충을 잘 알기에, 계산식들은 물론 사용할 증권사의 OpenAPI 호출 로직까지 따로 빼내어 클라이언트 라이브러리로 만드는 중이다.

겸사겸사 끝판왕인 듯 하다.

아 물론, 메인 전략은 private이다. 안알랴줌. 물론 아직 존재하지도 않는다.

나름의 계획

  1. 일단 주식 현금주문, 정정/취소주문, 시세 OpenAPI 정상 작동하도록 완성(korea-investment-api)
  2. OpenAPI의 시세 스트림으로부터 trading-toolkit의 각종 수치들을 계산해서 HTS의 수치랑 비교해서 맞는지 확인, 틀리면 버그픽스
  3. 라이브러리 문서화
  4. 트레이딩 책에 나온 대로 아주 기본적인 전략 하나 구현 -> 평가 시작
  5. 고유한 전략 제작 -> 평가 반복

알리지 않고서는 못베기는 삽질

주식 현금주문 response의 status가 500으로 뜨는데 body조차 출력되지 않는 초유의 사태가 발생했다. 설상가상으로, 시니어인 팀장님이, OpenAPI 관리가 생각보다 개떡이라, 문서와 다른 경우가 있어 하나하나 찾아야 한다는 정보를 주셨다. 그래서 각종 auth 관련 리퀘스트도 싹 다 확인하고, 파라미터 대소문자, 언더바 바꿔보기 등 별의 별 짓을 다해보고 있었다.

윈도우 가상머신을 띄워서 과거 API 신청한 내역까지 다시 살펴봐도 별다른 문제는 없어 보였다.(그나저나 고작 API 신청한 계좌가 뭔지 보는데 윈도우 켜게 만드네. 화가 난다. 개발자센터는 왜 있는거임? 쓸 기능도 없는데 로그인은 왜 함?) 그러던 중, 그냥 curl로 호출해 보기로 했다. 왜 진작 안해봤을까. curl로 리퀘스트를 날리니, 사실 body가 있었다. 그리고 계좌번호가 틀렸다는 꿀정보를 담고 있었다.

띠용? 하고 다시 고생스럽게 켠 윈도우에서 계좌번호를 확인해보니, 뒷자리 3개가 달랐다. 그리고 그제서야 전에 모의투자 계좌를 재발급받았던 것이 떠올랐다............

그럼 이 문제의 원흉을 다시 색출하면 어느 놈일까.

답은 내가 짠 소스에 있다.

println!("{:?}", response);

잡았다 요놈!

response의 자료형에서 derive했을 Debug trait 탓이다. Debug trait을 impl하면서 fmt를 구현할텐데, 여기다 body를 안넣어놓은 것으로 보임. 그래서 header 까지만 딱 출력되고 body는 저기 어디 숨어서 코빼기도 보이지 않았던 것이었다.

결론: 사실 이 문제의 원흉은 진작에 curl 안 때려본 본인이다.