feat: 순자산 차트 오늘(장중) 값 라벨 실시간 갱신

net-chart-last 라벨을 실시간 순자산으로 갱신(라이브 점일 때만). 순자산 변동분=손익 변동분(baseline·cf 세션중 고정)이라 net/pnl/period 모드 공통 처리.
SVG 점 위치는 새로고침 시(장중 이동 미미·Y재스케일 위험 회피). setOwnerKpis에서 owner별 갱신.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
hyowons
2026-06-08 17:32:50 +09:00
parent ab0343338e
commit 5448a0ab5f
+15 -2
View File
@@ -3278,7 +3278,7 @@ def _expand_progress_group(filtered: list[tuple[str, int]], daily_series: list[t
return baseline + in_group
def _render_net_worth_chart(series: list[tuple[str, int]], current_net: int | None = None, selected_days: int = NET_WORTH_CHART_DAYS, selected_unit: str = NET_WORTH_CHART_UNIT, cash_flow_by_date: dict | None = None, today_cash_flow: dict | None = None, mode: str = NET_WORTH_CHART_MODE, prev_baseline_point: tuple[str, int] | None = None) -> str:
def _render_net_worth_chart(series: list[tuple[str, int]], current_net: int | None = None, selected_days: int = NET_WORTH_CHART_DAYS, selected_unit: str = NET_WORTH_CHART_UNIT, cash_flow_by_date: dict | None = None, today_cash_flow: dict | None = None, mode: str = NET_WORTH_CHART_MODE, prev_baseline_point: tuple[str, int] | None = None, rt_owner: str | None = None, rt_base_net: int | None = None) -> str:
"""꺾은선 SVG (순자산 / 손익누적 공용). 외부 의존성 없음. 데이터 < 2점이면 안내문 반환.
mode='net'(기본): series raw 순자산 시계열. 입출금 마커·툴팁 표시.
@@ -3695,7 +3695,10 @@ def _render_net_worth_chart(series: list[tuple[str, int]], current_net: int | No
'<span class="net-chart-foot-r">'
'<button type="button" class="nw-nav" data-nw-step="prev" aria-label="이전 날짜">◀</button>'
'<button type="button" class="nw-nav" data-nw-step="next" aria-label="다음 날짜">▶</button>'
f'<span class="net-chart-last">{html.escape(last_label_v)}</span>'
f'<span class="net-chart-last"'
+ (f' data-rt-nw-owner="{html.escape(rt_owner, quote=True)}" data-rt-nw-basenet="{rt_base_net}" data-rt-nw-baseval="{last_v}" data-rt-nw-pnl="{1 if is_pnl else 0}" data-rt-nw-live="{1 if has_live else 0}"'
if (rt_owner is not None and rt_base_net is not None and has_live) else '')
+ f'>{html.escape(last_label_v)}</span>'
'</span>'
'</div>'
)
@@ -5688,6 +5691,7 @@ def _render_summary_panel(ordered_owners: list[str], owner_data: dict, balances:
today_cash_flow=None,
mode=chart_mode,
prev_baseline_point=prev_baseline,
rt_owner=owner, rt_base_net=d.get('total_net'),
))
else:
# net 모드도 baseline 점(예: 5/1) prepend → 첫 영업일 변동이 0 기점에서 분기되는 모양. baseline 구간은 점선.
@@ -5700,6 +5704,7 @@ def _render_summary_panel(ordered_owners: list[str], owner_data: dict, balances:
today_cash_flow=today_cf,
mode='net',
prev_baseline_point=prev_baseline,
rt_owner=owner, rt_base_net=d.get('total_net'),
))
market_card = _render_market_indicators_card()
@@ -9033,6 +9038,14 @@ window.openPinModal = openPinModal;
if(td) td.innerHTML='<span class="'+udcls(T.daypl)+'">'+sgn(T.daypl)+''+(T.dpct!==null?' ('+(T.dpct>=0?'+':'')+T.dpct.toFixed(2)+'%)':'')+'</span>';
}
});
// 순자산 차트 오늘(장중) 포인트 라벨 실시간 위치(SVG) 새로고침 , 라벨만 라이브.
document.querySelectorAll('.net-chart-last[data-rt-nw-owner="'+owner+'"][data-rt-nw-live="1"]').forEach(function(el){
var basenet=parseFloat(el.getAttribute('data-rt-nw-basenet')||'0');
var baseval=parseFloat(el.getAttribute('data-rt-nw-baseval')||'0');
var v=Math.round(baseval+(T.net-basenet)); // 순자산 변동분 = 손익 변동분(baseline·cf는 세션 고정)
var s=(el.getAttribute('data-rt-nw-pnl')==='1') ? ((v>=0?'+':'')+Math.abs(v).toLocaleString()+'') : (v.toLocaleString()+'');
el.textContent=s+' (장중)';
});
}
// KPI 총합 owner scope의 consolidated pane 행만 합산(중복합산 방지). 시세 미수신 종목은 data-rt-px(서버값) fallback.
function updateScopes(px){