Pre-launch hardening: KOL module, Telegram, scanners, WS resilience

Big-picture changes since b941223:

KOL pipeline (new) — Substack/podcast/blog RSS → AI ticker extraction →
on-chain wallet diff → talks-vs-trades divergence detection. Daily polls,
19 feeds, divergence emits Post + Telegram fan-out.

Telegram push (new) — walletless free tier + wallet-linked Pro upgrade,
in-bot preference commands (/trump /btc /funding /kol /conf /quiet),
signed-envelope API for dashboard. Disconnect-wallet keeps free
subscription.

BTC funding-rate reversal scanner (new) — hourly cron, 30d cumulative
funding threshold + mean-revert + 7d price confirm, emits via
/api/signals/ingest. BTC bottom-reversal scanner promoted to System 2.

WS broadcast rewrite — per-client send timeout + parallel fan-out
(asyncio.gather). Fixes "Binance WS no close frame" reconnect storms +
APScheduler 11-min job misses, both caused by one slow client stalling
the kline loop.

Error visibility — three silent-error sites (trumpstruth/truth_social
fetchers, funding_reversal scanner) now include exception type name so
httpx ConnectError-style empty-message errors stop logging blank lines.
Telegram bot loop now classifies ReadTimeout vs network vs unknown +
logger.exception for the unknown bucket.

Security hygiene — trumpsignal.db untracked from git (held subscriber
wallets + encrypted HL keys + 22 bot trades); .gitignore now blocks
*.db/.next/backups. CORS only allows FRONTEND_URL in production.

New ops scripts —
  - scripts/preflight.py: env/DB/Telegram/AI auth verification gate
  - scripts/backup_db.sh: cron-friendly daily DB backup (SQLite + Postgres)
  - scripts/seed_kol_wallets.py: idempotent KOL on-chain wallet seeder

15 new Alembic migrations (007-021) covering convex strategy fields,
phase-1 safety, two-system frozen exits, invalidation prices, dynamic
SYS2 leverage, staged de-risk + pyramiding, peak gain tracking, risk
mode, auto-trade + grow flags, KOL module, KOL on-chain, KOL divergence,
Telegram bindings + walletless.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
k
2026-05-25 00:52:56 +08:00
parent b941223c88
commit 5fb1d52026
81 changed files with 13251 additions and 158 deletions
+162
View File
@@ -0,0 +1,162 @@
#!/usr/bin/env python3
"""
Seed the kol_wallets table with publicly attributed on-chain addresses.
Why this exists:
The talks-vs-trades divergence module can only fire on KOLs whose wallets
we know. As of 2026-05-24 only 3 KOLs had wallets configured, which is
why we had ~3 divergence detections across the whole dataset.
Adding a new wallet here REQUIRES:
1. Public attribution — Arkham label, the KOL's own X bio, a public
investigation by ZachXBT / Inspex / similar, or the KOL's ENS clearly
visible in transactions.
2. The `handle` field MUST exactly match a `handle` value in
app/services/kol_substack.py KOL_FEEDS — otherwise the divergence
scanner cannot match "post by handle X" against "wallet activity by
handle X".
3. The `source_url` must link to that public attestation. Don't add
speculative addresses, even if "everyone knows" — misattribution
damages both the KOL and our credibility.
Idempotent: runs UPSERT-style. Existing rows for (handle, address) are
preserved; only new ones are inserted.
Usage:
DATABASE_URL='sqlite+aiosqlite:///./trumpsignal.db' \\
venv/bin/python scripts/seed_kol_wallets.py
"""
from __future__ import annotations
import asyncio
import sys
from datetime import datetime, timezone
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from sqlalchemy import select
from app.database import AsyncSessionLocal
from app.models import KolWallet
# ────────────────────────────────────────────────────────────────────────────
# Verified seed list.
#
# Each entry MUST have a working source_url. If you can't link to a public
# attestation, DON'T add it.
#
# To find more candidates yourself:
# • https://platform.arkhamintelligence.com/ — search by handle, click
# "labels" tab. Labels prefixed with "Entity:" are Arkham-verified.
# • https://etherscan.io/labelcloud — Etherscan public label registry.
# • ZachXBT investigations on X — he posts the underlying tx evidence.
# • Many KOLs put their address in their X bio or pinned tweet.
#
# When the KOL's handle in KOL_FEEDS doesn't match the on-chain handle here,
# add it under the handle that's IN KOL_FEEDS — divergence join is by handle.
# ────────────────────────────────────────────────────────────────────────────
SEED_WALLETS: list[dict] = [
# ── Already in DB (kept here so the script is self-documenting) ──────
{
"handle": "cryptohayes",
"chain": "ethereum",
"address": "0xa86e3d1c80a750a310b484fb9bdc470753a7506f",
"label": "Arthur Hayes (main)",
"source_url": "https://etherscan.io/address/0xa86e3d1c80a750a310b484fb9bdc470753a7506f",
},
{
"handle": "cryptohayes",
"chain": "ethereum",
"address": "0x534a0076fb7c2b1f83fa21497429ad7ad3bd7587",
"label": "Arthur Hayes (secondary)",
"source_url": "https://etherscan.io/address/0x534a0076fb7c2b1f83fa21497429ad7ad3bd7587",
},
{
"handle": "andrewkang",
"chain": "ethereum",
"address": "0xff3879b8a363aed92a6eaba8f61f1a96a9ec3c1e",
"label": "Andrew Kang (beanwhale.eth)",
"source_url": "https://etherscan.io/address/0xff3879b8a363aed92a6eaba8f61f1a96a9ec3c1e",
},
{
"handle": "murad",
"chain": "ethereum",
"address": "0x93f019699ef400df7dc3477dbb6400ed9445a657",
"label": "Murad Mahmudov (via ZachXBT investigation)",
"source_url": "https://www.blocmates.com/news-posts/24million-in-memecoins-zachxbt-unveils-murad-mahmudov-s-alleged-wallets",
},
# ── Add new VERIFIED entries below this line ─────────────────────────
#
# Template — copy, replace fields, push only after verifying source_url:
#
# {
# "handle": "<matches handle in KOL_FEEDS>",
# "chain": "ethereum", # or "solana", "base", "arbitrum"
# "address": "0x...",
# "label": "<KOL display name (annotation)>",
# "source_url": "<public link proving attribution>",
# },
#
# Candidates to research (NOT seeded — verify before adding):
#
# • niccarter — Nic Carter has spoken openly about his wallet
# history on podcasts; check Coin Center filings.
# • pomp — Pompliano has a public BTC-only treasury; less
# useful for ETH-side divergence detection.
# • dragonfly — Dragonfly Capital portfolio wallets often
# labeled on Arkham as "Dragonfly Fund".
# • placeholder — Placeholder VC fund wallets per their public
# investment disclosures.
# • eugene — Eugene Ng Ah Sio — verify before adding.
#
# Also worth tracking even if not in KOL_FEEDS (would need to add the
# corresponding feed entry first or they'll never have post-side data):
#
# • justinsuntron — Tron founder, very active ETH trader, well-labeled.
# • cobie — Jordan Fish, address known via Arkham labels.
# • gcr / sam — anon traders, no reliably verifiable address.
]
async def main() -> int:
inserted = 0
skipped = 0
async with AsyncSessionLocal() as session:
for entry in SEED_WALLETS:
# Idempotency: skip if (handle, address) already present.
existing = await session.execute(
select(KolWallet).where(
KolWallet.handle == entry["handle"],
KolWallet.address == entry["address"].lower(),
)
)
if existing.scalar_one_or_none():
skipped += 1
continue
row = KolWallet(
handle=entry["handle"],
chain=entry["chain"],
address=entry["address"].lower(),
label=entry["label"],
source_url=entry["source_url"],
active=True,
added_at=datetime.now(timezone.utc).replace(tzinfo=None),
)
session.add(row)
inserted += 1
print(f" + {entry['handle']:18s} {entry['address']} ({entry['label']})")
await session.commit()
print()
print(f"Inserted {inserted} wallets, skipped {skipped} existing.")
print()
print("Next step: edit SEED_WALLETS above and re-run. Each new wallet")
print("MUST cite a public attestation in source_url — see the docstring.")
return 0
if __name__ == "__main__":
raise SystemExit(asyncio.run(main()))