정보

코딩 몰라도 가능한 '바이브 코딩'으로 나만의 트레이딩 봇 만들기

돈버블로 2026. 4. 30. 11:16

20년차 트레이더가 AI 에이전트와 한 달간 협업하며 깨달은 것들

20년 가까이 차트를 들여다보고 호가창을 읽어왔지만, 정작 '나만의 시스템'을 코드로 구현하는 일은 늘 외주의 영역이었다. 파이썬을 어깨너머로 배워봐도 백테스팅 프레임워크를 직접 짜는 일은 늘 다른 전공자의 몫이었고, 외주를 맡기면 내 머릿속의 미묘한 진입 조건이 80%만 반영된 결과물이 돌아오곤 했다. 그런데 지난 몇 달 사이에 그 진입장벽이 사라졌다. 이른바 바이브 코딩(Vibe Coding) 의 등장이다.

이 글은 코드를 한 줄도 못 짜는 사람을 위한 입문서가 아니다. 오히려 자기 전략은 명확한데 구현이 늘 발목을 잡았던 트레이더들, 혹은 시스템 트레이딩의 외주 비용과 커뮤니케이션 손실에 지친 실무자들을 위한 워크플로우 정리다. 주식과 선물 양쪽에서 검증한 경험을 토대로, 어디까지가 가능하고 어디서부터는 여전히 사람의 판단이 필요한지를 가감 없이 적었다.

 

1. 바이브 코딩이 정확히 무엇인가

바이브 코딩은 OpenAI 공동창업자 안드레이 카파시(Andrej Karpathy)가 2025년 초에 던진 개념이다. 핵심은 단순하다. 코드를 직접 타이핑하는 대신, AI 에이전트에게 '느낌'과 '의도'를 자연어로 전달하면서 결과물을 함께 다듬어가는 개발 방식이다. 전통적인 의미의 프로그래밍이 '명령어의 정확한 조합'이라면, 바이브 코딩은 '의도의 해상도를 점점 높여가는 대화'에 가깝다.

이게 트레이딩 봇 개발과 궁합이 좋은 이유는 분명하다. 트레이더의 머릿속에 있는 진입 조건은 본질적으로 휴리스틱이다. "거래량이 평소 대비 확 터지면서 직전 고점을 살짝 돌파하는 자리"라는 표현은, 외주 개발자에게 넘기면 100명이 100가지로 해석하지만, 같은 트레이더가 GPT나 Claude 같은 모델과 대화하며 백테스팅 결과를 본 뒤 "아니, 이건 너무 늦게 잡혔어. 돌파 직전 봉의 매수세 강도를 추가 조건으로 넣자"고 즉시 수정할 수 있다. 피드백 루프의 길이가 며칠에서 몇 분으로 줄어든다는 게 핵심이다.

다만 명확히 짚고 가야 할 부분이 있다. 바이브 코딩은 "코딩을 몰라도 된다"는 말과 "엔지니어링 감각이 필요 없다"는 말이 다르다는 점에서 자주 오해받는다. 함수가 무엇인지, API가 어떻게 호출되는지, 데이터프레임이 무엇인지 정도의 개념은 결국 알아야 디버깅 단계에서 바이브가 무너지지 않는다. 실전에서는 "읽을 수는 있지만 쓰지는 못하는" 수준이 가장 효율적이라는 게 내 결론이다.

 

2. 왜 지금 시점이 진입 적기인가

세 가지 변화가 동시에 일어났다.

첫째, 에이전트형 AI의 성숙이다. 단발성 코드 생성을 넘어 Claude Code, Cursor, Codex 같은 도구들이 파일 시스템을 직접 조작하고, 테스트를 돌려보고, 오류를 보고 스스로 수정하는 단계까지 왔다. 트레이딩 봇처럼 데이터 수집-신호 생성-주문 집행-로깅이 맞물린 멀티 컴포넌트 시스템에서 이 자율성은 결정적이다.

둘째, 증권사 API의 표준화다. 한국투자증권의 KIS Developers, 키움증권 OpenAPI+, 이베스트의 xingAPI, 그리고 해외로는 Interactive Brokers의 IBKR API와 Alpaca까지, REST 기반의 깔끔한 인터페이스가 일반 투자자에게 풀렸다. 5년 전이라면 ActiveX 기반 키움 OpenAPI를 다루느라 윈도우 전용 환경에서 32비트 파이썬을 깔고 시작해야 했다.

셋째, 백테스팅·페이퍼 트레이딩 인프라의 오픈소스화다. backtesting.py, vectorbt, zipline-reloaded 같은 라이브러리가 활발하게 유지되고 있고, 데이터 소스 역시 yfinance, FinanceDataReader, pykrx 등으로 무료 옵션이 충분하다.

이 세 가지가 합쳐지면서 "전략은 있는데 구현이 안 돼서 못 쓰던" 사장된 알파들이 다시 살아날 환경이 만들어졌다. 외주로 6개월 걸리던 작업이 주말 이틀로 줄어든 셈이다.

 

3. 실전 워크플로우: 6단계로 본 봇 개발 사이클

3.1. 전략의 자연어 명세서(Strategy Spec) 작성

가장 중요한 단계이자 가장 자주 건너뛰는 단계다. AI에게 코드를 시키기 전에, 사람이 봐도 모호하지 않은 명세서를 먼저 만든다. 나는 이걸 strategy.md 파일로 따로 관리한다.

전략명: VWAP Reversion Sniper (KOSPI200 선물용)

진입 조건 (롱)
1. 09:00~10:30 사이에만 진입
2. 종목/지수가 일중 VWAP 아래 1.5% 이상 이탈
3. 1분봉 RSI(14)가 30 이하에서 35 위로 상향 돌파
4. 직전 5분 누적 매수호가 잔량 > 매도호가 잔량 * 1.2

청산 조건
- 익절: VWAP 도달 시 전량 또는 +0.8% 도달 시 50% 분할
- 손절: 진입가 대비 -0.5%
- 시간 손절: 진입 후 30분 경과 시 무조건 청산

포지션 사이징
- 계좌 자본의 0.5% 리스크 한도
- 최대 동시 포지션 2개

이걸 그대로 Claude나 GPT에 던지면, 5년 전 외주 개발자에게 줬을 때보다 훨씬 정확한 1차 구현물이 돌아온다. 자연어 명세서가 곧 사양서이자 테스트 시나리오이자 문서가 된다.

3.2. 프로토타입 생성 - 첫 번째 바이브 코딩 세션

명세서를 던진 뒤 받은 첫 코드는 보통 다음과 같은 골격으로 나온다.

 

import pandas as pd
import numpy as np
from datetime import time

class VWAPReversionStrategy:
    def __init__(self, risk_per_trade=0.005, max_positions=2):
        self.risk_per_trade = risk_per_trade
        self.max_positions = max_positions
        self.positions = []

    def calculate_vwap(self, df):
        """누적 VWAP 계산"""
        q = df['volume'].values
        p = (df['high'] + df['low'] + df['close']).values / 3
        return (p * q).cumsum() / q.cumsum()

    def calculate_rsi(self, prices, period=14):
        delta = prices.diff()
        gain = delta.where(delta > 0, 0).rolling(period).mean()
        loss = -delta.where(delta < 0, 0).rolling(period).mean()
        rs = gain / loss
        return 100 - (100 / (1 + rs))

    def check_entry_signal(self, df, current_idx):
        row = df.iloc[current_idx]
        current_time = row.name.time()

        # 시간대 필터
        if not (time(9, 0) <= current_time <= time(10, 30)):
            return False

        # VWAP 이탈 체크
        vwap = self.calculate_vwap(df.iloc[:current_idx+1])[-1]
        deviation = (row['close'] - vwap) / vwap
        if deviation > -0.015:
            return False

        # RSI 상향 돌파
        rsi = self.calculate_rsi(df['close'].iloc[:current_idx+1])
        if not (rsi.iloc[-2] < 30 and rsi.iloc[-1] >= 35):
            return False

        return True

 

여기서 핵심은 돌아온 코드를 그대로 쓰지 않는다는 점이다. 위 코드만 봐도 베테랑 눈에는 즉시 두세 가지 문제가 보인다. VWAP을 매 시점마다 누적 재계산하는 건 백테스팅에서는 괜찮지만 실시간에선 비효율이고, RSI에서 rolling(period).mean()은 단순 이동평균이라 정통적인 Wilder's smoothing과 결과가 다르다. 호가 잔량 조건은 아예 빠져있다. 이런 걸 잡아내려면 본인이 코드를 읽을 줄은 알아야 한다.

 

3.3. 백테스팅 통합 - 가장 손이 많이 가는 단계

여기서 진짜 작업이 시작된다. 단순히 동작하는 코드와 백테스팅에서 신뢰할 수 있는 코드는 다르다. 슬리피지, 수수료, 시장가/지정가 차이, 호가 단위, 거래정지·VI 같은 한국 시장 특유의 마찰까지 반영해야 한다.

from backtesting import Backtest, Strategy

class VWAPReversionBT(Strategy):
    risk_pct = 0.005
    sl_pct = 0.005
    tp_pct = 0.008
    time_stop_bars = 30  # 1분봉 기준

    def init(self):
        close = self.data.Close
        self.vwap = self.I(self._vwap_calc)
        self.rsi = self.I(self._rsi_calc, close, 14)
        self.entry_bar = -1

    def _vwap_calc(self):
        tp = (self.data.High + self.data.Low + self.data.Close) / 3
        return (tp * self.data.Volume).cumsum() / self.data.Volume.cumsum()

    def _rsi_calc(self, close, n):
        # Wilder's smoothing 사용
        delta = pd.Series(close).diff()
        gain = delta.where(delta > 0, 0)
        loss = -delta.where(delta < 0, 0)
        avg_gain = gain.ewm(alpha=1/n, adjust=False).mean()
        avg_loss = loss.ewm(alpha=1/n, adjust=False).mean()
        rs = avg_gain / avg_loss
        return 100 - (100 / (1 + rs))

    def next(self):
        # 시간 손절
        if self.position and (len(self.data) - self.entry_bar) >= self.time_stop_bars:
            self.position.close()
            return

        # 진입 로직
        if not self.position:
            deviation = (self.data.Close[-1] - self.vwap[-1]) / self.vwap[-1]
            rsi_cross = self.rsi[-2] < 30 and self.rsi[-1] >= 35

            if deviation < -0.015 and rsi_cross:
                size = self._calc_position_size()
                sl = self.data.Close[-1] * (1 - self.sl_pct)
                tp = self.data.Close[-1] * (1 + self.tp_pct)
                self.buy(size=size, sl=sl, tp=tp)
                self.entry_bar = len(self.data)

    def _calc_position_size(self):
        risk_amount = self.equity * self.risk_pct
        stop_distance = self.data.Close[-1] * self.sl_pct
        return int(risk_amount / stop_distance)

 

이 단계에서 AI 에이전트는 정말 유능한 페어 프로그래머처럼 작동한다. "수수료 0.015%, 슬리피지 1틱 적용해서 다시 돌려달라"고 하면 바로 반영해준다. 다만 백테스팅 결과를 해석하는 건 100% 사람 몫이다. 샤프지수 2.5짜리 결과가 나왔다고 흥분하기 전에, 표본이 충분한지(거래 수가 200개 미만이면 거의 노이즈), 룩어헤드 바이어스가 없는지, 데이터 스누핑은 없는지를 따져야 한다.

3.4. 페이퍼 트레이딩  절대 건너뛰면 안 되는 단계

20년차로서 가장 단호하게 말할 수 있는 부분이다. 백테스팅과 실전 사이에는 페이퍼 트레이딩이 반드시 들어가야 한다. 그리고 최소 1개월, 가능하면 한 번의 옵션 만기일과 한 번의 FOMC를 포함하는 기간이 좋다.

한국투자증권 KIS API의 모의투자 환경, IBKR의 Paper Trading 계좌, Alpaca의 Paper API가 대표적이다. 이 단계에서 잡히는 버그는 거의 항상 시간 처리, 주문 체결 확인 로직, 부분 체결 처리, 네트워크 끊김 복구에서 나온다. 백테스팅에선 절대 안 보이는 것들이다.

3.5. 라이브 배포와 모니터링

소액부터 시작한다. 백테스팅과 페이퍼 트레이딩에서 잘 나왔다고 바로 풀 사이즈로 가는 건 자살행위다. 보통 의도한 사이즈의 10%로 2주, 30%로 2주, 그다음에 풀 사이즈로 올리는 게 안전하다.

모니터링은 텔레그램 봇으로 매매 알림을 받는 게 가장 가성비 좋다. 이것도 바이브 코딩으로 30분이면 붙인다.

 

3.6. 지속적인 개선과 전략 디그러데이션 추적

알파는 마모된다. 시장이 바뀌고, 같은 전략을 따라 하는 사람이 늘어나면 엣지가 사라진다. 월별 PnL의 회귀선 기울기, 승률, 평균 손익비, 최대낙폭을 자동으로 추적하는 대시보드를 만들어두는 게 좋다. 이것도 Streamlit 같은 라이브러리에 데이터프레임 던져주면 AI가 30분 안에 만들어준다.

 

4. 실전에서 마주친 함정들

첫째, AI는 그럴듯하게 틀린다. 특히 한국 시장 특유의 거래 단위(주식 1주, 미니선물 0.05포인트), VI 발동 조건, 동시호가 시간대 같은 디테일에서 자신감 있게 잘못된 코드를 내놓는다. 도메인 지식 없는 사람은 이걸 그대로 쓴다.

둘째, 데이터 품질이 결국 발목을 잡는다. 무료 데이터는 정정공시 반영이 늦거나, 액면분할·합병 처리가 들쭉날쭉하다. 진지하게 운용할 거면 유료 데이터(Refinitiv, FnGuide, KRX 정식 데이터)로 옮겨가는 시점이 반드시 온다.

셋째, 과최적화의 유혹이 더 강해진다. 파라미터를 바꿔가며 백테스팅을 돌리는 게 너무 쉬워졌기 때문이다. 워크포워드 분석과 OOS(Out-of-Sample) 테스트는 선택이 아니라 필수다.

넷째, '내 전략'을 AI에 입력하는 순간의 보안 이슈도 생각해야 한다. 정말 엣지가 있는 시그널이라면, 클라우드 모델보다는 로컬에서 돌릴 수 있는 모델이나 본인 환경에서 작동하는 코딩 도구를 고민해볼 만하다.

 

5. 마치며

바이브 코딩은 트레이더의 지적 자산을 코드로 변환하는 비용을 한 자릿수로 줄였다. 다만 변환 비용이 줄었을 뿐, 전략 자체의 가치를 만들어주지는 않는다. 결국 백테스팅 결과를 의심할 줄 아는 회의주의, 실패한 거래에서 패턴을 읽어내는 직관, 시장 미시구조에 대한 누적된 감각은 여전히 사람의 영역이다.

다만 이제는 그 감각을 가진 사람이 외주에 의존하지 않고 자신의 시스템을 자신의 속도로 만들 수 있는 시대가 됐다. 책상 앞에서 차트만 보던 트레이더가 한 달 만에 자기 손으로 페이퍼 트레이딩 봇을 돌리는 광경은, 5년 전에는 상상하기 어려웠다. 진입장벽이 사라진 만큼, 결국 차이를 만드는 건 다시 본질로 돌아간다. 무엇을 자동화할 가치가 있는가, 그 질문에 대한 답이다.