복수 종목 동시 감시 기능 구현기 | 토스 개발기 #2-2

strategy.py로 매수 판단 로직을 분리한 지 하루 만에, 로드맵에 적어뒀던 다음 항목으로 넘어갔다. 종목 하나만 보던 봇에 여러 종목을 동시에 붙이는 작업이다.

문제 상황: 종목 하나만 감시하던 구조의 한계

기존 auto_trader.pyconfig.pyTARGET_SYMBOL 하나(단일 문자열)만 감시하는 구조였다. 문제는 오류 처리 방식이었다. 연속 오류가 한도를 넘으면 감시 대상이 하나뿐이라는 전제 하에 엔진 전체가 종료돼 버렸다. 종목이 여러 개가 되면 이 방식은 더 이상 맞지 않는다. 한 종목에서 네트워크 오류가 계속 나도 나머지 종목은 멀쩡히 감시가 돌아야 하니까.

설계 결정: TARGET_SYMBOL → TARGET_SYMBOLS

config.pyTARGET_SYMBOL(단일 문자열)을 TARGET_SYMBOLS(리스트)로 바꿨다. 그리고 종목마다 독립된 ThresholdBuyStrategy 인스턴스와 독립된 연속 오류 카운터를 부여했다. 한 종목의 상태가 다른 종목에 새어 들어가지 않도록 하는 게 핵심이었다.

가장 크게 바꾼 부분은 오류 처리 정책이다. 기존엔 오류 한도 초과 시 엔진 전체 종료였는데, 이번엔 해당 종목만 감시 목록에서 제외하고 나머지는 계속 돌아가도록 바꿨다. 가용성 측면에서는 확실히 나아졌지만, 반대로 “조용히 하나가 빠져도 못 알아차리는” 리스크는 남는다. 이 부분은 나중에 알림 로직으로 보완할 생각이다.

토큰 만료는 종목별 이슈가 아니라 전체 공통 이슈라서, 감지되는 즉시 재인증 후 전체 종목을 다시 조회하도록 처리했다.

class SymbolWatcher:
    def __init__(self, symbol, strategy, max_error_count=5):
        self.symbol = symbol
        self.strategy = strategy
        self.error_count = 0
        self.max_error_count = max_error_count
        self.active = True

    def handle_error(self):
        self.error_count += 1
        if self.error_count >= self.max_error_count:
            self.active = False  # 이 종목만 제외, 엔진은 계속 실행

예시로 삼성전자(005930), SK하이닉스(000660), 카카오(035720), 네이버(035420) 4개 가상 종목을 등록해서 테스트했다. (실제 계좌의 종목·금액과는 무관한 예시다.)

검증: 모킹 시뮬레이션 → 실사용자 로컬 실행

1차로는 실제 API 없이 모킹 시뮬레이션을 돌렸다. “즉시 매수 성공”, “계속 네트워크 오류로 제외”, “정상 감시 지속 후 매수” 이 3가지 케이스를 가상 종목으로 동시에 실행해서, 각 종목이 서로 간섭 없이 독립적으로 처리되는지 확인했다.

2차는 실제로 4개 가상 종목을 등록하고 auto_trader.py를 직접 실행했다. 5초 간격으로 4개 종목이 순서대로 정상 감시되는 걸 눈으로 확인했다.

기존 pytest 38개 테스트는 전부 회귀 없이 통과했고, DRY_RUN=True, TARGET_BUY_PRICE=1 같은 안전장치 값은 이번 작업에서 손대지 않았다.

삽질 기록: TARGET_STOCKS와 TARGET_SYMBOLS

종목 리스트를 4개로 늘렸는데도 실행해 보면 여전히 1개 종목만 감시되는 현상이 있었다. 원인을 찾아보니 config.py 안에 이름이 비슷한 변수가 두 개 있었다. TARGET_STOCKS는 시세 조회용으로 get_price.py가 쓰는 변수였고, 정작 자동매매 감시 대상으로 쓰이는 건 TARGET_SYMBOLS였다. 앞의 것을 고쳤으니 반영이 안 될 수밖에.

원인을 확인하고 정확한 변수를 수정하니 바로 해결됐다. 이름이 너무 비슷해서 헷갈리기 쉬운 부분이라, 나중에 더 구분되는 이름으로 리네이밍하는 걸 로드맵에 참고사항으로 남겨뒀다.

다음 로드맵: 플러그인 인터페이스 설계

Phase 2의 남은 항목은 이동평균·RSI 같은 지표 기반 전략을 플러그인 형태로 추가할 수 있는 인터페이스 설계다. 오늘 종목별로 독립된 전략 인스턴스를 만들어둔 구조가 다음 단계와 자연스럽게 이어질 것 같다.

FAQ

Q. 여러 종목을 감시하다가 하나가 계속 오류가 나면 어떻게 되나요?

연속 오류 한도를 넘긴 종목만 감시 목록에서 제외되고, 나머지 종목은 계속 정상적으로 감시됩니다. 예전처럼 엔진 전체가 종료되지 않습니다.

Q. 종목별로 서로 다른 매수 전략을 쓸 수 있나요?

네, 종목마다 독립된 전략 인스턴스를 부여하는 구조라 이론적으로는 가능합니다. 다만 이번 글에서는 동일 전략을 여러 종목에 병렬로 적용하는 것까지만 검증했습니다.

Q. 토큰 만료도 종목별로 따로 처리하나요?

아니요. 토큰 만료는 전체 종목에 공통으로 영향을 주는 이슈라서, 감지되는 즉시 재인증 후 전체 종목을 다시 조회하도록 처리했습니다.