Skip to main content
Glama

MaverickMCP

by wshobson
MIT License
165
  • Apple
test_technical_analysis.py9.94 kB
""" Tests for technical analysis module. """ import unittest from datetime import datetime, timedelta import numpy as np import pandas as pd from maverick_mcp.core.technical_analysis import ( add_technical_indicators, analyze_bollinger_bands, analyze_macd, analyze_rsi, analyze_stochastic, analyze_trend, analyze_volume, generate_outlook, identify_chart_patterns, identify_resistance_levels, identify_support_levels, ) def create_test_dataframe(days=100): """Create a test dataframe with price data.""" date_today = datetime.now() dates = [date_today - timedelta(days=i) for i in range(days)] dates.reverse() # Oldest first # Start with a seed value and generate slightly random walk data np.random.seed(42) # For reproducibility close_price = 100.0 prices = [] volumes = [] for _ in range(days): # Simulate some volatility with random noise and a slight upward trend pct_change = np.random.normal(0.0005, 0.015) # mean, std dev close_price = close_price * (1 + pct_change) # Calculate OHLC and volume open_price = close_price * (1 + np.random.normal(0, 0.005)) high_price = max(open_price, close_price) * ( 1 + abs(np.random.normal(0, 0.008)) ) low_price = min(open_price, close_price) * (1 - abs(np.random.normal(0, 0.008))) volume = int(np.random.normal(1000000, 300000)) prices.append([open_price, high_price, low_price, close_price]) volumes.append(volume) # Create DataFrame df = pd.DataFrame( prices, index=pd.DatetimeIndex(dates), columns=["open", "high", "low", "close"] ) df["volume"] = volumes return df class TestTechnicalAnalysis(unittest.TestCase): """Test cases for technical analysis functions.""" def setUp(self): """Set up test fixtures.""" self.df = create_test_dataframe(days=200) self.df_with_indicators = add_technical_indicators(self.df) def test_add_technical_indicators(self): """Test that indicators are added to the dataframe.""" result = add_technical_indicators(self.df) # Check that all expected columns are present expected_columns = [ "open", "high", "low", "close", "volume", "ema_21", "sma_50", "sma_200", "rsi", "macd_12_26_9", "macds_12_26_9", "macdh_12_26_9", "sma_20", "stdev", "bbu_20_2.0", "bbl_20_2.0", "atr", "stochk_14_3_3", "stochd_14_3_3", "adx_14", ] for col in expected_columns: self.assertIn(col, result.columns) # Check that NaN values are only in the beginning (for moving windows) self.assertTrue( pd.notna(result["sma_200"].iloc[199]) or isinstance(result["sma_200"].iloc[199], float) ) def test_identify_support_levels(self): """Test identification of support levels.""" support_levels = identify_support_levels(self.df_with_indicators) # We expect at least one support level self.assertGreater(len(support_levels), 0) # Support levels should be sorted self.assertEqual(support_levels, sorted(support_levels)) # Support levels should be below current price current_price = self.df_with_indicators["close"].iloc[-1] self.assertLessEqual(support_levels[0], current_price) def test_identify_resistance_levels(self): """Test identification of resistance levels.""" resistance_levels = identify_resistance_levels(self.df_with_indicators) # We expect at least one resistance level self.assertGreater(len(resistance_levels), 0) # Resistance levels should be sorted self.assertEqual(resistance_levels, sorted(resistance_levels)) # At least one resistance level should be above current price current_price = self.df_with_indicators["close"].iloc[-1] self.assertGreaterEqual(resistance_levels[-1], current_price) def test_analyze_trend(self): """Test trend analysis function.""" trend = analyze_trend(self.df_with_indicators) # Check that trend is an integer between 0 and 7 (trend strength score) self.assertIsInstance(trend, int) self.assertGreaterEqual(trend, 0) self.assertLessEqual(trend, 7) def test_analyze_rsi(self): """Test RSI analysis function.""" rsi_analysis = analyze_rsi(self.df_with_indicators) # Check that analysis contains expected keys expected_keys = ["current", "signal", "description"] for key in expected_keys: self.assertIn(key, rsi_analysis) # Check value ranges self.assertGreaterEqual(rsi_analysis["current"], 0) self.assertLessEqual(rsi_analysis["current"], 100) # Check signal values self.assertIn( rsi_analysis["signal"], ["bullish", "bearish", "overbought", "oversold"] ) def test_analyze_macd(self): """Test MACD analysis function.""" macd_analysis = analyze_macd(self.df_with_indicators) # Check that analysis contains expected keys expected_keys = [ "macd", "signal", "histogram", "indicator", "crossover", "description", ] for key in expected_keys: self.assertIn(key, macd_analysis) # Check signal values self.assertIn( macd_analysis["indicator"], ["bullish", "bearish", "improving", "weakening", "neutral"], ) self.assertIn( macd_analysis["crossover"], [ "bullish crossover detected", "bearish crossover detected", "no recent crossover", ], ) def test_generate_outlook(self): """Test outlook generation function.""" # First, get required analyses trend = analyze_trend(self.df_with_indicators) rsi_analysis = analyze_rsi(self.df_with_indicators) macd_analysis = analyze_macd(self.df_with_indicators) stoch_analysis = analyze_stochastic(self.df_with_indicators) # Generate outlook trend_direction = ( "bullish" if trend > 3 else "bearish" if trend < -3 else "neutral" ) outlook = generate_outlook( self.df_with_indicators, trend_direction, rsi_analysis, macd_analysis, stoch_analysis, ) # Check output self.assertIn( outlook, [ "strongly bullish", "moderately bullish", "strongly bearish", "moderately bearish", "neutral", ], ) def test_analyze_bollinger_bands(self): """Test Bollinger Bands analysis function.""" bb_analysis = analyze_bollinger_bands(self.df_with_indicators) # Check that analysis contains expected keys expected_keys = [ "upper_band", "middle_band", "lower_band", "position", "signal", "volatility", "description", ] for key in expected_keys: self.assertIn(key, bb_analysis) # Check value types self.assertIsInstance(bb_analysis["upper_band"], float) self.assertIsInstance(bb_analysis["middle_band"], float) self.assertIsInstance(bb_analysis["lower_band"], float) self.assertIsInstance(bb_analysis["position"], str) self.assertIsInstance(bb_analysis["signal"], str) self.assertIsInstance(bb_analysis["volatility"], str) self.assertIsInstance(bb_analysis["description"], str) # Check plausible signal values self.assertIn( bb_analysis["signal"], ["overbought", "oversold", "bullish", "bearish"] ) def test_analyze_volume(self): """Test volume analysis function.""" volume_analysis = analyze_volume(self.df_with_indicators) # Check that analysis contains expected keys expected_keys = ["current", "average", "ratio", "description", "signal"] for key in expected_keys: self.assertIn(key, volume_analysis) # Check value types self.assertIsInstance(volume_analysis["current"], int) self.assertIsInstance(volume_analysis["average"], int) self.assertIsInstance(volume_analysis["ratio"], float) self.assertIsInstance(volume_analysis["description"], str) self.assertIsInstance(volume_analysis["signal"], str) # Check plausible signal values self.assertIn( volume_analysis["signal"], [ "bullish (high volume on up move)", "bearish (high volume on down move)", "weak conviction", "neutral", ], ) def test_identify_chart_patterns(self): """Test chart pattern identification function.""" patterns = identify_chart_patterns(self.df_with_indicators) # Should return a list self.assertIsInstance(patterns, list) # All elements should be strings for pattern in patterns: self.assertIsInstance(pattern, str) # All patterns should be from the known set known_patterns = [ "Double Bottom (W)", "Double Top (M)", "Bullish Flag/Pennant", "Bearish Flag/Pennant", ] for pattern in patterns: self.assertIn(pattern, known_patterns) 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