얼럿 메시지, 이 규격 그대로
TradingView의 Webhook URL 칸에는 콘솔에서 발급한 개인 웹훅 주소를, 메시지 칸에는 아래 JSON 예시를 붙여넣으세요. Pine 헬퍼로 조립해도 됩니다.
Pine Script를 짜는 AI 에이전트(Claude / Codex)용: /llms.txt 를 가져와 프롬프트에 그대로 넣으세요. 이 계약 전체·템플릿·체크리스트가 평문으로 들어 있습니다.
source: TV 없으면 주문 안 나감
source 값은 대소문자를 구분하여 정확히 TV여야 합니다. 없거나 다르면 HTTP 200으로 무시하며 매매일지에도 기록하지 않습니다.
BingX 신호는 실주문입니다: MARKET 진입, STOP_MARKET 손절, TAKE_PROFIT_MARKET 익절, reduce-only MARKET 청산(헤지 모드). 수량은 얼럿에서 받지 않습니다: 콘솔 설정(레버리지·마진%)과 진입 직전 가용 마진 조회로 서버가 계산합니다. 진입 체결 이후 어떤 단계라도 실패하면 거래소 확인을 요구하는 상태로 기록합니다.
30초 요약
- POST https://tvhook.app/hook/<token>. 본문은 반드시 JSON — TradingView는 얼럿 메시지를 그대로 보내므로 메시지 자체가 JSON이어야 합니다.
- 얼럿 하나에 객체 하나: source, action(entry|exit), symbol, direction(long|short), exchange(bingx), ep, sl, tp. alert_id는 선택.
- 수량·레버리지는 페이로드에 없습니다. 서버가 콘솔 설정(레버리지·마진%·사다리)과 진입 직전 가용 마진으로 계산합니다.
- entry = 거래소에 MARKET 진입 + STOP_MARKET 손절 + TAKE_PROFIT_MARKET 익절. 심볼·방향당 포지션 하나.
- exit = 추적 수량 전량 reduce-only MARKET 청산 후 남은 스탑 취소.
- Pine: alert(msg, alert.freq_once_per_bar) + 알림 조건 "Any alert() function call" + barstate.isrealtime 가드 + JSON 문자열 직접 조립.
웹훅 계약
| 필드 | 필수여부 | 설명 | 예시값 |
|---|---|---|---|
source | 필수 | 정확한 신호 출처. 에코 메시지는 이 게이트를 통과하지 못합니다. | TV |
action | 필수 | entry는 포지션 진입, exit는 추적 중인 포지션을 reduce-only MARKET으로 청산합니다. | entry |
symbol | 필수 | 거래소 종목 코드. BTCUSDT·BTC-USDT·BTCUSDT.P·BINGX:BTCUSDT.P 모두 BingX BTC-USDT로 매핑(접두사·.P 제거). | BTCUSDT |
direction | 필수 | long 또는 short만 허용(buy/sell 거부). exit는 열린 포지션 방향과 일치해야 합니다. | long |
exchange | 필수 | bingx(유일한 지원 거래소). | bingx |
ep | 필수 | 진입·기준 가격. 유한한 양수 또는 십진 문자열. exit에도 필수(값은 무시). | 60000 |
tp | 필수 | 익절 가격(TAKE_PROFIT_MARKET). 진입: 롱은 ep보다 높게, 숏은 낮게. exit: 양수면 됨. | 65000 |
sl | 필수 | 손절 가격(STOP_MARKET). 진입: 롱은 ep보다 낮게, 숏은 높게. exit: 양수면 됨. | 58000 |
alert_id | 선택 | 중복 방지 태그. 영숫자·_.- 64자 이내. 같은 신호가 10분 안에 다시 오면 무시하므로 봉마다 다른 alert_id를 주면 구분됩니다. | bar-1726200000 |
진입 가격 순서를 강제합니다: 롱은 sl < ep < tp, 숏은 tp < ep < sl(등호 불가). 아니면 HTTP 400. exit 얼럿도 ep/tp/sl에 양수를 채워야 합니다 — 셋 다 현재가를 넣으세요.
진입 얼럿 예시
청산 얼럿 예시 · 추적 중인 롱 포지션 청산
exit는 tvhook이 같은 종목·같은 방향의 열린 포지션을 추적 중일 때만 실행되며, 아니면 rejected로 기록합니다. reduce-only MARKET 청산을 먼저 보내고 남은 손절·익절 주문을 취소합니다.
지원 형식
예시의 직접 JSON 객체 또는 {"content":"source: TV\nsymbol: BTCUSDT\n…"} 형태의 유효한 JSON을 보내세요. content가 있으면 그 내용만 파싱합니다. key: value는 줄바꿈·공백·쉼표·|로 구분하며 중복 필드는 거부합니다. 얼럿에 API 키나 시크릿을 넣지 마세요.
응답과 거부 코드
HTTP: 미등록 토큰 404 · 잘못된 JSON·규격 위반 400 · 본문 16KB 초과 413 · DB 실패 500. 통과한 신호는 전부 200과 {id, status, error_code} — 거부도 HTTP 200이므로 본문을 읽어야 합니다. source≠TV → 200 ignored. 10분 내 중복 → 200 duplicate.
| status | error_code | 의미 |
|---|---|---|
rejected | invalid_symbol | 심볼이 BASE-QUOTE로 정규화되지 않음. |
rejected | keys_missing / keys_invalid / keys_ambiguous | 콘솔에 쓸 수 있는 BingX API 키가 없음. |
rejected | position_exists | 같은 심볼·방향 포지션을 이미 추적 중인데 entry가 옴. exit부터 보내세요. |
rejected | no_position | 추적 중인 포지션이 없는데 exit가 옴. |
rejected | direction_mismatch | exit 방향이 열린 포지션과 다름. 반대 진입으로 바뀌지 않습니다. |
rejected | position_locked | 다른 exit·리컨실이 그 포지션을 처리 중. 1분 뒤 재시도. |
sizing_failed | qty_below_minimum / no_available_margin / contract_missing | 전송 안 함: 계산 수량이 계약 최소 미만이거나 가용 마진 없음. |
leverage_failed | bingx_<code> | 레버리지 설정 거부. 전송 안 함. |
entry_rejected | bingx_<code> / order_<status> | 거래소가 MARKET 진입을 거부, 열린 것 없음. bingx_101414 = 마진 모드 "Separate Cross"(거래소 준비 참고). |
entry_unknown / entry_unconfirmed | <transport> / fill_<status> | 주문이 존재할 수 있음: needs_review로 보류, 크론이 매분 리컨실. |
sl_attach_failed | bingx_<code> | 진입 체결됐지만 손절 부착 실패: 크론이 재부착할 때까지 open_no_sl. |
filled | null / tp_attach_failed | 진입 체결·보호됨(익절 부착은 실패했을 수 있음 — 손절은 있음). |
exit_rejected / exit_unknown | bingx_<code> / qty_unknown / <transport> | 청산 미확인. 스탑은 그대로 두고 크론이 매분 재시도. |
closed | null / already_closed / sl_filled / tp_filled | 청산 또는 리컨실 완료. sl_filled / tp_filled = 거래소 스탑이 청산, 손익 기록됨. |
Pine 템플릿 (복붙)
Pine v6. 헬퍼가 JSON을 직접 조립하고 숫자는 str.tostring(x, format.mintick), alert_id는 봉 시각입니다. 라이브 검증된 테스트 스크립트와 같은 문법으로 썼지만 여기서 컴파일하지는 않았습니다 — Pine 에디터에서 한 번 컴파일하고 쓰세요.
헬퍼 — 로직 위에 한 번 붙여넣기
strategy() 삽입 예
indicator() 삽입 예
TradingView 알림 생성 (3단계)
- Add the script to the chart, then open Alerts and create an alert on it (not on the symbol).
- Condition: pick the script and choose "Any alert() function call" — the Message box is ignored; alert() supplies the JSON.
- Notifications: enable Webhook URL and paste https://tvhook.app/hook/<token> from your console. Expiration: open-ended.
흔한 실수 체크리스트
- 메시지가 JSON이 아니라 평문 "source: TV …" → 400 Invalid JSON. 텍스트 형식은 {"content":"…"}로 감쌌을 때만 통과.
- alert()에 barstate.isrealtime 가드가 없음 → 과거봉 훑는 동안 상태가 소진돼 실시간에 아무것도 안 쏨.
- alert()에 alert.freq_once_per_bar가 없음 → 봉 하나에 웹훅 여러 번.
- 알림 조건을 Crossing / Greater than / 주문 체결로 고름 → "Any alert() function call"이어야 JSON이 나감.
- exit 얼럿에 ep/sl/tp 누락 → 400. 셋 다 현재가로 채우세요.
- direction에 buy / sell → 400. long / short만.
- SL 방향 반대(롱인데 sl ≥ ep, 숏인데 sl ≤ ep) → 400.
- 정규화 안 되는 심볼(이상한 접미사·접두사) → rejected invalid_symbol. BTCUSDT·BTCUSDT.P·BINGX:BTCUSDT.P는 됨.
- BingX 마진 모드 "Separate Cross"(NEW) → 모든 API 주문이 bingx_101414로 거부. Cross / Isolated / Separate Isolated만.
- 포지션이 열린 채 두 번째 entry → position_exists. exit 방향 ≠ 열린 방향 → direction_mismatch.
- alert_id 없이 같은 신호가 10분 안에 반복 → duplicate로 조용히 미실행.
- 얼럿 본문에 API 키·시크릿·웹훅 토큰 금지. 추가 필드(qty, leverage)는 무시됩니다.
TP/SL·정산 동작
- 스탑은 거래소에 걸려 있습니다(reduce-only, 헤지 모드). 가격이 닿으면 BingX가 얼럿 없이 포지션을 닫습니다.
- 그 다음에 오는 같은 심볼·방향 exit 얼럿이 라이브 포지션 없음을 확인하고 추적 중인 스탑 주문을 조회해 closed + sl_filled(패) 또는 tp_filled(승)로 청산가·손익을 기록합니다. 새 주문은 안 보냅니다.
- 보류 포지션(needs_review, open_no_sl)은 크론이 매분 훑습니다: 거부된 청산 재전송, 네이키드 포지션 스탑 재부착, 사라진 포지션 정산.
- 전략이 거래 종료로 보는 모든 경우(TP·SL·시간 종료·반대 신호)에 반드시 exit 얼럿을 쏘세요. 없으면 일지 행이 열린 채 남아 다음 entry가 position_exists로 거부됩니다.
- 부분 청산 없음: exit는 추적 수량 전량. 뒤집으려면 exit 다음 반대 방향 entry(얼럿 둘).
- 역마틴 사다리(켜져 있으면)는 정산된 승패마다 레버리지를 옮기며, 페이로드는 이를 제어하지 않습니다.
거래소 준비 (BingX USDT-M 무기한)
- 심볼별 마진 모드: Cross / Isolated / Separate Isolated. "Separate Cross"는 금지 — API 주문 소스를 거부합니다(101414, 2026-09-14 실측).
- 포지션 모드: 헤지(LONG / SHORT). tvhook이 진입 전 방향별 레버리지를 설정합니다.
- API 키는 하위 계정에, 거래 권한만, 출금 권한 없이. 콘솔은 출금 불가 확인 없이는 키를 받지 않으며 권한을 API로 검증하지 않습니다 — 직접 확인하세요.
- 사이징: 레버리지 1~100(기본 3), 진입당 가용 잔고 대비 마진% 0.1~95(기본 10). 명목 = 가용 × 마진% × 레버리지, 수량은 계약 단위로 내림. 너무 작으면 sizing_failed qty_below_minimum.
- 레버리지 3·마진 1~5%·30초봉 테스트 스크립트로 시작해 일지에서 진입→청산 왕복 하나를 확인한 뒤 실제 전략을 연결하세요.