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:
Executable
+162
@@ -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()))
|
||||
Reference in New Issue
Block a user