Skip to main content
Glama

MaverickMCP

by wshobson
MIT License
165
  • Apple
test_macro_data_provider.py14.7 kB
""" Tests for the MacroDataProvider class. """ import unittest from datetime import datetime from unittest.mock import MagicMock, patch import pandas as pd from maverick_mcp.providers.macro_data import MacroDataProvider class TestMacroDataProvider(unittest.TestCase): """Test suite for MacroDataProvider.""" @patch("fredapi.Fred") def setUp(self, mock_fred_class): """Set up test fixtures.""" mock_fred = MagicMock() mock_fred_class.return_value = mock_fred # Create provider with mocked FRED self.provider = MacroDataProvider() self.provider.fred = mock_fred @patch("fredapi.Fred") def test_init_with_fred_api(self, mock_fred_class): """Test initialization with FRED API.""" mock_fred = MagicMock() mock_fred_class.return_value = mock_fred provider = MacroDataProvider(window_days=180) self.assertEqual(provider.window_days, 180) self.assertIsNotNone(provider.scaler) self.assertIsNotNone(provider.weights) mock_fred_class.assert_called_once() def test_calculate_weighted_rolling_performance(self): """Test weighted rolling performance calculation.""" # Mock FRED data mock_data = pd.Series( [100, 102, 104, 106, 108], index=pd.date_range(end=datetime.now(), periods=5, freq="D"), ) with patch.object(self.provider.fred, "get_series") as mock_get_series: mock_get_series.return_value = mock_data result = self.provider._calculate_weighted_rolling_performance( # type: ignore[attr-defined] "SP500", [30, 90, 180], [0.5, 0.3, 0.2] ) self.assertIsInstance(result, float) self.assertEqual(mock_get_series.call_count, 3) def test_calculate_weighted_rolling_performance_empty_data(self): """Test weighted rolling performance with empty data.""" with patch.object(self.provider.fred, "get_series") as mock_get_series: mock_get_series.return_value = pd.Series([]) result = self.provider._calculate_weighted_rolling_performance( # type: ignore[attr-defined] "SP500", [30], [1.0] ) self.assertEqual(result, 0.0) def test_get_sp500_performance(self): """Test S&P 500 performance calculation.""" with patch.object( self.provider, "_calculate_weighted_rolling_performance" ) as mock_calc: mock_calc.return_value = 5.5 result = self.provider.get_sp500_performance() self.assertEqual(result, 5.5) mock_calc.assert_called_once_with("SP500", [30, 90, 180], [0.5, 0.3, 0.2]) def test_get_nasdaq_performance(self): """Test NASDAQ performance calculation.""" with patch.object( self.provider, "_calculate_weighted_rolling_performance" ) as mock_calc: mock_calc.return_value = 7.2 result = self.provider.get_nasdaq_performance() self.assertEqual(result, 7.2) mock_calc.assert_called_once_with( "NASDAQ100", [30, 90, 180], [0.5, 0.3, 0.2] ) def test_get_gdp_growth_rate(self): """Test GDP growth rate fetching.""" mock_data = pd.Series( [2.5, 2.8], index=pd.date_range(end=datetime.now(), periods=2, freq="Q") ) with patch.object(self.provider.fred, "get_series") as mock_get_series: mock_get_series.return_value = mock_data result = self.provider.get_gdp_growth_rate() self.assertIsInstance(result, dict) self.assertEqual(result["current"], 2.8) self.assertEqual(result["previous"], 2.5) def test_get_gdp_growth_rate_empty_data(self): """Test GDP growth rate with no data.""" with patch.object(self.provider.fred, "get_series") as mock_get_series: mock_get_series.return_value = pd.Series([]) result = self.provider.get_gdp_growth_rate() self.assertEqual(result["current"], 0.0) self.assertEqual(result["previous"], 0.0) def test_get_unemployment_rate(self): """Test unemployment rate fetching.""" mock_data = pd.Series( [3.5, 3.6, 3.7], index=pd.date_range(end=datetime.now(), periods=3, freq="M"), ) with patch.object(self.provider.fred, "get_series") as mock_get_series: mock_get_series.return_value = mock_data result = self.provider.get_unemployment_rate() self.assertIsInstance(result, dict) self.assertEqual(result["current"], 3.7) self.assertEqual(result["previous"], 3.6) def test_get_inflation_rate(self): """Test inflation rate calculation.""" # Create CPI data for 24 months dates = pd.date_range(end=datetime.now(), periods=24, freq="MS") cpi_values = [100 + i * 0.2 for i in range(24)] # Gradual increase mock_data = pd.Series(cpi_values, index=dates) with patch.object(self.provider.fred, "get_series") as mock_get_series: mock_get_series.return_value = mock_data result = self.provider.get_inflation_rate() self.assertIsInstance(result, dict) self.assertIn("current", result) self.assertIn("previous", result) self.assertIn("bounds", result) self.assertIsInstance(result["bounds"], tuple) def test_get_inflation_rate_insufficient_data(self): """Test inflation rate with insufficient data.""" # Only 6 months of data (need 13+ for YoY) dates = pd.date_range(end=datetime.now(), periods=6, freq="MS") mock_data = pd.Series([100, 101, 102, 103, 104, 105], index=dates) with patch.object(self.provider.fred, "get_series") as mock_get_series: mock_get_series.return_value = mock_data result = self.provider.get_inflation_rate() self.assertEqual(result["current"], 0.0) self.assertEqual(result["previous"], 0.0) def test_get_vix(self): """Test VIX fetching.""" # Test with yfinance first with patch("yfinance.Ticker") as mock_ticker_class: mock_ticker = MagicMock() mock_ticker_class.return_value = mock_ticker mock_ticker.history.return_value = pd.DataFrame( {"Close": [18.5]}, index=[datetime.now()] ) result = self.provider.get_vix() self.assertEqual(result, 18.5) def test_get_vix_fallback_to_fred(self): """Test VIX fetching with FRED fallback.""" with patch("yfinance.Ticker") as mock_ticker_class: mock_ticker = MagicMock() mock_ticker_class.return_value = mock_ticker mock_ticker.history.return_value = pd.DataFrame() # Empty yfinance data mock_fred_data = pd.Series([20.5], index=[datetime.now()]) with patch.object(self.provider.fred, "get_series") as mock_get_series: mock_get_series.return_value = mock_fred_data result = self.provider.get_vix() self.assertEqual(result, 20.5) def test_get_sp500_momentum(self): """Test S&P 500 momentum calculation.""" # Create mock data with upward trend dates = pd.date_range(end=datetime.now(), periods=15, freq="D") values = [3000 + i * 10 for i in range(15)] mock_data = pd.Series(values, index=dates) with patch.object(self.provider.fred, "get_series") as mock_get_series: mock_get_series.return_value = mock_data result = self.provider.get_sp500_momentum() self.assertIsInstance(result, float) self.assertGreater(result, 0) # Should be positive for upward trend def test_get_nasdaq_momentum(self): """Test NASDAQ momentum calculation.""" dates = pd.date_range(end=datetime.now(), periods=15, freq="D") values = [15000 + i * 50 for i in range(15)] mock_data = pd.Series(values, index=dates) with patch.object(self.provider.fred, "get_series") as mock_get_series: mock_get_series.return_value = mock_data result = self.provider.get_nasdaq_momentum() self.assertIsInstance(result, float) self.assertGreater(result, 0) def test_get_usd_momentum(self): """Test USD momentum calculation.""" dates = pd.date_range(end=datetime.now(), periods=15, freq="D") values = [100 + i * 0.1 for i in range(15)] mock_data = pd.Series(values, index=dates) with patch.object(self.provider.fred, "get_series") as mock_get_series: mock_get_series.return_value = mock_data result = self.provider.get_usd_momentum() self.assertIsInstance(result, float) def test_update_historical_bounds(self): """Test updating historical bounds.""" # Mock data for different indicators gdp_data = pd.Series([1.5, 2.0, 2.5, 3.0]) unemployment_data = pd.Series([3.5, 4.0, 4.5, 5.0]) with patch.object(self.provider.fred, "get_series") as mock_get_series: def side_effect(series_id, *args, **kwargs): if series_id == "A191RL1Q225SBEA": return gdp_data elif series_id == "UNRATE": return unemployment_data else: return pd.Series([]) mock_get_series.side_effect = side_effect self.provider.update_historical_bounds() self.assertIn("gdp_growth_rate", self.provider.historical_data_bounds) self.assertIn("unemployment_rate", self.provider.historical_data_bounds) def test_default_bounds(self): """Test default bounds for indicators.""" bounds = self.provider.default_bounds("vix") self.assertEqual(bounds["min"], 10.0) self.assertEqual(bounds["max"], 50.0) bounds = self.provider.default_bounds("unknown_indicator") self.assertEqual(bounds["min"], 0.0) self.assertEqual(bounds["max"], 1.0) def test_normalize_indicators(self): """Test indicator normalization.""" indicators = { "vix": 30.0, # Middle of 10-50 range "sp500_momentum": 0.0, # Middle of -15 to 15 range "unemployment_rate": 6.0, # Middle of 2-10 range "gdp_growth_rate": 2.0, # In -2 to 6 range } normalized = self.provider.normalize_indicators(indicators) # VIX should be inverted (lower is better) self.assertAlmostEqual(normalized["vix"], 0.5, places=1) # SP500 momentum at 0 should normalize to 0.5 self.assertAlmostEqual(normalized["sp500_momentum"], 0.5, places=1) # Unemployment should be inverted self.assertAlmostEqual(normalized["unemployment_rate"], 0.5, places=1) def test_normalize_indicators_with_none_values(self): """Test normalization with None values.""" indicators = { "vix": None, "sp500_momentum": 5.0, } normalized = self.provider.normalize_indicators(indicators) self.assertEqual(normalized["vix"], 0.5) # Default for None self.assertGreater(normalized["sp500_momentum"], 0.5) def test_get_historical_data(self): """Test fetching historical data.""" # Mock different data series sp500_data = pd.Series( [3000, 3050, 3100], index=pd.date_range(end=datetime.now(), periods=3, freq="D"), ) vix_data = pd.Series( [15, 16, 17], index=pd.date_range(end=datetime.now(), periods=3, freq="D") ) with patch.object(self.provider.fred, "get_series") as mock_get_series: def side_effect(series_id, *args, **kwargs): if series_id == "SP500": return sp500_data elif series_id == "VIXCLS": return vix_data else: return pd.Series([]) mock_get_series.side_effect = side_effect result = self.provider.get_historical_data() self.assertIsInstance(result, dict) self.assertIn("sp500_performance", result) self.assertIn("vix", result) self.assertIsInstance(result["sp500_performance"], list) self.assertIsInstance(result["vix"], list) def test_get_macro_statistics(self): """Test comprehensive macro statistics.""" # Mock all the individual methods with patch.object(self.provider, "get_gdp_growth_rate") as mock_gdp: mock_gdp.return_value = {"current": 2.5, "previous": 2.3} with patch.object( self.provider, "get_unemployment_rate" ) as mock_unemployment: mock_unemployment.return_value = {"current": 3.7, "previous": 3.8} with patch.object( self.provider, "get_inflation_rate" ) as mock_inflation: mock_inflation.return_value = { "current": 2.1, "previous": 2.0, "bounds": (1.5, 3.0), } with patch.object(self.provider, "get_vix") as mock_vix: mock_vix.return_value = 18.5 result = self.provider.get_macro_statistics() self.assertIsInstance(result, dict) self.assertEqual(result["gdp_growth_rate"], 2.5) self.assertEqual(result["unemployment_rate"], 3.7) self.assertEqual(result["inflation_rate"], 2.1) self.assertEqual(result["vix"], 18.5) self.assertIn("sentiment_score", result) self.assertIsInstance(result["sentiment_score"], float) self.assertTrue(1 <= result["sentiment_score"] <= 100) def test_get_macro_statistics_error_handling(self): """Test macro statistics with errors.""" with patch.object(self.provider, "update_historical_bounds") as mock_update: mock_update.side_effect = Exception("Update error") result = self.provider.get_macro_statistics() # Should return safe defaults self.assertEqual(result["gdp_growth_rate"], 0.0) self.assertEqual(result["unemployment_rate"], 0.0) self.assertEqual(result["sentiment_score"], 50.0) if __name__ == "__main__": unittest.main()

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/wshobson/maverick-mcp'

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