auto: 일일 백업 2026-06-23 02:00
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1390,13 +1390,13 @@ def _fetch_all_data(entries: list[dict], only_owner: str | None = None) -> dict:
|
||||
r['ohlc_krx'] = {
|
||||
'open': qk['open'], 'high': qk['high'], 'low': qk['low'],
|
||||
'price': qk.get('price', 0), 'change_pct': qk.get('change_pct', 0.0),
|
||||
'change': qk.get('change', 0),
|
||||
'change': qk.get('change', 0), 'volume': qk.get('volume', 0),
|
||||
}
|
||||
if qn_valid:
|
||||
r['ohlc_nxt'] = {
|
||||
'open': qn['open'], 'high': qn['high'], 'low': qn['low'],
|
||||
'price': qn.get('price', 0), 'change_pct': qn.get('change_pct', 0.0),
|
||||
'change': qn.get('change', 0),
|
||||
'change': qn.get('change', 0), 'volume': qn.get('volume', 0),
|
||||
}
|
||||
# 단일 캔들 primary — 4값(open/high/low/price) 모두 있는 응답만 후보. 거래 없는 시간대 0값 응답 배제.
|
||||
qk_full = qk_valid and qk.get('open') and qk.get('high') and qk.get('low')
|
||||
@@ -2364,6 +2364,12 @@ def _render_ohlc_mini_dual(krx: dict | None, nxt: dict | None, active_market: st
|
||||
if not price:
|
||||
return f'<span class="ohlc-cell-empty{dim_cls}">-</span>'
|
||||
return f'<span class="ohlc-cell{dim_cls}"><span class="ohlc-price">{price:,}원</span></span>'
|
||||
elif key == 'volume':
|
||||
# 거래량 — 등락률 없이 주 수만 표시.
|
||||
vol = d.get('volume', 0) or 0
|
||||
if not vol:
|
||||
return f'<span class="ohlc-cell-empty{dim_cls}">-</span>'
|
||||
return f'<span class="ohlc-cell{dim_cls}"><span class="ohlc-price">{vol:,}주</span></span>'
|
||||
else:
|
||||
price = d.get(key, 0)
|
||||
base = d.get('price', 0) - d.get('change', 0)
|
||||
@@ -2397,6 +2403,7 @@ def _render_ohlc_mini_dual(krx: dict | None, nxt: dict | None, active_market: st
|
||||
('고가', 'high'),
|
||||
('저가', 'low'),
|
||||
('당일종가', 'close_today'),
|
||||
('거래량', 'volume'),
|
||||
]
|
||||
krx_th_dim = ' ohlc-dim' if krx_dim else ''
|
||||
nxt_th_dim = ' ohlc-dim' if nxt_dim else ''
|
||||
@@ -10336,7 +10343,8 @@ class Handler(BaseHTTPRequestHandler):
|
||||
try:
|
||||
import stock_analysis as sa
|
||||
import kiwoom_client as kc
|
||||
mins = kc.get_minute_candles(code, tic_scope=tic_scope, today_only=True)
|
||||
# _AL(통합) — 정규장(KRX)→NXT(15:30~20:00)가 한 차트에 연속.
|
||||
mins = kc.get_minute_candles(code, tic_scope=tic_scope, today_only=True, exchange='AL')
|
||||
if not mins:
|
||||
self.send_error(404, 'no minute candles')
|
||||
return
|
||||
|
||||
@@ -979,18 +979,21 @@ def get_daily_candles(code: str, count: int = 250, base_dt: str | None = None,
|
||||
|
||||
|
||||
def get_minute_candles(code: str, tic_scope: int = 5, today_only: bool = True,
|
||||
account_label: str | None = None) -> list[dict]:
|
||||
account_label: str | None = None, exchange: str = 'KRX') -> list[dict]:
|
||||
"""주식 분봉 차트 (ka10080). 수정주가 기준.
|
||||
|
||||
tic_scope: 1/3/5/10/15/30/45/60 분. 한 호출에 ~900봉 (5분봉 ≈ 11일치).
|
||||
today_only: True 면 오늘 봉만 추출.
|
||||
exchange: 'KRX'=KRX 단독(기본) / 'NX'=NXT 단독 / 'AL'=통합(KRX→NXT 연속).
|
||||
NX/AL은 stk_cd에 suffix를 붙여 NXT 시간대(15:30~20:00)에도 분봉이 이어진다.
|
||||
|
||||
반환: 시간 오름차순 list of dict — {date, time, open, high, low, close, volume}
|
||||
date='YYYYMMDD', time='HHMMSS'.
|
||||
"""
|
||||
label = account_label or _default_account_label()
|
||||
suffix = f'_{exchange}' if exchange in ('NX', 'AL') else ''
|
||||
body = {
|
||||
'stk_cd': _clean_code(code),
|
||||
'stk_cd': _clean_code(code) + suffix,
|
||||
'tic_scope': str(tic_scope),
|
||||
'upd_stkpc_tp': '1',
|
||||
}
|
||||
|
||||
@@ -859,7 +859,7 @@ def _build_data_block(snap: dict) -> str:
|
||||
lines.append(f'### 종목: {snap["name"]} ({snap["code"]})')
|
||||
lines.append(f'- 현재가: {b["price"]:,}원 ({b["change"]:+,} / {b["change_pct"]:+.2f}%)')
|
||||
lines.append(f'- 오늘 시고저: 시 {b["open"]:,} / 고 {b["high"]:,} / 저 {b["low"]:,}')
|
||||
lines.append(f'- 시가총액: {b["market_cap"]:,} (단위 키움원본) · 상장주식수: {b["listed_shares"]:,}주')
|
||||
lines.append(f'- 시가총액: {_fmt_market_cap(b["market_cap"])} · 상장주식수: {b["listed_shares"]:,}주')
|
||||
lines.append(f'- 52주 고저: 고 {b["high_52w"]:,}원 ({_fmt_date(b["high_52w_dt"])}) / 저 {b["low_52w"]:,}원 ({_fmt_date(b["low_52w_dt"])})')
|
||||
lines.append(f'- 회전율(오늘): {b["turnover_rate"]:.2f}% · 외국인 보유비율: {b["foreign_holding_pct"]:.2f}%')
|
||||
lines.append(f'- PER {b["per"]} · PBR {b["pbr"]} · ROE {b["roe"]} · EPS {b["eps"]:,} · BPS {b["bps"]:,}')
|
||||
@@ -1121,6 +1121,19 @@ def _fmt_pct_signed(v: float) -> str:
|
||||
return f'{v:+.2f}%'
|
||||
|
||||
|
||||
def _fmt_market_cap(eok) -> str:
|
||||
"""키움 mac(억원) → 사람이 읽는 '2,084조 1,983억원'. 0/None은 '—'."""
|
||||
if not isinstance(eok, (int, float)) or eok <= 0:
|
||||
return '—'
|
||||
eok = int(eok)
|
||||
jo, rem = divmod(eok, 10000)
|
||||
if jo and rem:
|
||||
return f'{jo:,}조 {rem:,}억원'
|
||||
if jo:
|
||||
return f'{jo:,}조원'
|
||||
return f'{rem:,}억원'
|
||||
|
||||
|
||||
def _fmt_date(s) -> str:
|
||||
"""20260519 → 2026-05-19. 형식 다르면 원본 반환."""
|
||||
s = str(s or '').strip()
|
||||
@@ -1477,6 +1490,12 @@ def build_report_html(snap: dict, parsed: dict) -> str:
|
||||
v = p.get(field)
|
||||
return f'{v:,}{suffix}' if isinstance(v, (int, float)) else '—'
|
||||
|
||||
def _peer_mac(p: dict) -> str:
|
||||
if p.get('error'):
|
||||
return '<span style="color:#ef4444;font-size:11px">조회 실패</span>'
|
||||
v = p.get('market_cap')
|
||||
return _fmt_market_cap(v) if isinstance(v, (int, float)) else '—'
|
||||
|
||||
def _peer_pct(p: dict, field: str) -> str:
|
||||
if p.get('error'):
|
||||
return '<span style="color:#ef4444;font-size:11px">조회 실패</span>'
|
||||
@@ -1501,8 +1520,7 @@ def build_report_html(snap: dict, parsed: dict) -> str:
|
||||
('오늘 시가', f'{b["open"]:,}원', lambda p: _peer_int(p, 'open', '원')),
|
||||
('오늘 고가', f'{b["high"]:,}원', lambda p: _peer_int(p, 'high', '원')),
|
||||
('오늘 저가', f'{b["low"]:,}원', lambda p: _peer_int(p, 'low', '원')),
|
||||
('시가총액', f'{b["market_cap"]:,} <span style="color:#7a8493;font-size:11px">(키움 원본 단위)</span>',
|
||||
lambda p: _peer_int(p, 'market_cap', '')),
|
||||
('시가총액', _fmt_market_cap(b["market_cap"]), _peer_mac),
|
||||
('상장주식수', f'{b["listed_shares"]:,}주', lambda p: _peer_int(p, 'listed_shares', '주')),
|
||||
('52주 최고', f'{b["high_52w"]:,}원 <span style="color:#7a8493;font-size:11px">({_fmt_date(b["high_52w_dt"])})</span>',
|
||||
lambda p: _peer_52w(p, 'high_52w', 'high_52w_dt')),
|
||||
|
||||
Reference in New Issue
Block a user