Files
k 54884f3e24 KOL feeds: fix dead/blocked sources, drop stale feeds (29→25)
Feed-health pass over KOL_FEEDS:
- raoulpal: stale Substack (last 2024-05) → Real Vision podcast feed
- dampedspring: paywalled (0 entries) → free "Damped Spring 101" Substack
- unchained: Cloudflare 403 → canonical Megaphone podcast feed
- lynalden: Cloudflare 202 → FeedBurner mirror
- glassnode: recovered via httpx http2=True (was 403 on HTTP/1.1)
- browser User-Agent + Accept headers on feed fetch
- removed dead feeds with no active replacement: placeholder,
  dragonfly, niccarter, eugene
- pin h2==4.3.0 (required by http2=True)

All 25 remaining feeds verified fetching real body content; newest
post per feed ≤88d. Bundles in-flight KOL-module work already in the
working tree (kol_x ingest, migration 027, tests).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 22:55:16 +08:00

106 lines
5.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
database_url: str
frontend_url: str = "http://localhost:3001"
truth_social_rss: str = "https://truthsocial.com/@realDonaldTrump.rss"
truth_social_poll_seconds: int = 15
# WS URL is now built programmatically in binance.py from ASSET_MAP so the
# stream list and the routing table are always in sync. This setting is kept
# for external callers that still reference it; binance.py ignores it.
binance_ws_url: str = "wss://data-stream.binance.vision/stream" # base only
binance_rest_url: str = "https://data-api.binance.vision"
environment: str = "production"
ai_api_key: str = ""
ai_base_url: str = "https://api.deepseek.com/v1"
ai_model: str = "deepseek-v4-pro" # batch / reanalysis (quality over speed)
ai_live_model: str = "deepseek-v4-flash" # live post analysis (latency-sensitive, ~2s)
# Native Anthropic API key — if set, takes priority over ai_api_key + ai_base_url.
# Get from https://console.anthropic.com → API Keys
anthropic_api_key: str = ""
# Hyperliquid — API wallet private key (NOT your MetaMask key)
# Created at https://app.hyperliquid.xyz/API and authorized by MetaMask
hl_api_private_key: str = ""
# Your MetaMask address — this is the actual account holding USDC/positions
hl_account_address: str = ""
# BTC perp leverage (150x isolated margin)
hl_leverage: int = 3
# Trade mainnet (True) or testnet (False)
hl_mainnet: bool = True
# KEK for envelope-encrypting HL API keys at rest.
# Generate with: openssl rand -hex 32
encryption_key: str = ""
# Shared secret for /api/signals/ingest — external trading modules pass it
# in the X-Ingest-Key header. Empty (default) = ingest endpoint is REJECTED
# entirely until a key is configured (fail-closed).
ingest_api_key: str = ""
# Base URL for internal signal ingest (used by scanners). In Docker, set to
# the service name (e.g. http://api:8000); bare-metal defaults to localhost.
ingest_base_url: str = "http://localhost:8000"
# Glassnode on-chain data. Used only by the BTC bottom-reversal state
# machine (MVRV-Z + STH-SOPR). Empty = scanner logs and skips fail-closed.
glassnode_api_key: str = ""
# Etherscan API key — free at etherscan.io/register → My API Keys.
# Used for KOL A-tier: fetch all ERC-20 token balances for a given ETH address.
# Empty = skip Ethereum wallet snapshots (only HL perp positions polled).
etherscan_api_key: str = ""
# ── Telegram push alerts ─────────────────────────────────────────────────
# Bot token from @BotFather (https://t.me/BotFather → /newbot). Free.
# Empty (default) = Telegram alerts disabled completely (bot loop skipped,
# notify_signal becomes a no-op, API endpoints return 503).
telegram_bot_token: str = ""
# Bot username (no @) — used by the Settings UI to render the deep link
# t.me/<username>?start=<code>. Example: "trumpalpha_bot".
telegram_bot_username: str = ""
# Public broadcast channel chat_id (e.g. "-1001234567890" or "@trumpalpha").
# When set, every actionable signal is also posted here in sanitised form
# (no trading details, no /adopt CTA). Leave empty to disable.
telegram_public_channel_id: str = ""
# ── X (Twitter) auto-poster ──────────────────────────────────────────────
# OAuth 1.0a User Context — for posting from a single fixed bot account
# (@TrumpAlpha_signals). Get all four from developer.x.com → your App →
# "Keys and tokens". App permissions MUST be "Read and Write", and the
# Access Token/Secret must be regenerated AFTER setting write permission.
# Bearer Token / Client ID / Client Secret are NOT used (those are read /
# OAuth2 web-flow credentials). Empty = X posting disabled (no-op).
x_api_key: str = "" # = Consumer Key
x_api_secret: str = "" # = Consumer Secret
x_access_token: str = ""
x_access_secret: str = ""
# Master switch. Even with keys set, posting stays off unless this is true.
# Lets you load creds without going live (dry-run = logs the tweet text).
x_enabled: bool = False
# Only post when ai_confidence >= this (0100). Keeps low-quality noise off
# the public timeline. Scanner signals carry their own score.
x_min_confidence: int = 60
# Hard daily cap on tweets (initial + follow-ups counted together) to stay
# under Free-tier 1,500/mo and avoid spam flags. In-memory, resets at UTC
# midnight. Single-process by design so a plain counter is safe.
x_daily_cap: int = 40
# Minutes after the initial prediction tweet to post the result follow-up.
x_followup_minutes: int = 15
# Public site URL appended to the follow-up tweet. Falls back to frontend_url.
x_link_url: str = ""
# ── X (Twitter) READ — KOL tweet ingestion (separate from the poster above) ──
# twitterapi.io managed-scraper key, sent as the `x-api-key` header. Powers
# kol_x.py: polls each tracked KOL's recent tweets → x_analysis.analyze_x_post
# → KolPost(source="twitter") → kol_divergence. This is READ-ONLY third-party
# data and is UNRELATED to the OAuth 1.0a poster creds above (those write our
# own tweets; this reads other people's). Empty = X ingestion disabled (no-op).
# Get a pay-as-you-go key at twitterapi.io (~$0.15 / 1k tweets).
twitterapi_io_key: str = ""
model_config = {"env_file": ".env", "env_file_encoding": "utf-8", "extra": "ignore"}
settings = Settings()