Skip to main content
Glama

MCP Stock Details Server

by whdghk1907
test_advanced_financial_tools.pyβ€’20.7 kB
""" Unit tests for advanced financial analysis tools TDD Red Phase: Write failing tests for enhanced financial functionality """ import pytest import asyncio from unittest.mock import Mock, AsyncMock, patch from datetime import datetime, date from typing import Dict, Any, List # Test imports will fail initially - this is expected in TDD Red phase try: from src.tools.financial_tools import FinancialAnalyzer, RatioAnalyzer, TrendAnalyzer from src.models.financial import FinancialStatements, RatioAnalysis, TrendAnalysis, PeerComparison from src.exceptions import MCPStockDetailsError, InsufficientDataError from src.utils.financial_calculator import FinancialCalculator except ImportError: # Expected in Red phase - we haven't implemented these yet pass class TestFinancialAnalyzer: """Test cases for enhanced financial analysis functionality""" @pytest.fixture def financial_analyzer(self): """Create financial analyzer instance for testing""" return FinancialAnalyzer() @pytest.fixture def sample_multi_year_data(self): """Sample multi-year financial data for testing""" return { "005930": [ { "year": 2023, "revenue": 258_774_000_000_000, "operating_profit": 22_034_000_000_000, "net_profit": 15_349_000_000_000, "total_assets": 426_071_000_000_000, "total_equity": 319_167_000_000_000, "total_debt": 106_904_000_000_000, "current_assets": 200_000_000_000_000, "current_liabilities": 80_000_000_000_000, "cash": 50_000_000_000_000, "inventory": 30_000_000_000_000 }, { "year": 2022, "revenue": 302_231_000_000_000, "operating_profit": 43_376_000_000_000, "net_profit": 28_095_000_000_000, "total_assets": 399_653_000_000_000, "total_equity": 295_321_000_000_000, "total_debt": 104_332_000_000_000, "current_assets": 180_000_000_000_000, "current_liabilities": 75_000_000_000_000, "cash": 45_000_000_000_000, "inventory": 28_000_000_000_000 }, { "year": 2021, "revenue": 279_621_000_000_000, "operating_profit": 51_634_000_000_000, "net_profit": 39_895_000_000_000, "total_assets": 373_280_000_000_000, "total_equity": 281_866_000_000_000, "total_debt": 91_414_000_000_000, "current_assets": 170_000_000_000_000, "current_liabilities": 70_000_000_000_000, "cash": 42_000_000_000_000, "inventory": 25_000_000_000_000 } ] } @pytest.mark.asyncio async def test_get_comprehensive_financial_analysis(self, financial_analyzer, sample_multi_year_data): """Test comprehensive financial analysis with multiple years""" company_code = "005930" analysis = await financial_analyzer.get_comprehensive_analysis( company_code=company_code, years=3, include_ratios=True, include_trends=True, include_peer_comparison=True ) assert analysis is not None assert "financial_statements" in analysis assert "ratio_analysis" in analysis assert "trend_analysis" in analysis assert "peer_comparison" in analysis assert "financial_health_score" in analysis # Test financial statements structure financial_statements = analysis["financial_statements"] assert len(financial_statements) == 3 # 3 years of data assert all("year" in stmt for stmt in financial_statements) assert all("revenue" in stmt for stmt in financial_statements) # Test ratio analysis structure ratio_analysis = analysis["ratio_analysis"] assert "profitability" in ratio_analysis assert "liquidity" in ratio_analysis assert "leverage" in ratio_analysis assert "efficiency" in ratio_analysis assert "market" in ratio_analysis # Test trend analysis structure trend_analysis = analysis["trend_analysis"] assert "revenue_trend" in trend_analysis assert "profit_trend" in trend_analysis assert "margin_trends" in trend_analysis assert "growth_rates" in trend_analysis # Test financial health score health_score = analysis["financial_health_score"] assert "overall_score" in health_score assert "grade" in health_score assert 0 <= health_score["overall_score"] <= 100 @pytest.mark.asyncio async def test_calculate_advanced_ratios(self, financial_analyzer): """Test calculation of advanced financial ratios""" company_code = "005930" ratios = await financial_analyzer.calculate_advanced_ratios( company_code=company_code, years=3 ) assert ratios is not None # Test profitability ratios profitability = ratios["profitability"] required_ratios = ["gross_margin", "operating_margin", "net_margin", "roe", "roa", "roic"] for ratio in required_ratios: assert ratio in profitability assert isinstance(profitability[ratio], (int, float)) # Test liquidity ratios liquidity = ratios["liquidity"] liquidity_ratios = ["current_ratio", "quick_ratio", "cash_ratio", "operating_cash_ratio"] for ratio in liquidity_ratios: assert ratio in liquidity assert liquidity[ratio] > 0 # Test leverage ratios leverage = ratios["leverage"] leverage_ratios = ["debt_to_equity", "debt_to_assets", "equity_ratio", "interest_coverage"] for ratio in leverage_ratios: assert ratio in leverage assert isinstance(leverage[ratio], (int, float)) # Test efficiency ratios efficiency = ratios["efficiency"] efficiency_ratios = ["asset_turnover", "inventory_turnover", "receivables_turnover", "working_capital_turnover"] for ratio in efficiency_ratios: assert ratio in efficiency assert efficiency[ratio] > 0 @pytest.mark.asyncio async def test_analyze_financial_trends(self, financial_analyzer): """Test financial trend analysis over multiple years""" company_code = "005930" trends = await financial_analyzer.analyze_trends( company_code=company_code, years=5 ) assert trends is not None assert "revenue_trend" in trends assert "profit_trend" in trends assert "margin_trends" in trends assert "growth_rates" in trends assert "seasonality" in trends # Test growth analysis growth = trends["growth_rates"] assert "revenue_cagr" in growth assert "profit_cagr" in growth assert "asset_growth" in growth assert "volatility" in growth # Test margin trends margin_trends = trends["margin_trends"] assert "operating_margin_trend" in margin_trends assert "net_margin_trend" in margin_trends assert "margin_stability" in margin_trends # Test seasonality analysis seasonality = trends["seasonality"] assert "quarterly_patterns" in seasonality assert "seasonal_strength" in seasonality @pytest.mark.asyncio async def test_peer_comparison_analysis(self, financial_analyzer): """Test peer comparison functionality""" company_code = "005930" industry_code = "26211" # Semiconductor manufacturing comparison = await financial_analyzer.compare_with_peers( company_code=company_code, industry_code=industry_code, peer_count=10 ) assert comparison is not None assert "company_metrics" in comparison assert "peer_metrics" in comparison assert "industry_benchmarks" in comparison assert "relative_performance" in comparison assert "ranking" in comparison # Test company metrics company_metrics = comparison["company_metrics"] assert "profitability_score" in company_metrics assert "liquidity_score" in company_metrics assert "leverage_score" in company_metrics # Test peer metrics peer_metrics = comparison["peer_metrics"] assert "peer_count" in peer_metrics assert "average_ratios" in peer_metrics assert "percentiles" in peer_metrics # Test ranking ranking = comparison["ranking"] assert "overall_rank" in ranking assert "percentile" in ranking assert 0 <= ranking["percentile"] <= 100 @pytest.mark.asyncio async def test_dupont_analysis(self, financial_analyzer): """Test DuPont analysis for ROE decomposition""" company_code = "005930" dupont = await financial_analyzer.calculate_dupont_analysis( company_code=company_code, years=3 ) assert dupont is not None assert "roe" in dupont assert "roe_components" in dupont assert "trend_analysis" in dupont # Test ROE components components = dupont["roe_components"] assert "net_margin" in components assert "asset_turnover" in components assert "equity_multiplier" in components # Verify DuPont formula: ROE = Net Margin Γ— Asset Turnover Γ— Equity Multiplier calculated_roe = components["net_margin"] * components["asset_turnover"] * components["equity_multiplier"] assert abs(calculated_roe - dupont["roe"]) < 1.0 # Allow small rounding differences @pytest.mark.asyncio async def test_cash_flow_analysis(self, financial_analyzer): """Test cash flow analysis functionality""" company_code = "005930" cash_flow = await financial_analyzer.analyze_cash_flows( company_code=company_code, years=3 ) assert cash_flow is not None assert "operating_cash_flow" in cash_flow assert "investing_cash_flow" in cash_flow assert "financing_cash_flow" in cash_flow assert "free_cash_flow" in cash_flow assert "cash_flow_ratios" in cash_flow assert "cash_conversion_cycle" in cash_flow # Test cash flow ratios ratios = cash_flow["cash_flow_ratios"] assert "operating_cash_ratio" in ratios assert "cash_coverage_ratio" in ratios assert "free_cash_flow_yield" in ratios # Test cash conversion cycle cycle = cash_flow["cash_conversion_cycle"] assert "days_sales_outstanding" in cycle assert "days_inventory_outstanding" in cycle assert "days_payable_outstanding" in cycle assert "cash_cycle_days" in cycle @pytest.mark.asyncio async def test_financial_forecasting(self, financial_analyzer): """Test financial forecasting capabilities""" company_code = "005930" forecast = await financial_analyzer.generate_financial_forecast( company_code=company_code, forecast_years=2, scenario="base" ) assert forecast is not None assert "forecast_data" in forecast assert "assumptions" in forecast assert "scenarios" in forecast assert "confidence_intervals" in forecast # Test forecast data forecast_data = forecast["forecast_data"] assert len(forecast_data) == 2 # 2 years forecast for year_data in forecast_data: assert "year" in year_data assert "revenue" in year_data assert "operating_profit" in year_data assert "net_profit" in year_data assert year_data["year"] > 2023 # Future years # Test scenarios scenarios = forecast["scenarios"] assert "optimistic" in scenarios assert "pessimistic" in scenarios assert "base" in scenarios @pytest.mark.asyncio async def test_financial_health_scoring(self, financial_analyzer): """Test comprehensive financial health scoring""" company_code = "005930" health_score = await financial_analyzer.calculate_financial_health_score( company_code=company_code ) assert health_score is not None assert "overall_score" in health_score assert "component_scores" in health_score assert "grade" in health_score assert "risk_factors" in health_score assert "strengths" in health_score assert "recommendations" in health_score # Test score ranges assert 0 <= health_score["overall_score"] <= 100 assert health_score["grade"] in ["A+", "A", "B+", "B", "C+", "C", "D", "F"] # Test component scores components = health_score["component_scores"] required_components = ["profitability", "liquidity", "leverage", "efficiency", "growth"] for component in required_components: assert component in components assert 0 <= components[component] <= 100 @pytest.mark.asyncio async def test_error_handling_insufficient_data(self, financial_analyzer): """Test error handling for insufficient financial data""" invalid_company = "999999" with pytest.raises(InsufficientDataError): await financial_analyzer.get_comprehensive_analysis( company_code=invalid_company, years=10 # Requesting too many years ) @pytest.mark.asyncio async def test_quarterly_analysis(self, financial_analyzer): """Test quarterly financial data analysis""" company_code = "005930" quarterly = await financial_analyzer.analyze_quarterly_data( company_code=company_code, quarters=8 # 2 years of quarterly data ) assert quarterly is not None assert "quarterly_data" in quarterly assert "seasonal_patterns" in quarterly assert "quarterly_growth" in quarterly assert "consistency_metrics" in quarterly # Test quarterly data structure quarterly_data = quarterly["quarterly_data"] assert len(quarterly_data) == 8 for quarter in quarterly_data: assert "year" in quarter assert "quarter" in quarter assert "revenue" in quarter assert "operating_profit" in quarter assert quarter["quarter"] in [1, 2, 3, 4] class TestRatioAnalyzer: """Test cases for specialized ratio analysis""" @pytest.fixture def ratio_analyzer(self): """Create ratio analyzer instance""" return RatioAnalyzer() def test_calculate_all_ratios(self, ratio_analyzer): """Test calculation of all financial ratios at once""" financial_data = { "revenue": 100_000_000_000, "gross_profit": 40_000_000_000, "operating_profit": 25_000_000_000, "net_profit": 18_000_000_000, "total_assets": 150_000_000_000, "current_assets": 80_000_000_000, "total_liabilities": 60_000_000_000, "current_liabilities": 30_000_000_000, "total_equity": 90_000_000_000, "cash": 20_000_000_000, "inventory": 15_000_000_000, "receivables": 12_000_000_000 } all_ratios = ratio_analyzer.calculate_all_ratios(financial_data) # Test that all major categories are present assert "profitability" in all_ratios assert "liquidity" in all_ratios assert "leverage" in all_ratios assert "efficiency" in all_ratios assert "coverage" in all_ratios # Test specific calculations profitability = all_ratios["profitability"] assert profitability["gross_margin"] == 40.0 # 40/100 * 100 assert profitability["operating_margin"] == 25.0 # 25/100 * 100 assert profitability["net_margin"] == 18.0 # 18/100 * 100 def test_ratio_benchmarking(self, ratio_analyzer): """Test ratio benchmarking against industry standards""" company_ratios = { "current_ratio": 2.5, "debt_to_equity": 0.3, "roe": 15.0, "operating_margin": 12.0 } industry_code = "26211" benchmark = ratio_analyzer.benchmark_ratios(company_ratios, industry_code) assert benchmark is not None assert "comparisons" in benchmark assert "overall_assessment" in benchmark assert "recommendations" in benchmark # Test comparison structure comparisons = benchmark["comparisons"] for ratio_name in company_ratios.keys(): assert ratio_name in comparisons comparison = comparisons[ratio_name] assert "company_value" in comparison assert "industry_median" in comparison assert "percentile" in comparison assert "assessment" in comparison class TestTrendAnalyzer: """Test cases for trend analysis functionality""" @pytest.fixture def trend_analyzer(self): """Create trend analyzer instance""" return TrendAnalyzer() def test_calculate_trend_indicators(self, trend_analyzer): """Test calculation of various trend indicators""" historical_data = [ {"year": 2019, "revenue": 80_000_000_000, "profit": 8_000_000_000}, {"year": 2020, "revenue": 85_000_000_000, "profit": 9_000_000_000}, {"year": 2021, "revenue": 92_000_000_000, "profit": 11_000_000_000}, {"year": 2022, "revenue": 98_000_000_000, "profit": 12_000_000_000}, {"year": 2023, "revenue": 105_000_000_000, "profit": 13_500_000_000} ] trends = trend_analyzer.analyze_trends(historical_data) assert trends is not None assert "growth_rates" in trends assert "trend_strength" in trends assert "volatility" in trends assert "forecasts" in trends # Test growth rates growth_rates = trends["growth_rates"] assert "revenue_cagr" in growth_rates assert "profit_cagr" in growth_rates assert growth_rates["revenue_cagr"] > 0 # Should be positive growth assert growth_rates["profit_cagr"] > 0 # Should be positive growth def test_seasonal_analysis(self, trend_analyzer): """Test seasonal pattern analysis""" quarterly_data = [] # Generate 3 years of quarterly data with seasonal pattern for year in [2021, 2022, 2023]: for quarter in [1, 2, 3, 4]: base_revenue = 20_000_000_000 seasonal_factor = [0.9, 1.0, 1.1, 1.2][quarter - 1] # Q4 typically strongest revenue = base_revenue * seasonal_factor * (1 + (year - 2021) * 0.1) quarterly_data.append({ "year": year, "quarter": quarter, "revenue": revenue }) seasonal = trend_analyzer.analyze_seasonality(quarterly_data) assert seasonal is not None assert "seasonal_factors" in seasonal assert "seasonal_strength" in seasonal assert "peak_quarters" in seasonal # Test seasonal factors factors = seasonal["seasonal_factors"] assert len(factors) == 4 # One factor per quarter assert max(factors) > min(factors) # Should show variation if __name__ == "__main__": # Run tests with pytest pytest.main([__file__, "-v"])

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/whdghk1907/mcp-stock-details'

If you have feedback or need assistance with the MCP directory API, please join our Discord server