자동매매봇 패치...

강냉쓰·2022년 10월 4일
0

근황로그..

목록 보기
4/4
post-thumbnail

요즘 근황이다.
최근 여기 남긴것처럼 수해를 당했으나 이제 어느정도 복구가 되어 일상으로 돌아왔다.

그전까지 내 놀고있는 노트북 한대를 이용해 코드서버를 만들고 그 코드서버에 빗썸에서 자동매매를 할수있는 봇을 만들고 있었다. 하지만 나스가 침수되어 물거품이 되는듯 했으나 나스는 퍼포스 서버로 버전관리만 하는거였고 복제된 코드들은 다행히도 노트북에 갖고있었기때문에 어느정도 다행이라 생각했으나 더 다행인건 나스가 침수되었어도 살아있었다는 사실이었다.

내가 침수된 상황을 본거는 아니었어서 나스에 어느정도까지 물이 찼는지는 모르겠으나 확실한건 아래쪽엔 흙탕물이 쌓여있는듯한 흔적이 있었고 그쪽엔 하드디스크의 접지부가 있었기때문에 망했다고 생각했다. 1주일 완전건조를 하고 전원 어댑터는 완전 침수되었어도 말렸으나 1주일이 지났는데도 계속 흔들면 물이 나오는 상황이었어서 새로 사는걸 결정했고 새로 산 어댑터를 1주일 말린 나스에 연결하니 다행히도 작동이 되었다.

하지만 내 나스는 2bay 였는데, 한... 3주인가 4주정도 지나니까 갑자기 한 하드디스크에 불량섹터가 급증하더니...
사망했다.
다행히도 사망하기전에 다른하드로 백업을 해서 살려놓긴 했으나 어느파일이 깨졌는지는 파악이 안된다... 뭐 여튼...

다시 회사를 다니며 짬짬히 코인봇을 열심히 만들었는데 역시 태블릿으로 코드서버가 되니 무료했던 이동시간이 매우 유익해졌고 그 시간이 짧은 시간은 아니니 개발속도도 빨랐던것같다.

현재 코인봇의 구현기능들은

  • 자동 매매, 매수
  • 최초 투자금보다 많은 돈이 이익이 발생하면 그 돈을 킵해두는 기능
  • 현재 알고리즘으로 1분,3분,5분 등 원하는 시간대로 쌓여있는 데이터를 받아와 빠르게 백테스팅
  • 현재 알고리즘으로 실전과 같이 테스트(실제돈은 안들어감)
  • 각종 이벤트때 텔레그램으로 알림

음... 생각나는건 이정도...?


그런데 시퀀스가... 매우 많이 프로토같다...

일단 시작하려면 무조건 main.py 파일을 컴퓨터에서 실행해야하며, 어떤 일을 할지는 번호로 입력, 입력된 수행이 끝나면 그냥 강종되고 다시 실행되지 않는다. 뭐 그건 별로 큰일은 아닌것같고... 사용자만 불편하지 않으면 되니까... 사용자는 나니까
텔레그램에게 알림이 가는 일은 뭐 그렇다치고... 봇이 돌다가 특정 이벤트(매수, 매매등)가 발생하면 로그를 찍도록 했는데 그때 필요한 정보들을 출력했다. 이렇다보니 지금 당장 어떤 정보를 얻고싶은데 해당 이벤트가 실행되기 전까지는 절대 알 수 없고, 또한 런타임 중에 어떤 변수를 수정해야 할때도 마이너한거를 수정한다거나, 상황마다 변수를 바꾸면서 테스트를 해봐야 할때도 매번 코드 수정하고 봇을 강종했다가 다시 실행하고 를 반복해야했는데, 그렇게 되면 현재까지 매수했던 코인들과 기록들이 전부 없어진다. 한마디로 전체적으로 라디오같은 매우 수동적인 의사소통 관계가 됐으며 뭔가 내가 요구하고싶은데 그 요구를 들어줄 수 있는 방안이 없었다.

물론 저런 기록들은 파일로 저장을 해놓은 다음 그걸 읽어와서 다시 한다던가... 음? 이것도 좋아보이는데 이것도 한번 생각해보고...

그러다가 갑자기 텔레그램 봇이 자동답장도 할 수 있으니까 그 기능을 이용해 내가 원하는 정보를 텔레그램으로 물어보면 그 정보를 알려주게 하자는 아이디어가 떠올라서 실행에 옮겼다.

일단 답장을 하려면 updator객체를 만들어 updator.start_polling()을 해야했다.
근데 문제는 이게 한 봇에 한해 한번만 풀링이 가능하다는 것이다.

이게 왜 문제냐면...

나는 봇을 여러개를 돌리고 있었다. 예를들어 main.py를 한개 실행하고 한번 실행할 때 타겟으로 할 ticker를 결정할 수 있게 했는데 만약 두개, 혹은 세개의 코인이 좀 눈에 들어와서 자동봇을 돌려놓고싶다면 main.py여러개 실행하여 ticker가 여러개 돌릴 수 있게 했다. 여러개의 인스턴스가 생기는것이다. 하지만 telegram의 polling 은 한 봇에 한 인스턴스만 polling이 가능하다... 그래서 여러개의 ticker를 돌리고 싶을때는 한개의 인스턴스에서 해야할 필요가 있어서 고민을 좀 했다.

일단 여러개의 main.py를 돌려야했던 이유는 매 초마다 현재의 가격을 bithum에서 가져와 그 가격을 가지고 계산하고 그 다음 time.sleep(1)을 이용해 1초 기다린 후 영원히 반복하는 while문을 사용했기 때문이다. 하지만 여러개의 ticker를 지정하고 싶을때는 이 모든기능을 메인스레드에서 도는게 아니라 멀티스레드로 처리할 필요가 있었다.

스레드는... 텔레그램 봇을 만들때 잠깐 쓰레드로 처리할 필요가 있어서 잠깐 바꾼적이 있었는데, 그걸 참고해서 어렵지않게 모든기능을 쓰레드로 바꿨고 이제 어떤 ticker 를 대상으로 할지만 기다리고 한번 입력하면 thread 로 봇 로직을 타게 던진다음 다시 어떤 ticker 로 봇을 돌릴건지 기다리게 수정했다.

자, 일단 이건 이렇게 됐는데... 문제는 또 있다... 만약 ticker 가 여러개 생겼는데 봇에게 현재정보를 출력하거나 봇에게 어떤일을 지시할 때 어떤 ticker 에게 지시할지 모호한 상황이 되었다.
ticker 로 하게 된다면 그것도 문제가 생긴다. 만약 로직이 변경되어서 다시 main.py를 실행해야 할 일이 생긴다면 현재 돌고있는 봇은 지금부터 매수를 금지하고 매도모드에만 들어가게 한 후 그것이 다 끝날때까지는 봇이 살이있다가 다 끝난다면 자연스럽게 종료되어야한다. 종료될때까지 기다렸다가 새 main.py를 실행하기엔 시간이 너무 아깝기때문에 그냥 매도모드로 변경한 후 바로 새 main.py를 실행해야하는데 같은 ticker 를 사용했을때는 명령어를 내릴때 어떤 ticker 로 명령이 내려질지도 모호해진다. 한마디로 ticker 는 유일한 객체로 보장하기엔 좀 아쉬운 변수라는 뜻이다. 그래서 봇이 만들어질때 unique id 를 할당했고 그 unique id를 텔레그램에서 쓰고 명령어를 쓰면 그에대한 일을 수행하도록 했다.

사실 위 문제는 두개의 인스턴스에서 polling이 안되기 때문에 저렇게 하기위해선 먼저 끝내려는 봇의 main.py를 죽여야만 새 인스턴스에서도 정상적으로 polling 이 가능하기때문에 어쩌피 종료해야한다. 하지만 종료하지않아도 update.stop()을 호출하면 그 인스턴스에서는 polling 이 멈추고 새 인스턴스에서 polling이 가능해진다. 그래서 이전 인스턴스에서는 polling을 그만두고 새 인스턴스에서만 polling 이 가능하도록 수정했다.

이제 어느정도 텔레그램으로 원하는정보를 출력하게 보내면 봇이 내가 미리 설정한거지만 내가 한 말에 알맞은 답장을 하게했다. 하지만 또 고민이 있는데... 명령어를 내가 다 알고있지 않아서 생각이 안날땐 코드를 매번 봐야한다는 것이다...
그래서 help같은게 필요한데... 문제는 이걸 하드하게 해버리면 help를 출력하는곳에도 명령어를 추가해야하고 실제 명령어를 실행하는 곳에도 명령어를 추가해야한다. 명령어를 실행하는 곳에는 전부 if ~ elif로 되어있기때문에 하나하나 다 가서 추가해야하고 help를 출력하는것도 그 목록만 출력해야하기때문에 if ~ elif로 입력한 모든걸 다 help출력함수에다가 추가해야하는것이다.

나는 개인적으로 개발하면 뭔가 하나를 추가할때 여기도 수정하고 저기도 수정하는걸 매우 싫어한다. 그렇게 되면 유지보수가 나중에는 개같아지기때문이다.
나는 이 상황을 절대로 참을 수 없었기 때문에 머리를 굴려봤는데 바로 명령어를 enum으로 만드는 것이다. 혹은... 명령어로 된 배열을 하나 생성하는것도 좋은방법일것같다.
음... 이 글을 쓰기 전까지는 enum으로 만들어야지~ 했는데 가만 생각해보니 그냥 배열만드는게 더 간단해 보이는데...? 그냥 그렇게 해야겠다.

자... 그 다음 해야할게... 매도모드는 추가해놨고, 매도모드로 이제 거의 다 팔았을 때 스스로 종료하는 시퀀스까지도 추가해야한다. 이건 어떻게 해야하는지 아직 아이디어가 없어서 아이디어 생기면 작업하면 될것같고...

그리고 또 아까 텔레그램의 updator.start_polling() 이라는 함수 호출이 어떤 함수 안에서 호출하는게 아니라 걍 전역에서 호출하고있기때문에 매매봇만 실행해도 텔레그램 봇도 같이 polling 이 돌아버려서 텔레그램 봇 필요없는데도 너 polling 두번했는데 그라면안돼~ 하면서 난리를 친다. 이미 하나는 돌고있는 상태에서 테스트를 하기때문에... 그래서 이것도 정말 봇이 필요할때만 polling 관련 함수가 돌 수 있도록 수정해야한다. 일단 polling 함수가 있는 코드는 따로 함수화를 시켜놨는데 이걸 언제 호출하게할지가 고민이다. main.py에서 봇이 필요할때만 이 polling 함수를 호출하게 할지... 근데 그렇게 되면 이걸 해야하는곳에 전부 다 가서 하나하나 추가해줘야한다. 또 참을 수 없는 뭔가가 올라오는데... 하지만 매매봇이 하나 돌때마다 이걸 맨날 start polling을 한다면 음... 그것도 또 문제다. 한번만 호출하면 되는데 왜 굳이 또 할 필요가 있나... 이미 활성화 됐는지 체크하면 되긴하는데 그 체크하는 작업 마저도... 불필요한데 말이다. 그래서 그건 사알짝 고민중~

또한 전부 텍스트로만 알려주다보니 실제로 어느 시점에 팔고, 어느 시점에 샀는지, 혹은 지금 추세는 어떤지를 파악하기 어려운데 numpy 를 이용해 그래프를 생성할 수 있길래 그걸 이미지 파일로 만든 후 텔레그램으로 전송하게 하는것도 생각중이다.

어찌하다보니 개발로그가 됐는데
음... 이것도 나쁘지 않은것같다.

profile
개발하다가 나온 여러가지 고민과 그에 대한 해결책들을 간결하지않고 일기처럼 끄적여봅니다.

0개의 댓글