107 lines
3.2 KiB
Python
107 lines
3.2 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
from backend.agents.skills_manager import SkillsManager
|
|
from backend.skills.builtin.valuation_review.scripts.dcf_report import (
|
|
build_dcf_report,
|
|
)
|
|
from backend.skills.builtin.valuation_review.scripts.multiple_valuation_report import (
|
|
build_ev_ebitda_report,
|
|
build_residual_income_report,
|
|
)
|
|
from backend.skills.builtin.valuation_review.scripts.owner_earnings_report import (
|
|
build_owner_earnings_report,
|
|
)
|
|
|
|
|
|
def test_build_dcf_report_renders_assessment():
|
|
report = build_dcf_report(
|
|
[
|
|
{
|
|
"ticker": "AAPL",
|
|
"current_fcf": 100.0,
|
|
"growth_rate": 0.05,
|
|
"market_cap": 900.0,
|
|
"discount_rate": 0.10,
|
|
"terminal_growth": 0.03,
|
|
"num_years": 5,
|
|
},
|
|
],
|
|
"2026-03-17",
|
|
)
|
|
|
|
assert "DCF Valuation Analysis (2026-03-17)" in report
|
|
assert "AAPL:" in report
|
|
assert "Market Cap: $900" in report
|
|
assert "Value Gap:" in report
|
|
|
|
|
|
def test_build_owner_earnings_report_handles_errors():
|
|
report = build_owner_earnings_report(
|
|
[
|
|
{
|
|
"ticker": "MSFT",
|
|
"error": "Negative owner earnings ($-50)",
|
|
},
|
|
],
|
|
"2026-03-17",
|
|
)
|
|
|
|
assert "MSFT: Negative owner earnings ($-50)" in report
|
|
|
|
|
|
def test_multiple_valuation_reports_render_expected_sections():
|
|
ev_report = build_ev_ebitda_report(
|
|
[
|
|
{
|
|
"ticker": "NVDA",
|
|
"current_multiple": 18.0,
|
|
"median_multiple": 20.0,
|
|
"current_ebitda": 50.0,
|
|
"market_cap": 800.0,
|
|
"net_debt": 100.0,
|
|
},
|
|
],
|
|
"2026-03-17",
|
|
)
|
|
residual_report = build_residual_income_report(
|
|
[
|
|
{
|
|
"ticker": "META",
|
|
"book_value": 200.0,
|
|
"initial_ri": 30.0,
|
|
"market_cap": 300.0,
|
|
"cost_of_equity": 0.10,
|
|
"bv_growth": 0.03,
|
|
"terminal_growth": 0.03,
|
|
"num_years": 5,
|
|
"margin_of_safety": 0.20,
|
|
},
|
|
],
|
|
"2026-03-17",
|
|
)
|
|
|
|
assert "EV/EBITDA Valuation (2026-03-17)" in ev_report
|
|
assert "NVDA:" in ev_report
|
|
assert "Residual Income Valuation (2026-03-17)" in residual_report
|
|
assert "META:" in residual_report
|
|
|
|
|
|
def test_prepare_active_skills_copies_skill_scripts(tmp_path):
|
|
builtin_skill = tmp_path / "backend" / "skills" / "builtin" / "valuation_review"
|
|
scripts_dir = builtin_skill / "scripts"
|
|
scripts_dir.mkdir(parents=True, exist_ok=True)
|
|
(builtin_skill / "SKILL.md").write_text(
|
|
"---\nname: 估值分析\ndescription: desc\nversion: 1.0.0\n---\n",
|
|
encoding="utf-8",
|
|
)
|
|
(scripts_dir / "dcf_report.py").write_text("print('ok')\n", encoding="utf-8")
|
|
|
|
manager = SkillsManager(project_root=tmp_path)
|
|
active_map = manager.prepare_active_skills(
|
|
config_name="demo",
|
|
agent_defaults={"valuation_analyst": ["valuation_review"]},
|
|
)
|
|
|
|
active_dir = active_map["valuation_analyst"][0]
|
|
assert (active_dir / "scripts" / "dcf_report.py").exists()
|