자동매매를 처음 구축했을 때 저는 시그널 자체보다 알림 설정에서 더 많은 손실을 봤습니다. 전략 로직은 백테스트에서 잘 돌아갔는데, 막상 실계좌에서 트레이딩뷰 알림이 엉뚱한 타이밍에 발화하거나 중복으로 쏘아지는 경우가 반복됐습니다. 알림이 한 번 어긋나면 웹훅 → Flask API → 거래소 주문까지 연쇄적으로 틀어집니다. 이번 주 칼럼은 제가 4시간봉 멀티코인 환경을 운영하면서 직접 부딪힌 트레이딩뷰 알림 정확도 문제와 그 해결 과정을 정리한 기록입니다.
문제 정의 — 알림은 발화했는데 왜 타이밍이 어긋나는가
트레이딩뷰 알림의 가장 흔한 오작동은 크게 세 가지입니다. 첫째, 캔들 확정 전 알림입니다. Pine Script에서 조건을 단순히 crossover(fast_ma, slow_ma) 형태로 작성하면, 현재 캔들이 아직 진행 중인 상태에서 조건이 잠시 충족됐다가 캔들 마감 전에 조건이 해소되는 경우에도 알림이 발화됩니다. 4시간봉 기준으로 이 문제는 꽤 빈번합니다. 해결법은 barstate.isconfirmed 조건을 논리식 앞에 추가하는 것입니다. if barstate.isconfirmed and crossover(fast_ma, slow_ma) 형태로 감싸면 캔들이 완전히 확정된 시점에만 알림이 나갑니다. 둘째, 알림 지속 조건 설정입니다. 트레이딩뷰 알림 생성 시 『조건이 충족될 때마다』가 아닌 『한 번만』으로 설정해두면, 전략이 리셋될 때 알림이 다시 활성화되지 않습니다. 저는 이 설정을 놓쳐서 며칠간 시그널을 받지 못한 채 포지션이 방치된 적이 있습니다. 셋째, 다중 코인 알림을 같은 스크립트 인스턴스로 관리할 때 발생하는 타임존 편차입니다. UTC 기준 캔들 마감 시점이 코인마다 수 초씩 다를 수 있고, 이게 누적되면 슬리피지 이상의 타이밍 손실로 이어집니다. 저는 현재 BTC, ETH, SOL 각각에 독립 알림 인스턴스를 생성하고, 각 웹훅 메시지에 심볼명과 타임스탬프를 함께 포함시켜 추적 가능하게 만들고 있습니다.
해결 접근 — 웹훅 메시지 구조 설계가 정확도를 결정한다
알림 조건을 잘 잡아도 웹훅 메시지 설계가 엉성하면 Flask API 쪽에서 파싱 오류가 납니다. 저는 초기에 웹훅 본문을 단순 텍스트로 보냈다가 파이썬 쪽에서 예외 처리를 못 해 주문이 두 번 들어간 사례를 경험했습니다. 지금은 JSON 형식으로 웹훅 본문을 구성하며 필수 필드를 다섯 가지로 고정하고 있습니다. symbol(거래 페어), side(long/short/close), timeframe(4h), price({{close}}), timestamp({{timenow}}) 입니다. Pine Script에서는 alert() 함수 안에 문자열 템플릿으로 이 필드들을 채워 넣을 수 있습니다. 예를 들어 alert(‘{ symbol: BTCUSDT, side: long, timeframe: 4h, price: ‘ + str.tostring(close) + ‘, timestamp: ‘ + str.tostring(timenow) + ‘ }’, alert.freq_once_per_bar_close) 형태입니다. 여기서 alert.freq_once_per_bar_close 파라미터가 핵심입니다. 이 옵션을 쓰면 캔들 마감 시점에만 알림이 한 번 발화하므로, barstate.isconfirmed와 이중으로 방어막이 형성됩니다. Flask API 수신 쪽에서는 반드시 timestamp 필드를 검사해 이전 5분 이내 같은 심볼·방향 조합의 중복 요청을 걸러내는 de-duplication 로직을 추가해야 합니다. 저는 Redis를 따로 띄우지 않고 파이썬 딕셔너리에 last_signal_time을 심볼별로 저장하는 가벼운 방식으로 운영 중이며, 이것만으로도 중복 주문을 대부분 차단할 수 있었습니다.
실전 적용 — 알림 바깥에 필터 레이어를 추가하면 생존율이 달라진다
트레이딩뷰 알림 정확도를 높이는 마지막 단계는 알림 자체가 아니라 알림 바깥에 조건 필터를 추가하는 것입니다. 저는 현재 세 가지 레이어를 순서대로 적용하고 있습니다. 1단계는 트레이딩뷰 내부 필터입니다. 주요 지지/저항 구간에서만 알림이 발화하도록 ATR 기반 변동성 조건을 and 연산으로 연결합니다. atr_14 = ta.atr(14) 값이 일정 임계값 이상일 때만 시그널을 허용하는 식입니다. 잠잠한 장에서 노이즈 알림이 절반 이상 줄었습니다. 2단계는 Flask API 내부 필터입니다. 수신된 시그널의 price 값이 현재 거래소 실시간 가격과 0.5% 이상 차이 날 경우 주문을 보류합니다. 트레이딩뷰 서버 지연이나 네트워크 레이턴시로 인해 시그널 발화 후 실제 집행까지 수 초~수십 초 차이가 날 수 있고, 이 구간에서 가격이 급변하면 의도치 않은 진입이 생깁니다. 3단계는 포지션 상태 확인입니다. 거래소 API로 현재 해당 심볼의 포지션 사이즈를 조회한 뒤, 이미 같은 방향 포지션이 열려 있으면 신규 주문을 막습니다. 이 로직은 트레이딩뷰 알림이 중복 발화하더라도 거래소 레벨에서 2차 방어가 되기 때문에 가장 믿을 수 있는 안전망입니다. 세 레이어를 모두 붙인 이후로 오발주 빈도가 현저히 줄었고, 현재도 관찰 중입니다.
💬 운영자 한마디
저는 알림 설정을 처음엔 가볍게 봤습니다. 전략 로직이 좋으면 다 해결되는 줄 알았죠. 근데 실전에서 진짜 구멍은 대부분 인프라 레이어에 있었습니다. 트레이딩뷰 알림 하나를 제대로 설계하는 데 코딩보다 더 많은 시간을 쓴 적도 있습니다. 귀찮더라도 심볼별 독립 인스턴스, barstate.isconfirmed, de-duplication, 포지션 확인 이 네 가지는 꼭 챙기시길 권합니다.
— J_River · autoprofit 운영자
✅ 이번 주 체크리스트
- Pine Script 조건에 barstate.isconfirmed 또는 alert.freq_once_per_bar_close 반드시 포함
- 웹훅 메시지 본문을 JSON 형식으로 구성하고 symbol, side, timestamp 필드 고정
- Flask API 또는 수신 서버에 5분 이내 중복 시그널 차단 로직 추가
- 시그널 수신 price 와 실시간 거래소 가격 간 0.5% 이상 차이 시 주문 보류 처리
- 주문 전 거래소 API로 현재 포지션 사이즈 조회해 중복 진입 방지
- ATR 등 변동성 지표를 and 조건으로 연결해 잠잠한 장 노이즈 알림 제거
- BTC, ETH, SOL 등 코인별로 트레이딩뷰 알림 인스턴스를 분리해 타임존 편차 최소화
알림 정확도는 전략 수익률만큼 중요한 인프라 지표입니다. 이번 주 설정을 한 번 점검해보세요. 작은 설정 하나가 오발주를 막는 가장 확실한 방어선입니다.
※ 본 콘텐츠는 운영자 개인의 경험과 연구를 바탕으로 한 정보 제공 목적이며, 특정 종목에 대한 투자 권유나 매매 시그널이 아닙니다. 암호화폐 및 자동매매는 원금 손실 가능성이 있는 고위험 활동이며, 모든 투자 판단과 그 결과에 대한 책임은 투자자 본인에게 있습니다.