feat: 미리보기 행 NXT/KRX 텍스트 마크 → 거래가능 초록점
- _render_row: 가격 출처(NXT/KRX) 텍스트 배지 대신 '지금 거래시간 여부'로 초록점(.px-dot.tradable) / 점 없음. 정규장=전부, NXT시간대=NXT거래종목만 (_nxt_price>0), 장마감·휴장·주말=점 없음. 가격 None은 기존대로 점 없음 - 보유종목 상세행(_render_holding_row)의 NXT/KRX 텍스트는 그대로 유지 - CSS .px-dot 추가 (px-mark.px-nxt/krx는 보유행이 계속 사용) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -596,6 +596,16 @@ def _market_phase_state() -> dict:
|
||||
return {'phase': 'closed', 'label': '장외 시간', 'active': False, 'time': time_str}
|
||||
|
||||
|
||||
def _is_preopen_market_day() -> bool:
|
||||
"""거래일 08:00 전. 장전 가격으로 당일 손익을 만들지 않는다."""
|
||||
now = datetime.now(KST)
|
||||
return (
|
||||
now.weekday() < 5
|
||||
and now.hour < 8
|
||||
and now.strftime('%Y-%m-%d') not in _load_holidays()
|
||||
)
|
||||
|
||||
|
||||
def _load_watchlist() -> list[dict]:
|
||||
if not WATCHLIST.exists():
|
||||
return []
|
||||
@@ -975,10 +985,15 @@ def _build_owner_data(positions_by_acc: dict, balances: dict, journal_by_label:
|
||||
net_cash_flow = cash_in - cash_out
|
||||
|
||||
day_pl_total = (total_net - prev_net - net_cash_flow) if prev_net is not None else None
|
||||
day_pl_reason = None
|
||||
if _is_preopen_market_day():
|
||||
day_pl_total = None
|
||||
day_pl_reason = 'preopen'
|
||||
# 휴장일/주말은 시장 변동이 없어야 자연. 단 NXT 가격 보정으로 어제 스냅샷과 차이가 생겨
|
||||
# day_pl_total이 0이 아닌 값을 갖게 됨 → 사용자 혼란 차단 위해 None으로 강제(미표시).
|
||||
if _market_phase_state().get('phase') in ('holiday', 'weekend'):
|
||||
day_pl_total = None
|
||||
day_pl_reason = 'closed'
|
||||
|
||||
owner_data[owner] = {
|
||||
'labels': lbls,
|
||||
@@ -993,6 +1008,7 @@ def _build_owner_data(positions_by_acc: dict, balances: dict, journal_by_label:
|
||||
'traded_today': traded_today,
|
||||
'prev_net': prev_net,
|
||||
'day_pl_total': day_pl_total,
|
||||
'day_pl_reason': day_pl_reason,
|
||||
'realized_pl_total': realized_pl_total,
|
||||
'realized_fees_total': realized_fees_total,
|
||||
'cash_in': cash_in,
|
||||
@@ -1863,14 +1879,19 @@ def _render_row(c: dict, source: str = 'watchlist') -> str:
|
||||
price_cell = '<span class="muted">-</span>'
|
||||
diff_cell = f'<span class="muted">{html.escape(err) if err else "조회 불가"}</span>'
|
||||
else:
|
||||
# 가격 출처 마크 — _krx_price/_nxt_price 비교. NXT 가격이 살아있고 KRX와 다르면 NXT.
|
||||
krx_p = c.get('_krx_price', 0) or 0
|
||||
# 거래가능 표시 — 지금 거래시간이면 초록점, 아니면 점 없음.
|
||||
# 정규장: KRX+NXT 모두 거래 → 초록점
|
||||
# NXT 시간대: NXT 거래되는 종목(_nxt_price 살아있음)만 초록점
|
||||
# 장마감·휴장·주말: 점 없음
|
||||
nxt_p = c.get('_nxt_price', 0) or 0
|
||||
if nxt_p > 0 and (krx_p == 0 or krx_p != nxt_p):
|
||||
mark = 'NXT'
|
||||
_phase = _market_phase_state()['phase']
|
||||
if _phase == 'regular':
|
||||
_tradable = True
|
||||
elif _phase == 'nxt':
|
||||
_tradable = nxt_p > 0
|
||||
else:
|
||||
mark = 'KRX'
|
||||
mark_html = f'<span class="px-mark px-{mark.lower()}">{mark}</span>'
|
||||
_tradable = False
|
||||
mark_html = '<span class="px-dot tradable" title="지금 거래 가능"></span>' if _tradable else ''
|
||||
# 미리보기 등락은 KRX 전일종가 대비 — ka10095의 change_pct가 이미 KRX 기준이라 그대로 사용.
|
||||
day_pct = c.get('day_change_pct')
|
||||
if c.get('_show_day_change') and isinstance(day_pct, (int, float)):
|
||||
@@ -2131,8 +2152,10 @@ def _render_owner_kpi(owner: str, d: dict, owner_label_text: str, compact: bool
|
||||
|
||||
day_pl_total = d.get('day_pl_total')
|
||||
if day_pl_total is None:
|
||||
if d.get('day_pl_reason') == 'preopen':
|
||||
day_pl_html = '<span class="muted small">장 시작 전</span>'
|
||||
# 휴장일/주말은 시장 변동이 없는 정상 상태 — "전날 스냅샷 없음"과 구분된 문구.
|
||||
if _market_phase_state().get('phase') in ('holiday', 'weekend'):
|
||||
elif _market_phase_state().get('phase') in ('holiday', 'weekend'):
|
||||
day_pl_html = '<span class="muted small">휴장 — 변동 없음</span>'
|
||||
else:
|
||||
day_pl_html = '<span class="muted small">전날 스냅샷 없음</span>'
|
||||
@@ -4235,6 +4258,8 @@ details.row + .section-label { margin-top: 14px; padding-top: 24px; border-top-c
|
||||
.ohlc-mini.ohlc-dual .ohlc-cell.ohlc-dim .ohlc-pct { color: #5a5e69 !important; }
|
||||
.ohlc-mini.ohlc-dual .ohlc-cell-empty.ohlc-dim { color: #3a3e48; }
|
||||
/* 미리보기 현재가 왼쪽 출처 마크 — NXT(파랑톤) / KRX(회색톤). 어두운 채도로 보조 정보 강조 X. */
|
||||
.px-dot { display: inline-block; width: 6px; height: 6px; border-radius: 50%; margin-right: 5px; vertical-align: 1px; }
|
||||
.px-dot.tradable { background: #2ecc71; box-shadow: 0 0 4px rgba(46,204,113,0.6); }
|
||||
.px-mark { font-size: 8px; font-weight: 600; margin-right: 4px; padding: 1px 3px; border-radius: 2px; background: #14171f; vertical-align: 2px; letter-spacing: 0.3px; }
|
||||
.px-mark.px-nxt { color: #2d5a8a; }
|
||||
.px-mark.px-krx { color: #4a4e58; }
|
||||
|
||||
Reference in New Issue
Block a user