Skip to main content
Glama

MCP Stock Details Server

by whdghk1907
test_risk_analyzer.pyβ€’14.8 kB
""" Unit tests for RiskAnalyzer class TDD Red Phase: Write failing tests for risk analysis engine """ import pytest import asyncio from unittest.mock import Mock, AsyncMock, patch from datetime import datetime, date, timedelta from typing import Dict, Any, List, Optional # Test imports - initially will fail (TDD Red phase) from src.tools.risk_tools import RiskAnalyzer from src.exceptions import MCPStockDetailsError, InsufficientDataError class TestRiskAnalyzer: """Test cases for RiskAnalyzer class""" @pytest.fixture def risk_analyzer(self): """Create RiskAnalyzer instance for testing""" return RiskAnalyzer() @pytest.fixture def sample_financial_data(self): """Sample financial data for risk calculations""" return { "company_code": "005930", "revenue": 258_774_000_000_000, "total_debt": 45_000_000_000_000, "total_equity": 100_000_000_000_000, "current_assets": 180_000_000_000_000, "current_liabilities": 85_000_000_000_000, "ebitda": 28_500_000_000_000, "interest_expense": 2_100_000_000_000, "market_cap": 435_000_000_000_000, "beta": 1.25 } @pytest.fixture def sample_price_history(self): """Sample price history for volatility calculations""" return [ {"date": "2024-01-15", "close": 73000, "return": 0.007}, {"date": "2024-01-14", "close": 72500, "return": 0.010}, {"date": "2024-01-13", "close": 71800, "return": 0.018}, {"date": "2024-01-12", "close": 70500, "return": 0.010}, {"date": "2024-01-11", "close": 69800, "return": 0.014} ] @pytest.mark.asyncio async def test_calculate_market_risk(self, risk_analyzer, sample_financial_data, sample_price_history): """Test market risk calculation (Beta, VaR, volatility)""" market_risk = await risk_analyzer.calculate_market_risk( financial_data=sample_financial_data, price_history=sample_price_history, market_returns=[0.005, 0.008, 0.012, 0.006, 0.009] ) assert market_risk is not None assert isinstance(market_risk, dict) # Should contain market risk metrics assert "beta" in market_risk assert "volatility" in market_risk assert "var_95" in market_risk assert "var_99" in market_risk assert "correlation_market" in market_risk # Beta should be reasonable assert 0.5 <= market_risk["beta"] <= 2.0 # VaR should be positive assert market_risk["var_95"] > 0 assert market_risk["var_99"] > market_risk["var_95"] @pytest.mark.asyncio async def test_calculate_credit_risk(self, risk_analyzer, sample_financial_data): """Test credit risk assessment""" credit_risk = await risk_analyzer.calculate_credit_risk( financial_data=sample_financial_data, credit_rating="AA" ) assert credit_risk is not None assert isinstance(credit_risk, dict) # Should contain credit risk components assert "credit_rating" in credit_risk assert "probability_default" in credit_risk assert "debt_to_equity" in credit_risk assert "interest_coverage" in credit_risk assert "current_ratio" in credit_risk assert "credit_score" in credit_risk # Credit metrics should be reasonable assert credit_risk["debt_to_equity"] >= 0 assert credit_risk["interest_coverage"] > 0 assert credit_risk["current_ratio"] > 0 assert 0 <= credit_risk["credit_score"] <= 100 @pytest.mark.asyncio async def test_calculate_liquidity_risk(self, risk_analyzer, sample_financial_data): """Test liquidity risk assessment""" trading_data = { "average_volume": 15000000, "bid_ask_spread": 0.002, "price_impact": 0.015, "market_cap": sample_financial_data["market_cap"] } liquidity_risk = await risk_analyzer.calculate_liquidity_risk( financial_data=sample_financial_data, trading_data=trading_data ) assert liquidity_risk is not None assert isinstance(liquidity_risk, dict) # Should contain liquidity metrics assert "liquidity_score" in liquidity_risk assert "trading_volume" in liquidity_risk assert "bid_ask_spread" in liquidity_risk assert "market_impact" in liquidity_risk assert "liquidity_risk_level" in liquidity_risk # Liquidity score should be 0-100 assert 0 <= liquidity_risk["liquidity_score"] <= 100 # Risk level should be categorical assert liquidity_risk["liquidity_risk_level"] in ["low", "medium", "high"] @pytest.mark.asyncio async def test_calculate_operational_risk(self, risk_analyzer, sample_financial_data): """Test operational risk assessment""" operational_factors = { "industry_risk": 65.0, "regulatory_environment": 70.0, "technology_dependence": 85.0, "management_quality": 78.0, "geographic_exposure": 60.0 } operational_risk = await risk_analyzer.calculate_operational_risk( financial_data=sample_financial_data, operational_factors=operational_factors ) assert operational_risk is not None assert isinstance(operational_risk, dict) # Should contain operational risk components assert "business_risk_score" in operational_risk assert "regulatory_risk" in operational_risk assert "technology_risk" in operational_risk assert "management_risk" in operational_risk assert "operational_risk_level" in operational_risk # Scores should be 0-100 for score_key in ["business_risk_score", "regulatory_risk", "technology_risk", "management_risk"]: assert 0 <= operational_risk[score_key] <= 100 @pytest.mark.asyncio async def test_calculate_concentration_risk(self, risk_analyzer, sample_financial_data): """Test concentration risk assessment""" concentration_data = { "geographic_breakdown": {"domestic": 0.55, "asia": 0.30, "americas": 0.10, "europe": 0.05}, "product_breakdown": {"semiconductors": 0.60, "displays": 0.25, "mobile": 0.15}, "customer_breakdown": {"customer_1": 0.22, "customer_2": 0.18, "others": 0.60} } concentration_risk = await risk_analyzer.calculate_concentration_risk( financial_data=sample_financial_data, concentration_data=concentration_data ) assert concentration_risk is not None assert isinstance(concentration_risk, dict) # Should contain concentration metrics assert "geographic_concentration" in concentration_risk assert "product_concentration" in concentration_risk assert "customer_concentration" in concentration_risk assert "concentration_risk_score" in concentration_risk # Concentration ratios should be 0-1 assert 0 <= concentration_risk["geographic_concentration"] <= 1 assert 0 <= concentration_risk["product_concentration"] <= 1 assert 0 <= concentration_risk["customer_concentration"] <= 1 @pytest.mark.asyncio async def test_calculate_integrated_risk_score(self, risk_analyzer): """Test integrated risk score calculation""" risk_components = { "market_risk": {"score": 65.0, "weight": 0.25}, "credit_risk": {"score": 78.0, "weight": 0.20}, "liquidity_risk": {"score": 85.0, "weight": 0.15}, "operational_risk": {"score": 72.0, "weight": 0.25}, "concentration_risk": {"score": 68.0, "weight": 0.15} } integrated_score = await risk_analyzer.calculate_integrated_risk_score( risk_components=risk_components ) assert integrated_score is not None assert isinstance(integrated_score, dict) # Should contain integrated metrics assert "overall_risk_score" in integrated_score assert "risk_level" in integrated_score assert "risk_grade" in integrated_score assert "component_breakdown" in integrated_score # Overall score should be 0-100 assert 0 <= integrated_score["overall_risk_score"] <= 100 # Risk level should be categorical assert integrated_score["risk_level"] in ["very_low", "low", "medium", "high", "very_high"] # Risk grade should be letter grade assert integrated_score["risk_grade"] in ["A", "B", "C", "D", "F"] @pytest.mark.asyncio async def test_calculate_risk_adjusted_returns(self, risk_analyzer, sample_price_history): """Test risk-adjusted returns calculation""" performance_data = { "annual_return": 0.15, "benchmark_return": 0.08, "risk_free_rate": 0.03, "beta": 1.25, "volatility": 0.28 } risk_adjusted = await risk_analyzer.calculate_risk_adjusted_returns( performance_data=performance_data, price_history=sample_price_history ) assert risk_adjusted is not None assert isinstance(risk_adjusted, dict) # Should contain risk-adjusted metrics assert "sharpe_ratio" in risk_adjusted assert "treynor_ratio" in risk_adjusted assert "jensen_alpha" in risk_adjusted assert "information_ratio" in risk_adjusted assert "sortino_ratio" in risk_adjusted # Ratios should be reasonable assert -5 <= risk_adjusted["sharpe_ratio"] <= 5 assert -5 <= risk_adjusted["treynor_ratio"] <= 5 @pytest.mark.asyncio async def test_perform_scenario_analysis(self, risk_analyzer, sample_financial_data): """Test scenario analysis and stress testing""" scenarios = { "bull_case": {"market_change": 0.20, "sector_change": 0.25, "company_specific": 0.15}, "base_case": {"market_change": 0.08, "sector_change": 0.10, "company_specific": 0.05}, "bear_case": {"market_change": -0.15, "sector_change": -0.20, "company_specific": -0.10} } scenario_results = await risk_analyzer.perform_scenario_analysis( financial_data=sample_financial_data, scenarios=scenarios, current_price=73000 ) assert scenario_results is not None assert isinstance(scenario_results, dict) # Should contain scenario results assert "bull_case" in scenario_results assert "base_case" in scenario_results assert "bear_case" in scenario_results assert "stress_test" in scenario_results # Each scenario should have expected fields for scenario in ["bull_case", "base_case", "bear_case"]: assert "expected_price" in scenario_results[scenario] assert "probability" in scenario_results[scenario] assert "impact" in scenario_results[scenario] @pytest.mark.asyncio async def test_generate_risk_recommendations(self, risk_analyzer): """Test risk recommendation generation""" risk_profile = { "overall_risk_score": 72.5, "risk_level": "medium", "key_risks": ["market_volatility", "concentration_risk", "liquidity_risk"], "risk_components": { "market_risk": 65.0, "credit_risk": 85.0, "operational_risk": 70.0 } } recommendations = await risk_analyzer.generate_risk_recommendations( risk_profile=risk_profile, investment_horizon="long_term" ) assert recommendations is not None assert isinstance(recommendations, list) assert len(recommendations) > 0 # Each recommendation should have required fields for rec in recommendations: assert "category" in rec assert "recommendation" in rec assert "priority" in rec assert "impact" in rec assert rec["priority"] in ["high", "medium", "low"] @pytest.mark.asyncio async def test_comprehensive_risk_analysis(self, risk_analyzer, sample_financial_data): """Test comprehensive risk analysis""" comprehensive_analysis = await risk_analyzer.comprehensive_risk_analysis( financial_data=sample_financial_data, include_all_metrics=True ) assert comprehensive_analysis is not None assert isinstance(comprehensive_analysis, dict) # Should contain all major risk categories assert "market_risk" in comprehensive_analysis assert "credit_risk" in comprehensive_analysis assert "liquidity_risk" in comprehensive_analysis assert "operational_risk" in comprehensive_analysis assert "integrated_score" in comprehensive_analysis assert "risk_summary" in comprehensive_analysis # Should have summary metrics assert "overall_risk_rating" in comprehensive_analysis["risk_summary"] assert "key_risk_factors" in comprehensive_analysis["risk_summary"] assert "recommendations" in comprehensive_analysis["risk_summary"] @pytest.mark.asyncio async def test_error_handling_insufficient_data(self, risk_analyzer): """Test error handling for insufficient data""" # Test with insufficient financial data insufficient_data = {"company_code": "005930"} with pytest.raises(InsufficientDataError): await risk_analyzer.calculate_credit_risk(insufficient_data) @pytest.mark.asyncio async def test_error_handling_invalid_parameters(self, risk_analyzer, sample_financial_data): """Test error handling for invalid parameters""" # Test with invalid risk weights invalid_components = { "market_risk": {"score": 65.0, "weight": -0.25} # Negative weight } with pytest.raises(MCPStockDetailsError): await risk_analyzer.calculate_integrated_risk_score(invalid_components)

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