트레이딩뷰 자동매매 완전 가이드 — Pine Script부터 웹훅·증권사·거래소 연동까지
트레이딩뷰는 한국 트레이더에게 가장 친숙한 차트 플랫폼이고, "내 차트에서 신호가 나오면 자동으로 매매됐으면" 이라는 욕구는 자동매매 의뢰 1순위 패턴입니다. 그러나 트레이딩뷰는 차트·알람만 담당하고 실제 주문은 본인이 만든 서버에서 처리해야 합니다. 그 분담의 전체 그림을 처음부터 끝까지 정리한 한국어 자료는 의외로 적습니다.
이 글은 입문자가 따라가면 작동하는 트레이딩뷰 자동매매를 완성할 수 있게 8부로 구성했습니다. Pine Script 기본 전략, 알람 설정, Python Flask 웹훅 서버, 그리고 한국 주식 2개(키움·KIS) + 코인 거래소 3개(바이낸스·업비트·빗썸) 모두의 연동 코드를 포함합니다.
이 글의 8부 구성
- Part 1 — 트레이딩뷰 자동매매 전체 구조 (3개 컴포넌트의 역할)
- Part 2 — Pine Script 입문 (전략·알람·시그널)
- Part 3 — 알람 설정과 웹훅 메시지 포맷
- Part 4 — Python Flask 웹훅 서버 구축
- Part 5 — 한국 증권사 연동 (키움 OpenAPI+, KIS API)
- Part 6 — 코인 거래소 연동 (바이낸스·업비트·빗썸)
- Part 7 — 보안과 운영 (시그너처·VPS·헬스체크)
- Part 8 — 체크리스트 + 5가지 함정
Part 1 — 트레이딩뷰 자동매매 전체 구조
"차트와 신호는 트레이딩뷰가, 실거래는 본인 서버가." 분담을 이해해야 모든 게 보입니다.
전체 흐름
3개 컴포넌트의 역할
| 컴포넌트 | 역할 | 구현 위치 |
|---|---|---|
| 트레이딩뷰 | 차트·지표·전략 신호 발생·알람 발송 | 트레이딩뷰 웹/앱 |
| 웹훅 서버 | 알람 수신·검증·증권사/거래소 API 호출 | 본인 VPS |
| 증권사·거래소 | 실주문 체결 | 키움/KIS/바이낸스/업비트/빗썸 |
왜 트레이딩뷰 + 외부 서버 분담인가
- 트레이딩뷰의 강점: 차트·지표·백테스트·알람이 모두 한 자리. Pine Script로 빠른 전략 프로토타이핑.
- 트레이딩뷰의 한계: 실제 주문 기능은 일부 거래소(바이낸스·OANDA 등)만 지원. 한국 증권사·업비트·빗썸 직접 주문 불가.
- 외부 서버의 역할: 트레이딩뷰가 보낸 신호를 받아 원하는 거래소·증권사 API로 변환·실행.
💡 한국 사용자가 트레이딩뷰 자동매매를 선호하는 이유: (1) Pine Script가 Python보다 진입장벽 낮음 (2) 차트 보면서 전략 검증 (3) 다양한 시장(주식·코인·선물) 동일 인터페이스 (4) 신호 발생 시점·로그가 차트에 시각화 — 이 4가지가 자동매매 본질과 잘 맞습니다.
Part 2 — Pine Script 입문
JavaScript 비슷한 단순 언어. 1~2주면 자동매매에 필요한 수준 충분.
가장 단순한 전략 — EMA 크로스
5일선이 20일선 위로 골든크로스 → 매수 신호. Pine Script v5 기준:
//@version=5
strategy("EMA Crossover", overlay=true)
// 입력 파라미터
fastLen = input.int(5, "Fast EMA")
slowLen = input.int(20, "Slow EMA")
// 지표 계산
fast = ta.ema(close, fastLen)
slow = ta.ema(close, slowLen)
// 매매 조건
longCondition = ta.crossover(fast, slow)
shortCondition = ta.crossunder(fast, slow)
// 전략 실행
if longCondition
strategy.entry("Long", strategy.long)
if shortCondition
strategy.close("Long")
// 차트 표시
plot(fast, color=color.blue)
plot(slow, color=color.red)
지표(Indicator) vs 전략(Strategy)
| 유형 | 용도 | 알람 발송 |
|---|---|---|
indicator() | 지표·시그널 표시 | alertcondition()로 가능 |
strategy() | 백테스트·자동 진입/청산 | 주문 발생 시 자동 알람 가능 |
자동매매 목적이면 strategy()로 작성. 백테스트 결과까지 한 번에 확인 가능.
웹훅용 알람 메시지 동적 생성
알람을 보낼 때 현재가·심볼·매매 방향·수량을 JSON으로 동적 생성하는 것이 표준:
// 알람 메시지 동적 변수 (트레이딩뷰 v5+)
alertMsg = '{"symbol":"' + syminfo.ticker +
'","action":"BUY",' +
'"price":' + str.tostring(close) +
',"time":"' + str.format_time(time, "yyyy-MM-dd HH:mm:ss") + '"}'
if longCondition
strategy.entry("Long", strategy.long, alert_message=alertMsg)
Pine Script 깊은 예시는 → 키움 자동매매 + 트레이딩뷰 웹훅 사례
Part 3 — 알람 설정과 웹훅 메시지 포맷
트레이딩뷰 차트 우상단 알람 버튼 → 웹훅 URL 설정.
알람 설정 5단계
- 차트에 전략 추가
- 알람 버튼 (시계 아이콘) 클릭
- Condition: 본인 전략의 진입/청산 이벤트 선택
- Webhook URL:
https://본인VPS/webhook입력 - Message 본문: Pine Script가 생성한 동적 JSON 사용 (또는
{{strategy.order.alert_message}})
표준 웹훅 메시지 포맷
{
"secret": "본인_시크릿_키",
"symbol": "BTCUSDT",
"action": "BUY",
"price": 60125.50,
"qty": 0.001,
"strategy": "EMA Crossover",
"time": "2026-06-16 10:23:00"
}
플랜별 알람 제한
| 플랜 | 월 비용 | 웹훅 가능? | 활성 알람 수 |
|---|---|---|---|
| Basic (무료) | $0 | ❌ | 1개 |
| Essential | $14.95 | ✅ | 20개 |
| Plus | $29.95 | ✅ | 100개 |
| Premium | $59.95 | ✅ | 400개 |
⚠️ 알람 누락 가능성: 트레이딩뷰는 알람 100% 보장하지 않습니다. 서버 부하·인터넷 끊김 시 누락. 결정적 매매(손절·청산)는 트레이딩뷰가 아니라 봇 자체 로직으로 백업해야 합니다.
Part 4 — Python Flask 웹훅 서버 구축
VPS에 100줄짜리 웹훅 서버. 모든 거래소·증권사 연동의 진입점.
최소 골격 — 100줄 Flask 서버
from flask import Flask, request, abort, jsonify
import json, os, hmac, hashlib
from datetime import datetime
app = Flask(__name__)
SECRET = os.getenv("TV_WEBHOOK_SECRET") # 환경변수에서 로드
# ─── 로깅 ──────────────────────────────────────
import logging
logging.basicConfig(filename="webhook.log", level=logging.INFO,
format="%(asctime)s %(levelname)s %(message)s")
log = logging.getLogger(__name__)
# ─── 메인 핸들러 ───────────────────────────────
@app.route("/webhook", methods=["POST"])
def webhook():
try:
data = request.get_json(force=True)
except Exception as e:
log.error(f"JSON 파싱 실패: {e}")
abort(400)
# 1. 시크릿 검증 — 무단 호출 차단
if data.get("secret") != SECRET:
log.warning(f"Invalid secret from {request.remote_addr}")
abort(403)
# 2. 중복 신호 차단 (5초 내 동일 페이로드 무시)
if is_duplicate(data):
log.info("Duplicate signal ignored")
return jsonify({"status": "duplicate"}), 200
# 3. 라우팅 — 심볼별 처리
symbol = data.get("symbol")
action = data.get("action")
log.info(f"신호 수신: {action} {symbol} @ {data.get('price')}")
try:
result = route_order(data)
log.info(f"체결: {result}")
return jsonify({"status": "ok", "result": result}), 200
except Exception as e:
log.error(f"주문 실패: {e}")
# 텔레그램 알림
send_telegram(f"주문 실패: {symbol} {action} - {e}")
return jsonify({"status": "error", "error": str(e)}), 500
# ─── 중복 신호 방어 (메모리 캐시) ─────────────
_recent = {}
def is_duplicate(data, window=5):
key = json.dumps(data, sort_keys=True)
now = datetime.now().timestamp()
if key in _recent and now - _recent[key] < window:
return True
_recent[key] = now
# 오래된 항목 정리
for k, t in list(_recent.items()):
if now - t > 60:
del _recent[k]
return False
# ─── 라우팅: 심볼별 거래소 결정 ───────────────
def route_order(data):
symbol = data["symbol"]
if symbol.endswith("USDT"):
return execute_binance(data)
elif symbol.startswith("KRW-"):
return execute_upbit(data)
elif symbol.isdigit(): # 한국 주식 (6자리)
return execute_kis(data)
else:
raise ValueError(f"Unknown symbol: {symbol}")
# ─── 텔레그램 알림 ─────────────────────────────
def send_telegram(msg):
import requests
token = os.getenv("TG_BOT_TOKEN")
chat = os.getenv("TG_CHAT_ID")
if token and chat:
requests.post(f"https://api.telegram.org/bot{token}/sendMessage",
json={"chat_id": chat, "text": msg})
if __name__ == "__main__":
# 운영은 gunicorn 권장
app.run(host="0.0.0.0", port=5000)
실행 (개발)
# .env (반드시 .gitignore 추가)
TV_WEBHOOK_SECRET=긴_랜덤_문자열_64자
TG_BOT_TOKEN=텔레그램_봇_토큰
TG_CHAT_ID=본인_챗_ID
pip install flask python-dotenv requests
python webhook_server.py
운영 (gunicorn + systemd)
# /etc/systemd/system/tv-webhook.service
[Unit]
Description=TradingView Webhook
After=network.target
[Service]
User=algolab
WorkingDirectory=/home/algolab/bot
ExecStart=/home/algolab/bot/venv/bin/gunicorn -w 2 -b 0.0.0.0:5000 webhook_server:app
Restart=always
[Install]
WantedBy=multi-user.target
Part 5 — 한국 증권사 연동
키움 OpenAPI+ 또는 KIS API. 한국 주식 자동매매의 두 갈래.
1. KIS API 연동 (권장)
REST API라 어디서나 작동. 토큰 자동 갱신 + 주문:
import requests, os, json, time
KIS_BASE = "https://openapi.koreainvestment.com:9443"
_token_cache = {"token": None, "expires": 0}
def get_kis_token():
if _token_cache["expires"] > time.time():
return _token_cache["token"]
url = f"{KIS_BASE}/oauth2/tokenP"
res = requests.post(url, json={
"grant_type": "client_credentials",
"appkey": os.getenv("KIS_APP_KEY"),
"appsecret": os.getenv("KIS_APP_SECRET")
})
d = res.json()
_token_cache["token"] = d["access_token"]
_token_cache["expires"] = time.time() + 23 * 3600
return d["access_token"]
def execute_kis(data):
"""트레이딩뷰 신호로 KIS 주식 주문"""
token = get_kis_token()
cano, acnt = os.getenv("KIS_ACCOUNT_NO").split("-")
tr_id = "TTTC0802U" if data["action"] == "BUY" else "TTTC0801U"
headers = {
"authorization": f"Bearer {token}",
"appkey": os.getenv("KIS_APP_KEY"),
"appsecret": os.getenv("KIS_APP_SECRET"),
"tr_id": tr_id
}
body = {
"CANO": cano,
"ACNT_PRDT_CD": acnt,
"PDNO": data["symbol"],
"ORD_DVSN": "01", # 시장가
"ORD_QTY": str(int(data["qty"])),
"ORD_UNPR": "0"
}
url = f"{KIS_BASE}/uapi/domestic-stock/v1/trading/order-cash"
res = requests.post(url, headers=headers, data=json.dumps(body))
return res.json()
KIS API 발급·토큰 자동 갱신 자세히: → KIS API 발급부터 첫 주문까지 30분
2. 키움 OpenAPI+ 연동
32bit Python + PyQt5 필요. Windows VPS 또는 별도 윈도우 머신:
# 키움 OpenAPI+는 비동기 OCX 컴포넌트라 별도 프로세스 권장
# webhook_server.py는 Flask가 받고, 키움 프로세스로 메시지 큐 전달
import zmq
def execute_kiwoom(data):
"""ZeroMQ로 32bit 키움 프로세스에 전달"""
ctx = zmq.Context()
socket = ctx.socket(zmq.REQ)
socket.connect("tcp://localhost:5555")
socket.send_json(data)
return socket.recv_json()
키움 OpenAPI+ 설치·오류 대응: → 키움 OpenAPI+ 설치·오류 해결 완전 가이드
Part 6 — 코인 거래소 연동
바이낸스·업비트·빗썸 — 같은 웹훅 서버에서 3개 거래소 동시 운영.
바이낸스 (현물)
from binance.client import Client
binance = Client(os.getenv("BINANCE_API_KEY"),
os.getenv("BINANCE_API_SECRET"))
def execute_binance(data):
if data["action"] == "BUY":
return binance.order_market_buy(
symbol=data["symbol"],
quoteOrderQty=data.get("usdt", 10))
elif data["action"] == "SELL":
return binance.order_market_sell(
symbol=data["symbol"],
quantity=data["qty"])
업비트
import pyupbit
upbit = pyupbit.Upbit(os.getenv("UPBIT_ACCESS_KEY"),
os.getenv("UPBIT_SECRET_KEY"))
def execute_upbit(data):
if data["action"] == "BUY":
return upbit.buy_market_order(data["symbol"],
data.get("krw", 10000))
elif data["action"] == "SELL":
return upbit.sell_market_order(data["symbol"], data["qty"])
빗썸
import python_bithumb as pb
bithumb = pb.Bithumb(os.getenv("BITHUMB_CONNECT_KEY"),
os.getenv("BITHUMB_SECRET_KEY"))
def execute_bithumb(data):
if data["action"] == "BUY":
return bithumb.buy_market_order(data["symbol"],
data.get("krw", 10000))
elif data["action"] == "SELL":
return bithumb.sell_market_order(data["symbol"], data["qty"])
각 거래소 봇 만들기 30분 시리즈:
Part 7 — 보안과 운영
웹훅 URL이 노출되면 누구든 매매 신호를 보낼 수 있습니다. 5가지 안전장치.
1. 시크릿 키 검증
모든 웹훅 페이로드에 secret 필드 포함, 서버에서 검증. 위 Flask 코드의 핵심.
2. HTTPS 필수
HTTP는 평문 → 시크릿 노출. Let's Encrypt 무료 인증서로 HTTPS 적용:
sudo apt install nginx certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.com
3. 트레이딩뷰 IP만 허용 (선택)
트레이딩뷰 웹훅 IP 목록만 화이트리스트:
# nginx
location /webhook {
allow 52.89.214.238; # 트레이딩뷰 IP
allow 34.212.75.30;
allow 54.218.53.128;
allow 52.32.178.7;
deny all;
proxy_pass http://localhost:5000;
}
4. 중복 신호·페이로드 검증
같은 페이로드가 5초 내 재도착하면 무시 (위 Flask 코드 is_duplicate).
5. 헬스체크 + 텔레그램
# 5분마다 자동 헬스체크
*/5 * * * * curl -s https://your-domain.com/health || \
curl -s -X POST "https://api.telegram.org/botTOKEN/sendMessage" \
-d "chat_id=CHAT&text=웹훅 서버 다운!"
✅ 운영 체크리스트: HTTPS · 시크릿 · 화이트리스트 · 중복 방어 · 헬스체크 — 5가지가 모두 작동하면 안심 운영 가능. 하나라도 빠지면 봇이 잘못 매매 또는 자산 유실 위험.
Part 8 — 16단계 체크리스트 + 5가지 함정
실전 운영 시작 전 마지막 점검.
5가지 함정
함정 1. 알람 누락에 대한 대비 없음
트레이딩뷰 알람이 100% 보장 안 된다는 사실 인지 못 하고 운영. 봇 자체에 백업 로직(시간 손절·강제 청산) 필수.
함정 2. 시그너처 없는 웹훅
웹훅 URL이 노출되면 누구든 신호 발송 가능 → 자본 손실. 시크릿 키 + HTTPS + 화이트리스트.
함정 3. 같은 신호 여러 번 처리
트레이딩뷰가 같은 이벤트로 여러 번 알람 발송하면 중복 매수 발생. 페이로드 해시 캐싱.
함정 4. Pine Script repaint 신호
닫히지 않은 봉의 신호로 매매 → 봉 닫히면 신호 사라짐. barstate.isconfirmed로 봉 확정 후에만 신호 발생.
함정 5. 백테스트 결과를 실거래로 착각
Pine Script strategy.equity는 슬리피지·수수료를 단순화. 실전은 다름. 페이퍼 트레이딩 2주 후 실거래.
16단계 체크리스트
Pine Script (4단계)
- ☐ Pine Script v5+ 사용
- ☐
barstate.isconfirmed로 봉 확정 후 신호 - ☐ 알람 메시지 JSON 동적 생성
- ☐
strategy()로 백테스트 결과 확인
웹훅 서버 (4단계)
- ☐ Flask + gunicorn + systemd
- ☐ 시크릿 키 환경변수 (.env)
- ☐ 중복 신호 방어 (5초 윈도우)
- ☐ 로깅 + 텔레그램 알림
보안 (4단계)
- ☐ HTTPS (Let's Encrypt)
- ☐ 트레이딩뷰 IP 화이트리스트
- ☐ 거래소 API 키 출금 OFF + IP 화이트리스트
- ☐
.gitignore에.env추가
운영 (4단계)
- ☐ 페이퍼 트레이딩 2주 검증
- ☐ 실거래 최소 금액 1주 검증
- ☐ 5분 헬스체크 + 자동 알림
- ☐ 일일/주간 손실 한도 Circuit Breaker
자주 묻는 질문
Q. 트레이딩뷰 자동매매란 정확히?
Pine Script 신호 → 알람 → 웹훅 → 본인 서버 → 증권사·거래소 API → 실거래. 트레이딩뷰는 차트·신호만, 실주문은 본인 서버.
Q. Pine Script를 몰라도 가능?
기본 지표 알람(이동평균 크로스, RSI 30 등)만 쓰면 가능. 복잡한 전략은 Pine Script 학습(1~2주) 필요.
Q. 웹훅에 유료 플랜 필요?
네, Essential($14.95/월) 이상. 본격 운영은 Plus 권장.
Q. 키움·KIS에 트레이딩뷰로 주문 가능?
가능. 웹훅 서버에서 증권사 API 호출. KIS가 진입 친화적, 키움은 32bit 종속.
Q. 신호 누락 가능?
가능. 봇 자체 백업 로직(시간 손절·강제 청산) + 헬스체크 필수.
Q. 봇 제작 비용?
단일 연동 80만~200만원, 다거래소 통합 150만~400만원, 풀패키지 200만~500만원.
마무리
트레이딩뷰 자동매매는 차트 친화적 입문자에게 가장 빠른 자동매매 진입 경로입니다. Pine Script로 전략을 시각적으로 검증하고, 같은 신호를 한국 주식·코인 어디든 보낼 수 있다는 점이 강력합니다.
이 글의 8부 구성을 따라가면, 트레이딩뷰 알람부터 본인 VPS에서 실거래까지의 전체 파이프라인을 구축할 수 있습니다. 알고랩에서 제작하는 모든 트레이딩뷰 봇은 이 골격을 기본으로 합니다.
트레이딩뷰 자동매매 봇 맞춤 제작
Pine Script 작성, 웹훅 서버, 증권사·거래소 연동, 보안·운영까지 통합된 트레이딩뷰 봇을 알고랩이 1~3주 안에 제작해드립니다.
24시간 빠른 답변 가능합니다.