---
name: coinbench
description: "Ben's live holder and market-cap tracker for Robinhood Chain coins, running on the kookwatch droplet. Load whenever a coin should be added to or removed from tracking, when an alert is questioned, when the tracker misbehaves, or before building any holder-growth, market-cap or turnover analysis on Robinhood Chain, because every guard in it exists because of a wrong call it already produced."
---

# COINBENCH

## Where it lives

Droplet **kookwatch 159.223.88.168**, key `~/kookwatch/id_kookwatch`, reached through Desktop_Commander on Ben's Mac. Service `coinbench.service`, code in `/opt/coinbench/`, sqlite at `/opt/coinbench/bench.db`. Pushes text and PNG charts to the same Telegram chat as the rest of the alert fleet.

```
bench.py      the loop, snapshots, message assembly
verdict.py    scoring and the action word
guards.py     READ THIS FIRST. Every past mistake as a runtime check
board.py      one cross-sectional PNG per sector
charts.py     first-24-hours launch benchmark PNG, coins under 24h only
backfill.py   30h of history from Dune plus GeckoTerminal
config.json   tracked coins with a sector field
refcurves.json  reference holder and mcap curves
```

Add a coin: `python3 /opt/coinbench/bench.py add 0xADDRESS LABEL "Sector name"`. Remove: `... drop 0xADDRESS`. Mute: `"muted": true` in config.json.

## The mechanism, from first principles

```
marketcap = holders x door          door = mcap / holders
dlog(mcap) = dlog(holders) + dlog(door)
```

Every price move splits into how many people are in the room and what each paid. Those are independent, and the pair is the whole signal. Turnover (24h volume / aggregate liquidity) is the third gate: under 10x the money stayed, over 20x it went in the front door and out the back.

Verdicts are **STRONG BUY / BUY / HOLD / TRIM / SELL**, with hedges (`HOLD / TRIM`) when the score lands on a boundary or the terms conflict, and **NO READ YET** when there is no history. Never invent new vocabulary: Ben has explicitly rejected state names like "seeding", "absorbing" and "bargain watch". One action word, one sentence of instruction, then the receipts.

## THE GUARDS. Do not remove one because it is inconvenient.

Each exists because it already produced a wrong call.

1. **No history means no verdict.** A partial score once put seven mature protocol tokens in TRIM off the turnover term alone. A scoring model must have an explicit not-enough-data state or a partial score silently becomes a recommendation.
2. **Filter off-price pools.** Keep only pools priced within 25% of the highest-volume pool before summing liquidity and volume. Measured spreads: PONS 1.8%, MOO 3.1%, DINO 68.9%, GG 956%, OPTIMUS 3,104,067% (it has a pool quoting against itself). Print how many were excluded.
3. **Price comes from the highest-VOLUME pool, never the deepest.** The deepest pool is often not the one that traded.
4. **Benchmark only within the same launch platform.** Doppler and other bonding-curve launches hold supply on the curve, so their day-one holder counts start near zero by construction. MOO showed 5 holders at 24 hours and is a $25M coin. Only instant-distribution launches (PONS v2, LaunchHook) are comparable to each other, and a launch-curve benchmark is meaningless past about 30 hours of age.
5. **GeckoTerminal `currency=usd` silently returns quote-token units on some Robinhood pools.** Always fetch the latest candle for the same pool, compare to DexScreener `priceUsd`, and reject the pool if the implied scale is more than 0.35 in log10 from 1.
6. **Total supply is marketCap / priceUsd, never Blockscout.** Blockscout 403s intermittently and a silent fallback once defaulted every token to 1e9.
7. **A holder series spliced from two sources must be scaled at the join.** The Dune running-balance reconstruction runs 0 to 12% below Blockscout. Splice raw and it prints a fake double-digit arrival spike. Scale by `blockscout_now / dune_now` and refuse a scale outside 0.5 to 2.0.
8. **Blockscout needs a browser User-Agent and a retry with backoff.** It is reliable from the droplet, flaky from a cloud container.
9. **A jump too large to be real is a data error, not a signal.** Holders over 60%/h, door over 300%/h, or turnover over 400x block the verdict and print DATA CHECK FAILED instead.

## Cadence

Under 24 hours old, every 10 minutes, because the first day is where the information is. One to seven days, hourly. Over seven days, every four hours. **All rates are normalised to per-hour against the previous reading, whatever its age**, so cadence never changes the score. A fixed 60-minute lookback was the original bug behind spurious NO READ YET.

## Charts

- **Launch benchmark** (coins under 24h): four panels against same-platform reference coins over their first 24 hours. Holders vs age, market cap vs age, **holders added per hour**, door price vs age. Panel three is the one that decides: winners keep climbing all day, the failure front-loads then flatlines.
- **Sector board** (everything else): holders vs market cap with $/head iso-lines so cheap is bottom-right, holder growth per hour ranked, turnover ranked with the 10x and 20x lines, and multiple to the sector ceiling. Sent hourly or immediately on any level change.

Palette validated CVD-safe: `#2563EB, #059669, #EA580C, #7C3AED`.

## What the base rates say, so a screen does not have to rediscover them

- Day-one holder count does not predict the ceiling. AI finished day one with 493 holders and is over $200M. FATCOIN finished with 3,172 and is near $1M.
- Shape beats level. The failure signature is a first-hour holder spike followed by a flat line.
- $/head is a stage metric, not a value metric. Price appreciation is what makes a door expensive, so the direction of the door is the signal and the level is not.
- Holder count is chain-level and already covers every pool. What pools poison is liquidity, volume and therefore turnover.