一个轻量、文件驱动的 perp listing intelligence 项目。
从交易所抓取新上币信号,经过清洗、CoinGecko 富化、RWA 标注、质量审计与归档,最终推送到 Lark 卡片并在 Streamlit dashboard 上可视化。整条 pipeline 以本地文件为中心,无需常驻服务。
🔗 Live Demo: https://mrperps-listing-monitor.streamlit.app/?page=overview
ingestion ──► transform ──► quality ──► delivery / app
抓取上币 清洗 + 富化 数据审计 Lark 推送 / dashboard
按 pipeline 分层的目录职责:
| 目录 | 职责 |
|---|---|
src/ingestion/ |
交易所抓取与 listing 检测 |
src/transform/ |
清洗、CoinGecko enrich、RWA 标注、归档、SQLite query layer |
src/quality/ |
数据质量审计 |
src/delivery/ |
Lark 推送层 |
src/app/ |
Streamlit dashboard |
config/ |
显式配置,如 CoinGecko override map |
data/ |
raw / cache / processed / marts / audits / history / db |
- Quick Start
- Directory Layout
- Architecture Notes
- Environment
- Makefile
- Core Files
- Run The Pipeline
- RWA Labeling
- Daily Snapshot And SQLite Query Layer
- Lark Delivery
- Streamlit Dashboard
- Public Beta Deployment
- Backward Compatibility Notes
- Git Hygiene
# 1. 安装锁定依赖
pip install -r requirements.txt
# 2. 配置环境变量
cp .env.example .env # 然后填入 LARK_WEBHOOK_URL 等
# 3. 刷新数据并跑一遍 pipeline
make all
# 4. 启动本地 dashboard
make uilisting-monitor/
README.md
.env
.env.example
.gitignore
config/
coingecko_overrides.py
rwa_allowlist.csv
docs/
architecture/
Listing Monitor架构walkthrough.md
listing_monitor_review_prompt.md
src/
ingestion/
hl_listing_monitor.py
fetch_venue_ticker_metrics.py
transform/
clean_watchboard.py
enrich_watchboard_coingecko.py
label_rwa_tokens.py
archive_daily_snapshot.py
build_history_store.py
quality/
audit_watchboard_quality.py
delivery/
lark_listing_watchboard.py
app/
streamlit_app.py
watchboard_query.py
common/
paths.py
data/
raw/
cache/
processed/
marts/
audits/
history/
db/
Project architecture and review context are archived in docs/architecture/:
Listing Monitor架构walkthrough.md:comprehensive architecture walkthrough and Claude review outputlisting_monitor_review_prompt.md:the review prompt used to generate the architecture assessment
These files are documentation only; they do not affect the runtime pipeline.
安装依赖:
pip install -r requirements.txt创建 .env:
cp .env.example .env填入:
LARK_WEBHOOK_URL=https://open.larksuite.com/open-apis/bot/v2/hook/your-webhook
WATCHBOARD_DASHBOARD_URL=http://localhost:8511/?page=overview
WATCHBOARD_HISTORY_DIFF_URL=http://localhost:8511/?page=history说明:
- 所有脚本都通过
src/common/paths.py按项目根目录解析路径,不依赖当前工作目录。 lark_listing_watchboard.py仍然支持--webhook显式覆盖.env。- Streamlit Community Cloud 的 public beta 不需要
.env或 Secrets。
常用入口已经收进 Makefile:
| 命令 | 作用 |
|---|---|
make listings |
刷新 listing state 和 data/raw/listing_watchboard.csv,不推 Lark |
make clean |
清洗 watchboard |
make market |
CoinGecko enrich + 生成 leaderboard marts |
make rwa |
生成 token-level RWA labels 与 review queue |
make tickers |
抓取 venue ticker metrics |
make metrics |
token metrics / leaderboard(由 market 步骤生成) |
make audit |
数据质量审计 |
make archive |
归档当日输出到 data/history/ |
make db |
构建 SQLite query layer |
make lark |
推送每日 Lark 卡片 |
make ui |
启动本地 Streamlit dashboard |
make ui-lan |
在局域网内启动 dashboard(0.0.0.0:8511) |
make pipeline |
clean + market + rwa + tickers + metrics + audit + archive + db |
make daily |
pipeline + lark |
make all |
listings + pipeline |
推荐日常用法:
make all # 刷新上币信号并跑完整 pipeline
make daily # 跑 pipeline 并推送 Lark
make ui # 启动 dashboard主要数据层:
data/raw/known_listings.jsondata/raw/listing_watchboard.csvdata/cache/coingecko_coin_details_cache.jsondata/processed/listing_watchboard_clean.csvdata/processed/token_market_metrics.csvdata/processed/token_rwa_labels.csvdata/processed/token_rwa_review_queue.csvdata/processed/venue_ticker_metrics.csvdata/processed/listing_watchboard_token_metrics.csvdata/marts/top_volume_tokens.csvdata/marts/top_gainers_tokens.csvdata/marts/top_losers_tokens.csvdata/marts/hot_new_tokens.csvdata/audits/listing_coverage_audit.csvdata/audits/token_market_match_audit.csvdata/audits/token_market_metrics_audit.csvdata/db/listing_watchboard_history.sqlite
语义约定:
token_market_metrics.csv= CoinGecko token-level aggregated market data。token_rwa_labels.csv= token-level RWA classification keyed primarily bycoingecko_id。venue_ticker_metrics.csv= exchange-specific perp/swap/futures metrics。- 不要把 CoinGecko
volume_24h_usd理解成某个交易所的 venue 成交量。
最常用的一条本地 pipeline:
python src/transform/clean_watchboard.py
python src/transform/enrich_watchboard_coingecko.py
python src/transform/label_rwa_tokens.py
python src/ingestion/fetch_venue_ticker_metrics.py
python src/quality/audit_watchboard_quality.py
python src/transform/archive_daily_snapshot.py --overwrite
python src/transform/build_history_store.py等价于
make pipeline。下面按步骤拆解每一环的行为。
Hyperliquid / multi-venue listing monitor:
python src/ingestion/hl_listing_monitor.py snapshot --venue all
python src/ingestion/hl_listing_monitor.py daily-summary --venue all
python src/ingestion/hl_listing_monitor.py poll --venue all行为说明:
- 首次运行会初始化
data/raw/known_listings.json,并且不发告警。 - 后续运行检测新增 listings 并推送 Lark。
snapshot --venue all会做一次性 listing state / raw watchboard 刷新,不推送 Lark。poll --venue all会在一个进程里顺序检查各 venue,避免多个进程并发写同一状态文件。
python src/transform/clean_watchboard.py输入 / 输出:
- 输入:
data/raw/listing_watchboard.csv - 输出:
data/processed/listing_watchboard_clean.csv
python src/transform/enrich_watchboard_coingecko.py输出:
data/processed/token_market_metrics.csvdata/processed/listing_watchboard_token_metrics.csvdata/marts/top_volume_tokens.csvdata/marts/top_gainers_tokens.csvdata/marts/top_losers_tokens.csvdata/marts/hot_new_tokens.csvdata/audits/token_market_match_audit.csvdata/audits/token_market_metrics_audit.csv
python src/transform/label_rwa_tokens.py输出:
data/processed/token_rwa_labels.csvdata/processed/token_rwa_review_queue.csvdata/cache/coingecko_coin_details_cache.json
V1 规则:
- 主键优先使用
coingecko_id,不依赖 symbol 作为唯一分类键 - 优先级严格为:
manual_overrideseed_allowlistcached_coingecko_categoriesconservative_keyword_fallback
- CoinGecko detail cache 只会对前两层都未命中的 coin ID 拉取并缓存
- public CoinGecko 额度较紧时,detail cache 会按小批量渐进预热;一旦确认持续
429,本轮会停止继续拉取并直接落地标签结果 - 主流稳定币默认排除为
non_rwa - 证据冲突或边界模糊时使用
review_pending token_rwa_review_queue.csv只聚焦review_pending,并优先按24h volume、market cap、再按是否存在 keyword/category 证据排序,便于运营先看高价值待复核 token
当前 config/rwa_allowlist.csv schema:
coingecko_idrwa_labelrwa_categoryprotocolforce_overridenotes
python src/ingestion/fetch_venue_ticker_metrics.py输出:
data/processed/venue_ticker_metrics.csv
当前 resilience 行为:
- 每个 venue 最多重试 3 次,按
1s / 2s / 4sexponential backoff。 - 单个 venue 最终失败时,不会中断整条 ticker pipeline;其他 venue 继续处理。
- 如果本地已有上一份成功的
venue_ticker_metrics.csv,失败 venue 会优先复用上一份该 venue 的 rows,并标记为 stale fallback。 venue_ticker_metrics.csv会额外写出:fetch_status、snapshot_time、data_freshness、source_error。
python src/quality/audit_watchboard_quality.py输出:
data/audits/listing_coverage_audit.csvdata/audits/token_market_metrics_audit.csv
归档当前日输出:
python src/transform/archive_daily_snapshot.py --overwrite会复制当前主要结果到 data/history/YYYY-MM-DD/。
构建 SQLite query layer:
python src/transform/build_history_store.pySQLite 文件:data/db/listing_watchboard_history.sqlite
当前表层次:
listing_snapshotstoken_market_metrics_dailytoken_rwa_labels_dailyvenue_ticker_metrics_dailytoken_metrics_dailyleaderboard_daily
RWA 查询例子:
-- 最新一版 review queue
SELECT
snapshot_date,
token,
coingecko_id,
rwa_label,
rwa_category,
confidence,
label_source
FROM token_rwa_labels_daily
WHERE snapshot_date = (SELECT MAX(snapshot_date) FROM token_rwa_labels_daily)
AND rwa_label = 'review_pending'
ORDER BY confidence ASC, token ASC;-- 某天的 core / related RWA token
SELECT
l.snapshot_date,
l.token,
l.coingecko_id,
l.rwa_label,
l.rwa_category,
l.protocol,
t.venue_count,
t.volume_24h_usd
FROM token_rwa_labels_daily l
LEFT JOIN token_metrics_daily t
ON l.snapshot_date = t.snapshot_date
AND l.token = t.token
WHERE l.snapshot_date = '2026-04-15'
AND l.rwa_label IN ('core', 'related')
ORDER BY l.rwa_label, t.volume_24h_usd DESC, l.token ASC;人工复核工作流:
- 每天优先查看
token_rwa_labels_daily中rwa_label = 'review_pending'的 token - 核对对应
coingecko_id、CoinGecko categories、项目描述与官网定位 - 如果结论明确,把 coin ID 写入
config/rwa_allowlist.csv - 若必须强制纠偏,设置
force_override = true
推送每日卡片:
python src/delivery/lark_listing_watchboard.py临时覆盖 webhook:
python src/delivery/lark_listing_watchboard.py --webhook "https://open.larksuite.com/open-apis/bot/v2/hook/another-webhook"卡片当前聚焦:
New Listings 24hHot New TokensTop Volume 24hTop Movers 24h
并明确区分:
- Token Market View = CoinGecko token-level aggregated market data
- Venue Perp View = exchange-specific perp/swap/futures metrics
在线体验:https://mrperps-listing-monitor.streamlit.app/?page=overview
启动本地 dashboard:
python3 -m streamlit run src/app/streamlit_app.py
# 或
make ui主要页面:
OverviewToken Drill-downVenue ViewHistory / DiffData Quality
常用 deep links:
http://localhost:8511/?page=overview&snapshot=2026-04-14
http://localhost:8511/?page=token&snapshot=2026-04-14&token=SUI
http://localhost:8511/?page=venue&snapshot=2026-04-14&venue=binance
http://localhost:8511/?page=history&snapshot=2026-04-14&token=SUI
http://localhost:8511/?page=quality&snapshot=2026-04-14
部署路径为 GitHub repository → Streamlit Community Cloud。当前线上入口为 Live Demo。
| 配置项 | 值 |
|---|---|
| Branch | codex/public-beta-streamlit |
| Main file | src/app/streamlit_app.py |
| Data source | 已提交的 data/history/YYYY-MM-DD/*.csv 快照 |
| Secrets | 当前 public beta 不需要 |
Cloud 首次启动会从历史快照重建只读 SQLite query layer;不要提交本地 .env、Secrets、缓存或 SQLite 文件。
如果你想在同一个局域网里给同事演示:
make ui-lan然后让同事打开:
http://<your-lan-ip>:8511
注意:
- 同事需要和你在同一个 LAN / Wi‑Fi 网络里。
- macOS / Windows 防火墙可能需要允许
8511入站连接。 .streamlit/config.toml里提供了一个 LAN 示例配置;如果你的局域网 IP 变化了,需要把browser.serverAddress改成当前机器的 IP。
- 旧的根目录脚本路径已经迁移到
src/...。 - 旧的数据文件路径已经迁移到
data/...。 data/processed/listing_watchboard_enriched.csv作为 legacy 输出保留,但不再是主要 source of truth。- 如果你之前有手工脚本或 cron 指向旧路径,需要改成新的
src/...命令。
推荐纳入版本管理的内容:
README.md、.gitignore、.env.example、Makefileconfig/、src/data/*/.gitkeep- 其他代码、配置、文档类文件
不建议提交:
.env及其他.env.*secrets 文件.streamlit/secrets.toml*.sqlite/*.db本地数据库*.log、logs/等本地运行日志data/raw/*、data/cache/*、data/processed/*、data/marts/*、data/audits/*、data/db/*- 本地 IDE / Python 缓存目录,如
.vscode/、.idea/、__pycache__/、.venv/
public beta 的一个例外:可以提交少量 data/history/YYYY-MM-DD/*.csv 快照,作为 Streamlit Community Cloud 的只读展示数据来源。
推荐初始化方式:
git init
git add README.md .gitignore .env.example Makefile config src \
data/raw/.gitkeep data/processed/.gitkeep data/marts/.gitkeep \
data/audits/.gitkeep data/history/.gitkeep data/db/.gitkeep
git commit -m "Initial listing monitor pipeline structure"首次推送到远程:
git branch -M main
git remote add origin <your-repo-url>
git push -u origin main