GitHub Copilot을 사용하여 고장 난 Forex 봇을 처음부터 다시 구축했습니다 — 실제로 일어난 일들
요약
GitHub Copilot을 활용하여 승률 1.94%의 실패한 Forex 트레이딩 봇을 기관급 수준의 APEX v12로 재구축한 사례를 다룹니다. Copilot은 단순 코드 작성을 넘어 실시간 가격 피드 로직 개선과 유동성 스윕 탐지 전략의 정교화에 핵심적인 역할을 했습니다.
핵심 포인트
- GitHub Copilot을 통한 기존 코드의 구조적 결함(REST API 폴링 등) 개선
- 지수 백오프 및 하트비트 모니터링 등 안정적인 스트리밍 로직 구현
- 단순 지표 추종에서 기관급 유동성 스윕 탐지 전략으로의 전환
- AI의 제안을 통한 진입 확인 봉(Confirmation Bars) 로직 추가
이 게시물은 GitHub Finish-Up-A-Thon Challenge를 위한 제출물입니다.
내가 만든 것
완전 자율형, 기관급 Forex 트레이딩 봇인 APEX v12입니다. 이 봇은 개인 VPS에서 주 5일 24시간 라이브로 실행되며, 유동성 스윕 탐지 (liquidity sweep detection), V20 스트리밍 가격 피드 (V20 streaming price feeds), 그리고 켈리 공식 (Kelly Criterion) 포지션 사이징을 사용하여 10개의 통화 쌍을 거래합니다.
하지만 처음부터 이랬던 것은 아닙니다.
이 프로젝트는 103번의 거래 동안 1.94%의 승률을 기록하며 돈을 쏟아붓고 있던, 고장 나고 절반만 완성된 스크립트로 시작되었습니다.
이전 상태: 보기 부끄러운 수준의 봇
약 6개월 전, 저는 자동화된 FX 트레이딩 시스템을 구축하기 시작했습니다. 아이디어는 간단했습니다. 기술적 지표 (EMA 교차, RSI, MACD)를 사용하여 거래를 식별하고, 적절한 규모로 설정한 뒤, 실행되도록 하는 것이었습니다.
하지만 실제로 제가 만든 것은 엉망진창이었습니다:
- 30분마다 수행되는 REST API 폴링 (polling) — 즉, 항상 오래되고 업데이트되지 않은 가격으로 거래하고 있었다는 의미입니다.
- 동적 사이징 (dynamic sizing)이 없는 하드코딩된 손절매 (stop-losses).
- 실제로 의미 있는 무엇과도 연결되지 않은
class StreamingPriceFeed:
async def connect(self) -> None:
pairs_str = "%2C".join(PAIRS)
...
Copilot은 단순히 이 코드를 작성하는 것을 도와준 것뿐만 아니라, 재연결 시 지수 백오프 (exponential backoff), 하트비트 모니터 (heartbeat monitor), 그리고 오래된 가격 임계값 (stale price threshold)이 필요하다는 점을 지적해 주었습니다. 제가 놓쳤을 법한 것들이었습니다.
2. 지표 추종 (Indicator-Chasing) → 유동성 스윕 (Liquidity Sweep) 로직으로 전환
기존 봇은 EMA 교차 (EMA crossovers)를 추종했습니다. 새로운 전략은 기관 트레이더들이 사용하는 개념인 **유동성 스윕 탐지 (liquidity sweep detection)**를 기반으로 구축되었습니다.
핵심 아이디어는 이렇습니다. 거대 자본가(large players)들은 개인 투자자들의 손절매 (stop-losses)를 유발하여 그 유동성을 확보한 뒤, 가격을 급격히 반전시키기 위해 의도적으로 가격을 주요 고점/저점 너머로 밀어붙입니다. 만약 당신이 그 스윕을 탐지하고 거부 (rejection) 시점에 진입할 수 있다면, 기관급 수준의 진입 타점을 얻을 수 있습니다.
Copilot은 전체 스윕 탐지 엔진을 구현하는 데 도움을 주었습니다:
async def detect_sweep(self, pair: str, candles: List[dict]) -> Optional[dict]:
# 지난 20일간의 일봉 및 8주간의 주봉 고점/저점에서 주요 레벨 식별
levels = await self.get_key_levels(pair, candles)
...
Copilot이 저의 초기 구현을 검토했을 때, 제가 진입 전 **확인 봉 (confirmation bars)**을 기다리지 않고 있다는 점을 잡아냈습니다. 저는 가격이 레벨 위로 다시 터치하는 순간 바로 뛰어들고 있었는데, 이것이 바로 속임수 (fake-out)에 당하는 전형적인 방식입니다. Copilot은 진입 전 두 개의 M5 캔들이 레벨 위에서 종가로 마감될 때까지 기다리도록 SWEEP_CONFIRM_BARS = 2 파라미터를 추가할 것을 제안했습니다.
그 제안 하나만으로도 수십 번의 잘못된 거래를 피할 수 있었을 것입니다.
3. 고정 로트 크기 (Fixed Lot Sizes) → 켈리 공식 (Kelly Criterion)
기존 봇은 모든 거래에 0.1 로트 크기를 고정해서 사용했습니다. 계좌 잔고, 변동성(volatility), 또는 승률 (win rate)과는 아무런 상관이 없었습니다.
Copilot은 트레이딩을 위한 켈리 공식 (Kelly Criterion) 구현을 제게 소개해 주었습니다:
async def run_audit(self, session) -> PerformanceStats:
trades = await self.fetch_closed_trades(session)
...
이제 봇은 시작할 때마다 **자신의 과거 성과 (historical performance)**를 바탕으로 최적의 포지션 규모를 계산합니다. 봇은 학습하면서 스스로를 최적화합니다.
상한선 (Hard caps): 거래당 최소 0.5%, 거래당 최대 6%. 절대 전 재산을 걸지 마십시오.
4. 모니터링 부재 → 전체 비동기 데몬 (Full Async Daemon) + 와치독 (Watchdog)
기존 봇은 충돌 복구 (crash recovery) 기능이 없었습니다. 봇이 중단되면 제가 SSH로 접속하여 수동으로 재시작할 때까지 그대로 멈춰 있었습니다.
새로운 아키텍처에는 다음과 같은 기능을 수행하는 데몬 와치독 (daemon watchdog)이 포함되어 있습니다:
- 15분마다 봇 프로세스를 모니터링
- 충돌 발생 시 자동 재시작
- 모든 재시작을 타임스탬프와 함께 로그 기록
- 문제가 발생하면 Telegram 알림 전송
def watchdog_loop():
while True:
time.sleep(900) # 15분
...
여기서 Copilot의 기여는 여러 인스턴스가 생성되는 것을 방지하기 위해 **잠금 파일 (lock file)**을 사용하도록 제안한 것이었습니다. 이는 제가 즉시 맞닥뜨렸을 전형적인 레이스 컨디션 (race condition) 문제였습니다.
데모: v12의 실행 모습
봇은 현재 페이퍼 트레이딩 (paper trading) 계정(시작 잔고 $100k)에서 실시간으로 가동 중입니다:
현재 상태 (2026년 6월):
- 잔고 (Balance): $94,902.80
- 스트리밍 (Streaming): 10개 통화쌍 실시간 가동 (EUR/USD, GBP/USD, USD/JPY, AUD/USD, GBP/JPY, EUR/JPY, USD/CAD, NZD/USD, USD/CHF, EUR/GBP)
- 스캐닝 (Scanning): 5분마다 수행
- 오픈 트레이드 (Open trades): 실시간 손익 (P&L) 추적과 함께 활성화됨
- 업타임 (Uptime): 99.9% (데몬 + 와치독)
Telegram 연동을 통해 일일 요약 보고서가 전송됩니다:
📊 APEX v12 Daily Report
Balance: $94,902.80 | NAV: $94,894.80
Open Trades: GBP_USD — 100k units | P&L: -$10.00
...
재기 성공 스토리
원래 봇의 **승률 (win rate)은 1.94%**였습니다. 오타가 아닙니다.
재구축에는 Copilot과 함께한 약 3회의 집중 세션이 소요되었습니다. 아키텍처 리팩터링 (refactoring), 전략 재고, 적절한 리스크 관리 (risk management) 추가 등이 포함되었습니다. 혼자서 연구했다면 몇 주가 걸렸을 작업들을, Copilot은 기관급 개념을 설명하고, 제가 놓칠 법한 엣지 케이스 (edge cases)를 제안하며, 버그가 운영 환경에 반영되기 전에 잡아냄으로써 가속화해 주었습니다.
가장 큰 사고방식의 변화는 다음과 같습니다. Copilot은 저에게 봇을 단순한 스크립트 (script)가 아닌 시스템 (system)으로 취급하라고 촉구했습니다. 스크립트는 깨지지만, 시스템은 복구됩니다.
실제로 중요했던 Copilot의 주요 기여 사항:
- 내가 묻기도 전에 오래된 가격 (stale price) 문제를 지적함 — 거래량이 적은 세션에는 30초 임계값이 너무 타이트하다는 점을 감지함
- 스윕 진입 (sweep entries)을 위한 컨퍼메이션 바 (confirmation bars) 패턴을 제안함
- 소수점 켈리 (fractional Kelly) 사이징을 도입함 (나는 매우 공격적인 방식인 풀 켈리 (full Kelly)를 사용할 예정이었음)
- 와치독 (watchdog)에 잠금 파일 (lock file)을 추가함 (멀티 인스턴스 버그를 방지함)
- 자동 디렉토리 생성을 포함하여 영구적인 파일 경로로 로깅 (logging)할 것을 권장함
프로젝트는 끝나지 않았습니다. 어떤 트레이딩 봇도 완성된 상태로 존재하지 않으니까요. 하지만 이 프로젝트는 내가 부끄러워하던 것에서 실제로 실행하는 것이 자랑스러운 무언가로 변했습니다. 이것이 바로 '피니시 업 어톤 (finish-up-a-thon)'의 핵심입니다.
코드 (The Code)
전체 v12 봇은 내 VPS에서 사용 가능하며, 요청 시 핵심 모듈을 기꺼이 공유하겠습니다. 주요 파일:
fx_bot_runner.py— 메인 비동기 (async) 엔진 (1,100줄 이상)apex_v12_daemon.py— 와치독 데몬 (watchdog daemon)apex_edge_strategy.py— 유동성 스윕 (liquidity sweep) 탐지
GitHub Copilot, Python, aiohttp, OANDA V20 API로 구축되었습니다. Ubuntu VPS에서 주 5일 24시간 가동 중입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기