feat: 분봉 크로스헤어 툴팁에 '당일시가 대비 등락률' 추가
분봉 차트 클릭(세로선) 시 OHLC 팝업에 그 봉 종가의 당일 시가(첫 봉) 대비 등락률을 표시 — 그 시점까지의 오늘 누적 등락을 한눈에. 일봉은 미표시(분봉만). - render_svg_chart(intraday=) → meta.dayOpen(첫 봉 시가, 분봉만) 주입 - 분봉 엔드포인트 intraday=True - _setOhlcText: 당일시가대비 라인 + 팝업 박스/닫기버튼 동적 리사이즈 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -7317,8 +7317,14 @@ def render_html() -> str:
|
||||
'xTipTxt.appendChild(_mkTspan({"font-size":24,"font-weight":500},_pctStr(c.l,c.o),lcol));'
|
||||
'xTipTxt.appendChild(_mkTspan({x:16,dy:34,"font-size":28,"font-weight":700},"종 "+c.c.toLocaleString()+" ",ccol));'
|
||||
'xTipTxt.appendChild(_mkTspan({"font-size":24,"font-weight":700},_pctStr(c.c,c.o),ccol));'
|
||||
# 분봉: 당일 시가(첫 봉) 대비 등락률 — 그 시점까지의 오늘 누적 등락.
|
||||
'var hasDO=meta.dayOpen&&meta.dayOpen>0;'
|
||||
'if(hasDO){xTipTxt.appendChild(_mkTspan({x:16,dy:32,"font-size":23,"font-weight":600},"당일시가대비 "+_pctStr(c.c,meta.dayOpen),_col(c.c,meta.dayOpen)));}'
|
||||
# 팝업 위치 — vline 의 반대 쪽으로 자동 배치 (좌/우). 화면 벗어남 방지 clamp.
|
||||
'var tipW=320,tipH=176,gap=10;'
|
||||
'var tipW=340,tipH=hasDO?212:176,gap=10;'
|
||||
# 당일시가 라인 유무에 따라 배경 박스·닫기버튼 위치 동적 조정.
|
||||
'xTipBg.setAttribute("width",tipW);xTipBg.setAttribute("height",tipH);'
|
||||
'closeG.setAttribute("transform","translate("+(tipW-20)+",20)");'
|
||||
'var tipX=xPos+gap;'
|
||||
'if(tipX+tipW>meta.chartW-meta.padR)tipX=xPos-gap-tipW;'
|
||||
'if(tipX<meta.padL)tipX=meta.padL+2;'
|
||||
@@ -10055,7 +10061,7 @@ class Handler(BaseHTTPRequestHandler):
|
||||
prev_close = _pc
|
||||
except Exception:
|
||||
pass
|
||||
svg = sa.render_svg_chart(snap, range_key='1Y', ref_price=prev_close)
|
||||
svg = sa.render_svg_chart(snap, range_key='1Y', ref_price=prev_close, intraday=True)
|
||||
body = svg.encode('utf-8')
|
||||
body, enc = _maybe_gzip(body, self.headers.get('Accept-Encoding'))
|
||||
self.send_response(200)
|
||||
|
||||
@@ -546,10 +546,11 @@ VOL_BOT = VOL_TOP + VOL_PANEL_H
|
||||
CHART_RANGE_DAYS = {'1Y': 250, '6M': 120, '1M': 21}
|
||||
|
||||
|
||||
def render_svg_chart(snap: dict, range_key: str = '1Y') -> str:
|
||||
def render_svg_chart(snap: dict, range_key: str = '1Y', ref_price: float | None = None, intraday: bool = False) -> str:
|
||||
"""캔들 + SMA 3선 + 거래량 막대 인라인 SVG.
|
||||
|
||||
range_key: '1Y' (250일) | '6M' (120일) | '1M' (21일). 같은 snapshot 데이터에서 슬라이스만.
|
||||
ref_price: 기준가(전일종가 등) — 지정 시 노란 점선 기준선 + 마지막 종가의 대비 등락률 표시 (분봉용).
|
||||
snap: collect_snapshot 결과. candles_asc·sma5/20/60 사용.
|
||||
외부 JS 의존성 0. CSS는 inline.
|
||||
"""
|
||||
@@ -570,6 +571,9 @@ def render_svg_chart(snap: dict, range_key: str = '1Y') -> str:
|
||||
sma_vals = [v for v in (sma5 + sma20 + sma60) if v is not None]
|
||||
y_max = max(max(highs), max(sma_vals) if sma_vals else 0)
|
||||
y_min = min(min(lows), min(sma_vals) if sma_vals else float('inf'))
|
||||
if ref_price:
|
||||
y_max = max(y_max, ref_price) # 기준선이 항상 보이게 스케일에 포함
|
||||
y_min = min(y_min, ref_price)
|
||||
if y_min == y_max:
|
||||
y_max = y_min + 1
|
||||
# 위·아래 패딩 5%
|
||||
@@ -607,6 +611,8 @@ def render_svg_chart(snap: dict, range_key: str = '1Y') -> str:
|
||||
],
|
||||
'ymin': y_min,
|
||||
'ymax': y_max,
|
||||
# 분봉일 때만 당일 시가(첫 봉 시가) — 크로스헤어 툴팁의 '당일시가 대비 등락률'용.
|
||||
'dayOpen': (candles[0]['open'] if (intraday and candles) else 0),
|
||||
'priceTop': PRICE_TOP,
|
||||
'priceBot': PRICE_BOT,
|
||||
'volTop': VOL_TOP,
|
||||
@@ -696,6 +702,24 @@ def render_svg_chart(snap: dict, range_key: str = '1Y') -> str:
|
||||
parts.append(sma_path(sma20, '#34d399', 'SMA20')) # 초록
|
||||
parts.append(sma_path(sma60, '#a78bfa', 'SMA60')) # 보라
|
||||
|
||||
# ---- 전일종가 기준선 + 대비 등락률 (ref_price 지정 시 — 분봉) ----
|
||||
if ref_price:
|
||||
ry = price_y(ref_price)
|
||||
parts.append(
|
||||
f'<line x1="{CHART_PAD_L}" y1="{ry:.1f}" x2="{CHART_W-CHART_PAD_R}" y2="{ry:.1f}" '
|
||||
f'stroke="#eab308" stroke-width="1.5" stroke-dasharray="7 5" opacity="0.85"/>'
|
||||
)
|
||||
parts.append(
|
||||
f'<text x="{CHART_W - CHART_PAD_R + 6}" y="{ry-4:.1f}" text-anchor="start" fill="#eab308" font-size="24">전일</text>'
|
||||
)
|
||||
last_close = candles[-1]['close']
|
||||
pct = (last_close / ref_price - 1) * 100
|
||||
pc = '#ef4444' if pct > 0 else '#3b82f6' if pct < 0 else '#9ca3af' # 한국 관습: 상승=빨강
|
||||
parts.append(
|
||||
f'<text x="{CHART_W - CHART_PAD_R - 8}" y="{PRICE_TOP + 36}" text-anchor="end" '
|
||||
f'fill="{pc}" font-size="30" font-weight="700">{last_close:,} 전일대비 {pct:+.2f}%</text>'
|
||||
)
|
||||
|
||||
# SMA 범례
|
||||
legend_y = PRICE_TOP + 14
|
||||
legend_items = [('SMA5', '#fbbf24'), ('SMA20', '#34d399'), ('SMA60', '#a78bfa')]
|
||||
|
||||
Reference in New Issue
Block a user