From 76001b19940779d3b215a77d1f87f03ac4003136 Mon Sep 17 00:00:00 2001 From: hyowons Date: Thu, 11 Jun 2026 12:23:10 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EA=B8=B0=EC=97=85=EC=A0=95=EB=B3=B4=20?= =?UTF-8?q?=EC=A2=85=ED=95=A9=20=ED=8C=90=EB=8B=A8=EC=97=90=20=EC=B6=94?= =?UTF-8?q?=EC=A0=95ROE=C2=B7=EC=B6=94=EC=A0=95EPS=20=EB=A6=AC=EB=B9=84?= =?UTF-8?q?=EC=A0=84=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ROE: trailing 낮아도 추정ROE 급증(≥15% & 현재의 1.5배↑) 전망이면 좋은 점으로 표시 - PBR≥3: 추정ROE≥20%면 고평가 단정 대신 '실현 여부 관건'으로 완화 (PER/추정PER과 동일 패턴) - 추정EPS 리비전(est_change_pct)을 전망 개선/악화 판단에 추가 (목표가 리비전보다 직접적 신호) - synthNote: pbrJustified로 valHigh 제외 + EPS 리비전을 grPos/grNeg에 포함 Co-Authored-By: Claude Opus 4.8 (1M context) --- agents/stock/workspace/scripts/behive_web.py | 32 ++++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/agents/stock/workspace/scripts/behive_web.py b/agents/stock/workspace/scripts/behive_web.py index 29b7aa6..78f471f 100644 --- a/agents/stock/workspace/scripts/behive_web.py +++ b/agents/stock/workspace/scripts/behive_web.py @@ -7911,7 +7911,14 @@ def render_html() -> str: 'function companyGC(j){' 'var good=[],caution=[],per=_gnum(j.per),pbr=_gnum(j.pbr),roe=_gnum(j.roe);' 'var fwd=_gnum((j.fundamentals&&j.fundamentals.consensus)?j.fundamentals.consensus.per:null);' - '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)+"% — 자본 수익성 다소 낮음");}' + 'var estRoe=_gnum((j.consensus&&j.consensus.this_year)?j.consensus.this_year.roe:null);' + # ROE: trailing 낮아도 추정ROE 급증 전망이면 그쪽을 우선 표시 (PER/추정PER과 동일 패턴). + 'if(roe!=null){' + 'if(roe<0)caution.push("ROE "+roe.toFixed(1)+"% — 자기자본이 손실(수익성 부진)");' + 'else if(roe>=15)good.push("ROE "+roe.toFixed(1)+"% — 자본 수익성 우수");' + 'else if(estRoe!=null&&estRoe>=15&&estRoe>=roe*1.5)good.push("추정ROE "+estRoe.toFixed(1)+"% — 올해 수익성 급증 전망(현재 "+roe.toFixed(1)+"%)");' + 'else if(roe<8)caution.push("ROE "+roe.toFixed(1)+"% — 자본 수익성 다소 낮음");' + '}' # PER: trailing 높아도 추정(forward) PER이 크게 낮으면 이익 급증 기대 반영 → 고평가로 단정 X, 다만 추정치 미달 위험 경고. 'if(per!=null){' 'if(per<=0)caution.push("PER 산정 불가 — 적자 또는 이익 미미");' @@ -7921,7 +7928,14 @@ def render_html() -> str: '}' '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)+"배 — 자산가치(청산가치) 이하");}' + # PBR: 높아도 추정ROE가 충분히 높으면 정당화 가능 → 단정 대신 실현 여부 관건으로 표현. + 'if(pbr!=null){' + 'if(pbr>=3){' + 'if(estRoe!=null&&estRoe>=20)caution.push("PBR "+pbr.toFixed(1)+"배 — 자산가치 대비 높지만, 추정ROE "+estRoe.toFixed(1)+"% 실현 여부가 관건");' + 'else caution.push("PBR "+pbr.toFixed(1)+"배 — 자산가치 대비 비싼 편");' + '}' + 'else if(pbr>0&&pbr<1)good.push("PBR "+pbr.toFixed(1)+"배 — 자산가치(청산가치) 이하");' + '}' 'return {good:good,caution:caution};' '}' 'function growthGC(j){' @@ -7934,6 +7948,9 @@ def render_html() -> str: 'if(p&&tp){var up=(tp/p-1)*100;if(up>=15)good.push("목표주가까지 상승여력 +"+up.toFixed(0)+"%");else if(up<0)caution.push("현재가가 목표주가를 "+(-up).toFixed(0)+"% 웃돔 — 추가 상승여력 제한");}' '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)+"%) — 전망 악화");}' + # 추정EPS 리비전 — 목표가 리비전보다 직접적인 이익 전망 신호. + 'var er=_gnum(cn.est_change_pct);var ri=cn.rev_item||"EPS";' + 'if(er!=null){if(er>0)good.push("최근 추정"+escHtml(ri)+" 상향(+"+er.toFixed(1)+"%) — 이익 전망 개선");else if(er<0)caution.push("최근 추정"+escHtml(ri)+" 하향("+er.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 {good:good,caution:caution};' '}' @@ -7943,13 +7960,16 @@ def render_html() -> str: '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 fwd=_gnum(fc.per);' + 'var fwd=_gnum(fc.per);var er=_gnum(cn.est_change_pct);' + 'var estRoe=_gnum((cn&&cn.this_year)?cn.this_year.roe:null);' 'var growthPriced=(per!=null&&per>=30&&fwd!=null&&fwd>0&&fwd=30&&!growthPriced)||(pbr!=null&&pbr>=3);' + # 추정ROE가 충분히 높으면 높은 PBR을 고평가로 단정하지 않음 (companyGC와 동일 기준). + 'var pbrJustified=(pbr!=null&&pbr>=3&&estRoe!=null&&estRoe>=20);' + 'var valHigh=(per!=null&&per>=30&&!growthPriced)||(pbr!=null&&pbr>=3&&!pbrJustified);' '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);' + 'var grPos=(oy!=null&&oy>=20)||(up!=null&&up>=15)||buy||(tr!=null&&tr>0)||(er!=null&&er>0);' + 'var grNeg=(oy!=null&&oy<0)||(sy!=null&&sy<0)||(up!=null&&up<0)||(tr!=null&&tr<0)||(er!=null&&er<0);' 'if(growthPriced)return "현재 PER은 "+per.toFixed(0)+"배로 높지만 추정이익이 급증해 추정(forward) PER은 "+fwd.toFixed(1)+"배로 낮아요. 시장이 가파른 이익 성장을 기대하는 구간으로, 성장이 실현되면 밸류가 정당화되지만 추정치에 못 미치면 조정 위험이 큽니다.";' 'if(valHigh&&grPos)return "성장·실적 기대는 좋지만 현재 밸류에이션이 높아 그 기대가 주가에 이미 상당 부분 반영돼 있어요. 성장이 기대만큼 이어지는지가 관건입니다.";' 'if(valCheap&&grNeg)return "밸류에이션은 저평가 구간이나 성장·전망이 부진해요. 싸다는 이유만으로 접근하기보다 실적 반등 신호를 함께 봐야 합니다.";'