feat: 기업정보 모달 — 가치+성장 종합 해석을 요약탭에 통합
각 탭의 개별 판단 박스 제거. 요약탭 최상단에 📌종합(가치 vs 성장·컨센서스 상충을 한 문장으로 화해: 고평가+긍정/저평가+부진/고평가+부진/저평가+긍정 4분기) + ✅좋은 점 / ⚠️주의할 점(두 영역 합산) 표시. companyJudge/growthJudge → companyGC/growthGC({good,caution}) + synthNote 추가. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -4443,6 +4443,8 @@ dl.pending-detail .pending-line-meta { margin-top: 2px; }
|
|||||||
.info-summary { background: #11161f; border: 1px solid #232a36; border-radius: 8px; padding: 10px 12px; margin: 0 0 12px; }
|
.info-summary { background: #11161f; border: 1px solid #232a36; border-radius: 8px; padding: 10px 12px; margin: 0 0 12px; }
|
||||||
.info-jd + .info-jd { margin-top: 8px; }
|
.info-jd + .info-jd { margin-top: 8px; }
|
||||||
.info-jd > b { display: block; font-size: 12px; margin-bottom: 3px; }
|
.info-jd > b { display: block; font-size: 12px; margin-bottom: 3px; }
|
||||||
|
.info-jd-s > b { color: #8ab4f8; }
|
||||||
|
.info-jd-s-b { font-size: 12.5px; color: #d6d8dd; line-height: 1.65; }
|
||||||
.info-jd-g > b { color: #34d399; }
|
.info-jd-g > b { color: #34d399; }
|
||||||
.info-jd-c > b { color: #fbbf24; }
|
.info-jd-c > b { color: #fbbf24; }
|
||||||
.info-summary ul { margin: 0; padding-left: 17px; }
|
.info-summary ul { margin: 0; padding-left: 17px; }
|
||||||
@@ -7880,7 +7882,10 @@ def render_html() -> str:
|
|||||||
'var fg=j.fundamentals||{},gr=fg.growth||{},fc=fg.consensus||{},cn=j.consensus||{};'
|
'var fg=j.fundamentals||{},gr=fg.growth||{},fc=fg.consensus||{},cn=j.consensus||{};'
|
||||||
'var chg=(j.change>0?"#ef4444":(j.change<0?"#3b82f6":"#9ca3af"));'
|
'var chg=(j.change>0?"#ef4444":(j.change<0?"#3b82f6":"#9ca3af"));'
|
||||||
'var pc=(j.change_pct!=null?(\' <span style="color:\'+chg+\';font-size:12px">(\'+(j.change_pct>0?"+":"")+fmtNum(j.change_pct,2)+\'%)</span>\'):"");'
|
'var pc=(j.change_pct!=null?(\' <span style="color:\'+chg+\';font-size:12px">(\'+(j.change_pct>0?"+":"")+fmtNum(j.change_pct,2)+\'%)</span>\'):"");'
|
||||||
'var h=\'<dl class="info-grid">\';'
|
# 가치 + 성장·컨센서스 종합 해석 박스 (요약탭 최상단).
|
||||||
|
'var _cg=companyGC(j),_gg=growthGC(j);'
|
||||||
|
'var h=judgeBox(synthNote(j),_cg.good.concat(_gg.good),_cg.caution.concat(_gg.caution));'
|
||||||
|
'h+=\'<dl class="info-grid">\';'
|
||||||
'h+=row("현재가",\'<span style="color:\'+chg+\';font-weight:700">\'+infoWon(j.price)+\'</span>\'+pc,"현재가");'
|
'h+=row("현재가",\'<span style="color:\'+chg+\';font-weight:700">\'+infoWon(j.price)+\'</span>\'+pc,"현재가");'
|
||||||
'h+=row("시가총액",capDisp(j.market_cap),"시가총액");'
|
'h+=row("시가총액",capDisp(j.market_cap),"시가총액");'
|
||||||
'if(fc.target_price!=null)h+=row("목표주가",\'<span style="color:#fbbf24;font-weight:700">\'+infoWon(fc.target_price)+\'</span>\'+(fc.opinion_label?\' <span style="color:#9aa4b2;font-size:12px">\'+escHtml(fc.opinion_label)+\'</span>\':""),"목표주가");'
|
'if(fc.target_price!=null)h+=row("목표주가",\'<span style="color:#fbbf24;font-weight:700">\'+infoWon(fc.target_price)+\'</span>\'+(fc.opinion_label?\' <span style="color:#9aa4b2;font-size:12px">\'+escHtml(fc.opinion_label)+\'</span>\':""),"목표주가");'
|
||||||
@@ -7894,21 +7899,23 @@ def render_html() -> str:
|
|||||||
'}'
|
'}'
|
||||||
# 탭 상단 해석 박스 — 지표를 ✅좋은 점 / ⚠️주의할 점으로 판단(규칙 기반). 특이점 없으면 미표시.
|
# 탭 상단 해석 박스 — 지표를 ✅좋은 점 / ⚠️주의할 점으로 판단(규칙 기반). 특이점 없으면 미표시.
|
||||||
'function _gnum(v){var n=Number(v);return (v==null||v===""||isNaN(n))?null:n;}'
|
'function _gnum(v){var n=Number(v);return (v==null||v===""||isNaN(n))?null:n;}'
|
||||||
'function judgeBox(good,caution){'
|
'function judgeBox(synth,good,caution){'
|
||||||
'if(!good.length&&!caution.length)return "";'
|
'if(!synth&&!good.length&&!caution.length)return "";'
|
||||||
'var h="";'
|
'var h="";'
|
||||||
|
'if(synth)h+=\'<div class="info-jd info-jd-s"><b>📌 종합</b><div class="info-jd-s-b">\'+synth+\'</div></div>\';'
|
||||||
'if(good.length)h+=\'<div class="info-jd info-jd-g"><b>✅ 좋은 점</b><ul>\'+good.map(function(x){return "<li>"+x+"</li>";}).join("")+\'</ul></div>\';'
|
'if(good.length)h+=\'<div class="info-jd info-jd-g"><b>✅ 좋은 점</b><ul>\'+good.map(function(x){return "<li>"+x+"</li>";}).join("")+\'</ul></div>\';'
|
||||||
'if(caution.length)h+=\'<div class="info-jd info-jd-c"><b>⚠️ 주의할 점</b><ul>\'+caution.map(function(x){return "<li>"+x+"</li>";}).join("")+\'</ul></div>\';'
|
'if(caution.length)h+=\'<div class="info-jd info-jd-c"><b>⚠️ 주의할 점</b><ul>\'+caution.map(function(x){return "<li>"+x+"</li>";}).join("")+\'</ul></div>\';'
|
||||||
'return \'<div class="info-summary">\'+h+\'</div>\';'
|
'return \'<div class="info-summary">\'+h+\'</div>\';'
|
||||||
'}'
|
'}'
|
||||||
'function companyJudge(j){'
|
# 가치/성장 지표를 {good,caution} 으로 분류 (요약탭에서 합쳐 표시).
|
||||||
|
'function companyGC(j){'
|
||||||
'var good=[],caution=[],per=_gnum(j.per),pbr=_gnum(j.pbr),roe=_gnum(j.roe);'
|
'var good=[],caution=[],per=_gnum(j.per),pbr=_gnum(j.pbr),roe=_gnum(j.roe);'
|
||||||
'if(roe!=null){if(roe<0)caution.push("ROE "+roe.toFixed(1)+"% — 자기자본이 손실(수익성 부진)");else if(roe>=15)good.push("ROE "+roe.toFixed(1)+"% — 자본 수익성 우수");else if(roe<8)caution.push("ROE "+roe.toFixed(1)+"% — 자본 수익성 다소 낮음");}'
|
'if(roe!=null){if(roe<0)caution.push("ROE "+roe.toFixed(1)+"% — 자기자본이 손실(수익성 부진)");else if(roe>=15)good.push("ROE "+roe.toFixed(1)+"% — 자본 수익성 우수");else if(roe<8)caution.push("ROE "+roe.toFixed(1)+"% — 자본 수익성 다소 낮음");}'
|
||||||
'if(per!=null){if(per<=0)caution.push("PER 산정 불가 — 적자 또는 이익 미미");else if(per>=30)caution.push("PER "+per.toFixed(1)+"배 — 기대가 선반영된 고평가 부담");else if(per<=10)good.push("PER "+per.toFixed(1)+"배 — 밸류에이션 부담이 작음");}'
|
'if(per!=null){if(per<=0)caution.push("PER 산정 불가 — 적자 또는 이익 미미");else if(per>=30)caution.push("PER "+per.toFixed(1)+"배 — 기대가 선반영된 고평가 부담");else if(per<=10)good.push("PER "+per.toFixed(1)+"배 — 밸류에이션 부담이 작음");}'
|
||||||
'if(pbr!=null){if(pbr>=3)caution.push("PBR "+pbr.toFixed(1)+"배 — 자산가치 대비 비싼 편");else if(pbr>0&&pbr<1)good.push("PBR "+pbr.toFixed(1)+"배 — 자산가치(청산가치) 이하");}'
|
'if(pbr!=null){if(pbr>=3)caution.push("PBR "+pbr.toFixed(1)+"배 — 자산가치 대비 비싼 편");else if(pbr>0&&pbr<1)good.push("PBR "+pbr.toFixed(1)+"배 — 자산가치(청산가치) 이하");}'
|
||||||
'return judgeBox(good,caution);'
|
'return {good:good,caution:caution};'
|
||||||
'}'
|
'}'
|
||||||
'function growthJudge(j){'
|
'function growthGC(j){'
|
||||||
'var gr=(j.fundamentals&&j.fundamentals.growth)||{},fc=(j.fundamentals&&j.fundamentals.consensus)||{},cn=j.consensus||{},good=[],caution=[];'
|
'var gr=(j.fundamentals&&j.fundamentals.growth)||{},fc=(j.fundamentals&&j.fundamentals.consensus)||{},cn=j.consensus||{},good=[],caution=[];'
|
||||||
'var sy=_gnum(gr.sales_yoy),oy=_gnum(gr.oper_profit_yoy),ey=_gnum(gr.eps_yoy);'
|
'var sy=_gnum(gr.sales_yoy),oy=_gnum(gr.oper_profit_yoy),ey=_gnum(gr.eps_yoy);'
|
||||||
'if(oy!=null){if(oy>=20)good.push("영업이익 +"+oy.toFixed(0)+"% — 이익 고성장");else if(oy<0)caution.push("영업이익 "+oy.toFixed(0)+"% — 이익 역성장");}'
|
'if(oy!=null){if(oy>=20)good.push("영업이익 +"+oy.toFixed(0)+"% — 이익 고성장");else if(oy<0)caution.push("영업이익 "+oy.toFixed(0)+"% — 이익 역성장");}'
|
||||||
@@ -7919,10 +7926,29 @@ def render_html() -> str:
|
|||||||
'if(fc.opinion_label){if(fc.opinion_label.indexOf("매수")>=0)good.push("증권사 투자의견 "+escHtml(fc.opinion_label));else if(fc.opinion_label.indexOf("매도")>=0||fc.opinion_label.indexOf("중립")>=0||fc.opinion_label.indexOf("보유")>=0)caution.push("투자의견 "+escHtml(fc.opinion_label)+" — 적극 매수는 아님");}'
|
'if(fc.opinion_label){if(fc.opinion_label.indexOf("매수")>=0)good.push("증권사 투자의견 "+escHtml(fc.opinion_label));else if(fc.opinion_label.indexOf("매도")>=0||fc.opinion_label.indexOf("중립")>=0||fc.opinion_label.indexOf("보유")>=0)caution.push("투자의견 "+escHtml(fc.opinion_label)+" — 적극 매수는 아님");}'
|
||||||
'var tr=_gnum(cn.target_change_pct);if(tr!=null){if(tr>0)good.push("최근 3개월 목표가 상향(+"+tr.toFixed(1)+"%) — 전망 개선");else if(tr<0)caution.push("최근 3개월 목표가 하향("+tr.toFixed(1)+"%) — 전망 악화");}'
|
'var tr=_gnum(cn.target_change_pct);if(tr!=null){if(tr>0)good.push("최근 3개월 목표가 상향(+"+tr.toFixed(1)+"%) — 전망 개선");else if(tr<0)caution.push("최근 3개월 목표가 하향("+tr.toFixed(1)+"%) — 전망 악화");}'
|
||||||
'var so=_gnum(cn.surprise_op);if(so!=null){if(so>0)good.push("최근 영업이익 어닝 서프라이즈(+"+so.toFixed(1)+"%)");else if(so<0)caution.push("최근 영업이익이 컨센서스 하회("+so.toFixed(1)+"%)");}'
|
'var so=_gnum(cn.surprise_op);if(so!=null){if(so>0)good.push("최근 영업이익 어닝 서프라이즈(+"+so.toFixed(1)+"%)");else if(so<0)caution.push("최근 영업이익이 컨센서스 하회("+so.toFixed(1)+"%)");}'
|
||||||
'return judgeBox(good,caution);'
|
'return {good:good,caution:caution};'
|
||||||
'}'
|
'}'
|
||||||
'var companyInner=companyJudge(j)+titled("가치지표",secGrid("가치지표"))+titled("기본정보",secGrid("기본정보"));'
|
# 가치(고평가 등) vs 성장·컨센서스(긍정 등) 상충을 한 문장으로 종합.
|
||||||
'var growthInner=growthJudge(j)+secGrid("성장성·컨센서스");'
|
'function synthNote(j){'
|
||||||
|
'var per=_gnum(j.per),pbr=_gnum(j.pbr);'
|
||||||
|
'var gr=(j.fundamentals&&j.fundamentals.growth)||{},fc=(j.fundamentals&&j.fundamentals.consensus)||{},cn=j.consensus||{};'
|
||||||
|
'var oy=_gnum(gr.oper_profit_yoy),sy=_gnum(gr.sales_yoy),tr=_gnum(cn.target_change_pct);'
|
||||||
|
'var p=_gnum(j.price),tp=_gnum(fc.target_price),up=(p&&tp)?(tp/p-1)*100:null;'
|
||||||
|
'var valHigh=(per!=null&&per>=30)||(pbr!=null&&pbr>=3);'
|
||||||
|
'var valCheap=(per!=null&&per>0&&per<=10)||(pbr!=null&&pbr>0&&pbr<1);'
|
||||||
|
'var buy=fc.opinion_label&&fc.opinion_label.indexOf("매수")>=0;'
|
||||||
|
'var grPos=(oy!=null&&oy>=20)||(up!=null&&up>=15)||buy||(tr!=null&&tr>0);'
|
||||||
|
'var grNeg=(oy!=null&&oy<0)||(sy!=null&&sy<0)||(up!=null&&up<0)||(tr!=null&&tr<0);'
|
||||||
|
'if(valHigh&&grPos)return "성장·실적 기대는 좋지만 현재 밸류에이션이 높아 그 기대가 주가에 이미 상당 부분 반영돼 있어요. 성장이 기대만큼 이어지는지가 관건입니다.";'
|
||||||
|
'if(valCheap&&grNeg)return "밸류에이션은 저평가 구간이나 성장·전망이 부진해요. 싸다는 이유만으로 접근하기보다 실적 반등 신호를 함께 봐야 합니다.";'
|
||||||
|
'if(valHigh&&grNeg)return "밸류에이션이 높은데 성장·전망도 약한 부담스러운 조합이에요. 신중히 접근하세요.";'
|
||||||
|
'if(valCheap&&grPos)return "저평가 구간에 성장·전망까지 양호한 긍정적 조합이에요.";'
|
||||||
|
'if(grPos)return "밸류 부담은 크지 않은 수준에서 성장·전망이 양호한 편이에요.";'
|
||||||
|
'if(grNeg)return "성장·전망이 다소 부진한 편이에요.";'
|
||||||
|
'return "";'
|
||||||
|
'}'
|
||||||
|
'var companyInner=titled("가치지표",secGrid("가치지표"))+titled("기본정보",secGrid("기본정보"));'
|
||||||
|
'var growthInner=secGrid("성장성·컨센서스");'
|
||||||
'var repInner=infoReportsHtml(j);'
|
'var repInner=infoReportsHtml(j);'
|
||||||
'var TB=[["summary","요약",sumPanel()],["company","기업정보·가치",companyInner],["growth","성장성·컨센서스",growthInner],["reports","투자리포트",repInner]];'
|
'var TB=[["summary","요약",sumPanel()],["company","기업정보·가치",companyInner],["growth","성장성·컨센서스",growthInner],["reports","투자리포트",repInner]];'
|
||||||
'var bar=\'<div class="info-tabs" role="tablist">\';var pans="";'
|
'var bar=\'<div class="info-tabs" role="tablist">\';var pans="";'
|
||||||
|
|||||||
Reference in New Issue
Block a user