A KOL's "strategy" isn't a badge they pick — it's the distribution of how they actually hold. Someone who closes 80% of positions in the first hour is a scalper regardless of how they describe themselves on their Twitter bio. Someone who holds 60% of positions beyond 24 hours is a swing trader, even if they post hourly chart calls.
GET /api/v1/kol/{wallet}/timing is the endpoint that makes this quantitative. It returns the raw behavioral distribution — hold time statistics, fast-close percentages, average trade size, hourly activity histogram — that MadeOnSol uses internally to auto-classify every tracked KOL into one of five behavioral tags.
This post explains what the endpoint returns, how the auto-classifier interprets it, and the copy-trade implications of each tag.
The call
GET /api/v1/kol/{wallet}/timing?period=7d|30d
Authorization: Bearer msk_...
Period defaults to 30d. Only 7d and 30d are supported — behavior on this endpoint is noisy in shorter windows and rarely useful beyond 30 days (trading style can drift).
Available on every tier. Full response shape on BASIC, PRO, and ULTRA.
The response
{
"kol": {
"name": "Mezoteric",
"wallet": "7xK..."
},
"timing": {
"tokens_traded": 124,
"positions_closed": 96,
"avg_hold_minutes": 58.4,
"median_hold_minutes": 22.0,
"pct_closed_1h": 0.62,
"pct_closed_6h": 0.84,
"pct_closed_24h": 0.93,
"avg_buy_size_sol": 2.1,
"avg_sell_size_sol": 2.4,
"most_active_hours": [14, 15, 16, 22, 23],
"hour_distribution": {
"0": 2, "1": 1, "14": 18, "15": 22, "16": 19, "22": 14, "23": 12
}
},
"period": "30d"
}
Five distinct behavioral dimensions: hold-time stats, fast-close percentages, trade sizing, and hourly activity.
Field by field
median_hold_minutes — the classifier input
This is the one field the auto-classifier actually keys on. The mv_kol_scores materialized view computes auto_strategy_tag directly from 30-day median hold time:
median_hold_minutes (30d) | auto_strategy_tag |
|---|
| NULL (insufficient sample) | mixed |
< 30 | scalper |
30 – 360 (under 6h) | day_trader |
360 – 1440 (6–24h) | swing_trader |
>= 1440 (24h+) | hodler |
That's the entire classifier. When you see auto_strategy_tag: "scalper" on a /kol/feed row, it means the wallet's median 30-day hold is under 30 minutes. When it's "mixed", it means the wallet doesn't have enough closed positions in 30 days for the classifier to commit.
pct_closed_1h / pct_closed_6h / pct_closed_24h
Fraction of closed positions exited within 1 hour, 6 hours, and 24 hours respectively. These are cumulative — a wallet with pct_closed_1h: 0.62 will also have at least 0.62 for the 6h and 24h fields.
These don't drive the tag but they're where behavior gets interesting:
- A wallet tagged
scalper will usually have pct_closed_1h >= 0.55 — both numbers are consistent with fast-exit behavior.
- A wallet tagged
day_trader with pct_closed_1h: 0.70 has a median hold above 30 min but most of its positions still close fast — the long tail of held positions drags the median up. Classifier still calls it a day_trader, but functionally they scalp.
- A
swing_trader with low pct_closed_24h is holding a real book overnight — read this together with the tag to understand risk exposure.
Use median_hold_minutes to predict the classifier. Use pct_closed_* to see behavioral nuance inside the bucket.
avg_hold_minutes vs median_hold_minutes
Mean and median will diverge when a few long-tail holds drag the mean up. median_hold_minutes: 22 with avg_hold_minutes: 58.4 means most trades close fast, a minority are held much longer — the archetypal "cut losses fast, let winners run" profile.
If median equals mean, the wallet holds everything roughly the same duration regardless of outcome — robotic, consistent, and often bot-like.
avg_buy_size_sol / avg_sell_size_sol
Average position sizes in SOL. When sell size is materially larger than buy size (e.g. buy 1.2 SOL avg, sell 3.4 SOL avg), the wallet is scaling in with small buys and closing with fewer larger sells — accumulating then dumping. When buy > sell, they're entering with conviction and scaling out in chunks — position management style.
Equal-sized in/out (avg_buy_size_sol ≈ avg_sell_size_sol) almost always indicates a single buy / single sell per token. Very common for snipers.
most_active_hours / hour_distribution
Hours of day (UTC, 0–23) when the wallet trades most. most_active_hours is a sorted list of their top-5 peak hours; hour_distribution is the full 0–23 histogram.
Two practical uses:
- Timezone fingerprint. A KOL trading heavily during 13:00–21:00 UTC is on North American daytime. 00:00–08:00 UTC = Asia. 07:00–15:00 UTC = Europe. Timing alone won't tell you who they are, but it narrows the cohort.
- Live-trading alignment. If your copy-trade infra has an overnight maintenance window, prefer KOLs whose peak hours avoid your downtime.
A perfectly flat hour_distribution with non-zero values across all 24 hours is a strong bot signal. Humans sleep.
The auto-classifier in practice
When you hit /kol/feed or /kol/leaderboard, every row comes with a pre-computed auto_strategy_tag field sourced from mv_kol_scores. You don't need to call /timing to get the tag — it's already there. But calling /timing lets you see the underlying distribution and understand why a wallet was tagged the way it was.
The classifier is a single CASE expression in mv_kol_scores that reads median_hold_minutes over the 30-day window and falls through the buckets in order (scalper → day_trader → swing_trader → hodler). If the wallet has no 30-day median (too few closed positions to compute), the tag falls back to mixed.
Edge cases worth knowing:
- Fresh wallets with no 30-day median hold return
mixed until enough closed positions accumulate to compute a median. That happens once the wallet has a meaningful number of closed trades in the 30-day window.
- Low-activity wallets that hold every position for days typically land in
hodler or swing_trader — a single long-held position with no other closes can pull the median up.
- Burst traders who scalp heavily during active days but go silent between them often land in
day_trader on 30d — the median across a mixed set of fast scalps and infrequent longer holds sits in the 30-min-to-6-hour range.
Always pull both 7d and 30d tags when the distinction matters — they'll diverge for non-continuous traders.
Copy-trade implications by tag
The tag is load-bearing for setting up copy-trade infra. Each style has different requirements:
Scalper (median_hold_minutes < 30)
Fast entries, fast exits. Your copy-trade infra needs sub-second signal delivery (WebSocket or webhook, never polling) or you'll enter after they've already closed. Rate-limit tolerance is critical — a scalper can fire 10+ signals/hour.
Size suggestion: proportional sizing mode on /copytrade/subscriptions, scaled down because individual trades are small and frequent.
Day trader (median_hold_minutes 30 – 360)
Moderate-speed signals — 30-second delivery lag is fine. Can poll /copytrade/signals if you prefer pull-based integration. Position sizes are typically larger than scalpers.
Size suggestion: fixed or percent_source with 0.1–0.3 sizing multiplier.
Swing trader (median_hold_minutes 360 – 1440)
Signal latency basically doesn't matter. Minutes-late entries are still profitable. These KOLs hold overnight — you need risk rules for tokens that rug during your sleep window.