An open-source, candle-only crypto pump detector–looking for ML contributors An open-source, candle-only crypto pump detector, the pump-dump-crypto-screener, is seeking machine learning contributors to improve its detection algorithms. The TypeScript monorepo, available on GitHub, pulls 1-minute and 5-minute market statistics and bulk kline archives from Binance and Bybit, detects pump/dump regimes, and alerts via Telegram, with a live bot at @pumpdumpscreenerautobot. The project requires Node.js 20+, pnpm 9+, and pm2, and includes a manual review workflow to build a human-labeled dataset for evaluating and improving the screener. TypeScript pnpm monorepo for pulling 1m/5m market statistics and bulk kline archives from Binance and Bybit, detecting pump/dump regimes, and alerting via Telegram. Try the live bot: Open @pumpdumpscreenerautobot on Telegram https://t.me/pumpdumpscreenerautobot Requirements: Node.js 20+, pnpm 9+, pm2 https://pm2.keymetrics.io/ process manager for production . No exchange API keys. Binance and Bybit data comes from public bulk archives and public REST endpoints. You need two free accounts ~2 minutes each : | Service | Why | Setup | |---|---|---| | Stores pumps, monitor runs, and Telegram subscribers | turso db create screener → copy URL + auth token into config.js | Telegram /stats / /runs / /about bot @BotFather https://t.me/BotFather → /newbot → see docs/telegram setup.md /aleks-ent/pump-dump-crypto-screener/blob/main/docs/telegram setup.md pnpm install cp config.example.js config.js fill in Turso + Telegram see table above Edit config.js — at minimum, configure database , telegramBotToken , and your private classifierTelegramChatId . Anyone who sends /start is automatically subscribed to alerts and can use /stats , /runs , and /about ; only the configured chat can classify alerts. Pump lookback and scan settings live under pump defaults in config.example.js /aleks-ent/pump-dump-crypto-screener/blob/main/config.example.js : database: { url: "libsql://screener-....turso.io", authToken: "...", }, telegramBotToken: "123456789:ABC...", classifierTelegramChatId: "36772199", web: { port: 3000, // local app server; nginx terminates public HTTP/HTTPS host: "127.0.0.1", }, pump: { days: 5, // lookback calendar days for download + scan minScore: 80, scanCache: true, requireCalmPrePump: false, // feature flag: require a calm 2h period before pumps }, pnpm build pnpm db:bootstrap Run pnpm build again after every code change — PM2 does not rebuild for you. Production runs are defined in ecosystem.config.cjs /aleks-ent/pump-dump-crypto-screener/blob/main/ecosystem.config.cjs at the repo root. It starts three processes: | PM2 name | What it runs | Role | |---|---|---| pump-monitor | pnpm pump:monitor | Download → scan → persist pumps → Telegram alerts | pump-bot | pnpm pump:bot | /stats , /runs , /about , and Pump | Dump | None button clicks | pump-web | pnpm pump:web | Plain HTTP page showing the last 10 stored pumps | pm2 start ecosystem.config.cjs PM2 keeps all processes alive. When pump-monitor finishes a pipeline run it exits; PM2 immediately starts the next run autorestart: true . That replaces a manual cron loop. First run downloads pump.days of candles into data/market stats/ — network + disk required; can take hours. Market data is not in the repository. The web page is served by pump-web on 127.0.0.1:3000 by default. Put nginx in front of it for public HTTP/HTTPS; see docs/nginx letsencrypt.md /aleks-ent/pump-dump-crypto-screener/blob/main/docs/nginx letsencrypt.md . Persist PM2 across reboots: pm2 save pm2 startup follow the printed command once per server The manual reviewer at /review turns detected pumps into a human-labeled dataset for evaluating and improving the screener. It is designed for a fast, keyboard-friendly workflow: - Browse and filter stored pump events by status, category, exchange, symbol, and date. - Inspect Telegram subscriber votes alongside a 1m or 5m OHLCV chart centered on the screener's detection time. Charts use local history when available and otherwise load the four-hour window from the event's public Binance or Bybit API. - Classify each event as a wick spike, weak pump, sustained move, volume only, illiquid noise, or unclear; optionally record confidence and a comment. - Save and advance with keyboard shortcuts, revisit existing labels, track review progress, and export labeled datasets as JSON or CSV. Human annotations are stored separately from the original pump records, so review does not modify detector output. The workspace uses the existing Turso database, makes no browser-to-exchange requests, and can be protected with simple HTTP Basic authentication. See the pump review operator guide /aleks-ent/pump-dump-crypto-screener/blob/main/docs/pump-event-review/implementation.md for setup, access control, deployment, and release checks. pm2 status pm2 logs all apps pm2 logs pump-monitor download + scan pipeline pm2 logs pump-bot Telegram bot pm2 logs pump-web HTTP page pm2 restart ecosystem.config.cjs after config.js or code changes rebuild first pm2 restart pump-monitor restart pipeline only pm2 restart pump-bot restart bot only pm2 restart pump-web restart HTTP page only pm2 stop ecosystem.config.cjs pm2 delete ecosystem.config.cjs After editing config.js , restart the affected process pm2 restart pump-monitor , pump-bot , or pump-web . No PM2 reload is needed for config-only changes if you restart. Classification buttons need pump-bot running — it is included in ecosystem.config.cjs , not optional in production. Each PM2-driven run is an end-to-end pipeline: Download — last pump.days of 1m/5m candles from Binance and Bybit archives + REST fallback . See docs/fetch all.md /aleks-ent/pump-dump-crypto-screener/blob/main/docs/fetch all.md . Scan — pump/dump detection; output data/market stats/reports/pump events.ndjson . Persist + alert — upsert pump episodes to Turso; Telegram message per new, current pump coin|pump start utc . Episodes ending before the previous successful monitor cycle began are historical backfill: they are stored for /review but are not broadcast as fresh alerts. The exchange symbol universe is re-discovered when data/market stats/reports/symbol universe.json reaches pump.universeRefreshDays old default: 4 days . This adds new listings and removes delisted instruments from subsequent fetches and scans. On disk: data/market stats/ archives/ , api fallback/raw/ , reports/ . Cached series are skipped on repeat runs. Nothing is ever pruned automatically — see Disk usage and retention disk-usage-and-retention . Alerts sent to classifierTelegramChatId have Pump | Dump | None buttons. pump-bot verifies the callback came from that chat before writing pumps.classification ; other subscribers receive the same alerts without classification buttons. Turso bootstrap one-time : turso db create screener turso db show screener --url turso db tokens create screener pnpm db:bootstrap Telegram details: docs/telegram setup.md /aleks-ent/pump-dump-crypto-screener/blob/main/docs/telegram setup.md . Per-coin results under data/market stats/reports/scan cache/ override with --cache-dir on the underlying CLI . Entries are reused when detector version, scan params, window start, and loaded candle identity per exchange are unchanged — not file mtimes. New 5m bars trigger an incremental tail rescan ~400 bars ; UTC midnight window rolls trigger a full rescan. Disable cache: set pump.scanCache: false in config.js , or delete scan cache/ , then pm2 restart pump-monitor . Scanning uses a worker thread pool auto-detected CPU cores . Production scan step uses compiled dist/cli.js with native worker threads required on Linux/VDS . Nothing in the pipeline deletes anything — every run only appends. On a long-lived VDS data/market stats/ grows without bound 100 GB+ over a couple of months is normal . | Path | What it holds | Grows with | Read back? | |---|---|---|---| archives/ | Binance bulk archive downloads, symbol=X/date=YYYY-MM-DD | days × symbols | yes | api fallback/raw/ | REST fallback candles, date=YYYY-MM-DD/symbol=X | days × symbols | yes | extracted/ | archives unpacked to NDJSON, date=YYYY-MM-DD/symbol=X | days × symbols | yes — derived, regenerable from archives/ | reports/pump detector/