Fri 08-28 · 오늘 5건 · 통산 704호
falette
스크랩 쪽지 로그인
업비트 자동매매 봇 만들기
 
※ 이 게시글은 개인이 운영하는 자동매매 봇 개발 기록이며, 투자 조언이 아니라 개인 기록용입니다.

⑫ 그래서, 뭘 버릴 것인가

매매일지 · Part 4 정리 · 마지막 편
⑫ 그래서, 뭘 버릴 것인가
지금 이 글을 쓰면서 좀 이상한 기분이 든다. 열한 개 편을 이어오면서 매번 "다음 편에서 이어집니다"로 끝냈는데, 이번엔 그 말을 못 쓴다. 이게 마지막 편이니까. 그리고 이번 편은 뭔가를 밝혀내는 글이 아니라, 지금까지 쌓아온 것 중에서 무엇을 남기고 무엇을 버릴지 스스로 판정하는 글이다.

계측 없이는 판정도 없다

⑪편에서 계측 얘기를 했다. check_risk()와 check_risk_b_plan()이 로그를 하나도 안 남기고 있었다는 것, 있는 줄 알았던 live_monitor.py가 서버에 아예 존재하지 않았다는 것. 부끄러운 얘기였지만 필요한 얘기였다. 이번 편을 쓰려면 정확히 그 계측이 있어야 했기 때문이다. "이 기능이 실제로 도움이 됐는가"를 판단하려면 최소한 얼마나 자주 작동했는지는 알아야 하는데, 그걸 볼 방법이 없었다.

그래서 이번 편은 완벽한 데이터 기반 결론이 아니라, 몇 달 동안 봇을 돌리면서 몸으로 느낀 것과 코드를 다시 읽으면서 확인한 것을 섞은 판단이다. 정확한 숫자보다는 방향에 대한 이야기로 읽어주면 좋겠다. 그리고 이번 정리 과정에서 각 관문과 로직에 카운트 로그를 최소한으로 붙여뒀다. 앞으로 몇 주치 데이터가 쌓이면 이번 판단이 맞았는지 다시 검증할 생각이다.

다섯 개 매수 관문 — 절반만 남긴다

처음 봇을 설계할 때 매수 조건을 다섯 개나 걸었다. RSI 조건, 이동평균 배열 조건, 거래량 조건, 국면 필터, 그리고 쿨다운까지. 당시엔 "조건을 많이 걸수록 안전하다"는 단순한 생각이었다. 그런데 지금 코드를 다시 읽어보니 그중 두 개는 사실상 같은 순간에 같이 발생하는, 서로 겹치는 조건이었다. RSI가 과매도 구간에 들어오는 시점과 이동평균이 특정 배열을 이루는 시점이 대부분 겹쳤다. 관문이 다섯 개가 아니라 실질적으로는 세 개였던 셈이다. 나머지 두 개는 "혹시 몰라서" 걸어둔, 판단에 거의 영향을 주지 않는 장식에 가까웠다.

왜 몰랐나 각 관문이 얼마나 자주 매수를 막았는지 세어본 적이 한 번도 없었다. "다섯 개나 검사하니까 안전하겠지"라는 감각만 있었을 뿐, 실제로 어느 조건이 걸림돌 역할을 하는지는 확인한 적이 없다.

이번에 아주 단순한 카운트 로그를 추가했다. 각 관문에서 조건이 통과됐는지, 걸렸는지만 기록하는 수준이다.

logger.info(f"[GATE] {gate_name} pass={result} rsi={rsi:.1f} ma_state={ma_state}")

몇 주 데이터가 쌓이면 정말 겹치는 조건인지 확인하고, 겹친다면 하나로 합칠 생각이다. 지금 다섯 개짜리 관문을 계속 유지할 이유는 없어 보인다.

3단 손절 — 못 버린다, 대신 이제는 이유를 안다

트레일링 스탑, 다이나믹 스탑, 손절 B플랜까지 3단으로 걸어둔 손절 로직은 사실 이번 시리즈 전체를 관통한 주제였다. ⑨편에서 근본 원인을 찾았고, ⑩편에서 실제로 고쳤다. peak_pct가 트리거 값을 넘은 적이 없으면 트레일링 스탑 조건 자체가 None을 반환하며 조용히 무력화되던 게 문제였는데, 그 조건을 제거한 뒤 6월 데이터로 백테스트해보니 트리거 발동 횟수가 여러 배로 늘었고 손익도 눈에 띄게 개선됐다. 이건 버릴 게 아니라 오히려 더 아껴야 할 부분이라는 결론이다.

재미있는 건, 이 3단 구조 중에서도 실제로 자주 발동하는 건 하나뿐이라는 점이다. 나머지 둘은 극단적인 상황에서만 작동하는 안전판에 가깝다. 그런데 "잘 안 쓰이니까 빼자"고 판단하면 안 된다는 걸 이번에 깨달았다.

발동 빈도와 가치는 다르다 6월의 대규모 손실 구간이 바로 그 안 쓰이던 안전판이 필요했던 순간이었다. 평소엔 조용하다가 진짜 필요할 때 딱 한 번 작동하는 게 손절 로직의 본질이라면, 발동 빈도만으로 가치를 판단하는 건 잘못된 기준이다.

국면 분류 — 이게 제일 아팠다

④편에서 캔들을 재구성해가며 92.5%짜리 확신으로 만들었던 국면 분류 로직. 상승장, 하락장, 횡보장을 나눠서 매수 전략을 다르게 가져가겠다는 아이디어였는데, 솔직히 지금은 이게 제일 정리가 필요한 부분이라고 생각한다.

문제는 분류 자체가 틀렸다는 게 아니라, 그 분류 결과가 매수 판단에 실제로 어떻게 반영되는지가 코드 안에서 너무 흩어져 있다는 점이다. 국면 값을 참조하는 곳이 최소 세 군데인데, 각각 다른 방식으로 가중치를 준다. 누가 봐도 한 사람이 몇 달에 걸쳐 이것저것 덧붙인 흔적이다.

설계가 이해 가능한 범위를 벗어났다는 신호 나 스스로도 지금 국면 분류가 최종 매수 판단에 정확히 얼마만큼 영향을 미치는지 자신 있게 설명하지 못한다. 이건 성능 문제가 아니라 설계 자체가 한 사람이 감당할 수 있는 복잡도를 넘어섰다는 신호다.

다음 단계는 기능을 더 붙이는 게 아니라, 국면 값이 쓰이는 세 군데를 하나의 함수로 합쳐서 최소한 "지금 이게 왜 이렇게 판단했는지"를 한 곳에서 볼 수 있게 만드는 것부터다. 통합하기 전까지는 이 로직을 신뢰하지 않기로 했다.

웹 명령 인터페이스 — 이건 그냥 버린다

봇을 웹에서 원격으로 켜고 끄고, 파라미터를 실시간으로 바꿀 수 있게 만든 인터페이스가 있다. 만들 때는 꽤 뿌듯했다. 그런데 최근 몇 달간의 사용 흐름을 떠올려보면 실제로 쓴 기억이 거의 없다. SSH로 직접 서버에 들어가서 설정 파일을 고치는 쪽이 더 빠르고 확실했기 때문이다.

결국 이건 "있으면 멋있을 것 같아서" 만든 기능이었지, 실제 운영 흐름에서 필요해서 만든 기능이 아니었다. 게다가 이 인터페이스가 지금 별도 인증 없이 특정 포트로 열려 있다는 것도 이번에 다시 확인했다. 쓰지도 않으면서 공격 표면만 넓히고 있었던 셈이다. 다음 정리 작업에서 완전히 제거할 예정이다.

항목판정근거
매수 관문 5개절반으로 축소 검토조건 간 중복 발견, 카운트 로그로 검증 예정
3단 손절유지·강화⑨~⑩편에서 실효성 확인, 발동 빈도와 가치는 별개
국면 분류통합 후 재평가참조 지점 3곳 분산, 설명 불가능한 복잡도
웹 명령 인터페이스제거실사용 없음, 인증 없는 개방 포트

정리하면서 든 생각

열두 편을 쓰는 동안 이 봇에는 계속 뭔가가 더해지기만 했다. 손실이 나면 조건을 하나 더 걸었고, 불안하면 안전장치를 하나 더 붙였다. 그 결과가 지금 다섯 개 매수 관문과 3단 손절과 세 군데에 흩어진 국면 로직과, 아무도 안 쓰는 웹 인터페이스다. 되돌아보니 이건 성장이 아니라 축적이었다. 뭔가 불안할 때마다 코드를 늘리는 게 가장 쉬운 해결책이었으니까.

이번 편을 쓰면서 처음으로 "무엇을 더할까"가 아니라 "무엇을 남길 자격이 있는가"를 물었다. 그리고 그 기준은 결국 하나였다 — 계측했을 때 설명이 되는가. 설명이 안 되는 기능은, 그게 아무리 안전해 보여도, 사실은 안전한 게 아니라 그냥 이해를 포기한 부분이었다.

매매일지는 여기서 일단 마무리한다. 처음엔 6월 -53%짜리 손실의 범인을 찾는 탐정 이야기로 시작했는데, 끝나고 보니 결국은 "내가 만든 걸 내가 얼마나 이해하고 있는가"에 대한 이야기였던 것 같다. 봇은 계속 돌아간다. 다음에 다시 뭔가 쓸 일이 생긴다면, 아마 이번에 정리한 국면 로직 통합 작업일 가능성이 높다.

본 시리즈는 개인이 운영하는 자동매매 봇의 실제 개발·운영 기록이며, 특정 종목이나 전략에 대한 투자 권유가 아닙니다. 언급된 수치는 백테스트 및 실거래 로그를 바탕으로 하되 상대적인 경향을 전달하기 위한 것으로, 절대적인 성과를 보장하지 않습니다.
댓글 0
첫 번째 댓글을 남겨보세요
댓글 작성
※ 이 게시판은 개인이 운영하는 자동매매 봇 개발 기록이며, 투자 조언이 아니라 개인 기록용입니다.
연재 화수 12
누적 조회 500
연재 기간 08.02 → 08.28
번호제목조회날짜
LOGIN