Score / core /scoring.py
Corin1998's picture
Update core/scoring.py
cbdf486 verified
# core/scoring.py
from __future__ import annotations
from typing import Dict, Any
def _safe_ratio(a, b):
try:
if a is None or b in (None, 0):
return None
return float(a) / float(b)
except Exception:
return None
def _ramp(x, good, bad, lo=0.0, hi=100.0, neutral=50.0):
if x is None:
return neutral
if good > bad:
if x <= bad: return lo
if x >= good: return hi
return lo + (hi-lo) * (x-bad)/(good-bad)
else:
if x >= bad: return lo
if x <= good: return hi
return lo + (hi-lo) * (x-good)/(bad-good)
def score_company(fin: Dict[str, Any]) -> Dict[str, Any]:
bs = fin.get("balance_sheet") or {}
is_ = fin.get("income_statement") or {}
cf = fin.get("cash_flows") or {}
ca = bs.get("current_assets")
cl = bs.get("current_liabilities")
ta = bs.get("total_assets")
tl = bs.get("total_liabilities")
sales = is_.get("sales")
opinc = is_.get("operating_income")
ni = is_.get("net_income")
ocf = cf.get("operating_cash_flow")
fcf = None
if ocf is not None and is_.get("operating_expenses") is not None:
fcf = ocf - is_.get("operating_expenses")
# 単位ばらつき吸収:比率中心
cr = _safe_ratio(ca, cl) # 流動比率
lev = _safe_ratio(tl, ta) # 負債比率
opm = _safe_ratio(opinc, sales) # 営業利益率
npm = _safe_ratio(ni, sales) # 純利益率
ocf_ms = _safe_ratio(ocf, sales) # 営業CF/売上
details = []
details.append({"metric": "流動比率", "score": round(_ramp(cr, 2.0, 0.8),1)})
details.append({"metric": "負債比率(低い程良)", "score": round(_ramp(lev, 0.4, 1.2),1)})
details.append({"metric": "営業利益率", "score": round(_ramp(opm, 0.12, 0.00),1)})
details.append({"metric": "純利益率", "score": round(_ramp(npm, 0.08, -0.05),1)})
details.append({"metric": "営業CF/売上", "score": round(_ramp(ocf_ms, 0.10, -0.05),1)})
total = round(sum(d["score"] for d in details)/len(details), 1)
grade = "S" if total>=85 else "A" if total>=75 else "B" if total>=65 else "C" if total>=50 else "D"
return {"total_score": total, "grade": grade, "details": details}