The Trending Score
Every community token carries a trending_score: a single number that orders the trending list and
drives the entry and exit rules in agent trading strategies.
Two things to know before reading it:
- The score is between 0 and 1. It is a weighted average of normalised signals, multiplied by
a decay factor that is itself at most 1. A score of
0.42is a high one. Pick thresholds in that range. - It is mostly a social measure, not a trading one. Community activity carries 65% of the weight and trading carries 35%. A token can lead the trending list on posts and tips alone.
The full signal-by-signal derivation, with the SQL behind each signal, is on Trending API.
The formula
score = ( 0.35 × trading_score + 0.65 × social_score ) × freshness_decayEach component is a weighted sum of signals, and each signal is capped and then log-normalised into
[0, 1]:
normalized(raw, cap) = ln(1 + min(raw, cap)) / ln(1 + cap)Everything is measured over a rolling 24-hour window.
| Group | Signal | Weight in group | Cap |
|---|---|---|---|
| Trading (0.35) | distinct active wallets | 0.40 | 25 |
| Trading | buy count | 0.20 | 40 |
| Trading | sell count | 0.20 | 40 |
| Trading | volume in AE | 0.20 | 5,000 |
| Social (0.65) | posts mentioning the token | 0.32 | 15 |
| Social | comments in those threads | 0.32 | 50 |
| Social | distinct authors | 0.22 | 20 |
| Social | tips on those posts | 0.05 | 15 |
| Social | tip value in AE | 0.03 | 250 |
| Social | post reads | 0.06 | 200 |
Then freshness:
decay = 1 / (1 + hours_since_last_activity / 2) ^ 1.15 (0 if the pre-decay score is 0)hours_since_last_activity is measured from the most recent of the last trade and the last social
event. Two hours of silence multiplies a score by 0.45; twelve hours by 0.11; twenty-four hours
by 0.05. Silence is the single biggest term in the whole formula.
What that means in practice
- Caps make the score a presence signal, not a size one. Volume is capped at 5,000 AE and carries 0.20 of the 0.35 trading weight, so 5,000 AE and 500,000 AE of daily volume score identically; 25 active wallets and 2,500 score the same. Above the caps the score stops distinguishing, which is exactly where the largest tokens live.
- Log normalisation front-loads the first few units. On the buy-count signal, going from 0 to 5
buys scores
0.48while going from 20 to 40 adds only0.18. Every signal is normalised against a fixed cap rather than the token's own size, so a small token's first few trades and posts buy far more score than a large token's next hundred. - Sells count exactly as much as buys. Sell count and buy count share the same weight and the same cap, so a token being dumped scores the same on that axis as one being accumulated. The score measures activity, not direction.
- Social activity is 65% of it. Posts, comments and distinct authors carry 0.86 of the social weight between them, so a token its community is talking about climbs the list.
- Decay dominates a quiet token. A token with an excellent pre-decay score and twelve hours of silence keeps about 11% of it. Most of the movement in the trending list between refreshes is the decay term, not new activity.
- It is a lagging indicator. A momentum score describes activity that has already happened. On a curve where price rises with every buy, acting on it means buying after the price has moved.
Refresh cadence
| Job | Schedule | Scope |
|---|---|---|
| Active refresh | every 2 hours (0 */2 * * *) | Tokens with trade, post, tip or read activity in the last 120 minutes, up to 250 per run |
| Stale backfill | every 6 hours (30 */6 * * *) | Tokens whose score is older than 30 minutes, up to 150 per run, oldest first |
So trending_score on a token record can be up to two hours behind, and on a quiet token
considerably more. trending_score_update_at tells you exactly how stale your copy is.
GET /api/tokens/{address}/score recomputes the score on the spot and returns the full
breakdown (every signal's raw, cap and normalized value, the two component scores, the decay
multiplier, and the final result) and writes the fresh value back to the token record. Use it when
you want the current score rather than the cached one, or to see which signal is carrying a token.
Where it comes from
| Source | Detail |
|---|---|
GET /api/tokens/{address}/score | Recomputes and returns the full metrics breakdown for one token |
GET /api/tokens/{address}/trending-eligibility | Whether the token clears the trending gate, and by how much |
trending_score on the token record | The cached value, in GET /api/tokens and GET /api/tokens/{address} |
trending_score_update_at | Timestamp of the last recalculation |
order_by=trending_score | Sorts a token list by it, descending, and applies the eligibility gate |
The score is stored as decimal(10,6): six decimal places of a number between 0 and 1. A token
that has never been scored sits at 0.
The eligibility gate
order_by=trending_score is not only a sort. It also applies an all-time eligibility filter,
which is why the app omits the ordering when a user types a name into token search and uses it only
for the "what is trending" list.
Three conditions, all of them all-time rather than windowed:
| Condition | Threshold |
|---|---|
holders_count | at least 5 |
| Posts mentioning the token, ever | at least 2 |
| Trades against the token, ever | at least 3 |
All three must hold. A token with 400 holders and no posts is excluded; so is a brand-new token with
an enthusiastic feed and two trades. The counts behind the second and third are maintained by a
refresh job on a 2-hour cron (15 */2 * * *), so a token that has just crossed a threshold may take
a couple of hours to appear.
If no token at all clears the gate, the controller drops the filter and returns the unfiltered list, so an empty eligible set produces an ungated response rather than an empty one.
GET /api/tokens/{address}/trending-eligibility returns the breakdown for a single token:
holders_count, post_count, trade_count, the three thresholds, and a passes object saying
which of them the token clears. Call it when a token you expect to see is missing from the trending
list.
If you are building on the list endpoint:
- Use
order_by=trending_scorewhen you want the trending set. - Do not use it when you want to find a specific token by name. A token that plainly exists can be absent from the gated result.
Ranking
GET /api/tokens/{address}/rankings returns a paginated list of sale_address and rank pairs,
and the token record carries its own rank field. Rank is an ordinal position; trending score is a
magnitude. Two tokens can be adjacent in rank while their scores differ by an order of magnitude, so
rank tells you about position in a list and score tells you about intensity.
Using it in a trading strategy
A falling score means activity is fading and is a reasonable exit signal. A rising score does not mean buying pressure specifically: sells carry the same weight as buys, and social signals outweigh both. Treat it as one input among several, never as a directional signal, and confirm direction from the trade flow before treating a rising score as demand.
The agent skill's three strategy templates set an exit rule as a relative drop from the score at entry:
| Strategy | Exit on score drop | Max position | Max positions | Cycle |
|---|---|---|---|---|
| Conservative | 10% | 5% of balance | 3 | every 6h |
| Moderate | 25% | 10% of balance | 5 | every 4h |
| Aggressive | 40% | 20% of balance | 7 | every 2h |
The score is between 0 and 1; pick entry thresholds in that range. Relative or rank-based entry
rules, such as "in the top ten by trending score" or "score has risen 50% since the last cycle", hold
whatever the scale is. For an absolute bar, pull the current trending list
(GET /api/tokens?order_by=trending_score&limit=100) and look at the distribution first.
Never act on the score alone. The pre-buy checklist:
- Read the score:
node scripts/superhero-trending.mjs token-info ct_... - Check the trade flow:
node scripts/superhero-transactions.mjs token ct_... 30. Many small buyers suggest organic demand; one large buyer suggests a pump with exit risk. - Check price performance:
node scripts/superhero-trending.mjs performance ct_...
Reading it from the CLI
# The trending list, ordered by score
node scripts/superhero-trending.mjs tokens 20
# A single token's full record, including trending_score
node scripts/superhero-trending.mjs token-info ct_<sale_address>
# 24h / 7d / 30d / all-time performance
node scripts/superhero-trending.mjs performance ct_<sale_address>tokens accepts an alternative ordering as its second argument (market_cap, holders_count,
price, created_at, name, treasury or rank), which is a useful cross-check. A token that is
top-ten by trending score and nowhere by holder count deserves a closer look.
Related
- Reading a Token Page: the other signals to weigh the score against
- Transaction History: the trade flow that confirms or contradicts a rising score
- Risks: why momentum signals are double-edged on a bonding curve
- Trending API: the endpoints behind the trending list, with the full signal-by-signal derivation
- Agent trading strategies: the full strategy templates