"""T4.3 Monte Carlo 模拟 + 组合再平衡测试。 测试边际回报率计算、组合再平衡和 Monte Carlo 模拟。 """ import pytest from app.services.monte_carlo import simulate_portfolio from app.services.portfolio_rebalancer import ( calculate_marginal_return, rebalance_portfolio, run_monte_carlo, ) class TestCalculateMarginalReturn: """边际回报率测试。""" def test_positive_investment(self): """正常投入计算边际回报。""" result = calculate_marginal_return(1000, 500, 0.2) assert result > 0 def test_zero_additional(self): """追加投入为 0 时返回 0。""" result = calculate_marginal_return(1000, 0, 0.2) assert result == 0.0 def test_negative_additional(self): """追加投入为负时返回 0。""" result = calculate_marginal_return(1000, -100, 0.2) assert result == 0.0 class TestRebalancePortfolio: """组合再平衡测试。""" def test_returns_dict(self): """返回再平衡结果。""" companies = [ {"company_id": "c1", "marginal_return": 0.15}, {"company_id": "c2", "marginal_return": 0.08}, {"company_id": "c3", "marginal_return": 0.20}, {"company_id": "c4", "marginal_return": 0.05}, ] result = rebalance_portfolio(companies) assert "marginal_returns" in result assert "reallocation_plan" in result assert "irr_impact" in result assert "dpi_impact" in result def test_top_quartile_increased(self): """高回报企业应被增加投入。""" companies = [ {"company_id": "c1", "marginal_return": 0.05}, {"company_id": "c2", "marginal_return": 0.20}, {"company_id": "c3", "marginal_return": 0.15}, {"company_id": "c4", "marginal_return": 0.01}, ] result = rebalance_portfolio(companies) increase = result["reallocation_plan"]["increase"] assert "c2" in increase class TestRunMonteCarlo: """Monte Carlo 模拟测试。""" def test_with_floats(self): """浮点数回报率列表。""" result = run_monte_carlo([0.1, 0.2, 0.15, 0.05], iterations=100) assert "irr_distribution" in result assert "percentile_p5" in result assert "percentile_p50" in result assert "percentile_p95" in result def test_with_dicts(self): """字典格式回报率列表。""" result = run_monte_carlo( [{"irr": 0.1}, {"irr": 0.2}, {"irr": 0.15}], iterations=100, ) assert "irr_distribution" in result def test_empty_returns(self): """空列表返回默认结果。""" result = run_monte_carlo([], iterations=100) assert result["percentile_p5"] == 0 assert result["percentile_p50"] == 0 class TestSimulatePortfolio: """Monte Carlo 异步接口测试。""" async def test_simulate(self): """异步模拟接口。""" result = await simulate_portfolio([0.1, 0.2, 0.15], iterations=100) assert "irr_distribution" in result