# 10만원으로 자동매매는 수익을 낼 수 있는가: 업비트·라즈베리파이·Codex 검증 설계 자동매매 프로그램을 만드는 일은 어렵지 않다. 이미 공개된 거래소 API, 파이썬 래퍼, 이동평균선 예제, 서버 운영 방법을 조합하면 시세를 읽고 조건에 따라 주문하는 프로그램을 만들 수 있다. 어려운 것은 그 프로그램이 **거래 비용을 빼고도 실제로 돈을 벌 수 있는가**라는 두 번째 질문이다. 첫 번째 질문에 성공했다고 두 번째 질문까지 해결되는 것은 아니다. 이 실험은 전업 투자의 준비나 고수익을 보장하는 시스템 구축이 아니라, **약 100,000원을 최대 실험 자본으로 정하고 소형 컴퓨터에서 자동매매의 경제적 가능성을 확인하는 개발·검증 프로젝트**다. 처음부터 100,000원을 모두 거래에 투입할 이유는 없다. 먼저 공개 시세로 백테스트하고, 같은 전략을 실시간 모의매매에 적용하고, 시스템의 주문·복구·정지 능력을 확인한 뒤, 실제 체결을 관찰할 수 있을 만큼만 소액 주문을 연결한다. 이때 성공 판정에는 두 개의 분리된 장부가 필요하다. **기술 장부**에는 시세 수집, API 오류, 주문 중복, 누락, 재부팅 복구가 기록된다. **경제 장부**에는 실현·미실현 손익, 수수료, 호가 스프레드, 슬리피지와 동일 기간의 단순 보유 기준선이 기록된다. 첫 장부가 깨끗해야 두 번째 장부를 믿을 수 있고, 두 번째 장부의 결과가 우연인지 판별해야 수익이라는 말을 할 수 있다. ## 왜 10만원인가: 실험의 장점과 통계적 한계 100,000원은 성과를 원화로 직접 느낄 수 있고, 실패 비용을 한정하기에도 비교적 작은 금액이다. 그러나 **작은 투자금이 안전한 전략을 의미하지는 않는다.** 가격 급변, 시장가 체결, 주문 중복, 무제한 물타기, 프로그램 버그는 금액과 관계없이 발생한다. 더욱이 원금이 작으면 수익률이 꽤 높아도 원화 수익은 미미할 수 있다. 자동매매 실험에는 데이터 수집과 시스템 관리에 드는 시간이라는 비용도 있다. 업비트 원화마켓의 최소 주문액은 이 논의에서 **5,000원**, 일반 KRW 거래 수수료는 **매수·매도 각 0.05%**로 제시되었다. 이는 당시 참고한 조건이며, 운영 시점에는 [거래 이용 안내](https://support.upbit.com/hc/ko/articles/4403838454809-%EA%B1%B0%EB%9E%98-%EC%9D%B4%EC%9A%A9-%EC%95%88%EB%82%B4)와 계정별 주문 가능 정보로 다시 확인해야 한다. 가령 10,000원을 매수하여 같은 가격에 모두 매도하면, 단순 계산상 매수와 매도 수수료를 합쳐 약 10원이 든다. 100,000원을 거래하면 약 100원이다. 이 계산은 **가격 변동·스프레드·슬리피지를 뺀 순수한 수수료 예시**다. 왕복 기본 수수료가 명목 거래대금의 약 0.1%라는 사실은 0.2% 안팎의 미세한 움직임을 반복해서 먹겠다는 전략에 특히 가혹하다. | 실험 항목 | 제안된 시작값 | 지위 | | --- | --- | --- | | 총 실험 예산 | 100,000원 | 자본 상한 제안 | | 1회 주문액 | 5,000·10,000·20,000원 비교 | 실험 변수 | | 동시에 열어 둘 포지션 | 1개 | 오류와 노출 제한 | | 일일 주문 횟수 상한 | 5회 | 보수적 제안 | | 일일 손실 정지선 | 2,000원 | 자본의 2%라는 제안, 보장된 최대손실 아님 | | 연속 손실 정지 | 2회 | 보수적 제안 | | 모의 슬리피지 | 편도 0.02%·0.05%·0.10% | 실측치가 아닌 민감도 가정 | | 일반 KRW 수수료 가정 | 편도 0.05% | 당시 안내 기준, 재확인 필요 | | 모의매매 기간 | 최소 2주 | 운영 안정성 관찰의 출발점, 수익성 입증 기간 아님 | 손절선을 -0.4%나 -0.6%로 놓았다는 사실이 실제 손실을 그 안에 가둬 주지는 않는다. 갭에 준하는 급변이나 시스템 오류로 더 불리한 가격에 청산될 수 있다. 일일 정지선도 신규 주문을 중단하는 안전장치이지 시장 위험을 없애는 계약상의 보증이 아니다. ## 거래소 가입과 외부 서비스의 선택 처음에는 유료 자동매매 서비스나 매매 신호 구독이 필요하지 않다. **거래소 계정 하나와 공개 API 문서, 직접 관리하는 작은 프로그램**으로 충분하다. 유료 봇이나 리딩방은 가입비만큼 실험 비용을 높이고, 신호가 왜 발생했는지 검증할 권한을 사용자가 갖지 못하게 할 수 있다. 남의 수익률 스크린샷은 동일한 시장·체결·수수료 조건에서 재현한 증거가 아니다. 국내 거래소 후보로 업비트, 코인원, 빗썸이 거론되었다. 업비트를 우선한 이유는 국내 원화 거래와 공개 Python 예제, REST·WebSocket 문서 접근의 편의성이다. 코인원은 API 거래 수수료가 당시 **0.02%**로 소개되어 비용 비교 후보로 남았고, 빗썸도 API 거래는 가능하지만 첫 실험에서 거래소를 여러 개 연결할 필요는 없다고 판단하였다. **거래소별 수수료·유동성·제휴은행은 변하는 정보**이므로 이 비교를 최신 요금 확정표로 읽어서는 안 된다. 업비트 실거래 전 준비 단계로 업비트 가입, 고객확인, 원화 입출금을 위한 케이뱅크 실명확인 계좌 연동, Open API Key 발급이 제시되었다. 특히 시세 수집과 백테스트에는 **개인 API Key가 없어도 된다.** 출금 권한 없는 조회·주문용 키는 실거래 단계에서만 발급하며, 지원되는 경우 실험 자본만 분리해 놓는 서브포켓을 고려한다. 포켓의 현재 기능과 키 권한은 [업비트 포켓 안내](https://docs.upbit.com/kr/reference/pocket-overview)를 다시 확인해야 한다. API 키의 허용 범위는 자산 조회, 주문 조회, 주문하기, 필요한 주문 취소 정도로 최소화한다. **출금 권한, 입출금 관련 권한, 비밀키의 GitHub 커밋·채팅 전송·로그 출력은 금지**한다. 키는 실행 장치의 환경변수나 접근 제한된 비밀 설정으로 관리하고, 저장소에는 비밀값 없는 설정 예시만 둔다. ## GitHub에 이미 있는 것을 어떻게 활용할까 자동매매 코드가 풍부하다는 사실은 개발 초기에 큰 이점이자 함정이다. 시세 조회와 주문 기능은 이미 공유되어 있지만, 공개 저장소의 존재 자체가 수익성이 검증되었다는 뜻은 아니다. - **pyupbit**는 업비트 전용 Python 래퍼다. 현재가 조회, 분봉 OHLCV, 호가, 잔고와 주문 호출을 빠르게 실험할 수 있다. [공개 저장소](https://github.com/sharebook-kr/pyupbit)와 [문서](https://pyupbit.readthedocs.io/en/latest/index.html)를 참고하되 유지보수 상태와 현재 API 적합성을 확인한다. - **CCXT**는 여러 거래소를 공통 형태로 다루는 범용 라이브러리다. 초기의 단일 업비트 실험에는 추상화 비용이 불필요할 수 있으므로 나중에 비교·확장할 때 살핀다. [CCXT 저장소](https://github.com/ccxt/ccxt). - **완성형 자동매매 봇**은 변동성 돌파, 이동평균, RSI, 주기적 주문, 서버리스 실행, 메시지 알림 등의 구체적인 참고자료다. 그러나 전략 성능과 키 저장 방식, 예외 처리, API 최신화 여부를 코드 단위로 감사하지 않았다면 실행 파일 그대로 사용하지 않는다. - **백테스트 프레임워크**로는 backtesting.py, vectorbt, backtrader가 후보로 소개되었다. 가벼운 실험의 시작은 backtesting.py, 대량 파라미터 계산은 vectorbt, 상세한 이벤트 기반 모사는 backtrader와 같은 방향으로 비교할 수 있다. 도구 이름보다 중요한 것은 같은 체결 가정으로 같은 성과를 재현하는 능력이다. 재사용할 것은 API 연결 형태, 주문 조회, 로그·알림, SQLite 기록, 프로세스 관리와 테스트 구조다. 그대로 믿지 말아야 할 것은 공개 작성자의 익절·손절 수치, 수익률, 무제한 재시도 코드, 손절 없는 물타기, 마틴게일, 급등코인 추격매수, 상장 직후의 자동주문과 텔레그램 신호 자동 추종이다. 공개 코드에 실거래 키를 넣기 전에는 외부 서버로 자격증명을 보내는지, 출금 관련 호출이 있는지, 주문 상한과 중지 모드가 있는지, 부분체결과 주문 실패를 어떻게 처리하는지, 재시작 때 주문을 중복 발행하지 않는지를 반드시 읽어야 한다. **코드를 실행할 수 있다는 것과 신뢰할 수 있다는 것은 다른 능력**이다. ## Raspberry Pi에서 굴러가는 최소 아키텍처 초기 구조는 Raspberry Pi의 Linux 환경에서 **Python 3 + pyupbit + SQLite + systemd**를 사용하는 단일 프로세스 또는 작은 서비스다. 설명에서는 Raspberry Pi 4를 대표 환경으로 권장했지만, 실제 보유 장치의 모델과 가용 메모리는 아직 확인된 것이 아니다. 분봉 단위 실험은 밀리초 경쟁이 아니며, 개인 회선과 거래소 API를 쓰는 환경에서 초고빈도 거래를 목표로 삼지 않는다. 시세 수집은 처음에 REST로 1분마다 호출해도 된다. 이후 호가·체결 지연이나 체결 순간의 미끄러짐을 더 정밀하게 보고 싶을 때 WebSocket을 붙인다. 업비트는 [API 개요](https://docs.upbit.com/kr/reference/api-overview)에 시세 조회와 인증된 주문을 구분하고 REST와 WebSocket을 제공한다. 주문 생성은 REST, 실시간 호가·체결 감시와 내 주문 이벤트 수신은 적합한 WebSocket 채널을 이용하는 설계다. 서비스는 다음 기능으로 분리한다. | 구성요소 | 책임 | | --- | --- | | main | 실행 시각과 상태를 확인하고 각 모듈을 호출 | | market_data | BTC·ETH·XRP 등의 분봉·현재가·호가 수집과 누락 탐지 | | strategy | 현재까지 확정된 과거 데이터만으로 매수·매도 신호 산출 | | simulator / backtest | 동일한 신호를 가상 체결하고 비용을 차감 | | risk | 주문 가능 여부·일일 손실·횟수·연속 손실·수동 중지 검사 | | exchange_upbit | 거래소 인증·주문 가능 정보·주문 테스트·생성·조회·취소 | | storage | SQLite 저장 및 재실행 때 상태 재구성 | | recovery | 미체결 주문·실제 잔고·로컬 포지션을 대조 | | monitoring | 구조화 로그와 알림, 상태 및 실패 이유 제공 | | coinbot.service | systemd 자동 시작·재시작·로그 감독 | DB에는 단순히 거래 내역만 남기는 것이 아니라 **무엇을 보고 판단했고, 실제로 무엇이 체결됐는지**를 분리해야 한다. candles_1m(시각·시가·고가·저가·종가·거래량), ticker_snapshots와 orderbook_snapshots(최우선 매수·매도호가·스프레드), signals(전략·입력 특성·판단), orders(클라이언트 식별자·거래소 UUID·주문상태), fills(부분체결별 가격·수량·수수료), positions(잔량·평단), daily_stats(일별 손익·중지 이유), bot_state(재시작 복구 상태), event_logs(오류·지연·요청제한)를 구분하는 스키마가 제안되었다. 저장 시 주문 식별자와 체결 식별자에 중복 방지 제약을 두고, 실제 매매에서는 매번 메모리 속 변수만 믿지 않는다. 예컨대 시장가 매수는 총 지출금액을 지정하지만 시장가 매도는 보유 수량을 지정한다. 주문 결과 응답을 받지 못한 경우 **같은 주문을 맹목적으로 다시 보내지 말고 식별자로 조회**해야 한다. 이 사소한 차이가 중복 매수 사고를 막는 핵심이다. WebSocket 연결이 잠시 조용한 것은 체결이 없어서일 수도 있다. 따라서 무응답과 무체결을 동일하게 취급하지 않고 ping/pong, 재연결, 누락 구간 조회를 별도 구현한다. REST 요청은 Rate Limit과 429 응답, 5xx 오류, 타임아웃을 구분하고 호출 횟수와 응답 지연을 남긴다. 단, 비밀 헤더나 키가 로그에 들어가면 안 된다. ## 무엇을 매매할 것인가: 세 가지 비교 전략 첫 실험 대상은 유동성을 관찰하기 좋은 KRW-BTC, KRW-ETH, KRW-XRP 중 소수로 제안되었다. 모두 매수하라는 뜻이 아니라, 서로 다른 시장에서 같은 규칙을 비교하기 위한 후보다. 전략의 목표는 **그럴듯한 차트를 찾는 것보다 먼저 실패 가능한 가설을 명시하는 것**이다. ### 이동평균 크로스: 추세가 이어지는가 짧은 기간 이동평균이 긴 기간 이동평균을 위로 통과할 때 진입하고 반대 상황 또는 별도 청산 조건에서 나오는 단순 규칙이다. 5분·20분의 단순 이동평균처럼 해석 가능한 예를 들 수 있지만, 구체적인 기간은 검증 변수다. 횡보장에서는 매수와 매도 신호가 번갈아 발생하여 수수료를 누적시키는 약점이 있다. 처음 구현할 전략으로 유용한 이유는 수익 가능성이 입증돼서가 아니라, **신호 생성·종가 확정·다음 봉 체결·거래 비용·재현성**을 테스트하기 쉽기 때문이다. 사후에 완성된 봉을 이용한 신호를 그 봉의 이전 시점에 체결한 것으로 처리하면 미래 정보를 훔쳐 보는 백테스트가 된다. ### 변동성 돌파: 움직임이 계속되는가 이전 구간의 가격 범위나 변동성을 기준으로 정한 문턱을 돌파할 때 진입하는 방식이다. 목표는 강한 움직임 뒤의 연속성을 이용하는 것이지만, 거짓 돌파와 급격한 되돌림에 취약하다. 거래량 조건, 스프레드 제한, 시간 기반 청산 같은 필터를 시험하되, 필터를 많이 추가할수록 사후 과최적화 가능성도 커진다. ### 거래량 기반 단기 매매: 거래가 몰리면 유리한가 최근 거래량이 이전 평균보다 커지고 가격·호가 조건이 동시에 충족될 때 진입하는 단기 규칙이다. 변동성이 커질수록 체결 기회가 늘 수 있지만 **가격 미끄러짐과 부분체결 위험도 함께 커지는 전략**이다. 단순 1분봉만으로 호가 깊이를 가정하면 지나치게 낙관적인 결과가 나올 수 있으므로, 가능하면 실제 호가 샘플도 별도로 저장한다. RSI를 이용한 평균회귀는 비교군으로 추가할 수 있는 후보이지만, 초기 세 가지를 모두 구현한 다음에 확장하는 편이 낫다. 이전 제안에 포함된 **+0.4~0.7% 익절, -0.4~0.7% 손절, 15분 시간 청산** 역시 효과가 확인된 숫자가 아니라 민감도 분석용 출발값이다. 진입·청산 조건과 추정 체결 방식은 사전에 기록하고, 테스트 결과가 좋다는 이유로 계속 숫자를 바꾸는 것을 경계한다. ## 백테스트가 실거래 수익을 증명하지 못하는 이유 과거 시세에 전략을 실행하는 **백테스트**, 현재 시세에 실제 주문 없이 판단을 기록하는 **실시간 모의매매**, 실제 자금이 거래되는 **실거래**는 구별되어야 한다. 각각 다른 실패를 발견한다. - 백테스트는 전략이 과거 여러 장세와 비용 가정 아래 어떻게 움직였는지 보여 준다. 미래의 유효성을 보증하지 않는다. - 실시간 모의매매는 전략을 사후 수정할 수 없는 상태로 운용하고 데이터 지연·장애·알림·운영 상태를 점검한다. 모의 체결은 실제 호가와 반드시 일치하지 않는다. - 실거래는 실제 체결가격·수수료·부분체결·주문 거절·지연을 관찰한다. 소규모 흑자 몇 건만으로 장기 기대수익이 양수라고 말할 수 없다. 비용 모델에는 편도 수수료 외에 스프레드와 슬리피지를 독립 변수로 놓는다. 편도 0.02%·0.05%·0.10% 슬리피지를 각각 적용하여 성과가 얼마나 달라지는지 본다. 주문액이 5,000원, 10,000원, 20,000원일 때의 결과도 비교한다. 이 수치는 실측 결과가 아니라 가정이며, 실거래를 시작하면 호가와 실제 체결 차이로 보정해야 한다. **과최적화의 역설**도 중요하다. 매개변수 수십 가지 가운데 과거에 우연히 최고였던 조합을 고르면, 좋은 전략보다 '과거의 잡음에 잘 맞는 전략'을 선택할 수 있다. 그러므로 학습·탐색에 사용한 구간(in-sample)과 손대지 않고 검증하는 구간(out-of-sample)을 분리하고, 구간을 앞으로 이동시키는 walk-forward 검증을 실시한다. 최종 성과표에는 총수익률만 두지 않는다. 총손익과 순손익, 수수료·추정 슬리피지, 승률, Profit Factor, 최대 낙폭(MDD), 거래 횟수, 평균 보유시간, 연속 손실, 전략별 성과, 동일 기간 단순 보유·현금 유지 기준선을 함께 표시한다. 가능한 경우 신뢰 구간과 표본 수를 함께 내어, 거래 두세 번의 흑자를 유의미한 우위로 포장하지 않는다. 수익률 계산은 투입자본 대비 실제 순손익을 기준으로 하며 미실현 포지션도 별도로 표시한다. 업비트 분봉은 체결이 없었던 시간에 생성되지 않을 수 있어, 누락된 시간을 단순히 '가격 0'이나 '거래량 0의 확정 캔들'로 잘못 취급하지 않는다. 원시 데이터를 보존하고 채움 또는 제외 정책을 명시한다. 시스템이 만들어 낸 임의의 가짜 데이터를 실제 시장 이력으로 섞지 않는 것이 중요하다. ## Codex에 일을 나눠 맡기는 12개의 개발 프롬프트 한 번에 '수익 나는 봇을 완성하라'고 요구하면 여러 가정이 동시에 굳어지기 쉽다. 각 단계에서 Codex가 **코드, 실행 명령, 테스트, 실패 사례, 다음 단계의 진입 조건**을 제출하게 하고 결과를 검토한 뒤 다음 단계로 넘어간다. 다음은 실전에서 복사해 순서대로 적용할 수 있도록 작성한 지시문의 골격이다. 아래 단계는 **개발 계획**이지 현재 구현·실행 완료 이력이 아니다. ### P1. 프로젝트와 실행 환경 **Codex 지시문:** Raspberry Pi Linux에서 실행할 업비트 자동매매 실험 프로젝트의 Python 패키지 골격을 만들어라. 사용자는 100,000원 규모의 전략 검증을 목표로 하며 실거래는 아직 허용하지 않는다. Python 가상환경, pyupbit, SQLite, pytest, .gitignore, .env.example, README와 systemd 단위 파일 초안을 만들라. main 실행 시에는 상태 로그만 출력하고, 공개 시세 조회 이외의 주문 호출은 금지하라. 파일별 역할과 전체 실행·테스트 명령을 설명하라. **통과 기준:** 초기 실행과 pytest가 통과하며 비밀키가 저장소에 없고, 주문 엔드포인트가 호출되지 않는다. ### P2. 형식이 있는 설정과 위험 상한 **Codex 지시문:** 설정값을 타입 검증하는 모듈을 만들라. 초기값은 DRY_RUN 활성, ALLOW_REAL_TRADING 비활성, 주문 5,000~20,000원, 동시 포지션 1개, 일 최대 손실 2,000원, 일 최대 주문 5회, 연속 손실 2회다. 손절·익절·수수료·슬리피지는 독립 설정으로 구분하고 잘못된 값은 시작 단계에서 차단하라. 실제 거래 가능 조건은 별도 검증 객체로 만들고 모든 실패 사유를 한국어로 출력하라. **통과 기준:** 주문 상한이나 필수 안전값이 무효이면 서비스가 주문 없이 종료된다. ### P3. 읽기 전용 시세 기록기 **Codex 지시문:** 업비트의 인증 없는 시세 API를 사용해 KRW-BTC, KRW-ETH, KRW-XRP의 현재가·1분봉·호가를 선택적으로 수집하라. 원시 응답에서 시각과 가격·거래량을 추출하여 SQLite에 중복 없이 적재하고 누락 분봉을 감지하라. 무체결 시간과 수집 장애를 구별하고 API 요청제한을 준수하라. 주문 기능을 구현하지 말라. **통과 기준:** 반복 수집과 재실행에도 중복 행이 발생하지 않으며 수집 실패 기록이 남는다. ### P4. 수집기 CLI와 장애 시험 **Codex 지시문:** 시세 기록기에 일회 실행, 연속 실행, 종목 선택을 위한 CLI를 추가하라. 429, 5xx, 네트워크 타임아웃, 잘못된 응답을 테스트 더블로 재현하라. 안전한 지수 백오프와 요청 제한 로그를 넣되 API 자격증명은 로깅하지 말라. 24시간 관찰을 위한 누락률·응답시간 통계를 만들라. **통과 기준:** 외부 네트워크 실패가 무한 재시도나 프로세스 폭주로 이어지지 않고 데이터를 조용히 날리지 않는다. ### P5. 모의 체결 엔진 **Codex 지시문:** 동일한 신호에 대하여 종이매매를 수행하는 이벤트 기반 시뮬레이터를 만들라. 100,000원 초기 현금, 주문 최소액, 잔고 한도, 편도 수수료, 슬리피지, 부분체결, 미체결·취소·완료 상태, 주문 고유 식별자를 모델링하라. orders, fills, positions, daily_stats를 분리해 저장하라. 실제 거래소 주문 엔드포인트는 절대 호출하지 말라. **통과 기준:** 매수·매도·부분체결·잔고·수수료가 장부에서 일치하며, 같은 식별자는 두 번 실행되지 않는다. ### P6. 실패 중심의 모의 엔진 테스트 **Codex 지시문:** P5 엔진에 중복 주문, 잔액 부족, 부분체결 후 취소, 일손실 제한, 연속 손실, 30분 쿨다운, 재시작 상태 복구를 검증하는 pytest 테스트를 작성하라. 실제 네트워크 없이 재현 가능하게 하며 각 테스트가 막는 사고를 문서화하라. **통과 기준:** 안전 제약을 우회하는 주문이 하나도 통과하지 않는다. ### P7. 서로 다른 전략의 공정한 비교 **Codex 지시문:** 확정된 시세 데이터만으로 작동하는 이동평균 크로스, 변동성 돌파, 거래량 기반 단기 매매 전략을 같은 인터페이스로 구현하라. 선택한 기간·임계값·매수금액·손절·익절·시간 청산을 설정 파일로 관리하라. 다음 봉 체결 원칙을 적용해 미래 데이터를 사용하지 않도록 하라. 전략별 거래 로그와 비용 차감 전후 수익을 저장하라. **통과 기준:** 동일한 입력과 난수 시드가 동일한 결과를 만들고 미래봉 참조가 테스트에서 차단된다. ### P8. 과최적화 방지 보고서 **Codex 지시문:** P7 결과를 학습·검증 기간으로 나누어 파라미터 스윕과 walk-forward 검증을 수행하라. 슬리피지 0.02·0.05·0.10%와 주문액 5,000·10,000·20,000원에 대한 민감도표를 만들라. 수수료 이후 순손익, Profit Factor, MDD, 거래 수, 보유기간과 단순 보유 기준선을 CSV·Markdown·차트로 출력하라. 검증 구간 결과가 악화되면 실거래 보류 판정을 명시하라. **통과 기준:** 최고 수익률 하나만 내세우지 않으며 검증 구간의 실패도 보고서에 보존된다. ### P9. 실제 주문 어댑터의 테스트 전용 연결 **Codex 지시문:** 거래소 인증 어댑터를 구현하되 기본적으로 실거래 엔드포인트 호출을 막아라. 주문 가능 정보, 수수료, 최소 주문액, 호가 단위를 조회하고 업비트의 주문 생성 테스트 API를 사용할 수 있게 하라. 시장가 매수는 지출금액, 시장가 매도는 보유 수량을 사용하도록 구분하라. 주문 식별자를 생성·저장하고 타임아웃 발생 시 무조건 재주문하지 말고 주문 상태 조회를 우선하라. **통과 기준:** 테스트 API로 형식만 검증되며 실제 자산 변동이 없다. ### P10. 실거래 이중 스위치와 킬 스위치 **Codex 지시문:** DRY_RUN과 ALLOW_REAL_TRADING을 별도로 두어 실수로 하나의 설정만 바꿔도 실주문하지 않도록 하라. 별도의 수동 승인, 주문 상한, 일손실·거래횟수 제한, STOP_TRADING.flag, 오류 발생 시 신규 주문 중단을 구현하라. 실거래 전에는 백테스트 결과, 14일 이상 모의 운용, 최근 중대 오류 0건, 중복 주문 0건, 주문 생성 테스트 성공을 점검하라. 재부팅 직후에는 자동으로 실거래를 재개하지 말라. **통과 기준:** 조건 미달이면 실패 이유를 출력하고 주문을 차단한다. 실거래 활성은 별도의 명시적 사용자 승인 사항이다. ### P11. 알림과 운영 관측 **Codex 지시문:** systemd 감독 아래 구조화 로그를 남기고 journalctl로 진단할 수 있게 하라. 주문 제출·체결·손절·일손실 정지·API 오류·재연결·복구 완료를 알림 이벤트로 정의하라. Telegram 또는 Discord는 선택 구현으로 분리하고 자격증명은 마스킹하라. 네트워크와 거래소가 조용할 때도 프로세스 생존을 확인할 수 있는 헬스 지표를 제공하라. **통과 기준:** 장애와 일시적인 무체결을 구분할 수 있고, 민감정보가 로그에 등장하지 않는다. ### P12. 재부팅과 실제 잔고의 대조 **Codex 지시문:** 서비스 재시작 시 DB 상태, 거래소 잔고, 미체결·완료 주문과 체결 내역을 차례로 조회하여 로컬 포지션을 복원하라. 조회 중 신규 주문을 막고, 주문 식별자를 통해 고아 주문 및 중복 기록을 찾아라. 거래소 실제 상태와 DB가 불일치하면 거래를 중단하고 복구 보고서를 남겨라. 네트워크 단절·주문 응답 누락·부분체결 상태에서 강제 재시작하는 시험을 추가하라. **통과 기준:** 이미 발행한 주문을 다시 내지 않고, 알 수 없는 포지션을 임의로 0으로 초기화하지 않는다. ## 언제 5천원짜리 실제 거래로 넘어가는가 일반적인 권장 순서는 **시세 기록 → 과거 데이터 검증 → 실시간 모의매매 → 주문 형식 테스트 → 최소 금액 실주문 → 확장 여부 재검토**다. 단계별로 성능을 관찰하되, 실거래 전환은 코딩 에이전트가 자의적으로 실행하는 작업이 아니다. 실거래가 허용되는 조건으로 모의매매 최소 14일, 최근 중대한 운영 오류 0건, 중복 주문 0건, 수수료 이후 백테스트 결과와 검증 구간 결과의 점검, 주문 테스트 API 통과가 제안되었다. 이 기준은 **시스템 안정성의 필요조건에 가까울 뿐 수익의 충분조건이 아니다.** 신호 수가 너무 적거나 장세가 한쪽으로만 흐른 14일이라면 더 오래 관찰해야 한다. 초기에는 최소 주문액인 5,000원부터 10,000원 이내의 소액으로 실제 주문 결과를 기록하고, 주문 금액을 20,000원까지 늘릴지는 체결·알림·복구의 정확도와 손익을 본 뒤 결정한다. API 오류가 났다고 포지션을 모른 채 다시 주문하지 않는다. 실거래 직전 현재 계정의 주문 가능 정보와 수수료, 최소 금액, 호가 정책을 다시 읽고, 포지션 및 잔고를 동기화한다. 또 하나의 구별이 필요하다. **운영상 정지**는 신규 위험 노출을 막는 행동이고, **보유 자산을 시장가 청산**하는 것은 별개의 거래 행위다. 정지 플래그를 켰을 때 무조건 시장가 매도하도록 설계하면 장애 중 불리한 체결을 강제할 수 있다. 정지 후 열린 포지션을 어떻게 처리할지도 사전에 정하고 기록해야 한다. ## 수익 판단: 한 번의 흑자보다 반증 가능한 증거 100,000원으로 1,000원을 벌었다면 계좌는 분명히 1% 증가한 것이다. 그러나 같은 기간 시장 자체가 5% 상승했다면, 그 결과만으로 자동매매가 유리했다고 평가하기 어렵다. 반대로 손실이 났어도 같은 시장이 훨씬 크게 하락했다면 전략의 위험 회피 기능을 따로 검토할 여지는 있다. **절대 수익과 위험조정·기준선 대비 성과는 다른 질문**이다. 더 중요한 검사는 비용이 늘거나 기간이 바뀌면 전략이 무너지는지다. 슬리피지를 조금만 늘려도 흑자가 적자로 바뀐다면 거래량 기반의 매매 규칙은 실거래에서 취약할 수 있다. 특정 종목과 특정 주의 특정 파라미터에서만 흑자인 전략도 마찬가지다. 이 때문에 백테스트를 통과한 전략이라도 실시간 관찰 결과와 실제 체결 로그를 대조해야 한다. 실패한 전략도 정보가 된다. 수수료 때문에 무너졌다면 거래 빈도를 줄여야 하는지, 평균 수익폭이 비용보다 작은지 검토할 수 있다. 횡보장에서 빈번한 손절이 문제라면 진입 조건이 추세를 구분하지 못하는지 분석할 수 있다. 실제 체결이 모의 체결보다 불리하다면 API보다 시장 미시구조의 가정이 잘못되었을 수 있다. 전략의 실패와 소프트웨어의 실패를 한 장부에 섞지 않는 이유다. ## 중단해야 할 신호와 남겨야 할 증거 안전장치 없이 무제한 주문이 가능하거나, 주문이 체결되었는지 몰라 중복 발행하거나, 출금 권한 있는 API 키를 사용하거나, 손절 없이 물타기를 반복하는 상태라면 실거래를 시작하지 않는다. 데이터 누락을 조용히 채워 넣거나, 백테스트에 미래 정보를 사용하거나, 상장 직후 급등 종목을 무조건 따라가는 상태도 검증 시스템으로 적절하지 않다. 반면 마지막 결과가 손익 0원 또는 약간의 손실이어도, 다음 자료가 남았다면 실험은 성과를 갖는다. 거래소 공개 시세의 시간순 원본, 거래 전 신호와 전략 설정, 모의·실제 주문 및 체결의 대조, 비용 차감 뒤 성과표, 재시작·오류·중복주문 방지 테스트, 그리고 어떤 조건에서 전략이 무너졌는지에 관한 기록이다. 이 프로젝트의 결론은 수익을 미리 확정하는 문장이 아니다. **'코드는 많지만 수익은 보장되지 않는다'**라는 출발점에서, 전략에 우위가 있는지, 있다면 비용과 운영 장애를 견디는지를 작은 돈과 재현 가능한 실험으로 묻는 과정이다. 현재까지 확인된 상태는 **아키텍처와 개발·검증 로드맵의 설계**이며, 업비트 계정 가입 완료·봇 구현·모의매매 운용·실거래 수익의 존재는 확인되지 않았다. ## 참고 자료와 검증 범위 개발 시 우선 대조할 곳은 [업비트 공식 API 개요](https://docs.upbit.com/kr/reference/api-overview), [주문 생성 테스트](https://docs.upbit.com/kr/reference/order-test), [주문 가능 정보](https://docs.upbit.com/kr/reference/available-order-information), [내 주문과 체결 WebSocket](https://docs.upbit.com/kr/reference/websocket-myorder), [API 요청 제한](https://docs.upbit.com/kr/reference/rate-limits), [pyupbit 공개 저장소](https://github.com/sharebook-kr/pyupbit)다. 백테스트 도구의 선택은 [backtesting.py 문서](https://kernc.github.io/backtesting.py/doc/backtesting/), [vectorbt](https://vectorbt.dev/), [backtrader](https://www.backtrader.com/)를 비교하는 수준에서 제시되었다. 이 글에 등장하는 수수료·최소 주문액·계좌 연동·API 기능은 앞선 설명과 그 안에서 언급된 참고 문헌을 토대로 정리한 것으로 **이 편집에서 외부 최신 정보를 새로 검증한 것은 아니다**. 실험의 수익률, 전략의 우월성, 장치의 실제 설치 상황, 계정과 API 키 발급 여부도 실측 결과로 주장하지 않는다.