Transparency
Score Methodology
Every BullRadar Score is produced by the same deterministic pipeline that runs in production. This page documents every input, weight, and edge-case treatment verbatim from the source code — so you can audit any token's score against the formula below.
The number you see
BullRadar Score (0–100)
Shown on every token page. Higher = safer and hotter. Clamped 0–100. Computed as Σ(raw × weight). The five core factors are unchanged when RSS is unavailable; a valid normalized Reddit RSS score adds one optional 15% social contribution.
| Factor | Raw signal (0–100) | Milestone | Weight |
|---|---|---|---|
| 24h Volume | volumeUsd / $50 k × 100, capped 100 | $50 k | 20% |
| Holder concentration | 100 − topHolderPct, capped 0–100 | — | 20% |
| Liquidity | liquidityUsd / $100 k × 100, capped 100 | $100 k | 20% |
| Momentum | trendingScore (0–100, see §3) | — | 15% |
| Risk (safety) | 100 − rugRiskScore | — | 25% |
| RSS social buzz | normalized recent Reddit RSS mentions, capped 0–100 | 20 mentions = 100 | 15% optional |
BullRadar bands
Safety leg input
Rug-risk score (1–100)
Stored in the DB score column. Higher = riskier. The Safety factor fed into the BullRadar Score is 100 − rugRiskScore.
| Signal | Additive weight |
|---|---|
| Base score | 10 |
| Honeypot detected | +85 |
| Top holder > 50% of supply | +30 |
| Top holder 20–50% of supply | +15 |
| No LP reading (liquidityUsd ≤ 0) | +40 base + maturity sub-bump 0–18 |
| Thin liquidity ($0 < liq < $1 k) | +25 |
| Low liquidity ($1 k – $10 k) | +12 |
| Owner cannot renounce mint key | +8 |
Zero-liquidity maturity sub-bump (0–18 extra points)
When liquidityUsd = 0, the scanner can't confirm a clean LP, so it adds a +40 base bump. Hot pairs (high volume, big price move, or large market cap) receive up to 18 extra points on top, producing distinct risk integers per token instead of a single flat value:
0.5 if |Δ24h| ≥ 20% OR mcap ≥ $250 k;
else 0
No-security-coverage floor
When no contract-security aggregator (GoPlus / honeypot.is) contributed to the snapshot, the score is clamped to the range 34–66 so the token cannot show riskLevel: 'low' without verified data, but also can't reach riskLevel: 'high' (threshold 67) on absence of evidence alone. Liquidity, holder, and renounce bumps still add on top of the 34 floor, so absent-evidence rows still produce distinct integers per token.
Rug-risk bands
Momentum leg input
Trending score (0–100)
Stored as trendingScore on every ScannedPair row. Recomputed on every upsert. trendingScore = round(100 × raw)
| Component | Weight | Formula |
|---|---|---|
| Vol/liq velocity | 45% | clamp01(vol / max(1, liq) / 5) 5+ turnovers = full mark if liq = 0: clamp01(vol / $500 k) |
| Liq-weighted price move | 35% | clamp01((|Δ24h| / 100) × log₁₀(liq / $10 k)) if liq = 0: clamp01(|Δ24h| / 100) |
| Age bonus | 10% | clamp01(1 − max(0, ageHours − 6) / 24) 1.0 at < 6 h → 0 at > 30 h |
| Mcap gate | 10% | 1.0 if mcap ≥ $5 M, else 0.4 |
Edge-case treatment
Zero or unavailable liquidity
A liquidityUsd = 0 row cannot confirm a clean LP, so the scanner adds a +40 base risk bump instead of the lower thin/low-liq bumps. Hot pairs (high vol, big price move, or large mcap) receive up to +18 extra points on top via the maturity sub-bump formula above, producing distinct risk integers per token instead of a single flat value.
The vol/liq velocity leg falls back to a pure volume ramp (vol / $500 k); the price-move leg uses raw |Δ24h| / 100 (no log weighting). Both legs still move independently, so a zero-liquidity token with real volume and price movement earns non-trivial momentum — it doesn't collapse to zero just because LP data is unavailable.
Quick reference
Key constants at a glance
Weights and constants are read directly from production source code and updated whenever the scoring pipeline changes. Questions? bullradar-ai@polsia.app