feat(stock-lab): 텔레그램 노드 풀 라벨 + 원 단위 표기
- 아이콘(👤외/🆙고/...) 제거하고 풀 한글 라벨로 변경 (외국인/거래량급증/20일모멘텀/52주신고가/RS레이팅/이평선정배열/VCP수축) - 가격은 "103,917원" 형태로 원 단위 명시 - 활성 노드 없을 때 fallback 문구 - 테스트도 새 포맷으로 갱신 + 원 단위 검증 신규 케이스
This commit is contained in:
@@ -4,14 +4,15 @@ from __future__ import annotations
|
||||
|
||||
import datetime as dt
|
||||
|
||||
NODE_ICONS = {
|
||||
"foreign_buy": "👤외",
|
||||
"volume_surge": "⚡거",
|
||||
"momentum": "🚀모",
|
||||
"high52w": "🆙고",
|
||||
"rs_rating": "💪RS",
|
||||
"ma_alignment": "📈MA",
|
||||
"vcp_lite": "🌀VCP",
|
||||
# 노드별 풀 라벨 (아이콘 대신 사용 — 사용자가 명확한 이름 선호)
|
||||
NODE_LABELS = {
|
||||
"foreign_buy": "외국인",
|
||||
"volume_surge": "거래량급증",
|
||||
"momentum": "20일모멘텀",
|
||||
"high52w": "52주신고가",
|
||||
"rs_rating": "RS레이팅",
|
||||
"ma_alignment": "이평선정배열",
|
||||
"vcp_lite": "VCP수축",
|
||||
}
|
||||
|
||||
PAGE_BASE = "https://gahusb.synology.me/stock/screener"
|
||||
@@ -25,9 +26,21 @@ def _escape_md(s: str) -> str:
|
||||
|
||||
|
||||
def _format_won(n) -> str:
|
||||
"""1,234,567원 형태 (None 시 '-')."""
|
||||
if n is None:
|
||||
return "-"
|
||||
return f"{int(n):,}"
|
||||
return "\\-"
|
||||
return f"{int(n):,}원"
|
||||
|
||||
|
||||
def _format_active_nodes(scores: dict, threshold: int = 70) -> str:
|
||||
"""70점 이상 노드를 '라벨 점수' 형태로 나열, 콤마 구분."""
|
||||
active = []
|
||||
for name, sc in scores.items():
|
||||
label = NODE_LABELS.get(name)
|
||||
if label is None or sc < threshold:
|
||||
continue
|
||||
active.append(f"{_escape_md(label)} {int(sc)}")
|
||||
return " · ".join(active) if active else "\\(70점 이상 노드 없음\\)"
|
||||
|
||||
|
||||
def build_telegram_payload(asof: dt.date, mode: str, survivors_count: int,
|
||||
@@ -40,17 +53,14 @@ def build_telegram_payload(asof: dt.date, mode: str, survivors_count: int,
|
||||
|
||||
lines = []
|
||||
for r in rows[:10]:
|
||||
icons = " ".join(
|
||||
NODE_ICONS[name] for name, sc in r["scores"].items()
|
||||
if sc >= 70 and name in NODE_ICONS
|
||||
)
|
||||
nodes_str = _format_active_nodes(r.get("scores", {}))
|
||||
score_str = f"{r['total_score']:.1f}"
|
||||
r_pct = r.get("r_pct")
|
||||
r_pct_str = f"{r_pct:.1f}" if r_pct is not None else "-"
|
||||
lines.append(
|
||||
f"{r['rank']}\\. *{_escape_md(r['name'])}* `{r['ticker']}` "
|
||||
f"⭐ {_escape_md(score_str)}\n"
|
||||
f" {icons}\n"
|
||||
f" {nodes_str}\n"
|
||||
f" 진입 {_format_won(r.get('entry_price'))} "
|
||||
f"손절 {_format_won(r.get('stop_price'))} "
|
||||
f"익절 {_format_won(r.get('target_price'))} "
|
||||
|
||||
Reference in New Issue
Block a user