설정 분리와 재시도 로직 통합 정리 | 토스 개발기 #1

토스 자동매매 개발기 시리즈 (현재 3번째 글 · 전체 3편)

이전 글: Phase 0-1 — 통화 표시 버그 수정 / 다음 글: 발행 후 추가 예정

Phase 0에서 기반 시스템을 만들고, Phase 0-1에서 통화 표시 버그를 잡았다. 로드맵대로면 이제 Phase 1, 안정성과 설정 관리를 강화할 차례다. 오늘은 그중 두 가지를 끝냈다.

문제: 흩어진 설정값과 중복된 재시도 코드

종목코드, 감시 주기, 목표가 같은 값들이 여러 파일에 하드코딩되어 있었다. 값 하나 바꾸려면 파일을 4~5개씩 열어야 했다. 재시도·타임아웃 처리 로직도 마찬가지였다 — 같은 로직이 파일마다 복사-붙여넣기 되어 있었다.

작업 1: config.py로 설정 중앙화

신규 config.py를 만들어 TARGET_STOCKS, TARGET_SYMBOL, ORDER_QUANTITY, MONITOR_INTERVAL, ERROR_BACKOFF_INTERVAL, MAX_CONSECUTIVE_ERRORS, DEFAULT_TIMEOUT을 한곳에 모았다. get_price.py, auto_trader.py, toss_common.py가 이 값을 참조하도록 고쳤다.

여기서 중요한 건 DRY_RUN=True, TARGET_BUY_PRICE=1 같은 안전장치 값은 손대지 않고 그대로 유지한 것이다. 3중 안전 브레이크 원칙은 리팩토링 중에도 예외 없이 지킨다. python get_price.py를 돌려서 가상 종목(삼성전자 005930) 시세가 정상 조회되는 것까지 확인했다.

작업 2: 재시도·백오프 로직 하나로 합치기

toss_common.pyretry_on_network_error() 데코레이터를 새로 만들었다. Timeout이나 네트워크 오류일 때만 자동 재시도하고, 횟수·간격은 config.py에서 관리한다. get_access_token, get_account_sequence, get_current_prices, fetch_holdings, fetch_holdings_raw에 적용했다.

다만 auto_trader.pyget_current_price()에는 일부러 데코레이터를 적용하지 않았다. 감시 루프 자체가 이미 재시도 성격을 가지고 있어서, 여기까지 데코레이터를 붙이면 재시도가 중복된다. “즉각 재시도(1차 방어)”와 “장기 백오프(2차 방어)”를 계층으로 분리하는 쪽을 택했다.

재시도 로직을 데코레이터로 통합하면 네트워크 오류 대응 코드가 한 곳에 모여 유지보수가 쉬워지고, 감시 루프와의 중복 재시도를 피할 수 있다.

강제로 Timeout을 모킹해서, 설정된 횟수만큼만 재시도하고 이후 안전하게 기본값을 반환하는지도 테스트했다.

삽질: 회귀 사고와 복구

재시도 데코레이터 작업 중에 사고가 났다. 지난번(7/7)에 고쳐놨던 toss_portfolio.py의 KRW/USD 통화 분리 기능이 어느 순간 사라져 있었다. 원인을 뜯어보니, 작업을 시작할 때 최신 로컬 파일이 아니라 구버전 파일을 기준으로 코드를 이어붙인 거였다.

다행히 사용자가 실행 결과(원화만 표시되는 화면)를 공유해준 덕분에 배포 전에 조기 발견됐다. 복구 후에는 가상 테스트 데이터로 함수를 직접 실행해서 재검증했다. 재발 방지책도 하나 세웠다 — 파일을 교체하기 전에 Select-String(또는 grep)으로 핵심 함수명이 실제로 존재하는지 먼저 확인하는 절차를 넣기로 했다.

다음 로드맵

Phase 1의 남은 항목은 로그 파일 회전(RotatingFileHandler)과 pytest 단위 테스트 도입이다. 오늘 겪은 회귀 사고는 사실 pytest가 왜 필요한지를 그대로 보여주는 사례였다. 다음 글은 아마 이 두 가지로 이어질 것 같다.

“설정 분리와 재시도 로직 통합 정리 | 토스 개발기 #1”에 대한 11개의 생각

댓글 남기기