Files

1 line
40 KiB
JSON

{"repo": "arushsinghal/intelliquant-v2", "files": {"intellitrade/config/settings.py": {"dddcb159d8d4a8e112b77375cad819e6e542cbed": {"t": 1785746910.1431835, "n": 19193, "h": "3b2e7cb5030160eb", "c": "\"\"\"\nIntelliTrade Configuration Management System\n\nProvides centralized configuration with:\n- Environment-specific settings (dev/staging/prod)\n- Validation on startup\n- Type hints for all config values\n- Environment variable loading\n- Hot-reload for non-critical configs\n\nUsage:\n from intellitrade.config import get_config, load_config\n\n # Load config at startup\n config = load_config()\n\n # Access config values\n api_key = config.polygon.api_key\n max_position_size = config.risk.max_position_size\n\n # Check environment\n if config.is_production:\n # Production-specific behavior\n pass\n\"\"\"\n\nimport os\nfrom dataclasses import dataclass, field\nfrom typing import Any, Dict, List, Optional, Set, Tuple, Type\nfrom pathlib import Path\nfrom enum import Enum\nimport json\n\n\n# =============================================================================\n# Environment Detection\n# =============================================================================\n\nclass Environment(Enum):\n \"\"\"Application environment.\"\"\"\n DEVELOPMENT = \"development\"\n STAGING = \"staging\"\n PRODUCTION = \"production\"\n TESTING = \"testing\"\n\n\ndef detect_environment() -> Environment:\n \"\"\"Detect current environment from environment variables.\"\"\"\n env = os.getenv(\"INTELLITRADE_ENV\", os.getenv(\"ENVIRONMENT\", \"development\")).lower()\n\n # Check for common cloud platform indicators\n if os.getenv(\"RAILWAY_ENVIRONMENT\"):\n if \"prod\" in os.getenv(\"RAILWAY_ENVIRONMENT\", \"\").lower():\n return Environment.PRODUCTION\n return Environment.STAGING\n\n if os.getenv(\"RENDER\"):\n return Environment.PRODUCTION\n\n if os.getenv(\"REPLIT\"):\n return Environment.STAGING\n\n # Fall back to explicit setting\n env_map = {\n \"development\": Environment.DEVELOPMENT,\n \"dev\": Environment.DEVELOPMENT,\n \"staging\": Environment.STAGING,\n \"stage\": Environment.STAGING,\n \"production\": Environment.PRODUCTION,\n \"prod\": Environment.PRODUCTION,\n \"testing\": Environment.TESTING,\n \"test\": Environment.TESTING,\n }\n\n return env_map.get(env, Environment.DEVELOPMENT)\n\n\n# =============================================================================\n# Configuration Sections\n# =============================================================================\n\n@dataclass\nclass APIConfig:\n \"\"\"API provider configuration.\"\"\"\n # OpenAI\n openai_api_key: str = \"\"\n openai_model: str = \"gpt-4\"\n openai_temperature: float = 0.7\n openai_max_tokens: int = 4096\n\n # Polygon.io\n polygon_api_key: str = \"\"\n polygon_plan: str = \"free\" # free, starter, developer, advanced\n\n # Optional AI Providers\n deepseek_api_key: str = \"\"\n google_api_key: str = \"\"\n grok_api_key: str = \"\"\n openrouter_api_key: str = \"\"\n\n # Search\n brave_api_key: str = \"\"\n serper_api_key: str = \"\"\n\n def __post_init__(self):\n # Load from environment\n self.openai_api_key = os.getenv(\"OPENAI_API_KEY\", self.openai_api_key)\n self.polygon_api_key = os.getenv(\"POLYGON_API_KEY\", self.polygon_api_key)\n self.polygon_plan = os.getenv(\"POLYGON_PLAN\", self.polygon_plan)\n self.deepseek_api_key = os.getenv(\"DEEPSEEK_API_KEY\", self.deepseek_api_key)\n self.google_api_key = os.getenv(\"GOOGLE_API_KEY\", self.google_api_key)\n self.grok_api_key = os.getenv(\"GROK_API_KEY\", self.grok_api_key)\n self.openrouter_api_key = os.getenv(\"OPENROUTER_API_KEY\", self.openrouter_api_key)\n self.brave_api_key = os.getenv(\"BRAVE_API_KEY\", self.brave_api_key)\n self.serper_api_key = os.getenv(\"SERPER_API_KEY\", self.serper_api_key)\n\n def validate(self) -> List[str]:\n \"\"\"Validate API configuration.\"\"\"\n errors = []\n\n if not self.openai_api_key:\n errors.append(\"OPENAI_API_KEY is required\")\n elif not self.openai_api_key.startswith((\"sk-\", \"sk-proj-\")):\n errors.append(\"OPENAI_API_KEY appears invalid (should start with 'sk-')\")\n\n if not self.polygon_api_key:\n errors.append(\"POLYGON_API_KEY is required\")\n\n return errors\n\n\n@dataclass\nclass NotificationConfig:\n \"\"\"Notification configuration.\"\"\"\n # Pushover\n pushover_user: str = \"\"\n pushover_token: str = \"\"\n\n # Email (SendGrid)\n sendgrid_api_key: str = \"\"\n email_from: str = \"\"\n email_to: str = \"\"\n\n # Slack\n slack_webhook_url: str = \"\"\n\n # Discord\n discord_webhook_url: str = \"\"\n\n # Twilio (SMS)\n twilio_account_sid: str = \"\"\n twilio_auth_token: str = \"\"\n twilio_from_number: str = \"\"\n twilio_to_number: str = \"\"\n\n # Enable flags\n enable_pushover: bool = True\n enable_email: bool = True\n enable_slack: bool = True\n enable_discord: bool = True\n enable_sms: bool = False\n\n def __post_init__(self):\n self.pushover_user = os.getenv(\"PUSHOVER_USER\", self.pushover_user)\n self.pushover_token = os.getenv(\"PUSHOVER_TOKEN\", self.pushover_token)\n self.sendgrid_api_key = os.getenv(\"SENDGRID_API_KEY\", self.sendgrid_api_key)\n self.slack_webhook_url = os.getenv(\"SLACK_WEBHOOK_URL\", self.slack_webhook_url)\n self.discord_webhook_url = os.getenv(\"DISCORD_WEBHOOK_URL\", self.discord_webhook_url)\n self.twilio_account_sid = os.getenv(\"TWILIO_ACCOUNT_SID\", self.twilio_account_sid)\n self.twilio_auth_token = os.getenv(\"TWILIO_AUTH_TOKEN\", self.twilio_auth_token)\n\n @property\n def pushover_enabled(self) -> bool:\n return self.enable_pushover and self.pushover_user and self.pushover_token\n\n @property\n def email_enabled(self) -> bool:\n return self.enable_email and self.sendgrid_api_key\n\n @property\n def slack_enabled(self) -> bool:\n return self.enable_slack and self.slack_webhook_url\n\n @property\n def discord_enabled(self) -> bool:\n return self.enable_discord and self.discord_webhook_url\n\n @property\n def sms_enabled(self) -> bool:\n return self.enable_sms and self.twilio_account_sid and self.twilio_auth_token\n\n\n@dataclass\nclass SchedulerConfig:\n \"\"\"Scheduler configuration.\"\"\"\n run_every_n_minutes: int = 60\n run_even_when_market_closed: bool = False\n use_many_models: bool = False\n\n # Trading hours (US Eastern)\n market_open_hour: int = 9\n market_open_minute: int = 30\n market_close_hour: int = 16\n market_close_minute: int = 0\n\n # Retry settings\n max_retries: int = 3\n retry_delay_seconds: int = 60\n\n def __post_init__(self):\n self.run_every_n_minutes = int(os.getenv(\n \"RUN_EVERY_N_MINUTES\",\n str(self.run_every_n_minutes)\n ))\n self.run_even_when_market_closed = os.getenv(\n \"RUN_EVEN_WHEN_MARKET_IS_CLOSED\",\n str(self.run_even_when_market_closed)\n ).lower() == \"true\"\n self.use_many_models = os.getenv(\n \"USE_MANY_MODELS\",\n str(self.use_many_models)\n ).lower() == \"true\"\n\n\n@dataclass\nclass RiskConfig:\n \"\"\"Risk management configuration.\"\"\"\n # Position limits\n max_position_size: float = 10000.0 # Max $ per position\n max_position_pct: float = 0.30 # Max 30% in one stock\n max_portfolio_heat: float = 0.80 # Max 80% portfolio at risk\n\n # Daily limits\n max_daily_loss: float = 1000.0 # Max $ loss per day\n max_daily_trades: int = 50 # Max trades per day\n\n # Stop loss / Take profit\n default_stop_loss_pct: float = 0.02 # 2% stop loss\n default_take_profit_pct: float = 0.05 # 5% take profit\n\n # Leverage\n max_leverage: float = 2.0\n\n # Sector concentration\n max_sector_concentration: float = 0.40 # Max 40% in one sector\n\n def __post_init__(self):\n # Load from environment if set\n if os.getenv(\"MAX_POSITION_SIZE\"):\n self.max_position_size = float(os.getenv(\"MAX_POSITION_SIZE\"))\n if os.getenv(\"MAX_DAILY_LOSS\"):\n self.max_daily_loss = float(os.getenv(\"MAX_DAILY_LOSS\"))\n\n\n@dataclass\nclass DatabaseConfig:\n \"\"\"Database configuration.\"\"\"\n database_url: str = \"\"\n sqlite_path: str = \"data/intellitrade.db\"\n\n # Pool settings\n pool_min_size: int = 2\n pool_max_size: int = 10\n pool_timeout: float = 30.0\n\n # Query settings\n query_timeout: float = 30.0\n log_queries: bool = False\n log_slow_queries: bool = True\n slow_query_threshold_ms: float = 100.0\n\n # Backup settings\n backup_enabled: bool = True\n backup_interval_hours: int = 6\n backup_retention_days: int = 30\n backup_path: str = \"backups\"\n\n def __post_init__(self):\n self.database_url = os.getenv(\"DATABASE_URL\", self.database_url)\n\n @property\n def is_postgresql(self) -> bool:\n return self.database_url.startswith((\"postgresql://\", \"postgres://\"))\n\n\n@dataclass\nclass LoggingConfig:\n \"\"\"Logging configuration.\"\"\"\n log_level: str = \"INFO\"\n log_dir: str = \"logs\"\n log_format: str = \"colored\" # \"colored\" or \"json\"\n log_max_bytes: int = 10 * 1024 * 1024 # 10MB\n log_backup_count: int = 5\n\n # LangSmith tracing\n langsmith_tracing: bool = False\n langsmith_endpoint: str = \"https://api.smith.langchain.com\"\n langsmith_api_key: str = \"\"\n langsmith_project: str = \"intellitrade\"\n\n def __post_init__(self):\n self.log_level = os.getenv(\"INTELLITRADE_LOG_LEVEL\", self.log_level)\n self.log_dir = os.getenv(\"INTELLITRADE_LOG_DIR\", self.log_dir)\n self.langsmith_tracing = os.getenv(\"LANGSMITH_TRACING\", \"false\").lower() == \"true\"\n self.langsmith_api_key = os.getenv(\"LANGSMITH_API_KEY\", self.langsmith_api_key)\n self.langsmith_project = os.getenv(\"LANGSMITH_PROJECT\", self.langsmith_project)\n\n\n@dataclass\nclass ServerConfig:\n \"\"\"Server configuration.\"\"\"\n host: str = \"0.0.0.0\"\n port: int = 7860\n debug: bool = False\n workers: int = 1\n\n # Gradio settings\n share: bool = False\n auth_username: str = \"\"\n auth_password: str = \"\"\n\n # Security\n enable_https: bool = False\n ssl_cert_path: str = \"\"\n ssl_key_path: str = \"\"\n\n # CORS\n allowed_origins: List[str] = field(default_factory=lambda: [\"*\"])\n\n def __post_init__(self):\n self.port = int(os.getenv(\"PORT\", str(self.port)))\n self.debug = os.getenv(\"DEBUG\", \"false\").lower() == \"true\"\n\n\n@dataclass\nclass TradingConfig:\n \"\"\"Trading-specific configuration.\"\"\"\n # Paper trading vs live\n paper_trading: bool = True\n\n # Symbols\n default_symbols: List[str] = field(default_factory=lambda: [\n \"AAPL\", \"GOOGL\", \"MSFT\", \"AMZN\", \"META\", \"NVDA\", \"TSLA\"\n ])\n\n # Strategy settings\n default_strategy: str = \"multi_agent\"\n enabled_strategies: List[str] = field(default_factory=lambda: [\"multi_agent\"])\n\n # Order settings\n default_order_type: str = \"market\"\n enable_limit_orders: bool = True\n enable_stop_orders: bool = True\n\n def __post_init__(self):\n self.paper_trading = os.getenv(\"PAPER_TRADING\", \"true\").lower() == \"true\"\n\n\n# =============================================================================\n# Main Config Class\n# =============================================================================\n\n@dataclass\nclass Config:\n \"\"\"\n Main configuration class.\n\n Contains all configuration sections for IntelliTrade.\n\n Usage:\n config = Config()\n config.load()\n\n # Access nested config\n api_key = config.api.openai_api_key\n max_loss = config.risk.max_daily_loss\n \"\"\"\n\n # Environment\n environment: Environment = field(default_factory=detect_environment)\n\n # Configuration sections\n api: APIConfig = field(default_factory=APIConfig)\n notifications: NotificationConfig = field(default_factory=NotificationConfig)\n scheduler: SchedulerConfig = field(default_factory=SchedulerConfig)\n risk: RiskConfig = field(default_factory=RiskConfig)\n database: DatabaseConfig = field(default_factory=DatabaseConfig)\n logging: LoggingConfig = field(default_factory=LoggingConfig)\n server: ServerConfig = field(default_factory=ServerConfig)\n trading: TradingConfig = field(default_factory=TradingConfig)\n\n # Meta\n version: str = \"1.0.0\"\n app_name: str = \"IntelliTrade\"\n\n def __post_init__(self):\n # Reload all sections\n self.api = APIConfig()\n self.notifications = NotificationConfig()\n self.scheduler = SchedulerConfig()\n self.risk = RiskConfig()\n self.database = DatabaseConfig()\n self.logging = LoggingConfig()\n self.server = ServerConfig()\n self.trading = TradingConfig()\n\n @property\n def is_production(self) -> bool:\n return self.environment == Environment.PRODUCTION\n\n @property\n def is_development(self) -> bool:\n return self.environment == Environment.DEVELOPMENT\n\n @property\n def is_staging(self) -> bool:\n return self.environment == Environment.STAGING\n\n @property\n def is_testing(self) -> bool:\n return self.environment == Environment.TESTING\n\n def validate(self) -> Tuple[bool, List[str]]:\n \"\"\"\n Validate all configuration.\n\n Returns:\n Tuple of (is_valid, list_of_errors)\n \"\"\"\n errors = []\n\n # Validate API config\n errors.extend(self.api.validate())\n\n # Validate risk limits\n if self.risk.max_daily_loss <= 0:\n errors.append(\"MAX_DAILY_LOSS must be positive\")\n\n if self.risk.max_position_pct > 1.0:\n errors.append(\"MAX_POSITION_PCT must be <= 1.0\")\n\n # Validate server config\n if self.server.port < 1 or self.server.port > 65535:\n errors.append(f\"Invalid port: {self.server.port}\")\n\n return len(errors) == 0, errors\n\n def to_dict(self, include_secrets: bool = False) -> Dict[str, Any]:\n \"\"\"Convert config to dictionary.\"\"\"\n result = {\n \"environment\": self.environment.value,\n \"version\": self.version,\n \"app_name\": self.app_name,\n \"scheduler\": {\n \"run_every_n_minutes\": self.scheduler.run_every_n_minutes,\n \"run_even_when_market_closed\": self.scheduler.run_even_when_market_closed,\n \"use_many_models\": self.scheduler.use_many_models,\n },\n \"risk\": {\n \"max_position_size\": self.risk.max_position_size,\n \"max_daily_loss\": self.risk.max_daily_loss,\n \"max_position_pct\": self.risk.max_position_pct,\n \"default_stop_loss_pct\": self.risk.default_stop_loss_pct,\n },\n \"server\": {\n \"port\": self.server.port,\n \"debug\": self.server.debug,\n },\n \"trading\": {\n \"paper_trading\": self.trading.paper_trading,\n \"default_symbols\": self.trading.default_symbols,\n },\n }\n\n if include_secrets:\n result[\"api\"] = {\n \"openai_api_key\": self.api.openai_api_key[:10] + \"...\",\n \"polygon_api_key\": self.api.polygon_api_key[:10] + \"...\",\n \"polygon_plan\": self.api.polygon_plan,\n }\n\n return result\n\n def save_to_file(self, path: str) -> None:\n \"\"\"Save configuration to JSON file.\"\"\"\n config_dict = self.to_dict(include_secrets=False)\n Path(path).parent.mkdir(parents=True, exist_ok=True)\n with open(path, \"w\") as f:\n json.dump(config_dict, f, indent=2)\n\n @classmethod\n def load_from_file(cls, path: str) -> \"Config\":\n \"\"\"Load configuration from JSON file.\"\"\"\n with open(path, \"r\") as f:\n data = json.load(f)\n\n config = cls()\n # Apply file values (environment vars take precedence)\n # ... implementation\n return config\n\n\n# =============================================================================\n# Environment-Specific Configs\n# =============================================================================\n\nclass DevConfig(Config):\n \"\"\"Development configuration with relaxed settings.\"\"\"\n\n def __post_init__(self):\n super().__post_init__()\n self.environment = Environment.DEVELOPMENT\n self.server.debug = True\n self.logging.log_level = \"DEBUG\"\n self.database.log_queries = True\n self.trading.paper_trading = True\n\n\nclass StagingConfig(Config):\n \"\"\"Staging configuration for pre-production testing.\"\"\"\n\n def __post_init__(self):\n super().__post_init__()\n self.environment = Environment.STAGING\n self.server.debug = False\n self.logging.log_level = \"INFO\"\n self.trading.paper_trading = True\n\n\nclass ProdConfig(Config):\n \"\"\"Production configuration with strict settings.\"\"\"\n\n def __post_init__(self):\n super().__post_init__()\n self.environment = Environment.PRODUCTION\n self.server.debug = False\n self.logging.log_level = \"INFO\"\n self.logging.log_format = \"json\"\n self.database.log_queries = False\n self.database.log_slow_queries = True\n\n\n# =============================================================================\n# Global Config Instance\n# =============================================================================\n\n_config: Optional[Config] = None\n\n\ndef load_config(\n environment: Optional[Environment] = None,\n validate: bool = True,\n) -> Config:\n \"\"\"\n Load and validate configuration.\n\n Should be called once at application startup.\n\n Args:\n environment: Override environment detection\n validate: Whether to validate config on load\n\n Returns:\n Config instance\n\n Raises:\n ValueError: If validation fails and validate=True\n \"\"\"\n global _config\n\n # Detect or use provided environment\n env = environment or detect_environment()\n\n # Select config class based on environment\n if env == Environment.DEVELOPMENT:\n _config = DevConfig()\n elif env == Environment.STAGING:\n _config = StagingConfig()\n elif env == Environment.PRODUCTION:\n _config = ProdConfig()\n else:\n _config = Config()\n\n # Validate if requested\n if validate:\n is_valid, errors = _config.validate()\n if not is_valid:\n # Log errors but don't fail for development\n import logging\n logger = logging.getLogger(\"intellitrade.config\")\n for error in errors:\n if env == Environment.PRODUCTION:\n logger.error(f\"Config error: {error}\")\n else:\n logger.warning(f\"Config warning: {error}\")\n\n # Fail in production if critical errors\n if env == Environment.PRODUCTION and errors:\n raise ValueError(f\"Configuration errors: {', '.join(errors)}\")\n\n return _config\n\n\ndef get_config() -> Config:\n \"\"\"\n Get the current configuration.\n\n Loads config with defaults if not already loaded.\n\n Returns:\n Config instance\n \"\"\"\n global _config\n\n if _config is None:\n _config = load_config(validate=False)\n\n return _config\n\n\ndef reload_config() -> Config:\n \"\"\"Reload configuration from environment.\"\"\"\n global _config\n _config = None\n return load_config()\n"}, "91c298708acc7700cbeb298fc8c830653d00398c": {"t": 1785768828.0761695, "n": 19193, "h": "3b2e7cb5030160eb", "c": "\"\"\"\nIntelliTrade Configuration Management System\n\nProvides centralized configuration with:\n- Environment-specific settings (dev/staging/prod)\n- Validation on startup\n- Type hints for all config values\n- Environment variable loading\n- Hot-reload for non-critical configs\n\nUsage:\n from intellitrade.config import get_config, load_config\n\n # Load config at startup\n config = load_config()\n\n # Access config values\n api_key = config.polygon.api_key\n max_position_size = config.risk.max_position_size\n\n # Check environment\n if config.is_production:\n # Production-specific behavior\n pass\n\"\"\"\n\nimport os\nfrom dataclasses import dataclass, field\nfrom typing import Any, Dict, List, Optional, Set, Tuple, Type\nfrom pathlib import Path\nfrom enum import Enum\nimport json\n\n\n# =============================================================================\n# Environment Detection\n# =============================================================================\n\nclass Environment(Enum):\n \"\"\"Application environment.\"\"\"\n DEVELOPMENT = \"development\"\n STAGING = \"staging\"\n PRODUCTION = \"production\"\n TESTING = \"testing\"\n\n\ndef detect_environment() -> Environment:\n \"\"\"Detect current environment from environment variables.\"\"\"\n env = os.getenv(\"INTELLITRADE_ENV\", os.getenv(\"ENVIRONMENT\", \"development\")).lower()\n\n # Check for common cloud platform indicators\n if os.getenv(\"RAILWAY_ENVIRONMENT\"):\n if \"prod\" in os.getenv(\"RAILWAY_ENVIRONMENT\", \"\").lower():\n return Environment.PRODUCTION\n return Environment.STAGING\n\n if os.getenv(\"RENDER\"):\n return Environment.PRODUCTION\n\n if os.getenv(\"REPLIT\"):\n return Environment.STAGING\n\n # Fall back to explicit setting\n env_map = {\n \"development\": Environment.DEVELOPMENT,\n \"dev\": Environment.DEVELOPMENT,\n \"staging\": Environment.STAGING,\n \"stage\": Environment.STAGING,\n \"production\": Environment.PRODUCTION,\n \"prod\": Environment.PRODUCTION,\n \"testing\": Environment.TESTING,\n \"test\": Environment.TESTING,\n }\n\n return env_map.get(env, Environment.DEVELOPMENT)\n\n\n# =============================================================================\n# Configuration Sections\n# =============================================================================\n\n@dataclass\nclass APIConfig:\n \"\"\"API provider configuration.\"\"\"\n # OpenAI\n openai_api_key: str = \"\"\n openai_model: str = \"gpt-4\"\n openai_temperature: float = 0.7\n openai_max_tokens: int = 4096\n\n # Polygon.io\n polygon_api_key: str = \"\"\n polygon_plan: str = \"free\" # free, starter, developer, advanced\n\n # Optional AI Providers\n deepseek_api_key: str = \"\"\n google_api_key: str = \"\"\n grok_api_key: str = \"\"\n openrouter_api_key: str = \"\"\n\n # Search\n brave_api_key: str = \"\"\n serper_api_key: str = \"\"\n\n def __post_init__(self):\n # Load from environment\n self.openai_api_key = os.getenv(\"OPENAI_API_KEY\", self.openai_api_key)\n self.polygon_api_key = os.getenv(\"POLYGON_API_KEY\", self.polygon_api_key)\n self.polygon_plan = os.getenv(\"POLYGON_PLAN\", self.polygon_plan)\n self.deepseek_api_key = os.getenv(\"DEEPSEEK_API_KEY\", self.deepseek_api_key)\n self.google_api_key = os.getenv(\"GOOGLE_API_KEY\", self.google_api_key)\n self.grok_api_key = os.getenv(\"GROK_API_KEY\", self.grok_api_key)\n self.openrouter_api_key = os.getenv(\"OPENROUTER_API_KEY\", self.openrouter_api_key)\n self.brave_api_key = os.getenv(\"BRAVE_API_KEY\", self.brave_api_key)\n self.serper_api_key = os.getenv(\"SERPER_API_KEY\", self.serper_api_key)\n\n def validate(self) -> List[str]:\n \"\"\"Validate API configuration.\"\"\"\n errors = []\n\n if not self.openai_api_key:\n errors.append(\"OPENAI_API_KEY is required\")\n elif not self.openai_api_key.startswith((\"sk-\", \"sk-proj-\")):\n errors.append(\"OPENAI_API_KEY appears invalid (should start with 'sk-')\")\n\n if not self.polygon_api_key:\n errors.append(\"POLYGON_API_KEY is required\")\n\n return errors\n\n\n@dataclass\nclass NotificationConfig:\n \"\"\"Notification configuration.\"\"\"\n # Pushover\n pushover_user: str = \"\"\n pushover_token: str = \"\"\n\n # Email (SendGrid)\n sendgrid_api_key: str = \"\"\n email_from: str = \"\"\n email_to: str = \"\"\n\n # Slack\n slack_webhook_url: str = \"\"\n\n # Discord\n discord_webhook_url: str = \"\"\n\n # Twilio (SMS)\n twilio_account_sid: str = \"\"\n twilio_auth_token: str = \"\"\n twilio_from_number: str = \"\"\n twilio_to_number: str = \"\"\n\n # Enable flags\n enable_pushover: bool = True\n enable_email: bool = True\n enable_slack: bool = True\n enable_discord: bool = True\n enable_sms: bool = False\n\n def __post_init__(self):\n self.pushover_user = os.getenv(\"PUSHOVER_USER\", self.pushover_user)\n self.pushover_token = os.getenv(\"PUSHOVER_TOKEN\", self.pushover_token)\n self.sendgrid_api_key = os.getenv(\"SENDGRID_API_KEY\", self.sendgrid_api_key)\n self.slack_webhook_url = os.getenv(\"SLACK_WEBHOOK_URL\", self.slack_webhook_url)\n self.discord_webhook_url = os.getenv(\"DISCORD_WEBHOOK_URL\", self.discord_webhook_url)\n self.twilio_account_sid = os.getenv(\"TWILIO_ACCOUNT_SID\", self.twilio_account_sid)\n self.twilio_auth_token = os.getenv(\"TWILIO_AUTH_TOKEN\", self.twilio_auth_token)\n\n @property\n def pushover_enabled(self) -> bool:\n return self.enable_pushover and self.pushover_user and self.pushover_token\n\n @property\n def email_enabled(self) -> bool:\n return self.enable_email and self.sendgrid_api_key\n\n @property\n def slack_enabled(self) -> bool:\n return self.enable_slack and self.slack_webhook_url\n\n @property\n def discord_enabled(self) -> bool:\n return self.enable_discord and self.discord_webhook_url\n\n @property\n def sms_enabled(self) -> bool:\n return self.enable_sms and self.twilio_account_sid and self.twilio_auth_token\n\n\n@dataclass\nclass SchedulerConfig:\n \"\"\"Scheduler configuration.\"\"\"\n run_every_n_minutes: int = 60\n run_even_when_market_closed: bool = False\n use_many_models: bool = False\n\n # Trading hours (US Eastern)\n market_open_hour: int = 9\n market_open_minute: int = 30\n market_close_hour: int = 16\n market_close_minute: int = 0\n\n # Retry settings\n max_retries: int = 3\n retry_delay_seconds: int = 60\n\n def __post_init__(self):\n self.run_every_n_minutes = int(os.getenv(\n \"RUN_EVERY_N_MINUTES\",\n str(self.run_every_n_minutes)\n ))\n self.run_even_when_market_closed = os.getenv(\n \"RUN_EVEN_WHEN_MARKET_IS_CLOSED\",\n str(self.run_even_when_market_closed)\n ).lower() == \"true\"\n self.use_many_models = os.getenv(\n \"USE_MANY_MODELS\",\n str(self.use_many_models)\n ).lower() == \"true\"\n\n\n@dataclass\nclass RiskConfig:\n \"\"\"Risk management configuration.\"\"\"\n # Position limits\n max_position_size: float = 10000.0 # Max $ per position\n max_position_pct: float = 0.30 # Max 30% in one stock\n max_portfolio_heat: float = 0.80 # Max 80% portfolio at risk\n\n # Daily limits\n max_daily_loss: float = 1000.0 # Max $ loss per day\n max_daily_trades: int = 50 # Max trades per day\n\n # Stop loss / Take profit\n default_stop_loss_pct: float = 0.02 # 2% stop loss\n default_take_profit_pct: float = 0.05 # 5% take profit\n\n # Leverage\n max_leverage: float = 2.0\n\n # Sector concentration\n max_sector_concentration: float = 0.40 # Max 40% in one sector\n\n def __post_init__(self):\n # Load from environment if set\n if os.getenv(\"MAX_POSITION_SIZE\"):\n self.max_position_size = float(os.getenv(\"MAX_POSITION_SIZE\"))\n if os.getenv(\"MAX_DAILY_LOSS\"):\n self.max_daily_loss = float(os.getenv(\"MAX_DAILY_LOSS\"))\n\n\n@dataclass\nclass DatabaseConfig:\n \"\"\"Database configuration.\"\"\"\n database_url: str = \"\"\n sqlite_path: str = \"data/intellitrade.db\"\n\n # Pool settings\n pool_min_size: int = 2\n pool_max_size: int = 10\n pool_timeout: float = 30.0\n\n # Query settings\n query_timeout: float = 30.0\n log_queries: bool = False\n log_slow_queries: bool = True\n slow_query_threshold_ms: float = 100.0\n\n # Backup settings\n backup_enabled: bool = True\n backup_interval_hours: int = 6\n backup_retention_days: int = 30\n backup_path: str = \"backups\"\n\n def __post_init__(self):\n self.database_url = os.getenv(\"DATABASE_URL\", self.database_url)\n\n @property\n def is_postgresql(self) -> bool:\n return self.database_url.startswith((\"postgresql://\", \"postgres://\"))\n\n\n@dataclass\nclass LoggingConfig:\n \"\"\"Logging configuration.\"\"\"\n log_level: str = \"INFO\"\n log_dir: str = \"logs\"\n log_format: str = \"colored\" # \"colored\" or \"json\"\n log_max_bytes: int = 10 * 1024 * 1024 # 10MB\n log_backup_count: int = 5\n\n # LangSmith tracing\n langsmith_tracing: bool = False\n langsmith_endpoint: str = \"https://api.smith.langchain.com\"\n langsmith_api_key: str = \"\"\n langsmith_project: str = \"intellitrade\"\n\n def __post_init__(self):\n self.log_level = os.getenv(\"INTELLITRADE_LOG_LEVEL\", self.log_level)\n self.log_dir = os.getenv(\"INTELLITRADE_LOG_DIR\", self.log_dir)\n self.langsmith_tracing = os.getenv(\"LANGSMITH_TRACING\", \"false\").lower() == \"true\"\n self.langsmith_api_key = os.getenv(\"LANGSMITH_API_KEY\", self.langsmith_api_key)\n self.langsmith_project = os.getenv(\"LANGSMITH_PROJECT\", self.langsmith_project)\n\n\n@dataclass\nclass ServerConfig:\n \"\"\"Server configuration.\"\"\"\n host: str = \"0.0.0.0\"\n port: int = 7860\n debug: bool = False\n workers: int = 1\n\n # Gradio settings\n share: bool = False\n auth_username: str = \"\"\n auth_password: str = \"\"\n\n # Security\n enable_https: bool = False\n ssl_cert_path: str = \"\"\n ssl_key_path: str = \"\"\n\n # CORS\n allowed_origins: List[str] = field(default_factory=lambda: [\"*\"])\n\n def __post_init__(self):\n self.port = int(os.getenv(\"PORT\", str(self.port)))\n self.debug = os.getenv(\"DEBUG\", \"false\").lower() == \"true\"\n\n\n@dataclass\nclass TradingConfig:\n \"\"\"Trading-specific configuration.\"\"\"\n # Paper trading vs live\n paper_trading: bool = True\n\n # Symbols\n default_symbols: List[str] = field(default_factory=lambda: [\n \"AAPL\", \"GOOGL\", \"MSFT\", \"AMZN\", \"META\", \"NVDA\", \"TSLA\"\n ])\n\n # Strategy settings\n default_strategy: str = \"multi_agent\"\n enabled_strategies: List[str] = field(default_factory=lambda: [\"multi_agent\"])\n\n # Order settings\n default_order_type: str = \"market\"\n enable_limit_orders: bool = True\n enable_stop_orders: bool = True\n\n def __post_init__(self):\n self.paper_trading = os.getenv(\"PAPER_TRADING\", \"true\").lower() == \"true\"\n\n\n# =============================================================================\n# Main Config Class\n# =============================================================================\n\n@dataclass\nclass Config:\n \"\"\"\n Main configuration class.\n\n Contains all configuration sections for IntelliTrade.\n\n Usage:\n config = Config()\n config.load()\n\n # Access nested config\n api_key = config.api.openai_api_key\n max_loss = config.risk.max_daily_loss\n \"\"\"\n\n # Environment\n environment: Environment = field(default_factory=detect_environment)\n\n # Configuration sections\n api: APIConfig = field(default_factory=APIConfig)\n notifications: NotificationConfig = field(default_factory=NotificationConfig)\n scheduler: SchedulerConfig = field(default_factory=SchedulerConfig)\n risk: RiskConfig = field(default_factory=RiskConfig)\n database: DatabaseConfig = field(default_factory=DatabaseConfig)\n logging: LoggingConfig = field(default_factory=LoggingConfig)\n server: ServerConfig = field(default_factory=ServerConfig)\n trading: TradingConfig = field(default_factory=TradingConfig)\n\n # Meta\n version: str = \"1.0.0\"\n app_name: str = \"IntelliTrade\"\n\n def __post_init__(self):\n # Reload all sections\n self.api = APIConfig()\n self.notifications = NotificationConfig()\n self.scheduler = SchedulerConfig()\n self.risk = RiskConfig()\n self.database = DatabaseConfig()\n self.logging = LoggingConfig()\n self.server = ServerConfig()\n self.trading = TradingConfig()\n\n @property\n def is_production(self) -> bool:\n return self.environment == Environment.PRODUCTION\n\n @property\n def is_development(self) -> bool:\n return self.environment == Environment.DEVELOPMENT\n\n @property\n def is_staging(self) -> bool:\n return self.environment == Environment.STAGING\n\n @property\n def is_testing(self) -> bool:\n return self.environment == Environment.TESTING\n\n def validate(self) -> Tuple[bool, List[str]]:\n \"\"\"\n Validate all configuration.\n\n Returns:\n Tuple of (is_valid, list_of_errors)\n \"\"\"\n errors = []\n\n # Validate API config\n errors.extend(self.api.validate())\n\n # Validate risk limits\n if self.risk.max_daily_loss <= 0:\n errors.append(\"MAX_DAILY_LOSS must be positive\")\n\n if self.risk.max_position_pct > 1.0:\n errors.append(\"MAX_POSITION_PCT must be <= 1.0\")\n\n # Validate server config\n if self.server.port < 1 or self.server.port > 65535:\n errors.append(f\"Invalid port: {self.server.port}\")\n\n return len(errors) == 0, errors\n\n def to_dict(self, include_secrets: bool = False) -> Dict[str, Any]:\n \"\"\"Convert config to dictionary.\"\"\"\n result = {\n \"environment\": self.environment.value,\n \"version\": self.version,\n \"app_name\": self.app_name,\n \"scheduler\": {\n \"run_every_n_minutes\": self.scheduler.run_every_n_minutes,\n \"run_even_when_market_closed\": self.scheduler.run_even_when_market_closed,\n \"use_many_models\": self.scheduler.use_many_models,\n },\n \"risk\": {\n \"max_position_size\": self.risk.max_position_size,\n \"max_daily_loss\": self.risk.max_daily_loss,\n \"max_position_pct\": self.risk.max_position_pct,\n \"default_stop_loss_pct\": self.risk.default_stop_loss_pct,\n },\n \"server\": {\n \"port\": self.server.port,\n \"debug\": self.server.debug,\n },\n \"trading\": {\n \"paper_trading\": self.trading.paper_trading,\n \"default_symbols\": self.trading.default_symbols,\n },\n }\n\n if include_secrets:\n result[\"api\"] = {\n \"openai_api_key\": self.api.openai_api_key[:10] + \"...\",\n \"polygon_api_key\": self.api.polygon_api_key[:10] + \"...\",\n \"polygon_plan\": self.api.polygon_plan,\n }\n\n return result\n\n def save_to_file(self, path: str) -> None:\n \"\"\"Save configuration to JSON file.\"\"\"\n config_dict = self.to_dict(include_secrets=False)\n Path(path).parent.mkdir(parents=True, exist_ok=True)\n with open(path, \"w\") as f:\n json.dump(config_dict, f, indent=2)\n\n @classmethod\n def load_from_file(cls, path: str) -> \"Config\":\n \"\"\"Load configuration from JSON file.\"\"\"\n with open(path, \"r\") as f:\n data = json.load(f)\n\n config = cls()\n # Apply file values (environment vars take precedence)\n # ... implementation\n return config\n\n\n# =============================================================================\n# Environment-Specific Configs\n# =============================================================================\n\nclass DevConfig(Config):\n \"\"\"Development configuration with relaxed settings.\"\"\"\n\n def __post_init__(self):\n super().__post_init__()\n self.environment = Environment.DEVELOPMENT\n self.server.debug = True\n self.logging.log_level = \"DEBUG\"\n self.database.log_queries = True\n self.trading.paper_trading = True\n\n\nclass StagingConfig(Config):\n \"\"\"Staging configuration for pre-production testing.\"\"\"\n\n def __post_init__(self):\n super().__post_init__()\n self.environment = Environment.STAGING\n self.server.debug = False\n self.logging.log_level = \"INFO\"\n self.trading.paper_trading = True\n\n\nclass ProdConfig(Config):\n \"\"\"Production configuration with strict settings.\"\"\"\n\n def __post_init__(self):\n super().__post_init__()\n self.environment = Environment.PRODUCTION\n self.server.debug = False\n self.logging.log_level = \"INFO\"\n self.logging.log_format = \"json\"\n self.database.log_queries = False\n self.database.log_slow_queries = True\n\n\n# =============================================================================\n# Global Config Instance\n# =============================================================================\n\n_config: Optional[Config] = None\n\n\ndef load_config(\n environment: Optional[Environment] = None,\n validate: bool = True,\n) -> Config:\n \"\"\"\n Load and validate configuration.\n\n Should be called once at application startup.\n\n Args:\n environment: Override environment detection\n validate: Whether to validate config on load\n\n Returns:\n Config instance\n\n Raises:\n ValueError: If validation fails and validate=True\n \"\"\"\n global _config\n\n # Detect or use provided environment\n env = environment or detect_environment()\n\n # Select config class based on environment\n if env == Environment.DEVELOPMENT:\n _config = DevConfig()\n elif env == Environment.STAGING:\n _config = StagingConfig()\n elif env == Environment.PRODUCTION:\n _config = ProdConfig()\n else:\n _config = Config()\n\n # Validate if requested\n if validate:\n is_valid, errors = _config.validate()\n if not is_valid:\n # Log errors but don't fail for development\n import logging\n logger = logging.getLogger(\"intellitrade.config\")\n for error in errors:\n if env == Environment.PRODUCTION:\n logger.error(f\"Config error: {error}\")\n else:\n logger.warning(f\"Config warning: {error}\")\n\n # Fail in production if critical errors\n if env == Environment.PRODUCTION and errors:\n raise ValueError(f\"Configuration errors: {', '.join(errors)}\")\n\n return _config\n\n\ndef get_config() -> Config:\n \"\"\"\n Get the current configuration.\n\n Loads config with defaults if not already loaded.\n\n Returns:\n Config instance\n \"\"\"\n global _config\n\n if _config is None:\n _config = load_config(validate=False)\n\n return _config\n\n\ndef reload_config() -> Config:\n \"\"\"Reload configuration from environment.\"\"\"\n global _config\n _config = None\n return load_config()\n"}}}}