"""System configuration defaults and DB-backed accessors.""" from __future__ import annotations import os from app.db.runtime_config_db import ( get_bootstrap_admin_config, get_email_config, get_event_driven_config, get_llm_config, get_monitoring_config, get_notification_config, get_onchain_config, get_paper_trading_config, get_price_streamer_config, get_scheduler_config, get_sentiment_config, seed_system_defaults, ) def _env_bool(name, default=False): value = os.getenv(name) if value is None: return default return str(value).strip().lower() in ("1", "true", "yes", "on") def _env_int(name, default): try: return int(os.getenv(name, str(default)) or default) except Exception: return default def _env_float(name, default): try: return float(os.getenv(name, str(default)) or default) except Exception: return default def _env_str(name, default=""): return os.getenv(name, default).strip() def _env_list(name, default): raw = os.getenv(name, ",".join(default)) return [x.strip().lower() for x in raw.split(",") if x.strip()] or list(default) def default_llm_config(): return { "enabled": _env_bool("ALPHAX_LLM_ENABLED", False), "base_url": _env_str("ALPHAX_LLM_BASE_URL", "https://api.openai.com/v1"), "api_key_env": _env_str("ALPHAX_LLM_API_KEY_ENV", "ALPHAX_LLM_API_KEY"), "model": _env_str("ALPHAX_LLM_MODEL", "gpt-4o-mini"), "timeout": _env_int("ALPHAX_LLM_TIMEOUT", 20), "max_tokens": _env_int("ALPHAX_LLM_MAX_TOKENS", 900), "modules": { "recommendations": _env_bool("ALPHAX_LLM_RECOMMENDATIONS_ENABLED", True), "sentiment": _env_bool("ALPHAX_LLM_SENTIMENT_ENABLED", True), "review": _env_bool("ALPHAX_LLM_REVIEW_ENABLED", True), }, } def default_onchain_config(default_chains=("ethereum", "bsc", "base", "arbitrum", "solana")): return { "enabled": _env_bool("ALPHAX_ONCHAIN_ENABLED", False), "chains": _env_list("ALPHAX_ONCHAIN_CHAINS", default_chains), "timeout": _env_int("ALPHAX_ONCHAIN_TIMEOUT", 15), "candidate_enabled": _env_bool("ALPHAX_ONCHAIN_CANDIDATE_ENABLED", True), "candidate_min_score": _env_float("ALPHAX_ONCHAIN_CANDIDATE_MIN_SCORE", 70), "candidate_min_confidence": _env_int("ALPHAX_ONCHAIN_CANDIDATE_MIN_CONFIDENCE", 70), "candidate_cooldown_hours": _env_float("ALPHAX_ONCHAIN_CANDIDATE_COOLDOWN_HOURS", 6), "dexscreener_enabled": _env_bool("ALPHAX_ONCHAIN_DEXSCREENER_ENABLED", True), "dex_volume_spike_pct": _env_float("ALPHAX_ONCHAIN_DEX_VOLUME_SPIKE_PCT", 80), "dex_min_liquidity_usd": _env_float("ALPHAX_ONCHAIN_DEX_MIN_LIQUIDITY_USD", 100000), "dex_min_volume_24h_usd": _env_float("ALPHAX_ONCHAIN_DEX_MIN_VOLUME_24H_USD", 100000), "liquidity_add_pct": _env_float("ALPHAX_ONCHAIN_LIQUIDITY_ADD_PCT", 25), "liquidity_remove_pct": _env_float("ALPHAX_ONCHAIN_LIQUIDITY_REMOVE_PCT", -25), "whale_tx_usd": _env_float("ALPHAX_ONCHAIN_WHALE_TX_USD", 250000), "etherscan_api_key_env": "ALPHAX_ETHERSCAN_API_KEY", "helius_api_key_env": "ALPHAX_HELIUS_API_KEY", } def default_paper_trading_config(): return { "enabled": _env_bool("ALPHAX_PAPER_TRADING_ENABLED", True), "account_equity_usdt": _env_float("ALPHAX_PAPER_ACCOUNT_EQUITY_USDT", 20000), "trade_notional_usdt": _env_float("ALPHAX_PAPER_TRADE_NOTIONAL_USDT", 5000), "trade_leverage": _env_float("ALPHAX_PAPER_TRADE_LEVERAGE", 5), "fee_rate": _env_float("ALPHAX_PAPER_TRADE_FEE_RATE", 0.001), "slippage_pct": _env_float("ALPHAX_PAPER_TRADE_SLIPPAGE_PCT", 0.05), } def default_price_streamer_config(): return { "enabled": _env_bool("ALPHAX_PRICE_STREAMER_ENABLED", True), "provider": _env_str("ALPHAX_PRICE_STREAMER_PROVIDER", "binance_spot"), "stream_url": _env_str("ALPHAX_PRICE_STREAMER_URL", "wss://stream.binance.com:9443/stream"), "refresh_symbols_seconds": _env_float("ALPHAX_PRICE_STREAMER_REFRESH_SYMBOLS_SECONDS", 20), "idle_sleep_seconds": _env_float("ALPHAX_PRICE_STREAMER_IDLE_SLEEP_SECONDS", 5), "reconnect_delay_seconds": _env_float("ALPHAX_PRICE_STREAMER_RECONNECT_DELAY_SECONDS", 5), "max_stream_symbols": _env_int("ALPHAX_PRICE_STREAMER_MAX_SYMBOLS", 200), "include_actionable_recommendations": True, "include_open_paper_trades": True, "update_latest_price_cache": True, "sync_paper_trading": True, "log_every_events": _env_int("ALPHAX_PRICE_STREAMER_LOG_EVERY_EVENTS", 100), } def default_sentiment_config(): return { "enabled": _env_bool("ALPHAX_SENTIMENT_ENABLED", True), "provider": _env_str("ALPHAX_SENTIMENT_PROVIDER", "coingecko"), "max_bonus": _env_float("ALPHAX_SENTIMENT_MAX_BONUS", 2), "trending_top5_bonus": _env_float("ALPHAX_SENTIMENT_TOP5_BONUS", 2.0), "trending_top10_bonus": _env_float("ALPHAX_SENTIMENT_TOP10_BONUS", 1.0), "new_entry_bonus": _env_float("ALPHAX_SENTIMENT_NEW_ENTRY_BONUS", 1.0), "decay_hours": _env_float("ALPHAX_SENTIMENT_DECAY_HOURS", 6), "decay_factor": _env_float("ALPHAX_SENTIMENT_DECAY_FACTOR", 0.1), "min_decay": _env_float("ALPHAX_SENTIMENT_MIN_DECAY", 0.3), "collect_interval_min": _env_int("ALPHAX_SENTIMENT_COLLECT_INTERVAL_MIN", 30), "alert_conditions": { "holding_top3": True, "new_trending_top10": True, }, } def default_event_driven_config(): return { "enabled": _env_bool("ALPHAX_EVENT_DRIVEN_ENABLED", True), "poll_interval_min": _env_int("ALPHAX_EVENT_POLL_INTERVAL_MIN", 1), "decision_target_seconds": _env_int("ALPHAX_EVENT_DECISION_TARGET_SECONDS", 60), "news_time_window_hours": _env_float("ALPHAX_EVENT_NEWS_TIME_WINDOW_HOURS", 3), "max_event_age_hours": _env_float("ALPHAX_EVENT_MAX_EVENT_AGE_HOURS", 6), "dedup_window_hours": _env_float("ALPHAX_EVENT_DEDUP_WINDOW_HOURS", 24), "min_importance_level": _env_str("ALPHAX_EVENT_MIN_IMPORTANCE_LEVEL", "A"), "sources": {}, "importance": { "s_keywords": [ "will list", "will launch", "futures will launch", "perpetual contract", "launchpool", "megadrop", "hodler airdrops", "coinbase will add", "upbit listing", "bithumb listing", ], "a_keywords": [ "margin will add", "new trading pairs", "earn", "convert", "roadmap", "mainnet", "tokenomics", "airdrop", "burn", "buyback", "partnership", "integration", "upgrade", ], "negative_keywords": [ "delist", "suspend trading", "remove", "cease trading", "risk warning", ], }, "technical_check": { "min_tech_score_recommend": 6, "min_tech_score_observe": 3, "reject_if_24h_gain_gt": 30, "warn_if_24h_gain_gt": 18, "reject_if_funding_gt": 0.003, "allow_static_accumulation": True, "allow_volume_breakout": True, "allow_ignition": True, }, "push": { "recommend": True, "observe": True, "risk": True, "cooldown_hours": 6, }, "theme_expansion": { "enabled": True, "min_theme_importance": "A", "max_expanded_symbols": 12, "static_accumulation_bonus": { "enabled": True, "min_static_count": 8, "score_bonus": 3, "note": "重大生态事件命中后,强静K蓄力币提前升权", }, "themes": {}, }, } def default_monitoring_config(): return { "untouched_rate": { "description": "未触达率自动监控", "threshold_pct": 35, "check_window_days": 2, "auto_bump": { "enabled": True, "min_score_5_to_6": True, "min_score_max": 6, "require_human_if_exceeded": True, }, }, "param_audit": { "description": "参数变更审计", "validate_script": "scripts/validate_params.py", "hash_algorithm": "semantic_sha256", "critical_sections": ["confirm", "screener", "pa_engine", "signal_weights", "tracker", "sentiment"], }, } def default_notification_config(): return { "enabled": _env_bool("ALPHAX_NOTIFICATION_ENABLED", True), "feishu": { "enabled": _env_bool("ALPHAX_FEISHU_ENABLED", True), "webhook_env": _env_str("ALPHAX_FEISHU_WEBHOOK_ENV", "ALTCOIN_FEISHU_WEBHOOK"), "timeout": _env_int("ALPHAX_FEISHU_TIMEOUT", 10), }, } def default_email_config(): return { "enabled": _env_bool("ALPHAX_EMAIL_ENABLED", True), "smtp": { "host": _env_str("ALPHAX_SMTP_HOST", _env_str("ASTOCK_SMTP_HOST", "")), "port": _env_int("ALPHAX_SMTP_PORT", _env_int("ASTOCK_SMTP_PORT", 465)), "username_env": _env_str("ALPHAX_SMTP_USERNAME_ENV", "ASTOCK_SMTP_USERNAME"), "password_env": _env_str("ALPHAX_SMTP_PASSWORD_ENV", "ASTOCK_SMTP_PASSWORD"), "sender": _env_str("ALPHAX_SMTP_SENDER", ""), "sender_env": _env_str("ALPHAX_SMTP_SENDER_ENV", "ASTOCK_SMTP_SENDER"), "timeout": _env_int("ALPHAX_SMTP_TIMEOUT", 12), }, } def default_bootstrap_admin_config(): return { "enabled": _env_bool("ALPHAX_BOOTSTRAP_ADMIN", True), "email_env": _env_str("ALPHAX_DEFAULT_ADMIN_EMAIL_ENV", "ALPHAX_DEFAULT_ADMIN_EMAIL"), "password_env": _env_str("ALPHAX_DEFAULT_ADMIN_PASSWORD_ENV", "ALPHAX_DEFAULT_ADMIN_PASSWORD"), } def default_scheduler_config(): return { "dry_run": _env_bool("ALPHAX_SCHEDULER_DRY_RUN", True), "poll_seconds": _env_float("ALPHAX_SCHEDULER_POLL_SECONDS", 1.0), "config_reload_seconds": _env_float("ALPHAX_SCHEDULER_CONFIG_RELOAD_SECONDS", 5.0), "pending_warn_seconds": _env_float("ALPHAX_SCHEDULER_PENDING_WARN_SECONDS", 30.0), } def seed_runtime_system_defaults(): return seed_system_defaults({ "llm": (default_llm_config(), "LLM provider and module switches; API key remains in env"), "onchain": (default_onchain_config(), "On-chain provider and signal thresholds; API keys remain in env"), "paper_trading": (default_paper_trading_config(), "Paper trading account and execution model"), "price_streamer": (default_price_streamer_config(), "Realtime websocket price streamer settings"), "sentiment": (default_sentiment_config(), "Sentiment monitoring settings"), "event_driven": (default_event_driven_config(), "Event/news driven screening settings"), "monitoring": (default_monitoring_config(), "Monitoring and audit settings"), "notification": (default_notification_config(), "Notification channel switches and env pointers"), "email": (default_email_config(), "SMTP email settings; password remains in env"), "bootstrap_admin": (default_bootstrap_admin_config(), "Default admin bootstrap env pointers"), "scheduler": (default_scheduler_config(), "Scheduler runtime process settings"), }) def _seed_one(key: str, value, description: str): return seed_system_defaults({key: (value, description)}) def llm_config(): cfg = get_llm_config(default=None) if cfg is None: _seed_one("llm", default_llm_config(), "LLM provider and module switches; API key remains in env") cfg = get_llm_config(default=None) return cfg or default_llm_config() def onchain_config(default_chains=("ethereum", "bsc", "base", "arbitrum", "solana")): cfg = get_onchain_config(default=None) if cfg is None: _seed_one("onchain", default_onchain_config(default_chains), "On-chain provider and signal thresholds; API keys remain in env") cfg = get_onchain_config(default=None) return cfg or default_onchain_config(default_chains) def paper_trading_config(): cfg = get_paper_trading_config(default=None) if cfg is None: _seed_one("paper_trading", default_paper_trading_config(), "Paper trading account and execution model") cfg = get_paper_trading_config(default=None) return cfg or default_paper_trading_config() def price_streamer_config(): cfg = get_price_streamer_config(default=None) if cfg is None: _seed_one("price_streamer", default_price_streamer_config(), "Realtime websocket price streamer settings") cfg = get_price_streamer_config(default=None) return cfg or default_price_streamer_config() def notification_config(): cfg = get_notification_config(default=None) if cfg is None: _seed_one("notification", default_notification_config(), "Notification channel switches and env pointers") cfg = get_notification_config(default=None) return cfg or default_notification_config() def sentiment_config(): cfg = get_sentiment_config(default=None) if cfg is None: _seed_one("sentiment", default_sentiment_config(), "Sentiment monitoring settings") cfg = get_sentiment_config(default=None) return cfg or default_sentiment_config() def event_driven_config(): cfg = get_event_driven_config(default=None) if cfg is None: _seed_one("event_driven", default_event_driven_config(), "Event/news driven screening settings") cfg = get_event_driven_config(default=None) return cfg or default_event_driven_config() def monitoring_config(): cfg = get_monitoring_config(default=None) if cfg is None: _seed_one("monitoring", default_monitoring_config(), "Monitoring and audit settings") cfg = get_monitoring_config(default=None) return cfg or default_monitoring_config() def email_config(): cfg = get_email_config(default=None) if cfg is None: _seed_one("email", default_email_config(), "SMTP email settings; password remains in env") cfg = get_email_config(default=None) return cfg or default_email_config() def bootstrap_admin_config(): cfg = get_bootstrap_admin_config(default=None) if cfg is None: _seed_one("bootstrap_admin", default_bootstrap_admin_config(), "Default admin bootstrap env pointers") cfg = get_bootstrap_admin_config(default=None) return cfg or default_bootstrap_admin_config() def scheduler_config(): cfg = get_scheduler_config(default=None) if cfg is None: _seed_one("scheduler", default_scheduler_config(), "Scheduler runtime process settings") cfg = get_scheduler_config(default=None) return cfg or default_scheduler_config() __all__ = [ "bootstrap_admin_config", "default_bootstrap_admin_config", "default_email_config", "default_event_driven_config", "default_llm_config", "default_monitoring_config", "default_notification_config", "default_onchain_config", "default_paper_trading_config", "default_price_streamer_config", "default_scheduler_config", "default_sentiment_config", "email_config", "event_driven_config", "llm_config", "monitoring_config", "notification_config", "onchain_config", "paper_trading_config", "price_streamer_config", "scheduler_config", "sentiment_config", "seed_runtime_system_defaults", ]