본문 바로가기
IT & 비즈니스

파이썬 자동매매 시스템 구축 가이드

by notes9107 2026. 8. 23.

저는 2023년 4월부터 파이썬으로 암호화폐 자동매매 봇을 만들기 시작했습니다. 처음에는 이동평균선 두 개만 비교하면 주문이 알아서 체결되고 수익도 따라올 줄 알았습니다. 주말 동안 작성한 코드로 소액을 넣어 돌렸는데, 첫날에는 매수와 매도가 몇 번 정상적으로 발생해 꽤 뿌듯했습니다. 하지만 이틀 뒤 잔고를 확인하니 수수료와 잦은 재진입 때문에 10만 원이 9만 6,800원으로 줄어 있었습니다. 그때 저는 전략보다 먼저 주문 상태와 비용을 추적하는 구조를 만들어야 한다는 사실을 체감했습니다.

1. 첫 시도에서 API 키를 노출한 날

처음에는 거래소 API 키를 파이썬 파일 안에 그대로 적었습니다. 로컬 컴퓨터에서만 실행하니 괜찮다고 여겼지만, 2023년 5월 8일 코드를 깃허브에 올리면서 상황이 달라졌습니다. 몇 분 뒤 보안 알림 메일이 도착했고, 저는 급히 키를 폐기한 뒤 새 키를 발급받았습니다. 다행히 출금 권한을 꺼둔 상태라 금전 피해는 없었습니다. 이후에는 .env 파일과 환경 변수를 사용하고, 저장소에는 .gitignore를 적용했습니다. API 권한도 조회와 주문으로만 제한했으며, 서버 IP를 허용 목록에 등록했습니다. 이 일을 겪고 나서 보안 설정을 기능 개발보다 뒤로 미루지 않게 됐습니다.
제가 두 번째로 놓친 부분은 주문 중복 처리였습니다. 1분봉이 끝날 때 매수 신호를 보내도록 만들었는데, 네트워크 응답이 늦어지자 봇이 주문이 실패했다고 판단하고 같은 주문을 다시 전송했습니다. 2023년 5월 21일 새벽에는 한 번의 신호에 매수 주문이 세 건 들어가 보유 금액이 계획보다 세 배 커졌습니다. 이후 주문 전송 전 로컬 주문 ID를 만들고, 거래소에서 실제 체결 상태를 조회한 뒤 다음 동작으로 넘어가게 수정했습니다. 프로그램이 재시작돼도 마지막 포지션과 미체결 주문을 복구하도록 별도 파일에 상태를 기록했습니다. 자동화에서는 주문을 보내는 코드보다 이미 보낸 주문을 확인하는 코드가 더 길어져야 한다는 점을 배웠습니다.

2. 집 컴퓨터와 클라우드 서버에서 겪은 차이

처음 한 달은 집에 있는 노트북으로 봇을 실행했습니다. 노트북이 절전 모드로 들어간 2023년 6월 2일 새벽에는 매도 조건이 발생했는데 프로그램이 멈춰 주문을 내지 못했습니다. 아침에 확인했을 때 가격은 4.7% 더 내려가 있었습니다. 그 뒤 월 1만 8천 원 수준의 가상 서버를 빌려 우분투 환경을 구성했고, 파이썬 가상환경과 systemd 서비스를 설정했습니다. 서버로 옮긴 뒤에도 문제가 완전히 사라지지는 않았습니다. 거래소 API가 잠시 응답하지 않으면 프로세스가 종료됐고, 로그 파일이 며칠 만에 디스크를 채웠습니다. 재시작 정책과 로그 순환을 설정하고 나서야 며칠씩 지켜보지 않아도 되는 운영 형태가 갖춰졌습니다.
저는 운영 로그를 뒤늦게 설계한 일을 특히 후회합니다. 초기 버전은 “매수 실행”이라는 문장만 남겼고, 어떤 가격과 수량으로 주문했는지 기록하지 않았습니다. 손실이 발생한 날 원인을 찾으려 했지만 신호 시각과 주문 응답을 서로 대조하기 어려웠습니다. 지금은 캔들 시각, 현재가, 지표 값, 주문 수량, 응답 코드, 체결 수량을 한 줄에 남깁니다. 2023년 7월 14일에는 거래소 시간이 UTC로 기록되고 제 서버 로그는 한국 시간으로 남아 두 기록이 세 시간 어긋나는 문제도 발견했습니다. 모든 로그를 UTC로 저장하고 화면에 표시할 때만 한국 시간으로 바꾸니 분석 과정이 훨씬 덜 헷갈렸습니다.

3. 지표 계산보다 먼저 확인한 캔들 데이터

처음 만든 전략은 5일 이동평균선이 20일 이동평균선을 위로 통과하면 매수하는 방식이었습니다. 그런데 제가 받은 캔들 목록이 최신순으로 정렬돼 있다는 사실을 놓쳤습니다. pandas의 rolling 계산 결과가 뒤집힌 순서로 만들어졌고, 백테스트에서는 매번 미래 가격을 참고한 것처럼 보였습니다. 2023년 7월 28일 이 오류를 고친 뒤 수익률이 31%에서 4.2%로 내려갔습니다. 처음에는 성능이 나빠진 줄 알고 실망했지만, 오히려 그 수치가 현실에 가까웠습니다. 이후에는 시간순 정렬 여부, 중복 캔들, 비어 있는 구간, 아직 끝나지 않은 현재 봉을 매번 검사합니다.
실시간 주문에서도 현재 진행 중인 1분봉을 확정된 봉처럼 사용해 손실을 키웠습니다. 가격이 잠깐 이동평균선을 넘는 순간 매수하고 몇 초 뒤 다시 내려오면 신호가 사라지는 일이 반복됐습니다. 2023년 8월에는 이런 진입이 하루 평균 12회까지 발생했고, 거래 수수료만 일주일에 3만 4천 원이 빠져나갔습니다. 그래서 봉의 종료 시각이 지난 뒤에만 신호를 계산하고, 같은 봉에서는 한 번만 판단하도록 조건을 추가했습니다. 결측 구간을 무조건 직전 가격으로 채우는 방식도 사용하지 않았습니다. 거래소 점검이나 네트워크 장애로 생긴 공백은 별도로 표시한 뒤 해당 구간의 신호를 건너뛰었습니다.

4. 백테스트 수익률을 믿었다가 겪은 손실

제가 가장 크게 착각한 부분은 백테스트 화면에 표시된 수익률이 실제 계좌에서도 비슷하게 나타난다는 생각이었습니다. 2023년 8월 19일에는 2021년부터 2023년 7월까지의 15분봉으로 테스트한 결과가 누적 58%로 나왔습니다. 그러나 수수료와 슬리피지를 넣지 않은 숫자였습니다. 체결 가격에 매수·매도 각각 0.05%의 비용을 적용하고, 신호가 나온 다음 봉의 시가로 진입하게 고치자 수익률은 11%로 낮아졌습니다. 거래량이 적은 시간대에는 지정가 주문이 체결되지 않는 상황도 반영하지 못했습니다. 그 뒤부터는 총수익률 하나만 보지 않고 최대 낙폭, 월별 손익, 연속 손실 횟수, 거래당 평균 비용을 함께 기록했습니다.
백테스트 기간을 전략에 맞춰 골라버린 경험도 있습니다. 상승장이 길었던 2021년 데이터에서 이동평균 조합을 여러 번 바꿔 가장 좋아 보이는 설정을 골랐습니다. 그런데 2022년 하락장에 그대로 적용하자 5개월 동안 18.6% 손실이 발생했습니다. 이후 기간을 학습 구간과 검증 구간으로 나누고, 마지막 구간은 전략을 조정할 때 보지 않았습니다. 파라미터도 7개 이상 두지 않으려 했고, 특정 코인 하나에서만 잘 맞는 조건은 제외했습니다. 과거 차트에 예쁘게 맞는 전략보다, 여러 장세에서 덜 무너지는 전략을 남기는 쪽으로 기준을 바꿨습니다.

5. 제가 지금도 지키는 소액 운영 원칙

현재 저는 새 전략을 만들면 바로 큰 금액을 넣지 않고, 최소 2주 동안 모의 주문과 소액 주문을 번갈아 확인합니다. 2024년 1월에는 백테스트가 괜찮았던 돌파 전략을 20만 원으로 시험했는데, 실제 호가 간격 때문에 예상보다 불리한 가격에 체결됐습니다. 손절 조건도 코드상으로는 2%였지만, 급격한 움직임에서는 2.8% 하락 뒤에 체결됐습니다. 그래서 주문 전 잔고와 최소 주문 금액을 확인하고, 하루 손실이 계좌의 1%를 넘으면 새 진입을 막았습니다. 서버가 살아 있어도 거래소 응답이 이상하면 주문을 멈추는 안전 스위치도 별도로 뒀습니다.
자동매매를 시작한 뒤 저는 수익을 내는 조건보다 멈춰야 하는 조건을 먼저 작성하게 됐습니다. API 오류가 연속 세 번 나오거나 잔고 조회 결과가 이전 기록과 크게 다르면 프로그램을 중단하고 알림을 보냅니다. 매일 아침에는 전날 주문 수와 체결 누락 여부, 수수료, 최대 손실을 직접 확인합니다. 자동화는 손을 완전히 떼는 기능이 아니라 반복 작업을 줄이고, 사람이 확인해야 할 지점을 드러내는 도구에 가깝다고 느꼈습니다. 독자분이 비슷한 작업을 시작한다면 처음부터 수익률을 좇기보다 API 권한을 줄이고, 한 번의 중복 주문을 막고, 비용을 포함한 기록을 남기는 데 시간을 쓰길 권합니다. 감당 가능한 금액으로 충분히 오래 관찰한 뒤에만 다음 단계로 넘어가는 편이 제 경험상 훨씬 안전했습니다.