""" Central configuration: RSS feeds, subreddits, narrative keywords, API endpoints. All sources are free — no paid API keys required. """ # --------------------------------------------------------------------------- # RSS Feeds — no key required # --------------------------------------------------------------------------- RSS_FEEDS = { # Tier-1 outlets "CoinDesk": "https://www.coindesk.com/arc/outboundfeeds/rss/", "CoinTelegraph": "https://cointelegraph.com/rss", "Decrypt": "https://decrypt.co/feed", "Bitcoin Magazine":"https://bitcoinmagazine.com/feed", "The Block": "https://www.theblock.co/rss.xml", "Blockworks": "https://blockworks.co/feed", "CryptoSlate": "https://cryptoslate.com/feed/", "NewsBTC": "https://www.newsbtc.com/feed/", "AMBCrypto": "https://ambcrypto.com/feed/", "CryptoNews": "https://cryptonews.com/news/feed/", # Additional free outlets "BeInCrypto": "https://beincrypto.com/feed/", "CryptoPotato": "https://cryptopotato.com/feed/", "Bitcoinist": "https://bitcoinist.com/feed/", "U.Today": "https://u.today/rss", "CoinGape": "https://coingape.com/feed/", "DailyHodl": "https://dailyhodl.com/feed/", "CoinJournal": "https://coinjournal.net/news/feed/", "Crypto Briefing": "https://cryptobriefing.com/feed/", "Coinpedia": "https://coinpedia.org/feed/", "ZyCrypto": "https://zycrypto.com/feed/", # Google News aggregators (free, no key — each pulls from hundreds of outlets) "GoogleNews: Crypto": "https://news.google.com/rss/search?q=cryptocurrency+when:1d&hl=en-US&gl=US&ceid=US:en", "GoogleNews: Bitcoin": "https://news.google.com/rss/search?q=bitcoin+when:1d&hl=en-US&gl=US&ceid=US:en", "GoogleNews: Ethereum": "https://news.google.com/rss/search?q=ethereum+OR+%22ETH%22+crypto+when:1d&hl=en-US&gl=US&ceid=US:en", "GoogleNews: Regulation": "https://news.google.com/rss/search?q=crypto+regulation+OR+SEC+when:1d&hl=en-US&gl=US&ceid=US:en", } # --------------------------------------------------------------------------- # US Macro feeds — these move the whole risk-asset market (incl. crypto). # Tracked as a SEPARATE signal (not mixed into crypto-native sentiment) but # shown as the "macro backdrop" because it spills over into crypto. # Sources here are tagged is_macro=True by the collector. # --------------------------------------------------------------------------- MACRO_FEEDS = { "Macro: Fed": "https://news.google.com/rss/search?q=federal+reserve+interest+rates+when:1d&hl=en-US&gl=US&ceid=US:en", "Macro: Inflation": "https://news.google.com/rss/search?q=US+inflation+CPI+when:1d&hl=en-US&gl=US&ceid=US:en", "Macro: Economy": "https://news.google.com/rss/search?q=US+economy+recession+OR+jobs+report+when:1d&hl=en-US&gl=US&ceid=US:en", "Macro: Markets": "https://news.google.com/rss/search?q=stock+market+S%26P+500+nasdaq+when:1d&hl=en-US&gl=US&ceid=US:en", } # --------------------------------------------------------------------------- # Reddit — free, requires PRAW app credentials (see .env) # --------------------------------------------------------------------------- SUBREDDITS = [ "CryptoCurrency", "Bitcoin", "ethereum", "CryptoMarkets", "altcoin", "defi", "solana", "binance", "Ripple", "dogecoin", ] REDDIT_POST_LIMIT = 100 # posts per subreddit per fetch REDDIT_COMMENT_LIMIT = 10 # top comments to fetch per post # --------------------------------------------------------------------------- # CoinGecko — free public API, no key needed # --------------------------------------------------------------------------- COINGECKO_BASE = "https://api.coingecko.com/api/v3" COINGECKO_TRENDING_URL = f"{COINGECKO_BASE}/search/trending" COINGECKO_GLOBAL_URL = f"{COINGECKO_BASE}/global" COINGECKO_COINS_URL = f"{COINGECKO_BASE}/coins/markets" TOP_COINS_TO_TRACK = [ "bitcoin", "ethereum", "solana", "binancecoin", "ripple", "cardano", "dogecoin", "avalanche-2", "chainlink", "polkadot", "sui", "aptos", "arbitrum", "optimism", "injective-protocol", ] # --------------------------------------------------------------------------- # Fear & Greed Index — free, no key # --------------------------------------------------------------------------- FEAR_GREED_URL = "https://api.alternative.me/fng/?limit=7" # --------------------------------------------------------------------------- # cryptocurrency.cv — free, no key # --------------------------------------------------------------------------- CRYPTOCV_NEWS_URL = "https://cryptocurrency.cv/api/v1/news" # --------------------------------------------------------------------------- # Narrative Definitions — keyword clusters mapped to narrative names # --------------------------------------------------------------------------- NARRATIVES: dict[str, list[str]] = { "ETF Approval": [ "etf", "exchange traded fund", "spot etf", "bitcoin etf", "ethereum etf", "sec approval", "blackrock etf", "fidelity etf", "etf launch", "etf inflows", ], "AI & Crypto": [ "artificial intelligence", "ai token", "ai agent", "machine learning", "gpt", "large language model", "llm", "ai narrative", "fetch.ai", "bittensor", "render network", "ai crypto", ], "RWA (Real World Assets)": [ "real world asset", "rwa", "tokenized asset", "tokenized bonds", "tokenized real estate", "on-chain asset", "asset tokenization", "blackrock tokenize", "ondo finance", "centrifuge", ], "Memecoin": [ "memecoin", "meme coin", "meme token", "dogecoin", "shiba inu", "pepe", "bonk", "wif", "floki", "meme rally", "casino narrative", ], "DeFi": [ "defi", "decentralized finance", "yield farming", "liquidity pool", "dex", "uniswap", "aave", "compound", "tvl", "total value locked", "lending protocol", "automated market maker", ], "Layer 2 Scaling": [ "layer 2", "l2", "rollup", "optimistic rollup", "zk rollup", "arbitrum", "optimism", "zksync", "polygon", "base", "scaling solution", ], "Institutional Adoption": [ "institutional", "hedge fund", "wall street", "treasury", "corporate bitcoin", "microstrategy", "grayscale", "fidelity", "morgan stanley", "goldman sachs", "blackrock bitcoin", "institutional investor", ], "Regulation": [ "regulation", "sec", "cftc", "enforcement", "lawsuit", "crackdown", "compliance", "legal", "ban", "legislation", "congress", "senate", "regulatory", "policy", "finra", ], "Exchange Listing": [ "listed on", "exchange listing", "coinbase listing", "binance listing", "kraken listing", "new listing", "ipo", "token launch", ], "Security Breach / Hack": [ "hack", "exploit", "breach", "stolen funds", "rug pull", "exit scam", "smart contract vulnerability", "attack", "drained", "flash loan attack", ], "Ecosystem Upgrade": [ "upgrade", "hard fork", "soft fork", "protocol upgrade", "migration", "eip", "bip", "taproot", "merge", "shapella", "dencun", "pectra", ], "Bitcoin Halving": [ "halving", "halvening", "bitcoin supply", "block reward", "miner reward", "post halving", "halving cycle", ], "Staking & Yield": [ "staking", "stake", "validator", "proof of stake", "liquid staking", "lido", "rocketpool", "staking yield", "restaking", "eigenlayer", ], "Cross-chain / Interoperability": [ "cross-chain", "bridge", "interoperability", "multichain", "cosmos", "polkadot", "ibc protocol", "wormhole", "layerzero", "chainlink ccip", ], "NFT": [ "nft", "non fungible token", "opensea", "nft market", "ordinals", "nft collection", "blue chip nft", "nft gaming", ], "GameFi / Play-to-Earn": [ "gamefi", "play to earn", "p2e", "blockchain game", "axie infinity", "gaming token", "gaming narrative", "metaverse", ], } # --------------------------------------------------------------------------- # Ensemble sentiment: how much each model contributes to the blended score # --------------------------------------------------------------------------- ENSEMBLE_WEIGHTS = { "cryptobert": 0.65, # transformer, more reliable on crypto slang/context "vader": 0.35, # lexicon, fast sanity check } # --------------------------------------------------------------------------- # Source credibility — multiplier applied when aggregating 24h sentiment. # Established outlets count more than anonymous social posts. # Matched as a case-insensitive substring of the item's "source" field. # --------------------------------------------------------------------------- SOURCE_WEIGHTS = { "CoinDesk": 1.6, "The Block": 1.6, "Bloomberg": 1.7, "Reuters": 1.7, "Blockworks": 1.4, "CoinTelegraph": 1.3, "Decrypt": 1.3, "Bitcoin Magazine": 1.2, "CryptoSlate": 1.1, "NewsBTC": 1.0, "AMBCrypto": 1.0, "CryptoNews": 1.0, "NewsData": 1.1, "BeInCrypto": 1.0, "CryptoPotato": 0.95, "Bitcoinist": 0.95, "U.Today": 0.95, "CoinGape": 0.9, "DailyHodl": 0.9, "CoinJournal": 1.0, "Crypto Briefing": 1.1, "Coinpedia": 0.9, "ZyCrypto": 0.85, "GoogleNews": 1.2, # aggregator across many outlets "Reddit": 0.7, # social signal, noisier "_default": 1.0, } # --------------------------------------------------------------------------- # Spike detection thresholds # --------------------------------------------------------------------------- SPIKE = { "baseline_snapshots": 8, # how many past snapshots form the baseline "volume_ratio": 2.0, # mentions >= 2x baseline avg → spike "sentiment_swing": 0.30, # net sentiment moved >= 0.30 → swing "new_min_volume": 4, # min mentions for a NEW_NARRATIVE alert "max_alerts": 8, # cap alerts per refresh } # --------------------------------------------------------------------------- # Scoring Weights # --------------------------------------------------------------------------- SCORING = { "recency_decay_hours": 24, # articles older than this lose full score "reddit_upvote_weight": 0.3, "news_volume_weight": 0.4, "sentiment_weight": 0.3, "trending_coin_bonus": 1.5, # multiplier if coin is trending on CoinGecko } # --------------------------------------------------------------------------- # Google Trends — keywords to track interest over time # --------------------------------------------------------------------------- TREND_KEYWORDS = [ "bitcoin etf", "crypto regulation", "AI crypto", "real world assets crypto", "memecoin", "bitcoin halving", "DeFi", "layer 2 crypto", ] # --------------------------------------------------------------------------- # Storage # --------------------------------------------------------------------------- DB_PATH = "narrative_analysis.db" MAX_ARTICLE_AGE_HOURS = 72 # keep articles in cache for 3 days # --------------------------------------------------------------------------- # Display # --------------------------------------------------------------------------- REFRESH_INTERVAL_MINUTES = 30 # auto-refresh interval for live mode TOP_NARRATIVES_TO_SHOW = 10