텔레그램 셋업(한 번만) @BotFather에게 /newbot → Bot 생성 → BOT_TOKEN 확보. 알림 받을 그룹/채널 만들고 봇을 초대(채널은 관리자로 추가). 봇




좋아. 지금 가진 RyuCoin_bot 토큰으로 끝까지 연결하는 과정을 “실패 포인트 없이” 정리했어.

(토큰은 비밀값이므로 공개 채널/스크린샷에 노출하지 말고, 유출되면 BotFather에서 /revoke로 즉시 교체하세요.)


1) Chat ID 얻기 (개인/그룹/채널)

텔레그램은 chat_id만 알면 봇이 메시지를 보낼 수 있어요. 가장 확실한 방법:

사전 세팅 (한 번만)

  1. BotFather에서 만든 봇(@RyuCoin_bot) 토큰 확보 ✅

  2. (선택) /setprivacy → Disable

    • 그룹에서 일반 텍스트도 업데이트로 받으려면 비활성화가 편해요.

    • 단순 “보내기 전용”이면 꼭 꺼둘 필요는 없음.

업데이트를 보기 전에 “웹훅 제거”

봇에 웹훅이 걸려 있으면 getUpdates가 비어있을 수 있음:

bash
https://api.telegram.org/bot<토큰>/deleteWebhook?drop_pending_updates=true

A) 개인(1:1) chat_id

  1. 봇과 대화창을 열고 Start 누르기(아무 메시지라도 보내기).

  2. 브라우저에서 열기:

    bash
    https://api.telegram.org/bot<토큰>/getUpdates
  3. 응답 JSON에서

    arduino
    "message": { "chat": { "id": 123456789, "type": "private", ... } }

    id 값이 chat_id (양수).

B) 그룹/슈퍼그룹 chat_id

  1. 알림 받을 그룹을 만들고 @RyuCoin_bot을 초대(원하면 관리자).

  2. 그룹에서 봇을 멘션해서 아무 말이나 보내기: @RyuCoin_bot hi

    (Privacy가 켜져 있어도 멘션은 업데이트로 옵니다.)

  3. 다시 getUpdates 확인 →

    arduino
    "my_chat_member" 또는 "message": { "chat": { "id": -987654321, "type": "supergroup", ... } }

    id 값이 chat_id (음수).

C) 채널 chat_id

  1. 채널 만들기 → 봇을 관리자로 추가.

  2. getUpdates"my_chat_member" 이벤트가 생김.

    arduino
    "chat": { "id": -1001234567890, "type": "channel", ... }

    -100… 형태가 chat_id.

팁: 업데이트가 너무 많으면 getUpdates?offset=<마지막 update_id+1>로 건너뛰거나, 위에서 deleteWebhook?drop_pending_updates=true를 먼저 실행해 깨끗한 상태로 시작하세요.


2) 토큰/채팅 매핑 환경변수 세팅 (Cloud Run)

봇 토큰:

8458261443:AAFIU8knogmoI4BS-DgQurlWi3i6id-DT5Q

예시로 DOGE, BTC 방만 먼저 넣고, 나머지는 차례대로 추가하면 돼요.

bash
# 공통: 토큰과 기본방(없으면 비워두기) gcloud run services update doge-webhook \ --region=asia-northeast3 \ --set-env-vars TELEGRAM_BOT_TOKEN=8458261443:AAFIU8knogmoI4BS-DgQurlWi3i6id-DT5Q \ --set-env-vars TG_CHAT_DEFAULT=-100999888777 # 기본 방(선택) # 코인별 방 매핑(심볼은 TV의 syminfo.ticker 값과 맞춰야 합니다) gcloud run services update doge-webhook \ --region=asia-northeast3 \ --set-env-vars TG_CHAT_DOGE=-1001234567890 # 다른 코인 서비스에도 각각 설정 (예: btc-webhook) gcloud run services update btc-webhook \ --region=asia-northeast3 \ --set-env-vars TELEGRAM_BOT_TOKEN=8458261443:AAFIU8knogmoI4BS-DgQurlWi3i6id-DT5Q \ --set-env-vars TG_CHAT_BTC=-100222333444

chat_id가 음수면 따옴표로 감싸거나 그대로 넣어도 되지만, 쉘에 따라 해석될 수 있으니 가급적 " -100... " 형태로 넣어주세요.


3) 서버(Cloud Run) 알림 전송 코드 (붙여넣기용)

api/app.py의 웹훅 핸들러에 아래 유틸을 추가하고, data(TV JSON)를 파싱한 뒤 fanout_to_telegram(data)만 호출하세요.

python
# --- Telegram fanout util --- import os, asyncio, httpx from datetime import datetime, timezone TG_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN", "") TG_API = f"https://api.telegram.org/bot{TG_TOKEN}/sendMessage" CHAT_MAP = { "OKX:DOGEUSDT.P": os.getenv("TG_CHAT_DOGE", ""), "OKX:BTCUSDT.P": os.getenv("TG_CHAT_BTC", ""), "OKX:ETHUSDT.P": os.getenv("TG_CHAT_ETH", ""), "OKX:XRPUSDT.P": os.getenv("TG_CHAT_XRP", ""), "OKX:SOLUSDT.P": os.getenv("TG_CHAT_SOL", ""), "OKX:PEPEUSDT.P": os.getenv("TG_CHAT_PEPE", ""), "OKX:SHIBUSDT.P": os.getenv("TG_CHAT_SHIBA",""), "OKX:CROUSDT.P": os.getenv("TG_CHAT_CRO", ""), "OKX:CBKUSDT.P": os.getenv("TG_CHAT_CBK", ""), "OKX:ADAUSDT.P": os.getenv("TG_CHAT_ADA", ""), "OKX:BERAUSDT.P": os.getenv("TG_CHAT_BERA",""), "OKX:QTUMUSDT.P": os.getenv("TG_CHAT_QTUM",""), } TG_CHAT_DEFAULT = os.getenv("TG_CHAT_DEFAULT", "") def _fmt_utc(ms: int) -> str: try: return datetime.fromtimestamp(ms/1000, tz=timezone.utc).strftime("%Y-%m-%d %H:%M:%S") except Exception: return "" def _build_text(d: dict) -> str: evt = d.get("evt","") tkr = d.get("ticker","") tf = d.get("tf","") p = d.get("price","") sl = d.get("stop","") tp2 = d.get("tp2","") t = _fmt_utc(int(d.get("t", 0))) return ( f"📣 <b>{evt}</b> <code>{tkr}</code> {tf}\n" f"💵 price: <b>{p}</b>\n" f"🛡️ SL: {sl} 🎯 TP2: {tp2}\n" f"⏱️ {t} UTC" ) async def _tg_send(chat_id: str, text: str): if not TG_TOKEN or not chat_id: return async with httpx.AsyncClient(timeout=10) as x: await x.post(TG_API, json={ "chat_id": chat_id, "text": text, "parse_mode": "HTML", "disable_web_page_preview": True }) def fanout_to_telegram(d: dict): tkr = d.get("ticker","") chat_id = CHAT_MAP.get(tkr) or TG_CHAT_DEFAULT if not chat_id: return text = _build_text(d) asyncio.create_task(_tg_send(chat_id, text))

웹훅 핸들러 내부(시크릿 검증 뒤)에 넣는 한 줄:

python
fanout_to_telegram(data) # TV alert JSON을 그대로 넣어줌

4) 빠른 테스트

A) 봇으로 직접 전송(서버 없이)

브라우저 주소창:

bash
https://api.telegram.org/bot<토큰>/sendMessage?chat_id=<CHAT_ID>&text=hello

B) 서버를 통해 전송(Cloud Run 웹훅 테스트)

PowerShell:

powershell
$body = @{ evt="ENTRY"; ticker="OKX:DOGEUSDT.P"; tf="5m"; t=1724764800000; price=0.2145; stop=0.2130; tp2=0.2173; secret="DOGE-secret-2024" } | ConvertTo-Json Invoke-RestMethod -Uri "https://doge-webhook-367722291280.asia-northeast3.run.app/webhook/tradingview" ` -Method Post -Body $body -ContentType "application/json"

→ 해당 방으로 메시지가 오면 성공.


5) TradingView 쪽 최종 체크

  • 각 코인 차트에서 SRB Long v1.0.2 붙이기

  • Inputs → secret에 코인별 시크릿 입력

  • Alert: Any alert() function call + Webhook URL = 각 코인 Cloud Run 주소

  • 알림이 뜨면 서버가 검증 → DB기록 → 텔레그램으로 팬아웃


보안 & 운영 팁

  • 토큰/채팅ID는 Cloud Run 환경변수로만 주입(코드에 하드코딩 금지).

  • 유출 시 BotFather → /revoke로 즉시 새 토큰 발급.

  • 메시지 폭주 방지: 동일 바 중복 알림은 서버에서 idempotency 키로 스킵(앞서 드린 샘플 참고).

  • 포맷 바꾸고 싶으면 _build_text()에서 HTML만 수정하면 됨.

원하면 지금 토큰으로 chat_id 추출을 같이 해줄 수 있도록, 안전한 절차(웹훅 제거 → getUpdates) 기준으로 안내 더 해줄게.

댓글 남기기