Skip to main content
Glama

MaverickMCP

by wshobson
MIT License
165
  • Apple
technical_indicators.py6.5 kB
""" Value objects for technical indicators. These are immutable objects representing technical analysis concepts in the domain layer. They contain no infrastructure dependencies. """ from dataclasses import dataclass from enum import Enum class Signal(Enum): """Trading signal types.""" STRONG_BUY = "strong_buy" BUY = "buy" NEUTRAL = "neutral" SELL = "sell" STRONG_SELL = "strong_sell" class TrendDirection(Enum): """Market trend directions.""" STRONG_UPTREND = "strong_uptrend" UPTREND = "uptrend" SIDEWAYS = "sideways" DOWNTREND = "downtrend" STRONG_DOWNTREND = "strong_downtrend" @dataclass(frozen=True) class RSIIndicator: """Relative Strength Index value object.""" value: float period: int = 14 def __post_init__(self): if not 0 <= self.value <= 100: raise ValueError("RSI must be between 0 and 100") if self.period <= 0: raise ValueError("Period must be positive") @property def is_overbought(self) -> bool: """Check if RSI indicates overbought condition.""" return self.value >= 70 @property def is_oversold(self) -> bool: """Check if RSI indicates oversold condition.""" return self.value <= 30 @property def signal(self) -> Signal: """Get trading signal based on RSI value.""" if self.value >= 80: return Signal.STRONG_SELL elif self.value >= 70: return Signal.SELL elif self.value <= 20: return Signal.STRONG_BUY elif self.value <= 30: return Signal.BUY else: return Signal.NEUTRAL @dataclass(frozen=True) class MACDIndicator: """MACD (Moving Average Convergence Divergence) value object.""" macd_line: float signal_line: float histogram: float fast_period: int = 12 slow_period: int = 26 signal_period: int = 9 @property def is_bullish_crossover(self) -> bool: """Check if MACD crossed above signal line.""" return self.macd_line > self.signal_line and self.histogram > 0 @property def is_bearish_crossover(self) -> bool: """Check if MACD crossed below signal line.""" return self.macd_line < self.signal_line and self.histogram < 0 @property def signal(self) -> Signal: """Get trading signal based on MACD.""" if self.is_bullish_crossover and self.histogram > 0.5: return Signal.STRONG_BUY elif self.is_bullish_crossover: return Signal.BUY elif self.is_bearish_crossover and self.histogram < -0.5: return Signal.STRONG_SELL elif self.is_bearish_crossover: return Signal.SELL else: return Signal.NEUTRAL @dataclass(frozen=True) class BollingerBands: """Bollinger Bands value object.""" upper_band: float middle_band: float lower_band: float current_price: float period: int = 20 std_dev: int = 2 @property def bandwidth(self) -> float: """Calculate bandwidth (volatility indicator).""" return (self.upper_band - self.lower_band) / self.middle_band @property def percent_b(self) -> float: """Calculate %B (position within bands).""" denominator = self.upper_band - self.lower_band if denominator == 0: return 0.5 # Return middle if bands are flat return (self.current_price - self.lower_band) / denominator @property def is_squeeze(self) -> bool: """Check if bands are in a squeeze (low volatility).""" return self.bandwidth < 0.1 @property def signal(self) -> Signal: """Get trading signal based on Bollinger Bands.""" if self.current_price > self.upper_band: return Signal.SELL elif self.current_price < self.lower_band: return Signal.BUY elif self.percent_b > 0.8: return Signal.SELL elif self.percent_b < 0.2: return Signal.BUY else: return Signal.NEUTRAL @dataclass(frozen=True) class StochasticOscillator: """Stochastic Oscillator value object.""" k_value: float d_value: float period: int = 14 def __post_init__(self): if not 0 <= self.k_value <= 100: raise ValueError("%K must be between 0 and 100") if not 0 <= self.d_value <= 100: raise ValueError("%D must be between 0 and 100") @property def is_overbought(self) -> bool: """Check if stochastic indicates overbought.""" return self.k_value >= 80 @property def is_oversold(self) -> bool: """Check if stochastic indicates oversold.""" return self.k_value <= 20 @property def signal(self) -> Signal: """Get trading signal based on stochastic.""" if self.k_value > self.d_value and self.k_value < 20: return Signal.BUY elif self.k_value < self.d_value and self.k_value > 80: return Signal.SELL elif self.is_oversold: return Signal.BUY elif self.is_overbought: return Signal.SELL else: return Signal.NEUTRAL @dataclass(frozen=True) class PriceLevel: """Support or resistance price level.""" price: float strength: int # 1-5, with 5 being strongest touches: int # Number of times price touched this level def __post_init__(self): if self.price <= 0: raise ValueError("Price must be positive") if not 1 <= self.strength <= 5: raise ValueError("Strength must be between 1 and 5") if self.touches < 0: raise ValueError("Touches must be non-negative") @dataclass(frozen=True) class VolumeProfile: """Volume analysis value object.""" current_volume: int average_volume: float volume_trend: TrendDirection unusual_activity: bool @property def relative_volume(self) -> float: """Calculate volume relative to average.""" return ( self.current_volume / self.average_volume if self.average_volume > 0 else 0 ) @property def is_high_volume(self) -> bool: """Check if volume is significantly above average.""" return self.relative_volume > 1.5 @property def is_low_volume(self) -> bool: """Check if volume is significantly below average.""" return self.relative_volume < 0.5

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