Composite Scoring
Composite Scoring
Every token receives a single 0–100 composite score that blends four independent dimensions into one number. The composite is the headline signal — the same four dimensions the self-learning loop recalibrates over time.
The four dimensions
The composite is a weighted sum of four dimension scores, each itself normalised to 0–100. The default weights below are version 1 — they are what ship until enough labelled outcomes accumulate for the self-learning model to update them.
Fee Opportunity
0.20Unclaimed creator fees (WETH × ETH price), scored on both an absolute USD scale and relative to market cap. Blended 70/30 with fee velocity at composite time.
Developer Quality
0.30The full developer composite — on-chain track record, FrontrunPro smart-follower quality, background pedigree, and activity recency.
Tech Research
0.30Built from the AI research report: inverted LARP probability (40%) + leadership score (30%) + traction score (30%). Defaults to 50 when no report exists yet.
Novelty
0.20The research report's novelty score — how unique the concept is vs prior art. Defaults to 50 with no report.
How the dimensions combine
The composite is a straight weighted blend, clamped to 0–100 and rounded. Crucially, the crowd score from the multi-persona swarm is deliberately not part of this formula — it is captured alongside the score as a candidate feature for future learning, not an input today.
// agents/scoring.ts — CompositeScorer.score() // Fee velocity is folded INTO the fee dimension (it doesn't add a 5th weight): // fast-accumulating fees amplify the fee opportunity. const effectiveFeeScore = Math.round(feeScore * 0.70 + velocityScore * 0.30); const composite = Math.round(Math.min(100, Math.max(0, effectiveFeeScore * weights.fee_weight + // default 0.20 devScore * weights.dev_weight + // default 0.30 techScore * weights.tech_weight + // default 0.30 noveltyScore * weights.novelty_weight // default 0.20 ))); // The swarm crowd_score is NOT in this formula. It is copied from the token's // most recent swarm run (within ~24h) at saveScore time as a candidate feature // so future learning can correlate it with outcomes — fail-soft, stays null on // any error. The ridge-regression dimensions stay on these same 4.
Fee opportunity sub-scoring
The fee dimension itself blends an absolute USD bucket (40%) with a market-cap-relative bucket (60%). A claimed or zero balance scores 0 — the signal is specifically unclaimed value.
// feeOpportunityScore() — only counts UNCLAIMED fees if (!feeClaim || feeClaim.is_claimed) return 0; // Absolute USD scale const abs = usd >= 10_000 ? 100 : usd >= 1_000 ? 80 : usd >= 100 ? 60 : usd >= 10 ? 40 : 20; // Relative to market cap (unclaimed / mcap) const rel = mcap > 0 ? (usd/mcap >= 0.05 ? 100 : usd/mcap >= 0.02 ? 80 : usd/mcap >= 0.01 ? 60 : usd/mcap >= 0.005 ? 40 : 20) : abs; // no mcap → fall back to absolute return Math.round(abs * 0.4 + rel * 0.6);
Tech research sub-scoring
// techResearchScore() — no report yet → neutral 50 if (!research) return 50; const notLarp = 100 - (research.larp_probability ?? 50); return Math.round(Math.min(100, Math.max(0, notLarp * 0.40 + (research.leadership_score ?? 50) * 0.30 + (research.traction_score ?? 50) * 0.30 )));
Confidence tiers
Separate from the score itself, each composite carries a confidence label reflecting how much of the underlying data was actually available when it was computed. More inputs present = higher confidence. A research report counts double because it's the richest signal.
// assessConfidence() — points-based let pts = 0; if (feeClaim) pts++; // fee data present if (research) pts += 2; // AI report present (weighted) if (devResult.dimensions.onchain_history.score > 0) pts++; // real on-chain analysis // Tier mapping: // pts >= 4 → 'very_high' // pts >= 3 → 'high' // pts >= 2 → 'medium' // else → 'low'
Fee data + research report + real on-chain dev analysis all present.
Research report present plus at least one other signal.
A research report exists, or two lighter signals are present.
Sparse data — score computed largely from defaults. Treat with caution.
Hidden-gem detection
Alongside the numeric score, the scorer flags hidden gems — tokens with a credible, active developer that the market hasn't discovered yet. The idea is a strong builder sitting on low volume is an early, low-competition opportunity. It is a boolean flag surfaced as a score reason, not a score multiplier.
// isHiddenGem() — ALL conditions must hold: devResult.composite >= 50 // credible developer && (token.volume_24h_usd ?? 0) <= 5_000 // market hasn't found it (< $5K/day) && (token.market_cap_usd ?? 0) >= 1_000 // but the token is real / has holders && !research?.is_larp // not flagged as a LARP && devResult.dimensions.activity_recency.score >= 30 // dev still active // When true, adds the reason: // "💎 HIDDEN GEM — strong developer with minimal market activity // (low competition, early opportunity)"
Score reasons
Every score ships with a human-readable list of reasons — the unclaimed fee amount, developer signals, LARP/novelty findings, fee-velocity notes, and an overall verdict band. These power the dashboard explanations and the alert messages.
// generateReasons() produces lines such as: // "$<usd> (<eth> ETH) in creator fees unclaimed — developer has // not withdrawn their <pct>% fee share" // "⚠️ HIGH LARP RISK (<p>%) — insufficient technical substance found" // "Technology is novel (novelty score: <n>/100)" // "⚡ High fee velocity — fees accumulating fast (velocity score: <v>/100)" // // Overall band: // composite >= 75 → "🟢 HIGH OPPORTUNITY — strong signals across all dimensions" // composite >= 65 → "🟡 MODERATE OPPORTUNITY — meets alert threshold" // composite < 30 → "🔴 LOW SCORE — significant concerns"
What gets stored
Each run inserts a row into composite_scores with the per-dimension scores, the composite, confidence, the full breakdown and reasons as JSON, the weights version used, the market cap at scoring time (so outcomes can be measured later), and the captured crowd score.
-- composite_scores (one row per scoring run) INSERT INTO composite_scores (id, token_address, fee_opportunity_score, developer_score, tech_research_score, novelty_score, fee_velocity_score, composite_score, composite_confidence, score_breakdown, score_reasons, weights_version, market_cap_usd_at_scoring, -- baseline for outcome measurement crowd_score) -- captured swarm signal (NOT a scoring input) VALUES (...);
How alerts and downstream agents key off the score
A composite of 65 is the threshold that fires Telegram / Discord alerts (LARP probability > 50 vetoes the alert regardless). The same ≥ 65 threshold gates the multi-persona swarm, and the market-cap-at-scoring baseline lets the outcome researcher measure what actually happened.