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 BullRadar community 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% |
| Community social buzz | exact-pair tagged posts + persisted token activity, capped 0–100 | 10 recent posts = 100 | 15% optional |
App-native social signal
The scorer reads only CommunityPost rows whose persisted tokenScannedPairId exactly matches the ScannedPair being written. It keeps posts from the last 24 hours, deduplicates by post id, and ignores stale, future, untagged, or differently-paired rows. Engagement is defined here as tagged-post activity (count plus recency); this checkout has no stored likes, replies, views, or reactions counter.
Activity milestones are $50k volume, $100k liquidity, 50% absolute 24-hour change, and the stored 0–100 trending score. Their weights are 40%, 20%, 20%, and 20%; available fields are renormalized. No qualifying post or no positive finite activity returns no signal, leaves the social fields null, and removes the optional 15% leg rather than fabricating a zero.
Social-buzz source, contribution, and freshness
A persisted reddit-rss value comes from the scanner's public Reddit search RSS capture and is saved as a dated token-history point only: its normalized score and fetch time are saved as the observation score and time. It does not feed the live social-buzz score or BullRadar ranking. Those continue to use exact-pair tagged CommunityPost rows, which emit source: 'bullradar-community'. The live CommunityPost signal retains its source URL and fetchedAt metadata; RSS history stores the exact fetch time in observedAt.
RSS and CommunityPost normalization use a fixed 24-hour lookback, discard stale or future results, deduplicate entries, and cap the count at 500. CommunityPost rows must also be tagged to the exact pair; untagged or differently-paired rows are discarded. Ten recent posts maps to 100 before the recency multiplier. Activity uses $50k volume, $100k liquidity, absolute 50% 24-hour price change, and the stored 0–100 trending score; if an activity field is absent, the remaining weights are renormalized.
For valid persisted social data, socialScore = round(0.70 × postScore + 0.30 × activityScore) on a 0–100 scale. The displayed methodology contribution is that social raw score multiplied by the optional 15% weight; the existing core factor weights do not change.
The live CommunityPost signal records the 24-hour lookback and fetch timestamp. The ranking presentation labels that signal stale at 24 hours or older while retaining its attribution, rather than presenting a fabricated zero. No qualifying post, no positive finite activity, invalid persisted metadata, or a provider/read failure yields no social signal (null/omitted optional leg). The core ranking remains usable, and the social contribution is not treated as zero.
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